/** * Convert a string to an IP address. * * @param client where to send the IP address * @param hostname the hostname to resolve * @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 af) { int ret; struct GNUNET_SERVER_TransmitContext *tc; tc = GNUNET_SERVER_transmit_context_create (client); ret = GNUNET_NO; #if HAVE_GETADDRINFO if (ret == GNUNET_NO) ret = getaddrinfo_resolve (tc, hostname, af); #endif #if HAVE_GETHOSTBYNAME2 if (ret == GNUNET_NO) ret = gethostbyname2_resolve (tc, hostname, af); #endif #if HAVE_GETHOSTBYNAME if ((ret == GNUNET_NO) && ((af == AF_UNSPEC) || (af == PF_INET))) gethostbyname_resolve (tc, 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); }
static int getaddrinfo_resolve (struct GNUNET_SERVER_TransmitContext *tc, const char *hostname, int af) { int s; struct addrinfo hints; struct addrinfo *result; struct addrinfo *pos; #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 (tc, hostname, AF_INET); ret2 = getaddrinfo_resolve (tc, 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))) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Could not resolve `%s' (%s): %s\n"), hostname, (af == AF_INET) ? "IPv4" : ((af == AF_INET6) ? "IPv6" : "any"), gai_strerror (s)); if ((s == EAI_BADFLAGS) || (s == EAI_MEMORY) #ifndef WINDOWS || (s == EAI_SYSTEM) #else || 1 #endif ) return GNUNET_NO; /* other function may still succeed */ return GNUNET_SYSERR; } if (NULL == result) return GNUNET_SYSERR; for (pos = result; pos != NULL; pos = pos->ai_next) { 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); 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); break; default: /* unsupported, skip */ break; } } freeaddrinfo (result); return GNUNET_OK; }