From 08f1726b6552ac29830637e9f7be4d42e2ea4294 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Mon, 19 Sep 2016 08:40:49 +0000 Subject: [PATCH] -modifying tests to use new service MQ API, implementing more of service MQ API --- src/util/Makefile.am | 20 +-- src/util/service_new.c | 102 ++++++++++++++-- src/util/test_client.c | 210 +++++++++++++++----------------- src/util/test_client_data.conf | 3 + src/util/test_client_unix.conf | 6 + src/util/test_mq_client.c | 182 --------------------------- src/util/test_service_data.conf | 1 - 7 files changed, 215 insertions(+), 309 deletions(-) create mode 100644 src/util/test_client_data.conf create mode 100644 src/util/test_client_unix.conf delete mode 100644 src/util/test_mq_client.c diff --git a/src/util/Makefile.am b/src/util/Makefile.am index b7e60022f..0172df67f 100644 --- a/src/util/Makefile.am +++ b/src/util/Makefile.am @@ -265,6 +265,7 @@ endif check_PROGRAMS = \ test_bio \ test_client.nc \ + test_client_unix.nc \ $(SSH_USING_TESTS) \ test_common_allocation \ test_common_endian \ @@ -299,7 +300,6 @@ check_PROGRAMS = \ test_connection_timeout_no_connect.nc \ test_connection_transmit_cancel.nc \ test_mq \ - test_mq_client.nc \ test_os_network \ test_peer \ test_plugin \ @@ -325,18 +325,18 @@ check_PROGRAMS = \ # Declare .nc (NO-CONCURRENCY) as a test extension so that we can impart # sequential execution order for them TEST_EXTENSIONS = .nc -test_connection.log: test_client.log +test_connection.log: test_client.log test_connection_addressing.log: test_connection.log test_connection_timeout_no_connect.log: test_connection_addressing.log test_connection_transmit_cancel.log: test_connection_timeout_no_connect.log test_connection_receive_cancel.log: test_connection_transmit_cancel.log test_connection_timeout.log: test_connection_receive_cancel.log -test_mq_client.log: test_connection_timeout.log -test_resolver_api.log: test_mq_client.log +test_resolver_api.log: test_connection_timeout.log test_server.log: test_resolver_api.log test_server_disconnect.log: test_server.log test_server_with_client.log: test_server_disconnect.log test_server_mst_interrupt.log: test_server_with_client.log +test_client_unix.log: test_server_mst_interrupt.log test_bio_SOURCES = \ test_bio.c @@ -357,6 +357,11 @@ test_client_nc_SOURCES = \ test_client_nc_LDADD = \ libgnunetutil.la +test_client_unix_nc_SOURCES = \ + test_client.c +test_client_unix_nc_LDADD = \ + libgnunetutil.la + test_socks_nc_SOURCES = \ test_socks.c test_socks_nc_LDADD = \ @@ -538,11 +543,6 @@ test_mq_SOURCES = \ test_mq_LDADD = \ libgnunetutil.la -test_mq_client_nc_SOURCES = \ - test_mq_client.c -test_mq_client_nc_LDADD = \ - libgnunetutil.la - test_os_network_SOURCES = \ test_os_network.c test_os_network_LDADD = \ @@ -670,6 +670,8 @@ perf_malloc_LDADD = \ EXTRA_DIST = \ + test_client_data.conf \ + test_client_unix.conf \ test_configuration_data.conf \ test_program_data.conf \ test_resolver_api_data.conf \ diff --git a/src/util/service_new.c b/src/util/service_new.c index d6eda3250..fe8e79f17 100644 --- a/src/util/service_new.c +++ b/src/util/service_new.c @@ -265,6 +265,11 @@ struct GNUNET_SERVICE_Client */ struct GNUNET_SCHEDULER_Task *send_task; + /** + * Pointer to the message to be transmitted by @e send_task. + */ + const struct GNUNET_MessageHeader *msg; + /** * User context value, value returned from * the connect callback. @@ -276,6 +281,11 @@ struct GNUNET_SERVICE_Client * to the application. */ struct GNUNET_TIME_Absolute warn_start; + + /** + * Current position in @e msg at which we are transmitting. + */ + size_t msg_pos; /** * Persist the file handle for this client no matter what happens, @@ -1775,25 +1785,87 @@ GNUNET_SERVICE_suspend (struct GNUNET_SERVICE_Handle *sh) } +/** + * Task run when we are ready to transmit data to the + * client. + * + * @param cls the `struct GNUNET_SERVICE_Client *` to send to + */ +static void +do_send (void *cls) +{ + struct GNUNET_SERVICE_Client *client = cls; + ssize_t ret; + size_t left; + const char *buf; + + client->send_task = NULL; + buf = (const char *) client->msg; + left = ntohs (client->msg->size) - client->msg_pos; + ret = GNUNET_NETWORK_socket_send (client->sock, + &buf[client->msg_pos], + left); + GNUNET_assert (ret <= (ssize_t) left); + if (0 == ret) + { + GNUNET_MQ_inject_error (client->mq, + GNUNET_MQ_ERROR_WRITE); + return; + } + if (-1 == ret) + { + if ( (EAGAIN == errno) || + (EINTR == errno) ) + { + /* ignore */ + ret = 0; + } + else + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, + "send"); + GNUNET_MQ_inject_error (client->mq, + GNUNET_MQ_ERROR_WRITE); + return; + } + } + client->msg_pos += ret; + if (left > ret) + { + client->send_task + = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL, + client->sock, + &do_send, + client); + return; + } + GNUNET_MQ_impl_send_continue (client->mq); +} + + /** * Signature of functions implementing the sending functionality of a * message queue. * * @param mq the message queue * @param msg the message to send - * @param impl_state state of the implementation + * @param impl_state our `struct GNUNET_SERVICE_Client *` */ static void service_mq_send (struct GNUNET_MQ_Handle *mq, const struct GNUNET_MessageHeader *msg, void *impl_state) { - // struct GNUNET_SERVICE_Client *client = cls; - - // FIXME 1: setup "client->send_task" for transmission. - // FIXME 2: I seriously hope we do not need to make a copy of `msg`! - // OPTIMIZATION: ideally, we'd like the ability to peak at the rest of - // the queue and transmit more than one message if possible. + struct GNUNET_SERVICE_Client *client = impl_state; + + GNUNET_assert (NULL == client->send_task); + client->msg = msg; + client->msg_pos = 0; + client->send_task + = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL, + client->sock, + &do_send, + client); } @@ -1807,8 +1879,9 @@ static void service_mq_cancel (struct GNUNET_MQ_Handle *mq, void *impl_state) { - // struct GNUNET_SERVICE_Client *client = cls; + struct GNUNET_SERVICE_Client *client = impl_state; + GNUNET_assert (0); // not implemented // FIXME: stop transmission! (must be possible, otherwise // we must have told MQ that the message was sent!) } @@ -2334,4 +2407,17 @@ GNUNET_SERVICE_client_persist (struct GNUNET_SERVICE_Client *c) } +/** + * Obtain the message queue of @a c. Convenience function. + * + * @param c the client to continue receiving from + * @return the message queue of @a c + */ +struct GNUNET_MQ_Handle * +GNUNET_SERVICE_client_get_mq (struct GNUNET_SERVICE_Client *c) +{ + return c->mq; +} + + /* end of service_new.c */ diff --git a/src/util/test_client.c b/src/util/test_client.c index 558a3cf1e..aa4d84495 100644 --- a/src/util/test_client.c +++ b/src/util/test_client.c @@ -20,95 +20,48 @@ /** * @file util/test_client.c * @brief tests for client.c + * @author Christian Grothoff */ #include "platform.h" #include "gnunet_util_lib.h" +static int global_ret; -#define PORT 14325 - -#define MYNAME "test_client" - -static struct GNUNET_MQ_Handle *mq; - -static struct GNUNET_SERVER_Handle *server; - -static struct GNUNET_CONFIGURATION_Handle *cfg; +static struct GNUNET_MQ_Handle *client_mq; #define MY_TYPE 130 -struct CopyContext -{ - struct GNUNET_SERVER_Client *client; - struct GNUNET_MessageHeader *cpy; -}; - - -static size_t -copy_msg (void *cls, size_t size, void *buf) -{ - struct CopyContext *ctx = cls; - struct GNUNET_MessageHeader *cpy = ctx->cpy; - - GNUNET_assert (sizeof (struct GNUNET_MessageHeader) == ntohs (cpy->size)); - GNUNET_assert (size >= ntohs (cpy->size)); - GNUNET_memcpy (buf, cpy, ntohs (cpy->size)); - GNUNET_SERVER_receive_done (ctx->client, GNUNET_OK); - GNUNET_free (cpy); - GNUNET_free (ctx); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Message bounced back to client\n"); - return sizeof (struct GNUNET_MessageHeader); -} - /** * Callback that just bounces the message back to the sender. */ static void -echo_cb (void *cls, - struct GNUNET_SERVER_Client *client, - const struct GNUNET_MessageHeader *message) +handle_echo (void *cls, + const struct GNUNET_MessageHeader *message) { - struct CopyContext *cc; - struct GNUNET_MessageHeader *cpy; + struct GNUNET_SERVICE_Client *c = cls; + struct GNUNET_MQ_Handle *mq = GNUNET_SERVICE_client_get_mq (c); + struct GNUNET_MQ_Envelope *env; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Receiving message from client, bouncing back\n"); - GNUNET_assert (sizeof (struct GNUNET_MessageHeader) == ntohs (message->size)); - cc = GNUNET_new (struct CopyContext); - cc->client = client; - cpy = GNUNET_malloc (ntohs (message->size)); - GNUNET_memcpy (cpy, message, ntohs (message->size)); - cc->cpy = cpy; - GNUNET_assert (NULL != - GNUNET_SERVER_notify_transmit_ready (client, - ntohs (message->size), - GNUNET_TIME_UNIT_SECONDS, - ©_msg, cc)); + env = GNUNET_MQ_msg_copy (message); + GNUNET_MQ_send (mq, + env); + GNUNET_SERVICE_client_continue (c); } -static struct GNUNET_SERVER_MessageHandler handlers[] = { - {&echo_cb, NULL, MY_TYPE, sizeof (struct GNUNET_MessageHeader)}, - {NULL, NULL, 0, 0} -}; - - static void handle_bounce (void *cls, const struct GNUNET_MessageHeader *got) { - int *ok = cls; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Receiving bounce, checking content\n"); GNUNET_assert (NULL != got); - GNUNET_MQ_destroy (mq); - mq = NULL; - GNUNET_SERVER_destroy (server); - server = NULL; - *ok = 0; + global_ret = 2; + GNUNET_MQ_destroy (client_mq); + client_mq = NULL; } @@ -129,13 +82,10 @@ mq_error_handler (void *cls, static void -task (void *cls) +task (void *cls, + const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_SERVICE_Handle *sh) { - struct sockaddr_in sa; - struct sockaddr *sap[2]; - socklen_t slens[2]; - struct GNUNET_MQ_Envelope *env; - struct GNUNET_MessageHeader *msg; struct GNUNET_MQ_MessageHandler chandlers[] = { GNUNET_MQ_hd_fixed_size (bounce, MY_TYPE, @@ -143,61 +93,103 @@ task (void *cls) cls), GNUNET_MQ_handler_end () }; + struct GNUNET_MQ_Envelope *env; + struct GNUNET_MessageHeader *msg; /* test that ill-configured client fails instantly */ - GNUNET_assert (NULL == GNUNET_CLIENT_connecT (cfg, - "invalid-service", - NULL, - &mq_error_handler, - NULL)); - - /* test IPC between client and server */ - sap[0] = (struct sockaddr *) &sa; - slens[0] = sizeof (sa); - sap[1] = NULL; - slens[1] = 0; - memset (&sa, 0, sizeof (sa)); -#if HAVE_SOCKADDR_IN_SIN_LEN - sa.sin_len = sizeof (sa); -#endif - sa.sin_family = AF_INET; - sa.sin_port = htons (PORT); - server = - GNUNET_SERVER_create (NULL, NULL, sap, slens, - GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_SECONDS, 10), GNUNET_NO); - GNUNET_assert (server != NULL); - handlers[0].callback_cls = cls; - handlers[1].callback_cls = cls; - GNUNET_SERVER_add_handlers (server, handlers); - mq = GNUNET_CLIENT_connecT (cfg, - MYNAME, - chandlers, - &mq_error_handler, - NULL); - GNUNET_assert (NULL != mq); + GNUNET_assert (NULL == + GNUNET_CLIENT_connecT (cfg, + "invalid-service", + NULL, + &mq_error_handler, + NULL)); + client_mq = GNUNET_CLIENT_connecT (cfg, + "test_client", + chandlers, + &mq_error_handler, + NULL); + GNUNET_assert (NULL != client_mq); env = GNUNET_MQ_msg (msg, MY_TYPE); - GNUNET_MQ_send (mq, + GNUNET_MQ_send (client_mq, env); } +/** + * Function called when the client connects to the service. + * + * @param cls the name of the service + * @param c connecting client + * @param mq message queue to talk to the client + * @return @a c + */ +static void * +connect_cb (void *cls, + struct GNUNET_SERVICE_Client *c, + struct GNUNET_MQ_Handle *mq) +{ + return c; +} + + +/** + * Function called when the client disconnects. + * + * @param cls our service name + * @param c disconnecting client + * @param internal_cls must match @a c + */ +static void +disconnect_cb (void *cls, + struct GNUNET_SERVICE_Client *c, + void *internal_cls) +{ + if (2 == global_ret) + { + GNUNET_SCHEDULER_shutdown (); + global_ret = 0; + } +} + + int -main (int argc, char *argv[]) +main (int argc, + char *argv[]) { - int ok; + struct GNUNET_MQ_MessageHandler shandlers[] = { + GNUNET_MQ_hd_fixed_size (echo, + MY_TYPE, + struct GNUNET_MessageHeader, + NULL), + GNUNET_MQ_handler_end () + }; + char * test_argv[] = { + (char *) "test_client", + "-c", + "test_client_data.conf", + NULL + }; GNUNET_log_setup ("test_client", "WARNING", NULL); - cfg = GNUNET_CONFIGURATION_create (); - GNUNET_CONFIGURATION_set_value_number (cfg, MYNAME, "PORT", PORT); - GNUNET_CONFIGURATION_set_value_string (cfg, MYNAME, "HOSTNAME", "localhost"); - ok = 1; - GNUNET_SCHEDULER_run (&task, &ok); - GNUNET_CONFIGURATION_destroy (cfg); - return ok; + if (0 != strstr (argv[0], + "unix")) + test_argv[2] = "test_client_unix.conf"; + global_ret = 1; + if (0 != + GNUNET_SERVICE_ruN_ (3, + test_argv, + "test_client", + GNUNET_SERVICE_OPTION_NONE, + &task, + &connect_cb, + &disconnect_cb, + NULL, + shandlers)) + global_ret = 3; + return global_ret; } /* end of test_client.c */ diff --git a/src/util/test_client_data.conf b/src/util/test_client_data.conf new file mode 100644 index 000000000..fa9a0be03 --- /dev/null +++ b/src/util/test_client_data.conf @@ -0,0 +1,3 @@ +[test_client] +PORT=14325 +HOSTNAME=localhost diff --git a/src/util/test_client_unix.conf b/src/util/test_client_unix.conf new file mode 100644 index 000000000..d3d90627d --- /dev/null +++ b/src/util/test_client_unix.conf @@ -0,0 +1,6 @@ +[test_client] +PORT=0 +HOSTNAME=localhost +UNIXPATH=$GNUNET_RUNTIME_DIR/test-client-unix.sock +UNIX_MATCH_UID = YES +UNIX_MATCH_GID = YES diff --git a/src/util/test_mq_client.c b/src/util/test_mq_client.c deleted file mode 100644 index f436d1a4c..000000000 --- a/src/util/test_mq_client.c +++ /dev/null @@ -1,182 +0,0 @@ -/* - This file is part of GNUnet. - Copyright (C) 2012 GNUnet e.V. - - GNUnet is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3, or (at your - option) any later version. - - GNUnet is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with GNUnet; see the file COPYING. If not, write to the - Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -/** - * @file util/test_mq_client.c - * @brief tests for mq with connection client - */ -#include "platform.h" -#include "gnunet_util_lib.h" - -#define PORT 23336 - -#define MY_TYPE 128 - - -static struct GNUNET_SERVER_Handle *server; - -static struct GNUNET_CONFIGURATION_Handle *cfg; - -static int ok; - -static int notify = GNUNET_NO; - -static int received = 0; - - -static void -recv_cb (void *cls, - struct GNUNET_SERVER_Client *argclient, - const struct GNUNET_MessageHeader *message) -{ - received++; - if (received == 2) - { - GNUNET_SERVER_receive_done (argclient, - GNUNET_NO); - return; - } - - /* can happen if notify does not work */ - GNUNET_assert (received < 2); - - GNUNET_SERVER_receive_done (argclient, GNUNET_YES); -} - - -static void -clean_up (void *cls) -{ - GNUNET_SERVER_destroy (server); - server = NULL; - GNUNET_CONFIGURATION_destroy (cfg); - cfg = NULL; -} - - -/** - * Functions with this signature are called whenever a client - * is disconnected on the network level. - * - * @param cls closure - * @param client identification of the client - */ -static void -notify_disconnect (void *cls, - struct GNUNET_SERVER_Client *client) -{ - if (client == NULL) - return; - ok = 0; - GNUNET_SCHEDULER_add_now (&clean_up, NULL); -} - - -static struct GNUNET_SERVER_MessageHandler handlers[] = { - {&recv_cb, NULL, MY_TYPE, sizeof (struct GNUNET_MessageHeader)}, - {NULL, NULL, 0, 0} -}; - - -static void -send_cb (void *cls) -{ - /* the notify should only be called once */ - GNUNET_assert (GNUNET_NO == notify); - notify = GNUNET_YES; -} - -static void -send_trap_cb (void *cls) -{ - GNUNET_assert (0); -} - - -static void -test_mq () -{ - struct GNUNET_MQ_Handle *mq; - struct GNUNET_MQ_Envelope *mqm; - - /* FIXME: test handling responses */ - mq = GNUNET_CLIENT_connecT (cfg, - "test", - NULL, NULL, NULL); - - mqm = GNUNET_MQ_msg_header (MY_TYPE); - GNUNET_MQ_send (mq, mqm); - - mqm = GNUNET_MQ_msg_header (MY_TYPE); - GNUNET_MQ_notify_sent (mqm, &send_trap_cb, NULL); - GNUNET_MQ_send (mq, mqm); - GNUNET_MQ_send_cancel (mqm); - - mqm = GNUNET_MQ_msg_header (MY_TYPE); - GNUNET_MQ_notify_sent (mqm, &send_cb, NULL); - GNUNET_MQ_send (mq, mqm); -} - - -static void -task (void *cls) -{ - struct sockaddr_in sa; - struct sockaddr *sap[2]; - socklen_t slens[2]; - - sap[0] = (struct sockaddr *) &sa; - slens[0] = sizeof (sa); - sap[1] = NULL; - slens[1] = 0; - memset (&sa, 0, sizeof (sa)); -#if HAVE_SOCKADDR_IN_SIN_LEN - sa.sin_len = sizeof (sa); -#endif - sa.sin_family = AF_INET; - sa.sin_port = htons (PORT); - server = - GNUNET_SERVER_create (NULL, NULL, sap, slens, - GNUNET_TIME_relative_multiply - (GNUNET_TIME_UNIT_MILLISECONDS, 250), GNUNET_NO); - GNUNET_assert (server != NULL); - handlers[0].callback_cls = cls; - GNUNET_SERVER_add_handlers (server, handlers); - GNUNET_SERVER_disconnect_notify (server, ¬ify_disconnect, cls); - cfg = GNUNET_CONFIGURATION_create (); - GNUNET_CONFIGURATION_set_value_number (cfg, "test", "PORT", PORT); - GNUNET_CONFIGURATION_set_value_string (cfg, "test", "HOSTNAME", "localhost"); - GNUNET_CONFIGURATION_set_value_string (cfg, "resolver", "HOSTNAME", - "localhost"); - test_mq (); -} - - -int -main (int argc, char *argv[]) -{ - GNUNET_log_setup ("test-mq-client", - "INFO", - NULL); - ok = 1; - GNUNET_SCHEDULER_run (&task, NULL); - GNUNET_assert (GNUNET_YES == notify); - return ok; -} diff --git a/src/util/test_service_data.conf b/src/util/test_service_data.conf index 7f6baaab1..c04626b5b 100644 --- a/src/util/test_service_data.conf +++ b/src/util/test_service_data.conf @@ -2,7 +2,6 @@ PORT=12435 BINDTO=localhost PIDFILE=/tmp/test-service.pid -TIMEOUT=30 s MAXBUF=1024 DISABLEV6=NO ACCEPT_FROM=127.0.0.1; -- 2.25.1