cpp-common/bt2c/fmt.hpp: use `wise_enum::string_type` in `EnableIfIsWiseEnum` definition
[babeltrace.git] / src / compat / socket.hpp
1 /*
2 * SPDX-License-Identifier: MIT
3 *
4 * Copyright (C) 2015-2017 Michael Jeanson <mjeanson@efficios.com>
5 * Copyright (C) 2015 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
6 */
7
8 #ifndef BABELTRACE_COMPAT_SOCKET_HPP
9 #define BABELTRACE_COMPAT_SOCKET_HPP
10
11 #include <stdbool.h>
12
13 #include "cpp-common/bt2c/logging.hpp"
14
15 #ifdef __MINGW32__
16
17 # include <winsock2.h>
18
19 # define BT_INVALID_SOCKET INVALID_SOCKET
20 # define BT_SOCKET_ERROR SOCKET_ERROR
21 # define BT_SOCKET SOCKET
22
23 static inline int bt_socket_init(const bt2c::Logger& logger)
24 {
25 WORD verreq;
26 WSADATA wsa;
27 int ret;
28
29 /* Request winsock 2.2 support */
30 verreq = MAKEWORD(2, 2);
31
32 ret = WSAStartup(verreq, &wsa);
33 if (ret != 0) {
34 BT_CPPLOGE_SPEC(logger, "Winsock init failed with error: {}", ret);
35 goto end;
36 }
37
38 if (LOBYTE(wsa.wVersion) != 2 || HIBYTE(wsa.wVersion) != 2) {
39 BT_CPPLOGE_SPEC(logger, "Could not init winsock 2.2 support");
40 WSACleanup();
41 ret = -1;
42 }
43
44 end:
45 return ret;
46 }
47
48 static inline int bt_socket_fini(void)
49 {
50 return WSACleanup();
51 }
52
53 static inline int bt_socket_send(int sockfd, const void *buf, size_t len, int flags)
54 {
55 return send(sockfd, (const char *) buf, len, flags);
56 }
57
58 static inline int bt_socket_recv(int sockfd, void *buf, size_t len, int flags)
59 {
60 return recv(sockfd, (char *) buf, len, flags);
61 }
62
63 static inline int bt_socket_close(int fd)
64 {
65 return closesocket(fd);
66 }
67
68 static inline bool bt_socket_interrupted(void)
69 {
70 /* There is no equivalent to EINTR in winsock 2.2 */
71 return false;
72 }
73
74 static inline const char *bt_socket_errormsg(void)
75 {
76 const char *errstr;
77 int error = WSAGetLastError();
78
79 switch (error) {
80 case WSAEINTR:
81 errstr = "Call interrupted";
82 break;
83 case WSAEBADF:
84 errstr = "Bad file";
85 break;
86 case WSAEACCES:
87 errstr = "Bad access";
88 break;
89 case WSAEFAULT:
90 errstr = "Bad argument";
91 break;
92 case WSAEINVAL:
93 errstr = "Invalid arguments";
94 break;
95 case WSAEMFILE:
96 errstr = "Out of file descriptors";
97 break;
98 case WSAEWOULDBLOCK:
99 errstr = "Call would block";
100 break;
101 case WSAEINPROGRESS:
102 case WSAEALREADY:
103 errstr = "Blocking call in progress";
104 break;
105 case WSAENOTSOCK:
106 errstr = "Descriptor is not a socket";
107 break;
108 case WSAEDESTADDRREQ:
109 errstr = "Need destination address";
110 break;
111 case WSAEMSGSIZE:
112 errstr = "Bad message size";
113 break;
114 case WSAEPROTOTYPE:
115 errstr = "Bad protocol";
116 break;
117 case WSAENOPROTOOPT:
118 errstr = "Protocol option is unsupported";
119 break;
120 case WSAEPROTONOSUPPORT:
121 errstr = "Protocol is unsupported";
122 break;
123 case WSAESOCKTNOSUPPORT:
124 errstr = "Socket is unsupported";
125 break;
126 case WSAEOPNOTSUPP:
127 errstr = "Operation not supported";
128 break;
129 case WSAEAFNOSUPPORT:
130 errstr = "Address family not supported";
131 break;
132 case WSAEPFNOSUPPORT:
133 errstr = "Protocol family not supported";
134 break;
135 case WSAEADDRINUSE:
136 errstr = "Address already in use";
137 break;
138 case WSAEADDRNOTAVAIL:
139 errstr = "Address not available";
140 break;
141 case WSAENETDOWN:
142 errstr = "Network down";
143 break;
144 case WSAENETUNREACH:
145 errstr = "Network unreachable";
146 break;
147 case WSAENETRESET:
148 errstr = "Network has been reset";
149 break;
150 case WSAECONNABORTED:
151 errstr = "Connection was aborted";
152 break;
153 case WSAECONNRESET:
154 errstr = "Connection was reset";
155 break;
156 case WSAENOBUFS:
157 errstr = "No buffer space";
158 break;
159 case WSAEISCONN:
160 errstr = "Socket is already connected";
161 break;
162 case WSAENOTCONN:
163 errstr = "Socket is not connected";
164 break;
165 case WSAESHUTDOWN:
166 errstr = "Socket has been shut down";
167 break;
168 case WSAETOOMANYREFS:
169 errstr = "Too many references";
170 break;
171 case WSAETIMEDOUT:
172 errstr = "Timed out";
173 break;
174 case WSAECONNREFUSED:
175 errstr = "Connection refused";
176 break;
177 case WSAELOOP:
178 errstr = "Loop??";
179 break;
180 case WSAENAMETOOLONG:
181 errstr = "Name too long";
182 break;
183 case WSAEHOSTDOWN:
184 errstr = "Host down";
185 break;
186 case WSAEHOSTUNREACH:
187 errstr = "Host unreachable";
188 break;
189 case WSAENOTEMPTY:
190 errstr = "Not empty";
191 break;
192 case WSAEPROCLIM:
193 errstr = "Process limit reached";
194 break;
195 case WSAEUSERS:
196 errstr = "Too many users";
197 break;
198 case WSAEDQUOT:
199 errstr = "Bad quota";
200 break;
201 case WSAESTALE:
202 errstr = "Something is stale";
203 break;
204 case WSAEREMOTE:
205 errstr = "Remote error";
206 break;
207 case WSAEDISCON:
208 errstr = "Disconnected";
209 break;
210
211 /* Extended Winsock errors */
212 case WSASYSNOTREADY:
213 errstr = "Winsock library is not ready";
214 break;
215 case WSANOTINITIALISED:
216 errstr = "Winsock library not initialised";
217 break;
218 case WSAVERNOTSUPPORTED:
219 errstr = "Winsock version not supported";
220 break;
221
222 /* getXbyY() errors (already handled in herrmsg):
223 * Authoritative Answer: Host not found */
224 case WSAHOST_NOT_FOUND:
225 errstr = "Host not found";
226 break;
227
228 /* Non-Authoritative: Host not found, or SERVERFAIL */
229 case WSATRY_AGAIN:
230 errstr = "Host not found, try again";
231 break;
232
233 /* Non recoverable errors, FORMERR, REFUSED, NOTIMP */
234 case WSANO_RECOVERY:
235 errstr = "Unrecoverable error in call to nameserver";
236 break;
237
238 /* Valid name, no data record of requested type */
239 case WSANO_DATA:
240 errstr = "No data record of requested type";
241 break;
242
243 default:
244 errstr = "Unknown error";
245 }
246
247 return errstr;
248 }
249
250 #else /* __MINGW32__ */
251
252 # include <errno.h>
253 # include <glib.h>
254 # include <netdb.h>
255 # include <netinet/in.h>
256 # include <sys/socket.h>
257 # include <unistd.h>
258
259 # define BT_INVALID_SOCKET -1
260 # define BT_SOCKET_ERROR -1
261 # define BT_SOCKET int
262
263 static inline int bt_socket_init(const bt2c::Logger&)
264 {
265 return 0;
266 }
267
268 static inline int bt_socket_fini(void)
269 {
270 return 0;
271 }
272
273 static inline int bt_socket_send(int sockfd, const void *buf, size_t len, int flags)
274 {
275 return send(sockfd, buf, len, flags);
276 }
277
278 static inline int bt_socket_recv(int sockfd, void *buf, size_t len, int flags)
279 {
280 return recv(sockfd, buf, len, flags);
281 }
282
283 static inline int bt_socket_close(int fd)
284 {
285 return close(fd);
286 }
287
288 static inline bool bt_socket_interrupted(void)
289 {
290 return (errno == EINTR);
291 }
292
293 static inline const char *bt_socket_errormsg(void)
294 {
295 return g_strerror(errno);
296 }
297 #endif
298
299 /*
300 * This wrapper is used on platforms that have no way of ignoring SIGPIPE
301 * during a send().
302 */
303
304 #ifndef MSG_NOSIGNAL
305 # ifdef SO_NOSIGPIPE
306 # define MSG_NOSIGNAL SO_NOSIGPIPE
307 # elif defined(__MINGW32__)
308 # define MSG_NOSIGNAL 0
309 # endif
310 #endif
311
312 #if defined(MSG_NOSIGNAL)
313 static inline ssize_t bt_socket_send_nosigpipe(int fd, const void *buffer, size_t size)
314 {
315 return bt_socket_send(fd, buffer, size, MSG_NOSIGNAL);
316 }
317 #else
318
319 # include <signal.h>
320
321 static inline ssize_t bt_socket_send_nosigpipe(int fd, const void *buffer, size_t size)
322 {
323 ssize_t sent;
324 int saved_err;
325 sigset_t sigpipe_set, pending_set, old_set;
326 int sigpipe_was_pending;
327
328 /*
329 * Discard the SIGPIPE from send(), not disturbing any SIGPIPE
330 * that might be already pending. If a bogus SIGPIPE is sent to
331 * the entire process concurrently by a malicious user, it may
332 * be simply discarded.
333 */
334 if (sigemptyset(&pending_set)) {
335 return -1;
336 }
337 /*
338 * sigpending returns the mask of signals that are _both_
339 * blocked for the thread _and_ pending for either the thread or
340 * the entire process.
341 */
342 if (sigpending(&pending_set)) {
343 return -1;
344 }
345 sigpipe_was_pending = sigismember(&pending_set, SIGPIPE);
346 /*
347 * If sigpipe was pending, it means it was already blocked, so
348 * no need to block it.
349 */
350 if (!sigpipe_was_pending) {
351 if (sigemptyset(&sigpipe_set)) {
352 return -1;
353 }
354 if (sigaddset(&sigpipe_set, SIGPIPE)) {
355 return -1;
356 }
357 if (pthread_sigmask(SIG_BLOCK, &sigpipe_set, &old_set)) {
358 return -1;
359 }
360 }
361
362 /* Send and save errno. */
363 sent = bt_socket_send(fd, buffer, size, 0);
364 saved_err = errno;
365
366 if (sent == -1 && errno == EPIPE && !sigpipe_was_pending) {
367 struct timespec timeout = {0, 0};
368 int ret;
369
370 do {
371 ret = sigtimedwait(&sigpipe_set, NULL, &timeout);
372 } while (ret == -1 && errno == EINTR);
373 }
374 if (!sigpipe_was_pending) {
375 if (pthread_sigmask(SIG_SETMASK, &old_set, NULL)) {
376 return -1;
377 }
378 }
379 /* Restore send() errno */
380 errno = saved_err;
381
382 return sent;
383 }
384 #endif
385
386 #endif /* BABELTRACE_COMPAT_SOCKET_HPP */
This page took 0.036417 seconds and 4 git commands to generate.