View Issue Details

IDProjectCategoryView StatusLast Update
0001620GNUnetobsoletepublic2024-05-03 13:51
ReporterLRN Assigned ToNDurner  
PrioritynormalSeveritymajorReproducibilityN/A
Status closedResolutionfixed 
Product VersionGit master 
Summary0001620: poll() implementation for W32
DescriptionThe patch (attached) adds a poll() function, as well as a number of I/O routines that should be used with it. A simple testcase (for sockets) is also included.
Additional Information1) This is a preview. While it will apply to current SVN HEAD and should compile without problems, it doesn't really do anything (except allowing the test to pass), because GNUnet I/O code is not ported to use it.
2) No testcases for pipes yet.
3) Lots of FIXMEs. Some might be redundant.
4) Header layout is inherited from the original patch i wrote ~a year ago. I'm not sure yet which functions will go into public headers in src/include, and which will stay in w32io.h
5) GNUNET_new is purely cosmetic, if you won't accept it - that's fine
6) I'm always open for suggestions.

This patch will be required to solve 0001616 - it allows named pipes to be polled along with sockets and anonymous pipes (and disk files) in a single WaitForMultipleObjects() call. At the moment sockets and pipes are polled separately, and the wait is performed upon sockets only (i.e. no pipes will be polled until a wait on sockets succeeds or times out).
TagsNo tags attached.
Attached Files
0001-poll-implementation-for-W32.patch (101,602 bytes)   
From 2069a5fb31ede2f7f1129632f03b104b90a04bd7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=A0=D1=83=D1=81=D0=BB=D0=B0=D0=BD=20=D0=98=D0=B6=D0=B1=D1=83=D0=BB=D0=B0=D1=82=D0=BE=D0=B2?= <lrn1986@gmail.com>
Date: Thu, 18 Nov 2010 02:00:12 +0300
Subject: [PATCH] poll() implementation for W32

---
 src/include/gnunet_common.h |   12 +
 src/util/Makefile.am        |   11 +
 src/util/test_w32io.c       |  205 ++++
 src/util/w32io.c            | 2421 +++++++++++++++++++++++++++++++++++++++++++
 src/util/w32io.h            |  268 +++++
 5 files changed, 2917 insertions(+), 0 deletions(-)
 create mode 100644 src/util/test_w32io.c
 create mode 100644 src/util/w32io.c
 create mode 100644 src/util/w32io.h

diff --git a/src/include/gnunet_common.h b/src/include/gnunet_common.h
index badb528..c41e8d2 100644
--- a/src/include/gnunet_common.h
+++ b/src/include/gnunet_common.h
@@ -354,6 +354,18 @@ unsigned long long GNUNET_htonll (unsigned long long n);
 #define GNUNET_malloc(size) GNUNET_xmalloc_(size, __FILE__, __LINE__)
 
 /**
+ * Wrapper around malloc. Allocates enough memory to hold
+ * @number of variables if type @value_type.
+ * The memory will be zero'ed out.
+ *
+ * @param value_type the type to use for size calulations
+ * @param number the number of sizeof(@value_type)-sized chunks to
+ *     allocate. sizeof(@value_type) * @number must be less than 40 MB.
+ * @return pointer to size bytes of memory, never NULL (!)
+ */
+#define GNUNET_new(value_type, number) GNUNET_xmalloc_(sizeof(value_type)*number, __FILE__, __LINE__)
+
+/**
  * Wrapper around malloc. Allocates size bytes of memory.
  * The memory will be zero'ed out.
  *
diff --git a/src/util/Makefile.am b/src/util/Makefile.am
index 427ed25..b65d97b 100644
--- a/src/util/Makefile.am
+++ b/src/util/Makefile.am
@@ -6,8 +6,11 @@ if MINGW
 noinst_LTLIBRARIES = \
   libgnunetutilwin.la
 libgnunetutilwin_la_SOURCES = \
+  w32io.c \
+  w32io.h \
   win.cc \
   winproc.c
+WINTESTS = test_w32io
 libgnunetutilwin_la_LDFLAGS = \
   -Wl,--no-undefined -Wl,--export-all-symbols 
 libgnunetutilwin_la_LIBADD = \
@@ -108,6 +111,7 @@ libgnunet_plugin_test_la_LDFLAGS = \
  $(GN_PLUGIN_LDFLAGS)
 
 check_PROGRAMS = \
+ $(WINTESTS) \
  test_bio \
  test_client \
  test_common_allocation \
@@ -157,6 +161,13 @@ if !DISABLE_TEST_RUN
 TESTS = $(check_PROGRAMS)
 endif
 
+if MINGW
+test_w32io_SOURCES = \
+ test_w32io.c
+test_w32io_LDADD =\
+ $(top_builddir)/src/util/libgnunetutil.la
+endif
+
 test_bio_SOURCES = \
  test_bio.c
 test_bio_LDADD = \
diff --git a/src/util/test_w32io.c b/src/util/test_w32io.c
new file mode 100644
index 0000000..2c5a362
--- /dev/null
+++ b/src/util/test_w32io.c
@@ -0,0 +1,205 @@
+/*
+     This file is part of GNUnet.
+     (C) 2003, 2004, 2005, 2006, 2009 Christian Grothoff (and other contributing authors)
+
+     GNUnet is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+     Boston, MA 02111-1307, USA.
+*/
+/**
+ * @file util/test_w32io.c
+ * @brief testcase for util/w32io.c
+ */
+#include "platform.h"
+#include "gnunet_common.h"
+#include "gnunet_configuration_lib.h"
+#include "gnunet_os_lib.h"
+#include "w32io.h"
+
+#define VERBOSE GNUNET_NO
+
+#define PORT 56421
+
+SOCKET
+create_listening_socket ()
+{
+  struct sockaddr_in sa;
+  SOCKET s;
+  memset (&sa, 0, sizeof (sa));
+#if HAVE_SOCKADDR_IN_SIN_LEN
+  sa.sin_len = sizeof (sa);
+#endif
+  sa.sin_addr.s_addr = inet_addr("127.0.0.1");
+  sa.sin_port = htons (PORT);
+  sa.sin_family = AF_INET;
+
+  s = WSASocket (AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0);
+  GNUNET_assert (s != INVALID_SOCKET);
+  GNUNET_assert (bind (s, (struct sockaddr *) &sa, sizeof (sa)) == 0);
+  GNUNET_assert (listen (s, 5) == 0);
+  return s;
+}
+
+SOCKET
+create_connecting_socket ()
+{
+  SOCKET s;
+
+  s = WSASocket (AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0);
+  GNUNET_assert (s != INVALID_SOCKET);
+  return s;
+}
+
+
+static int
+test_socket_connect_server ()
+{
+  int r;
+  intptr_t sr;
+  struct sockaddr sa;
+  int sizeofsa = sizeof (sa);
+  struct W32PollFd server[2];
+  char buf[1024];
+  SOCKET a;
+  SOCKET s = create_listening_socket ();
+
+  server[0].fd = GNUNET_W32IO_fd_from_handle ((HANDLE) s, GNUNET_W32IO_SOCKET, GENERIC_READ | GENERIC_WRITE, 0, 0, 0);
+  GNUNET_assert (server[0].fd != NULL);
+
+  sr = spawnlp (_P_NOWAIT, "test_w32io.exe", "test_w32io.exe", "client", NULL);
+
+  server[0].fd->events = POLLIN | POLLOUT;
+  r = GNUNET_W32IO_ppoll (server, 1, NULL, NULL);
+  GNUNET_assert (r == 1);
+  GNUNET_assert (server[0].fd->revents & POLLIN);
+
+  a = GNUNET_W32IO_accept (server[0].fd, &sa, &sizeofsa);
+  GNUNET_assert (a != INVALID_SOCKET);
+
+  server[1].fd = GNUNET_W32IO_fd_from_handle ((HANDLE) a, GNUNET_W32IO_SOCKET, GENERIC_READ | GENERIC_WRITE, 1, 1, 0);
+  GNUNET_assert (server[1].fd != NULL);
+
+  server[0].fd->events = 0;
+  server[1].fd->events = POLLIN | POLLOUT;
+  r = GNUNET_W32IO_ppoll (server, 2, NULL, NULL);
+  GNUNET_assert (r == 1);
+  GNUNET_assert ((server[1].fd->revents & POLLOUT) && !(server[1].fd->revents & POLLIN));
+
+  r = GNUNET_W32IO_send (server[1].fd, "12345", 5, 0);
+
+  server[0].fd->events = 0;
+  server[1].fd->events = POLLIN;
+  r = GNUNET_W32IO_ppoll (server, 2, NULL, NULL);
+  GNUNET_assert (r == 1);
+  GNUNET_assert (!(server[1].fd->revents & POLLOUT) && (server[1].fd->revents & POLLIN));
+
+  r = GNUNET_W32IO_recv (server[1].fd, buf, 5, 0);
+
+  GNUNET_assert (buf[0] == '5' && buf[1] == '4' && buf[2] == '3' && buf[3] == '2' && buf[4] == '1');
+
+  server[0].fd->events = 0;
+  server[1].fd->events = POLLOUT;
+  r = GNUNET_W32IO_ppoll (server, 2, NULL, NULL);
+  GNUNET_assert (r == 1);
+  GNUNET_assert ((server[1].fd->revents & POLLOUT) && !(server[1].fd->revents & POLLIN));
+
+  r = GNUNET_W32IO_send (server[1].fd, "98765", 5, 0);
+
+  server[0].fd->events = 0;
+  server[1].fd->events = 0;
+  r = GNUNET_W32IO_ppoll (server, 2, NULL, NULL);
+  GNUNET_assert (r == 1);
+  GNUNET_assert (!(server[1].fd->revents & POLLOUT) && !(server[1].fd->revents & POLLIN) && (server[1].fd->revents & POLLHUP));
+
+  GNUNET_W32IO_close (server[0].fd, 1);
+  GNUNET_W32IO_close (server[1].fd, 1);
+  return 0;
+}
+
+static int
+test_socket_connect_client ()
+{
+  int r;
+  char buf[1024];
+  struct W32PollFd client;
+  struct sockaddr_in sa;
+  memset (&sa, 0, sizeof (sa));
+#if HAVE_SOCKADDR_IN_SIN_LEN
+  sa.sin_len = sizeof (sa);
+#endif
+  sa.sin_addr.s_addr = inet_addr("127.0.0.1");
+  sa.sin_port = htons (PORT);
+  sa.sin_family = AF_INET;
+
+
+  SOCKET s = create_connecting_socket ();
+
+  client.fd = GNUNET_W32IO_fd_from_handle ((HANDLE) s, GNUNET_W32IO_SOCKET, GENERIC_READ | GENERIC_WRITE, 0, 0, 0);
+  GNUNET_assert (client.fd != NULL);
+
+  GNUNET_W32IO_connect (client.fd, (struct sockaddr *) &sa, sizeof (sa));
+
+  client.fd->events = POLLOUT;
+  r = GNUNET_W32IO_ppoll (&client, 1, NULL, NULL);
+  GNUNET_assert (r == 1);
+  GNUNET_assert (client.fd->revents & POLLOUT);
+
+  client.fd->events = POLLIN;
+  r = GNUNET_W32IO_ppoll (&client, 1, NULL, NULL);
+  GNUNET_assert (r == 1);
+  GNUNET_assert (client.fd->revents & POLLIN);
+
+  GNUNET_W32IO_recv (client.fd, buf, 5, 0);
+  GNUNET_assert (buf[0] == '1' && buf[1] == '2' && buf[2] == '3' && buf[3] == '4' && buf[4] == '5');
+
+  client.fd->events = POLLIN | POLLOUT;
+  r = GNUNET_W32IO_ppoll (&client, 1, NULL, NULL);
+  GNUNET_assert (r == 1);
+  GNUNET_assert ((client.fd->revents & POLLOUT) && !(client.fd->revents & POLLIN));
+
+  GNUNET_W32IO_send (client.fd, "54321", 5, 0);
+
+  client.fd->events = POLLIN;
+  r = GNUNET_W32IO_ppoll (&client, 1, NULL, NULL);
+  GNUNET_assert (r == 1);
+  GNUNET_assert (!(client.fd->revents & POLLOUT) && (client.fd->revents & POLLIN));
+
+  GNUNET_W32IO_recv (client.fd, buf, 5, 0);
+  GNUNET_assert (buf[0] == '9' && buf[1] == '8' && buf[2] == '7' && buf[3] == '6' && buf[4] == '5');
+
+  GNUNET_W32IO_close (client.fd, 1);
+  return 0;
+}
+
+int
+main (int argc, char *argv[])
+{
+  int errCnt = 0;
+
+  GNUNET_log_setup ("test-w32io",
+#if VERBOSE
+     "DEBUG",
+#else
+     "WARNING",
+#endif
+      NULL);
+  if (argc < 2)
+  {
+    if (0 != test_socket_connect_server ())
+      errCnt++;
+  }
+  else if (0 != test_socket_connect_client ())
+    errCnt++;
+  return errCnt;
+}
diff --git a/src/util/w32io.c b/src/util/w32io.c
new file mode 100644
index 0000000..076abbb
--- /dev/null
+++ b/src/util/w32io.c
@@ -0,0 +1,2421 @@
+/*
+     This file is part of GNUnet.
+     (C) 2001, 2002, 2005, 2006, 2009, 2010 Christian Grothoff (and other contributing authors)
+
+     GNUnet is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published
+     by the Free Software Foundation; either version 2, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+     Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file util/w32io.c
+ * @brief POSIX-compatible I/O under NT
+ * @author LRN
+ */
+
+#include "platform.h"
+#include "gnunet_common.h"
+#include "w32io.h"
+
+#if WINDOWS
+
+void *
+GNUNET_W32IO_anonymous_pipe_thread_func (void *data);
+
+#define GNUNET_W32IO_PIPE_NAME_PREFIX "\\\\.\\pipe\\"
+
+#define SOCKET_POLL_EVENT POLLIN_BIT
+#define SOCKET_WAKEUP_EVENT POLLOUT_BIT
+#define ANON_PIPE_THREAD_POLL_EVENT POLLIN_BIT
+#define ANON_PIPE_MAIN_THREAD_POLL_EVENT POLLOUT_BIT
+#define ANON_PIPE_CLOSE_POLL_EVENT POLLHUP_BIT
+#define FILE_READY_POLL_EVENT POLLIN_BIT
+
+#define ZeroOverlappedExceptEvent(o) o.Internal = o.InternalHigh = o.Offset = o.OffsetHigh = 0
+
+void *
+GNUNET_memdup (void *src, size_t size)
+{
+  return memcpy (GNUNET_malloc (size), src, size);
+}
+
+
+HANDLE
+GNUNET_W32IO_fd_get_handle (struct W32Fd *fd)
+{
+  return fd->fd;
+}
+
+void
+GNUNET_W32IO_generate_random_local_pipe_name (char pipename[255])
+{
+  int i;
+  static DWORD seed = 0;
+  static float scale = 32767 / 25;
+  static int prefixlen = 9;
+  if (seed == 0)
+  {
+    seed = GetCurrentProcessId ();
+    srand (seed);
+  }
+  /* Uniqueness is not guaranteed - but we can always regenerate the name until
+   * it comes out to be unique.
+   */
+  memcpy (pipename, GNUNET_W32IO_PIPE_NAME_PREFIX, prefixlen);
+  for (i = prefixlen; i < 254; i++)
+  {
+    /* Get a random 0-32767 integer, then scale it to 65-90. This is not
+     * really a requirement - MSDN says that the only forbidden character
+     * for pipe names is the backslash. But i won't be taking any chances.
+     */
+    /* TODO: use RtlRandom() or RtlRandomEx() instead of rand() */
+    pipename[i] = 65 + (char) (rand() / scale);
+  }
+  pipename[254] = 0;
+}
+
+int
+GNUNET_W32IO_pipe (struct W32Fd *fd[2], int server_inheritable, int client_inheritable, DWORD server_mode, DWORD client_mode)
+{
+  char pipename[255];
+  SECURITY_ATTRIBUTES sa;
+  DWORD err;
+  BOOL bret;
+  OVERLAPPED ov;
+  HANDLE p[2];
+  p[0] = p[1] = NULL;
+  memset (&ov, 0, sizeof (ov));
+  while (!p[0])
+  {
+    sa.nLength = sizeof (sa);
+    sa.lpSecurityDescriptor = NULL;
+    sa.bInheritHandle = server_inheritable;
+    GNUNET_W32IO_generate_random_local_pipe_name (pipename);
+    /* FILE_FLAG_FIRST_PIPE_INSTANCE makes sure that we're first to create a
+     * pipe with such name.
+     * FILE_FLAG_OVERLAPPED creates async pipe. If the user wants to perform
+     * blocking I/O, we can easily create a blocking wrapper.
+     */
+    p[0] = CreateNamedPipeA ((LPCSTR) pipename, server_mode |
+        FILE_FLAG_FIRST_PIPE_INSTANCE | FILE_FLAG_OVERLAPPED |
+        PIPE_ACCESS_INBOUND, /*inbound access is necessary to read pipe info*/
+        PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
+        PIPE_UNLIMITED_INSTANCES, 4096, 4096, 0, &sa);
+    if (p[0] == INVALID_HANDLE_VALUE)
+    {
+      err = GetLastError ();
+      switch (err)
+      {
+        case ERROR_ACCESS_DENIED:
+          p[0] = NULL;
+          continue;
+      }
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to create a named pipe. GLE: %d\n", err);
+      return FALSE;
+    }
+  }
+  bret = ConnectNamedPipe (p[0], &ov);
+  if (bret == 0)
+  {
+    err = GetLastError ();
+    if (err == ERROR_IO_PENDING)
+    {
+      //It's ok, it works in the background while we finish other things
+    }
+    else if (err != ERROR_PIPE_CONNECTED)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to connect a named pipe. GLE: %d\n", err);
+      CloseHandle (p[0]);
+      return FALSE;
+    }
+  }
+  sa.nLength = sizeof (sa);
+  sa.lpSecurityDescriptor = NULL;
+  sa.bInheritHandle = client_inheritable;
+  p[1] = CreateFileA ((LPCSTR) pipename, client_mode, 0, &sa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED | FILE_READ_ATTRIBUTES, NULL);
+  if (p[1] == INVALID_HANDLE_VALUE)
+  {
+    err = GetLastError ();
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to open client side of a named pipe. GLE: %d\n", err);
+    CloseHandle(p[0]);
+    return FALSE;
+  }
+  //We've made both I/O calls, wait until the pipe is connected an opened
+  bret = GetOverlappedResult (p[0], &ov, &err, TRUE);
+
+  /* Both are not readable because we know that there is no data to read (yet).
+   * Write end is writable, because no writing is being done.
+   * Read end is, however, not writable, because it is read-only.
+   */
+  fd[0] = GNUNET_W32IO_fd_from_handle (p[0], GNUNET_W32IO_NAMED_PIPE, (server_mode & PIPE_ACCESS_OUTBOUND ? GENERIC_WRITE : 0) | (server_mode & PIPE_ACCESS_INBOUND ? GENERIC_READ : 0), TRUE, server_mode & PIPE_ACCESS_OUTBOUND, server_mode & PIPE_ACCESS_INBOUND);
+  fd[1] = GNUNET_W32IO_fd_from_handle (p[1], GNUNET_W32IO_NAMED_PIPE, (client_mode & GENERIC_READ ? GENERIC_READ : 0) | (client_mode & GENERIC_WRITE ? GENERIC_WRITE : 0), TRUE, client_mode & GENERIC_WRITE, client_mode & GENERIC_READ);
+
+  return TRUE;
+}
+
+int
+GNUNET_W32IO_anonymous_pipe (struct W32Fd *fd[2], int read_inheritable, int write_inheritable)
+{
+  int ret = TRUE;
+  BOOL bret;
+  DWORD err;
+  HANDLE p[2] = { 0, 0 };
+  SECURITY_ATTRIBUTES sa;
+  /* Mark handle as inheritable if at least one end must be inheritable */
+  int create_inheritance = read_inheritable || write_inheritable;
+
+  sa.nLength = sizeof (sa);
+  sa.lpSecurityDescriptor = NULL;
+  sa.bInheritHandle = create_inheritance;
+
+  bret = CreatePipe (&p[0], &p[1], &sa, 4096);
+  if (bret == 0)
+  {
+    err = GetLastError ();
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to create an anonymous pipe. GLE: %d\n", err);
+    ret = FALSE;
+  }
+  if (create_inheritance && !read_inheritable)
+  {
+    /* Desired read inheritance does not match create_inheritance */
+    HANDLE t = p[0];
+    bret = DuplicateHandle (GetCurrentProcess (), t, GetCurrentProcess (), &p[0],
+        0, read_inheritable, DUPLICATE_SAME_ACCESS);
+    if (bret == 0)
+    {
+      err = GetLastError ();
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to duplicate read end of an anonymous pipe. GLE: %d\n", err);
+      ret = FALSE;
+      p[0] = t;
+    }
+    else
+      CloseHandle (t);
+  }
+  if (create_inheritance && !write_inheritable)
+  {
+    /* Desired write inheritance does not match create_inheritance */
+    HANDLE t = p[1];
+    bret = DuplicateHandle (GetCurrentProcess (), t, GetCurrentProcess (), &p[1],
+        0, write_inheritable, DUPLICATE_SAME_ACCESS);
+    if (bret == 0)
+    {
+      err = GetLastError ();
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to duplicate write end of an anonymous pipe. GLE: %d\n", err);
+      ret = FALSE;
+      p[1] = t;
+    }
+    else
+      CloseHandle (t);
+  }
+
+  if (ret == FALSE)
+  {
+    if (p[0])
+      CloseHandle (p[0]);
+    if (p[1])
+      CloseHandle (p[1]);
+    return ret;
+  }
+
+  fd[0] = GNUNET_W32IO_fd_from_handle (p[0], GNUNET_W32IO_ANONYMOUS_PIPE, GENERIC_READ, TRUE, FALSE, TRUE);
+  fd[1] = GNUNET_W32IO_fd_from_handle (p[1], GNUNET_W32IO_ANONYMOUS_PIPE, GENERIC_WRITE, TRUE, TRUE, FALSE);
+
+  return ret;
+}
+
+int
+GNUNET_W32IO_fsync (struct W32Fd *wfd)
+{
+  if (wfd == NULL || wfd->fd == (void *) -1)
+  {
+    errno = EBADF;
+    return -1;
+  }
+
+  FlushFileBuffers (wfd->fd);
+  return 0;
+}
+
+int
+GNUNET_W32IO_close (struct W32Fd *wfd, int closehandle)
+{
+  int i;
+  DWORD dwresult;
+
+  int ret = 0;
+  if (wfd == NULL || wfd->fd == (void *) -1)
+    return ret;
+  switch (wfd->fd_type)
+  {
+  case GNUNET_W32IO_SOCKET:
+    /* Break the link between the socket and its event */
+    WSAEventSelect ((SOCKET) wfd->fd, NULL, 0);
+    ret = CloseHandle (wfd->overlapped[SOCKET_POLL_EVENT].hEvent);
+    ret = CloseHandle (wfd->overlapped[SOCKET_WAKEUP_EVENT].hEvent);
+    if (closehandle)
+    {
+      ret = ret || closesocket ((SOCKET) wfd->fd);
+    }
+    break;
+  case GNUNET_W32IO_FILE:
+  case GNUNET_W32IO_NAMED_PIPE:
+    for (i = 0; i < POLLLAST; i++)
+    {
+      if (wfd->overlapped[i].hEvent == INVALID_HANDLE_VALUE)
+        continue;
+
+      dwresult = WaitForSingleObject (wfd->overlapped[i].hEvent, 0);
+      if (dwresult == WAIT_TIMEOUT && (i == POLLIN_BIT || i == POLLOUT_BIT))
+      {
+        /* Disabled state of the event means that there is still an
+         * operation going on (event has to be reset manually and should
+         * stay signalled after I/O is complete until it is started again).
+         * Except for FD_CONNECT (it is unset after pipe is connected)
+         */
+        /* We're going to free the event. Have to cancel all I/O issued by
+         * this thread using this fd.
+         */
+        if (CancelIo (wfd->fd))
+        {
+          /* Wait until I/O is cancelled */
+          GetOverlappedResult (wfd->fd, &wfd->overlapped[i], &dwresult, TRUE);
+        }
+      }
+      ret = ret || CloseHandle (wfd->overlapped[i].hEvent);
+      wfd->overlapped[i].hEvent = NULL;
+    }
+
+    if (wfd->writebuffer)
+    {
+      GNUNET_free (wfd->writebuffer);
+      wfd->writebuffer = NULL;
+    }
+    if (closehandle)
+    {
+      if (wfd->fd_type == GNUNET_W32IO_NAMED_PIPE)
+        DisconnectNamedPipe (wfd->fd);
+      ret = ret || CloseHandle (wfd->fd);
+    }
+    break;
+  case GNUNET_W32IO_ANONYMOUS_PIPE:
+    /* FIXME: do the same as for named pipes - free events, etc */
+    ret = GNUNET_W32IO_anonymous_pipe_close (wfd);
+    if (closehandle)
+      ret = ret || CloseHandle (wfd->fd);
+    break;
+  default:
+    errno = ENOSYS;
+  }
+  GNUNET_free (wfd);
+  return ret;
+}
+
+int
+GNUNET_W32IO_ppoll (struct W32PollFd *fds, uint64_t nfds, const struct timespec *t, const sigset_t *sigmask)
+{
+  HANDLE *hEvents = NULL;
+  int eventCount = 0;
+  DWORD timeout = 0;
+  DWORD dwResult = 0;
+  DWORD wait_ret = 0;
+  DWORD dwError = 0;
+  int result = 0;
+  int any_errors = FALSE;
+  int i, j, k;
+  int repeat;
+  int hits = 0;
+
+  /* You *can't* get better than 1 millisecond resolution on Windows. */
+  if (t != NULL)
+    timeout = t->tv_sec * 1000 + t->tv_nsec / 1000000;
+  else
+    timeout = -1;
+
+  /* Special case for using ppoll() as a portable way tosleep */
+  if (nfds == 0)
+  {
+    SetLastError (0);
+    dwResult = WaitForSingleObject (GetCurrentProcess (), timeout == -1 ? INFINITE : timeout);
+    dwError = GetLastError ();
+    if (dwResult == WAIT_FAILED)
+    {
+      SetErrnoFromWinError (dwError);
+      result = -1;
+    }
+    return result;
+  }
+
+  /* Instead of counting or using dynamic memory allocation, we'll just
+   * allocate the amount that is guaranteed to cover our needs.
+   */
+  hEvents = GNUNET_new(HANDLE, nfds * (POLLLAST + 1));
+
+  repeat = 1;
+  while (repeat == 1)
+  {
+    DWORD time1, time2;
+    eventCount = 0;
+    dwResult = 0;
+    wait_ret = 0;
+    dwError = 0;
+    result = 0;
+    repeat = -1;
+    for (i = 0; i < nfds; i++)
+    {
+      j = GNUNET_W32IO_prepare_for_poll (&fds[i], &hEvents[eventCount]);
+    
+      if (eventCount + j - 1 >= nfds * (POLLLAST + 1) || j < 0)
+      {
+        GNUNET_free (hEvents);
+        return -1;
+      }
+      else
+        eventCount += j;
+    }
+  
+    SetLastError (0);
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+        "WaitForMultipleObjectsEx (%d, %x, FALSE, %d, FALSE)\n", eventCount,
+        hEvents, timeout == -1 ? INFINITE : timeout);
+    time1 = GetTickCount ();
+    dwResult = WaitForMultipleObjectsEx (eventCount, hEvents, FALSE,
+        timeout == -1 ? INFINITE : timeout, FALSE);
+    dwError = GetLastError ();
+    if ((dwResult < eventCount && dwError == NO_ERROR) || dwResult == WAIT_TIMEOUT)
+    {
+      for (i = 0; i < nfds; i++)
+      {
+        int selected = 0;
+        if (fds[i].fd->fd_type == GNUNET_W32IO_SOCKET)
+        {
+          int enumerated = 0;
+          for (j = 0; j < POLLLAST; j++)
+          {
+            if (fds[i].fd->overlapped[j].hEvent == INVALID_HANDLE_VALUE)
+              continue;
+  
+            wait_ret = WaitForSingleObject (fds[i].fd->overlapped[j].hEvent, 0);
+            if (wait_ret == WAIT_TIMEOUT)
+              continue;
+  
+            if ((j == SOCKET_POLL_EVENT || j == SOCKET_WAKEUP_EVENT))
+            {
+              WSANETWORKEVENTS events;
+              if (!enumerated)
+              {
+                enumerated = 1;
+                memset (&events, 0, sizeof (events));
+                int enum_ret = WSAEnumNetworkEvents ((SOCKET) fds[i].fd->fd, fds[i].fd->overlapped[SOCKET_POLL_EVENT].hEvent, &events);
+                if (enum_ret != 0) {
+                  dwError = GetLastError ();
+                  any_errors = TRUE;
+                  SetErrnoFromWinError (dwError);
+                  /* FIXME: make sure this is correct */
+                  if (dwError == WSAECONNRESET)
+                  {
+                    fds[i].fd->revents |= POLLHUP;
+                  }
+                  else
+                    fds[i].fd->revents |= POLLERR;
+                  break;
+                }
+                /* This way we won't lose one-time events. However, we also must
+                 * watch what we do with the socket and drop the bits from
+                 * lNetworkEvents when appropriate.
+                 */
+                fds[i].fd->wsaevents.lNetworkEvents |= events.lNetworkEvents;
+                for (k = 0; k < FD_MAX_EVENTS; k++)
+                {
+                  int bit = 1 << k;
+                  if (fds[i].fd->events & bit & fds[i].fd->wsaevents.lNetworkEvents)
+                  {
+                    fds[i].fd->revents |= bit;
+                    hits += 1;
+                    selected = 1;
+                    if (fds[i].fd->wsaevents.iErrorCode[k] != 0)
+                      fds[i].fd->revents |= POLLERR;
+                  }
+                }
+                if (fds[i].fd->revents & FD_CONNECT)
+                {
+                  fds[i].fd->revents &= ~FD_CONNECT;
+                  fds[i].fd->revents |= POLLOUT;
+                }
+                if (fds[i].fd->revents & FD_ACCEPT)
+                {
+                  fds[i].fd->revents &= ~FD_ACCEPT;
+                  fds[i].fd->revents |= POLLIN;
+                }
+                if (fds[i].fd->wsaevents.lNetworkEvents & FD_CLOSE)
+                {
+                  fds[i].fd->revents |= POLLHUP;
+                  fds[i].fd->revents &= ~POLLOUT;
+                  hits += 1;
+                  selected = 1;
+                }
+              }
+              if (j == SOCKET_WAKEUP_EVENT)
+                ResetEvent (fds[i].fd->overlapped[j].hEvent);
+            }
+            else
+            {
+              switch (j)
+              {
+              case POLLERR_BIT:
+              case POLLHUP_BIT:
+              case POLLNVAL_BIT:
+                fds[i].fd->revents |= 1 << j;
+                break;
+              default:
+                ;
+              }
+              ResetEvent (fds[i].fd->overlapped[j].hEvent);
+            }
+          }
+        }
+        else if (fds[i].fd->fd_type == GNUNET_W32IO_FILE)
+        {
+          /* TODO: better implementation (consider two processes sharing
+           * a file, both for reading and for writing; consider deleting
+           * a file while a process waits on it).
+           */
+          for (j = 0; j < POLLLAST; j++)
+          {
+            DWORD eventSet;
+            BOOL bret;
+            int bit = 1 << j;
+  
+            if (fds[i].fd->overlapped[j].hEvent == INVALID_HANDLE_VALUE)
+              continue;
+  
+            eventSet = 0;
+            eventSet = WaitForSingleObject (fds[i].fd->overlapped[j].hEvent, 0);
+            if (eventSet == WAIT_FAILED)
+            {
+              // FIXME: handle the error
+              any_errors = TRUE;
+              continue;
+            }
+            if (eventSet == WAIT_TIMEOUT)
+              continue;
+  
+            /* common code for all three events */          
+            bret = 0;
+            switch (j)
+            {
+            case POLLIN_BIT:
+            case POLLOUT_BIT:
+              fds[i].fd->revents |= bit;
+              fds[i].fd->wsaevents.lNetworkEvents |= bit;
+              fds[i].fd->wsaevents.iErrorCode[j] = 0;
+              /* If ReadFile returned immediately, won't GetOvelappedResult() block forever? */
+              /*
+              bret = GetOverlappedResult (fds[i].fd->fd,
+                  &fds[i].fd->overlapped[j], &wait_ret, TRUE);
+              */
+              selected = 1;
+              break;
+            case POLLERR_BIT:
+            case POLLNVAL_BIT:
+              fds[i].fd->wsaevents.iErrorCode[j] = fds[i].fd->dwerror;
+            default:
+              fds[i].fd->revents |= bit;
+              fds[i].fd->wsaevents.lNetworkEvents |= bit;
+            }
+  
+            switch (j)
+            {
+            case POLLIN_BIT:
+              /*
+              if (bret != 0)
+                break;
+  
+  
+              wait_ret = GetLastError ();
+              if (wait_ret == ERROR_HANDLE_EOF) {
+                fds[i].fd->revents &= ~FD_READ;
+                fds[i].fd->wsaevents.lNetworkEvents &= ~FD_READ;
+              } else {
+                any_errors = TRUE;
+                fds[i].fd->revents |= POLLERR;
+                fds[i].fd->wsaevents.iErrorCode[j] = wait_ret;
+                errno = gst_win32_error_to_errno(wait_ret);
+              }
+              */
+              break;
+            case POLLOUT_BIT:
+              if (fds[i].fd->writebuffer) {
+                GNUNET_free (fds[i].fd->writebuffer);
+                fds[i].fd->writebuffer = NULL;
+              }
+              /*
+              if (bret != 0)
+                break;
+  
+              wait_ret = GetLastError ();
+              if (wait_ret != NO_ERROR)
+              {
+                any_errors = TRUE;
+                fds[i].fd->revents |= POLLERR;
+                fds[i].fd->wsaevents.iErrorCode[j] = wait_ret;
+                errno = gst_win32_error_to_errno(wait_ret);
+              }
+              */
+              break;
+            default:
+              break;
+            }
+            ResetEvent (fds[i].fd->overlapped[j].hEvent);
+          }
+        }
+        else if (fds[i].fd->fd_type == GNUNET_W32IO_ANONYMOUS_PIPE)
+        {
+          for (j = 0; j < POLLLAST; j++)
+          {
+            DWORD eventSet;
+            BOOL bret;
+            int bit = 1 << j;
+  
+            if (fds[i].fd->overlapped[j].hEvent == INVALID_HANDLE_VALUE)
+              continue;
+  
+            if (j == POLLOUT_BIT && WaitForSingleObject (fds[i].fd->anon_thread_mutex, 0) == WAIT_OBJECT_0)
+            {
+              /* Writability is uncheckable and always assumed to be true whenever
+               * the pipe is not writing.
+               * POLLOUT event only indicates that a write operation is complete,
+               * but if no write operation took place, the code in the switch
+               * below will not be executed for POLLOUT, which is why this check
+               * is necessary.
+               */
+              if (fds[i].fd->writebuffer == NULL)
+              {
+                fds[i].fd->revents |= bit;
+                fds[i].fd->wsaevents.lNetworkEvents |= bit;
+                SetEvent (fds[i].fd->overlapped[POLLOUT_BIT].hEvent);
+              }
+              ReleaseMutex (fds[i].fd->anon_thread_mutex);
+            }
+  
+            eventSet = 0;
+            eventSet = WaitForSingleObject (fds[i].fd->overlapped[j].hEvent, 0);
+            if (eventSet == WAIT_FAILED)
+            {
+              /* FIXME: handle the error */
+              any_errors = TRUE;
+              continue;
+            }
+            if (eventSet == WAIT_TIMEOUT)
+              continue;
+            
+            /* common code for all three events */          
+            bret = 0;
+            switch (j)
+            {
+            case POLLIN_BIT:
+            case POLLOUT_BIT:
+            case POLLHUP_BIT:
+              fds[i].fd->revents |= bit;
+              fds[i].fd->wsaevents.lNetworkEvents |= bit;
+              fds[i].fd->wsaevents.iErrorCode[j] = 0;
+            
+              selected = 1;
+              WaitForSingleObject (fds[i].fd->anon_thread_mutex, INFINITE);
+              break;
+            case POLLERR_BIT:
+            case POLLNVAL_BIT:
+              fds[i].fd->wsaevents.iErrorCode[j] = fds[i].fd->dwerror;
+            default:
+              fds[i].fd->revents |= bit;
+              fds[i].fd->wsaevents.lNetworkEvents |= bit;
+            }
+            
+            switch (j)
+            {
+            case POLLIN_BIT:
+              if (fds[i].fd->dwerror == ERROR_BROKEN_PIPE) {
+                fds[i].fd->revents |= POLLHUP;
+                fds[i].fd->wsaevents.lNetworkEvents |= FD_CLOSE;
+            
+                SetEvent (fds[i].fd->overlapped[POLLHUP_BIT].hEvent);
+              } else if (fds[i].fd->dwerror != NO_ERROR) {
+                any_errors = TRUE;
+                fds[i].fd->revents |= POLLERR;
+                fds[i].fd->wsaevents.iErrorCode[j] = wait_ret;
+                SetErrnoFromWinError (fds[i].fd->dwerror);
+              }
+              break;
+            case POLLOUT_BIT:
+              if (fds[i].fd->writebuffer) {
+                GNUNET_free (fds[i].fd->writebuffer);
+                fds[i].fd->writebuffer = NULL;
+              }
+            
+              if (fds[i].fd->dwerror == ERROR_BROKEN_PIPE) {
+                fds[i].fd->revents |= POLLHUP;
+                fds[i].fd->wsaevents.lNetworkEvents |= FD_CLOSE;
+            
+                SetEvent (fds[i].fd->overlapped[POLLHUP_BIT].hEvent);
+              } else if (fds[i].fd->dwerror != NO_ERROR) {
+                any_errors = TRUE;
+                fds[i].fd->revents |= POLLERR;
+                fds[i].fd->wsaevents.iErrorCode[j] = fds[i].fd->dwerror;
+                SetErrnoFromWinError (fds[i].fd->dwerror);
+              }
+              break;
+            case POLLHUP_BIT:
+              if (!(fds[i].fd->events & (POLLIN | POLLOUT)))
+              {
+                if (fds[i].fd->dwerror == ERROR_BROKEN_PIPE)
+                {
+                  fds[i].fd->revents |= POLLHUP;
+                  fds[i].fd->wsaevents.lNetworkEvents |= FD_CLOSE;
+                } else if (fds[i].fd->dwerror == NO_ERROR) {
+                  /* FIXME: make sure this is the right way...
+                   * something might have set [POLLHUP_BIT].hEvent but not
+                   * the dwerror
+                   */
+                  ResetEvent (fds[i].fd->overlapped[POLLHUP_BIT].hEvent);
+                } else {
+                  any_errors = TRUE;
+                  fds[i].fd->revents |= POLLERR;
+                  fds[i].fd->wsaevents.iErrorCode[j] = fds[i].fd->dwerror;
+                  SetErrnoFromWinError (fds[i].fd->dwerror);
+                }
+              }
+              break;
+            default:
+              /* Never set */
+              break;
+            }
+            
+            switch (j)
+            {
+            case POLLIN_BIT:
+            case POLLOUT_BIT:
+            case POLLHUP_BIT:
+              ReleaseMutex (fds[i].fd->anon_thread_mutex);
+              break;
+            default:
+              ;
+            }
+            ResetEvent (fds[i].fd->overlapped[j].hEvent);
+          }
+        }
+        else if (fds[i].fd->fd_type == GNUNET_W32IO_NAMED_PIPE)
+        {
+          for (j = 0; j < POLLLAST; j++)
+          {
+            DWORD eventSet;
+            int bret;
+            int bit = 1 << j;
+  
+            if (fds[i].fd->overlapped[j].hEvent == INVALID_HANDLE_VALUE)
+              continue;
+  
+            if (j == POLLOUT_BIT)
+            {
+              if (fds[i].fd->writebuffer == NULL)
+              {
+                fds[i].fd->revents |= bit;
+                fds[i].fd->wsaevents.lNetworkEvents |= bit;
+                SetEvent (fds[i].fd->overlapped[POLLOUT_BIT].hEvent);
+              }
+            }
+  
+            eventSet = 0;
+            eventSet = WaitForSingleObject (fds[i].fd->overlapped[j].hEvent, 0);
+            if (eventSet == WAIT_FAILED)
+            {
+              /* FIXME: handle the error */
+              any_errors = TRUE;
+              continue;
+            }
+            if (eventSet == WAIT_TIMEOUT)
+              continue;
+            
+            /* common code for all three events */          
+            bret = 0;
+            switch (j)
+            {
+            case POLLIN_BIT:
+            case FD_CONNECT_BIT:
+            case POLLOUT_BIT:
+              fds[i].fd->revents |= bit;
+              fds[i].fd->wsaevents.lNetworkEvents |= bit;
+              fds[i].fd->wsaevents.iErrorCode[j] = 0;
+              bret = GetOverlappedResult (fds[i].fd->fd,
+                  &fds[i].fd->overlapped[j], &wait_ret, TRUE);
+              selected = 1;
+              break;
+            default:
+              ;
+            }
+            
+            switch (j)
+            {
+            case POLLIN_BIT:
+              /* Our read-zero-bytes operation is complete, which means that
+               * there is data to be read. Keep the event set. It will be
+               * unset by our read() implementation or by *_prepare_for_poll
+               */
+              if (bret != 0)
+                break;
+            
+              wait_ret = GetLastError ();
+              if (wait_ret == ERROR_BROKEN_PIPE) {
+                fds[i].fd->revents |= FD_CLOSE;
+                fds[i].fd->wsaevents.lNetworkEvents |= FD_CLOSE;
+            
+                SetEvent (fds[i].fd->overlapped[FD_CLOSE_BIT].hEvent);
+            
+                /* Set FD_CONNECT event so that we can attempt to connect again */
+                SetEvent (fds[i].fd->overlapped[FD_CONNECT_BIT].hEvent);
+              } else {
+                any_errors = TRUE;
+                fds[i].fd->revents |= POLLERR;
+                fds[i].fd->wsaevents.iErrorCode[j] = wait_ret;
+                SetErrnoFromWinError (wait_ret);
+              }
+              break;
+            case FD_CONNECT_BIT:
+              /* Our ConnectNamedPipe() operation is complete, which means that
+               * the pipe was not connected before, but is connected now.
+               */
+              /* Unset the event - that would prevent *_prepare_for_poll from
+               * trying to re-connect the pipe each time it is called.
+               */
+              ResetEvent (fds[i].fd->overlapped[j].hEvent);
+            
+              if (bret != 0)
+                break;
+            
+              wait_ret = GetLastError ();
+              if (wait_ret == ERROR_NO_DATA) {
+                fds[i].fd->revents |= FD_CLOSE;
+                fds[i].fd->wsaevents.lNetworkEvents |= FD_CLOSE;
+                SetEvent (fds[i].fd->overlapped[FD_CLOSE_BIT].hEvent);
+                SetEvent (fds[i].fd->overlapped[FD_CONNECT_BIT].hEvent);
+              } else {
+                any_errors = TRUE;
+                fds[i].fd->revents |= POLLERR;
+                fds[i].fd->wsaevents.iErrorCode[j] = wait_ret;
+                SetErrnoFromWinError (wait_ret);
+              }
+            
+              break;
+            case POLLOUT_BIT:
+              /* Our WriteFile() operation is complete, which means that the pipe
+               * is ready to write once more. Keep the event set - it will be
+               * unset by our write() implementation.
+               */
+              if (fds[i].fd->writebuffer) {
+                GNUNET_free (fds[i].fd->writebuffer);
+                fds[i].fd->writebuffer = NULL;
+              }
+            
+              if (bret != 0)
+                break;
+            
+              wait_ret = GetLastError ();
+              if (wait_ret == ERROR_BROKEN_PIPE) {
+                fds[i].fd->revents |= FD_CLOSE;
+                fds[i].fd->wsaevents.lNetworkEvents |= FD_CLOSE;
+            
+                SetEvent (fds[i].fd->overlapped[FD_CLOSE_BIT].hEvent);
+                SetEvent (fds[i].fd->overlapped[FD_CONNECT_BIT].hEvent);
+              } else {
+                any_errors = TRUE;
+                fds[i].fd->revents |= POLLERR;
+                fds[i].fd->wsaevents.iErrorCode[j] = wait_ret;
+                SetErrnoFromWinError (wait_ret);
+              }
+            
+              break;
+            case POLLHUP_BIT:
+              if (!(fds[i].fd->events & (POLLIN | POLLOUT)))
+              { 
+                if (!(fds[i].fd->revents & POLLHUP))
+                {
+                  bret = GetOverlappedResult (fds[i].fd->fd,
+                      &fds[i].fd->overlapped[POLLHUP_BIT], &wait_ret, TRUE);
+                  selected = 1;
+  
+                  wait_ret = GetLastError ();
+                  if (wait_ret != NO_ERROR)
+                  {
+                    fds[i].fd->revents |= POLLHUP_BIT;
+                    fds[i].fd->wsaevents.lNetworkEvents |= FD_CLOSE;
+                  } else {
+                    ResetEvent (fds[i].fd->overlapped[FD_CLOSE_BIT].hEvent);
+                    fds[i].fd->revents &= ~POLLHUP_BIT;
+                    fds[i].fd->wsaevents.lNetworkEvents &= ~FD_CLOSE;
+                  }
+                }
+                else
+                {
+                   selected = 1;
+                   fds[i].fd->revents |= POLLHUP;
+                   fds[i].fd->wsaevents.lNetworkEvents |= FD_CLOSE;
+                }
+              }
+              break;
+            default:
+              break;
+            }
+            ResetEvent (fds[i].fd->overlapped[j].hEvent);
+          }
+        }
+        if (fds[i].fd->fd_type != GNUNET_W32IO_SOCKET)
+          hits += 1;
+        result += selected;
+      }
+    }
+    else if (dwResult == WAIT_TIMEOUT)
+    {
+      /* result = 0; */
+    }
+    else if (dwResult == WAIT_FAILED)
+    {
+      SetErrnoFromWinError (dwError);
+      result = -1;
+    }
+    if (any_errors && result >= 0)
+    {
+      result = -1;
+    }
+    if (hits == 0)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Repeating ppoll()\n");
+      time2 = GetTickCount ();
+      if (timeout != (DWORD) -1)
+      {
+        DWORD new_timeout = timeout - time2 > time1 ? time2 - time1 : (0xFFFFFFFF - time1) + time2;
+        if (new_timeout > timeout)
+          timeout = -1;
+        else
+          timeout = new_timeout;
+      }
+      hits = 0;
+      repeat = 1;
+    }
+  }
+
+  GNUNET_free (hEvents);
+  return result;
+}
+
+/**
+ * Prepares @wpfd for polling
+ */
+int
+GNUNET_W32IO_prepare_for_poll (struct W32PollFd *wpfd, HANDLE *polllist)
+{
+  struct W32Fd *wfd = wpfd->fd;
+
+  int ret;
+  DWORD dwret;
+  int result = 0;
+  wfd->revents = 0;
+  if (wfd->fd_type == GNUNET_W32IO_SOCKET)
+  {
+    //DWORD sockevents = wfd->events & FD_ALL_EVENTS;
+    WSANETWORKEVENTS events;
+    int hits = 0;
+    memset (&events, 0, sizeof (events));
+    int enum_ret = WSAEnumNetworkEvents ((SOCKET) wfd->fd, wfd->overlapped[SOCKET_POLL_EVENT].hEvent, &events);
+    if (enum_ret != 0) {
+      DWORD dwError = GetLastError ();
+      SetErrnoFromWinError (dwError);
+      /* FIXME: make sure this is correct */
+      if (dwError == WSAECONNRESET)
+      {
+        wfd->wsaevents.lNetworkEvents |= FD_CLOSE;
+      }
+      else
+      {
+        /* FIXME: Not sure about this one. Not all errors lead to FD_CLOSE */
+        wfd->wsaevents.lNetworkEvents |= FD_CLOSE;
+        wfd->wsaevents.iErrorCode[FD_CLOSE] = dwError;
+      }
+    }
+    else
+    {
+      /* This way we won't lose one-time events. However, we also must
+       * watch what we do with the socket and drop the bits from
+       * lNetworkEvents when appropriate.
+       */
+      int k;
+      wfd->wsaevents.lNetworkEvents |= events.lNetworkEvents;
+      for (k = 0; k < FD_MAX_EVENTS; k++)
+      {
+        int bit = 1 << k;
+        if (wfd->events & bit & wfd->wsaevents.lNetworkEvents)
+        {
+          wfd->revents |= bit;
+          hits += 1;
+          if (wfd->wsaevents.iErrorCode[k] != 0)
+            wfd->revents |= POLLERR;
+        }
+      }
+      if (wfd->revents & FD_CONNECT)
+      {
+        wfd->revents &= ~FD_CONNECT;
+        wfd->revents |= POLLOUT;
+      }
+      if (wfd->revents & FD_ACCEPT)
+      {
+        wfd->revents &= ~FD_ACCEPT;
+        wfd->revents |= POLLIN;
+      }
+      if (wfd->wsaevents.lNetworkEvents & FD_CLOSE)
+      {
+        wfd->revents |= POLLHUP;
+        wfd->revents &= ~POLLOUT;
+        hits += 1;
+      }
+    }
+    if (hits > 0 || ((wfd->events & POLLOUT) && (wfd->wsaevents.lNetworkEvents & FD_WRITE)) || (wfd->wsaevents.lNetworkEvents & FD_CLOSE))
+      SetEvent (wfd->overlapped[SOCKET_WAKEUP_EVENT].hEvent);
+    polllist[result++] = wfd->overlapped[SOCKET_POLL_EVENT].hEvent;
+    polllist[result++] = wfd->overlapped[SOCKET_WAKEUP_EVENT].hEvent;
+    wfd->revents = 0;
+  }
+  else if (wfd->fd_type == GNUNET_W32IO_FILE)
+  {
+    /* Only POLLIN and POLLOUT are relevant for files
+     * Error conditions will be reported later on their own accord, we do not
+     * need event objects to detect these
+     */
+    wfd->events &= POLLIN | POLLOUT;
+
+    if (wfd->events & POLLIN || wfd->events & POLLOUT)
+    {
+      /* Ready to read/write unconditinally */
+      SetEvent (wfd->overlapped[FILE_READY_POLL_EVENT].hEvent);
+      polllist[result++] = wfd->overlapped[FILE_READY_POLL_EVENT].hEvent;
+    }
+    else
+      ResetEvent (wfd->overlapped[FILE_READY_POLL_EVENT].hEvent);
+    polllist[result++] = wfd->overlapped[POLLERR_BIT].hEvent;
+    polllist[result++] = wfd->overlapped[POLLNVAL_BIT].hEvent;
+  }
+  else if (wfd->fd_type == GNUNET_W32IO_ANONYMOUS_PIPE)
+  {
+    /* Anonymous pipes support only POLLIN and POLLOUT.
+     * Also don't poll for reading/writing on write-only/read-only pipes
+     */
+    wfd->events &= (wfd->access & GENERIC_READ ? POLLIN : 0) | (wfd->access & GENERIC_WRITE ? POLLOUT : 0);
+    if (wfd->events & POLLIN)
+    {
+      if (WaitForSingleObject (wfd->anon_thread_mutex, 0) == WAIT_OBJECT_0)
+      {
+        /* We've locked the mutex - which means that worker thread is not
+         * working at the moment.
+         */
+        /* Try to read 0 bytes from the pipe. This will enable the event
+         * when there is data to read.
+         */
+        /* Don't worry about the impossibility of polling for readability
+         * and writing simultaneously. Anonymous pipes are either write-only
+         * or read-only, so the application naturally shouldn't try to do
+         * both. If it does, the behaviour is... undefined.
+         */
+        wfd->work = 0; /* read */
+        wfd->readbuffer = NULL;
+        wfd->to_read = 0;
+
+        /* Working thread waits with WaitForMultipleObjects, so it will only
+         * wake up when the event is set AND the mutex is available.
+         */
+        SetEvent (wfd->overlapped[ANON_PIPE_THREAD_POLL_EVENT].hEvent);
+        ReleaseMutex (wfd->anon_thread_mutex);
+      }
+      /* Else worker thread is already working. Just as well */;
+
+      /* We will wait upon wfd->overlapped[ANON_PIPE_MAIN_THREAD_POLL_EVENT].hEvent. When it is enabled,
+       * the worker thread have completed its work and released the mutex,
+       * and we can obtain the data.
+       */
+      polllist[result++] = wfd->overlapped[ANON_PIPE_MAIN_THREAD_POLL_EVENT].hEvent;
+    }
+    if (wfd->events & POLLOUT)
+    {
+      /* We will wait upon wfd->overlapped[ANON_PIPE_MAIN_THREAD_POLL_EVENT].hEvent. When it is enabled,
+       * the worker thread have completed its work and released the mutex,
+       * and we can write once again.
+       */
+      polllist[result++] = wfd->overlapped[ANON_PIPE_MAIN_THREAD_POLL_EVENT].hEvent;
+    }
+    /* Read or write operations will reveal a broken pipe, but if we
+     * have neither, we have to do something to detect that.
+     */
+    if (!(wfd->events & FD_READ) && !(wfd->events & FD_WRITE) && WaitForSingleObject (wfd->anon_thread_mutex, 0) == WAIT_OBJECT_0)
+    {
+      if (wfd->access & GENERIC_READ)
+      {
+        /* Prefer reading */
+        wfd->work = 0; /* read */
+        wfd->readbuffer = GNUNET_malloc (1);
+        /* Try to read 1 byte from the pipe.
+         * If we succeed, we can give this byte later to the caller from
+         * the read() function. If we fail, we will know that the pipe
+         * is broken.
+         * Reading 0 bytes won't really let us detect a broken pipe.
+         */
+        wfd->to_read = 1;
+   
+        /* Working thread waits with WaitForMultipleObjects, so it will only
+         * wake up when the event is set AND the mutex is available.
+         */
+        SetEvent (wfd->overlapped[ANON_PIPE_THREAD_POLL_EVENT].hEvent);
+      }
+      else if (wfd->access & GENERIC_WRITE)
+      {
+        int skipwriting = FALSE;
+        if (wfd->writebuffer)
+        {
+          /* We've been writing somethings */
+          GNUNET_free (wfd->writebuffer);
+          wfd->writebuffer = NULL;
+      
+          /* Process any error conditions from previous write operation */
+          if (wfd->bret == 0)
+          {
+            SetEvent (wfd->overlapped[POLLHUP_BIT].hEvent);
+            skipwriting = TRUE;
+          }
+        }
+
+        /* Writing a byte into the pipe. BAD IDEA! Disabled. */
+        if (!skipwriting && 0)
+        {
+          wfd->work = 1; /* write */
+          wfd->writebuffer = GNUNET_malloc (1);
+          wfd->writebuffer[0] = 0;
+          wfd->to_write = 0;
+        
+          SetEvent (wfd->overlapped[ANON_PIPE_THREAD_POLL_EVENT].hEvent);
+        }
+      }
+      ReleaseMutex (wfd->anon_thread_mutex);
+      /* We will wait upon wfd->overlapped[POLLHUP_BIT].hEvent,
+       * which will be set by the working thread when the pipe breaks
+       */
+    }
+    polllist[result++] = wfd->overlapped[POLLERR_BIT].hEvent;
+    polllist[result++] = wfd->overlapped[POLLNVAL_BIT].hEvent;
+    polllist[result++] = wfd->overlapped[POLLHUP_BIT].hEvent;
+  }
+  else if (wfd->fd_type == GNUNET_W32IO_NAMED_PIPE)
+  {
+    /* POLLIN and POLLOUT might mean that the caller is interested in
+     * connection events, not reads/writes, so we won't check these
+     * against access
+     */
+    wfd->events &= POLLIN | POLLOUT;
+    if (wfd->events & (POLLIN | POLLOUT))
+    {
+      if (WaitForSingleObject (wfd->overlapped[FD_CONNECT_BIT].hEvent, 0) ==
+          WAIT_OBJECT_0)
+      {
+        /* Try to connect the pipe every time it is possible to do that.
+         * Most of the time it will return immediately with the
+         * ERROR_PIPE_CONNECTED error code to indicate that the pipe is
+         * already connected, else it will set the pipe working on
+         * becoming connected.
+         */
+        ZeroOverlappedExceptEvent(wfd->overlapped[FD_CONNECT_BIT]);
+        dwret = ConnectNamedPipe (wfd->fd, &wfd->overlapped[FD_CONNECT_BIT]);
+        if (dwret == 0)
+        {
+          dwret = GetLastError ();
+          if (dwret == ERROR_PIPE_CONNECTED ||
+              dwret == ERROR_INVALID_FUNCTION)
+          {
+            /* Already connected or we're using client end of the pipe.
+             * Disable the event to prevent further connection attempts.
+             */
+            ResetEvent (wfd->overlapped[FD_CONNECT_BIT].hEvent);
+          }
+          else
+          {
+            SetEvent (wfd->overlapped[POLLERR_BIT].hEvent);
+            wfd->dwerror = dwret;
+          }
+        }
+      }
+      polllist[result++] = wfd->overlapped[FD_CONNECT_BIT].hEvent;
+    }
+    if (wfd->events & POLLIN)
+    {
+      if (WaitForSingleObject (wfd->overlapped[POLLIN_BIT].hEvent, 0) ==
+          WAIT_OBJECT_0)
+      {
+        /* Try to read 0 bytes from the pipe. This will enable the event
+         * when there is data to read.
+         */
+        ZeroOverlappedExceptEvent(wfd->overlapped[POLLIN_BIT]);
+        dwret = ReadFile (wfd->fd, (void *) &wfd->to_read, 0,
+            NULL, &wfd->overlapped[POLLIN_BIT]);
+        if (dwret == 0)
+        {
+          dwret = GetLastError ();
+          if (dwret == ERROR_BROKEN_PIPE)
+          {
+            SetEvent (wfd->overlapped[POLLHUP_BIT].hEvent);
+          }
+          else if (dwret != ERROR_IO_PENDING)
+          {
+            SetEvent (wfd->overlapped[POLLERR_BIT].hEvent);
+            wfd->dwerror = dwret;
+          }
+        }
+      }
+      polllist[result++] = wfd->overlapped[POLLIN_BIT].hEvent;
+    }
+    /* There is no need to prepare for POLLOUT - underlying writing is
+     * asynchronous and is always available if there is no writing operations
+     * pending.
+     */
+    if (wfd->events & POLLOUT)
+    {
+      polllist[result++] = wfd->overlapped[POLLOUT_BIT].hEvent;
+    }
+    /* read or write operations will reveal a broken pipe, but if we
+     * have neither, we have to do something to detect that.
+     */
+    if (!(wfd->events & POLLIN) && !(wfd->events & POLLOUT))
+    {
+      if (wfd->access & GENERIC_READ)
+      {
+        /* Prefer reading */
+        if (WaitForSingleObject (wfd->overlapped[POLLIN_BIT].hEvent, 0) ==
+            WAIT_OBJECT_0)
+        {
+          /* Try to read 0 bytes from the pipe. This will enable the event
+           * when there is data to read.
+           */
+          ZeroOverlappedExceptEvent(wfd->overlapped[POLLIN_BIT]);
+          dwret = ReadFile (wfd->fd, (void *) &wfd->to_read, 0,
+              NULL, &wfd->overlapped[POLLIN_BIT]);
+          if (dwret == 0)
+          {
+            dwret = GetLastError ();
+            if (dwret == ERROR_BROKEN_PIPE)
+            {
+              SetEvent (wfd->overlapped[POLLHUP_BIT].hEvent);
+            }
+            else if (dwret != ERROR_IO_PENDING)
+            {
+              SetEvent (wfd->overlapped[POLLERR_BIT].hEvent);
+              wfd->dwerror = dwret;
+            }
+          } else {
+            ResetEvent (wfd->overlapped[POLLHUP_BIT].hEvent);
+          }
+        }
+      }
+      else if (wfd->access & GENERIC_WRITE && 0)
+      {
+        if (wfd->writebuffer != NULL)
+        {
+          if (WaitForSingleObject (wfd->overlapped[POLLOUT_BIT].hEvent, 0) ==
+              WAIT_OBJECT_0 &&
+              WaitForSingleObject (wfd->overlapped[POLLHUP_BIT].hEvent, 0) ==
+              WAIT_TIMEOUT)
+          {
+            /* Get the operation result, free the buffer */
+            DWORD wait_ret;
+            ret = GetOverlappedResult ((HANDLE) wfd->fd,
+                &wfd->overlapped[POLLOUT_BIT], &wait_ret, TRUE);
+            GNUNET_free (wfd->writebuffer);
+            wfd->writebuffer = NULL;
+          }
+        }
+        if (wfd->writebuffer == NULL)
+        {
+          ZeroOverlappedExceptEvent(wfd->overlapped[POLLOUT_BIT]);
+          BOOL bret = WriteFile ((HANDLE) wfd->fd, (void *) &wfd->to_write, 0, NULL,
+              &wfd->overlapped[POLLOUT_BIT]);
+          if (bret == 0) {
+            DWORD dwret = GetLastError ();
+            if (dwret != ERROR_IO_PENDING)
+            {
+              if (dwret == ERROR_BROKEN_PIPE)
+                SetEvent (wfd->overlapped[POLLHUP_BIT].hEvent);
+              else
+                SetEvent (wfd->overlapped[POLLERR_BIT].hEvent);
+            }
+          } else {
+            ResetEvent (wfd->overlapped[POLLHUP_BIT].hEvent);
+          }
+        }        
+      }
+    }
+    polllist[result++] = wfd->overlapped[POLLERR_BIT].hEvent;
+    polllist[result++] = wfd->overlapped[POLLNVAL_BIT].hEvent;
+    polllist[result++] = wfd->overlapped[POLLHUP_BIT].hEvent;
+  }
+
+  return result;
+}
+
+GNUNET_W32IO_HandleType
+GNUNET_W32IO_find_handle_type (HANDLE h)
+{
+  DWORD dwret, dwerr, dwret2, dwerr2;
+  WSAPROTOCOL_INFO pi;
+  dwret = GetFileType (h);
+  dwerr = GetLastError ();
+  switch (dwret) {
+  case FILE_TYPE_DISK:
+    return GNUNET_W32IO_FILE;
+  case FILE_TYPE_CHAR:
+    return GNUNET_W32IO_CONSOLE;
+  case FILE_TYPE_PIPE:
+    /* It's a socket or a pipe */
+    dwret2 = WSADuplicateSocket ((SOCKET) h, 0, &pi);
+    dwerr2 = GetLastError ();
+    if (dwret2 == 0) {
+      /* WSADuplicateSocket() should always fail when called with these
+       * arguments.
+       */
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "This should not happen\n");
+      return GNUNET_W32IO_UNSPECIFIED;
+    } else {
+      if (dwerr2 == WSAEINVAL) {
+        /* Definitely a socket */
+        return GNUNET_W32IO_SOCKET;
+      } else {
+        /* Not likely a socket. A pipe? */
+        dwret2 = GetNamedPipeInfo (h, NULL, NULL, NULL, NULL);
+        dwerr2 = GetLastError ();
+        if (dwret2 != 0) {
+          /* It's a kind of pipe */
+          dwret2 = GetNamedPipeHandleStateA (h, NULL, NULL, NULL,
+              NULL, NULL, 0);
+          dwerr2 = GetLastError ();
+          if (dwret2 == 0) {
+            if (dwerr2 == ERROR_INVALID_PARAMETER) {
+              /* It's an anonymous pipe */
+              return GNUNET_W32IO_ANONYMOUS_PIPE;
+            } else {
+              /* We have no idea what it is */
+              return GNUNET_W32IO_UNKNOWN;
+            }
+          } else {
+            /* It's a named pipe */
+            return GNUNET_W32IO_NAMED_PIPE;
+          }
+        } else {
+          /* If it was something other than a pipe, we would have found
+           * it by now, and now it's not even a pipe.
+           * It could be that this is a pipe, but damaged (or in a wrong
+           * state), or not a pipe at all.
+           */
+          return GNUNET_W32IO_UNKNOWN;
+        }
+      }
+    }
+    break;
+  case FILE_TYPE_UNKNOWN:
+  default:
+    if (dwerr == NO_ERROR)
+      return GNUNET_W32IO_UNKNOWN;
+    else
+      return GNUNET_W32IO_UNSPECIFIED;
+  }
+  return GNUNET_W32IO_UNSPECIFIED;
+}
+
+/**
+ * Allows us to create W32Fd from a HANDLE we've already got somewhere else.
+ * Will try to find the handle type on its own, or we can point it out.
+ *
+ * @param h handle
+ * @param htype type of the handle @h
+ * @param access access rights to the handle @h
+ * @param connected 1 if @h is connected, 0 otherwise
+ * @param writeable 1 if it is possible to write into @h without blocking, 0 otherwise
+ * @param readable 1 if it is possible to read from @h without blocking, 0 otherwise
+ */
+struct W32Fd *
+GNUNET_W32IO_fd_from_handle (HANDLE h, GNUNET_W32IO_HandleType htype, DWORD access,
+    int connected, int writeable, int readable)
+{
+  int i;
+  struct W32Fd *wfd = NULL;
+  DWORD error_code = 0;
+  BOOL bret = FALSE;
+
+  wfd = GNUNET_new(struct W32Fd, 1);
+
+  wfd->fd = h;
+  wfd->fd_type = htype;
+  if (htype == GNUNET_W32IO_UNSPECIFIED)
+    wfd->fd_type = GNUNET_W32IO_find_handle_type (h);
+
+  for (i = 0; i < POLLLAST; i++)
+    wfd->overlapped[i].hEvent = INVALID_HANDLE_VALUE;
+
+  wfd->anon_thread = INVALID_HANDLE_VALUE;
+  wfd->anon_thread_mutex = INVALID_HANDLE_VALUE;
+  wfd->work = -1;
+
+  switch (wfd->fd_type) {
+  case GNUNET_W32IO_UNSPECIFIED:
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Handle %p is of unspecified type\n", h);
+    goto error;
+    break;
+  case GNUNET_W32IO_UNKNOWN:
+    /* Failed to find the type - should not happen, unless we're
+     * feeding unexpected handles to the function.
+     */
+    /* A special hacky logic will allow us to create W32Fds with
+     * zero handles. They will have one valid event (like sockets do).
+     * This can be used for wakeup purposes, i hope.
+     */
+    /*
+     * I've trashed wakeup-event concept in favor of normal control socket
+     * read/write, so i'm not sure this hack is necessary (besides, i've
+     * never tried to actually use it).
+     */
+    /* wfd->overlapped[0].hEvent = CreateEvent (NULL, TRUE, FALSE, NULL); */
+    goto error;
+    break;
+  case GNUNET_W32IO_FILE:
+    for (i = 0; i < POLLLAST; i++) 
+    {
+      switch (i)
+      {
+      case FILE_READY_POLL_EVENT:
+      case POLLHUP_BIT:
+      case POLLERR_BIT:
+      case POLLNVAL_BIT:
+        SetLastError (0);
+        wfd->overlapped[i].hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
+        error_code = GetLastError ();
+        if (wfd->overlapped[i].hEvent == INVALID_HANDLE_VALUE || error_code != NO_ERROR)
+        {
+          GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "CreateEvent() returned %d. GLE: %d\n", wfd->overlapped[i].hEvent, error_code);
+          goto error;
+        }
+        break;
+      default:
+        break;
+      }
+    }
+    wfd->access = access;
+    break;
+  case GNUNET_W32IO_NAMED_PIPE:
+    for (i = 0; i < POLLLAST; i++) 
+    {
+      switch (i)
+      {
+      case POLLIN_BIT:
+      case POLLOUT_BIT:
+      case FD_CONNECT_BIT:
+      case POLLHUP_BIT:
+      case POLLERR_BIT:
+      case POLLNVAL_BIT:
+        SetLastError (0);
+        wfd->overlapped[i].hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
+        error_code = GetLastError ();
+        if (wfd->overlapped[i].hEvent == INVALID_HANDLE_VALUE || error_code != NO_ERROR)
+        {
+          GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "CreateEvent() returned %d. GLE: %d\n", wfd->overlapped[i].hEvent, error_code);
+          goto error;
+        }
+        break;
+      default:
+        break;
+      }
+    }
+    /* Enable the overlapped read/write events where applicable,
+     * indicating that a write/read operation is not in progress.
+     * Enable the connect overlapped event if the pipe is not connected,
+     * indicating that a connection attempt can be made.
+     */
+    if (!connected)
+    {
+      SetLastError (0);
+      bret = SetEvent (wfd->overlapped[FD_CONNECT_BIT].hEvent);
+      error_code = GetLastError ();
+      if (error_code != NO_ERROR || !bret)
+      {
+        GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "SetEvent() returned %d. GLE: %d\n", bret, error_code);
+        goto error;
+      }
+    }
+    else
+    {
+      if (writeable && (access & GENERIC_WRITE))
+      {
+        SetLastError (0);
+        bret = SetEvent (wfd->overlapped[POLLOUT_BIT].hEvent);
+        error_code = GetLastError ();
+        if (error_code != NO_ERROR || !bret)
+        {
+          GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "SetEvent() returned %d. GLE: %d\n", bret, error_code);
+          goto error;
+        }
+      }
+      if (readable && (access & GENERIC_READ))
+      {
+        SetLastError (0);
+        bret = SetEvent (wfd->overlapped[POLLIN_BIT].hEvent);
+        error_code = GetLastError ();
+        if (error_code != NO_ERROR || !bret)
+        {
+          GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "SetEvent() returned %d. GLE: %d\n", bret, error_code);
+          goto error;
+        }
+      }
+    }
+    wfd->access = access;
+    break;
+  case GNUNET_W32IO_ANONYMOUS_PIPE:
+    SetLastError (0);
+    wfd->anon_thread_mutex = CreateMutex (NULL, FALSE, NULL);
+    error_code = GetLastError ();
+    if (wfd->anon_thread_mutex == INVALID_HANDLE_VALUE || error_code != NO_ERROR)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "CreateMutex() returned %d. GLE: %d\n", wfd->anon_thread_mutex, error_code);
+      goto error;
+    }
+    for (i = 0; i < POLLLAST; i++) 
+    {
+      switch (i)
+      {
+      case ANON_PIPE_THREAD_POLL_EVENT:
+      case ANON_PIPE_MAIN_THREAD_POLL_EVENT:
+      case POLLHUP_BIT:
+      case POLLERR_BIT:
+      case POLLNVAL_BIT:
+        SetLastError (0);
+        wfd->overlapped[i].hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
+        error_code = GetLastError ();
+        if (wfd->overlapped[i].hEvent == INVALID_HANDLE_VALUE || error_code != NO_ERROR)
+        {
+          GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "CreateEvent() returned %d. GLE: %d\n", wfd->overlapped[i].hEvent, error_code);
+          goto error;
+        }
+        break;
+      default:
+        break;
+      }
+    }
+    wfd->alive = TRUE;
+    if ((writeable && (access & GENERIC_WRITE)) || (readable && (access & GENERIC_READ)))
+    {
+      SetLastError (0);
+      bret = SetEvent (wfd->overlapped[ANON_PIPE_MAIN_THREAD_POLL_EVENT].hEvent);
+      error_code = GetLastError ();
+      if (error_code != NO_ERROR || !bret)
+      {
+        GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "SetEvent() returned %d. GLE: %d\n", bret, error_code);
+        goto error;
+      }
+    }
+    wfd->access = access;
+    /* The thread will be stared immediately, and will go into wait upon
+     * the wfd->overlapped[ANON_PIPE_THREAD_POLL_EVENT].hEvent (which is
+     * disabled at creation) soon after that
+     */
+    SetLastError (0);
+    wfd->anon_thread = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE) &GNUNET_W32IO_anonymous_pipe_thread_func, (LPVOID) wfd, 0, &error_code);
+    error_code = GetLastError ();
+    if (wfd->anon_thread == INVALID_HANDLE_VALUE || error_code != NO_ERROR)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "CreateThread() returned %d. GLE: %d\n", wfd->anon_thread, error_code);
+      goto error;
+    }
+    break;
+  case GNUNET_W32IO_CONSOLE:
+    /* It's a console handle or a CRT file descriptor.
+     * FIXME: does it support async I/O? Use threads?
+     */
+    break;
+  case GNUNET_W32IO_SOCKET:
+    for (i = 0; i < POLLLAST; i++) 
+    {
+      switch (i)
+      {
+      case SOCKET_POLL_EVENT:
+      case SOCKET_WAKEUP_EVENT:
+      case POLLHUP_BIT:
+      case POLLERR_BIT:
+      case POLLNVAL_BIT:
+        SetLastError (0);
+        wfd->overlapped[i].hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
+        error_code = GetLastError ();
+        if (wfd->overlapped[i].hEvent == INVALID_HANDLE_VALUE || error_code != NO_ERROR)
+        {
+          GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "CreateEvent() returned %d. GLE: %d\n", wfd->overlapped[i].hEvent, error_code);
+          goto error;
+        }
+        break;
+      default:
+        break;
+      }
+      if (i == SOCKET_POLL_EVENT)
+      {
+        /* Bind wfd->overlapped[SOCKET_POLL_EVENT].hEvent object to the socket wfd->fd.
+         * It will be set when one of the events from sockevents occurrs
+         * This call clears internal socket event record in wfd->fd, so
+         * any one-time events (events that are recorded only once per
+         * occurrence) will be lost. To preserve them an internal event field
+         * in W32Fd is used.
+         */
+        SetLastError (0);
+        bret = WSAEventSelect ((SOCKET) wfd->fd, wfd->overlapped[SOCKET_POLL_EVENT].hEvent, FD_ALL_EVENTS);
+        error_code = GetLastError ();
+        if (bret != 0 || error_code != NO_ERROR)
+        {
+          GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "WSAEventSelect() returned %d. GLE: %d\n", bret, error_code);
+          goto error;
+        }
+      }
+    }
+    if (connected)
+    {
+      if (writeable && (access & GENERIC_WRITE))
+      {
+        wfd->wsaevents.lNetworkEvents |= FD_WRITE;
+        SetEvent (wfd->overlapped[SOCKET_WAKEUP_EVENT].hEvent);
+      }
+      if (readable && (access & GENERIC_READ))
+      {
+        wfd->wsaevents.lNetworkEvents |= FD_READ;
+        SetEvent (wfd->overlapped[SOCKET_WAKEUP_EVENT].hEvent);
+      }
+    }
+    wfd->access = access;
+    break;
+  default:
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Wrong value returned from GNUNET_W32IO_find_handle_type()\n");
+    goto error;
+  }
+  goto end;
+error:
+  for (i = 0; i < POLLLAST; i++)
+    if (wfd->overlapped[i].hEvent != INVALID_HANDLE_VALUE)  
+      CloseHandle (wfd->overlapped[i].hEvent);
+  if (wfd->anon_thread != INVALID_HANDLE_VALUE)
+    CloseHandle (wfd->anon_thread);
+  if (wfd->anon_thread_mutex != INVALID_HANDLE_VALUE)
+    CloseHandle (wfd->anon_thread_mutex);
+  GNUNET_free (wfd);
+  wfd = NULL;
+end:
+  return wfd;
+}
+
+int
+GNUNET_W32IO_read_async_named_pipe (struct W32Fd *fd, char *in, size_t to_read)
+{
+  BOOL bret;
+  DWORD dwret;
+  int ret = to_read;
+  while (to_read > 0) {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ReadFile (%x, in, %d, &dwret, &fd->overlapped[POLLIN_BIT]);\n", fd->fd, to_read);
+    ZeroOverlappedExceptEvent(fd->overlapped[POLLIN_BIT]);
+    bret = ReadFile (fd->fd, in, to_read, &dwret,
+        &fd->overlapped[POLLIN_BIT]);
+    if (bret == 0)
+    {
+      dwret = GetLastError ();
+      if (dwret == ERROR_BROKEN_PIPE) {
+        errno = EPIPE;
+        SetEvent (fd->overlapped[POLLHUP_BIT].hEvent);
+        return -1;
+      }
+
+      /* TODO: figure out when it is appropriate to enable [POLLERR_BIT].hEvent */
+      if (dwret != ERROR_IO_PENDING)
+        goto error_and_fail;
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "WaitForSingleObject (%x, INFINITE);\n", fd->overlapped[POLLIN_BIT].hEvent);
+      dwret = WaitForSingleObject (fd->overlapped[POLLIN_BIT].hEvent,
+          INFINITE);
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "done\n");
+      if (dwret != WAIT_OBJECT_0)
+      {
+        dwret = GetLastError ();
+        goto error_and_fail;
+      }
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "GetOverlappedResult (%x, &fd->overlapped[POLLIN_BIT], &dwret, TRUE);\n", fd->fd);
+      bret = GetOverlappedResult ((HANDLE) fd->fd,
+          &fd->overlapped[POLLIN_BIT], &dwret, TRUE);
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got it\n");
+      if (bret == 0)
+      {
+        dwret = GetLastError ();
+        goto error_and_fail;
+      }
+    }
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Read %d bytes\n", dwret);
+    to_read -= dwret;
+    in += dwret;
+  }
+#if 0
+  /* If can't peek or pipe is empty - mark the pipe as unreadable.
+   * This will only affect the application if it actually checks fd for
+   * readability. It won't prevent subsequent calls to _read() from blocking.
+   */
+  if (!PeekNamedPipe ((HANDLE) fd->fd, NULL, 0, 0, &dwret, NULL) || !dwret) {
+    fd->revents &= ~FD_READ;
+    fd->wsaevents.lNetworkEvents &= ~FD_READ;
+  }
+#endif
+  return ret;
+
+error_and_fail:
+  GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to read\n");
+  SetErrnoFromWinError (dwret);
+  return -1;
+}
+
+int
+GNUNET_W32IO_write_async_named_pipe (struct W32Fd *fd, char *out, size_t to_write)
+{
+  BOOL bret;
+  DWORD dwret;
+  DWORD ret;
+
+  /* writebuffer isn't NULL -> there's a writing operation going on */
+  if (fd->writebuffer != NULL) {
+    /* Wait until event is set (meaning that operation is complete).
+     * This might block for a while (until the other end reads), that is - 
+     * you can't have more than one writing operation working at one pipe.
+     * This is somewhat mitigated by the pipe buffer (which is better be > 0).
+     * TODO: implement multiple buffering, so that it is possible to write
+     * more than once (especially if we're talking about writing small
+     * amounts of data multiple times).
+     */
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "WaitForSingleObject (%x, INFINITE);\n", fd->overlapped[POLLOUT_BIT].hEvent);
+    if (WaitForSingleObject (fd->overlapped[POLLOUT_BIT].hEvent, INFINITE) ==
+        WAIT_OBJECT_0)
+    {
+      /* Get the operation result, free the buffer */
+      DWORD wait_ret;
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "GetOverlappedResult (%x, %x, %x, TRUE);\n", fd->fd, &fd->overlapped[POLLOUT_BIT], &wait_ret);
+      ret = GetOverlappedResult ((HANDLE) fd->fd,
+          &fd->overlapped[POLLOUT_BIT], &wait_ret, TRUE);
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got it\n");
+      if (fd->writebuffer) {
+        GNUNET_free (fd->writebuffer);
+        fd->writebuffer = NULL;
+      }
+
+      if (ret == 0) {
+        errno = EIO;
+        return -1;
+      }
+    }
+  }
+
+  if (out)
+    fd->writebuffer = (char *) GNUNET_memdup (out, to_write);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "WriteFile (%x, %x, %d, NULL, %x);\n", fd->fd, fd->writebuffer, to_write, &fd->overlapped[POLLOUT_BIT]);
+  ZeroOverlappedExceptEvent(fd->overlapped[POLLOUT_BIT]);
+  bret = WriteFile ((HANDLE) fd->fd, fd->writebuffer, to_write, NULL,
+      &fd->overlapped[POLLOUT_BIT]);
+  if (bret == 0) {
+    dwret = GetLastError ();
+    if (dwret != ERROR_IO_PENDING)
+      goto error_and_fail;
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Wrote into heap buffer\n");
+  } else {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Wrote into kernel buffer\n");
+    GNUNET_free (fd->writebuffer);
+    fd->writebuffer = NULL;
+  }
+  return to_write;
+
+error_and_fail:
+  GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to write\n");
+  GNUNET_free (fd->writebuffer);
+  fd->writebuffer = NULL;
+  SetErrnoFromWinError (dwret);
+  return -1;
+}
+
+int
+GNUNET_W32IO_read (struct W32Fd *ifd, char *in, size_t to_read)
+{
+  switch (ifd->fd_type)
+  {
+  case GNUNET_W32IO_NAMED_PIPE:
+      /* Do not check whether the pipe is readable or not. If it isn't, it will
+       * block anyway.
+       */
+    return GNUNET_W32IO_read_async_named_pipe (ifd, in, to_read);
+    break;
+  case GNUNET_W32IO_FILE:
+    return GNUNET_W32IO_read_file (ifd, in, to_read);
+    break;
+  case GNUNET_W32IO_SOCKET:
+    return GNUNET_W32IO_recv (ifd, in, to_read, 0);
+  case GNUNET_W32IO_ANONYMOUS_PIPE:
+    return GNUNET_W32IO_anonymous_pipe_read (ifd, in, to_read);
+  default:
+    return 0;
+    /* FIXME: handle other descriptor types */
+  }
+}
+
+int
+GNUNET_W32IO_write (struct W32Fd *ifd, char *out, size_t to_write)
+{
+  int ret;
+  switch (ifd->fd_type)
+  {
+  case GNUNET_W32IO_NAMED_PIPE:
+    return GNUNET_W32IO_write_async_named_pipe (ifd, out, to_write);
+    break;
+  case GNUNET_W32IO_FILE:
+    return GNUNET_W32IO_write_file (ifd, out, to_write);
+    break;
+  case GNUNET_W32IO_SOCKET:
+    return GNUNET_W32IO_send (ifd, out, to_write, 0);
+  case GNUNET_W32IO_ANONYMOUS_PIPE:
+    ret = GNUNET_W32IO_anonymous_pipe_write (ifd, out, to_write);
+    return ret;
+  default:
+    return 0;
+    /* FIXME: handle other descriptor types */
+  }
+}
+
+int
+GNUNET_W32IO_recv (struct W32Fd *fd, char *buffer, size_t length, int flags)
+{
+  int ret;
+  switch (fd->fd_type)
+  {
+  case GNUNET_W32IO_SOCKET:
+    ret = recv ((SOCKET) fd->fd, (char *) buffer, length, flags);
+    if (ret == SOCKET_ERROR)
+    {
+      DWORD error_code = GetLastError ();
+      if (error_code == WSAEWOULDBLOCK)
+        fd->wsaevents.lNetworkEvents &= ~FD_READ;
+      SetErrnoFromWinError (error_code);
+    }
+    else
+    {
+      fd->wsaevents.lNetworkEvents &= ~FD_READ;
+      fd->wsaevents.iErrorCode[FD_READ] = 0;
+    }
+    return ret;
+  default:
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Can't recv() - fd is not a socket\n");
+    return 0;
+  }
+}
+
+int
+GNUNET_W32IO_recvfrom (struct W32Fd *fd, char *buffer, size_t length, int flags, struct sockaddr *address, int *address_len)
+{
+  int ret;
+  switch (fd->fd_type)
+  {
+  case GNUNET_W32IO_SOCKET:
+    ret = recvfrom ((SOCKET) fd->fd, (char *) buffer, length, flags, address, address_len);
+    if (ret == SOCKET_ERROR)
+    {
+      DWORD error_code = GetLastError ();
+      if (error_code == WSAEWOULDBLOCK)
+        fd->wsaevents.lNetworkEvents &= ~FD_READ;
+      SetErrnoFromWinError (error_code);
+    }
+    else
+    {
+      fd->wsaevents.iErrorCode[FD_READ] = 0;
+    }
+    return ret;
+  default:
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Can't recvfrom() - fd is not a socket\n");
+    return 0;
+  }
+}
+
+int
+GNUNET_W32IO_send (struct W32Fd *fd, char *buffer, size_t length, int flags)
+{
+  int ret;
+  switch (fd->fd_type)
+  {
+  case GNUNET_W32IO_SOCKET:
+    ret = send ((SOCKET) fd->fd, (char *) buffer, length, flags);
+    if (ret == SOCKET_ERROR)
+    {
+      DWORD error_code = GetLastError ();
+      if (error_code == WSAEWOULDBLOCK)
+        fd->wsaevents.lNetworkEvents &= ~FD_WRITE;
+      SetErrnoFromWinError (error_code);
+    }
+    else
+    {
+      fd->wsaevents.iErrorCode[FD_WRITE] = 0;
+    }
+    return ret;
+  default:
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Can't send() - fd is not a socket\n");
+    return 0;
+  }
+}
+
+int
+GNUNET_W32IO_sendto (struct W32Fd *fd, char *buffer, size_t length, int flags, struct sockaddr *address, int address_len)
+{
+  int ret;
+  switch (fd->fd_type)
+  {
+  case GNUNET_W32IO_SOCKET:
+    ret = sendto ((SOCKET) fd->fd, (char *) buffer, length, flags, address, address_len);
+    if (ret == SOCKET_ERROR)
+    {
+      DWORD error_code = GetLastError ();
+      if (error_code == WSAEWOULDBLOCK)
+        fd->wsaevents.lNetworkEvents &= ~FD_WRITE;
+      SetErrnoFromWinError (error_code);
+    }
+    else
+    {
+      fd->wsaevents.iErrorCode[FD_WRITE] = 0;
+    }
+    return ret;
+  default:
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Can't sendto() - fd is not a socket\n");
+    return 0;
+  }
+}
+
+int
+GNUNET_W32IO_connect (struct W32Fd *fd, const struct sockaddr *name,
+    int namelen)
+{
+  int ret;
+  switch (fd->fd_type)
+  {
+  case GNUNET_W32IO_SOCKET:
+    ret = WSAConnect ((SOCKET) fd->fd, name, namelen, NULL, NULL, NULL, NULL);
+    if (ret == SOCKET_ERROR)
+    {
+      SetErrnoFromWinError (GetLastError());
+    }
+    else
+    {
+      fd->wsaevents.lNetworkEvents &= ~FD_CONNECT;
+      fd->wsaevents.iErrorCode[FD_CONNECT] = 0;
+    }
+    return ret;
+  default:
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Can't connect() - fd is not a socket\n");
+    return 0;
+  }
+}
+
+SOCKET
+GNUNET_W32IO_accept (struct W32Fd *fd, struct sockaddr *name, int *namelen)
+{
+  SOCKET ret;
+  switch (fd->fd_type)
+  {
+  case GNUNET_W32IO_SOCKET:
+    ret = WSAAccept ((SOCKET) fd->fd, name, namelen, NULL, 0);
+    if (ret == SOCKET_ERROR)
+    {
+      SetErrnoFromWinError (GetLastError());
+    }
+    else
+    {
+      fd->wsaevents.lNetworkEvents &= ~FD_ACCEPT;
+      fd->wsaevents.iErrorCode[FD_ACCEPT] = 0;
+    }
+    return ret;
+  default:
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Can't accept() - fd is not a socket\n");
+    return 0;
+  }
+}
+
+int
+GNUNET_W32IO_listen (struct W32Fd *fd, int backlog)
+{
+  int ret;
+  switch (fd->fd_type)
+  {
+  case GNUNET_W32IO_SOCKET:
+    ret = listen ((SOCKET) fd->fd, backlog);
+    if (ret == SOCKET_ERROR)
+    {
+      SetErrnoFromWinError (GetLastError());
+    }
+    else
+    {
+      fd->wsaevents.lNetworkEvents &= ~(FD_READ | FD_WRITE | FD_ACCEPT | FD_CONNECT);
+      fd->wsaevents.iErrorCode[FD_READ] = 0;
+      fd->wsaevents.iErrorCode[FD_WRITE] = 0;
+      fd->wsaevents.iErrorCode[FD_ACCEPT] = 0;
+      fd->wsaevents.iErrorCode[FD_CONNECT] = 0;
+    }
+    return ret;
+  default:
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Can't accept() - fd is not a socket\n");
+    return 0;
+  }
+}
+
+/**
+ * Anonymous pipes on NT do not support asynchronous operations, which is
+ * why we need a separate thread to perform writing and reading operations,
+ * and the state of this thread can be easily checked by waiting upon
+ * an event object.
+ */
+void *
+GNUNET_W32IO_anonymous_pipe_thread_func (void *data)
+{
+  struct W32Fd *wfd = (struct W32Fd *) data;
+  HANDLE h[2];
+  h[0] = wfd->overlapped[ANON_PIPE_THREAD_POLL_EVENT].hEvent;
+  h[1] = wfd->anon_thread_mutex;
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "locking\n");
+  WaitForSingleObject (wfd->anon_thread_mutex, INFINITE);
+  while (wfd->alive)
+  {
+    do 
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "waiting\n");
+      ReleaseMutex (h[1]);
+      ResetEvent (h[0]);
+      WaitForMultipleObjects(2, h, TRUE, INFINITE);
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "done waiting\n");
+    } while (wfd->work < 0);
+    switch (wfd->work) 
+    {
+    case 0: /* read */
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "anonymous read %x %d\n", wfd->fd, wfd->to_read);
+      wfd->bret = ReadFile (wfd->fd, wfd->readbuffer, wfd->to_read, &wfd->bytes_read, NULL);
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "done, read %d\n", wfd->bytes_read);
+      if (wfd->bret == 0)
+      {
+        wfd->dwerror = GetLastError ();
+      }
+      break;
+    case 1: /* write */
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "anonymous write %x %d\n", wfd->fd, wfd->to_write);
+      wfd->bret = WriteFile (wfd->fd, wfd->writebuffer, wfd->to_write, &wfd->bytes_written, NULL);
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "done, write %d\n", wfd->bytes_written);
+      if (wfd->bret == 0)
+      {
+        wfd->dwerror = GetLastError ();
+      }
+      break;
+    case 2: /* close */
+      wfd->alive = FALSE;
+      break;
+    default:
+      continue;
+    }
+    wfd->work = -1;
+    
+    SetEvent (wfd->overlapped[ANON_PIPE_MAIN_THREAD_POLL_EVENT].hEvent);
+  }
+
+  return NULL;
+}
+
+int
+GNUNET_W32IO_anonymous_pipe_read (struct W32Fd *fd, char *in, size_t to_read)
+{
+  BOOL bret;
+  DWORD dwret;
+  int ret = to_read;
+  HANDLE h[2];
+  h[0] = fd->overlapped[ANON_PIPE_MAIN_THREAD_POLL_EVENT].hEvent;
+  h[1] = fd->anon_thread_mutex;
+  while (to_read > 0)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "locking\n");
+    WaitForSingleObject (fd->anon_thread_mutex, INFINITE);
+    /* We've locked the mutex - which means that worker thread is not
+     * working at the moment.
+     */
+
+    fd->work = 0; /* read */
+    fd->readbuffer = in;
+    fd->to_read = to_read;
+
+    SetEvent (fd->overlapped[ANON_PIPE_THREAD_POLL_EVENT].hEvent);
+    /* We've signaled the worker thread event. Once we unlock the mutex,
+     * the worker thread will wake up.
+     */
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "waiting\n");
+    ResetEvent (h[0]);
+    ReleaseMutex (h[1]);
+    WaitForMultipleObjects(2, h, TRUE, INFINITE);
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "done waiting\n");
+    /* We've unlocked the mutex. The worker thread now wakes up and sees that
+     * work is >= 0 and begins to read.
+     */
+    /* Once the read operation is complete, it fills wfd->* with data and
+     * enables the main event, then waits on thread event (while unlocking threadmutex),
+     * which is the moment when wait-for-multiple-objects takes the opportunity and locks
+     * threadmutex for us here and finally wakes up.
+     */
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "unlocking\n");
+    ReleaseMutex (h[1]);
+
+    bret = fd->bret;
+    dwret = fd->bytes_read;
+    if (bret == 0)
+    {
+      dwret = fd->dwerror;
+      if (dwret == ERROR_BROKEN_PIPE) {
+        errno = EPIPE;
+        return -1;
+      }
+      goto error_and_fail;
+    }
+    to_read -= dwret;
+    in += dwret;
+  }
+#if 0
+  /* Mark the pipe as unreadable, because we won't know if it has any data to
+   * read until we wait on it. Of course, that will not prevent the application
+   * from trying to read it, but reading might block.
+   */
+  fd->wsaevents.lNetworkEvents &= ~FD_READ;
+  fd->revents &= ~FD_READ;
+#endif
+  /* SetEvent (fd->overlapped[FD_READ_BIT].hEvent); */
+  return ret;
+
+error_and_fail:
+  SetErrnoFromWinError (dwret);
+  return -1;
+}
+
+int
+GNUNET_W32IO_anonymous_pipe_write (struct W32Fd *fd, char *out, size_t to_write)
+{
+  BOOL bret;
+  DWORD dwret;
+  int ret = to_write;
+  HANDLE h[2];
+  h[0] = fd->overlapped[ANON_PIPE_MAIN_THREAD_POLL_EVENT].hEvent;
+  h[1] = fd->anon_thread_mutex;
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "locking\n");
+  WaitForSingleObject (fd->anon_thread_mutex, INFINITE);
+  /* We've locked the mutex - which means that worker thread is not
+   * working at the moment. If the thread was writing at the moment of
+   * locking, g_mutex_lock() will block until writing is complete, then
+   * the worker thread will unlock for a short time, letting us get
+   * the lock.
+   */
+  if (fd->writebuffer)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "freeing the buffer\n");
+    /* We've been writing somethings */
+    GNUNET_free (fd->writebuffer);
+    fd->writebuffer = NULL;
+
+    /* Process any error conditions from previous write operation */
+    bret = fd->bret;
+    dwret = fd->bytes_written;
+    if (bret == 0)
+    {
+      dwret = fd->dwerror;
+      if (dwret == ERROR_BROKEN_PIPE) {
+        errno = EPIPE;
+        return -1;
+      }
+      goto error_and_fail;
+    }
+  }
+
+  fd->work = 1; /* write */
+  fd->writebuffer = GNUNET_memdup (out, to_write);
+  fd->to_write = to_write;
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "signalling\n");
+  SetEvent (fd->overlapped[ANON_PIPE_THREAD_POLL_EVENT].hEvent);
+  /* We've signaled the worker thread condition. Once we unlock the mutex,
+   * the worker thread will wake up.
+   */
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "unlocking\n");
+  ReleaseMutex (fd->anon_thread_mutex);
+  /* Unlock the mutex and let the worker thread do its thing. Return
+   * to_write, while actual writing takes place in background.
+   * If another write is attempted while thread is busy, it will block.
+   * And any other operation will block too, of course.
+   */
+
+  /* We will get errorneous condition eventually, if we do another
+   * (blocking) write or wait, but not immediately.
+   * That happens because of the assumption we make about I/O things:
+   * It is always writable no matter what, but it is only readable when
+   * there is data to read. Real I/O things may not be like that -
+   * they may return an error while writing takes place.
+   * So you should assume that this function will return an error only
+   * when errorneous condition is obvious (wrong fd or a pipe broken
+   * during previous operation).
+   */
+  
+#if 0
+  /* Mark the pipe as unwritable. Of course, that will not prevent the
+   * application from trying to write into it, but writing might block.
+   */
+  
+  fd->wsaevents.lNetworkEvents &= ~FD_WRITE;
+  fd->revents &= ~FD_WRITE;
+#endif
+  /* SetEvent (fd->overlapped[FD_WRITE_BIT].hEvent); */
+  return ret;
+
+error_and_fail:
+  SetErrnoFromWinError (dwret);
+  return -1;
+}
+
+int
+GNUNET_W32IO_anonymous_pipe_close (struct W32Fd *fd)
+{
+  int ret = 0;
+  HANDLE h[2];
+  h[0] = fd->overlapped[ANON_PIPE_MAIN_THREAD_POLL_EVENT].hEvent;
+  h[1] = fd->anon_thread_mutex;
+  WaitForSingleObject (fd->anon_thread_mutex, INFINITE);
+  /* We've locked the mutex - which means that worker thread is not
+   * working at the moment.
+   */
+  /* Do not check for errors - we can't report them here (any errors
+   * reported should be related to close(), not to some previous
+   * operation).
+   */
+
+  if (fd->writebuffer)
+  {
+    GNUNET_free (fd->writebuffer);
+    fd->writebuffer = NULL;
+  }
+
+  fd->work = 2; /* close  */
+
+  SetEvent (fd->overlapped[ANON_PIPE_THREAD_POLL_EVENT].hEvent);
+  /* We've signaled the worker thread condition. Once we unlock the mutex,
+   * the worker thread will wake up.
+   */
+  ReleaseMutex (fd->anon_thread_mutex);
+  /* We've unlocked the mutex. The worker thread now wakes up and sees that
+   * work is 2, signals maincond, then sets ->alive to FALSE and terminates.
+   */
+  WaitForSingleObject (fd->anon_thread, INFINITE);
+
+  return ret;
+}
+
+off_t
+GNUNET_W32IO_lseek_handle (HANDLE fd, uint64_t new_offset, int origin)
+{
+  BOOL bret;
+  DWORD dwError;
+  LARGE_INTEGER offset;
+  LARGE_INTEGER ret;
+  LARGE_INTEGER current;
+  off_t result;
+
+  if (origin != SEEK_SET && origin != SEEK_CUR && origin != SEEK_END)
+  {
+    errno = EINVAL;
+    return -1;
+  }
+
+  offset.QuadPart = 0;
+  SetLastError (0);
+  bret = SetFilePointerEx (fd, offset, &current, FILE_CURRENT);
+
+  dwError = GetLastError ();
+
+  if (bret == 0 && dwError != NO_ERROR)
+  {
+    SetErrnoFromWinError (dwError);
+    return -1;
+  }
+
+  offset.QuadPart = new_offset;
+  SetLastError (0);
+  bret = SetFilePointerEx (fd, offset, &ret,
+      (origin == SEEK_SET ? FILE_BEGIN :
+      (origin == SEEK_CUR ? FILE_CURRENT :
+      (origin == SEEK_END ? FILE_END : origin))));
+
+  dwError = GetLastError ();
+
+  if (bret == 0 && dwError != NO_ERROR)
+  {
+    SetFilePointerEx (fd, current, NULL, FILE_BEGIN);
+    SetErrnoFromWinError (dwError);
+    return -1;
+  }
+
+  /* FIXME: make sure this check works correctly with 32-bit values */
+  result = ret.QuadPart;
+  offset.QuadPart = result;
+  if (offset.QuadPart != ret.QuadPart)
+  {
+    SetFilePointerEx (fd, current, NULL, FILE_BEGIN);
+    errno = EOVERFLOW;
+    return -1;
+  }
+
+  return ret.QuadPart;
+}
+
+off_t
+GNUNET_W32IO_lseek (struct W32Fd *fd, uint64_t new_offset, int origin)
+{
+  if (fd->fd_type != GNUNET_W32IO_FILE)
+  {
+    errno = ESPIPE;
+    return -1;
+  }
+
+  return GNUNET_W32IO_lseek_handle (fd->fd, new_offset, origin);
+}
+
+int
+GNUNET_W32IO_read_file (struct W32Fd *fd, char *in, size_t to_read)
+{
+  BOOL bret;
+  DWORD dwret;
+  int ret = to_read;
+  while (to_read > 0) {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ReadFile (%x, in, %d, &dwret, &fd->overlapped[POLLIN_BIT]);\n", fd->fd, to_read);
+    ZeroOverlappedExceptEvent(fd->overlapped[POLLIN_BIT]);
+    bret = ReadFile (fd->fd, in, to_read, &dwret,
+        &fd->overlapped[POLLIN_BIT]);
+    if (bret == 0)
+    {
+      dwret = GetLastError ();
+      if (dwret == ERROR_HANDLE_EOF) {
+        /* FIXME: make sure this is correct */
+        return ret;
+      }
+
+      if (dwret != ERROR_IO_PENDING)
+        goto error_and_fail;
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "WaitForSingleObject (%x, INFINITE);\n", fd->overlapped[POLLIN_BIT].hEvent);
+      dwret = WaitForSingleObject (fd->overlapped[POLLIN_BIT].hEvent,
+          INFINITE);
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "done\n");
+      if (dwret != WAIT_OBJECT_0)
+      {
+        dwret = GetLastError ();
+        goto error_and_fail;
+      }
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "GetOverlappedResult (%x, &fd->overlapped[FD_READ_BIT], &dwret, TRUE);\n", fd->fd);
+      bret = GetOverlappedResult ((HANDLE) fd->fd,
+          &fd->overlapped[POLLIN_BIT], &dwret, TRUE);
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got it\n");
+      if (bret == 0)
+      {
+        dwret = GetLastError ();
+        if (dwret == ERROR_HANDLE_EOF) {
+          /* FIXME: make sure this is correct */
+          return ret;
+        }
+        goto error_and_fail;
+      }
+    }
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Read %d bytes\n", dwret);
+    to_read -= dwret;
+    in += dwret;
+  }
+  return ret;
+
+error_and_fail:
+  GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to read\n");
+  SetErrnoFromWinError (dwret);
+  return -1;
+}
+
+int
+GNUNET_W32IO_write_file (struct W32Fd *fd, char *out, size_t to_write)
+{
+  BOOL bret;
+  DWORD dwret;
+  DWORD ret;
+
+  /* writebuffer isn't NULL -> there's a writing operation going on */
+  if (fd->writebuffer != NULL) {
+    /* Wait until event is set (meaning that operation is complete).
+     * This might block for a while (until the other end reads), that is - 
+     * you can't have more than one writing operation working at one pipe.
+     * TODO: implement multiple buffering, so that it is possible to write
+     * more than once (especially if we're talking about writing small
+     * amounts of data multiple times).
+     */
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "WaitForSingleObject (%x, INFINITE);\n", fd->overlapped[POLLOUT_BIT].hEvent);
+    if (WaitForSingleObject (fd->overlapped[POLLOUT_BIT].hEvent, INFINITE) ==
+        WAIT_OBJECT_0)
+    {
+      /* Get the operation result, free the buffer */
+      DWORD wait_ret;
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "GetOverlappedResult (%x, %x, %x, TRUE);\n", fd->fd, &fd->overlapped[POLLOUT_BIT], &wait_ret);
+      ret = GetOverlappedResult ((HANDLE) fd->fd,
+          &fd->overlapped[POLLOUT_BIT], &wait_ret, TRUE);
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got it\n");
+      if (fd->writebuffer) {
+        GNUNET_free (fd->writebuffer);
+        fd->writebuffer = NULL;
+      }
+
+      if (ret == 0) {
+        errno = EIO;
+        return -1;
+      }
+    }
+  }
+
+  if (out)
+    fd->writebuffer = (char *) GNUNET_memdup (out, to_write);
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "WriteFile (%x, %x, %d, NULL, %x);\n", fd->fd, fd->writebuffer, to_write, &fd->overlapped[POLLOUT_BIT]);
+  ZeroOverlappedExceptEvent(fd->overlapped[POLLOUT_BIT]);
+  bret = WriteFile ((HANDLE) fd->fd, fd->writebuffer, to_write, NULL,
+      &fd->overlapped[POLLOUT_BIT]);
+  if (bret == 0) {
+    dwret = GetLastError ();
+    /* FIXME: handle ERROR_INVALID_USER_BUFFER or ERROR_NOT_ENOUGH_MEMORY as EAGAIN */
+    if (dwret != ERROR_IO_PENDING)
+      goto error_and_fail;
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Wrote into heap buffer\n");
+  } else {
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Wrote into kernel buffer\n");
+    GNUNET_free (fd->writebuffer);
+    fd->writebuffer = NULL;
+  }
+  return to_write;
+
+error_and_fail:
+  GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to write\n");
+  GNUNET_free (fd->writebuffer);
+  fd->writebuffer = NULL;
+  SetErrnoFromWinError (dwret);
+  return -1;
+}
+
+#endif /* WINDOWS */
\ No newline at end of file
diff --git a/src/util/w32io.h b/src/util/w32io.h
new file mode 100644
index 0000000..c66f2e1
--- /dev/null
+++ b/src/util/w32io.h
@@ -0,0 +1,268 @@
+/*
+     This file is part of GNUnet.
+     (C) 2001, 2002, 2005, 2006, 2009, 2010 Christian Grothoff (and other contributing authors)
+
+     GNUnet is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published
+     by the Free Software Foundation; either version 2, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+     Boston, MA 02111-1307, USA.
+*/
+#ifndef __GNUNET_W32IO_H__
+#define __GNUNET_W32IO_H__
+#include "platform.h"
+#include "gnunet_common.h"
+
+#if WINDOWS
+
+#include <sys/types.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <errno.h>
+#include <fcntl.h>
+
+#include <winsock2.h>
+
+/**
+ * GNUNET_W32IO_UNSPECIFIED - not specified by user. Should be
+ * autodetected when necessary
+ * GNUNET_W32IO_UNKNOWN - autodetection failed, type unknown
+ * GNUNET_W32IO_FILE - returned by CreateFile()
+ * GNUNET_W32IO_NAMED_PIPE - returned by CreateNamedPipe() (server)
+ * and CreateFile() (client)
+ * GNUNET_W32IO_ANONYMOUS_PIPE - returned by CreatePipe()
+ * GNUNET_W32IO_CONSOLE - returned by CreateFile()
+ * GNUNET_W32IO_SOCKET - returned by socket()
+ * GNUNET_W32IO_LAST - do not use
+ */
+typedef enum
+{
+  GNUNET_W32IO_UNSPECIFIED = 0,
+  GNUNET_W32IO_UNKNOWN,
+  GNUNET_W32IO_FILE,
+  GNUNET_W32IO_NAMED_PIPE,
+  GNUNET_W32IO_ANONYMOUS_PIPE,
+  GNUNET_W32IO_CONSOLE,
+  GNUNET_W32IO_SOCKET,
+  GNUNET_W32IO_LAST
+} GNUNET_W32IO_HandleType;
+
+typedef enum
+{
+  POLLIN = FD_READ | FD_ACCEPT,
+  POLLRDNORM = FD_READ | FD_ACCEPT,
+  POLLRDBAND = FD_OOB,
+  POLLOUT = FD_WRITE | FD_CONNECT,
+  POLLWRNORM = FD_WRITE | FD_CONNECT,
+  POLLHUP = FD_CLOSE,
+  POLLPRI = 1 << FD_MAX_EVENTS,
+  POLLWRBAND = 1 << FD_MAX_EVENTS << 1,
+  POLLERR = 1 << FD_MAX_EVENTS << 2,
+  POLLNVAL = 1 << FD_MAX_EVENTS << 3,
+  POLLLAST = FD_MAX_EVENTS + 4
+} GNUNET_W32IO_PollEvents;
+
+#define POLLIN_BIT FD_READ_BIT
+#define POLLOUT_BIT FD_WRITE_BIT
+#define POLLHUP_BIT FD_CLOSE_BIT
+#define POLLERR_BIT FD_MAX_EVENTS + 2
+#define POLLNVAL_BIT FD_MAX_EVENTS + 3
+
+struct timespec {
+    long    tv_sec;         /* seconds */
+    long    tv_nsec;        /* nanoseconds */
+};
+
+/**
+ * 
+ */
+struct W32Fd
+{
+  /**
+   * Untyped I/O descriptor (type depends on fd_type)
+   */
+  HANDLE fd;
+
+  /**
+   * Events that have occurred on a socket
+   * (as returned by WSAEnumNetworkEvents)
+   * Used to preserve some one-time events that
+   * are not re-posted by Winsock.
+   */
+  WSANETWORKEVENTS wsaevents;
+
+  /**
+   * An array of structures for file/pipe async I/O.
+   * Its 0th member is used by sockets.
+   * Its 0th and 1st members are used by @anon_thread as, respectedly,
+   * the @anon_thread event (tells the @anon_thread to wake up and do some
+   * work) and the main thread event (tells the main thread to wake up, since
+   * the @anon_thead have finished its work).
+   */
+  OVERLAPPED overlapped[POLLLAST];
+
+  /**
+   * fd_type - type of the descriptor
+   */
+  GNUNET_W32IO_HandleType fd_type;
+
+  /**
+   * The access we have to the handle
+   */
+  DWORD access;
+
+  /**
+   * The events in which the caller is interested in.
+   * May be modified internally by ppoll()
+   */
+  int16_t events;
+
+  /**
+   * The result of a ppoll() call - contains the events
+   * that have occurred on this W32Fd.
+   */
+  int16_t revents;
+
+  /*_______Anonymous pipe I/O implementation details_______*/
+
+  /**
+   * A thread that performs operations on anonymous pipe
+   */
+  HANDLE anon_thread;
+ 
+  /**
+   * A mutex that locks this W32Fd to prevent the main thread and
+   * the @anon_thread from accessing it at the same time.
+   */
+  HANDLE anon_thread_mutex;
+
+  /**
+   * Number of bytes to read
+   */
+  DWORD to_read;
+
+  /**
+   * Number of bytes to write
+   */
+  DWORD to_write;
+
+  /**
+   * Number of bytes read
+   */
+  DWORD bytes_read;
+
+  /**
+   * Number of bytes written
+   */
+  DWORD bytes_written;
+
+  /**
+   * A pointer to a block of memory that will receive data from a reading
+   * operation.
+   */
+  char *readbuffer;
+
+  /**
+   * A pointer to a block of memory that will provide data for a writing
+   * operation.
+   */
+  char *writebuffer;
+
+  /**
+   * A value returned by ReadFile()/WriteFile() within @anon_thread
+   */
+  BOOL bret;
+
+  /**
+   * A value returned by GetLastError() within @anon_thread
+   */
+  DWORD dwerror;
+
+  /**
+   * A type of work to be done.
+   * -1 - none
+   *  0 - read
+   *  1 - write
+   */
+  int work;
+
+  /**
+   * A boolean condition that can be set to FALSE to indicate that
+   * the @anon_thread must (when it wakes up) return.
+   */
+  BOOL alive;
+};
+
+/**
+ * Sometimes pollfd is used as a struct, not as a pointer, which is why
+ * we need to wrap W32Fd - to make sure it always stays a pointer
+ */
+struct W32PollFd
+{
+  struct W32Fd *fd;
+};
+
+int GNUNET_W32IO_error_to_errno (DWORD last_error);
+
+HANDLE GNUNET_W32IO_fd_get_handle (struct W32Fd *fd);
+
+void GNUNET_W32IO_generate_random_local_pipe_name (char *pipename);
+
+int GNUNET_W32IO_pipe (struct W32Fd *fd[2], int server_inheritable, int client_inheritable, DWORD server_mode, DWORD client_mode);
+
+int GNUNET_W32IO_anonymous_pipe (struct W32Fd *fd[2], int read_inheritable, int write_inheritable);
+
+int GNUNET_W32IO_fsync (struct W32Fd *wfd);
+
+int GNUNET_W32IO_close (struct W32Fd *wfd, int closehandle);
+
+GNUNET_W32IO_HandleType GNUNET_W32IO_find_handle_type (HANDLE h);
+
+struct W32Fd *GNUNET_W32IO_fd_from_handle (HANDLE h, GNUNET_W32IO_HandleType htype, DWORD handle_access, int connected,
+    int writeable, int readable);
+
+int GNUNET_W32IO_read_async_named_pipe (struct W32Fd *fd, char *in, size_t to_read);
+
+int GNUNET_W32IO_write_async_named_pipe (struct W32Fd *fd, char *out, size_t to_write);
+
+int GNUNET_W32IO_read (struct W32Fd *ifd, char *in, size_t to_read);
+
+int GNUNET_W32IO_write (struct W32Fd *ifd, char *out, size_t to_write);
+
+int GNUNET_W32IO_ppoll (struct W32PollFd *fds, uint64_t nfds, const struct timespec *t, const sigset_t *sigmask);
+
+int GNUNET_W32IO_prepare_for_poll (struct W32PollFd *wfd, HANDLE *events);
+
+int GNUNET_W32IO_recv (struct W32Fd *fd, char *buffer, size_t length, int flags);
+int GNUNET_W32IO_recvfrom (struct W32Fd *fd, char *buffer, size_t length, int flags, struct sockaddr *address, int *address_len);
+int GNUNET_W32IO_send (struct W32Fd *fd, char *buffer, size_t length, int flags);
+int GNUNET_W32IO_sendto (struct W32Fd *fd, char *buffer, size_t length, int flags, struct sockaddr *address, int address_len);
+
+int GNUNET_W32IO_connect (struct W32Fd *fd, const struct sockaddr *name, int namelen);
+SOCKET GNUNET_W32IO_accept (struct W32Fd *fd, struct sockaddr *name, int *namelen);
+int GNUNET_W32IO_listen (struct W32Fd *fd, int backlog);
+
+int GNUNET_W32IO_anonymous_pipe_read (struct W32Fd *fd, char *in, size_t to_read);
+int GNUNET_W32IO_anonymous_pipe_write (struct W32Fd *fd, char *out, size_t to_write);
+int GNUNET_W32IO_anonymous_pipe_close (struct W32Fd *fd);
+
+off_t GNUNET_W32IO_lseek_handle (HANDLE fd, uint64_t new_offset, int origin);
+off_t GNUNET_W32IO_lseek (struct W32Fd *fd, uint64_t new_offset, int origin);
+
+int GNUNET_W32IO_read_file (struct W32Fd *fd, char *in, size_t to_read);
+int GNUNET_W32IO_write_file (struct W32Fd *fd, char *out, size_t to_write);
+
+#endif /* WINDOWS */
+#endif /* __GNUNET_W32IO_H__ */
\ No newline at end of file
-- 
1.7.3.1.msysgit.0

0001-First-w32io-with-fake-FDs-commit.patch (245,557 bytes)   
From e91f21b8dd965402dfa862d1a4f0d1a6ff476de5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=A0=D1=83=D1=81=D0=BB=D0=B0=D0=BD=20=D0=98=D0=B6=D0=B1=D1=83=D0=BB=D0=B0=D1=82=D0=BE=D0=B2?= <lrn1986@gmail.com>
Date: Sun, 21 Nov 2010 21:15:15 +0300
Subject: [PATCH] First w32io-with-fake-FDs commit

Second w32io-with-fake-FDs commit

Fixed the select() implementation and the socket test

Added a shutdown() wrapper, fixed shutdown in the test

Fixed select() and the test

Fixed named pipe tests and poll()

Almost final W32I/O commit

W32IO: Finally passing all 45 tests

Merge W32IO into latest head. Disable NAT on MinGW
---
 src/include/gnunet_common.h          |    2 +-
 src/include/gnunet_network_lib.h     |   13 -
 src/include/platform.h               |  136 ++-
 src/include/winproc.h                |    1 +
 src/nat/Makefile.am                  |    3 +-
 src/transport/Makefile.am            |    4 +-
 src/transport/gnunet-nat-server.c    |    2 +
 src/transport/plugin_transport_tcp.c |    4 +
 src/util/Makefile.am                 |   14 +-
 src/util/client.c                    |    2 +-
 src/util/common_logging.c            |   22 +-
 src/util/disk.c                      |  205 +--
 src/util/disk.h                      |   15 -
 src/util/gnunet-service-resolver.c   |    6 +-
 src/util/network.c                   |  552 ++----
 src/util/os_installation.c           |    6 +-
 src/util/os_network.c                |    2 +-
 src/util/os_priority.c               |  122 +-
 src/util/scheduler.c                 |   68 +-
 src/util/service.c                   |    8 +-
 src/util/signal.c                    |   10 +-
 src/util/strings.c                   |    6 +-
 src/util/test_configuration.c        |    2 +-
 src/util/test_getopt.c               |    2 +-
 src/util/test_os_start_process.c     |   12 +-
 src/util/test_resolver_api.c         |    7 +-
 src/util/test_scheduler.c            |    5 +-
 src/util/test_service.c              |    3 -
 src/util/test_service_data.conf      |    2 +
 src/util/test_strings.c              |    2 +-
 src/util/test_w32io.c                |  960 +++++++++
 src/util/w32io.c                     | 3698 ++++++++++++++++++++++++++++++++++
 src/util/w32io.h                     |  279 +++
 src/util/winproc.c                   |    9 +-
 34 files changed, 5473 insertions(+), 711 deletions(-)
 create mode 100644 src/util/test_w32io.c
 create mode 100644 src/util/w32io.c
 create mode 100644 src/util/w32io.h

diff --git a/src/include/gnunet_common.h b/src/include/gnunet_common.h
index dddee06..b75d36f 100644
--- a/src/include/gnunet_common.h
+++ b/src/include/gnunet_common.h
@@ -36,7 +36,7 @@
 #if HAVE_NETINET_IN_H
 #include <netinet/in.h>
 #endif
-#ifdef MINGW
+#if WINDOWS && !defined(__CYGWIN__)
 #include "winproc.h"
 #endif
 #ifdef HAVE_STDINT_H
diff --git a/src/include/gnunet_network_lib.h b/src/include/gnunet_network_lib.h
index 7330368..a5ae0e4 100644
--- a/src/include/gnunet_network_lib.h
+++ b/src/include/gnunet_network_lib.h
@@ -271,19 +271,6 @@ void GNUNET_NETWORK_fdset_set (struct GNUNET_NETWORK_FDSet *fds,
                                const struct GNUNET_NETWORK_Handle *desc);
 
 
-#ifdef __MINGW32__
-/* TODO: maybe #ifdef WINDOWS? -ndurner */
-/**
- * Add a W32 file handle to the fd set
- * @param fds fd set
- * @param h the file handle to add
- */
-void
-GNUNET_NETWORK_fdset_handle_set_native_w32_handle (struct GNUNET_NETWORK_FDSet *fds,
-						   HANDLE h);
-#endif
-
-
 /**
  * Check whether a socket is part of the fd set
  * @param fds fd set
diff --git a/src/include/platform.h b/src/include/platform.h
index cc2aa03..26a800d 100644
--- a/src/include/platform.h
+++ b/src/include/platform.h
@@ -80,7 +80,7 @@
 #include <Winsock2.h>
 #include <ws2tcpip.h>
 #else
-#ifndef MINGW
+#if !WINDOWS || defined(__CYGWIN__)
 #include <netdb.h>
 #include <sys/socket.h>
 #include <sys/un.h>
@@ -199,7 +199,7 @@
 #define SIOCGIFADDR     _IOW('s', 102, struct ifreq)    /* Get if addr */
 #endif
 
-#ifndef MINGW
+#if !WINDOWS || defined(__CYGWIN__)
 #include <sys/mman.h>
 #endif
 
@@ -239,4 +239,136 @@ long long atoll (const char *nptr);
 #define MAKE_UNALIGNED(val) val
 #endif
 
+#ifdef WINDOWS
+struct W32Fd;
+/**
+ * Sometimes pollfd is used as a struct, not as a pointer, which is why
+ * we need to wrap W32Fd - to make sure it always stays a pointer.
+ * Also keeps things consistent (caller might expect to access pollfd.events)
+ */
+struct W32PollFd
+{
+  struct W32Fd *fd;
+  short events;
+  short revents;
+};
+struct pollfd
+{
+  int fd;
+  short events;
+  short revents;
+};
+#define POLL_FD_TYPE struct W32Fd *
+#define POLLFD struct W32PollFd
+#define NATIVE_FD_TYPE HANDLE
+
+typedef enum
+{
+  POLLIN = FD_READ | FD_ACCEPT,
+  POLLRDNORM = FD_READ | FD_ACCEPT,
+  POLLRDBAND = FD_OOB,
+  POLLOUT = FD_WRITE | FD_CONNECT,
+  POLLWRNORM = FD_WRITE | FD_CONNECT,
+  POLLHUP = FD_CLOSE,
+  POLLPRI = 1 << FD_MAX_EVENTS,
+  POLLWRBAND = 1 << (FD_MAX_EVENTS + 1),
+  POLLERR = 1 << (FD_MAX_EVENTS + 2),
+  POLLNVAL = 1 << (FD_MAX_EVENTS + 3),
+  POLLLAST = FD_MAX_EVENTS + 4
+} GNUNET_W32IO_PollEvents;
+
+#define POLLIN_BIT FD_READ_BIT
+#define POLLOUT_BIT FD_WRITE_BIT
+#define POLLHUP_BIT FD_CLOSE_BIT
+#define POLLWRBAND_BIT FD_MAX_EVENTS + 1
+#define POLLERR_BIT FD_MAX_EVENTS + 2
+#define POLLNVAL_BIT FD_MAX_EVENTS + 3
+
+#else
+#define POLL_FD_TYPE int
+#define POLLFD struct pollfd
+#define NATIVE_FD_TYPE int
+#endif
+
+#define INVALID_POLL_FD (POLL_FD_TYPE) -1
+
+typedef long int __fd_mask;
+
+#undef __NFDBITS
+#define __NFDBITS	(8 * sizeof (__fd_mask))
+#define	__FDELT(d)	((d) / __NFDBITS)
+#define	__FDMASK(d)	((__fd_mask) 1 << ((d) % __NFDBITS))
+
+#undef __FD_SETSIZE
+#define __FD_SETSIZE  1024
+
+#undef __FDSET_LONGS
+#define __FDSET_LONGS  (__FD_SETSIZE/__NFDBITS)
+
+/* Maximum number of file descriptors in `fd_set'.  */
+#define	W32_FD_SETSIZE		__FD_SETSIZE
+
+#ifdef __USE_MISC
+/* Sometimes the fd_set member is assumed to have this type.  */
+typedef __fd_mask fd_mask;
+
+/* Number of bits per word of `fd_set' (some code assumes this is 32).  */
+# define W32_NFDBITS		__NFDBITS
+#endif
+
+# define __FD_ZERO(fdsp) \
+  do {									      \
+    int __d0, __d1;							      \
+    __asm__ __volatile__ ("cld; rep; stosl"				      \
+			  : "=c" (__d0), "=D" (__d1)			      \
+			  : "a" (0), "0" (sizeof (w32fd_set)		      \
+					  / sizeof (__fd_mask)),	      \
+			    "1" (&__FDS_BITS (fdsp)[0])			      \
+			  : "memory");					      \
+  } while (0)
+
+# define __FD_SET(fd, fdsp) \
+  __asm__ __volatile__ ("btsl %1,%0"					      \
+			: "=m" (__FDS_BITS (fdsp)[__FDELT (fd)])	      \
+			: "r" (((int) (fd)) % __NFDBITS)		      \
+			: "cc","memory")
+# define __FD_CLR(fd, fdsp) \
+  __asm__ __volatile__ ("btrl %1,%0"					      \
+			: "=m" (__FDS_BITS (fdsp)[__FDELT (fd)])	      \
+			: "r" (((int) (fd)) % __NFDBITS)		      \
+			: "cc","memory")
+# define __FD_ISSET(fd, fdsp) \
+  (__extension__							      \
+   ({register char __result;						      \
+     __asm__ __volatile__ ("btl %1,%2 ; setcb %b0"			      \
+			   : "=q" (__result)				      \
+			   : "r" (((int) (fd)) % __NFDBITS),		      \
+			     "m" (__FDS_BITS (fdsp)[__FDELT (fd)])	      \
+			   : "cc");					      \
+     __result; }))
+
+/* fd_set for select and pselect.  */
+typedef struct 
+  {
+    /* XPG4.2 requires this member name.  Otherwise avoid the name
+       from the global namespace.  */
+#ifdef __USE_XOPEN
+    __fd_mask fds_bits[__FDSET_LONGS];
+# define __FDS_BITS(set) ((set)->fds_bits)
+#else
+    __fd_mask __fds_bits[__FDSET_LONGS];
+# define __FDS_BITS(set) ((set)->__fds_bits)
+#endif
+  } w32fd_set;
+
+/* Access macros for `fd_set'.  */
+#define	W32_FD_SET(fd, fdsetp)		__FD_SET(fd, fdsetp)
+#define	W32_FD_CLR(fd, fdsetp)		__FD_CLR(fd, fdsetp)
+#define	W32_FD_ISSET(fd, fdsetp)	__FD_ISSET(fd, fdsetp)
+#define	W32_FD_ZERO(fdsetp)		__FD_ZERO(fdsetp)
+
+#ifdef WINDOWS
+  typedef long nfds_t;
+#endif
+
 #endif
diff --git a/src/include/winproc.h b/src/include/winproc.h
index 595180a..f23b00b 100644
--- a/src/include/winproc.h
+++ b/src/include/winproc.h
@@ -45,6 +45,7 @@
 #include <Ntsecapi.h>
 #include <lm.h>
 #include <Aclapi.h>
+#include <shlwapi.h>
 
 
 #ifdef __cplusplus
diff --git a/src/nat/Makefile.am b/src/nat/Makefile.am
index 3ca896b..e091327 100644
--- a/src/nat/Makefile.am
+++ b/src/nat/Makefile.am
@@ -48,4 +48,5 @@ test_nat_LDADD = \
  $(top_builddir)/src/nat/libgnunetnat.la \
  $(top_builddir)/src/util/libgnunetutil.la \
  @LIBCURL@
-endif
+
+endif
\ No newline at end of file
diff --git a/src/transport/Makefile.am b/src/transport/Makefile.am
index 313d948..468082c 100644
--- a/src/transport/Makefile.am
+++ b/src/transport/Makefile.am
@@ -7,9 +7,11 @@ if MINGW
   NATBIN = gnunet-nat-server gnunet-nat-client
   NATSERVER = gnunet-nat-server-windows.c
   NATCLIENT = gnunet-nat-client-windows.c
+  NATLIB = 
 else
   NATSERVER = gnunet-nat-server.c
   NATCLIENT = gnunet-nat-client.c
+  NATLIB = $(top_builddir)/src/nat/libgnunetnat.la
 endif
 
 if HAVE_MHD
@@ -117,7 +119,7 @@ libgnunet_plugin_transport_tcp_la_LIBADD = \
   $(top_builddir)/src/hello/libgnunethello.la \
   $(top_builddir)/src/statistics/libgnunetstatistics.la \
   $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
-  $(top_builddir)/src/nat/libgnunetnat.la \
+  $(NATLIB) \
   $(top_builddir)/src/util/libgnunetutil.la 
 libgnunet_plugin_transport_tcp_la_LDFLAGS = \
  $(GN_PLUGIN_LDFLAGS)
diff --git a/src/transport/gnunet-nat-server.c b/src/transport/gnunet-nat-server.c
index ab99b5f..5c5b924 100644
--- a/src/transport/gnunet-nat-server.c
+++ b/src/transport/gnunet-nat-server.c
@@ -461,6 +461,7 @@ make_icmp_socket ()
 	       strerror (errno));
       return -1;
     }
+#if WINDOWS && !defined(__CYGWIN__)
   if (ret >= FD_SETSIZE)
     {
       fprintf (stderr,
@@ -470,6 +471,7 @@ make_icmp_socket ()
       close (ret);
       return -1;
     }
+#endif
   return ret;
 }
 
diff --git a/src/transport/plugin_transport_tcp.c b/src/transport/plugin_transport_tcp.c
index 18aad98..7179da9 100644
--- a/src/transport/plugin_transport_tcp.c
+++ b/src/transport/plugin_transport_tcp.c
@@ -619,10 +619,12 @@ add_to_address_list (struct Plugin *plugin,
       GNUNET_break (0);
       return;
     }
+#if !WINDOWS || defined(__CYGWIN__)
   if (plugin->allow_upnp)
     lal->nat = GNUNET_NAT_register (sa, salen,
 				    &nat_port_map_callback,
 				    lal);
+#endif
 }
 
 
@@ -2910,8 +2912,10 @@ libgnunet_plugin_transport_tcp_done (void *cls)
       GNUNET_CONTAINER_DLL_remove (plugin->lal_head,
 				   plugin->lal_tail,
 				   lal);
+#if !WINDOWS || defined(__CYGWIN__)
       if (lal->nat != NULL)
 	GNUNET_NAT_unregister (lal->nat);
+#endif
       GNUNET_free_non_null (lal->external_nat_address);
       GNUNET_free (lal);
     }
diff --git a/src/util/Makefile.am b/src/util/Makefile.am
index 427ed25..e99341e 100644
--- a/src/util/Makefile.am
+++ b/src/util/Makefile.am
@@ -6,14 +6,18 @@ if MINGW
 noinst_LTLIBRARIES = \
   libgnunetutilwin.la
 libgnunetutilwin_la_SOURCES = \
+  w32io.c \
+  w32io.h \
   win.cc \
   winproc.c
 libgnunetutilwin_la_LDFLAGS = \
   -Wl,--no-undefined -Wl,--export-all-symbols 
 libgnunetutilwin_la_LIBADD = \
   -lshell32 -liconv -lstdc++ \
-  -lcomdlg32 -lgdi32
+  -lcomdlg32 -lgdi32 
 WINLIB = libgnunetutilwin.la
+
+WINTESTS = test_w32io
 endif
 
 if USE_COVERAGE
@@ -108,6 +112,7 @@ libgnunet_plugin_test_la_LDFLAGS = \
  $(GN_PLUGIN_LDFLAGS)
 
 check_PROGRAMS = \
+ $(WINTESTS) \
  test_bio \
  test_client \
  test_common_allocation \
@@ -157,6 +162,13 @@ if !DISABLE_TEST_RUN
 TESTS = $(check_PROGRAMS)
 endif
 
+if MINGW
+test_w32io_SOURCES = \
+ test_w32io.c
+test_w32io_LDADD = \
+ $(top_builddir)/src/util/libgnunetutil.la
+endif
+
 test_bio_SOURCES = \
  test_bio.c
 test_bio_LDADD = \
diff --git a/src/util/client.c b/src/util/client.c
index d957dd0..90d1576 100644
--- a/src/util/client.c
+++ b/src/util/client.c
@@ -34,7 +34,7 @@
 #include "gnunet_server_lib.h"
 #include "gnunet_scheduler_lib.h"
 
-#define DEBUG_CLIENT GNUNET_NO
+#define DEBUG_CLIENT GNUNET_YES
 
 /**
  * How often do we re-try tranmsitting requests before giving up?
diff --git a/src/util/common_logging.c b/src/util/common_logging.c
index 1a32c44..c7df541 100644
--- a/src/util/common_logging.c
+++ b/src/util/common_logging.c
@@ -134,6 +134,11 @@ static unsigned int skip_log;
  */
 static FILE *GNUNET_stderr;
 
+#if WINDOWS && !defined(__CYGWIN__)
+CRITICAL_SECTION cs;
+BOOL cs_inited = FALSE;
+#endif
+
 /**
  * Convert a textual description of a loglevel
  * to the respective GNUNET_GE_KIND.
@@ -173,6 +178,13 @@ GNUNET_log_setup (const char *comp, const char *loglevel, const char *logfile)
   int dirwarn;
   char *fn;
 
+#if WINDOWS && !defined(__CYGWIN__)
+  if (!cs_inited)
+  {
+    cs_inited = TRUE;
+    InitializeCriticalSection (&cs);
+  }
+#endif
   GNUNET_free_non_null (component);
   GNUNET_asprintf (&component,
 		   "%s-%d",
@@ -263,6 +275,9 @@ output_message (enum GNUNET_ErrorType kind,
                 const char *comp, const char *datestr, const char *msg)
 {
   struct CustomLogger *pos;
+#if WINDOWS && !defined(__CYGWIN__)
+  EnterCriticalSection (&cs);
+#endif
   if (GNUNET_stderr != NULL)
     {
       fprintf (GNUNET_stderr, "%s %s %s %s", datestr, comp, 
@@ -275,6 +290,9 @@ output_message (enum GNUNET_ErrorType kind,
       pos->logger (pos->logger_cls, kind, comp, datestr, msg);
       pos = pos->next;
     }
+#if WINDOWS && !defined(__CYGWIN__)
+  LeaveCriticalSection (&cs);
+#endif
 }
 
 
@@ -599,7 +617,7 @@ GNUNET_a2s (const struct sockaddr *addr, socklen_t addrlen)
 void __attribute__ ((constructor)) GNUNET_util_cl_init ()
 {
   GNUNET_stderr = stderr;
-#ifdef MINGW
+#if WINDOWS
   GNInitWinEnv (NULL);
 #endif
 }
@@ -610,7 +628,7 @@ void __attribute__ ((constructor)) GNUNET_util_cl_init ()
  */
 void __attribute__ ((destructor)) GNUNET_util_cl_fini ()
 {
-#ifdef MINGW
+#if WINDOWS
   GNShutdownWinEnv ();
 #endif
 }
diff --git a/src/util/disk.c b/src/util/disk.c
index 0b37da8..168edb9 100644
--- a/src/util/disk.c
+++ b/src/util/disk.c
@@ -32,7 +32,7 @@
 #include "gnunet_scheduler_lib.h"
 #include "gnunet_strings_lib.h"
 #include "disk.h"
-
+#include "w32io.h"
 
 /**
  * Block size for IO for copying files.
@@ -52,7 +52,7 @@
 #include <sys/types.h>
 #include <sys/statvfs.h>
 #else
-#ifdef MINGW
+#if WINDOWS && !defined(__CYGWIN__)
 #define  	_IFMT		0170000 /* type of file */
 #define  	_IFLNK		0120000 /* symbolic link */
 #define  S_ISLNK(m)	(((m)&_IFMT) == _IFLNK)
@@ -182,11 +182,7 @@ getSizeRec (void *cls, const char *fn)
 int
 GNUNET_DISK_handle_invalid (const struct GNUNET_DISK_FileHandle *h)
 {
-#ifdef MINGW
-  return ((!h) || (h->h == INVALID_HANDLE_VALUE)) ? GNUNET_YES : GNUNET_NO;
-#else
   return ((!h) || (h->fd == -1)) ? GNUNET_YES : GNUNET_NO;
-#endif
 }
 
 
@@ -208,24 +204,13 @@ GNUNET_DISK_file_seek (const struct GNUNET_DISK_FileHandle * h, off_t offset,
       return GNUNET_SYSERR;
     }
 
-#ifdef MINGW
-  DWORD ret;
-  static DWORD t[] = {[GNUNET_DISK_SEEK_SET] = FILE_BEGIN,
-    [GNUNET_DISK_SEEK_CUR] = FILE_CURRENT,[GNUNET_DISK_SEEK_END] = FILE_END
-  };
-
-  ret = SetFilePointer (h->h, offset, NULL, t[whence]);
-  if (ret == INVALID_SET_FILE_POINTER)
-    {
-      SetErrnoFromWinError (GetLastError ());
-      return GNUNET_SYSERR;
-    }
-  return ret;
-#else
   static int t[] = {[GNUNET_DISK_SEEK_SET] = SEEK_SET,
     [GNUNET_DISK_SEEK_CUR] = SEEK_CUR,[GNUNET_DISK_SEEK_END] = SEEK_END
   };
 
+#if WINDOWS
+  return GNUNET_W32IO_lseek (h->fd, offset, t[whence]);
+#else
   return lseek (h->fd, offset, t[whence]);
 #endif
 }
@@ -308,7 +293,7 @@ GNUNET_DISK_file_get_identifiers (const char *filename,
   fh = GNUNET_DISK_file_open(filename, GNUNET_DISK_OPEN_READ, 0);
   if (fh == NULL)
     return GNUNET_SYSERR;
-  succ = GetFileInformationByHandle(fh->h, &info);
+  succ = GetFileInformationByHandle(GNUNET_W32IO_fd_get_handle (fh->fd), &info);
   GNUNET_DISK_file_close(fh);
   if (succ)
     {
@@ -354,7 +339,7 @@ GNUNET_DISK_mktemp (const char *t)
     {
       GNUNET_asprintf (&tmpl, "%s%s", t, "XXXXXX");
     }
-#ifdef MINGW
+#if WINDOWS && !defined(__CYGWIN__)
   fn = (char *) GNUNET_malloc (MAX_PATH + 1);
   if (ERROR_SUCCESS != plibc_conv_to_win_path (tmpl, fn))
     {
@@ -398,7 +383,7 @@ GNUNET_DISK_get_blocks_available (const char *part)
       return -1;
     }
   return buf.f_bavail;
-#elif MINGW
+#elif WINDOWS
   DWORD dwDummy;
   DWORD dwBlocks;
   char szDrive[4];
@@ -532,7 +517,7 @@ GNUNET_DISK_directory_create (const char *dir)
     return GNUNET_SYSERR;
 
   len = strlen (rdir);
-#ifndef MINGW
+#if !WINDOWS || defined(__CYGWIN__)
   pos = 1;                      /* skip heading '/' */
 #else
   /* Local or Network path? */
@@ -567,7 +552,7 @@ GNUNET_DISK_directory_create (const char *dir)
             }
           if (ret == GNUNET_NO)
             {
-#ifndef MINGW
+#if !WINDOWS || defined(__CYGWIN__)
               ret = mkdir (rdir, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);  /* 755 */
 #else
               ret = mkdir (rdir);
@@ -638,15 +623,8 @@ GNUNET_DISK_file_read (const struct GNUNET_DISK_FileHandle * h, void *result,
       return GNUNET_SYSERR;
     }
 
-#ifdef MINGW
-  DWORD bytesRead;
-
-  if (!ReadFile (h->h, result, len, &bytesRead, NULL))
-    {
-      SetErrnoFromWinError (GetLastError ());
-      return GNUNET_SYSERR;
-    }
-  return bytesRead;
+#if WINDOWS
+  return GNUNET_W32IO_read (h->fd, result, len);
 #else
   return read (h->fd, result, len);
 #endif
@@ -695,15 +673,8 @@ GNUNET_DISK_file_write (const struct GNUNET_DISK_FileHandle * h,
       return GNUNET_SYSERR;
     }
 
-#ifdef MINGW
-  DWORD bytesWritten;
-
-  if (!WriteFile (h->h, buffer, n, &bytesWritten, NULL))
-    {
-      SetErrnoFromWinError (GetLastError ());
-      return GNUNET_SYSERR;
-    }
-  return bytesWritten;
+#if WINDOWS
+  return GNUNET_W32IO_write (h->fd, buffer, n);
 #else
   return write (h->fd, buffer, n);
 #endif
@@ -1122,7 +1093,7 @@ GNUNET_DISK_filename_canonicalize (char *fn)
 int
 GNUNET_DISK_file_change_owner (const char *filename, const char *user)
 {
-#ifndef MINGW
+#if !WINDOWS || defined(__CYGWIN__)
   struct passwd *pws;
 
   pws = getpwnam (user);
@@ -1158,7 +1129,7 @@ GNUNET_DISK_file_lock (struct GNUNET_DISK_FileHandle *fh, off_t lockStart,
       return GNUNET_SYSERR;
     }
 
-#ifndef MINGW
+#if !WINDOWS || defined(__CYGWIN__)
   struct flock fl;
 
   memset (&fl, 0, sizeof (struct flock));
@@ -1174,7 +1145,7 @@ GNUNET_DISK_file_lock (struct GNUNET_DISK_FileHandle *fh, off_t lockStart,
   memset (&o, 0, sizeof (OVERLAPPED));
   o.Offset = lockStart;
 
-  if (!LockFileEx (fh->h, (excl ? LOCKFILE_EXCLUSIVE_LOCK : 0)
+  if (!LockFileEx (GNUNET_W32IO_fd_get_handle (fh->fd), (excl ? LOCKFILE_EXCLUSIVE_LOCK : 0)
                    | LOCKFILE_FAIL_IMMEDIATELY, 0, lockEnd - lockStart, 0,
                    &o))
     {
@@ -1204,7 +1175,7 @@ GNUNET_DISK_file_unlock (struct GNUNET_DISK_FileHandle *fh, off_t unlockStart,
       return GNUNET_SYSERR;
     }
 
-#ifndef MINGW
+#if !WINDOWS || defined(__CYGWIN__)
   struct flock fl;
 
   memset (&fl, 0, sizeof (struct flock));
@@ -1220,7 +1191,7 @@ GNUNET_DISK_file_unlock (struct GNUNET_DISK_FileHandle *fh, off_t unlockStart,
   memset (&o, 0, sizeof (OVERLAPPED));
   o.Offset = unlockStart;
 
-  if (!UnlockFileEx (fh->h, 0, unlockEnd - unlockStart, 0, &o))
+  if (!UnlockFileEx (GNUNET_W32IO_fd_get_handle (fh->fd), 0, unlockEnd - unlockStart, 0, &o))
     {
       SetErrnoFromWinError (GetLastError ());
       return GNUNET_SYSERR;
@@ -1250,7 +1221,7 @@ GNUNET_DISK_file_open (const char *fn,
 {
   char *expfn;
   struct GNUNET_DISK_FileHandle *ret;
-#ifdef MINGW
+#if WINDOWS
   DWORD access;
   DWORD disp;
   HANDLE h;
@@ -1263,7 +1234,7 @@ GNUNET_DISK_file_open (const char *fn,
   expfn = GNUNET_STRINGS_filename_expand (fn);
   if (NULL == expfn)
     return NULL;
-#ifndef MINGW
+#if !WINDOWS || defined(__CYGWIN__)
   mode = 0;
   if (GNUNET_DISK_OPEN_READWRITE == (flags & GNUNET_DISK_OPEN_READWRITE))
     oflags = O_RDWR;            /* note: O_RDWR is NOT always O_RDONLY | O_WRONLY */
@@ -1356,9 +1327,8 @@ GNUNET_DISK_file_open (const char *fn,
 #endif
 
   ret = GNUNET_malloc (sizeof (struct GNUNET_DISK_FileHandle));
-#ifdef MINGW
-  ret->h = h;
-  ret->type = GNUNET_DISK_FILE;
+#if WINDOWS
+  ret->fd = GNUNET_W32IO_fd_from_handle (h, GNUNET_W32IO_FILE, access, 1, 1, 1);
 #else
   ret->fd = fd;
 #endif
@@ -1381,10 +1351,9 @@ GNUNET_DISK_file_close (struct GNUNET_DISK_FileHandle *h)
       return GNUNET_SYSERR;
     }
 
-#if MINGW
-  if (!CloseHandle (h->h))
+#if WINDOWS
+  if (GNUNET_W32IO_close (h->fd, 1) != 0)
     {
-      SetErrnoFromWinError (GetLastError ());
       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "close");
       GNUNET_free (h);
       return GNUNET_SYSERR;
@@ -1478,7 +1447,7 @@ GNUNET_DISK_get_home_filename (const struct GNUNET_CONFIGURATION_Handle *cfg,
  */
 struct GNUNET_DISK_MapHandle
 {
-#ifdef MINGW
+#if WINDOWS && !defined(__CYGWIN__)
   /**
    * Underlying OS handle.
    */
@@ -1521,7 +1490,7 @@ GNUNET_DISK_file_map (const struct GNUNET_DISK_FileHandle *h,
       return NULL;
     }
 
-#ifdef MINGW
+#if WINDOWS
   DWORD mapAccess, protect;
   void *ret;
 
@@ -1548,7 +1517,7 @@ GNUNET_DISK_file_map (const struct GNUNET_DISK_FileHandle *h,
     }
 
   *m = GNUNET_malloc (sizeof (struct GNUNET_DISK_MapHandle));
-  (*m)->h = CreateFileMapping (h->h, NULL, protect, 0, 0, NULL);
+  (*m)->h = CreateFileMapping (GNUNET_W32IO_fd_get_handle (h->fd), NULL, protect, 0, 0, NULL);
   if ((*m)->h == INVALID_HANDLE_VALUE)
     {
       SetErrnoFromWinError (GetLastError ());
@@ -1601,7 +1570,7 @@ GNUNET_DISK_file_unmap (struct GNUNET_DISK_MapHandle *h)
       return GNUNET_SYSERR;
     }
 
-#ifdef MINGW
+#if WINDOWS && !defined(__CYGWIN__)
   ret = UnmapViewOfFile (h->h) ? GNUNET_OK : GNUNET_SYSERR;
   if (ret != GNUNET_OK)
     SetErrnoFromWinError (GetLastError ());
@@ -1632,13 +1601,8 @@ GNUNET_DISK_file_sync (const struct GNUNET_DISK_FileHandle *h)
       return GNUNET_SYSERR;
     }
 
-#ifdef MINGW
-  int ret;
-
-  ret = FlushFileBuffers (h->h) ? GNUNET_OK : GNUNET_SYSERR;
-  if (ret != GNUNET_OK)
-    SetErrnoFromWinError (GetLastError ());
-  return ret;
+#if WINDOWS
+  return GNUNET_W32IO_fsync (h->fd) == -1 ? GNUNET_SYSERR : GNUNET_OK;
 #elif defined(FREEBSD) || defined(OPENBSD) || defined(DARWIN)
   return fsync (h->fd) == -1 ? GNUNET_SYSERR : GNUNET_OK;
 #else
@@ -1668,7 +1632,7 @@ GNUNET_DISK_pipe (int blocking, int inherit_read, int inherit_write)
   fds = (struct GNUNET_DISK_FileHandle *) &p[1];
   p->fd[0] = &fds[0];
   p->fd[1] = &fds[1];
-#ifndef MINGW
+#if !WINDOWS || defined(__CYGWIN__)
   int fd[2];
   int ret;
   int flags;
@@ -1717,51 +1681,16 @@ GNUNET_DISK_pipe (int blocking, int inherit_read, int inherit_write)
     }
 #else
   BOOL ret;
-  HANDLE tmp_handle;
+  int pipe[2];
 
-  ret = CreatePipe (&p->fd[0]->h, &p->fd[1]->h, NULL, 0);
+  ret = GNUNET_W32IO_anonymous_pipe (pipe, inherit_read == GNUNET_YES ? TRUE : FALSE, inherit_write == GNUNET_YES ? TRUE : FALSE);
   if (!ret)
     {
       GNUNET_free (p);
-      SetErrnoFromWinError (GetLastError ());
       return NULL;
     }
-  if (!DuplicateHandle (GetCurrentProcess (), p->fd[0]->h,
-		GetCurrentProcess (), &tmp_handle, 0, inherit_read == GNUNET_YES ? TRUE : FALSE,
-			DUPLICATE_SAME_ACCESS))
-	{
-	  SetErrnoFromWinError (GetLastError ());
-	  CloseHandle (p->fd[0]->h);
-	  CloseHandle (p->fd[1]->h);
-	  GNUNET_free (p);
-	  return NULL;
-	}
-	CloseHandle (p->fd[0]->h);
-	p->fd[0]->h = tmp_handle;
-
-	if (!DuplicateHandle (GetCurrentProcess (), p->fd[1]->h,
-			GetCurrentProcess (), &tmp_handle, 0, inherit_write == GNUNET_YES ? TRUE : FALSE,
-			DUPLICATE_SAME_ACCESS))
-	{
-	  SetErrnoFromWinError (GetLastError ());
-	  CloseHandle (p->fd[0]->h);
-	  CloseHandle (p->fd[1]->h);
-	  GNUNET_free (p);
-	  return NULL;
-	}
-  CloseHandle (p->fd[1]->h);
-  p->fd[1]->h = tmp_handle;
-  if (!blocking)
-    {
-      DWORD mode;
-
-      mode = PIPE_NOWAIT;
-      SetNamedPipeHandleState (p->fd[0]->h, &mode, NULL, NULL);
-      SetNamedPipeHandleState (p->fd[1]->h, &mode, NULL, NULL);
-      /* this always fails on Windows 95, so we don't care about error handling */
-    }
-  p->fd[0]->type = GNUNET_PIPE;
-  p->fd[1]->type = GNUNET_PIPE;
+  p->fd[0]->fd = pipe[0];
+  p->fd[1]->fd = pipe[1];
 #endif
   return p;
 }
@@ -1781,26 +1710,26 @@ GNUNET_DISK_pipe_close_end (struct GNUNET_DISK_PipeHandle *p,
   int ret = GNUNET_OK;
   int save;
 
-#ifdef MINGW
+#if WINDOWS
+  save = 0;
   if (end == GNUNET_DISK_PIPE_END_READ)
     {
-      if (!CloseHandle (p->fd[0]->h))
+      if (0 != GNUNET_W32IO_close (p->fd[0]->fd, 1))
         {
-          SetErrnoFromWinError (GetLastError ());
           ret = GNUNET_SYSERR;
+          save = errno;
         }
-      p->fd[0]->h = INVALID_HANDLE_VALUE;
+      p->fd[0]->fd = -1;
     }
   else if (end == GNUNET_DISK_PIPE_END_WRITE)
     {
-      if (!CloseHandle (p->fd[1]->h))
+      if (0 != GNUNET_W32IO_close (p->fd[1]->fd, 1))
         {
-          SetErrnoFromWinError (GetLastError ());
           ret = GNUNET_SYSERR;
+          save = errno;
         }
-      p->fd[1]->h = INVALID_HANDLE_VALUE;
+      p->fd[1]->fd = -1;
     }
-  save = errno;
 #else
   save = 0;
   if (end == GNUNET_DISK_PIPE_END_READ)
@@ -1838,18 +1767,25 @@ GNUNET_DISK_pipe_close (struct GNUNET_DISK_PipeHandle *p)
   int ret = GNUNET_OK;
   int save;
 
-#ifdef MINGW
-  if (!CloseHandle (p->fd[0]->h))
+#if WINDOWS
+  save = 0;
+  if (p->fd[0]->fd != -1)
     {
-      SetErrnoFromWinError (GetLastError ());
-      ret = GNUNET_SYSERR;
+      if (0 != GNUNET_W32IO_close (p->fd[0]->fd, 1))
+        {
+          ret = GNUNET_SYSERR;
+          save = errno;
+        }
     }
-  if (!CloseHandle (p->fd[1]->h))
+
+  if (p->fd[1]->fd != -1)
     {
-      SetErrnoFromWinError (GetLastError ());
-      ret = GNUNET_SYSERR;
+      if (0 != GNUNET_W32IO_close (p->fd[1]->fd, 1))
+        {
+          ret = GNUNET_SYSERR;
+          save = errno;
+        }
     }
-  save = errno;
 #else
   save = 0;
   if (p->fd[0]->fd != -1)
@@ -1888,7 +1824,7 @@ GNUNET_DISK_npipe_open (const char *fn,
                        enum GNUNET_DISK_OpenFlags flags,
                        enum GNUNET_DISK_AccessPermissions perm)
 {
-#ifdef MINGW
+#if WINDOWS && !defined(__CYGWIN__)
   struct GNUNET_DISK_FileHandle *ret;
   HANDLE h;
   DWORD openMode;
@@ -1916,7 +1852,7 @@ GNUNET_DISK_npipe_open (const char *fn,
     }
 
   ret = GNUNET_malloc(sizeof(*ret));
-  ret->h = h;
+  ret->fd = GNUNET_W32IO_fd_from_handle (h, GNUNET_W32IO_NAMED_PIPE, (openMode & PIPE_ACCESS_OUTBOUND ? GENERIC_WRITE : 0) | (openMode & PIPE_ACCESS_INBOUND ? GENERIC_READ : 0), 0, 0, 0);
 
   return ret;
 #else
@@ -1940,19 +1876,10 @@ GNUNET_DISK_npipe_open (const char *fn,
 int
 GNUNET_DISK_npipe_close (struct GNUNET_DISK_FileHandle *pipe)
 {
-#ifndef MINGW
+#if !WINDOWS || defined(__CYGWIN__)
   return close(pipe->fd) == 0 ? GNUNET_OK : GNUNET_SYSERR;
 #else
-  BOOL ret;
-
-  ret = CloseHandle(pipe->h);
-  if (!ret)
-    {
-      SetErrnoFromWinError(GetLastError());
-      return GNUNET_SYSERR;
-    }
-  else
-    return GNUNET_OK;
+  return GNUNET_W32IO_close (pipe->fd, 1);
 #endif
 }
 
@@ -1992,15 +1919,9 @@ int
 GNUNET_DISK_internal_file_handle_ (const struct GNUNET_DISK_FileHandle *fh,
                                    void *dst, size_t dst_len)
 {
-#ifdef MINGW
-  if (dst_len < sizeof (HANDLE))
-    return GNUNET_SYSERR;
-  *((HANDLE *) dst) = fh->h;
-#else
   if (dst_len < sizeof (int))
     return GNUNET_SYSERR;
   *((int *) dst) = fh->fd;
-#endif
 
   return GNUNET_OK;
 }
diff --git a/src/util/disk.h b/src/util/disk.h
index 093d704..73b84f4 100644
--- a/src/util/disk.h
+++ b/src/util/disk.h
@@ -34,25 +34,10 @@
  */ 
 struct GNUNET_DISK_FileHandle 
 {
-  
-#ifdef MINGW
-  /**
-   * File handle under W32.
-   */ 
-  HANDLE h;
-
-  /**
-   * Type
-   */
-  enum {GNUNET_DISK_FILE, GNUNET_PIPE} type;
-#else
-
   /**
    * File handle on other OSes.
    */ 
   int fd;
-   
-#endif                          /* 
 */
 };
 



 /**
diff --git a/src/util/gnunet-service-resolver.c b/src/util/gnunet-service-resolver.c
index f72b70d..97de8a6 100644
--- a/src/util/gnunet-service-resolver.c
+++ b/src/util/gnunet-service-resolver.c
@@ -250,7 +250,7 @@ getaddrinfo_resolve (struct GNUNET_SERVER_TransmitContext *tc,
 
   memset (&hints, 0, sizeof (struct addrinfo));
 // FIXME in PlibC
-#ifndef MINGW
+#if !WINDOWS || defined(__CYGWIN__)
   hints.ai_family = domain;
 #else
   hints.ai_family = AF_INET;
@@ -266,7 +266,7 @@ getaddrinfo_resolve (struct GNUNET_SERVER_TransmitContext *tc,
                                          AF_INET6) ? "IPv6" : "any"),
                   gai_strerror (s));
       if ((s == EAI_BADFLAGS) || (s == EAI_MEMORY) 
-#ifndef MINGW
+#if !WINDOWS || defined(__CYGWIN__)
           || (s == EAI_SYSTEM)
 #else
           // FIXME NILS
@@ -466,7 +466,7 @@ handle_get (void *cls,
     {
 #if DEBUG_RESOLVER
       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-                  _("Resolver asked to look up IP address.\n"));
+                  _("Resolver asked to look up IP address `%s'.\n"), GNUNET_a2s ((const struct sockaddr *) &msg[1], size));
 #endif
       get_ip_as_string (client, (const struct sockaddr *) &msg[1], size);
     }
diff --git a/src/util/network.c b/src/util/network.c
index 3b76a35..af15862 100644
--- a/src/util/network.c
+++ b/src/util/network.c
@@ -28,6 +28,7 @@
 #include "gnunet_disk_lib.h"
 #include "disk.h"
 #include "gnunet_container_lib.h"
+#include "w32io.h"
 
 #define DEBUG_NETWORK GNUNET_NO
 
@@ -38,13 +39,8 @@
 
 struct GNUNET_NETWORK_Handle
 {
-#ifndef MINGW
   int fd;
 
-#else
-  SOCKET fd;
-#endif
-
   /**
    * Address family / domain.
    */
@@ -60,23 +56,25 @@ struct GNUNET_NETWORK_FDSet
    */
   int nsds;
 
+#if WINDOWS
   /**
    * Bitset with the descriptors.
    */
-  fd_set sds;
-
-#ifdef WINDOWS
+  w32fd_set sds;
+#else
   /**
-   * Linked list of handles
+   * Bitset with the descriptors.
    */
-  struct GNUNET_CONTAINER_SList *handles;
+  fd_set sds;
 #endif
-
 };
 
 #ifndef FD_COPY
 #define FD_COPY(s, d) (memcpy ((d), (s), sizeof (fd_set)))
 #endif
+#if WINDOWS
+#define W32_FD_COPY(s, d) (memcpy ((d), (s), sizeof (w32fd_set)))
+#endif
 
 
 /**
@@ -89,11 +87,11 @@ static int
 socket_set_blocking (struct GNUNET_NETWORK_Handle *fd, int doBlock)
 {
 
-#if MINGW
+#if WINDOWS && !defined(__CYGWIN__)
   u_long mode;
   mode = !doBlock;
-  if (ioctlsocket (fd->fd, FIONBIO, &mode) == SOCKET_ERROR)
 
+  if (ioctlsocket ((SOCKET) GNUNET_W32IO_fd_get_handle (fd->fd), FIONBIO, &mode) == SOCKET_ERROR)
     {
       SetErrnoFromWinsockError (WSAGetLastError ());
       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "ioctlsocket");
@@ -102,7 +100,7 @@ socket_set_blocking (struct GNUNET_NETWORK_Handle *fd, int doBlock)
   return GNUNET_OK;
 
 #else
-  /* not MINGW */
+  /* not WINDOWS */
   int flags = fcntl (fd->fd, F_GETFL);
   if (flags == -1)
 
@@ -126,7 +124,7 @@ socket_set_blocking (struct GNUNET_NETWORK_Handle *fd, int doBlock)
 }
 
 
-#ifndef MINGW
+#if !WINDOWS || defined(__CYGWIN__)
 /**
  * Make a socket non-inheritable to child processes
  *
@@ -179,13 +177,13 @@ socket_set_nosigpipe (const struct GNUNET_NETWORK_Handle *h)
 static void
 socket_set_nodelay (const struct GNUNET_NETWORK_Handle *h)
 {
-#ifndef WINDOWS  
+#if !WINDOWS || defined(__CYGWIN__)
   int value = 1;
   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)))
+  if (0 != setsockopt ((SOCKET) GNUNET_W32IO_fd_get_handle (h->fd), IPPROTO_TCP, TCP_NODELAY, abs_value, sizeof (abs_value)))
     GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "setsockopt");
 #endif	
 }
@@ -207,17 +205,26 @@ GNUNET_NETWORK_socket_accept (const struct GNUNET_NETWORK_Handle *desc,
   struct GNUNET_NETWORK_Handle *ret;
 
   ret = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle));
+#if !WINDOWS || defined(__CYGWIN__)
   ret->fd = accept (desc->fd, address, address_len);
+#else
+  ret->fd = GNUNET_W32IO_accept (desc->fd, address, address_len);
+#endif
   ret->af = address->sa_family;
   if (ret->fd == INVALID_SOCKET)
     {
-#ifdef MINGW
-      SetErrnoFromWinsockError (WSAGetLastError ());
-#endif
       GNUNET_free (ret);
       return NULL;
     }
-#ifndef MINGW
+#if WINDOWS && !defined(__CYGWIN__)
+  if (ret->fd >= W32_FD_SETSIZE)
+    {
+      GNUNET_break (0 == GNUNET_W32IO_close (ret->fd, 1));
+      GNUNET_free (ret);
+      errno = EMFILE;
+      return NULL;
+    }
+#else
   if (ret->fd >= FD_SETSIZE)
     {
       GNUNET_break (0 == close (ret->fd));
@@ -227,16 +234,14 @@ GNUNET_NETWORK_socket_accept (const struct GNUNET_NETWORK_Handle *desc,
     }
 #endif
   if (GNUNET_SYSERR == socket_set_blocking (ret, GNUNET_NO))
-
     {
-
       /* we might want to treat this one as fatal... */
       GNUNET_break (0);
       GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (ret));
       return NULL;
     }
 
-#ifndef MINGW
+#if !WINDOWS || defined(__CYGWIN__)
   if (GNUNET_OK != socket_set_inheritable (ret))
     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
                          "socket_set_inheritable");
@@ -269,19 +274,25 @@ GNUNET_NETWORK_socket_bind (struct GNUNET_NETWORK_Handle *desc,
 #ifdef IPV6_V6ONLY 
 #ifdef IPPROTO_IPV6
   const int on = 1;
+#if !WINDOWS || defined(__CYGWIN__)
   if (desc->af == AF_INET6)
     setsockopt (desc->fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof (on));
+#else
+  if (desc->af == AF_INET6)
+    setsockopt (GNUNET_W32IO_fd_get_handle (desc->fd), IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof (on));
+#endif
 #if 0
   /* is this needed or desired? or done elsewhere? */
   setsockopt (desc->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on));
 #endif
 #endif
 #endif
+#if !WINDOWS || defined(__CYGWIN__)
   ret = bind (desc->fd, address, address_len);
-#ifdef MINGW
-  if (SOCKET_ERROR == ret)
-    SetErrnoFromWinsockError (WSAGetLastError ());
 #else
+  ret = GNUNET_W32IO_bind (desc->fd, address, address_len);
+#endif
+#if !WINDOWS || defined(__CYGWIN__)
 #ifndef LINUX
   if ( (ret == 0) && (address->sa_family == AF_UNIX))
     {
@@ -307,9 +318,8 @@ GNUNET_NETWORK_socket_close (struct GNUNET_NETWORK_Handle *desc)
 {
   int ret;
 
-#ifdef MINGW
-  ret = closesocket (desc->fd);
-  SetErrnoFromWinsockError (WSAGetLastError ());
+#if WINDOWS && !defined(__CYGWIN__)
+  ret = GNUNET_W32IO_close (desc->fd, 1);
 #else
   ret = close (desc->fd);
 #endif
@@ -327,8 +337,16 @@ GNUNET_NETWORK_socket_close (struct GNUNET_NETWORK_Handle *desc)
 struct GNUNET_NETWORK_Handle *
 GNUNET_NETWORK_socket_box_native (int fd)
 {
-#if MINGW
-  return NULL;
+#if WINDOWS && !defined(__CYGWIN__)
+  struct GNUNET_NETWORK_Handle *ret;
+
+  if (GNUNET_W32IO_find_handle_type ((HANDLE) fd) != GNUNET_W32IO_SOCKET)
+    return NULL; /* invalid FD */
+  ret = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle)); 
+  /* The arguments (three 1's at the end) are subject to discussion */
+  ret->fd = GNUNET_W32IO_fd_from_handle ((HANDLE) fd, GNUNET_W32IO_SOCKET, GENERIC_READ | GENERIC_WRITE, 1, 1, 1);
+  ret->af = AF_UNSPEC;
+  return ret;
 #else
   struct GNUNET_NETWORK_Handle *ret;
 
@@ -341,7 +359,6 @@ GNUNET_NETWORK_socket_box_native (int fd)
 #endif
 }
 
-
 /**
  * Connect a socket
  * @param desc socket
@@ -355,16 +372,10 @@ GNUNET_NETWORK_socket_connect (const struct GNUNET_NETWORK_Handle *desc,
                                socklen_t address_len)
 {
   int ret;
+#if WINDOWS && !defined(__CYGWIN__)
+  ret = GNUNET_W32IO_connect (desc->fd, address, address_len);
+#else
   ret = connect (desc->fd, address, address_len);
-
-#ifdef MINGW
-  if (SOCKET_ERROR == ret)
-
-    {
-      SetErrnoFromWinsockError (WSAGetLastError ());
-      if (errno == EWOULDBLOCK)
-        errno = EINPROGRESS;
-    }
 #endif
   return ret == 0 ? GNUNET_OK : GNUNET_SYSERR;
 }
@@ -386,15 +397,15 @@ GNUNET_NETWORK_socket_getsockopt (const struct GNUNET_NETWORK_Handle *desc,
                                   socklen_t * optlen)
 {
   int ret;
-  ret = getsockopt (desc->fd, level, optname, optval, optlen);
-
-#ifdef MINGW
+#if WINDOWS && !defined(__CYGWIN__)
+  ret = getsockopt ((SOCKET) GNUNET_W32IO_fd_get_handle (desc->fd), level, optname, optval, optlen);
   if (ret == 0 && level == SOL_SOCKET && optname == SO_ERROR)
     *((int *) optval) = GetErrnoFromWinsockError (*((int *) optval));
 
   else if (SOCKET_ERROR == ret)
     SetErrnoFromWinsockError (WSAGetLastError ());
-
+#else
+  ret = getsockopt (desc->fd, level, optname, optval, optlen);
 #endif
   return ret == 0 ? GNUNET_OK : GNUNET_SYSERR;
 }
@@ -411,12 +422,10 @@ GNUNET_NETWORK_socket_listen (const struct GNUNET_NETWORK_Handle *desc,
                               int backlog)
 {
   int ret;
+#if WINDOWS && !defined(__CYGWIN__)
+  ret = GNUNET_W32IO_listen (desc->fd, backlog);
+#else
   ret = listen (desc->fd, backlog);
-
-#ifdef MINGW
-  if (SOCKET_ERROR == ret)
-    SetErrnoFromWinsockError (WSAGetLastError ());
-
 #endif
   return ret == 0 ? GNUNET_OK : GNUNET_SYSERR;
 }
@@ -435,13 +444,13 @@ GNUNET_NETWORK_socket_recvfrom_amount (const struct GNUNET_NETWORK_Handle
   int error;
 
   /* How much is there to be read? */
-#ifndef WINDOWS
+#if !WINDOWS || defined(__CYGWIN__)
   int pending;
   error = ioctl (desc->fd, FIONREAD, &pending);
   if (error == 0)
-#else
+#elif WINDOWS
   u_long pending;
-  error = ioctlsocket (desc->fd, FIONREAD, &pending);
+  error = ioctlsocket ((SOCKET) GNUNET_W32IO_fd_get_handle (desc->fd), FIONREAD, &pending);
   if (error != SOCKET_ERROR)
 #endif
     return pending;
@@ -470,13 +479,12 @@ GNUNET_NETWORK_socket_recvfrom (const struct GNUNET_NETWORK_Handle * desc,
 
 #ifdef MSG_DONTWAIT
   flags |= MSG_DONTWAIT;
-
 #endif
+#if WINDOWS && !defined(__CYGWIN__)
+  ret = GNUNET_W32IO_recvfrom (desc->fd, buffer, length, flags, src_addr, addrlen);
+#else
   ret = recvfrom (desc->fd, buffer, length, flags, src_addr, addrlen);
-#ifdef MINGW
-  if (SOCKET_ERROR == ret)
-    SetErrnoFromWinsockError (WSAGetLastError ());
-#endif 
+#endif
   return ret;
 }
 
@@ -498,10 +506,10 @@ GNUNET_NETWORK_socket_recv (const struct GNUNET_NETWORK_Handle * desc,
 #ifdef MSG_DONTWAIT
   flags |= MSG_DONTWAIT;
 #endif
+#if WINDOWS && !defined(__CYGWIN__)
+  ret = GNUNET_W32IO_recv (desc->fd, buffer, length, flags);
+#else
   ret = recv (desc->fd, buffer, length, flags);
-#ifdef MINGW
-  if (SOCKET_ERROR == ret)
-    SetErrnoFromWinsockError (WSAGetLastError ());
 #endif
   return ret;
 }
@@ -525,19 +533,16 @@ GNUNET_NETWORK_socket_send (const struct GNUNET_NETWORK_Handle * desc,
 
 #ifdef MSG_DONTWAIT
   flags |= MSG_DONTWAIT;
-
 #endif /*  */
 #ifdef MSG_NOSIGNAL
   flags |= MSG_NOSIGNAL;
-
 #endif /*  */
+#if WINDOWS && !defined(__CYGWIN__)
+  ret = desc->fd;
+  ret = GNUNET_W32IO_send (ret, buffer, length, flags);
+#else
   ret = send (desc->fd, buffer, length, flags);
-
-#ifdef MINGW
-  if (SOCKET_ERROR == ret)
-    SetErrnoFromWinsockError (WSAGetLastError ());
-
-#endif /*  */
+#endif
   return ret;
 }
 
@@ -569,10 +574,10 @@ GNUNET_NETWORK_socket_sendto (const struct GNUNET_NETWORK_Handle * desc,
 #ifdef MSG_NOSIGNAL
   flags |= MSG_NOSIGNAL;
 #endif
+#if WINDOWS && !defined(__CYGWIN__)
+  ret = GNUNET_W32IO_sendto (desc->fd, message, length, flags, dest_addr, dest_len);
+#else
   ret = sendto (desc->fd, message, length, flags, dest_addr, dest_len);
-#ifdef MINGW
-  if (SOCKET_ERROR == ret)
-    SetErrnoFromWinsockError (WSAGetLastError ());
 #endif
   return ret;
 }
@@ -595,10 +600,12 @@ GNUNET_NETWORK_socket_setsockopt (struct GNUNET_NETWORK_Handle *fd,
 {
   int ret;
 
-  ret = setsockopt (fd->fd, level, option_name, option_value, option_len);
-#ifdef MINGW
+#if WINDOWS && !defined(__CYGWIN__)
+  ret = setsockopt ((SOCKET) GNUNET_W32IO_fd_get_handle (fd->fd), level, option_name, option_value, option_len);
   if (SOCKET_ERROR == ret)
     SetErrnoFromWinsockError (WSAGetLastError ());
+#else
+  ret = setsockopt (fd->fd, level, option_name, option_value, option_len);
 #endif
   return ret == 0 ? GNUNET_OK : GNUNET_SYSERR;
 }
@@ -620,17 +627,30 @@ GNUNET_NETWORK_socket_create (int domain, int type, int protocol)
   struct GNUNET_NETWORK_Handle *ret;
   ret = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle));
   ret->af = domain;
+#if WINDOWS && !defined(__CYGWIN__)
+  ret->fd = GNUNET_W32IO_fd_from_handle ((HANDLE) WSASocket (domain, type, protocol, NULL, 0, WSA_FLAG_OVERLAPPED), GNUNET_W32IO_SOCKET, GENERIC_READ | GENERIC_WRITE, 0, 0, 0);
+  if (ret->fd == -1)
+    {
+      GNUNET_free (ret);
+      return NULL;
+    }
+#else
   ret->fd = socket (domain, type, protocol);
   if (INVALID_SOCKET == ret->fd)
     {
-#ifdef MINGW
-      SetErrnoFromWinsockError (WSAGetLastError ());
+      GNUNET_free (ret);
+      return NULL;
+    }
 #endif
+#if WINDOWS && !defined(__CYGWIN__)
+  if (ret->fd >= W32_FD_SETSIZE)
+    {
+      GNUNET_break (0 == GNUNET_W32IO_close (ret->fd, 1));
       GNUNET_free (ret);
+      errno = EMFILE;
       return NULL;
     }
-
-#ifndef MINGW
+#else
   if (ret->fd >= FD_SETSIZE)
     {
       GNUNET_break (0 == close (ret->fd));
@@ -638,7 +658,6 @@ GNUNET_NETWORK_socket_create (int domain, int type, int protocol)
       errno = EMFILE;
       return NULL;
     }
-
 #endif
   if (GNUNET_SYSERR == socket_set_blocking (ret, GNUNET_NO))
     {
@@ -648,7 +667,7 @@ GNUNET_NETWORK_socket_create (int domain, int type, int protocol)
       return NULL;
     }
 
-#ifndef MINGW
+#if !WINDOWS || defined(__CYGWIN__)
   if (GNUNET_OK != socket_set_inheritable (ret))
     GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
                          "socket_set_inheritable");
@@ -665,7 +684,6 @@ GNUNET_NETWORK_socket_create (int domain, int type, int protocol)
   return ret;
 }
 
-
 /**
  * Shut down socket operations
  * @param desc socket
@@ -677,10 +695,10 @@ GNUNET_NETWORK_socket_shutdown (struct GNUNET_NETWORK_Handle *desc, int how)
 {
   int ret;
 
+#if WINDOWS && !defined(__CYGWIN__)
+  ret = GNUNET_W32IO_shutdown (desc->fd, how);
+#else
   ret = shutdown (desc->fd, how);
-#ifdef MINGW
-  if (ret != 0)
-    SetErrnoFromWinsockError (WSAGetLastError ());
 #endif
   return ret == 0 ? GNUNET_OK : GNUNET_SYSERR;
 }
@@ -693,11 +711,12 @@ GNUNET_NETWORK_socket_shutdown (struct GNUNET_NETWORK_Handle *desc, int how)
 void
 GNUNET_NETWORK_fdset_zero (struct GNUNET_NETWORK_FDSet *fds)
 {
+#if WINDOWS && !defined(__CYGWIN__)
+  W32_FD_ZERO(&fds->sds);
+#else
   FD_ZERO (&fds->sds);
-  fds->nsds = 0;
-#ifdef MINGW
-  GNUNET_CONTAINER_slist_clear (fds->handles);
 #endif
+  fds->nsds = 0;
 }
 
 /**
@@ -709,7 +728,11 @@ void
 GNUNET_NETWORK_fdset_set (struct GNUNET_NETWORK_FDSet *fds,
                           const struct GNUNET_NETWORK_Handle *desc)
 {
+#if WINDOWS && !defined(__CYGWIN__)
+  W32_FD_SET(desc->fd, &fds->sds);
+#else
   FD_SET (desc->fd, &fds->sds);
+#endif
   if (desc->fd + 1 > fds->nsds)
     fds->nsds = desc->fd + 1;
 }
@@ -725,7 +748,11 @@ int
 GNUNET_NETWORK_fdset_isset (const struct GNUNET_NETWORK_FDSet *fds,
                             const struct GNUNET_NETWORK_Handle *desc)
 {
+#if WINDOWS && !defined(__CYGWIN__)
+  return W32_FD_ISSET(desc->fd, &fds->sds);
+#else
   return FD_ISSET (desc->fd, &fds->sds);
+#endif
 }
 
 
@@ -739,6 +766,16 @@ GNUNET_NETWORK_fdset_add (struct GNUNET_NETWORK_FDSet *dst,
                           const struct GNUNET_NETWORK_FDSet *src)
 {
   int nfds;
+#if WINDOWS && !defined(__CYGWIN__)
+  for (nfds = src->nsds; nfds > 0; nfds--)
+    if (W32_FD_ISSET(nfds, &src->sds))
+
+      {
+        W32_FD_SET(nfds, &dst->sds);
+        if (nfds + 1 > dst->nsds)
+          dst->nsds = nfds + 1;
+      }
+#else
   for (nfds = src->nsds; nfds > 0; nfds--)
     if (FD_ISSET (nfds, &src->sds))
 
@@ -747,8 +784,6 @@ GNUNET_NETWORK_fdset_add (struct GNUNET_NETWORK_FDSet *dst,
         if (nfds + 1 > dst->nsds)
           dst->nsds = nfds + 1;
       }
-#ifdef MINGW
-  GNUNET_CONTAINER_slist_append (dst->handles, src->handles);
 #endif
 }
 
@@ -763,13 +798,12 @@ void
 GNUNET_NETWORK_fdset_copy (struct GNUNET_NETWORK_FDSet *to,
                            const struct GNUNET_NETWORK_FDSet *from)
 {
+#if WINDOWS && !defined(__CYGWIN__)
+  W32_FD_COPY(&from->sds, &to->sds);
+#else
   FD_COPY (&from->sds, &to->sds);
-  to->nsds = from->nsds;
-
-#ifdef MINGW
-  GNUNET_CONTAINER_slist_clear (to->handles);
-  GNUNET_CONTAINER_slist_append (to->handles, from->handles);
 #endif
+  to->nsds = from->nsds;
 }
 
 int
@@ -789,7 +823,11 @@ void
 GNUNET_NETWORK_fdset_copy_native (struct GNUNET_NETWORK_FDSet *to,
                                   const fd_set * from, int nfds)
 {
+#if WINDOWS && !defined(__CYGWIN__)
+  W32_FD_COPY(from, &to->sds);
+#else
   FD_COPY (from, &to->sds);
+#endif
   to->nsds = nfds;
 }
 
@@ -803,7 +841,11 @@ GNUNET_NETWORK_fdset_copy_native (struct GNUNET_NETWORK_FDSet *to,
 void GNUNET_NETWORK_fdset_set_native (struct GNUNET_NETWORK_FDSet *to,
 				      int nfd)
 {
+#if WINDOWS && !defined(__CYGWIN__)
+  W32_FD_SET(nfd, &to->sds);
+#else
   FD_SET (nfd, &to->sds);
+#endif
   to->nsds = GNUNET_MAX (nfd + 1, to->nsds);
 }
 
@@ -821,7 +863,11 @@ GNUNET_NETWORK_fdset_test_native (const struct GNUNET_NETWORK_FDSet *to,
 {
   if ( (nfd == -1) || (to == NULL) )
     return GNUNET_NO;
+#if WINDOWS && !defined(__CYGWIN__)
+  return W32_FD_ISSET(nfd, &to->sds) ? GNUNET_YES : GNUNET_NO;
+#else
   return FD_ISSET (nfd, &to->sds) ? GNUNET_YES : GNUNET_NO;
+#endif
 }
 
 
@@ -834,19 +880,16 @@ void
 GNUNET_NETWORK_fdset_handle_set (struct GNUNET_NETWORK_FDSet *fds,
                                  const struct GNUNET_DISK_FileHandle *h)
 {
-#ifdef MINGW
-  GNUNET_CONTAINER_slist_add (fds->handles,
-                              GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT,
-                              h, sizeof (struct GNUNET_DISK_FileHandle));
-
-#else
   int fd;
   GNUNET_DISK_internal_file_handle_ (h, &fd, sizeof (int));
+#if WINDOWS && !defined(__CYGWIN__)
+  W32_FD_SET(fd, &fds->sds);
+#else
   FD_SET (fd, &fds->sds);
+#endif
   if (fd + 1 > fds->nsds)
     fds->nsds = fd + 1;
 
-#endif
 }
 
 
@@ -861,9 +904,8 @@ GNUNET_NETWORK_fdset_handle_isset (const struct GNUNET_NETWORK_FDSet *fds,
                                    const struct GNUNET_DISK_FileHandle *h)
 {
 
-#ifdef MINGW
-  return GNUNET_CONTAINER_slist_contains (fds->handles, h,
-                                          sizeof (struct GNUNET_DISK_FileHandle));
+#if WINDOWS && !defined(__CYGWIN__)
+  return W32_FD_ISSET (h->fd, &fds->sds);
 #else
   return FD_ISSET (h->fd, &fds->sds);
 #endif
@@ -880,7 +922,7 @@ int
 GNUNET_NETWORK_fdset_overlap (const struct GNUNET_NETWORK_FDSet *fds1,
                               const struct GNUNET_NETWORK_FDSet *fds2)
 {
-#ifndef MINGW
+#if !WINDOWS || defined(__CYGWIN__)
   int nfds;
 
   nfds = fds1->nsds;
@@ -893,35 +935,17 @@ GNUNET_NETWORK_fdset_overlap (const struct GNUNET_NETWORK_FDSet *fds1,
 	return GNUNET_YES;
     }
 #else
-  struct GNUNET_CONTAINER_SList_Iterator *it;
-  struct GNUNET_DISK_FileHandle *h;
-  int i;
-  int j;
-
-  /*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... */
+  int nfds;
 
-  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)
+  nfds = fds1->nsds;
+  if (nfds > fds2->nsds)
+    nfds = fds2->nsds;
+  while (nfds > 0)
     {
-      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);
+      nfds--;
+      if (W32_FD_ISSET(nfds, &fds1->sds) && W32_FD_ISSET(nfds, &fds2->sds))
+	return GNUNET_YES;
     }
-  GNUNET_CONTAINER_slist_iter_destroy (it);
 #endif
   return GNUNET_NO;
 }
@@ -936,9 +960,6 @@ GNUNET_NETWORK_fdset_create ()
 {
   struct GNUNET_NETWORK_FDSet *fds;
   fds = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_FDSet));
-#ifdef MINGW
-  fds->handles = GNUNET_CONTAINER_slist_create ();
-#endif
   GNUNET_NETWORK_fdset_zero (fds);
   return fds;
 }
@@ -951,9 +972,6 @@ GNUNET_NETWORK_fdset_create ()
 void
 GNUNET_NETWORK_fdset_destroy (struct GNUNET_NETWORK_FDSet *fds)
 {
-#ifdef MINGW
-  GNUNET_CONTAINER_slist_destroy (fds->handles);
-#endif
   GNUNET_free (fds);
 }
 
@@ -972,33 +990,18 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds,
                               const struct GNUNET_TIME_Relative timeout)
 {
   int nfds;
-#ifdef MINGW
-  int handles;
-#endif
   nfds = 0;
-#ifdef MINGW
-  handles = 0;
-#endif
   if (NULL != rfds)
     {
       nfds = rfds->nsds;
-#ifdef MINGW
-      handles = GNUNET_CONTAINER_slist_count (rfds->handles);
-#endif
     }
   if (NULL != wfds)
     {
       nfds = GNUNET_MAX (nfds, wfds->nsds);
-#ifdef MINGW
-      handles += GNUNET_CONTAINER_slist_count (wfds->handles);
-#endif
     }
   if (NULL != efds)
     {
       nfds = GNUNET_MAX (nfds, efds->nsds);
-#ifdef MINGW
-      handles += GNUNET_CONTAINER_slist_count (efds->handles);
-#endif
     }
 
   struct timeval tv;
@@ -1006,9 +1009,6 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds,
   tv.tv_usec =
     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_log (GNUNET_ERROR_TYPE_ERROR,
@@ -1017,244 +1017,20 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds,
                   "select");
       GNUNET_break (0);
     }
-#ifndef MINGW
-  return select (nfds,
+#if WINDOWS && !defined(__CYGWIN__)
+  return GNUNET_W32IO_select (nfds,
                  (rfds != NULL) ? &rfds->sds : NULL,
                  (wfds != NULL) ? &wfds->sds : NULL,
                  (efds != NULL) ? &efds->sds : NULL,
                  (timeout.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
                  ? NULL : &tv);
-
 #else
-  DWORD limit;
-  fd_set sock_read, sock_write, sock_except;
-  fd_set aread, awrite, aexcept;
-  struct GNUNET_CONTAINER_SList *handles_read, *handles_write,
-    *handles_except;
-
-  int i;
-  struct timeval tvslice;
-  int retcode;
-  DWORD ms_total;
-
-#define SAFE_FD_ISSET(fd, set)  (set != NULL && FD_ISSET(fd, set))
-
-  /* calculate how long we need to wait in milliseconds */
-  if (timeout.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
-    ms_total = INFINITE;
-
-  else
-    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))
-
-    {
-      Sleep (ms_total);
-      return 0;
-    }
-
-  handles_read = GNUNET_CONTAINER_slist_create ();
-  handles_write = GNUNET_CONTAINER_slist_create ();
-  handles_except = GNUNET_CONTAINER_slist_create ();
-
-  if (rfds)
-    sock_read = rfds->sds;
-  else
-    FD_ZERO (&sock_read);
-  if (wfds)
-    sock_write = wfds->sds;
-  else
-    FD_ZERO (&sock_write);
-  if (efds)
-    sock_except = efds->sds;
-  else
-    FD_ZERO (&sock_except);
-
-  /* multiplex between winsock select() and waiting on the handles */
-  FD_ZERO (&aread);
-  FD_ZERO (&awrite);
-  FD_ZERO (&aexcept);
-  limit = GetTickCount () + ms_total;
-
-  do
-    {
-      retcode = 0;
-      if (nfds > 0)
-
-        {
-
-          /* overwrite the zero'd sets here; the select call
-           * will clear those that are not active */
-          FD_COPY (&sock_read, &aread);
-          FD_COPY (&sock_write, &awrite);
-          FD_COPY (&sock_except, &aexcept);
-          tvslice.tv_sec = 0;
-          tvslice.tv_usec = 100000;
-          if ((retcode =
-               select (nfds + 1, &aread, &awrite, &aexcept,
-                       &tvslice)) == SOCKET_ERROR)
-
-            {
-              SetErrnoFromWinsockError (WSAGetLastError ());
-              if (errno == ENOTSOCK)
-                errno = EBADF;
-
-#if DEBUG_NETWORK
-              GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "select");
-
-#endif
-              goto select_loop_end;
-            }
-        }
-
-      /* Poll read pipes */
-      if (rfds)
-
-        {
-          struct GNUNET_CONTAINER_SList_Iterator *i;
-          for (i = GNUNET_CONTAINER_slist_begin (rfds->handles);
-               GNUNET_CONTAINER_slist_end (i) != GNUNET_YES;
-               GNUNET_CONTAINER_slist_next (i))
-
-            {
-              struct GNUNET_DISK_FileHandle *fh;
-              DWORD dwBytes;
-              fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (i, NULL);
-              if (fh->type == GNUNET_PIPE)
-                {
-                  if (!PeekNamedPipe (fh->h, NULL, 0, NULL, &dwBytes, NULL))
-                    {
-                      retcode = -1;
-                      SetErrnoFromWinError (GetLastError ());
-
-    #if DEBUG_NETWORK
-                      GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
-                                           "PeekNamedPipe");
-
-    #endif
-                      goto select_loop_end;
-                    }
-                  else if (dwBytes)
-
-                    {
-                      GNUNET_CONTAINER_slist_add (handles_read,
-                                                  GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT,
-                                                  fh, sizeof (struct GNUNET_DISK_FileHandle));
-                      retcode++;
-                    }
-                }
-              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,
-                                              fh, sizeof (struct GNUNET_DISK_FileHandle));
-                }
-            }
-          GNUNET_CONTAINER_slist_iter_destroy (i);
-        }
-
-      /* Poll for faulty pipes */
-      if (efds)
-
-        {
-          struct GNUNET_CONTAINER_SList_Iterator *i;
-          for (i = GNUNET_CONTAINER_slist_begin (efds->handles);
-               GNUNET_CONTAINER_slist_end (i) != GNUNET_YES;
-               GNUNET_CONTAINER_slist_next (i))
-
-            {
-              struct GNUNET_DISK_FileHandle *fh;
-              DWORD dwBytes;
-
-              fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (i, NULL);
-              if (fh->type == GNUNET_PIPE)
-                {
-                  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);
-        }
-
-      if (wfds)
-        {
-          GNUNET_CONTAINER_slist_append (handles_write, wfds->handles);
-          retcode += GNUNET_CONTAINER_slist_count (wfds->handles);
-        }
-
-      /* Check for closed sockets */
-      for (i = 0; i < nfds; i++)
-
-        {
-          if (SAFE_FD_ISSET (i, &sock_read))
-
-            {
-              struct sockaddr addr;
-              int len;
-              if (getpeername (i, &addr, &len) == SOCKET_ERROR)
-
-                {
-                  int err, len;
-                  len = sizeof (err);
-                  if (getsockopt
-                      (i, SOL_SOCKET, SO_ERROR, (char *) &err, &len) == 0
-                      && err == WSAENOTCONN)
-
-                    {
-                      if (!SAFE_FD_ISSET (i, &aread))
-
-                        {
-                          FD_SET (i, &aread);
-                          retcode++;
-                        }
-                    }
-                }
-            }
-        }
-    select_loop_end:
-      if (retcode == 0 && nfds == 0)
-        Sleep (GNUNET_MIN (100, limit - GetTickCount ()));
-    }
-  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_clear (wfds->handles);
-          GNUNET_CONTAINER_slist_append (wfds->handles, handles_write);
-        }
-      if (efds)
-        {
-          GNUNET_NETWORK_fdset_zero (efds);
-          GNUNET_NETWORK_fdset_copy_native (efds, &aexcept, retcode);
-          GNUNET_CONTAINER_slist_clear (efds->handles);
-          GNUNET_CONTAINER_slist_append (efds->handles, handles_except);
-        }
-    }
-
-  GNUNET_CONTAINER_slist_destroy (handles_read);
-  GNUNET_CONTAINER_slist_destroy (handles_write);
-  GNUNET_CONTAINER_slist_destroy (handles_except);
-
-  return retcode;
+  return select (nfds,
+                 (rfds != NULL) ? &rfds->sds : NULL,
+                 (wfds != NULL) ? &wfds->sds : NULL,
+                 (efds != NULL) ? &efds->sds : NULL,
+                 (timeout.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
+                 ? NULL : &tv);
 #endif
 }
 
diff --git a/src/util/os_installation.c b/src/util/os_installation.c
index cbbc614..830b68d 100644
--- a/src/util/os_installation.c
+++ b/src/util/os_installation.c
@@ -106,7 +106,7 @@ get_path_from_proc_exe ()
 }
 #endif
 
-#if WINDOWS
+#if WINDOWS && !defined(__CYGWIN__)
 /**
  * Try to determine path with win32-specific function
  */
@@ -268,7 +268,7 @@ os_get_gnunet_path ()
   if (ret != NULL)
     return ret;
 #endif
-#if WINDOWS
+#if WINDOWS && !defined(__CYGWIN__)
   ret = get_path_from_module_filename ();
   if (ret != NULL)
     return ret;
@@ -310,7 +310,7 @@ os_get_exec_path ()
   if (ret != NULL)
     return ret;
 #endif
-#if WINDOWS
+#if WINDOWS && !defined(__CYGWIN__)
   ret = get_path_from_module_filename ();
   if (ret != NULL)
     return ret;
diff --git a/src/util/os_network.c b/src/util/os_network.c
index 453eea6..76e9579 100644
--- a/src/util/os_network.c
+++ b/src/util/os_network.c
@@ -41,7 +41,7 @@ void
 GNUNET_OS_network_interfaces_list (GNUNET_OS_NetworkInterfaceProcessor proc,
                                    void *proc_cls)
 {
-#ifdef MINGW
+#if WINDOWS && !defined(__CYGWIN__)
   PMIB_IFTABLE pTable;
   PMIB_IPADDRTABLE pAddrTable;
   DWORD dwIfIdx, dwExternalNIC;
diff --git a/src/util/os_priority.c b/src/util/os_priority.c
index fb6c292..093d2a7 100644
--- a/src/util/os_priority.c
+++ b/src/util/os_priority.c
@@ -23,16 +23,16 @@
  * @brief Methods to set process priority
  * @author Nils Durner
  */
-
 #include "platform.h"
 #include "gnunet_common.h"
 #include "gnunet_os_lib.h"
 #include "disk.h"
+#include "w32io.h"
 
 struct GNUNET_OS_Process
 {
   pid_t pid;
-#if WINDOWS
+#if WINDOWS && !defined(__CYGWIN__)
   HANDLE handle;
 #endif
 };
@@ -40,7 +40,7 @@ struct GNUNET_OS_Process
 static struct GNUNET_OS_Process current_process;
 
 
-#if WINDOWS
+#if WINDOWS && !defined(__CYGWIN__)
 void
 GNUNET_OS_process_set_handle(struct GNUNET_OS_Process *proc, HANDLE handle)
 {
@@ -62,7 +62,7 @@ GNUNET_OS_process_set_handle(struct GNUNET_OS_Process *proc, HANDLE handle)
 struct GNUNET_OS_Process *
 GNUNET_OS_process_current ()
 {
-#if WINDOWS
+#if WINDOWS && !defined(__CYGWIN__)
   current_process.pid = GetCurrentProcessId ();
   current_process.handle = GetCurrentProcess ();
 #else
@@ -74,7 +74,7 @@ GNUNET_OS_process_current ()
 int
 GNUNET_OS_process_kill (struct GNUNET_OS_Process *proc, int sig)
 {
-#if WINDOWS
+#if WINDOWS && !defined(__CYGWIN__)
   if (sig == SIGKILL || sig == SIGTERM)
   {
     HANDLE h = proc->handle;
@@ -117,14 +117,14 @@ GNUNET_OS_process_get_pid (struct GNUNET_OS_Process *proc)
 void
 GNUNET_OS_process_close (struct GNUNET_OS_Process *proc)
 {
-#if WINDOWS
+#if WINDOWS && !defined(__CYGWIN__)
   if (proc->handle != NULL)
     CloseHandle (proc->handle);
 #endif  
   GNUNET_free (proc);
 }
 
-#if WINDOWS
+#if WINDOWS && !defined(__CYGWIN__)
 #include "gnunet_signal_lib.h"
 
 extern GNUNET_SIGNAL_Handler w32_sigchld_handler;
@@ -173,7 +173,7 @@ GNUNET_OS_set_process_priority (struct GNUNET_OS_Process *proc,
     {
     case GNUNET_SCHEDULER_PRIORITY_UI:
     case GNUNET_SCHEDULER_PRIORITY_URGENT:
-#ifdef MINGW
+#if WINDOWS && !defined(__CYGWIN__)
       rprio = HIGH_PRIORITY_CLASS;
 #else
       rprio = 0;
@@ -181,7 +181,7 @@ GNUNET_OS_set_process_priority (struct GNUNET_OS_Process *proc,
       break;
 
     case GNUNET_SCHEDULER_PRIORITY_HIGH:
-#ifdef MINGW
+#if WINDOWS && !defined(__CYGWIN__)
       rprio = ABOVE_NORMAL_PRIORITY_CLASS;
 #else
       rprio = 5;
@@ -189,7 +189,7 @@ GNUNET_OS_set_process_priority (struct GNUNET_OS_Process *proc,
       break;
 
     case GNUNET_SCHEDULER_PRIORITY_DEFAULT:
-#ifdef MINGW
+#if WINDOWS && !defined(__CYGWIN__)
       rprio = NORMAL_PRIORITY_CLASS;
 #else
       rprio = 7;
@@ -197,7 +197,7 @@ GNUNET_OS_set_process_priority (struct GNUNET_OS_Process *proc,
       break;
 
     case GNUNET_SCHEDULER_PRIORITY_BACKGROUND:
-#ifdef MINGW
+#if WINDOWS && !defined(__CYGWIN__)
       rprio = BELOW_NORMAL_PRIORITY_CLASS;
 #else
       rprio = 10;
@@ -205,7 +205,7 @@ GNUNET_OS_set_process_priority (struct GNUNET_OS_Process *proc,
       break;
 
     case GNUNET_SCHEDULER_PRIORITY_IDLE:
-#ifdef MINGW
+#if WINDOWS && !defined(__CYGWIN__)
       rprio = IDLE_PRIORITY_CLASS;
 #else
       rprio = 19;
@@ -217,7 +217,7 @@ GNUNET_OS_set_process_priority (struct GNUNET_OS_Process *proc,
     }
 
   /* Set process priority */
-#ifdef MINGW
+#if WINDOWS && !defined(__CYGWIN__)
   {
     HANDLE h = proc->handle;
     GNUNET_assert (h != NULL);
@@ -274,7 +274,7 @@ GNUNET_OS_start_process (struct GNUNET_DISK_PipeHandle *pipe_stdin,
 {
   va_list ap;
 
-#ifndef MINGW
+#if !WINDOWS || defined(__CYGWIN__)
   pid_t ret;
   struct GNUNET_OS_Process *gnunet_proc = NULL;
   char **argv;
@@ -368,22 +368,43 @@ GNUNET_OS_start_process (struct GNUNET_DISK_PipeHandle *pipe_stdin,
   STARTUPINFO start;
   PROCESS_INFORMATION proc;
   struct GNUNET_OS_Process *gnunet_proc = NULL;
-
-  HANDLE stdin_handle;
-  HANDLE stdout_handle;
+  size_t flen;
 
   char path[MAX_PATH + 1];
 
+  int stdin_handle;
+  int stdout_handle;
+
+  flen = strlen (filename);
+
+  if (flen < 4 || (filename[flen - 1] != 'e' && filename[flen - 1] != 'E') ||
+      (filename[flen - 2] != 'x' && filename[flen - 2] != 'X') ||
+      (filename[flen - 3] != 'e' && filename[flen - 3] != 'E') ||
+      (filename[flen - 4] != '.'))
+    snprintf (path, MAX_PATH + 1, "%s.exe", filename);
+  else
+    snprintf (path, MAX_PATH + 1, "%s", filename);
+
   cmdlen = 0;
   va_start (ap, filename);
   while (NULL != (arg = va_arg (ap, char *)))
-      cmdlen = cmdlen + strlen (arg) + 3;
+  {
+      if (cmdlen == 0)
+        cmdlen = cmdlen + strlen (path) + 3;
+      else
+        cmdlen = cmdlen + strlen (arg) + 3;
+  }
   va_end (ap);
 
   cmd = idx = GNUNET_malloc (sizeof (char) * (cmdlen + 1));
   va_start (ap, filename);
   while (NULL != (arg = va_arg (ap, char *)))
-      idx += sprintf (idx, "\"%s\" ", arg);
+  {
+      if (idx == cmd)
+        idx += sprintf (idx, "\"%s\" ", path);
+      else
+        idx += sprintf (idx, "\"%s\" ", arg);
+  }
   va_end (ap);
 
   memset (&start, 0, sizeof (start));
@@ -394,32 +415,37 @@ GNUNET_OS_start_process (struct GNUNET_DISK_PipeHandle *pipe_stdin,
 
   if (pipe_stdin != NULL)
     {
-      GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle(pipe_stdin, GNUNET_DISK_PIPE_END_READ), &stdin_handle, sizeof (HANDLE));
-      start.hStdInput = stdin_handle;
+      GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle(pipe_stdin, GNUNET_DISK_PIPE_END_READ), &stdin_handle, sizeof (int));
+      start.hStdInput = GNUNET_W32IO_fd_get_handle (stdin_handle);
     }
 
   if (pipe_stdout != NULL)
     {
-      GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle(pipe_stdout, GNUNET_DISK_PIPE_END_WRITE), &stdout_handle, sizeof (HANDLE));
-      start.hStdOutput = stdout_handle;
+      GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle(pipe_stdout, GNUNET_DISK_PIPE_END_WRITE), &stdout_handle, sizeof (int));
+      start.hStdOutput = GNUNET_W32IO_fd_get_handle (stdout_handle);
     }
 
-  if (32 >= (int) FindExecutableA (filename, NULL, path)) 
+  if (!CreateProcessA
+      (path, cmd, NULL, NULL, TRUE, DETACHED_PROCESS | CREATE_SUSPENDED, NULL, NULL, &start,
+       &proc))
     {
       SetErrnoFromWinError (GetLastError ());
-      GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "FindExecutable", filename);
+      GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "CreateProcess", filename);
       return NULL;
     }
 
-  if (!CreateProcessA
-      (path, cmd, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, &start,
-       &proc))
+  if (pipe_stdin != NULL)
     {
-      SetErrnoFromWinError (GetLastError ());
-      GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "CreateProcess", path);
-      return NULL;
+      GNUNET_DISK_pipe_close_end (pipe_stdin, GNUNET_DISK_PIPE_END_READ);
+    }
+
+  if (pipe_stdout != NULL)
+    {
+      GNUNET_DISK_pipe_close_end (pipe_stdout, GNUNET_DISK_PIPE_END_WRITE);
     }
 
+  ResumeThread (proc.hThread);
+
   gnunet_proc = GNUNET_malloc (sizeof (struct GNUNET_OS_Process));
   gnunet_proc->pid = proc.dwProcessId;
   gnunet_proc->handle = proc.hProcess;
@@ -450,7 +476,7 @@ struct GNUNET_OS_Process *
 GNUNET_OS_start_process_v (const int *lsocks,
 			   const char *filename, char *const argv[])
 {
-#ifndef MINGW
+#if !WINDOWS || defined(__CYGWIN__)
   pid_t ret;
   char lpid[16];
   char fds[16];
@@ -555,17 +581,21 @@ GNUNET_OS_start_process_v (const int *lsocks,
   STARTUPINFO start;
   PROCESS_INFORMATION proc;
   int argcount = 0;
-  char non_const_filename[MAX_PATH +1];
+  char path[MAX_PATH +1];
+  size_t flen;
   struct GNUNET_OS_Process *gnunet_proc = NULL;
 
   GNUNET_assert (lsocks == NULL);
 
-  if (32 >= (int) FindExecutableA (filename, NULL, non_const_filename)) 
-    {
-      SetErrnoFromWinError (GetLastError ());
-      GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "FindExecutable", filename);
-      return NULL;
-    }
+  flen = strlen (filename);
+
+  if (flen < 4 || (filename[flen - 1] != 'e' && filename[flen - 1] != 'E') ||
+      (filename[flen - 2] != 'x' && filename[flen - 2] != 'X') ||
+      (filename[flen - 3] != 'e' && filename[flen - 3] != 'E') ||
+      (filename[flen - 4] != '.'))
+    snprintf (path, MAX_PATH + 1, "%s.exe", filename);
+  else
+    snprintf (path, MAX_PATH + 1, "%s", filename);
 
   /* Count the number of arguments */
   arg = (char **) argv;
@@ -583,7 +613,10 @@ GNUNET_OS_start_process_v (const int *lsocks,
   arg = (char **) argv;
   while (*arg)
     {
-      non_const_argv[argcount] = GNUNET_strdup (*arg);
+      if (argcount == 0)
+        non_const_argv[argcount] = GNUNET_strdup (path);
+      else
+        non_const_argv[argcount] = GNUNET_strdup (*arg);
       arg++;
       argcount++;
     }
@@ -610,8 +643,8 @@ GNUNET_OS_start_process_v (const int *lsocks,
   memset (&start, 0, sizeof (start));
   start.cb = sizeof (start);
 
-  if (!CreateProcess
-      (non_const_filename, cmd, NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &start,
+  if (!CreateProcessA
+      (path, cmd, NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &start,
        &proc))
     {
       SetErrnoFromWinError (GetLastError ());
@@ -648,7 +681,7 @@ GNUNET_OS_process_status (struct GNUNET_OS_Process *proc,
 			  enum GNUNET_OS_ProcessStatusType *type,
                           unsigned long *code)
 {
-#ifndef MINGW
+#if !WINDOWS || defined(__CYGWIN__)
   int status;
   int ret;
 
@@ -742,7 +775,7 @@ int
 GNUNET_OS_process_wait (struct GNUNET_OS_Process *proc)
 {
 
-#ifndef MINGW
+#if !WINDOWS || defined(__CYGWIN__)
   pid_t pid = proc->pid;
   if (pid != waitpid (pid, NULL, 0))
     return GNUNET_SYSERR;
@@ -777,3 +810,4 @@ GNUNET_OS_process_wait (struct GNUNET_OS_Process *proc)
 
 
 /* end of os_priority.c */
+
diff --git a/src/util/scheduler.c b/src/util/scheduler.c
index 13b3f85..fda1ab4 100644
--- a/src/util/scheduler.c
+++ b/src/util/scheduler.c
@@ -666,7 +666,7 @@ static struct GNUNET_DISK_PipeHandle *shutdown_pipe_handle;
 /**
  * Signal handler called for SIGPIPE.
  */
-#ifndef MINGW
+#if !WINDOWS || defined(__CYGWIN__)
 static void
 sighandler_pipe ()
 {
@@ -712,7 +712,7 @@ GNUNET_SCHEDULER_run (GNUNET_SCHEDULER_Task task, void *task_cls)
   int ret;
   struct GNUNET_SIGNAL_Context *shc_int;
   struct GNUNET_SIGNAL_Context *shc_term;
-#ifndef MINGW
+#if !WINDOWS || defined(__CYGWIN__)
   struct GNUNET_SIGNAL_Context *shc_quit;
   struct GNUNET_SIGNAL_Context *shc_hup;
   struct GNUNET_SIGNAL_Context *shc_pipe;
@@ -732,7 +732,7 @@ GNUNET_SCHEDULER_run (GNUNET_SCHEDULER_Task task, void *task_cls)
   GNUNET_assert (pr != NULL);
   shc_int = GNUNET_SIGNAL_handler_install (SIGINT, &sighandler_shutdown);
   shc_term = GNUNET_SIGNAL_handler_install (SIGTERM, &sighandler_shutdown);
-#ifndef MINGW
+#if !WINDOWS || defined(__CYGWIN__)
   shc_pipe = GNUNET_SIGNAL_handler_install (SIGPIPE, &sighandler_pipe);
   shc_quit = GNUNET_SIGNAL_handler_install (SIGQUIT, &sighandler_shutdown);
   shc_hup = GNUNET_SIGNAL_handler_install (SIGHUP, &sighandler_shutdown);
@@ -764,7 +764,7 @@ GNUNET_SCHEDULER_run (GNUNET_SCHEDULER_Task task, void *task_cls)
             continue;
 
           GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "select");
-#ifndef MINGW
+#if !WINDOWS || defined(__CYGWIN__)
 #if USE_LSOF
 	  char lsof[512];
 	  snprintf (lsof, sizeof (lsof), "lsof -p %d", getpid());
@@ -803,7 +803,7 @@ GNUNET_SCHEDULER_run (GNUNET_SCHEDULER_Task task, void *task_cls)
     }
   GNUNET_SIGNAL_handler_uninstall (shc_int);
   GNUNET_SIGNAL_handler_uninstall (shc_term);
-#ifndef MINGW
+#if !WINDOWS || defined(__CYGWIN__)
   GNUNET_SIGNAL_handler_uninstall (shc_pipe);
   GNUNET_SIGNAL_handler_uninstall (shc_quit);
   GNUNET_SIGNAL_handler_uninstall (shc_hup);
@@ -1194,7 +1194,6 @@ GNUNET_SCHEDULER_add_now (GNUNET_SCHEDULER_Task task,
  * @return unique task identifier for the job
  *         only valid until "task" is started!
  */
-#ifndef MINGW
 GNUNET_SCHEDULER_TaskIdentifier
 add_without_sets (struct GNUNET_TIME_Relative delay,
 		  int rfd,
@@ -1244,7 +1243,6 @@ add_without_sets (struct GNUNET_TIME_Relative delay,
 #endif
   return t->id;
 }
-#endif
 
 
 
@@ -1269,25 +1267,11 @@ GNUNET_SCHEDULER_add_read_net (struct GNUNET_TIME_Relative delay,
                                struct GNUNET_NETWORK_Handle * rfd,
                                GNUNET_SCHEDULER_Task task, void *task_cls)
 {
-#if MINGW
-  struct GNUNET_NETWORK_FDSet *rs;
-  GNUNET_SCHEDULER_TaskIdentifier ret;
-
-  GNUNET_assert (rfd != NULL);
-  rs = GNUNET_NETWORK_fdset_create ();
-  GNUNET_NETWORK_fdset_set (rs, rfd);
-  ret = GNUNET_SCHEDULER_add_select (check_priority (current_priority),
-                                     GNUNET_SCHEDULER_NO_TASK, delay,
-                                     rs, NULL, task, task_cls);
-  GNUNET_NETWORK_fdset_destroy (rs);
-  return ret;
-#else
   return add_without_sets (delay,
 			   GNUNET_NETWORK_get_fd (rfd),
 			   -1,
 			   task,
 			   task_cls);
-#endif
 }
 
 
@@ -1312,25 +1296,11 @@ GNUNET_SCHEDULER_add_write_net (struct GNUNET_TIME_Relative delay,
                                 struct GNUNET_NETWORK_Handle * wfd,
                                 GNUNET_SCHEDULER_Task task, void *task_cls)
 {
-#if MINGW
-  struct GNUNET_NETWORK_FDSet *ws;
-  GNUNET_SCHEDULER_TaskIdentifier ret;
-
-  GNUNET_assert (wfd != NULL);
-  ws = GNUNET_NETWORK_fdset_create ();
-  GNUNET_NETWORK_fdset_set (ws, wfd);
-  ret = GNUNET_SCHEDULER_add_select (check_priority (current_priority),
-                                     GNUNET_SCHEDULER_NO_TASK, delay,
-                                     NULL, ws, task, task_cls);
-  GNUNET_NETWORK_fdset_destroy (ws);
-  return ret;
-#else
   return add_without_sets (delay,
 			   -1,
 			   GNUNET_NETWORK_get_fd (wfd),
 			   task,
 			   task_cls);
-#endif
 }
 
 
@@ -1355,19 +1325,6 @@ GNUNET_SCHEDULER_add_read_file (struct GNUNET_TIME_Relative delay,
                                 const struct GNUNET_DISK_FileHandle * rfd,
                                 GNUNET_SCHEDULER_Task task, void *task_cls)
 {
-#if MINGW
-  struct GNUNET_NETWORK_FDSet *rs;
-  GNUNET_SCHEDULER_TaskIdentifier ret;
-
-  GNUNET_assert (rfd != NULL);
-  rs = GNUNET_NETWORK_fdset_create ();
-  GNUNET_NETWORK_fdset_handle_set (rs, rfd);
-  ret = GNUNET_SCHEDULER_add_select (check_priority (current_priority),
-                                     GNUNET_SCHEDULER_NO_TASK, delay,
-                                     rs, NULL, task, task_cls);
-  GNUNET_NETWORK_fdset_destroy (rs);
-  return ret;
-#else
   int fd;
 
   GNUNET_DISK_internal_file_handle_ (rfd, &fd, sizeof (int));
@@ -1377,7 +1334,6 @@ GNUNET_SCHEDULER_add_read_file (struct GNUNET_TIME_Relative delay,
 			   task,
 			   task_cls);
 
-#endif
 }
 
 
@@ -1402,19 +1358,6 @@ GNUNET_SCHEDULER_add_write_file (struct GNUNET_TIME_Relative delay,
                                  const struct GNUNET_DISK_FileHandle * wfd,
                                  GNUNET_SCHEDULER_Task task, void *task_cls)
 {
-#if MINGW
-  struct GNUNET_NETWORK_FDSet *ws;
-  GNUNET_SCHEDULER_TaskIdentifier ret;
-
-  GNUNET_assert (wfd != NULL);
-  ws = GNUNET_NETWORK_fdset_create ();
-  GNUNET_NETWORK_fdset_handle_set (ws, wfd);
-  ret = GNUNET_SCHEDULER_add_select (check_priority (current_priority),
-                                     GNUNET_SCHEDULER_NO_TASK,
-                                     delay, NULL, ws, task, task_cls);
-  GNUNET_NETWORK_fdset_destroy (ws);
-  return ret;
-#else
   int fd;
 
   GNUNET_DISK_internal_file_handle_ (wfd, &fd, sizeof (int));
@@ -1424,7 +1367,6 @@ GNUNET_SCHEDULER_add_write_file (struct GNUNET_TIME_Relative delay,
 			   task,
 			   task_cls);
 
-#endif
 }
 
 
diff --git a/src/util/service.c b/src/util/service.c
index 25a9b08..30f6680 100644
--- a/src/util/service.c
+++ b/src/util/service.c
@@ -1099,7 +1099,7 @@ setup_service (struct GNUNET_SERVICE_Context *sctx)
 {
   struct GNUNET_TIME_Relative idleout;
   int tolerant;
-#ifndef MINGW
+#if !WINDOWS || defined(__CYGWIN__)
   const char *lpid;
   unsigned int pid;
   const char *nfds;
@@ -1144,7 +1144,7 @@ setup_service (struct GNUNET_SERVICE_Context *sctx)
   else
     tolerant = GNUNET_NO;
 
-#ifndef MINGW
+#if !WINDOWS || defined(__CYGWIN__)
   errno = 0;
   if ( (NULL != (lpid = getenv ("LISTEN_PID"))) &&
        (1 == sscanf (lpid, "%u", &pid)) &&
@@ -1365,7 +1365,7 @@ service_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
 static int
 detach_terminal (struct GNUNET_SERVICE_Context *sctx)
 {
-#ifndef MINGW
+#if !WINDOWS || defined(__CYGWIN__)
   pid_t pid;
   int nullfd;
   int filedes[2];
@@ -1449,7 +1449,7 @@ set_user_id (struct GNUNET_SERVICE_Context *sctx)
 
   if (NULL == (user = get_user_name (sctx)))
     return GNUNET_OK;           /* keep */
-#ifndef MINGW
+#if !WINDOWS || defined(__CYGWIN__)
   struct passwd *pws;
 
   errno = 0;
diff --git a/src/util/signal.c b/src/util/signal.c
index 0fe4bfc..efcad10 100644
--- a/src/util/signal.c
+++ b/src/util/signal.c
@@ -34,12 +34,12 @@ struct GNUNET_SIGNAL_Context
 
   GNUNET_SIGNAL_Handler method;
 
-#ifndef MINGW
+#if !WINDOWS || defined(__CYGWIN__)
   struct sigaction oldsig;
 #endif
 };
 
-#ifdef WINDOWS
+#if WINDOWS
 GNUNET_SIGNAL_Handler w32_sigchld_handler = NULL;
 #endif
 
@@ -47,14 +47,14 @@ struct GNUNET_SIGNAL_Context *
 GNUNET_SIGNAL_handler_install (int signum, GNUNET_SIGNAL_Handler handler)
 {
   struct GNUNET_SIGNAL_Context *ret;
-#ifndef MINGW
+#if !WINDOWS || defined(__CYGWIN__)
   struct sigaction sig;
 #endif
 
   ret = GNUNET_malloc (sizeof (struct GNUNET_SIGNAL_Context));
   ret->sig = signum;
   ret->method = handler;
-#ifndef MINGW
+#if !WINDOWS || defined(__CYGWIN__)
   sig.sa_handler = (void *) handler;
   sigemptyset (&sig.sa_mask);
 #ifdef SA_INTERRUPT
@@ -84,7 +84,7 @@ GNUNET_SIGNAL_handler_install (int signum, GNUNET_SIGNAL_Handler handler)
 void
 GNUNET_SIGNAL_handler_uninstall (struct GNUNET_SIGNAL_Context *ctx)
 {
-#ifndef MINGW
+#if !WINDOWS || defined(__CYGWIN__)
   struct sigaction sig;
 
   sigemptyset (&sig.sa_mask);
diff --git a/src/util/strings.c b/src/util/strings.c
index fa445f6..c78cdc1 100644
--- a/src/util/strings.c
+++ b/src/util/strings.c
@@ -199,7 +199,7 @@ GNUNET_STRINGS_to_utf8 (const char *input, size_t len, const char *charset)
   itmp = tmp;
   finSize = tmpSize;
   if (iconv (cd,
-#if FREEBSD || DARWIN || WINDOWS
+#if FREEBSD || DARWIN || (WINDOWS && !defined(__CYGWIN__))
              (const char **) &input,
 #else
              (char **) &input,
@@ -241,7 +241,7 @@ char *
 GNUNET_STRINGS_filename_expand (const char *fil)
 {
   char *buffer;
-#ifndef MINGW
+#if !WINDOWS || defined(__CYGWIN__)
   size_t len;
   size_t n;
   char *fm;
@@ -254,7 +254,7 @@ GNUNET_STRINGS_filename_expand (const char *fil)
   if (fil == NULL)
     return NULL;
 
-#ifndef MINGW
+#if !WINDOWS || defined(__CYGWIN__)
   if (fil[0] == DIR_SEPARATOR)
     /* absolute path, just copy */
     return GNUNET_strdup (fil);
diff --git a/src/util/test_configuration.c b/src/util/test_configuration.c
index 77e33a5..0d05f46 100644
--- a/src/util/test_configuration.c
+++ b/src/util/test_configuration.c
@@ -320,7 +320,7 @@ testConfig ()
       GNUNET_break (0);
       return 8;
     }
-#ifndef MINGW
+#if !WINDOWS || defined(__CYGWIN__)
   if (0 != strcmp (c, "/hello/world"))
 #else
 #define HI "\\hello\\world"
diff --git a/src/util/test_getopt.c b/src/util/test_getopt.c
index 88a4255..4464d13 100644
--- a/src/util/test_getopt.c
+++ b/src/util/test_getopt.c
@@ -194,7 +194,7 @@ main (int argc, char *argv[])
 
   GNUNET_log_setup ("test_getopt", "WARNING", NULL);
   /* suppress output from -h, -v options */
-#ifndef MINGW
+#if !WINDOWS || defined(__CYGWIN__)
   GNUNET_break (0 == CLOSE (1));
 #endif
   if (0 != testMinimal ())
diff --git a/src/util/test_os_start_process.c b/src/util/test_os_start_process.c
index f82860e..8b7720c 100644
--- a/src/util/test_os_start_process.c
+++ b/src/util/test_os_start_process.c
@@ -106,9 +106,12 @@ task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
   char *fn;
   const struct GNUNET_DISK_FileHandle *stdout_read_handle;
   const struct GNUNET_DISK_FileHandle *wh;
-
+#if !WINDOWS || defined(__CYGWIN__)
   GNUNET_asprintf(&fn, "cat");
-
+#else
+  /* Assume that MSys sets %HOME% to %MSYSDIR%/home/%USERNAME% */
+  GNUNET_asprintf(&fn, "%s\\..\\..\\bin\\cat.exe", getenv ("HOME"));
+#endif
   hello_pipe_stdin = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO);
   hello_pipe_stdout = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_NO, GNUNET_YES);
 
@@ -124,11 +127,6 @@ task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
                                  "test_gnunet_echo_hello", "-", NULL);
   GNUNET_free (fn);
 
-  /* Close the write end of the read pipe */
-  GNUNET_DISK_pipe_close_end(hello_pipe_stdout, GNUNET_DISK_PIPE_END_WRITE);
-  /* Close the read end of the write pipe */
-  GNUNET_DISK_pipe_close_end(hello_pipe_stdin, GNUNET_DISK_PIPE_END_READ);
-
   wh = GNUNET_DISK_pipe_handle (hello_pipe_stdin, GNUNET_DISK_PIPE_END_WRITE);
 
   /* Write the test_phrase to the cat process */
diff --git a/src/util/test_resolver_api.c b/src/util/test_resolver_api.c
index bf2f8f0..dc01b63 100644
--- a/src/util/test_resolver_api.c
+++ b/src/util/test_resolver_api.c
@@ -315,8 +315,13 @@ run(void *cls, char * const *args,
       GNUNET_break(0);
     }
 
+#if WINDOWS && !defined(__CYGWIN__)
+  rootserver
+      = gethostbyaddr((const char *) &rootserver_addr, sizeof(rootserver_addr), AF_INET);
+#else
   rootserver
       = gethostbyaddr(&rootserver_addr, sizeof(rootserver_addr), AF_INET);
+#endif
   if (rootserver == NULL)
     {
       /* Error: resolving IP addresses does not work */
@@ -345,7 +350,7 @@ run(void *cls, char * const *args,
 
   memset(&sa, 0, sizeof(sa));
   sa.sin_family = AF_INET;
-#ifndef MINGW
+#if !WINDOWS || defined(__CYGWIN__)
   inet_aton(ROOTSERVER_IP, &sa.sin_addr);
 #else
   sa.sin_addr.S_un.S_addr = inet_addr(ROOTSERVER_IP);
diff --git a/src/util/test_scheduler.c b/src/util/test_scheduler.c
index f0c908d..3b5c5cb 100644
--- a/src/util/test_scheduler.c
+++ b/src/util/test_scheduler.c
@@ -181,6 +181,7 @@ checkShutdown ()
   return ok;
 }
 
+#if !WINDOWS || defined(__CYGWIN__)
 
 static void
 taskSig (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
@@ -206,7 +207,7 @@ checkSignal ()
   GNUNET_SCHEDULER_run (&taskSig, &ok);
   return ok;
 }
-
+#endif
 
 static void
 taskCancel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
@@ -243,7 +244,7 @@ main (int argc, char *argv[])
 
   GNUNET_log_setup ("test_scheduler", "WARNING", NULL);
   ret += check ();
-#ifndef MINGW
+#if !WINDOWS || defined(__CYGWIN__)
   ret += checkSignal ();
 #endif
   ret += checkShutdown ();
diff --git a/src/util/test_service.c b/src/util/test_service.c
index 9bd5835..3f445f4 100644
--- a/src/util/test_service.c
+++ b/src/util/test_service.c
@@ -273,10 +273,7 @@ main (int argc, char *argv[])
   ret += check ();
   ret += check ();
 
-  // FIXME
-#ifndef MINGW
   s = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
-#endif
   if (NULL == s)
     {
       if ((errno == ENOBUFS) ||
diff --git a/src/util/test_service_data.conf b/src/util/test_service_data.conf
index cff43cc..a243745 100644
--- a/src/util/test_service_data.conf
+++ b/src/util/test_service_data.conf
@@ -10,6 +10,7 @@ REJECT_FROM=1.2.3.0/15;4.5.0.0/8;6.7.8.9/255.255.255.0;
 ACCEPT_FROM6=::1;
 REJECT_FROM6=AB:CD:EF::00;AB:CD::00/40;
 HOSTNAME=localhost
+OPTIONS = -l test_service.log -L DEBUG
 
 [test_service6]
 PORT=12435
@@ -22,6 +23,7 @@ REJECT_FROM=1.2.3.0/15;4.5.0.0/8;6.7.8.9/255.255.255.0;
 ACCEPT_FROM6=::1;
 REJECT_FROM6=AB:CD:EF::00;AB:CD::00/40;
 HOSTNAME=::1
+OPTIONS = -l test_service-6.log -L DEBUG
 
 [resolver]
 HOSTNAME=localhost
diff --git a/src/util/test_strings.c b/src/util/test_strings.c
index a1614b4..0f2135a 100644
--- a/src/util/test_strings.c
+++ b/src/util/test_strings.c
@@ -66,7 +66,7 @@ check ()
                                             (GNUNET_TIME_UNIT_MILLISECONDS,
                                              7 * 60 * 60 * 1000));
   WANT (buf, b);
-#ifndef MINGW
+#if !WINDOWS || defined(__CYGWIN__)
   hdir = getenv ("HOME");
 #else
   hdir = getenv ("USERPROFILE");
diff --git a/src/util/test_w32io.c b/src/util/test_w32io.c
new file mode 100644
index 0000000..2523a62
--- /dev/null
+++ b/src/util/test_w32io.c
@@ -0,0 +1,960 @@
+/*
+     This file is part of GNUnet.
+     (C) 2003, 2004, 2005, 2006, 2009 Christian Grothoff (and other contributing authors)
+
+     GNUnet is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published
+     by the Free Software Foundation; either version 3, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+     Boston, MA 02111-1307, USA.
+*/
+/**
+ * @file util/test_w32io.c
+ * @brief testcase for util/w32io.c
+ */
+#include "platform.h"
+#include "gnunet_common.h"
+#include "gnunet_configuration_lib.h"
+#include "gnunet_os_lib.h"
+#include "disk.h"
+#include "w32io.h"
+
+#define VERBOSE GNUNET_NO
+
+
+char self_name[MAX_PATH + 1];
+
+SOCKET
+create_listening_socket (int port)
+{
+  struct sockaddr_in sa;
+  SOCKET s;
+  int r;
+  DWORD e;
+  memset (&sa, 0, sizeof (sa));
+#if HAVE_SOCKADDR_IN_SIN_LEN
+  sa.sin_len = sizeof (sa);
+#endif
+  sa.sin_addr.s_addr = inet_addr("127.0.0.1");
+  sa.sin_port = htons (port);
+  sa.sin_family = AF_INET;
+
+#if VERBOSE
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Creating a socket...\n");
+#endif
+  SetLastError (0);
+  //s = WSASocket (AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
+  s = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
+  e = GetLastError ();
+  GNUNET_assert (s != INVALID_SOCKET);
+#if VERBOSE
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Binding the socket...\n");
+#endif
+  SetLastError (0);
+  r = bind (s, (struct sockaddr *) &sa, sizeof (sa));
+  e = GetLastError ();
+  GNUNET_assert (r == 0);
+#if VERBOSE
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Listening on the socket...\n");
+#endif
+  SetLastError (0);
+  r = listen (s, 5);
+  e = GetLastError ();
+  GNUNET_assert (r == 0);
+  return s;
+}
+
+SOCKET
+create_connecting_socket ()
+{
+  SOCKET s;
+
+  s = WSASocket (AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
+  GNUNET_assert (s != INVALID_SOCKET);
+  return s;
+}
+
+
+static int
+test_socket_server (int do_spawn, int port)
+{
+  int r;
+  struct sockaddr sa;
+  int sizeofsa = sizeof (sa);
+  int server[2];
+  w32fd_set rset;
+  w32fd_set wset;
+  char buf[1024];
+#if VERBOSE
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Testing sockets...\n");
+#endif
+
+  SOCKET s = create_listening_socket (port);
+
+#if VERBOSE
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Created a listening socket.\n");
+#endif
+
+  server[0] = GNUNET_W32IO_fd_from_handle ((HANDLE) s, GNUNET_W32IO_SOCKET, GENERIC_READ | GENERIC_WRITE, 0, 0, 0);
+  GNUNET_assert (server[0] >= 0);
+
+  sprintf (buf, "%d", port);
+
+  if (do_spawn)
+  {
+#if VERBOSE
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Spawning client process.\n");
+#endif
+    struct GNUNET_OS_Process *p;
+    p = GNUNET_OS_start_process (NULL, NULL, self_name, self_name, "socket", buf, NULL);
+    GNUNET_OS_process_close (p);
+  }
+
+#if VERBOSE
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Waiting for the listening socket readability.\n");
+#endif
+  W32_FD_ZERO(&rset);
+  W32_FD_SET(server[0], &rset);
+  r = GNUNET_W32IO_select (server[0] + 1, &rset, NULL, NULL, NULL);
+  GNUNET_assert (r == 1);
+  GNUNET_assert (W32_FD_ISSET (server[0], &rset));
+
+#if VERBOSE
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Accepting client connection.\n");
+#endif
+
+  server[1] = GNUNET_W32IO_accept (server[0], &sa, &sizeofsa);
+  GNUNET_assert (server[1] >= 0);
+
+#if VERBOSE
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Waiting for server socket writability.\n");
+#endif
+
+  W32_FD_ZERO(&rset);
+  W32_FD_SET(server[0], &rset);
+  W32_FD_ZERO(&wset);
+  W32_FD_SET(server[0], &wset);
+  W32_FD_SET(server[1], &wset);
+  r = GNUNET_W32IO_select (server[1] + 1, &rset, &wset, NULL, NULL);
+  GNUNET_assert (r == 1);
+  GNUNET_assert (W32_FD_ISSET(server[1], &wset));
+  GNUNET_assert (!W32_FD_ISSET(server[0], &rset) && !W32_FD_ISSET(server[0], &wset));
+
+#if VERBOSE
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Sending 12345 to client.\n");
+#endif
+  r = GNUNET_W32IO_send (server[1], "12345", 5, 0);
+
+#if VERBOSE
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Waiting for server socket readability.\n");
+#endif
+  W32_FD_ZERO(&rset);
+  W32_FD_SET(server[0], &rset);
+  W32_FD_SET(server[1], &rset);
+  W32_FD_ZERO(&wset);
+  W32_FD_SET(server[0], &wset);
+  r = GNUNET_W32IO_select (server[1] + 1, &rset, &wset, NULL, NULL);
+  GNUNET_assert (r == 1);
+  GNUNET_assert (W32_FD_ISSET(server[1], &rset));
+  GNUNET_assert (!W32_FD_ISSET(server[0], &rset) && !W32_FD_ISSET(server[0], &wset));
+
+#if VERBOSE
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Reading 54321 from client.\n");
+#endif
+  r = GNUNET_W32IO_recv (server[1], buf, 5, 0);
+
+  GNUNET_assert (buf[0] == '5' && buf[1] == '4' && buf[2] == '3' && buf[3] == '2' && buf[4] == '1');
+
+#if VERBOSE
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Waiting for server socket writability.\n");
+#endif
+  W32_FD_ZERO(&rset);
+  W32_FD_SET(server[0], &rset);
+  W32_FD_ZERO(&wset);
+  W32_FD_SET(server[0], &wset);
+  W32_FD_SET(server[1], &wset);
+  r = GNUNET_W32IO_select (server[1] + 1, &rset, &wset, NULL, NULL);
+  GNUNET_assert (r == 1);
+  GNUNET_assert (W32_FD_ISSET(server[1], &wset));
+  GNUNET_assert (!W32_FD_ISSET(server[0], &rset) && !W32_FD_ISSET(server[0], &wset));
+
+#if VERBOSE
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Sending 98765 to client.\n");
+#endif
+  r = GNUNET_W32IO_send (server[1], "98765", 5, 0);
+
+#if VERBOSE
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Shutting the server down.\n");
+#endif
+  GNUNET_W32IO_shutdown (server[1], SD_SEND);
+  GNUNET_W32IO_shutdown (server[0], SD_BOTH);
+
+#if VERBOSE
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Waiting for server socket readability.\n");
+#endif
+  W32_FD_ZERO(&rset);
+  W32_FD_SET(server[0], &rset);
+  W32_FD_SET(server[1], &rset);
+  W32_FD_ZERO(&wset);
+  W32_FD_SET(server[0], &wset);
+  r = GNUNET_W32IO_select (server[1] + 1, &rset, &wset, NULL, NULL);
+  GNUNET_assert (r == 1);
+  GNUNET_assert (W32_FD_ISSET(server[1], &rset));
+  GNUNET_assert (!W32_FD_ISSET(server[1], &wset));
+  GNUNET_assert (!W32_FD_ISSET(server[0], &rset));
+  GNUNET_assert (!W32_FD_ISSET(server[0], &wset));
+
+#if VERBOSE
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Closing the server.\n");
+#endif
+  GNUNET_W32IO_close (server[0], 1);
+  GNUNET_W32IO_close (server[1], 1);
+
+#if VERBOSE
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Done!\n");
+#endif
+  return 0;
+}
+
+static int
+test_socket_client (int port)
+{
+  int r;
+  char buf[1024];
+  w32fd_set rset;
+  w32fd_set wset;
+  int client;
+  struct sockaddr_in sa;
+  memset (&sa, 0, sizeof (sa));
+#if HAVE_SOCKADDR_IN_SIN_LEN
+  sa.sin_len = sizeof (sa);
+#endif
+  sa.sin_addr.s_addr = inet_addr("127.0.0.1");
+  sa.sin_port = htons (port);
+  sa.sin_family = AF_INET;
+
+#if VERBOSE
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Creating a client socket.\n");
+#endif
+  SOCKET s = create_connecting_socket ();
+
+  client = GNUNET_W32IO_fd_from_handle ((HANDLE) s, GNUNET_W32IO_SOCKET, GENERIC_READ | GENERIC_WRITE, 0, 0, 0);
+  GNUNET_assert (client >= 0);
+
+#if VERBOSE
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Connecting the client socket.\n");
+#endif
+  GNUNET_W32IO_connect (client, (struct sockaddr *) &sa, sizeof (sa));
+
+#if VERBOSE
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Waiting for client socket readability.\n");
+#endif
+  W32_FD_ZERO(&rset);
+  W32_FD_SET(client, &rset);
+  r = GNUNET_W32IO_select (client + 1, &rset, NULL, NULL, NULL);
+  GNUNET_assert (r == 1);
+  GNUNET_assert (W32_FD_ISSET(client, &rset));
+
+#if VERBOSE
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Receiving 12345 from the server.\n");
+#endif
+  GNUNET_W32IO_recv (client, buf, 5, 0);
+  GNUNET_assert (buf[0] == '1' && buf[1] == '2' && buf[2] == '3' && buf[3] == '4' && buf[4] == '5');
+
+#if VERBOSE
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Waiting for client socket writability.\n");
+#endif
+  W32_FD_ZERO(&wset);
+  W32_FD_SET(client, &wset);
+  r = GNUNET_W32IO_select (client + 1, NULL, &wset, NULL, NULL);
+  GNUNET_assert (r == 1);
+  GNUNET_assert (W32_FD_ISSET(client, &wset));
+
+#if VERBOSE
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Sending 54321 to the server.\n");
+#endif
+  GNUNET_W32IO_send (client, "54321", 5, 0);
+
+#if VERBOSE
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Waiting for client socket readability.\n");
+#endif
+  W32_FD_ZERO(&rset);
+  W32_FD_SET(client, &rset);
+  r = GNUNET_W32IO_select (client + 1, &rset, NULL, NULL, NULL);
+  GNUNET_assert (r == 1);
+  GNUNET_assert (W32_FD_ISSET(client, &rset));
+
+#if VERBOSE
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Reading 98765 from the server.\n");
+#endif
+  GNUNET_W32IO_recv (client, buf, 5, 0);
+  GNUNET_assert (buf[0] == '9' && buf[1] == '8' && buf[2] == '7' && buf[3] == '6' && buf[4] == '5');
+
+#if VERBOSE
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Shutting the client down.\n");
+#endif
+  GNUNET_W32IO_shutdown (client, SD_SEND);
+
+#if VERBOSE
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Waiting for client socket readability.\n");
+#endif
+  W32_FD_ZERO(&rset);
+  W32_FD_SET(client, &rset);
+  r = GNUNET_W32IO_select (client + 1, &rset, NULL, NULL, NULL);
+  GNUNET_assert (r == 1);
+  GNUNET_assert (W32_FD_ISSET(client, &rset));
+
+#if VERBOSE
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Closing the client.\n");
+#endif
+  GNUNET_W32IO_close (client, 1);
+  return 0;
+}
+
+int thread_ret[2];
+
+DWORD
+test_socket_threaded_server (void *arg)
+{
+  thread_ret[0] = test_socket_server (0, (int) arg);
+  return 0;
+}
+
+DWORD
+test_socket_threaded_client (void *arg)
+{
+  thread_ret[1] = test_socket_client ((int) arg);
+  return 0;
+}
+
+static int
+test_socket_threaded (int port)
+{
+  DWORD thread_ids[2];
+  DWORD dw_ret;
+  HANDLE threads[2];
+  thread_ret[0] = thread_ret[1] = -1;
+#if VERBOSE
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Testing sockets (threaded)...\n");
+#endif
+  threads[0] = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE) &test_socket_threaded_server, (void *) port, 0, &thread_ids[0]);
+  /* Give the server enough time to set up a listening socket.
+   * I'm too lazy to do proper synchronization with events here.
+   */
+  Sleep (100);
+  threads[1] = CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE) &test_socket_threaded_client, (void *) port, 0, &thread_ids[1]);
+  dw_ret = WaitForMultipleObjects (2, threads, TRUE, INFINITE);
+#if VERBOSE
+  if (thread_ret[0] == 0 && thread_ret[1] == 0)
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Done!\n");
+  else
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Error!\n");
+#endif
+  return (thread_ret[0] == 0 && thread_ret[1] == 0) ? 0 : 1;
+}
+
+static int
+test_named_pipe_server_read (int do_spawn)
+{
+  int r;
+  w32fd_set rset;
+  w32fd_set wset;
+  int server;
+  char buf[1024];
+  char *servername = NULL;
+
+#if VERBOSE
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Testing named pipes (client->server)...\n");
+#endif
+  server = GNUNET_W32IO_named_pipe_server (&servername, PIPE_ACCESS_INBOUND);
+  GNUNET_assert (server >= 0);
+
+  if (do_spawn)
+  {
+    struct GNUNET_OS_Process *p;
+    p = GNUNET_OS_start_process (NULL, NULL, self_name, self_name, "named_pipe", "write", servername, NULL);
+    GNUNET_OS_process_close (p);
+  }
+
+  W32_FD_ZERO(&rset);
+  W32_FD_SET(server, &rset);
+  W32_FD_ZERO(&wset);
+  W32_FD_SET(server, &wset);
+  r = GNUNET_W32IO_select (server + 1, &rset, &wset, NULL, NULL);
+  GNUNET_assert (r == 1);
+  GNUNET_assert (W32_FD_ISSET(server, &rset) && !W32_FD_ISSET(server, &wset));
+
+  r = GNUNET_W32IO_read (server, buf, 5);
+
+  GNUNET_assert (buf[0] == '5' && buf[1] == '4' && buf[2] == '3' && buf[3] == '2' && buf[4] == '1');
+
+  GNUNET_W32IO_close (server, 1);
+
+#if VERBOSE
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Done!\n");
+#endif
+  return 0;
+}
+
+static int
+test_named_pipe_client_write (char *name)
+{
+  int r;
+  char buf[1024];
+  w32fd_set rset;
+  w32fd_set wset;
+  int client;
+
+  client = GNUNET_W32IO_named_pipe_client (name, PIPE_ACCESS_OUTBOUND);
+  GNUNET_assert (client >= 0);
+
+  W32_FD_ZERO(&rset);
+  W32_FD_SET(client, &rset);
+  W32_FD_ZERO(&wset);
+  W32_FD_SET(client, &wset);
+  r = GNUNET_W32IO_select (client + 1, &rset, &wset, NULL, NULL);
+  GNUNET_assert (r == 1);
+  GNUNET_assert (!W32_FD_ISSET(client, &rset) && W32_FD_ISSET(client, &wset));
+
+  buf[0] = '5';
+  buf[1] = '4';
+  buf[2] = '3';
+  buf[3] = '2';
+  buf[4] = '1';
+
+  r = GNUNET_W32IO_write (client, buf, 5);
+
+  W32_FD_ZERO(&rset);
+  W32_FD_SET(client, &rset);
+  W32_FD_ZERO(&wset);
+  W32_FD_SET(client, &wset);
+  r = GNUNET_W32IO_select (client + 1, &rset, &wset, NULL, NULL);
+  GNUNET_assert (r == 1);
+  GNUNET_assert (!W32_FD_ISSET(client, &rset) && W32_FD_ISSET(client, &wset));
+
+  GNUNET_W32IO_close (client, 1);
+  return 0;
+}
+
+static int
+test_named_pipe_server_hup (int do_spawn)
+{
+  int r;
+  w32fd_set rset;
+  w32fd_set wset;
+  int server;
+  char buf[1024];
+  char *servername = NULL;
+
+#if VERBOSE
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Testing named pipes (broken pipe)...\n");
+#endif
+  server = GNUNET_W32IO_named_pipe_server (&servername, PIPE_ACCESS_INBOUND);
+  GNUNET_assert (server >= 0);
+
+  if (do_spawn)
+  {
+    struct GNUNET_OS_Process *p;
+    p = GNUNET_OS_start_process (NULL, NULL, self_name, self_name, "named_pipe", "hup", servername, NULL);
+    GNUNET_OS_process_close (p);
+  }
+
+  W32_FD_ZERO(&rset);
+  W32_FD_SET(server, &rset);
+  W32_FD_ZERO(&wset);
+  W32_FD_SET(server, &wset);
+  r = GNUNET_W32IO_select (server + 1, &rset, &wset, NULL, NULL);
+  GNUNET_assert (r == 1);
+  GNUNET_assert (W32_FD_ISSET(server, &rset) && !W32_FD_ISSET(server, &wset));
+
+  r = GNUNET_W32IO_read (server, buf, 5);
+
+  GNUNET_assert (buf[0] == '5' && buf[1] == '4' && buf[2] == '3' && buf[3] == '2' && buf[4] == '1');
+
+  W32_FD_ZERO(&rset);
+  W32_FD_SET(server, &rset);
+  W32_FD_ZERO(&wset);
+  W32_FD_SET(server, &wset);
+  r = GNUNET_W32IO_select (server + 1, &rset, &wset, NULL, NULL);
+  GNUNET_assert (r == 1);
+  GNUNET_assert (W32_FD_ISSET(server, &rset) && !W32_FD_ISSET(server, &wset));
+
+  GNUNET_W32IO_close (server, 1);
+
+#if VERBOSE
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Done!\n");
+#endif
+  return 0;
+}
+
+static int
+test_named_pipe_client_hup (char *name)
+{
+  int r;
+  char buf[1024];
+  w32fd_set rset;
+  w32fd_set wset;
+  int client;
+
+  client = GNUNET_W32IO_named_pipe_client (name, PIPE_ACCESS_OUTBOUND);
+  GNUNET_assert (client >= 0);
+
+  W32_FD_ZERO(&rset);
+  W32_FD_SET(client, &rset);
+  W32_FD_ZERO(&wset);
+  W32_FD_SET(client, &wset);
+  r = GNUNET_W32IO_select (client + 1, &rset, &wset, NULL, NULL);
+  GNUNET_assert (r == 1);
+  GNUNET_assert (!W32_FD_ISSET(client, &rset) && W32_FD_ISSET(client, &wset));
+
+  buf[0] = '5';
+  buf[1] = '4';
+  buf[2] = '3';
+  buf[3] = '2';
+  buf[4] = '1';
+
+  r = GNUNET_W32IO_write (client, buf, 5);
+
+  W32_FD_ZERO(&rset);
+  W32_FD_SET(client, &rset);
+  W32_FD_ZERO(&wset);
+  W32_FD_SET(client, &wset);
+  r = GNUNET_W32IO_select (client + 1, &rset, &wset, NULL, NULL);
+  GNUNET_assert (r == 1);
+  GNUNET_assert (!W32_FD_ISSET(client, &rset) && W32_FD_ISSET(client, &wset));
+
+  GNUNET_W32IO_close (client, 1);
+  return 0;
+}
+
+static int
+test_named_pipe_server_write (int do_spawn)
+{
+  int r;
+  w32fd_set rset;
+  w32fd_set wset;
+  int server;
+  char buf[1024];
+  char *servername = NULL;
+
+#if VERBOSE
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Testing named pipes (server->client)...\n");
+#endif
+  server = GNUNET_W32IO_named_pipe_server (&servername, PIPE_ACCESS_OUTBOUND);
+  GNUNET_assert (server >= 0);
+
+  if (do_spawn)
+  {
+    struct GNUNET_OS_Process *p;
+    p = GNUNET_OS_start_process (NULL, NULL, self_name, self_name, "named_pipe", "read", servername, NULL);
+    GNUNET_OS_process_close (p);
+  }
+
+  W32_FD_ZERO(&rset);
+  W32_FD_SET(server, &rset);
+  W32_FD_ZERO(&wset);
+  W32_FD_SET(server, &wset);
+  r = GNUNET_W32IO_select (server + 1, &rset, &wset, NULL, NULL);
+  GNUNET_assert (r == 1);
+  GNUNET_assert (!W32_FD_ISSET(server, &rset) && W32_FD_ISSET(server, &wset));
+
+  buf[0] = '5';
+  buf[1] = '4';
+  buf[2] = '3';
+  buf[3] = '2';
+  buf[4] = '1';
+
+  r = GNUNET_W32IO_write (server, buf, 5);
+
+  W32_FD_ZERO(&rset);
+  W32_FD_SET(server, &rset);
+  W32_FD_ZERO(&wset);
+  W32_FD_SET(server, &wset);
+  r = GNUNET_W32IO_select (server + 1, &rset, &wset, NULL, NULL);
+  GNUNET_assert (r == 1);
+  GNUNET_assert (!W32_FD_ISSET(server, &rset) && W32_FD_ISSET(server, &wset));
+
+  GNUNET_W32IO_close (server, 1);
+
+#if VERBOSE
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Done!\n");
+#endif
+  return 0;
+}
+
+static int
+test_named_pipe_client_read (char *name)
+{
+  int r;
+  char buf[1024];
+  w32fd_set rset;
+  w32fd_set wset;
+  int client;
+
+  client = GNUNET_W32IO_named_pipe_client (name, PIPE_ACCESS_INBOUND);
+  GNUNET_assert (client >= 0);
+
+  W32_FD_ZERO(&rset);
+  W32_FD_SET(client, &rset);
+  W32_FD_ZERO(&wset);
+  W32_FD_SET(client, &wset);
+  r = GNUNET_W32IO_select (client + 1, &rset, &wset, NULL, NULL);
+  GNUNET_assert (r == 1);
+  GNUNET_assert (W32_FD_ISSET(client, &rset) && !W32_FD_ISSET(client, &wset));
+
+  r = GNUNET_W32IO_read (client, buf, 5);
+
+  GNUNET_assert (buf[0] == '5' && buf[1] == '4' && buf[2] == '3' && buf[3] == '2' && buf[4] == '1');
+
+  W32_FD_ZERO(&rset);
+  W32_FD_SET(client, &rset);
+  W32_FD_ZERO(&wset);
+  W32_FD_SET(client, &wset);
+  r = GNUNET_W32IO_select (client + 1, &rset, &wset, NULL, NULL);
+  GNUNET_assert (r == 1);
+  GNUNET_assert (W32_FD_ISSET(client, &rset) && !W32_FD_ISSET(client, &wset));
+
+  GNUNET_W32IO_close (client, 1);
+  return 0;
+}
+
+static int
+test_anonymous_pipe_server_write ()
+{
+  int r;
+  w32fd_set rset;
+  w32fd_set wset;
+  struct GNUNET_DISK_PipeHandle *stdin_pipe, *test_pipe;
+  int server;
+  SOCKET s;
+  char buf[1024];
+
+#if VERBOSE
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Testing anonymous pipes (stdin)...\n");
+#endif
+  stdin_pipe = GNUNET_DISK_pipe (0, 1, 0);
+#if VERBOSE
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Created anonymous pipe (writable, not readable).\n");
+#endif
+  GNUNET_assert (stdin_pipe != NULL);
+  GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle(stdin_pipe, GNUNET_DISK_PIPE_END_WRITE), &server, sizeof (int));
+
+  {
+#if VERBOSE
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Spawning the child process...\n");
+#endif
+    struct GNUNET_OS_Process *p;
+    p = GNUNET_OS_start_process (stdin_pipe, NULL, self_name, self_name, "anonymous_pipe", "read", NULL);
+    GNUNET_OS_process_close (p);
+#if VERBOSE
+    GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Spawned the child process.\n");
+#endif
+  }
+
+  W32_FD_ZERO(&rset);
+  W32_FD_SET(server, &rset);
+  W32_FD_ZERO(&wset);
+  W32_FD_SET(server, &wset);
+#if VERBOSE
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Waiting for the server pipe writability...\n");
+#endif
+  r = GNUNET_W32IO_select (server + 1, &rset, &wset, NULL, NULL);
+#if VERBOSE
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Done waiting for the server pipe writability...\n");
+#endif
+  GNUNET_assert (r == 1);
+  GNUNET_assert (!W32_FD_ISSET(server, &rset) && W32_FD_ISSET(server, &wset));
+
+  buf[0] = '5';
+  buf[1] = '4';
+  buf[2] = '3';
+  buf[3] = '2';
+  buf[4] = '1';
+
+#if VERBOSE
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Writing 54321 server->client \n");
+#endif
+  r = GNUNET_W32IO_write (server, buf, 5);
+#if VERBOSE
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Done writing 54321 server->client \n");
+#endif
+
+  W32_FD_ZERO(&rset);
+  W32_FD_SET(server, &rset);
+  W32_FD_ZERO(&wset);
+  W32_FD_SET(server, &wset);
+#if VERBOSE
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Waiting for the server pipe writability...\n");
+#endif
+  r = GNUNET_W32IO_select (server + 1, &rset, &wset, NULL, NULL);
+#if VERBOSE
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Done waiting for the server pipe writability...\n");
+#endif
+  GNUNET_assert (r == 1);
+  GNUNET_assert (!W32_FD_ISSET(server, &rset) && W32_FD_ISSET(server, &wset));
+
+#if VERBOSE
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Closing the server pipe\n");
+#endif
+  GNUNET_DISK_pipe_close (stdin_pipe);
+#if VERBOSE
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Done!\n");
+#endif
+  return 0;
+}
+
+static int
+test_anonymous_pipe_client_read (HANDLE in)
+{
+  int r;
+  char buf[1024];
+  w32fd_set rset;
+  w32fd_set wset;
+  int client;
+
+  client = GNUNET_W32IO_fd_from_handle (in, GNUNET_W32IO_ANONYMOUS_PIPE, GENERIC_READ, 1, 0, 1);
+  GNUNET_assert (client >= 0);
+
+  W32_FD_ZERO(&rset);
+  W32_FD_SET(client, &rset);
+  W32_FD_ZERO(&wset);
+  W32_FD_SET(client, &wset);
+  r = GNUNET_W32IO_select (client + 1, &rset, &wset, NULL, NULL);
+  GNUNET_assert (r == 1);
+  GNUNET_assert (W32_FD_ISSET(client, &rset) && !W32_FD_ISSET(client, &wset));
+
+  r = GNUNET_W32IO_read (client, buf, 5);
+
+  GNUNET_assert (buf[0] == '5' && buf[1] == '4' && buf[2] == '3' && buf[3] == '2' && buf[4] == '1');
+
+  W32_FD_ZERO(&rset);
+  W32_FD_SET(client, &rset);
+  W32_FD_ZERO(&wset);
+  W32_FD_SET(client, &wset);
+  r = GNUNET_W32IO_select (client + 1, &rset, &wset, NULL, NULL);
+  GNUNET_assert (r == 1);
+  GNUNET_assert (W32_FD_ISSET(client, &rset) && !W32_FD_ISSET(client, &wset));
+
+  GNUNET_W32IO_close (client, 1);
+  return 0;
+}
+
+static int
+test_anonymous_pipe_client_write (HANDLE out)
+{
+  int r;
+  char buf[1024];
+  w32fd_set rset;
+  w32fd_set wset;
+  int client;
+
+  client = GNUNET_W32IO_fd_from_handle (out, GNUNET_W32IO_ANONYMOUS_PIPE, GENERIC_WRITE, 1, 1, 0);
+  GNUNET_assert (client >= 0);
+
+  W32_FD_ZERO(&rset);
+  W32_FD_SET(client, &rset);
+  W32_FD_ZERO(&wset);
+  W32_FD_SET(client, &wset);
+  r = GNUNET_W32IO_select (client + 1, &rset, &wset, NULL, NULL);
+  GNUNET_assert (r == 1);
+  GNUNET_assert (!W32_FD_ISSET(client, &rset) && W32_FD_ISSET(client, &wset));
+
+  buf[0] = '5';
+  buf[1] = '4';
+  buf[2] = '3';
+  buf[3] = '2';
+  buf[4] = '1';
+
+  r = GNUNET_W32IO_write (client, buf, 5);
+
+  W32_FD_ZERO(&rset);
+  W32_FD_SET(client, &rset);
+  W32_FD_ZERO(&wset);
+  W32_FD_SET(client, &wset);
+  r = GNUNET_W32IO_select (client + 1, &rset, &wset, NULL, NULL);
+  GNUNET_assert (r == 1);
+  GNUNET_assert (!W32_FD_ISSET(client, &rset) && W32_FD_ISSET(client, &wset));
+
+  GNUNET_W32IO_close (client, 1);
+  return 0;
+}
+
+static int
+test_anonymous_pipe_server_read ()
+{
+  int r;
+  w32fd_set rset;
+  w32fd_set wset;
+  struct GNUNET_DISK_PipeHandle *stdout_pipe;
+  int server;
+  char buf[1024];
+
+#if VERBOSE
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Testing anonymous pipes (stdout)...\n");
+#endif
+  stdout_pipe = GNUNET_DISK_pipe (0, 0, 1);
+  GNUNET_assert (stdout_pipe != NULL);
+  GNUNET_DISK_internal_file_handle_ (GNUNET_DISK_pipe_handle(stdout_pipe, GNUNET_DISK_PIPE_END_READ), &server, sizeof (int));
+
+  {
+    struct GNUNET_OS_Process *p;
+    p = GNUNET_OS_start_process (NULL, stdout_pipe, self_name, self_name, "anonymous_pipe", "write", NULL);
+    GNUNET_OS_process_close (p);
+  }
+
+  W32_FD_ZERO(&rset);
+  W32_FD_SET(server, &rset);
+  W32_FD_ZERO(&wset);
+  W32_FD_SET(server, &wset);
+  r = GNUNET_W32IO_select (server + 1, &rset, &wset, NULL, NULL);
+  GNUNET_assert (r == 1);
+  GNUNET_assert (W32_FD_ISSET(server, &rset) && !W32_FD_ISSET(server, &wset));
+
+  r = GNUNET_W32IO_read (server, buf, 5);
+  GNUNET_assert (buf[0] == '5' && buf[1] == '4' && buf[2] == '3' && buf[3] == '2' && buf[4] == '1');
+
+  W32_FD_ZERO(&rset);
+  W32_FD_SET(server, &rset);
+  W32_FD_ZERO(&wset);
+  W32_FD_SET(server, &wset);
+  r = GNUNET_W32IO_select (server + 1, &rset, &wset, NULL, NULL);
+  GNUNET_assert (r == 1);
+  GNUNET_assert (W32_FD_ISSET(server, &rset) && !W32_FD_ISSET(server, &wset));
+
+  GNUNET_DISK_pipe_close (stdout_pipe);
+
+#if VERBOSE
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Done!\n");
+#endif
+  return 0;
+}
+static int
+test_named_pipe_threaded ()
+{
+  return 0;
+}
+static int
+test_anonymous_pipe_threaded ()
+{
+  return 0;
+}
+
+
+int
+main (int argc, char *argv[])
+{
+  int errCnt = 0;
+  int port = 53210;
+
+  char *self_dir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_SELF_PREFIX);
+  sprintf (self_name, "%s%s", self_dir, "test_w32io.exe");
+  GNUNET_free (self_dir);
+
+  if (argc < 2)
+  {
+  GNUNET_log_setup ("test-w32io",
+#if VERBOSE
+     "DEBUG",
+#else
+     "WARNING",
+#endif
+      NULL);
+
+    if (0 != test_anonymous_pipe_server_read ())
+      errCnt++;
+    if (0 != test_anonymous_pipe_server_write ())
+      errCnt++;
+    if (0 != test_socket_server (1, port++))
+      errCnt++;
+    if (0 != test_named_pipe_server_read (1))
+      errCnt++;
+    if (0 != test_named_pipe_server_write (1))
+      errCnt++;
+    if (0 != test_named_pipe_server_hup (1))
+      errCnt++;
+    if (0 != test_socket_threaded (port++))
+      errCnt++;
+    if (0 != test_named_pipe_threaded ())
+      errCnt++;
+    if (0 != test_anonymous_pipe_threaded ())
+      errCnt++;
+  }
+  else
+  {
+  GNUNET_log_setup ("test-w32io",
+#if VERBOSE
+     "DEBUG",
+#else
+     "WARNING",
+#endif
+      NULL);
+
+    if (strcmp (argv[1], "socket") == 0)
+    {
+      if (argc < 3)
+        errCnt++;
+      else
+      {
+        port = strtol (argv[2], NULL, 10);
+        if (0 != test_socket_client (port))
+          errCnt++;
+      }
+    }
+    else if (strcmp (argv[1], "named_pipe") == 0)
+    {
+      if (argc < 4)
+        errCnt++;
+      else
+      {
+        if (strcmp (argv[2], "read") == 0)
+        {
+          if (0 != test_named_pipe_client_read (argv[3]))
+            errCnt++;
+        }
+        if (strcmp (argv[2], "write") == 0)
+        {
+          if (0 != test_named_pipe_client_write (argv[3]))
+            errCnt++;
+        }
+        if (strcmp (argv[2], "hup") == 0)
+        {
+          if (0 != test_named_pipe_client_hup (argv[3]))
+            errCnt++;
+        }
+      }
+    }
+    else if (strcmp (argv[1], "anonymous_pipe") == 0)
+    {
+      if (argc < 3)
+      {
+        errCnt++;
+      }
+      else
+      {
+        if (strcmp (argv[2], "read") == 0)
+        {
+          if (0 != test_anonymous_pipe_client_read (GetStdHandle (STD_INPUT_HANDLE)))
+            errCnt++;
+        }
+        if (strcmp (argv[2], "write") == 0)
+        {
+          if (0 != test_anonymous_pipe_client_write (GetStdHandle (STD_OUTPUT_HANDLE)))
+            errCnt++;
+        }
+      }
+    }
+  }
+#if VERBOSE
+  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "All done, %d test failed\n", errCnt);
+#endif
+  return errCnt;
+}
diff --git a/src/util/w32io.c b/src/util/w32io.c
new file mode 100644
index 0000000..7c5aba7
--- /dev/null
+++ b/src/util/w32io.c
@@ -0,0 +1,3698 @@
+/*
+     This file is part of GNUnet.
+     (C) 2001, 2002, 2005, 2006, 2009, 2010 Christian Grothoff (and other contributing authors)
+
+     GNUnet is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published
+     by the Free Software Foundation; either version 2, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+     Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file util/w32io.c
+ * @brief POSIX-compatible I/O under NT
+ * @author LRN
+ */
+
+#include "platform.h"
+#include "gnunet_common.h"
+#include "w32io.h"
+
+#if WINDOWS
+
+#define W32IO_DISABLE_LOCKING 0
+#define DEBUG_W32IO GNUNET_NO
+#define DEBUG_W32IO_THREADS GNUNET_NO
+
+struct W32Fd **fds = NULL;
+size_t fds_len = 0;
+HANDLE fds_mutex = NULL;
+
+/**
+ * Call it at least once.
+ */
+int w32io_init ()
+{
+#if W32IO_DISABLE_LOCKING
+  return 0;
+#else
+  if (fds_mutex == NULL)
+  {
+    fds_mutex = CreateMutex (NULL, FALSE, NULL);
+    return 0;
+  }
+  return -1;
+#endif
+}
+
+int w32io_deinit ()
+{
+#if W32IO_DISABLE_LOCKING
+  return 0;
+#else
+  if (fds_mutex != NULL)
+  {
+    CloseHandle (fds_mutex);
+    return 0;
+  }
+  return -1;
+#endif
+}
+
+/**
+ * Fetches a real W32Fd from the array of FDs using @fake_fd as an index.
+ * Might lock waiting for the mutex.
+ *
+ * @param fake_fd fake FD, as returned and taken by W32IO functions.
+ * @return "real" W32Fd, used internally by W32IO
+ */
+struct W32Fd *
+w32io_fetch_fd (int fake_fd)
+{
+  DWORD error_code;
+  DWORD dw_result;
+  /* To keep the amount of locktime minimum all logging operations are moved
+   * outside of the locked area (well, logs[0] is moved, everything else is
+   * outside as it is, but i kept them together for consistency).
+   */
+  int logs[3] = {0, 0, 0};
+  size_t len = 0;
+  struct W32Fd *result = NULL;
+#if !W32IO_DISABLE_LOCKING
+  SetLastError (0);
+  dw_result = WaitForSingleObject (fds_mutex, INFINITE);
+  error_code = GetLastError ();
+  if (dw_result == WAIT_OBJECT_0)
+  {
+#endif
+    if (fds_len <= fake_fd)
+    {
+      logs[0] = 1;
+      len = fds_len;
+      errno = EINVAL;
+    }
+    else
+    {
+      result = fds[fake_fd];
+    }
+#if !W32IO_DISABLE_LOCKING
+    ReleaseMutex (fds_mutex);
+#endif
+    if (result == NULL)
+    {
+      logs[1] = 1;
+      errno = EINVAL;
+    }
+#if !W32IO_DISABLE_LOCKING
+  }
+  else
+  {
+    logs[2] = 1;
+    SetErrnoFromWinError (error_code);
+  }
+#endif
+  if (logs[0])
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to fetch real fd for fake fd %d - array length is only %d\n", fake_fd, len);
+  if (logs[1])
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to fetch real fd for fake fd %d - real fd is NULL\n", fake_fd);
+  if (logs[2])
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to fetch real fd for fake fd %d - can't lock mutex %08X\n", fake_fd, fds_mutex);
+  return result;
+}
+
+/**
+ * Inserts a real W32Fd into the array of FDs and returns a @fake_fd.
+ * Might lock waiting for the mutex.
+ *
+ * @param real_fd "real" W32Fd, used internally by W32IO.
+ * @return "fake" FD
+ */
+int
+w32io_insert_fd (struct W32Fd *real_fd)
+{
+  DWORD error_code;
+  DWORD dw_result;
+  int i;
+  /* To keep the amount of locktime minimum all logging operations are moved
+   * outside of the locked area (well, logs[0] is moved, everything else is
+   * outside as it is, but i kept them together for consistency).
+   */
+  int result = -1;
+#if !W32IO_DISABLE_LOCKING
+  SetLastError (0);
+  dw_result = WaitForSingleObject (fds_mutex, INFINITE);
+  error_code = GetLastError ();
+  if (dw_result == WAIT_OBJECT_0)
+  {
+#endif
+    for (i = 0; i < fds_len; i++)
+    {
+      if (fds[i] == NULL)
+      {
+        fds[i] = real_fd;
+        result = i;
+        break;
+      }
+    }
+    if (result == -1)
+    {
+      result = fds_len;
+      GNUNET_array_grow(fds, fds_len, fds_len > 0 ? fds_len * 2 : 5);
+      fds_len = fds_len * 2;
+      fds[result] = real_fd;
+    }
+#if !W32IO_DISABLE_LOCKING
+    ReleaseMutex (fds_mutex);
+  }
+  else
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to insert real fd %08X - can't lock mutex %08X\n", real_fd, fds_mutex);
+    SetErrnoFromWinError (error_code);
+  }
+#endif
+  return result;
+}
+
+/**
+ * Removes a real W32Fd from the array of FDs by its "fake" index.
+ * Might lock waiting for the mutex.
+ *
+ * @param fake_fd "fake" FD
+ */
+void
+w32io_remove_fd (int fake_fd)
+{
+  DWORD error_code;
+  DWORD dw_result;
+  int logs[3] = {0, 0, 0};
+  size_t len = 0;
+  struct W32Fd *result = NULL;
+#if !W32IO_DISABLE_LOCKING
+  SetLastError (0);
+  dw_result = WaitForSingleObject (fds_mutex, INFINITE);
+  error_code = GetLastError ();
+  if (dw_result == WAIT_OBJECT_0)
+  {
+#endif
+    if (fds_len <= fake_fd)
+    {
+      logs[0] = 1;
+      len = fds_len;
+      errno = EINVAL;
+    }
+    else
+    {
+      result = fds[fake_fd];
+      fds[fake_fd] = NULL;
+    }
+#if !W32IO_DISABLE_LOCKING
+    ReleaseMutex (fds_mutex);
+#endif
+    if (result == NULL)
+    {
+      logs[1] = 1;
+      errno = EINVAL;
+    }
+#if !W32IO_DISABLE_LOCKING
+  }
+  else
+  {
+    logs[2] = 1;
+    SetErrnoFromWinError (error_code);
+  }
+#endif
+  if (logs[0])
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to fetch real fd for fake fd %d - array length is only %d\n", fake_fd, len);
+  if (logs[1])
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to fetch real fd for fake fd %d - real fd is NULL\n", fake_fd);
+  if (logs[2])
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to fetch real fd for fake fd %d - can't lock mutex %08X\n", fake_fd, fds_mutex);
+}
+
+DWORD __stdcall w32io_anonymous_pipe_thread_func (void *data);
+
+#define GNUNET_W32IO_PIPE_NAME_PREFIX "\\\\.\\pipe\\"
+
+#define SOCKET_POLL_EVENT POLLIN_BIT
+#define SOCKET_WAKEUP_EVENT POLLOUT_BIT
+#define SOCKET_OVERLAPPED_WRITE_EVENT POLLWRBAND_BIT
+#define ANON_PIPE_THREAD_POLL_EVENT POLLIN_BIT
+#define ANON_PIPE_CONFIRM_POLL_EVENT POLLWRBAND_BIT
+#define ANON_PIPE_MAIN_THREAD_POLL_EVENT POLLOUT_BIT
+#define ANON_PIPE_CLOSE_POLL_EVENT POLLHUP_BIT
+#define FILE_READY_POLL_EVENT POLLIN_BIT
+
+#define ZeroOverlappedExceptEvent(o) o.Internal = o.InternalHigh = o.Offset = o.OffsetHigh = 0
+
+HANDLE
+w32io_fd_get_handle (struct W32Fd *fd)
+{
+  return fd->fd;
+}
+
+HANDLE
+GNUNET_W32IO_fd_get_handle (int fd)
+{
+  struct W32Fd *wfd = w32io_fetch_fd (fd);
+  if (wfd == NULL || wfd == INVALID_POLL_FD)
+    return INVALID_HANDLE_VALUE;
+  return w32io_fd_get_handle (wfd);
+}
+
+void
+GNUNET_W32IO_generate_random_local_pipe_name (char pipename[255])
+{
+  int i;
+  static DWORD seed = 0;
+  static float scale = 32767 / 25;
+  static int prefixlen = 9;
+  if (seed == 0)
+  {
+    seed = GetCurrentProcessId ();
+    srand (seed);
+  }
+  /* Uniqueness is not guaranteed - but we can always regenerate the name until
+   * it comes out to be unique.
+   */
+  memcpy (pipename, GNUNET_W32IO_PIPE_NAME_PREFIX, prefixlen);
+  for (i = prefixlen; i < 254; i++)
+  {
+    /* Get a random 0-32767 integer, then scale it to 65-90. This is not
+     * really a requirement - MSDN says that the only forbidden character
+     * for pipe names is the backslash. But i won't be taking any chances.
+     */
+    /* TODO: use RtlRandom() or RtlRandomEx() instead of rand() */
+    pipename[i] = 65 + (char) (rand() / scale);
+  }
+  pipename[254] = 0;
+}
+
+int
+w32io_pipe (struct W32Fd *fd[2], int server_inheritable, int client_inheritable, DWORD server_mode, DWORD client_mode)
+{
+  char pipename[255];
+  SECURITY_ATTRIBUTES sa;
+  DWORD err;
+  BOOL bret;
+  OVERLAPPED ov;
+  HANDLE p[2];
+  p[0] = p[1] = NULL;
+  memset (&ov, 0, sizeof (ov));
+  while (!p[0])
+  {
+    sa.nLength = sizeof (sa);
+    sa.lpSecurityDescriptor = NULL;
+    sa.bInheritHandle = server_inheritable;
+    GNUNET_W32IO_generate_random_local_pipe_name (pipename);
+    /* FILE_FLAG_FIRST_PIPE_INSTANCE makes sure that we're first to create a
+     * pipe with such name.
+     * FILE_FLAG_OVERLAPPED creates async pipe. If the user wants to perform
+     * blocking I/O, we can easily create a blocking wrapper.
+     */
+    p[0] = CreateNamedPipeA ((LPCSTR) pipename, server_mode |
+        FILE_FLAG_FIRST_PIPE_INSTANCE | FILE_FLAG_OVERLAPPED |
+        PIPE_ACCESS_INBOUND, /*inbound access is necessary to read pipe info*/
+        PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
+        PIPE_UNLIMITED_INSTANCES, 4096, 4096, 0, &sa);
+    if (p[0] == INVALID_HANDLE_VALUE)
+    {
+      err = GetLastError ();
+      switch (err)
+      {
+        case ERROR_ACCESS_DENIED:
+          p[0] = NULL;
+          continue;
+      }
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to create a named pipe. GLE: %d\n", err);
+      return FALSE;
+    }
+  }
+  bret = ConnectNamedPipe (p[0], &ov);
+  if (bret == 0)
+  {
+    err = GetLastError ();
+    if (err == ERROR_IO_PENDING)
+    {
+      //It's ok, it works in the background while we finish other things
+    }
+    else if (err != ERROR_PIPE_CONNECTED)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to connect a named pipe. GLE: %d\n", err);
+      CloseHandle (p[0]);
+      return FALSE;
+    }
+  }
+  sa.nLength = sizeof (sa);
+  sa.lpSecurityDescriptor = NULL;
+  sa.bInheritHandle = client_inheritable;
+  p[1] = CreateFileA ((LPCSTR) pipename, client_mode, 0, &sa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED | FILE_READ_ATTRIBUTES, NULL);
+  if (p[1] == INVALID_HANDLE_VALUE)
+  {
+    err = GetLastError ();
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to open client side of a named pipe. GLE: %d\n", err);
+    CloseHandle(p[0]);
+    return FALSE;
+  }
+  //We've made both I/O calls, wait until the pipe is connected an opened
+  bret = GetOverlappedResult (p[0], &ov, &err, TRUE);
+
+  /* Both are not readable because we know that there is no data to read (yet).
+   * Write end is writable, because no writing is being done.
+   * Read end is, however, not writable, because it is read-only.
+   */
+  fd[0] = w32io_fd_from_handle (p[0], GNUNET_W32IO_NAMED_PIPE, (server_mode & PIPE_ACCESS_OUTBOUND ? GENERIC_WRITE : 0) | (server_mode & PIPE_ACCESS_INBOUND ? GENERIC_READ : 0), TRUE, server_mode & PIPE_ACCESS_OUTBOUND, server_mode & PIPE_ACCESS_INBOUND);
+  fd[1] = w32io_fd_from_handle (p[1], GNUNET_W32IO_NAMED_PIPE, (client_mode & PIPE_ACCESS_OUTBOUND ? GENERIC_WRITE : 0) | (client_mode & PIPE_ACCESS_INBOUND ? GENERIC_READ : 0), TRUE, client_mode & PIPE_ACCESS_OUTBOUND, client_mode & PIPE_ACCESS_INBOUND);
+
+  return TRUE;
+}
+
+int
+GNUNET_W32IO_pipe (int fd[2], int server_inheritable, int client_inheritable, DWORD server_mode, DWORD client_mode)
+{
+  struct W32Fd *wfd[2];
+  int ret;
+  ret = w32io_pipe (wfd, server_inheritable, client_inheritable, server_mode, client_mode);
+  if (ret)
+  {
+    fd[0] = w32io_insert_fd (wfd[0]);
+    fd[1] = w32io_insert_fd (wfd[1]);
+  }
+  return ret;
+}
+
+int
+w32io_anonymous_pipe (struct W32Fd *fd[2], int read_inheritable, int write_inheritable)
+{
+  int ret = TRUE;
+  BOOL bret;
+  DWORD err;
+  HANDLE p[2] = { 0, 0 };
+  SECURITY_ATTRIBUTES sa;
+  /* Mark handle as inheritable if at least one end must be inheritable */
+  int create_inheritance = read_inheritable || write_inheritable;
+
+  sa.nLength = sizeof (sa);
+  sa.lpSecurityDescriptor = NULL;
+  sa.bInheritHandle = create_inheritance;
+
+  bret = CreatePipe (&p[0], &p[1], &sa, 4096);
+  if (bret == 0)
+  {
+    err = GetLastError ();
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to create an anonymous pipe. GLE: %d\n", err);
+    ret = FALSE;
+  }
+  if (create_inheritance && !read_inheritable)
+  {
+    /* Desired read inheritance does not match create_inheritance */
+    HANDLE t = p[0];
+    bret = DuplicateHandle (GetCurrentProcess (), t, GetCurrentProcess (), &p[0],
+        0, read_inheritable, DUPLICATE_SAME_ACCESS);
+    if (bret == 0)
+    {
+      err = GetLastError ();
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to duplicate read end of an anonymous pipe. GLE: %d\n", err);
+      ret = FALSE;
+      p[0] = t;
+    }
+    else
+      CloseHandle (t);
+  }
+  if (create_inheritance && !write_inheritable)
+  {
+    /* Desired write inheritance does not match create_inheritance */
+    HANDLE t = p[1];
+    bret = DuplicateHandle (GetCurrentProcess (), t, GetCurrentProcess (), &p[1],
+        0, write_inheritable, DUPLICATE_SAME_ACCESS);
+    if (bret == 0)
+    {
+      err = GetLastError ();
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to duplicate write end of an anonymous pipe. GLE: %d\n", err);
+      ret = FALSE;
+      p[1] = t;
+    }
+    else
+      CloseHandle (t);
+  }
+
+  if (ret == FALSE)
+  {
+    if (p[0])
+      CloseHandle (p[0]);
+    if (p[1])
+      CloseHandle (p[1]);
+    return ret;
+  }
+
+#if DEBUG_W32IO_THREADS
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Registering the read handle...\n");
+#endif
+  fd[0] = w32io_fd_from_handle (p[0], GNUNET_W32IO_ANONYMOUS_PIPE, read_inheritable ? 0 : GENERIC_READ, TRUE, FALSE, TRUE);
+#if DEBUG_W32IO_THREADS
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Registering the write handle...\n");
+#endif
+  fd[1] = w32io_fd_from_handle (p[1], GNUNET_W32IO_ANONYMOUS_PIPE, write_inheritable ? 0 : GENERIC_WRITE, TRUE, TRUE, FALSE);
+#if DEBUG_W32IO_THREADS
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Done creating an anonymous pipe...\n");
+#endif
+
+  return ret;
+}
+
+int
+GNUNET_W32IO_anonymous_pipe (int fd[2], int read_inheritable, int write_inheritable)
+{
+  struct W32Fd *wfd[2];
+  int ret;
+  ret = w32io_anonymous_pipe (wfd, read_inheritable, write_inheritable);
+  if (ret)
+  {
+    fd[0] = w32io_insert_fd (wfd[0]);
+    fd[1] = w32io_insert_fd (wfd[1]);
+  }
+  return ret;
+}
+
+int
+w32io_fsync (struct W32Fd *wfd)
+{
+  int ret;
+  if (wfd == NULL || wfd->fd == (void *) -1)
+  {
+    errno = EBADF;
+    return -1;
+  }
+
+  switch (wfd->fd_type)
+  {
+  case GNUNET_W32IO_FILE:
+  case GNUNET_W32IO_NAMED_PIPE:
+  case GNUNET_W32IO_ANONYMOUS_PIPE:
+    ret = TRUE == FlushFileBuffers (wfd->fd);
+    break;
+  default:
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Can't fsync() - fd is not a file or pipe\n");
+    ret = 0;
+  }
+  return ret;
+}
+
+int
+GNUNET_W32IO_fsync (int fd)
+{
+  return w32io_fsync (w32io_fetch_fd (fd));
+}
+
+int
+w32io_shutdown (struct W32Fd *wfd, int how)
+{
+  int ret;
+  switch (wfd->fd_type)
+  {
+  case GNUNET_W32IO_SOCKET:
+    ret = shutdown ((SOCKET) wfd->fd, how);
+    if (ret == SOCKET_ERROR)
+    {
+      DWORD error_code = GetLastError ();
+      SetErrnoFromWinError (error_code);
+    }
+    if (how == SD_SEND || how == SD_BOTH)
+      wfd->wsaevents.lNetworkEvents &= ~FD_WRITE;
+    if (how == SD_RECEIVE || how == SD_BOTH)
+      wfd->wsaevents.lNetworkEvents &= ~FD_READ;
+    return ret;
+  default:
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Can't shutdown() - fd is not a socket\n");
+    return 0;
+  }
+}
+
+int
+GNUNET_W32IO_shutdown (int fd, int how)
+{
+  return w32io_shutdown (w32io_fetch_fd (fd), how);
+}
+
+int
+w32io_close (struct W32Fd *wfd, int closehandle)
+{
+  int i;
+  DWORD dwresult;
+
+  int ret = 0;
+  if (wfd == NULL || wfd->fd == (void *) -1)
+    return ret;
+  switch (wfd->fd_type)
+  {
+  case GNUNET_W32IO_SOCKET:
+    /* Break the link between the socket and its event */
+    WSAEventSelect ((SOCKET) wfd->fd, NULL, 0);
+    ret = ret || !CloseHandle (wfd->overlapped[SOCKET_POLL_EVENT].hEvent);
+    ret = ret || !CloseHandle (wfd->overlapped[SOCKET_WAKEUP_EVENT].hEvent);
+
+    dwresult = WaitForSingleObject (wfd->overlapped[SOCKET_OVERLAPPED_WRITE_EVENT].hEvent, 0);
+    if (dwresult == WAIT_TIMEOUT)
+    {
+      /* Disabled state of the event means that there is still an
+       * operation going on (event has to be reset manually and should
+       * stay signalled after I/O is complete until it is started again).
+       * Except for FD_CONNECT (it is unset after pipe is connected)
+       */
+      /* We're going to free the event. Have to cancel all I/O issued by
+       * this thread using this fd.
+       */
+      if (CancelIo (wfd->fd))
+      {
+        DWORD r;
+        /* Wait until I/O is cancelled */
+        WSAGetOverlappedResult ((SOCKET) wfd->fd, &wfd->overlapped[SOCKET_OVERLAPPED_WRITE_EVENT], &dwresult, TRUE, &r);
+      }
+    }
+    ret = ret || !CloseHandle (wfd->overlapped[SOCKET_OVERLAPPED_WRITE_EVENT].hEvent);
+
+    if (wfd->wrbuffer)
+    {
+      GNUNET_free (wfd->wrbuffer->buf);
+      GNUNET_free (wfd->wrbuffer);
+      wfd->wrbuffer = NULL;
+    }
+    if (closehandle)
+    {
+      ret = ret || closesocket ((SOCKET) wfd->fd);
+    }
+    break;
+  case GNUNET_W32IO_FILE:
+  case GNUNET_W32IO_NAMED_PIPE:
+    for (i = 0; i < POLLLAST; i++)
+    {
+      if (wfd->overlapped[i].hEvent == INVALID_HANDLE_VALUE)
+        continue;
+
+      dwresult = WaitForSingleObject (wfd->overlapped[i].hEvent, 0);
+      if (dwresult == WAIT_TIMEOUT && (i == POLLIN_BIT || i == POLLOUT_BIT))
+      {
+        /* Disabled state of the event means that there is still an
+         * operation going on (event has to be reset manually and should
+         * stay signalled after I/O is complete until it is started again).
+         * Except for FD_CONNECT (it is unset after pipe is connected)
+         */
+        /* We're going to free the event. Have to cancel all I/O issued by
+         * this thread using this fd.
+         */
+        if (CancelIo (wfd->fd))
+        {
+          /* Wait until I/O is cancelled */
+          GetOverlappedResult (wfd->fd, &wfd->overlapped[i], &dwresult, TRUE);
+        }
+      }
+      ret = ret || !CloseHandle (wfd->overlapped[i].hEvent);
+      wfd->overlapped[i].hEvent = NULL;
+    }
+
+    if (wfd->wrbuffer)
+    {
+      GNUNET_free (wfd->wrbuffer->buf);
+      GNUNET_free (wfd->wrbuffer);
+      wfd->wrbuffer = NULL;
+    }
+    if (closehandle)
+    {
+      if (wfd->access & GENERIC_WRITE)
+        FlushFileBuffers (wfd->fd);
+      if (wfd->fd_type == GNUNET_W32IO_NAMED_PIPE)
+        DisconnectNamedPipe (wfd->fd);
+      ret = ret || !CloseHandle (wfd->fd);
+    }
+    break;
+  case GNUNET_W32IO_ANONYMOUS_PIPE:
+    ret = w32io_anonymous_pipe_close (wfd, closehandle);
+    break;
+  default:
+    errno = ENOSYS;
+  }
+  GNUNET_free (wfd);
+  return ret;
+}
+
+int
+GNUNET_W32IO_close (int fd, int closehandle)
+{
+  int ret = w32io_close (w32io_fetch_fd (fd), closehandle);
+  /* w32io_remove_fd() will NOT close or dealloc W32Fd,
+   * it is for fd namespace management only
+   */
+  w32io_remove_fd (fd);
+  return ret;
+}
+
+int
+w32io_poll (struct W32PollFd *fds, nfds_t nfds, int timeout, int emulate_select)
+{
+  HANDLE *hEvents = NULL;
+  unsigned int hEvents_len = 0;
+  int eventCount = 0;
+  DWORD dwResult = 0;
+  DWORD wait_ret = 0;
+  DWORD dwError = 0;
+  int result = 0;
+  int any_errors = FALSE;
+  int i, j, k;
+  int repeat;
+  int hits = 0;
+
+  /* Special case for using ppoll() as a portable way to sleep */
+  if (nfds == 0)
+  {
+    SetLastError (0);
+    dwResult = WaitForSingleObject (GetCurrentProcess (), timeout == -1 ? INFINITE : timeout);
+    dwError = GetLastError ();
+    if (dwResult == WAIT_FAILED)
+    {
+      SetErrnoFromWinError (dwError);
+      result = -1;
+    }
+    return result;
+  }
+
+  /* Instead of counting or using dynamic memory allocation, we'll just
+   * allocate the amount that is guaranteed to cover our needs.
+   */
+  hEvents = NULL;
+  GNUNET_array_grow(hEvents, hEvents_len, nfds * (POLLLAST + 1) * sizeof (HANDLE));
+
+  repeat = 1;
+  while (repeat == 1)
+  {
+    DWORD time1, time2;
+    eventCount = 0;
+    dwResult = 0;
+    wait_ret = 0;
+    dwError = 0;
+    result = 0;
+    repeat = -1;
+    for (i = 0; i < nfds; i++)
+    {
+      j = w32io_prepare_for_poll (&fds[i], &hEvents[eventCount]);
+    
+      if (eventCount + j - 1 >= nfds * (POLLLAST + 1) || j < 0)
+      {
+        GNUNET_free (hEvents);
+        return -1;
+      }
+      else
+        eventCount += j;
+    }
+  
+    SetLastError (0);
+#if DEBUG_W32IO
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+        "WaitForMultipleObjectsEx (%d, %x, FALSE, %d, FALSE)\n", eventCount,
+        hEvents, timeout == -1 ? INFINITE : timeout);
+#endif
+    time1 = GetTickCount ();
+    dwResult = WaitForMultipleObjectsEx (eventCount, hEvents, FALSE,
+        timeout == -1 ? INFINITE : timeout, FALSE);
+    dwError = GetLastError ();
+    if ((dwResult < eventCount && dwError == NO_ERROR) || dwResult == WAIT_TIMEOUT)
+    {
+      for (i = 0; i < nfds; i++)
+      {
+        int selected = 0;
+        if (fds[i].fd == INVALID_POLL_FD)
+          continue;
+        if (fds[i].fd->fd_type == GNUNET_W32IO_SOCKET)
+        {
+          int enumerated = 0;
+          for (j = 0; j < POLLLAST; j++)
+          {
+            if (fds[i].fd->overlapped[j].hEvent == INVALID_HANDLE_VALUE)
+              continue;
+  
+            wait_ret = WaitForSingleObject (fds[i].fd->overlapped[j].hEvent, 0);
+            if (wait_ret == WAIT_TIMEOUT)
+              continue;
+  
+            if ((j == SOCKET_POLL_EVENT || j == SOCKET_WAKEUP_EVENT))
+            {
+              WSANETWORKEVENTS events;
+              if (!enumerated)
+              {
+                enumerated = 1;
+                memset (&events, 0, sizeof (events));
+                int enum_ret = WSAEnumNetworkEvents ((SOCKET) fds[i].fd->fd, fds[i].fd->overlapped[SOCKET_POLL_EVENT].hEvent, &events);
+                if (enum_ret != 0) {
+                  dwError = GetLastError ();
+                  any_errors = TRUE;
+                  SetErrnoFromWinError (dwError);
+                  /* FIXME: make sure this is correct */
+                  if (dwError == WSAECONNRESET)
+                  {
+                    fds[i].fd->revents |= POLLHUP;
+                  }
+                  else
+                    fds[i].fd->revents |= POLLERR;
+                  break;
+                }
+                /* This way we won't lose one-time events. However, we also must
+                 * watch what we do with the socket and drop the bits from
+                 * lNetworkEvents when appropriate.
+                 */
+                fds[i].fd->wsaevents.lNetworkEvents |= events.lNetworkEvents;
+                for (k = 0; k < FD_MAX_EVENTS; k++)
+                {
+                  int bit = 1 << k;
+                  if (fds[i].fd->events & bit & fds[i].fd->wsaevents.lNetworkEvents)
+                  {
+                    fds[i].fd->revents |= bit;
+                    hits += 1;
+                    selected = 1;
+                    if (fds[i].fd->wsaevents.iErrorCode[k] != 0)
+                      fds[i].fd->revents |= POLLERR;
+                  }
+                }
+                if (fds[i].fd->revents & FD_CONNECT)
+                {
+                  fds[i].fd->revents &= ~FD_CONNECT;
+                  fds[i].fd->revents |= POLLOUT;
+                }
+                if (fds[i].fd->revents & FD_ACCEPT)
+                {
+                  fds[i].fd->revents &= ~FD_ACCEPT;
+                  fds[i].fd->revents |= POLLIN;
+                }
+                if (fds[i].fd->wsaevents.lNetworkEvents & FD_CLOSE)
+                {
+                  fds[i].fd->revents |= POLLHUP;
+                  fds[i].fd->revents &= ~POLLOUT;
+                  hits += 1;
+                  selected = 1;
+                }
+              }
+              if (j == SOCKET_WAKEUP_EVENT)
+                ResetEvent (fds[i].fd->overlapped[j].hEvent);
+            }
+            else if (j == SOCKET_OVERLAPPED_WRITE_EVENT)
+            {
+              DWORD r, t, e;
+              SetLastError (0);
+              if (!WSAGetOverlappedResult ((SOCKET) fds[i].fd->fd, &fds[i].fd->overlapped[j], &t, TRUE, &r))
+              {
+                e = GetLastError ();
+                /* FIXME: handle the error */
+              }
+              if (fds[i].fd->wrbuffer)
+              {
+                GNUNET_free (fds[i].fd->wrbuffer->buf);
+                GNUNET_free (fds[i].fd->wrbuffer);
+                fds[i].fd->wrbuffer = NULL;
+              }
+              ResetEvent (fds[i].fd->overlapped[j].hEvent);
+            }
+            else
+            {
+              switch (j)
+              {
+              case POLLERR_BIT:
+              case POLLHUP_BIT:
+              case POLLNVAL_BIT:
+                fds[i].fd->revents |= 1 << j;
+                break;
+              default:
+                ;
+              }
+              ResetEvent (fds[i].fd->overlapped[j].hEvent);
+            }
+          }
+        }
+        else if (fds[i].fd->fd_type == GNUNET_W32IO_FILE)
+        {
+          /* TODO: better implementation (consider two processes sharing
+           * a file, both for reading and for writing; consider deleting
+           * a file while a process waits on it).
+           */
+          for (j = 0; j < POLLLAST; j++)
+          {
+            DWORD eventSet;
+            BOOL bret;
+            int bit = 1 << j;
+  
+            if (fds[i].fd->overlapped[j].hEvent == INVALID_HANDLE_VALUE)
+              continue;
+  
+            eventSet = 0;
+            eventSet = WaitForSingleObject (fds[i].fd->overlapped[j].hEvent, 0);
+            if (eventSet == WAIT_FAILED)
+            {
+              // FIXME: handle the error
+              any_errors = TRUE;
+              continue;
+            }
+            if (eventSet == WAIT_TIMEOUT)
+              continue;
+  
+            /* common code for all three events */          
+            bret = 0;
+            switch (j)
+            {
+            case POLLIN_BIT:
+            case POLLOUT_BIT:
+              fds[i].fd->revents |= bit;
+              fds[i].fd->wsaevents.lNetworkEvents |= bit;
+              fds[i].fd->wsaevents.iErrorCode[j] = 0;
+              /* If ReadFile returned immediately, won't GetOvelappedResult() block forever? */
+              /*
+              bret = GetOverlappedResult (fds[i].fd->fd,
+                  &fds[i].fd->overlapped[j], &wait_ret, TRUE);
+              */
+              selected = 1;
+              break;
+            case POLLERR_BIT:
+            case POLLNVAL_BIT:
+              fds[i].fd->wsaevents.iErrorCode[j] = fds[i].fd->dwerror;
+            default:
+              fds[i].fd->revents |= bit;
+              fds[i].fd->wsaevents.lNetworkEvents |= bit;
+            }
+  
+            switch (j)
+            {
+            case POLLIN_BIT:
+              /*
+              if (bret != 0)
+                break;
+  
+  
+              wait_ret = GetLastError ();
+              if (wait_ret == ERROR_HANDLE_EOF) {
+                fds[i].fd->revents &= ~FD_READ;
+                fds[i].fd->wsaevents.lNetworkEvents &= ~FD_READ;
+              } else {
+                any_errors = TRUE;
+                fds[i].fd->revents |= POLLERR;
+                fds[i].fd->wsaevents.iErrorCode[j] = wait_ret;
+                errno = gst_win32_error_to_errno(wait_ret);
+              }
+              */
+              break;
+            case POLLOUT_BIT:
+              if (fds[i].fd->wrbuffer) {
+                GNUNET_free (fds[i].fd->wrbuffer->buf);
+                GNUNET_free (fds[i].fd->wrbuffer);
+                fds[i].fd->wrbuffer = NULL;
+              }
+              /*
+              if (bret != 0)
+                break;
+  
+              wait_ret = GetLastError ();
+              if (wait_ret != NO_ERROR)
+              {
+                any_errors = TRUE;
+                fds[i].fd->revents |= POLLERR;
+                fds[i].fd->wsaevents.iErrorCode[j] = wait_ret;
+                errno = gst_win32_error_to_errno(wait_ret);
+              }
+              */
+              break;
+            default:
+              break;
+            }
+            ResetEvent (fds[i].fd->overlapped[j].hEvent);
+          }
+        }
+        else if (fds[i].fd->fd_type == GNUNET_W32IO_ANONYMOUS_PIPE)
+        {
+          for (j = 0; j < POLLLAST; j++)
+          {
+            DWORD eventSet;
+            BOOL bret;
+            int bit = 1 << j;
+  
+            if (fds[i].fd->overlapped[j].hEvent == INVALID_HANDLE_VALUE || j == ANON_PIPE_THREAD_POLL_EVENT || j == ANON_PIPE_CONFIRM_POLL_EVENT)
+              continue;
+
+            eventSet = 0;
+            eventSet = WaitForSingleObject (fds[i].fd->overlapped[j].hEvent, 0);
+            if (eventSet == WAIT_FAILED)
+            {
+              /* FIXME: handle the error */
+              any_errors = TRUE;
+              continue;
+            }
+            if (eventSet == WAIT_TIMEOUT)
+              continue;
+            
+            /* common code for all three events */          
+            bret = 0;
+            switch (j)
+            {
+            case ANON_PIPE_MAIN_THREAD_POLL_EVENT:
+              fds[i].fd->revents |= (fds[i].fd->access & GENERIC_WRITE ? POLLOUT : 0) | (fds[i].fd->access & GENERIC_READ ? POLLIN : 0);
+              selected = 1;
+#if DEBUG_W32IO
+              GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Locking the thread mutex.\n");
+#endif
+
+              WaitForSingleObject (fds[i].fd->anon_thread_mutex, INFINITE);
+#if DEBUG_W32IO
+              GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Locked the thread mutex.\n");
+#endif
+              break;
+            case POLLHUP_BIT:
+              fds[i].fd->revents |= bit;
+            
+              selected = 1;
+#if DEBUG_W32IO
+              GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Locking the thread mutex.\n");
+#endif
+              WaitForSingleObject (fds[i].fd->anon_thread_mutex, INFINITE);
+#if DEBUG_W32IO
+              GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Locked the thread mutex.\n");
+#endif
+              break;
+            case POLLERR_BIT:
+            case POLLNVAL_BIT:
+              fds[i].fd->revents |= bit;
+            default:
+              ;
+            }
+            
+            switch (j)
+            {
+            case ANON_PIPE_MAIN_THREAD_POLL_EVENT:
+              if (fds[i].fd->dwerror == ERROR_BROKEN_PIPE) {
+                fds[i].fd->revents |= POLLHUP;
+                SetEvent (fds[i].fd->overlapped[POLLHUP_BIT].hEvent);
+              } else if (fds[i].fd->dwerror != NO_ERROR) {
+                any_errors = TRUE;
+                fds[i].fd->revents |= POLLERR;
+                SetErrnoFromWinError (fds[i].fd->dwerror);
+              }
+              break;
+            case POLLHUP_BIT:
+              if (!(fds[i].fd->events & (POLLIN | POLLOUT)))
+              {
+                if (fds[i].fd->dwerror == ERROR_BROKEN_PIPE)
+                {
+                  fds[i].fd->revents |= POLLHUP;
+                } else if (fds[i].fd->dwerror == NO_ERROR) {
+                  /* FIXME: make sure this is the right way...
+                   * something might have set [POLLHUP_BIT].hEvent but not
+                   * the dwerror
+                   */
+                  ResetEvent (fds[i].fd->overlapped[POLLHUP_BIT].hEvent);
+                } else {
+                  any_errors = TRUE;
+                  fds[i].fd->revents |= POLLERR;
+                  SetErrnoFromWinError (fds[i].fd->dwerror);
+                }
+              }
+              break;
+            default:
+              /* Never set */
+              break;
+            }
+            
+            switch (j)
+            {
+            case ANON_PIPE_MAIN_THREAD_POLL_EVENT:
+            case POLLHUP_BIT:
+            case POLLERR_BIT:
+            case POLLNVAL_BIT:
+              ResetEvent (fds[i].fd->overlapped[j].hEvent);
+              ReleaseMutex (fds[i].fd->anon_thread_mutex);
+              break;
+            default:
+              ;
+            }
+          }
+        }
+        else if (fds[i].fd->fd_type == GNUNET_W32IO_NAMED_PIPE)
+        {
+          for (j = 0; j < POLLLAST; j++)
+          {
+            DWORD eventSet;
+            int bret;
+            int bit = 1 << j;
+  
+            if (fds[i].fd->overlapped[j].hEvent == INVALID_HANDLE_VALUE)
+              continue;
+
+            /*  
+            if (j == POLLOUT_BIT)
+            {
+              if (fds[i].fd->writebuffer == NULL && (fds[i].fd->access & GENERIC_WRITE))
+              {
+                fds[i].fd->revents |= bit;
+                fds[i].fd->wsaevents.lNetworkEvents |= bit;
+                SetEvent (fds[i].fd->overlapped[POLLOUT_BIT].hEvent);
+              }
+            }
+            */
+            eventSet = 0;
+            eventSet = WaitForSingleObject (fds[i].fd->overlapped[j].hEvent, 0);
+            if (eventSet == WAIT_FAILED)
+            {
+              /* FIXME: handle the error */
+              any_errors = TRUE;
+              continue;
+            }
+            if (eventSet == WAIT_TIMEOUT)
+              continue;
+            
+            /* common code for all three events */          
+            bret = 0;
+            switch (j)
+            {
+            case POLLIN_BIT:
+            case FD_CONNECT_BIT:
+            case POLLOUT_BIT:
+              fds[i].fd->revents |= bit;
+              fds[i].fd->wsaevents.lNetworkEvents |= bit;
+              fds[i].fd->wsaevents.iErrorCode[j] = 0;
+              bret = GetOverlappedResult (fds[i].fd->fd,
+                  &fds[i].fd->overlapped[j], &wait_ret, TRUE);
+              selected = 1;
+              break;
+            default:
+              ;
+            }
+            
+            switch (j)
+            {
+            case POLLIN_BIT:
+              /* Our read-zero-bytes operation is complete, which means that
+               * there is data to be read. Keep the event set. It will be
+               * unset by our read() implementation or by *_prepare_for_poll
+               */
+              if (bret != 0)
+                break;
+            
+              wait_ret = GetLastError ();
+#if DEBUG_W32IO
+              GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "GetOverlappedResult failed with GLE %d\n", wait_ret);
+#endif
+              if (wait_ret == ERROR_BROKEN_PIPE || wait_ret == ERROR_PIPE_NOT_CONNECTED) {
+                fds[i].fd->revents |= FD_CLOSE;
+                fds[i].fd->wsaevents.lNetworkEvents |= FD_CLOSE;
+            
+                SetEvent (fds[i].fd->overlapped[FD_CLOSE_BIT].hEvent);
+            
+                /* Set FD_CONNECT event so that we can attempt to connect again */
+                SetEvent (fds[i].fd->overlapped[FD_CONNECT_BIT].hEvent);
+              } else if (wait_ret != NO_ERROR) {
+                any_errors = TRUE;
+                fds[i].fd->revents |= POLLERR;
+                fds[i].fd->wsaevents.iErrorCode[j] = wait_ret;
+                SetErrnoFromWinError (wait_ret);
+              }
+              break;
+            case FD_CONNECT_BIT:
+              /* Our ConnectNamedPipe() operation is complete, which means that
+               * the pipe was not connected before, but is connected now.
+               */
+              /* Unset the event - that would prevent *_prepare_for_poll from
+               * trying to re-connect the pipe each time it is called.
+               */
+              ResetEvent (fds[i].fd->overlapped[j].hEvent);
+
+              if (bret != 0)
+                break;
+            
+              wait_ret = GetLastError ();
+#if DEBUG_W32IO
+              GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "GetOverlappedResult failed with GLE %d\n", wait_ret);
+#endif
+              if (wait_ret == ERROR_NO_DATA) {
+                fds[i].fd->revents |= FD_CLOSE;
+                fds[i].fd->wsaevents.lNetworkEvents |= FD_CLOSE;
+                SetEvent (fds[i].fd->overlapped[FD_CLOSE_BIT].hEvent);
+                SetEvent (fds[i].fd->overlapped[FD_CONNECT_BIT].hEvent);
+              } else if (wait_ret != NO_ERROR) {
+                any_errors = TRUE;
+                fds[i].fd->revents |= POLLERR;
+                fds[i].fd->wsaevents.iErrorCode[j] = wait_ret;
+                SetErrnoFromWinError (wait_ret);
+              }
+            
+              break;
+            case POLLOUT_BIT:
+              /* Our WriteFile() operation is complete, which means that the pipe
+               * is ready to write once more. Keep the event set - it will be
+               * unset by our write() implementation.
+               */
+              if (fds[i].fd->wrbuffer) {
+                GNUNET_free (fds[i].fd->wrbuffer->buf);
+                GNUNET_free (fds[i].fd->wrbuffer);
+                fds[i].fd->wrbuffer = NULL;
+              }
+            
+              if (bret != 0)
+                break;
+            
+              wait_ret = GetLastError ();
+#if DEBUG_W32IO
+              GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "GetOverlappedResult failed with GLE %d\n", wait_ret);
+#endif
+              if (wait_ret == ERROR_BROKEN_PIPE) {
+                fds[i].fd->revents |= FD_CLOSE;
+                fds[i].fd->wsaevents.lNetworkEvents |= FD_CLOSE;
+            
+                SetEvent (fds[i].fd->overlapped[FD_CLOSE_BIT].hEvent);
+                SetEvent (fds[i].fd->overlapped[FD_CONNECT_BIT].hEvent);
+              } else if (wait_ret != NO_ERROR) {
+                any_errors = TRUE;
+                fds[i].fd->revents |= POLLERR;
+                fds[i].fd->wsaevents.iErrorCode[j] = wait_ret;
+                SetErrnoFromWinError (wait_ret);
+              }
+            
+              break;
+            case POLLHUP_BIT:
+              if (!(fds[i].fd->events & (POLLIN | POLLOUT)))
+              { 
+                if (!(fds[i].fd->revents & POLLHUP))
+                {
+                  bret = GetOverlappedResult (fds[i].fd->fd,
+                      &fds[i].fd->overlapped[POLLHUP_BIT], &wait_ret, TRUE);
+                  selected = 1;
+  
+                  wait_ret = GetLastError ();
+                  if (wait_ret != NO_ERROR)
+                  {
+                    fds[i].fd->revents |= POLLHUP_BIT;
+                    fds[i].fd->wsaevents.lNetworkEvents |= FD_CLOSE;
+                  } else {
+                    ResetEvent (fds[i].fd->overlapped[FD_CLOSE_BIT].hEvent);
+                    fds[i].fd->revents &= ~POLLHUP_BIT;
+                    fds[i].fd->wsaevents.lNetworkEvents &= ~FD_CLOSE;
+                  }
+                }
+                else
+                {
+                   selected = 1;
+                   fds[i].fd->revents |= POLLHUP;
+                   fds[i].fd->wsaevents.lNetworkEvents |= FD_CLOSE;
+                }
+              }
+              else
+              {
+                if ((fds[i].fd->events & POLLIN) && (fds[i].fd->access & GENERIC_READ))
+                {
+                  selected = 1;
+                  fds[i].fd->revents |= POLLIN;
+                }
+                if ((fds[i].fd->events & POLLOUT) && (fds[i].fd->access & GENERIC_WRITE))
+                {
+                  selected = 1;
+                  fds[i].fd->revents |= POLLOUT;
+                }
+              }
+              break;
+            default:
+              break;
+            }
+          }
+          if (fds[i].fd->revents & FD_CONNECT)
+          {
+            fds[i].fd->revents &= ~FD_CONNECT;
+            if (fds[i].fd->access & GENERIC_READ)
+            {
+              SetEvent (fds[i].fd->overlapped[POLLIN_BIT].hEvent);
+              fds[i].fd->revents |= POLLIN;
+            }
+            if (fds[i].fd->access & GENERIC_WRITE)
+            {
+              SetEvent (fds[i].fd->overlapped[POLLOUT_BIT].hEvent);
+              fds[i].fd->revents |= POLLOUT;
+            }
+          }
+
+        }
+        if (emulate_select)
+        {
+          /* there's no HUP in select() */
+          if (fds[i].fd->revents & POLLHUP)
+          {
+            int waking = 0;
+            fds[i].fd->revents &= ~POLLHUP;
+            
+            if (fds[i].fd->events & POLLIN & fds[i].fd->revents)
+              waking = 1;
+            if (fds[i].fd->events & POLLOUT & fds[i].fd->revents)
+              waking = 1;
+            if (!waking && fds[i].fd->access & GENERIC_READ && fds[i].fd->events & POLLIN)
+            {
+              waking = 1;
+              fds[i].fd->revents |= POLLIN;
+            }
+            if (!waking && fds[i].fd->access & GENERIC_WRITE && fds[i].fd->events & POLLOUT)
+            {
+              waking = 1;
+              fds[i].fd->revents |= POLLOUT;
+            }
+          }
+          /* FIXME: What about ERR and NVAL? */
+        }
+        if (fds[i].fd->fd_type != GNUNET_W32IO_SOCKET)
+          hits += 1;
+        result += selected;
+        fds[i].revents = fds[i].fd->revents;
+      }
+    }
+    else if (dwResult == WAIT_TIMEOUT)
+    {
+      /* result = 0; */
+    }
+    else if (dwResult == WAIT_FAILED)
+    {
+      SetErrnoFromWinError (dwError);
+      result = -1;
+    }
+    if (any_errors && result >= 0)
+    {
+      result = -1;
+    }
+    if (hits == 0)
+    {
+#if DEBUG_W32IO
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Repeating ppoll()\n");
+#endif
+      time2 = GetTickCount ();
+      if (timeout != -1)
+      {
+        DWORD new_timeout = timeout - time2 > time1 ? time2 - time1 : (0xFFFFFFFF - time1) + time2;
+        if (new_timeout > timeout)
+          timeout = -1;
+        else
+          timeout = new_timeout;
+      }
+      hits = 0;
+      repeat = 1;
+    }
+  }
+
+  GNUNET_free (hEvents);
+  return result;
+}
+
+int
+GNUNET_W32IO_poll (struct pollfd fds[], nfds_t nfds, int timeout)
+{
+  struct W32PollFd *wfds;
+  int i;
+  int result;
+  wfds = GNUNET_malloc (sizeof (struct W32PollFd) * nfds);
+  for (i = 0; i < nfds; i++)
+  {
+    wfds[i].fd = w32io_fetch_fd (fds[i].fd);
+    wfds[i].events = fds[i].events;
+  }
+  result = w32io_poll (wfds, nfds, timeout, 0);
+  GNUNET_free (wfds);
+  return result;
+}
+
+int
+GNUNET_W32IO_select (int nfds, w32fd_set *readfds,
+       w32fd_set *writefds, w32fd_set *errorfds,
+       struct timeval *timeout)
+{
+  struct W32PollFd *wfds;
+  int i, j, ins;
+  int result = 0;
+  int ms_time;
+  short t;
+  wfds = GNUNET_malloc (sizeof (struct W32PollFd) * nfds);
+  for (i = 0; i < nfds; i++)
+    wfds[i].fd = INVALID_POLL_FD;
+  j = 0;
+  for (i = 0; i < nfds; i++)
+  {
+    ins = 0;
+    if (readfds && W32_FD_ISSET(i, readfds))
+    {
+      wfds[j].fd = w32io_fetch_fd (i);
+      if (!wfds[j].fd)
+      {
+        errno = EBADF;
+        result = -1;
+        break;
+      }
+      t = POLLIN;
+      wfds[j].events |= t;
+      ins = 1;
+    }
+    if (writefds && W32_FD_ISSET(i, writefds))
+    {
+      wfds[j].fd = w32io_fetch_fd (i);
+      if (!wfds[j].fd)
+      {
+        errno = EBADF;
+        result = -1;
+        break;
+      }
+      t = POLLOUT;
+      wfds[j].events |= t;
+      ins = 1;
+    }
+    if (errorfds && W32_FD_ISSET(i, errorfds))
+    {
+      wfds[j].fd = w32io_fetch_fd (i);
+      if (!wfds[j].fd)
+      {
+        errno = EBADF;
+        result = -1;
+        break;
+      }
+      wfds[j].events |= POLLERR;
+      ins = 1;
+    }
+    j += ins;
+  }
+#if DEBUG_W32IO
+  if (result != 0)
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Some of the FDs were fetched as NULL\n");
+  else
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "select() fetched everything without errors\n");
+#endif
+  if (result == 0)
+  {
+    if (timeout)
+      ms_time = timeout->tv_sec * 1000 + timeout->tv_usec / 1000;
+    else
+      ms_time = -1;
+    result = w32io_poll (wfds, j, ms_time, 1);
+#if DEBUG_W32IO
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "w32io_poll() returned %d\n", result);
+#endif
+  }
+  if (result >= 0)
+  {
+    result = 0;
+    j = 0;
+    for (i = 0; i < nfds; i++)
+    {
+      ins = 0;
+      if (readfds && W32_FD_ISSET(i, readfds))
+      {
+        ins = 1;
+        if (wfds[j].revents & (POLLIN | POLLHUP | POLLNVAL))
+        {
+          result += 1;
+        }
+        else
+          W32_FD_CLR(i, readfds);
+      }
+      if (writefds && W32_FD_ISSET(i, writefds))
+      {
+        ins = 1;
+        if (wfds[j].revents & (POLLOUT | POLLHUP | POLLNVAL))
+        {
+          result += 1;
+        }
+        else
+          W32_FD_CLR(i, writefds);
+      }
+      if (errorfds && W32_FD_ISSET(i, errorfds))
+      {
+        ins = 1;
+        if (wfds[j].revents & (POLLERR | POLLHUP | POLLNVAL))
+        {
+          result += 1;
+        }
+        else
+          W32_FD_CLR(i, errorfds);
+      }
+      j += ins;
+    }
+  }
+  GNUNET_free (wfds);
+  return result;
+}
+
+/**
+ * Prepares @wpfd for polling
+ */
+int
+w32io_prepare_for_poll (struct W32PollFd *wpfd, HANDLE *polllist)
+{
+  struct W32Fd *wfd = wpfd->fd;
+
+  int ret;
+  DWORD dwret;
+  int result = 0;
+  wpfd->revents = 0;
+  if (wpfd->fd == INVALID_POLL_FD)
+    return 0;
+  wfd->revents = 0;
+  wfd->events = wpfd->events;
+
+  if (wfd->fd_type == GNUNET_W32IO_SOCKET)
+  {
+    //DWORD sockevents = wfd->events & FD_ALL_EVENTS;
+    WSANETWORKEVENTS events;
+    int hits = 0;
+    memset (&events, 0, sizeof (events));
+    int enum_ret = WSAEnumNetworkEvents ((SOCKET) wfd->fd, wfd->overlapped[SOCKET_POLL_EVENT].hEvent, &events);
+    if (enum_ret != 0) {
+      DWORD dwError = GetLastError ();
+      SetErrnoFromWinError (dwError);
+      /* FIXME: make sure this is correct */
+      if (dwError == WSAECONNRESET)
+      {
+        wfd->wsaevents.lNetworkEvents |= FD_CLOSE;
+      }
+      else
+      {
+        /* FIXME: Not sure about this one. Not all errors lead to FD_CLOSE */
+        wfd->wsaevents.lNetworkEvents |= FD_CLOSE;
+        wfd->wsaevents.iErrorCode[FD_CLOSE] = dwError;
+      }
+    }
+    else
+    {
+      /* This way we won't lose one-time events. However, we also must
+       * watch what we do with the socket and drop the bits from
+       * lNetworkEvents when appropriate.
+       */
+      int k;
+      wfd->wsaevents.lNetworkEvents |= events.lNetworkEvents;
+      for (k = 0; k < FD_MAX_EVENTS; k++)
+      {
+        int bit = 1 << k;
+        if (wfd->events & bit & wfd->wsaevents.lNetworkEvents)
+        {
+          wfd->revents |= bit;
+          hits += 1;
+          if (wfd->wsaevents.iErrorCode[k] != 0)
+            wfd->revents |= POLLERR;
+        }
+      }
+      if (wfd->revents & FD_CONNECT)
+      {
+        wfd->revents &= ~FD_CONNECT;
+        wfd->revents |= POLLOUT;
+      }
+      if (wfd->revents & FD_ACCEPT)
+      {
+        wfd->revents &= ~FD_ACCEPT;
+        wfd->revents |= POLLIN;
+      }
+      if (wfd->wsaevents.lNetworkEvents & FD_CLOSE)
+      {
+        wfd->revents |= POLLHUP;
+        wfd->revents &= ~POLLOUT;
+        hits += 1;
+      }
+    }
+    if (hits > 0 || ((wfd->events & POLLOUT) && (wfd->wsaevents.lNetworkEvents & FD_WRITE)) || (wfd->wsaevents.lNetworkEvents & FD_CLOSE))
+      SetEvent (wfd->overlapped[SOCKET_WAKEUP_EVENT].hEvent);
+    polllist[result++] = wfd->overlapped[SOCKET_POLL_EVENT].hEvent;
+    polllist[result++] = wfd->overlapped[SOCKET_WAKEUP_EVENT].hEvent;
+    polllist[result++] = wfd->overlapped[SOCKET_OVERLAPPED_WRITE_EVENT].hEvent;
+    wfd->revents = 0;
+  }
+  else if (wfd->fd_type == GNUNET_W32IO_FILE)
+  {
+    /* Only POLLIN and POLLOUT are relevant for files
+     * Error conditions will be reported later on their own accord, we do not
+     * need event objects to detect these
+     */
+    wfd->events &= POLLIN | POLLOUT;
+
+    if (wfd->events & POLLIN || wfd->events & POLLOUT)
+    {
+      /* Ready to read/write unconditinally */
+      SetEvent (wfd->overlapped[FILE_READY_POLL_EVENT].hEvent);
+      polllist[result++] = wfd->overlapped[FILE_READY_POLL_EVENT].hEvent;
+    }
+    else
+      ResetEvent (wfd->overlapped[FILE_READY_POLL_EVENT].hEvent);
+    polllist[result++] = wfd->overlapped[POLLERR_BIT].hEvent;
+    polllist[result++] = wfd->overlapped[POLLNVAL_BIT].hEvent;
+  }
+  else if (wfd->fd_type == GNUNET_W32IO_ANONYMOUS_PIPE)
+  {
+    /* Anonymous pipes support only POLLIN and POLLOUT.
+     * Also don't poll for reading/writing on write-only/read-only pipes
+     */
+    wfd->events &= (wfd->access & GENERIC_READ ? POLLIN : 0) | (wfd->access & GENERIC_WRITE ? POLLOUT : 0);
+    if (wfd->events & POLLIN || (!(wfd->events & POLLOUT) && (wfd->access & GENERIC_READ)))
+    {
+      /* Get the mutex (shouldn't delay us for too long */
+#if DEBUG_W32IO
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Locking the thread mutex.\n");
+#endif
+      dwret = WaitForSingleObject (wfd->anon_thread_mutex, INFINITE);
+#if DEBUG_W32IO
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Locked the thread mutex.\n");
+#endif
+      /* Check the state of the buffer */
+      if (wfd->bytes_read >= 0 && wfd->alive)
+      {
+        /* No unread data in the buffer.
+         * Make sure we wake up when there is some (worker thread will enable
+         * ANON_PIPE_MAIN_THREAD_POLL_EVENT every time bytes_read <= 0)
+         */
+        ResetEvent (wfd->overlapped[ANON_PIPE_MAIN_THREAD_POLL_EVENT].hEvent);
+      }
+      else
+      {
+        /* Just to be safe **/
+        SetEvent (wfd->overlapped[ANON_PIPE_MAIN_THREAD_POLL_EVENT].hEvent);
+      }
+      ReleaseMutex (wfd->anon_thread_mutex);
+
+      /* We will wait upon wfd->overlapped[ANON_PIPE_MAIN_THREAD_POLL_EVENT].hEvent. When it is enabled,
+       * the worker thread has some unread data.
+       */
+      polllist[result++] = wfd->overlapped[ANON_PIPE_MAIN_THREAD_POLL_EVENT].hEvent;
+    }
+    else if (wfd->events & POLLOUT)
+    {
+      /* We will wait upon wfd->overlapped[ANON_PIPE_MAIN_THREAD_POLL_EVENT].hEvent. When it is enabled,
+       * the worker thread have completed its work and released the mutex,
+       * and we can write once again.
+       */
+      polllist[result++] = wfd->overlapped[ANON_PIPE_MAIN_THREAD_POLL_EVENT].hEvent;
+    }
+    /* Read or write operations will reveal a broken pipe, but if we
+     * have neither, we have to do something to detect that.
+     */
+    if (!(wfd->events & POLLIN) && !(wfd->events & POLLOUT) && WaitForSingleObject (wfd->anon_thread_mutex, 0) == WAIT_OBJECT_0)
+    {
+      int wait_confirm = 0;
+      if (wfd->access & GENERIC_READ)
+      {
+        /* We are reading already */
+      }
+      else if (wfd->access & GENERIC_WRITE)
+      {
+        int skipwriting = FALSE;
+        if (wfd->wrbuffer)
+        {
+          /* We've been writing somethings */
+          GNUNET_free (wfd->wrbuffer->buf);
+          GNUNET_free (wfd->wrbuffer);
+          wfd->wrbuffer = NULL;
+      
+          /* Process any error conditions from previous write operation */
+          if (wfd->bret == 0)
+          {
+            SetEvent (wfd->overlapped[POLLHUP_BIT].hEvent);
+            skipwriting = TRUE;
+          }
+        }
+
+        /* Writing a byte into the pipe. BAD IDEA! Disabled. */
+        if (!skipwriting && 0)
+        {
+          wfd->work = 1; /* write */
+          wfd->wrbuffer = GNUNET_malloc (sizeof (WSABUF));
+          wfd->wrbuffer->len = 1;
+          wfd->wrbuffer->buf = GNUNET_malloc (1);
+          ((char *)wfd->wrbuffer->buf)[0] = 0;
+        
+          ResetEvent (wfd->overlapped[ANON_PIPE_CONFIRM_POLL_EVENT].hEvent);
+          SetEvent (wfd->overlapped[ANON_PIPE_THREAD_POLL_EVENT].hEvent);
+          wait_confirm = 1;
+        }
+      }
+      ReleaseMutex (wfd->anon_thread_mutex);
+      if (wait_confirm)
+      {
+#if DEBUG_W32IO
+        GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Waiting for confirmation.\n");
+#endif
+        WaitForSingleObject (wfd->overlapped[ANON_PIPE_CONFIRM_POLL_EVENT].hEvent, INFINITE);
+#if DEBUG_W32IO
+        GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Done waiting for confirmation.\n");
+#endif
+      }
+      /* We will wait upon wfd->overlapped[POLLHUP_BIT].hEvent,
+       * which will be set by the working thread when the pipe breaks
+       */
+    }
+    polllist[result++] = wfd->overlapped[POLLERR_BIT].hEvent;
+    polllist[result++] = wfd->overlapped[POLLNVAL_BIT].hEvent;
+    polllist[result++] = wfd->overlapped[POLLHUP_BIT].hEvent;
+  }
+  else if (wfd->fd_type == GNUNET_W32IO_NAMED_PIPE)
+  {
+    /* POLLIN and POLLOUT might mean that the caller is interested in
+     * connection events, not reads/writes, so we won't check these
+     * against access
+     */
+    wfd->events &= POLLIN | POLLOUT;
+    if (wfd->events & (POLLIN | POLLOUT))
+    {
+      if (WaitForSingleObject (wfd->overlapped[FD_CONNECT_BIT].hEvent, 0) ==
+          WAIT_OBJECT_0)
+      {
+        /* Try to connect the pipe every time it is possible to do that.
+         * Most of the time it will return immediately with the
+         * ERROR_PIPE_CONNECTED error code to indicate that the pipe is
+         * already connected, else it will set the pipe working on
+         * becoming connected.
+         */
+        ZeroOverlappedExceptEvent(wfd->overlapped[FD_CONNECT_BIT]);
+        dwret = ConnectNamedPipe (wfd->fd, &wfd->overlapped[FD_CONNECT_BIT]);
+        if (dwret == 0)
+        {
+          dwret = GetLastError ();
+          if (dwret == ERROR_PIPE_CONNECTED ||
+              dwret == ERROR_INVALID_FUNCTION)
+          {
+            /* Already connected or we're using client end of the pipe.
+             * Disable the event to prevent further connection attempts.
+             */
+            ResetEvent (wfd->overlapped[FD_CONNECT_BIT].hEvent);
+            /* Reading (see below) might be possible on a broken pipe,
+             * but writing is not, so we only attempt a writing operation
+             * when the pipe is known to be connected.
+             */
+            /* Enable the events, so that the code below can check for
+             * writeability
+             */
+            if (wfd->access & GENERIC_WRITE)
+              SetEvent (wfd->overlapped[POLLOUT_BIT].hEvent);
+          }
+          else if (dwret == ERROR_IO_PENDING)
+          {
+            /* OK */
+          }
+          else
+          {
+            SetEvent (wfd->overlapped[POLLERR_BIT].hEvent);
+            wfd->dwerror = dwret;
+            /* Keep the event set - this will trigger a connection attempt
+             * later on
+             */
+          }
+          if (dwret != ERROR_IO_PENDING)
+          {
+            /* Pending means that we ARE unconnected, and that a connection
+             * attempt is in process. Otherwise, even if we've got an error,
+             * it MIGHT be possible to get something out of the pipe buffer.
+             */
+            /* Enable the events, so that the code below can check for
+             * readablilty.
+             */
+            if (wfd->access & GENERIC_READ)
+              SetEvent (wfd->overlapped[POLLIN_BIT].hEvent);
+          }
+        }
+      }
+      polllist[result++] = wfd->overlapped[FD_CONNECT_BIT].hEvent;
+    }
+    if (wfd->events & POLLIN)
+    {
+      if (WaitForSingleObject (wfd->overlapped[POLLIN_BIT].hEvent, 0) ==
+          WAIT_OBJECT_0)
+      {
+        /* Try to read 0 bytes from the pipe. This will enable the event
+         * when there is data to read.
+         */
+        ZeroOverlappedExceptEvent(wfd->overlapped[POLLIN_BIT]);
+        dwret = ReadFile (wfd->fd, (void *) &wfd->bytes_read, 0,
+            NULL, &wfd->overlapped[POLLIN_BIT]);
+        if (dwret == 0)
+        {
+          dwret = GetLastError ();
+          if (dwret == ERROR_BROKEN_PIPE || dwret == ERROR_PIPE_NOT_CONNECTED)
+          {
+            SetEvent (wfd->overlapped[POLLHUP_BIT].hEvent);
+          }
+          else if (dwret != ERROR_IO_PENDING)
+          {
+            SetEvent (wfd->overlapped[POLLERR_BIT].hEvent);
+            wfd->dwerror = dwret;
+          }
+          /* For some reason ReadFile won't enable the event after a failure */
+          SetEvent (wfd->overlapped[POLLIN_BIT].hEvent);
+        }
+      }
+      polllist[result++] = wfd->overlapped[POLLIN_BIT].hEvent;
+    }
+    /* There is no need to prepare for POLLOUT - underlying writing is
+     * asynchronous and is always available if there is no writing operations
+     * pending.
+     */
+    if (wfd->events & POLLOUT)
+    {
+      polllist[result++] = wfd->overlapped[POLLOUT_BIT].hEvent;
+    }
+    /* read or write operations will reveal a broken pipe, but if we
+     * have neither, we have to do something to detect that.
+     */
+    if (!(wfd->events & POLLIN) && !(wfd->events & POLLOUT))
+    {
+      if (wfd->access & GENERIC_READ)
+      {
+        /* Prefer reading */
+        if (WaitForSingleObject (wfd->overlapped[POLLIN_BIT].hEvent, 0) ==
+            WAIT_OBJECT_0)
+        {
+          /* Try to read 0 bytes from the pipe. This will enable the event
+           * when there is data to read.
+           */
+          ZeroOverlappedExceptEvent(wfd->overlapped[POLLIN_BIT]);
+          dwret = ReadFile (wfd->fd, (void *) &wfd->bytes_read, 0,
+              NULL, &wfd->overlapped[POLLIN_BIT]);
+          if (dwret == 0)
+          {
+            dwret = GetLastError ();
+            if (dwret == ERROR_BROKEN_PIPE || dwret == ERROR_PIPE_NOT_CONNECTED)
+            {
+              SetEvent (wfd->overlapped[POLLHUP_BIT].hEvent);
+            }
+            else if (dwret != ERROR_IO_PENDING)
+            {
+              SetEvent (wfd->overlapped[POLLERR_BIT].hEvent);
+              wfd->dwerror = dwret;
+            }
+          } else {
+            ResetEvent (wfd->overlapped[POLLHUP_BIT].hEvent);
+          }
+        }
+      }
+      else if (wfd->access & GENERIC_WRITE && 0)
+      {
+        if (wfd->wrbuffer != NULL)
+        {
+          if (WaitForSingleObject (wfd->overlapped[POLLOUT_BIT].hEvent, 0) ==
+              WAIT_OBJECT_0 &&
+              WaitForSingleObject (wfd->overlapped[POLLHUP_BIT].hEvent, 0) ==
+              WAIT_TIMEOUT)
+          {
+            /* Get the operation result, free the buffer */
+            DWORD wait_ret;
+            ret = GetOverlappedResult ((HANDLE) wfd->fd,
+                &wfd->overlapped[POLLOUT_BIT], &wait_ret, TRUE);
+            GNUNET_free (wfd->wrbuffer->buf);
+            GNUNET_free (wfd->wrbuffer);
+            wfd->wrbuffer = NULL;
+          }
+        }
+        if (wfd->wrbuffer == NULL)
+        {
+          ZeroOverlappedExceptEvent(wfd->overlapped[POLLOUT_BIT]);
+          BOOL bret = WriteFile ((HANDLE) wfd->fd, (void *) &wfd->alive, 0, NULL,
+              &wfd->overlapped[POLLOUT_BIT]);
+          if (bret == 0) {
+            DWORD dwret = GetLastError ();
+            if (dwret != ERROR_IO_PENDING)
+            {
+              if (dwret == ERROR_BROKEN_PIPE || dwret == ERROR_PIPE_NOT_CONNECTED)
+                SetEvent (wfd->overlapped[POLLHUP_BIT].hEvent);
+              else
+                SetEvent (wfd->overlapped[POLLERR_BIT].hEvent);
+            }
+          } else {
+            ResetEvent (wfd->overlapped[POLLHUP_BIT].hEvent);
+          }
+        }        
+      }
+    }
+    polllist[result++] = wfd->overlapped[POLLERR_BIT].hEvent;
+    polllist[result++] = wfd->overlapped[POLLNVAL_BIT].hEvent;
+    polllist[result++] = wfd->overlapped[POLLHUP_BIT].hEvent;
+  }
+
+  return result;
+}
+
+GNUNET_W32IO_HandleType
+GNUNET_W32IO_find_handle_type (HANDLE h)
+{
+  DWORD dwret, dwerr, dwret2, dwerr2;
+  WSAPROTOCOL_INFO pi;
+  dwret = GetFileType (h);
+  dwerr = GetLastError ();
+  switch (dwret) {
+  case FILE_TYPE_DISK:
+    return GNUNET_W32IO_FILE;
+  case FILE_TYPE_CHAR:
+    return GNUNET_W32IO_CONSOLE;
+  case FILE_TYPE_PIPE:
+    /* It's a socket or a pipe */
+    dwret2 = WSADuplicateSocket ((SOCKET) h, 0, &pi);
+    dwerr2 = GetLastError ();
+    if (dwret2 == 0) {
+      /* WSADuplicateSocket() should always fail when called with these
+       * arguments.
+       */
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "This should not happen\n");
+      return GNUNET_W32IO_UNSPECIFIED;
+    } else {
+      if (dwerr2 == WSAEINVAL) {
+        /* Definitely a socket */
+        return GNUNET_W32IO_SOCKET;
+      } else {
+        /* Not likely a socket. A pipe? */
+        dwret2 = GetNamedPipeInfo (h, NULL, NULL, NULL, NULL);
+        dwerr2 = GetLastError ();
+        if (dwret2 != 0) {
+          /* It's a kind of pipe */
+          dwret2 = GetNamedPipeHandleStateA (h, NULL, NULL, NULL,
+              NULL, NULL, 0);
+          dwerr2 = GetLastError ();
+          if (dwret2 == 0) {
+            if (dwerr2 == ERROR_INVALID_PARAMETER) {
+              /* It's an anonymous pipe */
+              return GNUNET_W32IO_ANONYMOUS_PIPE;
+            } else {
+              /* We have no idea what it is */
+              return GNUNET_W32IO_UNKNOWN;
+            }
+          } else {
+            /* It's a named pipe */
+            return GNUNET_W32IO_NAMED_PIPE;
+          }
+        } else {
+          /* If it was something other than a pipe, we would have found
+           * it by now, and now it's not even a pipe.
+           * It could be that this is a pipe, but damaged (or in a wrong
+           * state), or not a pipe at all.
+           */
+          return GNUNET_W32IO_UNKNOWN;
+        }
+      }
+    }
+    break;
+  case FILE_TYPE_UNKNOWN:
+  default:
+    if (dwerr == NO_ERROR)
+      return GNUNET_W32IO_UNKNOWN;
+    else
+      return GNUNET_W32IO_UNSPECIFIED;
+  }
+  return GNUNET_W32IO_UNSPECIFIED;
+}
+
+/**
+ * Allows us to create W32Fd from a HANDLE we've already got somewhere else.
+ * Will try to find the handle type on its own, or we can point it out.
+ *
+ * @param h handle
+ * @param htype type of the handle @h
+ * @param access access rights to the handle @h
+ * @param connected 1 if @h is connected, 0 otherwise
+ * @param writeable 1 if it is possible to write into @h without blocking, 0 otherwise
+ * @param readable 1 if it is possible to read from @h without blocking, 0 otherwise
+ */
+struct W32Fd *
+w32io_fd_from_handle (HANDLE h, GNUNET_W32IO_HandleType htype, DWORD access,
+    int connected, int writeable, int readable)
+{
+  int i;
+  struct W32Fd *wfd = NULL;
+  DWORD error_code = 0, thread_error, threadID;
+  BOOL bret = FALSE;
+  HANDLE tw[2];
+
+  if (h == INVALID_HANDLE_VALUE)
+  {
+    errno = EINVAL;
+    return NULL;
+  }
+
+  wfd = GNUNET_malloc(sizeof (struct W32Fd));
+
+  wfd->fd = h;
+  wfd->fd_type = htype;
+  if (htype == GNUNET_W32IO_UNSPECIFIED)
+    wfd->fd_type = GNUNET_W32IO_find_handle_type (h);
+
+  for (i = 0; i < POLLLAST; i++)
+    wfd->overlapped[i].hEvent = INVALID_HANDLE_VALUE;
+
+  wfd->anon_thread = INVALID_HANDLE_VALUE;
+  wfd->anon_thread_mutex = INVALID_HANDLE_VALUE;
+  wfd->work = -1;
+
+  switch (wfd->fd_type) {
+  case GNUNET_W32IO_UNSPECIFIED:
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Handle %p is of unspecified type\n", h);
+    goto error;
+    break;
+  case GNUNET_W32IO_UNKNOWN:
+    /* Failed to find the type - should not happen, unless we're
+     * feeding unexpected handles to the function.
+     */
+    /* A special hacky logic will allow us to create W32Fds with
+     * zero handles. They will have one valid event (like sockets do).
+     * This can be used for wakeup purposes, i hope.
+     */
+    /*
+     * I've trashed wakeup-event concept in favor of normal control socket
+     * read/write, so i'm not sure this hack is necessary (besides, i've
+     * never tried to actually use it).
+     */
+    /* wfd->overlapped[0].hEvent = CreateEvent (NULL, TRUE, FALSE, NULL); */
+    goto error;
+    break;
+  case GNUNET_W32IO_FILE:
+    for (i = 0; i < POLLLAST; i++) 
+    {
+      switch (i)
+      {
+      case FILE_READY_POLL_EVENT:
+      case POLLHUP_BIT:
+      case POLLERR_BIT:
+      case POLLNVAL_BIT:
+        SetLastError (0);
+        wfd->overlapped[i].hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
+        error_code = GetLastError ();
+        if (wfd->overlapped[i].hEvent == INVALID_HANDLE_VALUE || error_code != NO_ERROR)
+        {
+          GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "CreateEvent() returned %d. GLE: %d\n", wfd->overlapped[i].hEvent, error_code);
+          goto error;
+        }
+        break;
+      default:
+        break;
+      }
+    }
+    SetLastError (0);
+    bret = SetEvent (wfd->overlapped[FILE_READY_POLL_EVENT].hEvent);
+    error_code = GetLastError ();
+    if (error_code != NO_ERROR || !bret)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "SetEvent() returned %d. GLE: %d\n", bret, error_code);
+      goto error;
+    }
+    wfd->access = access;
+    break;
+  case GNUNET_W32IO_NAMED_PIPE:
+    for (i = 0; i < POLLLAST; i++) 
+    {
+      switch (i)
+      {
+      case POLLIN_BIT:
+      case POLLOUT_BIT:
+      case FD_CONNECT_BIT:
+      case POLLHUP_BIT:
+      case POLLERR_BIT:
+      case POLLNVAL_BIT:
+        SetLastError (0);
+        wfd->overlapped[i].hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
+        error_code = GetLastError ();
+        if (wfd->overlapped[i].hEvent == INVALID_HANDLE_VALUE || error_code != NO_ERROR)
+        {
+          GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "CreateEvent() returned %d. GLE: %d\n", wfd->overlapped[i].hEvent, error_code);
+          goto error;
+        }
+        break;
+      default:
+        break;
+      }
+    }
+    /* Enable the overlapped read/write events where applicable,
+     * indicating that a write/read operation is not in progress.
+     * Enable the connect overlapped event if the pipe is not connected,
+     * indicating that a connection attempt can be made.
+     */
+    if (!connected)
+    {
+      SetLastError (0);
+      bret = SetEvent (wfd->overlapped[FD_CONNECT_BIT].hEvent);
+      error_code = GetLastError ();
+      if (error_code != NO_ERROR || !bret)
+      {
+        GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "SetEvent() returned %d. GLE: %d\n", bret, error_code);
+        goto error;
+      }
+    }
+    else
+    {
+      if (writeable && (access & GENERIC_WRITE))
+      {
+        SetLastError (0);
+        bret = SetEvent (wfd->overlapped[POLLOUT_BIT].hEvent);
+        error_code = GetLastError ();
+        if (error_code != NO_ERROR || !bret)
+        {
+          GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "SetEvent() returned %d. GLE: %d\n", bret, error_code);
+          goto error;
+        }
+      }
+      if (readable && (access & GENERIC_READ))
+      {
+        SetLastError (0);
+        bret = SetEvent (wfd->overlapped[POLLIN_BIT].hEvent);
+        error_code = GetLastError ();
+        if (error_code != NO_ERROR || !bret)
+        {
+          GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "SetEvent() returned %d. GLE: %d\n", bret, error_code);
+          goto error;
+        }
+      }
+    }
+    wfd->access = access;
+    break;
+  case GNUNET_W32IO_ANONYMOUS_PIPE:
+    SetLastError (0);
+    wfd->anon_thread_mutex = CreateMutex (NULL, FALSE, NULL);
+    error_code = GetLastError ();
+    if (wfd->anon_thread_mutex == INVALID_HANDLE_VALUE || error_code != NO_ERROR)
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "CreateMutex() returned %d. GLE: %d\n", wfd->anon_thread_mutex, error_code);
+      goto error;
+    }
+    for (i = 0; i < POLLLAST; i++) 
+    {
+      switch (i)
+      {
+      case ANON_PIPE_THREAD_POLL_EVENT:
+      case ANON_PIPE_MAIN_THREAD_POLL_EVENT:
+      case ANON_PIPE_CONFIRM_POLL_EVENT:
+      case POLLHUP_BIT:
+      case POLLERR_BIT:
+      case POLLNVAL_BIT:
+        SetLastError (0);
+        wfd->overlapped[i].hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
+        error_code = GetLastError ();
+        if (wfd->overlapped[i].hEvent == INVALID_HANDLE_VALUE || error_code != NO_ERROR)
+        {
+          GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "CreateEvent() returned %d. GLE: %d\n", wfd->overlapped[i].hEvent, error_code);
+          goto error;
+        }
+        break;
+      default:
+        break;
+      }
+    }
+    wfd->alive = TRUE;
+    wfd->access = access;
+    /* The thread will be stared immediately, and will go into wait upon
+     * the wfd->overlapped[ANON_PIPE_THREAD_POLL_EVENT].hEvent (which is
+     * disabled at creation) soon after that
+     */
+    /* Reading pipes must start reading immediately */
+    if ((wfd->access & GENERIC_READ) && !(wfd->access & GENERIC_WRITE))
+    {
+      wfd->readbuffer_read_pos = 0;
+      wfd->readbuffer_write_pos = -1;
+      wfd->readbuffer = GNUNET_malloc (1024);
+      wfd->readbuffer_size = 1024;
+      wfd->work = 0;
+    }
+    {
+      ResetEvent (wfd->overlapped[ANON_PIPE_MAIN_THREAD_POLL_EVENT].hEvent);
+#if DEBUG_W32IO_THREADS
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Calling CreateThread()...\n");
+#endif
+      SetLastError (0);
+      wfd->anon_thread = CreateThread (NULL, 0, w32io_anonymous_pipe_thread_func, (LPVOID) wfd, 0, &threadID);
+      error_code = GetLastError ();
+      /* CreateThread might succeed, but the thread might fail AFTER
+       * it is created, trapping us in a later wait call forever.
+       * Instead we'll wait for 5ms (should trigger a context switch),
+       * then check that the thread IS alive with GetExitCodeThread().
+       */
+      thread_error = STILL_ACTIVE;
+      if (wfd->anon_thread != NULL)
+      {
+#if DEBUG_W32IO_THREADS
+        GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Checking thread %08X %d...\n", wfd->anon_thread, threadID);
+#endif
+        WaitForSingleObject (wfd->anon_thread, 5);
+        GetExitCodeThread (wfd->anon_thread, &thread_error);
+#if DEBUG_W32IO_THREADS
+        GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Thread exit code is %d.\n", thread_error);
+#endif
+      }
+      if (wfd->anon_thread == NULL || error_code != NO_ERROR || thread_error != STILL_ACTIVE)
+      {
+        if (thread_error == 0)
+        {
+#if DEBUG_W32IO_THREADS
+          GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Thread completed its work in-place\n");
+#endif
+          SetEvent (wfd->overlapped[ANON_PIPE_MAIN_THREAD_POLL_EVENT].hEvent);
+        }
+        else
+        {
+          GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "CreateThread() returned %d, thread status is %d, GLE: %d\n", wfd->anon_thread, thread_error, error_code);
+          goto error;
+        }
+      }
+      tw[0] = wfd->overlapped[ANON_PIPE_MAIN_THREAD_POLL_EVENT].hEvent;
+      tw[1] = wfd->anon_thread;
+#if DEBUG_W32IO_THREADS
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Waiting on %08X or %08X...\n", tw[0], tw[1]);
+#endif
+      if ((error_code = WaitForMultipleObjects (2, tw, FALSE, 1000)) != WAIT_OBJECT_0)
+      {
+        GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to wait for the worker thread to initialize, wait function returned %d, GLE: %d\n", error_code, GetLastError());
+        goto error;
+      }
+      else
+      {
+#if DEBUG_W32IO_THREADS
+        GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Done waiting.\n");
+#endif
+      }
+    }
+    if ((writeable && (access & GENERIC_WRITE)) || (readable && (access & GENERIC_READ)))
+    {
+      SetLastError (0);
+      bret = SetEvent (wfd->overlapped[ANON_PIPE_MAIN_THREAD_POLL_EVENT].hEvent);
+      error_code = GetLastError ();
+      if (error_code != NO_ERROR || !bret)
+      {
+        GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "SetEvent() returned %d. GLE: %d\n", bret, error_code);
+        goto error;
+      }
+    }
+    else if (thread_error == STILL_ACTIVE)
+    {
+      ResetEvent (wfd->overlapped[ANON_PIPE_MAIN_THREAD_POLL_EVENT].hEvent);
+    }
+    break;
+  case GNUNET_W32IO_CONSOLE:
+    /* It's a console handle or a CRT file descriptor.
+     * FIXME: does it support async I/O? Use threads?
+     */
+    break;
+  case GNUNET_W32IO_SOCKET:
+    for (i = 0; i < POLLLAST; i++) 
+    {
+      switch (i)
+      {
+      case SOCKET_POLL_EVENT:
+      case SOCKET_WAKEUP_EVENT:
+      case SOCKET_OVERLAPPED_WRITE_EVENT:
+      case POLLHUP_BIT:
+      case POLLERR_BIT:
+      case POLLNVAL_BIT:
+        SetLastError (0);
+        wfd->overlapped[i].hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
+        error_code = GetLastError ();
+        if (wfd->overlapped[i].hEvent == INVALID_HANDLE_VALUE || error_code != NO_ERROR)
+        {
+          GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "CreateEvent() returned %d. GLE: %d\n", wfd->overlapped[i].hEvent, error_code);
+          goto error;
+        }
+        break;
+      default:
+        break;
+      }
+      if (i == SOCKET_POLL_EVENT)
+      {
+        /* Bind wfd->overlapped[SOCKET_POLL_EVENT].hEvent object to the socket wfd->fd.
+         * It will be set when one of the events from sockevents occurrs
+         * This call clears internal socket event record in wfd->fd, so
+         * any one-time events (events that are recorded only once per
+         * occurrence) will be lost. To preserve them an internal event field
+         * in W32Fd is used.
+         */
+        SetLastError (0);
+        bret = WSAEventSelect ((SOCKET) wfd->fd, wfd->overlapped[SOCKET_POLL_EVENT].hEvent, FD_ALL_EVENTS);
+        error_code = GetLastError ();
+        if (bret != 0 || error_code != NO_ERROR)
+        {
+          GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "WSAEventSelect() returned %d. GLE: %d\n", bret, error_code);
+          goto error;
+        }
+      }
+    }
+    if (connected)
+    {
+      if (writeable && (access & GENERIC_WRITE))
+      {
+        wfd->wsaevents.lNetworkEvents |= FD_WRITE;
+        SetEvent (wfd->overlapped[SOCKET_WAKEUP_EVENT].hEvent);
+      }
+      if (readable && (access & GENERIC_READ))
+      {
+        wfd->wsaevents.lNetworkEvents |= FD_READ;
+        SetEvent (wfd->overlapped[SOCKET_WAKEUP_EVENT].hEvent);
+      }
+    }
+    wfd->access = access;
+    break;
+  default:
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Wrong value returned from GNUNET_W32IO_find_handle_type()\n");
+    goto error;
+  }
+  goto end;
+error:
+  for (i = 0; i < POLLLAST; i++)
+    if (wfd->overlapped[i].hEvent != INVALID_HANDLE_VALUE)  
+      CloseHandle (wfd->overlapped[i].hEvent);
+  if (wfd->anon_thread != INVALID_HANDLE_VALUE)
+    CloseHandle (wfd->anon_thread);
+  if (wfd->anon_thread_mutex != INVALID_HANDLE_VALUE)
+    CloseHandle (wfd->anon_thread_mutex);
+  GNUNET_free (wfd);
+  wfd = NULL;
+end:
+  return wfd;
+}
+
+int
+GNUNET_W32IO_fd_from_handle (HANDLE h, GNUNET_W32IO_HandleType htype, DWORD access,
+    int connected, int writeable, int readable)
+{
+  struct W32Fd *fd = w32io_fd_from_handle (h, htype, access, connected, writeable, readable);
+  if (fd != NULL && fd != INVALID_POLL_FD)
+    return w32io_insert_fd (fd);
+  return -1;
+}
+
+
+int
+w32io_read_async_named_pipe (struct W32Fd *fd, void *in, size_t to_read)
+{
+  BOOL bret;
+  DWORD dwret;
+  int ret = to_read;
+  while (to_read > 0) {
+#if DEBUG_W32IO
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ReadFile (%x, in, %d, &dwret, &fd->overlapped[POLLIN_BIT]);\n", fd->fd, to_read);
+#endif
+    ZeroOverlappedExceptEvent(fd->overlapped[POLLIN_BIT]);
+    bret = ReadFile (fd->fd, in, to_read, &dwret,
+        &fd->overlapped[POLLIN_BIT]);
+    if (bret == 0)
+    {
+      dwret = GetLastError ();
+      if (dwret == ERROR_BROKEN_PIPE || dwret == ERROR_PIPE_NOT_CONNECTED) {
+        errno = EPIPE;
+        SetEvent (fd->overlapped[POLLHUP_BIT].hEvent);
+        return 0;
+      }
+
+      /* TODO: figure out when it is appropriate to enable [POLLERR_BIT].hEvent */
+      if (dwret != ERROR_IO_PENDING)
+        goto error_and_fail;
+#if DEBUG_W32IO
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "WaitForSingleObject (%x, INFINITE);\n", fd->overlapped[POLLIN_BIT].hEvent);
+#endif
+      dwret = WaitForSingleObject (fd->overlapped[POLLIN_BIT].hEvent,
+          INFINITE);
+#if DEBUG_W32IO
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "done\n");
+#endif
+      if (dwret != WAIT_OBJECT_0)
+      {
+        dwret = GetLastError ();
+        goto error_and_fail;
+      }
+#if DEBUG_W32IO
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "GetOverlappedResult (%x, &fd->overlapped[POLLIN_BIT], &dwret, TRUE);\n", fd->fd);
+#endif
+      bret = GetOverlappedResult ((HANDLE) fd->fd,
+          &fd->overlapped[POLLIN_BIT], &dwret, TRUE);
+#if DEBUG_W32IO
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got it\n");
+#endif
+      if (bret == 0)
+      {
+        dwret = GetLastError ();
+        goto error_and_fail;
+      }
+    }
+#if DEBUG_W32IO
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Read %d bytes\n", dwret);
+#endif
+    to_read -= dwret;
+    in += dwret;
+  }
+#if 0
+  /* If can't peek or pipe is empty - mark the pipe as unreadable.
+   * This will only affect the application if it actually checks fd for
+   * readability. It won't prevent subsequent calls to _read() from blocking.
+   */
+  if (!PeekNamedPipe ((HANDLE) fd->fd, NULL, 0, 0, &dwret, NULL) || !dwret) {
+    fd->revents &= ~FD_READ;
+    fd->wsaevents.lNetworkEvents &= ~FD_READ;
+  }
+#endif
+  return ret;
+
+error_and_fail:
+  GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to read\n");
+  SetErrnoFromWinError (dwret);
+  return -1;
+}
+
+int
+w32io_write_async_named_pipe (struct W32Fd *fd, const void *out, size_t to_write)
+{
+  BOOL bret;
+  DWORD dwret;
+  DWORD ret;
+
+  /* writebuffer isn't NULL -> there's a writing operation going on */
+  if (fd->wrbuffer != NULL) {
+    /* Wait until event is set (meaning that operation is complete).
+     * This might block for a while (until the other end reads), that is - 
+     * you can't have more than one writing operation working at one pipe.
+     * This is somewhat mitigated by the pipe buffer (which is better be > 0).
+     * TODO: implement multiple buffering, so that it is possible to write
+     * more than once (especially if we're talking about writing small
+     * amounts of data multiple times).
+     */
+#if DEBUG_W32IO
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "WaitForSingleObject (%x, INFINITE);\n", fd->overlapped[POLLOUT_BIT].hEvent);
+#endif
+    if (WaitForSingleObject (fd->overlapped[POLLOUT_BIT].hEvent, INFINITE) ==
+        WAIT_OBJECT_0)
+    {
+      /* Get the operation result, free the buffer */
+      DWORD wait_ret;
+#if DEBUG_W32IO
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "GetOverlappedResult (%x, %x, %x, TRUE);\n", fd->fd, &fd->overlapped[POLLOUT_BIT], &wait_ret);
+#endif
+      ret = GetOverlappedResult ((HANDLE) fd->fd,
+          &fd->overlapped[POLLOUT_BIT], &wait_ret, TRUE);
+#if DEBUG_W32IO
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got it\n");
+#endif
+      if (fd->wrbuffer) {
+        GNUNET_free (fd->wrbuffer->buf);
+        GNUNET_free (fd->wrbuffer);
+        fd->wrbuffer = NULL;
+      }
+
+      if (ret == 0) {
+        errno = EIO;
+        return -1;
+      }
+    }
+  }
+
+  if (out)
+  {
+    fd->wrbuffer = GNUNET_malloc (sizeof (WSABUF));
+    fd->wrbuffer->buf = memcpy (GNUNET_malloc (to_write), out, to_write);
+    fd->wrbuffer->len = to_write;
+  }
+#if DEBUG_W32IO
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "WriteFile (%x, %x, %d, NULL, %x);\n", fd->fd, fd->wrbuffer->buf, to_write, &fd->overlapped[POLLOUT_BIT]);
+#endif
+  ZeroOverlappedExceptEvent(fd->overlapped[POLLOUT_BIT]);
+  bret = WriteFile ((HANDLE) fd->fd, fd->wrbuffer->buf, to_write, NULL,
+      &fd->overlapped[POLLOUT_BIT]);
+  if (bret == 0) {
+    dwret = GetLastError ();
+    if (dwret != ERROR_IO_PENDING)
+      goto error_and_fail;
+#if DEBUG_W32IO
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Wrote into heap buffer\n");
+#endif
+  } else {
+#if DEBUG_W32IO
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Wrote into kernel buffer\n");
+#endif
+    GNUNET_free (fd->wrbuffer->buf);
+    GNUNET_free (fd->wrbuffer);
+    fd->wrbuffer = NULL;
+  }
+  return to_write;
+
+error_and_fail:
+  GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to write\n");
+  GNUNET_free (fd->wrbuffer->buf);
+  GNUNET_free (fd->wrbuffer);
+  fd->wrbuffer = NULL;
+  SetErrnoFromWinError (dwret);
+  return -1;
+}
+
+int
+w32io_recv (struct W32Fd *fd, void *buffer, size_t length, int flags)
+{
+  int ret;
+  switch (fd->fd_type)
+  {
+  case GNUNET_W32IO_SOCKET:
+    ret = recv ((SOCKET) fd->fd, buffer, length, flags);
+    if (ret == SOCKET_ERROR)
+    {
+      DWORD error_code = GetLastError ();
+      if (error_code == WSAEWOULDBLOCK)
+        fd->wsaevents.lNetworkEvents &= ~FD_READ;
+      SetErrnoFromWinError (error_code);
+    }
+    else
+    {
+      fd->wsaevents.lNetworkEvents &= ~FD_READ;
+      fd->wsaevents.iErrorCode[FD_READ] = 0;
+    }
+    return ret;
+  default:
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Can't recv() - fd is not a socket\n");
+    return 0;
+  }
+}
+
+int
+GNUNET_W32IO_recv (int fd, void *buffer, size_t length, int flags)
+{
+  return w32io_recv (w32io_fetch_fd (fd), buffer, length, flags);
+}
+
+int
+w32io_recvfrom (struct W32Fd *fd, void *buffer, size_t length, int flags, struct sockaddr *address, int *address_len)
+{
+  int ret;
+  switch (fd->fd_type)
+  {
+  case GNUNET_W32IO_SOCKET:
+    ret = recvfrom ((SOCKET) fd->fd, buffer, length, flags, address, address_len);
+    if (ret == SOCKET_ERROR)
+    {
+      DWORD error_code = GetLastError ();
+      if (error_code == WSAEWOULDBLOCK)
+        fd->wsaevents.lNetworkEvents &= ~FD_READ;
+      SetErrnoFromWinError (error_code);
+    }
+    else
+    {
+      fd->wsaevents.iErrorCode[FD_READ] = 0;
+    }
+    return ret;
+  default:
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Can't recvfrom() - fd is not a socket\n");
+    return 0;
+  }
+}
+
+int
+GNUNET_W32IO_recvfrom (int fd, void *buffer, size_t length, int flags, struct sockaddr *address, int *address_len)
+{
+  return w32io_recvfrom (w32io_fetch_fd (fd), buffer, length, flags, address, address_len);
+}
+
+int
+w32io_send_async (struct W32Fd *fd, const void *buffer, size_t length, int flags)
+{
+  int ret;
+  DWORD error_code;
+  if (fd->wrbuffer)
+  {
+    DWORD t,r;
+    DWORD wait_ret = WaitForSingleObject (fd->overlapped[SOCKET_OVERLAPPED_WRITE_EVENT].hEvent, INFINITE);
+    if (wait_ret == WAIT_OBJECT_0)
+      WSAGetOverlappedResult ((SOCKET) fd->fd, &fd->overlapped[SOCKET_OVERLAPPED_WRITE_EVENT], &t, TRUE, &r);
+    GNUNET_free (fd->wrbuffer->buf);
+    GNUNET_free (fd->wrbuffer);
+    fd->wrbuffer = NULL;
+  }
+  fd->wrbuffer = GNUNET_malloc (sizeof (WSABUF));
+  fd->wrbuffer->buf = GNUNET_malloc (length);
+  fd->wrbuffer->len = length;
+  memcpy (fd->wrbuffer->buf, buffer, length);
+  SetLastError (0);
+  ret = WSASend ((SOCKET) fd->fd, fd->wrbuffer, 1, NULL, 0, &fd->overlapped[SOCKET_OVERLAPPED_WRITE_EVENT], NULL);
+  error_code = GetLastError ();
+  if (ret == -1)
+  {
+    if (error_code == WSA_IO_PENDING)
+      ret = length;
+    else
+    {
+      SetEvent (fd->overlapped[SOCKET_OVERLAPPED_WRITE_EVENT].hEvent);
+      SetErrnoFromWinError (error_code);
+    }
+  }
+  return ret;
+}
+
+int
+w32io_send (struct W32Fd *fd, const void *buffer, size_t length, int flags)
+{
+  int ret;
+  switch (fd->fd_type)
+  {
+  case GNUNET_W32IO_SOCKET:
+    ret = send ((SOCKET) fd->fd, buffer, length, flags);
+    if (ret == SOCKET_ERROR)
+    {
+      DWORD error_code = GetLastError ();
+      if (error_code == WSAEWOULDBLOCK)
+      {
+        fd->wsaevents.lNetworkEvents &= ~FD_WRITE;
+        ret = w32io_send_async (fd, buffer, length, flags);
+      }
+      else
+        SetErrnoFromWinError (error_code);
+    }
+    else
+    {
+      fd->wsaevents.iErrorCode[FD_WRITE] = 0;
+    }
+    return ret;
+  default:
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Can't send() - fd is not a socket\n");
+    return 0;
+  }
+}
+
+int
+GNUNET_W32IO_send (int fd, const void *buffer, size_t length, int flags)
+{
+  return w32io_send (w32io_fetch_fd (fd), buffer, length, flags);
+}
+
+int
+w32io_sendto (struct W32Fd *fd, const void *buffer, size_t length, int flags, const struct sockaddr *address, int address_len)
+{
+  int ret;
+  switch (fd->fd_type)
+  {
+  case GNUNET_W32IO_SOCKET:
+    ret = sendto ((SOCKET) fd->fd, buffer, length, flags, address, address_len);
+    if (ret == SOCKET_ERROR)
+    {
+      DWORD error_code = GetLastError ();
+      if (error_code == WSAEWOULDBLOCK)
+        fd->wsaevents.lNetworkEvents &= ~FD_WRITE;
+      SetErrnoFromWinError (error_code);
+    }
+    else
+    {
+      fd->wsaevents.iErrorCode[FD_WRITE] = 0;
+    }
+    return ret;
+  default:
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Can't sendto() - fd is not a socket\n");
+    return 0;
+  }
+}
+
+int
+GNUNET_W32IO_sendto (int fd, const void *buffer, size_t length, int flags, const  struct sockaddr *address, int address_len)
+{
+  return w32io_sendto (w32io_fetch_fd (fd), buffer, length, flags, address, address_len);
+}
+
+int
+w32io_connect (struct W32Fd *fd, const struct sockaddr *name,
+    int namelen)
+{
+  int ret;
+  DWORD error_code;
+  switch (fd->fd_type)
+  {
+  case GNUNET_W32IO_SOCKET:
+    SetLastError (0);
+    ret = WSAConnect ((SOCKET) fd->fd, name, namelen, NULL, NULL, NULL, NULL);
+    error_code = GetLastError ();
+    if (ret == SOCKET_ERROR && error_code != WSAEWOULDBLOCK)
+    {
+      SetErrnoFromWinError (GetLastError());
+    }
+    else
+    {
+      if (error_code == WSAEWOULDBLOCK)
+        errno = EINPROGRESS;
+      fd->wsaevents.lNetworkEvents &= ~FD_CONNECT;
+      fd->wsaevents.iErrorCode[FD_CONNECT] = 0;
+    }
+    return ret;
+  default:
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Can't connect() - fd is not a socket\n");
+    return 0;
+  }
+}
+
+int
+GNUNET_W32IO_connect (int fd, const struct sockaddr *name,
+    int namelen)
+{
+  return w32io_connect (w32io_fetch_fd (fd), name, namelen);
+}
+
+int
+w32io_accept (struct W32Fd *fd, struct sockaddr *name, int *namelen)
+{
+  SOCKET ret;
+  DWORD error_code;
+  switch (fd->fd_type)
+  {
+  case GNUNET_W32IO_SOCKET:
+    SetLastError (0);
+    ret = WSAAccept ((SOCKET) fd->fd, name, namelen, NULL, 0);
+    error_code = GetLastError ();
+    if (ret == SOCKET_ERROR)
+    {
+      if (error_code == WSAEWOULDBLOCK)
+      {
+        fd->wsaevents.lNetworkEvents &= ~FD_ACCEPT;
+        fd->wsaevents.iErrorCode[FD_ACCEPT] = 0;
+      }
+      SetErrnoFromWinError (GetLastError());
+    }
+    else
+    {
+      fd->wsaevents.lNetworkEvents &= ~FD_ACCEPT;
+      fd->wsaevents.iErrorCode[FD_ACCEPT] = 0;
+    }
+    return ret;
+  default:
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Can't accept() - fd is not a socket\n");
+    return 0;
+  }
+}
+
+int
+GNUNET_W32IO_accept (int fd, struct sockaddr *name, int *namelen)
+{
+  SOCKET s = w32io_accept (w32io_fetch_fd (fd), name, namelen);
+  if (s != INVALID_SOCKET)
+    return GNUNET_W32IO_fd_from_handle ((HANDLE) s, GNUNET_W32IO_SOCKET, GENERIC_READ | GENERIC_WRITE, 1, 1, 0);
+  return s;
+}
+
+int
+w32io_bind (struct W32Fd *fd, const struct sockaddr *name, int namelen)
+{
+  int ret;
+  switch (fd->fd_type)
+  {
+  case GNUNET_W32IO_SOCKET:
+    ret = bind ((SOCKET) fd->fd, name, namelen);
+    if (ret == SOCKET_ERROR)
+    {
+      DWORD error_code = GetLastError ();
+      SetErrnoFromWinError (error_code);
+    }
+    return ret;
+  default:
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Can't bind() - fd is not a socket\n");
+    return 0;
+  }
+}
+
+int
+GNUNET_W32IO_bind (int fd, const struct sockaddr *name, int namelen)
+{
+  return w32io_bind (w32io_fetch_fd (fd), name, namelen);
+}
+
+int
+w32io_listen (struct W32Fd *fd, int backlog)
+{
+  int ret;
+  switch (fd->fd_type)
+  {
+  case GNUNET_W32IO_SOCKET:
+    ret = listen ((SOCKET) fd->fd, backlog);
+    if (ret == SOCKET_ERROR)
+    {
+      SetErrnoFromWinError (GetLastError());
+    }
+    else
+    {
+      fd->wsaevents.lNetworkEvents &= ~(FD_READ | FD_WRITE | FD_ACCEPT | FD_CONNECT);
+      fd->wsaevents.iErrorCode[FD_READ] = 0;
+      fd->wsaevents.iErrorCode[FD_WRITE] = 0;
+      fd->wsaevents.iErrorCode[FD_ACCEPT] = 0;
+      fd->wsaevents.iErrorCode[FD_CONNECT] = 0;
+    }
+    return ret;
+  default:
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Can't listen() - fd is not a socket\n");
+    return 0;
+  }
+}
+
+int
+GNUNET_W32IO_listen (int fd, int backlog)
+{
+  return w32io_listen (w32io_fetch_fd (fd), backlog);
+}
+
+/**
+ * Anonymous pipes on NT do not support asynchronous operations, which is
+ * why we need a separate thread to perform writing and reading operations,
+ * and the state of this thread can be easily checked by waiting upon
+ * an event object.
+ */
+DWORD __stdcall
+w32io_anonymous_pipe_thread_func (void *data)
+{
+  struct W32Fd *wfd = (struct W32Fd *) data;
+  HANDLE h[2];
+  void *tmp_buffer = NULL;
+  DWORD tmp_written, dw_error;
+  int towrite = 0;
+
+  int rpos;
+  int wpos;
+  int rb;
+  size_t tmp_size;
+
+  HANDLE tmp_fd = wfd->fd;
+  HANDLE die_event;
+  HANDLE mutex;
+  BOOL bret;
+  /* Duplication will increase the reference count on the event, so even if
+   * the main thread closes it, it will live on.
+   * The Main thread will enable it before freeing the data related to
+   * this thread. If it is enabled, assume wfd to point to a freed location,
+   * and all handles and events (except die_event and mutex) to be closed.
+   */
+  DuplicateHandle(GetCurrentProcess(), wfd->overlapped[ANON_PIPE_CLOSE_POLL_EVENT].hEvent,
+      GetCurrentProcess(), &die_event, 0, FALSE, DUPLICATE_SAME_ACCESS);
+  DuplicateHandle(GetCurrentProcess(), wfd->anon_thread_mutex,
+      GetCurrentProcess(), &mutex, 0, FALSE, DUPLICATE_SAME_ACCESS);
+  h[0] = wfd->overlapped[ANON_PIPE_THREAD_POLL_EVENT].hEvent;
+  h[1] = mutex;
+/*#if DEBUG_W32IO_THREADS
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "locking\n");
+#endif*/
+  WaitForSingleObject (mutex, INFINITE);
+
+  if (wfd->work == 0)
+  {
+    tmp_buffer = GNUNET_malloc (wfd->readbuffer_size);
+    rpos = 0;
+    wpos = -1;
+    tmp_size = wfd->readbuffer_size;
+    rb = 0;
+  }
+/*#if DEBUG_W32IO_THREADS
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "locked\n");
+#endif*/
+  while (die_event != 0 && (WaitForSingleObject (die_event, 0) == WAIT_TIMEOUT) && wfd->alive)
+  {
+    while (die_event != 0 && (WaitForSingleObject (die_event, 0) == WAIT_TIMEOUT) && wfd->work < 0)
+    {
+/*#if DEBUG_W32IO_THREADS
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "waiting\n");
+#endif*/
+      ResetEvent (h[0]);
+      ReleaseMutex (h[1]);
+      SetEvent (wfd->overlapped[ANON_PIPE_MAIN_THREAD_POLL_EVENT].hEvent);
+      WaitForMultipleObjects(2, h, TRUE, INFINITE);
+/*#if DEBUG_W32IO_THREADS
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "done waiting\n");
+#endif*/
+    }
+    if (die_event != 0 && (WaitForSingleObject (die_event, 0) != WAIT_TIMEOUT))
+    {
+      CloseHandle (die_event);
+      die_event = 0;
+      break;
+    }
+    switch (wfd->work) 
+    {
+    case 0: /* read */
+      SetEvent (wfd->overlapped[ANON_PIPE_MAIN_THREAD_POLL_EVENT].hEvent);
+      while (die_event != 0 && wfd->alive)
+      {
+        DWORD dwret, wait_ret;
+        /* At this point we've locked the mutex. */
+        while ((wpos == rpos - 1 && wpos >= 0) || (wpos == tmp_size - 1 && rpos == 0))
+        {
+          /* Buffer is full (we're about to re-write a byte that isn't yet
+           * consumed by the main thread) */
+          if (rb > 0)
+          {
+            /* And the main thread asked for more data than we could hold - grow the buffer */
+            void *new_buffer = NULL;
+            size_t new_buffer_size = tmp_size + rb;
+            new_buffer = GNUNET_malloc (new_buffer_size);
+            memcpy (new_buffer, &((char *) tmp_buffer)[rpos], tmp_size - rpos);
+            memcpy (&((char *) new_buffer)[tmp_size - rpos], tmp_buffer, rpos);
+            rpos = 0;
+            if (wpos >= 0)
+              wpos = tmp_size - 1;
+            GNUNET_free (tmp_buffer);
+            tmp_buffer = new_buffer;
+            tmp_size = new_buffer_size;
+            GNUNET_free (wfd->readbuffer);
+            wfd->readbuffer = tmp_buffer;
+            wfd->readbuffer_size = tmp_size;
+            wfd->readbuffer_read_pos = rpos;
+            wfd->readbuffer_write_pos = wpos;
+            wfd->bytes_read = rb;
+          }
+          else
+          {
+            /* And the main thread didn't ask for more data - wait until some
+             * data is consumed or until the main thread asks for more.
+             */
+            SetEvent (wfd->overlapped[ANON_PIPE_MAIN_THREAD_POLL_EVENT].hEvent);
+            ResetEvent (h[0]);
+            ReleaseMutex (h[1]);
+/*#if DEBUG_W32IO_THREADS
+            GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "waiting for consumer\n");
+#endif*/
+            WaitForMultipleObjects(2, h, TRUE, INFINITE);
+/*#if DEBUG_W32IO_THREADS
+            GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "done waiting for consumer\n");
+#endif*/
+          }
+        }
+        if (WaitForSingleObject (die_event, 0) == WAIT_TIMEOUT)
+        {
+          SetEvent (wfd->overlapped[ANON_PIPE_CONFIRM_POLL_EVENT].hEvent);
+          /* Stash the write pos, we can't read it from wfd while the
+           * mutex is not locked by us.
+           */
+          wpos = wfd->readbuffer_write_pos;
+          /* Let the main thread consume some data while we are reading. */
+          ReleaseMutex (h[1]);
+/*#if DEBUG_W32IO_THREADS
+          GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "anonymous read %x %d\n", wfd->fd, 1);
+#endif*/
+          /* Read one byte */
+          bret = ReadFile (tmp_fd, &((char *) tmp_buffer)[wpos + 1], 1, &dwret, NULL);
+#if DEBUG_W32IO_THREADS
+          GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "done, read %d bytes to `%02x'\n", dwret, ((char *) tmp_buffer)[wpos + 1]);
+#endif
+        }
+        else
+        {
+          bret = 1;
+        }
+        if (bret == 0)
+        {
+          dw_error = GetLastError ();
+        }
+        if (die_event != 0 && WaitForSingleObject (die_event, 0) == WAIT_TIMEOUT)
+        {
+        /* Lock the mutex */
+/*#if DEBUG_W32IO_THREADS
+          GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "locking after reading\n");
+#endif*/
+          wait_ret = WaitForSingleObject (h[1], INFINITE);
+/*#if DEBUG_W32IO_THREADS
+          GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "locked after reading\n");
+#endif*/
+          if (dw_error == ERROR_BROKEN_PIPE)
+          {
+            wfd->alive = 0;
+          }
+          wfd->bret = bret;
+          wfd->dwerror = dw_error;
+          ((char *) wfd->readbuffer)[wpos + 1] = ((char *) tmp_buffer)[wpos + 1];
+          /* Advance write position */
+          wfd->readbuffer_write_pos += dwret;
+          /* Reduce the number of bytes that the main thread wants us to read */
+          wfd->bytes_read -= dwret;
+          if (wfd->bytes_read <= 0)
+          {
+            SetEvent (wfd->overlapped[ANON_PIPE_MAIN_THREAD_POLL_EVENT].hEvent);
+          }
+          rpos = wfd->readbuffer_read_pos;
+          wpos = wfd->readbuffer_write_pos;
+          rb = wfd->bytes_read;
+        }
+        else if (die_event != 0)
+        {
+          CloseHandle (die_event);
+          die_event = 0;
+        }
+        /* If the main thread was waiting for us to read enough bytes, this will
+         * wake it up. wfd->bytes_read CAN go negative,
+         * as deep as -wfd->readbuffer_size (which means that the whole buffer
+         * is filled with read-ahead data).
+         * The main thread appends to wfd->bytes_read the number of bytes it
+         * wishes to read, and sleeps if wfd->bytes_read becomes positive.
+         */
+      }
+      break;
+    case 1: /* write */
+/*#if DEBUG_W32IO_THREADS
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "anonymous write %x %d\n", wfd->fd, wfd->wrbuffer->len);
+#endif*/
+      tmp_buffer = memcpy (GNUNET_malloc (wfd->wrbuffer->len), wfd->wrbuffer->buf, wfd->wrbuffer->len);
+      towrite = wfd->wrbuffer->len;
+      SetEvent (wfd->overlapped[ANON_PIPE_CONFIRM_POLL_EVENT].hEvent);
+      bret = WriteFile (tmp_fd, tmp_buffer, towrite, &tmp_written, NULL);
+/*#if DEBUG_W32IO_THREADS
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "done, write %d\n", wfd->bytes_written);
+#endif*/
+      if (bret == 0)
+      {
+        dw_error = GetLastError ();
+      }
+      GNUNET_free (tmp_buffer);
+      if (WaitForSingleObject (die_event, 0) == WAIT_TIMEOUT)
+      {
+        wfd->bytes_written = tmp_written;
+        wfd->bret = bret;
+        wfd->dwerror = dw_error;
+      }
+      else
+      {
+        CloseHandle (die_event);
+        die_event = 0;
+      }
+      break;
+    case 2: /* close */
+      wfd->alive = FALSE;
+      SetEvent (wfd->overlapped[POLLHUP_BIT].hEvent);
+      break;
+    default:
+      continue;
+    }
+    if (die_event != 0)
+      wfd->work = -1;
+  }
+/*#if DEBUG_W32IO_THREADS
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "thread is about to exit\n");
+#endif*/
+  if (die_event != 0)
+  {
+    ResetEvent (h[0]);
+    SetEvent (wfd->overlapped[ANON_PIPE_MAIN_THREAD_POLL_EVENT].hEvent);
+    SetEvent (die_event);
+    CloseHandle (die_event);
+  }
+  else
+    CloseHandle (tmp_fd);
+  CloseHandle (mutex);
+  return 0;
+}
+
+int
+w32io_anonymous_pipe_read (struct W32Fd *fd, void *in, size_t to_read)
+{
+  BOOL bret;
+  DWORD dwret;
+  int ret = to_read;
+  HANDLE h[2];
+  h[0] = fd->overlapped[ANON_PIPE_MAIN_THREAD_POLL_EVENT].hEvent;
+  h[1] = fd->anon_thread_mutex;
+#if DEBUG_W32IO
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "locking\n");
+#endif
+  /* First, lock the mutex. It is available while the worker thread
+   * either waits (its buffer is full) or reads (can't access anything
+   * other than the free bytes in the buffer - no race conditions on that)
+   */
+  WaitForSingleObject (fd->anon_thread_mutex, INFINITE);
+/*
+  fd->work = 0;
+  fd->readbuffer = in;
+  fd->to_read = to_read;
+*/
+
+  /* "Read" to_read bytes from the buffer */
+  fd->bytes_read += to_read;
+  if (fd->bytes_read > 0 && fd->alive)
+  {
+    /* bytes_read is > 0 - we did not have enough bytes in the buffer */
+    /* Release the mutex, wait for the mutex and the signal that the
+     * buffer is filled.
+     */
+    ResetEvent (h[0]);
+    ReleaseMutex (h[1]);
+#if DEBUG_W32IO
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "waiting\n");
+#endif
+    WaitForMultipleObjects (2, h, TRUE, INFINITE);
+#if DEBUG_W32IO
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "done waiting\n");
+#endif
+  }
+  if (fd->bytes_read > 0)
+  {
+    /* bytes_read is > 0 - we were fd-bytes_read short when we hit EOF */
+    /* If fd->alive was false, we will have here bytes_read == to_read,
+     * making it ret = 0, otherwise its a positive integer < to_read
+     */
+    ret = to_read - fd->bytes_read;
+    /* for the next read()-after-EOF */
+    fd->bytes_read = 0;
+  }
+  else
+    /* bytes_read is <= 0 - we had enough bytes in the buffer */
+    ret = to_read;
+  if (ret > 0)
+  {
+    dwret = fd->readbuffer_read_pos + ret;
+    if (dwret <= fd->readbuffer_size)
+    {
+      memcpy (in, &((char *) fd->readbuffer)[fd->readbuffer_read_pos], dwret);
+    }
+    else
+    {
+      memcpy ((char *) in, &((char *) fd->readbuffer)[fd->readbuffer_read_pos], fd->readbuffer_size - fd->readbuffer_read_pos);
+      memcpy (&((char *) in)[fd->readbuffer_size - fd->readbuffer_read_pos], fd->readbuffer, ret - (fd->readbuffer_size - fd->readbuffer_read_pos));
+    }
+    fd->readbuffer_read_pos += ret;
+    if (fd->readbuffer_read_pos >= fd->readbuffer_size)
+      fd->readbuffer_read_pos -= fd->readbuffer_size;
+  }
+  bret = fd->bret;
+  dwret = fd->dwerror;
+  /* Let the worker thread continue */
+#if DEBUG_W32IO
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "unlocking\n");
+#endif
+  ReleaseMutex (h[1]);
+
+  if (ret == 0)
+  {
+    if (dwret == ERROR_BROKEN_PIPE) {
+      errno = EPIPE;
+      return 0;
+    }
+    goto error_and_fail;
+  }
+#if 0
+  /* Mark the pipe as unreadable, because we won't know if it has any data to
+   * read until we wait on it. Of course, that will not prevent the application
+   * from trying to read it, but reading might block.
+   */
+  fd->wsaevents.lNetworkEvents &= ~FD_READ;
+  fd->revents &= ~FD_READ;
+#endif
+  /* SetEvent (fd->overlapped[FD_READ_BIT].hEvent); */
+  return ret;
+
+error_and_fail:
+  SetErrnoFromWinError (dwret);
+  return -1;
+}
+
+int
+w32io_anonymous_pipe_write (struct W32Fd *fd, const void *out, size_t to_write)
+{
+  BOOL bret;
+  DWORD dwret;
+  int ret = to_write;
+  HANDLE h[2];
+  h[0] = fd->overlapped[ANON_PIPE_MAIN_THREAD_POLL_EVENT].hEvent;
+  h[1] = fd->anon_thread_mutex;
+#if DEBUG_W32IO
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "locking\n");
+#endif
+  WaitForSingleObject (fd->anon_thread_mutex, INFINITE);
+  /* We've locked the mutex - which means that worker thread is not
+   * working at the moment. If the thread was writing at the moment of
+   * locking, g_mutex_lock() will block until writing is complete, then
+   * the worker thread will unlock for a short time, letting us get
+   * the lock.
+   */
+  if (fd->wrbuffer)
+  {
+#if DEBUG_W32IO
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "freeing the buffer\n");
+#endif
+    /* We've been writing somethings */
+    GNUNET_free (fd->wrbuffer->buf);
+    GNUNET_free (fd->wrbuffer);
+    fd->wrbuffer = NULL;
+
+    /* Process any error conditions from previous write operation */
+    bret = fd->bret;
+    dwret = fd->bytes_written;
+    if (bret == 0)
+    {
+      dwret = fd->dwerror;
+      if (dwret == ERROR_BROKEN_PIPE) {
+        errno = EPIPE;
+        return -1;
+      }
+      goto error_and_fail;
+    }
+  }
+
+  fd->work = 1; /* write */
+  fd->wrbuffer = GNUNET_malloc (sizeof (WSABUF));
+  fd->wrbuffer->buf = memcpy (GNUNET_malloc (to_write), out, to_write);
+  fd->wrbuffer->len = to_write;
+#if DEBUG_W32IO
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "signalling\n");
+#endif
+  SetEvent (fd->overlapped[ANON_PIPE_THREAD_POLL_EVENT].hEvent);
+  /* We've signaled the worker thread condition. Once we unlock the mutex,
+   * the worker thread will wake up.
+   */
+#if DEBUG_W32IO
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "unlocking\n");
+#endif
+  /* Unlock the mutex and let the worker thread do its thing. Return
+   * to_write, while actual writing takes place in background.
+   * If another write is attempted while thread is busy, it will block.
+   * And any other operation will block too, of course.
+   */
+  ReleaseMutex (fd->anon_thread_mutex);
+  /* Wait until the worker thead acknowledges the write request.
+   * Otherwise it would have been possible to overwrite one write
+   * request with another, because the worker thread didn't have an opportunity
+   * to wake up and block/lock on the first request
+   */
+  WaitForSingleObject (fd->overlapped[ANON_PIPE_CONFIRM_POLL_EVENT].hEvent, INFINITE);
+
+  /* We will get errorneous condition eventually, if we do another
+   * (blocking) write or wait, but not immediately.
+   * That happens because of the assumption we make about I/O things:
+   * It is always writable no matter what, but it is only readable when
+   * there is data to read. Real I/O things may not be like that -
+   * they may return an error while writing takes place.
+   * So you should assume that this function will return an error only
+   * when errorneous condition is obvious (wrong fd or a pipe broken
+   * during previous operation).
+   */
+  
+#if 0
+  /* Mark the pipe as unwritable. Of course, that will not prevent the
+   * application from trying to write into it, but writing might block.
+   */
+  
+  fd->wsaevents.lNetworkEvents &= ~FD_WRITE;
+  fd->revents &= ~FD_WRITE;
+#endif
+  /* SetEvent (fd->overlapped[FD_WRITE_BIT].hEvent); */
+  return ret;
+
+error_and_fail:
+  SetErrnoFromWinError (dwret);
+  return -1;
+}
+
+int
+w32io_anonymous_pipe_close (struct W32Fd *fd, int closehandle)
+{
+  int ret = 0, i;
+  int closewait = 100;
+  int closed = 0;
+  HANDLE h[2];
+  h[0] = fd->overlapped[ANON_PIPE_MAIN_THREAD_POLL_EVENT].hEvent;
+  h[1] = fd->anon_thread_mutex;
+  if (fd->access & GENERIC_WRITE || fd->access == 0)
+  {
+#if DEBUG_W32IO_THREADS
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Checking writing thread status\n");
+#endif
+    if (WaitForSingleObject (fd->anon_thread_mutex, closewait) == WAIT_OBJECT_0)
+    {
+#if DEBUG_W32IO_THREADS
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Not working\n");
+#endif
+      /* We've locked the mutex - which means that worker thread is not
+       * working at the moment.
+       */
+      /* Do not check for errors - we can't report them here (any errors
+       * reported should be related to close(), not to some previous
+       * operation).
+       */
+      //SetEvent (fd->overlapped[ANON_PIPE_CLOSE_POLL_EVENT].hEvent);
+
+      if (fd->wrbuffer)
+      {
+        GNUNET_free (fd->wrbuffer->buf);
+        GNUNET_free (fd->wrbuffer);
+        fd->wrbuffer = NULL;
+      }
+
+      fd->work = 2; /* close  */
+  
+      SetEvent (fd->overlapped[ANON_PIPE_THREAD_POLL_EVENT].hEvent);
+      /* We've signaled the worker thread condition. Once we unlock the mutex,
+       * the worker thread will wake up.
+       */
+      ReleaseMutex (fd->anon_thread_mutex);
+      /* We've unlocked the mutex. The worker thread now wakes up and sees that
+       * work is 2, signals maincond, then sets ->alive to FALSE and terminates.
+       */
+#if DEBUG_W32IO_THREADS
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Waiting for the worker to die\n");
+#endif
+      WaitForSingleObject (fd->anon_thread, INFINITE);
+#if DEBUG_W32IO_THREADS
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Worker is dead\n");
+#endif
+      if (closehandle)
+        ret = ret || !CloseHandle (fd->fd);
+    }
+    else
+    {
+#if DEBUG_W32IO_THREADS
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Terminating\n");
+#endif
+      SetEvent (fd->overlapped[ANON_PIPE_CLOSE_POLL_EVENT].hEvent);
+      fd->alive = 0;
+    }
+    closed = 1;
+  }
+  if (fd->access & GENERIC_READ)
+  {
+#if DEBUG_W32IO_THREADS
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Terminating (reader)\n");
+#endif
+    SetEvent (fd->overlapped[ANON_PIPE_CLOSE_POLL_EVENT].hEvent);
+    if (fd->readbuffer)
+      GNUNET_free (fd->readbuffer);
+#if DEBUG_W32IO_THREADS
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Terminated (reader)\n");
+#endif
+  }
+  CloseHandle (fd->anon_thread);
+  CloseHandle (fd->anon_thread_mutex);
+  
+  fd->anon_thread = INVALID_HANDLE_VALUE;
+
+  for (i = 0; i < POLLLAST; i++)
+  {
+    if (fd->overlapped[i].hEvent != INVALID_HANDLE_VALUE)
+    {
+      CloseHandle (fd->overlapped[i].hEvent);
+      fd->overlapped[i].hEvent = INVALID_HANDLE_VALUE;
+    }
+  }
+  return ret;
+}
+
+off_t
+GNUNET_W32IO_lseek_handle (HANDLE fd, uint64_t new_offset, int origin)
+{
+  BOOL bret;
+  DWORD dwError;
+  LARGE_INTEGER offset;
+  LARGE_INTEGER ret;
+  LARGE_INTEGER current;
+  off_t result;
+
+  if (origin != SEEK_SET && origin != SEEK_CUR && origin != SEEK_END)
+  {
+    errno = EINVAL;
+    return -1;
+  }
+
+  offset.QuadPart = 0;
+  SetLastError (0);
+  bret = SetFilePointerEx (fd, offset, &current, FILE_CURRENT);
+
+  dwError = GetLastError ();
+
+  if (bret == 0 && dwError != NO_ERROR)
+  {
+    SetErrnoFromWinError (dwError);
+    return -1;
+  }
+
+  offset.QuadPart = new_offset;
+  SetLastError (0);
+  bret = SetFilePointerEx (fd, offset, &ret,
+      (origin == SEEK_SET ? FILE_BEGIN :
+      (origin == SEEK_CUR ? FILE_CURRENT :
+      (origin == SEEK_END ? FILE_END : origin))));
+
+  dwError = GetLastError ();
+
+  if (bret == 0 && dwError != NO_ERROR)
+  {
+    SetFilePointerEx (fd, current, NULL, FILE_BEGIN);
+    SetErrnoFromWinError (dwError);
+    return -1;
+  }
+
+  /* FIXME: make sure this check works correctly with 32-bit values */
+  result = ret.QuadPart;
+  offset.QuadPart = result;
+  if (offset.QuadPart != ret.QuadPart)
+  {
+    SetFilePointerEx (fd, current, NULL, FILE_BEGIN);
+    errno = EOVERFLOW;
+    return -1;
+  }
+
+  return ret.QuadPart;
+}
+
+off_t
+w32io_lseek (struct W32Fd *fd, uint64_t new_offset, int origin)
+{
+  off_t result;
+  if (fd->fd_type != GNUNET_W32IO_FILE)
+  {
+    errno = ESPIPE;
+    return -1;
+  }
+
+  result = GNUNET_W32IO_lseek_handle (fd->fd, new_offset, origin);
+  fd->pos = result;
+  return result;
+}
+
+off_t
+GNUNET_W32IO_lseek (int fd, uint64_t new_offset, int origin)
+{
+  return w32io_lseek (w32io_fetch_fd (fd), new_offset, origin);
+}
+
+int
+w32io_read_file (struct W32Fd *fd, void *in, size_t to_read)
+{
+  BOOL bret;
+  DWORD dwret, error_code;
+  int ret = 0;
+  
+  do
+  {
+#if DEBUG_W32IO
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "WaitForSingleObject (%x, INFINITE);\n", fd->overlapped[FILE_READY_POLL_EVENT].hEvent);
+#endif
+    dwret = WaitForSingleObject (fd->overlapped[FILE_READY_POLL_EVENT].hEvent,
+        INFINITE);
+#if DEBUG_W32IO
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "done\n");
+#endif
+    if (dwret != WAIT_OBJECT_0)
+    {
+      error_code = GetLastError ();
+      goto error_and_fail;
+    }
+#if DEBUG_W32IO
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "GetOverlappedResult (%x, &fd->overlapped[FILE_READY_POLL_EVENT], &dwret, TRUE);\n", fd->fd);
+#endif
+    SetLastError (0);
+    bret = GetOverlappedResult ((HANDLE) fd->fd,
+        &fd->overlapped[FILE_READY_POLL_EVENT], &dwret, TRUE);
+    error_code = GetLastError ();
+#if DEBUG_W32IO
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got it\n");
+#endif
+    if (bret == 0 || error_code != NO_ERROR)
+    {
+      if (error_code == ERROR_HANDLE_EOF) {
+         return ret;
+      }
+      goto error_and_fail;
+    }
+
+#if DEBUG_W32IO
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ReadFile (%x, in, %d, &dwret, &fd->overlapped[FILE_READY_POLL_EVENT]);\n", fd->fd, to_read);
+#endif
+    ZeroOverlappedExceptEvent(fd->overlapped[FILE_READY_POLL_EVENT]);
+    fd->overlapped[FILE_READY_POLL_EVENT].Offset = fd->pos & ((DWORD) -1);
+    fd->overlapped[FILE_READY_POLL_EVENT].OffsetHigh = fd->pos >> (sizeof (DWORD) * 8);
+    dwret = 0;
+    SetLastError (0);
+    bret = ReadFile (fd->fd, in, to_read, &dwret,
+        &fd->overlapped[FILE_READY_POLL_EVENT]);
+    error_code = GetLastError ();
+    if (bret == 0 || error_code != NO_ERROR)
+    {
+      if (error_code == ERROR_HANDLE_EOF) {
+        /* For some reason this will not enable the event, do it manually */
+        SetEvent (fd->overlapped[FILE_READY_POLL_EVENT].hEvent);
+        return ret;
+      }
+
+      if (error_code != ERROR_IO_PENDING)
+        goto error_and_fail;
+    }
+#if DEBUG_W32IO
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Read %d bytes\n", dwret);
+#endif
+    to_read -= dwret;
+    in += dwret;
+    fd->pos += dwret;
+    ret += dwret;
+  } while (to_read > 0);
+  return ret;
+
+error_and_fail:
+  GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to read\n");
+  SetErrnoFromWinError (error_code);
+  return -1;
+}
+
+int
+w32io_write_file (struct W32Fd *fd, const void *out, size_t to_write)
+{
+  BOOL bret;
+  DWORD error_code;
+  DWORD ret;
+
+  /* writebuffer isn't NULL -> there's a writing operation going on */
+  if (fd->wrbuffer != NULL || WaitForSingleObject (fd->overlapped[FILE_READY_POLL_EVENT].hEvent, 0) == WAIT_TIMEOUT) {
+    /* Wait until event is set (meaning that operation is complete).
+     * This might block for a while (until the other end reads), that is - 
+     * you can't have more than one writing operation working at one pipe.
+     * TODO: implement multiple buffering, so that it is possible to write
+     * more than once (especially if we're talking about writing small
+     * amounts of data multiple times).
+     */
+#if DEBUG_W32IO
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "WaitForSingleObject (%x, INFINITE);\n", fd->overlapped[FILE_READY_POLL_EVENT].hEvent);
+#endif
+    if (WaitForSingleObject (fd->overlapped[FILE_READY_POLL_EVENT].hEvent, INFINITE) ==
+        WAIT_OBJECT_0)
+    {
+      /* Get the operation result, free the buffer */
+      DWORD wait_ret;
+#if DEBUG_W32IO
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "GetOverlappedResult (%x, %x, %x, TRUE);\n", fd->fd, &fd->overlapped[FILE_READY_POLL_EVENT], &wait_ret);
+#endif
+      ret = GetOverlappedResult ((HANDLE) fd->fd,
+          &fd->overlapped[FILE_READY_POLL_EVENT], &wait_ret, TRUE);
+#if DEBUG_W32IO
+      GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got it\n");
+#endif
+      if (fd->wrbuffer) {
+        GNUNET_free (fd->wrbuffer->buf);
+        GNUNET_free (fd->wrbuffer);
+        fd->wrbuffer = NULL;
+      }
+
+      if (ret == 0) {
+        errno = EIO;
+        return -1;
+      }
+    }
+  }
+
+  if (out)
+  {
+    fd->wrbuffer = GNUNET_malloc (sizeof (WSABUF));
+    fd->wrbuffer->buf = memcpy (GNUNET_malloc (to_write), out, to_write);
+    fd->wrbuffer->len = to_write;
+  }
+#if DEBUG_W32IO
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "WriteFile (%x, %x, %d, NULL, %x);\n", fd->fd, fd->wrbuffer->buf, to_write, &fd->overlapped[FILE_READY_POLL_EVENT]);
+#endif
+  ZeroOverlappedExceptEvent(fd->overlapped[FILE_READY_POLL_EVENT]);
+  fd->overlapped[FILE_READY_POLL_EVENT].Offset = fd->pos & ((DWORD) -1);
+  fd->overlapped[FILE_READY_POLL_EVENT].OffsetHigh = fd->pos >> (sizeof (DWORD) * 8);
+  SetLastError (0);
+  bret = WriteFile ((HANDLE) fd->fd, fd->wrbuffer->buf, to_write, NULL,
+      &fd->overlapped[FILE_READY_POLL_EVENT]);
+  error_code = GetLastError ();
+  if (bret == 0 || error_code != NO_ERROR) {
+    /* FIXME: handle ERROR_INVALID_USER_BUFFER or ERROR_NOT_ENOUGH_MEMORY as EAGAIN */
+    if (error_code != ERROR_IO_PENDING)
+      goto error_and_fail;
+#if DEBUG_W32IO
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Wrote into heap buffer\n");
+#endif
+  } else {
+#if DEBUG_W32IO
+    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Wrote into kernel buffer\n");
+#endif
+    GNUNET_free (fd->wrbuffer->buf);
+    GNUNET_free (fd->wrbuffer);
+    fd->wrbuffer = NULL;
+  }
+  fd->pos += to_write;
+  return to_write;
+
+error_and_fail:
+  GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to write\n");
+  GNUNET_free (fd->wrbuffer->buf);
+  GNUNET_free (fd->wrbuffer);
+  fd->wrbuffer = NULL;
+  SetErrnoFromWinError (error_code);
+  return -1;
+}
+
+int
+w32io_read (struct W32Fd *ifd, void *in, size_t to_read)
+{
+  switch (ifd->fd_type)
+  {
+  case GNUNET_W32IO_NAMED_PIPE:
+    return w32io_read_async_named_pipe (ifd, in, to_read);
+    break;
+  case GNUNET_W32IO_FILE:
+    return w32io_read_file (ifd, in, to_read);
+    break;
+  case GNUNET_W32IO_SOCKET:
+    return w32io_recv (ifd, in, to_read, 0);
+  case GNUNET_W32IO_ANONYMOUS_PIPE:
+    return w32io_anonymous_pipe_read (ifd, in, to_read);
+  default:
+    return 0;
+    /* FIXME: handle other descriptor types */
+  }
+}
+
+int
+GNUNET_W32IO_read (int ifd, void *in, size_t to_read)
+{
+  return w32io_read (w32io_fetch_fd (ifd), in, to_read);
+}
+
+int
+w32io_write (struct W32Fd *ifd, const void *out, size_t to_write)
+{
+  int ret;
+  switch (ifd->fd_type)
+  {
+  case GNUNET_W32IO_NAMED_PIPE:
+    return w32io_write_async_named_pipe (ifd, out, to_write);
+    break;
+  case GNUNET_W32IO_FILE:
+    return w32io_write_file (ifd, out, to_write);
+    break;
+  case GNUNET_W32IO_SOCKET:
+    return w32io_send (ifd, out, to_write, 0);
+  case GNUNET_W32IO_ANONYMOUS_PIPE:
+    ret = w32io_anonymous_pipe_write (ifd, out, to_write);
+    return ret;
+  default:
+    return 0;
+    /* FIXME: handle other descriptor types */
+  }
+}
+
+int
+GNUNET_W32IO_write (int ifd, const void *out, size_t to_write)
+{
+  return w32io_write (w32io_fetch_fd (ifd), out, to_write);
+}
+
+/**
+ * Create a named pipe server.
+ * Server is created unconnected. To accept a connection form a client
+ * poll() the server for POLLIN or POLLOUT. Once it polls true, the pipe
+ * is connected and is readable/writable.
+ *
+ * @param name pointer to a (char *) that points to the pipe name.
+ *   if *@name is NULL, the name will be generated randomly until
+ *   a unique name is found, and upon return *@name will point to
+ *   that name (free it with GNUNET_free).
+ * @param mode mode of the pipe handle (as accepted by CreateNamedPipe ())
+ * @return a pointer to FD on success, NULL on error.
+ */
+struct W32Fd *
+w32io_named_pipe_server (char **name, int mode)
+{
+  /* POSIX equivalent: mkfifo() if it doesn't exist, then open() */
+  char pipename[255];
+  int repeat = 1;
+  struct W32Fd *result;
+  HANDLE server = NULL;
+  
+  if (name == NULL)
+    return NULL;
+  if (*name == NULL)
+    repeat = 2;
+
+  while (repeat > 0)
+  {
+    if (repeat == 2)
+      GNUNET_W32IO_generate_random_local_pipe_name (pipename);
+    else
+      strncpy (pipename, *name, 255);
+    server = CreateNamedPipeA ((LPCSTR) pipename, mode |
+        FILE_FLAG_FIRST_PIPE_INSTANCE | FILE_FLAG_OVERLAPPED |
+        PIPE_ACCESS_INBOUND, /*inbound access is necessary to read pipe info*/
+        PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
+        PIPE_UNLIMITED_INSTANCES, 4096, 4096, 0, NULL);
+    if (server == INVALID_HANDLE_VALUE)
+    {
+      DWORD err = GetLastError ();
+      switch (err)
+      {
+        case ERROR_ACCESS_DENIED:
+          server = NULL;
+          if (repeat == 2)
+            continue;
+      }
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to create a named pipe. GLE: %d\n", err);
+      return NULL;
+    }
+    repeat = 0;
+  }
+  
+  result = w32io_fd_from_handle (server, GNUNET_W32IO_NAMED_PIPE, (mode & PIPE_ACCESS_OUTBOUND ? GENERIC_WRITE : 0) | (mode & PIPE_ACCESS_INBOUND ? GENERIC_READ : 0), 0, 0, 0);
+  if (result == NULL)
+  {
+    CloseHandle (server);
+  }
+  else
+  {
+    if (*name == NULL)
+      GNUNET_asprintf (name, "%s", pipename);
+  }
+  return result;
+}
+
+int 
+GNUNET_W32IO_named_pipe_server (char **name, int mode)
+{
+  struct W32Fd *fd = w32io_named_pipe_server (name, mode);
+  if (fd != NULL && fd != INVALID_POLL_FD)
+    return w32io_insert_fd (fd);
+  return -1;
+}
+
+/**
+ * Create a named pipe client.
+ * Client is created and connected atomically in one call. If it is
+ *  not possible to connect the client, it will not be created.
+ *
+ * @param name a (char *) that points to the pipe name.
+ * @param mode mode of the pipe handle (as accepted by CreateFile ())
+ * @return a pointer to FD on success, NULL on error.
+ */
+struct W32Fd *
+w32io_named_pipe_client (const char *name, int mode)
+{
+  /* POSIX equivalent: open() the pipe, but only if it exists and is opened
+   * by another process with mode opposite to @mode.
+   * Note that NT named pipes can be fully duplex, while POSIX named 
+   * pipes usually can not.
+   */
+  struct W32Fd *result;
+  HANDLE p;
+
+  p = CreateFileA ((LPCSTR) name, mode, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED | FILE_READ_ATTRIBUTES, NULL);
+  if (p == INVALID_HANDLE_VALUE)
+  {
+    DWORD err = GetLastError ();
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to open client side of a named pipe. GLE: %d\n", err);
+    return NULL;
+  }
+  result = w32io_fd_from_handle (p, GNUNET_W32IO_NAMED_PIPE, (mode & PIPE_ACCESS_OUTBOUND ? GENERIC_WRITE : 0) | (mode & PIPE_ACCESS_INBOUND ? GENERIC_READ : 0), 1, mode & PIPE_ACCESS_OUTBOUND, mode & PIPE_ACCESS_INBOUND);
+  if (result == NULL)
+    CloseHandle (p);
+  return result;
+}
+
+int
+GNUNET_W32IO_named_pipe_client (const char *name, int mode)
+{
+  struct W32Fd *fd = w32io_named_pipe_client (name, mode);
+  if (fd != NULL && fd != INVALID_POLL_FD)
+    return w32io_insert_fd (fd);
+  return -1;
+}
+
+#endif /* WINDOWS */
\ No newline at end of file
diff --git a/src/util/w32io.h b/src/util/w32io.h
new file mode 100644
index 0000000..c6abe9c
--- /dev/null
+++ b/src/util/w32io.h
@@ -0,0 +1,279 @@
+/*
+     This file is part of GNUnet.
+     (C) 2001, 2002, 2005, 2006, 2009, 2010 Christian Grothoff (and other contributing authors)
+
+     GNUnet is free software; you can redistribute it and/or modify
+     it under the terms of the GNU General Public License as published
+     by the Free Software Foundation; either version 2, or (at your
+     option) any later version.
+
+     GNUnet is distributed in the hope that it will be useful, but
+     WITHOUT ANY WARRANTY; without even the implied warranty of
+     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+     General Public License for more details.
+
+     You should have received a copy of the GNU General Public License
+     along with GNUnet; see the file COPYING.  If not, write to the
+     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+     Boston, MA 02111-1307, USA.
+*/
+#ifndef __GNUNET_W32IO_H__
+#define __GNUNET_W32IO_H__
+#include "platform.h"
+#include "gnunet_common.h"
+
+#if WINDOWS
+
+#include <sys/types.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <errno.h>
+#include <fcntl.h>
+
+#include <winsock2.h>
+
+/**
+ * GNUNET_W32IO_UNSPECIFIED - not specified by user. Should be
+ * autodetected when necessary
+ * GNUNET_W32IO_UNKNOWN - autodetection failed, type unknown
+ * GNUNET_W32IO_FILE - returned by CreateFile()
+ * GNUNET_W32IO_NAMED_PIPE - returned by CreateNamedPipe() (server)
+ * and CreateFile() (client)
+ * GNUNET_W32IO_ANONYMOUS_PIPE - returned by CreatePipe()
+ * GNUNET_W32IO_CONSOLE - returned by CreateFile()
+ * GNUNET_W32IO_SOCKET - returned by socket()
+ * GNUNET_W32IO_LAST - do not use
+ */
+typedef enum
+{
+  GNUNET_W32IO_UNSPECIFIED = 0,
+  GNUNET_W32IO_UNKNOWN,
+  GNUNET_W32IO_FILE,
+  GNUNET_W32IO_NAMED_PIPE,
+  GNUNET_W32IO_ANONYMOUS_PIPE,
+  GNUNET_W32IO_CONSOLE,
+  GNUNET_W32IO_SOCKET,
+  GNUNET_W32IO_LAST
+} GNUNET_W32IO_HandleType;
+
+/**
+ * 
+ */
+struct W32Fd
+{
+  /**
+   * Untyped I/O descriptor (type depends on fd_type)
+   */
+  HANDLE fd;
+
+  /**
+   * Events that have occurred on a socket
+   * (as returned by WSAEnumNetworkEvents)
+   * Used to preserve some one-time events that
+   * are not re-posted by Winsock.
+   */
+  WSANETWORKEVENTS wsaevents;
+
+  /**
+   * An array of structures for file/pipe async I/O.
+   * Its 0th member is used by sockets.
+   * Its 0th and 1st members are used by @anon_thread as, respectedly,
+   * the @anon_thread event (tells the @anon_thread to wake up and do some
+   * work) and the main thread event (tells the main thread to wake up, since
+   * the @anon_thead have finished its work).
+   */
+  OVERLAPPED overlapped[POLLLAST];
+
+  /**
+   * fd_type - type of the descriptor
+   */
+  GNUNET_W32IO_HandleType fd_type;
+
+  /**
+   * The access we have to the handle
+   */
+  DWORD access;
+
+  /**
+   * The events in which the caller is interested in.
+   * May be modified internally by ppoll()
+   */
+  int16_t events;
+
+  /**
+   * The result of a ppoll() call - contains the events
+   * that have occurred on this W32Fd.
+   */
+  int16_t revents;
+
+  /*_______Anonymous pipe I/O implementation details_______*/
+
+  /**
+   * A thread that performs operations on anonymous pipe
+   */
+  HANDLE anon_thread;
+ 
+  /**
+   * A mutex that locks this W32Fd to prevent the main thread and
+   * the @anon_thread from accessing it at the same time.
+   */
+  HANDLE anon_thread_mutex;
+
+  /**
+   * Number of bytes read
+   */
+  int bytes_read;
+
+  /**
+   * Number of bytes written
+   */
+  DWORD bytes_written;
+
+  /**
+   * A pointer to a block of memory that will receive data from a reading
+   * operation.
+   */
+  void *readbuffer;
+
+  /**
+   * Size of the read buffer
+   */
+  size_t readbuffer_size;
+
+  /**
+   * Previous write position in the read buffer (initially -1)
+   */
+  int readbuffer_write_pos;
+
+  /**
+   * Current read position in the read buffer
+   */
+  int readbuffer_read_pos;
+
+  /**
+   * A pointer to a block of memory that will provide data for a writing
+   * operation.
+   */
+  WSABUF *wrbuffer;
+
+  /**
+   * A value returned by ReadFile()/WriteFile() within @anon_thread
+   */
+  BOOL bret;
+
+  /**
+   * A value returned by GetLastError() within @anon_thread
+   */
+  DWORD dwerror;
+
+  /**
+   * A type of work to be done.
+   * -1 - none
+   *  0 - read
+   *  1 - write
+   *  2 - close
+   */
+  int work;
+
+  /**
+   * A boolean condition that can be set to FALSE to indicate that
+   * the @anon_thread must (when it wakes up) return.
+   */
+  BOOL alive;
+
+  /**
+   * Position withing a file (for files)
+   */
+  uint64_t pos;
+};
+
+int w32io_init ();
+int w32io_deinit ();
+
+struct W32Fd *w32io_fetch_fd (int fake_fd);
+int w32io_insert_fd (struct W32Fd *real_fd);
+void w32io_remove_fd (int fake_fd);
+
+HANDLE w32io_fd_get_handle (struct W32Fd *fd);
+HANDLE GNUNET_W32IO_fd_get_handle (int fd);
+
+void GNUNET_W32IO_generate_random_local_pipe_name (char *pipename);
+
+int GNUNET_W32IO_pipe (int fd[2], int server_inheritable, int client_inheritable, DWORD server_mode, DWORD client_mode);
+int w32io_pipe (struct W32Fd *fd[2], int server_inheritable, int client_inheritable, DWORD server_mode, DWORD client_mode);
+
+int GNUNET_W32IO_anonymous_pipe (int fd[2], int read_inheritable, int write_inheritable);
+int w32io_anonymous_pipe (struct W32Fd *fd[2], int read_inheritable, int write_inheritable);
+
+int GNUNET_W32IO_fsync (int wfd);
+int w32io_fsync (struct W32Fd *wfd);
+
+int GNUNET_W32IO_close (int wfd, int closehandle);
+int w32io_close (struct W32Fd *wfd, int closehandle);
+
+int w32io_shutdown (struct W32Fd *wfd, int how);
+int GNUNET_W32IO_shutdown (int fd, int how);
+
+GNUNET_W32IO_HandleType GNUNET_W32IO_find_handle_type (HANDLE h);
+
+int GNUNET_W32IO_fd_from_handle (HANDLE h, GNUNET_W32IO_HandleType htype, DWORD handle_access, int connected,
+    int writeable, int readable);
+struct W32Fd *w32io_fd_from_handle (HANDLE h, GNUNET_W32IO_HandleType htype, DWORD handle_access, int connected,
+    int writeable, int readable);
+
+int w32io_read_async_named_pipe (struct W32Fd *fd, void *in, size_t to_read);
+
+int w32io_write_async_named_pipe (struct W32Fd *fd, const void *out, size_t to_write);
+
+int GNUNET_W32IO_read (int ifd, void *in, size_t to_read);
+int w32io_read (struct W32Fd *ifd, void *in, size_t to_read);
+
+int GNUNET_W32IO_write (int ifd, const void *out, size_t to_write);
+int w32io_write (struct W32Fd *ifd, const void *out, size_t to_write);
+
+int GNUNET_W32IO_poll (struct pollfd *fds, nfds_t nfds, int timeout);
+int w32io_poll (struct W32PollFd *fds, nfds_t nfds, int timeout, int emulate_select);
+
+int GNUNET_W32IO_select (int nfds, w32fd_set *readfds, w32fd_set *writefds, w32fd_set *errorfds, struct timeval *timeout);
+
+int w32io_prepare_for_poll (struct W32PollFd *wfd, HANDLE *events);
+
+int GNUNET_W32IO_recv (int fd, void *buffer, size_t length, int flags);
+int GNUNET_W32IO_recvfrom (int fd, void *buffer, size_t length, int flags, struct sockaddr *address, int *address_len);
+int GNUNET_W32IO_send (int fd, const void *buffer, size_t length, int flags);
+int GNUNET_W32IO_sendto (int fd, const void *buffer, size_t length, int flags, const struct sockaddr *address, int address_len);
+int w32io_recv (struct W32Fd *fd, void *buffer, size_t length, int flags);
+int w32io_recvfrom (struct W32Fd *fd, void *buffer, size_t length, int flags, struct sockaddr *address, int *address_len);
+int w32io_send (struct W32Fd *fd, const void *buffer, size_t length, int flags);
+int w32io_sendto (struct W32Fd *fd, const void *buffer, size_t length, int flags, const struct sockaddr *address, int address_len);
+
+int GNUNET_W32IO_connect (int fd, const struct sockaddr *name, int namelen);
+int GNUNET_W32IO_accept (int fd, struct sockaddr *name, int *namelen);
+int GNUNET_W32IO_listen (int fd, int backlog);
+int w32io_connect (struct W32Fd *fd, const struct sockaddr *name, int namelen);
+int w32io_accept (struct W32Fd *fd, struct sockaddr *name, int *namelen);
+int w32io_listen (struct W32Fd *fd, int backlog);
+int GNUNET_W32IO_bind (int fd, const struct sockaddr *name, int namelen);
+int w32io_bind (struct W32Fd *fd, const struct sockaddr *name, int namelen);
+
+int w32io_anonymous_pipe_read (struct W32Fd *fd, void *in, size_t to_read);
+int w32io_anonymous_pipe_write (struct W32Fd *fd, const void *out, size_t to_write);
+int w32io_anonymous_pipe_close (struct W32Fd *fd, int closehandle);
+
+off_t GNUNET_W32IO_lseek_handle (HANDLE fd, uint64_t new_offset, int origin);
+off_t GNUNET_W32IO_lseek (int fd, uint64_t new_offset, int origin);
+off_t w32io_lseek (struct W32Fd *fd, uint64_t new_offset, int origin);
+
+int w32io_read_file (struct W32Fd *fd, void *in, size_t to_read);
+int w32io_write_file (struct W32Fd *fd, const void *out, size_t to_write);
+
+int GNUNET_W32IO_named_pipe_server (char **name, int mode);
+int GNUNET_W32IO_named_pipe_client (const char *name, int mode);
+struct W32Fd *w32io_named_pipe_server (char **name, int mode);
+struct W32Fd *w32io_named_pipe_client (const char *name, int mode);
+
+#endif /* WINDOWS */
+#endif /* __GNUNET_W32IO_H__ */
\ No newline at end of file
diff --git a/src/util/winproc.c b/src/util/winproc.c
index 2df6383..8a7344b 100644
--- a/src/util/winproc.c
+++ b/src/util/winproc.c
@@ -29,7 +29,8 @@
 
 #define DEBUG_WINPROC 0
 
-#ifdef MINGW
+#if WINDOWS
+#include "w32io.h"
 
 static HINSTANCE hNTDLL, hIphlpapi, hAdvapi, hNetapi;
 
@@ -91,6 +92,8 @@ GNInitWinEnv ()
   plibc_set_panic_proc (plibc_panic);
   ret = plibc_init ("GNU", PACKAGE);
 
+  w32io_init ();
+  
   /* don't load other DLLs twice */
   if (hNTDLL)
     return ret;
@@ -235,6 +238,8 @@ GNShutdownWinEnv ()
 {
   plibc_shutdown ();
 
+  w32io_deinit ();
+
   FreeLibrary (hNTDLL);
   FreeLibrary (hIphlpapi);
   FreeLibrary (hAdvapi);
@@ -243,7 +248,7 @@ GNShutdownWinEnv ()
   CoUninitialize ();
 }
 
-#endif /* MINGW */
+#endif /* WINDOWS */
 
 #if !HAVE_ATOLL
 long long
-- 
1.7.3.1.msysgit.0

Relationships

related to 0001735 closedLRN Introduce adaptive poll cycle length in GNUNET_NETWORK_socket_select () 

Activities

LRN

2010-11-26 13:09

developer   ~0004188

Uploaded 0001-First-w32io-with-fake-FDs-commit.patch
At the moment it should apply cleanly to SVN HEAD, should compile relatively clean (might show a couple of warnings) and passes 45 util tests on my machine.
It might require further fixing later on, as i work on passing the tests, but i think for now it's good enough for a review.

The patch is a bit heavy on commented-out code and logging statements - ignore these, some parts were hacked together roughly, as i was trying to fix the TerminateThread bug that i myself introduced (i wasn't whining, by the way).

ndurner, i think we should discuss the way you handle named pipe opening at the moment. So far your variant is not used anywhere, so it is not too late to change it. The only thing i did with your variant is to wrap it into W32IO fake fd, so nothing seems to be wrong with it, but the way a name should be generated (especially in a cross-platform way) is a subject for discussion (by the way, you didn't check for pipe name length).

I would also like to point out that it makes the code a bit more cleaner when W32-specific code is moved into separate source file and is made to provide the interface GNUnet expects from POSIX (with, possibly, small variations). With my patch disk.c in some places boils down to something like:
#if WINDOWS && !defined(__CYGWIN__)
GNUNET_W32IO_blah_syscall(foo, bar)
#else
blah_syscall(foo, bar)
#endif
So i would like to advise to do it like this in future and keep W32-specific code isolated.

About WINDOWS and MINGW:
1) My opinion is that CYGWIN means "compile as much POSIX code as possible; compile WinAPI-using code only for things that are NOT implemented by Cygwin", and AFAIK Cygwin implements a LOT - signals, I/O, process management, mmap - you name it.
2) My opinion is that current MINGW means "Windows platform; compile WinAPI code" - which is not related to MinGW itself in any way (any other toolset could be used), so "MINGW" is a bit misleading (someone compiling GNUnet with MSVC will have to -DMINGW=1 mostly).
There are two ways of doing this:
A) Define WINDOWS for CYGWIN (which is what ndurner does, according to him), use WINDOWS on WinAPI code. This will make Cygwin compile all WinAPI code (which conflicts with (1) above). Code that Cygwin should avoid is marked additionally with && !defined(__CYGWIN__)
B) Do not define WINDOWS for CYGWIN. This will make Cygwin compile all POSIX code (which is what (1) says it should do). WinAPI code, that should be compiled by Cygwin in favor of POSIX code, is marked with || defined(__CYGWIN__)
At the moment i did (A), although it leads to much more numerous extra && !defined(__CYGWIN__) checks than (B) would.
As for (2), MINGW should be used exactly for MinGW - GCC on Windows. I don't remember seeing any code in GNUnet that is specific to GCC on Windows, only code specific to Windows in general, regardless of the compiler.
__CYGWIN__ seems to be equivalent to CYGWIN, but the former is defined internally by Cygwin itself, while CYGWIN is a custom define. Same goes for __MINGW32__ vs MINGW. I have nothing against CYGWIN being used instead of __CYGWIN__, actually. Might help with cross-compiling - as long as there's a convenient (and documented way) to play with these definitions (i find it a bit gross to ask people to do CPPFLAGS="-DCYGWIN=1" or something like that)

LRN

2010-11-27 00:55

developer   ~0004189

OK, from the IRC discussion there appear to be three concerns about this patch:

1) Performance.
I have no idea of how many kernel mode switches are made, so i can't judge that. As long as you don't select() repeatedly with 0 or near-0 timeout, it shouldn't be a problem.
Anonymous pipe operations might introduce slight delays even for non-blocking operations, because they might require a couple of thread context switches.
As an alternative to running transport tests to measure performance, someone (not me) might want to re-implement test_w32io in WinAPI and measure it vs my test_w32io.

I can guess a little by looking at _prepare() function.
For sockets it only does one WSAEnumNetworkEvents() call and, possibly, one SetEvent().
For files it does either SetEvent() or ResetEvent() once.
For anonymous pipes it does one infinite wait (almost a guaranteed syscall) and a SetEvent or ResetEvent(). The last branch is almost never executed (it requires for both POLLIN and POLLOUT to be unset, and that's difficult to imagine).
For named pipes it does up to three Wait* calls with 0 delay (never a syscall, AFAIU), and for each successful Wait* it will do an I/O call (connect/read/write) - each probably a syscall. And some more conditional stuff.

Select itself is a single WaitForMultipleObjects call with (usually) non-zero timeout, and that's a syscall.

Then there's a long loop over all events in all FDs being polled (each FD can have up to roughly 13 events, and each one is considered, although the loop will continue if the event handle is -1 or if a Wait* call with 0 timeout on it times out, so there's no syscalls here, just a big loop).
For each enabled event (which means a successful poll on a FD most of the time) it will do more stuff, roughly the same stuff it did in _prepare(), so only anonymous pipes are likely to do syscalls there (unless Set/ResetEvent causes a syscall - these will be called for almost every enabled event).

That concludes my uneducated analysis of my select/poll().

2) Overkill.
It all started when it was decided to use named pipes on W32 to communicate shutdown signals to child processes, and i discovered that GNUnet doesn't have much code to support operations on named pipes (because it never used them).
ndurner's solution would be to modify GNUnet's current select() I/O calls to work with named pipes - in the same awkward way it was before - select()ing on sockets, then peeking at each pipe after select() returns, possibly after timeout (which, admittedly, worked well enough for, like, 8 years so far).
My solution would be to push W32 I/O into separate file and implement a POSIX interface on top of it. It obviously requires much more code, hence the concern. However, it not only allows seamless usage of named pipes in select()(which was the original goal), but also simplifies cross-platform parts of GNUnet, because they tend to use POSIX interfaces. So it might be a bit less of an overkill, if you count in all the #ifdefed code that i was able to remove from network.c and disk.c

3) Pushing it into plibc
Because, as any wrapping, W32IO complicates things, and it gives away fake FDs instead of native handles, ndurner doesn't want it in plibc. Otherwise it would have been possible to push it there.
It MIGHT be possible to rewrite the whole thing to give away real native handles, and accept these as arguments for I/O calls, then use them to lookup metadata in an internal array of FDs, but:
a) This doesn't allow fast fd_set operations anymore (which was the main reason to use select())
b) If you have two different handles (say, a socket and a file) with the same absolute value (they don't share the same namespace), you might try eventually to send() on a file or ReadFile() on a socket - and that'll break things (i think i've seen something like that in 0.8, at least it was theorized that handle mix was behind the problem i've experienced). That might be fixable with some extra voodoo magic (if you give a hint to the lookup function about the type of FD you're looking for, you're going to be fine).
My conclusion is that current approach is justified from both sides and that W32IO isn't going to plibc. But it still remains a separate .c/.h pair of files, if that makes you feel better, grothoff.

Christian Grothoff

2011-07-03 13:19

manager   ~0004473

From a quick glance at it, I'd say it looks fine. Let's plan to push something along those lines once SVN HEAD kind-of works again on GNU/Linux so we can test this to be sure it doesn't cause major regressions elsewhere...

Christian Grothoff

2011-07-03 13:20

manager   ~0004474

Changed severity to 'major' since the performance issue this seems to fix is big enough to be considered a bug from my point of view.

LRN

2011-07-03 13:45

developer   ~0004475

I'll remind you that there are two alternatives to this:
1) Reduce the cycle timeout in existing implementation. This clearly improves the throughput of the transport tests. Might have side effects (since the lower the timeout is, the closer it gets to being a CPU-time-wasting busy-loop).
2) Use GNUlib's implementation of select(). It is probably based on the same ideas as mine (i think i took a look at that code at some point in the past, or was it glib's implementation?), but at least GNUlib is a dedicated GNU project (and probably well-tested too). Bratao promised to check its performance within a couple of weeks.
We'll see which alternative is the most promising one after i manage to get the transport test results for W32IO.

LRN

2011-07-12 23:59

developer   ~0004498

Despite my best efforts, W32 I/O can't match the speed of winsock's select() (500 kb/s vs 11000-12000 kb/s).
I haven't heard back from bratao yet, but i wouldn't hold my breath.

I'll file the a separate bug for adaptive cycle delay.

Christian Grothoff

2011-07-15 14:39

manager   ~0004510

Should this bug be closed since we patched according to 0001735?

LRN

2011-07-15 15:07

developer   ~0004511

Yeah, i think it is time to put it out of its misery.

Issue History

Date Modified Username Field Change
2010-11-18 00:17 LRN New Issue
2010-11-18 00:17 LRN Status new => assigned
2010-11-18 00:17 LRN Assigned To => NDurner
2010-11-18 00:17 LRN File Added: 0001-poll-implementation-for-W32.patch
2010-11-26 12:44 LRN File Added: 0001-First-w32io-with-fake-FDs-commit.patch
2010-11-26 13:09 LRN Note Added: 0004188
2010-11-27 00:55 LRN Note Added: 0004189
2011-07-03 13:19 Christian Grothoff Note Added: 0004473
2011-07-03 13:20 Christian Grothoff Note Added: 0004474
2011-07-03 13:20 Christian Grothoff Severity feature => major
2011-07-03 13:20 Christian Grothoff Product Version => Git master
2011-07-03 13:45 LRN Note Added: 0004475
2011-07-12 23:59 LRN Note Added: 0004498
2011-07-15 14:38 Christian Grothoff Relationship added related to 0001735
2011-07-15 14:39 Christian Grothoff Note Added: 0004510
2011-07-15 15:07 LRN Note Added: 0004511
2011-07-18 13:28 Christian Grothoff Status assigned => closed
2011-07-18 13:28 Christian Grothoff Resolution open => fixed
2024-01-12 14:28 schanzen Category Win32 port => Win32 port (deprecated)
2024-05-03 13:51 Christian Grothoff Category Win32 port (deprecated) => obsolete