Code release

This commit is contained in:
2025-10-16 14:12:55 +03:00
parent 09414d96c9
commit fdb2c3ba4f
18 changed files with 1058 additions and 2 deletions
+16
View File
@@ -53,3 +53,19 @@ dkms.conf
# debug information files
*.dwo
# Valgrind debug log
WG_LOG
#Tags
tags
#Binaries
bin
build
#VS code
.vscode
#wdir contents
wdir
+30
View File
@@ -0,0 +1,30 @@
CFLAGS := -ggdb -Wall -pedantic
SRC_DIR := src
OBJ_DIR := src/obj
BIN_DIR := bin
SRCS := $(wildcard $(SRC_DIR)/*.c)
OBJS := $(SRCS:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o)
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c $(SRC_DIR)/%.h
$(CC) $(CFLAGS) -c $< -o $@
server: $(OBJS)
$(CC) $(CFLAGS) $^ -o $(BIN_DIR)/$@
ifneq (clean, $(MAKECMDGOALS))
-include deps.mk
endif
deps.mk: $(SRCS)
$(CC) -MM $^ > $(SRC_DIR)/$@
clean:
rm -f $(OBJ_DIR)/*.o $(BIN_DIR)/server
run:
$(BIN_DIR)/server wdir
valgrind:
valgrind --tool=memcheck ./server wdir
+9 -2
View File
@@ -1,2 +1,9 @@
# bbs-server
Bulletin Board System (server part)
# Bulletin Board System (Server Side)
This is my sandbox project. I made it test and develop my programming skills. Maybe one day it become a mature and production-ready project.
## Setup
1. Create necessary file structure by running `$ ./setup.sh`.
It will create all necessary file structure in order to run the program correctly and will create a test user `user` with password `1234` with all privileges. **Delete this user before running into production!** It will also create a test file inside the `wdir/storage/` directory.
2. Build the binary running `make` or `make server`
3. Run it by `make run`
+12
View File
@@ -0,0 +1,12 @@
# Development plans
## Features
- [ ] Database integration
- [ ] Registration
- [ ] Message to admin
- [ ] Advanced folder structure for the storage
- [ ] File encryption
- [ ] Connection encryption
- [ ] Multithreading
+7
View File
@@ -0,0 +1,7 @@
client.o: src/client.c src/client.h src/main.h src/file_p.h src/session.h
file_p.o: src/file_p.c src/file_p.h src/main.h src/session.h
main.o: src/main.c src/main.h src/file_p.h src/server.h
server.o: src/server.c src/main.h src/session.h src/user.h
session.o: src/session.c src/session.h src/main.h src/client.h \
src/file_p.h src/user.h
user.o: src/user.c src/main.h src/session.h
Executable
+19
View File
@@ -0,0 +1,19 @@
#!/bin/sh
mkdir wdir
mkdir wdir/storage
touch wdir/file_descriptions
touch wdir/welcome
touch wdir/userlist
echo "Welcome to the BBS Setup!" >> wdir/welcome
echo "user 1234 15" >> wdir/userlist
# Test file
touch wdir/storage/testfile.txt
printf 'testfile.txt\nuser\n1\nThis is a test file. You may not need it.\n:END:\n' >> wdir/file_descriptions
echo "Lorem ipsum dolor sit amet consectetur adipiscing elit. Quisque faucibus ex sapien vitae pellentesque sem placerat. In id cursus mi pretium tellus duis convallis. Tempus leo eu aenean sed diam urna tempor. Pulvinar vivamus fringilla lacus nec metus bibendum egestas. Iaculis massa nisl malesuada lacinia integer nunc posuere. \
Ut hendrerit semper vel class aptent taciti sociosqu. Ad litora torquent per \
conubia nostra inceptos himenaeos." >> wdir/storage/testfile.txt
+47
View File
@@ -0,0 +1,47 @@
#include "client.h"
#include "file_p.h"
#include "main.h"
#include "session.h"
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
// TODO: синхронизовать c C++
void process_client_command(char *line, session *sess, server_data_t *s_d) {
char arg_1[32];
char arg_2[32];
int res;
sscanf(line, "%s %s", arg_1, arg_2);
if (!strcmp(arg_1, "file")) {
/* LIST */
if (!strcmp(arg_2, "list")) {
file_list(sess, s_d);
return;
}
/* UPLOAD */
if (!strcmp(arg_2, "upload")) {
res = file_receive_prepare(sess, line, s_d);
if (!res)
sess->state = OP_UPLOAD;
return;
}
/* DOWNLOAD */
if (!strcmp(arg_2, "download")) {
res = file_send_prepare(sess, line, s_d);
if (!res)
sess->state = OP_DOWNLOAD;
return;
}
}
if (!strncmp(line, "exit", sizeof "exit")) {
sess->state = ERR;
sess->reason = EXIT;
session_send_string(sess, "OK. Bye!\n");
}
}
+7
View File
@@ -0,0 +1,7 @@
#ifndef CLIENT_H
#define CLIENT_H
#include "main.h"
void process_client_command(char *line, session *sess, server_data_t *s_d);
#endif
+305
View File
@@ -0,0 +1,305 @@
#include "file_p.h"
#include "main.h"
#include "session.h"
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/statvfs.h>
#include <sys/syslog.h>
#include <sys/types.h>
#include <sys/un.h>
#include <unistd.h>
char *extract_second_arg(char *);
size_t get_file_size(char *, char *);
void file_list(session *sess, server_data_t *s_d) {
// TODO: change of format (rewrite in C++)
char list_end[] = "list_end\n";
fl_t *current;
current = s_d->fl_start;
char item_h[256];
do {
int n_len = strlen(sess->uname);
if (strncmp(current->owner, sess->uname, n_len) && !current->permissions) {
continue;
}
int h_len = sprintf(item_h, "%s %zu %s", current->name, current->size,
current->owner);
int d_len = strlen(current->description);
int f_len = h_len + d_len + 2;
char *full_str = malloc(sizeof(char) * f_len);
sprintf(full_str, "%s %s", item_h, current->description);
int i;
for (i = h_len; i < h_len + d_len; i++) {
if (full_str[i] == '\n') {
full_str[i] = '\a';
}
}
write(sess->sd, full_str, f_len-1); // -1 : do not include \0
free(full_str);
} while ((current = current->next) != NULL);
write(sess->sd, list_end, sizeof(list_end));
}
int file_send_prepare(session *sess, char *line, server_data_t *s_d) {
// TODO: рефактор в C++
int sd = sess->sd;
char fname[32];
sscanf(line, "%*s %*s %s", fname);
char filepath[256];
sprintf(filepath, "%s/%s", STORAGE_FOLDER, fname);
size_t fsize;
char st_message[256];
int file_d = open(filepath, O_RDONLY);
if (file_d == -1) {
fprintf(stdout, "ERROR: %d\n", errno);
char err_mes[256];
int mlen;
mlen = sprintf(err_mes, "Can't open file named \"%s\"\n", fname);
write(sd, err_mes, mlen);
return -1;
}
fsize = lseek(file_d, 0, SEEK_END);
lseek(file_d, 0, SEEK_SET);
sess->fd = file_d;
sess->fsize = fsize;
sess->f_rest = fsize;
sess->fname = malloc(strlen(fname));
int fname_len = strlen(fname) - 1;
strncpy(sess->fname, fname, fname_len);
sess->fname[fname_len] = 0;
return 0;
}
int file_receive_prepare(session *sess, char *line, server_data_t *s_d) {
int sd = sess->sd;
char fname[64];
size_t fsize;
int perm;
sscanf(line, "file upload \"%s %zd %d", fname, &fsize, &perm);
sess->fname = malloc(sizeof(char) * strlen(fname));
sess->f_perm = (char)perm;
strncpy(sess->fname, fname, strlen(fname) - 1); // remove the last \"
sess->fpath = malloc(strlen(sess->fname) + sizeof(STORAGE_FOLDER) + 2);
sprintf(sess->fpath, "%s/%s", STORAGE_FOLDER, sess->fname);
char mes[256];
char mes_len = 0;
struct statvfs st_str;
statvfs(".", &st_str);
size_t available_space = st_str.f_bavail * st_str.f_bsize;
if (strlen(sess->fname) > st_str.f_namemax) {
mes_len = sprintf(mes, "file name is tool long\n");
write(sd, mes, mes_len);
sess->state = OP_WAIT;
clear_file_from_sess(sess);
return -1;
}
if (fsize > available_space) {
mes_len = sprintf(mes, "There is no space for such length! (%ld)\n", fsize);
write(sd, mes, mes_len);
clear_file_from_sess(sess);
return -1;
}
int file_d = open(sess->fpath, O_WRONLY | O_CREAT | O_EXCL, 0666);
if (file_d == -1) {
if (errno == EEXIST) {
mes_len =
sprintf(mes, "File with name \"%s\" is already exist\n", sess->fname);
write(sd, mes, mes_len);
}
mes_len =
sprintf(mes, "Can't create file with such name: \"%s\"\n", sess->fname);
write(sd, mes, mes_len);
clear_file_from_sess(sess);
return -1;
}
mes_len = sprintf(mes, "accept");
sess->fd = file_d;
sess->fsize = fsize;
sess->f_rest = fsize;
write(sd, mes, mes_len);
return 0;
}
void clear_file_from_sess(session *sess) {
if (sess->fname != NULL) {
free(sess->fname);
sess->fname = NULL;
}
if (sess->fpath != NULL) {
free(sess->fpath);
sess->fpath = NULL;
}
if (sess->fdesc != NULL) {
free(sess->fdesc);
sess->fdesc = NULL;
}
if (sess->fd > -1) {
close(sess->fd);
}
sess->fd = -1;
sess->fsize = 0;
sess->f_rest = 0;
}
void file_download_upload(session *sess, enum f_actions f_action) {
int source_d = f_action == F_DOWNLOAD ? sess->fd : sess->sd;
int dest_d = f_action == F_DOWNLOAD ? sess->sd : sess->fd;
char buf[INBUFSIZE];
int rlen = read(source_d, buf, INBUFSIZE);
if (rlen == 0) {
if (sess->f_rest) {
if (f_action == F_DOWNLOAD) {
fprintf(stderr, "Error downloading file %s!\n", sess->fname);
} else {
fprintf(stderr, "Error uploading file %s!\n", sess->fname);
unlink(sess->fpath); /* remove file */
}
clear_file_from_sess(sess);
}
sess->state = OP_WAIT;
return;
}
write(dest_d, buf, rlen);
sess->f_rest -= rlen;
if (!sess->f_rest) {
if (f_action == F_DOWNLOAD) {
printf("File %s is downloaded from the server\n", sess->fname);
clear_file_from_sess(sess);
} else {
printf("File %s is uploaded to the server\n", sess->fname);
}
if (f_action == F_UPLOAD) {
sess->state = OP_UPLOAD_DESCRIPTION;
} else {
sess->state = OP_WAIT;
}
}
}
size_t get_file_size(char *dir_n, char *file_n) {
char filepath[256];
int dn_len;
size_t fsize;
strcpy(filepath, dir_n);
dn_len = strlen(filepath);
strcat(filepath + dn_len, file_n);
int file_d = open(filepath, O_RDONLY);
if (file_d == -1)
return 0;
fsize = lseek(file_d, 0, SEEK_END);
lseek(file_d, 0, SEEK_SET);
close(file_d);
return fsize;
}
/* returns 1 if there is :END: ; 0 if opposite */
int file_upload_description(session *sess, char *line, server_data_t *s_d) {
for (;;) {
if (line != NULL && sess->fdesc == NULL) { /* first query */
sess->fdesc = malloc(strlen(line) + 1);
strcpy(sess->fdesc, line);
} else { /* subsequent queries */
if (line == NULL) {
if (sess->buf_used > 0) {
query_extract_from_buf(sess, &line);
} else {
return 0;
}
}
sess->fdesc =
realloc(sess->fdesc, strlen(sess->fdesc) + strlen(line) + 1);
strcat(sess->fdesc, line);
}
char *desc_end = strstr(line, ":END:");
if (desc_end != NULL) {
return 1;
}
}
}
// TODO: синхронизовать c C++
void get_files_descriptions(server_data_t *s_d) {
int fd = open(FILE_DESCRIPTIONS_NAME, O_RDONLY);
if (-1 == fd) {
perror(FILE_DESCRIPTIONS_NAME);
exit(8);
}
int rlen;
char buf[INBUFSIZE] = "";
chdir(STORAGE_FOLDER);
while ((rlen = read(fd, buf, FILEBUFSIZE)) > 0) {
char *buf_pos = buf;
char tmp[256];
while (buf_pos[0] != '\0') {
fl_t *fl_item = malloc(sizeof(fl_t));
fl_item->next = NULL;
/* file name */
sscanf(buf_pos, "%s\n", tmp);
buf_pos += strlen(tmp)+1;
fl_item->name = malloc(sizeof(char) * (strlen(tmp) + 1));
strcpy(fl_item->name,tmp);
/* file owner */
sscanf(buf_pos, "%s\n", tmp);
buf_pos += strlen(tmp)+1;
fl_item->owner = malloc(sizeof(char) * (strlen(tmp) + 1));
strcpy(fl_item->owner, tmp);
/* file permissions */
sscanf(buf_pos, "%s\n", tmp);
buf_pos += strlen(tmp)+1;
fl_item->permissions = atoi(tmp);
/* file size */
int fd = open(fl_item->name, O_RDONLY);
if (-1 == fd) {
perror(fl_item->name);
free(fl_item->name);
free(fl_item->owner);
free(fl_item);
buf_pos += strstr(buf_pos, ":END:") + 6 - buf_pos;
continue;
}
fl_item->size = lseek(fd, 0, SEEK_END);
close(fd);
/* file description */
int d_len = strstr(buf_pos, ":END:\n") - buf_pos;
fl_item->description = malloc(d_len + 1);
strncpy(fl_item->description, buf_pos, d_len);
fl_item->description[d_len] = 0;
buf_pos += d_len + 6;
if (s_d->fl_start == NULL) {
s_d->fl_start = fl_item;
s_d->fl_current = fl_item;
} else {
s_d->fl_current->next = fl_item;
s_d->fl_current = fl_item;
}
}
}
close(fd);
chdir("..");
}
+16
View File
@@ -0,0 +1,16 @@
#ifndef FILEP_H
#define FILEP_H
#include "main.h"
void get_files_descriptions(server_data_t *);
void file_list(session *, server_data_t *);
int file_send_prepare(session *, char *, server_data_t *);
enum f_actions {
F_UPLOAD,
F_DOWNLOAD,
};
void file_download_upload(session *sess, enum f_actions);
int file_receive_prepare(session *sess, char *line, server_data_t *s_d);
int file_upload_description(session *sess, char *line, server_data_t *s_d);
int file_save_db(session *sess, server_data_t *s_d);
void clear_file_from_sess(session *sess);
#endif
+16
View File
@@ -0,0 +1,16 @@
#include "main.h"
#include "file_p.h"
#include "server.h"
/* *** MAIN *** */
int main(int argc, char *argv[]) {
server_data_t server_data;
prepare_start(argc, argv);
server_data.welcome_message = get_welcome_mes();
server_data.fl_start = NULL;
server_data.fl_current = NULL;
get_files_descriptions(&server_data);
server_data.ls = start_server();
server_main_loop(&server_data);
return 0;
}
+77
View File
@@ -0,0 +1,77 @@
#ifndef MAIN_H
#define MAIN_H
#include <stddef.h>
#define PORT 2000
#define MAX_CONNECTIONS 1024
#define INBUFSIZE 1024
#define FILEBUFSIZE 4096
#define WSIZE 128
#define LISTEN_QLEN 32
#define STORAGE_FOLDER "./storage"
#define FILE_DESCRIPTIONS_NAME "./file_descriptions"
#define FILE_USER_LIST_NAME "userlist"
#define WELCOME_FILE_NAME "welcome"
enum sess_states {
OP_EDIT_FILE,
OP_DOWNLOAD,
OP_EDIT_USER,
OP_LOGIN_USR,
OP_LOGIN_PSS,
OP_WAIT,
OP_UPLOAD,
OP_UPLOAD_DESCRIPTION,
ERR,
FIN
};
enum user_privileges {
ADD_FILE = 01,
EDIT_FILES = 02,
REMOVE_FILES = 04,
EDIT_USER = 010
};
enum error_reason {
NO_REASON,
LOGIN,
EXIT,
};
typedef struct session {
unsigned long from_ip;
unsigned short from_port;
char buf[INBUFSIZE];
int buf_used;
enum sess_states state;
enum error_reason reason;
char privileges;
char *uname;
int sd; /* session descriptor */
int fd; /* file descriptor */
char *fname;
char *fpath;
char f_perm;
char *fdesc;
size_t fsize;
size_t f_rest;
long int userpos; /* hint to the position in user list */
} session;
typedef struct fl_t {
char *name;
char *description;
char *owner;
char permissions;
size_t size;
struct fl_t *next;
} fl_t;
typedef struct server_data_t {
fl_t *fl_start;
fl_t *fl_current;
char *welcome_message;
int ls;
} server_data_t;
#endif
+143
View File
@@ -0,0 +1,143 @@
#include "main.h"
#include "session.h"
#include "user.h"
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/select.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>
void server_main_loop(server_data_t *s_d) {
fd_set readfds;
int i, sr;
session *connections[MAX_CONNECTIONS];
for (i = 0; i < MAX_CONNECTIONS; i++) {
connections[i] = NULL;
}
int maxfd, res;
for (;;) {
FD_ZERO(&readfds);
FD_SET(s_d->ls, &readfds);
maxfd = s_d->ls;
for (i = 0; i < MAX_CONNECTIONS; i++) {
if (connections[i] != NULL) {
FD_SET(i, &readfds);
if (i > maxfd)
maxfd = i;
/* active uploads/downloads */
int fd = connections[i]->fd;
if (fd > -1) {
FD_SET(fd, &readfds);
if (fd > maxfd)
maxfd = fd;
}
}
}
sr = select(maxfd + 1, &readfds, NULL, NULL, NULL);
if (sr == -1) {
perror("select");
exit(6);
}
if (FD_ISSET(s_d->ls, &readfds)) {
if (-1 == accept_client(s_d->ls, connections, s_d->welcome_message)) {
fprintf(stderr, "Can't accept connection, error: %d\n", errno);
}
}
for (i = 0; i < MAX_CONNECTIONS; i++) {
/* download/upload file */
if (connections[i] != NULL && (connections[i]->state == OP_UPLOAD ||
connections[i]->state == OP_DOWNLOAD)) {
if (connections[i] != NULL && connections[i]->fd > -1 &&
FD_ISSET(connections[i]->fd, &readfds)) {
perform_session_action(connections[i], NULL, s_d);
}
} else if (connections[i] != NULL && FD_ISSET(i, &readfds)) {
/* server/client requests */
session *sess = connections[i];
char *line;
res = session_do_read(sess, &line);
if (line != NULL && res) {
perform_session_action(sess, line, s_d);
free(line);
if (process_error(sess)) {
close_session(connections, i);
}
}
if (res == 0) {
close_session(connections, i);
}
}
}
}
}
char *get_welcome_mes() {
int fd = open(WELCOME_FILE_NAME, O_RDONLY);
if (fd == -1) {
perror(WELCOME_FILE_NAME);
exit(7);
}
int filesize = lseek(fd, 0, SEEK_END);
lseek(fd, 0, SEEK_SET);
char *welcome_message =
mmap(NULL, filesize, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
if (welcome_message == MAP_FAILED) {
perror(WELCOME_FILE_NAME);
close(fd);
exit(5);
}
close(fd);
return welcome_message;
}
int start_server() {
int res;
int ls = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in s_addr;
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 = bind(ls, (struct sockaddr *)&s_addr, sizeof(s_addr));
if (res == -1) {
perror("bind");
exit(3);
}
res = listen(ls, LISTEN_QLEN);
if (res == -1) {
perror("listen");
exit(4);
}
return ls;
}
void prepare_start(int argc, char *argv[]) {
if (argc != 2) {
fprintf(stderr, "Usage: %s <work_dir>\n", argv[0]);
exit(1);
}
if (-1 == chdir(argv[1])) {
perror(argv[1]);
exit(2);
}
}
+8
View File
@@ -0,0 +1,8 @@
#ifndef SERVER_H
#define SERVER_H
#include "main.h"
int start_server();
char *get_welcome_mes();
void server_main_loop(server_data_t *);
void prepare_start(int argc, char *argv[]);
#endif
+237
View File
@@ -0,0 +1,237 @@
#include "session.h"
#include "client.h"
#include "file_p.h"
#include "main.h"
#include "user.h"
#include <arpa/inet.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
session *make_new_session(int fd, struct sockaddr_in *from, char *wm);
int accept_client(int ls, session *connections[], char *wm) {
int sd;
struct sockaddr_in addr;
socklen_t len = sizeof(addr);
sd = accept(ls, (struct sockaddr *)&addr, &len);
if (sd == -1) {
perror("accept");
return -1;
}
session *sess = make_new_session(sd, &addr, wm);
fprintf(stdout, "New connection: %s:%u\n", inet_ntoa(addr.sin_addr),
ntohs(addr.sin_port));
connections[sd] = sess;
return 0;
}
session *make_new_session(int fd, struct sockaddr_in *from, char *wm) {
struct session *sess = malloc(sizeof(*sess));
sess->from_ip = ntohl(from->sin_addr.s_addr);
sess->from_port = ntohs(from->sin_port);
sess->buf_used = 0;
sess->state = OP_LOGIN_USR;
sess->reason = NO_REASON;
sess->uname = NULL;
sess->f_perm = 0;
sess->fdesc = NULL;
sess->sd = fd;
sess->fd = -1;
sess->fsize = 0;
sess->f_rest = 0;
sess->fname = NULL;
sess->fpath = NULL;
session_send_string(sess, wm);
session_send_string(sess, "login> ");
return sess;
}
void session_send_string(struct session *sess, const char *str) {
write(sess->sd, str, strlen(str));
}
int session_do_read(session *sess, char **read_str) {
int rc, bufp = sess->buf_used;
rc = read(sess->sd, sess->buf + bufp, INBUFSIZE - bufp);
sess->buf[bufp + rc] = 0;
if (rc <= 0) {
sess->state = ERR;
return 0;
}
sess->buf_used += rc;
char *line;
query_extract_from_buf(sess, &line);
if (line == NULL) {
*read_str = line;
return 0;
} else {
*read_str = line;
}
if (sess->buf_used >= INBUFSIZE) {
/* we can't read further, no room in the buffer, no whole line yet */
session_send_string(sess, "Line too long! Good bye...\n");
sess->state = ERR;
return 0;
}
if (sess->state == FIN)
return 0;
return 1;
}
// TODO: синхронизовать c C++
int query_extract_from_buf(session *sess, char **output_line) {
char *line;
int pos = -1;
if (sess->buf_used > 0) {
char *cptr = strchr(sess->buf, '\n');
if (cptr != NULL)
pos = cptr - sess->buf;
} else {
return 0;
}
if (pos == -1) {
int b_used = sess->buf_used;
sess->buf_used = 0;
line = malloc(b_used + 1);
strncpy(line, sess->buf, b_used);
line[b_used] = 0;
*output_line = line;
return b_used;
} else {
line = malloc(pos + 2);
strncpy(line, sess->buf, pos + 1);
line[++pos] = 0;
sess->buf_used -= (pos);
if (!pos)
pos++;
memmove(sess->buf, sess->buf + pos, sess->buf_used);
sess->buf[sess->buf_used] = 0;
if (line[pos-2] == '\r') {
line[pos-2] = line[pos-1];
pos--;
line[pos-1] = 0;
}
*output_line = line;
}
return pos + 1;
}
void perform_session_action(session *sess, char *line, server_data_t *s_d) {
int state = sess->state;
char tmp_buf[256];
int priv;
int tmp_buf_pos;
int res;
/* while (sess->buf_used) { */
switch (state) {
case OP_LOGIN_USR:
res = find_user(line);
if (res == -2) {
sess->state = ERR;
sess->reason = EXIT;
session_send_string(sess, "Bye!");
break;
}
sess->userpos = res;
sess->state = OP_LOGIN_PSS;
session_send_string(sess, "password> ");
break;
case OP_LOGIN_PSS:
if (sess->userpos == -1) {
sess->state = ERR;
sess->reason = LOGIN;
} else {
if (login(sess, line)) {
sess->state = OP_WAIT;
sprintf(tmp_buf, "Welcome, %s\n", sess->uname);
session_send_string(sess, tmp_buf);
} else {
sess->state = ERR;
sess->reason = LOGIN;
}
}
break;
case OP_WAIT:
process_client_command(line, sess, s_d);
break;
case OP_DOWNLOAD:
file_download_upload(sess, F_DOWNLOAD);
break;
case OP_UPLOAD:
file_download_upload(sess, F_UPLOAD);
break;
case OP_UPLOAD_DESCRIPTION:
res = file_upload_description(sess, line, s_d);
if (res) {
file_save_db(sess, s_d);
session_send_string(sess, "File is saved!\n");
sess->state = OP_WAIT;
}
break;
}
/* } */
}
int file_save_db(session *sess, server_data_t *s_d) {
/* crate and fill the new item */
fl_t *nitem = malloc(sizeof(fl_t));
nitem->description = sess->fdesc;
nitem->name = sess->fname;
nitem->size = sess->fsize;
nitem->owner = malloc(strlen(sess->uname));
strcpy(nitem->owner, sess->uname);
nitem->permissions = sess->f_perm;
nitem->next = NULL;
/* set to NULL and clear */
sess->fname = NULL;
free(sess->fpath);
sess->fpath = NULL;
sess->fdesc = NULL;
if (sess->fd > -1) {
close(sess->fd);
}
sess->fd = -1;
sess->fsize = 0;
sess->f_rest = 0;
/* add new item to list */
s_d->fl_current->next = nitem;
s_d->fl_current = nitem;
/* save to the db file */
int fd = open(FILE_DESCRIPTIONS_NAME, O_WRONLY);
lseek(fd, 0, SEEK_END);
char permissions[4];
snprintf(permissions, 3, "%d", nitem->permissions);
unsigned int res_len = strlen(nitem->name) + 1 + strlen(nitem->owner) + 1 +
strlen(permissions) + 1 + strlen(nitem->description) +
1;
char *res_str = malloc(res_len);
res_len = sprintf(res_str, "%s\n%s\n%s\n%s", nitem->name, nitem->owner,
permissions, nitem->description);
nitem->description[strlen(nitem->description) - 6] = 0;
write(fd, res_str, res_len);
close(fd);
return 0;
}
void close_session(session *connections[], int sd) {
if (connections[sd] != NULL) {
close(sd);
connections[sd]->sd = -1;
free(connections[sd]->uname);
free(connections[sd]);
connections[sd] = NULL;
}
}
+12
View File
@@ -0,0 +1,12 @@
#ifndef SESSION_H
#define SESSION_H
#include "main.h"
int accept_client(int ls, session *connections[], char *wm);
void session_send_string(struct session *sess, const char *str);
int query_extract_from_buf(session *sess, char **output_line);
int session_do_read(session *sess, char **read_str);
void perform_session_action(session *sess, char *line, server_data_t *s_d);
void close_session(session *connections[], int sd);
/* session *make_new_session(int fd, struct sockaddr_in *from, char *wm); */
/* int query_extract_from_sess(session *sess, char **output_line); */
#endif
+89
View File
@@ -0,0 +1,89 @@
#include "main.h"
#include "session.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
long int find_user(char *uname) {
FILE *fptr = fopen(FILE_USER_LIST_NAME, "r");
if (fptr == NULL) {
perror(FILE_USER_LIST_NAME);
exit(9);
}
char *line = NULL;
size_t bsize = WSIZE;
char b_uname[32];
long int cur_pos = 0;
int lsize = 0;
if (!strncmp(uname, "exit", sizeof "exit")) {
return -2;
}
while (getline(&line, &bsize, fptr)) {
if (line[0] == '\b')
break;
sscanf(line, "%s", b_uname);
if (!strcmp(uname, b_uname)) {
line = NULL;
fclose(fptr);
return cur_pos;
} else {
cur_pos += lsize;
line = NULL;
}
}
fclose(fptr);
return -1;
}
/* returns 1 if success */
int login(session *sess, char *pass) {
FILE *fptr = fopen(FILE_USER_LIST_NAME, "r");
fseek(fptr, sess->userpos, SEEK_SET);
int res = 0;
char *line = NULL;
size_t lsize = WSIZE;
char *pass_tok, *name_tok, *priv_tok;
getline(&line, &lsize, fptr);
name_tok = strtok(line, " ");
pass_tok = strtok(NULL, " ");
if (!strcmp(pass_tok, pass)) {
int n_len = pass_tok - name_tok - 1; /* exclude space */
sess->uname = malloc(n_len + 1);
strncpy(sess->uname, name_tok, n_len);
sess->uname[n_len] = 0;
priv_tok = strtok(NULL, " ");
sess->privileges = (char)atoi(priv_tok);
res = 1;
}
fclose(fptr);
return res;
}
// TODO: синхронизовать c C++
/* returns 1 if session needs to be closed, 0 - in the opposite case */
int process_error(session *sess) {
if (sess->state == ERR) {
switch (sess->reason) {
case NO_REASON:
case EXIT:
return 1;
break;
case LOGIN:
session_send_string(sess, "Can't find the user with such credentials\n");
sess->state = OP_LOGIN_USR;
sess->reason = NO_REASON;
session_send_string(sess, "login_again> ");
break;
}
}
return 0;
}
+8
View File
@@ -0,0 +1,8 @@
#ifndef USER_H
#define USER_H
#include "main.h"
int login(session *sess, char *pass);
int process_error(session *sess);
long int find_user(char *uname);
#endif