aboutsummaryrefslogtreecommitdiff
path: root/src/util/network.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/util/network.c')
-rw-r--r--src/util/network.c866
1 files changed, 2 insertions, 864 deletions
diff --git a/src/util/network.c b/src/util/network.c
index ec76424eb..6f8a8ff5a 100644
--- a/src/util/network.c
+++ b/src/util/network.c
@@ -759,10 +759,6 @@ GNUNET_NETWORK_socket_recvfrom(const struct GNUNET_NETWORK_Handle *desc,
759 flags, 759 flags,
760 src_addr, 760 src_addr,
761 addrlen); 761 addrlen);
762#ifdef MINGW
763 if (SOCKET_ERROR == ret)
764 SetErrnoFromWinsockError(WSAGetLastError());
765#endif
766 return ret; 762 return ret;
767} 763}
768 764
@@ -792,10 +788,6 @@ GNUNET_NETWORK_socket_recv(const struct GNUNET_NETWORK_Handle *desc,
792 buffer, 788 buffer,
793 length, 789 length,
794 flags); 790 flags);
795#ifdef MINGW
796 if (SOCKET_ERROR == ret)
797 SetErrnoFromWinsockError(WSAGetLastError());
798#endif
799 return ret; 791 return ret;
800} 792}
801 793
@@ -827,10 +819,6 @@ GNUNET_NETWORK_socket_send(const struct GNUNET_NETWORK_Handle *desc,
827 buffer, 819 buffer,
828 length, 820 length,
829 flags); 821 flags);
830#ifdef MINGW
831 if (SOCKET_ERROR == ret)
832 SetErrnoFromWinsockError(WSAGetLastError());
833#endif
834 return ret; 822 return ret;
835} 823}
836 824
@@ -865,10 +853,6 @@ GNUNET_NETWORK_socket_sendto(const struct GNUNET_NETWORK_Handle *desc,
865 flags |= MSG_NOSIGNAL; 853 flags |= MSG_NOSIGNAL;
866#endif 854#endif
867 ret = sendto(desc->fd, message, length, flags, dest_addr, dest_len); 855 ret = sendto(desc->fd, message, length, flags, dest_addr, dest_len);
868#ifdef MINGW
869 if (SOCKET_ERROR == ret)
870 SetErrnoFromWinsockError(WSAGetLastError());
871#endif
872 return ret; 856 return ret;
873} 857}
874 858
@@ -897,10 +881,7 @@ GNUNET_NETWORK_socket_setsockopt(struct GNUNET_NETWORK_Handle *fd,
897 option_name, 881 option_name,
898 option_value, 882 option_value,
899 option_len); 883 option_len);
900#ifdef MINGW 884
901 if (SOCKET_ERROR == ret)
902 SetErrnoFromWinsockError(WSAGetLastError());
903#endif
904 return ret == 0 ? GNUNET_OK : GNUNET_SYSERR; 885 return ret == 0 ? GNUNET_OK : GNUNET_SYSERR;
905} 886}
906 887
@@ -950,10 +931,7 @@ GNUNET_NETWORK_socket_shutdown(struct GNUNET_NETWORK_Handle *desc,
950 int ret; 931 int ret;
951 932
952 ret = shutdown(desc->fd, how); 933 ret = shutdown(desc->fd, how);
953#ifdef MINGW 934
954 if (0 != ret)
955 SetErrnoFromWinsockError(WSAGetLastError());
956#endif
957 return (0 == ret) ? GNUNET_OK : GNUNET_SYSERR; 935 return (0 == ret) ? GNUNET_OK : GNUNET_SYSERR;
958} 936}
959 937
@@ -1054,7 +1032,6 @@ void
1054GNUNET_NETWORK_fdset_add(struct GNUNET_NETWORK_FDSet *dst, 1032GNUNET_NETWORK_fdset_add(struct GNUNET_NETWORK_FDSet *dst,
1055 const struct GNUNET_NETWORK_FDSet *src) 1033 const struct GNUNET_NETWORK_FDSet *src)
1056{ 1034{
1057#ifndef MINGW
1058 int nfds; 1035 int nfds;
1059 1036
1060 for (nfds = src->nsds; nfds >= 0; nfds--) 1037 for (nfds = src->nsds; nfds >= 0; nfds--)
@@ -1062,31 +1039,6 @@ GNUNET_NETWORK_fdset_add(struct GNUNET_NETWORK_FDSet *dst,
1062 FD_SET(nfds, &dst->sds); 1039 FD_SET(nfds, &dst->sds);
1063 dst->nsds = GNUNET_MAX(dst->nsds, 1040 dst->nsds = GNUNET_MAX(dst->nsds,
1064 src->nsds); 1041 src->nsds);
1065#else
1066 /* This is MinGW32-specific implementation that relies on the code that
1067 * winsock2.h defines for FD_SET. Namely, it relies on FD_SET checking
1068 * that fd being added is not already in the set.
1069 * Also relies on us knowing what's inside fd_set (fd_count and fd_array).
1070 *
1071 * NOTE: I don't understand why the UNIX-logic wouldn't work
1072 * for the first part here as well. -CG
1073 */
1074 unsigned int i;
1075
1076 for (i = 0; i < src->sds.fd_count; i++)
1077 FD_SET(src->sds.fd_array[i],
1078 &dst->sds);
1079 dst->nsds = GNUNET_MAX(src->nsds,
1080 dst->nsds);
1081
1082 /* also copy over `struct GNUNET_DISK_FileHandle` array */
1083 if (dst->handles_pos + src->handles_pos > dst->handles_size)
1084 GNUNET_array_grow(dst->handles,
1085 dst->handles_size,
1086 ((dst->handles_pos + src->handles_pos) << 1));
1087 for (i = 0; i < src->handles_pos; i++)
1088 dst->handles[dst->handles_pos++] = src->handles[i];
1089#endif
1090} 1042}
1091 1043
1092 1044
@@ -1103,16 +1055,6 @@ GNUNET_NETWORK_fdset_copy(struct GNUNET_NETWORK_FDSet *to,
1103 FD_COPY(&from->sds, 1055 FD_COPY(&from->sds,
1104 &to->sds); 1056 &to->sds);
1105 to->nsds = from->nsds; 1057 to->nsds = from->nsds;
1106#ifdef MINGW
1107 if (from->handles_pos > to->handles_size)
1108 GNUNET_array_grow(to->handles,
1109 to->handles_size,
1110 from->handles_pos * 2);
1111 GNUNET_memcpy(to->handles,
1112 from->handles,
1113 from->handles_pos * sizeof(struct GNUNET_NETWORK_Handle *));
1114 to->handles_pos = from->handles_pos;
1115#endif
1116} 1058}
1117 1059
1118 1060
@@ -1217,13 +1159,6 @@ void
1217GNUNET_NETWORK_fdset_handle_set(struct GNUNET_NETWORK_FDSet *fds, 1159GNUNET_NETWORK_fdset_handle_set(struct GNUNET_NETWORK_FDSet *fds,
1218 const struct GNUNET_DISK_FileHandle *h) 1160 const struct GNUNET_DISK_FileHandle *h)
1219{ 1161{
1220#ifdef MINGW
1221 if (fds->handles_pos == fds->handles_size)
1222 GNUNET_array_grow(fds->handles,
1223 fds->handles_size,
1224 fds->handles_size * 2 + 2);
1225 fds->handles[fds->handles_pos++] = h;
1226#else
1227 int fd; 1162 int fd;
1228 1163
1229 GNUNET_assert(GNUNET_OK == 1164 GNUNET_assert(GNUNET_OK ==
@@ -1234,7 +1169,6 @@ GNUNET_NETWORK_fdset_handle_set(struct GNUNET_NETWORK_FDSet *fds,
1234 &fds->sds); 1169 &fds->sds);
1235 fds->nsds = GNUNET_MAX(fd + 1, 1170 fds->nsds = GNUNET_MAX(fd + 1,
1236 fds->nsds); 1171 fds->nsds);
1237#endif
1238} 1172}
1239 1173
1240 1174
@@ -1247,22 +1181,7 @@ void
1247GNUNET_NETWORK_fdset_handle_set_first(struct GNUNET_NETWORK_FDSet *fds, 1181GNUNET_NETWORK_fdset_handle_set_first(struct GNUNET_NETWORK_FDSet *fds,
1248 const struct GNUNET_DISK_FileHandle *h) 1182 const struct GNUNET_DISK_FileHandle *h)
1249{ 1183{
1250#ifdef MINGW
1251 if (fds->handles_pos == fds->handles_size)
1252 GNUNET_array_grow(fds->handles,
1253 fds->handles_size,
1254 fds->handles_size * 2 + 2);
1255 fds->handles[fds->handles_pos] = h;
1256 if (fds->handles[0] != h)
1257 {
1258 const struct GNUNET_DISK_FileHandle *bak = fds->handles[0];
1259 fds->handles[0] = h;
1260 fds->handles[fds->handles_pos] = bak;
1261 }
1262 fds->handles_pos++;
1263#else
1264 GNUNET_NETWORK_fdset_handle_set(fds, h); 1184 GNUNET_NETWORK_fdset_handle_set(fds, h);
1265#endif
1266} 1185}
1267 1186
1268 1187
@@ -1277,42 +1196,11 @@ int
1277GNUNET_NETWORK_fdset_handle_isset(const struct GNUNET_NETWORK_FDSet *fds, 1196GNUNET_NETWORK_fdset_handle_isset(const struct GNUNET_NETWORK_FDSet *fds,
1278 const struct GNUNET_DISK_FileHandle *h) 1197 const struct GNUNET_DISK_FileHandle *h)
1279{ 1198{
1280#ifdef MINGW
1281 unsigned int i;
1282
1283 for (i = 0; i < fds->handles_pos; i++)
1284 if (fds->handles[i] == h)
1285 return GNUNET_YES;
1286 return GNUNET_NO;
1287#else
1288 return FD_ISSET(h->fd, 1199 return FD_ISSET(h->fd,
1289 &fds->sds); 1200 &fds->sds);
1290#endif
1291} 1201}
1292 1202
1293 1203
1294#ifdef MINGW
1295/**
1296 * Numerically compare pointers to sort them.
1297 * Used to test for overlap in the arrays.
1298 *
1299 * @param p1 a pointer
1300 * @param p2 a pointer
1301 * @return -1, 0 or 1, if the p1 < p2, p1==p2 or p1 > p2.
1302 */
1303static int
1304ptr_cmp(const void *p1,
1305 const void *p2)
1306{
1307 if (p1 == p2)
1308 return 0;
1309 if ((intptr_t)p1 < (intptr_t)p2)
1310 return -1;
1311 return 1;
1312}
1313#endif
1314
1315
1316/** 1204/**
1317 * Checks if two fd sets overlap 1205 * Checks if two fd sets overlap
1318 * 1206 *
@@ -1324,7 +1212,6 @@ int
1324GNUNET_NETWORK_fdset_overlap(const struct GNUNET_NETWORK_FDSet *fds1, 1212GNUNET_NETWORK_fdset_overlap(const struct GNUNET_NETWORK_FDSet *fds1,
1325 const struct GNUNET_NETWORK_FDSet *fds2) 1213 const struct GNUNET_NETWORK_FDSet *fds2)
1326{ 1214{
1327#ifndef MINGW
1328 int nfds; 1215 int nfds;
1329 1216
1330 nfds = GNUNET_MIN(fds1->nsds, 1217 nfds = GNUNET_MIN(fds1->nsds,
@@ -1339,53 +1226,6 @@ GNUNET_NETWORK_fdset_overlap(const struct GNUNET_NETWORK_FDSet *fds1,
1339 return GNUNET_YES; 1226 return GNUNET_YES;
1340 } 1227 }
1341 return GNUNET_NO; 1228 return GNUNET_NO;
1342#else
1343 unsigned int i;
1344 unsigned int j;
1345
1346 /* This code is somewhat hacky, we are not supposed to know what's
1347 * inside of fd_set; also the O(n^2) is really bad... */
1348 for (i = 0; i < fds1->sds.fd_count; i++)
1349 for (j = 0; j < fds2->sds.fd_count; j++)
1350 if (fds1->sds.fd_array[i] == fds2->sds.fd_array[j])
1351 return GNUNET_YES;
1352
1353 /* take a short cut if possible */
1354 if ((0 == fds1->handles_pos) ||
1355 (0 == fds2->handles_pos))
1356 return GNUNET_NO;
1357
1358 /* Sort file handles array to avoid quadratic complexity when
1359 checking for overlap */
1360 qsort(fds1->handles,
1361 fds1->handles_pos,
1362 sizeof(void *),
1363 &ptr_cmp);
1364 qsort(fds2->handles,
1365 fds2->handles_pos,
1366 sizeof(void *),
1367 &ptr_cmp);
1368 i = 0;
1369 j = 0;
1370 while ((i < fds1->handles_pos) &&
1371 (j < fds2->handles_pos))
1372 {
1373 switch (ptr_cmp(fds1->handles[i],
1374 fds2->handles[j]))
1375 {
1376 case -1:
1377 i++;
1378 break;
1379
1380 case 0:
1381 return GNUNET_YES;
1382
1383 case 1:
1384 j++;
1385 }
1386 }
1387 return GNUNET_NO;
1388#endif
1389} 1229}
1390 1230
1391 1231
@@ -1413,192 +1253,10 @@ GNUNET_NETWORK_fdset_create()
1413void 1253void
1414GNUNET_NETWORK_fdset_destroy(struct GNUNET_NETWORK_FDSet *fds) 1254GNUNET_NETWORK_fdset_destroy(struct GNUNET_NETWORK_FDSet *fds)
1415{ 1255{
1416#ifdef MINGW
1417 GNUNET_array_grow(fds->handles,
1418 fds->handles_size,
1419 0);
1420#endif
1421 GNUNET_free(fds); 1256 GNUNET_free(fds);
1422} 1257}
1423 1258
1424 1259
1425#if MINGW
1426/**
1427 * FIXME.
1428 */
1429struct _select_params {
1430 /**
1431 * Read set.
1432 */
1433 fd_set *r;
1434
1435 /**
1436 * Write set.
1437 */
1438 fd_set *w;
1439
1440 /**
1441 * Except set.
1442 */
1443 fd_set *e;
1444
1445 /**
1446 * Timeout for select().
1447 */
1448 struct timeval *tv;
1449
1450 /**
1451 * FIXME.
1452 */
1453 HANDLE wakeup;
1454
1455 /**
1456 * FIXME.
1457 */
1458 HANDLE standby;
1459
1460 /**
1461 * FIXME.
1462 */
1463 _win_socket wakeup_socket;
1464
1465 /**
1466 * Set to return value from select.
1467 */
1468 int status;
1469};
1470
1471
1472/**
1473 * FIXME.
1474 */
1475static DWORD WINAPI
1476_selector(LPVOID p)
1477{
1478 struct _select_params *sp = p;
1479
1480 while (1)
1481 {
1482 WaitForSingleObject(sp->standby,
1483 INFINITE);
1484 ResetEvent(sp->standby);
1485 sp->status = select(1,
1486 sp->r,
1487 sp->w,
1488 sp->e,
1489 sp->tv);
1490 if (FD_ISSET(sp->wakeup_socket,
1491 sp->r))
1492 {
1493 FD_CLR(sp->wakeup_socket,
1494 sp->r);
1495 sp->status -= 1;
1496 }
1497 SetEvent(sp->wakeup);
1498 }
1499 return 0;
1500}
1501
1502
1503static HANDLE hEventPipeWrite;
1504
1505static HANDLE hEventReadReady;
1506
1507static struct _select_params sp;
1508
1509static HANDLE select_thread;
1510
1511static HANDLE select_finished_event;
1512
1513static HANDLE select_standby_event;
1514
1515static _win_socket select_wakeup_socket = -1;
1516
1517static _win_socket select_send_socket = -1;
1518
1519static struct timeval select_timeout;
1520
1521
1522/**
1523 * On W32, we actually use a thread to help with the
1524 * event loop due to W32-API limitations. This function
1525 * initializes that thread.
1526 */
1527static void
1528initialize_select_thread()
1529{
1530 _win_socket select_listening_socket = -1;
1531 struct sockaddr_in s_in;
1532 int alen;
1533 int res;
1534 unsigned long p;
1535
1536 select_standby_event = CreateEvent(NULL, TRUE, FALSE, NULL);
1537 select_finished_event = CreateEvent(NULL, TRUE, FALSE, NULL);
1538
1539 select_wakeup_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
1540
1541 select_listening_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
1542
1543 p = 1;
1544 res = ioctlsocket(select_wakeup_socket, FIONBIO, &p);
1545 LOG(GNUNET_ERROR_TYPE_DEBUG,
1546 "Select thread initialization: ioctlsocket() returns %d\n",
1547 res);
1548
1549 alen = sizeof(s_in);
1550 s_in.sin_family = AF_INET;
1551 s_in.sin_port = 0;
1552 s_in.sin_addr.S_un.S_un_b.s_b1 = 127;
1553 s_in.sin_addr.S_un.S_un_b.s_b2 = 0;
1554 s_in.sin_addr.S_un.S_un_b.s_b3 = 0;
1555 s_in.sin_addr.S_un.S_un_b.s_b4 = 1;
1556 res = bind(select_listening_socket,
1557 (const struct sockaddr *)&s_in,
1558 sizeof(s_in));
1559 LOG(GNUNET_ERROR_TYPE_DEBUG,
1560 "Select thread initialization: bind() returns %d\n",
1561 res);
1562
1563 res = getsockname(select_listening_socket,
1564 (struct sockaddr *)&s_in,
1565 &alen);
1566 LOG(GNUNET_ERROR_TYPE_DEBUG,
1567 "Select thread initialization: getsockname() returns %d\n",
1568 res);
1569
1570 res = listen(select_listening_socket,
1571 SOMAXCONN);
1572 LOG(GNUNET_ERROR_TYPE_DEBUG,
1573 "Select thread initialization: listen() returns %d\n",
1574 res);
1575 res = connect(select_wakeup_socket,
1576 (const struct sockaddr *)&s_in,
1577 sizeof(s_in));
1578 LOG(GNUNET_ERROR_TYPE_DEBUG,
1579 "Select thread initialization: connect() returns %d\n",
1580 res);
1581
1582 select_send_socket = accept(select_listening_socket,
1583 (struct sockaddr *)&s_in,
1584 &alen);
1585
1586 closesocket(select_listening_socket);
1587
1588 sp.wakeup = select_finished_event;
1589 sp.standby = select_standby_event;
1590 sp.wakeup_socket = select_wakeup_socket;
1591
1592 select_thread = CreateThread(NULL,
1593 0,
1594 _selector,
1595 &sp,
1596 0, NULL);
1597}
1598
1599
1600#endif
1601
1602/** 1260/**
1603 * Test if the given @a port is available. 1261 * Test if the given @a port is available.
1604 * 1262 *
@@ -1657,7 +1315,6 @@ GNUNET_NETWORK_test_port_free(int ipproto,
1657} 1315}
1658 1316
1659 1317
1660#ifndef MINGW
1661/** 1318/**
1662 * Check if sockets or pipes meet certain conditions 1319 * Check if sockets or pipes meet certain conditions
1663 * 1320 *
@@ -1714,523 +1371,4 @@ GNUNET_NETWORK_socket_select(struct GNUNET_NETWORK_FDSet *rfds,
1714 GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us) ? NULL : &tv); 1371 GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us) ? NULL : &tv);
1715} 1372}
1716 1373
1717
1718#else
1719/* MINGW */
1720
1721
1722/**
1723 * Non-blocking test if a pipe is ready for reading.
1724 *
1725 * @param fh pipe handle
1726 * @return #GNUNET_YES if the pipe is ready for reading
1727 */
1728static int
1729pipe_read_ready(const struct GNUNET_DISK_FileHandle *fh)
1730{
1731 DWORD error;
1732 BOOL bret;
1733 DWORD waitstatus = 0;
1734
1735 SetLastError(0);
1736 bret = PeekNamedPipe(fh->h, NULL, 0, NULL, &waitstatus, NULL);
1737 error = GetLastError();
1738 if (0 == bret)
1739 {
1740 /* TODO: either add more errors to this condition, or eliminate it
1741 * entirely (failed to peek -> pipe is in serious trouble, should
1742 * be selected as readable).
1743 */
1744 if ((error != ERROR_BROKEN_PIPE) &&
1745 (error != ERROR_INVALID_HANDLE))
1746 return GNUNET_NO;
1747 }
1748 else if (waitstatus <= 0)
1749 return GNUNET_NO;
1750 return GNUNET_YES;
1751}
1752
1753
1754/**
1755 * Non-blocking test if a pipe is having an IO exception.
1756 *
1757 * @param fh pipe handle
1758 * @return #GNUNET_YES if the pipe is having an IO exception.
1759 */
1760static int
1761pipe_except_ready(const struct GNUNET_DISK_FileHandle *fh)
1762{
1763 DWORD dwBytes;
1764
1765 if (PeekNamedPipe(fh->h, NULL, 0, NULL, &dwBytes, NULL))
1766 return GNUNET_NO;
1767 return GNUNET_YES;
1768}
1769
1770
1771/**
1772 * Iterate over handles in fds, destructively rewrite the
1773 * handles array contents of fds so that it starts with the
1774 * handles that are ready, and update handles_pos accordingly.
1775 *
1776 * @param fds set of handles (usually pipes) to be checked for readiness
1777 * @param except GNUNET_NO if fds should be checked for readiness to read,
1778 * GNUNET_YES if fds should be checked for exceptions
1779 * (there is no way to check for write-readiness - pipes are always write-ready)
1780 * @param set_for_sure a HANDLE that is known to be set already,
1781 * because WaitForMultipleObjects() returned its index.
1782 * @return number of ready handles
1783 */
1784static int
1785check_handles_status(struct GNUNET_NETWORK_FDSet *fds,
1786 int except,
1787 HANDLE set_for_sure)
1788{
1789 const struct GNUNET_DISK_FileHandle *fh;
1790 unsigned int roff;
1791 unsigned int woff;
1792
1793 for (woff = 0, roff = 0; roff < fds->handles_pos; roff++)
1794 {
1795 fh = fds->handles[roff];
1796 if (fh == set_for_sure)
1797 {
1798 fds->handles[woff++] = fh;
1799 }
1800 else if (fh->type == GNUNET_DISK_HANLDE_TYPE_PIPE)
1801 {
1802 if ((except && pipe_except_ready(fh)) ||
1803 (!except && pipe_read_ready(fh)))
1804 fds->handles[woff++] = fh;
1805 }
1806 else if (fh->type == GNUNET_DISK_HANLDE_TYPE_FILE)
1807 {
1808 if (!except)
1809 fds->handles[woff++] = fh;
1810 }
1811 else
1812 {
1813 if (WAIT_OBJECT_0 == WaitForSingleObject(fh->h, 0))
1814 fds->handles[woff++] = fh;
1815 }
1816 }
1817 fds->handles_pos = woff;
1818 return woff;
1819}
1820
1821
1822/**
1823 * Check if sockets or pipes meet certain conditions, version for W32.
1824 *
1825 * @param rfds set of sockets or pipes to be checked for readability
1826 * @param wfds set of sockets or pipes to be checked for writability
1827 * @param efds set of sockets or pipes to be checked for exceptions
1828 * @param timeout relative value when to return
1829 * @return number of selected sockets or pipes, #GNUNET_SYSERR on error
1830 */
1831int
1832GNUNET_NETWORK_socket_select(struct GNUNET_NETWORK_FDSet *rfds,
1833 struct GNUNET_NETWORK_FDSet *wfds,
1834 struct GNUNET_NETWORK_FDSet *efds,
1835 const struct GNUNET_TIME_Relative timeout)
1836{
1837 const struct GNUNET_DISK_FileHandle *fh;
1838 int nfds;
1839 int handles;
1840 unsigned int i;
1841 int retcode;
1842 uint64_t mcs_total;
1843 DWORD ms_rounded;
1844 int nhandles = 0;
1845 int read_pipes_off;
1846 HANDLE handle_array[FD_SETSIZE + 2];
1847 int returncode;
1848 int returnedpos = 0;
1849 int selectret;
1850 fd_set aread;
1851 fd_set awrite;
1852 fd_set aexcept;
1853
1854 nfds = 0;
1855 handles = 0;
1856 if (NULL != rfds)
1857 {
1858 nfds = GNUNET_MAX(nfds, rfds->nsds);
1859 handles += rfds->handles_pos;
1860 }
1861 if (NULL != wfds)
1862 {
1863 nfds = GNUNET_MAX(nfds, wfds->nsds);
1864 handles += wfds->handles_pos;
1865 }
1866 if (NULL != efds)
1867 {
1868 nfds = GNUNET_MAX(nfds, efds->nsds);
1869 handles += efds->handles_pos;
1870 }
1871
1872 if ((0 == nfds) &&
1873 (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us == timeout.rel_value_us) &&
1874 (0 == handles))
1875 {
1876 GNUNET_break(0);
1877 LOG(GNUNET_ERROR_TYPE_ERROR,
1878 _("Fatal internal logic error, process hangs in `%s' (abort with CTRL-C)!\n"),
1879 "select");
1880 }
1881#define SAFE_FD_ISSET(fd, set) (set != NULL && FD_ISSET(fd, set))
1882 /* calculate how long we need to wait in microseconds */
1883 if (timeout.rel_value_us == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
1884 {
1885 mcs_total = INFINITE;
1886 ms_rounded = INFINITE;
1887 }
1888 else
1889 {
1890 mcs_total = timeout.rel_value_us / GNUNET_TIME_UNIT_MICROSECONDS.rel_value_us;
1891 ms_rounded = (DWORD)(mcs_total / GNUNET_TIME_UNIT_MILLISECONDS.rel_value_us);
1892 if (mcs_total > 0 && ms_rounded == 0)
1893 ms_rounded = 1;
1894 }
1895 /* select() may be used as a portable way to sleep */
1896 if (!(rfds || wfds || efds))
1897 {
1898 Sleep(ms_rounded);
1899 return 0;
1900 }
1901
1902 if (NULL == select_thread)
1903 initialize_select_thread();
1904
1905 FD_ZERO(&aread);
1906 FD_ZERO(&awrite);
1907 FD_ZERO(&aexcept);
1908 if (rfds)
1909 FD_COPY(&rfds->sds, &aread);
1910 if (wfds)
1911 FD_COPY(&wfds->sds, &awrite);
1912 if (efds)
1913 FD_COPY(&efds->sds, &aexcept);
1914
1915 /* Start by doing a fast check on sockets and pipes (without
1916 waiting). It is cheap, and is sufficient most of the time. By
1917 profiling we detected that to be true in 90% of the cases.
1918 */
1919
1920 /* Do the select now */
1921 select_timeout.tv_sec = 0;
1922 select_timeout.tv_usec = 0;
1923
1924 /* Copy all the writes to the except, so we can detect connect() errors */
1925 for (i = 0; i < awrite.fd_count; i++)
1926 FD_SET(awrite.fd_array[i],
1927 &aexcept);
1928 if ((aread.fd_count > 0) ||
1929 (awrite.fd_count > 0) ||
1930 (aexcept.fd_count > 0))
1931 selectret = select(1,
1932 (NULL != rfds) ? &aread : NULL,
1933 (NULL != wfds) ? &awrite : NULL,
1934 &aexcept,
1935 &select_timeout);
1936 else
1937 selectret = 0;
1938 if (-1 == selectret)
1939 {
1940 /* Throw an error early on, while we still have the context. */
1941 LOG(GNUNET_ERROR_TYPE_ERROR,
1942 "W32 select(%d, %d, %d) failed: %lu\n",
1943 rfds ? aread.fd_count : 0,
1944 wfds ? awrite.fd_count : 0,
1945 aexcept.fd_count,
1946 GetLastError());
1947 GNUNET_assert(0);
1948 }
1949
1950 /* Check aexcept, if something is in there and we copied that
1951 FD before to detect connect() errors, add it back to the
1952 write set to report errors. */
1953 if (NULL != wfds)
1954 for (i = 0; i < aexcept.fd_count; i++)
1955 if (FD_ISSET(aexcept.fd_array[i],
1956 &wfds->sds))
1957 FD_SET(aexcept.fd_array[i],
1958 &awrite);
1959
1960
1961 /* If our select returned something or is a 0-timed request, then
1962 also check the pipes and get out of here! */
1963 /* Sadly, it means code duplication :( */
1964 if ((selectret > 0) || (0 == mcs_total))
1965 {
1966 retcode = 0;
1967
1968 /* Read Pipes */
1969 if (rfds && (rfds->handles_pos > 0))
1970 retcode += check_handles_status(rfds, GNUNET_NO, NULL);
1971
1972 /* wfds handles remain untouched, on W32
1973 we pretend our pipes are "always" write-ready */
1974
1975 /* except pipes */
1976 if (efds && (efds->handles_pos > 0))
1977 retcode += check_handles_status(efds, GNUNET_YES, NULL);
1978
1979 if (rfds)
1980 {
1981 GNUNET_NETWORK_fdset_zero(rfds);
1982 if (selectret != -1)
1983 GNUNET_NETWORK_fdset_copy_native(rfds, &aread, selectret);
1984 }
1985 if (wfds)
1986 {
1987 GNUNET_NETWORK_fdset_zero(wfds);
1988 if (selectret != -1)
1989 GNUNET_NETWORK_fdset_copy_native(wfds, &awrite, selectret);
1990 }
1991 if (efds)
1992 {
1993 GNUNET_NETWORK_fdset_zero(efds);
1994 if (selectret != -1)
1995 GNUNET_NETWORK_fdset_copy_native(efds, &aexcept, selectret);
1996 }
1997 if (-1 == selectret)
1998 return -1;
1999 /* Add our select() FDs to the total return value */
2000 retcode += selectret;
2001 return retcode;
2002 }
2003
2004 /* If we got this far, use slower implementation that is able to do a waiting select
2005 on both sockets and pipes simultaneously */
2006
2007 /* Events for pipes */
2008 if (!hEventReadReady)
2009 hEventReadReady = CreateEvent(NULL, TRUE, TRUE, NULL);
2010 if (!hEventPipeWrite)
2011 hEventPipeWrite = CreateEvent(NULL, TRUE, TRUE, NULL);
2012 retcode = 0;
2013
2014 FD_ZERO(&aread);
2015 FD_ZERO(&awrite);
2016 FD_ZERO(&aexcept);
2017 if (rfds)
2018 FD_COPY(&rfds->sds, &aread);
2019 if (wfds)
2020 FD_COPY(&wfds->sds, &awrite);
2021 if (efds)
2022 FD_COPY(&efds->sds, &aexcept);
2023 /* We will first Add the PIPES to the events */
2024 /* Track how far in `handle_array` the read pipes go,
2025 so we may by-pass them quickly if none of them
2026 are selected. */
2027 read_pipes_off = 0;
2028 if (rfds && (rfds->handles_pos > 0))
2029 {
2030 for (i = 0; i < rfds->handles_pos; i++)
2031 {
2032 fh = rfds->handles[i];
2033 if (fh->type == GNUNET_DISK_HANLDE_TYPE_EVENT)
2034 {
2035 handle_array[nhandles++] = fh->h;
2036 continue;
2037 }
2038 if (fh->type != GNUNET_DISK_HANLDE_TYPE_PIPE)
2039 continue;
2040 /* Read zero bytes to check the status of the pipe */
2041 if (!ReadFile(fh->h, NULL, 0, NULL, fh->oOverlapRead))
2042 {
2043 DWORD error_code = GetLastError();
2044
2045 if (error_code == ERROR_IO_PENDING)
2046 {
2047 /* add as unready */
2048 handle_array[nhandles++] = fh->oOverlapRead->hEvent;
2049 read_pipes_off++;
2050 }
2051 else
2052 {
2053 /* add as ready */
2054 handle_array[nhandles++] = hEventReadReady;
2055 read_pipes_off++;
2056 }
2057 }
2058 else
2059 {
2060 /* error also counts as ready */
2061 handle_array[nhandles++] = hEventReadReady;
2062 read_pipes_off++;
2063 }
2064 }
2065 }
2066
2067 if (wfds && (wfds->handles_pos > 0))
2068 {
2069 LOG(GNUNET_ERROR_TYPE_DEBUG,
2070 "Adding the write ready event to the array as %d\n",
2071 nhandles);
2072 handle_array[nhandles++] = hEventPipeWrite;
2073 }
2074
2075 sp.status = 0;
2076 if (nfds > 0)
2077 {
2078 LOG(GNUNET_ERROR_TYPE_DEBUG,
2079 "Adding the socket event to the array as %d\n",
2080 nhandles);
2081 handle_array[nhandles++] = select_finished_event;
2082 if (timeout.rel_value_us == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
2083 {
2084 sp.tv = NULL;
2085 }
2086 else
2087 {
2088 select_timeout.tv_sec = timeout.rel_value_us / GNUNET_TIME_UNIT_SECONDS.rel_value_us;
2089 select_timeout.tv_usec = (timeout.rel_value_us -
2090 (select_timeout.tv_sec *
2091 GNUNET_TIME_UNIT_SECONDS.rel_value_us));
2092 sp.tv = &select_timeout;
2093 }
2094 FD_SET(select_wakeup_socket, &aread);
2095 do
2096 {
2097 i = recv(select_wakeup_socket,
2098 (char *)&returnedpos,
2099 1,
2100 0);
2101 }
2102 while (i == 1);
2103 sp.r = &aread;
2104 sp.w = &awrite;
2105 sp.e = &aexcept;
2106 /* Failed connections cause sockets to be set in errorfds on W32,
2107 * but on POSIX it should set them in writefds.
2108 * First copy all awrite sockets to aexcept, later we'll
2109 * check aexcept and set its contents in awrite as well
2110 * Sockets are also set in errorfds when OOB data is available,
2111 * but we don't use OOB data.
2112 */
2113 for (i = 0; i < awrite.fd_count; i++)
2114 FD_SET(awrite.fd_array[i],
2115 &aexcept);
2116 ResetEvent(select_finished_event);
2117 SetEvent(select_standby_event);
2118 }
2119
2120 /* NULL-terminate array */
2121 handle_array[nhandles] = NULL;
2122 LOG(GNUNET_ERROR_TYPE_DEBUG,
2123 "nfds: %d, handles: %d, will wait: %llu mcs\n",
2124 nfds,
2125 nhandles,
2126 mcs_total);
2127 if (nhandles)
2128 {
2129 returncode
2130 = WaitForMultipleObjects(nhandles,
2131 handle_array,
2132 FALSE,
2133 ms_rounded);
2134 LOG(GNUNET_ERROR_TYPE_DEBUG,
2135 "WaitForMultipleObjects Returned: %d\n",
2136 returncode);
2137 }
2138 else if (nfds > 0)
2139 {
2140 GNUNET_break(0); /* This branch shouldn't actually be executed...*/
2141 i = (int)WaitForSingleObject(select_finished_event,
2142 INFINITE);
2143 returncode = WAIT_TIMEOUT;
2144 }
2145 else
2146 {
2147 /* Shouldn't come this far. If it does - investigate. */
2148 GNUNET_assert(0);
2149 }
2150
2151 if (nfds > 0)
2152 {
2153 /* Don't wake up select-thread when delay is 0, it should return immediately
2154 * and wake up by itself.
2155 */
2156 if (0 != mcs_total)
2157 i = send(select_send_socket,
2158 (const char *)&returnedpos,
2159 1,
2160 0);
2161 i = (int)WaitForSingleObject(select_finished_event,
2162 INFINITE);
2163 LOG(GNUNET_ERROR_TYPE_DEBUG,
2164 "Finished waiting for the select thread: %d %d\n",
2165 i,
2166 sp.status);
2167 if (0 != mcs_total)
2168 {
2169 do
2170 {
2171 i = recv(select_wakeup_socket,
2172 (char *)&returnedpos,
2173 1, 0);
2174 }
2175 while (1 == i);
2176 }
2177 /* Check aexcept, add its contents to awrite */
2178 for (i = 0; i < aexcept.fd_count; i++)
2179 FD_SET(aexcept.fd_array[i], &awrite);
2180 }
2181
2182 returnedpos = returncode - WAIT_OBJECT_0;
2183 LOG(GNUNET_ERROR_TYPE_DEBUG,
2184 "return pos is: %d\n",
2185 returnedpos);
2186
2187 if (rfds)
2188 {
2189 /* We queued a zero-long read on each pipe to check
2190 * its state, now we must cancel these read operations.
2191 * This must be done while rfds->handles_pos is still
2192 * intact and matches the number of read handles that we
2193 * got from the caller.
2194 */
2195 for (i = 0; i < rfds->handles_pos; i++)
2196 {
2197 fh = rfds->handles[i];
2198 if (GNUNET_DISK_HANLDE_TYPE_PIPE == fh->type)
2199 CancelIo(fh->h);
2200 }
2201
2202 /* We may have some pipes ready for reading. */
2203 if (returnedpos < read_pipes_off)
2204 retcode += check_handles_status(rfds, GNUNET_NO, handle_array[returnedpos]);
2205 else
2206 rfds->handles_pos = 0;
2207
2208 if (-1 != sp.status)
2209 GNUNET_NETWORK_fdset_copy_native(rfds, &aread, retcode);
2210 }
2211 if (wfds)
2212 {
2213 retcode += wfds->handles_pos;
2214 /* wfds handles remain untouched */
2215 if (-1 != sp.status)
2216 GNUNET_NETWORK_fdset_copy_native(wfds, &awrite, retcode);
2217 }
2218 if (efds)
2219 {
2220 retcode += check_handles_status(rfds,
2221 GNUNET_YES,
2222 returnedpos < nhandles ? handle_array[returnedpos] : NULL);
2223 if (-1 != sp.status)
2224 GNUNET_NETWORK_fdset_copy_native(efds, &aexcept, retcode);
2225 }
2226
2227 if (sp.status > 0)
2228 retcode += sp.status;
2229
2230 return retcode;
2231}
2232
2233/* MINGW */
2234#endif
2235
2236/* end of network.c */ 1374/* end of network.c */