#include #include #include #include #include #include #include #include #include #include #include #define PORT 9000 #define HOST "127.0.0.1" #define BUF_SIZE 2048 #define BREAK 1 #define CONTINUE 2 char *get_current_dir_name(void); int server_sock; pid_t pid; /* Signal Handler for SIGINT */ void sigintHandler(int sig_num); static inline void die(char const *msg); int write_all(int target_sock, char *buffer, size_t size); void send_file(char *path); int parse(char *buffer, ssize_t length); void read_stdin(); _Noreturn void read_server_sock(); int main() { setvbuf(stdout, NULL, _IONBF, 0); struct sockaddr_in addr = { .sin_family = AF_INET, .sin_port = htons(PORT), .sin_addr.s_addr = inet_addr(HOST) }; if ((server_sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) die("Could not open socket"); if (connect(server_sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) die("Could not connect to socket"); signal(SIGINT, &sigintHandler); pid = fork(); if (pid == 0) { read_stdin(); } else { read_server_sock(); } close(server_sock); kill(pid, SIGKILL); return 0; } void receive_file(int recv_sock, char *path, int size) { char buffer[BUF_SIZE]; int file_fd; int received; if ((file_fd = open(path, (O_WRONLY | O_CREAT | O_TRUNC), 0644)) == -1) { perror("Open"); } if (size == 0) { // just touch close(file_fd); return; } received = 0; /* Read all data */ while (received < size) { int nread; if ((nread = read(recv_sock, buffer, BUF_SIZE)) > 0) { if (write_all(file_fd, buffer, nread) != nread) { break; } received += nread; } } if (received == size) { printf("successfully got remote file \"%s/%s\"", get_current_dir_name(), path); printf("\n"); } else { printf("error getting remote file \"%s/%s\"", get_current_dir_name(), path); printf("\n"); } close(file_fd); } bool check_get(char *buffer) { // "< 0) { server_buffer[length] = '\0'; // get issued, as it seems if (check_get(server_buffer)) { printf("$> "); fflush(stdout); continue; } printf("%s", server_buffer); if (length == 1 && server_buffer[length - 1] == '\n') { printf("$> "); fflush(stdout); } } } } void read_stdin() { char stdin_buffer[BUF_SIZE]; bool done = false; while (!done) { ssize_t length; memset(stdin_buffer, 0, BUF_SIZE); if ((length = read(STDIN_FILENO, stdin_buffer, BUF_SIZE)) > 0) { switch (parse(stdin_buffer, length)) { case CONTINUE: continue; case BREAK: done = true; break; default: break; } } } } void sigintHandler(int sig_num) { (void) sig_num; errno = 0; if (fcntl(server_sock, F_GETFD) != -1 || errno != EBADF) { (void) write(server_sock, "exit\n", 6); close(server_sock); } errno = 0; die("Terminating client\n"); } static inline void die(char const *msg) { perror(msg); kill(pid, SIGKILL); exit(-1); } int write_all(int target_sock, char *buffer, size_t size) { int sent = 0; while (sent < size) { int nwrite; if ((nwrite = write(target_sock, buffer + sent, size - sent)) < 0) { die("Write"); } sent += nwrite; } return sent; } void send_file(char *path) { printf("Trying to send \"%s\" to remote...\n", path); char buffer[BUF_SIZE]; memset(buffer, 0, BUF_SIZE); int tmp_fd, file_fd; if ((tmp_fd = open(path, O_RDONLY)) == -1) { perror("Open"); return; } FILE *file = fdopen(tmp_fd, "r"); fseek(file, 0L, SEEK_END); long int sz = ftell(file); fseek(file, 0L, SEEK_SET); fclose(file); close(tmp_fd); if ((file_fd = open(path, O_RDONLY)) == -1) { perror("Open"); return; } int length = snprintf(NULL, 0, "%ld", sz); sprintf(buffer, "< 0) { printf("Sent %i bytes\n", write_all(server_sock, buffer, count)); } if (errno) perror("wad"); close(file_fd); printf("done.\n"); } int parse(char *buffer, ssize_t length) { char cmd[4]; char path[BUF_SIZE - 3]; memcpy(cmd, buffer, 3); cmd[3] = 0; memcpy(path, buffer + 4, BUF_SIZE - 4); path[strlen(path) - 1] = 0; if (strcmp(cmd, "put") == 0) { if (strlen(path) == 0) { fprintf(stderr, "path missing\n"); } else { send_file(path); } return CONTINUE; } buffer[length] = '\0'; if (strspn(buffer, " \n\t") == strlen(buffer)) { // skip empty lines - empty being just spaces or tabs return CONTINUE; } if (write(server_sock, buffer, strlen(buffer)) < 0) die("Could not send message"); // TODO: exit should only close the connection (cleanly), NOT terminate the server if (strcmp(buffer, "exit\n") == 0) { return BREAK; } return 0; }