Compare commits

...
16 Commits
29 changed files with 716 additions and 133 deletions
+4 -24
View File
@@ -1,35 +1,15 @@
## Tasks
# Testing
- [x] file_receive_prepare / file_send_prepare more reliable line processing
- [ ] test empty names
# Development plans
- [ ] Remove file when error while saving the data in DB
- [ ] Colorize server messages
- [x] make print_log to write a file log
- [x] Colorize server messages
- [ ] Unified list of exit codes
## Features
- [x] Database integration
- [x] Paging in the file list
- [x] Get files in FS by their hash
- [x] Registration
- [x] Encrypt passwords in DB
- [x] Registration: Error when username or email is already used
- [ ] Sorting in the file list
- [ ] Check correctness of email
- [ ] Message to admin
- [x] Advanced folder structure in the storage
- [ ] File encryption
- [ ] Connection encryption
- [ ] Advanced rights for files
- [ ] Multithreading
## Done
- [x] Switch to SQLite
- [x] Close the DB correctly in any quit case (also by SIGTERM)
- [x] Get rid of unsigned integers
- [x] Check registration
- [x] Auto create a database when one is missing
- [x] Show date in server log
+22 -8
View File
@@ -2,18 +2,15 @@
/* Copyright (c) 2026 Oleksandr Zhylin */
#include <client.h>
#include <fcntl.h>
#include <file_p.h>
#include <main.h>
#include <session.h>
#include <utils.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#define DIF_LIMIT 15
#define DIF_PAGE_NUM 1
#include <utils.h>
void process_client_command(char *line, session *sess, server_data_t *s_d) {
char arg_1[32];
@@ -23,7 +20,15 @@ void process_client_command(char *line, session *sess, server_data_t *s_d) {
fl_args.name = NULL;
int32_t ret = 0;
sscanf(line, "%s %s", arg_1, arg_2);
ret = sscanf(line, "%s %s", arg_1, arg_2);
if (ret == 1) {
if (!strcmp(arg_1, "file")) {
session_send_string(sess,
"Available commands: list, upload, download, search");
return;
}
}
if (!strcmp(arg_1, "file")) {
/* LIST */
@@ -60,11 +65,18 @@ void process_client_command(char *line, session *sess, server_data_t *s_d) {
if (!strcmp(arg_2, "search")) {
char *s_type = arg_1; /* since we don't need the contents of arg_1 and
arg_2 variables */
char *s_val = arg_2;
char s_val[256];
ret = sscanf(line, "%*s %*s %s %s %u %u", s_type, s_val, &(fl_args.limit),
&(fl_args.page));
switch (ret) {
case 0:
case -1:
session_send_string(sess, "The search criteria is not specified!");
return;
case 1:
session_send_string(sess, "The file name is not specified!");
return;
case 2:
fl_args.limit = DIF_LIMIT;
case 3:
@@ -89,7 +101,7 @@ void process_client_command(char *line, session *sess, server_data_t *s_d) {
void download_confirm(char *line, session *sess, server_data_t *s_d) {
if (!strncmp(line, "continue", sizeof "continue" - 1)) {
int pac_siz = 0;
int pac_siz = PACKAGE_SIZE;
sscanf(line, "continue %d\n", &pac_siz);
sess->state = OP_DOWNLOAD;
sess->file->package_rest = pac_siz;
@@ -100,5 +112,7 @@ void download_confirm(char *line, session *sess, server_data_t *s_d) {
sess->file->name);
clear_file_from_sess(sess);
sess->state = OP_WAIT;
return;
}
print_log(stdout, pl_info, "The answer is not correct. Send either \"continue \%PACKAGE_SIZE\% or \"cancel\"");
}
+3
View File
@@ -4,6 +4,9 @@
#ifndef CLIENT_H
#define CLIENT_H
#define DIF_LIMIT 15
#define DIF_PAGE_NUM 1
#include <main.h>
void process_client_command(char *line, session *sess, server_data_t *s_d);
void download_confirm(char *line, session *sess, server_data_t *s_d);
+16 -18
View File
@@ -108,7 +108,7 @@ void file_list(session *sess, i_file_list_t *f_args) {
fl_current->size, fl_current->owner);
int d_len = strlen(fl_current->description);
for (int i = h_len; i < d_len; i++) {
for (int i = 0; i < d_len; i++) {
if (fl_current->description[i] == '\n') {
fl_current->description[i] = '\a';
}
@@ -172,8 +172,7 @@ int32_t file_send_prepare(session *sess, char *line, server_data_t *s_d) {
}
int name_len = name_end - name_begin;
if (name_len == 0) {
session_send_string(
sess, "File name should not be empty");
session_send_string(sess, "File name should not be empty");
clear_file_from_sess(sess);
return -6;
}
@@ -238,8 +237,7 @@ int file_receive_prepare(session *sess, char *line, server_data_t *s_d) {
}
int name_len = name_end - name_begin;
if (name_len == 0) {
session_send_string(
sess, "File name should not be empty");
session_send_string(sess, "File name should not be empty");
clear_file_from_sess(sess);
return -7;
}
@@ -367,7 +365,7 @@ void file_download(session *sess) {
int rlen = read(source_d, buf, read_len);
if (rlen == 0) {
if (sess->file->rest) {
print_log(stdout, pl_error, "Error downloading file %s!\n",
print_log(stdout, pl_fail, "Fail while downloading file %s!\n",
sess->file->name);
clear_file_from_sess(sess);
}
@@ -377,7 +375,7 @@ void file_download(session *sess) {
int ret = write(dest_d, buf, rlen);
if (ret == -1) {
const char *err_mes = strerror(errno);
print_log(stdout, pl_error, "Error downloading file %s! %s\n",
print_log(stdout, pl_fail, "Fail while downloading file %s! %s\n",
sess->file->name, err_mes);
sess->state = ERR;
clear_file_from_sess(sess);
@@ -386,7 +384,7 @@ void file_download(session *sess) {
sess->file->rest -= rlen;
sess->file->package_rest -= rlen;
if (!sess->file->rest) {
print_log(stdout, pl_info, "File %s is downloaded from the server\n",
print_log(stdout, pl_success, "File %s is downloaded from the server\n",
sess->file->name);
clear_file_from_sess(sess);
sess->state = OP_WAIT;
@@ -402,10 +400,10 @@ void file_download(session *sess) {
{ \
int res = write(dest_d, buf, len); \
if (res == -1) { \
session_send_string( \
sess, "There is an error sending the file named \"%s\"\n"); \
session_send_string(sess, \
"There is an error sending the file name \"%s\"\n"); \
char *err_mes = strerror(errno); \
print_log(stdout, pl_error, "Error uploading the file \"%s\": %s\n", \
print_log(stdout, pl_fail, "Fail while uploading the file \"%s\": %s\n", \
sess->file->name, err_mes); \
close(dest_d); \
unlink(sess->file->path); /* remove file */ \
@@ -425,7 +423,7 @@ void file_upload(session *sess) {
if (rlen == 0) {
if (sess->file->rest) {
print_log(stdout, pl_error, "Error uploading file %s!\n",
print_log(stdout, pl_fail, "Fail while uploading file %s!\n",
sess->file->name);
unlink(sess->file->path); /* remove file */
clear_file_from_sess(sess);
@@ -460,7 +458,7 @@ void file_upload(session *sess) {
sess->file->package_rest = fpd->package_size - rlen;
break;
case sig_cancel:
print_log(stdout, pl_error, "Upload of %s is cancelled!\n",
print_log(stdout, pl_fail, "Upload of %s is cancelled!\n",
sess->file->name);
unlink(sess->file->path); /* remove file */
clear_file_from_sess(sess);
@@ -479,13 +477,13 @@ void file_upload(session *sess) {
}
fin:
if (!sess->file->rest) {
print_log(stdout, pl_info, "File %s is uploaded to the server\n",
print_log(stdout, pl_success, "File %s is uploaded to the server\n",
sess->file->name);
session_send_string(sess, "finished\n");
if (db_save_file(sess)) {
clear_file_from_sess(sess);
}
sess->state = OP_WAIT;
sess->state = OP_UPLOAD_DESCRIPTION;
// if (db_save_file(sess)) {
// clear_file_from_sess(sess);
// }
}
}
+48 -24
View File
@@ -1,27 +1,30 @@
/* SPDX-License-Identifier: MIT */
/* Copyright (c) 2026 Oleksandr Zhylin */
#include <db.h>
#include <file_p.h>
#include <main.h>
#include <session.h>
#include <utils.h>
#include <arpa/inet.h>
#include <db.h>
#include <errno.h>
#include <fcntl.h>
#include <file_p.h>
#include <main.h>
#include <netinet/in.h>
#include <session.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <unistd.h>
#include <utils.h>
volatile sig_atomic_t shutdown_requested = 0;
volatile sig_atomic_t signal_received = 0;
void set_signals(sigset_t *orig_mask);
void term_int_handler(int s) {
shutdown_requested = 1;
signal_received = s;
@@ -30,14 +33,9 @@ void term_int_handler(int s) {
void server_main_loop(server_data_t *s_d) {
fd_set readfds;
int i, sr;
sigset_t mask, orig_mask;
sigset_t orig_mask;
set_signals(&orig_mask);
signal(SIGINT, term_int_handler);
signal(SIGTERM, term_int_handler);
sigemptyset(&mask);
sigaddset(&mask, SIGINT);
sigaddset(&mask, SIGTERM);
sigprocmask(SIG_BLOCK, &mask, &orig_mask);
session *connections[MAX_CONNECTIONS];
for (i = 0; i < MAX_CONNECTIONS; i++) {
@@ -68,7 +66,6 @@ void server_main_loop(server_data_t *s_d) {
}
}
}
sr = pselect(maxfd + 1, &readfds, NULL, NULL, NULL, &orig_mask);
if (shutdown_requested != 0) {
@@ -78,7 +75,7 @@ void server_main_loop(server_data_t *s_d) {
}
if (sr == -1) {
perror("select");
print_log(stderr, pl_error, "select: %s", strerror(errno));
exit(6);
}
@@ -119,7 +116,8 @@ void server_main_loop(server_data_t *s_d) {
char *get_welcome_mes(void) {
int fd = open(WELCOME_FILE_NAME, O_RDONLY);
if (fd == -1) {
perror(WELCOME_FILE_NAME);
print_log(stderr, pl_fatal, "starting, welcome file \"%s\": %s\n",
WELCOME_FILE_NAME, strerror(errno));
exit(7);
}
int filesize = lseek(fd, 0, SEEK_END) + 1;
@@ -127,7 +125,8 @@ char *get_welcome_mes(void) {
char *welcome_message =
mmap(NULL, filesize, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
if (welcome_message == MAP_FAILED) {
perror(WELCOME_FILE_NAME);
print_log(stderr, pl_fatal, "starting, welcome file \"%s\": %s\n",
WELCOME_FILE_NAME, strerror(errno));
close(fd);
exit(5);
}
@@ -141,39 +140,64 @@ int start_server(void) {
int ls = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in s_addr;
if (ls == -1) {
print_log(stderr, pl_fatal, "starting, socket: %s\n", strerror(errno));
exit(3);
}
s_addr.sin_family = AF_INET;
s_addr.sin_port = htons(PORT);
s_addr.sin_addr.s_addr = htonl(INADDR_ANY);
int opt = 1;
setsockopt(ls, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
res = setsockopt(ls, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
if (res == -1) {
print_log(stderr, pl_fatal, "starting, setsockopt: %s\n", strerror(errno));
exit(4);
}
res = bind(ls, (struct sockaddr *)&s_addr, sizeof(s_addr));
if (res == -1) {
perror("bind");
exit(3);
print_log(stderr, pl_fatal, "starting, socket bind: %s\n", strerror(errno));
exit(5);
}
res = listen(ls, LISTEN_QLEN);
if (res == -1) {
perror("listen");
exit(4);
print_log(stderr, pl_fatal, "starting, socket listen: %s\n",
strerror(errno));
exit(6);
}
return ls;
}
void prepare_start(int argc, char *argv[]) {
if (argc != 2) {
if (argc < 2) {
print_log(stdout, pl_error, "Usage: %s <work_dir>\n", argv[0]);
exit(1);
}
if (-1 == chdir(argv[1])) {
perror(argv[1]);
print_log(stderr, pl_fatal, "chdir: \"%s\" %s\n", argv[1], strerror(errno));
exit(2);
}
if (!directory_exists(STORAGE_FOLDER)) {
mkdir(STORAGE_FOLDER, 0700);
if (mkdir(STORAGE_FOLDER, 0700) == -1) {
print_log(stderr, pl_fatal, "mkdir: \"%s\" %s\n", argv[1],
strerror(errno));
exit(8);
}
}
}
void set_signals(sigset_t *orig_mask) {
sigset_t mask;
signal(SIGINT, term_int_handler);
signal(SIGTERM, term_int_handler);
sigemptyset(&mask);
sigaddset(&mask, SIGINT);
sigaddset(&mask, SIGTERM);
sigprocmask(SIG_BLOCK, &mask, orig_mask);
}
+12 -11
View File
@@ -2,14 +2,12 @@
/* Copyright (c) 2026 Oleksandr Zhylin */
#include "session.h"
#include <client.h>
#include <file_p.h>
#include <main.h>
#include <user.h>
#include <utils.h>
#include <arpa/inet.h>
#include <client.h>
#include <db.h>
#include <fcntl.h>
#include <file_p.h>
#include <main.h>
#include <netinet/in.h>
#include <stdarg.h>
#include <stddef.h>
@@ -19,6 +17,8 @@
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#include <user.h>
#include <utils.h>
session *make_new_session(int fd, struct sockaddr_in *from, char *wm);
@@ -51,8 +51,7 @@ session *make_new_session(int fd, struct sockaddr_in *from, char *wm) {
sess->file = NULL;
sess->fl_start = NULL;
sess->fl_current = NULL;
session_send_string(sess, wm);
session_send_string(sess, "login> ");
session_send_string(sess, "%slogin> ", wm);
return sess;
}
@@ -207,14 +206,16 @@ void perform_session_action(session *sess, char *line, server_data_t *s_d) {
case OP_UPLOAD_DESCRIPTION:
res = file_upload_description(sess, line, s_d);
if (res) {
if (db_save_file(sess)) {
if (db_save_file(sess->file, sess->uid)) {
session_send_string(sess, "File \"%s\" is saved!\04\n",
sess->file->name);
clear_file_from_sess(sess);
sess->state = OP_WAIT;
} else {
// TODO: error case
session_send_string(sess, "Error while saving the file %s!\04\n",
sess->file->name);
unlink(sess->file->path);
}
clear_file_from_sess(sess);
sess->state = OP_WAIT;
}
break;
case OP_DOWNLOAD_WAIT_CONFIRM_PACKAGE:
+79 -7
View File
@@ -1,9 +1,63 @@
#include "utils.h"
#include <asm-generic/errno-base.h>
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#define LOGFILE_NAME "bbs-server.log"
/* COLORS */
#define INFO_COLOR "\033[0m"
#define WARN_COLOR "\033[0m\033[33m"
#define ERR_COLOR "\033[0m\033[31m"
#define FATAL_COLOR "\033[0m\033[31m\033[1m"
#define FATAL_COLOR "\033[0m\033[31m\033[1m"
#define SUCCESS_COLOR "\033[0m\033[32m"
#define FAIL_COLOR "\033[0m\033[35m"
static struct {
int fd;
} file;
int open_log_file(char *path, int *_fd) {
int fd = open(path, O_WRONLY | O_CREAT | O_EXCL, 0666);
if (fd == -1) {
return errno;
}
*_fd = fd;
return 0;
}
void close_log_file() { close(file.fd); }
/* TODO: create recursive backups 5 times */
int init_log_file() {
int fd;
int res = open_log_file(LOGFILE_NAME, &fd);
if (res == EEXIST) {
int res = open_log_file(LOGFILE_NAME ".old", &fd);
if (res == EEXIST) {
unlink(LOGFILE_NAME ".old");
} else {
close(fd);
}
rename(LOGFILE_NAME, LOGFILE_NAME ".old");
res = open_log_file(LOGFILE_NAME, &fd);
if (res != 0) {
return -1;
}
}
file.fd = fd;
return fd;
}
int write_into_log_file(char *fmt, va_list args) {
return vdprintf(file.fd, fmt, args);
}
int print_log(FILE *output, enum pl_type type, const char *format_message,
...) {
@@ -15,24 +69,42 @@ int print_log(FILE *output, enum pl_type type, const char *format_message,
va_list args;
sprintf(date_preffix, "[%s] ", ctime(&t));
strftime(date_preffix, 128, "[%d.%m.%y %T]", tm);
const char *tcolor;
switch (type) {
case pl_info:
uff_str = "%s %s";
uff_str = "%s%s %s";
tcolor = INFO_COLOR;
break;
case pl_warning:
uff_str = "%s Warning: %s";
uff_str = "%s%s Warning: %s";
tcolor = WARN_COLOR;
break;
case pl_error:
uff_str = "%s Error: %s";
uff_str = "%s%s Error: %s";
tcolor = ERR_COLOR;
break;
case pl_fatal:
uff_str = "%s Fatal: %s";
uff_str = "%s%s Fatal: %s";
tcolor = FATAL_COLOR;
break;
case pl_success:
uff_str = "%s%s %s";
tcolor = SUCCESS_COLOR;
break;
case pl_fail:
uff_str = "%s%s Fail: %s";
tcolor = FAIL_COLOR;
break;
}
char *uf_str = malloc(strlen(date_preffix) + 16 + strlen(format_message) + 4);
sprintf(uf_str, uff_str, date_preffix, format_message);
char *uf_str = malloc(strlen(date_preffix) + 32 + strlen(format_message) + 4);
sprintf(uf_str, uff_str, tcolor, date_preffix, format_message);
va_start(args, format_message);
ret = vfprintf(stdout, uf_str, args);
ret = vfprintf(output, uf_str, args);
va_end(args);
va_start(args, format_message);
write_into_log_file(uf_str + strlen(tcolor), args);
va_end(args);
free(uf_str);
va_end(args);
return ret;
}
+4
View File
@@ -4,11 +4,15 @@
#include <stdio.h>
enum pl_type {
pl_info,
pl_success,
pl_fail,
pl_warning,
pl_error,
pl_fatal,
};
int print_log(FILE * output, enum pl_type type, const char *format_message, ...);
int init_log_file();
void close_log_file();
#endif
+1 -1
View File
@@ -47,7 +47,7 @@ typedef struct {
enum db_cb_resp { db_no_result, db_success, db_err, db_fail }; /* fail: the problem is on the user's side; no error */
int32_t init_db_connection();
int32_t db_save_file(session *s);
int32_t db_save_file(s_file_t *sfP, int uid);
int32_t db_user_auth(i_auth_t *credentials, o_auth_t *response);
s_file_t *db_get_file(i_get_file_db *arg);
int32_t db_get_files_data(i_get_files_db *arg, fl_t **fl_start,
+5 -6
View File
@@ -3,9 +3,7 @@
/* TODO: variadic function for preparing parameters */
#include "../main.h"
#include "../utils.h"
#include "db_common.h"
#include <main.h>
#include <db.h>
#include <endian.h>
#include <fcntl.h>
@@ -18,6 +16,8 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "utils.h"
#include "db_common.h"
#define UNUSED(x) (void)(x)
#define Q_LEN 128
@@ -198,15 +198,14 @@ int32_t db_user_create(i_db_user_create *args) {
return ret_value;
}
int32_t db_save_file(session *s) {
int32_t db_save_file(s_file_t *sf, int uid) {
const char *paramValues[6];
int paramFormats[6];
int paramLengths[6];
/* int collision_id = 0; */
s_file_t *sf = s->file;
char empty_str[] = "";
int32_t uid_n = htonl(s->uid);
int32_t uid_n = htonl(uid);
size_t size_n = htobe64(sf->size);
int32_t hash_n = htonl(sf->hash);
int32_t perm_n = htonl(sf->permissions);
+3 -4
View File
@@ -3,7 +3,6 @@
#include <main.h>
#include <utils.h>
#include "db_common.h"
#include <db.h>
#include <endian.h>
#include <openssl/sha.h>
@@ -16,6 +15,7 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "db_common.h"
#define UNUSED(x) (void)(x)
#define Q_LEN 128
@@ -284,8 +284,7 @@ enum db_cb_resp db_save_file_cb(sqlite3_stmt *stmt, void *resp) {
return res;
};
int32_t db_save_file(session *s) {
s_file_t *sfP = s->file;
int32_t db_save_file(s_file_t *sfP, int uid) {
struct db_save_file_data resp_data = {.id = 0};
const char empty_str[] = "";
enum db_cb_resp res = db_no_result;
@@ -296,7 +295,7 @@ int32_t db_save_file(session *s) {
"hash, description, permissions) "
"VALUES ($1, $2, $3, date(), $4, $5, $6) "
"RETURNING id",
db_save_file_cb, &resp_data, arg_types, s->uid, sfP->name,
db_save_file_cb, &resp_data, arg_types, uid, sfP->name,
sfP->size, sfP->hash,
sfP->description != NULL ? sfP->description : empty_str,
sfP->permissions);
+2
View File
@@ -14,8 +14,10 @@ int main(int argc, char *argv[]) {
init_db_connection();
server_data.ls = start_server();
/* TODO: display server port */
init_log_file();
print_log(stdout, pl_info, "Server is started!\n");
server_main_loop(&server_data);
db_close_connection();
close_log_file();
return 0;
}
+1
View File
@@ -3,3 +3,4 @@ add_subdirectory(user)
add_subdirectory(file_p)
add_subdirectory(test_utils)
add_subdirectory(client)
add_subdirectory(server)
+19 -1
View File
@@ -12,6 +12,24 @@ target_link_libraries(process_client_command
test_utils
)
target_link_options(process_client_command PRIVATE -Wl,--wrap=file_list,--wrap=file_send_prepare,--wrap=file_receive_prepare)
target_link_options(process_client_command PRIVATE -Wl,--wrap=file_list,--wrap=file_send_prepare,--wrap=file_receive_prepare,--wrap=session_send_string)
add_test(NAME client_process_client_command_test_1 COMMAND process_client_command)
# ---/ download_confirm /--------------------------------------------------
add_executable(download_confirm
download_confirm.c
)
target_link_libraries(download_confirm
cmocka
client
file_p
main
test_utils
)
target_link_options(download_confirm PRIVATE -Wl,--wrap=print_log,--wrap=clear_file_from_sess)
add_test(NAME client_download_confirm_test_1 COMMAND download_confirm)
+83
View File
@@ -0,0 +1,83 @@
#include <cmocka.h>
#include <db/db.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <client.h>
#include <file_p.h>
#include <main.h>
#include <string.h>
#define PAC_SIZ 107898
#define FNAME "test_file_1"
char *str2snd = NULL;
int clear_file_from_sess_call = 0;
extern void *print_str_arr;
void __wrap_clear_file_from_sess(session *s) {
clear_file_from_sess_call++;
s->file = NULL;
return;
}
void test__download_confirm__continue(void **state) {
s_file_t file = {.package_rest = 0};
session sess = {.state = OP_DOWNLOAD_WAIT_CONFIRM_PACKAGE, .file = &file};
char line[128];
sprintf(line, "continue %d\n", PAC_SIZ);
download_confirm(line, &sess, NULL);
assert_int_equal(sess.state, OP_DOWNLOAD);
assert_int_equal(sess.file->package_rest, PAC_SIZ);
}
void test__download_confirm__continue_no_size(void **state) {
s_file_t file = {.package_rest = 0};
session sess = {.state = OP_DOWNLOAD_WAIT_CONFIRM_PACKAGE, .file = &file};
char line[128];
sprintf(line, "continue");
download_confirm(line, &sess, NULL);
assert_int_equal(sess.state, OP_DOWNLOAD);
assert_int_equal(sess.file->package_rest, PACKAGE_SIZE);
}
void test__download_confirm__cancel(void **state) {
s_file_t file = {.package_rest = 0, .name = FNAME};
session sess = {.state = OP_DOWNLOAD_WAIT_CONFIRM_PACKAGE, .file = &file};
const char *fmt_args[] = {"Downloading of %s is canceled by the client\n",
FNAME, NULL};
print_str_arr = fmt_args;
download_confirm("cancel\n", &sess, NULL);
assert_int_equal(sess.state, OP_WAIT);
assert_ptr_equal(sess.file, NULL);
}
void test__download_confirm__noise(void **state) {
s_file_t file = {.package_rest = 0, .name = FNAME};
session sess = {.state = OP_DOWNLOAD_WAIT_CONFIRM_PACKAGE, .file = &file};
const char *fmt_args[] = {"The answer is not correct. Send either \"continue "
"\%PACKAGE_SIZE\% or \"cancel\"",
NULL};
print_str_arr = fmt_args;
download_confirm("jasdf", &sess, NULL);
assert_int_equal(sess.state, OP_DOWNLOAD_WAIT_CONFIRM_PACKAGE);
}
int setup(void **state) { return 0; }
int tear_down(void **state) { return 0; }
int main(int argc, char **argv) {
const struct CMUnitTest tests[] = {
cmocka_unit_test(test__download_confirm__continue),
cmocka_unit_test(test__download_confirm__continue_no_size),
cmocka_unit_test(test__download_confirm__cancel),
cmocka_unit_test(test__download_confirm__noise),
};
return cmocka_run_group_tests(tests, setup, tear_down);
}
+136 -4
View File
@@ -1,11 +1,9 @@
#include <cmocka.h>
#include <db/db.h>
#include <setjmp.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <client.h>
#include <file_p.h>
@@ -13,16 +11,31 @@
#include <string.h>
int file_list_calls = 0;
int _limit = 15;
int _page = 2;
int _limit = DIF_LIMIT;
int _page = DIF_PAGE_NUM;
char *_name = NULL;
char _line[128];
char file_name[] = "hello_file";
int file_size = 121212;
int file_perm = 1;
char *str2snd = NULL;
void __wrap_session_send_string(struct session *sess, const char *fmt, ...) {
if (str2snd != NULL) {
assert_string_equal(fmt, str2snd);
str2snd = NULL;
}
}
void __wrap_file_list(session *sess, i_file_list_t *f_args) {
assert_int_equal(_limit, f_args->limit);
if (_limit != DIF_LIMIT) _limit = DIF_LIMIT;
if (_page != DIF_PAGE_NUM) _page = DIF_PAGE_NUM;
assert_int_equal(_page, f_args->page);
if (_name != NULL) {
assert_string_equal(_name, f_args->name);
_name = NULL;
}
file_list_calls++;
}
@@ -71,6 +84,116 @@ void test__process_client_command__file_upload_fail(void **state) {
assert_int_equal(sess.state, OP_WAIT);
}
void test__process_client_command__file_download(void **state) {
session sess = {.state = OP_WAIT};
will_return(__wrap_file_send_prepare, 0);
sprintf(_line, "file download \"%s\" %d %d", file_name, file_size, file_perm);
process_client_command(_line, &sess, NULL);
assert_int_equal(sess.state, OP_DOWNLOAD);
}
void test__process_client_command__file_download_fail(void **state) {
session sess = {.state = OP_WAIT};
will_return(__wrap_file_send_prepare, 1);
sprintf(_line, "file download \"%s\" %d %d", file_name, file_size, file_perm);
process_client_command(_line, &sess, NULL);
assert_int_equal(file_list_calls, 0);
assert_int_equal(sess.state, OP_WAIT);
}
void test__process_client_command__file_search(void **state) {
session sess = {.state = OP_WAIT};
_name = "name";
_limit = 20;
_page = 2;
sprintf(_line, "file search %s \"%s\" %d %d", _name, file_name, _limit, _page);
process_client_command(_line, &sess, NULL);
assert_int_equal(file_list_calls, 0);
assert_int_equal(sess.state, OP_WAIT);
}
void test__process_client_command__file_search_no_page(void **state) {
session sess = {.state = OP_WAIT};
_name = "name";
_limit = 20;
sprintf(_line, "file search %s \"%s\" %d", _name, file_name, _limit);
process_client_command(_line, &sess, NULL);
assert_int_equal(file_list_calls, 0);
assert_int_equal(sess.state, OP_WAIT);
}
void test__process_client_command__file_search_no_limit(void **state) {
session sess = {.state = OP_WAIT};
_name = "name";
sprintf(_line, "file search %s \"%s\"", _name, file_name);
process_client_command(_line, &sess, NULL);
assert_int_equal(file_list_calls, 0);
assert_int_equal(sess.state, OP_WAIT);
}
void test__process_client_command__file_search_no_name(void **state) {
session sess = {.state = OP_WAIT};
_name = "name";
sprintf(_line, "file search name");
str2snd = "The file name is not specified!";
process_client_command(_line, &sess, NULL);
assert_int_equal(file_list_calls, 0);
assert_int_equal(sess.state, OP_WAIT);
}
void test__process_client_command__file_search_no_type(void **state) {
session sess = {.state = OP_WAIT};
sprintf(_line, "file search");
str2snd = "The search criteria is not specified!";
process_client_command(_line, &sess, NULL);
assert_int_equal(file_list_calls, 0);
assert_int_equal(sess.state, OP_WAIT);
}
void test__process_client_command__file(void **state) {
session sess = {.state = OP_WAIT};
sprintf(_line, "file");
str2snd = "Available commands: list, upload, download, search";
process_client_command(_line, &sess, NULL);
assert_int_equal(file_list_calls, 0);
assert_int_equal(sess.state, OP_WAIT);
}
void test__process_client_command__exit(void **state) {
session sess = {.state = OP_WAIT};
str2snd = "OK. Bye!\n";
process_client_command("exit", &sess, NULL);
assert_int_equal(file_list_calls, 0);
assert_int_equal(sess.state, ERR);
assert_int_equal(sess.reason, EXIT);
}
int setup(void **state) { return 0; }
int tear_down(void **state) { return 0; }
@@ -79,6 +202,15 @@ int main(int argc, char **argv) {
cmocka_unit_test(test__process_client_command__file_list),
cmocka_unit_test(test__process_client_command__file_upload),
cmocka_unit_test(test__process_client_command__file_upload_fail),
cmocka_unit_test(test__process_client_command__file_download),
cmocka_unit_test(test__process_client_command__file_download_fail),
cmocka_unit_test(test__process_client_command__file_search),
cmocka_unit_test(test__process_client_command__file_search_no_page),
cmocka_unit_test(test__process_client_command__file_search_no_limit),
cmocka_unit_test(test__process_client_command__file_search_no_name),
cmocka_unit_test(test__process_client_command__file_search_no_type),
cmocka_unit_test(test__process_client_command__file),
cmocka_unit_test(test__process_client_command__exit),
};
return cmocka_run_group_tests(tests, setup, tear_down);
+4 -4
View File
@@ -65,7 +65,7 @@ target_link_options(file_send_prepare PRIVATE -Wl,--wrap=write,--wrap=print_log,
add_test(NAME file_p_file_send_prepare_test_1 COMMAND file_send_prepare)
# ---/ file_receive_prepare /-------------------------------------------
# ---/ file_receive_prepare /----------------------------------------
add_executable(file_receive_prepare
file_receive_prepare.c
@@ -83,7 +83,7 @@ target_link_options(file_receive_prepare PRIVATE -Wl,--wrap=statvfs,--wrap=stat,
add_test(NAME file_p_file_receive_prepare_test_1 COMMAND file_receive_prepare)
# ---/ clear_file_from_sess /-------------------------------------------
# ---/ clear_file_from_sess /----------------------------------------
add_executable(clear_file_from_sess
clear_file_from_sess.c
@@ -101,7 +101,7 @@ target_link_options(clear_file_from_sess PRIVATE -Wl,--wrap=free)
add_test(NAME file_p_clear_file_from_sess_test_1 COMMAND clear_file_from_sess)
# ---/ file_download /-------------------------------------------
# ---/ file_download /-----------------------------------------------
add_executable(file_download
file_download.c
@@ -120,7 +120,7 @@ target_link_options(file_download PRIVATE -Wl,--wrap=print_log,--wrap=read,--wra
add_test(NAME file_p_file_download_test_1 COMMAND file_download)
# ---/ file_upload /-------------------------------------------
# ---/ file_upload /-------------------------------------------------
add_executable(file_upload
file_upload.c
-2
View File
@@ -1,10 +1,8 @@
#include <cmocka.h>
#include <db/db.h>
#include <setjmp.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
-4
View File
@@ -1,15 +1,11 @@
#include <cmocka.h>
#include <db/db.h>
#include <setjmp.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <file_p.h>
#include <main.h>
#include <string.h>
#include <test_utils.h>
fl_t fl_sample = {
-5
View File
@@ -1,16 +1,11 @@
#include <cmocka.h>
#include <db/db.h>
#include <setjmp.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <file_p.h>
#include <main.h>
#include <string.h>
#include <sys/cdefs.h>
#include <unistd.h>
-1
View File
@@ -1,6 +1,5 @@
#include <cmocka.h>
#include <db/db.h>
#include <setjmp.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
-1
View File
@@ -1,7 +1,6 @@
#include <cmocka.h>
#include <db/db.h>
#include <errno.h>
#include <setjmp.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
+1 -1
View File
@@ -1,6 +1,5 @@
#include <cmocka.h>
#include <db/db.h>
#include <setjmp.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
@@ -15,6 +14,7 @@
#include <unistd.h>
#include <utils.h>
#include <test_utils.h>
char *str2snd = NULL;
dbuf_t *dbuf;
+41
View File
@@ -0,0 +1,41 @@
# ---/ start_server /------------------------------------------------
add_executable(start_server
start_server.c
)
target_link_libraries(start_server
cmocka
client
file_p
session
utils
main
server
test_utils
)
target_link_options(start_server PRIVATE -Wl,--wrap=socket,--wrap=setsockopt,--wrap=bind,--wrap=listen,--wrap=exit,--wrap=print_log)
add_test(NAME client_start_server_test_1 COMMAND start_server)
# ---/ prepare_start /-----------------------------------------------
add_executable(prepare_start
prepare_start.c
)
target_link_libraries(prepare_start
cmocka
client
file_p
session
utils
main
server
test_utils
)
target_link_options(prepare_start PRIVATE -Wl,--wrap=print_log,--wrap=chdir,--wrap=mkdir,--wrap=exit,--wrap=directory_exists)
add_test(NAME client_prepare_start_test_1 COMMAND prepare_start)
+106
View File
@@ -0,0 +1,106 @@
#include <cmocka.h>
#include <main.h>
#include <server.h>
int _errno = 0;
int _exit_code = 0;
extern void *print_str_arr;
void __wrap_exit(int __status) { _exit_code = __status; }
int __wrap_chdir(const char *__path) { return mock_type(int); }
int __wrap_mkdir(const char *__path, __mode_t __mode) { return mock_type(int); }
int __wrap_directory_exists(const char *path) { return mock_type(int); }
void test__prepare_start__success(void **state) {
int argc = 2;
char *argv[] = {"test_prog", "w_dir"};
will_return(__wrap_chdir, 0);
will_return(__wrap_directory_exists, 1);
prepare_start(argc, argv);
assert_int_equal(_exit_code, 0);
}
void test__prepare_start__success_mkdir(void **state) {
int argc = 2;
char *argv[] = {"test_prog", "w_dir"};
will_return(__wrap_chdir, 0);
will_return(__wrap_directory_exists, 0);
will_return(__wrap_mkdir, 1);
prepare_start(argc, argv);
assert_int_equal(_exit_code, 0);
}
void test__prepare_start__err_no_arg(void **state) {
int argc = 1;
char *argv[] = {"test_prog"};
const char *fmt_args[] = {"Usage: %s <work_dir>\n", argv[0] , NULL};
print_str_arr = fmt_args;
will_return(__wrap_chdir, 0);
will_return(__wrap_directory_exists, 0);
will_return(__wrap_mkdir, 1);
prepare_start(argc, argv);
assert_int_equal(_exit_code, 1);
}
void test__prepare_start__err_chdir(void **state) {
int argc = 2;
char *argv[] = {"test_prog", "w_dir"};
const char *fmt_args[] = {"chdir: \"%s\" %s\n", argv[1], NULL};
print_str_arr = fmt_args;
will_return(__wrap_chdir, -1);
will_return(__wrap_directory_exists, 0);
will_return(__wrap_mkdir, 1);
prepare_start(argc, argv);
assert_int_equal(_exit_code, 2);
}
void test__prepare_start__err_mkdir(void **state) {
int argc = 2;
char *argv[] = {"test_prog", "w_dir"};
const char *fmt_args[] = {"chdir: \"%s\" %s\n", argv[1], NULL};
print_str_arr = fmt_args;
will_return(__wrap_chdir, -1);
will_return(__wrap_directory_exists, 0);
will_return(__wrap_mkdir, -1);
prepare_start(argc, argv);
assert_int_equal(_exit_code, 8);
}
int setup(void **state) {
print_str_arr = NULL;
return 0;
}
int tear_down(void **state) { return 0; }
int main(int argc, char **argv) {
const struct CMUnitTest tests[] = {
cmocka_unit_test(test__prepare_start__success),
cmocka_unit_test(test__prepare_start__success_mkdir),
cmocka_unit_test(test__prepare_start__err_no_arg),
cmocka_unit_test(test__prepare_start__err_chdir),
cmocka_unit_test(test__prepare_start__err_mkdir),
};
return cmocka_run_group_tests(tests, setup, tear_down);
}
+122
View File
@@ -0,0 +1,122 @@
#include <cmocka.h>
#include <db/db.h>
#include <errno.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <sys/socket.h>
#include <client.h>
#include <file_p.h>
#include <main.h>
#include <server.h>
int _errno = 0;
int _exit_code = 0;
extern void *print_str_arr;
int __wrap_socket(int __domain, int __type, int __protocol) {
errno = _errno;
return mock_type(int);
}
int __wrap_setsockopt(int __fd, int __level, int __optname,
const void *__optval, socklen_t __optlen) {
errno = _errno;
return mock_type(int);
}
int __wrap_bind(int __fd, __CONST_SOCKADDR_ARG __addr, socklen_t __len) {
errno = _errno;
return mock_type(int);
}
int __wrap_listen(int __fd, int __n) {
errno = _errno;
return mock_type(int);
}
void __wrap_exit(int __status) { _exit_code = __status; }
void test__start_server_success(void **state) {
will_return(__wrap_socket, 1);
will_return(__wrap_setsockopt, 0);
will_return(__wrap_bind, 0);
will_return(__wrap_listen, 0);
int ret = start_server();
assert_int_equal(ret, 1);
}
void test__start_server_err_socket(void **state) {
will_return(__wrap_socket, -1);
will_return(__wrap_setsockopt, 0);
will_return(__wrap_bind, 0);
will_return(__wrap_listen, 0);
_errno = EACCES;
const char *fmt_args[] = {"starting, socket: %s\n", strerror(_errno), NULL};
print_str_arr = fmt_args;
start_server();
assert_int_equal(_exit_code, 3);
}
void test__start_server_err_setsockopt(void **state) {
_errno = EBADF;
will_return(__wrap_socket, 1);
will_return(__wrap_setsockopt, -1);
will_return(__wrap_bind, 0);
will_return(__wrap_listen, 0);
const char *fmt_args[] = {"starting, setsockopt: %s\n", strerror(_errno),
NULL};
print_str_arr = fmt_args;
start_server();
assert_int_equal(_exit_code, 4);
}
void test__start_server_err_bind(void **state) {
_errno = EBADF;
will_return(__wrap_socket, 1);
will_return(__wrap_setsockopt,0);
will_return(__wrap_bind, -1);
will_return(__wrap_listen, 0);
const char *fmt_args[] = {"starting, socket bind: %s\n", strerror(_errno),
NULL};
print_str_arr = fmt_args;
start_server();
assert_int_equal(_exit_code, 5);
}
void test__start_server_err_listen(void **state) {
_errno = EBADF;
will_return(__wrap_socket, 1);
will_return(__wrap_setsockopt,0);
will_return(__wrap_bind, 0);
will_return(__wrap_listen, -1);
const char *fmt_args[] = {"starting, socket listen: %s\n", strerror(_errno),
NULL};
print_str_arr = fmt_args;
start_server();
assert_int_equal(_exit_code, 6);
}
int setup(void **state) {
print_str_arr = NULL;
return 0;
}
int tear_down(void **state) { return 0; }
int main(int argc, char **argv) {
const struct CMUnitTest tests[] = {
cmocka_unit_test(test__start_server_success),
cmocka_unit_test(test__start_server_err_socket),
cmocka_unit_test(test__start_server_err_bind),
cmocka_unit_test(test__start_server_err_listen),
};
return cmocka_run_group_tests(tests, setup, tear_down);
}
-2
View File
@@ -1,8 +1,6 @@
#include <cmocka.h>
#include <setjmp.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <main.h>
-1
View File
@@ -1,5 +1,4 @@
#include <cmocka.h>
#include <setjmp.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
+1 -1
View File
@@ -1,4 +1,4 @@
#include "../../src/main.h"
#include <main.h>
#include "cmocka.h"
#include <stddef.h>
#include <stdint.h>