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>