diff --git a/lib/threadpool/apiFile.c b/lib/threadpool/apiFile.c index d8c69e8..1c0b08a 100644 --- a/lib/threadpool/apiFile.c +++ b/lib/threadpool/apiFile.c @@ -71,6 +71,46 @@ _sendM_cleanup: return; } +// invia un file +int sendFile(fileT *f, long fd_c, taglia_t *taglia) { + if(!f || !taglia) { + errno = EINVAL; + return -1; + } + + // send filepath dimension, then filepath + int64_t filepathLength = (int64_t) strnlen(f->filepath, MAXLENMESS)+1; + if (writen(fd_c, &filepathLength, sizeof(filepathLength)) < 0) { + perror("writen"); + return -1; + } + if (writen(fd_c, f->filepath, (size_t) filepathLength) < 0) { + perror("writen"); + return -1; + } + // send file dimension, then file + int64_t validLength = (int64_t) f->valid; + if (writen(fd_c, &validLength, sizeof(validLength)) < 0) { + perror("writen"); + return -1; + } + if (writen(fd_c, f->data, f->valid) < 0) { + perror("writen"); + return -1; + } + + char tmp_log[LOGBUFSIZE]; + int n = 0; + size_t m = sizeof(tmp_log); + + n += snprintf(tmp_log+n, m-n, "File \"%s\", di dimensione %llu Bytes al client %ld .\n", f->filepath, validLength, fd_c); + if(taglia_write(taglia, tmp_log) < 0) { + perror("taglia_write"); + return 1; + } + return 0; +} + // invio il messaggio al client e poi il file void sendMessageFile(char *m, fileT *f, long fd_c, taglia_t *taglia, char *mlog) { if(!f) { @@ -94,8 +134,10 @@ void sendMessageFile(char *m, fileT *f, long fd_c, taglia_t *taglia, char *mlog) goto _sendMF_cleanup; } - if(taglia_write(taglia, mlog) < 0) + if(taglia_write(taglia, mlog) < 0) { + perror("log write"); goto _sendMF_cleanup; + } return; @@ -137,8 +179,8 @@ _sendMFN_cleanup: return; } -// ----------------------------------------------------------------------------- +// ----------------------------------------------------------------------------- void openFile(char *filepath, int flags, queueT *q, long fd_c, taglia_t *taglia) { // messaggio da scrivere sul logfile char tmp_buf[LOGBUFSIZE]; @@ -526,36 +568,259 @@ void lockFile(char *filepath, queueT *q, long fd_c, taglia_t *taglia, pthread_mu void unlockFile(char *filepath, queueT *q, long fd_c, taglia_t *taglia, pthread_mutex_t *lock, waiting_t **waiting) { + // messaggio da scrivere sul logfile + char tmp_buf[LOGBUFSIZE]; + int n = 0; + size_t m = sizeof(tmp_buf); + + if(!filepath || !q || !taglia || !lock || !waiting) { + n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una unlockFile sul file \"%s\" e' terminata con errore.\n", fd_c, filepath); + errno = EINVAL; + serror(MESY, fd_c, taglia, tmp_buf); + return; + } + + // cerco il file su cui rilasciare la lock + if(!searchFile(q, filepath)) { // file e' assente + n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una unlockFile sul file \"%s\" ma risulta assente.\n", fd_c, filepath); + errno = ENOENT; + serror(MENT, fd_c, taglia, tmp_buf); + return; + } + + if (unlockFileInQueue(q, filepath, fd_c) != 0) { + n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una unlockFile sul file \"%s\" ma non è stata rilasciata la lock.\n", fd_c, filepath); + serror(MENT, fd_c, taglia, tmp_buf); + return; + } + + n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una unlockFile sul file \"%s\" e' terminata con successo\n", fd_c, filepath); + sendMessage(MEOK, fd_c, taglia, tmp_buf); + + // segnalo a un client in lista d'attesa che una lock e' stata rilasciata + if (pthread_mutex_lock(lock) == -1) { // begin ME + perror("lock"); + return; + } + + int waked = -1; + waked = removeFirstWaiting(waiting, filepath); + + if (waked != -1) { + // we lock the file for the other client + lockFile(filepath, q, waked, taglia, lock, waiting); + } + + if (pthread_mutex_unlock(lock) == -1) { // end ME + perror("unlock"); + return; + } return; } void closeFile(char *filepath, queueT *q, long fd_c, taglia_t *taglia, pthread_mutex_t *lock, waiting_t **waiting) { + // messaggio da scrivere sul logfile + char tmp_buf[LOGBUFSIZE]; + int n = 0; + size_t m = sizeof(tmp_buf); + + if(!filepath || !q || !taglia || !lock || !waiting) { + n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una closeFile sul file \"%s\" e' terminata con errore.\n", fd_c, filepath); + errno = EINVAL; + serror(MESY, fd_c, taglia, tmp_buf); + return; + } + + // cerco il file da chiudere + if(!searchFile(q, filepath)) { // file e' assente + n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una closeFile sul file \"%s\" ma risulta assente.\n", fd_c, filepath); + errno = ENOENT; + serror(MENT, fd_c, taglia, tmp_buf); + return; + } + + if (closeFileInQueue(q, filepath, fd_c) == -1) { + n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una closeFile sul file \"%s\" e' terminata con errore.\n", fd_c, filepath); + serror(MENT, fd_c, taglia, tmp_buf); + return; + } + + n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una closeFile sul file \"%s\" e' terminata con successo\n", fd_c, filepath); + sendMessage(MEOK, fd_c, taglia, tmp_buf); + + // segnalo a un client in lista d'attesa che una lock e' stata rilasciata + if (pthread_mutex_lock(lock) == -1) { // begin ME + perror("lock"); + return; + } + + int waked = -1; + waked = removeFirstWaiting(waiting, filepath); + + if (waked != -1) { + // we lock the file for the other client + lockFile(filepath, q, waked, taglia, lock, waiting); + } + + if (pthread_mutex_unlock(lock) == -1) { // end ME + perror("unlock"); + return; + } return; } void removeFile(char *filepath, queueT *q, long fd_c, taglia_t *taglia, pthread_mutex_t *lock, waiting_t **waiting) { + // messaggio da scrivere sul logfile + char tmp_buf[LOGBUFSIZE]; + int n = 0; + size_t m = sizeof(tmp_buf); + + if(!filepath || !q || !taglia || !lock || !waiting) { + n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una removeFile sul file \"%s\" e' terminata con errore.\n", fd_c, filepath); + errno = EINVAL; + serror(MESY, fd_c, taglia, tmp_buf); + return; + } + + // cerco il file da eliminare + if(!searchFile(q, filepath)) { // file e' assente + n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una removeFile sul file \"%s\" ma risulta assente.\n", fd_c, filepath); + errno = ENOENT; + serror(MENT, fd_c, taglia, tmp_buf); + return; + } + + if (removeFileFromQueue(q, filepath, fd_c) == -1) { + n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una removeFile sul file \"%s\" e' terminata con errore.\n", fd_c, filepath); + serror(MENT, fd_c, taglia, tmp_buf); + return; + } + + n += snprintf(tmp_buf+n, m-n, "Client %ld ha richiesto una removeFile sul file \"%s\" e' terminata con successo\n", fd_c, filepath); + sendMessage(MEOK, fd_c, taglia, tmp_buf); + + // segnalo a un client in lista d'attesa che un file e' stato rimosso + if (pthread_mutex_lock(lock) == -1) { // begin ME + perror("lock"); + return; + } + + int waked = -1; + waked = removeFirstWaiting(waiting, filepath); + + if (waked != -1) { + // we lock the file for the other client + lockFile(filepath, q, waked, taglia, lock, waiting); + } + + if (pthread_mutex_unlock(lock) == -1) { // end ME + perror("unlock"); + return; + } return; } +// ----------------------------------------------------------------------------- +/* funzioni ausiliarie relative ai client in attesa di lock */ +int addWaiting(waiting_t **waiting, char *filepath, int fd_c) { + if(!waiting || !filepath) { + errno = EINVAL; + return -1; + } + + waiting_t *new = calloc(1, sizeof(waiting_t)); + if (!new) { + perror("calloc"); + return -1; + } + new->file = calloc(MAXLENMESS, sizeof(char)); + if (!new->file) { + perror("calloc"); + free(new); + return -1; + } + + strncpy(new->file, filepath, strnlen(filepath, MAXLENMESS-1)+1); + new->fd = fd_c; + new->next = NULL; + + // se la lista è vuota + if(*waiting == NULL) { + *waiting = new; + return 0; + } + + // se la lista ha almeno un elemento + waiting_t *tail = *waiting; + while(tail->next) { + tail = tail->next; + } + tail->next = new; -int sendFile(fileT *f, long fd_c, taglia_t *taglia) { return 0; } +// remove first who is waiting on the lock for the file +int removeFirstWaiting(waiting_t **waiting, char *filepath) { + if(!waiting || !filepath) { + errno = EINVAL; + return -1; + } -int addWaiting(waiting_t **waiting, char *file, int fd) { - return 0; + // none waiting + if(*waiting == NULL) { + return -1; + } + + waiting_t *curr = *waiting; + waiting_t *prec = NULL; + long fd_c = -1; + + // first one waiting + if (strcmp(curr->file, filepath) == 0) { + fd_c = curr->fd; + *waiting = curr->next; + free(curr->file); + free(curr); + + return fd_c; + } + + // more than one waiting + while (curr->next) { + prec = curr; + curr = curr->next; + + if (strcmp(curr->file, filepath) == 0) { + fd_c = curr->fd; + prec->next = curr->next; + free(curr->file); + free(curr); + + return fd_c; + } + } + + return -1; } - -int removeFirstWaiting(waiting_t **waiting, char *file) { - return 0; -} - - +// destroy waiting structure void clearWaiting(waiting_t **waiting) { + if(!waiting) { + return; + } + waiting_t *curr = *waiting; + waiting_t *next = NULL; + + while (curr) { + next = curr->next; + free(curr->file); + free(curr); + curr = next; + } + *waiting = NULL; return; } diff --git a/lib/threadpool/apiFile.h b/lib/threadpool/apiFile.h index c87ec3a..23c03e7 100644 --- a/lib/threadpool/apiFile.h +++ b/lib/threadpool/apiFile.h @@ -51,10 +51,10 @@ void removeFile(char *filepath, queueT *q, long fd_c, taglia_t *taglia, pthread_ int sendFile(fileT *f, long fd_c, taglia_t *taglia); // Aggiunge una coppia client/file alla coda in attesa di ottenere una lock -int addWaiting(waiting_t **waiting, char *file, int fd); +int addWaiting(waiting_t **waiting, char *filepath, int fd_c); // Ottiene il primo client in attesa su una lock di un determinato file -int removeFirstWaiting(waiting_t **waiting, char *file); +int removeFirstWaiting(waiting_t **waiting, char *filepath); // Distrugge la lista d'attesa e ne libera la memoria void clearWaiting(waiting_t **waiting);