unload again
[oweals/gnunet.git] / src / util / network.c
index c10317258e081854e83c47853ed4394d69408dee..b5e65de60069ea5532610d93e6448dcded56a9a2 100644 (file)
 \r
 #define DEBUG_SOCK GNUNET_NO\r
 \r
+#ifndef INVALID_SOCKET\r
+#define INVALID_SOCKET -1\r
+#endif\r
+\r
 struct GNUNET_NETWORK_Handle\r
 {\r
   int fd;\r
@@ -51,6 +55,109 @@ struct GNUNET_NETWORK_FDSet
 #define FD_COPY(s, d) (memcpy ((d), (s), sizeof (fd_set)))\r
 #endif\r
 \r
+\r
+\r
+/**\r
+ * Set if a socket should use blocking or non-blocking IO.\r
+ * @param fd socket\r
+ * @param doBlock blocking mode\r
+ * @return GNUNET_OK on success, GNUNET_SYSERR on error\r
+ */\r
+static int\r
+socket_set_blocking (struct GNUNET_NETWORK_Handle *fd,\r
+                    int doBlock)\r
+{\r
+#if MINGW\r
+  u_long mode;\r
+  mode = !doBlock;\r
+  if (ioctlsocket (fd->fd, FIONBIO, &mode) == SOCKET_ERROR)\r
+    {\r
+      SetErrnoFromWinsockError (WSAGetLastError ());\r
+      GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "ioctlsocket");\r
+      return GNUNET_SYSERR;\r
+    }\r
+  return GNUNET_OK;\r
+\r
+#else\r
+  /* not MINGW */\r
+  int flags = fcntl (fd->fd, F_GETFL);\r
+  if (flags == -1)\r
+    {\r
+      GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "fcntl");\r
+      return GNUNET_SYSERR;\r
+    }\r
+  if (doBlock)\r
+    flags &= ~O_NONBLOCK;\r
+  else\r
+    flags |= O_NONBLOCK;\r
+  if (0 != fcntl (fd->fd, F_SETFL, flags))\r
+    {\r
+      GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "fcntl");\r
+      return GNUNET_SYSERR;\r
+    }\r
+  return GNUNET_OK;\r
+#endif\r
+}\r
+\r
+\r
+#ifndef MINGW\r
+/**\r
+ * Make a socket non-inheritable to child processes\r
+ *\r
+ * @param h the socket to make non-inheritable\r
+ * @return GNUNET_OK on success, GNUNET_SYSERR otherwise\r
+ * @warning Not implemented on Windows\r
+ */\r
+static int\r
+socket_set_inheritable (const struct GNUNET_NETWORK_Handle\r
+                                       *h)\r
+{\r
+  int i;\r
+\r
+  i = fcntl (h->fd, F_GETFD);\r
+  if (i == (i | FD_CLOEXEC))\r
+    return GNUNET_OK;\r
+  return (fcntl (h->fd, F_SETFD, i | FD_CLOEXEC) == 0)\r
+    ? GNUNET_OK : GNUNET_SYSERR;\r
+}\r
+#endif\r
+\r
+\r
+\r
+#ifdef DARWIN\r
+/**\r
+ * The MSG_NOSIGNAL equivalent on Mac OS X\r
+ *\r
+ * @param h the socket to make non-delaying\r
+ */\r
+static void\r
+socket_set_nosigpipe (const struct GNUNET_NETWORK_Handle\r
+                   *h)\r
+{\r
+  int value = 1;\r
+  setsockopt (h->fd, SOL_SOCKET, SO_NOSIGPIPE, &value, sizeof(value));\r
+}\r
+#endif\r
+\r
+\r
+\r
+/**\r
+ * Disable delays when sending data via the socket.\r
+ * (GNUnet makes sure that messages are as big as\r
+ * possible already).\r
+ *\r
+ * @param h the socket to make non-delaying\r
+ */\r
+static void\r
+socket_set_nodelay (const struct GNUNET_NETWORK_Handle\r
+                   *h)\r
+{\r
+  int value = 1;\r
+  setsockopt (h->fd, IPPROTO_TCP, TCP_NODELAY, &value, sizeof(value));\r
+}\r
+\r
+\r
+\r
 /**\r
  * accept a new connection on a socket\r
  *\r
@@ -68,10 +175,39 @@ GNUNET_NETWORK_socket_accept (const struct GNUNET_NETWORK_Handle *desc,
 \r
   ret = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle));\r
   ret->fd = accept (desc->fd, address, address_len);\r
+  if (ret->fd == INVALID_SOCKET)\r
+    {\r
 #ifdef MINGW\r
-  if (INVALID_SOCKET == ret->fd)\r
-    SetErrnoFromWinsockError (WSAGetLastError ());\r
+      SetErrnoFromWinsockError (WSAGetLastError ());\r
+#endif\r
+      GNUNET_free (ret);\r
+      return NULL;\r
+    }\r
+#ifndef MINGW\r
+  if (ret->fd >= FD_SETSIZE)\r
+    {\r
+      close (ret->fd);\r
+      GNUNET_free (ret);\r
+      errno = EMFILE;\r
+      return NULL;\r
+    }\r
 #endif\r
+  if (GNUNET_SYSERR == socket_set_blocking (ret, GNUNET_NO))\r
+    {\r
+      /* we might want to treat this one as fatal... */\r
+      GNUNET_break (0);\r
+      GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (ret));\r
+      return NULL; \r
+    }\r
+#ifndef MINGW\r
+  if (GNUNET_OK != socket_set_inheritable (ret))\r
+    GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,\r
+                        "socket_set_inheritable");\r
+#endif\r
+#ifdef DARWIN\r
+  socket_set_nosigpipe (ret);  \r
+#endif\r
+  socket_set_nodelay (ret);\r
   return ret;\r
 }\r
 \r
@@ -97,47 +233,6 @@ GNUNET_NETWORK_socket_bind (struct GNUNET_NETWORK_Handle *desc,
   return ret == 0 ? GNUNET_OK : GNUNET_SYSERR;\r
 }\r
 \r
-/**\r
- * Set if a socket should use blocking or non-blocking IO.\r
- * @param fd socket\r
- * @param doBlock blocking mode\r
- * @return GNUNET_OK on success, GNUNET_SYSERR on error\r
- */\r
-int\r
-GNUNET_NETWORK_socket_set_blocking (struct GNUNET_NETWORK_Handle *fd,\r
-                                    int doBlock)\r
-{\r
-#if MINGW\r
-  u_long mode;\r
-  mode = !doBlock;\r
-  if (ioctlsocket (fd->fd, FIONBIO, &mode) == SOCKET_ERROR)\r
-    {\r
-      SetErrnoFromWinsockError (WSAGetLastError ());\r
-      GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "ioctlsocket");\r
-      return GNUNET_SYSERR;\r
-    }\r
-  return GNUNET_OK;\r
-\r
-#else\r
-  /* not MINGW */\r
-  int flags = fcntl (fd->fd, F_GETFL);\r
-  if (flags == -1)\r
-    {\r
-      GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "fcntl");\r
-      return GNUNET_SYSERR;\r
-    }\r
-  if (doBlock)\r
-    flags &= ~O_NONBLOCK;\r
-  else\r
-    flags |= O_NONBLOCK;\r
-  if (0 != fcntl (fd->fd, F_SETFL, flags))\r
-    {\r
-      GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "fcntl");\r
-      return GNUNET_SYSERR;\r
-    }\r
-  return GNUNET_OK;\r
-#endif\r
-}\r
 \r
 /**\r
  * Close a socket\r
@@ -190,6 +285,7 @@ GNUNET_NETWORK_socket_connect (const struct GNUNET_NETWORK_Handle *desc,
 \r
 /**\r
  * Get socket options\r
+ *\r
  * @param desc socket\r
  * @param level protocol level of the option\r
  * @param optname identifier of the option\r
@@ -236,18 +332,22 @@ GNUNET_NETWORK_socket_listen (const struct GNUNET_NETWORK_Handle *desc,
 }\r
 \r
 /**\r
- * Read data from a connected socket\r
+ * Read data from a connected socket (always non-blocking).\r
  * @param desc socket\r
  * @param buffer buffer\r
  * @param length length of buffer\r
- * @param flags type of message reception\r
  */\r
 ssize_t\r
 GNUNET_NETWORK_socket_recv (const struct GNUNET_NETWORK_Handle * desc,\r
-                            void *buffer, size_t length, int flags)\r
+                            void *buffer, size_t length)\r
 {\r
   int ret;\r
+  int flags;\r
 \r
+  flags = 0;\r
+#ifdef MSG_DONTWAIT\r
+  flags |= MSG_DONTWAIT;\r
+#endif\r
   ret = recv (desc->fd, buffer, length, flags);\r
 #ifdef MINGW\r
   if (SOCKET_ERROR == ret)\r
@@ -258,19 +358,27 @@ GNUNET_NETWORK_socket_recv (const struct GNUNET_NETWORK_Handle * desc,
 }\r
 \r
 /**\r
- * Send data\r
+ * Send data (always non-blocking).\r
+ *\r
  * @param desc socket\r
  * @param buffer data to send\r
  * @param length size of the buffer\r
- * @param flags type of message transmission\r
  * @return number of bytes sent, GNUNET_SYSERR on error\r
  */\r
 ssize_t\r
 GNUNET_NETWORK_socket_send (const struct GNUNET_NETWORK_Handle * desc,\r
-                            const void *buffer, size_t length, int flags)\r
+                            const void *buffer, size_t length)\r
 {\r
   int ret;\r
+  int flags;\r
 \r
+  flags = 0;\r
+#ifdef MSG_DONTWAIT\r
+  flags |= MSG_DONTWAIT;\r
+#endif\r
+#ifdef MSG_NOSIGNAL\r
+  flags |= MSG_NOSIGNAL;\r
+#endif\r
   ret = send (desc->fd, buffer, length, flags);\r
 #ifdef MINGW\r
   if (SOCKET_ERROR == ret)\r
@@ -280,24 +388,34 @@ GNUNET_NETWORK_socket_send (const struct GNUNET_NETWORK_Handle * desc,
   return ret;\r
 }\r
 \r
+\r
 /**\r
- * Send data\r
+ * Send data to a particular destination (always non-blocking).\r
+ * This function only works for UDP sockets.\r
+ *\r
  * @param desc socket\r
  * @param message data to send\r
  * @param length size of the data\r
- * @param flags type of message transmission\r
  * @param dest_addr destination address\r
  * @param dest_len length of address\r
  * @return number of bytes sent, GNUNET_SYSERR on error\r
  */\r
 ssize_t\r
 GNUNET_NETWORK_socket_sendto (const struct GNUNET_NETWORK_Handle * desc,\r
-                              const void *message, size_t length, int flags,\r
+                              const void *message, size_t length,\r
                               const struct sockaddr * dest_addr,\r
                               socklen_t dest_len)\r
 {\r
   int ret;\r
+  int flags;\r
 \r
+  flags = 0;\r
+#ifdef MSG_DONTWAIT\r
+  flags |= MSG_DONTWAIT;\r
+#endif\r
+#ifdef MSG_NOSIGNAL\r
+  flags |= MSG_NOSIGNAL;\r
+#endif\r
   ret = sendto (desc->fd, message, length, flags, dest_addr, dest_len);\r
 #ifdef MINGW\r
   if (SOCKET_ERROR == ret)\r
@@ -333,30 +451,60 @@ GNUNET_NETWORK_socket_setsockopt (struct GNUNET_NETWORK_Handle *fd,
   return ret == 0 ? GNUNET_OK : GNUNET_SYSERR;\r
 }\r
 \r
+\r
+\r
 /**\r
- * Create a new socket\r
+ * Create a new socket.  Configure it for non-blocking IO and\r
+ * mark it as non-inheritable to child processes (set the\r
+ * close-on-exec flag).\r
+ *\r
  * @param domain domain of the socket\r
  * @param type socket type\r
  * @param protocol network protocol\r
  * @return new socket, NULL on error\r
  */\r
 struct GNUNET_NETWORK_Handle *\r
-GNUNET_NETWORK_socket_socket (int domain, int type, int protocol)\r
+GNUNET_NETWORK_socket_create (int domain, int type, int protocol)\r
 {\r
   struct GNUNET_NETWORK_Handle *ret;\r
 \r
   ret = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle));\r
   ret->fd = socket (domain, type, protocol);\r
-#ifdef MINGW\r
   if (INVALID_SOCKET == ret->fd)\r
-    SetErrnoFromWinsockError (WSAGetLastError ());\r
+    {\r
+#ifdef MINGW\r
+      SetErrnoFromWinsockError (WSAGetLastError ());\r
 #endif\r
-\r
-  if (ret->fd < 0)\r
+      GNUNET_free (ret);\r
+      return NULL;\r
+    }\r
+#ifndef MINGW\r
+  if (ret->fd >= FD_SETSIZE)\r
     {\r
+      close (ret->fd);\r
       GNUNET_free (ret);\r
-      ret = NULL;\r
+      errno = EMFILE;\r
+      return NULL;\r
     }\r
+#endif\r
+\r
+  if (GNUNET_SYSERR == socket_set_blocking (ret, GNUNET_NO))\r
+    {\r
+      /* we might want to treat this one as fatal... */\r
+      GNUNET_break (0);\r
+      GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (ret));\r
+      return NULL; \r
+    }\r
+#ifndef MINGW\r
+  if (GNUNET_OK != socket_set_inheritable (ret))\r
+    GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,\r
+                        "socket_set_inheritable");\r
+#endif\r
+#ifdef DARWIN\r
+  socket_set_nosigpipe (ret);  \r
+#endif\r
+  if (type == SOCK_STREAM)\r
+    socket_set_nodelay (ret);\r
 \r
   return ret;\r
 }\r
@@ -382,27 +530,6 @@ GNUNET_NETWORK_socket_shutdown (struct GNUNET_NETWORK_Handle *desc,
   return ret == 0 ? GNUNET_OK : GNUNET_SYSERR;\r
 }\r
 \r
-/**\r
- * Make a non-inheritable to child processes\r
- * @param socket\r
- * @return GNUNET_OK on success, GNUNET_SYSERR otherwise\r
- * @warning Not implemented on Windows\r
- */\r
-int\r
-GNUNET_NETWORK_socket_set_inheritable (const struct GNUNET_NETWORK_Handle\r
-                                       *desc)\r
-{\r
-#ifdef MINGW\r
-  errno = ENOSYS;\r
-  return GNUNET_SYSERR;\r
-#else\r
-  return fcntl (desc->fd, F_SETFD,\r
-                fcntl (desc->fd,\r
-                       F_GETFD) | FD_CLOEXEC) ==\r
-    0 ? GNUNET_OK : GNUNET_SYSERR;\r
-#endif\r
-}\r
-\r
 \r
 /**\r
  * Reset FD set\r