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