+ s->addrlen = len;
+ s->target = *target;
+ s->sock_addr = (const struct sockaddr *) &s[1];
+ s->last_expected_delay = GNUNET_TIME_UNIT_SECONDS;
+ start_session_timeout(s);
+ return s;
+}
+
+
+static int
+session_cmp_it (void *cls,
+ const struct GNUNET_HashCode * key,
+ void *value)
+{
+ struct SessionCompareContext * cctx = cls;
+ const struct GNUNET_HELLO_Address *address = cctx->addr;
+ struct Session *s = value;
+
+ socklen_t s_addrlen = s->addrlen;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Comparing address %s <-> %s\n",
+ udp_address_to_string (NULL, (void *) address->address, address->address_length),
+ GNUNET_a2s (s->sock_addr, s->addrlen));
+ if ((address->address_length == sizeof (struct IPv4UdpAddress)) &&
+ (s_addrlen == sizeof (struct sockaddr_in)))
+ {
+ struct IPv4UdpAddress * u4 = NULL;
+ u4 = (struct IPv4UdpAddress *) address->address;
+ const struct sockaddr_in *s4 = (const struct sockaddr_in *) s->sock_addr;
+ if ((0 == memcmp ((const void *) &u4->ipv4_addr,(const void *) &s4->sin_addr, sizeof (struct in_addr))) &&
+ (u4->u4_port == s4->sin_port))
+ {
+ cctx->res = s;
+ return GNUNET_NO;
+ }
+
+ }
+ if ((address->address_length == sizeof (struct IPv6UdpAddress)) &&
+ (s_addrlen == sizeof (struct sockaddr_in6)))
+ {
+ struct IPv6UdpAddress * u6 = NULL;
+ u6 = (struct IPv6UdpAddress *) address->address;
+ const struct sockaddr_in6 *s6 = (const struct sockaddr_in6 *) s->sock_addr;
+ if ((0 == memcmp (&u6->ipv6_addr, &s6->sin6_addr, sizeof (struct in6_addr))) &&
+ (u6->u6_port == s6->sin6_port))
+ {
+ cctx->res = s;
+ return GNUNET_NO;
+ }
+ }
+ return GNUNET_YES;
+}
+
+
+/**
+ * Creates a new outbound session the transport service will use to send data to the
+ * peer
+ *
+ * @param cls the plugin
+ * @param address the address
+ * @return the session or NULL of max connections exceeded
+ */
+static struct Session *
+udp_plugin_get_session (void *cls,
+ const struct GNUNET_HELLO_Address *address)
+{
+ struct Session * s = NULL;
+ struct Plugin * plugin = cls;
+ struct IPv6UdpAddress * udp_a6;
+ struct IPv4UdpAddress * udp_a4;
+
+ GNUNET_assert (plugin != NULL);
+ GNUNET_assert (address != NULL);
+
+
+ if ((address->address == NULL) ||
+ ((address->address_length != sizeof (struct IPv4UdpAddress)) &&
+ (address->address_length != sizeof (struct IPv6UdpAddress))))
+ {
+ GNUNET_break (0);
+ return NULL;
+ }
+
+ if (address->address_length == sizeof (struct IPv4UdpAddress))
+ {
+ if (plugin->sockv4 == NULL)
+ return NULL;
+ udp_a4 = (struct IPv4UdpAddress *) address->address;
+ if (udp_a4->u4_port == 0)
+ return NULL;
+ }
+
+ if (address->address_length == sizeof (struct IPv6UdpAddress))
+ {
+ if (plugin->sockv6 == NULL)
+ return NULL;
+ udp_a6 = (struct IPv6UdpAddress *) address->address;
+ if (udp_a6->u6_port == 0)
+ return NULL;
+ }
+
+ /* check if session already exists */
+ struct SessionCompareContext cctx;
+ cctx.addr = address;
+ cctx.res = NULL;
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Looking for existing session for peer `%s' `%s' \n",
+ GNUNET_i2s (&address->peer),
+ udp_address_to_string(NULL, address->address, address->address_length));
+ GNUNET_CONTAINER_multihashmap_get_multiple(plugin->sessions, &address->peer.hashPubKey, session_cmp_it, &cctx);
+ if (cctx.res != NULL)
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Found existing session %p\n", cctx.res);
+ return cctx.res;
+ }
+
+ /* otherwise create new */
+ s = create_session (plugin,
+ &address->peer,
+ address->address,
+ address->address_length,
+ NULL, NULL);
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Creating new session %p for peer `%s' address `%s'\n",
+ s,
+ GNUNET_i2s(&address->peer),
+ udp_address_to_string(NULL,address->address,address->address_length));
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CONTAINER_multihashmap_put (plugin->sessions,
+ &s->target.hashPubKey,
+ s,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
+
+ GNUNET_STATISTICS_set(plugin->env->stats,
+ "# UDP sessions active",
+ GNUNET_CONTAINER_multihashmap_size(plugin->sessions),
+ GNUNET_NO);
+
+ return s;
+}
+
+
+static void
+enqueue (struct Plugin *plugin, struct UDPMessageWrapper * udpw)
+{
+
+ if (udpw->session->addrlen == sizeof (struct sockaddr_in))
+ GNUNET_CONTAINER_DLL_insert(plugin->ipv4_queue_head, plugin->ipv4_queue_tail, udpw);
+ if (udpw->session->addrlen == sizeof (struct sockaddr_in6))
+ GNUNET_CONTAINER_DLL_insert(plugin->ipv6_queue_head, plugin->ipv6_queue_tail, udpw);
+}
+
+
+/**
+ * Fragment message was transmitted via UDP, let fragmentation know
+ * to send the next fragment now.
+ *
+ * @param cls the 'struct UDPMessageWrapper' of the fragment
+ * @param target destination peer (ignored)
+ * @param result GNUNET_OK on success (ignored)
+ */
+static void
+send_next_fragment (void *cls,
+ const struct GNUNET_PeerIdentity *target,
+ int result)
+{
+ struct UDPMessageWrapper *udpw = cls;
+
+ GNUNET_FRAGMENT_context_transmission_done (udpw->frag_ctx->frag);
+}