LCOV - code coverage report
Current view: top level - common - socket_utils.cc (source / functions) Hit Total Coverage
Test: Test Coverage for xapian-core 954b5873a738 Lines: 12 25 48.0 %
Date: 2019-06-30 05:20:33 Functions: 1 2 50.0 %
Branches: 13 36 36.1 %

           Branch data     Line data    Source code
       1                 :            : /** @file  socket_utils.cc
       2                 :            :  *  @brief Socket handling utilities.
       3                 :            :  */
       4                 :            : /* Copyright (C) 2006,2007,2008,2015,2018 Olly Betts
       5                 :            :  *
       6                 :            :  * This program is free software; you can redistribute it and/or modify
       7                 :            :  * it under the terms of the GNU General Public License as published by
       8                 :            :  * the Free Software Foundation; either version 2 of the License, or
       9                 :            :  * (at your option) any later version.
      10                 :            :  *
      11                 :            :  * This program is distributed in the hope that it will be useful,
      12                 :            :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13                 :            :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14                 :            :  * GNU General Public License for more details.
      15                 :            :  *
      16                 :            :  * You should have received a copy of the GNU General Public License
      17                 :            :  * along with this program; if not, write to the Free Software
      18                 :            :  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
      19                 :            :  */
      20                 :            : 
      21                 :            : #include <config.h>
      22                 :            : #include "socket_utils.h"
      23                 :            : 
      24                 :            : #include <limits>
      25                 :            : 
      26                 :            : #include "realtime.h"
      27                 :            : #include "safesyssocket.h"
      28                 :            : 
      29                 :            : using namespace std;
      30                 :            : 
      31                 :            : #include "stringutils.h"
      32                 :            : 
      33                 :            : #ifndef __WIN32__
      34                 :            : # include <arpa/inet.h>
      35                 :            : #else
      36                 :            : # include <io.h>
      37                 :            : # include "msvcignoreinvalidparam.h"
      38                 :            : # include <cerrno>
      39                 :            : 
      40                 :            : /// Convert an fd (which might be a socket) to a WIN32 HANDLE.
      41                 :            : extern HANDLE fd_to_handle(int fd) {
      42                 :            :     MSVCIgnoreInvalidParameter invalid_handle_value_is_ok;
      43                 :            :     HANDLE handle = (HANDLE)_get_osfhandle(fd);
      44                 :            :     if (handle != INVALID_HANDLE_VALUE) return handle;
      45                 :            :     // On WIN32, a socket fd isn't the same as a non-socket fd - in fact it's
      46                 :            :     // already a HANDLE!
      47                 :            :     return reinterpret_cast<HANDLE>(fd);
      48                 :            : }
      49                 :            : 
      50                 :            : /// Close an fd, which might be a socket.
      51                 :            : extern void close_fd_or_socket(int fd) {
      52                 :            :     MSVCIgnoreInvalidParameter invalid_fd_value_is_ok;
      53                 :            :     if (close(fd) == -1 && errno == EBADF) {
      54                 :            :         // Bad file descriptor - probably because the fd is actually
      55                 :            :         // a socket.
      56                 :            :         closesocket(fd);
      57                 :            :     }
      58                 :            : }
      59                 :            : 
      60                 :            : #endif
      61                 :            : 
      62                 :            : void
      63                 :          0 : set_socket_timeouts(int fd, double timeout)
      64                 :            : {
      65                 :            :     (void)fd;
      66                 :            :     (void)timeout;
      67                 :            : #if defined SO_SNDTIMEO || defined SO_RCVTIMEO
      68                 :            :     {
      69                 :            : # ifndef __WIN32__
      70                 :            :         struct timeval t;
      71                 :          0 :         RealTime::to_timeval(timeout, &t);
      72                 :            : # else
      73                 :            :         // Just to be different, it's a DWORD counting in milliseconds.
      74                 :            :         DWORD t;
      75                 :            :         if (usual(timeout < numeric_limits<DWORD>::max() / 1000))
      76                 :            :             t = timeout * 1000;
      77                 :            :         else
      78                 :            :             t = numeric_limits<DWORD>::max();
      79                 :            : # endif
      80                 :            : # ifdef SO_SNDTIMEO
      81                 :            :         (void)setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO,
      82                 :          0 :                          reinterpret_cast<char*>(&t), sizeof(t));
      83                 :            : # endif
      84                 :            : # ifdef SO_RCVTIMEO
      85                 :            :         (void)setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO,
      86                 :          0 :                          reinterpret_cast<char*>(&t), sizeof(t));
      87                 :            : # endif
      88                 :            :     }
      89                 :            : #endif
      90                 :            : #ifdef SO_KEEPALIVE
      91                 :            :     // SO_SNDTIMEO and SO_RCVTIMEO may be ignored even if they exist, so set
      92                 :            :     // SO_KEEPALIVE anyway if it exists, as it will cause stuck connections to
      93                 :            :     // time out eventually (though it may take ~2 hours).
      94                 :            :     {
      95                 :            : # ifndef __WIN32__
      96                 :          0 :         int flag = 1;
      97                 :            : # else
      98                 :            :         DWORD flag = 1;
      99                 :            : # endif
     100                 :            :         (void)setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE,
     101                 :          0 :                          reinterpret_cast<char*>(&flag), sizeof(flag));
     102                 :            :     }
     103                 :            : #endif
     104                 :          0 : }
     105                 :            : 
     106                 :            : int
     107                 :        383 : pretty_ip6(const void* p, char* buf)
     108                 :            : {
     109                 :        383 :     const sockaddr* sa = reinterpret_cast<const sockaddr*>(p);
     110                 :        383 :     auto af = sa->sa_family;
     111                 :            :     int port;
     112         [ -  + ]:        383 :     if (af == AF_INET6) {
     113                 :          0 :         port = (reinterpret_cast<const sockaddr_in6*>(p))->sin6_port;
     114         [ +  - ]:        383 :     } else if (af == AF_INET) {
     115                 :        383 :         port = (reinterpret_cast<const sockaddr_in*>(p))->sin_port;
     116                 :            :     } else {
     117                 :          0 :         return -1;
     118                 :            :     }
     119                 :            : 
     120                 :            :     // WSAAddressToString() has a non-const first parameter.
     121                 :            :     //
     122                 :            :     // The mingw headers at least are also missing const from the corresponding
     123                 :            :     // (second) parameter of inet_ntop(), so just cast away the const in case
     124                 :            :     // this is more widespread.
     125                 :        383 :     auto src = reinterpret_cast<struct sockaddr*>(const_cast<void*>(p));
     126                 :            : #ifndef __WIN32__
     127                 :        383 :     const char* r = inet_ntop(af, src, buf, PRETTY_IP6_LEN);
     128         [ -  + ]:        383 :     if (!r)
     129                 :          0 :         return -1;
     130                 :            : #else
     131                 :            :     // inet_ntop() isn't always available, at least with mingw.
     132                 :            :     // WSAAddressToString() supports both IPv4 and IPv6, so just use that.
     133                 :            :     DWORD in_size = (af == AF_INET6 ?
     134                 :            :                      sizeof(struct sockaddr_in6) :
     135                 :            :                      sizeof(struct sockaddr_in));
     136                 :            :     DWORD size = PRETTY_IP6_LEN;
     137                 :            :     if (WSAAddressToString(src, in_size, NULL, buf, &size) != 0) {
     138                 :            :         return -1;
     139                 :            :     }
     140                 :            :     const char* r = buf;
     141                 :            : #endif
     142                 :            : 
     143 [ +  - ][ +  - ]:        383 :     if (startswith(r, "::ffff:") || startswith(r, "::FFFF:")) {
         [ +  - ][ -  + ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
           [ -  +  #  #  
          #  #  #  #  #  
                      # ]
     144         [ #  # ]:          0 :         if (strchr(r + 7, '.')) {
     145                 :          0 :             r += 7;
     146                 :            :         }
     147                 :            :     }
     148                 :            : 
     149         [ -  + ]:        383 :     if (r != buf)
     150                 :          0 :         memmove(buf, r, strlen(r) + 1);
     151                 :            : 
     152                 :        383 :     return port;
     153                 :            : }

Generated by: LCOV version 1.11