From d8a292fd3aea07f968af01e2201aa1a29d8aee46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francis=20Brosnan=20Bl=C3=A1zquez?= Date: Sun, 16 Aug 2015 17:10:42 +0000 Subject: [PATCH] nopoll: * [new] Updated noPoll conn API to include a new function to allow closing a connection, sending an error message and an error code along with it: - nopoll_conn_close_ext * [fix] Added regression test (test_28) to check connection close frame with status and reason to check functions added: - nopoll_conn_get_close_status - nopoll_conn_get_close_reason Everything working as expected.. --- src/libnopoll.def | 1 + src/nopoll_conn.c | 52 ++++++++++++++++++++++-- src/nopoll_conn.h | 2 + test/nopoll-regression-client.c | 66 +++++++++++++++++++++++++++++++ test/nopoll-regression-listener.c | 6 +++ 5 files changed, 124 insertions(+), 3 deletions(-) diff --git a/src/libnopoll.def b/src/libnopoll.def index 88f605d..bf9e428 100644 --- a/src/libnopoll.def +++ b/src/libnopoll.def @@ -30,6 +30,7 @@ nopoll_conn_accept_complete nopoll_conn_accept_socket nopoll_conn_check_mime_header_repeated nopoll_conn_close +nopoll_conn_close_ext nopoll_conn_complete_handshake nopoll_conn_complete_handshake_check nopoll_conn_complete_handshake_check_client diff --git a/src/nopoll_conn.c b/src/nopoll_conn.c index d960a3e..bc72bcf 100644 --- a/src/nopoll_conn.c +++ b/src/nopoll_conn.c @@ -1455,10 +1455,18 @@ void nopoll_conn_shutdown (noPollConn * conn) * (\ref noPollRole). * * @param conn The connection to close. + * + * @param status Optional status code to send to remote side. If + * status is < 0, no status code is sent. + * + * @param reason Pointer to the content to be sent. + * + * @param reason_size The amount of bytes that should be used from content pointer. */ -void nopoll_conn_close (noPollConn * conn) +void nopoll_conn_close_ext (noPollConn * conn, int status, const char * reason, int reason_size) { - int refs; + int refs; + char * content; #if defined(SHOW_DEBUG_LOG) const char * role = "unknown"; #endif @@ -1483,7 +1491,28 @@ void nopoll_conn_close (noPollConn * conn) if (conn->session != NOPOLL_INVALID_SOCKET) { nopoll_log (conn->ctx, NOPOLL_LEVEL_DEBUG, "requested proper connection close id=%d (session %d)", conn->id, conn->session); - /* send close message */ + /* build reason indication */ + content = NULL; + if (reason && reason_size > 0) { + /* send content */ + content = nopoll_new (char, reason_size + 3); + if (content) { + nopoll_set_16bit (status, content); + memcpy (content + 2, reason, reason_size); + } /* end if */ + } /* end if */ + + /* send close without reason */ + nopoll_conn_send_frame (conn, nopoll_true /* has_fin */, + /* masked */ + conn->role == NOPOLL_ROLE_CLIENT, NOPOLL_CLOSE_FRAME, + /* content size and content */ + reason_size > 0 ? reason_size + 2 : 0, content, + /* sleep in header */ + 0); + + /* release content (if defined) */ + nopoll_free (content); /* call to shutdown connection */ nopoll_conn_shutdown (conn); @@ -1501,6 +1530,23 @@ void nopoll_conn_close (noPollConn * conn) /* call to unref connection */ nopoll_conn_unref (conn); + return; +} + +/** + * @brief Allows to close an opened \ref noPollConn no matter its role + * (\ref noPollRole). + * + * @param conn The connection to close. + * + * There is available an alternative extended version that allows to + * send the status code and the error message: \ref + * nopoll_conn_close_ext + */ +void nopoll_conn_close (noPollConn * conn) +{ + /* call to close without providing a reason */ + nopoll_conn_close_ext (conn, 0, NULL, 0); return; } diff --git a/src/nopoll_conn.h b/src/nopoll_conn.h index 8001a60..aff440f 100644 --- a/src/nopoll_conn.h +++ b/src/nopoll_conn.h @@ -125,6 +125,8 @@ void nopoll_conn_shutdown (noPollConn * conn); void nopoll_conn_close (noPollConn * conn); +void nopoll_conn_close_ext (noPollConn * conn, int status, const char * reason, int reason_size); + void nopoll_conn_set_hook (noPollConn * conn, noPollPtr ptr); noPollPtr nopoll_conn_get_hook (noPollConn * conn); diff --git a/test/nopoll-regression-client.c b/test/nopoll-regression-client.c index c14afa7..f4013c9 100644 --- a/test/nopoll-regression-client.c +++ b/test/nopoll-regression-client.c @@ -2318,6 +2318,65 @@ nopoll_bool test_27 (void) { } +nopoll_bool test_28 (void) { + + noPollConn * conn; + noPollCtx * ctx; + noPollMsg * msg; + + /* init context */ + ctx = create_ctx (); + + /* create connection */ + conn = nopoll_conn_new (ctx, "localhost", "1234", NULL, NULL, NULL, NULL); + if (! nopoll_conn_is_ok (conn)) { + printf ("ERROR: Expected to find proper client connection status, but found error..\n"); + return nopoll_false; + } /* end if */ + + /* wait until it is connected */ + nopoll_conn_wait_until_connection_ready (conn, 5); + + /* send a message to request connection close with a particular message */ + if (nopoll_conn_send_text (conn, "close with message", 18) != 18) { + printf ("ERROR: failed to send close with message.."); + return nopoll_false; + } /* end while */ + + /* wait for the reply */ + while ((msg = nopoll_conn_get_msg (conn)) == NULL) { + + if (! nopoll_conn_is_ok (conn)) { + /* connection was closed by remote side */ + break; + } /* end if */ + + nopoll_sleep (10000); + } /* end if */ + + printf ("Test 28: close reason received, statud=%d, message=%s\n", + nopoll_conn_get_close_status (conn), + nopoll_conn_get_close_reason (conn)); + if (nopoll_conn_get_close_status (conn) != 1048) { + printf ("ERROR: expected different error code..\n"); + return nopoll_false; + } + + if (! nopoll_cmp (nopoll_conn_get_close_reason (conn), "Hey, this is a very reasonable error message")) { + printf ("ERROR: expected different error message..\n"); + return nopoll_false; + } /* end if */ + + /* close connection */ + nopoll_conn_close (conn); + + /* release context */ + nopoll_ctx_unref (ctx); + + return nopoll_true; +} + + int main (int argc, char ** argv) { int iterator; @@ -2607,6 +2666,13 @@ int main (int argc, char ** argv) return -1; } /* end if */ + if (test_28 ()) { + printf ("Test 28: checking setting protocol [ OK ]\n"); + } else { + printf ("Test 28: chekcing setting protocol [ FAILED ]\n"); + return -1; + } /* end if */ + /* add support to reply with redirect 301 to an opening * request: page 19 and 22 */ diff --git a/test/nopoll-regression-listener.c b/test/nopoll-regression-listener.c index 9931010..8519f46 100644 --- a/test/nopoll-regression-listener.c +++ b/test/nopoll-regression-listener.c @@ -149,6 +149,12 @@ void listener_on_message (noPollCtx * ctx, noPollConn * conn, noPollMsg * msg, n } /* end if */ printf ("Message received: %s\n", content); + if (nopoll_ncmp (content, "close with message", 18)) { + printf ("Listener: RELEASING connection (closing it) with reason..\n"); + nopoll_conn_close_ext (conn, 1048, "Hey, this is a very reasonable error message", 44); + return; + } /* end if */ + if (nopoll_ncmp (content, "release-message", 15)) { printf ("Listener: RELEASING previous message..\n"); nopoll_msg_unref (previous_msg);