/** * 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; }
static int iface_proc (void *cls, const char *name, int isDefault, const struct sockaddr *addr, const struct sockaddr *broadcast_addr, const struct sockaddr *netmask, socklen_t addrlen) { struct Plugin *plugin = cls; if (addr != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "address %s for interface %s %p\n ", GNUNET_a2s (addr, addrlen), name, addr); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "broadcast address %s for interface %s %p\n ", GNUNET_a2s (broadcast_addr, addrlen), name, broadcast_addr); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "netmask %s for interface %s %p\n ", GNUNET_a2s (netmask, addrlen), name, netmask); /* Collecting broadcast addresses */ if (broadcast_addr != NULL) { struct BroadcastAddress *ba = GNUNET_malloc (sizeof (struct BroadcastAddress)); ba->addr = GNUNET_malloc (addrlen); memcpy (ba->addr, broadcast_addr, addrlen); ba->addrlen = addrlen; GNUNET_CONTAINER_DLL_insert (plugin->ipv4_broadcast_head, plugin->ipv4_broadcast_tail, ba); } } return GNUNET_OK; }
/** * This function is called once we either timeout * or have data ready to read. * * @param cls connection to read from * @param tc scheduler context */ static void receive_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_CONNECTION_Handle *connection = cls; char buffer[connection->max]; ssize_t ret; GNUNET_CONNECTION_Receiver receiver; connection->read_task = GNUNET_SCHEDULER_NO_TASK; if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) { /* ignore shutdown request, go again immediately */ connection->read_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_absolute_get_remaining (connection->receive_timeout), connection->sock, &receive_ready, connection); return; } if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_TIMEOUT)) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Receive from `%s' encounters error: timeout (%p)\n", GNUNET_a2s (connection->addr, connection->addrlen), GNUNET_TIME_absolute_get_duration (connection->receive_timeout).rel_value, connection); signal_receive_timeout (connection); return; } if (NULL == connection->sock) { /* connect failed for good */ signal_receive_error (connection, ECONNREFUSED); return; } GNUNET_assert (GNUNET_NETWORK_fdset_isset (tc->read_ready, connection->sock)); RETRY: ret = GNUNET_NETWORK_socket_recv (connection->sock, buffer, connection->max); if (-1 == ret) { if (EINTR == errno) goto RETRY; signal_receive_error (connection, errno); return; } LOG (GNUNET_ERROR_TYPE_DEBUG, "receive_ready read %u/%u bytes from `%s' (%p)!\n", (unsigned int) ret, connection->max, GNUNET_a2s (connection->addr, connection->addrlen), connection); GNUNET_assert (NULL != (receiver = connection->receiver)); connection->receiver = NULL; receiver (connection->receiver_cls, buffer, ret, connection->addr, connection->addrlen, 0); }
/** * Address-callback, used to send message to gnunet-nat-server. * * @param cls closure * @param add_remove #GNUNET_YES to mean the new public IP address, #GNUNET_NO to mean * the previous (now invalid) one * @param addr either the previous or the new public IP address * @param addrlen actual length of the @a addr */ static void addr_cb (void *cls, int add_remove, const struct sockaddr *addr, socklen_t addrlen) { struct GNUNET_NAT_Test *h = cls; struct ClientActivity *ca; struct GNUNET_CLIENT_Connection *client; struct GNUNET_NAT_TestMessage msg; const struct sockaddr_in *sa; if (GNUNET_YES != add_remove) return; if (addrlen != sizeof (struct sockaddr_in)) { LOG (GNUNET_ERROR_TYPE_DEBUG, "NAT test ignores IPv6 address `%s' returned from NAT library\n", GNUNET_a2s (addr, addrlen)); return; /* ignore IPv6 here */ } LOG (GNUNET_ERROR_TYPE_INFO, "Asking gnunet-nat-server to connect to `%s'\n", GNUNET_a2s (addr, addrlen)); sa = (const struct sockaddr_in *) addr; msg.header.size = htons (sizeof (struct GNUNET_NAT_TestMessage)); msg.header.type = htons (GNUNET_MESSAGE_TYPE_NAT_TEST); msg.dst_ipv4 = sa->sin_addr.s_addr; msg.dport = sa->sin_port; msg.data = h->data; msg.is_tcp = htonl ((uint32_t) h->is_tcp); client = GNUNET_CLIENT_connect ("gnunet-nat-server", h->cfg); if (NULL == client) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to connect to `gnunet-nat-server'\n")); return; } ca = GNUNET_new (struct ClientActivity); ca->client = client; GNUNET_CONTAINER_DLL_insert (h->ca_head, h->ca_tail, ca); GNUNET_break (GNUNET_OK == GNUNET_CLIENT_transmit_and_get_response (client, &msg.header, NAT_SERVER_TIMEOUT, GNUNET_YES, NULL, NULL)); }
/** * Main function run with scheduler. */ static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { struct GNUNET_NAT_Handle *nat; struct addr_cls data; struct sockaddr *addr; data.addr = NULL; GNUNET_OS_network_interfaces_list (process_if, &data); if (NULL == data.addr) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not find a valid interface address!\n"); exit (77); /* marks test as skipped */ } addr = data.addr; GNUNET_assert (addr->sa_family == AF_INET || addr->sa_family == AF_INET6); if (addr->sa_family == AF_INET) ((struct sockaddr_in *) addr)->sin_port = htons (2086); else ((struct sockaddr_in6 *) addr)->sin6_port = htons (2086); GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Requesting NAT redirection from address %s...\n", GNUNET_a2s (addr, data.addrlen)); nat = GNUNET_NAT_register (cfg, GNUNET_YES /* tcp */ , 2086, 1, (const struct sockaddr **) &addr, &data.addrlen, &addr_callback, NULL, NULL, NULL); GNUNET_free (addr); GNUNET_SCHEDULER_add_delayed (TIMEOUT, &stop, nat); }
/** * Create a HTTP address from a socketaddr * * @param protocol protocol * @param addr sockaddr * address * @param addrlen length of the address * @return the string */ char * http_common_address_from_socket (const char *protocol, const struct sockaddr *addr, socklen_t addrlen) { char *res; GNUNET_asprintf(&res, "%s://%s", protocol, GNUNET_a2s (addr, addrlen)); return res; }
/** * Function that will be called to figure if an address is an loopback, * LAN, WAN etc. address * * @param cls closure * @param addr binary address * @param addrlen length of the address * @return ATS Information containing the network type */ static struct GNUNET_ATS_Information plugin_env_address_to_type (void *cls, const struct sockaddr *addr, size_t addrlen) { struct GNUNET_ATS_Information ats; ats.type = htonl (GNUNET_ATS_NETWORK_TYPE); ats.value = htonl (GNUNET_ATS_NET_UNSPECIFIED); if (GST_ats == NULL) { GNUNET_break (0); return ats; } if (((addr->sa_family != AF_INET) && (addrlen != sizeof (struct sockaddr_in))) && ((addr->sa_family != AF_INET6) && (addrlen != sizeof (struct sockaddr_in6))) && (addr->sa_family != AF_UNIX)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed address with length %u `%s'\n", addrlen, GNUNET_a2s(addr, addrlen)); GNUNET_break (0); return (const struct GNUNET_ATS_Information) ats; } return GNUNET_ATS_address_get_type(GST_ats, addr, addrlen); }
/** * 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); }
/** * We've succeeded in establishing a connection. * * @param connection the connection we tried to establish */ static void connect_success_continuation (struct GNUNET_CONNECTION_Handle *connection) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Connection to `%s' succeeded! (%p)\n", GNUNET_a2s (connection->addr, connection->addrlen), connection); /* trigger jobs that waited for the connection */ if (NULL != connection->receiver) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Connection succeeded, starting with receiving data (%p)\n", connection); GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == connection->read_task); connection->read_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_absolute_get_remaining (connection->receive_timeout), connection->sock, &receive_ready, connection); } if (NULL != connection->nth.notify_ready) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Connection succeeded, starting with sending data (%p)\n", connection); GNUNET_assert (connection->nth.timeout_task != GNUNET_SCHEDULER_NO_TASK); GNUNET_SCHEDULER_cancel (connection->nth.timeout_task); connection->nth.timeout_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_assert (connection->write_task == GNUNET_SCHEDULER_NO_TASK); connection->write_task = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_absolute_get_remaining (connection->nth.transmit_timeout), connection->sock, &transmit_ready, connection); } }
static int client_receive_mst_cb (void *cls, void *client, const struct GNUNET_MessageHeader *message) { struct Session *s = cls; struct GNUNET_TIME_Relative delay; if (GNUNET_YES != exist_session(p, s)) { GNUNET_break (0); return GNUNET_OK; } delay = http_plugin_receive (s, &s->target, message, s, s->addr, s->addrlen); s->next_receive = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (), delay); if (GNUNET_TIME_absolute_get ().abs_value < s->next_receive.abs_value) { struct Plugin *plugin = s->plugin; GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Client: peer `%s' address `%s' next read delayed for %llu ms\n", GNUNET_i2s (&s->target), GNUNET_a2s (s->addr, s->addrlen), delay); } return GNUNET_OK; }
void udp_broadcast_receive (struct Plugin *plugin, const char * buf, ssize_t size, struct sockaddr *addr, size_t addrlen) { struct GNUNET_ATS_Information ats; if ((GNUNET_YES == plugin->broadcast_ipv4) && (addrlen == sizeof (struct sockaddr_in))) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Received IPv4 HELLO beacon broadcast with %i bytes from address %s\n", size, GNUNET_a2s ((const struct sockaddr *) addr, addrlen)); struct Mstv4Context *mc; mc = GNUNET_malloc (sizeof (struct Mstv4Context)); struct sockaddr_in *av4 = (struct sockaddr_in *) addr; mc->addr.ipv4_addr = av4->sin_addr.s_addr; mc->addr.u4_port = av4->sin_port; ats = plugin->env->get_address_type (plugin->env->cls, (const struct sockaddr *) addr, addrlen); mc->ats_address_network_type = ats.value; GNUNET_assert (NULL != plugin->broadcast_ipv4_mst); if (GNUNET_OK != GNUNET_SERVER_mst_receive (plugin->broadcast_ipv4_mst, mc, buf, size, GNUNET_NO, GNUNET_NO)) GNUNET_free (mc); } else if ((GNUNET_YES == plugin->broadcast_ipv4) && (addrlen == sizeof (struct sockaddr_in6))) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Received IPv6 HELLO beacon broadcast with %i bytes from address %s\n", size, GNUNET_a2s ((const struct sockaddr *) &addr, addrlen)); struct Mstv6Context *mc; mc = GNUNET_malloc (sizeof (struct Mstv6Context)); struct sockaddr_in6 *av6 = (struct sockaddr_in6 *) addr; mc->addr.ipv6_addr = av6->sin6_addr; mc->addr.u6_port = av6->sin6_port; ats = plugin->env->get_address_type (plugin->env->cls, (const struct sockaddr *) addr, addrlen); mc->ats_address_network_type = ats.value; GNUNET_assert (NULL != plugin->broadcast_ipv4_mst); if (GNUNET_OK != GNUNET_SERVER_mst_receive (plugin->broadcast_ipv6_mst, mc, buf, size, GNUNET_NO, GNUNET_NO)) GNUNET_free (mc); } }
/** * Function called on each address that the NAT service * believes to be valid for the transport. */ static void addr_callback (void *cls, int add_remove, const struct sockaddr *addr, socklen_t addrlen) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Address changed: %s `%s' (%u bytes)\n", add_remove == GNUNET_YES ? "added" : "removed", GNUNET_a2s (addr, addrlen), (unsigned int) addrlen); }
struct Session * lookup_session_old (struct Plugin *plugin, const struct GNUNET_PeerIdentity *target, struct Session *session, const void *addr, size_t addrlen, int force_address) { struct Session *t; int e_peer; int e_addr; for (t = plugin->head; NULL != t; t = t->next) { #if 0 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, "Comparing peer `%s' address `%s' len %i session %p to \n", GNUNET_i2s (target), GNUNET_a2s (addr, addrlen), addrlen, session); GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, "peer `%s' address `%s' len %i session %p \n\n", GNUNET_i2s (&t->target), GNUNET_a2s (t->addr, t->addrlen), t->addrlen, t); GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, "memcmp %i \n", memcmp (addr, t->addr, addrlen)); #endif e_peer = GNUNET_NO; e_addr = GNUNET_NO; if (0 == memcmp (target, &t->target, sizeof (struct GNUNET_PeerIdentity))) { e_peer = GNUNET_YES; if ( (addrlen == t->addrlen) && (0 == memcmp (addr, t->addr, addrlen)) ) e_addr = GNUNET_YES; if ( (t == session) && (t->addrlen == session->addrlen) && (0 == memcmp (session->addr, t->addr, t->addrlen)) ) e_addr = GNUNET_YES; } if ( ((e_peer == GNUNET_YES) && (force_address == GNUNET_NO)) || ((e_peer == GNUNET_YES) && (force_address == GNUNET_YES) && (e_addr == GNUNET_YES)) || ((e_peer == GNUNET_YES) && (force_address == GNUNET_SYSERR)) ) return t; } return NULL; }
/** * Signature of the callback passed to #GNUNET_NAT_register(). * for a function to call whenever someone asks us to do connection * reversal. * * @param cls closure, NULL * @param remote_addr public IP address of the other peer * @param remote_addrlen actual length of the @a remote_addr */ static void reversal_cb (void *cls, const struct sockaddr *remote_addr, socklen_t remote_addrlen) { GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, "Connection reversal requested by %s\n", GNUNET_a2s (remote_addr, remote_addrlen)); }
/** * Perform DNS resolution. * * @param ctx stub resolver to use * @param sa the socket address * @param sa_len the socket length * @param request DNS request to transmit * @param request_len number of bytes in msg * @param rc function to call with result * @param rc_cls closure for 'rc' * @return socket used for the request, NULL on error */ struct GNUNET_DNSSTUB_RequestSocket * GNUNET_DNSSTUB_resolve (struct GNUNET_DNSSTUB_Context *ctx, const struct sockaddr *sa, socklen_t sa_len, const void *request, size_t request_len, GNUNET_DNSSTUB_ResultCallback rc, void *rc_cls) { struct GNUNET_DNSSTUB_RequestSocket *rs; struct GNUNET_NETWORK_Handle *ret; int af; af = sa->sa_family; if (NULL == (rs = get_request_socket (ctx, af))) return NULL; if (NULL != rs->dnsout4) ret = rs->dnsout4; else ret = rs->dnsout6; GNUNET_assert (NULL != ret); memcpy (&rs->addr, sa, sa_len); rs->addrlen = sa_len; rs->rc = rc; rs->rc_cls = rc_cls; if (GNUNET_SYSERR == GNUNET_NETWORK_socket_sendto (ret, request, request_len, sa, sa_len)) GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Failed to send DNS request to %s\n"), GNUNET_a2s (sa, sa_len)); else GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Sent DNS request to %s\n"), GNUNET_a2s (sa, sa_len)); return rs; }
static void udp_ipv4_broadcast_send (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct Plugin *plugin = cls; int sent; uint16_t msg_size; char buf[65536] GNUNET_ALIGN; struct BroadcastAddress *baddr; plugin->send_ipv4_broadcast_task = GNUNET_SCHEDULER_NO_TASK; msg_size = prepare_beacon(plugin, (struct UDP_Beacon_Message *) &buf); sent = 0; baddr = plugin->ipv4_broadcast_head; /* just IPv4 */ while ((msg_size > 0) && (baddr != NULL) && (baddr->addrlen == sizeof (struct sockaddr_in))) { struct sockaddr_in *addr = (struct sockaddr_in *) baddr->addr; addr->sin_port = htons (plugin->port); sent = GNUNET_NETWORK_socket_sendto (plugin->sockv4, &buf, msg_size, (const struct sockaddr *) addr, baddr->addrlen); if (sent == GNUNET_SYSERR) { if ((ENETUNREACH == errno) || (ENETDOWN == errno)) { /* "Network unreachable" or "Network down" * * This indicates that we just do not have network connectivity */ GNUNET_log (GNUNET_ERROR_TYPE_BULK | GNUNET_ERROR_TYPE_WARNING, "Network connectivity is down, cannot send beacon!\n"); } else GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "sendto"); } else { LOG (GNUNET_ERROR_TYPE_DEBUG, "Sent HELLO beacon broadcast with %i bytes to address %s\n", sent, GNUNET_a2s (baddr->addr, baddr->addrlen)); } baddr = baddr->next; } plugin->send_ipv4_broadcast_task = GNUNET_SCHEDULER_add_delayed (plugin->broadcast_interval, &udp_ipv4_broadcast_send, plugin); }
/** * Signature of the callback passed to #GNUNET_NAT_register() for * a function to call whenever our set of 'valid' addresses changes. * * @param cls closure, NULL * @param add_remove #GNUNET_YES to add a new public IP address, * #GNUNET_NO to remove a previous (now invalid) one * @param ac address class the address belongs to * @param addr either the previous or the new public IP address * @param addrlen actual length of the @a addr */ static void address_cb (void *cls, int add_remove, enum GNUNET_NAT_AddressClass ac, const struct sockaddr *addr, socklen_t addrlen) { GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, "%s %s (%d)\n", add_remove ? "+" : "-", GNUNET_a2s (addr, addrlen), (int) ac); }
/** * Task invoked by the scheduler when a call to transmit * is timing out (we never got enough buffer space to call * the callback function before the specified timeout * expired). * * This task notifies the client about the timeout. * * @param cls the 'struct GNUNET_CONNECTION_Handle' * @param tc scheduler context */ static void transmit_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_CONNECTION_Handle *connection = cls; GNUNET_CONNECTION_TransmitReadyNotify notify; connection->nth.timeout_task = GNUNET_SCHEDULER_NO_TASK; LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmit to `%s:%u/%s' fails, time out reached (%p).\n", connection->hostname, connection->port, GNUNET_a2s (connection->addr, connection->addrlen), connection); notify = connection->nth.notify_ready; GNUNET_assert (NULL != notify); connection->nth.notify_ready = NULL; notify (connection->nth.notify_ready_cls, 0, NULL); }
/** * Check if access to the service is allowed from the given address. * * @param cls closure * @param uc credentials, if available, otherwise NULL * @param addr address * @param addrlen length of address * @return #GNUNET_YES to allow, #GNUNET_NO to deny, #GNUNET_SYSERR * for unknown address family (will be denied). */ static int check_access (void *cls, const struct GNUNET_CONNECTION_Credentials *uc, const struct sockaddr *addr, socklen_t addrlen) { struct GNUNET_SERVICE_Context *sctx = cls; const struct sockaddr_in *i4; const struct sockaddr_in6 *i6; int ret; switch (addr->sa_family) { case AF_INET: GNUNET_assert (addrlen == sizeof (struct sockaddr_in)); i4 = (const struct sockaddr_in *) addr; ret = ((NULL == sctx->v4_allowed) || (check_ipv4_listed (sctx->v4_allowed, &i4->sin_addr))) && ((NULL == sctx->v4_denied) || (!check_ipv4_listed (sctx->v4_denied, &i4->sin_addr))); break; case AF_INET6: GNUNET_assert (addrlen == sizeof (struct sockaddr_in6)); i6 = (const struct sockaddr_in6 *) addr; ret = ((NULL == sctx->v6_allowed) || (check_ipv6_listed (sctx->v6_allowed, &i6->sin6_addr))) && ((NULL == sctx->v6_denied) || (!check_ipv6_listed (sctx->v6_denied, &i6->sin6_addr))); break; #ifndef WINDOWS case AF_UNIX: ret = GNUNET_OK; /* controlled using file-system ACL now */ break; #endif default: LOG (GNUNET_ERROR_TYPE_WARNING, _("Unknown address family %d\n"), addr->sa_family); return GNUNET_SYSERR; } if (GNUNET_OK != ret) { LOG (GNUNET_ERROR_TYPE_WARNING, _("Access from `%s' denied to service `%s'\n"), GNUNET_a2s (addr, addrlen), sctx->service_name); } return ret; }
/** * Callback for message stream tokenizer * * @param cls the session * @param client not used * @param message the message received * @return always GNUNET_OK */ static int client_receive_mst_cb (void *cls, void *client, const struct GNUNET_MessageHeader *message) { struct Session *s = cls; struct HTTP_Client_Plugin *plugin; struct GNUNET_TIME_Relative delay; struct GNUNET_ATS_Information atsi[2]; char *stat_txt; if (GNUNET_YES != client_exist_session(p, s)) { GNUNET_break (0); return GNUNET_OK; } plugin = s->plugin; atsi[0].type = htonl (GNUNET_ATS_QUALITY_NET_DISTANCE); atsi[0].value = htonl (1); atsi[1].type = htonl (GNUNET_ATS_NETWORK_TYPE); atsi[1].value = s->ats_address_network_type; GNUNET_break (s->ats_address_network_type != ntohl (GNUNET_ATS_NET_UNSPECIFIED)); delay = s->plugin->env->receive (plugin->env->cls, &s->target, message, (const struct GNUNET_ATS_Information *) &atsi, 2, s, s->addr, s->addrlen); GNUNET_asprintf (&stat_txt, "# bytes received via %s_client", plugin->protocol); GNUNET_STATISTICS_update (plugin->env->stats, stat_txt, ntohs(message->size), GNUNET_NO); GNUNET_free (stat_txt); s->next_receive = GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (), delay); if (GNUNET_TIME_absolute_get ().abs_value < s->next_receive.abs_value) { GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Client: peer `%s' address `%s' next read delayed for %llu ms\n", GNUNET_i2s (&s->target), GNUNET_a2s (s->addr, s->addrlen), delay); } client_reschedule_session_timeout (s); return GNUNET_OK; }
static void udp_ipv6_broadcast_send (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct Plugin *plugin = cls; int sent; uint16_t msg_size; char buf[65536] GNUNET_ALIGN; plugin->send_ipv6_broadcast_task = GNUNET_SCHEDULER_NO_TASK; msg_size = prepare_beacon(plugin, (struct UDP_Beacon_Message *) &buf); sent = 0; sent = GNUNET_NETWORK_socket_sendto (plugin->sockv6, &buf, msg_size, (const struct sockaddr *) &plugin->ipv6_multicast_address, sizeof (struct sockaddr_in6)); if (sent == GNUNET_SYSERR) { if ((ENETUNREACH == errno) || (ENETDOWN == errno)) { /* "Network unreachable" or "Network down" * * This indicates that this system is IPv6 enabled, but does not * have a valid global IPv6 address assigned */ GNUNET_log (GNUNET_ERROR_TYPE_BULK | GNUNET_ERROR_TYPE_WARNING, "Network connectivity is down, cannot send beacon!\n"); } else GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "sendto"); } else { LOG (GNUNET_ERROR_TYPE_DEBUG, "Sending IPv6 HELLO beacon broadcast with %i bytes to address %s\n", sent, GNUNET_a2s ((const struct sockaddr *) &plugin->ipv6_multicast_address, sizeof (struct sockaddr_in6))); } plugin->send_ipv6_broadcast_task = GNUNET_SCHEDULER_add_delayed (plugin->broadcast_interval, &udp_ipv6_broadcast_send, plugin); }
/** * Function called on each address that the NAT service * believes to be valid for the transport. */ static void addr_callback (void *cls, int add_remove, const struct sockaddr *addr, socklen_t addrlen, enum GNUNET_NAT_StatusCode ret) { if (GNUNET_NAT_ERROR_SUCCESS == ret) { fprintf (stderr, "Address changed: %s `%s' (%u bytes)\n", add_remove == GNUNET_YES ? "added" : "removed", GNUNET_a2s (addr, addrlen), (unsigned int) addrlen); } else ; //TODO: proper error handling! }
static void start_report_addresses (struct Plugin *plugin) { int res = GNUNET_OK; struct sockaddr **addrs; socklen_t *addrlens; res = http_get_addresses (plugin, plugin->name, plugin->env->cfg, &addrs, &addrlens); GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, _("Found %u addresses to report to NAT service\n"), res); if (res != GNUNET_SYSERR) { plugin->nat = GNUNET_NAT_register (plugin->env->cfg, GNUNET_YES, plugin->port, (unsigned int) res, (const struct sockaddr **) addrs, addrlens, &nat_port_map_callback, NULL, plugin); while (res > 0) { res--; #if 0 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, _("FREEING %s\n"), GNUNET_a2s (addrs[res], addrlens[res])); #endif GNUNET_assert (addrs[res] != NULL); GNUNET_free (addrs[res]); } GNUNET_free_non_null (addrs); GNUNET_free_non_null (addrlens); } else { plugin->nat = GNUNET_NAT_register (plugin->env->cfg, GNUNET_YES, 0, 0, NULL, NULL, NULL, NULL, plugin); } }
/** * Our external IP address/port mapping has changed. * * @param cls closure, the 'struct LocalAddrList' * @param add_remove GNUNET_YES to mean the new public IP address, GNUNET_NO to mean * the previous (now invalid) one * @param addr either the previous or the new public IP address * @param addrlen actual lenght of the address */ static void nat_port_map_callback (void *cls, int add_remove, const struct sockaddr *addr, socklen_t addrlen) { GNUNET_assert (cls != NULL); struct Plugin *plugin = cls; GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "NPMC called %s to address `%s'\n", (add_remove == GNUNET_NO) ? "remove" : "add", GNUNET_a2s (addr, addrlen)); switch (add_remove) { case GNUNET_YES: nat_add_address (cls, add_remove, addr, addrlen); break; case GNUNET_NO: nat_remove_address (cls, add_remove, addr, addrlen); break; } }
/** * 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); }
/** * 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; }
/** * We are ready to transmit (or got a timeout). * * @param cls our connection handle * @param tc task context describing why we are here */ static void transmit_ready (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_CONNECTION_Handle *connection = cls; GNUNET_CONNECTION_TransmitReadyNotify notify; ssize_t ret; size_t have; LOG (GNUNET_ERROR_TYPE_DEBUG, "transmit_ready running (%p).\n", connection); GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != connection->write_task); connection->write_task = GNUNET_SCHEDULER_NO_TASK; GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == connection->nth.timeout_task); if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) { if (NULL != connection->sock) goto SCHEDULE_WRITE; /* ignore shutdown, go again immediately */ LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmit to `%s' fails, shutdown happened (%p).\n", GNUNET_a2s (connection->addr, connection->addrlen), connection); notify = connection->nth.notify_ready; if (NULL != notify) { connection->nth.notify_ready = NULL; notify (connection->nth.notify_ready_cls, 0, NULL); } return; } if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_TIMEOUT)) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmit to `%s' fails, time out reached (%p).\n", GNUNET_a2s (connection->addr, connection->addrlen), connection); notify = connection->nth.notify_ready; GNUNET_assert (NULL != notify); connection->nth.notify_ready = NULL; notify (connection->nth.notify_ready_cls, 0, NULL); return; } GNUNET_assert (NULL != connection->sock); if (NULL == tc->write_ready) { /* special circumstances (in particular, PREREQ_DONE after * connect): not yet ready to write, but no "fatal" error either. * Hence retry. */ goto SCHEDULE_WRITE; } if (!GNUNET_NETWORK_fdset_isset (tc->write_ready, connection->sock)) { GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == connection->write_task); /* special circumstances (in particular, shutdown): not yet ready * to write, but no "fatal" error either. Hence retry. */ goto SCHEDULE_WRITE; } GNUNET_assert (connection->write_buffer_off >= connection->write_buffer_pos); if ((NULL != connection->nth.notify_ready) && (connection->write_buffer_size < connection->nth.notify_size)) { connection->write_buffer = GNUNET_realloc (connection->write_buffer, connection->nth.notify_size); connection->write_buffer_size = connection->nth.notify_size; } process_notify (connection); have = connection->write_buffer_off - connection->write_buffer_pos; if (0 == have) { /* no data ready for writing, terminate write loop */ return; } GNUNET_assert (have <= connection->write_buffer_size); GNUNET_assert (have + connection->write_buffer_pos <= connection->write_buffer_size); GNUNET_assert (connection->write_buffer_pos <= connection->write_buffer_size); RETRY: ret = GNUNET_NETWORK_socket_send (connection->sock, &connection->write_buffer[connection->write_buffer_pos], have); if (-1 == ret) { if (EINTR == errno) goto RETRY; if (GNUNET_SCHEDULER_NO_TASK != connection->write_task) { GNUNET_SCHEDULER_cancel (connection->write_task); connection->write_task = GNUNET_SCHEDULER_NO_TASK; } signal_transmit_error (connection, errno); return; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Connection transmitted %u/%u bytes to `%s' (%p)\n", (unsigned int) ret, have, GNUNET_a2s (connection->addr, connection->addrlen), connection); connection->write_buffer_pos += ret; if (connection->write_buffer_pos == connection->write_buffer_off) { /* transmitted all pending data */ connection->write_buffer_pos = 0; connection->write_buffer_off = 0; } if ((0 == connection->write_buffer_off) && (NULL == connection->nth.notify_ready)) return; /* all data sent! */ /* not done writing, schedule more */ SCHEDULE_WRITE: LOG (GNUNET_ERROR_TYPE_DEBUG, "Re-scheduling transmit_ready (more to do) (%p).\n", connection); have = connection->write_buffer_off - connection->write_buffer_pos; GNUNET_assert ((NULL != connection->nth.notify_ready) || (have > 0)); if (GNUNET_SCHEDULER_NO_TASK == connection->write_task) connection->write_task = GNUNET_SCHEDULER_add_write_net ((connection->nth.notify_ready == NULL) ? GNUNET_TIME_UNIT_FOREVER_REL : GNUNET_TIME_absolute_get_remaining (connection->nth.transmit_timeout), connection->sock, &transmit_ready, connection); }
/** * Process response with a hostname for a DNS lookup. * * @param cls our "struct GNUNET_RESOLVER_RequestHandle" context * @param msg message with the hostname, NULL on error */ static void handle_response (void *cls, const struct GNUNET_MessageHeader *msg) { struct GNUNET_RESOLVER_RequestHandle *rh = cls; uint16_t size; LOG (GNUNET_ERROR_TYPE_DEBUG, "Receiving response from DNS service\n"); if (msg == NULL) { char buf[INET6_ADDRSTRLEN]; if (NULL != rh->name_callback) LOG (GNUNET_ERROR_TYPE_INFO, _("Timeout trying to resolve IP address `%s'.\n"), inet_ntop (rh->af, (const void *) &rh[1], buf, sizeof(buf))); else LOG (GNUNET_ERROR_TYPE_INFO, _("Timeout trying to resolve hostname `%s'.\n"), (const char *) &rh[1]); /* check if request was canceled */ if (rh->was_transmitted != GNUNET_SYSERR) { if (NULL != rh->name_callback) { /* no reverse lookup was successful, return ip as string */ if (rh->received_response == GNUNET_NO) rh->name_callback (rh->cls, no_resolve (rh->af, &rh[1], rh->data_len)); /* at least one reverse lookup was successful */ else rh->name_callback (rh->cls, NULL); } if (NULL != rh->addr_callback) rh->addr_callback (rh->cls, NULL, 0); } GNUNET_CONTAINER_DLL_remove (req_head, req_tail, rh); GNUNET_free (rh); GNUNET_CLIENT_disconnect (client); client = NULL; reconnect (); return; } if (GNUNET_MESSAGE_TYPE_RESOLVER_RESPONSE != ntohs (msg->type)) { GNUNET_break (0); GNUNET_CLIENT_disconnect (client); client = NULL; reconnect (); return; } size = ntohs (msg->size); /* message contains not data, just header */ if (size == sizeof (struct GNUNET_MessageHeader)) { /* check if request was canceled */ if (rh->was_transmitted != GNUNET_SYSERR) { if (NULL != rh->name_callback) rh->name_callback (rh->cls, NULL); if (NULL != rh->addr_callback) rh->addr_callback (rh->cls, NULL, 0); } GNUNET_CONTAINER_DLL_remove (req_head, req_tail, rh); GNUNET_free (rh); process_requests (); return; } /* return reverse lookup results to caller */ if (NULL != rh->name_callback) { const char *hostname; hostname = (const char *) &msg[1]; if (hostname[size - sizeof (struct GNUNET_MessageHeader) - 1] != '\0') { GNUNET_break (0); if (rh->was_transmitted != GNUNET_SYSERR) rh->name_callback (rh->cls, NULL); GNUNET_CONTAINER_DLL_remove (req_head, req_tail, rh); GNUNET_free (rh); GNUNET_CLIENT_disconnect (client); client = NULL; reconnect (); return; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Resolver returns `%s' for IP `%s'.\n", hostname, GNUNET_a2s ((const void *) &rh[1], rh->data_len)); if (rh->was_transmitted != GNUNET_SYSERR) rh->name_callback (rh->cls, hostname); rh->received_response = GNUNET_YES; GNUNET_CLIENT_receive (client, &handle_response, rh, GNUNET_TIME_absolute_get_remaining (rh->timeout)); } /* return lookup results to caller */ if (NULL != rh->addr_callback) { struct sockaddr_in v4; struct sockaddr_in6 v6; const struct sockaddr *sa; socklen_t salen; const void *ip; size_t ip_len; ip = &msg[1]; ip_len = size - sizeof (struct GNUNET_MessageHeader); if (ip_len == sizeof (struct in_addr)) { memset (&v4, 0, sizeof (v4)); v4.sin_family = AF_INET; v4.sin_addr = *(struct in_addr*) ip; #if HAVE_SOCKADDR_IN_SIN_LEN v4.sin_len = sizeof (v4); #endif salen = sizeof (v4); sa = (const struct sockaddr *) &v4; } else if (ip_len == sizeof (struct in6_addr)) { memset (&v6, 0, sizeof (v6)); v6.sin6_family = AF_INET6; v6.sin6_addr = *(struct in6_addr*) ip; #if HAVE_SOCKADDR_IN_SIN_LEN v6.sin6_len = sizeof (v6); #endif salen = sizeof (v6); sa = (const struct sockaddr *) &v6; } else { GNUNET_break (0); if (rh->was_transmitted != GNUNET_SYSERR) rh->addr_callback (rh->cls, NULL, 0); GNUNET_CONTAINER_DLL_remove (req_head, req_tail, rh); GNUNET_free (rh); GNUNET_CLIENT_disconnect (client); client = NULL; reconnect (); return; } rh->addr_callback (rh->cls, sa, salen); GNUNET_CLIENT_receive (client, &handle_response, rh, GNUNET_TIME_absolute_get_remaining (rh->timeout)); } }
/** * Callback function invoked for each interface found. * * @param cls closure with the `struct Plugin` * @param name name of the interface (can be NULL for unknown) * @param isDefault is this presumably the default interface * @param addr address of this interface (can be NULL for unknown or unassigned) * @param broadcast_addr the broadcast address (can be NULL for unknown or unassigned) * @param netmask the network mask (can be NULL for unknown or unassigned) * @param addrlen length of the address * @return #GNUNET_OK to continue iteration, #GNUNET_SYSERR to abort */ static int iface_proc (void *cls, const char *name, int isDefault, const struct sockaddr *addr, const struct sockaddr *broadcast_addr, const struct sockaddr *netmask, socklen_t addrlen) { struct Plugin *plugin = cls; struct BroadcastAddress *ba; enum GNUNET_ATS_Network_Type network; if (NULL == addr) return GNUNET_OK; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "address %s for interface %s %p\n ", GNUNET_a2s (addr, addrlen), name, addr); if (NULL == broadcast_addr) return GNUNET_OK; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "broadcast address %s for interface %s %p\n ", GNUNET_a2s (broadcast_addr, addrlen), name, broadcast_addr); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "netmask %s for interface %s %p\n ", GNUNET_a2s (netmask, addrlen), name, netmask); network = plugin->env->get_address_type (plugin->env->cls, broadcast_addr, addrlen); if (GNUNET_ATS_NET_LOOPBACK == network) { /* Broadcasting on loopback does not make sense */ return GNUNET_YES; } ba = GNUNET_new (struct BroadcastAddress); ba->plugin = plugin; ba->addr = GNUNET_malloc (addrlen); GNUNET_memcpy (ba->addr, broadcast_addr, addrlen); ba->addrlen = addrlen; if ( (GNUNET_YES == plugin->enable_ipv4) && (NULL != plugin->sockv4) && (addrlen == sizeof (struct sockaddr_in)) ) { #if LINUX /* * setup Cryogenic FD for ipv4 broadcasting */ char *filename; GNUNET_asprintf (&filename, "/dev/cryogenic/%s", name); if (0 == ACCESS (name, R_OK)) { ba->cryogenic_fd = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_WRITE, GNUNET_DISK_PERM_NONE); } GNUNET_free (filename); #endif ba->broadcast_task = GNUNET_SCHEDULER_add_now (&udp_ipv4_broadcast_send, ba); } if ((GNUNET_YES == plugin->enable_ipv6) && (NULL != plugin->sockv6) && (addrlen == sizeof (struct sockaddr_in6))) { /* Create IPv6 multicast request */ struct ipv6_mreq multicastRequest; const struct sockaddr_in6 *s6 = (const struct sockaddr_in6 *) broadcast_addr; multicastRequest.ipv6mr_multiaddr = plugin->ipv6_multicast_address.sin6_addr; /* http://tools.ietf.org/html/rfc2553#section-5.2: * * IPV6_JOIN_GROUP * * Join a multicast group on a specified local interface. If the * interface index is specified as 0, the kernel chooses the local * interface. For example, some kernels look up the multicast * group in the normal IPv6 routing table and using the resulting * interface; we do this for each interface, so no need to use * zero (anymore...). */ multicastRequest.ipv6mr_interface = s6->sin6_scope_id; /* Join the multicast group */ if (GNUNET_OK != GNUNET_NETWORK_socket_setsockopt (plugin->sockv6, IPPROTO_IPV6, IPV6_JOIN_GROUP, &multicastRequest, sizeof (multicastRequest))) { LOG (GNUNET_ERROR_TYPE_WARNING, "Failed to join IPv6 multicast group: IPv6 broadcasting not running\n"); } else { #if LINUX /* * setup Cryogenic FD for ipv6 broadcasting */ char *filename; GNUNET_asprintf (&filename, "/dev/cryogenic/%s", name); if (0 == ACCESS (name, R_OK)) { ba->cryogenic_fd = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_WRITE, GNUNET_DISK_PERM_NONE); } GNUNET_free (filename); #endif ba->broadcast_task = GNUNET_SCHEDULER_add_now (&udp_ipv6_broadcast_send, ba); } } GNUNET_CONTAINER_DLL_insert (plugin->broadcast_head, plugin->broadcast_tail, ba); return GNUNET_OK; }