\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
#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
\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
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
\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
}\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
}\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
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
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
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