From a72f0a0fad1361fc5f507cbbba59fa5bfa98a877 Mon Sep 17 00:00:00 2001 From: elvis Date: Tue, 15 Mar 2022 00:30:04 +0100 Subject: [PATCH] Added file queue handling --- config.ini | 7 +- lib/threadpool/fileQueue.c | 726 +++++++++++++++++++++++++++++++++++++ lib/threadpool/fileQueue.h | 224 ++++++++++++ lib/utils/serverStatus.h | 16 - lib/utils/serverUtil.h | 18 + lib/utils/util.h | 19 - src/server.c | 34 +- 7 files changed, 993 insertions(+), 51 deletions(-) create mode 100644 lib/threadpool/fileQueue.c create mode 100644 lib/threadpool/fileQueue.h delete mode 100644 lib/utils/serverStatus.h create mode 100644 lib/utils/serverUtil.h diff --git a/config.ini b/config.ini index b5ff269..b7f2f21 100644 --- a/config.ini +++ b/config.ini @@ -1,3 +1,8 @@ [threadpool] -quantity = 10 \ No newline at end of file +quantity = 10 + +[files] + +MaxFiles = 20 +MaxSize = 10000000 \ No newline at end of file diff --git a/lib/threadpool/fileQueue.c b/lib/threadpool/fileQueue.c new file mode 100644 index 0000000..16d3fde --- /dev/null +++ b/lib/threadpool/fileQueue.c @@ -0,0 +1,726 @@ +#include +#include + +#define NAMELEN 256 + +// creazione di un fileT +fileT* createFileT(char *f, int O_LOCK, int client, int open){ + if(!f){ + errno = EINVAL; + return NULL; + } + + fileT *file = malloc(sizeof(fileT)); + + if (f == NULL) { + perror("Malloc createFileT"); + return NULL; + } + + f->O_LOCK = (O_LOCK == 0)? 0 : 1; + f->owner = client; + f->open = (open == 0)? 0 : 1; + f->size = 0; + + if ((f->filepath = malloc(sizeof(char)*NAMELEN)) == NULL) { + perror("Malloc filepath"); + destroyFile(f); + return NULL; + } + + strncpy(f->filepath, f, NAMELEN); + + if ((f->data = malloc(1)) == NULL) { // così semplicemente facciamo realloc + perror("Malloc content"); + return NULL; + } + return f; +} + +// append su fileT +int writeFileT(fileT *f, void *data, size_t size) { + if(!f || !data || size < 0){ + errno = EINVAL; + return -1; + } + + if ((f->data = realloc(f->data, f->size + size)) == NULL) { + perror("Realloc content"); + return -1; + } + + memcpy((char*) f->data + f->size, data, size); + f->size = f->size + size; +} + +// destroy fileT +void destroyFile(fileT *f) { + if(!f) + return; + if(f->filepath) + free(f->filepath); + if(f->data) + free(f->data); + free(f); +} + +// -------------- + +// creazione queue +queueT* createQueue(size_t maxLen, size_t maxSize) { + if(maxLen<0 || maxSize<0){ + errno = EINVAL; + return NULL; + } + + queueT *q = malloc(sizeof(queueT)); + if(q==NULL){ + perror("Malloc createQueue"); + return NULL; + } + + // creazione lock + if (pthread_mutex_init(&q->m, NULL) != 0) { + perror("pthread_mutex_init createQueue"); + destroyQueue(q); + return NULL; + } + + q->head = NULL; + q->tail = NULL; + q->maxLen = maxLen; + q->len = 0; + q->maxSize = maxSize; + q->size = 0; + + return q; +} + +// insert +int enqueue(queueT *q, fileT* data) { + if(!q || !data){ + errno = EINVAL; + return -1; + } + + LOCK_RETURN(&q->m, -1); // begin me + + if (q->len == q->maxLen) { // too many files + errno = ENFILE; + goto _end_enqueue; + } + + if (q->size + data->size > q->maxSize) { + errno = EFBIG; + goto _end_enqueue; + } + + // inserisco l'elemento + nodeT *newNode = malloc(sizeof(nodeT)); + if (newNode == NULL) { + perror("malloc newNode"); + goto _end_enqueue; + } + + newNode->data = data; + newNode->next = NULL; + nodeT *tmp = queue->head; + + if (q->head == NULL) + q->head = newNode; + else { + while (tmp->next) + tmp = temp->next; + + temp->next = newNode; + } + + q->tail = newNode; + + ++q->len; + q->size += data->size; + + + UNLOCK_RETURN(&q->m, -1); // end me + return 0; + +_end_enqueue: + UNLOCK_RETURN(&q->m, -1); + return -1; +} + +// remove +fileT* dequeue(queueT *q) { + if(!q) { + errno = EINVAL; + return NULL; + } + + LOCK_RETURN(&q->m, NULL); // begin me + + if (q->head == NULL || q->len == 0) { // coda vuota + errno = ENOENT; + goto _end_dequeue; + } + + fileT *data = (q->head)->data; + + nodeT *tmp = NULL; + tmp = q->head; + q->head = (q->head)->next; + + if (q->head == NULL) { // coda diventa vuota + q->tail = NULL; + } + + --q->len; + q->size -= data->size; + free(tmp); // free del nodo + + UNLOCK_RETURN(&q->m, NULL); // end me + return data; + +_end_dequeue: + UNLOCK_RETURN(&q->m, NULL); + return NULL; +} + +void voidDequeue(queueT *q) { + if(!q) { + errno = EINVAL; + return; + } + + LOCK(&q->m); // begin me + + if (q->head == NULL || q->len == 0) { // coda vuota + errno = ENOENT; + goto _end_void_dequeue; + } + + nodeT *tmp = NULL; + tmp = q->head; + + q->head = (q->head)->next; + + if (q->head == NULL) { // coda diventa vuota + q->tail = NULL; + } + + --q->len; + q->size -= data->size; + + destroyFile(tmp->data); // free fileT + free(tmp); // free nodo + + UNLOCK(&q->m); // end me + return; + +_end_void_dequeue: + UNLOCK_RETURN(&q->m, NULL); + return NULL; +} + +// print queue +int printQueue(FILE *stream, queueT *q) { + if(!q || !stream) { + errno = EINVAL; + return -1; + } + + LOCK_RETURN(&q->m, -1); // begin me + + UNLOCK_RETURN(&q->m, -1); + return 0; + + nodeT *tmp = q->head; + + fprintf(stream, "Lista file:"); + fprintf(stream, "[Nome File] -> Dimensione in MB"); + while (temp!=NULL) { + float res = ((float)(tmp->data)->size)/1000000; // in MB + fprintf(stream, "[%s]\t-> %f MB\n", (tmp->data)->filepath, res); + temp = temp->next; + } + + UNLOCK_RETURN(&q->m, -1); // end me + return 0; + +_end_print_queue: + UNLOCK_RETURN(&q->m, -1); + return -1; +} + +// acquisizione lock +int lockFileInQueue(queueT *q, char *filepath, int owner) { + if(!q || !filepath) { + errno = EINVAL; + return -1; + } + + LOCK_RETURN(&q->m, -1); // begin me + + if (q->len == 0) { + errno = ENOENT; + goto _end_lock_file_queue; + } + + // scorro la queue per trovare l'elemento + nodeT *tmp = q->head; + + while (tmp) { + if (strcmp(filepath, (tmp->data)->filepath) == 0) { // trovato + break; + } + tmp = tmp->next; + } + + if(!tmp) { // non trovato + errno = ENOENT; + goto _end_lock_file_queue; + } + + if ((tmp->data)->O_LOCK && (tmp->data)->owner != owner) { // lock non del owner + errno = EPERM; + goto _end_lock_file_queue; + } + + // acquisisco lock sul file + (temp->data)->O_LOCK = 1; + (temp->data)->owner = owner; + + UNLOCK_RETURN(&q->m, -1); // end me + return 0; + +_end_lock_file_queue: + UNLOCK_RETURN(&q->m, -1); + return -1; +} + + +int unlockFileInQueue(queueT *q, char *filepath, int owner) { + if(!q || !filepath) { + errno = EINVAL; + return -1; + } + + LOCK_RETURN(&q->m, -1); // begin me + + if (q->len == 0) { + errno = ENOENT; + goto _end_unlock_file_queue; + } + + // scorro la queue per trovare l'elemento + nodeT *tmp = q->head; + + while (tmp) { + if (strcmp(filepath, (tmp->data)->filepath) == 0) { // trovato + break; + } + tmp = tmp->next; + } + + if(!tmp) { // non trovato + errno = ENOENT; + goto _end_lock_file_queue; + } + + if((tmp->data)->O_LOCK == 0) { // nessuno ha il lock + UNLOCK_RETURN(&q->m, -1); + return 0; + } + + if((tmp->data)->O_LOCK == 1 && (tmp->data)->owner != owner) { // lock non del owner + errno = EPERM; + goto _end_unlock_file_queue; + } + + (tmp->data)->O_LOCK = 0; + + UNLOCK_RETURN(&q->m, -1); // end me + return 0; + +_end_unlock_file_queue: + UNLOCK_RETURN(&q->m, -1); + return -1; +} + + +// open file +int openFileInQueue(queueT *q, char *filepath, int O_LOCK, int owner) { + if(!q || !filepath) { + errno = EINVAL; + return -1; + } + + LOCK_RETURN(&q->m, -1); // begin me + + if (q->len == 0) { + errno = ENOENT; + goto _end_open_file_queue; + } + + // scorro la queue per trovare l'elemento + nodeT *tmp = q->head; + while (tmp) { + if (strcmp(filepath, (tmp->data)->filepath) == 0) { // trovato + break; + } + tmp = tmp->next; + } + + if(!tmp) { // non trovato + errno = ENOENT; + goto _end_open_file_queue; + } + + if((tmp->data)->O_LOCK == 1 && (tmp->data)->owner != owner) { // lock non del owner + errno = EPERM; + goto _end_open_file_queue; + } + + (tmp->data)->open = 1; + (tmp->data)->O_LOCK = (O_LOCK==0)?0:1; + + if(O_LOCK!=0) { + (tmp->data)->owner = client; + } + + UNLOCK_RETURN(&q->m, -1); // end me + return 0; + +_end_open_file_queue: + UNLOCK_RETURN(&q->m, -1); + return -1; +} + +// close and relese lock +int closeFileInQueue(queueT *q, char *filepath, int owner) { + if(!q || !filepath) { + errno = EINVAL; + return -1; + } + + LOCK_RETURN(&q->m, -1); // begin me + + if (q->len == 0) { + errno = ENOENT; + goto _end_close_file_queue; + } + + // scorro la queue per trovare l'elemento + nodeT *tmp = q->head; + while (tmp) { + if (strcmp(filepath, (tmp->data)->filepath) == 0) { // trovato + break; + } + tmp = tmp->next; + } + + if(!tmp) { // non trovato + errno = ENOENT; + goto _end_close_file_queue; + } + + if((tmp->data)->O_LOCK == 1 && (tmp->data)->owner != owner) { // lock non del owner + errno = EPERM; + goto _end_close_file_queue; + } + + (tmp->data)->open = 0; + (tmp->data)->O_LOCK = 0; + (tmp->data)->owner = owner; + + UNLOCK_RETURN(&q->m, -1); // end me + return 0; + +_end_open_file_queue: + UNLOCK_RETURN(&q->m, -1); + return -1; +} + + +int writeFileInQueue(queueT *q, char *filepath, void *data, size_t size, int owner) { + if(!q || !filepath || !data) { + errno = EINVAL; + return -1; + } + + if(size == 0) + return 0; + + LOCK_RETURN(&q->m, -1); // begin me + + if (q->len == 0) { // coda vuota + errno = ENOENT; + goto _end_write_file_queue; + } + + if (q->size + size > q->maxSize) { // non c'e' abbastanza spazio + errno = EFBIG; + goto _end_write_file_queue; + } + + // scorro la queue per trovare l'elemento + nodeT *tmp = q->head; + while (tmp) { + if (strcmp(filepath, (tmp->data)->filepath) == 0) { // trovato + break; + } + tmp = tmp->next; + } + + if(!tmp) { // non trovato + errno = ENOENT; + goto _end_write_file_queue; + } + + if ((tmp->data)->open == 0 || ((tmp->data)->O_LOCK && (tmp->data)->owner != owner)) { + // if file non è aperto o la lock non è del owner + errno = EPERM; + goto _end_write_file_queue; + } + + // scrivo + if (((tmp->data)->data = realloc((tmp->data)->data, (tmp->data)->size + size)) == NULL) { + perror("Realloc content"); + goto _end_write_file_queue; + } + memcpy((tmp->data)->data, data, size); + + q->size = (q->size) - ((tmp->data)->size) + size; + (tmp->data)->size = size; + + UNLOCK_RETURN(&q->m, -1); // end me + return 0; + +_end_write_file_queue: + UNLOCK_RETURN(&q->m, -1); + return -1; +} + + +int appendFileInQueue(queueT *q, char *filepath, void *data, size_t size, int owner) { + if (!q || !filepath || !data) { + errno = EINVAL; + return -1; + } + if (size == 0) + return 0; + + LOCK_RETURN(&q->m, -1); // begin me + + if (q->len == 0) { // coda vuota + errno = ENOENT; + goto _end_append_file_queue; + } + + if (q->size + size > q->maxSize) { // non c'e' abbastanza spazio + errno = EFBIG; + goto _end_append_file_queue; + } + + // scorro la queue per trovare l'elemento + nodeT *tmp = q->head; + while (tmp) { + if (strcmp(filepath, (tmp->data)->filepath) == 0) { // trovato + break; + } + tmp = tmp->next; + } + + if(!tmp) { // non trovato + errno = ENOENT; + goto _end_append_file_queue; + } + + if ((tmp->data)->open == 0 || ((tmp->data)->O_LOCK && (tmp->data)->owner != owner)) { + // if file non è aperto o la lock non è del owner + errno = EPERM; + goto _end_append_file_queue; + } + + // scrivo + if (((tmp->data)->data = realloc((tmp->data)->data, (tmp->data)->size + size)) == NULL) { + perror("Realloc content"); + goto _end_append_file_queue; + } + + memcpy(((tmp->data)->data) + (tmp->data)->size, data, size); + // memmove sarebbe un'alternativa + (tmp->data)->size += size; + q->size += size; + + UNLOCK_RETURN(&q->m, -1); // end me + return 0; + +_end_append_file_queue: + UNLOCK_RETURN(&q->m, -1); + return -1; +} + + +int removeFileFromQueue(queueT *q, char *filepath, int owner) { + if(!q || !filepath) { + errno = EINVAL; + return -1; + } + + LOCK_RETURN(&q->m, -1); // begin me + + if (q->len == 0) { // coda vuota + errno = ENOENT; + goto _end_remove_file_queue; + } + + // scorro la queue per trovare l'elemento + nodeT *tmp = q->head; + nodeT *pre = q->head; + while (tmp) { + if (strcmp(filepath, (tmp->data)->filepath) == 0) { // trovato + break; + } + if(prc!=tmp) + prc = prc->next; + tmp = tmp->next; + } + + if (!tmp) { // non trovato + errno = ENOENT; + goto _end_remove_file_queue; + } + + if ((tmp->data)->open != 0 || ((tmp->data)->O_LOCK && (tmp->data)->owner != owner)) { + // if file è aperto o la lock non è del owner + errno = EPERM; + goto _end_append_file_queue; + } + + if (tmp == prc) { // file è il primo + q->head = tmp->next; + + if (tmp->next == NULL) { + q->tail = tmp; + } + } else { // file non è il primo + prc->next = tmp->next; + + if (prc->next == NULL) { + q->tail = prc; + } + } + + --q->len; + q->size -= (tmp->data)->size; + destroyFile(tmp->data); // free file + free(tmp); // free node + + UNLOCK_RETURN(&q->m, -1); // end me + return 0; + +_end_remove_file_queue: + UNLOCK_RETURN(&q->m, -1); + return -1; +} + + +// ---------------- + +// cerco e ritorno una copia +fileT* find(queueT *q, char *filepath) { + if(!q || !filepath) { + errno = EINVAL; + return NULL; + } + + LOCK_RETURN(&q->m, NULL); // begin me + + if (q->len == 0) + goto _end_find_in_queue; + + fileT *res = NULL; + nodeT *tmp = q->head; + + while (tmp) { + if (strcmp(filepath, (tmp->data)->filepath) == 0) { // trovato + break; + } + tmp = tmp->next; + } + + if(!tmp) + goto _end_find_in_queue; + + // creo una nuova istanza + res = createFileT((tmp->data)->filepath, (tmp->data)->O_LOCK, (tmp->data)->owner, (tmp->data)->open); + + if (!res) { + perror("createFileT res"); + goto _end_find_in_queue; + } + + if (writeFileT(res, (tmp->data)->data, (tmp->data)->size) == -1) { + perror("writeFileT res"); + goto _end_find_in_queue; + } + + UNLOCK_RETURN(&q->m, NULL); // end me + return res; + +_end_find_in_queue: + UNLOCK_RETURN(&q->m, NULL); + return NULL; +} + +// numero di elementi della queue +size_t getLen(queueT *q) { + if(!q) { + errno = EINVAL; + return -1; + } + size_t len = -1; + + LOCK_RETURN(&q->m, -1); // begin me + + len = queue->len; + + UNLOCK_RETURN(&q->m, -1); // end me + return len; +} + +// dimensione in byte +size_t getSize(queueT *q) { + if(!q) { + errno = EINVAL; + return -1; + } + size_t size = -1; + + LOCK_RETURN(&q->m, -1); // begin me + + size = q->size; + + UNLOCK_RETURN(&q->m, -1); // end me + return size; +} + +void destroyQueue(queueT *q) { + if(!q) + return; + + // no need for lock over queue + while (q->len > 0) { + errno = 0; + voiDequeue(q); + if (errno) { + perror("voiDequeue"); + } + } + + if (&queue->m) { + pthread_mutex_destroy(&q->m); + } + + free(queue); +} diff --git a/lib/threadpool/fileQueue.h b/lib/threadpool/fileQueue.h new file mode 100644 index 0000000..7cb8d05 --- /dev/null +++ b/lib/threadpool/fileQueue.h @@ -0,0 +1,224 @@ +#pragma once +#ifndef _FILE_QUEUE +#define _FILE_QUEUE + + +// struttura dati per gestire i file in memoria principale +typedef struct { + char *filepath; // path assoluto del file + int O_LOCK; // 1 se il file e' in modalita' locked + int owner; // client che possiede la lock sul file + int open; // 1 se il file e' aperto + void *data; // contenuto del file + size_t size; // dimensione del file in bytes +} fileT; + +// nodo di una linked list +typedef struct node { + fileT *data; + struct node *next; +} nodeT; + +// coda FIFO +typedef struct { + nodeT *head; // puntatore al primo elemento + nodeT *tail; // puntatore all'ultimo elemento + size_t maxLen; // numero massimo di elementi + size_t len; // numero attuale di elementi + size_t maxSize; // dimensione massima + size_t size; // dimensione attuale + pthread_mutex_t m; // lock sulla coda +} queueT; + + + +/** + * Creazione di un fileT. + * \param f: string che identifica il fileT tramite il suo path assoluto + * \param O_LOCK: 1 locked, 0 unlocked + * \param client: client associato + * \param open: apertura del file dopo la creazione + * + * \retval puntatore al fileT, NULL se errore (errno) + */ +fileT* createFileT(char *f, int O_LOCK, int client, int open); + +/** + * Append su un fileT. + * \param f: fileT sul quale scrivere + * \param data: puntatore al buffer da scrivere + * \param size: dimensione in bytes del buffer + * + * \retval 0 se successo, -1 se errore (errno) + */ +int writeFileT(fileT *f, void *data, size_t size); + +/** + * Rimozione di un fileT. + * \param f + */ +void destroyFile(fileT *f); + + + +/** + * Alloca ed inizializza una coda di fileT. Deve essere chiamata da un solo + * thread. + * \param maxLen: lunghezza massima della coda + * \param maxSize: dimensione massima della coda in bytes + * + * \retval puntatore alla coda allocata, NULL se errore + */ +queueT* createQueue(size_t maxLen, size_t maxSize); + +/** + * Inserisce un fileT nella coda. + * \param q: puntatore alla coda + * \param data: puntatore al fileT da inserire + * + * \retval 0 se successo, -1 se errore (errno) + */ +int enqueue(queueT *q, fileT* data); + +/** + * Estrae un fileT dalla coda. + * \param q: puntatore alla coda + * + * \retval puntatore al file estratto, NULL se errore + */ +fileT* dequeue(queueT *q); + +/** + * Estrae un fileT dalla coda come la dequeue, ma invece di restituire il + * file estratto lo distrugge immediatamente, liberandone la memoria. + * + * \param q: puntatore alla coda + */ +void voidDequeue(queueT *q); + +/** + * Stampa l'intero contenuto della coda. + * \param stream: file su cui stampare + * \param q: puntatore alla coda da stampare + * + * \retval 0 se successo, -1 se errore (errno) + */ +int printQueue(FILE *stream, queueT *q); + + + +/** + * Cerca di ottenere il lock su un fileT, fallisce se un altro client ha gia' + * richiesto la lock + * \param q: puntatore alla coda che contiene il fileT + * \param filepath: path assoluto (identificatore) del fileT + * \param owner: client che ha richiesto l'operazione + * + * \retval 0 se successo, -1 se errore (errno) + */ +int lockFileInQueue(queueT *q, char *filepath, int owner); + +/** + * Rilascia il lock di un file, fallisce se non si e' il possessore del lock + * \param q: puntatore alla coda che contiene il fileT + * \param filepath -> path assoluto (identificatore) del fileT + * \param owner -> client che ha richiesto l'operazione + * + * \retval 0 se successo, -1 se errore (errno) + */ +int unlockFileInQueue(queueT *q, char *filepath, int owner); + +/** + * Apre un fileT contenuto nella coda. Fallisce se il lock appartiene a un + * client diverso. + * \param q: puntatore alla coda che contiene il fileT da aprire + * \param filepath: path assoluto (identificatore) del fileT da aprire + * \param O_LOCK: 1 locked, 0 unlocked + * \param owner: client che ha richiesto l'apertura + * + * \retval 0 se successo, -1 se errore (errno) + */ +int openFileInQueue(queueT *q, char *filepath, int O_LOCK, int owner); + +/** + * Chiude un file contenuto nella coda. Ha successo se fileT non e' stato aperto. + * Fallisce se il file e' stato messo in modalita' locked da un client diverso. + * \param q: puntatore alla coda che contiene il fileT da chiudere + * \param filepath: path assoluto (identificatore) del fileT da chiudere + * \param owner: client che ha richiesto la chiusura + * + * \retval 0 se successo, -1 se errore (errno) + */ +int closeFileInQueue(queueT *q, char *filepath, int owner); + +/** + * Scrive del contenuto su un fileT all'interno della coda. Fallisce se il file + * non e' stato aperto o se il lock appartiene a un client diverso. + * \param q: puntatore alla coda che contiene il fileT su cui scrivere + * \param filepath: path assoluto (identificatore) del fileT + * \param data: buffer che contiene i dati + * \param size: dimensione in bytes del buffer + * \param owner: client che ha richiesto l'operazione di scrittura + * + * \retval 0 se successo, -1 se errore (errno) + */ +int writeFileInQueue(queueT *q, char *filepath, void *data, size_t size, int owner); + +/** + * Scrive del contenuto in append su un fileT all'interno della coda. Fallisce + * se il file non e' stato aperto o se il lock appartiene a un client diverso. + * \param q: puntatore alla coda che contiene il fileT su cui effettuare l'append + * \param filepath: path assoluto (identificatore) del fileT + * \param data: buffer che contiene i dati + * \param size: dimensione in bytes del buffer + * \param owner: client che ha richiesto l'operazione di append + * + * \retval 0 se successo, -1 se errore (setta errno) + */ +int appendFileInQueue(queueT *q, char *filepath, void *data, size_t size, int owner); + +/** + * Rimuove un fileT dalla coda. Fallisce se non si è in possesso della lock o se + * la lock e' posseduta da un client diverso. + * \param q: puntatore alla coda che contiene il fileT da rimuovere + * \param filepath: path assoluto (identificatore) del fileT da rimuovere + * \param owner: client che ha richiesto la rimozione + * + * \retval 0 se successo, -1 se errore (errno) + */ +int removeFileFromQueue(queueT *q, char *filepath, int owner); + + + +/** + * Cerca un fileT nella coda. + * \param q: puntatore alla coda sulla quale cercare il fileT + * \param filepath: path assoluto del fileT da cercare + * + * \retval puntatore a una copia del fileT se trovato, NULL se non trovato o errore (errno) + */ +fileT* find(queueT *q, char *filepath); + +/** + * Numero di elementi presenti nella coda. + * \param q: puntatore alla coda + * + * \retval numero di elementi presenti, -1 se errore (errno) + */ +size_t getLen(queueT *q); + +/** + * Restituisce la dimensione attuale della coda in bytes. + * \param q: puntatore alla coda + * + * \retval dimensione della coda in bytes, -1 se errore (errno) + */ +size_t getSize(queueT *q); + +/** + * Cancella una coda allocata con createQueue e ne libera la memoria. + * \param q: puntatore alla coda da distruggere + */ +void destroyQueue(queueT *q); + +#endif // _FILE_QUEUE diff --git a/lib/utils/serverStatus.h b/lib/utils/serverStatus.h deleted file mode 100644 index 41ea8a1..0000000 --- a/lib/utils/serverStatus.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once -#ifndef _SERVER_STATUS -#define _SERVER_STATUS - -typedef struct { - pthread_mutex_t *mtx; - pthread_cond_t *cond; - - long max_space_occupied; - long cur_space_occupied; - long max_files; - long cur_files; - char exiting; -} serverStatus; - -#endif /* _SERVER_STATUS */ diff --git a/lib/utils/serverUtil.h b/lib/utils/serverUtil.h new file mode 100644 index 0000000..b9ad88d --- /dev/null +++ b/lib/utils/serverUtil.h @@ -0,0 +1,18 @@ +#pragma once +#ifndef _SERVER_UTIL +#define _SERVER_UTIL + +#include +#include +#include + +#define CONFGETINT(var, config, t, q, p, base) \ + var = (int) strtol(ini_get(config, t, q), p, base); \ + if(var<=0) { \ + fprintf(stderr, "ERROR reading config for variable %c\n", t); \ + ini_free(config); \ + return 1; \ + } + + +#endif /* _SERVER_STATUS */ diff --git a/lib/utils/util.h b/lib/utils/util.h index 0fbec59..642ced2 100644 --- a/lib/utils/util.h +++ b/lib/utils/util.h @@ -83,25 +83,6 @@ static inline void print_error(const char * str, ...) { free(p); } - -/** - * \brief Controlla se la stringa passata come primo argomento e' un numero. - * \return 0 ok 1 non e' un numbero 2 overflow/underflow - */ -static inline int isNumber(const char* s, long* n) { - if (s==NULL) return 1; - if (strlen(s)==0) return 1; - char* e = NULL; - errno=0; - long val = strtol(s, &e, 10); - if (errno == ERANGE) return 2; // overflow/underflow - if (e != NULL && *e == (char)0) { - *n = val; - return 0; // successo - } - return 1; // non e' un numero -} - #define LOCK(l) if (pthread_mutex_lock(l)!=0) { \ fprintf(stderr, "ERRORE FATALE lock\n"); \ pthread_exit((void*)EXIT_FAILURE); \ diff --git a/src/server.c b/src/server.c index 5831b5a..f34cddc 100644 --- a/src/server.c +++ b/src/server.c @@ -13,7 +13,8 @@ #include #include #include -#include +#include +#include /** @@ -80,7 +81,9 @@ int main(int argc, char *argv[]) { // TODO read config file checkargs(argc, argv); ini_t *config = ini_load(argv[1]); - int threadsInPool = (int) strtol(ini_get(config, "threadpool", "quantity"), NULL, 10); + int threadsInPool; CONFGETINT(threadsInPool, config, "threadpool", "quantity", NULL, 10); + int maxFiles; CONFGETINT(maxFiles, config, "files", "MaxFiles", NULL, 10); + int maxSize; CONFGETINT(maxSize, config, "files", "MaxSize", NULL, 10); ini_free(config); sigset_t mask; @@ -90,7 +93,6 @@ int main(int argc, char *argv[]) { sigaddset(&mask, SIGTERM); if (pthread_sigmask(SIG_BLOCK, &mask, NULL) != 0) { - // TODO logging utility fprintf(stderr, "ERROR setting mask\n"); goto _cleanup; } @@ -100,55 +102,57 @@ int main(int argc, char *argv[]) { memset(&s, 0, sizeof(s)); s.sa_handler = SIG_IGN; if ( (sigaction(SIGPIPE,&s,NULL)) == -1 ) { - // TODO logging utility perror("sigaction"); goto _cleanup; } - /* - * La pipe viene utilizzata come canale di comunicazione tra il signal handler thread ed il - * thread lisener per notificare la terminazione. - * Una alternativa è quella di utilizzare la chiamata di sistema - * 'signalfd' ma non e' POSIX. - */ + printf("File Server ready."); + fflush(stdout); + int signal_pipe[2]; if (pipe(signal_pipe) == -1) { - // TODO logging utility perror("pipe"); goto _cleanup; } + // todo logging + statistiche + + + pthread_t sighandler_thread; sigHandler_t handlerArgs = { &mask, signal_pipe[1] }; if (pthread_create(&sighandler_thread, NULL, sigHandler, &handlerArgs) != 0) { - // TODO logging utility fprintf(stderr, "ERROR creating signal handler thread\n"); goto _cleanup; } int listenfd; if ((listenfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { - // TODO logging utility perror("socket"); goto _cleanup; } + // thread per i segnali struct sockaddr_un serv_addr; memset(&serv_addr, '0', sizeof(serv_addr)); serv_addr.sun_family = AF_UNIX; strncpy(serv_addr.sun_path, SOCKNAME, strlen(SOCKNAME)+1); if (bind(listenfd, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) == -1) { - // TODO logging utility perror("bind"); goto _cleanup; } if (listen(listenfd, MAXBACKLOG) == -1) { - // TODO logging utility perror("listen"); goto _cleanup; } + // creo la queue + queueT *queue = createQueue(maxFiles, maxSize); + + + + threadpool_t *pool = NULL; pool = createThreadPool(threadsInPool, threadsInPool);