Annotation of embedaddon/mtr/packet/wait_unix.c, revision 1.1.1.2
1.1 misho 1: /*
2: mtr -- a network diagnostic tool
3: Copyright (C) 2016 Matt Kimball
4:
5: This program is free software; you can redistribute it and/or modify
6: it under the terms of the GNU General Public License version 2 as
7: published by the Free Software Foundation.
8:
9: This program is distributed in the hope that it will be useful,
10: but WITHOUT ANY WARRANTY; without even the implied warranty of
11: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12: GNU General Public License for more details.
13:
1.1.1.2 ! misho 14: You should have received a copy of the GNU General Public License along
! 15: with this program; if not, write to the Free Software Foundation, Inc.,
! 16: 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
1.1 misho 17: */
18:
19: #include "wait.h"
20:
21: #include <assert.h>
22: #include <errno.h>
1.1.1.2 ! misho 23: #ifdef HAVE_ERROR_H
! 24: #include <error.h>
! 25: #else
! 26: #include "portability/error.h"
! 27: #endif
1.1 misho 28: #include <stdbool.h>
29: #include <stdio.h>
30: #include <stdlib.h>
31: #include <string.h>
32: #include <sys/select.h>
33:
34: /*
35: Gather all the file descriptors which should wake our select call when
36: they become readable.
37: */
38: static
39: int gather_read_fds(
40: const struct command_buffer_t *command_buffer,
41: const struct net_state_t *net_state,
42: fd_set * read_set,
43: fd_set * write_set)
44: {
45: int nfds;
46: int probe_nfds;
1.1.1.2 ! misho 47: int ip4_socket;
! 48: int ip6_socket;
1.1 misho 49: int command_stream = command_buffer->command_stream;
50:
51: FD_ZERO(read_set);
52: FD_ZERO(write_set);
53:
54: FD_SET(command_stream, read_set);
55: nfds = command_stream + 1;
56:
1.1.1.2 ! misho 57: if (net_state->platform.ip4_socket_raw) {
! 58: ip4_socket = net_state->platform.ip4_recv_socket;
! 59: FD_SET(ip4_socket, read_set);
! 60: if (ip4_socket >= nfds) {
! 61: nfds = ip4_socket + 1;
! 62: }
! 63: } else {
! 64: ip4_socket = net_state->platform.ip4_txrx_icmp_socket;
! 65: FD_SET(ip4_socket, read_set);
! 66: if (ip4_socket >= nfds) {
! 67: nfds = ip4_socket + 1;
! 68: }
! 69: ip4_socket = net_state->platform.ip4_txrx_udp_socket;
! 70: FD_SET(ip4_socket, read_set);
! 71: if (ip4_socket >= nfds) {
! 72: nfds = ip4_socket + 1;
! 73: }
1.1 misho 74: }
75:
1.1.1.2 ! misho 76: if (net_state->platform.ip6_socket_raw) {
! 77: ip6_socket = net_state->platform.ip6_recv_socket;
! 78: FD_SET(ip6_socket, read_set);
! 79: if (ip6_socket >= nfds) {
! 80: nfds = ip6_socket + 1;
! 81: }
! 82: } else {
! 83: ip6_socket = net_state->platform.ip6_txrx_icmp_socket;
! 84: FD_SET(ip6_socket, read_set);
! 85: if (ip6_socket >= nfds) {
! 86: nfds = ip6_socket + 1;
! 87: }
! 88: ip6_socket = net_state->platform.ip6_txrx_udp_socket;
! 89: FD_SET(ip6_socket, read_set);
! 90: if (ip6_socket >= nfds) {
! 91: nfds = ip6_socket + 1;
! 92: }
1.1 misho 93: }
94:
95: probe_nfds = gather_probe_sockets(net_state, write_set);
96: if (probe_nfds > nfds) {
97: nfds = probe_nfds;
98: }
99:
100: return nfds;
101: }
102:
103: /*
104: Sleep until we receive a new probe response, a new command on the
105: command stream, or a probe timeout. On Unix systems, this means
106: we use select to wait on file descriptors for the command stream
1.1.1.2 ! misho 107: and the raw receive socket.
1.1 misho 108: */
109: void wait_for_activity(
110: struct command_buffer_t *command_buffer,
111: struct net_state_t *net_state)
112: {
113: int nfds;
114: fd_set read_set;
115: fd_set write_set;
116: struct timeval probe_timeout;
117: struct timeval *select_timeout;
118: int ready_count;
119:
120: nfds =
121: gather_read_fds(command_buffer, net_state, &read_set, &write_set);
122:
123: while (true) {
124: select_timeout = NULL;
125:
126: /* Use the soonest probe timeout time as our maximum wait time */
127: if (get_next_probe_timeout(net_state, &probe_timeout)) {
128: assert(probe_timeout.tv_sec >= 0);
129: select_timeout = &probe_timeout;
130: }
131:
132: ready_count =
133: select(nfds, &read_set, &write_set, NULL, select_timeout);
134:
135: /*
136: If we didn't have an error, either one of our descriptors is
137: readable, or we timed out. So we can now return.
138: */
139: if (ready_count != -1) {
140: break;
141: }
142:
143: /*
144: We will get EINTR if we received a signal during the select, so
145: retry in that case. We may get EAGAIN if "the kernel was
146: (perhaps temporarily) unable to allocate the requested number of
147: file descriptors." I haven't seen this in practice, but selecting
148: again seems like the right thing to do.
149: */
150: if (errno != EINTR && errno != EAGAIN) {
151: /* We don't expect other errors, so report them */
1.1.1.2 ! misho 152: error(EXIT_FAILURE, errno, "unexpected select error");
1.1 misho 153: }
154: }
155: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>