Annotation of embedaddon/mtr/packet/wait_unix.c, revision 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>