From 64fda257bdaf166ed3d96dce3a01ea14017a2a3e Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Mon, 19 Sep 2016 13:26:44 +0000 Subject: misc minor fixes for new service MQ API, implementing resolver using new service API --- src/util/gnunet-service-resolver.c | 410 ++++++++++++++++++++++++------------- src/util/mq.c | 13 +- 2 files changed, 275 insertions(+), 148 deletions(-) (limited to 'src/util') diff --git a/src/util/gnunet-service-resolver.c b/src/util/gnunet-service-resolver.c index a87b1f5d0..12e484845 100644 --- a/src/util/gnunet-service-resolver.c +++ b/src/util/gnunet-service-resolver.c @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - Copyright (C) 2007-2013 GNUnet e.V. + Copyright (C) 2007-2016 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 @@ -196,6 +196,22 @@ cache_resolve (struct IPCache *cache) } +/** + * Function called after the replies for the request have all + * been transmitted to the client, and we can now read the next + * request from the client. + * + * @param cls the `struct GNUNET_SERVICE_Client` to continue with + */ +static void +notify_service_client_done (void *cls) +{ + struct GNUNET_SERVICE_Client *client = cls; + + GNUNET_SERVICE_client_continue (client); +} + + /** * Get an IP address as a string (works for both IPv4 and IPv6). Note * that the resolution happens asynchronously and that the first call @@ -207,16 +223,19 @@ cache_resolve (struct IPCache *cache) * @param ip `struct in_addr` or `struct in6_addr` */ static void -get_ip_as_string (struct GNUNET_SERVER_Client *client, +get_ip_as_string (struct GNUNET_SERVICE_Client *client, int af, const void *ip) { struct IPCache *pos; struct IPCache *next; struct GNUNET_TIME_Absolute now; - struct GNUNET_SERVER_TransmitContext *tc; + struct GNUNET_MQ_Envelope *env; + struct GNUNET_MQ_Handle *mq; + struct GNUNET_MessageHeader *msg; size_t ip_len; struct in6_addr ix; + size_t alen; switch (af) { @@ -267,7 +286,9 @@ get_ip_as_string (struct GNUNET_SERVER_Client *client, { pos = GNUNET_malloc (sizeof (struct IPCache) + ip_len); pos->ip = &pos[1]; - GNUNET_memcpy (&pos[1], ip, ip_len); + GNUNET_memcpy (&pos[1], + ip, + ip_len); pos->last_request = now; pos->last_refresh = now; pos->ip_len = ip_len; @@ -277,29 +298,41 @@ get_ip_as_string (struct GNUNET_SERVER_Client *client, pos); cache_resolve (pos); } - tc = GNUNET_SERVER_transmit_context_create (client); if (NULL != pos->addr) - GNUNET_SERVER_transmit_context_append_data (tc, pos->addr, - strlen (pos->addr) + 1, - GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE); + alen = strlen (pos->addr) + 1; else - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Reverse lookup failed\n"); - GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0, - GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE); - GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL); + alen = 0; + mq = GNUNET_SERVICE_client_get_mq (client); + env = GNUNET_MQ_msg_extra (msg, + alen, + GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE); + GNUNET_memcpy (&msg[1], + pos->addr, + alen); + GNUNET_MQ_send (mq, + env); + env = GNUNET_MQ_msg (msg, + GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE); + GNUNET_MQ_notify_sent (env, + ¬ify_service_client_done, + client); + GNUNET_MQ_send (mq, + env); } #if HAVE_GETADDRINFO static int -getaddrinfo_resolve (struct GNUNET_SERVER_TransmitContext *tc, - const char *hostname, int af) +getaddrinfo_resolve (struct GNUNET_MQ_Handle *mq, + const char *hostname, + int af) { int s; struct addrinfo hints; struct addrinfo *result; struct addrinfo *pos; + struct GNUNET_MessageHeader *msg; + struct GNUNET_MQ_Envelope *env; #ifdef WINDOWS /* Due to a bug, getaddrinfo will not return a mix of different families */ @@ -307,21 +340,32 @@ getaddrinfo_resolve (struct GNUNET_SERVER_TransmitContext *tc, { int ret1; int ret2; - ret1 = getaddrinfo_resolve (tc, hostname, AF_INET); - ret2 = getaddrinfo_resolve (tc, hostname, AF_INET6); - if ((ret1 == GNUNET_OK) || (ret2 == GNUNET_OK)) + ret1 = getaddrinfo_resolve (mq, + hostname, + AF_INET); + ret2 = getaddrinfo_resolve (mq, + hostname, + AF_INET6); + if ( (ret1 == GNUNET_OK) || + (ret2 == GNUNET_OK) ) return GNUNET_OK; - if ((ret1 == GNUNET_SYSERR) || (ret2 == GNUNET_SYSERR)) + if ( (ret1 == GNUNET_SYSERR) || + (ret2 == GNUNET_SYSERR) ) return GNUNET_SYSERR; return GNUNET_NO; } #endif - memset (&hints, 0, sizeof (struct addrinfo)); + memset (&hints, + 0, + sizeof (struct addrinfo)); hints.ai_family = af; hints.ai_socktype = SOCK_STREAM; /* go for TCP */ - if (0 != (s = getaddrinfo (hostname, NULL, &hints, &result))) + if (0 != (s = getaddrinfo (hostname, + NULL, + &hints, + &result))) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Could not resolve `%s' (%s): %s\n"), @@ -329,13 +373,11 @@ getaddrinfo_resolve (struct GNUNET_SERVER_TransmitContext *tc, (af == AF_INET) ? "IPv4" : ((af == AF_INET6) ? "IPv6" : "any"), gai_strerror (s)); - if ((s == EAI_BADFLAGS) || (s == EAI_MEMORY) + if ( (s == EAI_BADFLAGS) || #ifndef WINDOWS - || (s == EAI_SYSTEM) -#else - || 1 + (s == EAI_SYSTEM) || #endif - ) + (s == EAI_MEMORY) ) return GNUNET_NO; /* other function may still succeed */ return GNUNET_SYSERR; } @@ -346,16 +388,24 @@ getaddrinfo_resolve (struct GNUNET_SERVER_TransmitContext *tc, switch (pos->ai_family) { case AF_INET: - GNUNET_SERVER_transmit_context_append_data (tc, - &((struct sockaddr_in*) pos->ai_addr)->sin_addr, - sizeof (struct in_addr), - GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE); + env = GNUNET_MQ_msg_extra (msg, + sizeof (struct in_addr), + GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE); + GNUNET_memcpy (&msg[1], + &((struct sockaddr_in*) pos->ai_addr)->sin_addr, + sizeof (struct in_addr)); + GNUNET_MQ_send (mq, + env); break; case AF_INET6: - GNUNET_SERVER_transmit_context_append_data (tc, - &((struct sockaddr_in6*) pos->ai_addr)->sin6_addr, - sizeof (struct in6_addr), - GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE); + env = GNUNET_MQ_msg_extra (msg, + sizeof (struct in6_addr), + GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE); + GNUNET_memcpy (&msg[1], + &((struct sockaddr_in6*) pos->ai_addr)->sin6_addr, + sizeof (struct in6_addr)); + GNUNET_MQ_send (mq, + env); break; default: /* unsupported, skip */ @@ -371,13 +421,15 @@ getaddrinfo_resolve (struct GNUNET_SERVER_TransmitContext *tc, static int -gethostbyname2_resolve (struct GNUNET_SERVER_TransmitContext *tc, +gethostbyname2_resolve (struct GNUNET_MQ_Handle *mq, const char *hostname, int af) { struct hostent *hp; int ret1; int ret2; + struct GNUNET_MQ_Envelope *env; + struct GNUNET_MessageHeader *msg; #ifdef WINDOWS /* gethostbyname2() in plibc is a compat dummy that calls gethostbyname(). */ @@ -386,19 +438,27 @@ gethostbyname2_resolve (struct GNUNET_SERVER_TransmitContext *tc, if (af == AF_UNSPEC) { - ret1 = gethostbyname2_resolve (tc, hostname, AF_INET); - ret2 = gethostbyname2_resolve (tc, hostname, AF_INET6); - if ((ret1 == GNUNET_OK) || (ret2 == GNUNET_OK)) + ret1 = gethostbyname2_resolve (mq, + hostname, + AF_INET); + ret2 = gethostbyname2_resolve (mq, + hostname, + AF_INET6); + if ( (ret1 == GNUNET_OK) || + (ret2 == GNUNET_OK) ) return GNUNET_OK; - if ((ret1 == GNUNET_SYSERR) || (ret2 == GNUNET_SYSERR)) + if ( (ret1 == GNUNET_SYSERR) || + (ret2 == GNUNET_SYSERR) ) return GNUNET_SYSERR; return GNUNET_NO; } - hp = gethostbyname2 (hostname, af); + hp = gethostbyname2 (hostname, + af); if (hp == NULL) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, - _("Could not find IP of host `%s': %s\n"), hostname, + _("Could not find IP of host `%s': %s\n"), + hostname, hstrerror (h_errno)); return GNUNET_SYSERR; } @@ -407,17 +467,25 @@ gethostbyname2_resolve (struct GNUNET_SERVER_TransmitContext *tc, { case AF_INET: GNUNET_assert (hp->h_length == sizeof (struct in_addr)); - GNUNET_SERVER_transmit_context_append_data (tc, - hp->h_addr_list[0], - hp->h_length, - GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE); + env = GNUNET_MQ_msg_extra (msg, + hp->h_length, + GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE); + GNUNET_memcpy (&msg[1], + hp->h_addr_list[0], + hp->h_length); + GNUNET_MQ_send (mq, + env); break; case AF_INET6: GNUNET_assert (hp->h_length == sizeof (struct in6_addr)); - GNUNET_SERVER_transmit_context_append_data (tc, - hp->h_addr_list[0], - hp->h_length, - GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE); + env = GNUNET_MQ_msg_extra (msg, + hp->h_length, + GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE); + GNUNET_memcpy (&msg[1], + hp->h_addr_list[0], + hp->h_length); + GNUNET_MQ_send (mq, + env); break; default: GNUNET_break (0); @@ -430,10 +498,12 @@ gethostbyname2_resolve (struct GNUNET_SERVER_TransmitContext *tc, static int -gethostbyname_resolve (struct GNUNET_SERVER_TransmitContext *tc, - const char *hostname) +gethostbyname_resolve (struct GNUNET_MQ_Handle *mq, + const char *hostname) { struct hostent *hp; + struct GNUNET_MessageHeader *msg; + struct GNUNET_MQ_Envelope *env; hp = GETHOSTBYNAME (hostname); if (NULL == hp) @@ -450,10 +520,14 @@ gethostbyname_resolve (struct GNUNET_SERVER_TransmitContext *tc, return GNUNET_SYSERR; } GNUNET_assert (hp->h_length == sizeof (struct in_addr)); - GNUNET_SERVER_transmit_context_append_data (tc, - hp->h_addr_list[0], - hp->h_length, - GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE); + env = GNUNET_MQ_msg_extra (msg, + hp->h_length, + GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE); + GNUNET_memcpy (&msg[1], + hp->h_addr_list[0], + hp->h_length); + GNUNET_MQ_send (mq, + env); return GNUNET_OK; } #endif @@ -467,168 +541,197 @@ gethostbyname_resolve (struct GNUNET_SERVER_TransmitContext *tc, * @param af AF_INET or AF_INET6; use AF_UNSPEC for "any" */ static void -get_ip_from_hostname (struct GNUNET_SERVER_Client *client, +get_ip_from_hostname (struct GNUNET_SERVICE_Client *client, const char *hostname, int af) { int ret; - struct GNUNET_SERVER_TransmitContext *tc; + struct GNUNET_MQ_Handle *mq; + struct GNUNET_MQ_Envelope *env; + struct GNUNET_MessageHeader *msg; - tc = GNUNET_SERVER_transmit_context_create (client); + mq = GNUNET_SERVICE_client_get_mq (client); ret = GNUNET_NO; #if HAVE_GETADDRINFO if (ret == GNUNET_NO) - ret = getaddrinfo_resolve (tc, hostname, af); + ret = getaddrinfo_resolve (mq, + hostname, + af); #elif HAVE_GETHOSTBYNAME2 if (ret == GNUNET_NO) - ret = gethostbyname2_resolve (tc, hostname, af); + ret = gethostbyname2_resolve (mq, + hostname, + af); #elif HAVE_GETHOSTBYNAME - if ((ret == GNUNET_NO) && ((af == AF_UNSPEC) || (af == PF_INET))) - gethostbyname_resolve (tc, hostname); + if ( (ret == GNUNET_NO) && + ( (af == AF_UNSPEC) || + (af == PF_INET) ) ) + gethostbyname_resolve (mq, + hostname); #endif - GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0, - GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE); - GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL); + env = GNUNET_MQ_msg (msg, + GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE); + GNUNET_MQ_notify_sent (env, + ¬ify_service_client_done, + client); + GNUNET_MQ_send (mq, + env); } /** - * Handle GET-message. + * Verify well-formedness of GET-message. * * @param cls closure - * @param client identification of the client - * @param message the actual message + * @param get the actual message + * @return #GNUNET_OK if @a get is well-formed */ -static void -handle_get (void *cls, - struct GNUNET_SERVER_Client *client, - const struct GNUNET_MessageHeader *message) +static int +check_get (void *cls, + const struct GNUNET_RESOLVER_GetMessage *get) { - uint16_t msize; - const struct GNUNET_RESOLVER_GetMessage *msg; - const void *ip; uint16_t size; int direction; int af; - msize = ntohs (message->size); - if (msize < sizeof (struct GNUNET_RESOLVER_GetMessage)) - { - GNUNET_break (0); - GNUNET_SERVER_receive_done (client, - GNUNET_SYSERR); - return; - } - msg = (const struct GNUNET_RESOLVER_GetMessage *) message; - size = msize - sizeof (struct GNUNET_RESOLVER_GetMessage); - direction = ntohl (msg->direction); - af = ntohl (msg->af); + size = ntohs (get->header.size) - sizeof (*get); + direction = ntohl (get->direction); if (GNUNET_NO == direction) { /* IP from hostname */ const char *hostname; - hostname = (const char *) &msg[1]; + hostname = (const char *) &get[1]; if (hostname[size - 1] != '\0') { GNUNET_break (0); - GNUNET_SERVER_receive_done (client, - GNUNET_SYSERR); - return; + return GNUNET_SYSERR; } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Resolver asked to look up `%s'.\n", - hostname); - get_ip_from_hostname (client, hostname, af); - return; + return GNUNET_OK; } - ip = &msg[1]; + af = ntohl (get->af); switch (af) { case AF_INET: if (size != sizeof (struct in_addr)) { GNUNET_break (0); - GNUNET_SERVER_receive_done (client, - GNUNET_SYSERR); - return; + return GNUNET_SYSERR; } break; case AF_INET6: if (size != sizeof (struct in6_addr)) { GNUNET_break (0); - GNUNET_SERVER_receive_done (client, - GNUNET_SYSERR); - return; + return GNUNET_SYSERR; } break; default: GNUNET_break (0); - GNUNET_SERVER_receive_done (client, - GNUNET_SYSERR); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +/** + * Handle GET-message. + * + * @param cls identification of the client + * @param msg the actual message + */ +static void +handle_get (void *cls, + const struct GNUNET_RESOLVER_GetMessage *msg) +{ + struct GNUNET_SERVICE_Client *client = cls; + const void *ip; + int direction; + int af; + + direction = ntohl (msg->direction); + af = ntohl (msg->af); + if (GNUNET_NO == direction) + { + /* IP from hostname */ + const char *hostname; + + hostname = (const char *) &msg[1]; + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Resolver asked to look up `%s'.\n", + hostname); + get_ip_from_hostname (client, + hostname, + af); return; } + ip = &msg[1]; { char buf[INET6_ADDRSTRLEN]; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Resolver asked to look up IP address `%s'.\n", - inet_ntop (af, ip, buf, sizeof (buf))); + inet_ntop (af, + ip, + buf, + sizeof (buf))); } - get_ip_as_string (client, af, ip); + get_ip_as_string (client, + af, + ip); } /** - * Process resolver requests. + * Callback called when a client connects to the service. * - * @param cls closure - * @param server the initialized server - * @param cfg configuration to use + * @param cls closure for the service + * @param c the new client that connected to the service + * @param mq the message queue used to send messages to the client + * @return @a c */ -static void -run (void *cls, struct GNUNET_SERVER_Handle *server, - const struct GNUNET_CONFIGURATION_Handle *cfg) +static void * +connect_cb (void *cls, + struct GNUNET_SERVICE_Client *c, + struct GNUNET_MQ_Handle *mq) { - static const struct GNUNET_SERVER_MessageHandler handlers[] = { - {&handle_get, NULL, GNUNET_MESSAGE_TYPE_RESOLVER_REQUEST, 0}, - {NULL, NULL, 0, 0} - }; - GNUNET_SERVER_add_handlers (server, handlers); + return c; } /** - * The main function for the resolver service. + * Callback called when a client disconnected from the service * - * @param argc number of arguments from the command line - * @param argv command line arguments - * @return 0 ok, 1 on error + * @param cls closure for the service + * @param c the client that disconnected + * @param internal_cls should be equal to @a c */ -int -main (int argc, char *const *argv) +static void +disconnect_cb (void *cls, + struct GNUNET_SERVICE_Client *c, + void *internal_cls) { - struct IPCache *pos; - int ret; - - ret = - (GNUNET_OK == - GNUNET_SERVICE_run (argc, argv, - "resolver", - GNUNET_SERVICE_OPTION_NONE, - &run, NULL)) ? 0 : 1; - while (NULL != (pos = cache_head)) - { - GNUNET_CONTAINER_DLL_remove (cache_head, - cache_tail, - pos); - GNUNET_free_non_null (pos->addr); - GNUNET_free (pos); - } - return ret; + GNUNET_assert (c == internal_cls); } + +/** + * Define "main" method using service macro. + */ +GNUNET_SERVICE_MAIN +("resolver", + GNUNET_SERVICE_OPTION_NONE, + NULL, + &connect_cb, + &disconnect_cb, + NULL, + GNUNET_MQ_hd_var_size (get, + GNUNET_MESSAGE_TYPE_RESOLVER_REQUEST, + struct GNUNET_RESOLVER_GetMessage, + NULL), + GNUNET_MQ_handler_end ()); + + #if defined(LINUX) && defined(__GLIBC__) #include @@ -636,7 +739,7 @@ main (int argc, char *const *argv) * MINIMIZE heap size (way below 128k) since this process doesn't need much. */ void __attribute__ ((constructor)) -GNUNET_ARM_memory_init () +GNUNET_RESOLVER_memory_init () { mallopt (M_TRIM_THRESHOLD, 4 * 1024); mallopt (M_TOP_PAD, 1 * 1024); @@ -645,4 +748,23 @@ GNUNET_ARM_memory_init () #endif +/** + * Free globals on exit. + */ +void __attribute__ ((destructor)) +GNUNET_RESOLVER_memory_done () +{ + struct IPCache *pos; + + while (NULL != (pos = cache_head)) + { + GNUNET_CONTAINER_DLL_remove (cache_head, + cache_tail, + pos); + GNUNET_free_non_null (pos->addr); + GNUNET_free (pos); + } +} + + /* end of gnunet-service-resolver.c */ diff --git a/src/util/mq.c b/src/util/mq.c index b22d97f59..e9dba3d9d 100644 --- a/src/util/mq.c +++ b/src/util/mq.c @@ -359,6 +359,7 @@ GNUNET_MQ_send (struct GNUNET_MQ_Handle *mq, GNUNET_assert (NULL != mq); GNUNET_assert (NULL == ev->parent_queue); + mq->queue_length++; ev->parent_queue = mq; /* is the implementation busy? queue it! */ if (NULL != mq->current_envelope) @@ -366,11 +367,12 @@ GNUNET_MQ_send (struct GNUNET_MQ_Handle *mq, GNUNET_CONTAINER_DLL_insert_tail (mq->envelope_head, mq->envelope_tail, ev); - mq->queue_length++; return; } mq->current_envelope = ev; - mq->send_impl (mq, ev->mh, mq->impl_state); + mq->send_impl (mq, + ev->mh, + mq->impl_state); } @@ -422,6 +424,8 @@ impl_send_continue (void *cls) current_envelope = mq->current_envelope; GNUNET_assert (NULL != current_envelope); current_envelope->parent_queue = NULL; + GNUNET_assert (0 < mq->queue_length); + mq->queue_length--; if (NULL == mq->envelope_head) { mq->current_envelope = NULL; @@ -432,7 +436,6 @@ impl_send_continue (void *cls) GNUNET_CONTAINER_DLL_remove (mq->envelope_head, mq->envelope_tail, mq->current_envelope); - mq->queue_length--; mq->send_impl (mq, mq->current_envelope->mh, mq->impl_state); @@ -973,7 +976,6 @@ GNUNET_MQ_destroy (struct GNUNET_MQ_Handle *mq) mq->queue_length--; GNUNET_MQ_discard (ev); } - GNUNET_assert (0 == mq->queue_length); if (NULL != mq->current_envelope) { /* we can only discard envelopes that @@ -981,7 +983,9 @@ GNUNET_MQ_destroy (struct GNUNET_MQ_Handle *mq) mq->current_envelope->parent_queue = NULL; GNUNET_MQ_discard (mq->current_envelope); mq->current_envelope = NULL; + mq->queue_length--; } + GNUNET_assert (0 == mq->queue_length); if (NULL != mq->assoc_map) { GNUNET_CONTAINER_multihashmap32_destroy (mq->assoc_map); @@ -1039,6 +1043,7 @@ GNUNET_MQ_send_cancel (struct GNUNET_MQ_Envelope *ev) { // complex case, we already started with transmitting // the message + mq->queue_length--; mq->cancel_impl (mq, mq->impl_state); // continue sending the next message, if any -- cgit v1.2.3