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

