summaryrefslogblamecommitdiffstats
path: root/03_exercise/cli/client.c
blob: c1bc5d149a996dc21687c29772115e1ea7932d54 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
                  
                   

                   
                   

                  


                       
                   
 


                        

                     
         



                                 


                                                       




                                   
 




                                         















































                                                                                    








































                                                             
            

                                     




                                              
 
                                                     

                                     
                                                                   

                                           
                                   
 
                       
 





                                
 


                
 










                                                                 
             
         

     
 
 














                                                                         
         
     
 
#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;
            }
        }
    }
}