Index: src/vortex_tls.c =================================================================== --- src/vortex_tls.c (revision 689) +++ src/vortex_tls.c (revision 690) @@ -43,7 +43,7 @@ * \addtogroup vortex_tls * @{ */ - +#include #define LOG_DOMAIN "vortex-tls" #include @@ -1608,14 +1608,69 @@ typedef struct _VortexTlsSyncResult { - VortexConnection * connection; VortexStatus status; char * status_message; } VortexTlsSyncResult; +typedef struct _VortexTlsSync +{ + VortexMutex mutex; + int ref_count; + VortexAsyncQueue* queue; + VortexConnection* link; + VortexConnection* next; + VortexTlsSyncResult* result; +} VortexTlsSync; + /** * @internal * + * @brief Make a new sync object + */ +static VortexTlsSync* make_tls_sync(VortexConnection* link) +{ + VortexTlsSync* sync; + sync = calloc(1, sizeof *sync); + sync->ref_count = 1+1; // caller thread + vortex thread + sync->queue = vortex_async_queue_new(); + sync->link = link; + vortex_mutex_create(&sync->mutex); + // we have to ref the connection during use because caller + // code can close it behind our backs in case of timeouts + vortex_connection_ref(sync->link, __FUNCTION__); + return sync; +} + +/** + * @internal + * + * @brief Unref the sync object and in case we are the last ref, release it + * + * @return Return a VortexConnection pointer which is set to the new connection + * if the sync succedeed or a NULL pointer if the sync failed + */ +static VortexConnection* unref_tls_sync(VortexTlsSync* sync, const char* who) +{ + VortexConnection* rpy; int last; + + vortex_mutex_lock(&sync->mutex); + rpy = sync->next; + last = --sync->ref_count; + vortex_mutex_unlock(&sync->mutex); + assert( last >= 0 ); + if( last ) return rpy; + + axl_free(sync->result); + vortex_connection_unref(sync->link, who); + vortex_async_queue_unref(sync->queue); + vortex_mutex_destroy(&sync->mutex); + free(sync); + return rpy; +} + +/** + * @internal + * * @brief Support function for \ref vortex_tls_start_negotiation_sync * function. */ @@ -1624,20 +1679,24 @@ char * status_message, axlPointer user_data) { - VortexAsyncQueue * queue = user_data; + VortexTlsSync * sync = user_data; VortexTlsSyncResult * result; /* create a structure to hold all the result produced. */ result = axl_new (VortexTlsSyncResult, 1); - result->connection = connection; result->status = status; result->status_message = status_message; - /* push and unref man! */ - QUEUE_PUSH (queue, result); - vortex_async_queue_unref (queue); + vortex_mutex_lock(&sync->mutex); + // add the sync result to the sync object + sync->result = result; + // add the new connection to the sync object + if( sync->link != connection ) + sync->next = connection; + vortex_mutex_unlock(&sync->mutex); - return; + QUEUE_PUSH(sync->queue, result); + unref_tls_sync(sync, __FUNCTION__); } #endif @@ -1659,24 +1718,8 @@ * @param status An optional reference to a \ref VortexStatus variable so the caller could get a TLS activation status. * @param status_message An optional reference to get a textual diagnostic about TLS activation status. * - * @return The new connection with TLS profile activated. - * - * NOTE: About connection reference returned
- * - * The function always return a reference to a connection, even on TLS - * failures. Assuming this, it is required to call to \ref - * vortex_connection_is_ok to check status and proceed as requried if - * the case an error was found. The same can be done using - * status or status_message parameters (checking state). - * - * Because the function could fail before the TLS handshake can start - * or during it, the function returns the same connection if the - * failure was found before TLS started or a different connection - * reference (with the same data) if the error is found during the - * tuning. In both cases a valid reference (which is not the same as - * valid connection) is always returned (even if the connection is not - * working). - * + * @return The new connection with TLS profile activated, or a NULL pointer if an error occured + * Note that the input connection is always released. *
*/ VortexConnection * vortex_tls_start_negotiation_sync (VortexConnection * connection, @@ -1690,55 +1733,27 @@ (* status) = VortexError; if (status_message != NULL) (* status_message) = "trying to execute a synchronous tls-fication on a vortex library without TLS support"; - return NULL; + return connection; #else /* new connection received */ VortexConnection * _connection; VortexTlsSyncResult * result; - VortexAsyncQueue * queue; + VortexTlsSync * sync; - /* create an async queue and increase queue reference so the - * function could unref it without worry about race conditions - * with sync_process function. */ - queue = vortex_async_queue_new (); - vortex_async_queue_ref (queue); + sync = make_tls_sync(connection); /* start TLS negotiation */ vortex_tls_start_negotiation (connection, serverName, __vortex_tls_start_negotiation_sync_process, - queue); + sync); /* get status */ - result = vortex_async_queue_timedpop (queue, vortex_connection_get_timeout ()); - if (result == NULL) { - /* seems timeout have happen while waiting for SASL to - * end */ - if (status != NULL) - (* status) = VortexError; - if (status_message != NULL) - (* status_message) = "Timeout have been reached while waiting for TLS to finish"; - - /* return the same connection */ - return connection; - } - - /* get status */ - if (status != NULL) - (* status) = result->status; - - /* get message */ - if (status_message != NULL) - (* status_message) = result->status_message; - - /* get connection */ - _connection = result->connection; - - /* free and unref the queue */ - axl_free (result); - vortex_async_queue_unref (queue); - - /* return received value */ - return _connection; + result = vortex_async_queue_timedpop (sync->queue, vortex_connection_get_timeout ()); + if( status ) + *status = result ? result->status : VortexError; + if( status_message ) + *status_message = result ? result->status_message : "Timeout have been reached while waiting for TLS to finish"; + return unref_tls_sync(sync, __FUNCTION__); #endif }