aboutsummaryrefslogtreecommitdiff
path: root/src/util/network.c
diff options
context:
space:
mode:
authorng0 <ng0@n0.is>2019-09-10 16:59:32 +0000
committerng0 <ng0@n0.is>2019-09-10 16:59:32 +0000
commit04b6df21cd281e8cd540139f8d9ae85defc1961c (patch)
tree6357199445df8d5c0c631bc8f10aef838b1f9f1e /src/util/network.c
parent483b0139a218a5f8a8311bda3eb23bcd88f57688 (diff)
downloadgnunet-04b6df21cd281e8cd540139f8d9ae85defc1961c.tar.gz
gnunet-04b6df21cd281e8cd540139f8d9ae85defc1961c.zip
remove CYGWIN codeblocks, drop vendored Windows openvpn, drop win32 specific files.
configures and builds okay. testsuite wasn't checked, will be checked. diff including the plibc removal is now around 14370 lines of code less.
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 */