#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#define PORT 9000
#define HOST "127.0.0.1"
#define BUF_SIZE 2048
int sock;
/* Signal Handler for SIGINT */
void sigintHandler(int sig_num) {
errno = 0;
if (fcntl(sock, F_GETFD) != -1 || errno != EBADF) {
write(sock, "exit\n", 6);
close(sock);
}
printf("Terminating client\n");
fflush(stdout);
exit(-1);
}
static inline void die(const char *msg) {
perror(msg);
exit(-1);
}
int write_all(int sock, char *buffer, int size) {
int nwrite, sent = 0;
while (sent < size) {
if ((nwrite = write(sock, buffer + sent, size - sent)) < 0) {
perror("Write");
exit(1);
}
sent += nwrite;
}
return sent;
}
void send_file(int server_fd, char *path) {
char buffer[512];
int file_fd;
if ((file_fd = open(path, O_RDONLY)) == -1) { perror("Open"); }
FILE *file = fdopen(file_fd, "r");
fseek(file, 0L, SEEK_END);
long int sz = ftell(file);
fseek(file, 0L, SEEK_SET);
int length = snprintf(NULL, 0, "%ld", sz);
char msg[length + 1 + 3];
sprintf(msg, "<<!%ld", sz);
write(server_fd, msg, strlen(msg));
int size;
while (read(file_fd, buffer, sizeof(buffer)) != 0) {
size = strlen(buffer) + 1;
if (write(server_fd, &size, sizeof(size)) < 0) {
perror("Write");
exit(1);
}
printf("Sent %i bytes\n", write_all(server_fd, buffer, strlen(buffer) + 1));
}
fclose(file);
close(file_fd);
}
#define BREAK 1
#define CONTINUE 2
int parse(int server_sock, 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 {
printf("got put with %s\n", path);
send_file(sock, 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");
if (strcmp(buffer, "exit\n") == 0) {
return BREAK;
}
return 0;
}
void read_stdin(int *done);
void read_server_sock(int *done);
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 ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
die("Could not open socket");
if (connect(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0)
die("Could not connect to socket");
signal(SIGINT, &sigintHandler);
pid_t pid = fork();
int done = 0;
if (pid == 0) {
read_stdin(&done);
} else {
read_server_sock(&done);
}
close(sock);
return 0;
}
void read_server_sock(int *done) {
char server_buffer[BUF_SIZE];
ssize_t length;
while (!*done) {
if ((length = read(sock, server_buffer, BUF_SIZE)) > 0) {
server_buffer[length] = '\0';
printf("%s", server_buffer);
if (server_buffer[length - 1] == '\n') {
printf("$> ");
fflush(stdout);
}
}
}
}
void read_stdin(int *done) {
char stdinp_buffer[BUF_SIZE];
ssize_t length;
while (!*done) {
if ((length = read(STDIN_FILENO, stdinp_buffer, BUF_SIZE)) > 0) {
switch (parse(sock, stdinp_buffer, length)) {
case CONTINUE:
continue;
case BREAK:
*done = 1;
break;
default:
break;
}
}
}
}