stuff
[oweals/gnunet.git] / src / transport / plugin_transport_unix.c
index 0163a8e5b58c23da32af74641da614d49be687a6..2a7dc90650a1720654e3f50e87b837bf801ab5c8 100644 (file)
@@ -42,7 +42,8 @@
 #include "gnunet_transport_plugin.h"
 #include "transport.h"
 
-#define DEBUG_UNIX GNUNET_YES
+#define DEBUG_UNIX GNUNET_NO
+#define DETAILS GNUNET_NO
 
 #define MAX_PROBES 20
 
@@ -216,29 +217,6 @@ struct RetrySendContext
   struct RetryList *retry_list_entry;
 };
 
-/**
- * Local network addresses (actual unix path follows).
- */
-struct LocalAddrList
-{
-
-  /**
-   * This is a doubly linked list.
-   */
-  struct LocalAddrList *next;
-
-  /**
-   * This is a doubly linked list.
-   */
-  struct LocalAddrList *prev;
-
-  /**
-   * Number of bytes of the address that follow
-   */
-  size_t size;
-
-};
-
 
 /**
  * UNIX NAT "Session"
@@ -338,16 +316,6 @@ struct Plugin
    */
   uint16_t port;
 
-  /**
-   * List of our IP addresses.
-   */
-  struct LocalAddrList *lal_head;
-
-  /**
-   * Tail of our IP address list.
-   */
-  struct LocalAddrList *lal_tail;
-
   /**
    * FD Read set
    */
@@ -476,7 +444,7 @@ void retry_send_message (void *cls,
 {
   struct RetrySendContext *retry_ctx = cls;
 
-  if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
+  if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
     {
       GNUNET_free(retry_ctx->msg);
       GNUNET_free(retry_ctx->addr);
@@ -545,6 +513,7 @@ unix_real_send (void *cls,
   struct sockaddr_un un;
   size_t slen;
   struct RetryList *retry_list_entry;
+  int retry;
 
   if (send_handle == NULL)
     {
@@ -581,20 +550,57 @@ unix_real_send (void *cls,
   memset(&un, 0, sizeof(un));
   un.sun_family = AF_UNIX;
   slen = strlen (addr) + 1;
+  if (slen >= sizeof (un.sun_path))
+    slen = sizeof (un.sun_path) - 1;
   sent = 0;
   GNUNET_assert(slen < sizeof(un.sun_path));
   memcpy (un.sun_path, addr, slen);
   un.sun_path[slen] = '\0';
+  slen = sizeof (struct sockaddr_un);
 #if LINUX
   un.sun_path[0] = '\0';
 #endif
-  slen += sizeof (sa_family_t);
+#if HAVE_SOCKADDR_IN_SIN_LEN
+  un.sun_len = (u_char) slen;
+#endif
   sb = (struct sockaddr*) &un;
   sbs = slen;
+  retry = GNUNET_NO;
 
   sent = GNUNET_NETWORK_socket_sendto(send_handle, message, ssize, sb, sbs);
 
-  if (GNUNET_SYSERR == sent)
+  if ((GNUNET_SYSERR == sent) && (errno == EAGAIN))
+         retry = GNUNET_YES;
+
+  if ((GNUNET_SYSERR == sent) && (errno == EMSGSIZE))
+  {
+         socklen_t size = 0;
+         socklen_t len = sizeof (size);
+         GNUNET_NETWORK_socket_getsockopt ((struct GNUNET_NETWORK_Handle * ) send_handle,
+                         SOL_SOCKET,
+                         SO_SNDBUF,
+                         &size, &len);
+
+         if (size < ssize)
+         {
+#if DEBUG_UNIX
+          GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+             "Trying to increase socket buffer size from %i to %i for message size %i\n",
+             size,
+              ((ssize / 1000) + 2) * 1000, ssize);
+#endif
+                 size = ((ssize / 1000) + 2) * 1000;
+                 if (GNUNET_NETWORK_socket_setsockopt ((struct GNUNET_NETWORK_Handle * ) send_handle,
+                                 SOL_SOCKET,
+                                 SO_SNDBUF,
+                                 &size, sizeof(size)) == GNUNET_OK)
+                        retry = GNUNET_YES;
+                 else
+                        GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "setsockopt");
+         }
+  }
+
+  if (retry == GNUNET_YES)
     {
       if (incoming_retry_context == NULL)
         {
@@ -624,16 +630,8 @@ unix_real_send (void *cls,
           retry_ctx->delay = GNUNET_TIME_relative_multiply(retry_ctx->delay, 2);
         }
       retry_ctx->retry_task = GNUNET_SCHEDULER_add_delayed(retry_ctx->delay, &retry_send_message, retry_ctx);
-#if DETAILS
-      GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Error when trying to send %d byte message to %s\n", retry_ctx->msg_size, &un->sun_path[1]);
-      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                  "UNIX transmit %u-byte message to %s (%d: %s)\n",
-                  (unsigned int) ssize,
-                  GNUNET_a2s (sb, sbs),
-                  (int) sent,
-                  (sent < 0) ? STRERROR (errno) : "ok");
-#endif
-      GNUNET_log_strerror (GNUNET_ERROR_TYPE_DEBUG, "send");
+
+      //GNUNET_log_strerror (GNUNET_ERROR_TYPE_DEBUG, "send");
       GNUNET_free(message);
       return ssize;
     }
@@ -732,30 +730,6 @@ unix_plugin_send (void *cls,
 }
 
 
-static void
-add_to_address_list (struct Plugin *plugin,
-                    const void *arg,
-                    size_t arg_size)
-{
-  struct LocalAddrList *lal;
-
-  lal = plugin->lal_head;
-  while (NULL != lal)
-    {
-      if ( (lal->size == arg_size) &&
-          (0 == memcmp (&lal[1], arg, arg_size)) )
-       return;
-      lal = lal->next;
-    }
-  lal = GNUNET_malloc (sizeof (struct LocalAddrList) + arg_size);
-  lal->size = arg_size;
-  memcpy (&lal[1], arg, arg_size);
-  GNUNET_CONTAINER_DLL_insert (plugin->lal_head,
-                              plugin->lal_tail,
-                              lal);
-}
-
-
 /**
  * Demultiplexer for UNIX messages
  *
@@ -817,7 +791,7 @@ unix_plugin_select (void *cls,
   uint16_t csize;
 
   plugin->select_task = GNUNET_SCHEDULER_NO_TASK;
-  if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
+  if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
     return;
 
   addrlen = sizeof(un);
@@ -897,24 +871,26 @@ static int
 unix_transport_server_start (void *cls)
 {
   struct Plugin *plugin = cls;
-
   struct sockaddr *serverAddr;
   socklen_t addrlen;
-  int sockets_created;
   struct sockaddr_un un;
   size_t slen;
 
   memset(&un, 0, sizeof(un));
   un.sun_family = AF_UNIX;
   slen = strlen (plugin->unix_socket_path) + 1;
+  if (slen >= sizeof (un.sun_path))
+    slen = sizeof (un.sun_path) - 1;
 
-  GNUNET_assert(slen < sizeof(un.sun_path));
   memcpy (un.sun_path, plugin->unix_socket_path, slen);
   un.sun_path[slen] = '\0';
-  slen += sizeof (sa_family_t);
+  slen = sizeof (struct sockaddr_un);
+#if HAVE_SOCKADDR_IN_SIN_LEN
+  un.sun_len = (u_char) slen;
+#endif
+
   serverAddr = (struct sockaddr*) &un;
   addrlen = slen;
-  sockets_created = 0;
 #if LINUX
   un.sun_path[0] = '\0';
 #endif
@@ -922,24 +898,23 @@ unix_transport_server_start (void *cls)
   plugin->unix_sock.desc = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_DGRAM, 0);
   if (NULL == plugin->unix_sock.desc)
     {
-      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "socket");
+      GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
+      return GNUNET_SYSERR;
     }
-  else
+  if (GNUNET_NETWORK_socket_bind (plugin->unix_sock.desc, serverAddr, addrlen) !=
+      GNUNET_OK)
     {
-      if (GNUNET_NETWORK_socket_bind (plugin->unix_sock.desc, serverAddr, addrlen) !=
-            GNUNET_OK)
-       {
+      GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "bind");
+      GNUNET_NETWORK_socket_close (plugin->unix_sock.desc);
+      plugin->unix_sock.desc = NULL;
+      return GNUNET_SYSERR;
+    }
 #if DEBUG_UNIX
-         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                          "UNIX Binding failed!\n");
+  GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, 
+                  "unix",
+                  "Bound to `%s'\n",
+                  &un.sun_path[0]);
 #endif
-       }
-      else
-        GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Bound to `%s'\n", &un.sun_path[0]);
-      if (plugin->unix_sock.desc != NULL)
-        sockets_created++;
-    }
-
   plugin->rs = GNUNET_NETWORK_fdset_create ();
   GNUNET_NETWORK_fdset_zero (plugin->rs);
   GNUNET_NETWORK_fdset_set (plugin->rs,
@@ -950,7 +925,7 @@ unix_transport_server_start (void *cls)
                                  GNUNET_SCHEDULER_NO_TASK,
                                  GNUNET_TIME_UNIT_FOREVER_REL, plugin->rs,
                                  NULL, &unix_plugin_select, plugin);
-  return sockets_created;
+  return 1;
 }
 
 
@@ -1030,7 +1005,6 @@ unix_plugin_address_pretty_printer (void *cls,
                                    GNUNET_TRANSPORT_AddressStringCallback asc,
                                    void *asc_cls)
 {
-  struct Plugin *plugin = cls;
   struct PrettyPrinterContext *ppc;
   const void *sb;
   size_t sbs;
@@ -1075,8 +1049,7 @@ unix_plugin_address_pretty_printer (void *cls,
   ppc->asc = asc;
   ppc->asc_cls = asc_cls;
   ppc->port = port;
-  GNUNET_RESOLVER_hostname_get (plugin->env->cfg,
-                                sb,
+  GNUNET_RESOLVER_hostname_get (sb,
                                 sbs,
                                 !numeric, timeout, &append_port, ppc);
 }
@@ -1097,41 +1070,27 @@ unix_address_to_string (void *cls,
                        const void *addr,
                        size_t addrlen)
 {
-  static char rbuf[INET6_ADDRSTRLEN + 10];
-  char buf[INET6_ADDRSTRLEN];
-  const void *sb;
-  struct in_addr a4;
-  struct in6_addr a6;
-  const struct IPv4UdpAddress *t4;
-  const struct IPv6UdpAddress *t6;
-  int af;
-  uint16_t port;
-
-  if (addrlen == sizeof (struct IPv6UdpAddress))
-    {
-      t6 = addr;
-      af = AF_INET6;
-      port = ntohs (t6->u6_port);
-      memcpy (&a6, &t6->ipv6_addr, sizeof (a6));
-      sb = &a6;
-    }
-  else if (addrlen == sizeof (struct IPv4UdpAddress))
-    {
-      t4 = addr;
-      af = AF_INET;
-      port = ntohs (t4->u_port);
-      memcpy (&a4, &t4->ipv4_addr, sizeof (a4));
-      sb = &a4;
-    }
+  if ((addr != NULL) && (addrlen > 0))
+    return (const char *) addr;
   else
     return NULL;
-  inet_ntop (af, sb, buf, INET6_ADDRSTRLEN);
-  GNUNET_snprintf (rbuf,
-                   sizeof (rbuf),
-                   "%s:%u",
-                   buf,
-                   port);
-  return rbuf;
+}
+
+/**
+ * Notify transport service about address
+ *
+ * @param cls the plugin
+ * @param tc unused
+ */
+static void
+address_notification (void *cls,
+                    const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+  struct Plugin *plugin = cls;
+  plugin->env->notify_address(plugin->env->cls,
+                              GNUNET_YES,
+                              plugin->unix_socket_path,
+                              strlen(plugin->unix_socket_path) + 1);
 }
 
 /**
@@ -1153,22 +1112,13 @@ libgnunet_plugin_transport_unix_init (void *cls)
                                             "PORT",
                                             &port))
     port = UNIX_NAT_DEFAULT_PORT;
-  else if (port > 65535)
-    {
-      GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
-                  _("Given `%s' option is out of range: %llu > %u\n"),
-                  "PORT",
-                  port,
-                  65535);
-      return NULL;
-    }
-
-
   plugin = GNUNET_malloc (sizeof (struct Plugin));
   plugin->port = port;
   plugin->env = env;
-  GNUNET_asprintf(&plugin->unix_socket_path, "/tmp/unix-plugin-sock.%d", plugin->port);
-
+  GNUNET_asprintf (&plugin->unix_socket_path, 
+                  "/tmp/unix-plugin-sock.%d", 
+                  plugin->port);
+  
   api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions));
   api->cls = plugin;
 
@@ -1177,19 +1127,12 @@ libgnunet_plugin_transport_unix_init (void *cls)
   api->address_pretty_printer = &unix_plugin_address_pretty_printer;
   api->address_to_string = &unix_address_to_string;
   api->check_address = &unix_check_address;
-
-  add_to_address_list (plugin, plugin->unix_socket_path, strlen(plugin->unix_socket_path) + 1);
-
   sockets_created = unix_transport_server_start (plugin);
   if (sockets_created == 0)
     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
                _("Failed to open UNIX sockets\n"));
 
-  plugin->env->notify_address(plugin->env->cls,
-                              "unix",
-                              plugin->unix_socket_path,
-                              strlen(plugin->unix_socket_path) + 1,
-                              GNUNET_TIME_UNIT_FOREVER_REL);
+  GNUNET_SCHEDULER_add_now(address_notification, plugin);
   return api;
 }
 
@@ -1198,18 +1141,11 @@ libgnunet_plugin_transport_unix_done (void *cls)
 {
   struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
   struct Plugin *plugin = api->cls;
-  struct LocalAddrList *lal;
 
   unix_transport_server_stop (plugin);
 
   GNUNET_NETWORK_fdset_destroy (plugin->rs);
-  while (NULL != (lal = plugin->lal_head))
-    {
-      GNUNET_CONTAINER_DLL_remove (plugin->lal_head,
-                                  plugin->lal_tail,
-                                  lal);
-      GNUNET_free (lal);
-    }
+  GNUNET_free (plugin->unix_socket_path);
   GNUNET_free (plugin);
   GNUNET_free (api);
   return NULL;