/** * Stop an active NAT test. * * @param tst test to stop. */ void GNUNET_NAT_test_stop (struct GNUNET_NAT_Test *tst) { struct NatActivity *pos; struct ClientActivity *cpos; LOG (GNUNET_ERROR_TYPE_DEBUG, "Stopping NAT test\n"); while (NULL != (cpos = tst->ca_head)) { GNUNET_CONTAINER_DLL_remove (tst->ca_head, tst->ca_tail, cpos); GNUNET_CLIENT_disconnect (cpos->client); GNUNET_free (cpos); } while (NULL != (pos = tst->na_head)) { GNUNET_CONTAINER_DLL_remove (tst->na_head, tst->na_tail, pos); GNUNET_SCHEDULER_cancel (pos->rtask); GNUNET_NETWORK_socket_close (pos->sock); GNUNET_free (pos); } if (NULL != tst->ttask) GNUNET_SCHEDULER_cancel (tst->ttask); if (NULL != tst->ltask) GNUNET_SCHEDULER_cancel (tst->ltask); if (NULL != tst->lsock) GNUNET_NETWORK_socket_close (tst->lsock); if (NULL != tst->nat) GNUNET_NAT_unregister (tst->nat); GNUNET_free (tst); }
/** * Close the connection and free associated resources. There must * not be any pending requests for reading or writing to the * connection at this time. * * @param connection connection to destroy */ void GNUNET_CONNECTION_destroy (struct GNUNET_CONNECTION_Handle *connection) { struct AddressProbe *pos; LOG (GNUNET_ERROR_TYPE_DEBUG, "Shutting down connection (%p)\n", connection); GNUNET_assert (NULL == connection->nth.notify_ready); GNUNET_assert (NULL == connection->receiver); if (GNUNET_SCHEDULER_NO_TASK != connection->write_task) { GNUNET_SCHEDULER_cancel (connection->write_task); connection->write_task = GNUNET_SCHEDULER_NO_TASK; connection->write_buffer_off = 0; } if (GNUNET_SCHEDULER_NO_TASK != connection->read_task) { GNUNET_SCHEDULER_cancel (connection->read_task); connection->read_task = GNUNET_SCHEDULER_NO_TASK; } if (GNUNET_SCHEDULER_NO_TASK != connection->nth.timeout_task) { GNUNET_SCHEDULER_cancel (connection->nth.timeout_task); connection->nth.timeout_task = GNUNET_SCHEDULER_NO_TASK; } connection->nth.notify_ready = NULL; if (NULL != connection->dns_active) { GNUNET_RESOLVER_request_cancel (connection->dns_active); connection->dns_active = NULL; } while (NULL != (pos = connection->ap_head)) { GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (pos->sock)); GNUNET_SCHEDULER_cancel (pos->task); GNUNET_CONTAINER_DLL_remove (connection->ap_head, connection->ap_tail, pos); GNUNET_free (pos); } if ( (NULL != connection->sock) && (GNUNET_YES != connection->persist) ) { if ((GNUNET_YES != GNUNET_NETWORK_socket_shutdown (connection->sock, SHUT_RDWR)) && (ENOTCONN != errno) && (ECONNRESET != errno) ) LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "shutdown"); } if (NULL != connection->sock) { if (GNUNET_YES != connection->persist) GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (connection->sock)); else GNUNET_free (connection->sock); /* at least no memory leak (we deliberately * leak the socket in this special case) ... */ } GNUNET_free_non_null (connection->addr); GNUNET_free_non_null (connection->hostname); GNUNET_free (connection->write_buffer); GNUNET_free (connection); }
/** * Activity on our incoming socket. Read data from the * incoming connection. * * @param cls the `struct NatActivity` * @param tc scheduler context */ static void do_read (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct NatActivity *na = cls; struct GNUNET_NAT_Test *tst; uint16_t data; na->rtask = NULL; tst = na->h; GNUNET_CONTAINER_DLL_remove (tst->na_head, tst->na_tail, na); if ((NULL != tc->write_ready) && (GNUNET_NETWORK_fdset_isset (tc->read_ready, na->sock)) && (sizeof (data) == GNUNET_NETWORK_socket_recv (na->sock, &data, sizeof (data)))) { if (data == tst->data) tst->report (tst->report_cls, GNUNET_NAT_ERROR_SUCCESS); else LOG (GNUNET_ERROR_TYPE_DEBUG, "Received data does not match expected value\n"); } else LOG (GNUNET_ERROR_TYPE_DEBUG, "Failed to receive data from inbound connection\n"); GNUNET_NETWORK_socket_close (na->sock); GNUNET_free (na); }
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 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); }
/** * 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 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; }
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; }
/** * We failed to transmit data to the service, signal the error. * * @param connection handle that had trouble * @param ecode error code (errno) */ static void signal_transmit_error (struct GNUNET_CONNECTION_Handle *connection, int ecode) { GNUNET_CONNECTION_TransmitReadyNotify notify; LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmission encounterd error (%s), connection closed (%p)\n", STRERROR (ecode), connection); if (NULL != connection->sock) { GNUNET_NETWORK_socket_shutdown (connection->sock, SHUT_RDWR); GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (connection->sock)); connection->sock = NULL; GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == connection->write_task); } if (GNUNET_SCHEDULER_NO_TASK != connection->read_task) { /* send errors trigger read errors... */ GNUNET_SCHEDULER_cancel (connection->read_task); connection->read_task = GNUNET_SCHEDULER_NO_TASK; signal_receive_timeout (connection); return; } if (NULL == connection->nth.notify_ready) return; /* nobody to tell about it */ notify = connection->nth.notify_ready; connection->nth.notify_ready = NULL; notify (connection->nth.notify_ready_cls, 0, NULL); }
/** * 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; }
/** * Create a connection handle by accepting on a listen socket. This * function may block if the listen socket has no connection ready. * * @param access_cb function to use to check if access is allowed * @param access_cb_cls closure for @a access_cb * @param lsock listen socket * @return the connection handle, NULL on error */ struct GNUNET_CONNECTION_Handle * GNUNET_CONNECTION_create_from_accept (GNUNET_CONNECTION_AccessCheck access_cb, void *access_cb_cls, struct GNUNET_NETWORK_Handle *lsock) { struct GNUNET_CONNECTION_Handle *connection; char addr[128]; socklen_t addrlen; struct GNUNET_NETWORK_Handle *sock; int aret; struct sockaddr_in *v4; struct sockaddr_in6 *v6; struct sockaddr *sa; void *uaddr; struct GNUNET_CONNECTION_Credentials *gcp; struct GNUNET_CONNECTION_Credentials gc; #ifdef SO_PEERCRED struct ucred uc; socklen_t olen; #endif addrlen = sizeof (addr); sock = GNUNET_NETWORK_socket_accept (lsock, (struct sockaddr *) &addr, &addrlen); if (NULL == sock) { if (EAGAIN != errno) LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "accept"); return NULL; } if ((addrlen > sizeof (addr)) || (addrlen < sizeof (sa_family_t))) { GNUNET_break (0); GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock)); return NULL; } sa = (struct sockaddr *) addr; v6 = (struct sockaddr_in6 *) addr; if ( (AF_INET6 == sa->sa_family) && (IN6_IS_ADDR_V4MAPPED (&v6->sin6_addr)) ) { /* convert to V4 address */ v4 = GNUNET_new (struct sockaddr_in); memset (v4, 0, sizeof (struct sockaddr_in)); v4->sin_family = AF_INET; #if HAVE_SOCKADDR_IN_SIN_LEN v4->sin_len = (u_char) sizeof (struct sockaddr_in); #endif GNUNET_memcpy (&v4->sin_addr, &((char *) &v6->sin6_addr)[sizeof (struct in6_addr) - sizeof (struct in_addr)], sizeof (struct in_addr)); v4->sin_port = v6->sin6_port; uaddr = v4; addrlen = sizeof (struct sockaddr_in); }
/** * We're done with a GNUNET_DNSSTUB_RequestSocket, close it for now. * * @param rs request socket to clean up */ static void cleanup_rs (struct GNUNET_DNSSTUB_RequestSocket *rs) { if (NULL != rs->dnsout4) { GNUNET_NETWORK_socket_close (rs->dnsout4); rs->dnsout4 = NULL; } if (NULL != rs->dnsout6) { GNUNET_NETWORK_socket_close (rs->dnsout6); rs->dnsout6 = NULL; } if (GNUNET_SCHEDULER_NO_TASK != rs->read_task) { GNUNET_SCHEDULER_cancel (rs->read_task); rs->read_task = GNUNET_SCHEDULER_NO_TASK; } }
/** * Scheduler let us know that we're either ready to write on the * socket OR connect timed out. Do the right thing. * * @param cls the "struct AddressProbe*" with the address that we are probing * @param tc success or failure info about the connect attempt. */ static void connect_probe_continuation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct AddressProbe *ap = cls; struct GNUNET_CONNECTION_Handle *connection = ap->connection; struct AddressProbe *pos; int error; socklen_t len; GNUNET_assert (NULL != ap->sock); GNUNET_CONTAINER_DLL_remove (connection->ap_head, connection->ap_tail, ap); len = sizeof (error); errno = 0; error = 0; if ((0 == (tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY)) || (GNUNET_OK != GNUNET_NETWORK_socket_getsockopt (ap->sock, SOL_SOCKET, SO_ERROR, &error, &len)) || (0 != error)) { GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (ap->sock)); GNUNET_free (ap); if ((NULL == connection->ap_head) && (GNUNET_NO == connection->dns_active)) connect_fail_continuation (connection); return; } GNUNET_assert (NULL == connection->sock); connection->sock = ap->sock; GNUNET_assert (NULL == connection->addr); connection->addr = GNUNET_malloc (ap->addrlen); memcpy (connection->addr, ap->addr, ap->addrlen); connection->addrlen = ap->addrlen; GNUNET_free (ap); /* cancel all other attempts */ while (NULL != (pos = connection->ap_head)) { GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (pos->sock)); GNUNET_SCHEDULER_cancel (pos->task); GNUNET_CONTAINER_DLL_remove (connection->ap_head, connection->ap_tail, pos); GNUNET_free (pos); } connect_success_continuation (connection); }
/** * 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 }
/** * Activity on our incoming socket. Read data from the * incoming connection. * * @param cls * @param tc scheduler context */ static void do_udp_read (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_NAT_AutoHandle *ah = cls; unsigned char reply_buf[1024]; ssize_t rlen; struct sockaddr_in answer; if ((0 != (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY)) && (GNUNET_NETWORK_fdset_isset (tc->read_ready, lsock4))) { rlen = GNUNET_NETWORK_socket_recv (lsock4, reply_buf, sizeof (reply_buf)); //Lets handle the packet memset(&answer, 0, sizeof(struct sockaddr_in)); if(ah->phase == AUTO_NAT_PUNCHED) { //Destroy the connection GNUNET_NETWORK_socket_close (lsock4); GNUNET_log (GNUNET_ERROR_TYPE_INFO, "The external server was able to connect back"); ah->connected_back = GNUNET_YES; next_phase (ah); } else { if (GNUNET_OK == GNUNET_NAT_stun_handle_packet (reply_buf, rlen, &answer)) { //Process the answer process_stun_reply (&answer, ah); } else { next_phase (ah); } } } else { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "TIMEOUT while waiting for an answer\n"); if (ah->phase == AUTO_NAT_PUNCHED) { stop_stun(); } next_phase (ah); } }
/** * Task run for shutdown. * * @param cls closure, NULL if we need to self-restart * @param tc context */ static void shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct ServiceList *pos; struct ServiceList *nxt; struct ServiceListeningInfo *sli; if (GNUNET_SCHEDULER_NO_TASK != child_restart_task) { GNUNET_SCHEDULER_cancel (child_restart_task); child_restart_task = GNUNET_SCHEDULER_NO_TASK; } in_shutdown = GNUNET_YES; /* first, stop listening */ for (pos = running_head; NULL != pos; pos = pos->next) { while (NULL != (sli = pos->listen_head)) { GNUNET_CONTAINER_DLL_remove (pos->listen_head, pos->listen_tail, sli); if (sli->accept_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (sli->accept_task); sli->accept_task = GNUNET_SCHEDULER_NO_TASK; } GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sli->listen_socket)); GNUNET_free (sli->service_addr); GNUNET_free (sli); } } /* then, shutdown all existing service processes */ nxt = running_head; while (NULL != (pos = nxt)) { nxt = pos->next; if (pos->proc != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Stopping service `%s'\n", pos->name); pos->killed_at = GNUNET_TIME_absolute_get (); if (0 != GNUNET_OS_process_kill (pos->proc, SIGTERM)) GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); } else { free_service (pos); } } /* finally, should all service processes be already gone, terminate for real */ if (running_head == NULL) do_shutdown (); }
/** * 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; }
/** * Task called by the scheduler once we can do the TCP send * (or once we failed to connect...). * * @param cls the 'struct TcpContext' * @param tc scheduler context */ static void tcp_send (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct TcpContext *ctx = cls; if ((NULL != tc->write_ready) && (GNUNET_NETWORK_fdset_isset (tc->write_ready, ctx->s))) { if (-1 == GNUNET_NETWORK_socket_send (ctx->s, &ctx->data, sizeof (ctx->data))) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_DEBUG, "send"); } GNUNET_NETWORK_socket_shutdown (ctx->s, SHUT_RDWR); } GNUNET_NETWORK_socket_close (ctx->s); GNUNET_free (ctx); }
/** * Task run on shutdown. * * @param cls NULL */ static void do_shutdown (void *cls) { if (NULL != nh) { GNUNET_NAT_unregister (nh); nh = NULL; } if (NULL != ls) { GNUNET_NETWORK_socket_close (ls); ls = NULL; } if (NULL != rtask) { GNUNET_SCHEDULER_cancel (rtask); rtask = NULL; } }
/** * Function that terminates the test. */ static void stop_stun () { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Stopping STUN and quitting...\n"); /* Clean task */ if(NULL != ltask4) { GNUNET_SCHEDULER_cancel (ltask4); ltask4 = NULL; } /* Clean socket */ if(NULL != lsock4) { GNUNET_NETWORK_socket_close (lsock4); lsock4 = NULL; } }
/** * Function that terminates the test. */ static void stop () { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Stopping NAT and quitting...\n"); if (NULL != ltask4) { GNUNET_SCHEDULER_cancel (ltask4); ltask4 = NULL; } if(NULL != lsock4) { GNUNET_NETWORK_socket_close(lsock4); lsock4 = NULL; } if (NULL != rh) { GNUNET_NAT_stun_make_request_cancel (rh); rh = NULL; } }
/** * 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); }
/** * 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; }
/** * Create a connection handle by accepting on a listen socket. This * function may block if the listen socket has no connection ready. * * @param access function to use to check if access is allowed * @param access_cls closure for access * @param lsock listen socket * @return the connection handle, NULL on error */ struct GNUNET_CONNECTION_Handle * GNUNET_CONNECTION_create_from_accept (GNUNET_CONNECTION_AccessCheck access, void *access_cls, struct GNUNET_NETWORK_Handle *lsock) { struct GNUNET_CONNECTION_Handle *connection; char addr[128]; socklen_t addrlen; struct GNUNET_NETWORK_Handle *sock; int aret; struct sockaddr_in *v4; struct sockaddr_in6 *v6; struct sockaddr *sa; void *uaddr; struct GNUNET_CONNECTION_Credentials *gcp; struct GNUNET_CONNECTION_Credentials gc; #ifdef SO_PEERCRED struct ucred uc; socklen_t olen; #endif addrlen = sizeof (addr); sock = GNUNET_NETWORK_socket_accept (lsock, (struct sockaddr *) &addr, &addrlen); if (NULL == sock) { LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "accept"); return NULL; } if ((addrlen > sizeof (addr)) || (addrlen < sizeof (sa_family_t))) { GNUNET_break (0); GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock)); return NULL; } sa = (struct sockaddr *) addr; v6 = (struct sockaddr_in6 *) addr; if ((AF_INET6 == sa->sa_family) && (IN6_IS_ADDR_V4MAPPED (&v6->sin6_addr))) { /* convert to V4 address */ v4 = GNUNET_malloc (sizeof (struct sockaddr_in)); memset (v4, 0, sizeof (struct sockaddr_in)); v4->sin_family = AF_INET; #if HAVE_SOCKADDR_IN_SIN_LEN v4->sin_len = (u_char) sizeof (struct sockaddr_in); #endif memcpy (&v4->sin_addr, &((char *) &v6->sin6_addr)[sizeof (struct in6_addr) - sizeof (struct in_addr)], sizeof (struct in_addr)); v4->sin_port = v6->sin6_port; uaddr = v4; addrlen = sizeof (struct sockaddr_in); } else { uaddr = GNUNET_malloc (addrlen); memcpy (uaddr, addr, addrlen); } gcp = NULL; gc.uid = 0; gc.gid = 0; if (AF_UNIX == sa->sa_family) { #if HAVE_GETPEEREID /* most BSDs */ if (0 == getpeereid (GNUNET_NETWORK_get_fd (sock), &gc.uid, &gc.gid)) gcp = &gc; #else #ifdef SO_PEERCRED /* largely traditional GNU/Linux */ olen = sizeof (uc); if ((0 == getsockopt (GNUNET_NETWORK_get_fd (sock), SOL_SOCKET, SO_PEERCRED, &uc, &olen)) && (olen == sizeof (uc))) { gc.uid = uc.uid; gc.gid = uc.gid; gcp = &gc; } #else #if HAVE_GETPEERUCRED /* this is for Solaris 10 */ ucred_t *uc; uc = NULL; if (0 == getpeerucred (GNUNET_NETWORK_get_fd (sock), &uc)) { gc.uid = ucred_geteuid (uc); gc.gid = ucred_getegid (uc); gcp = &gc; } ucred_free (uc); #endif #endif #endif } if ((NULL != access) && (GNUNET_YES != (aret = access (access_cls, gcp, uaddr, addrlen)))) { if (GNUNET_NO == aret) LOG (GNUNET_ERROR_TYPE_INFO, _("Access denied to `%s'\n"), GNUNET_a2s (uaddr, addrlen)); GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_shutdown (sock, SHUT_RDWR)); GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock)); GNUNET_free (uaddr); return NULL; } connection = GNUNET_malloc (sizeof (struct GNUNET_CONNECTION_Handle)); connection->write_buffer_size = GNUNET_SERVER_MIN_BUFFER_SIZE; connection->write_buffer = GNUNET_malloc (connection->write_buffer_size); connection->addr = uaddr; connection->addrlen = addrlen; connection->sock = sock; LOG (GNUNET_ERROR_TYPE_INFO, _("Accepting connection from `%s': %p\n"), GNUNET_a2s (uaddr, addrlen), connection); return connection; }
/** * Read listen sockets from the parent process (ARM). * * @param sctx service context to initialize * @return #GNUNET_YES if ok, #GNUNET_NO if not ok (must bind yourself), * and #GNUNET_SYSERR on error. */ static int receive_sockets_from_parent (struct GNUNET_SERVICE_Context *sctx) { const char *env_buf; int fail; uint64_t count; uint64_t i; HANDLE lsocks_pipe; env_buf = getenv ("GNUNET_OS_READ_LSOCKS"); if ((NULL == env_buf) || (strlen (env_buf) <= 0)) return GNUNET_NO; /* Using W32 API directly here, because this pipe will * never be used outside of this function, and it's just too much of a bother * to create a GNUnet API that boxes a HANDLE (the way it is done with socks) */ lsocks_pipe = (HANDLE) strtoul (env_buf, NULL, 10); if ( (0 == lsocks_pipe) || (INVALID_HANDLE_VALUE == lsocks_pipe)) return GNUNET_NO; fail = 1; do { int ret; int fail2; DWORD rd; ret = ReadFile (lsocks_pipe, &count, sizeof (count), &rd, NULL); if ((0 == ret) || (sizeof (count) != rd) || (0 == count)) break; sctx->lsocks = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle *) * (count + 1)); fail2 = 1; for (i = 0; i < count; i++) { WSAPROTOCOL_INFOA pi; uint64_t size; SOCKET s; ret = ReadFile (lsocks_pipe, &size, sizeof (size), &rd, NULL); if ( (0 == ret) || (sizeof (size) != rd) || (sizeof (pi) != size) ) break; ret = ReadFile (lsocks_pipe, &pi, sizeof (pi), &rd, NULL); if ( (0 == ret) || (sizeof (pi) != rd)) break; s = WSASocketA (pi.iAddressFamily, pi.iSocketType, pi.iProtocol, &pi, 0, WSA_FLAG_OVERLAPPED); sctx->lsocks[i] = GNUNET_NETWORK_socket_box_native (s); if (NULL == sctx->lsocks[i]) break; else if (i == count - 1) fail2 = 0; } if (fail2) break; sctx->lsocks[count] = NULL; fail = 0; } while (fail); CloseHandle (lsocks_pipe); if (fail) { LOG (GNUNET_ERROR_TYPE_ERROR, _("Could not access a pre-bound socket, will try to bind myself\n")); for (i = 0; (i < count) && (NULL != sctx->lsocks[i]); i++) GNUNET_break (0 == GNUNET_NETWORK_socket_close (sctx->lsocks[i])); GNUNET_free_non_null (sctx->lsocks); sctx->lsocks = NULL; return GNUNET_NO; } return GNUNET_YES; }
/** * 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; } }
/** * 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); }
/** * Setup addr, addrlen, idle_timeout * based on configuration! * * Configuration may specify: * - PORT (where to bind to for TCP) * - UNIXPATH (where to bind to for UNIX domain sockets) * - TIMEOUT (after how many ms does an inactive service timeout); * - DISABLEV6 (disable support for IPv6, otherwise we use dual-stack) * - BINDTO (hostname or IP address to bind to, otherwise we take everything) * - ACCEPT_FROM (only allow connections from specified IPv4 subnets) * - ACCEPT_FROM6 (only allow connections from specified IPv6 subnets) * - REJECT_FROM (disallow allow connections from specified IPv4 subnets) * - REJECT_FROM6 (disallow allow connections from specified IPv6 subnets) * * @param sctx service context to initialize * @return #GNUNET_OK if configuration succeeded */ static int setup_service (struct GNUNET_SERVICE_Context *sctx) { struct GNUNET_TIME_Relative idleout; int tolerant; #ifndef MINGW const char *nfds; unsigned int cnt; int flags; #endif if (GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name, "TIMEOUT")) { if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (sctx->cfg, sctx->service_name, "TIMEOUT", &idleout)) { LOG (GNUNET_ERROR_TYPE_ERROR, _("Specified value for `%s' of service `%s' is invalid\n"), "TIMEOUT", sctx->service_name); return GNUNET_SYSERR; } sctx->timeout = idleout; } else sctx->timeout = GNUNET_TIME_UNIT_FOREVER_REL; if (GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name, "TOLERANT")) { if (GNUNET_SYSERR == (tolerant = GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, sctx->service_name, "TOLERANT"))) { LOG (GNUNET_ERROR_TYPE_ERROR, _("Specified value for `%s' of service `%s' is invalid\n"), "TOLERANT", sctx->service_name); return GNUNET_SYSERR; } } else tolerant = GNUNET_NO; #ifndef MINGW errno = 0; if ((NULL != (nfds = getenv ("LISTEN_FDS"))) && (1 == SSCANF (nfds, "%u", &cnt)) && (cnt > 0) && (cnt < FD_SETSIZE) && (cnt + 4 < FD_SETSIZE)) { sctx->lsocks = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle *) * (cnt + 1)); while (0 < cnt--) { flags = fcntl (3 + cnt, F_GETFD); if ((flags < 0) || (0 != (flags & FD_CLOEXEC)) || (NULL == (sctx->lsocks[cnt] = GNUNET_NETWORK_socket_box_native (3 + cnt)))) { LOG (GNUNET_ERROR_TYPE_ERROR, _ ("Could not access pre-bound socket %u, will try to bind myself\n"), (unsigned int) 3 + cnt); cnt++; while (sctx->lsocks[cnt] != NULL) GNUNET_break (0 == GNUNET_NETWORK_socket_close (sctx->lsocks[cnt++])); GNUNET_free (sctx->lsocks); sctx->lsocks = NULL; break; } } unsetenv ("LISTEN_FDS"); } #else if (getenv ("GNUNET_OS_READ_LSOCKS") != NULL) { receive_sockets_from_parent (sctx); putenv ("GNUNET_OS_READ_LSOCKS="); } #endif if ((NULL == sctx->lsocks) && (GNUNET_SYSERR == GNUNET_SERVICE_get_server_addresses (sctx->service_name, sctx->cfg, &sctx->addrs, &sctx->addrlens))) return GNUNET_SYSERR; sctx->require_found = tolerant ? GNUNET_NO : GNUNET_YES; sctx->match_uid = GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, sctx->service_name, "UNIX_MATCH_UID"); sctx->match_gid = GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, sctx->service_name, "UNIX_MATCH_GID"); process_acl4 (&sctx->v4_denied, sctx, "REJECT_FROM"); process_acl4 (&sctx->v4_allowed, sctx, "ACCEPT_FROM"); process_acl6 (&sctx->v6_denied, sctx, "REJECT_FROM6"); process_acl6 (&sctx->v6_allowed, sctx, "ACCEPT_FROM6"); return GNUNET_OK; }
/** * 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; }
/** * 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; }