/** * Create a connection handle by (asynchronously) connecting to a host. * This function returns immediately, even if the connection has not * yet been established. This function only creates TCP connections. * * @param af_family address family to use * @param serv_addr server address * @param addrlen length of server address * @return the connection handle */ struct GNUNET_CONNECTION_Handle * GNUNET_CONNECTION_create_from_sockaddr (int af_family, const struct sockaddr *serv_addr, socklen_t addrlen) { struct GNUNET_NETWORK_Handle *s; struct GNUNET_CONNECTION_Handle *connection; s = GNUNET_NETWORK_socket_create (af_family, SOCK_STREAM, 0); if (NULL == s) { LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK, "socket"); return NULL; } if ((GNUNET_OK != GNUNET_NETWORK_socket_connect (s, serv_addr, addrlen)) && (EINPROGRESS != errno)) { /* maybe refused / unsupported address, try next */ LOG_STRERROR (GNUNET_ERROR_TYPE_INFO, "connect"); LOG (GNUNET_ERROR_TYPE_INFO, _("Attempt to connect to `%s' failed\n"), GNUNET_a2s (serv_addr, addrlen)); GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (s)); return NULL; } connection = GNUNET_CONNECTION_create_from_existing (s); connection->addr = GNUNET_malloc (addrlen); memcpy (connection->addr, serv_addr, addrlen); connection->addrlen = addrlen; LOG (GNUNET_ERROR_TYPE_INFO, _("Trying to connect to `%s' (%p)\n"), GNUNET_a2s (serv_addr, addrlen), connection); return connection; }
int main (int argc, char *argv[]) { int ret = 0; struct GNUNET_NETWORK_Handle *s = NULL; GNUNET_log_setup ("test-service", "WARNING", NULL); ret += check (); ret += check (); // FIXME #ifndef MINGW s = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0); #endif if (NULL == s) { if ((errno == ENOBUFS) || (errno == ENOMEM) || (errno == ENFILE) || (errno == EACCES)) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket"); return 1; } FPRINTF (stderr, "IPv6 support seems to not be available (%s), not testing it!\n", strerror (errno)); } else { GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (s)); ret += check6 (); } ret += check_start_stop (); return ret; }
/** * Create and initialize a listen socket for the server. * * @return NULL on error, otherwise the listen socket */ static struct GNUNET_NETWORK_Handle * open_listen_socket () { const static int on = 1; struct sockaddr_in sa; struct GNUNET_NETWORK_Handle *desc; 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); desc = GNUNET_NETWORK_socket_create (AF_INET, SOCK_STREAM, 0); GNUNET_assert (desc != 0); if (GNUNET_NETWORK_socket_setsockopt (desc, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) != GNUNET_OK) GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "setsockopt"); if (GNUNET_OK != GNUNET_NETWORK_socket_bind (desc, (const struct sockaddr *) &sa, sizeof (sa))) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "bind"); GNUNET_assert (0); } GNUNET_NETWORK_socket_listen (desc, 5); return desc; }
/** * Create an IPv4 listen socket bound to our port. * * @return NULL on error */ static struct GNUNET_NETWORK_Handle * bind_v4 () { struct GNUNET_NETWORK_Handle *ls; struct sockaddr_in sa4; int eno; memset (&sa4, 0, sizeof (sa4)); sa4.sin_family = AF_INET; sa4.sin_port = htons (port); #if HAVE_SOCKADDR_IN_SIN_LEN sa4.sin_len = sizeof (sa4); #endif ls = GNUNET_NETWORK_socket_create (AF_INET, SOCK_DGRAM, 0); if (NULL == ls) return NULL; if (GNUNET_OK != GNUNET_NETWORK_socket_bind (ls, (const struct sockaddr *) &sa4, sizeof (sa4))) { eno = errno; GNUNET_NETWORK_socket_close (ls); errno = eno; return NULL; } return ls; }
/** * Try to send 'data' to the * IP 'dst_ipv4' at port 'dport' via UDP. * * @param dst_ipv4 target IP * @param dport target port * @param data data to send */ static void try_send_udp (uint32_t dst_ipv4, uint16_t dport, uint16_t data) { struct GNUNET_NETWORK_Handle *s; struct sockaddr_in sa; s = GNUNET_NETWORK_socket_create (AF_INET, SOCK_DGRAM, 0); if (NULL == s) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "socket"); return; } memset (&sa, 0, sizeof (sa)); sa.sin_family = AF_INET; #if HAVE_SOCKADDR_IN_SIN_LEN sa.sin_len = sizeof (sa); #endif sa.sin_addr.s_addr = dst_ipv4; sa.sin_port = htons (dport); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending UDP packet to `%s'\n", GNUNET_a2s ((struct sockaddr *) &sa, sizeof (sa))); if (-1 == GNUNET_NETWORK_socket_sendto (s, &data, sizeof (data), (const struct sockaddr *) &sa, sizeof (sa))) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "sendto"); GNUNET_NETWORK_socket_close (s); }
void http_check_ipv6 (struct Plugin *plugin) { struct GNUNET_NETWORK_Handle *desc = NULL; if (plugin->ipv6 == GNUNET_YES) { /* probe IPv6 support */ desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0); if (NULL == desc) { if ((errno == ENOBUFS) || (errno == ENOMEM) || (errno == ENFILE) || (errno == EACCES)) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket"); } GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, plugin->name, _ ("Disabling IPv6 since it is not supported on this system!\n")); plugin->ipv6 = GNUNET_NO; } else { GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc)); desc = NULL; } GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Testing IPv6 on this system: %s\n", (plugin->ipv6 == GNUNET_YES) ? "successful" : "failed"); } }
/** * Try to send 'data' to the * IP 'dst_ipv4' at port 'dport' via TCP. * * @param dst_ipv4 target IP * @param dport target port * @param data data to send */ static void try_send_tcp (uint32_t dst_ipv4, uint16_t dport, uint16_t data) { struct GNUNET_NETWORK_Handle *s; struct sockaddr_in sa; struct TcpContext *ctx; s = GNUNET_NETWORK_socket_create (AF_INET, SOCK_STREAM, 0); if (NULL == s) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "socket"); return; } memset (&sa, 0, sizeof (sa)); sa.sin_family = AF_INET; #if HAVE_SOCKADDR_IN_SIN_LEN sa.sin_len = sizeof (sa); #endif sa.sin_addr.s_addr = dst_ipv4; sa.sin_port = htons (dport); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending TCP message to `%s'\n", GNUNET_a2s ((struct sockaddr *) &sa, sizeof (sa))); if ((GNUNET_OK != GNUNET_NETWORK_socket_connect (s, (const struct sockaddr *) &sa, sizeof (sa))) && (errno != EINPROGRESS)) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "connect"); GNUNET_NETWORK_socket_close (s); return; } ctx = GNUNET_malloc (sizeof (struct TcpContext)); ctx->s = s; ctx->data = data; GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_SECONDS, s, &tcp_send, ctx); }
/** * Create a connection handle by connecting to a UNIX domain service. * This function returns immediately, even if the connection has not * yet been established. This function only creates UNIX connections. * * @param cfg configuration to use * @param unixpath path to connect to * @return the connection handle, NULL on systems without UNIX support */ struct GNUNET_CONNECTION_Handle * GNUNET_CONNECTION_create_from_connect_to_unixpath (const struct GNUNET_CONFIGURATION_Handle *cfg, const char *unixpath) { #ifdef AF_UNIX struct GNUNET_CONNECTION_Handle *connection; struct sockaddr_un *un; size_t slen; GNUNET_assert (0 < strlen (unixpath)); /* sanity check */ un = GNUNET_malloc (sizeof (struct sockaddr_un)); un->sun_family = AF_UNIX; slen = strlen (unixpath); if (slen >= sizeof (un->sun_path)) slen = sizeof (un->sun_path) - 1; memcpy (un->sun_path, unixpath, slen); un->sun_path[slen] = '\0'; slen = sizeof (struct sockaddr_un); #if HAVE_SOCKADDR_IN_SIN_LEN un->sun_len = (u_char) slen; #endif #if LINUX un->sun_path[0] = '\0'; #endif connection = GNUNET_malloc (sizeof (struct GNUNET_CONNECTION_Handle)); connection->cfg = cfg; connection->write_buffer_size = GNUNET_SERVER_MIN_BUFFER_SIZE; connection->write_buffer = GNUNET_malloc (connection->write_buffer_size); connection->port = 0; connection->hostname = NULL; connection->addr = (struct sockaddr *) un; connection->addrlen = slen; connection->sock = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0); if (NULL == connection->sock) { GNUNET_free (connection->addr); GNUNET_free (connection->write_buffer); GNUNET_free (connection); return NULL; } if (GNUNET_OK != GNUNET_NETWORK_socket_connect (connection->sock, connection->addr, connection->addrlen)) { /* Just return; we expect everything to work eventually so don't fail HARD */ GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (connection->sock)); connection->sock = NULL; return connection; } connect_success_continuation (connection); return connection; #else return NULL; #endif }
/** * Open source port for sending DNS requests * * @param af AF_INET or AF_INET6 * @return GNUNET_OK on success */ static struct GNUNET_NETWORK_Handle * open_socket (int af) { struct sockaddr_in a4; struct sockaddr_in6 a6; struct sockaddr *sa; socklen_t alen; struct GNUNET_NETWORK_Handle *ret; ret = GNUNET_NETWORK_socket_create (af, SOCK_DGRAM, 0); if (NULL == ret) return NULL; switch (af) { case AF_INET: memset (&a4, 0, alen = sizeof (struct sockaddr_in)); sa = (struct sockaddr *) &a4; break; case AF_INET6: memset (&a6, 0, alen = sizeof (struct sockaddr_in6)); sa = (struct sockaddr *) &a6; break; default: GNUNET_break (0); GNUNET_NETWORK_socket_close (ret); return NULL; } sa->sa_family = af; if (GNUNET_OK != GNUNET_NETWORK_socket_bind (ret, sa, alen)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Could not bind to any port: %s\n"), STRERROR (errno)); GNUNET_NETWORK_socket_close (ret); return NULL; } return ret; }
/** * Try to establish a connection given the specified address. * This function is called by the resolver once we have a DNS reply. * * @param cls our "struct GNUNET_CONNECTION_Handle *" * @param addr address to try, NULL for "last call" * @param addrlen length of addr */ static void try_connect_using_address (void *cls, const struct sockaddr *addr, socklen_t addrlen) { struct GNUNET_CONNECTION_Handle *connection = cls; struct AddressProbe *ap; struct GNUNET_TIME_Relative delay; if (NULL == addr) { connection->dns_active = NULL; if ((NULL == connection->ap_head) && (NULL == connection->sock)) connect_fail_continuation (connection); return; } if (NULL != connection->sock) return; /* already connected */ GNUNET_assert (NULL == connection->addr); /* try to connect */ LOG (GNUNET_ERROR_TYPE_DEBUG, "Trying to connect using address `%s:%u/%s:%u'\n", connection->hostname, connection->port, GNUNET_a2s (addr, addrlen), connection->port); ap = GNUNET_malloc (sizeof (struct AddressProbe) + addrlen); ap->addr = (const struct sockaddr *) &ap[1]; memcpy (&ap[1], addr, addrlen); ap->addrlen = addrlen; ap->connection = connection; switch (ap->addr->sa_family) { case AF_INET: ((struct sockaddr_in *) ap->addr)->sin_port = htons (connection->port); break; case AF_INET6: ((struct sockaddr_in6 *) ap->addr)->sin6_port = htons (connection->port); break; default: GNUNET_break (0); GNUNET_free (ap); return; /* not supported by us */ } ap->sock = GNUNET_NETWORK_socket_create (ap->addr->sa_family, SOCK_STREAM, 0); if (NULL == ap->sock) { GNUNET_free (ap); return; /* not supported by OS */ } LOG (GNUNET_ERROR_TYPE_INFO, _("Trying to connect to `%s' (%p)\n"), GNUNET_a2s (ap->addr, ap->addrlen), connection); if ((GNUNET_OK != GNUNET_NETWORK_socket_connect (ap->sock, ap->addr, ap->addrlen)) && (EINPROGRESS != errno)) { /* maybe refused / unsupported address, try next */ LOG_STRERROR (GNUNET_ERROR_TYPE_INFO, "connect"); #if 0 LOG (GNUNET_ERROR_TYPE_INFO, _("Failed to connect to `%s' (%p)\n"), GNUNET_a2s (ap->addr, ap->addrlen), connection); #endif GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (ap->sock)); GNUNET_free (ap); return; } GNUNET_CONTAINER_DLL_insert (connection->ap_head, connection->ap_tail, ap); delay = GNUNET_CONNECTION_CONNECT_RETRY_TIMEOUT; if (NULL != connection->nth.notify_ready) delay = GNUNET_TIME_relative_min (delay, GNUNET_TIME_absolute_get_remaining (connection-> nth.transmit_timeout)); if (NULL != connection->receiver) delay = GNUNET_TIME_relative_min (delay, GNUNET_TIME_absolute_get_remaining (connection->receive_timeout)); ap->task = GNUNET_SCHEDULER_add_write_net (delay, ap->sock, &connect_probe_continuation, ap); }
/** * Test if the service is running. If we are given a UNIXPATH or a local address, * we do this NOT by trying to connect to the service, but by trying to BIND to * the same port. If the BIND fails, we know the service is running. * * @param service name of the service to wait for * @param cfg configuration to use * @param timeout how long to wait at most * @param task task to run if service is running * (reason will be "PREREQ_DONE" (service running) * or "TIMEOUT" (service not known to be running)) * @param task_cls closure for task */ void GNUNET_CLIENT_service_test (const char *service, const struct GNUNET_CONFIGURATION_Handle *cfg, struct GNUNET_TIME_Relative timeout, GNUNET_SCHEDULER_Task task, void *task_cls) { char *hostname; unsigned long long port; struct GNUNET_NETWORK_Handle *sock; struct GNUNET_CLIENT_Connection *client; LOG (GNUNET_ERROR_TYPE_DEBUG, "Testing if service `%s' is running.\n", service); #ifdef AF_UNIX { /* probe UNIX support */ struct sockaddr_un s_un; size_t slen; char *unixpath; unixpath = NULL; if ((GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg, service, "UNIXPATH", &unixpath)) && (0 < strlen (unixpath))) /* We have a non-NULL unixpath, does that mean it's valid? */ { if (strlen (unixpath) >= sizeof (s_un.sun_path)) { LOG (GNUNET_ERROR_TYPE_WARNING, _("UNIXPATH `%s' too long, maximum length is %llu\n"), unixpath, (unsigned long long) sizeof (s_un.sun_path)); unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath); LOG (GNUNET_ERROR_TYPE_INFO, _("Using `%s' instead\n"), unixpath); } } if (NULL != unixpath) { sock = GNUNET_NETWORK_socket_create (PF_UNIX, SOCK_STREAM, 0); if (NULL != sock) { memset (&s_un, 0, sizeof (s_un)); s_un.sun_family = AF_UNIX; slen = strlen (unixpath) + 1; if (slen >= sizeof (s_un.sun_path)) slen = sizeof (s_un.sun_path) - 1; memcpy (s_un.sun_path, unixpath, slen); s_un.sun_path[slen] = '\0'; slen = sizeof (struct sockaddr_un); #if LINUX s_un.sun_path[0] = '\0'; #endif #if HAVE_SOCKADDR_IN_SIN_LEN s_un.sun_len = (u_char) slen; #endif if (GNUNET_OK != GNUNET_NETWORK_socket_bind (sock, (const struct sockaddr *) &s_un, slen)) { /* failed to bind => service must be running */ GNUNET_free (unixpath); (void) GNUNET_NETWORK_socket_close (sock); GNUNET_SCHEDULER_add_continuation (task, task_cls, GNUNET_SCHEDULER_REASON_PREREQ_DONE); return; } (void) GNUNET_NETWORK_socket_close (sock); /* let's try IP */ } } GNUNET_free_non_null (unixpath); } #endif hostname = NULL; if ((GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg, service, "PORT", &port)) || (port > 65535) || (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, service, "HOSTNAME", &hostname))) { /* UNIXPATH failed (if possible) AND IP failed => error */ service_test_error (task, task_cls); return; } if (0 == strcmp ("localhost", hostname) #if !LINUX && 0 #endif ) { /* can test using 'bind' */ struct sockaddr_in s_in; memset (&s_in, 0, sizeof (s_in)); #if HAVE_SOCKADDR_IN_SIN_LEN s_in.sin_len = sizeof (struct sockaddr_in); #endif s_in.sin_family = AF_INET; s_in.sin_port = htons (port); sock = GNUNET_NETWORK_socket_create (AF_INET, SOCK_STREAM, 0); if (NULL != sock) { if (GNUNET_OK != GNUNET_NETWORK_socket_bind (sock, (const struct sockaddr *) &s_in, sizeof (s_in))) { /* failed to bind => service must be running */ GNUNET_free (hostname); (void) GNUNET_NETWORK_socket_close (sock); GNUNET_SCHEDULER_add_continuation (task, task_cls, GNUNET_SCHEDULER_REASON_PREREQ_DONE); return; } (void) GNUNET_NETWORK_socket_close (sock); } } if (0 == strcmp ("ip6-localhost", hostname) #if !LINUX && 0 #endif ) { /* can test using 'bind' */ struct sockaddr_in6 s_in6; memset (&s_in6, 0, sizeof (s_in6)); #if HAVE_SOCKADDR_IN_SIN_LEN s_in6.sin6_len = sizeof (struct sockaddr_in6); #endif s_in6.sin6_family = AF_INET6; s_in6.sin6_port = htons (port); sock = GNUNET_NETWORK_socket_create (AF_INET6, SOCK_STREAM, 0); if (NULL != sock) { if (GNUNET_OK != GNUNET_NETWORK_socket_bind (sock, (const struct sockaddr *) &s_in6, sizeof (s_in6))) { /* failed to bind => service must be running */ GNUNET_free (hostname); (void) GNUNET_NETWORK_socket_close (sock); GNUNET_SCHEDULER_add_continuation (task, task_cls, GNUNET_SCHEDULER_REASON_PREREQ_DONE); return; } (void) GNUNET_NETWORK_socket_close (sock); } } if (((0 == strcmp ("localhost", hostname)) || (0 == strcmp ("ip6-localhost", hostname))) #if !LINUX && 0 #endif ) { /* all binds succeeded => claim service not running right now */ GNUNET_free_non_null (hostname); service_test_error (task, task_cls); return; } GNUNET_free_non_null (hostname); /* non-localhost, try 'connect' method */ client = GNUNET_CLIENT_connect (service, cfg); if (NULL == client) { LOG (GNUNET_ERROR_TYPE_INFO, _("Could not connect to service `%s', must not be running.\n"), service); service_test_error (task, task_cls); return; } client->test_cb = task; client->test_cb_cls = task_cls; client->test_deadline = GNUNET_TIME_relative_to_absolute (timeout); if (NULL == GNUNET_CLIENT_notify_transmit_ready (client, sizeof (struct GNUNET_MessageHeader), timeout, GNUNET_YES, &write_test, client)) { LOG (GNUNET_ERROR_TYPE_WARNING, _("Failure to transmit request to service `%s'\n"), service); service_test_error (task, task_cls); GNUNET_CLIENT_disconnect (client); return; } }
/** * Test if the service is running. If we are given a UNIXPATH or a * local address, we do this NOT by trying to connect to the service, * but by trying to BIND to the same port. If the BIND fails, we know * the service is running. * * @param service name of the service to wait for * @param cfg configuration to use * @param timeout how long to wait at most * @param cb function to call with the result * @param cb_cls closure for @a cb * @return handle to cancel the test */ struct GNUNET_CLIENT_TestHandle * GNUNET_CLIENT_service_test (const char *service, const struct GNUNET_CONFIGURATION_Handle *cfg, struct GNUNET_TIME_Relative timeout, GNUNET_CLIENT_TestResultCallback cb, void *cb_cls) { struct GNUNET_CLIENT_TestHandle *th; char *hostname; unsigned long long port; struct GNUNET_NETWORK_Handle *sock; th = GNUNET_new (struct GNUNET_CLIENT_TestHandle); th->cb = cb; th->cb_cls = cb_cls; th->test_deadline = GNUNET_TIME_relative_to_absolute (timeout); LOG (GNUNET_ERROR_TYPE_DEBUG, "Testing if service `%s' is running.\n", service); #ifdef AF_UNIX { /* probe UNIX support */ struct sockaddr_un s_un; char *unixpath; int abstract; unixpath = NULL; if ((GNUNET_OK == GNUNET_CONFIGURATION_get_value_filename (cfg, service, "UNIXPATH", &unixpath)) && (0 < strlen (unixpath))) /* We have a non-NULL unixpath, does that mean it's valid? */ { if (strlen (unixpath) >= sizeof (s_un.sun_path)) { LOG (GNUNET_ERROR_TYPE_WARNING, _("UNIXPATH `%s' too long, maximum length is %llu\n"), unixpath, (unsigned long long) sizeof (s_un.sun_path)); unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath); LOG (GNUNET_ERROR_TYPE_INFO, _("Using `%s' instead\n"), unixpath); } } #ifdef LINUX abstract = GNUNET_CONFIGURATION_get_value_yesno (cfg, "TESTING", "USE_ABSTRACT_SOCKETS"); #else abstract = GNUNET_NO; #endif if ((NULL != unixpath) && (GNUNET_YES != abstract)) { if (GNUNET_SYSERR == GNUNET_DISK_directory_create_for_file (unixpath)) GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "mkdir", unixpath); } if (NULL != unixpath) { sock = GNUNET_NETWORK_socket_create (PF_UNIX, SOCK_STREAM, 0); if (NULL != sock) { memset (&s_un, 0, sizeof (s_un)); s_un.sun_family = AF_UNIX; strncpy (s_un.sun_path, unixpath, sizeof (s_un.sun_path) - 1); if (GNUNET_YES == abstract) s_un.sun_path[0] = '\0'; #if HAVE_SOCKADDR_IN_SIN_LEN s_un.sun_len = (u_char) sizeof (struct sockaddr_un); #endif if (GNUNET_OK != GNUNET_NETWORK_socket_bind (sock, (const struct sockaddr *) &s_un, sizeof (struct sockaddr_un))) { /* failed to bind => service must be running */ GNUNET_free (unixpath); (void) GNUNET_NETWORK_socket_close (sock); service_test_report (th, GNUNET_YES); return th; } (void) GNUNET_NETWORK_socket_close (sock); /* let's try IP */ } } GNUNET_free_non_null (unixpath); } #endif hostname = NULL; if ((GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg, service, "PORT", &port)) || (port > 65535) || (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, service, "HOSTNAME", &hostname))) { /* UNIXPATH failed (if possible) AND IP failed => error */ service_test_report (th, GNUNET_SYSERR); return th; } if (0 == strcmp ("localhost", hostname) #if !LINUX && 0 #endif ) { /* can test using 'bind' */ struct sockaddr_in s_in; memset (&s_in, 0, sizeof (s_in)); #if HAVE_SOCKADDR_IN_SIN_LEN s_in.sin_len = sizeof (struct sockaddr_in); #endif s_in.sin_family = AF_INET; s_in.sin_port = htons (port); sock = GNUNET_NETWORK_socket_create (AF_INET, SOCK_STREAM, 0); if (NULL != sock) { if (GNUNET_OK != GNUNET_NETWORK_socket_bind (sock, (const struct sockaddr *) &s_in, sizeof (s_in))) { /* failed to bind => service must be running */ GNUNET_free (hostname); (void) GNUNET_NETWORK_socket_close (sock); service_test_report (th, GNUNET_YES); return th; } (void) GNUNET_NETWORK_socket_close (sock); } } if (0 == strcmp ("ip6-localhost", hostname) #if !LINUX && 0 #endif ) { /* can test using 'bind' */ struct sockaddr_in6 s_in6; memset (&s_in6, 0, sizeof (s_in6)); #if HAVE_SOCKADDR_IN_SIN_LEN s_in6.sin6_len = sizeof (struct sockaddr_in6); #endif s_in6.sin6_family = AF_INET6; s_in6.sin6_port = htons (port); sock = GNUNET_NETWORK_socket_create (AF_INET6, SOCK_STREAM, 0); if (NULL != sock) { if (GNUNET_OK != GNUNET_NETWORK_socket_bind (sock, (const struct sockaddr *) &s_in6, sizeof (s_in6))) { /* failed to bind => service must be running */ GNUNET_free (hostname); (void) GNUNET_NETWORK_socket_close (sock); service_test_report (th, GNUNET_YES); return th; } (void) GNUNET_NETWORK_socket_close (sock); } } if (((0 == strcmp ("localhost", hostname)) || (0 == strcmp ("ip6-localhost", hostname))) #if !LINUX && 0 #endif ) { /* all binds succeeded => claim service not running right now */ GNUNET_free_non_null (hostname); service_test_report (th, GNUNET_NO); return th; } GNUNET_free_non_null (hostname); /* non-localhost, try 'connect' method */ th->client = GNUNET_CLIENT_connect (service, cfg); if (NULL == th->client) { LOG (GNUNET_ERROR_TYPE_INFO, _("Could not connect to service `%s', configuration broken.\n"), service); service_test_report (th, GNUNET_SYSERR); return th; } th->th = GNUNET_CLIENT_notify_transmit_ready (th->client, sizeof (struct GNUNET_MessageHeader), timeout, GNUNET_YES, &write_test, th); if (NULL == th->th) { LOG (GNUNET_ERROR_TYPE_WARNING, _("Failure to transmit request to service `%s'\n"), service); service_test_report (th, GNUNET_SYSERR); return th; } return th; }
/** * Creating a listening socket for each of the service's addresses and * wait for the first incoming connection to it * * @param sa address associated with the service * @param addr_len length of sa * @param sl service entry for the service in question */ static void create_listen_socket (struct sockaddr *sa, socklen_t addr_len, struct ServiceList *sl) { static int on = 1; struct GNUNET_NETWORK_Handle *sock; struct ServiceListeningInfo *sli; switch (sa->sa_family) { case AF_INET: sock = GNUNET_NETWORK_socket_create (PF_INET, SOCK_STREAM, 0); break; case AF_INET6: sock = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0); break; case AF_UNIX: if (strcmp (GNUNET_a2s (sa, addr_len), "@") == 0) /* Do not bind to blank UNIX path! */ return; sock = GNUNET_NETWORK_socket_create (PF_UNIX, SOCK_STREAM, 0); break; default: GNUNET_break (0); sock = NULL; errno = EAFNOSUPPORT; break; } if (NULL == sock) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Unable to create socket for service `%s': %s\n"), sl->name, STRERROR (errno)); GNUNET_free (sa); return; } if (GNUNET_NETWORK_socket_setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) != GNUNET_OK) GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "setsockopt"); #ifdef IPV6_V6ONLY if ((sa->sa_family == AF_INET6) && (GNUNET_NETWORK_socket_setsockopt (sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof (on)) != GNUNET_OK)) GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "setsockopt"); #endif if (GNUNET_NETWORK_socket_bind (sock, (const struct sockaddr *) sa, addr_len) != GNUNET_OK) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Unable to bind listening socket for service `%s' to address `%s': %s\n"), sl->name, GNUNET_a2s (sa, addr_len), STRERROR (errno)); GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock)); GNUNET_free (sa); return; } if (GNUNET_NETWORK_socket_listen (sock, 5) != GNUNET_OK) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "listen"); GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock)); GNUNET_free (sa); return; } GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("ARM now monitors connections to service `%s' at `%s'\n"), sl->name, GNUNET_a2s (sa, addr_len)); sli = GNUNET_malloc (sizeof (struct ServiceListeningInfo)); sli->service_addr = sa; sli->service_addr_len = addr_len; sli->listen_socket = sock; sli->sl = sl; sli->accept_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, sock, &accept_connection, sli); GNUNET_CONTAINER_DLL_insert (sl->listen_head, sl->listen_tail, sli); }
/** * Main function that will be run. * * @param cls closure * @param args remaining command-line arguments * @param cfgfile name of the configuration file used (for saving, can be NULL!) * @param c configuration */ static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *c) { uint8_t af; struct sockaddr *local_sa; struct sockaddr *remote_sa; socklen_t local_len; size_t remote_len; if (use_tcp && use_udp) { GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, "Cannot use TCP and UDP\n"); global_ret = 1; return; } proto = 0; if (use_tcp) proto = IPPROTO_TCP; if (use_udp) proto = IPPROTO_UDP; GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL); if (0 == proto) { GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, "Must specify either TCP or UDP\n"); global_ret = 1; return; } if (NULL != local_addr) { local_len = (socklen_t) GNUNET_STRINGS_parse_socket_addr (local_addr, &af, &local_sa); if (0 == local_len) { GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, "Invalid socket address `%s'\n", local_addr); global_ret = 1; return; } } if (NULL != remote_addr) { remote_len = GNUNET_STRINGS_parse_socket_addr (remote_addr, &af, &remote_sa); if (0 == remote_len) { GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, "Invalid socket address `%s'\n", remote_addr); global_ret = 1; return; } } if (NULL != local_addr) { if (NULL == section_name) section_name = GNUNET_strdup ("undefined"); nh = GNUNET_NAT_register (c, section_name, proto, 1, (const struct sockaddr **) &local_sa, &local_len, &address_cb, (listen_reversal) ? &reversal_cb : NULL, NULL); } else if (listen_reversal) { GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, "Use of `-W` only effective in combination with `-i`\n"); global_ret = 1; GNUNET_SCHEDULER_shutdown (); return; } if (NULL != remote_addr) { int ret; if ( (NULL == nh) || (sizeof (struct sockaddr_in) != local_len) ) { GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, "Require IPv4 local address to initiate connection reversal\n"); global_ret = 1; GNUNET_SCHEDULER_shutdown (); return; } if (sizeof (struct sockaddr_in) != remote_len) { GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, "Require IPv4 reversal target address\n"); global_ret = 1; GNUNET_SCHEDULER_shutdown (); return; } GNUNET_assert (AF_INET == local_sa->sa_family); GNUNET_assert (AF_INET == remote_sa->sa_family); ret = GNUNET_NAT_request_reversal (nh, (const struct sockaddr_in *) local_sa, (const struct sockaddr_in *) remote_sa); switch (ret) { case GNUNET_SYSERR: GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, "Connection reversal internal error\n"); break; case GNUNET_NO: GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, "Connection reversal unavailable\n"); break; case GNUNET_OK: /* operation in progress */ break; } } if (do_stun) { if (NULL == local_addr) { GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, "Require local address to support STUN requests\n"); global_ret = 1; GNUNET_SCHEDULER_shutdown (); return; } if (IPPROTO_UDP != proto) { GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, "STUN only supported over UDP\n"); global_ret = 1; GNUNET_SCHEDULER_shutdown (); return; } ls = GNUNET_NETWORK_socket_create (af, SOCK_DGRAM, IPPROTO_UDP); if (GNUNET_OK != GNUNET_NETWORK_socket_bind (ls, local_sa, local_len)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to bind to %s: %s\n", GNUNET_a2s (local_sa, local_len), STRERROR (errno)); global_ret = 1; GNUNET_SCHEDULER_shutdown (); return; } rtask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, ls, &stun_read_task, NULL); } test_finished (); }
/** * Start testing if NAT traversal works using the * given configuration (IPv4-only). * * ALL failures are reported directly to the report callback * * @param cfg configuration for the NAT traversal * @param is_tcp #GNUNET_YES to test TCP, #GNUNET_NO to test UDP * @param bnd_port port to bind to, 0 for connection reversal * @param adv_port externally advertised port to use * @param timeout delay after which the test should be aborted * @param report function to call with the result of the test * @param report_cls closure for @a report * @return handle to cancel NAT test or NULL. The error is always indicated via the report callback */ struct GNUNET_NAT_Test * GNUNET_NAT_test_start (const struct GNUNET_CONFIGURATION_Handle *cfg, int is_tcp, uint16_t bnd_port, uint16_t adv_port, struct GNUNET_TIME_Relative timeout, GNUNET_NAT_TestCallback report, void *report_cls) { struct GNUNET_NAT_Test *nh; struct sockaddr_in sa; const struct sockaddr *addrs[] = { (const struct sockaddr *) &sa }; const socklen_t addrlens[] = { sizeof (sa) }; memset (&sa, 0, sizeof (sa)); sa.sin_family = AF_INET; sa.sin_port = htons (bnd_port); #if HAVE_SOCKADDR_IN_SIN_LEN sa.sin_len = sizeof (sa); #endif nh = GNUNET_new (struct GNUNET_NAT_Test); nh->cfg = cfg; nh->is_tcp = is_tcp; nh->data = bnd_port; nh->adv_port = adv_port; nh->report = report; nh->report_cls = report_cls; nh->status = GNUNET_NAT_ERROR_SUCCESS; if (0 == bnd_port) { nh->nat = GNUNET_NAT_register (cfg, is_tcp, 0, 0, NULL, NULL, &addr_cb, &reversal_cb, nh, NULL); } else { nh->lsock = GNUNET_NETWORK_socket_create (AF_INET, (is_tcp == GNUNET_YES) ? SOCK_STREAM : SOCK_DGRAM, 0); if ((nh->lsock == NULL) || (GNUNET_OK != GNUNET_NETWORK_socket_bind (nh->lsock, (const struct sockaddr *) &sa, sizeof (sa)))) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to create listen socket bound to `%s' for NAT test: %s\n"), GNUNET_a2s ((const struct sockaddr *) &sa, sizeof (sa)), STRERROR (errno)); if (NULL != nh->lsock) { GNUNET_NETWORK_socket_close (nh->lsock); nh->lsock = NULL; } nh->status = GNUNET_NAT_ERROR_INTERNAL_NETWORK_ERROR; nh->ttask = GNUNET_SCHEDULER_add_now (&do_timeout, nh); return nh; } if (GNUNET_YES == is_tcp) { GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_listen (nh->lsock, 5)); nh->ltask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, nh->lsock, &do_accept, nh); } else { nh->ltask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, nh->lsock, &do_udp_read, nh); } LOG (GNUNET_ERROR_TYPE_INFO, "NAT test listens on port %u (%s)\n", bnd_port, (GNUNET_YES == is_tcp) ? "tcp" : "udp"); nh->nat = GNUNET_NAT_register (cfg, is_tcp, adv_port, 1, addrs, addrlens, &addr_cb, NULL, nh, NULL); if (NULL == nh->nat) { LOG (GNUNET_ERROR_TYPE_INFO, _("NAT test failed to start NAT library\n")); if (NULL != nh->ltask) { GNUNET_SCHEDULER_cancel (nh->ltask); nh->ltask = NULL; } if (NULL != nh->lsock) { GNUNET_NETWORK_socket_close (nh->lsock); nh->lsock = NULL; } nh->status = GNUNET_NAT_ERROR_NAT_REGISTER_FAILED; nh->ttask = GNUNET_SCHEDULER_add_now (&do_timeout, nh); return nh; } } nh->ttask = GNUNET_SCHEDULER_add_delayed (timeout, &do_timeout, nh); return nh; }
/** * Get the list of addresses that a server for the given service * should bind to. * * @param service_name name of the service * @param cfg configuration (which specifies the addresses) * @param addrs set (call by reference) to an array of pointers to the * addresses the server should bind to and listen on; the * array will be NULL-terminated (on success) * @param addr_lens set (call by reference) to an array of the lengths * of the respective `struct sockaddr` struct in the @a addrs * array (on success) * @return number of addresses found on success, * #GNUNET_SYSERR if the configuration * did not specify reasonable finding information or * if it specified a hostname that could not be resolved; * #GNUNET_NO if the number of addresses configured is * zero (in this case, `*addrs` and `*addr_lens` will be * set to NULL). */ int GNUNET_SERVICE_get_server_addresses (const char *service_name, const struct GNUNET_CONFIGURATION_Handle *cfg, struct sockaddr ***addrs, socklen_t ** addr_lens) { int disablev6; struct GNUNET_NETWORK_Handle *desc; unsigned long long port; char *unixpath; struct addrinfo hints; struct addrinfo *res; struct addrinfo *pos; struct addrinfo *next; unsigned int i; int resi; int ret; int abstract; struct sockaddr **saddrs; socklen_t *saddrlens; char *hostname; *addrs = NULL; *addr_lens = NULL; desc = NULL; if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "DISABLEV6")) { if (GNUNET_SYSERR == (disablev6 = GNUNET_CONFIGURATION_get_value_yesno (cfg, service_name, "DISABLEV6"))) return GNUNET_SYSERR; } else disablev6 = GNUNET_NO; if (! disablev6) { /* probe IPv6 support */ desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0); if (NULL == desc) { if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) || (EACCES == errno)) { LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket"); return GNUNET_SYSERR; } LOG (GNUNET_ERROR_TYPE_INFO, _("Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n"), service_name, STRERROR (errno)); disablev6 = GNUNET_YES; } else { GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc)); desc = NULL; } } port = 0; if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "PORT")) { if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg, service_name, "PORT", &port)) { LOG (GNUNET_ERROR_TYPE_ERROR, _("Require valid port number for service `%s' in configuration!\n"), service_name); } if (port > 65535) { LOG (GNUNET_ERROR_TYPE_ERROR, _("Require valid port number for service `%s' in configuration!\n"), service_name); return GNUNET_SYSERR; } } if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "BINDTO")) { GNUNET_break (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg, service_name, "BINDTO", &hostname)); } else hostname = NULL; unixpath = NULL; abstract = GNUNET_NO; #ifdef AF_UNIX if ((GNUNET_YES == GNUNET_CONFIGURATION_have_value (cfg, service_name, "UNIXPATH")) && (GNUNET_OK == GNUNET_CONFIGURATION_get_value_filename (cfg, service_name, "UNIXPATH", &unixpath)) && (0 < strlen (unixpath))) { /* probe UNIX support */ struct sockaddr_un s_un; if (strlen (unixpath) >= sizeof (s_un.sun_path)) { LOG (GNUNET_ERROR_TYPE_WARNING, _("UNIXPATH `%s' too long, maximum length is %llu\n"), unixpath, (unsigned long long) sizeof (s_un.sun_path)); unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath); LOG (GNUNET_ERROR_TYPE_INFO, _("Using `%s' instead\n"), unixpath); } #ifdef LINUX abstract = GNUNET_CONFIGURATION_get_value_yesno (cfg, "TESTING", "USE_ABSTRACT_SOCKETS"); if (GNUNET_SYSERR == abstract) abstract = GNUNET_NO; #endif if ((GNUNET_YES != abstract) && (GNUNET_OK != GNUNET_DISK_directory_create_for_file (unixpath))) GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "mkdir", unixpath); } if (NULL != unixpath) { desc = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0); if (NULL == desc) { if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) || (EACCES == errno)) { LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket"); GNUNET_free_non_null (hostname); GNUNET_free (unixpath); return GNUNET_SYSERR; } LOG (GNUNET_ERROR_TYPE_INFO, _("Disabling UNIX domain socket support for service `%s', failed to create UNIX domain socket: %s\n"), service_name, STRERROR (errno)); GNUNET_free (unixpath); unixpath = NULL; } else { GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc)); desc = NULL; } } #endif if ((0 == port) && (NULL == unixpath)) { LOG (GNUNET_ERROR_TYPE_ERROR, _("Have neither PORT nor UNIXPATH for service `%s', but one is required\n"), service_name); GNUNET_free_non_null (hostname); return GNUNET_SYSERR; } if (0 == port) { saddrs = GNUNET_malloc (2 * sizeof (struct sockaddr *)); saddrlens = GNUNET_malloc (2 * sizeof (socklen_t)); add_unixpath (saddrs, saddrlens, unixpath, abstract); GNUNET_free_non_null (unixpath); GNUNET_free_non_null (hostname); *addrs = saddrs; *addr_lens = saddrlens; return 1; } if (NULL != hostname) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Resolving `%s' since that is where `%s' will bind to.\n", hostname, service_name); memset (&hints, 0, sizeof (struct addrinfo)); if (disablev6) hints.ai_family = AF_INET; hints.ai_protocol = IPPROTO_TCP; if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) || (NULL == res)) { LOG (GNUNET_ERROR_TYPE_ERROR, _("Failed to resolve `%s': %s\n"), hostname, gai_strerror (ret)); GNUNET_free (hostname); GNUNET_free_non_null (unixpath); return GNUNET_SYSERR; } next = res; i = 0; while (NULL != (pos = next)) { next = pos->ai_next; if ((disablev6) && (pos->ai_family == AF_INET6)) continue; i++; } if (0 == i) { LOG (GNUNET_ERROR_TYPE_ERROR, _("Failed to find %saddress for `%s'.\n"), disablev6 ? "IPv4 " : "", hostname); freeaddrinfo (res); GNUNET_free (hostname); GNUNET_free_non_null (unixpath); return GNUNET_SYSERR; } resi = i; if (NULL != unixpath) resi++; saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *)); saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t)); i = 0; if (NULL != unixpath) { add_unixpath (saddrs, saddrlens, unixpath, abstract); i++; } next = res; while (NULL != (pos = next)) { next = pos->ai_next; if ((disablev6) && (AF_INET6 == pos->ai_family)) continue; if ((IPPROTO_TCP != pos->ai_protocol) && (0 != pos->ai_protocol)) continue; /* not TCP */ if ((SOCK_STREAM != pos->ai_socktype) && (0 != pos->ai_socktype)) continue; /* huh? */ LOG (GNUNET_ERROR_TYPE_DEBUG, "Service `%s' will bind to `%s'\n", service_name, GNUNET_a2s (pos->ai_addr, pos->ai_addrlen)); if (AF_INET == pos->ai_family) { GNUNET_assert (sizeof (struct sockaddr_in) == pos->ai_addrlen); saddrlens[i] = pos->ai_addrlen; saddrs[i] = GNUNET_malloc (saddrlens[i]); memcpy (saddrs[i], pos->ai_addr, saddrlens[i]); ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port); } else { GNUNET_assert (AF_INET6 == pos->ai_family); GNUNET_assert (sizeof (struct sockaddr_in6) == pos->ai_addrlen); saddrlens[i] = pos->ai_addrlen; saddrs[i] = GNUNET_malloc (saddrlens[i]); memcpy (saddrs[i], pos->ai_addr, saddrlens[i]); ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port); } i++; } GNUNET_free (hostname); freeaddrinfo (res); resi = i; } else { /* will bind against everything, just set port */ if (disablev6) { /* V4-only */ resi = 1; if (NULL != unixpath) resi++; i = 0; saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *)); saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t)); if (NULL != unixpath) { add_unixpath (saddrs, saddrlens, unixpath, abstract); i++; } saddrlens[i] = sizeof (struct sockaddr_in); saddrs[i] = GNUNET_malloc (saddrlens[i]); #if HAVE_SOCKADDR_IN_SIN_LEN ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i]; #endif ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET; ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port); } else { /* dual stack */ resi = 2; if (NULL != unixpath) resi++; saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *)); saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t)); i = 0; if (NULL != unixpath) { add_unixpath (saddrs, saddrlens, unixpath, abstract); i++; } saddrlens[i] = sizeof (struct sockaddr_in6); saddrs[i] = GNUNET_malloc (saddrlens[i]); #if HAVE_SOCKADDR_IN_SIN_LEN ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0]; #endif ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6; ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port); i++; saddrlens[i] = sizeof (struct sockaddr_in); saddrs[i] = GNUNET_malloc (saddrlens[i]); #if HAVE_SOCKADDR_IN_SIN_LEN ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1]; #endif ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET; ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port); } } GNUNET_free_non_null (unixpath); *addrs = saddrs; *addr_lens = saddrlens; return resi; }