Code release
This commit is contained in:
@@ -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");
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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("..");
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user