+ }
+ if (NULL != efds)
+ {
+ nfds = GNUNET_MAX (nfds, efds->nsds);
+#ifdef MINGW
+ handles += GNUNET_CONTAINER_slist_count (efds->handles);
+#endif
+ }
+
+ struct timeval tv;
+ tv.tv_sec = timeout.rel_value / GNUNET_TIME_UNIT_SECONDS.rel_value;
+ 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,
+ _
+ ("Fatal internal logic error, process hangs in `%s' (abort with CTRL-C)!\n"),
+ "select");
+ GNUNET_break (0);
+ }
+#ifndef MINGW
+ 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);
+
+#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;
+#endif
+}
+
+
+/* end of network.c */