gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] r35053 - gnunet/src/transport


From: gnunet
Subject: [GNUnet-SVN] r35053 - gnunet/src/transport
Date: Sun, 1 Feb 2015 19:00:31 +0100

Author: grothoff
Date: 2015-02-01 19:00:31 +0100 (Sun, 01 Feb 2015)
New Revision: 35053

Modified:
   gnunet/src/transport/gnunet-service-transport.c
   gnunet/src/transport/gnunet-service-transport_neighbours.c
   gnunet/src/transport/gnunet-service-transport_plugins.c
   gnunet/src/transport/gnunet-service-transport_validation.c
   gnunet/src/transport/plugin_transport_tcp.c
   gnunet/src/transport/plugin_transport_udp.c
   gnunet/src/transport/plugin_transport_udp.h
   gnunet/src/transport/plugin_transport_udp_broadcasting.c
Log:
cleaning up UDP code to use only on address format throughout the code as much 
as possible

Modified: gnunet/src/transport/gnunet-service-transport.c
===================================================================
--- gnunet/src/transport/gnunet-service-transport.c     2015-01-30 12:18:47 UTC 
(rev 35052)
+++ gnunet/src/transport/gnunet-service-transport.c     2015-02-01 18:00:31 UTC 
(rev 35053)
@@ -359,7 +359,9 @@
     /* Blacklist allows to speak to this peer, forward SYN to neighbours  */
     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
                 "Received SYN message from peer `%s' with `%s' %p\n",
-                GNUNET_i2s (peer), GST_plugins_a2s (blctx->address), 
blctx->session);
+                GNUNET_i2s (peer),
+                GST_plugins_a2s (blctx->address),
+                blctx->session);
 
     if (GNUNET_OK !=
         GST_neighbours_handle_session_syn (blctx->msg,
@@ -416,16 +418,19 @@
   if (NULL == message)
     goto end;
   type = ntohs (message->type);
-  GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
-      "Received Message with type %u from peer `%s'\n", type,
-      GNUNET_i2s (&address->peer));
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Received Message with type %u from peer `%s'\n",
+              type,
+              GNUNET_i2s (&address->peer));
 
-  GNUNET_STATISTICS_update (GST_stats, gettext_noop
-                            ("# bytes total received"),
+  GNUNET_STATISTICS_update (GST_stats,
+                            gettext_noop ("# bytes total received"),
                             ntohs (message->size),
                             GNUNET_NO);
-  GST_neighbours_notify_data_recv (&address->peer, address, session, message);
-
+  GST_neighbours_notify_data_recv (&address->peer,
+                                   address,
+                                   session,
+                                   message);
   switch (type)
   {
   case GNUNET_MESSAGE_TYPE_HELLO_LEGACY:
@@ -434,8 +439,9 @@
   case GNUNET_MESSAGE_TYPE_HELLO:
     if (GNUNET_OK != GST_validation_handle_hello (message))
     {
-      GNUNET_break_op(0);
-      cancel_pending_blacklist_checks (address, session);
+      GNUNET_break_op (0);
+      cancel_pending_blacklist_checks (address,
+                                       session);
     }
     return ret;
   case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
@@ -448,8 +454,10 @@
                                     address,
                                     session))
     {
-      cancel_pending_blacklist_checks (address, session);
-      kill_session (plugin_name, session);
+      cancel_pending_blacklist_checks (address,
+                                       session);
+      kill_session (plugin_name,
+                    session);
     }
     break;
   case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
@@ -472,22 +480,29 @@
     memcpy (blctx->msg, message, ntohs(message->size));
     GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, blctx);
     if (NULL != (blc = GST_blacklist_test_allowed (&address->peer, NULL,
-          &connect_bl_check_cont, blctx)))
+                                                   &connect_bl_check_cont,
+                                                   blctx)))
     {
       blctx->blc = blc;
     }
     break;
   case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_SYN_ACK:
-    if (GNUNET_OK != GST_neighbours_handle_session_syn_ack (message,
-        &address->peer, address, session))
+    if (GNUNET_OK !=
+        GST_neighbours_handle_session_syn_ack (message,
+                                               &address->peer,
+                                               address,
+                                               session))
     {
       cancel_pending_blacklist_checks (address, session);
       kill_session (plugin_name, session);
     }
     break;
   case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_ACK:
-    if (GNUNET_OK
-        != GST_neighbours_handle_session_ack (message, &address->peer, 
address, session))
+    if (GNUNET_OK !=
+        GST_neighbours_handle_session_ack (message,
+                                           &address->peer,
+                                           address,
+                                           session))
     {
       GNUNET_break_op(0);
       cancel_pending_blacklist_checks (address, session);
@@ -505,16 +520,26 @@
     break;
   default:
     /* should be payload */
-    GNUNET_STATISTICS_update (GST_stats, gettext_noop
-    ("# bytes payload received"), ntohs (message->size), GNUNET_NO);
-    GST_neighbours_notify_payload_recv (&address->peer, address, session, 
message);
-    ret = process_payload (&address->peer, address, session, message);
+    GNUNET_STATISTICS_update (GST_stats,
+                              gettext_noop ("# bytes payload received"),
+                              ntohs (message->size),
+                              GNUNET_NO);
+    GST_neighbours_notify_payload_recv (&address->peer,
+                                        address,
+                                        session,
+                                        message);
+    ret = process_payload (&address->peer,
+                           address,
+                           session,
+                           message);
     break;
   }
   end:
-  GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
-      "Allowing receive from peer %s to continue in %s\n", GNUNET_i2s 
(&address->peer),
-      GNUNET_STRINGS_relative_time_to_string (ret, GNUNET_YES));
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Allowing receive from peer %s to continue in %s\n",
+              GNUNET_i2s (&address->peer),
+              GNUNET_STRINGS_relative_time_to_string (ret,
+                                                      GNUNET_YES));
   return ret;
 }
 
@@ -552,9 +577,9 @@
     }
   }
 
-  GNUNET_log(GNUNET_ERROR_TYPE_INFO,
-             "Transport now has %u addresses to communicate\n",
-             addresses);
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "Transport now has %u addresses to communicate\n",
+              addresses);
   GST_hello_modify_addresses (add_remove, address);
 }
 
@@ -595,7 +620,8 @@
               "Notification from plugin `%s' about terminated %s session %p 
from peer `%s' address `%s'\n",
               address->transport_name,
               GNUNET_HELLO_address_check_option (address,
-                                                 
GNUNET_HELLO_ADDRESS_INFO_INBOUND) ? "inbound" : "outbound", session,
+                                                 
GNUNET_HELLO_ADDRESS_INFO_INBOUND) ? "inbound" : "outbound",
+              session,
               GNUNET_i2s (&address->peer),
               GST_plugins_a2s (address));
 
@@ -839,10 +865,10 @@
   struct ConnectInfoMessage *connect_msg = (struct ConnectInfoMessage *) buf;
 
   connections++;
-  GNUNET_log(GNUNET_ERROR_TYPE_INFO,
-             "We are now connected to peer `%s' and %u peers in total\n",
-             GNUNET_i2s (peer),
-             connections);
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "We are now connected to peer `%s' and %u peers in total\n",
+              GNUNET_i2s (peer),
+              connections);
   connect_msg->header.size = htons (sizeof(buf));
   connect_msg->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
   connect_msg->id = *peer;
@@ -866,9 +892,10 @@
   struct DisconnectInfoMessage disconnect_msg;
 
   connections--;
-  GNUNET_log(GNUNET_ERROR_TYPE_INFO,
-             "Peer `%s' disconnected and we are connected to %u peers\n",
-             GNUNET_i2s (peer), connections);
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+              "Peer `%s' disconnected and we are connected to %u peers\n",
+              GNUNET_i2s (peer),
+              connections);
 
   GST_manipulation_peer_disconnect (peer);
   disconnect_msg.header.size = htons (sizeof(struct DisconnectInfoMessage));

Modified: gnunet/src/transport/gnunet-service-transport_neighbours.c
===================================================================
--- gnunet/src/transport/gnunet-service-transport_neighbours.c  2015-01-30 
12:18:47 UTC (rev 35052)
+++ gnunet/src/transport/gnunet-service-transport_neighbours.c  2015-02-01 
18:00:31 UTC (rev 35053)
@@ -738,10 +738,10 @@
  */
 static void
 set_alternative_address (struct NeighbourMapEntry *n,
-             const struct GNUNET_HELLO_Address *address,
-             struct Session *session,
-             struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
-             struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out)
+                         const struct GNUNET_HELLO_Address *address,
+                         struct Session *session,
+                         struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
+                         struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out)
 {
   struct GNUNET_TRANSPORT_PluginFunctions *papi;
 

Modified: gnunet/src/transport/gnunet-service-transport_plugins.c
===================================================================
--- gnunet/src/transport/gnunet-service-transport_plugins.c     2015-01-30 
12:18:47 UTC (rev 35052)
+++ gnunet/src/transport/gnunet-service-transport_plugins.c     2015-02-01 
18:00:31 UTC (rev 35053)
@@ -196,7 +196,7 @@
     }
     if (NULL == plug->api->check_address)
     {
-       fail = GNUNET_YES;
+      fail = GNUNET_YES;
       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                   _("Missing function `%s' in transport plugin for `%s'\n"),
                   "check_address",
@@ -204,7 +204,7 @@
     }
     if (NULL == plug->api->get_session)
     {
-       fail = GNUNET_YES;
+      fail = GNUNET_YES;
       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                   _("Missing function `%s' in transport plugin for `%s'\n"),
                   "get_session",
@@ -212,7 +212,7 @@
     }
     if (NULL == plug->api->get_network)
     {
-       fail = GNUNET_YES;
+      fail = GNUNET_YES;
       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                   _("Missing function `%s' in transport plugin for `%s'\n"),
                   "get_network",
@@ -220,7 +220,7 @@
     }
     if (NULL == plug->api->send)
     {
-       fail = GNUNET_YES;
+      fail = GNUNET_YES;
       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                   _("Missing function `%s' in transport plugin for `%s'\n"),
                   "send",

Modified: gnunet/src/transport/gnunet-service-transport_validation.c
===================================================================
--- gnunet/src/transport/gnunet-service-transport_validation.c  2015-01-30 
12:18:47 UTC (rev 35052)
+++ gnunet/src/transport/gnunet-service-transport_validation.c  2015-02-01 
18:00:31 UTC (rev 35053)
@@ -604,7 +604,6 @@
     else
     {
       GNUNET_assert (NULL != papi->send);
-      GNUNET_assert (NULL != papi->get_session);
       struct Session *session = papi->get_session (papi->cls,
                                                    ve->address);
 
@@ -612,7 +611,8 @@
       {
         ret = papi->send (papi->cls, session,
                           message_buf, tsize,
-                          PING_PRIORITY, ACCEPTABLE_PING_DELAY,
+                          PING_PRIORITY,
+                          ACCEPTABLE_PING_DELAY,
                           NULL, NULL);
         network = papi->get_network (papi->cls, session);
         if (GNUNET_ATS_NET_UNSPECIFIED == network)

Modified: gnunet/src/transport/plugin_transport_tcp.c
===================================================================
--- gnunet/src/transport/plugin_transport_tcp.c 2015-01-30 12:18:47 UTC (rev 
35052)
+++ gnunet/src/transport/plugin_transport_tcp.c 2015-02-01 18:00:31 UTC (rev 
35053)
@@ -1743,7 +1743,8 @@
 
   LOG (GNUNET_ERROR_TYPE_DEBUG,
        "Asked to transmit to `%4s', creating fresh session using address 
`%s'.\n",
-       GNUNET_i2s (&address->peer), GNUNET_a2s (sb, sbs));
+       GNUNET_i2s (&address->peer),
+       GNUNET_a2s (sb, sbs));
 
   session = create_session (plugin,
                             address,

Modified: gnunet/src/transport/plugin_transport_udp.c
===================================================================
--- gnunet/src/transport/plugin_transport_udp.c 2015-01-30 12:18:47 UTC (rev 
35052)
+++ gnunet/src/transport/plugin_transport_udp.c 2015-02-01 18:00:31 UTC (rev 
35053)
@@ -1,6 +1,6 @@
 /*
  This file is part of GNUnet
- (C) 2010-2014 Christian Grothoff (and other contributing authors)
+ (C) 2010-2015 Christian Grothoff (and other contributing authors)
 
  GNUnet is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published
@@ -102,10 +102,10 @@
   /**
    * Timeout task
    */
-  struct GNUNET_SCHEDULER_Task * timeout_task;
+  struct GNUNET_SCHEDULER_Task *timeout_task;
 
   /**
-   * IPv6 address
+   * Is this an IPv6 address?
    */
   int ipv6;
 
@@ -155,7 +155,7 @@
   /**
    * Session timeout task
    */
-  struct GNUNET_SCHEDULER_Task * timeout_task;
+  struct GNUNET_SCHEDULER_Task *timeout_task;
 
   /**
    * When does this session time out?
@@ -222,20 +222,10 @@
   struct GNUNET_PeerIdentity sender;
 
   /**
-   * Source address.
-   */
-  const void *arg;
-
-  /**
    * Associated session.
    */
   struct Session *session;
 
-  /**
-   * Number of bytes in source address.
-   */
-  size_t args;
-
 };
 
 /**
@@ -249,19 +239,19 @@
   struct DefragContext *rc;
 
   /**
-   * Address to find.
+   * Session associated with this context.
    */
-  const struct sockaddr *addr;
+  struct Session *session;
 
   /**
-   *
+   * Address to find.
    */
-  struct Session *session;
+  const union UdpAddress *udp_addr;
 
   /**
-   * Number of bytes in @e addr.
+   * Number of bytes in @e udp_addr.
    */
-  socklen_t addr_len;
+  size_t udp_addr_len;
 
 };
 
@@ -278,25 +268,42 @@
   struct GNUNET_DEFRAGMENT_Context *defrag;
 
   /**
+   * Reference to master plugin struct.
+   */
+  struct Plugin *plugin;
+
+  /**
+   * Node in the defrag heap.
+   */
+  struct GNUNET_CONTAINER_HeapNode *hnode;
+
+  /**
+   * Who's message(s) are we defragmenting here?
+   * Only initialized once we succeeded and
+   * @e have_sender is set.
+   */
+  struct GNUNET_PeerIdentity sender;
+
+  /**
    * Source address this receive context is for (allocated at the
    * end of the struct).
    */
-  const struct sockaddr *src_addr;
+  const union UdpAddress *udp_addr;
 
   /**
-   * Reference to master plugin struct.
+   * Length of @e udp_addr.
    */
-  struct Plugin *plugin;
+  size_t udp_addr_len;
 
   /**
-   * Node in the defrag heap.
+   * Network type the address belongs to.
    */
-  struct GNUNET_CONTAINER_HeapNode *hnode;
+  enum GNUNET_ATS_Network_Type network_type;
 
   /**
-   * Length of @e src_addr.
+   * Has the @e sender field been initialized yet?
    */
-  size_t addr_len;
+  int have_sender;
 };
 
 
@@ -464,7 +471,7 @@
 
 
 /**
- * UDP ACK Message-Packet header (after defragmentation).
+ * UDP ACK Message-Packet header.
  */
 struct UDP_ACK_Message
 {
@@ -606,8 +613,8 @@
  * to override the address again.
  *
  * @param cls closure
- * @param addr binary address
- * @param addrlen length of the address
+ * @param addr binary address (a `union UdpAddress`)
+ * @param addrlen length of the @a addr
  * @return string representing the same address
  */
 const char *
@@ -651,8 +658,13 @@
   inet_ntop (af, sb, buf, INET6_ADDRSTRLEN);
 
   GNUNET_snprintf (rbuf, sizeof(rbuf),
-      (af == AF_INET6) ? "%s.%u.[%s]:%u" : "%s.%u.%s:%u", PLUGIN_NAME, options,
-      buf, port);
+                   (af == AF_INET6)
+                   ? "%s.%u.[%s]:%u"
+                   : "%s.%u.%s:%u",
+                   PLUGIN_NAME,
+                   options,
+                   buf,
+                   port);
   return rbuf;
 }
 
@@ -661,7 +673,7 @@
  * Function called to convert a string address to
  * a binary address.
  *
- * @param cls closure ('struct Plugin*')
+ * @param cls closure (`struct Plugin *`)
  * @param addr string address
  * @param addrlen length of the address
  * @param buf location to store the buffer
@@ -822,7 +834,8 @@
  * @param cls closure with the `struct Plugin *`
  * @param type name of the transport that generated the address
  * @param addr one of the addresses of the host, NULL for the last address
- *        the specific address format depends on the transport
+ *        the specific address format depends on the transport;
+ *        a `union UdpAddress`
  * @param addrlen length of the address
  * @param numeric should (IP) addresses be displayed in numeric form?
  * @param timeout after how long should we give up?
@@ -1095,7 +1108,7 @@
  * traffic.
  *
  * @param cls closure, should be our handle to the Plugin
- * @param addr pointer to the address
+ * @param addr pointer to a `union UdpAddress`
  * @param addrlen length of @a addr
  * @return #GNUNET_OK if this is a plausible address for this peer
  *         and transport, #GNUNET_SYSERR if not
@@ -1285,7 +1298,7 @@
  *
  * @param cls the `struct FindReceiveContext`
  * @param node internal node of the heap
- * @param element value stored at the node (a 'struct ReceiveContext')
+ * @param element value stored at the node (a `struct ReceiveContext`)
  * @param cost cost associated with the node
  * @return #GNUNET_YES if we should continue to iterate,
  *         #GNUNET_NO if not.
@@ -1299,8 +1312,10 @@
   struct FindReceiveContext *frc = cls;
   struct DefragContext *e = element;
 
-  if ((frc->addr_len == e->addr_len)
-      && (0 == memcmp (frc->addr, e->src_addr, frc->addr_len)))
+  if ( (frc->udp_addr_len == e->udp_addr_len) &&
+       (0 == memcmp (frc->udp_addr,
+                     e->udp_addr,
+                     frc->udp_addr_len)) )
   {
     frc->rc = e;
     return GNUNET_NO;
@@ -1328,12 +1343,12 @@
   struct FindReceiveContext frc;
 
   GNUNET_assert (GNUNET_YES != s->in_destroy);
-  LOG(GNUNET_ERROR_TYPE_DEBUG,
-      "Session %p to peer `%s' address ended\n", s,
-      GNUNET_i2s (&s->target),
-      udp_address_to_string (NULL,
-                             s->address->address,
-                             s->address->address_length));
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Session %p to peer `%s' address ended\n", s,
+       GNUNET_i2s (&s->target),
+       udp_address_to_string (NULL,
+                              s->address->address,
+                              s->address->address_length));
   /* stop timeout task */
   if (NULL != s->timeout_task)
   {
@@ -1343,12 +1358,13 @@
   if (NULL != s->frag_ctx)
   {
     /* Remove fragmented message due to disconnect */
-    fragmented_message_done (s->frag_ctx, GNUNET_SYSERR);
+    fragmented_message_done (s->frag_ctx,
+                             GNUNET_SYSERR);
   }
 
   frc.rc = NULL;
-  frc.addr = s->address->address;
-  frc.addr_len = s->address->address_length;
+  frc.udp_addr = s->address->address;
+  frc.udp_addr_len = s->address->address_length;
   /* Lookup existing receive context for this address */
   if (NULL != plugin->defrag_ctxs)
   {
@@ -1555,8 +1571,8 @@
   s->plugin = plugin;
   s->address = GNUNET_HELLO_address_copy (address);
   s->target = address->peer;
-  s->last_expected_ack_delay = GNUNET_TIME_relative_multiply (
-      GNUNET_TIME_UNIT_MILLISECONDS, 250);
+  s->last_expected_ack_delay = GNUNET_TIME_relative_multiply 
(GNUNET_TIME_UNIT_MILLISECONDS,
+                                                              250);
   s->last_expected_msg_delay = GNUNET_TIME_UNIT_MILLISECONDS;
   s->flow_delay_from_other_peer = GNUNET_TIME_UNIT_ZERO_ABS;
   s->flow_delay_for_other_peer = GNUNET_TIME_UNIT_ZERO;
@@ -1634,20 +1650,21 @@
 
 
 /**
- * Creates a new outbound session the transport service will use to
- * send data to the peer
+ * Locate an existing session the transport service is using to
+ * send data to another peer.  Performs some basic sanity checks
+ * on the address and then tries to locate a matching session.
  *
  * @param cls the plugin
- * @param address the address
- * @return the session or NULL of max connections exceeded
+ * @param address the address we should locate the session by
+ * @return the session if it exists, or NULL if it is not found
  */
 static struct Session *
 udp_plugin_lookup_session (void *cls,
                            const struct GNUNET_HELLO_Address *address)
 {
-  struct Plugin * plugin = cls;
-  struct IPv6UdpAddress *udp_a6;
-  struct IPv4UdpAddress *udp_a4;
+  struct Plugin *plugin = cls;
+  const struct IPv6UdpAddress *udp_a6;
+  const struct IPv4UdpAddress *udp_a4;
   struct SessionCompareContext cctx;
 
   if ( (NULL == address->address) ||
@@ -1655,7 +1672,7 @@
         (address->address_length != sizeof (struct IPv6UdpAddress))))
   {
     LOG (GNUNET_ERROR_TYPE_WARNING,
-         _("Trying to create session for address of unexpected length %u 
(should be %u or %u)\n"),
+         _("Trying to locate session for address of unexpected length %u 
(should be %u or %u)\n"),
          address->address_length,
          sizeof (struct IPv4UdpAddress),
          sizeof (struct IPv6UdpAddress));
@@ -1664,19 +1681,19 @@
 
   if (address->address_length == sizeof(struct IPv4UdpAddress))
   {
-    if (plugin->sockv4 == NULL)
+    if (NULL == plugin->sockv4)
       return NULL;
-    udp_a4 = (struct IPv4UdpAddress *) address->address;
-    if (udp_a4->u4_port == 0)
+    udp_a4 = (const struct IPv4UdpAddress *) address->address;
+    if (0 == udp_a4->u4_port)
       return NULL;
   }
 
   if (address->address_length == sizeof(struct IPv6UdpAddress))
   {
-    if (plugin->sockv6 == NULL)
+    if (NULL == plugin->sockv6)
       return NULL;
-    udp_a6 = (struct IPv6UdpAddress *) address->address;
-    if (udp_a6->u6_port == 0)
+    udp_a6 = (const struct IPv6UdpAddress *) address->address;
+    if (0 == udp_a6->u6_port)
       return NULL;
   }
 
@@ -1689,7 +1706,7 @@
        udp_address_to_string(NULL, address->address, address->address_length));
   GNUNET_CONTAINER_multipeermap_get_multiple (plugin->sessions,
                                               &address->peer,
-                                              session_cmp_it,
+                                              &session_cmp_it,
                                               &cctx);
   if (NULL != cctx.res)
   {
@@ -1703,144 +1720,37 @@
 
 
 /**
- * Context to lookup a session based on a IP address
- */
-struct LookupContext
-{
-  /**
-   * The result
-   */
-  struct Session *res;
-
-  /**
-   * The socket address
-   */
-  const struct sockaddr *address;
-
-  /**
-   * The socket address length
-   */
-  size_t addr_len;
-
-  /**
-   * Is a fragmentation context required for the session
-   */
-  int must_have_frag_ctx;
-};
-
-
-/**
- * Find a session with a matching address.
- * FIXME: very similar code to #udp_plugin_lookup_session() above.
- * Unify?
+ * Allocate a new session for the given endpoint address.
+ * Note that this function does not inform the service
+ * of the new session, this is the responsibility of the
+ * caller (if needed).
  *
- * @param cls the `struct LookupContext *`
- * @param key peer identity (unused)
- * @param value the `struct Session *`
- * @return #GNUNET_NO if we found the session, #GNUNET_OK if not
+ * @param cls the `struct Plugin`
+ * @param address address of the other peer to use
+ * @param network_type network type the address belongs to
+ * @return NULL on error, otherwise session handle
  */
-static int
-lookup_session_by_sockaddr_it (void *cls,
-                               const struct GNUNET_PeerIdentity *key,
-                               void *value)
-{
-  struct LookupContext *l_ctx = cls;
-  struct Session *s = value;
-  struct IPv4UdpAddress u4;
-  struct IPv6UdpAddress u6;
-  void *arg;
-  size_t args;
-
-  /* convert address */
-  switch (l_ctx->address->sa_family)
-  {
-  case AF_INET:
-    GNUNET_assert(l_ctx->addr_len == sizeof(struct sockaddr_in));
-    memset (&u4, 0, sizeof(u4));
-    u6.options = htonl (0);
-    u4.ipv4_addr = ((struct sockaddr_in *) l_ctx->address)->sin_addr.s_addr;
-    u4.u4_port = ((struct sockaddr_in *) l_ctx->address)->sin_port;
-    arg = &u4;
-    args = sizeof(u4);
-    break;
-  case AF_INET6:
-    GNUNET_assert(l_ctx->addr_len == sizeof(struct sockaddr_in6));
-    memset (&u6, 0, sizeof(u6));
-    u6.options = htonl (0);
-    u6.ipv6_addr = ((struct sockaddr_in6 *) l_ctx->address)->sin6_addr;
-    u6.u6_port = ((struct sockaddr_in6 *) l_ctx->address)->sin6_port;
-    arg = &u6;
-    args = sizeof(u6);
-    break;
-  default:
-    GNUNET_break(0);
-    return GNUNET_YES;
-  }
-  if ( (GNUNET_YES == l_ctx->must_have_frag_ctx) &&
-       (NULL == s->frag_ctx))
-    return GNUNET_YES;
-
-  /* Does not compare peer identities but addresses */
-  if ((args == s->address->address_length) &&
-      (0 == memcmp (arg, s->address->address, args)))
-  {
-    l_ctx->res = s;
-    return GNUNET_NO;
-  }
-  return GNUNET_YES;
-}
-
-
 static struct Session *
 udp_plugin_create_session (void *cls,
-                           const struct GNUNET_HELLO_Address *address)
+                           const struct GNUNET_HELLO_Address *address,
+                           enum GNUNET_ATS_Network_Type network_type)
 {
   struct Plugin *plugin = cls;
   struct Session *s;
-  struct IPv4UdpAddress *udp_v4;
-  struct IPv6UdpAddress *udp_v6;
 
   s = create_session (plugin, address);
-  if (sizeof (struct IPv4UdpAddress) == address->address_length)
-  {
-    struct sockaddr_in v4;
+  s->ats.type = htonl (GNUNET_ATS_NETWORK_TYPE);
+  s->ats.value = htonl (network_type);
 
-    udp_v4 = (struct IPv4UdpAddress *) address->address;
-    memset (&v4, '\0', sizeof (v4));
-    v4.sin_family = AF_INET;
-#if HAVE_SOCKADDR_IN_SIN_LEN
-    v4.sin_len = sizeof (struct sockaddr_in);
-#endif
-    v4.sin_port = udp_v4->u4_port;
-    v4.sin_addr.s_addr = udp_v4->ipv4_addr;
-    s->ats.type = htonl (GNUNET_ATS_NETWORK_TYPE);
-    s->ats.value = htonl (plugin->env->get_address_type (plugin->env->cls,
-                                                         (const struct 
sockaddr *) &v4,
-                                                         sizeof (v4)));
-  }
-  else if (sizeof (struct IPv6UdpAddress) == address->address_length)
-  {
-    struct sockaddr_in6 v6;
-    udp_v6 = (struct IPv6UdpAddress *) address->address;
-    memset (&v6, '\0', sizeof (v6));
-    v6.sin6_family = AF_INET6;
-#if HAVE_SOCKADDR_IN_SIN_LEN
-    v6.sin6_len = sizeof (struct sockaddr_in6);
-#endif
-    v6.sin6_port = udp_v6->u6_port;
-    v6.sin6_addr = udp_v6->ipv6_addr;
-    s->ats.type = htonl (GNUNET_ATS_NETWORK_TYPE);
-    s->ats.value = htonl (plugin->env->get_address_type (plugin->env->cls,
-                                                         (const struct 
sockaddr *) &v6,
-                                                         sizeof (v6)));
-  }
-
   if (NULL == s)
     return NULL; /* protocol not supported or address invalid */
-  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));
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Creating new session %p for peer `%s' address `%s'\n",
+       s,
+       GNUNET_i2s (&address->peer),
+       udp_address_to_string (plugin,
+                              address->address,
+                              address->address_length));
   GNUNET_assert(GNUNET_OK ==
                 GNUNET_CONTAINER_multipeermap_put (plugin->sessions,
                                                    &s->target,
@@ -1884,8 +1794,8 @@
 
 
 /**
- * Creates a new outbound session the transport service will use to send data 
to the
- * peer
+ * Creates a new outbound session the transport service will use to
+ * send data to the peer.
  *
  * @param cls the plugin
  * @param address the address
@@ -1895,7 +1805,11 @@
 udp_plugin_get_session (void *cls,
                         const struct GNUNET_HELLO_Address *address)
 {
+  struct Plugin *plugin = cls;
   struct Session *s;
+  enum GNUNET_ATS_Network_Type network_type;
+  struct IPv4UdpAddress *udp_v4;
+  struct IPv6UdpAddress *udp_v6;
 
   if (NULL == address)
   {
@@ -1905,11 +1819,45 @@
   if ( (address->address_length != sizeof(struct IPv4UdpAddress)) &&
        (address->address_length != sizeof(struct IPv6UdpAddress)) )
     return NULL;
+  if (NULL != (s = udp_plugin_lookup_session (cls,
+                                              address)))
+    return s;
 
+  if (sizeof (struct IPv4UdpAddress) == address->address_length)
+  {
+    struct sockaddr_in v4;
+
+    udp_v4 = (struct IPv4UdpAddress *) address->address;
+    memset (&v4, '\0', sizeof (v4));
+    v4.sin_family = AF_INET;
+#if HAVE_SOCKADDR_IN_SIN_LEN
+    v4.sin_len = sizeof (struct sockaddr_in);
+#endif
+    v4.sin_port = udp_v4->u4_port;
+    v4.sin_addr.s_addr = udp_v4->ipv4_addr;
+    network_type = plugin->env->get_address_type (plugin->env->cls,
+                                                  (const struct sockaddr *) 
&v4,
+                                                  sizeof (v4));
+  }
+  else if (sizeof (struct IPv6UdpAddress) == address->address_length)
+  {
+    struct sockaddr_in6 v6;
+
+    udp_v6 = (struct IPv6UdpAddress *) address->address;
+    memset (&v6, '\0', sizeof (v6));
+    v6.sin6_family = AF_INET6;
+#if HAVE_SOCKADDR_IN_SIN_LEN
+    v6.sin6_len = sizeof (struct sockaddr_in6);
+#endif
+    v6.sin6_port = udp_v6->u6_port;
+    v6.sin6_addr = udp_v6->ipv6_addr;
+    network_type = plugin->env->get_address_type (plugin->env->cls,
+                                                  (const struct sockaddr *) 
&v6,
+                                                  sizeof (v6));
+  }
+
   /* otherwise create new */
-  if (NULL != (s = udp_plugin_lookup_session (cls, address)))
-    return s;
-  return udp_plugin_create_session (cls, address);
+  return udp_plugin_create_session (cls, address, network_type);
 }
 
 
@@ -2258,7 +2206,7 @@
   struct SourceInformation *si = client;
   struct GNUNET_TIME_Relative delay;
 
-  GNUNET_assert(si->session != NULL);
+  GNUNET_assert (NULL != si->session);
   if (GNUNET_YES == si->session->in_destroy)
     return GNUNET_OK;
   /* setup ATS */
@@ -2282,22 +2230,20 @@
  *
  * @param plugin plugin context
  * @param msg the message
- * @param sender_addr sender address
- * @param sender_addr_len number of bytes in @a sender_addr
+ * @param udp_addr sender address
+ * @param udp_addr_len number of bytes in @a udp_addr
+ * @param network_type network type the address belongs to
  */
 static void
 process_udp_message (struct Plugin *plugin,
                      const struct UDPMessage *msg,
-                     const struct sockaddr *sender_addr,
-                     socklen_t sender_addr_len)
+                     const union UdpAddress *udp_addr,
+                     size_t udp_addr_len,
+                     enum GNUNET_ATS_Network_Type network_type)
 {
   struct SourceInformation si;
-  struct Session * s;
+  struct Session *s;
   struct GNUNET_HELLO_Address *address;
-  struct IPv4UdpAddress u4;
-  struct IPv6UdpAddress u6;
-  const void *arg;
-  size_t args;
 
   if (0 != ntohl (msg->reserved))
   {
@@ -2311,42 +2257,16 @@
     return;
   }
 
-  /* convert address */
-  switch (sender_addr->sa_family)
-  {
-  case AF_INET:
-    GNUNET_assert(sender_addr_len == sizeof(struct sockaddr_in));
-    memset (&u4, 0, sizeof(u4));
-    u6.options = htonl (0);
-    u4.ipv4_addr = ((struct sockaddr_in *) sender_addr)->sin_addr.s_addr;
-    u4.u4_port = ((struct sockaddr_in *) sender_addr)->sin_port;
-    arg = &u4;
-    args = sizeof(u4);
-    break;
-  case AF_INET6:
-    GNUNET_assert(sender_addr_len == sizeof(struct sockaddr_in6));
-    memset (&u6, 0, sizeof(u6));
-    u6.options = htonl (0);
-    u6.ipv6_addr = ((struct sockaddr_in6 *) sender_addr)->sin6_addr;
-    u6.u6_port = ((struct sockaddr_in6 *) sender_addr)->sin6_port;
-    arg = &u6;
-    args = sizeof(u6);
-    break;
-  default:
-    GNUNET_break(0);
-    return;
-  }
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Received message with %u bytes from peer `%s' at `%s'\n",
-       (unsigned int ) ntohs (msg->header.size), GNUNET_i2s (&msg->sender),
-       GNUNET_a2s (sender_addr, sender_addr_len));
-
-  address = GNUNET_HELLO_address_allocate (&msg->sender, PLUGIN_NAME,
-                                           arg, args,
+  address = GNUNET_HELLO_address_allocate (&msg->sender,
+                                           PLUGIN_NAME,
+                                           udp_addr,
+                                           udp_addr_len,
                                            GNUNET_HELLO_ADDRESS_INFO_NONE);
   if (NULL == (s = udp_plugin_lookup_session (plugin, address)))
   {
-    s = udp_plugin_create_session (plugin, address);
+    s = udp_plugin_create_session (plugin,
+                                   address,
+                                   network_type);
     plugin->env->session_start (plugin->env->cls,
                                 address, s, NULL, 0);
     notify_session_monitor (s->plugin,
@@ -2361,8 +2281,6 @@
   /* iterate over all embedded messages */
   si.session = s;
   si.sender = msg->sender;
-  si.arg = arg;
-  si.args = args;
   s->rc++;
   GNUNET_SERVER_mst_receive (plugin->mst,
                              &si,
@@ -2387,6 +2305,7 @@
                    const struct GNUNET_MessageHeader *msg)
 {
   struct DefragContext *rc = cls;
+  const struct UDPMessage *um;
 
   if (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_TRANSPORT_UDP_MESSAGE)
   {
@@ -2398,10 +2317,14 @@
     GNUNET_break(0);
     return;
   }
+  um = (const struct UDPMessage *) msg;
+  rc->sender = um->sender;
+  rc->have_sender = GNUNET_YES;
   process_udp_message (rc->plugin,
-                       (const struct UDPMessage *) msg,
-                       rc->src_addr,
-                       rc->addr_len);
+                       um,
+                       rc->udp_addr,
+                       rc->udp_addr_len,
+                       rc->network_type);
 }
 
 
@@ -2423,26 +2346,32 @@
   uint32_t delay = 0;
   struct UDP_MessageWrapper *udpw;
   struct Session *s;
-  struct LookupContext l_ctx;
+  struct GNUNET_HELLO_Address *address;
 
-  l_ctx.address = rc->src_addr;
-  l_ctx.addr_len = rc->addr_len;
-  l_ctx.must_have_frag_ctx = GNUNET_NO;
-  l_ctx.res = NULL;
-  GNUNET_CONTAINER_multipeermap_iterate (rc->plugin->sessions,
-                                         &lookup_session_by_sockaddr_it,
-                                         &l_ctx);
-  s = l_ctx.res;
+  if (GNUNET_NO == rc->have_sender)
+  {
+    /* tried to defragment but never succeeded, hence will not ACK */
+    GNUNET_break_op (0);
+    return;
+  }
+  address = GNUNET_HELLO_address_allocate (&rc->sender,
+                                           PLUGIN_NAME,
+                                           rc->udp_addr,
+                                           rc->udp_addr_len,
+                                           GNUNET_HELLO_ADDRESS_INFO_NONE);
+  s = udp_plugin_lookup_session (rc->plugin,
+                                 address);
+  GNUNET_HELLO_address_free (address);
   if (NULL == s)
   {
     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
-        "Trying to transmit ACK to peer `%s' but not session found!\n",
-        GNUNET_a2s(rc->src_addr, rc->addr_len));
-
+                "Trying to transmit ACK to peer `%s' but no session found!\n",
+                udp_address_to_string (rc->plugin,
+                                       rc->udp_addr,
+                                       rc->udp_addr_len));
     GNUNET_CONTAINER_heap_remove_node (rc->hnode);
     GNUNET_DEFRAGMENT_context_destroy (rc->defrag);
     GNUNET_free (rc);
-
     return;
   }
   if (s->flow_delay_for_other_peer.rel_value_us <= UINT32_MAX)
@@ -2450,7 +2379,9 @@
 
   LOG (GNUNET_ERROR_TYPE_DEBUG,
        "Sending ACK to `%s' including delay of %s\n",
-       GNUNET_a2s (rc->src_addr, (rc->src_addr->sa_family == AF_INET) ? sizeof 
(struct sockaddr_in) : sizeof (struct sockaddr_in6)),
+       udp_address_to_string (rc->plugin,
+                              rc->udp_addr,
+                              rc->udp_addr_len),
        GNUNET_STRINGS_relative_time_to_string (s->flow_delay_for_other_peer,
                                                GNUNET_YES));
   udpw = GNUNET_malloc (sizeof (struct UDP_MessageWrapper) + msize);
@@ -2475,38 +2406,22 @@
 
 
 /**
- * FIXME.
+ * Handle an ACK message.
+ *
+ * @param plugin the UDP plugin
+ * @param msg the (presumed) UDP ACK message
+ * @param udp_addr sender address
+ * @param udp_addr_len number of bytes in @a udp_addr
  */
 static void
-read_process_msg (struct Plugin *plugin,
-                  const struct GNUNET_MessageHeader *msg,
-                  const struct sockaddr *addr,
-                  socklen_t fromlen)
-{
-  if (ntohs (msg->size) < sizeof(struct UDPMessage))
-  {
-    GNUNET_break_op(0);
-    return;
-  }
-  process_udp_message (plugin,
-                       (const struct UDPMessage *) msg,
-                       addr,
-                       fromlen);
-}
-
-
-/**
- * FIXME.
- */
-static void
 read_process_ack (struct Plugin *plugin,
                   const struct GNUNET_MessageHeader *msg,
-                  const struct sockaddr *addr,
-                  socklen_t fromlen)
+                  const union UdpAddress *udp_addr,
+                  socklen_t udp_addr_len)
 {
   const struct GNUNET_MessageHeader *ack;
   const struct UDP_ACK_Message *udp_ack;
-  struct LookupContext l_ctx;
+  struct GNUNET_HELLO_Address *address;
   struct Session *s;
   struct GNUNET_TIME_Relative flow_delay;
 
@@ -2517,23 +2432,27 @@
     return;
   }
   udp_ack = (const struct UDP_ACK_Message *) msg;
-
-  /* Lookup session based on sockaddr */
-  l_ctx.address = addr;
-  l_ctx.addr_len = fromlen;
-  l_ctx.res = NULL;
-  l_ctx.must_have_frag_ctx = GNUNET_YES;
-  GNUNET_CONTAINER_multipeermap_iterate (plugin->sessions,
-      &lookup_session_by_sockaddr_it, &l_ctx);
-  s = l_ctx.res;
-  if ((NULL == s) || (NULL == s->frag_ctx))
+  address = GNUNET_HELLO_address_allocate (&udp_ack->sender,
+                                           PLUGIN_NAME,
+                                           udp_addr,
+                                           udp_addr_len,
+                                           GNUNET_HELLO_ADDRESS_INFO_NONE);
+  s = udp_plugin_lookup_session (plugin,
+                                 address);
+  GNUNET_HELLO_address_free (address);
+  if ( (NULL == s) ||
+       (NULL == s->frag_ctx) )
   {
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+                "UDP session for ACK not found\n");
     return;
   }
 
   flow_delay.rel_value_us = (uint64_t) ntohl (udp_ack->delay);
-  LOG(GNUNET_ERROR_TYPE_DEBUG, "We received a sending delay of %s\n",
-      GNUNET_STRINGS_relative_time_to_string (flow_delay, GNUNET_YES));
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "We received a sending delay of %s\n",
+       GNUNET_STRINGS_relative_time_to_string (flow_delay,
+                                               GNUNET_YES));
   s->flow_delay_from_other_peer = GNUNET_TIME_relative_to_absolute 
(flow_delay);
 
   ack = (const struct GNUNET_MessageHeader *) &udp_ack[1];
@@ -2543,92 +2462,120 @@
     return;
   }
 
-  if (0
-      != memcmp (&l_ctx.res->target, &udp_ack->sender,
-          sizeof(struct GNUNET_PeerIdentity)))
-    GNUNET_break(0);
-  if (GNUNET_OK != GNUNET_FRAGMENT_process_ack (s->frag_ctx->frag, ack))
+  if (GNUNET_OK !=
+      GNUNET_FRAGMENT_process_ack (s->frag_ctx->frag,
+                                   ack))
   {
     LOG(GNUNET_ERROR_TYPE_DEBUG,
         "UDP processes %u-byte acknowledgement from `%s' at `%s'\n",
-        (unsigned int ) ntohs (msg->size), GNUNET_i2s (&udp_ack->sender),
-        GNUNET_a2s (addr, fromlen));
+        (unsigned int ) ntohs (msg->size),
+        GNUNET_i2s (&udp_ack->sender),
+        udp_address_to_string (plugin,
+                               udp_addr,
+                               udp_addr_len));
     /* Expect more ACKs to arrive */
     return;
   }
 
-  LOG(GNUNET_ERROR_TYPE_DEBUG, "Message full ACK'ed\n",
-      (unsigned int ) ntohs (msg->size), GNUNET_i2s (&udp_ack->sender),
-      GNUNET_a2s (addr, fromlen));
+  LOG (GNUNET_ERROR_TYPE_DEBUG,
+       "Message full ACK'ed\n",
+       (unsigned int ) ntohs (msg->size),
+       GNUNET_i2s (&udp_ack->sender),
+       udp_address_to_string (plugin,
+                              udp_addr,
+                              udp_addr_len));
 
+
   /* Remove fragmented message after successful sending */
-  fragmented_message_done (s->frag_ctx, GNUNET_OK);
+  fragmented_message_done (s->frag_ctx,
+                           GNUNET_OK);
 }
 
 
 /**
- * FIXME.
+ * We received a fragment, process it.
+ *
+ * @param plugin our plugin
+ * @param msg a message of type #GNUNET_MESSAGE_TYPE_FRAGMENT
+ * @param udp_addr sender address
+ * @param udp_addr_len number of bytes in @a udp_addr
+ * @param network_type network type the address belongs to
  */
 static void
 read_process_fragment (struct Plugin *plugin,
                        const struct GNUNET_MessageHeader *msg,
-                       const struct sockaddr *addr,
-                       socklen_t fromlen)
+                       const union UdpAddress *udp_addr,
+                       size_t udp_addr_len,
+                       enum GNUNET_ATS_Network_Type network_type)
 {
   struct DefragContext *d_ctx;
   struct GNUNET_TIME_Absolute now;
   struct FindReceiveContext frc;
 
   frc.rc = NULL;
-  frc.addr = addr;
-  frc.addr_len = fromlen;
+  frc.udp_addr = udp_addr;
+  frc.udp_addr_len = udp_addr_len;
 
-  LOG(GNUNET_ERROR_TYPE_DEBUG, "UDP processes %u-byte fragment from `%s'\n",
-      (unsigned int ) ntohs (msg->size), GNUNET_a2s (addr, fromlen));
   /* Lookup existing receive context for this address */
   GNUNET_CONTAINER_heap_iterate (plugin->defrag_ctxs,
-      &find_receive_context, &frc);
+                                 &find_receive_context,
+                                 &frc);
   now = GNUNET_TIME_absolute_get ();
   d_ctx = frc.rc;
 
-  if (d_ctx == NULL )
+  if (NULL == d_ctx)
   {
     /* Create a new defragmentation context */
-    d_ctx = GNUNET_malloc (sizeof (struct DefragContext) + fromlen);
-    memcpy (&d_ctx[1], addr, fromlen);
-    d_ctx->src_addr = (const struct sockaddr *) &d_ctx[1];
-    d_ctx->addr_len = fromlen;
+    d_ctx = GNUNET_malloc (sizeof (struct DefragContext) + udp_addr_len);
+    memcpy (&d_ctx[1],
+            udp_addr,
+            udp_addr_len);
+    d_ctx->udp_addr = (const union UdpAddress *) &d_ctx[1];
+    d_ctx->udp_addr_len = udp_addr_len;
+    d_ctx->network_type = network_type;
     d_ctx->plugin = plugin;
     d_ctx->defrag = GNUNET_DEFRAGMENT_context_create (plugin->env->stats,
-        UDP_MTU, UDP_MAX_MESSAGES_IN_DEFRAG, d_ctx, &fragment_msg_proc,
-        &ack_proc);
-    d_ctx->hnode = GNUNET_CONTAINER_heap_insert (plugin->defrag_ctxs, d_ctx,
+                                                      UDP_MTU,
+                                                      
UDP_MAX_MESSAGES_IN_DEFRAG,
+                                                      d_ctx,
+                                                      &fragment_msg_proc,
+                                                      &ack_proc);
+    d_ctx->hnode = GNUNET_CONTAINER_heap_insert (plugin->defrag_ctxs,
+                                                 d_ctx,
         (GNUNET_CONTAINER_HeapCostType) now.abs_value_us);
-    LOG(GNUNET_ERROR_TYPE_DEBUG,
-        "Created new defragmentation context for %u-byte fragment from `%s'\n",
-        (unsigned int ) ntohs (msg->size), GNUNET_a2s (addr, fromlen));
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Created new defragmentation context for %u-byte fragment from 
`%s'\n",
+         (unsigned int ) ntohs (msg->size),
+         udp_address_to_string (plugin,
+                                udp_addr,
+                                udp_addr_len));
   }
   else
   {
-    LOG(GNUNET_ERROR_TYPE_DEBUG,
-        "Found existing defragmentation context for %u-byte fragment from 
`%s'\n",
-        (unsigned int ) ntohs (msg->size), GNUNET_a2s (addr, fromlen));
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "Found existing defragmentation context for %u-byte fragment from 
`%s'\n",
+         (unsigned int ) ntohs (msg->size),
+         udp_address_to_string (plugin,
+                                udp_addr,
+                                udp_addr_len));
   }
 
-  if (GNUNET_OK == GNUNET_DEFRAGMENT_process_fragment (d_ctx->defrag, msg))
+  if (GNUNET_OK ==
+      GNUNET_DEFRAGMENT_process_fragment (d_ctx->defrag, msg))
   {
     /* keep this 'rc' from expiring */
-    GNUNET_CONTAINER_heap_update_cost (plugin->defrag_ctxs, d_ctx->hnode,
+    GNUNET_CONTAINER_heap_update_cost (plugin->defrag_ctxs,
+                                       d_ctx->hnode,
         (GNUNET_CONTAINER_HeapCostType) now.abs_value_us);
   }
   if (GNUNET_CONTAINER_heap_get_size (plugin->defrag_ctxs) >
-  UDP_MAX_SENDER_ADDRESSES_WITH_DEFRAG)
+      UDP_MAX_SENDER_ADDRESSES_WITH_DEFRAG)
   {
     /* remove 'rc' that was inactive the longest */
     d_ctx = GNUNET_CONTAINER_heap_remove_root (plugin->defrag_ctxs);
-    GNUNET_assert(NULL != d_ctx);
+    GNUNET_assert (NULL != d_ctx);
     GNUNET_DEFRAGMENT_context_destroy (d_ctx->defrag);
-    GNUNET_free(d_ctx);
+    GNUNET_free (d_ctx);
   }
 }
 
@@ -2648,11 +2595,20 @@
   char buf[65536] GNUNET_ALIGN;
   ssize_t size;
   const struct GNUNET_MessageHeader *msg;
+  struct IPv4UdpAddress v4;
+  struct IPv6UdpAddress v6;
+  const struct sockaddr *sa;
+  const struct sockaddr_in *sa4;
+  const struct sockaddr_in6 *sa6;
+  const union UdpAddress *int_addr;
+  size_t int_addr_len;
+  enum GNUNET_ATS_Network_Type network_type;
 
   fromlen = sizeof(addr);
   memset (&addr, 0, sizeof(addr));
   size = GNUNET_NETWORK_socket_recvfrom (rsock, buf, sizeof(buf),
                                          (struct sockaddr *) &addr, &fromlen);
+  sa = (const struct sockaddr *) &addr;
 #if MINGW
   /* On SOCK_DGRAM UDP sockets recvfrom might fail with a
    * WSAECONNRESET error to indicate that previous sendto() (yes, sendto!)
@@ -2680,50 +2636,94 @@
     LOG (GNUNET_ERROR_TYPE_WARNING,
          "UDP got %u bytes from %s, which is not enough for a GNUnet message 
header\n",
          (unsigned int ) size,
-         GNUNET_a2s ((const struct sockaddr *) &addr, fromlen));
+         GNUNET_a2s (sa, fromlen));
     /* _MAY_ be a connection failure (got partial message) */
     /* But it _MAY_ also be that the other side uses non-GNUnet protocol. */
     GNUNET_break_op(0);
     return;
   }
   msg = (const struct GNUNET_MessageHeader *) buf;
-
   LOG (GNUNET_ERROR_TYPE_DEBUG,
        "UDP received %u-byte message from `%s' type %u\n",
        (unsigned int) size,
-       GNUNET_a2s ((const struct sockaddr *) &addr, fromlen),
+       GNUNET_a2s (sa,
+                   fromlen),
        ntohs (msg->type));
-
   if (size != ntohs (msg->size))
   {
     LOG (GNUNET_ERROR_TYPE_WARNING,
          "UDP malformed message header from %s\n",
-         (unsigned int ) size,
-         GNUNET_a2s ((const struct sockaddr *) &addr, fromlen));
-    GNUNET_break_op(0);
+         (unsigned int) size,
+         GNUNET_a2s (sa,
+                     fromlen));
+    GNUNET_break_op (0);
     return;
   }
   GNUNET_STATISTICS_update (plugin->env->stats,
                             "# UDP, total, bytes, received",
                             size,
                             GNUNET_NO);
+  network_type = plugin->env->get_address_type (plugin->env->cls,
+                                                sa,
+                                                fromlen);
+  switch (sa->sa_family)
+  {
+  case AF_INET:
+    sa4 = (const struct sockaddr_in *) &addr;
+    v4.options = 0;
+    v4.ipv4_addr = sa4->sin_addr.s_addr;
+    v4.u4_port = sa4->sin_port;
+    int_addr = (union UdpAddress *) &v4;
+    int_addr_len = sizeof (v4);
+    break;
+  case AF_INET6:
+    sa6 = (const struct sockaddr_in6 *) &addr;
+    v6.options = 0;
+    v6.ipv6_addr = sa6->sin6_addr;
+    v6.u6_port = sa6->sin6_port;
+    int_addr = (union UdpAddress *) &v6;
+    int_addr_len = sizeof (v6);
+    break;
+  default:
+    GNUNET_break (0);
+    return;
+  }
 
   switch (ntohs (msg->type))
   {
   case GNUNET_MESSAGE_TYPE_TRANSPORT_BROADCAST_BEACON:
     if (GNUNET_YES == plugin->enable_broadcasting_receiving)
-      udp_broadcast_receive (plugin, buf, size, (const struct sockaddr *) 
&addr,
-          fromlen);
+      udp_broadcast_receive (plugin,
+                             buf,
+                             size,
+                             int_addr,
+                             int_addr_len,
+                             network_type);
     return;
   case GNUNET_MESSAGE_TYPE_TRANSPORT_UDP_MESSAGE:
-    read_process_msg (plugin, msg, (const struct sockaddr *) &addr, fromlen);
+    if (ntohs (msg->size) < sizeof(struct UDPMessage))
+    {
+      GNUNET_break_op(0);
+      return;
+    }
+    process_udp_message (plugin,
+                         (const struct UDPMessage *) msg,
+                         int_addr,
+                         int_addr_len,
+                         network_type);
     return;
   case GNUNET_MESSAGE_TYPE_TRANSPORT_UDP_ACK:
-    read_process_ack (plugin, msg, (const struct sockaddr *) &addr, fromlen);
+    read_process_ack (plugin,
+                      msg,
+                      int_addr,
+                      int_addr_len);
     return;
   case GNUNET_MESSAGE_TYPE_FRAGMENT:
-    read_process_fragment (plugin, msg, (const struct sockaddr *) &addr,
-        fromlen);
+    read_process_fragment (plugin,
+                           msg,
+                           int_addr,
+                           int_addr_len,
+                           network_type);
     return;
   default:
     GNUNET_break_op(0);
@@ -3008,15 +3008,21 @@
   else
   {
     /* Success */
-    LOG(GNUNET_ERROR_TYPE_DEBUG,
-        "UDP transmitted %u-byte message to  `%s' `%s' (%d: %s)\n",
-        (unsigned int ) (udpw->msg_size), GNUNET_i2s (&udpw->session->target),
-        GNUNET_a2s (a, slen), (int ) sent,
-        (sent < 0) ? STRERROR (errno) : "ok");
+    LOG (GNUNET_ERROR_TYPE_DEBUG,
+         "UDP transmitted %u-byte message to  `%s' `%s' (%d: %s)\n",
+         (unsigned int) (udpw->msg_size),
+         GNUNET_i2s (&udpw->session->target),
+         GNUNET_a2s (a, slen),
+         (int ) sent,
+         (sent < 0) ? STRERROR (errno) : "ok");
     GNUNET_STATISTICS_update (plugin->env->stats,
-        "# UDP, total, bytes, sent, success", sent, GNUNET_NO);
+                              "# UDP, total, bytes, sent, success",
+                              sent,
+                              GNUNET_NO);
     GNUNET_STATISTICS_update (plugin->env->stats,
-        "# UDP, total, messages, sent, success", 1, GNUNET_NO);
+                              "# UDP, total, messages, sent, success",
+                              1,
+                              GNUNET_NO);
     if (NULL != udpw->frag_ctx)
       udpw->frag_ctx->on_wire_size += udpw->msg_size;
     call_continuation (udpw, GNUNET_OK);
@@ -3233,8 +3239,10 @@
            GNUNET_a2s (server_addr, addrlen));
 
       /* binding */
-      if (GNUNET_OK
-          == GNUNET_NETWORK_socket_bind (plugin->sockv4, server_addr, addrlen))
+      if (GNUNET_OK ==
+          GNUNET_NETWORK_socket_bind (plugin->sockv4,
+                                      server_addr,
+                                      addrlen))
         break;
       eno = errno;
       if (0 != plugin->port)
@@ -3259,8 +3267,9 @@
 
     if (NULL != plugin->sockv4)
     {
-      LOG(GNUNET_ERROR_TYPE_DEBUG, "IPv4 socket created on port %s\n",
-          GNUNET_a2s (server_addr, addrlen));
+      LOG (GNUNET_ERROR_TYPE_DEBUG,
+           "IPv4 socket created on port %s\n",
+           GNUNET_a2s (server_addr, addrlen));
       addrs[sockets_created] = (struct sockaddr *) &server_addrv4;
       addrlens[sockets_created] = sizeof(struct sockaddr_in);
       sockets_created++;
@@ -3276,7 +3285,8 @@
 
   if (0 == sockets_created)
   {
-    LOG(GNUNET_ERROR_TYPE_WARNING, _("Failed to open UDP sockets\n"));
+    LOG (GNUNET_ERROR_TYPE_WARNING,
+         _("Failed to open UDP sockets\n"));
     return 0; /* No sockets created, return */
   }
 
@@ -3425,11 +3435,13 @@
   /* Get port number: port == 0 : autodetect a port,
    * > 0 : use this port, not given : 2086 default */
   if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-udp",
+      GNUNET_CONFIGURATION_get_value_number (env->cfg,
+                                             "transport-udp",
                                              "PORT", &port))
     port = 2086;
   if (GNUNET_OK !=
-      GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-udp",
+      GNUNET_CONFIGURATION_get_value_number (env->cfg,
+                                             "transport-udp",
                                              "ADVERTISED_PORT", &aport))
     aport = port;
   if (port > 65535)

Modified: gnunet/src/transport/plugin_transport_udp.h
===================================================================
--- gnunet/src/transport/plugin_transport_udp.h 2015-01-30 12:18:47 UTC (rev 
35052)
+++ gnunet/src/transport/plugin_transport_udp.h 2015-02-01 18:00:31 UTC (rev 
35053)
@@ -102,7 +102,24 @@
 };
 GNUNET_NETWORK_STRUCT_END
 
+/**
+ * Either an IPv4 or IPv6 UDP address.  Note that without a "length",
+ * one cannot tell which one of the two types this address represents.
+ */
+union UdpAddress
+{
+  /**
+   * IPv4 case.
+   */
+  struct IPv4UdpAddress v4;
 
+  /**
+   * IPv6 case.
+   */
+  struct IPv6UdpAddress v6;
+};
+
+
 /**
  * UDP Message-Packet header (after defragmentation).
  */
@@ -155,12 +172,12 @@
   /**
    * ID of select task for IPv4
    */
-  struct GNUNET_SCHEDULER_Task * select_task;
+  struct GNUNET_SCHEDULER_Task *select_task;
 
   /**
    * ID of select task for IPv6
    */
-  struct GNUNET_SCHEDULER_Task * select_task_v6;
+  struct GNUNET_SCHEDULER_Task *select_task_v6;
 
   /**
    * Tokenizer for inbound messages.
@@ -218,16 +235,11 @@
   struct GNUNET_NETWORK_Handle *sockv6;
 
   /**
-   * Tokenizer for inbound IPv6 messages.
+   * Tokenizer for inbound messages.
    */
-  struct GNUNET_SERVER_MessageStreamTokenizer *broadcast_ipv6_mst;
+  struct GNUNET_SERVER_MessageStreamTokenizer *broadcast_mst;
 
   /**
-   * Tokenizer for inbound IPv4 messages.
-   */
-  struct GNUNET_SERVER_MessageStreamTokenizer *broadcast_ipv4_mst;
-
-  /**
    * Head of DLL of broadcast addresses
    */
   struct BroadcastAddress *broadcast_tail;
@@ -336,20 +348,37 @@
 
 
 const char *
-udp_address_to_string (void *cls, const void *addr, size_t addrlen);
+udp_address_to_string (void *cls,
+                       const void *addr,
+                       size_t addrlen);
 
+
+/**
+ * We received a broadcast message.  Process it and all subsequent
+ * messages in the same packet.
+ *
+ * @param plugin the UDP plugin
+ * @param buf the buffer with the message(s)
+ * @param size number of bytes in @a buf
+ * @param udp_addr address of the sender
+ * @param udp_addr_len number of bytes in @a udp_addr
+ * @param network_type network type of the sender's address
+ */
 void
 udp_broadcast_receive (struct Plugin *plugin,
-                       const char * buf,
+                       const char *buf,
                        ssize_t size,
-                       const struct sockaddr *addr,
-                       size_t addrlen);
+                       const union UdpAddress *udp_addr,
+                       size_t udp_addr_len,
+                       enum GNUNET_ATS_Network_Type network_type);
 
+
 void
 setup_broadcast (struct Plugin *plugin,
                  struct sockaddr_in6 *server_addrv6,
                  struct sockaddr_in *server_addrv4);
 
+
 void
 stop_broadcast (struct Plugin *plugin);
 

Modified: gnunet/src/transport/plugin_transport_udp_broadcasting.c
===================================================================
--- gnunet/src/transport/plugin_transport_udp_broadcasting.c    2015-01-30 
12:18:47 UTC (rev 35052)
+++ gnunet/src/transport/plugin_transport_udp_broadcasting.c    2015-02-01 
18:00:31 UTC (rev 35053)
@@ -88,7 +88,7 @@
 
   struct Plugin *plugin;
 
-  void *addr;
+  struct sockaddr *addr;
 
   socklen_t addrlen;
 
@@ -106,25 +106,17 @@
 };
 
 
-struct Mstv4Context
+/**
+ * Client-specific context for #broadcast_mst_cb().
+ */
+struct MstContext
 {
   struct Plugin *plugin;
 
-  struct IPv4UdpAddress addr;
+  const union UdpAddress *udp_addr;
 
-  /**
-   * ATS network type.
-   */
-  enum GNUNET_ATS_Network_Type ats_address_network_type;
-};
+  size_t udp_addr_len;
 
-
-struct Mstv6Context
-{
-  struct Plugin *plugin;
-
-  struct IPv6UdpAddress addr;
-
   /**
    * ATS network type.
    */
@@ -132,12 +124,21 @@
 };
 
 
+/**
+ * Parse broadcast message received.
+ *
+ * @param cls the `struct Plugin`
+ * @param client the `struct MstContext` with sender address
+ * @param message the message we received
+ * @return #GNUNET_OK (always)
+ */
 static int
-broadcast_ipv6_mst_cb (void *cls, void *client,
-                       const struct GNUNET_MessageHeader *message)
+broadcast_mst_cb (void *cls,
+                  void *client,
+                  const struct GNUNET_MessageHeader *message)
 {
   struct Plugin *plugin = cls;
-  struct Mstv6Context *mc = client;
+  struct MstContext *mc = client;
   struct GNUNET_HELLO_Address *address;
   const struct GNUNET_MessageHeader *hello;
   const struct UDP_Beacon_Message *msg;
@@ -150,131 +151,76 @@
     return GNUNET_OK;
   LOG (GNUNET_ERROR_TYPE_DEBUG,
        "Received beacon with %u bytes from peer `%s' via address `%s'\n",
-       ntohs (msg->header.size), GNUNET_i2s (&msg->sender),
-       udp_address_to_string (NULL, &mc->addr, sizeof (mc->addr)));
+       ntohs (msg->header.size),
+       GNUNET_i2s (&msg->sender),
+       udp_address_to_string (NULL,
+                              mc->udp_addr,
+                              mc->udp_addr_len));
 
   /* setup ATS */
   atsi.type = htonl (GNUNET_ATS_NETWORK_TYPE);
   atsi.value = htonl (mc->ats_address_network_type);
-  GNUNET_break (ntohl(mc->ats_address_network_type) != 
GNUNET_ATS_NET_UNSPECIFIED);
+  GNUNET_break (ntohl(mc->ats_address_network_type) !=
+                GNUNET_ATS_NET_UNSPECIFIED);
 
   hello = (struct GNUNET_MessageHeader *) &msg[1];
-  address = GNUNET_HELLO_address_allocate (&msg->sender, PLUGIN_NAME,
-                                           (const char *) &mc->addr,
-                                           sizeof (mc->addr),
-                                           GNUNET_HELLO_ADDRESS_INFO_NONE);
-  plugin->env->receive (plugin->env->cls, address, NULL, hello);
-  plugin->env->update_address_metrics (plugin->env->cls, address,
-                                      NULL, &atsi, 1);
-  GNUNET_HELLO_address_free (address);
-  GNUNET_STATISTICS_update (plugin->env->stats,
-                            _
-                            ("# IPv6 multicast HELLO beacons received via 
udp"),
-                            1, GNUNET_NO);
-  GNUNET_free (mc);
-  return GNUNET_OK;
-}
-
-
-static int
-broadcast_ipv4_mst_cb (void *cls, void *client,
-                       const struct GNUNET_MessageHeader *message)
-{
-  struct Plugin *plugin = cls;
-  struct Mstv4Context *mc = client;
-  struct GNUNET_HELLO_Address *address;
-  const struct GNUNET_MessageHeader *hello;
-  const struct UDP_Beacon_Message *msg;
-  struct GNUNET_ATS_Information atsi;
-
-  msg = (const struct UDP_Beacon_Message *) message;
-
-  if (GNUNET_MESSAGE_TYPE_TRANSPORT_BROADCAST_BEACON !=
-      ntohs (msg->header.type))
-    return GNUNET_OK;
-  LOG (GNUNET_ERROR_TYPE_DEBUG,
-       "Received beacon with %u bytes from peer `%s' via address `%s'\n",
-       ntohs (msg->header.size), GNUNET_i2s (&msg->sender),
-       udp_address_to_string (NULL, &mc->addr, sizeof (mc->addr)));
-
-
-  /* setup ATS */
-  atsi.type = htonl (GNUNET_ATS_NETWORK_TYPE);
-  atsi.value = htonl (mc->ats_address_network_type);
-  GNUNET_break (ntohl(mc->ats_address_network_type) != 
GNUNET_ATS_NET_UNSPECIFIED);
-
-  hello = (struct GNUNET_MessageHeader *) &msg[1];
   address = GNUNET_HELLO_address_allocate (&msg->sender,
                                            PLUGIN_NAME,
-                                           (const char *) &mc->addr,
-                                           sizeof (mc->addr),
+                                           mc->udp_addr,
+                                           mc->udp_addr_len,
                                            GNUNET_HELLO_ADDRESS_INFO_NONE);
-  plugin->env->receive (plugin->env->cls, address, NULL, hello);
-  plugin->env->update_address_metrics (plugin->env->cls, address,
-                                       NULL, &atsi, 1);
+  plugin->env->receive (plugin->env->cls,
+                        address,
+                        NULL,
+                        hello);
+  plugin->env->update_address_metrics (plugin->env->cls,
+                                       address,
+                                      NULL,
+                                       &atsi,
+                                       1);
   GNUNET_HELLO_address_free (address);
-
   GNUNET_STATISTICS_update (plugin->env->stats,
-                            _("# IPv4 broadcast HELLO beacons received via 
udp"),
+                            _("# Multicast HELLO beacons received via UDP"),
                             1, GNUNET_NO);
-  GNUNET_free (mc);
   return GNUNET_OK;
 }
 
 
+/**
+ * We received a broadcast message.  Process it and all subsequent
+ * messages in the same packet.
+ *
+ * @param plugin the UDP plugin
+ * @param buf the buffer with the message(s)
+ * @param size number of bytes in @a buf
+ * @param udp_addr address of the sender
+ * @param udp_addr_len number of bytes in @a udp_addr
+ * @param network_type network type of the sender's address
+ */
 void
 udp_broadcast_receive (struct Plugin *plugin,
                        const char *buf,
                        ssize_t size,
-                       const struct sockaddr *addr,
-                       size_t addrlen)
+                       const union UdpAddress *udp_addr,
+                       size_t udp_addr_len,
+                       enum GNUNET_ATS_Network_Type network_type)
 {
-  if (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;
+  struct MstContext mc;
 
-    mc = GNUNET_new (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;
-    mc->ats_address_network_type = plugin->env->get_address_type 
(plugin->env->cls,
-                                                                  (const 
struct sockaddr *) addr,
-                                                                  addrlen);
-
-    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);
-  }
-  if (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_new (struct Mstv6Context);
-    struct sockaddr_in6 *av6 = (struct sockaddr_in6 *) addr;
-
-    mc->addr.ipv6_addr = av6->sin6_addr;
-    mc->addr.u6_port = av6->sin6_port;
-    mc->ats_address_network_type = plugin->env->get_address_type 
(plugin->env->cls, (const struct sockaddr *) addr, addrlen);
-    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);
-  }
+  mc.udp_addr = udp_addr;
+  mc.udp_addr_len = udp_addr_len;
+  mc.ats_address_network_type = network_type;
+  GNUNET_SERVER_mst_receive (plugin->broadcast_mst,
+                             &mc,
+                             buf, size,
+                             GNUNET_NO,
+                             GNUNET_NO);
 }
 
 
 static unsigned int
-prepare_beacon (struct Plugin *plugin, struct UDP_Beacon_Message *msg)
+prepare_beacon (struct Plugin *plugin,
+                struct UDP_Beacon_Message *msg)
 {
   uint16_t hello_size;
   uint16_t msg_size;
@@ -611,10 +557,8 @@
   }
 
   /* always create tokenizers */
-  plugin->broadcast_ipv4_mst =
-    GNUNET_SERVER_mst_create (&broadcast_ipv4_mst_cb, plugin);
-  plugin->broadcast_ipv6_mst =
-    GNUNET_SERVER_mst_create (&broadcast_ipv6_mst_cb, plugin);
+  plugin->broadcast_mst =
+    GNUNET_SERVER_mst_create (&broadcast_mst_cb, plugin);
 
   if (GNUNET_YES != plugin->enable_broadcasting)
     return; /* We do not send, just receive */
@@ -699,16 +643,11 @@
   }
 
   /* Destroy MSTs */
-  if (NULL != plugin->broadcast_ipv4_mst)
+  if (NULL != plugin->broadcast_mst)
   {
-    GNUNET_SERVER_mst_destroy (plugin->broadcast_ipv4_mst);
-    plugin->broadcast_ipv4_mst = NULL;
+    GNUNET_SERVER_mst_destroy (plugin->broadcast_mst);
+    plugin->broadcast_mst = NULL;
   }
-  if (NULL != plugin->broadcast_ipv6_mst)
-  {
-    GNUNET_SERVER_mst_destroy (plugin->broadcast_ipv6_mst);
-    plugin->broadcast_ipv6_mst = NULL;
-  }
 }
 
 /* end of plugin_transport_udp_broadcasting.c */




reply via email to

[Prev in Thread] Current Thread [Next in Thread]