X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fio-layer%2Fsockets.c;h=60429573c07f8f6e66f4b37aa6d0a80aa8428b74;hb=ca327b1162f17986d5c41c1ac1dd3aec6c89744b;hp=edb8e3aad1d2852a3cdf0e1bb0e06bbffc9431f4;hpb=f8d637595ce702376cd21a716c854bc03868ef11;p=mono.git diff --git a/mono/io-layer/sockets.c b/mono/io-layer/sockets.c index edb8e3aad1d..60429573c07 100644 --- a/mono/io-layer/sockets.c +++ b/mono/io-layer/sockets.c @@ -8,6 +8,9 @@ */ #include + +#ifndef DISABLE_SOCKETS + #include #include #include @@ -42,15 +45,22 @@ #include #include -#include #include #ifdef HAVE_SYS_SENDFILE_H #include #endif +#ifdef HAVE_NETDB_H +#include +#endif -#undef DEBUG +#if 0 +#define DEBUG(...) g_message(__VA_ARGS__) +#else +#define DEBUG(...) +#endif static guint32 startup_count=0; +static guint32 in_cleanup = 0; static void socket_close (gpointer handle, gpointer data); @@ -75,11 +85,9 @@ static void socket_close (gpointer handle, gpointer data) int ret; struct _WapiHandle_socket *socket_handle = (struct _WapiHandle_socket *)data; -#ifdef DEBUG - g_message ("%s: closing socket handle %p", __func__, handle); -#endif + DEBUG ("%s: closing socket handle %p", __func__, handle); - if (startup_count == 0) { + if (startup_count == 0 && !in_cleanup) { WSASetLastError (WSANOTINITIALISED); return; } @@ -96,14 +104,14 @@ static void socket_close (gpointer handle, gpointer data) if (ret == -1) { gint errnum = errno; -#ifdef DEBUG - g_message ("%s: close error: %s", __func__, strerror (errno)); -#endif + DEBUG ("%s: close error: %s", __func__, strerror (errno)); errnum = errno_to_WSA (errnum, __func__); - WSASetLastError (errnum); + if (!in_cleanup) + WSASetLastError (errnum); } - socket_handle->saved_error = 0; + if (!in_cleanup) + socket_handle->saved_error = 0; } int WSAStartup(guint32 requested, WapiWSAData *data) @@ -125,9 +133,7 @@ int WSAStartup(guint32 requested, WapiWSAData *data) data->wVersion = requested < data->wHighVersion? requested: data->wHighVersion; -#ifdef DEBUG - g_message ("%s: high version 0x%x", __func__, data->wHighVersion); -#endif + DEBUG ("%s: high version 0x%x", __func__, data->wHighVersion); strncpy (data->szDescription, "WAPI", WSADESCRIPTION_LEN); strncpy (data->szSystemStatus, "groovy", WSASYS_STATUS_LEN); @@ -144,16 +150,16 @@ cleanup_close (gpointer handle, gpointer data) int WSACleanup(void) { -#ifdef DEBUG - g_message ("%s: cleaning up", __func__); -#endif + DEBUG ("%s: cleaning up", __func__); if (--startup_count) { /* Do nothing */ return(0); } + in_cleanup = 1; _wapi_handle_foreach (WAPI_HANDLE_SOCKET, cleanup_close, NULL); + in_cleanup = 0; return(0); } @@ -220,9 +226,7 @@ guint32 _wapi_accept(guint32 fd, struct sockaddr *addr, socklen_t *addrlen) if (new_fd == -1) { gint errnum = errno; -#ifdef DEBUG - g_message ("%s: accept error: %s", __func__, strerror(errno)); -#endif + DEBUG ("%s: accept error: %s", __func__, strerror(errno)); errnum = errno_to_WSA (errnum, __func__); WSASetLastError (errnum); @@ -231,9 +235,7 @@ guint32 _wapi_accept(guint32 fd, struct sockaddr *addr, socklen_t *addrlen) } if (new_fd >= _wapi_fd_reserve) { -#ifdef DEBUG - g_message ("%s: File descriptor is too big", __func__); -#endif + DEBUG ("%s: File descriptor is too big", __func__); WSASetLastError (WSASYSCALLFAILURE); @@ -255,10 +257,8 @@ guint32 _wapi_accept(guint32 fd, struct sockaddr *addr, socklen_t *addrlen) return(INVALID_SOCKET); } -#ifdef DEBUG - g_message ("%s: returning newly accepted socket handle %p with", + DEBUG ("%s: returning newly accepted socket handle %p with", __func__, new_handle); -#endif return(new_fd); } @@ -281,9 +281,7 @@ int _wapi_bind(guint32 fd, struct sockaddr *my_addr, socklen_t addrlen) ret = bind (fd, my_addr, addrlen); if (ret == -1) { gint errnum = errno; -#ifdef DEBUG - g_message ("%s: bind error: %s", __func__, strerror(errno)); -#endif + DEBUG ("%s: bind error: %s", __func__, strerror(errno)); errnum = errno_to_WSA (errnum, __func__); WSASetLastError (errnum); @@ -318,10 +316,8 @@ int _wapi_connect(guint32 fd, const struct sockaddr *serv_addr, errnum = errno; if (errno != EINTR) { -#ifdef DEBUG - g_message ("%s: connect error: %s", __func__, + DEBUG ("%s: connect error: %s", __func__, strerror (errnum)); -#endif errnum = errno_to_WSA (errnum, __func__); if (errnum == WSAEINPROGRESS) @@ -341,7 +337,8 @@ int _wapi_connect(guint32 fd, const struct sockaddr *serv_addr, (gpointer *)&socket_handle); if (ok == FALSE) { /* ECONNRESET means the socket was closed by another thread */ - if (errnum != WSAECONNRESET) + /* Async close on mac raises ECONNABORTED. */ + if (errnum != WSAECONNRESET && errnum != WSAENETDOWN) g_warning ("%s: error looking up socket handle %p (error %d)", __func__, handle, errnum); } else { socket_handle->saved_error = errnum; @@ -351,16 +348,14 @@ int _wapi_connect(guint32 fd, const struct sockaddr *serv_addr, } fds.fd = fd; - fds.events = POLLOUT; + fds.events = MONO_POLLOUT; while (mono_poll (&fds, 1, -1) == -1 && !_wapi_thread_cur_apc_pending ()) { if (errno != EINTR) { errnum = errno_to_WSA (errno, __func__); -#ifdef DEBUG - g_message ("%s: connect poll error: %s", + DEBUG ("%s: connect poll error: %s", __func__, strerror (errno)); -#endif WSASetLastError (errnum); return(SOCKET_ERROR); @@ -372,10 +367,8 @@ int _wapi_connect(guint32 fd, const struct sockaddr *serv_addr, &len) == -1) { errnum = errno_to_WSA (errno, __func__); -#ifdef DEBUG - g_message ("%s: connect getsockopt error: %s", + DEBUG ("%s: connect getsockopt error: %s", __func__, strerror (errno)); -#endif WSASetLastError (errnum); return(SOCKET_ERROR); @@ -393,10 +386,8 @@ int _wapi_connect(guint32 fd, const struct sockaddr *serv_addr, socket_handle->saved_error = errnum; } -#ifdef DEBUG - g_message ("%s: connect getsockopt returned error: %s", + DEBUG ("%s: connect getsockopt returned error: %s", __func__, strerror (so_error)); -#endif WSASetLastError (errnum); return(SOCKET_ERROR); @@ -424,10 +415,8 @@ int _wapi_getpeername(guint32 fd, struct sockaddr *name, socklen_t *namelen) ret = getpeername (fd, name, namelen); if (ret == -1) { gint errnum = errno; -#ifdef DEBUG - g_message ("%s: getpeername error: %s", __func__, + DEBUG ("%s: getpeername error: %s", __func__, strerror (errno)); -#endif errnum = errno_to_WSA (errnum, __func__); WSASetLastError (errnum); @@ -456,10 +445,8 @@ int _wapi_getsockname(guint32 fd, struct sockaddr *name, socklen_t *namelen) ret = getsockname (fd, name, namelen); if (ret == -1) { gint errnum = errno; -#ifdef DEBUG - g_message ("%s: getsockname error: %s", __func__, + DEBUG ("%s: getsockname error: %s", __func__, strerror (errno)); -#endif errnum = errno_to_WSA (errnum, __func__); WSASetLastError (errnum); @@ -500,10 +487,8 @@ int _wapi_getsockopt(guint32 fd, int level, int optname, void *optval, ret = getsockopt (fd, level, optname, tmp_val, optlen); if (ret == -1) { gint errnum = errno; -#ifdef DEBUG - g_message ("%s: getsockopt error: %s", __func__, + DEBUG ("%s: getsockopt error: %s", __func__, strerror (errno)); -#endif errnum = errno_to_WSA (errnum, __func__); WSASetLastError (errnum); @@ -559,9 +544,7 @@ int _wapi_listen(guint32 fd, int backlog) ret = listen (fd, backlog); if (ret == -1) { gint errnum = errno; -#ifdef DEBUG - g_message ("%s: listen error: %s", __func__, strerror (errno)); -#endif + DEBUG ("%s: listen error: %s", __func__, strerror (errno)); errnum = errno_to_WSA (errnum, __func__); WSASetLastError (errnum); @@ -629,9 +612,7 @@ int _wapi_recvfrom(guint32 fd, void *buf, size_t len, int recv_flags, if (ret == -1) { gint errnum = errno; -#ifdef DEBUG - g_message ("%s: recv error: %s", __func__, strerror(errno)); -#endif + DEBUG ("%s: recv error: %s", __func__, strerror(errno)); errnum = errno_to_WSA (errnum, __func__); WSASetLastError (errnum); @@ -676,9 +657,7 @@ _wapi_recvmsg(guint32 fd, struct msghdr *msg, int recv_flags) if (ret == -1) { gint errnum = errno; -#ifdef DEBUG - g_message ("%s: recvmsg error: %s", __func__, strerror(errno)); -#endif + DEBUG ("%s: recvmsg error: %s", __func__, strerror(errno)); errnum = errno_to_WSA (errnum, __func__); WSASetLastError (errnum); @@ -710,10 +689,17 @@ int _wapi_send(guint32 fd, const void *msg, size_t len, int send_flags) if (ret == -1) { gint errnum = errno; -#ifdef DEBUG - g_message ("%s: send error: %s", __func__, strerror (errno)); -#endif + DEBUG ("%s: send error: %s", __func__, strerror (errno)); +#ifdef O_NONBLOCK + /* At least linux returns EAGAIN/EWOULDBLOCK when the timeout has been set on + * a blocking socket. See bug #599488 */ + if (errnum == EAGAIN) { + ret = fcntl (fd, F_GETFL, 0); + if (ret != -1 && (ret & O_NONBLOCK) == 0) + errnum = ETIMEDOUT; + } +#endif /* O_NONBLOCK */ errnum = errno_to_WSA (errnum, __func__); WSASetLastError (errnum); @@ -745,9 +731,7 @@ int _wapi_sendto(guint32 fd, const void *msg, size_t len, int send_flags, if (ret == -1) { gint errnum = errno; -#ifdef DEBUG - g_message ("%s: send error: %s", __func__, strerror (errno)); -#endif + DEBUG ("%s: send error: %s", __func__, strerror (errno)); errnum = errno_to_WSA (errnum, __func__); WSASetLastError (errnum); @@ -780,9 +764,7 @@ _wapi_sendmsg(guint32 fd, const struct msghdr *msg, int send_flags) if (ret == -1) { gint errnum = errno; -#ifdef DEBUG - g_message ("%s: sendmsg error: %s", __func__, strerror (errno)); -#endif + DEBUG ("%s: sendmsg error: %s", __func__, strerror (errno)); errnum = errno_to_WSA (errnum, __func__); WSASetLastError (errnum); @@ -798,6 +780,10 @@ int _wapi_setsockopt(guint32 fd, int level, int optname, gpointer handle = GUINT_TO_POINTER (fd); int ret; const void *tmp_val; +#if defined (__linux__) + /* This has its address taken so it cannot be moved to the if block which uses it */ + int bufsize = 0; +#endif struct timeval tv; if (startup_count == 0) { @@ -825,7 +811,7 @@ int _wapi_setsockopt(guint32 fd, int level, int optname, * buffer sizes "to allow space for bookkeeping * overhead." */ - int bufsize = *((int *) optval); + bufsize = *((int *) optval); bufsize /= 2; tmp_val = &bufsize; @@ -835,10 +821,8 @@ int _wapi_setsockopt(guint32 fd, int level, int optname, ret = setsockopt (fd, level, optname, tmp_val, optlen); if (ret == -1) { gint errnum = errno; -#ifdef DEBUG - g_message ("%s: setsockopt error: %s", __func__, + DEBUG ("%s: setsockopt error: %s", __func__, strerror (errno)); -#endif errnum = errno_to_WSA (errnum, __func__); WSASetLastError (errnum); @@ -896,10 +880,8 @@ int _wapi_shutdown(guint32 fd, int how) ret = shutdown (fd, how); if (ret == -1) { gint errnum = errno; -#ifdef DEBUG - g_message ("%s: shutdown error: %s", __func__, + DEBUG ("%s: shutdown error: %s", __func__, strerror (errno)); -#endif errnum = errno_to_WSA (errnum, __func__); WSASetLastError (errnum); @@ -926,15 +908,14 @@ guint32 _wapi_socket(int domain, int type, int protocol, void *unused, if (fd == -1 && domain == AF_INET && type == SOCK_RAW && protocol == 0) { /* Retry with protocol == 4 (see bug #54565) */ + // https://bugzilla.novell.com/show_bug.cgi?id=MONO54565 socket_handle.protocol = 4; fd = socket (AF_INET, SOCK_RAW, 4); } if (fd == -1) { gint errnum = errno; -#ifdef DEBUG - g_message ("%s: socket error: %s", __func__, strerror (errno)); -#endif + DEBUG ("%s: socket error: %s", __func__, strerror (errno)); errnum = errno_to_WSA (errnum, __func__); WSASetLastError (errnum); @@ -942,10 +923,8 @@ guint32 _wapi_socket(int domain, int type, int protocol, void *unused, } if (fd >= _wapi_fd_reserve) { -#ifdef DEBUG - g_message ("%s: File descriptor is too big (%d >= %d)", + DEBUG ("%s: File descriptor is too big (%d >= %d)", __func__, fd, _wapi_fd_reserve); -#endif WSASetLastError (WSASYSCALLFAILURE); close (fd); @@ -955,6 +934,7 @@ guint32 _wapi_socket(int domain, int type, int protocol, void *unused, /* .net seems to set this by default for SOCK_STREAM, not for * SOCK_DGRAM (see bug #36322) + * https://bugzilla.novell.com/show_bug.cgi?id=MONO36322 * * It seems winsock has a rather different idea of what * SO_REUSEADDR means. If it's set, then a new socket can be @@ -965,6 +945,7 @@ guint32 _wapi_socket(int domain, int type, int protocol, void *unused, * behaves as though any other system would when SO_REUSEADDR * is true, so we don't need to do anything else here. See * bug 53992. + * https://bugzilla.novell.com/show_bug.cgi?id=MONO53992 */ { int ret, true = 1; @@ -974,9 +955,7 @@ guint32 _wapi_socket(int domain, int type, int protocol, void *unused, if (ret == -1) { int errnum = errno; -#ifdef DEBUG - g_message ("%s: Error setting SO_REUSEADDR", __func__); -#endif + DEBUG ("%s: Error setting SO_REUSEADDR", __func__); errnum = errno_to_WSA (errnum, __func__); WSASetLastError (errnum); @@ -998,54 +977,11 @@ guint32 _wapi_socket(int domain, int type, int protocol, void *unused, return(INVALID_SOCKET); } -#ifdef DEBUG - g_message ("%s: returning socket handle %p", __func__, handle); -#endif + DEBUG ("%s: returning socket handle %p", __func__, handle); return(fd); } -struct hostent *_wapi_gethostbyname(const char *hostname) -{ - struct hostent *he; - - if (startup_count == 0) { - WSASetLastError (WSANOTINITIALISED); - return(NULL); - } - - he = gethostbyname (hostname); - if (he == NULL) { -#ifdef DEBUG - g_message ("%s: gethostbyname error: %s", __func__, - strerror (h_errno)); -#endif - - switch(h_errno) { - case HOST_NOT_FOUND: - WSASetLastError (WSAHOST_NOT_FOUND); - break; -#if NO_ADDRESS != NO_DATA - case NO_ADDRESS: -#endif - case NO_DATA: - WSASetLastError (WSANO_DATA); - break; - case NO_RECOVERY: - WSASetLastError (WSANO_RECOVERY); - break; - case TRY_AGAIN: - WSASetLastError (WSATRY_AGAIN); - break; - default: - g_warning ("%s: Need to translate %d into winsock error", __func__, h_errno); - break; - } - } - - return(he); -} - static gboolean socket_disconnect (guint32 fd) { struct _WapiHandle_socket *socket_handle; @@ -1067,9 +1003,7 @@ static gboolean socket_disconnect (guint32 fd) if (newsock == -1) { gint errnum = errno; -#ifdef DEBUG - g_message ("%s: socket error: %s", __func__, strerror (errno)); -#endif + DEBUG ("%s: socket error: %s", __func__, strerror (errno)); errnum = errno_to_WSA (errnum, __func__); WSASetLastError (errnum); @@ -1089,9 +1023,7 @@ static gboolean socket_disconnect (guint32 fd) if (ret == -1) { gint errnum = errno; -#ifdef DEBUG - g_message ("%s: dup2 error: %s", __func__, strerror (errno)); -#endif + DEBUG ("%s: dup2 error: %s", __func__, strerror (errno)); errnum = errno_to_WSA (errnum, __func__); WSASetLastError (errnum); @@ -1107,9 +1039,7 @@ static gboolean socket_disconnect (guint32 fd) static gboolean wapi_disconnectex (guint32 fd, WapiOverlapped *overlapped, guint32 flags, guint32 reserved) { -#ifdef DEBUG - g_message ("%s: called on socket %d!", __func__, fd); -#endif + DEBUG ("%s: called on socket %d!", __func__, fd); if (reserved != 0) { WSASetLastError (WSAEINVAL); @@ -1302,6 +1232,55 @@ WSAIoctl (guint32 fd, gint32 command, return(SOCKET_ERROR); } + if (command == SIO_KEEPALIVE_VALS) { + uint32_t onoff; + uint32_t keepalivetime; + uint32_t keepaliveinterval; + + if (i_len < (3 * sizeof (uint32_t))) { + WSASetLastError (WSAEINVAL); + return SOCKET_ERROR; + } + memcpy (&onoff, input, sizeof (uint32_t)); + memcpy (&keepalivetime, input + sizeof (uint32_t), sizeof (uint32_t)); + memcpy (&keepaliveinterval, input + 2 * sizeof (uint32_t), sizeof (uint32_t)); + ret = setsockopt (fd, SOL_SOCKET, SO_KEEPALIVE, &onoff, sizeof (uint32_t)); + if (ret < 0) { + gint errnum = errno; + errnum = errno_to_WSA (errnum, __func__); + WSASetLastError (errnum); + return SOCKET_ERROR; + } + if (onoff != 0) { +#if defined(TCP_KEEPIDLE) && defined(TCP_KEEPINTVL) + /* Values are in ms, but we need s */ + uint32_t rem; + + /* keepalivetime and keepaliveinterval are > 0 (checked in managed code) */ + rem = keepalivetime % 1000; + keepalivetime /= 1000; + if (keepalivetime == 0 || rem >= 500) + keepalivetime++; + ret = setsockopt (fd, IPPROTO_TCP, TCP_KEEPIDLE, &keepalivetime, sizeof (uint32_t)); + if (ret == 0) { + rem = keepaliveinterval % 1000; + keepaliveinterval /= 1000; + if (keepaliveinterval == 0 || rem >= 500) + keepaliveinterval++; + ret = setsockopt (fd, IPPROTO_TCP, TCP_KEEPINTVL, &keepaliveinterval, sizeof (uint32_t)); + } + if (ret != 0) { + gint errnum = errno; + errnum = errno_to_WSA (errnum, __func__); + WSASetLastError (errnum); + return SOCKET_ERROR; + } + return 0; +#endif + } + return 0; + } + if (i_len > 0) { buffer = g_memdup (input, i_len); } @@ -1309,10 +1288,8 @@ WSAIoctl (guint32 fd, gint32 command, ret = ioctl (fd, command, buffer); if (ret == -1) { gint errnum = errno; -#ifdef DEBUG - g_message("%s: WSAIoctl error: %s", __func__, + DEBUG("%s: WSAIoctl error: %s", __func__, strerror (errno)); -#endif errnum = errno_to_WSA (errnum, __func__); WSASetLastError (errnum); @@ -1409,9 +1386,7 @@ int ioctlsocket(guint32 fd, gint32 command, gpointer arg) if (ret == -1) { gint errnum = errno; -#ifdef DEBUG - g_message ("%s: ioctl error: %s", __func__, strerror (errno)); -#endif + DEBUG ("%s: ioctl error: %s", __func__, strerror (errno)); errnum = errno_to_WSA (errnum, __func__); WSASetLastError (errnum); @@ -1453,9 +1428,7 @@ int _wapi_select(int nfds G_GNUC_UNUSED, fd_set *readfds, fd_set *writefds, if (ret == -1) { gint errnum = errno; -#ifdef DEBUG - g_message ("%s: select error: %s", __func__, strerror (errno)); -#endif + DEBUG ("%s: select error: %s", __func__, strerror (errno)); errnum = errno_to_WSA (errnum, __func__); WSASetLastError (errnum); @@ -1581,3 +1554,5 @@ int WSASend (guint32 fd, WapiWSABuf *buffers, guint32 count, guint32 *sent, *sent = ret; return 0; } + +#endif /* ifndef DISABLE_SOCKETS */