still not really working... sending and receiving of messages a bit hinky
[oweals/gnunet.git] / src / transport / plugin_transport_udp.c
index 4520a71f98dd72027ed1b4eb3470418019bd6eb1..3df492a913213adc196b96a62acf12b3bf343224 100644 (file)
@@ -40,7 +40,7 @@
 #include "plugin_transport.h"
 #include "transport.h"
 
-#define DEBUG_UDP GNUNET_NO
+#define DEBUG_UDP GNUNET_YES
 
 /*
  * Transport cost to peer, always 1 for UDP (direct connection)
  */
 static struct GNUNET_RESOLVER_RequestHandle *hostname_dns;
 
+/**
+ * How long until we give up on transmitting the welcome message?
+ */
+#define HOSTNAME_RESOLVE_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
+
+
 /**
  * Message-Packet header.
  */
@@ -99,6 +105,11 @@ struct Plugin
    */
   struct GNUNET_SERVICE_Context *service;
 
+  /**
+   * Handle for request of hostname resolution, non-NULL if pending.
+   */
+  struct GNUNET_RESOLVER_RequestHandle *hostname_dns;
+
   /**
    * ID of task used to update our addresses when one expires.
    */
@@ -172,7 +183,8 @@ udp_transport_server_stop (void *cls)
  *
  * @param cls closure
  * @param target who should receive this message (ignored by UDP)
- * @param msg the message to transmit
+ * @param msgbuf one or more GNUNET_MessageHeader(s) strung together
+ * @param msgbufsize the size of the msgbuf to send
  * @param priority how important is the message (ignored by UDP)
  * @param timeout when should we time out (give up) if we can not transmit?
  * @param addr the addr to send the message to, needs to be a sockaddr for us
@@ -191,7 +203,8 @@ udp_transport_server_stop (void *cls)
 static ssize_t
 udp_plugin_send (void *cls,
                  const struct GNUNET_PeerIdentity *target,
-                 const struct GNUNET_MessageHeader *msg,
+                 char *msgbuf,
+                 size_t msgbuf_size,
                  unsigned int priority,
                  struct GNUNET_TIME_Relative timeout,
                  const void *addr,
@@ -205,21 +218,30 @@ udp_plugin_send (void *cls,
   ssize_t sent;
 
   GNUNET_assert(udp_sock != NULL);
-  GNUNET_assert(addr != NULL);
+
+  if ((addr == NULL) || (addrlen == 0))
+    {
+#if DEBUG_UDP
+  GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "udp", _
+                   ("udp_plugin_send called without address, returning!\n"));
+#endif
+      cont (cont_cls, target, GNUNET_OK);
+      return 0; /* Can never send if we don't have an address!! */
+    }
 
   /* Build the message to be sent */
-  message = GNUNET_malloc (sizeof (struct UDPMessage) + ntohs (msg->size));
-  ssize = sizeof (struct UDPMessage) + ntohs (msg->size);
+  message = GNUNET_malloc (sizeof (struct UDPMessage) + msgbuf_size);
+  ssize = sizeof (struct UDPMessage) + msgbuf_size;
 
 #if DEBUG_UDP
   GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "udp", _
-                   ("In udp_send, ssize is %d\n"), ssize);
+                   ("In udp_send, ssize is %d, sending message to %s\n"), ssize, GNUNET_a2s((const struct sockaddr *)addr, addrlen));
 #endif
   message->header.size = htons (ssize);
   message->header.type = htons (0);
   memcpy (&message->sender, plugin->env->my_identity,
           sizeof (struct GNUNET_PeerIdentity));
-  memcpy (&message[1], msg, ntohs (msg->size));
+  memcpy (&message[1], msgbuf, msgbuf_size);
 
   /* Actually send the message */
   sent =
@@ -232,13 +254,82 @@ udp_plugin_send (void *cls,
       if (sent == GNUNET_SYSERR)
         cont (cont_cls, target, GNUNET_SYSERR);
       else
-        cont (cont_cls, target, GNUNET_OK);
+        {
+#if DEBUG_UDP
+  GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "udp", _
+                   ("Sucessfully sent message, calling transmit continuation!\n"));
+#endif
+          cont (cont_cls, target, GNUNET_OK);
+        }
     }
   GNUNET_free (message);
   return sent;
 }
 
 
+/**
+ * Add the IP of our network interface to the list of
+ * our external IP addresses.
+ */
+static int
+process_interfaces (void *cls,
+                    const char *name,
+                    int isDefault,
+                    const struct sockaddr *addr, socklen_t addrlen)
+{
+  struct Plugin *plugin = cls;
+  int af;
+  struct sockaddr_in *v4;
+  struct sockaddr_in6 *v6;
+
+  af = addr->sa_family;
+  if (af == AF_INET)
+    {
+      v4 = (struct sockaddr_in *) addr;
+      v4->sin_port = htons (plugin->adv_port);
+    }
+  else
+    {
+      GNUNET_assert (af == AF_INET6);
+      v6 = (struct sockaddr_in6 *) addr;
+      v6->sin6_port = htons (plugin->adv_port);
+    }
+  GNUNET_log_from (GNUNET_ERROR_TYPE_INFO |
+                   GNUNET_ERROR_TYPE_BULK,
+                   "udp", _("Found address `%s' (%s)\n"),
+                   GNUNET_a2s (addr, addrlen), name);
+  plugin->env->notify_address (plugin->env->cls,
+                               "udp",
+                               addr, addrlen, GNUNET_TIME_UNIT_FOREVER_REL);
+
+  return GNUNET_OK;
+}
+
+
+/**
+ * Function called by the resolver for each address obtained from DNS
+ * for our own hostname.  Add the addresses to the list of our
+ * external IP addresses.
+ *
+ * @param cls closure
+ * @param addr one of the addresses of the host, NULL for the last address
+ * @param addrlen length of the address
+ */
+static void
+process_hostname_ips (void *cls,
+                      const struct sockaddr *addr, socklen_t addrlen)
+{
+  struct Plugin *plugin = cls;
+
+  if (addr == NULL)
+    {
+      plugin->hostname_dns = NULL;
+      return;
+    }
+  process_interfaces (plugin, "<hostname>", GNUNET_YES, addr, addrlen);
+}
+
+
 /*
  * @param cls the plugin handle
  * @param tc the scheduling context (for rescheduling this function again)
@@ -264,6 +355,11 @@ udp_plugin_select (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
   socklen_t fromlen;
   struct sockaddr_storage addr;
   ssize_t ret;
+  int offset;
+  int count;
+  int tsize;
+  char *msgbuf;
+  const struct GNUNET_MessageHeader *currhdr;
 
   do
     {
@@ -279,10 +375,7 @@ udp_plugin_select (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
 
       buf = GNUNET_malloc (buflen);
       fromlen = sizeof (addr);
-#if DEBUG_UDP
-      GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "udp", _
-                       ("src_addr_len is %u\n"), fromlen);
-#endif
+
       memset (&addr, 0, fromlen);
       ret =
         GNUNET_NETWORK_socket_recvfrom (udp_sock, buf, buflen,
@@ -318,20 +411,31 @@ udp_plugin_select (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
           break;
         }
       hdr = (const struct GNUNET_MessageHeader *) &msg[1];
+      msgbuf = (char *)&msg[1];
       sender = GNUNET_malloc (sizeof (struct GNUNET_PeerIdentity));
       memcpy (sender, &msg->sender, sizeof (struct GNUNET_PeerIdentity));
 
+      offset = 0;
+      count = 0;
+      tsize = ntohs (msg->header.size) - sizeof(struct UDPMessage);
+      while (offset < tsize)
+        {
+          currhdr = (struct GNUNET_MessageHeader *)&msgbuf[offset];
 #if DEBUG_UDP
       GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "udp", _
-                       ("msg reports message size of %d\n"),
-                       ntohs (hdr->size));
-
+                       ("processing msg %d: type %d, size %d at offset %d\n"),
+                       count, ntohs(currhdr->type), ntohs(currhdr->size), offset);
+#endif
+          plugin->env->receive (plugin->env->cls,
+              sender, currhdr, UDP_DIRECT_DISTANCE, (char *)&addr, fromlen);
+          offset += ntohs(currhdr->size);
+#if DEBUG_UDP
       GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "udp", _
-                       ("msg reports message type of %d\n"),
-                       ntohs (hdr->type));
+                       ("offset now %d, tsize %d\n"),
+                       offset, tsize);
 #endif
-      plugin->env->receive (plugin->env->cls,
-          sender, &msg->header, UDP_DIRECT_DISTANCE, (char *)&addr, fromlen);
+          count++;
+        }
 
       GNUNET_free (sender);
       GNUNET_free (buf);
@@ -488,7 +592,7 @@ udp_check_address (void *cls, void *addr, size_t addrlen)
       v6 = (struct sockaddr_in6 *) buf;
       v6->sin6_port = htons (check_port (plugin, ntohs (v6->sin6_port)));
     }
-#if DEBUG_TCP
+#if DEBUG_UDP
   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
                    "tcp",
                    "Informing transport service about my address `%s'.\n",
@@ -667,6 +771,16 @@ libgnunet_plugin_transport_udp_init (void *cls)
 
   plugin->service = service;
 
+  /* FIXME: do the two calls below periodically again and
+     not just once (since the info we get might change...) */
+  GNUNET_OS_network_interfaces_list (&process_interfaces, plugin);
+  plugin->hostname_dns = GNUNET_RESOLVER_hostname_resolve (env->sched,
+                                                           env->cfg,
+                                                           AF_UNSPEC,
+                                                           HOSTNAME_RESOLVE_TIMEOUT,
+                                                           &process_hostname_ips,
+                                                           plugin);
+
   udp_sock = udp_transport_server_start (plugin);
 
   GNUNET_assert (udp_sock != NULL);