Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /********************************************************************
- * Alumnes: Octavi Allué Fonoll (1224997) *
- * Pràctica SO: threads i sockets, segón quatrimestre *
- ********************************************************************/
- /* Llibreries incloses */
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <netdb.h>
- #include <unistd.h>
- #include <stdio.h>
- #include <pthread.h>
- #include <string.h>
- #include <fcntl.h>
- #include <dirent.h>
- /* Constants definides */
- #define MAXLISTENERS 10
- #define MAXPETICIONS 15
- #define TAM_BUFFER 1024
- #define MAXCHAR 100
- #define NPORT 8080
- /* Estructures de dades utilitzades */
- typedef struct {
- int idPet;
- char uri[MAXCHAR];
- } tReq;
- /* Variables globals */
- pthread_mutex_t mutexPending = PTHREAD_MUTEX_INITIALIZER;
- pthread_cond_t noPlena = PTHREAD_COND_INITIALIZER, noBuida = PTHREAD_COND_INITIALIZER;
- tReq peticions[MAXPETICIONS];
- int in = 0, out = 0;
- /* Tractament de les estructures de dades */
- int queueSize () {
- int i, size = 0;
- for (i = 0; i < MAXPETICIONS; ++i) if (peticions[i].idPet != -1) ++size;
- return(size);
- }
- void recibirPeticion (int descriptor, char *uri) {
- char buffer[TAM_BUFFER];
- int i;
- if (read(descriptor, &buffer, TAM_BUFFER) < 0) perror("Reading ERROR");
- for (i = 5; buffer[i] != ' '; ++i) { /* Al caràcter 5 comencem a llegir el nom del recurs fins que trobem un espai */
- uri[i-5] = buffer[i]; /* Copiem el nom del recurs demanat */
- }
- uri[i-5] = '\0';
- }
- void atenderPeticion (int descriptor, char *nFichero) {
- DIR *s;
- int source, nBytes, n, p[2], folder = 1, i = 0; /* Per defecte tractem amb un directori */
- char ext[MAXCHAR], file[MAXCHAR], aux[MAXCHAR], ls[TAM_BUFFER], buffer[TAM_BUFFER], h[MAXCHAR] = "HTTP/1.0 ";
- if ((s = opendir(nFichero)) == NULL) folder = 0; /* No es tracta d'un directori, assumim que és un fitxer */
- if (!folder) { /* Es tracta d'un fitxer */
- if ((source = open(nFichero, O_RDONLY)) < 0) { /* Intentem obrir el fitxer en mode lectura */
- perror("Opening File ERROR");
- strcat(h, "404 File not found\nContent-Type: text/plain\n\nNo s'ha trobat el fitxer.");
- if (write(descriptor, h, strlen(h)) < 0) perror("Writing to FD ERROR"); /* S'escriu la capçalera */
- }
- else { /* El fitxer és obert */
- strcat(h, "200 OK\nContent-Type: ");
- for (n = strlen(nFichero)-1; nFichero[n] != '.' && n >= 0; --n) { /* Mirem l'extensió del fitxer */
- aux[i] = nFichero[n];
- ++i;
- }
- aux[i] = '\0'; /* Col·loquem caràcter final de cadena */
- i = 0; /* Reiniciem comptador */
- for (n = strlen(aux)-1; n >= 0; --n) { /* Girem l'extensió del fitxer, la teniem invertida */
- ext[i] = aux[n];
- ++i;
- if (n == 0) ext[i] = '\0';
- }
- if (!strcmp(ext, "html") || !strcmp(ext, "htm")) strcat(h, "text/html\n\n"); /* Generem la capçalera amb l'extensió del fitxer */
- else if (!strcmp(ext, "gif") || !strcmp(ext, "jpeg") || !strcmp(ext, "jpg") || !strcmp(ext, "png") || !strcmp(ext, "ico")) {
- if (!strcmp(ext, "ico")) strcat(h, "image/vnd.microsoft.icon\n\n"); /* Capçalera per icones */
- else {
- strcat(h, "image/"); strcat(h, ext); strcat(h, "\n\n"); /* Capçalera per altres imatges */
- }
- }
- else strcat(h, "text/plain\n\n");
- if (write(descriptor, h, strlen(h)) < 0) perror ("Writing to FD ERROR"); /* Escribim la capçalera del fitxer */
- while ((n = read(source, buffer, TAM_BUFFER)) > 0) { /* Mentre anem llegint dades */
- if (write(descriptor, buffer, n) < 0) { /* Escribim el fitxer obert al descriptor del socket */
- perror("Writing to FD ERROR");
- break;
- }
- buffer[0] = '\0'; /* Netegem el buffer */
- }
- close(source); /* Tanquem el fitxer */
- }
- }
- else { /* Es tracta d'un directori */
- closedir(s); /* Tanquem el directori */
- pipe(p); /* Creem el pipe de comunicació Fill-Pare */
- strcat(h, "200 OK\nContent-Type: text/html\n\n"); /* Generem la capçalera HTML per directoris */
- if (write(descriptor, h, strlen(h)) < 0) perror("Writing to FD ERROR"); /* S'escriu la capçalera */
- if ((n = fork()) <= 0) { /* Procés fill */
- if (n < 0) perror("Can't create process");
- close(p[0]); close(1); dup(p[1]); close(p[1]); /* Redirigim el pipe p a la sortida estàndard */
- execlp("ls", "ls", nFichero, NULL); /* A la sortida estàndard obtindrem la sortida del 'ls nFichero' */
- }
- else { /* Procés pare */
- close(p[1]); /* Tanquem l'extrem del pipe que no utilitzem */
- nBytes = read(p[0], ls, TAM_BUFFER); /* Llegim l'extrem del pipe el contingut del ls */
- close(p[0]); /* Un cop llegit el pipe: el tanquem */
- if (nFichero[strlen(nFichero)-1] != '/') strcat(nFichero, "/"); /* Si nFichero no acaba en '/' (directori), ho afegim */
- strcpy(aux, nFichero);
- while (sscanf(ls, "%s\n", file) == 1) { /* Mentre no arribem a final d'stream (buffer) */
- strcat(aux, file);
- sprintf(buffer, "<A HREF=\"http://127.0.0.1:%d/%s\">%s</A><BR>\n", NPORT, aux, file); /* Afegim al buffer la direcció */
- strcpy(aux, nFichero);
- if (write(descriptor, buffer, strlen(buffer)) < 0) {
- perror("Writing to FD ERROR");
- break;
- }
- buffer[0] = '\0'; /* Netegem el buffer */
- for (i = 0; ls[i] != '\n'; ++i) { /* Netegem l'element llegit del buffer ls */
- if (ls[i] != ' ') ls[i] = ' ';
- }
- ls[i] = ' ';
- file[0] = '\0'; /* Netegem la cadena que conté el nom del fitxer */
- }
- }
- }
- close(descriptor); /* Un cop atesa la petició, tanquem el descriptor del socket */
- }
- /* Programa principal */
- void *thServer (void *n) { /* Thread d'atenció */
- char recurs[MAXCHAR];
- int descriptor;
- while (1) { /* Bucle infinit */
- int i;
- pthread_mutex_lock(&mutexPending); /* Entrem a la secció crítica */
- while (queueSize() == 0) pthread_cond_wait(&noBuida, &mutexPending); /* Cua de peticions buida */
- descriptor = peticions[out%MAXPETICIONS].idPet;
- strcpy(recurs, peticions[out%MAXPETICIONS].uri);
- peticions[out%MAXPETICIONS].idPet = -1; /* Netegem la petició */
- peticions[out%MAXPETICIONS].uri[0] = '\0';
- ++out; /* Atendre petició, consumir */
- pthread_mutex_unlock(&mutexPending); /* Fi de la secció crítica */
- pthread_cond_signal(&noPlena); /* S'ha atés una petició, la cua no pot estar plena */
- atenderPeticion(descriptor, recurs); /* La petició és atesa fora de la secció crítica */
- }
- pthread_exit(0);
- }
- int main () { /* Procés servidor: productor de peticions */
- int i, addrlen, addr_cli, dSocket, newSocket;
- struct sockaddr_in addr_srv;
- pthread_t server[MAXLISTENERS];
- addr_srv.sin_family = AF_INET; /* Utilitzem la família AF_INET */
- addr_srv.sin_addr.s_addr = INADDR_ANY; /* Loopback */
- addr_srv.sin_port = htons(NPORT); /* Escoltarem el port definit */
- for (i = 0; i < MAXPETICIONS; ++i) peticions[i].idPet = -1; /* Inicialitzem la cua de peticions */
- for (i = 0; i < MAXLISTENERS; ++i) pthread_create(&server[i], NULL, thServer, (void*)i); /* Creem els processos servidors de peticions */
- if ((dSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0) { /* El procés servidor intenta crear el socket */
- perror("ERROR al crear el socket.\n");
- return(-1);
- }
- if (bind(dSocket, (struct sockaddr *) &addr_srv, sizeof(addr_srv)) < 0) {
- perror("Binding ERROR.\n");
- return(-1);
- }
- if (listen(dSocket, 5) < 0) {
- perror("Listening ERROR.\n");
- return(-1);
- }
- while (1) { /* Bucle infinit */
- addrlen = sizeof(addr_cli);
- 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) */
- pthread_mutex_lock(&mutexPending); /* Entrem a la secció crítica */
- while (queueSize(peticions) == MAXPETICIONS) pthread_cond_wait(&noPlena, &mutexPending); /* Cua de peticions plena */
- peticions[in%MAXPETICIONS].idPet = i; /* Assignem el valor de l'identificador de la petició */
- recibirPeticion(peticions[in%MAXPETICIONS].idPet, peticions[in%MAXPETICIONS].uri);
- ++in; /* Llegir la petició de l'entrada, produir */
- pthread_mutex_unlock(&mutexPending); /* Fi de la secció crítica */
- pthread_cond_broadcast(&noBuida); /* S'ha rebut una petició, la cua no pot ser buida */
- }
- return(0); /* No esperem finalització de threads ni tanquem sockets perquè no s'arriba a sortir del bucle */
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement