Advertisement
Guest User

Threads i sockets

a guest
Mar 6th, 2014
84
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 9.32 KB | None | 0 0
  1. /********************************************************************
  2. * Alumnes: Octavi Allué Fonoll (1224997)                            *
  3. * Pràctica SO: threads i sockets, segón quatrimestre                *
  4. ********************************************************************/
  5.  
  6. /* Llibreries incloses */
  7.  
  8. #include <sys/types.h>
  9. #include <sys/socket.h>
  10. #include <netinet/in.h>
  11. #include <netdb.h>
  12. #include <unistd.h>
  13. #include <stdio.h>
  14. #include <pthread.h>
  15. #include <string.h>
  16. #include <fcntl.h>
  17. #include <dirent.h>
  18.  
  19. /* Constants definides */
  20.  
  21. #define MAXLISTENERS 10
  22. #define MAXPETICIONS 15
  23. #define TAM_BUFFER 1024
  24. #define MAXCHAR 100
  25. #define NPORT 8080
  26.  
  27. /* Estructures de dades utilitzades */
  28.  
  29. typedef struct {
  30.     int idPet;
  31.     char uri[MAXCHAR];
  32. } tReq;
  33.  
  34. /* Variables globals */
  35.  
  36. pthread_mutex_t mutexPending = PTHREAD_MUTEX_INITIALIZER;
  37. pthread_cond_t noPlena = PTHREAD_COND_INITIALIZER, noBuida = PTHREAD_COND_INITIALIZER;
  38. tReq peticions[MAXPETICIONS];
  39. int in = 0, out = 0;
  40.  
  41. /* Tractament de les estructures de dades */
  42.  
  43. int queueSize () {
  44.     int i, size = 0;
  45.     for (i = 0; i < MAXPETICIONS; ++i) if (peticions[i].idPet != -1) ++size;
  46.     return(size);
  47. }
  48.  
  49. void recibirPeticion (int descriptor, char *uri) {
  50.     char buffer[TAM_BUFFER];
  51.     int i;
  52.     if (read(descriptor, &buffer, TAM_BUFFER) < 0) perror("Reading ERROR");
  53.     for (i = 5; buffer[i] != ' '; ++i) { /* Al caràcter 5 comencem a llegir el nom del recurs fins que trobem un espai */
  54.         uri[i-5] = buffer[i]; /* Copiem el nom del recurs demanat */
  55.     }
  56.     uri[i-5] = '\0';
  57. }
  58.  
  59. void atenderPeticion (int descriptor, char *nFichero) {
  60.     DIR *s;
  61.     int source, nBytes, n, p[2], folder = 1, i = 0; /* Per defecte tractem amb un directori */
  62.     char ext[MAXCHAR], file[MAXCHAR], aux[MAXCHAR], ls[TAM_BUFFER], buffer[TAM_BUFFER], h[MAXCHAR] = "HTTP/1.0 ";
  63.     if ((s = opendir(nFichero)) == NULL) folder = 0; /* No es tracta d'un directori, assumim que és un fitxer */
  64.     if (!folder) { /* Es tracta d'un fitxer */
  65.         if ((source = open(nFichero, O_RDONLY)) < 0) { /* Intentem obrir el fitxer en mode lectura */
  66.             perror("Opening File ERROR");
  67.             strcat(h, "404 File not found\nContent-Type: text/plain\n\nNo s'ha trobat el fitxer.");
  68.             if (write(descriptor, h, strlen(h)) < 0) perror("Writing to FD ERROR"); /* S'escriu la capçalera */
  69.         }
  70.         else { /* El fitxer és obert */
  71.             strcat(h, "200 OK\nContent-Type: ");
  72.             for (n = strlen(nFichero)-1; nFichero[n] != '.' && n >= 0; --n) { /* Mirem l'extensió del fitxer */
  73.                 aux[i] = nFichero[n];
  74.                 ++i;
  75.             }
  76.             aux[i] = '\0'; /* Col·loquem caràcter final de cadena */
  77.             i = 0; /* Reiniciem comptador */
  78.             for (n = strlen(aux)-1; n >= 0; --n) { /* Girem l'extensió del fitxer, la teniem invertida */
  79.                 ext[i] = aux[n];
  80.                 ++i;
  81.                 if (n == 0) ext[i] = '\0';
  82.             }
  83.             if (!strcmp(ext, "html") || !strcmp(ext, "htm")) strcat(h, "text/html\n\n"); /* Generem la capçalera amb l'extensió del fitxer */
  84.             else if (!strcmp(ext, "gif") || !strcmp(ext, "jpeg") || !strcmp(ext, "jpg") || !strcmp(ext, "png") || !strcmp(ext, "ico")) {
  85.                 if (!strcmp(ext, "ico")) strcat(h, "image/vnd.microsoft.icon\n\n"); /* Capçalera per icones */
  86.                 else {
  87.                     strcat(h, "image/"); strcat(h, ext); strcat(h, "\n\n"); /* Capçalera per altres imatges */
  88.                 }
  89.             }
  90.             else strcat(h, "text/plain\n\n");
  91.             if (write(descriptor, h, strlen(h)) < 0) perror ("Writing to FD ERROR"); /* Escribim la capçalera del fitxer */
  92.             while ((n = read(source, buffer, TAM_BUFFER)) > 0) { /* Mentre anem llegint dades */
  93.                 if (write(descriptor, buffer, n) < 0) { /* Escribim el fitxer obert al descriptor del socket */
  94.                     perror("Writing to FD ERROR");
  95.                     break;
  96.                 }
  97.                 buffer[0] = '\0'; /* Netegem el buffer */
  98.             }
  99.             close(source); /* Tanquem el fitxer */
  100.         }
  101.     }
  102.     else { /* Es tracta d'un directori */
  103.         closedir(s); /* Tanquem el directori */
  104.         pipe(p); /* Creem el pipe de comunicació Fill-Pare */
  105.         strcat(h, "200 OK\nContent-Type: text/html\n\n"); /* Generem la capçalera HTML per directoris */
  106.         if (write(descriptor, h, strlen(h)) < 0) perror("Writing to FD ERROR"); /* S'escriu la capçalera */
  107.         if ((n = fork()) <= 0) { /* Procés fill */
  108.             if (n < 0) perror("Can't create process");
  109.             close(p[0]); close(1); dup(p[1]); close(p[1]); /* Redirigim el pipe p a la sortida estàndard */
  110.             execlp("ls", "ls", nFichero, NULL); /* A la sortida estàndard obtindrem la sortida del 'ls nFichero' */
  111.         }
  112.         else { /* Procés pare */
  113.             close(p[1]); /* Tanquem l'extrem del pipe que no utilitzem */
  114.             nBytes = read(p[0], ls, TAM_BUFFER); /* Llegim l'extrem del pipe el contingut del ls */
  115.             close(p[0]); /* Un cop llegit el pipe: el tanquem */
  116.             if (nFichero[strlen(nFichero)-1] != '/') strcat(nFichero, "/"); /* Si nFichero no acaba en '/' (directori), ho afegim */
  117.             strcpy(aux, nFichero);
  118.             while (sscanf(ls, "%s\n", file) == 1) { /* Mentre no arribem a final d'stream (buffer) */
  119.                 strcat(aux, file);
  120.                 sprintf(buffer, "<A HREF=\"http://127.0.0.1:%d/%s\">%s</A><BR>\n", NPORT, aux, file); /* Afegim al buffer la direcció */
  121.                 strcpy(aux, nFichero);
  122.                 if (write(descriptor, buffer, strlen(buffer)) < 0) {
  123.                     perror("Writing to FD ERROR");
  124.                     break;
  125.                 }
  126.                 buffer[0] = '\0'; /* Netegem el buffer */
  127.                 for (i = 0; ls[i] != '\n'; ++i) { /* Netegem l'element llegit del buffer ls */
  128.                     if (ls[i] != ' ') ls[i] = ' ';
  129.                 }
  130.                 ls[i] = ' ';
  131.                 file[0] = '\0'; /* Netegem la cadena que conté el nom del fitxer */
  132.             }
  133.         }
  134.     }
  135.     close(descriptor); /* Un cop atesa la petició, tanquem el descriptor del socket */
  136. }
  137.  
  138. /* Programa principal */
  139.  
  140. void *thServer (void *n) { /* Thread d'atenció */
  141.     char recurs[MAXCHAR];
  142.     int descriptor;
  143.     while (1) { /* Bucle infinit */
  144.         int i;
  145.         pthread_mutex_lock(&mutexPending); /* Entrem a la secció crítica */
  146.         while (queueSize() == 0) pthread_cond_wait(&noBuida, &mutexPending); /* Cua de peticions buida */
  147.         descriptor = peticions[out%MAXPETICIONS].idPet;
  148.         strcpy(recurs, peticions[out%MAXPETICIONS].uri);
  149.         peticions[out%MAXPETICIONS].idPet = -1; /* Netegem la petició */
  150.         peticions[out%MAXPETICIONS].uri[0] = '\0';
  151.         ++out; /* Atendre petició, consumir */
  152.         pthread_mutex_unlock(&mutexPending); /* Fi de la secció crítica */
  153.         pthread_cond_signal(&noPlena); /* S'ha atés una petició, la cua no pot estar plena */
  154.         atenderPeticion(descriptor, recurs); /* La petició és atesa fora de la secció crítica */
  155.     }
  156.     pthread_exit(0);
  157. }
  158.  
  159. int main () { /* Procés servidor: productor de peticions */
  160.     int i, addrlen, addr_cli, dSocket, newSocket;
  161.     struct sockaddr_in addr_srv;
  162.     pthread_t server[MAXLISTENERS];
  163.     addr_srv.sin_family = AF_INET; /* Utilitzem la família AF_INET */
  164.     addr_srv.sin_addr.s_addr = INADDR_ANY; /* Loopback */
  165.     addr_srv.sin_port = htons(NPORT); /* Escoltarem el port definit */
  166.     for (i = 0; i < MAXPETICIONS; ++i) peticions[i].idPet = -1; /* Inicialitzem la cua de peticions */
  167.     for (i = 0; i < MAXLISTENERS; ++i) pthread_create(&server[i], NULL, thServer, (void*)i); /* Creem els processos servidors de peticions */
  168.     if ((dSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0) { /* El procés servidor intenta crear el socket */
  169.         perror("ERROR al crear el socket.\n");
  170.         return(-1);
  171.     }
  172.     if (bind(dSocket, (struct sockaddr *) &addr_srv, sizeof(addr_srv)) < 0) {
  173.         perror("Binding ERROR.\n");
  174.         return(-1);
  175.     }
  176.     if (listen(dSocket, 5) < 0) {
  177.         perror("Listening ERROR.\n");
  178.         return(-1);
  179.     }
  180.     while (1) { /* Bucle infinit */
  181.         addrlen = sizeof(addr_cli);
  182.         i = accept(dSocket, (struct sockaddr *) &addr_cli, &addrlen); /* Bloqueja el procés servidor si no s'accepta cap petició (fora de la secció crítica) */
  183.         pthread_mutex_lock(&mutexPending); /* Entrem a la secció crítica */
  184.         while (queueSize(peticions) == MAXPETICIONS) pthread_cond_wait(&noPlena, &mutexPending); /* Cua de peticions plena */
  185.         peticions[in%MAXPETICIONS].idPet = i; /* Assignem el valor de l'identificador de la petició */
  186.         recibirPeticion(peticions[in%MAXPETICIONS].idPet, peticions[in%MAXPETICIONS].uri);
  187.         ++in; /* Llegir la petició de l'entrada, produir */
  188.         pthread_mutex_unlock(&mutexPending); /* Fi de la secció crítica */
  189.         pthread_cond_broadcast(&noBuida); /* S'ha rebut una petició, la cua no pot ser buida */
  190.     }
  191.     return(0); /* No esperem finalització de threads ni tanquem sockets perquè no s'arriba a sortir del bucle */
  192. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement