mirror of
https://github.com/nmap/nmap.git
synced 2025-12-10 07:01:32 +00:00
Do a non-blocking check for events when pcap data is available
For platforms without selectable pcap handles (e.g. Windows), the arrival of data for a pcap read would previously skip checking for any triggered non-pcap events in that loop iteration. This is not usually a problem because the next loop will be triggered immediately, picking up the non-pcap events before any further pcap data arrives. However, excessive pcap data on a handle in immediate mode might prevent the engine loop from checking for non-pcap events for long enough to result in timeouts. Instead, do a non-blocking check for triggered events in this case and handle those in the same loop iteration.
This commit is contained in:
@@ -289,14 +289,14 @@ int epoll_loop(struct npool *nsp, int msec_timeout) {
|
||||
* If there is anything read, just leave this loop. */
|
||||
if (pcap_read_on_nonselect(nsp)) {
|
||||
/* okay, something was read. */
|
||||
} else
|
||||
#endif
|
||||
#endif
|
||||
{
|
||||
results_left = epoll_wait(einfo->epfd, einfo->events, einfo->evlen, combined_msecs);
|
||||
if (results_left == -1)
|
||||
sock_err = socket_errno();
|
||||
// Make the epoll_wait call non-blocking
|
||||
combined_msecs = 0;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
results_left = epoll_wait(einfo->epfd, einfo->events, einfo->evlen, combined_msecs);
|
||||
if (results_left == -1)
|
||||
sock_err = socket_errno();
|
||||
|
||||
gettimeofday(&nsock_tod, NULL); /* Due to epoll delay */
|
||||
} while (results_left == -1 && sock_err == EINTR); /* repeat only if signal occurred */
|
||||
|
||||
@@ -360,29 +360,28 @@ int iocp_loop(struct npool *nsp, int msec_timeout) {
|
||||
/* okay, something was read. */
|
||||
gettimeofday(&nsock_tod, NULL);
|
||||
iterate_through_pcap_events(nsp);
|
||||
// Only do a non-blocking check for completed IO on the non-pcap events
|
||||
combined_msecs = 0;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
#endif
|
||||
{
|
||||
/* It is mandatory these values are reset before calling GetQueuedCompletionStatusEx */
|
||||
iinfo->entries_removed = 0;
|
||||
memset(iinfo->eov_list, 0, iinfo->capacity * sizeof(OVERLAPPED_ENTRY));
|
||||
bRet = GetQueuedCompletionStatusEx(iinfo->iocp, iinfo->eov_list, iinfo->capacity, &iinfo->entries_removed, combined_msecs, FALSE);
|
||||
/* It is mandatory these values are reset before calling GetQueuedCompletionStatusEx */
|
||||
iinfo->entries_removed = 0;
|
||||
memset(iinfo->eov_list, 0, iinfo->capacity * sizeof(OVERLAPPED_ENTRY));
|
||||
bRet = GetQueuedCompletionStatusEx(iinfo->iocp, iinfo->eov_list, iinfo->capacity, &iinfo->entries_removed, combined_msecs, FALSE);
|
||||
|
||||
gettimeofday(&nsock_tod, NULL); /* Due to iocp delay */
|
||||
if (!bRet) {
|
||||
sock_err = socket_errno();
|
||||
if (!iinfo->eov && sock_err != WAIT_TIMEOUT) {
|
||||
nsock_log_error("nsock_loop error %d: %s", sock_err, socket_strerror(sock_err));
|
||||
nsp->errnum = sock_err;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
iterate_through_event_lists(nsp);
|
||||
gettimeofday(&nsock_tod, NULL); /* Due to iocp delay */
|
||||
if (!bRet) {
|
||||
sock_err = socket_errno();
|
||||
if (!iinfo->eov && sock_err != WAIT_TIMEOUT) {
|
||||
nsock_log_error("nsock_loop error %d: %s", sock_err, socket_strerror(sock_err));
|
||||
nsp->errnum = sock_err;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
iterate_through_event_lists(nsp);
|
||||
}
|
||||
|
||||
/* iterate through timers and expired events */
|
||||
process_expired_events(nsp);
|
||||
|
||||
@@ -261,6 +261,17 @@ int kqueue_loop(struct npool *nsp, int msec_timeout) {
|
||||
* timeout) */
|
||||
combined_msecs = MIN((unsigned)event_msecs, (unsigned)msec_timeout);
|
||||
|
||||
#if HAVE_PCAP
|
||||
#ifndef PCAP_CAN_DO_SELECT
|
||||
/* do non-blocking read on pcap devices that doesn't support select()
|
||||
* If there is anything read, just leave this loop. */
|
||||
if (pcap_read_on_nonselect(nsp)) {
|
||||
/* okay, something was read. */
|
||||
// Make the kevent call non-blocking
|
||||
combined_msecs = 0;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
/* Set up the timeval pointer we will give to kevent() */
|
||||
memset(&ts, 0, sizeof(struct timespec));
|
||||
if (combined_msecs >= 0) {
|
||||
@@ -271,20 +282,9 @@ int kqueue_loop(struct npool *nsp, int msec_timeout) {
|
||||
ts_p = NULL;
|
||||
}
|
||||
|
||||
#if HAVE_PCAP
|
||||
#ifndef PCAP_CAN_DO_SELECT
|
||||
/* do non-blocking read on pcap devices that doesn't support select()
|
||||
* If there is anything read, just leave this loop. */
|
||||
if (pcap_read_on_nonselect(nsp)) {
|
||||
/* okay, something was read. */
|
||||
} else
|
||||
#endif
|
||||
#endif
|
||||
{
|
||||
results_left = kevent(kinfo->kqfd, NULL, 0, kinfo->events, kinfo->evlen, ts_p);
|
||||
if (results_left == -1)
|
||||
sock_err = socket_errno();
|
||||
}
|
||||
results_left = kevent(kinfo->kqfd, NULL, 0, kinfo->events, kinfo->evlen, ts_p);
|
||||
if (results_left == -1)
|
||||
sock_err = socket_errno();
|
||||
|
||||
gettimeofday(&nsock_tod, NULL); /* Due to kevent delay */
|
||||
} while (results_left == -1 && sock_err == EINTR); /* repeat only if signal occurred */
|
||||
|
||||
@@ -339,14 +339,14 @@ int poll_loop(struct npool *nsp, int msec_timeout) {
|
||||
* If there is anything read, just leave this loop. */
|
||||
if (pcap_read_on_nonselect(nsp)) {
|
||||
/* okay, something was read. */
|
||||
} else
|
||||
#endif
|
||||
#endif
|
||||
{
|
||||
results_left = Poll(pinfo->events, pinfo->max_fd + 1, combined_msecs);
|
||||
if (results_left == -1)
|
||||
sock_err = socket_errno();
|
||||
// Make the Poll call non-blocking
|
||||
combined_msecs = 0;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
results_left = Poll(pinfo->events, pinfo->max_fd + 1, combined_msecs);
|
||||
if (results_left == -1)
|
||||
sock_err = socket_errno();
|
||||
|
||||
gettimeofday(&nsock_tod, NULL); /* Due to poll delay */
|
||||
} while (results_left == -1 && sock_err == EINTR); /* repeat only if signal occurred */
|
||||
|
||||
@@ -281,6 +281,17 @@ int select_loop(struct npool *nsp, int msec_timeout) {
|
||||
* timeout) */
|
||||
combined_msecs = MIN((unsigned)event_msecs, (unsigned)msec_timeout);
|
||||
|
||||
#if HAVE_PCAP
|
||||
#ifndef PCAP_CAN_DO_SELECT
|
||||
/* do non-blocking read on pcap devices that doesn't support select()
|
||||
* If there is anything read, just leave this loop. */
|
||||
if (pcap_read_on_nonselect(nsp)) {
|
||||
/* okay, something was read. */
|
||||
// Make the select call non-blocking
|
||||
combined_msecs = 0;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
/* Set up the timeval pointer we will give to select() */
|
||||
memset(&select_tv, 0, sizeof(select_tv));
|
||||
if (combined_msecs > 0) {
|
||||
@@ -295,27 +306,16 @@ int select_loop(struct npool *nsp, int msec_timeout) {
|
||||
select_tv_p = NULL;
|
||||
}
|
||||
|
||||
#if HAVE_PCAP
|
||||
#ifndef PCAP_CAN_DO_SELECT
|
||||
/* do non-blocking read on pcap devices that doesn't support select()
|
||||
* If there is anything read, just leave this loop. */
|
||||
if (pcap_read_on_nonselect(nsp)) {
|
||||
/* okay, something was read. */
|
||||
} else
|
||||
#endif
|
||||
#endif
|
||||
{
|
||||
/* Set up the descriptors for select */
|
||||
sinfo->fds_results_r = sinfo->fds_master_r;
|
||||
sinfo->fds_results_w = sinfo->fds_master_w;
|
||||
sinfo->fds_results_x = sinfo->fds_master_x;
|
||||
/* Set up the descriptors for select */
|
||||
sinfo->fds_results_r = sinfo->fds_master_r;
|
||||
sinfo->fds_results_w = sinfo->fds_master_w;
|
||||
sinfo->fds_results_x = sinfo->fds_master_x;
|
||||
|
||||
results_left = fselect(sinfo->max_sd + 1, &sinfo->fds_results_r,
|
||||
&sinfo->fds_results_w, &sinfo->fds_results_x, select_tv_p);
|
||||
results_left = fselect(sinfo->max_sd + 1, &sinfo->fds_results_r,
|
||||
&sinfo->fds_results_w, &sinfo->fds_results_x, select_tv_p);
|
||||
|
||||
if (results_left == -1)
|
||||
sock_err = socket_errno();
|
||||
}
|
||||
if (results_left == -1)
|
||||
sock_err = socket_errno();
|
||||
|
||||
gettimeofday(&nsock_tod, NULL); /* Due to select delay */
|
||||
} while (results_left == -1 && sock_err == EINTR); /* repeat only if signal occurred */
|
||||
|
||||
Reference in New Issue
Block a user