#ifndef _BABELTRACE_COMPAT_SOCKET_H #define _BABELTRACE_COMPAT_SOCKET_H /* * Copyright (C) 2015-2017 Michael Jeanson * 2015 Mathieu Desnoyers * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include #ifdef __MINGW32__ #include #define BT_INVALID_SOCKET INVALID_SOCKET #define BT_SOCKET_ERROR SOCKET_ERROR #define BT_SOCKET SOCKET static inline int bt_socket_init(int log_level) { WORD verreq; WSADATA wsa; int ret; /* Request winsock 2.2 support */ verreq = MAKEWORD(2, 2); ret = WSAStartup(verreq, &wsa); if (ret != 0) { #ifdef BT_LOG_WRITE_CUR_LVL BT_LOG_WRITE_CUR_LVL(BT_LOG_ERROR, log_level, BT_LOG_TAG, "Winsock init failed with error: %d", ret); #endif goto end; } if (LOBYTE(wsa.wVersion) != 2 || HIBYTE(wsa.wVersion) != 2) { #ifdef BT_LOG_WRITE_CUR_LVL BT_LOG_WRITE_CUR_LVL(BT_LOG_ERROR, log_level, BT_LOG_TAG, "Could not init winsock 2.2 support"); #endif WSACleanup(); ret = -1; } end: return ret; } static inline int bt_socket_fini(void) { return WSACleanup(); } static inline int bt_socket_send(int sockfd, const void *buf, size_t len, int flags) { return send(sockfd, buf, len, flags); } static inline int bt_socket_recv(int sockfd, void *buf, size_t len, int flags) { return recv(sockfd, buf, len, flags); } static inline int bt_socket_close(int fd) { return closesocket(fd); } static inline bool bt_socket_interrupted(void) { /* There is no equivalent to EINTR in winsock 2.2 */ return false; } static inline const char *bt_socket_errormsg(void) { const char *errstr; int error = WSAGetLastError(); switch (error) { case WSAEINTR: errstr = "Call interrupted"; break; case WSAEBADF: errstr = "Bad file"; break; case WSAEACCES: errstr = "Bad access"; break; case WSAEFAULT: errstr = "Bad argument"; break; case WSAEINVAL: errstr = "Invalid arguments"; break; case WSAEMFILE: errstr = "Out of file descriptors"; break; case WSAEWOULDBLOCK: errstr = "Call would block"; break; case WSAEINPROGRESS: case WSAEALREADY: errstr = "Blocking call in progress"; break; case WSAENOTSOCK: errstr = "Descriptor is not a socket"; break; case WSAEDESTADDRREQ: errstr = "Need destination address"; break; case WSAEMSGSIZE: errstr = "Bad message size"; break; case WSAEPROTOTYPE: errstr = "Bad protocol"; break; case WSAENOPROTOOPT: errstr = "Protocol option is unsupported"; break; case WSAEPROTONOSUPPORT: errstr = "Protocol is unsupported"; break; case WSAESOCKTNOSUPPORT: errstr = "Socket is unsupported"; break; case WSAEOPNOTSUPP: errstr = "Operation not supported"; break; case WSAEAFNOSUPPORT: errstr = "Address family not supported"; break; case WSAEPFNOSUPPORT: errstr = "Protocol family not supported"; break; case WSAEADDRINUSE: errstr = "Address already in use"; break; case WSAEADDRNOTAVAIL: errstr = "Address not available"; break; case WSAENETDOWN: errstr = "Network down"; break; case WSAENETUNREACH: errstr = "Network unreachable"; break; case WSAENETRESET: errstr = "Network has been reset"; break; case WSAECONNABORTED: errstr = "Connection was aborted"; break; case WSAECONNRESET: errstr = "Connection was reset"; break; case WSAENOBUFS: errstr = "No buffer space"; break; case WSAEISCONN: errstr = "Socket is already connected"; break; case WSAENOTCONN: errstr = "Socket is not connected"; break; case WSAESHUTDOWN: errstr = "Socket has been shut down"; break; case WSAETOOMANYREFS: errstr = "Too many references"; break; case WSAETIMEDOUT: errstr = "Timed out"; break; case WSAECONNREFUSED: errstr = "Connection refused"; break; case WSAELOOP: errstr = "Loop??"; break; case WSAENAMETOOLONG: errstr = "Name too long"; break; case WSAEHOSTDOWN: errstr = "Host down"; break; case WSAEHOSTUNREACH: errstr = "Host unreachable"; break; case WSAENOTEMPTY: errstr = "Not empty"; break; case WSAEPROCLIM: errstr = "Process limit reached"; break; case WSAEUSERS: errstr = "Too many users"; break; case WSAEDQUOT: errstr = "Bad quota"; break; case WSAESTALE: errstr = "Something is stale"; break; case WSAEREMOTE: errstr = "Remote error"; break; case WSAEDISCON: errstr = "Disconnected"; break; /* Extended Winsock errors */ case WSASYSNOTREADY: errstr = "Winsock library is not ready"; break; case WSANOTINITIALISED: errstr = "Winsock library not initialised"; break; case WSAVERNOTSUPPORTED: errstr = "Winsock version not supported"; break; /* getXbyY() errors (already handled in herrmsg): * Authoritative Answer: Host not found */ case WSAHOST_NOT_FOUND: errstr = "Host not found"; break; /* Non-Authoritative: Host not found, or SERVERFAIL */ case WSATRY_AGAIN: errstr = "Host not found, try again"; break; /* Non recoverable errors, FORMERR, REFUSED, NOTIMP */ case WSANO_RECOVERY: errstr = "Unrecoverable error in call to nameserver"; break; /* Valid name, no data record of requested type */ case WSANO_DATA: errstr = "No data record of requested type"; break; default: errstr = "Unknown error"; } return errstr; } #else /* __MINGW32__ */ #include #include #include #include #include #include #define BT_INVALID_SOCKET -1 #define BT_SOCKET_ERROR -1 #define BT_SOCKET int static inline int bt_socket_init(int log_level) { return 0; } static inline int bt_socket_fini(void) { return 0; } static inline int bt_socket_send(int sockfd, const void *buf, size_t len, int flags) { return send(sockfd, buf, len, flags); } static inline int bt_socket_recv(int sockfd, void *buf, size_t len, int flags) { return recv(sockfd, buf, len, flags); } static inline int bt_socket_close(int fd) { return close(fd); } static inline bool bt_socket_interrupted(void) { return (errno == EINTR); } static inline const char *bt_socket_errormsg(void) { return g_strerror(errno); } #endif /* * This wrapper is used on platforms that have no way of ignoring SIGPIPE * during a send(). */ #ifndef MSG_NOSIGNAL # ifdef SO_NOSIGPIPE # define MSG_NOSIGNAL SO_NOSIGPIPE # elif defined(__MINGW32__) # define MSG_NOSIGNAL 0 # endif #endif #if defined(MSG_NOSIGNAL) static inline ssize_t bt_socket_send_nosigpipe(int fd, const void *buffer, size_t size) { return bt_socket_send(fd, buffer, size, MSG_NOSIGNAL); } #else #include static inline ssize_t bt_socket_send_nosigpipe(int fd, const void *buffer, size_t size) { ssize_t sent; int saved_err; sigset_t sigpipe_set, pending_set, old_set; int sigpipe_was_pending; /* * Discard the SIGPIPE from send(), not disturbing any SIGPIPE * that might be already pending. If a bogus SIGPIPE is sent to * the entire process concurrently by a malicious user, it may * be simply discarded. */ if (sigemptyset(&pending_set)) { return -1; } /* * sigpending returns the mask of signals that are _both_ * blocked for the thread _and_ pending for either the thread or * the entire process. */ if (sigpending(&pending_set)) { return -1; } sigpipe_was_pending = sigismember(&pending_set, SIGPIPE); /* * If sigpipe was pending, it means it was already blocked, so * no need to block it. */ if (!sigpipe_was_pending) { if (sigemptyset(&sigpipe_set)) { return -1; } if (sigaddset(&sigpipe_set, SIGPIPE)) { return -1; } if (pthread_sigmask(SIG_BLOCK, &sigpipe_set, &old_set)) { return -1; } } /* Send and save errno. */ sent = bt_socket_send(fd, buffer, size, 0); saved_err = errno; if (sent == -1 && errno == EPIPE && !sigpipe_was_pending) { struct timespec timeout = { 0, 0 }; int ret; do { ret = sigtimedwait(&sigpipe_set, NULL, &timeout); } while (ret == -1 && errno == EINTR); } if (!sigpipe_was_pending) { if (pthread_sigmask(SIG_SETMASK, &old_set, NULL)) { return -1; } } /* Restore send() errno */ errno = saved_err; return sent; } #endif #endif /* _BABELTRACE_COMPAT_SOCKET_H */