Advertisement
Guest User

Untitled

a guest
Dec 10th, 2019
111
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 8.40 KB | None | 0 0
  1. #include <errno.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <pthread.h>
  6. #include <semaphore.h>
  7. #include <unistd.h>
  8. #include <arpa/inet.h>
  9. #include <netinet/in.h>
  10. #include <sys/socket.h>
  11.  
  12. #include "common.h"
  13.  
  14. unsigned int shared_counters[N];
  15. /**
  16.     * COMPLETARE QUI
  17.     *
  18.     * Obiettivi:
  19.     * - dichiarare i semafori necessari per garantire la mutua esclusione
  20.     *   nell'accesso alle celle dell'array shared_counters
  21.     **/  
  22.  
  23. sem_t semafori[N];
  24.  
  25. // struttura dati con gli argomenti per thread connection_handler
  26. typedef struct handler_args_s {
  27.     unsigned int client_id;
  28.     int socket_desc;
  29.     struct sockaddr_in* client_addr;
  30. } handler_args_t;
  31.  
  32. unsigned int process_resource(unsigned int client_id, unsigned int resource_id) {
  33.     /**
  34.      * COMPLETARE QUI
  35.      *
  36.      * Obiettivi:
  37.      * - gestire la mutua esclusione tra thread che provano ad accedere
  38.      *   alla cella 'resource_id'-esima nella sezione critica
  39.      * - gestire eventuali errori
  40.      **/
  41.  
  42.     if (sem_wait(semafori+resource_id) == -1) {
  43.         handle_error("Errore nella wait");
  44.     }
  45.  
  46.     printf("Risorsa %u LOCKED dal client %u! Processamento in corso...\n", resource_id, client_id);
  47.    
  48.     /* inizio sezione critica */
  49.     unsigned int counter_updated = ++shared_counters[resource_id];
  50.     printf("Nuovo contatore per risorsa %u: %u\n", resource_id, counter_updated);
  51.     sleep(SLEEP_TIME);
  52.     /* fine sezione critica */
  53.  
  54.     if (sem_post(semafori+resource_id) == -1) {
  55.         handle_error("Errore nella post");
  56.     }
  57.    
  58.     printf("Risorsa %u UNLOCKED\n", resource_id);
  59.    
  60.     return counter_updated;
  61. }
  62.  
  63.  
  64. void* connection_handler(void* arg) {
  65.     int ret;
  66.    
  67.     handler_args_t* args = (handler_args_t*)arg;
  68.     int socket_desc = args->socket_desc;
  69.     struct sockaddr_in* client_addr = args->client_addr;
  70.     unsigned int client_id = args->client_id;
  71.    
  72.     char buf[1024];
  73.    
  74.     char* quit_command = SERVER_COMMAND;
  75.     size_t quit_command_len = strlen(quit_command);
  76.    
  77.     // parso il client IP address e la porta
  78.     char client_ip[INET_ADDRSTRLEN];
  79.     inet_ntop(AF_INET, &(client_addr->sin_addr), client_ip, INET_ADDRSTRLEN);
  80.     uint16_t client_port = ntohs(client_addr->sin_port); // port number is an unsigned short
  81.     printf("Client %u connesso sulla porta %u \n", client_id, client_port);
  82.    
  83.     // ciclo di scambio messaggi
  84.     unsigned int resource_id;
  85.     while (1) {
  86.    
  87.         int bytes_read = 0;
  88.         int i = 0;
  89.  
  90.         /**
  91.          * COMPLETARE QUI
  92.          *
  93.          * Obiettivi:
  94.          * - leggere un messaggio dal client e salvarlo nel buffer buf
  95.          * - gestire eventuali interruzioni ed errori
  96.          * - salvare il numero di byte ricevuti nella variabile 'bytes_read'
  97.          *   e il valore restituito da una singola lettura in 'ret'
  98.          * - gestire chiusure inattese della connessione da parte del
  99.          *   client uscendo dal loop usato per la lettura
  100.          *
  101.          * Si tenga a mente che l'ultimo byte valido in un messaggio (la
  102.          * cui lunghezza NON è nota a priori) è il terminatore di riga '\n'.
  103.          **/
  104.        
  105.         do {
  106.             ret = recv(socket_desc, buf+i, 1, 0);
  107.  
  108.                 if (ret == 0) break;
  109.             if (ret == -1) {
  110.                 if (errno == EINTR) continue;
  111.                 else {
  112.                     handle_error("Errore nella recv");
  113.                     break;
  114.                 }
  115.             }
  116.  
  117.             bytes_read += ret;
  118.             i++;
  119.         } while(buf[i-1] != '\n');
  120.        
  121.         size_t msg_len = bytes_read - 1; // NON MODIFICARE (vedi commenti sopra)
  122.        
  123.         // verifico se devo terminare (comando "QUIT" ricevuto, o endpoint chiuso)
  124.         if ((msg_len == quit_command_len && !memcmp(buf, quit_command, quit_command_len)) || ret == 0) break;
  125.        
  126.         // avvio il processamento della risorsa, aggiorno il relativo contatore e lo salvo in buf
  127.         buf[msg_len] = '\0';
  128.         int tmp = atoi(buf); // devo usare un int per gestire numeri negativi
  129.         resource_id = (tmp > 0 && tmp < N) ? tmp : 0;
  130.         unsigned int counter_updated = process_resource(client_id, resource_id);
  131.        
  132.         sprintf(buf, "[risorsa %u] contatore: %u", resource_id, counter_updated);
  133.         msg_len = strlen(buf);
  134.        
  135.         /**
  136.          * COMPLETARE QUI
  137.          *
  138.          * Obiettivi:
  139.          * - inviare al client i primi msg_len bytes contenuti in buf
  140.          * - gestire eventuali interruzioni ed errori
  141.          * - assicurarsi che tutti i byte siano stati scritti
  142.          **/
  143.  
  144.         int bytes_sent = 0;
  145.  
  146.         while(bytes_sent < msg_len) {
  147.             ret = send(socket_desc, buf+bytes_sent, 1, 0);
  148.        
  149.             if (ret == -1) {
  150.                 if (errno == EINTR) continue;
  151.                 else {
  152.                     handle_error("Errore nella send");
  153.                     break;
  154.                 }
  155.             }
  156.  
  157.             bytes_sent ++;
  158.         }
  159.     }
  160.    
  161.     /**
  162.      * COMPLETARE QUI
  163.      *
  164.      * Obiettivi:
  165.      * - chiudere descrittori in uso
  166.      * - gestire eventuali errori
  167.      * - liberare memoria in uso al thread
  168.      */
  169.  
  170.     if (close(socket_desc) == -1) {
  171.         handle_error("Errore nella close");
  172.     }
  173.  
  174.     free(arg);
  175.      
  176.     printf("Thread connection_handler terminato\n");
  177.    
  178.     pthread_exit(NULL);
  179. }
  180.  
  181.  
  182. int main(int argc, char* argv[]) {     
  183.     /**
  184.      * COMPLETARE QUI
  185.      *
  186.      * Obiettivi:
  187.      * - inizializzare i semafori
  188.      * - gestire eventuali errori di inizializzazione
  189.      **/
  190.     int ret;
  191.  
  192.     int i;
  193.  
  194.     for (i = 0; i < N; i++) {
  195.         if(sem_init(semafori+i, 0, 1) == -1) {
  196.             handle_error("Errore in sem_init");
  197.         }
  198.     }
  199.    
  200.     // creo le strutture per la socket
  201.     int socket_desc, client_desc;
  202.     struct sockaddr_in server_addr = {0};
  203.    
  204.     int sockaddr_len = sizeof(struct sockaddr_in); // da riusare per le accept()
  205.    
  206.     // inizializzo la socket
  207.     socket_desc = socket(AF_INET , SOCK_STREAM , 0);
  208.     if(socket_desc == -1) handle_error("Impossibile creare la socket");
  209.    
  210.     server_addr.sin_addr.s_addr = INADDR_ANY;
  211.     server_addr.sin_family      = AF_INET;
  212.     server_addr.sin_port        = htons(SERVER_PORT);
  213.    
  214.     // abilito l'opzione SO_REUSEADDR per riavviare il server dopo un crash
  215.     int reuseaddr_opt = 1;
  216.     ret = setsockopt(socket_desc, SOL_SOCKET, SO_REUSEADDR, &reuseaddr_opt, sizeof(reuseaddr_opt));
  217.     if(ret) handle_error("Impossibile settare l'opzione SO_REUSEADDR");
  218.    
  219.     // bind & listen
  220.     ret = bind(socket_desc, (struct sockaddr*) &server_addr, sockaddr_len);
  221.     if(ret) handle_error("Impossibile fare il binding indirizzo-socket");
  222.  
  223.     ret = listen(socket_desc, 16);
  224.     if(ret) handle_error("Impossibile ascoltare dalla socket");
  225.  
  226.  
  227.     // loop per gestire connessioni in ingresso con nuovi thread
  228.     printf("Server pronto ad accettare connessioni!\n");
  229.     unsigned int client_id = 0;
  230.     while (1) {
  231.        
  232.         pthread_t thread;
  233.         // alloco un buffer client_addr per la connessione
  234.         struct sockaddr_in* client_addr = calloc(1, sizeof(struct sockaddr_in));
  235.    
  236.         // accetto connessioni in ingresso
  237.         client_desc = accept(socket_desc, (struct sockaddr*) client_addr, (socklen_t*) &sockaddr_len);
  238.         if (client_desc == -1 && errno == EINTR) continue; // check per segnali di interruzione
  239.         if (client_desc == -1) handle_error("Impossibile aprire la socket per connessioni in ingresso.");
  240.         printf("Connessione accettata\n");
  241.         printf("Il numero è %d\n", N);
  242.        
  243.         /**
  244.          * COMPLETARE QUI
  245.          *
  246.          * Obiettivi:
  247.          * - preparare gli argomenti da passare al thread che eseguirà
  248.          *   connection_handler (si veda handler_args_t all'inizio)
  249.          * - creare un thread che esegua connection_handler() passando
  250.          *   la struct con gli argomenti predisposta
  251.          * - gestire eventuali errori
  252.          *
  253.          * Si tenga a mente che NON verranno effettuate in futuro
  254.          * operazioni di join sul thread appena creato.
  255.          **/
  256.        
  257.         handler_args_t* arg = malloc(sizeof(handler_args_t));
  258.  
  259.         if (arg == NULL) {
  260.             handle_error("Errore in malloc");
  261.         }
  262.  
  263.         arg->client_id = client_id;
  264.         arg->socket_desc = client_desc;
  265.         arg->client_addr = client_addr;
  266.            
  267.         if (pthread_create(&thread, NULL, connection_handler, (void*) arg) == -1) {
  268.             handle_error("Errore in pthread_create");
  269.         }
  270.            
  271.             // incremento il client ID dopo ogni connessione accettata
  272.             client_id++;
  273.     }
  274.  
  275.     for (i = 0; i < N; i++) {
  276.         if (sem_close(semafori+i) == -1) {
  277.             handle_error("Errore in close");
  278.         }
  279.     }
  280.  
  281.     return 0;
  282. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement