commit ea661e714805f15ddaa333943aa96a92a9a90f17 Author: Your Name Date: Sat Jun 29 14:39:23 2024 +0300 first commit diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..7a3094a --- /dev/null +++ b/LICENSE @@ -0,0 +1,11 @@ +DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE +Version 2, December 2004 + +Copyright (C) 2004 Sam Hocevar + +Everyone is permitted to copy and distribute verbatim or modified copies of this license document, and changing it is allowed as long as the name is changed. + +DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. You just DO WHAT THE FUCK YOU WANT TO. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..fc9c737 --- /dev/null +++ b/Makefile @@ -0,0 +1,5 @@ +CFLAGS?=-pedantic -O0 -s -Wall +CC?=cc + +all: + $(CC) plainbin.c $(CFLAGS) -oplainbin diff --git a/README.md b/README.md new file mode 100644 index 0000000..a5c1598 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +Send: echo "Hello" | nc ip 8080 +Get: echo "[code]" | nc ip 8081 +Server info: echo "INFO" | nc ip 8081 diff --git a/plainbin.c b/plainbin.c new file mode 100644 index 0000000..68c156b --- /dev/null +++ b/plainbin.c @@ -0,0 +1,374 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SEND_TIMEOUT 1 +#define RECV_TIMEOUT 2 +#define BUFLEN 1024 * 1024 +#define MSG1 "Server very loaded.\n" +#define MSG2 "File very big.\n" +#define MSG3 "Closing connection.\n" +#define MSG4 "No such file.\n" + +int iport = 8080; +int oport = 8081; +size_t max_clients = 15; +size_t max_size = 500; +size_t name_len = 15; +char *dir = "."; + +char *prog_name; +int ifd; +int ifd_clients; + +int ofd; +int ofd_clients; + +enum { + OUTPUT, + INPUT +}; + +enum { + WRITE, + SEND +}; + +int new_server(const int port) { + int listen_fd = socket(AF_INET, SOCK_STREAM, 0); + if (listen_fd < 0) + return -1; + + struct timeval tout = {.tv_sec = RECV_TIMEOUT, .tv_usec = 0}; + if (setsockopt(listen_fd, SOL_SOCKET, SO_RCVTIMEO, &tout, sizeof(tout)) < 0) + goto NS_ERROR; + + tout.tv_sec = SEND_TIMEOUT; + if (setsockopt(listen_fd, SOL_SOCKET, SO_SNDTIMEO, &tout, sizeof(tout)) < 0) + goto NS_ERROR; + + int reuse = 1; + if (setsockopt(listen_fd, SOL_SOCKET, SO_REUSEPORT, &reuse, sizeof(reuse)) < 0) + goto NS_ERROR; + + struct sockaddr_in serv_addr; + serv_addr.sin_family = AF_INET; + serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); + serv_addr.sin_port = htons(port); + + if (bind(listen_fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) + goto NS_ERROR; + + if (listen(listen_fd, 0) < 0) + goto NS_ERROR; + + return listen_fd; + +NS_ERROR: + close(listen_fd); + return -1; +} + +char *rand_string(void) { + char abc[] = "asdfghjklzxcvbnmqwertyuiopQWERTYUIOPASDFGHJKLZXCVBNM1234567890"; + char *res = malloc(name_len + 1); + if (res == NULL) + return NULL; + + for (int i = 0; i < name_len; i++) + res[i] = abc[rand() % (sizeof(abc) - 1)]; + + res[name_len] = '\0'; + return res; +} + +char *rand_name(void) { + while (1) { + char *filename = rand_string(); + if (filename == NULL) + continue; + + struct stat sb; + if (stat(filename, &sb) < 0) + return filename; + + free(filename); + } +} + +int send_str(int fd, const char *str, ssize_t size, int flag) { + ssize_t n = 0; + ssize_t rbytes = size; + + while (rbytes) { + ssize_t ret = 0; + if (flag) + ret = send(fd, str + n, rbytes, 0); + + else + ret = write(fd, str + n, rbytes); + + if (ret < 0 && (errno != EAGAIN || errno != EINTR)) + return 1; + + else if (ret == 0) + return 0; + + rbytes -= ret; + n += size - rbytes; + } + + return 0; +} + +void upload(int cfd, pid_t par) { + int ret = -1; + int ffd = 0; + + char *filename = rand_name(); + if (send(cfd, filename, strlen(filename), 0) < 0) + goto UPL_ERROR; + + if (send(cfd, "\n", 1, 0) < 0) + goto UPL_ERROR; + + ffd = open(filename, O_CREAT | O_WRONLY, 0666); + if (ffd < 0) + goto UPL_ERROR; + + char buf[BUFLEN + 1]; + + ssize_t tbytes = 0; + while (1) { + ssize_t rbytes = recv(cfd, buf, sizeof(buf), 0); + if (rbytes < 0 && (errno != EAGAIN || errno != EINTR)) + goto UPL_ERROR; + + else if (rbytes == 0) + break; + + tbytes += rbytes; + if (tbytes / 1024 / 1024 >= max_size) { + send_str(cfd, MSG2, sizeof(MSG2), WRITE); + break; + } + + if (send_str(ffd, buf, rbytes, WRITE)) + goto UPL_ERROR; + } + + ret = 0; + +UPL_ERROR: + if (ffd > 0) + close(ffd); + + send_str(cfd, MSG3, sizeof(MSG3), WRITE); + close(cfd); + if (ret == -1) + fprintf(stderr, "%s: input thread: %s: %s\n", prog_name, filename, strerror(errno)); + + free(filename); + kill(par, SIGUSR1); + exit(0); +} + +void load(int cfd, pid_t par) { + int ret = -1; + int ffd = 0; + + /* Get filename */ + char *filename = malloc(name_len + 1); + if (filename == NULL) + goto LD_ERROR; + + ssize_t rbytes = recv(cfd, filename, name_len, 0); + if (rbytes <= 0) { + if (rbytes == 0) + ret = 0; + + goto LD_ERROR; + } + + filename[rbytes] = '\0'; + char *ptr = strchr(filename, '\n'); + if (ptr) + *ptr = '\0'; + + if (strstr(filename, ".") || strstr(filename, "/")) + goto LD_ERROR; + + /* INFO */ + if (!strcmp(filename, "INFO")) { + char msg[64]; + int ret2 = snprintf(msg, sizeof(msg), "Max file size: %zuMB\nMax clients in thread: %zu\n", max_size, max_clients); + + if (send_str(cfd, msg, (ssize_t)ret2, SEND)) + goto LD_ERROR; + + ret = 0; + goto LD_ERROR; + } + + /* Open and send */ + ffd = open(filename, O_RDONLY); + if (ffd < 0) { + send_str(cfd, MSG4, sizeof(MSG4), SEND); + goto LD_ERROR; + } + + char buf[BUFLEN + 1]; + while (1) { + rbytes = read(ffd, buf, sizeof(buf)); + if (rbytes < 0 && (errno != EAGAIN || errno != EINTR)) + goto LD_ERROR; + + else if (rbytes == 0) + break; + + if (send_str(cfd, buf, rbytes, SEND)) + goto LD_ERROR; + } + + ret = 0; + +LD_ERROR: + if (ffd > 0) + close(ffd); + + close(cfd); + if (ret == -1) + fprintf(stderr, "%s: output thread: %s: %s\n", prog_name, filename, strerror(errno)); + + free(filename); + kill(par, SIGUSR2); + exit(0); +} + +void sig_handler(int sig) { + if (sig == SIGUSR1) + ifd_clients--; + + else if (sig == SIGUSR2) + ofd_clients--; + + else { + close(ifd); + close(ofd); + + exit(0); + } +} + +void Proc(int fd, int flag) { + static struct sockaddr_in cli_addr; + socklen_t length = sizeof(cli_addr); + + pid_t par = getpid(); + + while (1) { + int cfd = accept(fd, (struct sockaddr *)&cli_addr, &length); + if (cfd < 0) + continue; + + if (flag == INPUT && ifd_clients < max_clients) { + ifd_clients++; + + if (fork() == 0) { + close(fd); + upload(cfd, par); + } + } + + else if (flag == OUTPUT && ofd_clients < max_clients) { + ofd_clients++; + + if (fork() == 0) { + close(fd); + load(cfd, par); + } + } + + else { + send(cfd, MSG1, sizeof(MSG1), 0); + close(cfd); + } + } +} + +int main(int argc, char **argv) { + srand(time(NULL)); + prog_name = argv[0]; + + signal(SIGUSR1, sig_handler); + signal(SIGUSR2, sig_handler); + signal(SIGINT, sig_handler); + signal(SIGTERM, sig_handler); + signal(SIGCHLD, SIG_IGN); + + int opt; + while ((opt = getopt(argc, argv, "i:o:m:d:s:n:")) != -1) { + switch (opt) { + case 'i': + iport = atoi(optarg); + break; + + case 'o': + oport = atoi(optarg); + break; + + case 'm': + sscanf(optarg, "%zu", &max_clients); + break; + + case 'd': + dir = optarg; + break; + + case 's': + sscanf(optarg, "%zu", &max_size); + break; + + case 'n': + sscanf(optarg, "%zu", &name_len); + break; + + default: + printf("%s [iomds] - Simple file sharing server\n\t-i NUM Input port\tdefault: %d\n\t-o NUM Output port\tdefault: %d\n\t-m NUM Max clients\tdefault: %zu\n\t-d DIR Word directory\tdefault: %s\n\t-s NUM Max file size\tdefault: %zuMB\n\t-n NUM Filename length\tdefault: %zu\n", prog_name, iport, oport, max_clients, dir, max_size, name_len); + return 0; + } + } + + if (chdir(dir) < 0) { + fprintf(stderr, "%s: chdir: %s\n", prog_name, strerror(errno)); + return 1; + } + + ifd = new_server(iport); + if (ifd == -1) { + fprintf(stderr, "%s: new_server: input socket: %s\n", prog_name, strerror(errno)); + return 1; + } + + ofd = new_server(oport); + if (ofd == -1) { + fprintf(stderr, "%s: new_server: output socket: %s\n", prog_name, strerror(errno)); + return 1; + } + + if (fork() == 0) + Proc(ofd, OUTPUT); + + else + Proc(ifd, INPUT); +} diff --git a/tmp/.gitignore b/tmp/.gitignore new file mode 100644 index 0000000..e69de29