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>