Advertisement
MarvinIt

Untitled

Jun 24th, 2017
73
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 17.69 KB | None | 0 0
  1. /*
  2.  * membox Progetto del corso di LSO 2017
  3.  *
  4.  * Dipartimento di Informatica Università di Pisa
  5.  * Docenti: Prencipe, Torquati
  6.  *
  7.  */
  8. /**
  9.  * @file chatty.c
  10.  * @brief File principale del server chatterbox
  11.  */
  12. #define _POSIX_C_SOURCE 200809L
  13. #include <stdio.h>
  14. #include <unistd.h>
  15. #include <stdlib.h>
  16. #include <assert.h>
  17. #include <string.h>
  18. #include <signal.h>
  19. #include <pthread.h>
  20. #include <sys/types.h>
  21. #include <sys/stat.h>
  22. #include <sys/socket.h>
  23. #include <sys/un.h>
  24. #include <sys/time.h>
  25. #include <sys/select.h>
  26. // TODO:  METTERE QUESTI INCLUDE COME LIBRERIE STATICHE.
  27. #include "connections.h"
  28. #include "message.h"
  29. #include "ops.h"
  30. #include "stats.h"
  31. #include "config.h"
  32. #include "icl_hash.h"
  33.  
  34. /* inserire gli altri include che servono */
  35.  
  36. typedef enum{UNIXPATH, MAXCONNECTIONS, THREADSINPOOL, MAXMSGSIZE, MAXFILESIZE, MAXHISTMSGS, DIRNAME, STATFILENAME} options_type;
  37.  
  38.  
  39. static int optionsBit[STATFILENAME + 1];
  40. static char optionsValue[STATFILENAME + 1][CONFBUFFSIZE];
  41. static char* optionsName[] = {"UnixPath", "MaxConnections", "ThreadsInPool", "MaxMsgSize", "MaxFileSize", "MaxHistMsgs", "DirName", "StatFileName"};
  42. static char *serverName = "SRV";
  43.  
  44. /* struttura che memorizza le statistiche del server, struct statistics
  45.  * e' definita in stats.h.
  46.  *
  47.  */
  48. struct statistics  chattyStats = { 0,0,0,0,0,0,0 };
  49.  
  50. /* Struttura per la coda di richieste */
  51. typedef struct request_s{
  52.     message_t msg;
  53.     int fd;
  54. } request;
  55.  
  56. typedef struct requestQueue_s{
  57.     request *req;
  58.     struct requestQueue_s *next;
  59. } requestQueue;
  60.  
  61. typedef struct user_s{
  62.     char nick[MAX_NAME_LENGTH];
  63.     int fd;
  64. } user;
  65.  
  66.  
  67. void printRequests();
  68. int loadConfig(char*);
  69. char *removeSpecial(char*);
  70. void *pullAndServe(void*);
  71. int connUser_compare(void*, void*);
  72.  
  73. op_t registration(request);
  74. op_t deregistration(request);
  75. op_t connection(request);
  76. op_t postText(request);
  77. int usrList(char **);
  78.  
  79. /* Hash tables condivise per:
  80.  * Utenti registrati
  81.  * Utenti connessi
  82.  */
  83. icl_hash_t *registeredUsers;
  84. icl_hash_t *connectedUsers;
  85.  
  86. pthread_mutex_t mtxQueue = PTHREAD_MUTEX_INITIALIZER;
  87. pthread_cond_t emptyQueue = PTHREAD_COND_INITIALIZER;
  88. pthread_mutex_t mtxConnected[MAXHASHSIZE] = PTHREAD_MUTEX_INITIALIZER;
  89. pthread_mutex_t mtxRegistered[MAXHASHSIZE] = PTHREAD_MUTEX_INITIALIZER;
  90. pthread_mutex_t mtxGen = PTHREAD_MUTEX_INITIALIZER;
  91.  
  92.  
  93. requestQueue *queue;
  94.  
  95. int nOnline = 0;
  96.  
  97. static void usage(const char *progname) {
  98.     fprintf(stderr, "Il server va lanciato con il seguente comando:\n");
  99.     fprintf(stderr, "  %s -f conffile\n", progname);
  100. }
  101.  
  102. int main(int argc, char *argv[]) {
  103.     if(argc < 3){
  104.         usage(argv[0]);
  105.         return -1;
  106.     }
  107.     else if(argv[1][1] != 'f'){
  108.         usage(argv[0]);
  109.         return -1;
  110.     }
  111.  
  112.     int i;
  113.     /* Azzera i bit delle opzioni */
  114.     for(i = 0; i < STATFILENAME + 1; i++) optionsBit[i] = 0;
  115.  
  116.     /* Carica le configurazioni */
  117.     if(loadConfig(argv[2]) == -1){
  118.         fprintf(stderr, "Could not load config file\n");
  119.         return -1;
  120.     }
  121.     /* Print Config: "Option: Value" and check for missing options. */
  122.     for(i = 0; i < STATFILENAME + 1; i++){
  123.         printf("%s: %s \n", optionsName[i], optionsValue[i]);
  124.         if(optionsBit[i] == 0){
  125.             printf("Missing Option %s, exiting.\n", optionsName[i]);
  126.             return -1;
  127.         }
  128.     }
  129.     /* Coda di richieste */
  130.     queue = NULL;
  131.  
  132.     /* Crea la Hash per utenti registrati e connessi*/
  133.     registeredUsers = icl_hash_create(MAXHASHSIZE, &hash_djb2, NULL);
  134.     connectedUsers = icl_hash_create(MAXHASHSIZE, &hash_djb2, &connUser_compare);
  135.  
  136.     int *clSock = calloc(atoi(optionsValue[MAXCONNECTIONS]), sizeof(int));
  137.     int fdSock, newClient, fdNum = 0;
  138.     int act, addrlen;
  139.     char *msgBuffer = malloc(sizeof(char) * atoi(optionsValue[MAXMSGSIZE]));
  140.     pthread_t *thds = malloc(sizeof(pthread_t) * atoi(optionsValue[THREADSINPOOL]));
  141.     fd_set wrset, wr, rdset, rd;
  142.  
  143.     struct sockaddr_un sockAdd;
  144.     strncpy(sockAdd.sun_path, optionsValue[UNIXPATH], UNIX_PATH_MAX);
  145.     sockAdd.sun_family = AF_UNIX;
  146.  
  147.     fdSock = socket(AF_UNIX, SOCK_STREAM, 0);
  148.     if(fdSock == -1){
  149.         perror("Socket");
  150.         return -1;
  151.     }
  152.     unlink(optionsValue[UNIXPATH]);
  153.     if(bind(fdSock, (struct sockaddr*)&sockAdd, sizeof(sockAdd)) < 0){
  154.         perror("Bind");
  155.         return -1;
  156.     }
  157.     /* Launch the threads in the pool */
  158.     for(i = 0; i < atoi(optionsValue[THREADSINPOOL]); i++) pthread_create(&thds[i], NULL, &pullAndServe, NULL);
  159.     if(listen(fdSock, SOMAXCONN) < 0){
  160.         perror("Listen");
  161.         return -1;
  162.     }
  163.     printf(">> Start Listening...\n");
  164.     FD_ZERO(&rdset);
  165.     FD_SET(fdSock, &rdset);
  166.     if(fdSock > fdNum) fdNum = fdSock;
  167.     addrlen = sizeof(sockAdd);
  168.     while(strcmp("P", "NP") != 0){
  169.         rd = rdset;
  170.         act = select(fdNum + 1, &rd, NULL, NULL, NULL);
  171.         if(act < 0){
  172.             perror("Select");
  173.             return -1;
  174.         }
  175.         // Qualcuno sta scrivendo sul socket del server, nuova connessione.
  176.         if(FD_ISSET(fdSock, &rd)){
  177.             if((newClient = accept(fdSock, (struct sockaddr *)&sockAdd, (socklen_t *)&addrlen)) < 0){
  178.                 perror("Accept");
  179.                 return -1;
  180.             }
  181.             for(i = 0; i < atoi(optionsValue[MAXCONNECTIONS]); i++){
  182.                 if(clSock[i] == 0){
  183.                     clSock[i] = newClient;
  184.                     FD_SET(clSock[i], &rdset);
  185.                     if(fdNum < clSock[i]) fdNum = clSock[i];
  186.                     printf("Adding New Socket to the array in fd %d, position %d\n", clSock[i], i);
  187.                     break;
  188.                 }
  189.             }
  190.         }
  191.         // Scrittura da altri socket o chiusura di un socket.
  192.         for(i = 0; i < atoi(optionsValue[MAXCONNECTIONS]); i++){
  193.             if(FD_ISSET(clSock[i], &rd)){
  194.                 message_t msg;
  195.                 int bit = readMsg(clSock[i], &msg);
  196.                 if(bit == 0){
  197.                     int hashedFd = hash_djb2(&clSock[i]) % MAXHASHSIZE;
  198.                     pthread_mutex_lock(&mtxConnected[hashedFd % 16]);
  199.                     user *tmp = NULL;
  200.                     char *tmpS = NULL;
  201.                     if((tmp = (user*) icl_hash_find(connectedUsers, &clSock[i])) != NULL){
  202.                         tmpS = calloc(strlen(tmp->nick), sizeof(char));
  203.                         memcpy(tmpS, tmp->nick, strlen(tmp->nick));
  204.                         if(icl_hash_delete(connectedUsers, &clSock[i], NULL, NULL) == 0){
  205.                             pthread_mutex_lock(&mtxGen);
  206.                             nOnline--;
  207.                             pthread_mutex_unlock(&mtxGen);
  208.                         }
  209.                         int hashedNick = hash_djb2(tmpS) % MAXHASHSIZE;
  210.                         pthread_mutex_lock(&mtxRegistered[hashedNick % 16]);
  211.                         if (tmp != NULL) free(tmp);
  212.                         tmp = (user*) icl_hash_find(registeredUsers, tmpS);
  213.                         if(tmp != NULL) tmp->fd = -1;
  214.                         free(tmpS);
  215.                         pthread_mutex_unlock(&mtxRegistered[hashedNick % 16]);
  216.                     }
  217.                     pthread_mutex_unlock(&mtxConnected[hashedFd % 16]);
  218.  
  219.                     FD_CLR(clSock[i], &rdset);
  220.                     close(clSock[i]);
  221.                     clSock[i] = 0;
  222.                     printf("Closing socket %d\n", i);
  223.                 }
  224.                 else{
  225.                     request *req = calloc(1,sizeof(request));
  226.                     req->msg = msg;
  227.                     req->fd = clSock[i];
  228.                     requestQueue *tmp = malloc(sizeof(requestQueue));
  229.                     tmp->next = NULL;
  230.                     tmp->req = req;
  231.                     if(queue == NULL){
  232.                         pthread_mutex_lock(&mtxQueue);
  233.                         queue = tmp;
  234.                         pthread_cond_signal(&emptyQueue);
  235.                         pthread_mutex_unlock(&mtxQueue);
  236.                     }
  237.                     else{
  238.                         pthread_mutex_lock(&mtxQueue);
  239.                         requestQueue *app = queue;
  240.                         while(app->next != NULL) app = app->next;
  241.                         app->next = tmp;
  242.                         pthread_mutex_unlock(&mtxQueue);
  243.                     }
  244.                 }
  245.             }
  246.         }
  247.     }
  248.  
  249.     close(fdSock);
  250.     return 1;
  251. }
  252.  
  253. void *pullAndServe(void *arg){
  254.     while(1){
  255.         request *currReq = malloc(sizeof(request));
  256.         op_t retCode = OP_FAIL;
  257.         message_t msg;
  258.         memset(&msg.hdr, 0, sizeof(message_hdr_t));
  259.         memset(&msg.data, 0, sizeof(message_data_hdr_t));
  260.         char *arrBuf = NULL;
  261.         int b = 0;
  262.         int onlineNow;
  263.         pthread_mutex_lock(&mtxQueue);
  264.         while(queue == NULL)
  265.             pthread_cond_wait(&emptyQueue, &mtxQueue);
  266.         currReq = queue->req;
  267.         queue = queue->next;
  268.         pthread_mutex_unlock(&mtxQueue);
  269.         printf("Thread %d took message with buf %s\n", pthread_self(), currReq->msg.data.buf);
  270.         //Distinguo l'operazione
  271.         switch(currReq->msg.hdr.op){
  272.             case REGISTER_OP:
  273.                 retCode = registration(*currReq);
  274.                 printf("Registration RetCode: %d\n", retCode);
  275.                 if(retCode == OP_OK){
  276.                     retCode = connection(*currReq);
  277.                     printf("Connection RetCode: %d\n", retCode);
  278.                     if(retCode == OP_OK){
  279.                             onlineNow = usrList(&arrBuf);
  280.                             setData(&msg.data, currReq->msg.hdr.sender, arrBuf, (onlineNow * (1+MAX_NAME_LENGTH)));
  281.                     }
  282.                 }
  283.             break;
  284.             case CONNECT_OP:
  285.                 retCode = connection(*currReq);
  286.                 printf("Connection RetCode: %d\n", retCode);
  287.                 if(retCode == OP_OK){
  288.                         onlineNow = usrList(&arrBuf);
  289.                         setData(&msg.data, currReq->msg.hdr.sender, arrBuf, (onlineNow * (1+MAX_NAME_LENGTH)));
  290.                 }
  291.             break;
  292.             case UNREGISTER_OP:
  293.                 retCode = deregistration(*currReq);
  294.                 printf("Deregistration RetCode: %d\n", retCode);
  295.             break;
  296.             case USRLIST_OP:
  297.                 onlineNow = usrList(&arrBuf);
  298.                 retCode = OP_OK;
  299.                 setData(&msg.data, currReq->msg.hdr.sender, arrBuf, (onlineNow * (1+MAX_NAME_LENGTH)));
  300.             break;
  301.             case POSTTXT_OP:
  302.                 retCode = postText(*currReq);
  303.                 printf("Sending text RetCode: %d\n");
  304.             break;
  305.         }
  306.  
  307.         // Scrivo i Dati a seconda dell'operazione richiesta.
  308.         if(retCode == OP_OK){
  309.             switch(currReq->msg.hdr.op){
  310.                 case REGISTER_OP:
  311.                 case CONNECT_OP:
  312.                 case USRLIST_OP:
  313.                     setHeader(&msg.hdr, retCode, serverName);
  314.                     while((b += write(currReq->fd, &msg.hdr, sizeof(message_hdr_t)) != sizeof(message_hdr_t)));
  315.                     b = 0;
  316.                     while((b += write(currReq->fd, &msg.data.hdr, sizeof(message_data_hdr_t)) != sizeof(message_data_hdr_t)));
  317.                     b = 0;
  318.                     while((b += write(currReq->fd, arrBuf, (onlineNow * (1+MAX_NAME_LENGTH))) != onlineNow * (1+MAX_NAME_LENGTH)));
  319.                 break;
  320.             }
  321.         }
  322.  
  323.     }
  324. }
  325.  
  326. op_t postText(request currReq){
  327.     int hashedRec =  hash_djb2(currReq.msg.data.hdr.receiver) % MAXHASHSIZE;
  328.     pthread_mutex_lock(&mtxRegistered[hashedRec % 16]);
  329.     if(icl_hash_find(registeredUsers, currReq.msg.data.hdr.receiver) == NULL){
  330.         pthread_mutex_unlock(&mtxRegistered[hashedRec % 16]);
  331.         return OP_NICK_UNKNOWN;
  332.     }
  333.     pthread_mutex_unlock(&mtxRegistered[hashedRec % 16]);
  334.  
  335.     if(strlen(currReq.msg.data.buf) > atoi(optionsValue[MAXMSGSIZE])) return OP_MSG_TOOLONG;
  336.  
  337. }
  338.  
  339. op_t connection(request currReq){
  340.     int hashedNick = hash_djb2(currReq.msg.hdr.sender) % MAXHASHSIZE;
  341.     int hashedFd = hash_djb2(&currReq.fd) % MAXHASHSIZE;
  342.     user *tmp = NULL;
  343.     pthread_mutex_lock(&mtxRegistered[hashedNick % 16]);
  344.     if((tmp = (user*) icl_hash_find(registeredUsers, currReq.msg.hdr.sender)) != NULL){
  345.         tmp->fd = currReq.fd;
  346.         pthread_mutex_unlock(&mtxRegistered[hashedNick % 16]);
  347.     }
  348.     else{
  349.         pthread_mutex_unlock(&mtxRegistered[hashedNick % 16]);
  350.         return OP_NICK_UNKNOWN;
  351.     }
  352.  
  353.     user *cN = malloc(sizeof(user));
  354.     memset(&cN->nick, 0, sizeof(cN->nick));
  355.     memcpy(cN->nick, currReq.msg.hdr.sender, MAX_NAME_LENGTH + 1);
  356.     cN->fd = currReq.fd;
  357.     pthread_mutex_lock(&mtxConnected[hashedFd % 16]);
  358.     icl_hash_insert(connectedUsers, &(cN->fd), cN);
  359.     nOnline++;
  360.     pthread_mutex_unlock(&mtxConnected[hashedFd % 16]);
  361.  
  362.     return OP_OK;
  363. }
  364.  
  365. op_t deregistration(request currReq){
  366.     if(strcmp(currReq.msg.hdr.sender, currReq.msg.data.hdr.receiver) != 0) return OP_FAIL;
  367.     int hashedValue = hash_djb2(currReq.msg.hdr.sender) % MAXHASHSIZE;
  368.     pthread_mutex_lock(&mtxRegistered[hashedValue % 16]);
  369.     if(icl_hash_find(registeredUsers, currReq.msg.hdr.sender) == NULL){
  370.         pthread_mutex_unlock(&mtxRegistered[hashedValue % 16]);
  371.         return OP_NICK_UNKNOWN;
  372.     }
  373.     icl_hash_delete(registeredUsers, currReq.msg.hdr.sender, NULL, NULL);
  374.     pthread_mutex_unlock(&mtxRegistered[hashedValue % 16]);
  375.     if(strlen(currReq.msg.hdr.sender) > MAX_NAME_LENGTH) return OP_FAIL;
  376.     return OP_OK;
  377. }
  378.  
  379. op_t registration(request currReq){
  380.     int hashedValue = hash_djb2(currReq.msg.hdr.sender) % MAXHASHSIZE;
  381.     user *cN = malloc(sizeof(user));
  382.     memset(&cN->nick, 0, sizeof(cN->nick));
  383.     memcpy(cN->nick, currReq.msg.hdr.sender, MAX_NAME_LENGTH + 1);
  384.     cN->fd = currReq.fd;
  385.     pthread_mutex_lock(&mtxRegistered[hashedValue % 16]);
  386.     if(icl_hash_find(registeredUsers, currReq.msg.hdr.sender) != NULL){
  387.         pthread_mutex_unlock(&mtxRegistered[hashedValue % 16]);
  388.         return OP_NICK_ALREADY;
  389.     }
  390.     icl_hash_insert(registeredUsers, currReq.msg.hdr.sender, cN);
  391.     pthread_mutex_unlock(&mtxRegistered[hashedValue % 16]);
  392.     if(strlen(currReq.msg.hdr.sender) > MAX_NAME_LENGTH) return OP_FAIL;
  393.     return OP_OK;
  394. }
  395.  
  396. int loadConfig(char *path){
  397.     char buff[CONFBUFFSIZE];
  398.     char *token;
  399.     FILE *conf = fopen(path, "r");
  400.     if(conf == NULL){
  401.         perror("loadConfig");
  402.         return -1;
  403.     }
  404.  
  405.     while((fgets(buff, CONFBUFFSIZE, conf)) != NULL){
  406.         if(buff[0] != '#'){
  407.             token = strtok(buff, "=");
  408.             token = removeSpecial(token);
  409.             if(strcmp(token, optionsName[UNIXPATH]) == 0) {
  410.                 strcpy(optionsValue[UNIXPATH], removeSpecial(strtok(NULL, "=")));
  411.                 optionsBit[UNIXPATH] = 1;
  412.             }
  413.             if(strcmp(token, optionsName[MAXCONNECTIONS]) == 0) {
  414.                 strcpy(optionsValue[MAXCONNECTIONS], removeSpecial(strtok(NULL, "=")));
  415.                 optionsBit[MAXCONNECTIONS] = 1;
  416.             }
  417.             if(strcmp(token, optionsName[THREADSINPOOL]) == 0){
  418.                 strcpy(optionsValue[THREADSINPOOL], removeSpecial(strtok(NULL, "=")));
  419.                 optionsBit[THREADSINPOOL] = 1;
  420.             }
  421.             if(strcmp(token, optionsName[MAXMSGSIZE]) == 0){
  422.                 strcpy(optionsValue[MAXMSGSIZE], removeSpecial(strtok(NULL, "=")));
  423.                 optionsBit[MAXMSGSIZE] = 1;
  424.             }
  425.             if(strcmp(token, optionsName[MAXFILESIZE]) == 0){
  426.                 strcpy(optionsValue[MAXFILESIZE], removeSpecial(strtok(NULL, "=")));
  427.                 optionsBit[MAXFILESIZE] = 1;
  428.             }
  429.             if(strcmp(token, optionsName[MAXHISTMSGS]) == 0){
  430.                 strcpy(optionsValue[MAXHISTMSGS], removeSpecial(strtok(NULL, "=")));
  431.                 optionsBit[MAXHISTMSGS] = 1;
  432.             }
  433.             if(strcmp(token, optionsName[DIRNAME]) == 0){
  434.                 strcpy(optionsValue[DIRNAME], removeSpecial(strtok(NULL, "=")));
  435.                 optionsBit[DIRNAME] = 1;
  436.             }
  437.             if(strcmp(token, optionsName[STATFILENAME]) == 0){
  438.                 strcpy(optionsValue[STATFILENAME], removeSpecial(strtok(NULL, "=")));
  439.                 optionsBit[STATFILENAME] = 1;
  440.             }
  441.         }
  442.     }
  443.  
  444.  
  445.     return 1;
  446. }
  447.  
  448. char *removeSpecial(char *src){
  449.     char *dest = calloc(strlen(src), sizeof(char));
  450.     int i = 0, d = 0;
  451.     for(i = 0; src[i] != '\0'; i++){
  452.         if(src[i] != ' ' && src[i] != '\t' && src[i] != '\n'){
  453.             dest[d++] = src[i];
  454.         }
  455.     }
  456.     dest[d] = '\0';
  457.     return dest;
  458. }
  459.  
  460. int connUser_compare    (void *a, void *b){
  461.     int _a = *(int*)a;
  462.     int _b = *(int*)b;
  463.     return _a == _b;
  464. }
  465.  
  466. /**
  467.  * Inserisce i nickname della hashtable ConnectedUsers in una stringa
  468.  * @param[in] array -- Puntatore alla stringa di destinazione
  469.  * @returns il numero di utenti online su cui è stato creata la stringa
  470.  */
  471. int usrList(char **arrBuf){
  472.     int aCnn = 0;
  473.     pthread_mutex_lock(&mtxGen);
  474.     aCnn = nOnline;
  475.     pthread_mutex_unlock(&mtxGen);
  476.  
  477.     if(!*arrBuf){
  478.         *arrBuf = calloc(aCnn * (1 + MAX_NAME_LENGTH), sizeof(char));
  479.         memset(*arrBuf, 0, sizeof(*arrBuf));
  480.     }
  481.     icl_entry_t *tmp;
  482.     int i = 0;
  483.     int p = 0;
  484.     while(i < aCnn && p < MAXHASHSIZE){
  485.         pthread_mutex_lock(&mtxConnected[p % 16]);
  486.         for(tmp = connectedUsers->buckets[p]; tmp != NULL; tmp = tmp->next){
  487.             user *tmpCon;
  488.             tmpCon = (user*) tmp->data;
  489.             char *p = strchr(tmpCon->nick, '\n');
  490.             if (p != NULL) *p = '\0';
  491.             memcpy(*arrBuf + ((MAX_NAME_LENGTH + 1) * i), tmpCon->nick, MAX_NAME_LENGTH + 1);
  492.             i++;
  493.         }
  494.         pthread_mutex_unlock(&mtxConnected[p % 16]);
  495.         p++;
  496.     }
  497.     return aCnn;
  498. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement