Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- * membox Progetto del corso di LSO 2017
- *
- * Dipartimento di Informatica Università di Pisa
- * Docenti: Prencipe, Torquati
- *
- */
- /**
- * @file chatty.c
- * @brief File principale del server chatterbox
- */
- #define _POSIX_C_SOURCE 200809L
- #include <stdio.h>
- #include <unistd.h>
- #include <stdlib.h>
- #include <assert.h>
- #include <string.h>
- #include <signal.h>
- #include <pthread.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <sys/socket.h>
- #include <sys/un.h>
- #include <sys/time.h>
- #include <sys/select.h>
- // TODO: METTERE QUESTI INCLUDE COME LIBRERIE STATICHE.
- #include "connections.h"
- #include "message.h"
- #include "ops.h"
- #include "stats.h"
- #include "config.h"
- #include "icl_hash.h"
- /* inserire gli altri include che servono */
- typedef enum{UNIXPATH, MAXCONNECTIONS, THREADSINPOOL, MAXMSGSIZE, MAXFILESIZE, MAXHISTMSGS, DIRNAME, STATFILENAME} options_type;
- static int optionsBit[STATFILENAME + 1];
- static char optionsValue[STATFILENAME + 1][CONFBUFFSIZE];
- static char* optionsName[] = {"UnixPath", "MaxConnections", "ThreadsInPool", "MaxMsgSize", "MaxFileSize", "MaxHistMsgs", "DirName", "StatFileName"};
- static char *serverName = "SRV";
- /* struttura che memorizza le statistiche del server, struct statistics
- * e' definita in stats.h.
- *
- */
- struct statistics chattyStats = { 0,0,0,0,0,0,0 };
- /* Struttura per la coda di richieste */
- typedef struct request_s{
- message_t msg;
- int fd;
- } request;
- typedef struct requestQueue_s{
- request *req;
- struct requestQueue_s *next;
- } requestQueue;
- typedef struct user_s{
- char nick[MAX_NAME_LENGTH];
- int fd;
- } user;
- void printRequests();
- int loadConfig(char*);
- char *removeSpecial(char*);
- void *pullAndServe(void*);
- int connUser_compare(void*, void*);
- op_t registration(request);
- op_t deregistration(request);
- op_t connection(request);
- op_t postText(request);
- int usrList(char **);
- /* Hash tables condivise per:
- * Utenti registrati
- * Utenti connessi
- */
- icl_hash_t *registeredUsers;
- icl_hash_t *connectedUsers;
- pthread_mutex_t mtxQueue = PTHREAD_MUTEX_INITIALIZER;
- pthread_cond_t emptyQueue = PTHREAD_COND_INITIALIZER;
- pthread_mutex_t mtxConnected[MAXHASHSIZE] = PTHREAD_MUTEX_INITIALIZER;
- pthread_mutex_t mtxRegistered[MAXHASHSIZE] = PTHREAD_MUTEX_INITIALIZER;
- pthread_mutex_t mtxGen = PTHREAD_MUTEX_INITIALIZER;
- requestQueue *queue;
- int nOnline = 0;
- static void usage(const char *progname) {
- fprintf(stderr, "Il server va lanciato con il seguente comando:\n");
- fprintf(stderr, " %s -f conffile\n", progname);
- }
- int main(int argc, char *argv[]) {
- if(argc < 3){
- usage(argv[0]);
- return -1;
- }
- else if(argv[1][1] != 'f'){
- usage(argv[0]);
- return -1;
- }
- int i;
- /* Azzera i bit delle opzioni */
- for(i = 0; i < STATFILENAME + 1; i++) optionsBit[i] = 0;
- /* Carica le configurazioni */
- if(loadConfig(argv[2]) == -1){
- fprintf(stderr, "Could not load config file\n");
- return -1;
- }
- /* Print Config: "Option: Value" and check for missing options. */
- for(i = 0; i < STATFILENAME + 1; i++){
- printf("%s: %s \n", optionsName[i], optionsValue[i]);
- if(optionsBit[i] == 0){
- printf("Missing Option %s, exiting.\n", optionsName[i]);
- return -1;
- }
- }
- /* Coda di richieste */
- queue = NULL;
- /* Crea la Hash per utenti registrati e connessi*/
- registeredUsers = icl_hash_create(MAXHASHSIZE, &hash_djb2, NULL);
- connectedUsers = icl_hash_create(MAXHASHSIZE, &hash_djb2, &connUser_compare);
- int *clSock = calloc(atoi(optionsValue[MAXCONNECTIONS]), sizeof(int));
- int fdSock, newClient, fdNum = 0;
- int act, addrlen;
- char *msgBuffer = malloc(sizeof(char) * atoi(optionsValue[MAXMSGSIZE]));
- pthread_t *thds = malloc(sizeof(pthread_t) * atoi(optionsValue[THREADSINPOOL]));
- fd_set wrset, wr, rdset, rd;
- struct sockaddr_un sockAdd;
- strncpy(sockAdd.sun_path, optionsValue[UNIXPATH], UNIX_PATH_MAX);
- sockAdd.sun_family = AF_UNIX;
- fdSock = socket(AF_UNIX, SOCK_STREAM, 0);
- if(fdSock == -1){
- perror("Socket");
- return -1;
- }
- unlink(optionsValue[UNIXPATH]);
- if(bind(fdSock, (struct sockaddr*)&sockAdd, sizeof(sockAdd)) < 0){
- perror("Bind");
- return -1;
- }
- /* Launch the threads in the pool */
- for(i = 0; i < atoi(optionsValue[THREADSINPOOL]); i++) pthread_create(&thds[i], NULL, &pullAndServe, NULL);
- if(listen(fdSock, SOMAXCONN) < 0){
- perror("Listen");
- return -1;
- }
- printf(">> Start Listening...\n");
- FD_ZERO(&rdset);
- FD_SET(fdSock, &rdset);
- if(fdSock > fdNum) fdNum = fdSock;
- addrlen = sizeof(sockAdd);
- while(strcmp("P", "NP") != 0){
- rd = rdset;
- act = select(fdNum + 1, &rd, NULL, NULL, NULL);
- if(act < 0){
- perror("Select");
- return -1;
- }
- // Qualcuno sta scrivendo sul socket del server, nuova connessione.
- if(FD_ISSET(fdSock, &rd)){
- if((newClient = accept(fdSock, (struct sockaddr *)&sockAdd, (socklen_t *)&addrlen)) < 0){
- perror("Accept");
- return -1;
- }
- for(i = 0; i < atoi(optionsValue[MAXCONNECTIONS]); i++){
- if(clSock[i] == 0){
- clSock[i] = newClient;
- FD_SET(clSock[i], &rdset);
- if(fdNum < clSock[i]) fdNum = clSock[i];
- printf("Adding New Socket to the array in fd %d, position %d\n", clSock[i], i);
- break;
- }
- }
- }
- // Scrittura da altri socket o chiusura di un socket.
- for(i = 0; i < atoi(optionsValue[MAXCONNECTIONS]); i++){
- if(FD_ISSET(clSock[i], &rd)){
- message_t msg;
- int bit = readMsg(clSock[i], &msg);
- if(bit == 0){
- int hashedFd = hash_djb2(&clSock[i]) % MAXHASHSIZE;
- pthread_mutex_lock(&mtxConnected[hashedFd % 16]);
- user *tmp = NULL;
- char *tmpS = NULL;
- if((tmp = (user*) icl_hash_find(connectedUsers, &clSock[i])) != NULL){
- tmpS = calloc(strlen(tmp->nick), sizeof(char));
- memcpy(tmpS, tmp->nick, strlen(tmp->nick));
- if(icl_hash_delete(connectedUsers, &clSock[i], NULL, NULL) == 0){
- pthread_mutex_lock(&mtxGen);
- nOnline--;
- pthread_mutex_unlock(&mtxGen);
- }
- int hashedNick = hash_djb2(tmpS) % MAXHASHSIZE;
- pthread_mutex_lock(&mtxRegistered[hashedNick % 16]);
- if (tmp != NULL) free(tmp);
- tmp = (user*) icl_hash_find(registeredUsers, tmpS);
- if(tmp != NULL) tmp->fd = -1;
- free(tmpS);
- pthread_mutex_unlock(&mtxRegistered[hashedNick % 16]);
- }
- pthread_mutex_unlock(&mtxConnected[hashedFd % 16]);
- FD_CLR(clSock[i], &rdset);
- close(clSock[i]);
- clSock[i] = 0;
- printf("Closing socket %d\n", i);
- }
- else{
- request *req = calloc(1,sizeof(request));
- req->msg = msg;
- req->fd = clSock[i];
- requestQueue *tmp = malloc(sizeof(requestQueue));
- tmp->next = NULL;
- tmp->req = req;
- if(queue == NULL){
- pthread_mutex_lock(&mtxQueue);
- queue = tmp;
- pthread_cond_signal(&emptyQueue);
- pthread_mutex_unlock(&mtxQueue);
- }
- else{
- pthread_mutex_lock(&mtxQueue);
- requestQueue *app = queue;
- while(app->next != NULL) app = app->next;
- app->next = tmp;
- pthread_mutex_unlock(&mtxQueue);
- }
- }
- }
- }
- }
- close(fdSock);
- return 1;
- }
- void *pullAndServe(void *arg){
- while(1){
- request *currReq = malloc(sizeof(request));
- op_t retCode = OP_FAIL;
- message_t msg;
- memset(&msg.hdr, 0, sizeof(message_hdr_t));
- memset(&msg.data, 0, sizeof(message_data_hdr_t));
- char *arrBuf = NULL;
- int b = 0;
- int onlineNow;
- pthread_mutex_lock(&mtxQueue);
- while(queue == NULL)
- pthread_cond_wait(&emptyQueue, &mtxQueue);
- currReq = queue->req;
- queue = queue->next;
- pthread_mutex_unlock(&mtxQueue);
- printf("Thread %d took message with buf %s\n", pthread_self(), currReq->msg.data.buf);
- //Distinguo l'operazione
- switch(currReq->msg.hdr.op){
- case REGISTER_OP:
- retCode = registration(*currReq);
- printf("Registration RetCode: %d\n", retCode);
- if(retCode == OP_OK){
- retCode = connection(*currReq);
- printf("Connection RetCode: %d\n", retCode);
- if(retCode == OP_OK){
- onlineNow = usrList(&arrBuf);
- setData(&msg.data, currReq->msg.hdr.sender, arrBuf, (onlineNow * (1+MAX_NAME_LENGTH)));
- }
- }
- break;
- case CONNECT_OP:
- retCode = connection(*currReq);
- printf("Connection RetCode: %d\n", retCode);
- if(retCode == OP_OK){
- onlineNow = usrList(&arrBuf);
- setData(&msg.data, currReq->msg.hdr.sender, arrBuf, (onlineNow * (1+MAX_NAME_LENGTH)));
- }
- break;
- case UNREGISTER_OP:
- retCode = deregistration(*currReq);
- printf("Deregistration RetCode: %d\n", retCode);
- break;
- case USRLIST_OP:
- onlineNow = usrList(&arrBuf);
- retCode = OP_OK;
- setData(&msg.data, currReq->msg.hdr.sender, arrBuf, (onlineNow * (1+MAX_NAME_LENGTH)));
- break;
- case POSTTXT_OP:
- retCode = postText(*currReq);
- printf("Sending text RetCode: %d\n");
- break;
- }
- // Scrivo i Dati a seconda dell'operazione richiesta.
- if(retCode == OP_OK){
- switch(currReq->msg.hdr.op){
- case REGISTER_OP:
- case CONNECT_OP:
- case USRLIST_OP:
- setHeader(&msg.hdr, retCode, serverName);
- while((b += write(currReq->fd, &msg.hdr, sizeof(message_hdr_t)) != sizeof(message_hdr_t)));
- b = 0;
- while((b += write(currReq->fd, &msg.data.hdr, sizeof(message_data_hdr_t)) != sizeof(message_data_hdr_t)));
- b = 0;
- while((b += write(currReq->fd, arrBuf, (onlineNow * (1+MAX_NAME_LENGTH))) != onlineNow * (1+MAX_NAME_LENGTH)));
- break;
- }
- }
- }
- }
- op_t postText(request currReq){
- int hashedRec = hash_djb2(currReq.msg.data.hdr.receiver) % MAXHASHSIZE;
- pthread_mutex_lock(&mtxRegistered[hashedRec % 16]);
- if(icl_hash_find(registeredUsers, currReq.msg.data.hdr.receiver) == NULL){
- pthread_mutex_unlock(&mtxRegistered[hashedRec % 16]);
- return OP_NICK_UNKNOWN;
- }
- pthread_mutex_unlock(&mtxRegistered[hashedRec % 16]);
- if(strlen(currReq.msg.data.buf) > atoi(optionsValue[MAXMSGSIZE])) return OP_MSG_TOOLONG;
- }
- op_t connection(request currReq){
- int hashedNick = hash_djb2(currReq.msg.hdr.sender) % MAXHASHSIZE;
- int hashedFd = hash_djb2(&currReq.fd) % MAXHASHSIZE;
- user *tmp = NULL;
- pthread_mutex_lock(&mtxRegistered[hashedNick % 16]);
- if((tmp = (user*) icl_hash_find(registeredUsers, currReq.msg.hdr.sender)) != NULL){
- tmp->fd = currReq.fd;
- pthread_mutex_unlock(&mtxRegistered[hashedNick % 16]);
- }
- else{
- pthread_mutex_unlock(&mtxRegistered[hashedNick % 16]);
- return OP_NICK_UNKNOWN;
- }
- user *cN = malloc(sizeof(user));
- memset(&cN->nick, 0, sizeof(cN->nick));
- memcpy(cN->nick, currReq.msg.hdr.sender, MAX_NAME_LENGTH + 1);
- cN->fd = currReq.fd;
- pthread_mutex_lock(&mtxConnected[hashedFd % 16]);
- icl_hash_insert(connectedUsers, &(cN->fd), cN);
- nOnline++;
- pthread_mutex_unlock(&mtxConnected[hashedFd % 16]);
- return OP_OK;
- }
- op_t deregistration(request currReq){
- if(strcmp(currReq.msg.hdr.sender, currReq.msg.data.hdr.receiver) != 0) return OP_FAIL;
- int hashedValue = hash_djb2(currReq.msg.hdr.sender) % MAXHASHSIZE;
- pthread_mutex_lock(&mtxRegistered[hashedValue % 16]);
- if(icl_hash_find(registeredUsers, currReq.msg.hdr.sender) == NULL){
- pthread_mutex_unlock(&mtxRegistered[hashedValue % 16]);
- return OP_NICK_UNKNOWN;
- }
- icl_hash_delete(registeredUsers, currReq.msg.hdr.sender, NULL, NULL);
- pthread_mutex_unlock(&mtxRegistered[hashedValue % 16]);
- if(strlen(currReq.msg.hdr.sender) > MAX_NAME_LENGTH) return OP_FAIL;
- return OP_OK;
- }
- op_t registration(request currReq){
- int hashedValue = hash_djb2(currReq.msg.hdr.sender) % MAXHASHSIZE;
- user *cN = malloc(sizeof(user));
- memset(&cN->nick, 0, sizeof(cN->nick));
- memcpy(cN->nick, currReq.msg.hdr.sender, MAX_NAME_LENGTH + 1);
- cN->fd = currReq.fd;
- pthread_mutex_lock(&mtxRegistered[hashedValue % 16]);
- if(icl_hash_find(registeredUsers, currReq.msg.hdr.sender) != NULL){
- pthread_mutex_unlock(&mtxRegistered[hashedValue % 16]);
- return OP_NICK_ALREADY;
- }
- icl_hash_insert(registeredUsers, currReq.msg.hdr.sender, cN);
- pthread_mutex_unlock(&mtxRegistered[hashedValue % 16]);
- if(strlen(currReq.msg.hdr.sender) > MAX_NAME_LENGTH) return OP_FAIL;
- return OP_OK;
- }
- int loadConfig(char *path){
- char buff[CONFBUFFSIZE];
- char *token;
- FILE *conf = fopen(path, "r");
- if(conf == NULL){
- perror("loadConfig");
- return -1;
- }
- while((fgets(buff, CONFBUFFSIZE, conf)) != NULL){
- if(buff[0] != '#'){
- token = strtok(buff, "=");
- token = removeSpecial(token);
- if(strcmp(token, optionsName[UNIXPATH]) == 0) {
- strcpy(optionsValue[UNIXPATH], removeSpecial(strtok(NULL, "=")));
- optionsBit[UNIXPATH] = 1;
- }
- if(strcmp(token, optionsName[MAXCONNECTIONS]) == 0) {
- strcpy(optionsValue[MAXCONNECTIONS], removeSpecial(strtok(NULL, "=")));
- optionsBit[MAXCONNECTIONS] = 1;
- }
- if(strcmp(token, optionsName[THREADSINPOOL]) == 0){
- strcpy(optionsValue[THREADSINPOOL], removeSpecial(strtok(NULL, "=")));
- optionsBit[THREADSINPOOL] = 1;
- }
- if(strcmp(token, optionsName[MAXMSGSIZE]) == 0){
- strcpy(optionsValue[MAXMSGSIZE], removeSpecial(strtok(NULL, "=")));
- optionsBit[MAXMSGSIZE] = 1;
- }
- if(strcmp(token, optionsName[MAXFILESIZE]) == 0){
- strcpy(optionsValue[MAXFILESIZE], removeSpecial(strtok(NULL, "=")));
- optionsBit[MAXFILESIZE] = 1;
- }
- if(strcmp(token, optionsName[MAXHISTMSGS]) == 0){
- strcpy(optionsValue[MAXHISTMSGS], removeSpecial(strtok(NULL, "=")));
- optionsBit[MAXHISTMSGS] = 1;
- }
- if(strcmp(token, optionsName[DIRNAME]) == 0){
- strcpy(optionsValue[DIRNAME], removeSpecial(strtok(NULL, "=")));
- optionsBit[DIRNAME] = 1;
- }
- if(strcmp(token, optionsName[STATFILENAME]) == 0){
- strcpy(optionsValue[STATFILENAME], removeSpecial(strtok(NULL, "=")));
- optionsBit[STATFILENAME] = 1;
- }
- }
- }
- return 1;
- }
- char *removeSpecial(char *src){
- char *dest = calloc(strlen(src), sizeof(char));
- int i = 0, d = 0;
- for(i = 0; src[i] != '\0'; i++){
- if(src[i] != ' ' && src[i] != '\t' && src[i] != '\n'){
- dest[d++] = src[i];
- }
- }
- dest[d] = '\0';
- return dest;
- }
- int connUser_compare (void *a, void *b){
- int _a = *(int*)a;
- int _b = *(int*)b;
- return _a == _b;
- }
- /**
- * Inserisce i nickname della hashtable ConnectedUsers in una stringa
- * @param[in] array -- Puntatore alla stringa di destinazione
- * @returns il numero di utenti online su cui è stato creata la stringa
- */
- int usrList(char **arrBuf){
- int aCnn = 0;
- pthread_mutex_lock(&mtxGen);
- aCnn = nOnline;
- pthread_mutex_unlock(&mtxGen);
- if(!*arrBuf){
- *arrBuf = calloc(aCnn * (1 + MAX_NAME_LENGTH), sizeof(char));
- memset(*arrBuf, 0, sizeof(*arrBuf));
- }
- icl_entry_t *tmp;
- int i = 0;
- int p = 0;
- while(i < aCnn && p < MAXHASHSIZE){
- pthread_mutex_lock(&mtxConnected[p % 16]);
- for(tmp = connectedUsers->buckets[p]; tmp != NULL; tmp = tmp->next){
- user *tmpCon;
- tmpCon = (user*) tmp->data;
- char *p = strchr(tmpCon->nick, '\n');
- if (p != NULL) *p = '\0';
- memcpy(*arrBuf + ((MAX_NAME_LENGTH + 1) * i), tmpCon->nick, MAX_NAME_LENGTH + 1);
- i++;
- }
- pthread_mutex_unlock(&mtxConnected[p % 16]);
- p++;
- }
- return aCnn;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement