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