From 2788c6f94b4e24441718d74ed825f3087d48daa5 Mon Sep 17 00:00:00 2001 From: overflowerror Date: Wed, 12 May 2021 22:02:46 +0200 Subject: [PATCH] basic cleanup after chunked transfer works; cleanup of response/encoding thread still to do --- src/networking.c | 118 ++++++++++++++++++++++++++++++----------------- src/networking.h | 2 + 2 files changed, 78 insertions(+), 42 deletions(-) diff --git a/src/networking.c b/src/networking.c index 2edc1d4..c2a59ed 100644 --- a/src/networking.c +++ b/src/networking.c @@ -304,6 +304,57 @@ void safeEndConnection(struct connection* connection, bool force) { pthread_mutex_unlock(&(connection->lock)); } +// connection has to be locked beforehand +// TODO: Look into how self can be joined +// (because this function will be called in response or encoder thread) +void resetPersistentConnection(struct connection* connection) { + pthread_t self = pthread_self(); + + // kill request thread so that the connection doesn't get killed + stopThread(self, &(connection->threads.request), true); + + // if we are the encoding thread, + // wait for response thread to terminate (should have happend already) + // + // if caller is response thread stopThread will do nothing + stopThread(self, &(connection->threads.response), false); + + // wait for encoder + if (connection->threads.encoder != PTHREAD_NULL) { + // if caller is encoder stopThread will to nothing + debug("stopping encoder thread"); + stopThread(self, &(connection->threads.encoder), false); + debug("stopped encoder thread"); + } + + // free request specific data + if (connection->metaData.path != NULL) { + free(connection->metaData.path); + connection->metaData.path = NULL; + } + if (connection->metaData.queryString != NULL) { + free(connection->metaData.queryString); + connection->metaData.queryString = NULL; + } + if (connection->metaData.uri != NULL) { + free(connection->metaData.uri); + connection->metaData.uri = NULL; + } + if (connection->currentHeader != NULL) { + free(connection->currentHeader); + connection->currentHeader = NULL; + } + + connection->currentHeaderLength = 0; + + headers_free(&(connection->headers)); + + // set state to OPENED so a request can be read + connection->state = OPENED; + updateTiming(connection, true); + connection->inUse--; +} + struct chunkedEncodingData { struct connection* connection; int readfd; @@ -360,6 +411,16 @@ void* chunkedTransferEncodingThread(void* _data) { close(data->readfd); fclose(writeFile); // close dup, fd will stay open + + pthread_mutex_lock(&(data->connection->resetOkay)); + // once we have the lock we can destroy it + pthread_mutex_unlock(&(data->connection->resetOkay)); + pthread_mutex_destroy(&(data->connection->resetOkay)); + + pthread_mutex_lock(&(data->connection->lock)); + resetPersistentConnection(data->connection); + pthread_mutex_unlock(&(data->connection->lock)); + free(data); return NULL; @@ -485,6 +546,8 @@ int sendHeader(int statusCode, struct headers* headers, struct request* request) } } + connection->isChunked = chunkedTransferEncoding; + FILE* stream = fdopen(tmp, "w"); if (stream == NULL) { error("networking: sendHeader: fdopen: %s", strerror(errno)); @@ -506,47 +569,6 @@ int sendHeader(int statusCode, struct headers* headers, struct request* request) return fd; } -void resetPersistentConnection(struct connection* connection) { - pthread_t self = pthread_self(); - - // kill request thread so that the connection doesn't get killed - stopThread(self, &(connection->threads.request), true); - connection->threads.request = PTHREAD_NULL; - - // wait for encoder - if (connection->threads.encoder != PTHREAD_NULL) { - stopThread(self, &(connection->threads.encoder), false); - connection->threads.encoder = PTHREAD_NULL; - } - - // free request specific data - if (connection->metaData.path != NULL) { - free(connection->metaData.path); - connection->metaData.path = NULL; - } - if (connection->metaData.queryString != NULL) { - free(connection->metaData.queryString); - connection->metaData.queryString = NULL; - } - if (connection->metaData.uri != NULL) { - free(connection->metaData.uri); - connection->metaData.uri = NULL; - } - if (connection->currentHeader != NULL) { - free(connection->currentHeader); - connection->currentHeader = NULL; - } - - connection->currentHeaderLength = 0; - - headers_free(&(connection->headers)); - - // set state to OPENED so a request can be read - connection->state = OPENED; - updateTiming(connection, true); - connection->inUse--; -} - /* * This thread calls the handler. */ @@ -555,6 +577,11 @@ void* responseThread(void* data) { debug("networking: calling response handler"); + if (connection->isPersistent) { + pthread_mutex_init(&connection->resetOkay, NULL); + pthread_mutex_lock(&(connection->resetOkay)); + } + connection->threads.handler.handler((struct request) { .metaData = connection->metaData, .headers = &(connection->headers), @@ -571,7 +598,14 @@ void* responseThread(void* data) { // lock before isPersistent check in case the connection gets aborted pthread_mutex_lock(&(connection->lock)); if (connection->isPersistent) { - resetPersistentConnection(connection); + if (!connection->isChunked) { + pthread_mutex_unlock(&(connection->resetOkay)); + pthread_mutex_destroy(&(connection->resetOkay)); + + resetPersistentConnection(connection); + } else { + pthread_mutex_unlock(&(connection->resetOkay)); + } // unlock after reset pthread_mutex_unlock(&(connection->lock)); } else { diff --git a/src/networking.h b/src/networking.h index c7d62fc..060e5eb 100644 --- a/src/networking.h +++ b/src/networking.h @@ -45,6 +45,7 @@ struct connection { struct peer peer; struct bind* bind; pthread_mutex_t lock; + pthread_mutex_t resetOkay; volatile sig_atomic_t inUse; int readfd; int writefd; @@ -55,6 +56,7 @@ struct connection { struct timing timing; struct threads threads; bool isPersistent; + bool isChunked; #ifdef SSL_SUPPORT struct ssl_connection* sslConnection; #endif