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