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