struct GNUNET_NETWORK_Handle
{
+#ifndef MINGW
int fd;
+
+#else
+ SOCKET fd;
+#endif
+
+ /**
+ * Address family / domain.
+ */
+ int af;
};
{
/**
- * Maximum number of any socket socket descriptor in the set
+ * Maximum number of any socket socket descriptor in the set (plus one)
*/
int nsds;
#ifdef WINDOWS
/**
- * Linked list of handles
+ * Linked list of handles
*/
struct GNUNET_CONTAINER_SList *handles;
#endif
socket_set_inheritable (const struct GNUNET_NETWORK_Handle *h)
{
int i;
- i = fcntl (h->fd, F_GETFD);
+
+ i = fcntl (h->fd, F_GETFD);
+ if (i < 0)
+ return GNUNET_SYSERR;
if (i == (i | FD_CLOEXEC))
return GNUNET_OK;
- return (fcntl (h->fd, F_SETFD, i | FD_CLOEXEC) == 0)
- ? GNUNET_OK : GNUNET_SYSERR;
+ i |= FD_CLOEXEC;
+ if (fcntl (h->fd, F_SETFD, i) < 0)
+ return GNUNET_SYSERR;
+ return GNUNET_OK;
}
#endif
static void
socket_set_nosigpipe (const struct GNUNET_NETWORK_Handle *h)
{
- int value = 1;
+ int abs_value = 1;
if (0 !=
- setsockopt (h->fd, SOL_SOCKET, SO_NOSIGPIPE, &value, sizeof (value)))
+ setsockopt (h->fd, SOL_SOCKET, SO_NOSIGPIPE, &abs_value, sizeof (abs_value)))
GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "setsockopt");
}
#endif
static void
socket_set_nodelay (const struct GNUNET_NETWORK_Handle *h)
{
+#ifndef WINDOWS
int value = 1;
- if (0 !=
- setsockopt (h->fd, IPPROTO_TCP, TCP_NODELAY, &value, sizeof (value)))
+ if (0 != setsockopt (h->fd, IPPROTO_TCP, TCP_NODELAY, &value, sizeof (value)))
GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "setsockopt");
+#else
+ const char * abs_value = "1";
+ if (0 != setsockopt (h->fd, IPPROTO_TCP, TCP_NODELAY, abs_value, sizeof (abs_value)))
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "setsockopt");
+#endif
}
socklen_t * address_len)
{
struct GNUNET_NETWORK_Handle *ret;
+
ret = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle));
ret->fd = accept (desc->fd, address, address_len);
+ ret->af = address->sa_family;
if (ret->fd == INVALID_SOCKET)
{
#ifdef MINGW
#ifdef DARWIN
socket_set_nosigpipe (ret);
#endif
- socket_set_nodelay (ret);
+#ifdef AF_UNIX
+ if (address->sa_family != AF_UNIX)
+#endif
+ socket_set_nodelay (ret);
return ret;
}
socklen_t address_len)
{
int ret;
-
+
+#ifdef IPV6_V6ONLY
+#ifdef IPPROTO_IPV6
+ const int on = 1;
+ if (desc->af == AF_INET6)
+ if (0 != setsockopt (desc->fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof (on)))
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_DEBUG, "setsockopt");
+#if 0
+ /* is this needed or desired? or done elsewhere? */
+ if (0 != setsockopt (desc->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)))
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_DEBUG, "setsockopt");
+#endif
+#endif
+#endif
ret = bind (desc->fd, address, address_len);
#ifdef MINGW
if (SOCKET_ERROR == ret)
SetErrnoFromWinsockError (WSAGetLastError ());
+#else
+#ifndef LINUX
+ if ( (ret == 0) && (address->sa_family == AF_UNIX))
+ {
+ const struct sockaddr_un *un = (const struct sockaddr_un*) address;
+ if (0 != unlink (un->sun_path))
+ GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
+ "unlink",
+ un->sun_path);
+ }
+#endif
#endif
return ret == 0 ? GNUNET_OK : GNUNET_SYSERR;
}
GNUNET_NETWORK_socket_close (struct GNUNET_NETWORK_Handle *desc)
{
int ret;
- int eno;
#ifdef MINGW
ret = closesocket (desc->fd);
#else
ret = close (desc->fd);
#endif
- eno = errno;
GNUNET_free (desc);
- errno = eno;
return (ret == 0) ? GNUNET_OK : GNUNET_SYSERR;
}
+/**
+ * Box a native socket (and check that it is a socket).
+ *
+ * @param fd socket to box
+ * @return NULL on error (including not supported on target platform)
+ */
+struct GNUNET_NETWORK_Handle *
+GNUNET_NETWORK_socket_box_native (int fd)
+{
+#if MINGW
+ return NULL;
+#else
+ struct GNUNET_NETWORK_Handle *ret;
+
+ if (fcntl (fd, F_GETFD) < 0)
+ return NULL; /* invalid FD */
+ ret = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle));
+ ret->fd = fd;
+ ret->af = AF_UNSPEC;
+ return ret;
+#endif
+}
+
+
/**
* Connect a socket
* @param desc socket
* Returns GNUNET_NO if no data is available, or on error!
* @param desc socket
*/
-unsigned int
+ssize_t
GNUNET_NETWORK_socket_recvfrom_amount (const struct GNUNET_NETWORK_Handle
*desc)
{
int error;
- unsigned int pending;
/* How much is there to be read? */
+#ifndef WINDOWS
+ int pending;
error = ioctl (desc->fd, FIONREAD, &pending);
-
if (error == 0)
+#else
+ u_long pending;
+ error = ioctlsocket (desc->fd, FIONREAD, &pending);
+ if (error != SOCKET_ERROR)
+#endif
return pending;
else
return GNUNET_NO;
}
+
/**
* Read data from a connected socket (always non-blocking).
* @param desc socket
#ifdef MSG_DONTWAIT
flags |= MSG_DONTWAIT;
-#endif /* */
+#endif
ret = recvfrom (desc->fd, buffer, length, flags, src_addr, addrlen);
-
#ifdef MINGW
if (SOCKET_ERROR == ret)
SetErrnoFromWinsockError (WSAGetLastError ());
-
-#endif /* */
+#endif
return ret;
}
#ifdef MSG_DONTWAIT
flags |= MSG_DONTWAIT;
-
-#endif /* */
+#endif
ret = recv (desc->fd, buffer, length, flags);
-
#ifdef MINGW
if (SOCKET_ERROR == ret)
SetErrnoFromWinsockError (WSAGetLastError ());
-
-#endif /* */
+#endif
return ret;
}
{
struct GNUNET_NETWORK_Handle *ret;
ret = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle));
+ ret->af = domain;
ret->fd = socket (domain, type, protocol);
if (INVALID_SOCKET == ret->fd)
{
#ifdef DARWIN
socket_set_nosigpipe (ret);
#endif
- if (type == SOCK_STREAM)
+ if ( (type == SOCK_STREAM)
+#ifdef AF_UNIX
+ && (domain != AF_UNIX)
+#endif
+ )
socket_set_nodelay (ret);
return ret;
}
#endif
}
+
+/**
+ * Return file descriptor for this network handle
+ *
+ * @param desc wrapper to process
+ * @return POSIX file descriptor
+ */
int
GNUNET_NETWORK_get_fd (struct GNUNET_NETWORK_Handle *desc)
{
return desc->fd;
}
+
/**
* Copy a native fd set
*
to->nsds = nfds;
}
+
+/**
+ * Set a native fd in a set
+ *
+ * @param to destination
+ * @param nfd native FD to set
+ */
+void GNUNET_NETWORK_fdset_set_native (struct GNUNET_NETWORK_FDSet *to,
+ int nfd)
+{
+ GNUNET_assert(nfd >= 0);
+ FD_SET (nfd, &to->sds);
+ to->nsds = GNUNET_MAX (nfd + 1, to->nsds);
+}
+
+
+/**
+ * Test native fd in a set
+ *
+ * @param to set to test, NULL for empty set
+ * @param nfd native FD to test, or -1 for none
+ * @return GNUNET_YES if FD is set in the set
+ */
+int
+GNUNET_NETWORK_fdset_test_native (const struct GNUNET_NETWORK_FDSet *to,
+ int nfd)
+{
+ if ( (nfd == -1) || (to == NULL) )
+ return GNUNET_NO;
+ return FD_ISSET (nfd, &to->sds) ? GNUNET_YES : GNUNET_NO;
+}
+
+
/**
* Add a file handle to the fd set
* @param fds fd set
GNUNET_NETWORK_fdset_handle_set (struct GNUNET_NETWORK_FDSet *fds,
const struct GNUNET_DISK_FileHandle *h)
{
-
#ifdef MINGW
- HANDLE hw;
- GNUNET_DISK_internal_file_handle_ (h, &hw, sizeof (HANDLE));
GNUNET_CONTAINER_slist_add (fds->handles,
GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT,
- &hw, sizeof (HANDLE));
+ h, sizeof (struct GNUNET_DISK_FileHandle));
#else
int fd;
{
#ifdef MINGW
- return GNUNET_CONTAINER_slist_contains (fds->handles, &h->h,
- sizeof (HANDLE));
+ return GNUNET_CONTAINER_slist_contains (fds->handles, h,
+ sizeof (struct GNUNET_DISK_FileHandle));
#else
return FD_ISSET (h->fd, &fds->sds);
#endif
GNUNET_NETWORK_fdset_overlap (const struct GNUNET_NETWORK_FDSet *fds1,
const struct GNUNET_NETWORK_FDSet *fds2)
{
+#ifndef MINGW
int nfds;
+
nfds = fds1->nsds;
- if (nfds < fds2->nsds)
+ if (nfds > fds2->nsds)
nfds = fds2->nsds;
- for (; nfds >= 0; nfds--)
- if (FD_ISSET (nfds, &fds1->sds) && FD_ISSET (nfds, &fds2->sds))
- return GNUNET_YES;
-#ifdef MINGW
- {
- struct GNUNET_CONTAINER_SList_Iterator *it;
+ while (nfds > 0)
+ {
+ nfds--;
+ if (FD_ISSET (nfds, &fds1->sds) && FD_ISSET (nfds, &fds2->sds))
+ return GNUNET_YES;
+ }
+#else
+ struct GNUNET_CONTAINER_SList_Iterator *it;
+ struct GNUNET_DISK_FileHandle *h;
+ int i;
+ int j;
- for (it = GNUNET_CONTAINER_slist_begin (fds1->handles);
- GNUNET_CONTAINER_slist_end (it) != GNUNET_YES;
- GNUNET_CONTAINER_slist_next (it))
- {
- HANDLE *h;
-
- h = GNUNET_CONTAINER_slist_get (it, NULL);
- if (GNUNET_CONTAINER_slist_contains
- (fds2->handles, h, sizeof (HANDLE)))
- {
- GNUNET_CONTAINER_slist_iter_destroy (it);
- return GNUNET_YES;
- }
- }
- GNUNET_CONTAINER_slist_iter_destroy (it);
+ /*This code is somewhat hacky, we are not supposed to know what's
+ inside of fd_set; also the O(n^2) is really bad... */
+
+ for (i = 0; i < fds1->sds.fd_count; i++)
+ {
+ for (j = 0; j < fds2->sds.fd_count; j++)
+ {
+ if (fds1->sds.fd_array[i] == fds2->sds.fd_array[j])
+ return GNUNET_YES;
+ }
}
+ it = GNUNET_CONTAINER_slist_begin (fds1->handles);
+ while (GNUNET_CONTAINER_slist_end (it) != GNUNET_YES)
+ {
+ h = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (it, NULL);
+ if (GNUNET_CONTAINER_slist_contains
+ (fds2->handles, h, sizeof (struct GNUNET_DISK_FileHandle)))
+ {
+ GNUNET_CONTAINER_slist_iter_destroy (it);
+ return GNUNET_YES;
+ }
+ GNUNET_CONTAINER_slist_next (it);
+ }
+ GNUNET_CONTAINER_slist_iter_destroy (it);
#endif
return GNUNET_NO;
}
}
struct timeval tv;
- tv.tv_sec = timeout.value / GNUNET_TIME_UNIT_SECONDS.value;
+ tv.tv_sec = timeout.rel_value / GNUNET_TIME_UNIT_SECONDS.rel_value;
tv.tv_usec =
- 1000 * (timeout.value - (tv.tv_sec * GNUNET_TIME_UNIT_SECONDS.value));
- if ((nfds == 0) && (timeout.value == GNUNET_TIME_UNIT_FOREVER_REL.value)
+ 1000 * (timeout.rel_value - (tv.tv_sec * GNUNET_TIME_UNIT_SECONDS.rel_value));
+ if ((nfds == 0) && (timeout.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
#ifdef MINGW
&& handles == 0
#endif
GNUNET_break (0);
}
#ifndef MINGW
- return select (nfds + 1,
+ return select (nfds,
(rfds != NULL) ? &rfds->sds : NULL,
(wfds != NULL) ? &wfds->sds : NULL,
(efds != NULL) ? &efds->sds : NULL,
- (timeout.value == GNUNET_TIME_UNIT_FOREVER_REL.value)
+ (timeout.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
? NULL : &tv);
#else
#define SAFE_FD_ISSET(fd, set) (set != NULL && FD_ISSET(fd, set))
/* calculate how long we need to wait in milliseconds */
- if (timeout.value == GNUNET_TIME_UNIT_FOREVER_REL.value)
+ if (timeout.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
ms_total = INFINITE;
else
- ms_total = timeout.value / GNUNET_TIME_UNIT_MILLISECONDS.value;
+ ms_total = timeout.rel_value / GNUNET_TIME_UNIT_MILLISECONDS.rel_value;
/* select() may be used as a portable way to sleep */
if (!(rfds || wfds || efds))
GNUNET_CONTAINER_slist_next (i))
{
- HANDLE h;
+ struct GNUNET_DISK_FileHandle *fh;
DWORD dwBytes;
- h = *(HANDLE *) GNUNET_CONTAINER_slist_get (i, NULL);
- if (!PeekNamedPipe (h, NULL, 0, NULL, &dwBytes, NULL))
+ fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (i, NULL);
+ if (fh->type == GNUNET_PIPE)
{
- retcode = -1;
- SetErrnoFromWinError (GetLastError ());
-
-#if DEBUG_NETWORK
- GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
- "PeekNamedPipe");
+ if (!PeekNamedPipe (fh->h, NULL, 0, NULL, &dwBytes, NULL))
+ {
+ DWORD error_code = GetLastError ();
+ switch (error_code)
+ {
+ case ERROR_BROKEN_PIPE:
+ GNUNET_CONTAINER_slist_add (handles_read,
+ GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT,
+ fh, sizeof (struct GNUNET_DISK_FileHandle));
+ retcode++;
+ break;
+ default:
+ retcode = -1;
+ SetErrnoFromWinError (error_code);
+
+ #if DEBUG_NETWORK
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
+ "PeekNamedPipe");
+
+ #endif
+ goto select_loop_end;
+ }
+ }
+ else if (dwBytes)
-#endif
- goto select_loop_end;
+ {
+ GNUNET_CONTAINER_slist_add (handles_read,
+ GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT,
+ fh, sizeof (struct GNUNET_DISK_FileHandle));
+ retcode++;
+ }
}
- else if (dwBytes)
-
+ else
{
+ /* Should we wait for more bytes to read here (in case of previous EOF)? */
GNUNET_CONTAINER_slist_add (handles_read,
GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT,
- &h, sizeof (HANDLE));
- retcode++;
+ fh, sizeof (struct GNUNET_DISK_FileHandle));
}
}
GNUNET_CONTAINER_slist_iter_destroy (i);
GNUNET_CONTAINER_slist_next (i))
{
- HANDLE h;
+ struct GNUNET_DISK_FileHandle *fh;
DWORD dwBytes;
- h = *(HANDLE *) GNUNET_CONTAINER_slist_get (i, NULL);
- if (!PeekNamedPipe (h, NULL, 0, NULL, &dwBytes, NULL))
+ fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (i, NULL);
+ if (fh->type == GNUNET_PIPE)
{
- GNUNET_CONTAINER_slist_add (handles_except,
- GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT,
- &h, sizeof (HANDLE));
- retcode++;
+ if (!PeekNamedPipe (fh->h, NULL, 0, NULL, &dwBytes, NULL))
+
+ {
+ GNUNET_CONTAINER_slist_add (handles_except,
+ GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT,
+ fh, sizeof (struct GNUNET_DISK_FileHandle));
+ retcode++;
+ }
}
}
GNUNET_CONTAINER_slist_iter_destroy (i);
while (retcode == 0 && (ms_total == INFINITE || GetTickCount () < limit));
if (retcode != -1)
-
{
if (rfds)
-
{
GNUNET_NETWORK_fdset_zero (rfds);
GNUNET_NETWORK_fdset_copy_native (rfds, &aread, retcode);
GNUNET_CONTAINER_slist_clear (rfds->handles);
GNUNET_CONTAINER_slist_append (rfds->handles, handles_read);
-
}
if (wfds)
-
{
GNUNET_NETWORK_fdset_zero (wfds);
GNUNET_NETWORK_fdset_copy_native (wfds, &awrite, retcode);
GNUNET_CONTAINER_slist_append (wfds->handles, handles_write);
}
if (efds)
-
{
GNUNET_NETWORK_fdset_zero (efds);
GNUNET_NETWORK_fdset_copy_native (efds, &aexcept, retcode);