Annotation of embedaddon/mtr/packet/wait_unix.c, revision 1.1.1.1
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:
14: You should have received a copy of the GNU General Public License
15: along with this program; if not, write to the Free Software
16: Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17: */
18:
19: #include "wait.h"
20:
21: #include <assert.h>
22: #include <errno.h>
23: #include <stdbool.h>
24: #include <stdio.h>
25: #include <stdlib.h>
26: #include <string.h>
27: #include <sys/select.h>
28:
29: /*
30: Gather all the file descriptors which should wake our select call when
31: they become readable.
32: */
33: static
34: int gather_read_fds(
35: const struct command_buffer_t *command_buffer,
36: const struct net_state_t *net_state,
37: fd_set * read_set,
38: fd_set * write_set)
39: {
40: int nfds;
41: int probe_nfds;
42: int ip4_socket = net_state->platform.ip4_recv_socket;
43: int ip6_socket = net_state->platform.ip6_recv_socket;
44: int command_stream = command_buffer->command_stream;
45:
46: FD_ZERO(read_set);
47: FD_ZERO(write_set);
48:
49: FD_SET(command_stream, read_set);
50: nfds = command_stream + 1;
51:
52: FD_SET(ip4_socket, read_set);
53: if (ip4_socket >= nfds) {
54: nfds = ip4_socket + 1;
55: }
56:
57: FD_SET(ip6_socket, read_set);
58: if (ip6_socket >= nfds) {
59: nfds = ip6_socket + 1;
60: }
61:
62: probe_nfds = gather_probe_sockets(net_state, write_set);
63: if (probe_nfds > nfds) {
64: nfds = probe_nfds;
65: }
66:
67: return nfds;
68: }
69:
70: /*
71: Sleep until we receive a new probe response, a new command on the
72: command stream, or a probe timeout. On Unix systems, this means
73: we use select to wait on file descriptors for the command stream
74: and the raw recieve socket.
75: */
76: void wait_for_activity(
77: struct command_buffer_t *command_buffer,
78: struct net_state_t *net_state)
79: {
80: int nfds;
81: fd_set read_set;
82: fd_set write_set;
83: struct timeval probe_timeout;
84: struct timeval *select_timeout;
85: int ready_count;
86:
87: nfds =
88: gather_read_fds(command_buffer, net_state, &read_set, &write_set);
89:
90: while (true) {
91: select_timeout = NULL;
92:
93: /* Use the soonest probe timeout time as our maximum wait time */
94: if (get_next_probe_timeout(net_state, &probe_timeout)) {
95: assert(probe_timeout.tv_sec >= 0);
96: select_timeout = &probe_timeout;
97: }
98:
99: ready_count =
100: select(nfds, &read_set, &write_set, NULL, select_timeout);
101:
102: /*
103: If we didn't have an error, either one of our descriptors is
104: readable, or we timed out. So we can now return.
105: */
106: if (ready_count != -1) {
107: break;
108: }
109:
110: /*
111: We will get EINTR if we received a signal during the select, so
112: retry in that case. We may get EAGAIN if "the kernel was
113: (perhaps temporarily) unable to allocate the requested number of
114: file descriptors." I haven't seen this in practice, but selecting
115: again seems like the right thing to do.
116: */
117: if (errno != EINTR && errno != EAGAIN) {
118: /* We don't expect other errors, so report them */
119: perror("unexpected select error");
120: exit(EXIT_FAILURE);
121: }
122: }
123: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>