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>