Client-Server-Assignment / client.c
client.c
Raw
#include <stdio.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <netdb.h>
#include <unistd.h>
#include <stdbool.h>

typedef struct {
    char* basename;
    char* name;
    int num;
    char* auth;
    FILE* from;
    FILE* to;
    bool named;
} Client;

//Listens on a given port, returns listening socket (or exits on failure)
int open_listen(const char* port){
    struct addrinfo* ai = 0;
    struct addrinfo hints;

    memset(&hints, 0, sizeof(struct addrinfo));
    hints.ai_family = AF_INET; //IPV4
    hints.ai_socktype = SOCK_STREAM;

    int err;
    if ((err = getaddrinfo(NULL, port, &hints, &ai))) {
        freeaddrinfo(ai);
        fprintf(stderr, "Communications error\n");
        exit(2);
    }

    int fd = socket(AF_INET, SOCK_STREAM, 0);
    if (connect(fd, (struct sockaddr*)ai->ai_addr, sizeof(struct sockaddr))) {
        fprintf(stderr, "Communications error\n");
        exit(2);
    }
    //fd is now connected, return fd
    return fd;
}

//Increments the number at the end of the clients name
//If the number is non existent yet it will add zero on
void increment_name(Client* client){
    //Increment the client number
    client->num++;

    //Convert the num into a string
    char strnum[10];
    sprintf(strnum, "%d", client->num);

    //Store new client name
    char clientName[100];
    strcpy(clientName, client->basename);

    //Add the number on the end
    strcat(clientName, strnum);

    //Store the new name
    client->name = malloc(strlen(clientName) + 1);
    strcpy(client->name, clientName);
}

//Takes input from the server, interprets it and sends the appropriate response
//to the server
void* server_thread(void* c){
    Client* client = (Client*) c;
    char buffer[1024];
    char command[30];
    char arg1[900];
    char arg2[900];
    bool namesent = false;
    while (fgets(buffer, 1024, client->from)) {
        sscanf(buffer, "%[^:]:%[^:]:%[^\n]", command, arg1, arg2);
        //Interpret the message from server
        if (!strcmp(command, "AUTH")) {
            fprintf(client->to, "AUTH:%s\n", client->auth);
            fflush(client->to);
        } else if (!strcmp(command, "WHO")) {
            namesent = true;
            fprintf(client->to, "NAME:%s\n", client->name);
            fflush(client->to);
        } else if (!strcmp(command, "NAME_TAKEN")) {
            namesent = false;
            increment_name(client);
        } else if (!strcmp(command, "ENTER")) {
            char* name = arg1;
            strtok_r(arg1, "\n", &name);
            printf("(%s has entered the chat)\n", arg1);
            fflush(stdout);
        } else if (!strcmp(command, "LEAVE")) {
            char* name = arg1;
            strtok_r(arg1, "\n", &name);
            printf("(%s has left the chat)\n", arg1);
            fflush(stdout);
        } else if (!strcmp(command, "MSG")) {
            printf("%s: %s\n", arg1, arg2);
            fflush(stdout);
        } else if (!strcmp(command, "KICK")) {
            fprintf(stderr, "Kicked\n");
            exit(3);
        } else if (!strcmp(command, "LIST")) {
            char* names = arg1;
            strtok_r(arg1, "\n", &names);
            printf("(current chatters: %s)\n", arg1);
            fflush(stdout);
        } else if (!strcmp(command, "OK")) {
            if (namesent && !client->named) {
                client->named = true;
            }
        }
    }
    fprintf(stderr, "Communications error\n"); //EOF server has died
    exit(2);
    return NULL;
}

//Takes input from stdin and sends it as a message to the server
void* stdin_thread(void* c){

    Client* client = (Client*) c;

    char buffer[1024];
    while (fgets(buffer, 1024, stdin)) {
        while (!client->named) {
            //wait for client to be named
        }
        if (buffer[0] == '*') {
            //Command to server, remove the * and send
            char* command = buffer + 1;
            fprintf(client->to, "%s", command);
        } else {
            //Must be a message, put SAY: in front and send
            fprintf(client->to, "SAY:%s", buffer);
        }
        fflush(client->to);
    }

    return NULL;
}

int main(int argc, char* argv[]){
    int fdClient;

    if (argc != 4) {
        fprintf(stderr, "Usage: client name authfile port\n");
        return 1;
    }

    FILE* file = fopen(argv[2], "r");

    if (file == NULL) {
        fprintf(stderr, "Usage: client name authfile port\n");
        return 1;
    }

    char auth[300];
    fgets(auth, 300, file);
    strtok(auth, "\n");

    const char* port = argv[3];

    fdClient = open_listen(port);

    int fdClient2 = dup(fdClient);

    FILE* to = fdopen(fdClient, "w");
    FILE* from = fdopen(fdClient2, "r");

    Client clientinfo;
    clientinfo.name = argv[1];
    clientinfo.basename = argv[1];
    clientinfo.auth = auth;
    clientinfo.num = -1;
    clientinfo.to = to;
    clientinfo.from = from;
    clientinfo.named = false;

    //Server thread
    pthread_t printId;
    pthread_create(&printId, NULL, server_thread, &clientinfo);
    

    //Stdin thread
    pthread_t sendId;
    pthread_create(&sendId, NULL, stdin_thread, &clientinfo);

    pthread_join(printId, NULL);

    return 0;
}