aboutsummaryrefslogtreecommitdiff
path: root/src/util
diff options
context:
space:
mode:
authorLRN <lrn1986@gmail.com>2014-12-14 14:54:54 +0000
committerLRN <lrn1986@gmail.com>2014-12-14 14:54:54 +0000
commitea17e83e666b0104b43d04423cef193f92199c26 (patch)
tree02f5795bb0ddc364f2b81d60219e29a7f8c85437 /src/util
parent287a26a5ca4f5ea014419f4c0000c64f4e3acbf3 (diff)
downloadgnunet-ea17e83e666b0104b43d04423cef193f92199c26.tar.gz
gnunet-ea17e83e666b0104b43d04423cef193f92199c26.zip
Grothoff's W32 select slist elimination and prettification
Diffstat (limited to 'src/util')
-rw-r--r--src/util/network.c911
1 files changed, 393 insertions, 518 deletions
diff --git a/src/util/network.c b/src/util/network.c
index 47fdb91ab..411e468ab 100644
--- a/src/util/network.c
+++ b/src/util/network.c
@@ -1039,7 +1039,7 @@ GNUNET_NETWORK_fdset_zero (struct GNUNET_NETWORK_FDSet *fds)
1039 FD_ZERO (&fds->sds); 1039 FD_ZERO (&fds->sds);
1040 fds->nsds = 0; 1040 fds->nsds = 0;
1041#ifdef MINGW 1041#ifdef MINGW
1042 GNUNET_CONTAINER_slist_clear (fds->handles); 1042 fds->handles_pos = 0;
1043#endif 1043#endif
1044} 1044}
1045 1045
@@ -1092,25 +1092,33 @@ GNUNET_NETWORK_fdset_add (struct GNUNET_NETWORK_FDSet *dst,
1092 1092
1093 for (nfds = src->nsds; nfds >= 0; nfds--) 1093 for (nfds = src->nsds; nfds >= 0; nfds--)
1094 if (FD_ISSET (nfds, &src->sds)) 1094 if (FD_ISSET (nfds, &src->sds))
1095
1096 {
1097 FD_SET (nfds, &dst->sds); 1095 FD_SET (nfds, &dst->sds);
1098 if (nfds + 1 > dst->nsds) 1096 dst->nsds = GNUNET_MAX (dst->nsds,
1099 dst->nsds = nfds + 1; 1097 src->nsds);
1100 }
1101#else 1098#else
1102 /* This is MinGW32-specific implementation that relies on the code that 1099 /* This is MinGW32-specific implementation that relies on the code that
1103 * winsock2.h defines for FD_SET. Namely, it relies on FD_SET checking 1100 * winsock2.h defines for FD_SET. Namely, it relies on FD_SET checking
1104 * that fd being added is not already in the set. 1101 * that fd being added is not already in the set.
1105 * Also relies on us knowing what's inside fd_set (fd_count and fd_array). 1102 * Also relies on us knowing what's inside fd_set (fd_count and fd_array).
1103 *
1104 * NOTE: I don't understand why the UNIX-logic wouldn't work
1105 * for the first part here as well. -CG
1106 */ 1106 */
1107 int i; 1107 unsigned int i;
1108 for (i = 0; i < src->sds.fd_count; i++)
1109 FD_SET (src->sds.fd_array[i], &dst->sds);
1110 if (src->nsds > dst->nsds)
1111 dst->nsds = src->nsds;
1112 1108
1113 GNUNET_CONTAINER_slist_append (dst->handles, src->handles); 1109 for (i = 0; i < src->sds.fd_count; i++)
1110 FD_SET (src->sds.fd_array[i],
1111 &dst->sds);
1112 dst->nsds = GNUNET_MAX (src->nsds,
1113 dst->nsds);
1114
1115 /* also copy over `struct GNUNET_DISK_FileHandle` array */
1116 if (dst->handles_pos + src->handles_pos > dst->handles_size)
1117 GNUNET_array_grow (dst->handles,
1118 dst->handles_size,
1119 ((dst->handles_pos + src->handles_pos) << 1));
1120 for (i = 0; i < src->handles_pos; i++)
1121 dst->handles[dst->handles_pos++] = src->handles[i];
1114#endif 1122#endif
1115} 1123}
1116 1124
@@ -1129,8 +1137,14 @@ GNUNET_NETWORK_fdset_copy (struct GNUNET_NETWORK_FDSet *to,
1129 &to->sds); 1137 &to->sds);
1130 to->nsds = from->nsds; 1138 to->nsds = from->nsds;
1131#ifdef MINGW 1139#ifdef MINGW
1132 GNUNET_CONTAINER_slist_clear (to->handles); 1140 if (from->handles_pos > to->handles_size)
1133 GNUNET_CONTAINER_slist_append (to->handles, from->handles); 1141 GNUNET_array_grow (to->handles,
1142 to->handles_size,
1143 from->handles_pos * 2);
1144 memcpy (to->handles,
1145 from->handles,
1146 from->handles_pos * sizeof (struct GNUNET_NETWORK_Handle *));
1147 to->handles_pos = from->handles_pos;
1134#endif 1148#endif
1135} 1149}
1136 1150
@@ -1237,10 +1251,11 @@ GNUNET_NETWORK_fdset_handle_set (struct GNUNET_NETWORK_FDSet *fds,
1237 const struct GNUNET_DISK_FileHandle *h) 1251 const struct GNUNET_DISK_FileHandle *h)
1238{ 1252{
1239#ifdef MINGW 1253#ifdef MINGW
1240 GNUNET_CONTAINER_slist_add (fds->handles, 1254 if (fds->handles_pos == fds->handles_size)
1241 GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT, h, 1255 GNUNET_array_grow (fds->handles,
1242 sizeof (struct GNUNET_DISK_FileHandle)); 1256 fds->handles_size,
1243 1257 fds->handles_size * 2 + 2);
1258 fds->handles[fds->handles_pos++] = h;
1244#else 1259#else
1245 int fd; 1260 int fd;
1246 1261
@@ -1267,9 +1282,12 @@ GNUNET_NETWORK_fdset_handle_isset (const struct GNUNET_NETWORK_FDSet *fds,
1267 const struct GNUNET_DISK_FileHandle *h) 1282 const struct GNUNET_DISK_FileHandle *h)
1268{ 1283{
1269#ifdef MINGW 1284#ifdef MINGW
1270 return GNUNET_CONTAINER_slist_contains (fds->handles, h, 1285 unsigned int i;
1271 sizeof (struct 1286
1272 GNUNET_DISK_FileHandle)); 1287 for (i=0;i<fds->handles_pos;i++)
1288 if (fds->handles[i] == h)
1289 return GNUNET_YES;
1290 return GNUNET_NO;
1273#else 1291#else
1274 return FD_ISSET (h->fd, 1292 return FD_ISSET (h->fd,
1275 &fds->sds); 1293 &fds->sds);
@@ -1277,6 +1295,28 @@ GNUNET_NETWORK_fdset_handle_isset (const struct GNUNET_NETWORK_FDSet *fds,
1277} 1295}
1278 1296
1279 1297
1298#ifdef MINGW
1299/**
1300 * Numerically compare pointers to sort them.
1301 * Used to test for overlap in the arrays.
1302 *
1303 * @param p1 a pointer
1304 * @param p2 a pointer
1305 * @return -1, 0 or 1, if the p1 < p2, p1==p2 or p1 > p2.
1306 */
1307static int
1308ptr_cmp (const void *p1,
1309 const void *p2)
1310{
1311 if (p1 == p2)
1312 return 0;
1313 if ((intptr_t) p1 < (intptr_t) p2)
1314 return -1;
1315 return 1;
1316}
1317#endif
1318
1319
1280/** 1320/**
1281 * Checks if two fd sets overlap 1321 * Checks if two fd sets overlap
1282 * 1322 *
@@ -1304,49 +1344,47 @@ GNUNET_NETWORK_fdset_overlap (const struct GNUNET_NETWORK_FDSet *fds1,
1304 } 1344 }
1305 return GNUNET_NO; 1345 return GNUNET_NO;
1306#else 1346#else
1307 struct GNUNET_CONTAINER_SList_Iterator it; 1347 unsigned int i;
1308 struct GNUNET_DISK_FileHandle *h; 1348 unsigned int j;
1309 int i;
1310 int j;
1311 1349
1312 /* This code is somewhat hacky, we are not supposed to know what's 1350 /* This code is somewhat hacky, we are not supposed to know what's
1313 * inside of fd_set; also the O(n^2) is really bad... */ 1351 * inside of fd_set; also the O(n^2) is really bad... */
1314 for (i = 0; i < fds1->sds.fd_count; i++) 1352 for (i = 0; i < fds1->sds.fd_count; i++)
1315 {
1316 for (j = 0; j < fds2->sds.fd_count; j++) 1353 for (j = 0; j < fds2->sds.fd_count; j++)
1317 {
1318 if (fds1->sds.fd_array[i] == fds2->sds.fd_array[j]) 1354 if (fds1->sds.fd_array[i] == fds2->sds.fd_array[j])
1319 return GNUNET_YES; 1355 return GNUNET_YES;
1320 }
1321 }
1322 it = GNUNET_CONTAINER_slist_begin (fds1->handles);
1323 while (GNUNET_CONTAINER_slist_end (&it) != GNUNET_YES)
1324 {
1325#if DEBUG_NETWORK
1326 struct GNUNET_CONTAINER_SList_Iterator t;
1327#endif
1328 h = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (&it,
1329 NULL);
1330#if DEBUG_NETWORK
1331 LOG (GNUNET_ERROR_TYPE_DEBUG, "Checking that FD 0x%x is in another set:\n",
1332 h->h);
1333 for (t = GNUNET_CONTAINER_slist_begin (fds2->handles);
1334 GNUNET_CONTAINER_slist_end (&t) != GNUNET_YES;
1335 GNUNET_CONTAINER_slist_next (&t))
1336 {
1337 struct GNUNET_DISK_FileHandle *fh;
1338 1356
1339 fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (&t, 1357 /* take a short cut if possible */
1340 NULL); 1358 if ( (0 == fds1->handles_pos) ||
1341 LOG (GNUNET_ERROR_TYPE_DEBUG, "0x%x\n", fh->h); 1359 (0 == fds2->handles_pos) )
1342 } 1360 return GNUNET_NO;
1343#endif 1361
1344 if (GNUNET_CONTAINER_slist_contains 1362 /* Sort file handles array to avoid quadratic complexity when
1345 (fds2->handles, h, sizeof (struct GNUNET_DISK_FileHandle))) 1363 checking for overlap */
1364 qsort (fds1->handles,
1365 fds1->handles_pos,
1366 sizeof (void *),
1367 &ptr_cmp);
1368 qsort (fds2->handles,
1369 fds2->handles_pos,
1370 sizeof (void *),
1371 &ptr_cmp);
1372 i = 0;
1373 j = 0;
1374 while ( (i < fds1->handles_pos) &&
1375 (j < fds2->handles_pos) )
1376 {
1377 switch (ptr_cmp (fds1->handles[i],
1378 fds2->handles[j]))
1346 { 1379 {
1380 case -1:
1381 i++;
1382 break;
1383 case 0:
1347 return GNUNET_YES; 1384 return GNUNET_YES;
1385 case 1:
1386 j++;
1348 } 1387 }
1349 GNUNET_CONTAINER_slist_next (&it);
1350 } 1388 }
1351 return GNUNET_NO; 1389 return GNUNET_NO;
1352#endif 1390#endif
@@ -1364,9 +1402,6 @@ GNUNET_NETWORK_fdset_create ()
1364 struct GNUNET_NETWORK_FDSet *fds; 1402 struct GNUNET_NETWORK_FDSet *fds;
1365 1403
1366 fds = GNUNET_new (struct GNUNET_NETWORK_FDSet); 1404 fds = GNUNET_new (struct GNUNET_NETWORK_FDSet);
1367#ifdef MINGW
1368 fds->handles = GNUNET_CONTAINER_slist_create ();
1369#endif
1370 GNUNET_NETWORK_fdset_zero (fds); 1405 GNUNET_NETWORK_fdset_zero (fds);
1371 return fds; 1406 return fds;
1372} 1407}
@@ -1381,7 +1416,9 @@ void
1381GNUNET_NETWORK_fdset_destroy (struct GNUNET_NETWORK_FDSet *fds) 1416GNUNET_NETWORK_fdset_destroy (struct GNUNET_NETWORK_FDSet *fds)
1382{ 1417{
1383#ifdef MINGW 1418#ifdef MINGW
1384 GNUNET_CONTAINER_slist_destroy (fds->handles); 1419 GNUNET_array_grow (fds->handles,
1420 fds->handles_size,
1421 0);
1385#endif 1422#endif
1386 GNUNET_free (fds); 1423 GNUNET_free (fds);
1387} 1424}
@@ -1464,6 +1501,105 @@ _selector (LPVOID p)
1464 } 1501 }
1465 return 0; 1502 return 0;
1466} 1503}
1504
1505
1506static HANDLE hEventPipeWrite;
1507
1508static HANDLE hEventReadReady;
1509
1510static struct _select_params sp;
1511
1512static HANDLE select_thread;
1513
1514static HANDLE select_finished_event;
1515
1516static HANDLE select_standby_event;
1517
1518static SOCKET select_wakeup_socket = -1;
1519
1520static SOCKET select_send_socket = -1;
1521
1522static struct timeval select_timeout;
1523
1524
1525/**
1526 * On W32, we actually use a thread to help with the
1527 * event loop due to W32-API limitations. This function
1528 * initializes that thread.
1529 */
1530static void
1531initialize_select_thread ()
1532{
1533 SOCKET select_listening_socket = -1;
1534 struct sockaddr_in s_in;
1535 int alen;
1536 int res;
1537 unsigned long p;
1538
1539 select_standby_event = CreateEvent (NULL, TRUE, FALSE, NULL);
1540 select_finished_event = CreateEvent (NULL, TRUE, FALSE, NULL);
1541
1542 select_wakeup_socket = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
1543
1544 select_listening_socket = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
1545
1546 p = 1;
1547 res = ioctlsocket (select_wakeup_socket, FIONBIO, &p);
1548 LOG (GNUNET_ERROR_TYPE_DEBUG,
1549 "Select thread initialization: ioctlsocket() returns %d\n",
1550 res);
1551
1552 alen = sizeof (s_in);
1553 s_in.sin_family = AF_INET;
1554 s_in.sin_port = 0;
1555 s_in.sin_addr.S_un.S_un_b.s_b1 = 127;
1556 s_in.sin_addr.S_un.S_un_b.s_b2 = 0;
1557 s_in.sin_addr.S_un.S_un_b.s_b3 = 0;
1558 s_in.sin_addr.S_un.S_un_b.s_b4 = 1;
1559 res = bind (select_listening_socket,
1560 (const struct sockaddr *) &s_in,
1561 sizeof (s_in));
1562 LOG (GNUNET_ERROR_TYPE_DEBUG,
1563 "Select thread initialization: bind() returns %d\n",
1564 res);
1565
1566 res = getsockname (select_listening_socket,
1567 (struct sockaddr *) &s_in,
1568 &alen);
1569 LOG (GNUNET_ERROR_TYPE_DEBUG,
1570 "Select thread initialization: getsockname() returns %d\n",
1571 res);
1572
1573 res = listen (select_listening_socket,
1574 SOMAXCONN);
1575 LOG (GNUNET_ERROR_TYPE_DEBUG,
1576 "Select thread initialization: listen() returns %d\n",
1577 res);
1578 res = connect (select_wakeup_socket,
1579 (const struct sockaddr *) &s_in,
1580 sizeof (s_in));
1581 LOG (GNUNET_ERROR_TYPE_DEBUG,
1582 "Select thread initialization: connect() returns %d\n",
1583 res);
1584
1585 select_send_socket = accept (select_listening_socket,
1586 (struct sockaddr *) &s_in,
1587 &alen);
1588
1589 closesocket (select_listening_socket);
1590
1591 sp.wakeup = select_finished_event;
1592 sp.standby = select_standby_event;
1593 sp.wakeup_socket = select_wakeup_socket;
1594
1595 select_thread = CreateThread (NULL,
1596 0,
1597 _selector,
1598 &sp,
1599 0, NULL);
1600}
1601
1602
1467#endif 1603#endif
1468 1604
1469 1605
@@ -1522,6 +1658,87 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds,
1522 1658
1523 1659
1524/** 1660/**
1661 * Non-blocking test if a pipe is ready for reading.
1662 *
1663 * @param fh pipe handle
1664 * @return #GNUNET_YES if the pipe is ready for reading
1665 */
1666static int
1667pipe_read_ready (struct GNUNET_DISK_FileHandle *fh)
1668{
1669 DWORD error;
1670 BOOL bret;
1671 DWORD waitstatus = 0;
1672
1673 SetLastError (0);
1674 bret = PeekNamedPipe (fh->h, NULL, 0, NULL, &waitstatus, NULL);
1675 error = GetLastError ();
1676 if (0 == bret)
1677 {
1678 /* TODO: either add more errors to this condition, or eliminate it
1679 * entirely (failed to peek -> pipe is in serious trouble, should
1680 * be selected as readable).
1681 */
1682 if ( (error != ERROR_BROKEN_PIPE) &&
1683 (error != ERROR_INVALID_HANDLE) )
1684 return GNUNET_NO;
1685 }
1686 else if (waitstatus <= 0)
1687 return GNUNET_NO;
1688 return GNUNET_YES;
1689}
1690
1691
1692/**
1693 * Non-blocking test if a pipe is having an IO exception.
1694 *
1695 * @param fh pipe handle
1696 * @return #GNUNET_YES if the pipe is having an IO exception.
1697 */
1698static int
1699pipe_except_ready (struct GNUNET_DISK_FileHandle *fh)
1700{
1701 DWORD dwBytes;
1702
1703 if (PeekNamedPipe (fh->h, NULL, 0, NULL, &dwBytes, NULL))
1704 return GNUNET_NO;
1705 return GNUNET_YES;
1706}
1707
1708
1709/**
1710 * Iterate over handles in fds, destructively rewrite the
1711 * handles array contents of fds so that it starts with the
1712 * handles that are ready, and update handles_pos accordingly.
1713 *
1714 * @param fds set of handles (usually pipes) to be checked for readiness
1715 * @param except GNUNET_NO if fds should be checked for readiness to read,
1716 * GNUNET_YES if fds should be checked for exceptions
1717 * (there is no way to check for write-readiness - pipes are always write-ready)
1718 * @return number of ready handles
1719 */
1720static int
1721check_handles_status (struct GNUNET_NETWORK_FDSet *fds, int except)
1722{
1723 struct GNUNET_DISK_FileHandle *fh;
1724 unsigned int roff;
1725 unsigned int woff;
1726 int is_pipe;
1727
1728 for (woff = 0, roff = 0; roff < fds->handles_pos; roff++)
1729 {
1730 fh = fds->handles[roff];
1731 is_pipe = fh->type == GNUNET_DISK_HANLDE_TYPE_PIPE;
1732 if ((except && is_pipe && pipe_except_ready (fh)) ||
1733 (!except && (!is_pipe || pipe_read_ready (fh))))
1734 fds->handles[woff++] = fh;
1735 }
1736 fds->handles_pos = woff;
1737 return woff;
1738}
1739
1740
1741/**
1525 * Check if sockets or pipes meet certain conditions, version for W32. 1742 * Check if sockets or pipes meet certain conditions, version for W32.
1526 * 1743 *
1527 * @param rfds set of sockets or pipes to be checked for readability 1744 * @param rfds set of sockets or pipes to be checked for readability
@@ -1536,93 +1753,44 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds,
1536 struct GNUNET_NETWORK_FDSet *efds, 1753 struct GNUNET_NETWORK_FDSet *efds,
1537 const struct GNUNET_TIME_Relative timeout) 1754 const struct GNUNET_TIME_Relative timeout)
1538{ 1755{
1539 int nfds = 0; 1756 struct GNUNET_DISK_FileHandle *fh;
1540 int handles = 0; 1757 int nfds;
1541 int ex_handles = 0; 1758 int handles;
1542 int read_handles = 0; 1759 unsigned int i;
1543 int write_handles = 0; 1760 int retcode;
1544 1761 uint64_t mcs_total;
1545 int i = 0; 1762 DWORD ms_rounded;
1546 int retcode = 0;
1547 uint64_t mcs_total = 0;
1548 DWORD ms_rounded = 0;
1549
1550 int nhandles = 0; 1763 int nhandles = 0;
1551 1764 int read_pipes_off;
1552 static HANDLE hEventPipeWrite = 0;
1553 static HANDLE hEventReadReady = 0;
1554
1555 static struct _select_params sp;
1556 static HANDLE select_thread = NULL;
1557 static HANDLE select_finished_event = NULL;
1558 static HANDLE select_standby_event = NULL;
1559 static SOCKET select_wakeup_socket = -1;
1560 static SOCKET select_send_socket = -1;
1561 static struct timeval select_timeout;
1562
1563 int readPipes = 0;
1564 int writePipePos = 0;
1565
1566 HANDLE handle_array[FD_SETSIZE + 2]; 1765 HANDLE handle_array[FD_SETSIZE + 2];
1567 int returncode = -1; 1766 int returncode;
1568 int returnedpos = 0; 1767 int returnedpos = 0;
1569 1768 int selectret;
1570 struct GNUNET_CONTAINER_SList *handles_read;
1571 struct GNUNET_CONTAINER_SList *handles_write;
1572 struct GNUNET_CONTAINER_SList *handles_except;
1573
1574 int selectret = 0;
1575
1576 fd_set aread; 1769 fd_set aread;
1577 fd_set awrite; 1770 fd_set awrite;
1578 fd_set aexcept; 1771 fd_set aexcept;
1579 1772
1580#if DEBUG_NETWORK 1773 nfds = 0;
1581 fd_set bread; 1774 handles = 0;
1582 fd_set bwrite;
1583 fd_set bexcept;
1584#endif
1585
1586 /* TODO: Make this growable */
1587 struct GNUNET_DISK_FileHandle *readArray[50];
1588 struct timeval tv;
1589
1590 if (NULL != rfds) 1775 if (NULL != rfds)
1591 { 1776 {
1592 nfds = rfds->nsds; 1777 nfds = GNUNET_MAX (nfds, rfds->nsds);
1593 handles += read_handles = GNUNET_CONTAINER_slist_count (rfds->handles); 1778 handles += rfds->handles_pos;
1594#if DEBUG_NETWORK
1595 {
1596 struct GNUNET_CONTAINER_SList_Iterator t;
1597
1598 for (t = GNUNET_CONTAINER_slist_begin (rfds->handles);
1599 GNUNET_CONTAINER_slist_end (&t) != GNUNET_YES;
1600 GNUNET_CONTAINER_slist_next (&t))
1601 {
1602 struct GNUNET_DISK_FileHandle *fh;
1603
1604 fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (&t,
1605 NULL);
1606 LOG (GNUNET_ERROR_TYPE_DEBUG, "FD 0x%x (0x%x) is SET in rfds\n", fh->h,
1607 fh);
1608 }
1609 }
1610#endif
1611 } 1779 }
1612 if (NULL != wfds) 1780 if (NULL != wfds)
1613 { 1781 {
1614 nfds = GNUNET_MAX (nfds, wfds->nsds); 1782 nfds = GNUNET_MAX (nfds, wfds->nsds);
1615 handles += write_handles = GNUNET_CONTAINER_slist_count (wfds->handles); 1783 handles += wfds->handles_pos;
1616 } 1784 }
1617 if (NULL != efds) 1785 if (NULL != efds)
1618 { 1786 {
1619 nfds = GNUNET_MAX (nfds, efds->nsds); 1787 nfds = GNUNET_MAX (nfds, efds->nsds);
1620 handles += ex_handles = GNUNET_CONTAINER_slist_count (efds->handles); 1788 handles += efds->handles_pos;
1621 } 1789 }
1622 1790
1623 if ((nfds == 0) && 1791 if ((0 == nfds) &&
1624 (timeout.rel_value_us == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us) 1792 (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us == timeout.rel_value_us) &&
1625 && (handles == 0) ) 1793 (0 == handles) )
1626 { 1794 {
1627 GNUNET_break (0); 1795 GNUNET_break (0);
1628 LOG (GNUNET_ERROR_TYPE_ERROR, 1796 LOG (GNUNET_ERROR_TYPE_ERROR,
@@ -1644,97 +1812,28 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds,
1644 ms_rounded = 1; 1812 ms_rounded = 1;
1645 } 1813 }
1646 /* select() may be used as a portable way to sleep */ 1814 /* select() may be used as a portable way to sleep */
1647 if (!(rfds || wfds || efds)) 1815 if (! (rfds || wfds || efds))
1648 { 1816 {
1649 Sleep (ms_rounded); 1817 Sleep (ms_rounded);
1650 return 0; 1818 return 0;
1651 } 1819 }
1652 1820
1653 if (NULL == select_thread) 1821 if (NULL == select_thread)
1654 { 1822 initialize_select_thread ();
1655 SOCKET select_listening_socket = -1;
1656 struct sockaddr_in s_in;
1657 int alen;
1658 int res;
1659 unsigned long p;
1660
1661 select_standby_event = CreateEvent (NULL, TRUE, FALSE, NULL);
1662 select_finished_event = CreateEvent (NULL, TRUE, FALSE, NULL);
1663
1664 select_wakeup_socket = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
1665
1666 select_listening_socket = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
1667
1668 p = 1;
1669 res = ioctlsocket (select_wakeup_socket, FIONBIO, &p);
1670 LOG (GNUNET_ERROR_TYPE_DEBUG, "Select thread initialization: ioctlsocket() returns %d\n", res);
1671
1672 alen = sizeof (s_in);
1673 s_in.sin_family = AF_INET;
1674 s_in.sin_port = 0;
1675 s_in.sin_addr.S_un.S_un_b.s_b1 = 127;
1676 s_in.sin_addr.S_un.S_un_b.s_b2 = 0;
1677 s_in.sin_addr.S_un.S_un_b.s_b3 = 0;
1678 s_in.sin_addr.S_un.S_un_b.s_b4 = 1;
1679 res = bind (select_listening_socket, (const struct sockaddr *) &s_in, sizeof (s_in));
1680 LOG (GNUNET_ERROR_TYPE_DEBUG, "Select thread initialization: bind() returns %d\n", res);
1681
1682 res = getsockname (select_listening_socket, (struct sockaddr *) &s_in, &alen);
1683 LOG (GNUNET_ERROR_TYPE_DEBUG, "Select thread initialization: getsockname() returns %d\n", res);
1684
1685 res = listen (select_listening_socket, SOMAXCONN);
1686 LOG (GNUNET_ERROR_TYPE_DEBUG, "Select thread initialization: listen() returns %d\n", res);
1687 1823
1688 res = connect (select_wakeup_socket, (const struct sockaddr *) &s_in, sizeof (s_in));
1689 LOG (GNUNET_ERROR_TYPE_DEBUG, "Select thread initialization: connect() returns %d\n", res);
1690
1691 select_send_socket = accept (select_listening_socket, (struct sockaddr *) &s_in, &alen);
1692
1693 closesocket (select_listening_socket);
1694
1695 sp.wakeup = select_finished_event;
1696 sp.standby = select_standby_event;
1697 sp.wakeup_socket = select_wakeup_socket;
1698
1699 select_thread = CreateThread (NULL, 0, _selector, &sp, 0, NULL);
1700 }
1701
1702
1703 handles_read = GNUNET_CONTAINER_slist_create ();
1704 handles_write = GNUNET_CONTAINER_slist_create ();
1705 handles_except = GNUNET_CONTAINER_slist_create ();
1706 FD_ZERO (&aread); 1824 FD_ZERO (&aread);
1707 FD_ZERO (&awrite); 1825 FD_ZERO (&awrite);
1708 FD_ZERO (&aexcept); 1826 FD_ZERO (&aexcept);
1709#if DEBUG_NETWORK
1710 FD_ZERO (&bread);
1711 FD_ZERO (&bwrite);
1712 FD_ZERO (&bexcept);
1713#endif
1714 if (rfds) 1827 if (rfds)
1715 {
1716 FD_COPY (&rfds->sds, &aread); 1828 FD_COPY (&rfds->sds, &aread);
1717#if DEBUG_NETWORK
1718 FD_COPY (&rfds->sds, &bread);
1719#endif
1720 }
1721 if (wfds) 1829 if (wfds)
1722 {
1723 FD_COPY (&wfds->sds, &awrite); 1830 FD_COPY (&wfds->sds, &awrite);
1724#if DEBUG_NETWORK
1725 FD_COPY (&wfds->sds, &bwrite);
1726#endif
1727 }
1728 if (efds) 1831 if (efds)
1729 {
1730 FD_COPY (&efds->sds, &aexcept); 1832 FD_COPY (&efds->sds, &aexcept);
1731#if DEBUG_NETWORK
1732 FD_COPY (&efds->sds, &bexcept);
1733#endif
1734 }
1735 1833
1736 /* Start by doing a fast check on sockets and pipes (without waiting). It is cheap, and is sufficient most of the time. 1834 /* Start by doing a fast check on sockets and pipes (without
1737 By profiling we detected that to be true in 90% of the cases. 1835 waiting). It is cheap, and is sufficient most of the time. By
1836 profiling we detected that to be true in 90% of the cases.
1738 */ 1837 */
1739 1838
1740 /* Do the select now */ 1839 /* Do the select now */
@@ -1743,141 +1842,81 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds,
1743 1842
1744 /* Copy all the writes to the except, so we can detect connect() errors */ 1843 /* Copy all the writes to the except, so we can detect connect() errors */
1745 for (i = 0; i < awrite.fd_count; i++) 1844 for (i = 0; i < awrite.fd_count; i++)
1746 FD_SET (awrite.fd_array[i], &aexcept); 1845 FD_SET (awrite.fd_array[i],
1747 if (aread.fd_count > 0 || awrite.fd_count > 0 || aexcept.fd_count > 0) 1846 &aexcept);
1748 selectret = select (1, (rfds != NULL) ? &aread : NULL, 1847 if ( (aread.fd_count > 0) ||
1749 (wfds != NULL) ? &awrite : NULL, &aexcept, &select_timeout); 1848 (awrite.fd_count > 0) ||
1849 (aexcept.fd_count > 0) )
1850 selectret = select (1,
1851 (NULL != rfds) ? &aread : NULL,
1852 (NULL != wfds) ? &awrite : NULL,
1853 &aexcept,
1854 &select_timeout);
1750 else 1855 else
1751 selectret = 0; 1856 selectret = 0;
1752 if (selectret == -1) 1857 if (-1 == selectret)
1753 { 1858 {
1754 /* Throw an error early on, while we still have the context. */ 1859 /* Throw an error early on, while we still have the context. */
1755 LOG (GNUNET_ERROR_TYPE_ERROR, "W32 select(%d, %d, %d) failed: %lu\n", 1860 LOG (GNUNET_ERROR_TYPE_ERROR,
1756 rfds ? aread.fd_count : 0, wfds ? awrite.fd_count : 0, aexcept.fd_count, GetLastError ()); 1861 "W32 select(%d, %d, %d) failed: %lu\n",
1862 rfds ? aread.fd_count : 0,
1863 wfds ? awrite.fd_count : 0,
1864 aexcept.fd_count,
1865 GetLastError ());
1757 GNUNET_abort (); 1866 GNUNET_abort ();
1758 } 1867 }
1759 1868
1760 /* Check aexcept, add its contents to awrite 1869 /* Check aexcept, if something is in there and we copied that
1761 This is technically wrong (aexcept might have its own descriptors), we should 1870 FD before to detect connect() errors, add it back to the
1762 have checked that descriptors were in awrite originally before re-adding them from 1871 write set to report errors. */
1763 aexcept. Luckily, GNUnet never uses aexcept for anything, so this does not become a problem (yet). */ 1872 if (NULL != wfds)
1764 for (i = 0; i < aexcept.fd_count; i++) 1873 for (i = 0; i < aexcept.fd_count; i++)
1765 FD_SET (aexcept.fd_array[i], &awrite); 1874 if (FD_ISSET (aexcept.fd_array[i],
1875 &wfds->sds))
1876 FD_SET (aexcept.fd_array[i],
1877 &awrite);
1878
1766 1879
1767 /* If our select returned something or is a 0-timed request, then also check the pipes and get out of here! */ 1880 /* If our select returned something or is a 0-timed request, then
1881 also check the pipes and get out of here! */
1768 /* Sadly, it means code duplication :( */ 1882 /* Sadly, it means code duplication :( */
1769 if ((selectret > 0) || (mcs_total == 0)) 1883 if ( (selectret > 0) || (0 == mcs_total) )
1770 { 1884 {
1771 /* Read Pipes */ 1885 retcode = 0;
1772 if (rfds && read_handles)
1773 {
1774 struct GNUNET_CONTAINER_SList_Iterator i;
1775 int c;
1776
1777 for (c = 0, i = GNUNET_CONTAINER_slist_begin (rfds->handles);
1778 GNUNET_CONTAINER_slist_end (&i) != GNUNET_YES;
1779 GNUNET_CONTAINER_slist_next (&i), c++)
1780 {
1781 struct GNUNET_DISK_FileHandle *fh;
1782
1783 fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (&i,NULL);
1784 if (fh->type == GNUNET_DISK_HANLDE_TYPE_PIPE)
1785 {
1786 DWORD error;
1787 BOOL bret;
1788
1789 SetLastError (0);
1790 DWORD waitstatus = 0;
1791 bret = PeekNamedPipe (fh->h, NULL, 0, NULL, &waitstatus, NULL);
1792 error = GetLastError ();
1793 LOG (GNUNET_ERROR_TYPE_DEBUG, "Peek at read pipe %d (0x%x) returned %d (%d bytes available) GLE %u\n",
1794 c, fh->h, bret, waitstatus, error);
1795 if (bret == 0)
1796 {
1797 /* TODO: either add more errors to this condition, or eliminate it
1798 * entirely (failed to peek -> pipe is in serious trouble, should
1799 * be selected as readable).
1800 */
1801 if (error != ERROR_BROKEN_PIPE && error != ERROR_INVALID_HANDLE)
1802 continue;
1803 }
1804 else if (waitstatus <= 0)
1805 continue;
1806 GNUNET_CONTAINER_slist_add (handles_read, GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT,
1807 fh, sizeof (struct GNUNET_DISK_FileHandle));
1808 retcode++;
1809 LOG (GNUNET_ERROR_TYPE_DEBUG, "Added read Pipe 0x%x (0x%x)\n",
1810 fh, fh->h);
1811 }
1812 else
1813 {
1814 GNUNET_CONTAINER_slist_add (handles_read, GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT,
1815 fh, sizeof (struct GNUNET_DISK_FileHandle));
1816 retcode++;
1817 }
1818 }
1819 }
1820 if (wfds && write_handles)
1821 {
1822 LOG (GNUNET_ERROR_TYPE_DEBUG,
1823 "Adding the write ready event to the array as %d\n", nhandles);
1824 GNUNET_CONTAINER_slist_append (handles_write, wfds->handles);
1825 retcode += write_handles;
1826 }
1827 if (efds && ex_handles)
1828 {
1829 struct GNUNET_CONTAINER_SList_Iterator i;
1830 1886
1831 for (i = GNUNET_CONTAINER_slist_begin (efds->handles); 1887 /* Read Pipes */
1832 GNUNET_CONTAINER_slist_end (&i) != GNUNET_YES; 1888 if (rfds && (rfds->handles_pos > 0))
1833 GNUNET_CONTAINER_slist_next (&i)) 1889 retcode += check_handles_status (rfds, GNUNET_NO);
1834 {
1835 struct GNUNET_DISK_FileHandle *fh;
1836 DWORD dwBytes;
1837 1890
1838 fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (&i, NULL); 1891 /* wfds handles remain untouched, on W32
1839 if (fh->type == GNUNET_DISK_HANLDE_TYPE_PIPE) 1892 we pretend our pipes are "always" write-ready */
1840 {
1841 if (PeekNamedPipe (fh->h, NULL, 0, NULL, &dwBytes, NULL))
1842 continue;
1843 GNUNET_CONTAINER_slist_add (handles_except, GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT,
1844 fh, sizeof (struct GNUNET_DISK_FileHandle));
1845 retcode++;
1846 }
1847 }
1848 }
1849 1893
1850 /* Add our select() result.*/ 1894 /* except pipes */
1851 if (selectret >= 0) 1895 if (efds && (efds->handles_pos > 0))
1852 retcode += selectret; 1896 retcode += check_handles_status (efds, GNUNET_YES);
1853 1897
1854 if (rfds) 1898 if (rfds)
1855 { 1899 {
1856 GNUNET_NETWORK_fdset_zero (rfds); 1900 GNUNET_NETWORK_fdset_zero (rfds);
1857 if (selectret != -1) 1901 if (selectret != -1)
1858 GNUNET_NETWORK_fdset_copy_native (rfds, &aread, selectret); 1902 GNUNET_NETWORK_fdset_copy_native (rfds, &aread, selectret);
1859 GNUNET_CONTAINER_slist_append (rfds->handles, handles_read);
1860 } 1903 }
1861 if (wfds) 1904 if (wfds)
1862 { 1905 {
1863 GNUNET_NETWORK_fdset_zero (wfds); 1906 GNUNET_NETWORK_fdset_zero (wfds);
1864 if (selectret != -1) 1907 if (selectret != -1)
1865 GNUNET_NETWORK_fdset_copy_native (wfds, &awrite, selectret); 1908 GNUNET_NETWORK_fdset_copy_native (wfds, &awrite, selectret);
1866 GNUNET_CONTAINER_slist_append (wfds->handles, handles_write);
1867 } 1909 }
1868 if (efds) 1910 if (efds)
1869 { 1911 {
1870 GNUNET_NETWORK_fdset_zero (efds); 1912 GNUNET_NETWORK_fdset_zero (efds);
1871 if (selectret != -1) 1913 if (selectret != -1)
1872 GNUNET_NETWORK_fdset_copy_native (efds, &aexcept, selectret); 1914 GNUNET_NETWORK_fdset_copy_native (efds, &aexcept, selectret);
1873 GNUNET_CONTAINER_slist_append (efds->handles, handles_except);
1874 } 1915 }
1875 GNUNET_CONTAINER_slist_destroy (handles_read); 1916 if (-1 == selectret)
1876 GNUNET_CONTAINER_slist_destroy (handles_write);
1877 GNUNET_CONTAINER_slist_destroy (handles_except);
1878
1879 if (selectret == -1)
1880 return -1; 1917 return -1;
1918 /* Add our select() FDs to the total return value */
1919 retcode += selectret;
1881 return retcode; 1920 return retcode;
1882 } 1921 }
1883 1922
@@ -1885,134 +1924,69 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds,
1885 on both sockets and pipes simultaneously */ 1924 on both sockets and pipes simultaneously */
1886 1925
1887 /* Events for pipes */ 1926 /* Events for pipes */
1888 if (!hEventReadReady) 1927 if (! hEventReadReady)
1889 hEventReadReady = CreateEvent (NULL, TRUE, TRUE, NULL); 1928 hEventReadReady = CreateEvent (NULL, TRUE, TRUE, NULL);
1890 if (!hEventPipeWrite) 1929 if (! hEventPipeWrite)
1891 hEventPipeWrite = CreateEvent (NULL, TRUE, TRUE, NULL); 1930 hEventPipeWrite = CreateEvent (NULL, TRUE, TRUE, NULL);
1892 readPipes = 0;
1893 writePipePos = -1;
1894
1895 retcode = 0; 1931 retcode = 0;
1896 1932
1897 FD_ZERO (&aread); 1933 FD_ZERO (&aread);
1898 FD_ZERO (&awrite); 1934 FD_ZERO (&awrite);
1899 FD_ZERO (&aexcept); 1935 FD_ZERO (&aexcept);
1900#if DEBUG_NETWORK
1901 FD_ZERO (&bread);
1902 FD_ZERO (&bwrite);
1903 FD_ZERO (&bexcept);
1904#endif
1905 if (rfds) 1936 if (rfds)
1906 {
1907 FD_COPY (&rfds->sds, &aread); 1937 FD_COPY (&rfds->sds, &aread);
1908#if DEBUG_NETWORK
1909 FD_COPY (&rfds->sds, &bread);
1910#endif
1911 }
1912 if (wfds) 1938 if (wfds)
1913 {
1914 FD_COPY (&wfds->sds, &awrite); 1939 FD_COPY (&wfds->sds, &awrite);
1915#if DEBUG_NETWORK
1916 FD_COPY (&wfds->sds, &bwrite);
1917#endif
1918 }
1919 if (efds) 1940 if (efds)
1920 {
1921 FD_COPY (&efds->sds, &aexcept); 1941 FD_COPY (&efds->sds, &aexcept);
1922#if DEBUG_NETWORK
1923 FD_COPY (&efds->sds, &bexcept);
1924#endif
1925 }
1926 /* We will first Add the PIPES to the events */ 1942 /* We will first Add the PIPES to the events */
1927 /* Read Pipes */ 1943 /* Track how far in `handle_array` the read pipes go,
1928 if (rfds && read_handles) 1944 so we may by-pass them quickly if none of them
1945 are selected. */
1946 read_pipes_off = 0;
1947 if (rfds && (rfds->handles_pos > 0))
1929 { 1948 {
1930 struct GNUNET_CONTAINER_SList_Iterator i; 1949 for (i = 0; i <rfds->handles_pos; i++)
1931
1932 for (i = GNUNET_CONTAINER_slist_begin (rfds->handles);
1933 GNUNET_CONTAINER_slist_end (&i) != GNUNET_YES;
1934 GNUNET_CONTAINER_slist_next (&i))
1935 { 1950 {
1936 struct GNUNET_DISK_FileHandle *fh; 1951 fh = rfds->handles[i];
1937 1952 if (fh->type != GNUNET_DISK_HANLDE_TYPE_PIPE)
1938 fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (&i, 1953 continue;
1939 NULL); 1954 /* Read zero bytes to check the status of the pipe */
1940 if (fh->type == GNUNET_DISK_HANLDE_TYPE_PIPE) 1955 if (! ReadFile (fh->h, NULL, 0, NULL, fh->oOverlapRead))
1941 { 1956 {
1942 /* Read zero bytes to check the status of the pipe */ 1957 DWORD error_code = GetLastError ();
1943 LOG (GNUNET_ERROR_TYPE_DEBUG, "Reading 0 bytes from the pipe 0x%x\n", 1958
1944 fh->h); 1959 if (error_code == ERROR_IO_PENDING)
1945 if (!ReadFile (fh->h, NULL, 0, NULL, fh->oOverlapRead))
1946 { 1960 {
1947 DWORD error_code = GetLastError (); 1961 /* add as unready */
1948 1962 handle_array[nhandles++] = fh->oOverlapRead->hEvent;
1949 if (error_code == ERROR_IO_PENDING) 1963 read_pipes_off++;
1950 {
1951 LOG (GNUNET_ERROR_TYPE_DEBUG,
1952 "Adding the pipe's 0x%x overlapped event to the array as %d\n",
1953 fh->h, nhandles);
1954 handle_array[nhandles++] = fh->oOverlapRead->hEvent;
1955 readArray[readPipes++] = fh;
1956 }
1957 else
1958 {
1959 LOG (GNUNET_ERROR_TYPE_DEBUG,
1960 "Read failed, adding the read ready event to the array as %d\n", nhandles);
1961 handle_array[nhandles++] = hEventReadReady;
1962 readArray[readPipes++] = fh;
1963 }
1964 } 1964 }
1965 else 1965 else
1966 { 1966 {
1967 LOG (GNUNET_ERROR_TYPE_DEBUG, 1967 /* add as ready */
1968 "Adding the read ready event to the array as %d\n", nhandles);
1969 handle_array[nhandles++] = hEventReadReady; 1968 handle_array[nhandles++] = hEventReadReady;
1970 readArray[readPipes++] = fh; 1969 read_pipes_off++;
1971 } 1970 }
1972 } 1971 }
1973 else 1972 else
1974 { 1973 {
1975 GNUNET_CONTAINER_slist_add (handles_read, 1974 /* error also counts as ready */
1976 GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT, 1975 handle_array[nhandles++] = hEventReadReady;
1977 fh, sizeof (struct GNUNET_DISK_FileHandle)); 1976 read_pipes_off++;
1978 } 1977 }
1979 } 1978 }
1980 } 1979 }
1981 if (wfds && write_handles) 1980
1981 if (wfds && (wfds->handles_pos > 0))
1982 { 1982 {
1983 LOG (GNUNET_ERROR_TYPE_DEBUG, 1983 LOG (GNUNET_ERROR_TYPE_DEBUG,
1984 "Adding the write ready event to the array as %d\n", nhandles); 1984 "Adding the write ready event to the array as %d\n",
1985 nhandles);
1985 handle_array[nhandles++] = hEventPipeWrite; 1986 handle_array[nhandles++] = hEventPipeWrite;
1986 writePipePos = nhandles;
1987 }
1988 if (efds && ex_handles)
1989 {
1990 struct GNUNET_CONTAINER_SList_Iterator i;
1991
1992 for (i = GNUNET_CONTAINER_slist_begin (efds->handles);
1993 GNUNET_CONTAINER_slist_end (&i) != GNUNET_YES;
1994 GNUNET_CONTAINER_slist_next (&i))
1995 {
1996 struct GNUNET_DISK_FileHandle *fh;
1997 DWORD dwBytes;
1998
1999 fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (&i,
2000 NULL);
2001 if (fh->type == GNUNET_DISK_HANLDE_TYPE_PIPE)
2002 {
2003 if (!PeekNamedPipe (fh->h, NULL, 0, NULL, &dwBytes, NULL))
2004 {
2005 GNUNET_CONTAINER_slist_add (handles_except,
2006 GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT,
2007 fh,
2008 sizeof (struct GNUNET_DISK_FileHandle));
2009 }
2010 }
2011 }
2012 } 1987 }
2013 1988
2014 sp.status = 0; 1989 sp.status = 0;
2015
2016 if (nfds > 0) 1990 if (nfds > 0)
2017 { 1991 {
2018 LOG (GNUNET_ERROR_TYPE_DEBUG, 1992 LOG (GNUNET_ERROR_TYPE_DEBUG,
@@ -2122,147 +2096,48 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds,
2122 "return pos is: %d\n", 2096 "return pos is: %d\n",
2123 returnedpos); 2097 returnedpos);
2124 2098
2125 if (nhandles && (returnedpos < nhandles))
2126 {
2127 DWORD waitstatus;
2128
2129 if (sp.status > 0)
2130 retcode += sp.status;
2131
2132 if ((writePipePos != -1) && (returnedpos < writePipePos))
2133 {
2134 GNUNET_CONTAINER_slist_append (handles_write, wfds->handles);
2135 retcode += write_handles;
2136 LOG (GNUNET_ERROR_TYPE_DEBUG,
2137 "Added write pipe\n");
2138 }
2139 LOG (GNUNET_ERROR_TYPE_DEBUG,
2140 "ReadPipes is: %d\n",
2141 readPipes);
2142 /* We have some pipes ready for read. */
2143 if (returnedpos < readPipes)
2144 {
2145 for (i = 0; i < readPipes; i++)
2146 {
2147 DWORD error;
2148 BOOL bret;
2149
2150 SetLastError (0);
2151 waitstatus = 0;
2152 bret =
2153 PeekNamedPipe (readArray[i]->h, NULL, 0, NULL, &waitstatus, NULL);
2154 error = GetLastError ();
2155 LOG (GNUNET_ERROR_TYPE_DEBUG,
2156 "Peek at read pipe %d (0x%x) returned %d (%d bytes available) GLE %u\n",
2157 i, readArray[i]->h, bret, waitstatus, error);
2158 if (bret == 0)
2159 {
2160 /* TODO: either add more errors to this condition, or eliminate it
2161 * entirely (failed to peek -> pipe is in serious trouble, should
2162 * be selected as readable).
2163 */
2164 if (error != ERROR_BROKEN_PIPE && error != ERROR_INVALID_HANDLE)
2165 continue;
2166 }
2167 else if (waitstatus <= 0)
2168 continue;
2169 GNUNET_CONTAINER_slist_add (handles_read,
2170 GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT,
2171 readArray[i],
2172 sizeof (struct GNUNET_DISK_FileHandle));
2173 retcode++;
2174 LOG (GNUNET_ERROR_TYPE_DEBUG, "Added read Pipe 0x%x (0x%x)\n",
2175 readArray[i], readArray[i]->h);
2176 }
2177 }
2178 }
2179 if (! nhandles || (returnedpos >= nhandles))
2180 LOG (GNUNET_ERROR_TYPE_DEBUG,
2181 "Returning from _select() with nothing!\n");
2182 if (rfds) 2099 if (rfds)
2183 { 2100 {
2184 struct GNUNET_CONTAINER_SList_Iterator t; 2101 /* We queued a zero-long read on each pipe to check
2185 2102 * its state, now we must cancel these read operations.
2186 for (t = GNUNET_CONTAINER_slist_begin (rfds->handles); 2103 * This must be done while rfds->handles_pos is still
2187 GNUNET_CONTAINER_slist_end (&t) != GNUNET_YES; 2104 * intact and matches the number of read handles that we
2188 GNUNET_CONTAINER_slist_next (&t)) 2105 * got from the caller.
2106 */
2107 for (i = 0; i < rfds->handles_pos; i++)
2189 { 2108 {
2190 struct GNUNET_DISK_FileHandle *fh; 2109 fh = rfds->handles[i];
2191 2110 if (GNUNET_DISK_HANLDE_TYPE_PIPE == fh->type)
2192 fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (&t,
2193 NULL);
2194 if (fh->type == GNUNET_DISK_HANLDE_TYPE_PIPE)
2195 {
2196 CancelIo (fh->h); 2111 CancelIo (fh->h);
2197 }
2198 } 2112 }
2199 LOG (GNUNET_ERROR_TYPE_DEBUG, "Zeroing rfds%s\n", (retcode != -1 && nhandles && (returnedpos < nhandles)) ? ", copying fdset" : ""); 2113
2200 GNUNET_NETWORK_fdset_zero (rfds); 2114 /* We may have some pipes ready for reading. */
2201 if (retcode != -1 && nhandles && (returnedpos < nhandles)) 2115 if (returnedpos < read_pipes_off)
2116 retcode += check_handles_status (rfds, GNUNET_NO);
2117 else
2118 rfds->handles_pos = 0;
2119
2120 if (-1 != sp.status)
2202 GNUNET_NETWORK_fdset_copy_native (rfds, &aread, retcode); 2121 GNUNET_NETWORK_fdset_copy_native (rfds, &aread, retcode);
2203 GNUNET_CONTAINER_slist_append (rfds->handles, handles_read);
2204 } 2122 }
2205 if (wfds) 2123 if (wfds)
2206 { 2124 {
2207 LOG (GNUNET_ERROR_TYPE_DEBUG, "Zeroing wfds%s\n", (retcode != -1 && nhandles && (returnedpos < nhandles)) ? ", copying fdset" : ""); 2125 retcode += wfds->handles_pos;
2208 GNUNET_NETWORK_fdset_zero (wfds); 2126 /* wfds handles remain untouched */
2209 if (retcode != -1 && nhandles && (returnedpos < nhandles)) 2127 if (-1 != sp.status)
2210 GNUNET_NETWORK_fdset_copy_native (wfds, &awrite, retcode); 2128 GNUNET_NETWORK_fdset_copy_native (wfds, &awrite, retcode);
2211 GNUNET_CONTAINER_slist_append (wfds->handles, handles_write);
2212 } 2129 }
2213 if (efds) 2130 if (efds)
2214 { 2131 {
2215 LOG (GNUNET_ERROR_TYPE_DEBUG, "Zeroing efds%s\n", (retcode != -1 && nhandles && (returnedpos < nhandles)) ? ", copying fdset" : ""); 2132 retcode += check_handles_status (rfds, GNUNET_YES);
2216 GNUNET_NETWORK_fdset_zero (efds); 2133 if (-1 != sp.status)
2217 if (retcode != -1 && nhandles && (returnedpos < nhandles))
2218 GNUNET_NETWORK_fdset_copy_native (efds, &aexcept, retcode); 2134 GNUNET_NETWORK_fdset_copy_native (efds, &aexcept, retcode);
2219 GNUNET_CONTAINER_slist_append (efds->handles, handles_except);
2220 } 2135 }
2221 GNUNET_CONTAINER_slist_destroy (handles_read);
2222 GNUNET_CONTAINER_slist_destroy (handles_write);
2223 GNUNET_CONTAINER_slist_destroy (handles_except);
2224#if DEBUG_NETWORK
2225 if (rfds)
2226 {
2227 struct GNUNET_CONTAINER_SList_Iterator t;
2228 2136
2229 LOG (GNUNET_ERROR_TYPE_DEBUG, "rfds:\n"); 2137 if (sp.status > 0)
2230 for (i = 0; i < rfds->sds.fd_count; i++) 2138 retcode += sp.status;
2231 {
2232 LOG (GNUNET_ERROR_TYPE_DEBUG, "%d\n", rfds->sds.fd_array[i]);
2233 }
2234 for (t = GNUNET_CONTAINER_slist_begin (rfds->handles);
2235 GNUNET_CONTAINER_slist_end (&t) != GNUNET_YES;
2236 GNUNET_CONTAINER_slist_next (&t))
2237 {
2238 struct GNUNET_DISK_FileHandle *fh;
2239 2139
2240 fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (&t, 2140 return retcode;
2241 NULL);
2242 LOG (GNUNET_ERROR_TYPE_DEBUG, "%d\n", fh->h);
2243 }
2244 }
2245 if (wfds)
2246 {
2247 LOG (GNUNET_ERROR_TYPE_DEBUG, "wfds:\n");
2248 for (i = 0; i < wfds->sds.fd_count; i++)
2249 {
2250 LOG (GNUNET_ERROR_TYPE_DEBUG, "%d\n", wfds->sds.fd_array[i]);
2251 }
2252 }
2253 if (efds)
2254 {
2255 LOG (GNUNET_ERROR_TYPE_DEBUG, "efds:\n");
2256 for (i = 0; i < efds->sds.fd_count; i++)
2257 {
2258 LOG (GNUNET_ERROR_TYPE_DEBUG, "%d\n", efds->sds.fd_array[i]);
2259 }
2260 }
2261 LOG (GNUNET_ERROR_TYPE_DEBUG, "Returning %d or 0\n", retcode);
2262#endif
2263 if (nhandles && (returnedpos < nhandles))
2264 return retcode;
2265 return 0;
2266} 2141}
2267 2142
2268/* MINGW */ 2143/* MINGW */