Make TradWeight a simple subclass and deprecate
[xapian.git] / xapian-core / common / socket_utils.cc
blobed9c30f48a70880de6a84d07f2f3fc92ff70ae8e
1 /** @file
2 * @brief Socket handling utilities.
3 */
4 /* Copyright (C) 2006,2007,2008,2015,2018,2023 Olly Betts
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.
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.
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
21 #include <config.h>
22 #include "socket_utils.h"
24 #include <limits>
26 #include "realtime.h"
27 #include "safesyssocket.h"
29 using namespace std;
31 #include "stringutils.h"
33 #ifndef __WIN32__
34 # include <arpa/inet.h>
35 # include <netinet/in.h>
36 #else
37 # include <io.h>
38 # include "msvcignoreinvalidparam.h"
39 # include <cerrno>
41 /// Convert an fd (which might be a socket) to a WIN32 HANDLE.
42 extern HANDLE fd_to_handle(int fd) {
43 MSVCIgnoreInvalidParameter invalid_handle_value_is_ok;
44 HANDLE handle = (HANDLE)_get_osfhandle(fd);
45 if (handle != INVALID_HANDLE_VALUE) return handle;
46 // On WIN32, a socket fd isn't the same as a non-socket fd - in fact it's
47 // already a HANDLE!
49 // We need to convert to intptr_t first to suppress a compiler warning here
50 // about casting an integer to a wider pointer type which is a reasonable
51 // warning in general, but we check that the value isn't truncated before
52 // we cast the HANDLE to int (see common/safesyssocket.h).
53 return reinterpret_cast<HANDLE>(intptr_t(fd));
56 /// Close an fd, which might be a socket.
57 extern void close_fd_or_socket(int fd) {
58 MSVCIgnoreInvalidParameter invalid_fd_value_is_ok;
59 if (close(fd) == -1 && errno == EBADF) {
60 // Bad file descriptor - probably because the fd is actually
61 // a socket.
62 closesocket(fd);
66 #endif
68 void
69 set_socket_timeouts(int fd, double timeout)
71 (void)fd;
72 (void)timeout;
73 #if defined SO_SNDTIMEO || defined SO_RCVTIMEO
75 # ifndef __WIN32__
76 struct timeval t;
77 RealTime::to_timeval(timeout, &t);
78 # else
79 // Just to be different, it's a DWORD counting in milliseconds.
80 DWORD t;
81 if (usual(timeout < numeric_limits<DWORD>::max() / 1000))
82 t = timeout * 1000;
83 else
84 t = numeric_limits<DWORD>::max();
85 # endif
86 # ifdef SO_SNDTIMEO
87 (void)setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO,
88 reinterpret_cast<char*>(&t), sizeof(t));
89 # endif
90 # ifdef SO_RCVTIMEO
91 (void)setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO,
92 reinterpret_cast<char*>(&t), sizeof(t));
93 # endif
95 #endif
96 #ifdef SO_KEEPALIVE
97 // SO_SNDTIMEO and SO_RCVTIMEO may be ignored even if they exist, so set
98 // SO_KEEPALIVE anyway if it exists, as it will cause stuck connections to
99 // time out eventually (though it may take ~2 hours).
101 # ifndef __WIN32__
102 int flag = 1;
103 # else
104 DWORD flag = 1;
105 # endif
106 (void)setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE,
107 reinterpret_cast<char*>(&flag), sizeof(flag));
109 #endif
113 pretty_ip6(const void* p, char* buf)
115 const sockaddr* sa = reinterpret_cast<const sockaddr*>(p);
116 auto af = sa->sa_family;
117 int port;
118 #ifndef __WIN32__
119 const void* src;
120 #endif
121 if (af == AF_INET6) {
122 auto sa6 = reinterpret_cast<const sockaddr_in6*>(p);
123 port = sa6->sin6_port;
124 #ifndef __WIN32__
125 src = &sa6->sin6_addr;
126 #endif
127 } else if (af == AF_INET) {
128 auto sa4 = reinterpret_cast<const sockaddr_in*>(p);
129 port = sa4->sin_port;
130 #ifndef __WIN32__
131 src = &sa4->sin_addr;
132 #endif
133 } else {
134 return -1;
137 #ifndef __WIN32__
138 const char* r = inet_ntop(af, src, buf, PRETTY_IP6_LEN);
139 if (!r)
140 return -1;
141 #else
142 // inet_ntop() isn't always available (at least with mingw) but
143 // WSAAddressToString() supports both IPv4 and IPv6, so just use that.
145 // WSAAddressToString() has a non-const first parameter so we have to cast
146 // away const.
147 DWORD in_size = (af == AF_INET6 ?
148 sizeof(struct sockaddr_in6) :
149 sizeof(struct sockaddr_in));
150 DWORD size = PRETTY_IP6_LEN;
151 if (WSAAddressToString(const_cast<struct sockaddr*>(sa),
152 in_size, NULL, buf, &size) != 0) {
153 return -1;
155 const char* r = buf;
156 #endif
158 if (startswith(r, "::ffff:") || startswith(r, "::FFFF:")) {
159 if (strchr(r + 7, '.')) {
160 r += 7;
164 if (r != buf)
165 memmove(buf, r, strlen(r) + 1);
167 return port;