diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/util/network.c | 197 |
1 files changed, 194 insertions, 3 deletions
diff --git a/src/util/network.c b/src/util/network.c index 86bc47677..491e4fffd 100644 --- a/src/util/network.c +++ b/src/util/network.c | |||
@@ -1221,6 +1221,8 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds, | |||
1221 | struct GNUNET_CONTAINER_SList *handles_write; | 1221 | struct GNUNET_CONTAINER_SList *handles_write; |
1222 | struct GNUNET_CONTAINER_SList *handles_except; | 1222 | struct GNUNET_CONTAINER_SList *handles_except; |
1223 | 1223 | ||
1224 | int selectret = 0; | ||
1225 | |||
1224 | fd_set aread; | 1226 | fd_set aread; |
1225 | fd_set awrite; | 1227 | fd_set awrite; |
1226 | fd_set aexcept; | 1228 | fd_set aexcept; |
@@ -1364,6 +1366,196 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds, | |||
1364 | select_thread = CreateThread (NULL, 0, _selector, &sp, 0, NULL); | 1366 | select_thread = CreateThread (NULL, 0, _selector, &sp, 0, NULL); |
1365 | } | 1367 | } |
1366 | 1368 | ||
1369 | |||
1370 | handles_read = GNUNET_CONTAINER_slist_create (); | ||
1371 | handles_write = GNUNET_CONTAINER_slist_create (); | ||
1372 | handles_except = GNUNET_CONTAINER_slist_create (); | ||
1373 | FD_ZERO (&aread); | ||
1374 | FD_ZERO (&awrite); | ||
1375 | FD_ZERO (&aexcept); | ||
1376 | #if DEBUG_NETWORK | ||
1377 | FD_ZERO (&bread); | ||
1378 | FD_ZERO (&bwrite); | ||
1379 | FD_ZERO (&bexcept); | ||
1380 | #endif | ||
1381 | if (rfds) | ||
1382 | { | ||
1383 | FD_COPY (&rfds->sds, &aread); | ||
1384 | #if DEBUG_NETWORK | ||
1385 | FD_COPY (&rfds->sds, &bread); | ||
1386 | #endif | ||
1387 | } | ||
1388 | if (wfds) | ||
1389 | { | ||
1390 | FD_COPY (&wfds->sds, &awrite); | ||
1391 | #if DEBUG_NETWORK | ||
1392 | FD_COPY (&wfds->sds, &bwrite); | ||
1393 | #endif | ||
1394 | } | ||
1395 | if (efds) | ||
1396 | { | ||
1397 | FD_COPY (&efds->sds, &aexcept); | ||
1398 | #if DEBUG_NETWORK | ||
1399 | FD_COPY (&efds->sds, &bexcept); | ||
1400 | #endif | ||
1401 | } | ||
1402 | |||
1403 | /* Start by doing a fast check on sockets and pipes (without waiting). It is cheap, and is sufficient most of the time. | ||
1404 | By profiling we detected that to be true in 90% of the cases. | ||
1405 | */ | ||
1406 | |||
1407 | /* Do the select now */ | ||
1408 | select_timeout.tv_sec = 0; | ||
1409 | select_timeout.tv_usec = 0; | ||
1410 | |||
1411 | /* Copy all the writes to the except, so we can detect connect() errors */ | ||
1412 | for (i = 0; i < awrite.fd_count; i++) | ||
1413 | { | ||
1414 | if (awrite.fd_array[i] != 0 && awrite.fd_array[i] != -1) | ||
1415 | FD_SET (awrite.fd_array[i], &aexcept); | ||
1416 | } | ||
1417 | if (aread.fd_count > 0 || awrite.fd_count > 0 || aexcept.fd_count > 0) | ||
1418 | selectret = select (1, (rfds != NULL) ? &aread : NULL, | ||
1419 | (wfds != NULL) ? &awrite : NULL, &aexcept, &select_timeout); | ||
1420 | else | ||
1421 | selectret = 0; | ||
1422 | if (selectret == -1) | ||
1423 | { | ||
1424 | /* Throw an error early on, while we still have the context. */ | ||
1425 | LOG (GNUNET_ERROR_TYPE_ERROR, "W32 select(%d, %d, %d) failed: %lu\n", | ||
1426 | rfds ? aread.fd_count : 0, wfds ? awrite.fd_count : 0, aexcept.fd_count, GetLastError ()); | ||
1427 | GNUNET_abort (); | ||
1428 | } | ||
1429 | |||
1430 | /* Check aexcept, add its contents to awrite | ||
1431 | This is technically wrong (aexcept might have its own descriptors), we should | ||
1432 | have checked that descriptors were in awrite originally before re-adding them from | ||
1433 | aexcept. Luckily, GNUnet never uses aexcept for anything, so this does not become a problem (yet). */ | ||
1434 | for (i = 0; i < aexcept.fd_count; i++) | ||
1435 | { | ||
1436 | if (aexcept.fd_array[i] != 0 && aexcept.fd_array[i] != -1) | ||
1437 | FD_SET (aexcept.fd_array[i], &awrite); | ||
1438 | } | ||
1439 | |||
1440 | /* If our select returned something or is a 0-timed request, then also check the pipes and get out of here! */ | ||
1441 | /* Sadly, it means code duplication :( */ | ||
1442 | if ((selectret > 0) || (ms_total == 0)) | ||
1443 | { | ||
1444 | /* Read Pipes */ | ||
1445 | if (rfds && read_handles) | ||
1446 | { | ||
1447 | struct GNUNET_CONTAINER_SList_Iterator i; | ||
1448 | |||
1449 | for (i = GNUNET_CONTAINER_slist_begin (rfds->handles); | ||
1450 | GNUNET_CONTAINER_slist_end (&i) != GNUNET_YES; | ||
1451 | GNUNET_CONTAINER_slist_next (&i)) | ||
1452 | { | ||
1453 | struct GNUNET_DISK_FileHandle *fh; | ||
1454 | |||
1455 | fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (&i,NULL); | ||
1456 | if (fh->type == GNUNET_DISK_HANLDE_TYPE_PIPE) | ||
1457 | { | ||
1458 | DWORD error; | ||
1459 | BOOL bret; | ||
1460 | |||
1461 | SetLastError (0); | ||
1462 | DWORD waitstatus = 0; | ||
1463 | bret = PeekNamedPipe (fh->h, NULL, 0, NULL, &waitstatus, NULL); | ||
1464 | error = GetLastError (); | ||
1465 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Peek at read pipe %d (0x%x) returned %d (%d bytes available) GLE %u\n", | ||
1466 | i, fh->h, bret, waitstatus, error); | ||
1467 | if (bret == 0) | ||
1468 | { | ||
1469 | /* TODO: either add more errors to this condition, or eliminate it | ||
1470 | * entirely (failed to peek -> pipe is in serious trouble, should | ||
1471 | * be selected as readable). | ||
1472 | */ | ||
1473 | if (error != ERROR_BROKEN_PIPE && error != ERROR_INVALID_HANDLE) | ||
1474 | continue; | ||
1475 | } | ||
1476 | else if (waitstatus <= 0) | ||
1477 | continue; | ||
1478 | GNUNET_CONTAINER_slist_add (handles_read, GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT, | ||
1479 | fh, sizeof (struct GNUNET_DISK_FileHandle)); | ||
1480 | retcode++; | ||
1481 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Added read Pipe 0x%x (0x%x)\n", | ||
1482 | fh, fh->h); | ||
1483 | } | ||
1484 | else | ||
1485 | { | ||
1486 | GNUNET_CONTAINER_slist_add (handles_read, GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT, | ||
1487 | fh, sizeof (struct GNUNET_DISK_FileHandle)); | ||
1488 | retcode++; | ||
1489 | } | ||
1490 | } | ||
1491 | } | ||
1492 | if (wfds && write_handles) | ||
1493 | { | ||
1494 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1495 | "Adding the write ready event to the array as %d\n", nhandles); | ||
1496 | GNUNET_CONTAINER_slist_append (handles_write, wfds->handles); | ||
1497 | retcode += write_handles; | ||
1498 | } | ||
1499 | if (efds && ex_handles) | ||
1500 | { | ||
1501 | struct GNUNET_CONTAINER_SList_Iterator i; | ||
1502 | |||
1503 | for (i = GNUNET_CONTAINER_slist_begin (efds->handles); | ||
1504 | GNUNET_CONTAINER_slist_end (&i) != GNUNET_YES; | ||
1505 | GNUNET_CONTAINER_slist_next (&i)) | ||
1506 | { | ||
1507 | struct GNUNET_DISK_FileHandle *fh; | ||
1508 | DWORD dwBytes; | ||
1509 | |||
1510 | fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (&i, NULL); | ||
1511 | if (fh->type == GNUNET_DISK_HANLDE_TYPE_PIPE) | ||
1512 | { | ||
1513 | if (PeekNamedPipe (fh->h, NULL, 0, NULL, &dwBytes, NULL)) | ||
1514 | continue; | ||
1515 | GNUNET_CONTAINER_slist_add (handles_except, GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT, | ||
1516 | fh, sizeof (struct GNUNET_DISK_FileHandle)); | ||
1517 | retcode++; | ||
1518 | } | ||
1519 | } | ||
1520 | } | ||
1521 | |||
1522 | /* Add our select() result.*/ | ||
1523 | if (selectret >= 0) | ||
1524 | retcode += selectret; | ||
1525 | |||
1526 | if (rfds) | ||
1527 | { | ||
1528 | GNUNET_NETWORK_fdset_zero (rfds); | ||
1529 | if (selectret != -1) | ||
1530 | GNUNET_NETWORK_fdset_copy_native (rfds, &aread, selectret); | ||
1531 | GNUNET_CONTAINER_slist_append (rfds->handles, handles_read); | ||
1532 | } | ||
1533 | if (wfds) | ||
1534 | { | ||
1535 | GNUNET_NETWORK_fdset_zero (wfds); | ||
1536 | if (selectret != -1) | ||
1537 | GNUNET_NETWORK_fdset_copy_native (wfds, &awrite, selectret); | ||
1538 | GNUNET_CONTAINER_slist_append (wfds->handles, handles_write); | ||
1539 | } | ||
1540 | if (efds) | ||
1541 | { | ||
1542 | GNUNET_NETWORK_fdset_zero (efds); | ||
1543 | if (selectret != -1) | ||
1544 | GNUNET_NETWORK_fdset_copy_native (efds, &aexcept, selectret); | ||
1545 | GNUNET_CONTAINER_slist_append (efds->handles, handles_except); | ||
1546 | } | ||
1547 | GNUNET_CONTAINER_slist_destroy (handles_read); | ||
1548 | GNUNET_CONTAINER_slist_destroy (handles_write); | ||
1549 | GNUNET_CONTAINER_slist_destroy (handles_except); | ||
1550 | |||
1551 | if (selectret == -1) | ||
1552 | return -1; | ||
1553 | return retcode; | ||
1554 | } | ||
1555 | |||
1556 | /* If we got this far, use slower implementation that is able to do a waiting select | ||
1557 | on both sockets and pipes simultaneously */ | ||
1558 | |||
1367 | /* Events for pipes */ | 1559 | /* Events for pipes */ |
1368 | if (!hEventReadReady) | 1560 | if (!hEventReadReady) |
1369 | hEventReadReady = CreateEvent (NULL, TRUE, TRUE, NULL); | 1561 | hEventReadReady = CreateEvent (NULL, TRUE, TRUE, NULL); |
@@ -1372,9 +1564,8 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds, | |||
1372 | readPipes = 0; | 1564 | readPipes = 0; |
1373 | writePipePos = -1; | 1565 | writePipePos = -1; |
1374 | 1566 | ||
1375 | handles_read = GNUNET_CONTAINER_slist_create (); | 1567 | retcode = 0; |
1376 | handles_write = GNUNET_CONTAINER_slist_create (); | 1568 | |
1377 | handles_except = GNUNET_CONTAINER_slist_create (); | ||
1378 | FD_ZERO (&aread); | 1569 | FD_ZERO (&aread); |
1379 | FD_ZERO (&awrite); | 1570 | FD_ZERO (&awrite); |
1380 | FD_ZERO (&aexcept); | 1571 | FD_ZERO (&aexcept); |