LCOV - code coverage report
Current view: top level - src/network - network.cc (source / functions) Hit Total Coverage
Test: mosh-1.3.2 Code Coverage Lines: 262 382 68.6 %
Date: 2022-02-06 20:19:53 Functions: 19 25 76.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :     Mosh: the mobile shell
       3             :     Copyright 2012 Keith Winstein
       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 as published by
       7             :     the Free Software Foundation, either version 3 of the License, or
       8             :     (at your option) any later version.
       9             : 
      10             :     This program is distributed in the hope that it will be useful,
      11             :     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12             :     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13             :     GNU General Public License for more details.
      14             : 
      15             :     You should have received a copy of the GNU General Public License
      16             :     along with this program.  If not, see <http://www.gnu.org/licenses/>.
      17             : 
      18             :     In addition, as a special exception, the copyright holders give
      19             :     permission to link the code of portions of this program with the
      20             :     OpenSSL library under certain conditions as described in each
      21             :     individual source file, and distribute linked combinations including
      22             :     the two.
      23             : 
      24             :     You must obey the GNU General Public License in all respects for all
      25             :     of the code used other than OpenSSL. If you modify file(s) with this
      26             :     exception, you may extend this exception to your version of the
      27             :     file(s), but you are not obligated to do so. If you do not wish to do
      28             :     so, delete this exception statement from your version. If you delete
      29             :     this exception statement from all source files in the program, then
      30             :     also delete it here.
      31             : */
      32             : 
      33             : #include "config.h"
      34             : 
      35             : #include <sys/types.h>
      36             : #include <sys/socket.h>
      37             : #ifdef HAVE_SYS_UIO_H
      38             : #include <sys/uio.h>
      39             : #endif
      40             : #include <netdb.h>
      41             : #include <netinet/in.h>
      42             : #include <assert.h>
      43             : #include <errno.h>
      44             : #include <string.h>
      45             : #include <unistd.h>
      46             : 
      47             : #include "dos_assert.h"
      48             : #include "fatal_assert.h"
      49             : #include "byteorder.h"
      50             : #include "network.h"
      51             : #include "crypto.h"
      52             : 
      53             : #include "timestamp.h"
      54             : 
      55             : #ifndef MSG_DONTWAIT
      56             : #define MSG_DONTWAIT MSG_NONBLOCK
      57             : #endif
      58             : 
      59             : #ifndef AI_NUMERICSERV
      60             : #define AI_NUMERICSERV 0
      61             : #endif
      62             : 
      63             : using namespace Network;
      64             : using namespace Crypto;
      65             : 
      66             : const uint64_t DIRECTION_MASK = uint64_t(1) << 63;
      67             : const uint64_t SEQUENCE_MASK = uint64_t(-1) ^ DIRECTION_MASK;
      68             : 
      69             : /* Read in packet */
      70        5285 : Packet::Packet( const Message & message )
      71        5285 :   : seq( message.nonce.val() & SEQUENCE_MASK ),
      72        5285 :     direction( (message.nonce.val() & DIRECTION_MASK) ? TO_CLIENT : TO_SERVER ),
      73        5285 :     timestamp( -1 ),
      74        5285 :     timestamp_reply( -1 ),
      75        5285 :     payload()
      76             : {
      77        5285 :   dos_assert( message.text.size() >= 2 * sizeof( uint16_t ) );
      78             : 
      79        5285 :   const uint16_t *data = (uint16_t *)message.text.data();
      80        5285 :   timestamp = be16toh( data[ 0 ] );
      81        5285 :   timestamp_reply = be16toh( data[ 1 ] );
      82             : 
      83        5285 :   payload = string( message.text.begin() + 2 * sizeof( uint16_t ), message.text.end() );
      84        5285 : }
      85             : 
      86             : /* Output from packet */
      87     8005333 : Message Packet::toMessage( void )
      88             : {
      89     8005333 :   uint64_t direction_seq = (uint64_t( direction == TO_CLIENT ) << 63) | (seq & SEQUENCE_MASK);
      90             : 
      91     8005333 :   uint16_t ts_net[ 2 ] = { static_cast<uint16_t>( htobe16( timestamp ) ),
      92     8005333 :                            static_cast<uint16_t>( htobe16( timestamp_reply ) ) };
      93             : 
      94     8005333 :   string timestamps = string( (char *)ts_net, 2 * sizeof( uint16_t ) );
      95             : 
      96    16015999 :   return Message( Nonce( direction_seq ), timestamps + payload );
      97     8005333 : }
      98             : 
      99        5333 : Packet Connection::new_packet( const string &s_payload )
     100             : {
     101        5333 :   uint16_t outgoing_timestamp_reply = -1;
     102             : 
     103       10666 :   uint64_t now = timestamp();
     104             : 
     105        5333 :   if ( now - saved_timestamp_received_at < 1000 ) { /* we have a recent received timestamp */
     106             :     /* send "corrected" timestamp advanced by how long we held it */
     107        2839 :     outgoing_timestamp_reply = saved_timestamp + (now - saved_timestamp_received_at);
     108        2839 :     saved_timestamp = -1;
     109        2839 :     saved_timestamp_received_at = 0;
     110             :   }
     111             : 
     112       15999 :   Packet p( direction, timestamp16(), outgoing_timestamp_reply, s_payload );
     113             : 
     114        5333 :   return p;
     115             : }
     116             : 
     117           0 : void Connection::hop_port( void )
     118             : {
     119           0 :   assert( !server );
     120             : 
     121           0 :   setup();
     122           0 :   assert( remote_addr_len != 0 );
     123           0 :   socks.push_back( Socket( remote_addr.sa.sa_family ) );
     124             : 
     125           0 :   prune_sockets();
     126           0 : }
     127             : 
     128        5285 : void Connection::prune_sockets( void )
     129             : {
     130             :   /* don't keep old sockets if the new socket has been working for long enough */
     131        5285 :   if ( socks.size() > 1 ) {
     132           0 :     if ( timestamp() - last_port_choice > MAX_OLD_SOCKET_AGE ) {
     133           0 :       int num_to_kill = socks.size() - 1;
     134           0 :       for ( int i = 0; i < num_to_kill; i++ ) {
     135           0 :         socks.pop_front();
     136             :       }
     137             :     }
     138             :   } else {
     139             :     return;
     140             :   }
     141             : 
     142             :   /* make sure we don't have too many receive sockets open */
     143           0 :   if ( socks.size() > MAX_PORTS_OPEN ) {
     144           0 :     int num_to_kill = socks.size() - MAX_PORTS_OPEN;
     145           0 :     for ( int i = 0; i < num_to_kill; i++ ) {
     146           0 :       socks.pop_front();
     147             :     }
     148             :   }
     149             : }
     150             : 
     151         900 : Connection::Socket::Socket( int family )
     152         900 :   : _fd( socket( family, SOCK_DGRAM, 0 ) )
     153             : {
     154         900 :   if ( _fd < 0 ) {
     155           0 :     throw NetworkException( "socket", errno );
     156             :   }
     157             : 
     158             :   /* Disable path MTU discovery */
     159             : #ifdef HAVE_IP_MTU_DISCOVER
     160         900 :   int flag = IP_PMTUDISC_DONT;
     161         900 :   if ( setsockopt( _fd, IPPROTO_IP, IP_MTU_DISCOVER, &flag, sizeof flag ) < 0 ) {
     162           0 :     throw NetworkException( "setsockopt", errno );
     163             :   }
     164             : #endif
     165             : 
     166             :   //  int dscp = 0x92; /* OS X does not have IPTOS_DSCP_AF42 constant */
     167         900 :   int dscp = 0x02; /* ECN-capable transport only */
     168         900 :   if ( setsockopt( _fd, IPPROTO_IP, IP_TOS, &dscp, sizeof dscp ) < 0 ) {
     169             :     //    perror( "setsockopt( IP_TOS )" );
     170             :   }
     171             : 
     172             :   /* request explicit congestion notification on received datagrams */
     173             : #ifdef HAVE_IP_RECVTOS
     174         900 :   int tosflag = true;
     175         900 :   if ( setsockopt( _fd, IPPROTO_IP, IP_RECVTOS, &tosflag, sizeof tosflag ) < 0
     176         900 :        && family == IPPROTO_IP ) { /* FreeBSD disallows this option on IPv6 sockets. */
     177           0 :     perror( "setsockopt( IP_RECVTOS )" );
     178             :   }
     179             : #endif
     180         900 : }
     181             : 
     182         900 : void Connection::setup( void )
     183             : {
     184           0 :   last_port_choice = timestamp();
     185           0 : }
     186             : 
     187       33132 : const std::vector< int > Connection::fds( void ) const
     188             : {
     189       33132 :   std::vector< int > ret;
     190             : 
     191       33132 :   for ( std::deque< Socket >::const_iterator it = socks.begin();
     192       66264 :         it != socks.end();
     193             :         it++ ) {
     194       33132 :     ret.push_back( it->fd() );
     195             :   }
     196             : 
     197       33132 :   return ret;
     198           0 : }
     199             : 
     200         900 : void Connection::set_MTU( int family )
     201             : {
     202         900 :   switch ( family ) {
     203         900 :   case AF_INET:
     204         900 :     MTU = DEFAULT_IPV4_MTU - IPV4_HEADER_LEN;
     205         900 :     break;
     206           0 :   case AF_INET6:
     207           0 :     MTU = DEFAULT_IPV6_MTU - IPV6_HEADER_LEN;
     208           0 :     break;
     209           0 :   default:
     210           0 :     throw NetworkException( "Unknown address family", 0 );
     211             :   }
     212         900 : }
     213             : 
     214             : class AddrInfo {
     215             : public:
     216             :   struct addrinfo *res;
     217         900 :   AddrInfo( const char *node, const char *service,
     218         900 :             const struct addrinfo *hints ) :
     219         900 :     res( NULL ) {
     220         900 :     int errcode = getaddrinfo( node, service, hints, &res );
     221         900 :     if ( errcode != 0 ) {
     222           0 :       throw NetworkException( std::string( "Bad IP address (" ) + (node != NULL ? node : "(null)") + "): " + gai_strerror( errcode ), 0 );
     223             :     }
     224         900 :   }
     225         448 :   ~AddrInfo() { freeaddrinfo(res); }
     226             : private:
     227             :   AddrInfo(const AddrInfo &);
     228             :   AddrInfo &operator=(const AddrInfo &);
     229             : };
     230             : 
     231         452 : Connection::Connection( const char *desired_ip, const char *desired_port ) /* server */
     232         452 :   : socks(),
     233         452 :     has_remote_addr( false ),
     234         452 :     remote_addr(),
     235         452 :     remote_addr_len( 0 ),
     236         452 :     server( true ),
     237         452 :     MTU( DEFAULT_SEND_MTU ),
     238         452 :     key(),
     239         452 :     session( key ),
     240         452 :     direction( TO_CLIENT ),
     241         452 :     saved_timestamp( -1 ),
     242         452 :     saved_timestamp_received_at( 0 ),
     243         452 :     expected_receiver_seq( 0 ),
     244         452 :     last_heard( -1 ),
     245         452 :     last_port_choice( -1 ),
     246         452 :     last_roundtrip_success( -1 ),
     247         452 :     RTT_hit( false ),
     248         452 :     SRTT( 1000 ),
     249         452 :     RTTVAR( 500 ),
     250         452 :     send_error()
     251             : {
     252         904 :   setup();
     253             : 
     254             :   /* The mosh wrapper always gives an IP request, in order
     255             :      to deal with multihomed servers. The port is optional. */
     256             : 
     257             :   /* If an IP request is given, we try to bind to that IP, but we also
     258             :      try INADDR_ANY. If a port request is given, we bind only to that port. */
     259             : 
     260             :   /* convert port numbers */
     261         452 :   int desired_port_low = -1;
     262         452 :   int desired_port_high = -1;
     263             : 
     264         452 :   if ( desired_port && !parse_portrange( desired_port, desired_port_low, desired_port_high ) ) {
     265           0 :     throw NetworkException("Invalid port range", 0);
     266             :   }
     267             : 
     268             :   /* try to bind to desired IP first */
     269         452 :   if ( desired_ip ) {
     270         452 :     try {
     271         452 :       if ( try_bind( desired_ip, desired_port_low, desired_port_high ) ) { return; }
     272           0 :     } catch ( const NetworkException &e ) {
     273           0 :       fprintf( stderr, "Error binding to IP %s: %s\n",
     274             :                desired_ip,
     275           0 :                e.what() );
     276           0 :     }
     277             :   }
     278             : 
     279             :   /* now try any local interface */
     280           0 :   try {
     281           0 :     if ( try_bind( NULL, desired_port_low, desired_port_high ) ) { return; }
     282           0 :   } catch ( const NetworkException &e ) {
     283           0 :     fprintf( stderr, "Error binding to any interface: %s\n",
     284           0 :              e.what() );
     285           0 :     throw; /* this time it's fatal */
     286           0 :   }
     287             : 
     288           0 :   throw NetworkException( "Could not bind", errno );
     289           0 : }
     290             : 
     291         452 : bool Connection::try_bind( const char *addr, int port_low, int port_high )
     292             : {
     293         452 :   struct addrinfo hints;
     294         452 :   memset( &hints, 0, sizeof( hints ) );
     295         452 :   hints.ai_family = AF_UNSPEC;
     296         452 :   hints.ai_socktype = SOCK_DGRAM;
     297         452 :   hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST | AI_NUMERICSERV;
     298         452 :   AddrInfo ai( addr, "0", &hints );
     299             : 
     300         452 :   Addr local_addr;
     301         452 :   socklen_t local_addr_len = ai.res->ai_addrlen;
     302         452 :   memcpy( &local_addr.sa, ai.res->ai_addr, local_addr_len );
     303             : 
     304         452 :   int search_low = PORT_RANGE_LOW, search_high = PORT_RANGE_HIGH;
     305             : 
     306         452 :   if ( port_low != -1 ) { /* low port preference */
     307           0 :     search_low = port_low;
     308             :   }
     309         452 :   if ( port_high != -1 ) { /* high port preference */
     310           0 :     search_high = port_high;
     311             :   }
     312             : 
     313         904 :   socks.push_back( Socket( local_addr.sa.sa_family ) );
     314        1874 :   for ( int i = search_low; i <= search_high; i++ ) {
     315        1874 :     switch (local_addr.sa.sa_family) {
     316        1874 :     case AF_INET:
     317        1874 :       local_addr.sin.sin_port = htons( i );
     318        1874 :       break;
     319           0 :     case AF_INET6:
     320           0 :       local_addr.sin6.sin6_port = htons( i );
     321           0 :       break;
     322           0 :     default:
     323           0 :       throw NetworkException( "Unknown address family", 0 );
     324             :     }
     325             : 
     326        1874 :     if ( local_addr.sa.sa_family == AF_INET6
     327           0 :       && memcmp(&local_addr.sin6.sin6_addr, &in6addr_any, sizeof(in6addr_any)) == 0 ) {
     328           0 :       const int off = 0;
     329           0 :       if ( setsockopt( sock(), IPPROTO_IPV6, IPV6_V6ONLY, &off, sizeof(off) ) ) {
     330           0 :         perror( "setsockopt( IPV6_V6ONLY, off )" );
     331             :       }
     332             :     }
     333             : 
     334        1874 :     if ( ::bind( sock(), &local_addr.sa, local_addr_len ) == 0 ) {
     335         452 :       set_MTU( local_addr.sa.sa_family );
     336         452 :       return true;
     337             :     } // else fallthrough to below code, on last iteration.
     338             :   }
     339           0 :   int saved_errno = errno;
     340           0 :   socks.pop_back();
     341           0 :   char host[ NI_MAXHOST ], serv[ NI_MAXSERV ];
     342           0 :   int errcode = getnameinfo( &local_addr.sa, local_addr_len,
     343             :                              host, sizeof( host ), serv, sizeof( serv ),
     344             :                              NI_DGRAM | NI_NUMERICHOST | NI_NUMERICSERV );
     345           0 :   if ( errcode != 0 ) {
     346           0 :     throw NetworkException( std::string( "bind: getnameinfo: " ) + gai_strerror( errcode ), 0 );
     347             :   }
     348           0 :   fprintf( stderr, "Failed binding to %s:%s\n",
     349             :            host, serv );
     350           0 :   throw NetworkException( "bind", saved_errno );
     351         452 : }
     352             : 
     353         448 : Connection::Connection( const char *key_str, const char *ip, const char *port ) /* client */
     354         448 :   : socks(),
     355         448 :     has_remote_addr( false ),
     356         448 :     remote_addr(),
     357         448 :     remote_addr_len( 0 ),
     358         448 :     server( false ),
     359         448 :     MTU( DEFAULT_SEND_MTU ),
     360         448 :     key( key_str ),
     361         448 :     session( key ),
     362         448 :     direction( TO_SERVER ),
     363         448 :     saved_timestamp( -1 ),
     364         448 :     saved_timestamp_received_at( 0 ),
     365         448 :     expected_receiver_seq( 0 ),
     366         448 :     last_heard( -1 ),
     367         448 :     last_port_choice( -1 ),
     368         448 :     last_roundtrip_success( -1 ),
     369         448 :     RTT_hit( false ),
     370         448 :     SRTT( 1000 ),
     371         448 :     RTTVAR( 500 ),
     372         448 :     send_error()
     373             : {
     374         896 :   setup();
     375             : 
     376             :   /* associate socket with remote host and port */
     377         448 :   struct addrinfo hints;
     378         448 :   memset( &hints, 0, sizeof( hints ) );
     379         448 :   hints.ai_family = AF_UNSPEC;
     380         448 :   hints.ai_socktype = SOCK_DGRAM;
     381         448 :   hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV;
     382         448 :   AddrInfo ai( ip, port, &hints );
     383         448 :   fatal_assert( static_cast<size_t>( ai.res->ai_addrlen ) <= sizeof( remote_addr ) );
     384         448 :   remote_addr_len = ai.res->ai_addrlen;
     385         448 :   memcpy( &remote_addr.sa, ai.res->ai_addr, remote_addr_len );
     386             : 
     387         448 :   has_remote_addr = true;
     388             : 
     389         896 :   socks.push_back( Socket( remote_addr.sa.sa_family ) );
     390             : 
     391         448 :   set_MTU( remote_addr.sa.sa_family );
     392         448 : }
     393             : 
     394        5333 : void Connection::send( const string & s )
     395             : {
     396        5333 :   if ( !has_remote_addr ) {
     397           0 :     return;
     398             :   }
     399             : 
     400        5333 :   Packet px = new_packet( s );
     401             : 
     402        5333 :   string p = session.encrypt( px.toMessage() );
     403             : 
     404        5333 :   ssize_t bytes_sent = sendto( sock(), p.data(), p.size(), MSG_DONTWAIT,
     405        5333 :                                &remote_addr.sa, remote_addr_len );
     406             : 
     407        5333 :   if ( bytes_sent != static_cast<ssize_t>( p.size() ) ) {
     408             :     /* Make sendto() failure available to the frontend. */
     409           0 :     send_error = "sendto: ";
     410           0 :     send_error += strerror( errno );
     411             : 
     412           0 :     if ( errno == EMSGSIZE ) {
     413           0 :       MTU = DEFAULT_SEND_MTU; /* payload MTU of last resort */
     414             :     }
     415             :   }
     416             : 
     417       10666 :   uint64_t now = timestamp();
     418        5333 :   if ( server ) {
     419        3389 :     if ( now - last_heard > SERVER_ASSOCIATION_TIMEOUT ) {
     420           0 :       has_remote_addr = false;
     421        5333 :       fprintf( stderr, "Server now detached from client.\n" );
     422             :     }
     423             :   } else { /* client */
     424        1944 :     if ( ( now - last_port_choice > PORT_HOP_INTERVAL )
     425         284 :          && ( now - last_roundtrip_success > PORT_HOP_INTERVAL ) ) {
     426           0 :       hop_port();
     427             :     }
     428             :   }
     429       10666 : }
     430             : 
     431        5285 : string Connection::recv( void )
     432             : {
     433        5285 :   assert( !socks.empty() );
     434        5285 :   for ( std::deque< Socket >::const_iterator it = socks.begin();
     435        5285 :         it != socks.end();
     436             :         it++ ) {
     437        5285 :     string payload;
     438        5285 :     try {
     439        5285 :       payload = recv_one( it->fd());
     440           0 :     } catch ( NetworkException & e ) {
     441           0 :       if ( (e.the_errno == EAGAIN)
     442             :            || (e.the_errno == EWOULDBLOCK) ) {
     443           0 :         continue;
     444             :       } else {
     445           0 :         throw;
     446             :       }
     447           0 :     }
     448             : 
     449             :     /* succeeded */
     450        5285 :     prune_sockets();
     451       10570 :     return payload;
     452        5285 :   }
     453           0 :   throw NetworkException( "No packet received" );
     454             : }
     455             : 
     456        5285 : string Connection::recv_one( int sock_to_recv )
     457             : {
     458             :   /* receive source address, ECN, and payload in msghdr structure */
     459        5285 :   Addr packet_remote_addr;
     460        5285 :   struct msghdr header;
     461        5285 :   struct iovec msg_iovec;
     462             : 
     463        5285 :   char msg_payload[ Session::RECEIVE_MTU ];
     464        5285 :   char msg_control[ Session::RECEIVE_MTU ];
     465             : 
     466             :   /* receive source address */
     467        5285 :   header.msg_name = &packet_remote_addr;
     468        5285 :   header.msg_namelen = sizeof packet_remote_addr;
     469             : 
     470             :   /* receive payload */
     471        5285 :   msg_iovec.iov_base = msg_payload;
     472        5285 :   msg_iovec.iov_len = sizeof msg_payload;
     473        5285 :   header.msg_iov = &msg_iovec;
     474        5285 :   header.msg_iovlen = 1;
     475             : 
     476             :   /* receive explicit congestion notification */
     477        5285 :   header.msg_control = msg_control;
     478        5285 :   header.msg_controllen = sizeof msg_control;
     479             : 
     480             :   /* receive flags */
     481        5285 :   header.msg_flags = 0;
     482             : 
     483        5285 :   ssize_t received_len = recvmsg( sock_to_recv, &header, MSG_DONTWAIT );
     484             : 
     485        5285 :   if ( received_len < 0 ) {
     486           0 :     throw NetworkException( "recvmsg", errno );
     487             :   }
     488             : 
     489        5285 :   if ( header.msg_flags & MSG_TRUNC ) {
     490           0 :     throw NetworkException( "Received oversize datagram", errno );
     491             :   }
     492             : 
     493             :   /* receive ECN */
     494        5285 :   bool congestion_experienced = false;
     495             : 
     496        5285 :   struct cmsghdr *ecn_hdr = CMSG_FIRSTHDR( &header );
     497        5285 :   if ( ecn_hdr
     498        5285 :        && ecn_hdr->cmsg_level == IPPROTO_IP
     499        5285 :        && ( ecn_hdr->cmsg_type == IP_TOS
     500             : #ifdef IP_RECVTOS
     501        5285 :             || ecn_hdr->cmsg_type == IP_RECVTOS
     502             : #endif
     503             :             ) ) {
     504             :     /* got one */
     505        5285 :     uint8_t *ecn_octet_p = (uint8_t *)CMSG_DATA( ecn_hdr );
     506        5285 :     assert( ecn_octet_p );
     507             : 
     508        5285 :     congestion_experienced = (*ecn_octet_p & 0x03) == 0x03;
     509             :   }
     510             : 
     511        5285 :   Packet p( session.decrypt( msg_payload, received_len ) );
     512             : 
     513        8618 :   dos_assert( p.direction == (server ? TO_SERVER : TO_CLIENT) ); /* prevent malicious playback to sender */
     514             : 
     515        5285 :   if ( p.seq < expected_receiver_seq ) { /* don't use (but do return) out-of-order packets for timestamp or targeting */
     516           0 :     return p.payload;
     517             :   }
     518        5285 :   expected_receiver_seq = p.seq + 1; /* this is security-sensitive because a replay attack could otherwise
     519             :                                         screw up the timestamp and targeting */
     520             : 
     521        5285 :   if ( p.timestamp != uint16_t(-1) ) {
     522        5285 :     saved_timestamp = p.timestamp;
     523       10570 :     saved_timestamp_received_at = timestamp();
     524             : 
     525        5285 :     if ( congestion_experienced ) {
     526             :       /* signal counterparty to slow down */
     527             :       /* this will gradually slow the counterparty down to the minimum frame rate */
     528           0 :       saved_timestamp -= CONGESTION_TIMESTAMP_PENALTY;
     529           0 :       if ( server ) {
     530           0 :         fprintf( stderr, "Received explicit congestion notification.\n" );
     531             :       }
     532             :     }
     533             :   }
     534             : 
     535        5285 :   if ( p.timestamp_reply != uint16_t(-1) ) {
     536        5678 :     uint16_t now = timestamp16();
     537        5678 :     double R = timestamp_diff( now, p.timestamp_reply );
     538             : 
     539        2839 :     if ( R < 5000 ) { /* ignore large values, e.g. server was Ctrl-Zed */
     540        2839 :       if ( !RTT_hit ) { /* first measurement */
     541         900 :         SRTT = R;
     542         900 :         RTTVAR = R / 2;
     543         900 :         RTT_hit = true;
     544             :       } else {
     545        1939 :         const double alpha = 1.0 / 8.0;
     546        1939 :         const double beta = 1.0 / 4.0;
     547             :           
     548        1939 :         RTTVAR = (1 - beta) * RTTVAR + ( beta * fabs( SRTT - R ) );
     549        1939 :         SRTT = (1 - alpha) * SRTT + ( alpha * R );
     550             :       }
     551             :     }
     552             :   }
     553             : 
     554             :   /* auto-adjust to remote host */
     555        5285 :   has_remote_addr = true;
     556       10570 :   last_heard = timestamp();
     557             : 
     558        5285 :   if ( server && /* only client can roam */
     559        1952 :        ( remote_addr_len != header.msg_namelen ||
     560        1500 :          memcmp( &remote_addr, &packet_remote_addr, remote_addr_len ) != 0 ) ) {
     561         452 :     remote_addr = packet_remote_addr;
     562         452 :     remote_addr_len = header.msg_namelen;
     563         452 :     char host[ NI_MAXHOST ], serv[ NI_MAXSERV ];
     564         452 :     int errcode = getnameinfo( &remote_addr.sa, remote_addr_len,
     565             :                                host, sizeof( host ), serv, sizeof( serv ),
     566             :                                NI_DGRAM | NI_NUMERICHOST | NI_NUMERICSERV );
     567         452 :     if ( errcode != 0 ) {
     568           0 :       throw NetworkException( std::string( "recv_one: getnameinfo: " ) + gai_strerror( errcode ), 0 );
     569             :     }
     570         904 :     fprintf( stderr, "Server now attached to client at %s:%s\n",
     571             :              host, serv );
     572             :   }
     573        5285 :   return p.payload;
     574        5285 : }
     575             : 
     576         452 : std::string Connection::port( void ) const
     577             : {
     578         452 :   Addr local_addr;
     579         452 :   socklen_t addrlen = sizeof( local_addr );
     580             : 
     581         452 :   if ( getsockname( sock(), &local_addr.sa, &addrlen ) < 0 ) {
     582           0 :     throw NetworkException( "getsockname", errno );
     583             :   }
     584             : 
     585         452 :   char serv[ NI_MAXSERV ];
     586         452 :   int errcode = getnameinfo( &local_addr.sa, addrlen,
     587             :                              NULL, 0, serv, sizeof( serv ),
     588             :                              NI_DGRAM | NI_NUMERICSERV );
     589         452 :   if ( errcode != 0 ) {
     590           0 :     throw NetworkException( std::string( "port: getnameinfo: " ) + gai_strerror( errcode ), 0 );
     591             :   }
     592             : 
     593         452 :   return std::string( serv );
     594             : }
     595             : 
     596      335721 : uint64_t Network::timestamp( void )
     597             : {
     598      327549 :   return frozen_timestamp();
     599             : }
     600             : 
     601        8172 : uint16_t Network::timestamp16( void )
     602             : {
     603        8172 :   uint16_t ts = timestamp() % 65536;
     604        8172 :   if ( ts == uint16_t(-1) ) {
     605           0 :     ts++;
     606             :   }
     607        5333 :   return ts;
     608             : }
     609             : 
     610        2839 : uint16_t Network::timestamp_diff( uint16_t tsnew, uint16_t tsold )
     611             : {
     612        2839 :   int diff = tsnew - tsold;
     613        2839 :   if ( diff < 0 ) {
     614           1 :     diff += 65536;
     615             :   }
     616             :   
     617        2839 :   assert( diff >= 0 );
     618        2839 :   assert( diff <= 65535 );
     619             : 
     620        2839 :   return diff;
     621             : }
     622             : 
     623      127096 : uint64_t Connection::timeout( void ) const
     624             : {
     625      127096 :   uint64_t RTO = lrint( ceil( SRTT + 4 * RTTVAR ) );
     626      127096 :   if ( RTO < MIN_RTO ) {
     627             :     RTO = MIN_RTO;
     628             :   } else if ( RTO > MAX_RTO ) {
     629             :     RTO = MAX_RTO;
     630             :   }
     631      127096 :   return RTO;
     632             : }
     633             : 
     634        2252 : Connection::Socket::~Socket()
     635             : {
     636        2252 :   fatal_assert ( close( _fd ) == 0 );
     637        2252 : }
     638             : 
     639         900 : Connection::Socket::Socket( const Socket & other )
     640         900 :   : _fd( dup( other._fd ) )
     641             : {
     642         900 :   if ( _fd < 0 ) {
     643           0 :     throw NetworkException( "socket", errno );
     644             :   }
     645         900 : }
     646             : 
     647           0 : Connection::Socket & Connection::Socket::operator=( const Socket & other )
     648             : {
     649           0 :   if ( dup2( other._fd, _fd ) < 0 ) {
     650           0 :     throw NetworkException( "socket", errno );
     651             :   }
     652             : 
     653           0 :   return *this;
     654             : }
     655             : 
     656           0 : bool Connection::parse_portrange( const char * desired_port, int & desired_port_low, int & desired_port_high )
     657             : {
     658             :   /* parse "port" or "portlow:porthigh" */
     659           0 :   desired_port_low = desired_port_high = 0;
     660           0 :   char *end;
     661           0 :   long value;
     662             : 
     663             :   /* parse first (only?) port */
     664           0 :   errno = 0;
     665           0 :   value = strtol( desired_port, &end, 10 );
     666           0 :   if ( (errno != 0) || (*end != '\0' && *end != ':') ) {
     667           0 :     fprintf( stderr, "Invalid (low) port number (%s)\n", desired_port );
     668           0 :     return false;
     669             :   }
     670           0 :   if ( (value < 0) || (value > 65535) ) {
     671           0 :     fprintf( stderr, "(Low) port number %ld outside valid range [0..65535]\n", value );
     672           0 :     return false;
     673             :   }
     674             : 
     675           0 :   desired_port_low = (int)value;
     676           0 :   if (*end == '\0') { /* not a port range */
     677           0 :     desired_port_high = desired_port_low;
     678           0 :     return true;
     679             :   }
     680             :   /* port range; parse high port */
     681           0 :   const char * cp = end + 1;
     682           0 :   errno = 0;
     683           0 :   value = strtol( cp, &end, 10 );
     684           0 :   if ( (errno != 0) || (*end != '\0') ) {
     685           0 :     fprintf( stderr, "Invalid high port number (%s)\n", cp );
     686           0 :     return false;
     687             :   }
     688           0 :   if ( (value < 0) || (value > 65535) ) {
     689           0 :     fprintf( stderr, "High port number %ld outside valid range [0..65535]\n", value );
     690           0 :     return false;
     691             :   }
     692             : 
     693           0 :   desired_port_high = (int)value;
     694           0 :   if ( desired_port_low > desired_port_high ) {
     695           0 :     fprintf( stderr, "Low port %d greater than high port %d\n", desired_port_low, desired_port_high );
     696           0 :     return false;
     697             :   }
     698             : 
     699           0 :   if ( desired_port_low == 0 ) {
     700           0 :     fprintf( stderr, "Low port 0 incompatible with port ranges\n" );
     701           0 :     return false;
     702             :   }
     703             : 
     704             : 
     705             :   return true;
     706             : }

Generated by: LCOV version 1.14