\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
fd_set sds;\r
#ifdef WINDOWS\r
/* handles */\r
- struct GNUNET_CONTAINER_Vector *handles;\r
+ struct GNUNET_CONTAINER_SList *handles;\r
#endif\r
};\r
\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
GNUNET_NETWORK_socket_close (struct GNUNET_NETWORK_Handle *desc)\r
{\r
int ret;\r
+ int eno;\r
+\r
#ifdef MINGW\r
ret = closesocket (desc->fd);\r
- if (SOCKET_ERROR != ret)\r
- GNUNET_free (desc);\r
- else\r
- SetErrnoFromWinsockError (WSAGetLastError ());\r
+ SetErrnoFromWinsockError (WSAGetLastError ()); \r
#else\r
ret = close (desc->fd);\r
- if (-1 == ret)\r
- {\r
- GNUNET_free (desc);\r
- }\r
-#endif\r
-\r
- return ret == 0 ? GNUNET_OK : GNUNET_SYSERR;\r
+#endif \r
+ eno = errno;\r
+ GNUNET_free (desc);\r
+ errno = eno;\r
+ return (ret == 0) ? GNUNET_OK : GNUNET_SYSERR;\r
}\r
\r
/**\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
FD_ZERO (&fds->sds);\r
fds->nsds = 0;\r
#ifdef MINGW\r
- if (fds->handles)\r
- GNUNET_CONTAINER_vector_destroy (fds->handles);\r
- fds->handles = GNUNET_CONTAINER_vector_create (2);\r
+ GNUNET_CONTAINER_slist_clear (fds->handles);\r
#endif\r
}\r
\r
FD_COPY (&from->sds, &to->sds);\r
to->nsds = from->nsds;\r
#ifdef MINGW\r
- void *obj;\r
+ struct GNUNET_CONTAINER_SList_Iterator *iter;\r
+\r
+\r
+ GNUNET_CONTAINER_slist_clear (to->handles);\r
\r
- if (to->handles)\r
- GNUNET_CONTAINER_vector_destroy (to->handles);\r
- to->handles = GNUNET_CONTAINER_vector_create (2);\r
- for (obj = GNUNET_CONTAINER_vector_get_first (from->handles); obj != NULL;\r
- obj = GNUNET_CONTAINER_vector_get_next (from->handles))\r
+ for (iter = GNUNET_CONTAINER_slist_begin (from->handles);\r
+ GNUNET_CONTAINER_slist_end (iter) != GNUNET_YES; GNUNET_CONTAINER_slist_next (iter))\r
{\r
- GNUNET_CONTAINER_vector_insert_last (to->handles, obj);\r
+ void *handle;\r
+ size_t len;\r
+\r
+ handle = GNUNET_CONTAINER_slist_get (iter, &len);\r
+ GNUNET_CONTAINER_slist_add (to->handles, GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT, handle, len);\r
}\r
#endif\r
}\r
#ifdef MINGW\r
HANDLE hw;\r
\r
- GNUNET_internal_disk_file_handle (h, &hw, sizeof (HANDLE));\r
- GNUNET_CONTAINER_vector_insert_last (fds->handles, h);\r
+ GNUNET_DISK_internal_file_handle_ (h, &hw, sizeof (HANDLE));\r
+ GNUNET_CONTAINER_slist_add (fds->handles, GNUNET_NO, &hw, sizeof (HANDLE));\r
#else\r
int fd;\r
\r
- GNUNET_internal_disk_file_handle (h, &fd, sizeof (int));\r
+ GNUNET_DISK_internal_file_handle_ (h, &fd, sizeof (int));\r
FD_SET (fd, &fds->sds);\r
if (fd + 1 > fds->nsds)\r
fds->nsds = fd + 1;\r
const struct GNUNET_DISK_FileHandle *h)\r
{\r
#ifdef MINGW\r
- return GNUNET_CONTAINER_vector_index_of (fds->handles, h->h) !=\r
- (unsigned int) -1;\r
+ return GNUNET_CONTAINER_slist_contains (fds->handles, h->h, sizeof (HANDLE));\r
#else\r
return FD_ISSET (h->fd, &fds->sds);\r
#endif\r
\r
fds = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_FDSet));\r
#ifdef MINGW\r
- fds->handles = NULL;\r
+ fds->handles = GNUNET_CONTAINER_slist_create ();\r
#endif\r
GNUNET_NETWORK_fdset_zero (fds);\r
-\r
return fds;\r
}\r
\r
GNUNET_NETWORK_fdset_destroy (struct GNUNET_NETWORK_FDSet *fds)\r
{\r
#ifdef MINGW\r
- GNUNET_CONTAINER_vector_destroy (fds->handles);\r
+ GNUNET_CONTAINER_slist_destroy (fds->handles);\r
#endif\r
GNUNET_free (fds);\r
}\r
\r
/* Poll read pipes */\r
if (rfds)\r
- for (i = GNUNET_CONTAINER_vector_size (rfds->handles) - 1; i >= 0; i--)\r
- {\r
- DWORD dwBytes;\r
-\r
- if (!PeekNamedPipe\r
- (GNUNET_CONTAINER_vector_get_at (rfds->handles, i), NULL, 0,\r
- NULL, &dwBytes, NULL))\r
- {\r
- GNUNET_CONTAINER_vector_remove_at (rfds->handles, i);\r
-\r
- retcode = -1;\r
- SetErrnoFromWinError (GetLastError ());\r
+ {\r
+ struct GNUNET_CONTAINER_SList_Iterator *i;\r
+ int on_next;\r
+\r
+ on_next = GNUNET_NO;\r
+ for (i = GNUNET_CONTAINER_slist_begin (rfds->handles);\r
+ GNUNET_CONTAINER_slist_end (i) != GNUNET_YES;\r
+ on_next || GNUNET_CONTAINER_slist_next (i))\r
+ {\r
+ HANDLE h;\r
+ DWORD dwBytes;\r
+\r
+ h = *(HANDLE *) GNUNET_CONTAINER_slist_get (i, NULL);\r
+ on_next = GNUNET_NO;\r
+\r
+ if (!PeekNamedPipe (h, NULL, 0, NULL, &dwBytes, NULL))\r
+ {\r
+ GNUNET_CONTAINER_slist_erase (i);\r
+ on_next = GNUNET_YES;\r
+\r
+ retcode = -1;\r
+ SetErrnoFromWinError (GetLastError ());\r
#if DEBUG_SOCK\r
- GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "PeekNamedPipe");\r
-#endif\r
- goto select_loop_end;\r
- }\r
- else if (dwBytes)\r
- {\r
- retcode++;\r
- }\r
- else\r
- GNUNET_CONTAINER_vector_remove_at (rfds->handles, i);\r
- }\r
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "PeekNamedPipe");\r
+#endif\r
+ goto select_loop_end;\r
+ }\r
+ else if (dwBytes)\r
+ {\r
+ retcode++;\r
+ }\r
+ else\r
+ {\r
+ GNUNET_CONTAINER_slist_erase (i);\r
+ on_next = GNUNET_YES;\r
+ }\r
+ }\r
+ }\r
\r
/* Poll for faulty pipes */\r
if (efds)\r
- for (i = GNUNET_CONTAINER_vector_size (efds->handles); i >= 0; i--)\r
- {\r
- DWORD dwBytes;\r
+ {\r
+ struct GNUNET_CONTAINER_SList_Iterator *i;\r
+ int on_next;\r
+\r
+ on_next = GNUNET_NO;\r
+ for (i = GNUNET_CONTAINER_slist_begin (efds->handles);\r
+ GNUNET_CONTAINER_slist_end (i) != GNUNET_YES;\r
+ on_next || GNUNET_CONTAINER_slist_next (i))\r
+ {\r
+ HANDLE h;\r
+ DWORD dwBytes;\r
+\r
+ h = *(HANDLE *) GNUNET_CONTAINER_slist_get (i, NULL);\r
\r
- if (PeekNamedPipe\r
- (GNUNET_CONTAINER_vector_get_at (rfds->handles, i), NULL, 0,\r
- NULL, &dwBytes, NULL))\r
- {\r
- GNUNET_CONTAINER_vector_remove_at (efds->handles, i);\r
+ if (PeekNamedPipe (h, NULL, 0, NULL, &dwBytes, NULL))\r
+ {\r
+ GNUNET_CONTAINER_slist_erase (i);\r
+ on_next = GNUNET_YES;\r
\r
- retcode++;\r
- }\r
- }\r
+ retcode++;\r
+ }\r
+ else\r
+ on_next = GNUNET_NO;\r
+ }\r
+ }\r
\r
/* FIXME */\r
if (wfds)\r
- GNUNET_assert (GNUNET_CONTAINER_vector_size (wfds->handles) == 0);\r
+ GNUNET_assert (GNUNET_CONTAINER_slist_count (wfds->handles) == 0);\r
\r
/* Check for closed sockets */\r
for (i = 0; i < nfds; i++)\r