diff options
Diffstat (limited to 'src/util/network.c')
-rw-r--r-- | src/util/network.c | 866 |
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 | |||
1054 | GNUNET_NETWORK_fdset_add(struct GNUNET_NETWORK_FDSet *dst, | 1032 | GNUNET_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 | |||
1217 | GNUNET_NETWORK_fdset_handle_set(struct GNUNET_NETWORK_FDSet *fds, | 1159 | GNUNET_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 | |||
1247 | GNUNET_NETWORK_fdset_handle_set_first(struct GNUNET_NETWORK_FDSet *fds, | 1181 | GNUNET_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 | |||
1277 | GNUNET_NETWORK_fdset_handle_isset(const struct GNUNET_NETWORK_FDSet *fds, | 1196 | GNUNET_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 | */ | ||
1303 | static int | ||
1304 | ptr_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 | |||
1324 | GNUNET_NETWORK_fdset_overlap(const struct GNUNET_NETWORK_FDSet *fds1, | 1212 | GNUNET_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() | |||
1413 | void | 1253 | void |
1414 | GNUNET_NETWORK_fdset_destroy(struct GNUNET_NETWORK_FDSet *fds) | 1254 | GNUNET_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 | */ | ||
1429 | struct _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 | */ | ||
1475 | static 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 | |||
1503 | static HANDLE hEventPipeWrite; | ||
1504 | |||
1505 | static HANDLE hEventReadReady; | ||
1506 | |||
1507 | static struct _select_params sp; | ||
1508 | |||
1509 | static HANDLE select_thread; | ||
1510 | |||
1511 | static HANDLE select_finished_event; | ||
1512 | |||
1513 | static HANDLE select_standby_event; | ||
1514 | |||
1515 | static _win_socket select_wakeup_socket = -1; | ||
1516 | |||
1517 | static _win_socket select_send_socket = -1; | ||
1518 | |||
1519 | static 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 | */ | ||
1527 | static void | ||
1528 | initialize_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 | */ | ||
1728 | static int | ||
1729 | pipe_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 | */ | ||
1760 | static int | ||
1761 | pipe_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 | */ | ||
1784 | static int | ||
1785 | check_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 | */ | ||
1831 | int | ||
1832 | GNUNET_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 */ |