X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Ftransport%2Fgnunet-communicator-udp.c;h=fa8eb6acb913e602e45cf58158795abfccc29ff6;hb=9859b3162a9fd7c9cc0c19582b04dd7f1c1f9408;hp=d464cd0d17700ae5eba4305e37acdf3022f02d97;hpb=4781fabceb3530e976c27ea37999c8eaa3165612;p=oweals%2Fgnunet.git diff --git a/src/transport/gnunet-communicator-udp.c b/src/transport/gnunet-communicator-udp.c index d464cd0d1..fa8eb6acb 100644 --- a/src/transport/gnunet-communicator-udp.c +++ b/src/transport/gnunet-communicator-udp.c @@ -24,17 +24,13 @@ * @author Christian Grothoff * * TODO: - * - implement main BOXed sending logic - * - figure out what to do with MTU: 1280 for IPv6 is obvious; - * what for IPv4? 1500? Also, consider differences in - * headers for with/without box: need to give MIN of both - * to TNG (as TNG expects a fixed MTU!), or maybe - * we create a FRESH MQ while we have available BOXes SQNs? - * (otherwise padding will REALLY hurt) - * - add and use util/ check for IPv6 availability (#V6) * - consider imposing transmission limits in the absence * of ACKs; or: maybe this should be done at TNG service level? - * - support broadcasting for neighbour discovery (#) + * (at least the receiver might want to enforce limits on + * KX/DH operations per sender in here) (#5552) + * - overall, we should look more into flow control support + * (either in backchannel, or general solution in TNG service) + * - handle addresses discovered from broadcasts (#5551) * (think: what was the story again on address validation? * where is the API for that!?!) * - support DNS names in BINDTO option (#5528) @@ -61,6 +57,16 @@ */ #define PROTO_QUEUE_TIMEOUT GNUNET_TIME_UNIT_MINUTES +/** + * How often do we broadcast our presence on the LAN? + */ +#define BROADCAST_FREQUENCY GNUNET_TIME_UNIT_MINUTES + +/** + * How often do we scan for changes to our network interfaces? + */ +#define INTERFACE_SCAN_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5) + /** * AES key size. */ @@ -525,6 +531,12 @@ struct ReceiverAddress */ struct SharedSecret *ss_tail; + /** + * Address of the receiver in the human-readable format + * with the #COMMUNICATOR_ADDRESS_PREFIX. + */ + char *foreign_addr; + /** * Address of the other peer. */ @@ -564,6 +576,12 @@ struct ReceiverAddress * Length of the DLL at @a ss_head. */ unsigned int num_secrets; + + /** + * Number of BOX keys from ACKs we have currently + * available for this receiver. + */ + unsigned int acks_available; /** * Which network type does this queue use? @@ -573,6 +591,60 @@ struct ReceiverAddress }; +/** + * Interface we broadcast our presence on. + */ +struct BroadcastInterface +{ + + /** + * Kept in a DLL. + */ + struct BroadcastInterface *next; + + /** + * Kept in a DLL. + */ + struct BroadcastInterface *prev; + + /** + * Task for this broadcast interface. + */ + struct GNUNET_SCHEDULER_Task *broadcast_task; + + /** + * Sender's address of the interface. + */ + struct sockaddr *sa; + + /** + * Broadcast address to use on the interface. + */ + struct sockaddr *ba; + + /** + * Message we broadcast on this interface. + */ + struct UDPBroadcast bcm; + + /** + * If this is an IPv6 interface, this is the request + * we use to join/leave the group. + */ + struct ipv6_mreq mcreq; + + /** + * Number of bytes in @e sa. + */ + socklen_t salen; + + /** + * Was this interface found in the last #iface_proc() scan? + */ + int found; +}; + + /** * Cache of pre-generated key IDs. */ @@ -588,6 +660,11 @@ static struct GNUNET_SCHEDULER_Task *read_task; */ static struct GNUNET_SCHEDULER_Task *timeout_task; +/** + * ID of master broadcast task + */ +static struct GNUNET_SCHEDULER_Task *broadcast_task; + /** * For logging statistics. */ @@ -618,11 +695,26 @@ static struct GNUNET_CONTAINER_Heap *senders_heap; */ static struct GNUNET_CONTAINER_Heap *receivers_heap; +/** + * Broadcast interface tasks. Kept in a DLL. + */ +static struct BroadcastInterface *bi_head; + +/** + * Broadcast interface tasks. Kept in a DLL. + */ +static struct BroadcastInterface *bi_tail; + /** * Our socket. */ static struct GNUNET_NETWORK_Handle *udp_sock; +/** + * #GNUNET_YES if #udp_sock supports IPv6. + */ +static int have_v6_socket; + /** * Our public key. */ @@ -648,10 +740,47 @@ static struct GNUNET_NT_InterfaceScanner *is; */ static struct GNUNET_NAT_Handle *nat; +/** + * Port number to which we are actually bound. + */ +static uint16_t my_port; + /** - * Functions with this signature are called whenever we need - * to close a receiving state due to timeout. + * An interface went away, stop broadcasting on it. + * + * @param bi entity to close down + */ +static void +bi_destroy (struct BroadcastInterface *bi) +{ + if (AF_INET6 == bi->sa->sa_family) + { + /* Leave the multicast group */ + if (GNUNET_OK != + GNUNET_NETWORK_socket_setsockopt + (udp_sock, + IPPROTO_IPV6, + IPV6_LEAVE_GROUP, + &bi->mcreq, + sizeof (bi->mcreq))) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, + "setsockopt"); + } + } + GNUNET_CONTAINER_DLL_remove (bi_head, + bi_tail, + bi); + GNUNET_SCHEDULER_cancel (bi->broadcast_task); + GNUNET_free (bi->sa); + GNUNET_free_non_null (bi->ba); + GNUNET_free (bi); +} + + +/** + * Destroys a receiving state due to timeout or shutdown. * * @param receiver entity to close down */ @@ -668,6 +797,11 @@ receiver_destroy (struct ReceiverAddress *receiver) receiver->mq = NULL; GNUNET_MQ_destroy (mq); } + if (NULL != receiver->qh) + { + GNUNET_TRANSPORT_communicator_mq_del (receiver->qh); + receiver->qh = NULL; + } GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multipeermap_remove (receivers, &receiver->target, @@ -679,6 +813,7 @@ receiver_destroy (struct ReceiverAddress *receiver) GNUNET_CONTAINER_multipeermap_size (receivers), GNUNET_NO); GNUNET_free (receiver->address); + GNUNET_free (receiver->foreign_addr); GNUNET_free (receiver); } @@ -792,6 +927,8 @@ secret_destroy (struct SharedSecret *ss) receiver->ss_tail, ss); receiver->num_secrets--; + receiver->acks_available + -= (ss->sequence_allowed - ss->sequence_used); } while (NULL != (kce = ss->kce_head)) kce_destroy (kce); @@ -1131,6 +1268,17 @@ setup_shared_secret_enc (const struct GNUNET_CRYPTO_EcdhePrivateKey *ephemeral, } +/** + * Setup the MQ for the @a receiver. If a queue exists, + * the existing one is destroyed. Then the MTU is + * recalculated and a fresh queue is initialized. + * + * @param receiver receiver to setup MQ for + */ +static void +setup_receiver_mq (struct ReceiverAddress *receiver); + + /** * We received an ACK for @a pid. Check if it is for * the receiver in @a value and if so, handle it and @@ -1158,17 +1306,28 @@ handle_ack (void *cls, &ss->cmac, sizeof (struct GNUNET_HashCode))) { - ss->sequence_allowed = GNUNET_MAX (ss->sequence_allowed, - ntohl (ack->sequence_max)); - /* move ss to head to avoid discarding it anytime soon! */ - GNUNET_CONTAINER_DLL_remove (receiver->ss_head, - receiver->ss_tail, - ss); - GNUNET_CONTAINER_DLL_insert (receiver->ss_head, - receiver->ss_tail, - ss); - /* FIXME: if this changed sequence_allowed, - update MTU / MQ of 'receiver'! */ + uint32_t allowed; + + allowed = ntohl (ack->sequence_max); + + if (allowed > ss->sequence_allowed) + { + receiver->acks_available += (allowed - ss->sequence_allowed); + if ((allowed - ss->sequence_allowed) + == receiver->acks_available) + { + /* we just incremented from zero => MTU change! */ + setup_receiver_mq (receiver); + } + ss->sequence_allowed = allowed; + /* move ss to head to avoid discarding it anytime soon! */ + GNUNET_CONTAINER_DLL_remove (receiver->ss_head, + receiver->ss_tail, + ss); + GNUNET_CONTAINER_DLL_insert (receiver->ss_head, + receiver->ss_tail, + ss); + } return GNUNET_NO; } } @@ -1512,7 +1671,7 @@ sock_read (void *cls) "# broadcasts received", 1, GNUNET_NO); - // FIXME: we effectively just got a HELLO! + // FIXME #5551: we effectively just got a HELLO! // trigger verification NOW! return; } @@ -1624,12 +1783,12 @@ udp_address_to_sockaddr (const char *bindto, bindto); return NULL; } - /* FIXME #V6: add test to util/ for IPv6 availability, - and depending on the result, go directly for v4-only */ - if (GNUNET_YES == - GNUNET_CONFIGURATION_get_value_yesno (cfg, - COMMUNICATOR_CONFIG_SECTION, - "DISABLE_V6")) + if ( (GNUNET_NO == + GNUNET_NETWORK_test_pf (PF_INET6)) || + (GNUNET_YES == + GNUNET_CONFIGURATION_get_value_yesno (cfg, + COMMUNICATOR_CONFIG_SECTION, + "DISABLE_V6")) ) { struct sockaddr_in *i4; @@ -1733,6 +1892,43 @@ udp_address_to_sockaddr (const char *bindto, } +/** + * Pad @a dgram by @a pad_size using @a out_cipher. + * + * @param out_cipher cipher to use + * @param dgram datagram to pad + * @param pad_size number of bytes of padding to append + */ +static void +do_pad (gcry_cipher_hd_t out_cipher, + char *dgram, + size_t pad_size) +{ + char pad[pad_size]; + + GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, + pad, + sizeof (pad)); + if (sizeof (pad) > sizeof (struct GNUNET_MessageHeader)) + { + struct GNUNET_MessageHeader hdr = { + .size = htons (sizeof (pad)), + .type = htons (GNUNET_MESSAGE_TYPE_COMMUNICATOR_UDP_PAD) + }; + + memcpy (pad, + &hdr, + sizeof (hdr)); + } + GNUNET_assert (0 == + gcry_cipher_encrypt (out_cipher, + dgram, + sizeof (pad), + pad, + sizeof (pad))); +} + + /** * Signature of functions implementing the sending functionality of a * message queue. @@ -1758,10 +1954,9 @@ mq_send (struct GNUNET_MQ_Handle *mq, } reschedule_receiver_timeout (receiver); - // FIXME: add support for BOX encryption method! - - /* KX encryption method */ + if (0 == receiver->acks_available) { + /* use KX encryption method */ struct UdpHandshakeSignature uhs; struct UDPConfirmation uc; struct InitialKX kx; @@ -1814,31 +2009,9 @@ mq_send (struct GNUNET_MQ_Handle *mq, msg, msize)); dpos += msize; - /* Pad to MTU */ - { - char pad[sizeof (dgram) - dpos]; - - GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, - pad, - sizeof (pad)); - if (sizeof (pad) > sizeof (struct GNUNET_MessageHeader)) - { - struct GNUNET_MessageHeader hdr = { - .size = htons (sizeof (pad)), - .type = htons (GNUNET_MESSAGE_TYPE_COMMUNICATOR_UDP_PAD) - }; - - memcpy (pad, - &hdr, - sizeof (hdr)); - GNUNET_assert (0 == - gcry_cipher_encrypt (out_cipher, - &dgram[dpos], - sizeof (pad), - pad, - sizeof (pad))); - } - } + do_pad (out_cipher, + &dgram[dpos], + sizeof (dgram) - dpos); /* Datagram starts with kx */ kx.ephemeral = uhs.ephemeral; GNUNET_assert (0 == @@ -1858,7 +2031,65 @@ mq_send (struct GNUNET_MQ_Handle *mq, GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "send"); GNUNET_MQ_impl_send_continue (mq); + return; } /* End of KX encryption method */ + + /* begin "BOX" encryption method, scan for ACKs from tail! */ + for (struct SharedSecret *ss = receiver->ss_tail; + NULL != ss; + ss = ss->prev) + { + if (ss->sequence_used < ss->sequence_allowed) + { + char dgram[sizeof (struct UDPBox) + receiver->mtu]; + struct UDPBox *box; + gcry_cipher_hd_t out_cipher; + size_t dpos; + + box = (struct UDPBox *) dgram; + ss->sequence_used++; + get_kid (&ss->master, + ss->sequence_used, + &box->kid); + setup_cipher (&ss->master, + ss->sequence_used, + &out_cipher); + /* Append encrypted payload to dgram */ + dpos = sizeof (struct UDPBox); + GNUNET_assert (0 == + gcry_cipher_encrypt (out_cipher, + &dgram[dpos], + msize, + msg, + msize)); + dpos += msize; + do_pad (out_cipher, + &dgram[dpos], + sizeof (dgram) - dpos); + GNUNET_assert (0 == + gcry_cipher_gettag (out_cipher, + box->gcm_tag, + sizeof (box->gcm_tag))); + gcry_cipher_close (out_cipher); + if (-1 == + GNUNET_NETWORK_socket_sendto (udp_sock, + dgram, + sizeof (dgram), + receiver->address, + receiver->address_len)) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, + "send"); + GNUNET_MQ_impl_send_continue (mq); + receiver->acks_available--; + if (0 == receiver->acks_available) + { + /* We have no more ACKs => MTU change! */ + setup_receiver_mq (receiver); + } + return; + } + } + GNUNET_assert (0); } @@ -1922,6 +2153,77 @@ mq_error (void *cls, } +/** + * Setup the MQ for the @a receiver. If a queue exists, + * the existing one is destroyed. Then the MTU is + * recalculated and a fresh queue is initialized. + * + * @param receiver receiver to setup MQ for + */ +static void +setup_receiver_mq (struct ReceiverAddress *receiver) +{ + size_t base_mtu; + + if (NULL != receiver->qh) + { + GNUNET_TRANSPORT_communicator_mq_del (receiver->qh); + receiver->qh = NULL; + } + GNUNET_assert (NULL == receiver->mq); + switch (receiver->address->sa_family) + { + case AF_INET: + base_mtu + = 1480 /* Ethernet MTU, 1500 - Ethernet header - VLAN tag */ + - sizeof (struct GNUNET_TUN_IPv4Header) /* 20 */ + - sizeof (struct GNUNET_TUN_UdpHeader) /* 8 */; + break; + case AF_INET6: + base_mtu + = 1280 /* Minimum MTU required by IPv6 */ + - sizeof (struct GNUNET_TUN_IPv6Header) /* 40 */ + - sizeof (struct GNUNET_TUN_UdpHeader) /* 8 */; + break; + default: + GNUNET_assert (0); + break; + } + if (0 == receiver->acks_available) + { + /* MTU based on full KX messages */ + receiver->mtu + = base_mtu + - sizeof (struct InitialKX) /* 48 */ + - sizeof (struct UDPConfirmation); /* 104 */ + } + else + { + /* MTU based on BOXed messages */ + receiver->mtu + = base_mtu - sizeof (struct UDPBox); + } + /* => Effective MTU for CORE will range from 1080 (IPv6 + KX) to + 1404 (IPv4 + Box) bytes, depending on circumstances... */ + receiver->mq + = GNUNET_MQ_queue_for_callbacks (&mq_send, + &mq_destroy, + &mq_cancel, + receiver, + NULL, + &mq_error, + receiver); + receiver->qh + = GNUNET_TRANSPORT_communicator_mq_add (ch, + &receiver->target, + receiver->foreign_addr, + receiver->mtu, + receiver->nt, + GNUNET_TRANSPORT_CS_OUTBOUND, + receiver->mq); +} + + /** * Setup a receiver for transmission. Setup the MQ processing and * inform transport that the queue is ready. @@ -1952,54 +2254,35 @@ receiver_setup (const struct GNUNET_PeerIdentity *target, receiver->hn = GNUNET_CONTAINER_heap_insert (receivers_heap, receiver, receiver->timeout.abs_value_us); - receiver->mq - = GNUNET_MQ_queue_for_callbacks (&mq_send, - &mq_destroy, - &mq_cancel, - receiver, - NULL, - &mq_error, - receiver); - receiver->mtu = 1200 /* FIXME: MTU OK? */; - if (NULL == timeout_task) - timeout_task = GNUNET_SCHEDULER_add_now (&check_timeouts, - NULL); GNUNET_STATISTICS_set (stats, "# receivers active", GNUNET_CONTAINER_multipeermap_size (receivers), GNUNET_NO); + switch (address->sa_family) { - char *foreign_addr; - - switch (address->sa_family) - { - case AF_INET: - GNUNET_asprintf (&foreign_addr, - "%s-%s", - COMMUNICATOR_ADDRESS_PREFIX, - GNUNET_a2s (receiver->address, - receiver->address_len)); - break; - case AF_INET6: - GNUNET_asprintf (&foreign_addr, - "%s-%s", - COMMUNICATOR_ADDRESS_PREFIX, - GNUNET_a2s (receiver->address, - receiver->address_len)); - break; - default: - GNUNET_assert (0); - } - receiver->qh - = GNUNET_TRANSPORT_communicator_mq_add (ch, - &receiver->target, - foreign_addr, - receiver->mtu, - receiver->nt, - GNUNET_TRANSPORT_CS_OUTBOUND, - receiver->mq); - GNUNET_free (foreign_addr); + case AF_INET: + GNUNET_asprintf (&receiver->foreign_addr, + "%s-%s", + COMMUNICATOR_ADDRESS_PREFIX, + GNUNET_a2s (receiver->address, + receiver->address_len)); + break; + case AF_INET6: + GNUNET_asprintf (&receiver->foreign_addr, + "%s-%s", + COMMUNICATOR_ADDRESS_PREFIX, + GNUNET_a2s (receiver->address, + receiver->address_len)); + break; + default: + GNUNET_assert (0); } + + setup_receiver_mq (receiver); + + if (NULL == timeout_task) + timeout_task = GNUNET_SCHEDULER_add_now (&check_timeouts, + NULL); return receiver; } @@ -2106,6 +2389,13 @@ do_shutdown (void *cls) GNUNET_NAT_unregister (nat); nat = NULL; } + while (NULL != bi_head) + bi_destroy (bi_head); + if (NULL != broadcast_task) + { + GNUNET_SCHEDULER_cancel (broadcast_task); + broadcast_task = NULL; + } if (NULL != read_task) { GNUNET_SCHEDULER_cancel (read_task); @@ -2235,6 +2525,240 @@ nat_address_cb (void *cls, } +/** + * Broadcast our presence on one of our interfaces. + * + * @param cls a `struct BroadcastInterface` + */ +static void +ifc_broadcast (void *cls) +{ + struct BroadcastInterface *bi = cls; + struct GNUNET_TIME_Relative delay; + + delay = BROADCAST_FREQUENCY; + delay.rel_value_us = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, + delay.rel_value_us); + bi->broadcast_task + = GNUNET_SCHEDULER_add_delayed (INTERFACE_SCAN_FREQUENCY, + &ifc_broadcast, + bi); + + switch (bi->sa->sa_family) { + case AF_INET: + { + static int yes = 1; + static int no = 0; + ssize_t sent; + + if (GNUNET_OK != + GNUNET_NETWORK_socket_setsockopt (udp_sock, + SOL_SOCKET, + SO_BROADCAST, + &yes, + sizeof (int))) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, + "setsockopt"); + sent = GNUNET_NETWORK_socket_sendto (udp_sock, + &bi->bcm, + sizeof (bi->bcm), + bi->ba, + bi->salen); + if (-1 == sent) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, + "sendto"); + if (GNUNET_OK != + GNUNET_NETWORK_socket_setsockopt (udp_sock, + SOL_SOCKET, + SO_BROADCAST, + &no, + sizeof (int))) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, + "setsockopt"); + break; + } + case AF_INET6: + { + ssize_t sent; + struct sockaddr_in6 dst; + + dst.sin6_family = AF_INET6; + dst.sin6_port = htons (my_port); + dst.sin6_addr = bi->mcreq.ipv6mr_multiaddr; + dst.sin6_scope_id = ((struct sockaddr_in6*) bi->ba)->sin6_scope_id; + + sent = GNUNET_NETWORK_socket_sendto (udp_sock, + &bi->bcm, + sizeof (bi->bcm), + (const struct sockaddr *) + &dst, + sizeof (dst)); + if (-1 == sent) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, + "sendto"); + break; + } + default: + GNUNET_break (0); + break; + } +} + + +/** + * Callback function invoked for each interface found. + * Activates/deactivates broadcast interfaces. + * + * @param cls NULL + * @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 BroadcastInterface *bi; + enum GNUNET_NetworkType network; + struct UdpBroadcastSignature ubs; + + (void) cls; + (void) netmask; + network = GNUNET_NT_scanner_get_type (is, + addr, + addrlen); + if (GNUNET_NT_LOOPBACK == network) + { + /* Broadcasting on loopback does not make sense */ + return GNUNET_YES; + } + if (NULL == addr) + return GNUNET_YES; /* need to know our address! */ + for (bi = bi_head; NULL != bi; bi = bi->next) + { + if ( (bi->salen == addrlen) && + (0 == memcmp (addr, + bi->sa, + addrlen)) ) + { + bi->found = GNUNET_YES; + return GNUNET_OK; + } + } + + if ( (AF_INET6 == addr->sa_family) && + (NULL == broadcast_addr) ) + return GNUNET_OK; /* broadcast_addr is required for IPv6! */ + if ( (AF_INET6 == addr->sa_family) && + (GNUNET_YES != have_v6_socket) ) + return GNUNET_OK; /* not using IPv6 */ + + bi = GNUNET_new (struct BroadcastInterface); + bi->sa = GNUNET_memdup (addr, + addrlen); + if (NULL != broadcast_addr) + bi->ba = GNUNET_memdup (broadcast_addr, + addrlen); + bi->salen = addrlen; + bi->found = GNUNET_YES; + bi->bcm.sender = my_identity; + ubs.purpose.purpose = htonl (GNUNET_SIGNATURE_COMMUNICATOR_UDP_BROADCAST); + ubs.purpose.size = htonl (sizeof (ubs)); + ubs.sender = my_identity; + GNUNET_CRYPTO_hash (addr, + addrlen, + &ubs.h_address); + GNUNET_assert (GNUNET_OK == + GNUNET_CRYPTO_eddsa_sign (my_private_key, + &ubs.purpose, + &bi->bcm.sender_sig)); + bi->broadcast_task = GNUNET_SCHEDULER_add_now (&ifc_broadcast, + bi); + GNUNET_CONTAINER_DLL_insert (bi_head, + bi_tail, + bi); + if ( (AF_INET6 == addr->sa_family) && + (NULL != broadcast_addr) ) + { + /* Create IPv6 multicast request */ + const struct sockaddr_in6 *s6 + = (const struct sockaddr_in6 *) broadcast_addr; + + GNUNET_assert (1 == + inet_pton (AF_INET6, + "FF05::13B", + &bi->mcreq.ipv6mr_multiaddr)); + + /* 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...). + */ + bi->mcreq.ipv6mr_interface = s6->sin6_scope_id; + + /* Join the multicast group */ + if (GNUNET_OK != + GNUNET_NETWORK_socket_setsockopt + (udp_sock, + IPPROTO_IPV6, + IPV6_JOIN_GROUP, + &bi->mcreq, + sizeof (bi->mcreq))) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, + "setsockopt"); + } + } + return GNUNET_OK; +} + + +/** + * Scan interfaces to broadcast our presence on the LAN. + * + * @param cls NULL, unused + */ +static void +do_broadcast (void *cls) +{ + struct BroadcastInterface *bin; + + (void) cls; + for (struct BroadcastInterface *bi = bi_head; + NULL != bi; + bi = bi->next) + bi->found = GNUNET_NO; + GNUNET_OS_network_interfaces_list (&iface_proc, + NULL); + for (struct BroadcastInterface *bi = bi_head; + NULL != bi; + bi = bin) + { + bin = bi->next; + if (GNUNET_NO == bi->found) + bi_destroy (bi); + } + broadcast_task + = GNUNET_SCHEDULER_add_delayed (INTERFACE_SCAN_FREQUENCY, + &do_broadcast, + NULL); +} + + /** * Setup communicator and launch network interactions. * @@ -2290,6 +2814,8 @@ run (void *cls, GNUNET_free (bindto); return; } + if (AF_INET6 == in->sa_family) + have_v6_socket = GNUNET_YES; if (GNUNET_OK != GNUNET_NETWORK_socket_bind (udp_sock, in, @@ -2324,6 +2850,18 @@ run (void *cls, "Bound to `%s'\n", GNUNET_a2s ((const struct sockaddr *) &in_sto, sto_len)); + switch (in->sa_family) + { + case AF_INET: + my_port = ntohs (((struct sockaddr_in *) in)->sin_port); + break; + case AF_INET6: + my_port = ntohs (((struct sockaddr_in6 *) in)->sin6_port); + break; + default: + GNUNET_break (0); + my_port = 0; + } stats = GNUNET_STATISTICS_create ("C-UDP", cfg); senders = GNUNET_CONTAINER_multipeermap_create (32, @@ -2366,6 +2904,15 @@ run (void *cls, GNUNET_SCHEDULER_shutdown (); return; } + /* start broadcasting */ + if (GNUNET_YES != + GNUNET_CONFIGURATION_get_value_yesno (cfg, + COMMUNICATOR_CONFIG_SECTION, + "DISABLE_BROADCAST")) + { + broadcast_task = GNUNET_SCHEDULER_add_now (&do_broadcast, + NULL); + } nat = GNUNET_NAT_register (cfg, COMMUNICATOR_CONFIG_SECTION, IPPROTO_UDP,