X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Futil%2Fgnunet-service-resolver.c;h=cd40728362185e7c5fe1f4142b0b63df11555b4a;hb=4e29ecde9b3ad3e34af359f18b6679c06b17ce78;hp=5d4c5c224a184659ab63b5dd282a42e3d8919a44;hpb=83b19539f4d322b43683f5838b72e9ec2c8e6073;p=oweals%2Fgnunet.git diff --git a/src/util/gnunet-service-resolver.c b/src/util/gnunet-service-resolver.c index 5d4c5c224..cd4072836 100644 --- a/src/util/gnunet-service-resolver.c +++ b/src/util/gnunet-service-resolver.c @@ -1,21 +1,16 @@ /* This file is part of GNUnet. - (C) 2007, 2008, 2009 Christian Grothoff (and other contributing authors) + 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 - by the Free Software Foundation; either version 2, or (at your - option) any later version. + GNUnet is free software: you can redistribute it and/or modify it + under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, + 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., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. + Affero General Public License for more details. */ /** @@ -24,34 +19,35 @@ * @author Christian Grothoff */ #include "platform.h" -#include "gnunet_disk_lib.h" -#include "gnunet_getopt_lib.h" +#include "gnunet_util_lib.h" #include "gnunet_protocols.h" -#include "gnunet_service_lib.h" #include "gnunet_statistics_service.h" -#include "gnunet_strings_lib.h" -#include "gnunet_time_lib.h" #include "resolver.h" /** - * A cached DNS lookup result. + * A cached DNS lookup result (for reverse lookup). */ struct IPCache { /** - * This is a linked list. + * This is a doubly linked list. */ struct IPCache *next; + /** + * This is a doubly linked list. + */ + struct IPCache *prev; + /** * Hostname in human-readable form. */ char *addr; /** - * Hostname in binary format. + * Binary IP address, allocated at the end of this struct. */ - struct sockaddr *sa; + const void *ip; /** * Last time this entry was updated. @@ -64,16 +60,26 @@ struct IPCache struct GNUNET_TIME_Absolute last_request; /** - * Number of bytes in sa. + * Number of bytes in ip. + */ + size_t ip_len; + + /** + * Address family of the IP. */ - socklen_t salen; + int af; }; /** * Start of the linked list of cached DNS lookup results. */ -static struct IPCache *head; +static struct IPCache *cache_head; + +/** + * Tail of the linked list of cached DNS lookup results. + */ +static struct IPCache *cache_tail; #if HAVE_GETNAMEINFO @@ -86,11 +92,54 @@ static void getnameinfo_resolve (struct IPCache *cache) { char hostname[256]; + const struct sockaddr *sa; + struct sockaddr_in v4; + struct sockaddr_in6 v6; + size_t salen; + int ret; + + switch (cache->af) + { + case AF_INET: + GNUNET_assert (cache->ip_len == sizeof (struct in_addr)); + sa = (const struct sockaddr*) &v4; + memset (&v4, 0, sizeof (v4)); + v4.sin_addr = * (const struct in_addr*) cache->ip; + v4.sin_family = AF_INET; +#if HAVE_SOCKADDR_IN_SIN_LEN + v4.sin_len = sizeof (v4); +#endif + salen = sizeof (v4); + break; + case AF_INET6: + GNUNET_assert (cache->ip_len == sizeof (struct in6_addr)); + sa = (const struct sockaddr*) &v6; + memset (&v6, 0, sizeof (v6)); + v6.sin6_addr = * (const struct in6_addr*) cache->ip; + v6.sin6_family = AF_INET6; +#if HAVE_SOCKADDR_IN_SIN_LEN + v6.sin6_len = sizeof (v6); +#endif + salen = sizeof (v6); + break; + default: + GNUNET_assert (0); + } if (0 == - getnameinfo (cache->sa, cache->salen, hostname, sizeof (hostname), NULL, - 0, 0)) + (ret = getnameinfo (sa, salen, + hostname, sizeof (hostname), + NULL, + 0, 0))) + { cache->addr = GNUNET_strdup (hostname); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "getnameinfo failed: %s\n", + gai_strerror (ret)); + } } #endif @@ -106,26 +155,23 @@ gethostbyaddr_resolve (struct IPCache *cache) { struct hostent *ent; - switch (cache->sa->sa_family) + ent = gethostbyaddr (cache->ip, + cache->ip_len, + cache->af); + if (NULL != ent) { - case AF_INET: - ent = - gethostbyaddr (&((struct sockaddr_in *) cache->sa)->sin_addr, - sizeof (struct in_addr), AF_INET); - break; - case AF_INET6: - ent = - gethostbyaddr (&((struct sockaddr_in6 *) cache->sa)->sin6_addr, - sizeof (struct in6_addr), AF_INET6); - break; - default: - ent = NULL; - } - if (ent != NULL) cache->addr = GNUNET_strdup (ent->h_name); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "gethostbyaddr failed: %s\n", + hstrerror (h_errno)); + } } #endif + /** * Resolve the given request using the available methods. * @@ -135,16 +181,31 @@ static void cache_resolve (struct IPCache *cache) { #if HAVE_GETNAMEINFO - if (cache->addr == NULL) + if (NULL == cache->addr) getnameinfo_resolve (cache); #endif #if HAVE_GETHOSTBYADDR - if (cache->addr == NULL) + if (NULL == cache->addr) gethostbyaddr_resolve (cache); #endif } +/** + * 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 @@ -153,213 +214,298 @@ cache_resolve (struct IPCache *cache) * human-readable IP address). * * @param client handle to the client making the request (for sending the reply) - * @param sa should be of type "struct sockaddr*" - * @param salen number of bytes in sa + * @param af AF_INET or AF_INET6 + * @param ip `struct in_addr` or `struct in6_addr` */ static void -get_ip_as_string (struct GNUNET_SERVER_Client *client, - const struct sockaddr *sa, socklen_t salen) +get_ip_as_string (struct GNUNET_SERVICE_Client *client, + int af, + const void *ip) { - struct IPCache *cache; - struct IPCache *prev; + struct IPCache *pos; + struct IPCache *next; struct GNUNET_TIME_Absolute now; - struct GNUNET_SERVER_TransmitContext *tc; - - if (salen < sizeof (struct sockaddr)) + 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) { - GNUNET_break (0); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; + case AF_INET: + ip_len = sizeof (struct in_addr); + break; + case AF_INET6: + ip_len = sizeof (struct in6_addr); + break; + default: + GNUNET_assert (0); } now = GNUNET_TIME_absolute_get (); - cache = head; - prev = NULL; - while ((cache != NULL) && - ((cache->salen != salen) || (0 != memcmp (cache->sa, sa, salen)))) + next = cache_head; + while ( (NULL != (pos = next)) && + ( (pos->af != af) || + (pos->ip_len != ip_len) || + (0 != memcmp (pos->ip, ip, ip_len))) ) { - if (GNUNET_TIME_absolute_get_duration (cache->last_request).rel_value < - 60 * 60 * 1000) + next = pos->next; + if (GNUNET_TIME_absolute_get_duration (pos->last_request).rel_value_us < + 60 * 60 * 1000 * 1000LL) { - if (prev != NULL) - { - prev->next = cache->next; - GNUNET_free_non_null (cache->addr); - GNUNET_free (cache->sa); - GNUNET_free (cache); - cache = prev->next; - } - else - { - head = cache->next; - GNUNET_free_non_null (cache->addr); - GNUNET_free (cache->sa); - GNUNET_free (cache); - cache = head; - } + GNUNET_CONTAINER_DLL_remove (cache_head, + cache_tail, + pos); + GNUNET_free_non_null (pos->addr); + GNUNET_free (pos); continue; } - prev = cache; - cache = cache->next; } - if (cache != NULL) + if (NULL != pos) { - cache->last_request = now; - if (GNUNET_TIME_absolute_get_duration (cache->last_request).rel_value < - 60 * 60 * 1000) + if ( (1 == inet_pton (af, + pos->ip, + &ix)) && + (GNUNET_TIME_absolute_get_duration (pos->last_request).rel_value_us > + 120 * 1000 * 1000LL) ) { - GNUNET_free_non_null (cache->addr); - cache->addr = NULL; - cache->salen = 0; - cache_resolve (cache); + /* try again if still numeric AND 2 minutes have expired */ + GNUNET_free_non_null (pos->addr); + pos->addr = NULL; + cache_resolve (pos); + pos->last_request = now; } } else { - cache = GNUNET_malloc (sizeof (struct IPCache)); - cache->next = head; - cache->salen = salen; - cache->sa = GNUNET_malloc (salen); - memcpy (cache->sa, sa, salen); - cache->last_request = GNUNET_TIME_absolute_get (); - cache->last_refresh = GNUNET_TIME_absolute_get (); - cache->addr = NULL; - cache_resolve (cache); - head = cache; + pos = GNUNET_malloc (sizeof (struct IPCache) + ip_len); + pos->ip = &pos[1]; + GNUNET_memcpy (&pos[1], + ip, + ip_len); + pos->last_request = now; + pos->last_refresh = now; + pos->ip_len = ip_len; + pos->af = af; + GNUNET_CONTAINER_DLL_insert (cache_head, + cache_tail, + pos); + cache_resolve (pos); } - tc = GNUNET_SERVER_transmit_context_create (client); - if (cache->addr != NULL) - GNUNET_SERVER_transmit_context_append_data (tc, cache->addr, - strlen (cache->addr) + 1, - GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE); - 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); + if (NULL != pos->addr) + alen = strlen (pos->addr) + 1; + else + 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 domain) +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; - memset (&hints, 0, sizeof (struct addrinfo)); -// FIXME in PlibC -#ifndef MINGW - hints.ai_family = domain; -#else - hints.ai_family = AF_INET; +#ifdef WINDOWS + /* Due to a bug, getaddrinfo will not return a mix of different families */ + if (AF_UNSPEC == af) + { + int ret1; + int ret2; + 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) ) + return GNUNET_SYSERR; + return GNUNET_NO; + } #endif + + 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"), + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + _("Could not resolve `%s' (%s): %s\n"), hostname, - (domain == - AF_INET) ? "IPv4" : ((domain == AF_INET6) ? "IPv6" : "any"), + (af == + AF_INET) ? "IPv4" : ((af == AF_INET6) ? "IPv6" : "any"), gai_strerror (s)); - if ((s == EAI_BADFLAGS) || (s == EAI_MEMORY) -#ifndef MINGW - || (s == EAI_SYSTEM) -#else - // FIXME NILS - || 1 + if ( (s == EAI_BADFLAGS) || +#ifndef WINDOWS + (s == EAI_SYSTEM) || #endif - ) + (s == EAI_MEMORY) ) return GNUNET_NO; /* other function may still succeed */ return GNUNET_SYSERR; } - if (result == NULL) + if (NULL == result) return GNUNET_SYSERR; - pos = result; - while (pos != NULL) + for (pos = result; pos != NULL; pos = pos->ai_next) { - GNUNET_SERVER_transmit_context_append_data (tc, pos->ai_addr, - pos->ai_addrlen, - GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE); - pos = pos->ai_next; + switch (pos->ai_family) + { + case AF_INET: + 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: + 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 */ + break; + } } freeaddrinfo (result); return GNUNET_OK; } -#endif -#if HAVE_GETHOSTBYNAME2 + +#elif HAVE_GETHOSTBYNAME2 + + static int -gethostbyname2_resolve (struct GNUNET_SERVER_TransmitContext *tc, - const char *hostname, int domain) +gethostbyname2_resolve (struct GNUNET_MQ_Handle *mq, + const char *hostname, + int af) { struct hostent *hp; - struct sockaddr_in a4; - struct sockaddr_in6 a6; 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(). */ + return GNUNET_NO; +#endif - if (domain == AF_UNSPEC) + 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, domain); + 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; } - GNUNET_assert (hp->h_addrtype == domain); - if (domain == AF_INET) + GNUNET_assert (hp->h_addrtype == af); + switch (af) { + case AF_INET: GNUNET_assert (hp->h_length == sizeof (struct in_addr)); - memset (&a4, 0, sizeof (a4)); - a4.sin_family = AF_INET; -#if HAVE_SOCKADDR_IN_SIN_LEN - a4.sin_len = (u_char) sizeof (struct sockaddr_in); -#endif - memcpy (&a4.sin_addr, hp->h_addr_list[0], hp->h_length); - GNUNET_SERVER_transmit_context_append_data (tc, &a4, sizeof (a4), - GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE); - } - else - { + 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)); - memset (&a6, 0, sizeof (a6)); - a6.sin6_family = AF_INET6; -#if HAVE_SOCKADDR_IN_SIN_LEN - a6.sin6_len = (u_char) sizeof (struct sockaddr_in6); -#endif - memcpy (&a6.sin6_addr, hp->h_addr_list[0], hp->h_length); - GNUNET_SERVER_transmit_context_append_data (tc, &a6, sizeof (a6), - 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); + return GNUNET_SYSERR; } return GNUNET_OK; } -#endif -#if HAVE_GETHOSTBYNAME +#elif HAVE_GETHOSTBYNAME + + 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 sockaddr_in addr; + struct GNUNET_MessageHeader *msg; + struct GNUNET_MQ_Envelope *env; hp = GETHOSTBYNAME (hostname); - if (hp == NULL) + if (NULL == hp) { 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; } @@ -369,14 +515,14 @@ gethostbyname_resolve (struct GNUNET_SERVER_TransmitContext *tc, return GNUNET_SYSERR; } GNUNET_assert (hp->h_length == sizeof (struct in_addr)); - memset (&addr, 0, sizeof (addr)); - addr.sin_family = AF_INET; -#if HAVE_SOCKADDR_IN_SIN_LEN - addr.sin_len = (u_char) sizeof (struct sockaddr_in); -#endif - memcpy (&addr.sin_addr, hp->h_addr_list[0], hp->h_length); - GNUNET_SERVER_transmit_context_append_data (tc, &addr, sizeof (addr), - 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 @@ -387,177 +533,242 @@ gethostbyname_resolve (struct GNUNET_SERVER_TransmitContext *tc, * * @param client where to send the IP address * @param hostname the hostname to resolve - * @param domain AF_INET or AF_INET6; use AF_UNSPEC for "any" + * @param af AF_INET or AF_INET6; use AF_UNSPEC for "any" */ static void -get_ip_from_hostname (struct GNUNET_SERVER_Client *client, const char *hostname, - int domain) +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, domain); -#endif -#if HAVE_GETHOSTBYNAME2 + ret = getaddrinfo_resolve (mq, + hostname, + af); +#elif HAVE_GETHOSTBYNAME2 if (ret == GNUNET_NO) - ret = gethostbyname2_resolve (tc, hostname, domain); -#endif -#if HAVE_GETHOSTBYNAME - if ((ret == GNUNET_NO) && ((domain == AF_UNSPEC) || (domain == PF_INET))) - gethostbyname_resolve (tc, hostname); + ret = gethostbyname2_resolve (mq, + hostname, + af); +#elif HAVE_GETHOSTBYNAME + 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 cls closure, unused + * @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 char *hostname; - const struct sockaddr *sa; uint16_t size; int direction; - int domain; + 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); - domain = ntohl (msg->domain); - if (direction == GNUNET_NO) + (void) cls; + size = ntohs (get->header.size) - sizeof (*get); + direction = ntohl (get->direction); + if (GNUNET_NO == direction) { /* IP from hostname */ - hostname = (const char *) &msg[1]; + const char *hostname; + + hostname = (const char *) &get[1]; if (hostname[size - 1] != '\0') { GNUNET_break (0); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; + return GNUNET_SYSERR; } -#if DEBUG_RESOLVER - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Resolver asked to look up `%s'.\n"), - hostname); -#endif - get_ip_from_hostname (client, hostname, domain); + return GNUNET_OK; } - else + af = ntohl (get->af); + switch (af) { -#if DEBUG_RESOLVER - char buf[INET6_ADDRSTRLEN]; -#endif - if (size < sizeof (struct sockaddr)) + case AF_INET: + if (size != sizeof (struct in_addr)) { GNUNET_break (0); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; + return GNUNET_SYSERR; } - sa = (const struct sockaddr *) &msg[1]; - switch (sa->sa_family) + break; + case AF_INET6: + if (size != sizeof (struct in6_addr)) { - case AF_INET: - if (size != sizeof (struct sockaddr_in)) - { - GNUNET_break (0); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } -#if DEBUG_RESOLVER - inet_ntop (AF_INET, sa, buf, size); -#endif - break; - case AF_INET6: - if (size != sizeof (struct sockaddr_in6)) - { - GNUNET_break (0); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; - } -#if DEBUG_RESOLVER - inet_ntop (AF_INET6, sa, buf, size); -#endif - break; - default: GNUNET_break (0); - GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); - return; + return GNUNET_SYSERR; } -#if DEBUG_RESOLVER - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - _("Resolver asked to look up IP address `%s'.\n"), buf); -#endif - get_ip_as_string (client, sa, size); + break; + default: + GNUNET_break (0); + return GNUNET_SYSERR; } + return GNUNET_OK; } /** - * Process resolver requests. + * Handle GET-message. * - * @param cls closure - * @param server the initialized server - * @param cfg configuration to use + * @param cls identification of the client + * @param msg the actual message */ static void -run (void *cls, struct GNUNET_SERVER_Handle *server, - const struct GNUNET_CONFIGURATION_Handle *cfg) +handle_get (void *cls, + const struct GNUNET_RESOLVER_GetMessage *msg) { - 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); + 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]; + +#if !defined(GNUNET_CULL_LOGGING) + { + 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))); + } +#endif + get_ip_as_string (client, + af, + ip); } /** - * The main function for the resolver service. + * Callback called when a client connects to 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, unused + * @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 */ -int -main (int argc, char *const *argv) +static void * +connect_cb (void *cls, + struct GNUNET_SERVICE_Client *c, + struct GNUNET_MQ_Handle *mq) { - int ret; - struct IPCache *pos; + (void) cls; + (void) mq; + + return c; +} + + +/** + * Callback called when a client disconnected from the service + * + * @param cls closure for the service + * @param c the client that disconnected + * @param internal_cls should be equal to @a c + */ +static void +disconnect_cb (void *cls, + struct GNUNET_SERVICE_Client *c, + void *internal_cls) +{ + (void) cls; + + 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 + +/** + * MINIMIZE heap size (way below 128k) since this process doesn't need much. + */ +void __attribute__ ((constructor)) +GNUNET_RESOLVER_memory_init () +{ + mallopt (M_TRIM_THRESHOLD, 4 * 1024); + mallopt (M_TOP_PAD, 1 * 1024); + malloc_trim (0); +} +#endif - ret = - (GNUNET_OK == - GNUNET_SERVICE_run (argc, argv, "resolver", GNUNET_SERVICE_OPTION_NONE, - &run, NULL)) ? 0 : 1; - while (head != NULL) +/** + * Free globals on exit. + */ +void __attribute__ ((destructor)) +GNUNET_RESOLVER_memory_done () +{ + struct IPCache *pos; + + while (NULL != (pos = cache_head)) { - pos = head->next; - GNUNET_free_non_null (head->addr); - GNUNET_free (head->sa); - GNUNET_free (head); - head = pos; + GNUNET_CONTAINER_DLL_remove (cache_head, + cache_tail, + pos); + GNUNET_free_non_null (pos->addr); + GNUNET_free (pos); } - return ret; } + /* end of gnunet-service-resolver.c */