* @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)
*/
#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.
*/
*/
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.
*/
* 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?
};
+/**
+ * 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.
*/
*/
static struct GNUNET_SCHEDULER_Task *timeout_task;
+/**
+ * ID of master broadcast task
+ */
+static struct GNUNET_SCHEDULER_Task *broadcast_task;
+
/**
* For logging statistics.
*/
*/
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.
*/
*/
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
*/
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,
GNUNET_CONTAINER_multipeermap_size (receivers),
GNUNET_NO);
GNUNET_free (receiver->address);
+ GNUNET_free (receiver->foreign_addr);
GNUNET_free (receiver);
}
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);
}
+/**
+ * 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
&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;
}
}
"# broadcasts received",
1,
GNUNET_NO);
- // FIXME: we effectively just got a HELLO!
+ // FIXME #5551: we effectively just got a HELLO!
// trigger verification NOW!
return;
}
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;
}
+/**
+ * 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.
}
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;
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 ==
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);
}
}
+/**
+ * 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.
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;
}
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);
}
+/**
+ * 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.
*
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,
"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,
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,