X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fio-layer%2Fsockets.c;h=b2cf55faf211c4398f153bba7e86636c7d907b4a;hb=a6bce082e4da5a3f144b7ae8974819a88efb6817;hp=7606462af670092b8437acb50bdbe7023a3ca275;hpb=a90ce13b8cf54d53778ad7190ff8a9bc0b35e168;p=mono.git diff --git a/mono/io-layer/sockets.c b/mono/io-layer/sockets.c index 7606462af67..b2cf55faf21 100644 --- a/mono/io-layer/sockets.c +++ b/mono/io-layer/sockets.c @@ -1,3 +1,12 @@ +/* + * sockets.c: Socket handles + * + * Author: + * Dick Porter (dick@ximian.com) + * + * (C) 2002 Ximian, Inc. + */ + #include #include #include @@ -13,119 +22,134 @@ #include /* defines SIOCATMARK */ #endif #include +#include -#include "mono/io-layer/wapi.h" -#include "wapi-private.h" +#ifndef HAVE_MSG_NOSIGNAL +#include +#endif -#define DEBUG +#include +#include +#include +#include +#include -struct _WapiHandle_socket -{ - WapiHandle handle; - int fd; -}; +#undef DEBUG static guint32 startup_count=0; -static GPtrArray *sockets=NULL; static pthread_key_t error_key; -static pthread_once_t error_key_once=PTHREAD_ONCE_INIT; +static mono_once_t error_key_once=MONO_ONCE_INIT; -static void socket_close(WapiHandle *handle); +static void socket_close (gpointer handle, gpointer data); -static struct _WapiHandleOps socket_ops = { +struct _WapiHandleOps _wapi_socket_ops = { socket_close, /* close */ - NULL, /* getfiletype */ - NULL, /* readfile */ - NULL, /* writefile */ - NULL, /* seek */ - NULL, /* setendoffile */ - NULL, /* getfilesize */ - NULL, /* getfiletime */ - NULL, /* setfiletime */ - NULL, /* wait */ - NULL, /* wait_multiple */ NULL, /* signal */ + NULL, /* own */ + NULL, /* is_owned */ }; -static void socket_close(WapiHandle *handle) +static mono_once_t socket_ops_once=MONO_ONCE_INIT; + +static void socket_ops_init (void) { + /* No capabilities to register */ +} + +static void socket_close (gpointer handle, gpointer data G_GNUC_UNUSED) +{ + int ret; + #ifdef DEBUG - g_message(G_GNUC_PRETTY_FUNCTION ": closing socket handle %p", handle); + g_message ("%s: closing socket handle %p", __func__, handle); #endif - closesocket(handle); + if (startup_count == 0) { + WSASetLastError (WSANOTINITIALISED); + return; + } + + do { + ret = close (GPOINTER_TO_UINT(handle)); + } while (ret == -1 && errno == EINTR && + !_wapi_thread_cur_apc_pending ()); + + if (ret == -1) { + gint errnum = errno; +#ifdef DEBUG + g_message ("%s: close error: %s", __func__, strerror (errno)); +#endif + errnum = errno_to_WSA (errnum, __func__); + WSASetLastError (errnum); + } } int WSAStartup(guint32 requested, WapiWSAData *data) { - if(data==NULL) { + if (data == NULL) { return(WSAEFAULT); } /* Insist on v2.0+ */ - if(requested < MAKEWORD(2,0)) { + if (requested < MAKEWORD(2,0)) { return(WSAVERNOTSUPPORTED); } - if(startup_count==0) { - sockets=g_ptr_array_new(); - } - startup_count++; /* I've no idea what is the minor version of the spec I read */ - data->wHighVersion=MAKEWORD(2,0); + data->wHighVersion = MAKEWORD(2,0); - data->wVersion=requested < data->wHighVersion? requested: + data->wVersion = requested < data->wHighVersion? requested: data->wHighVersion; #ifdef DEBUG - g_message(G_GNUC_PRETTY_FUNCTION ": high version 0x%x", - data->wHighVersion); + g_message ("%s: high version 0x%x", __func__, data->wHighVersion); #endif - strncpy(data->szDescription, "WAPI", WSADESCRIPTION_LEN); - strncpy(data->szSystemStatus, "groovy", WSASYS_STATUS_LEN); + strncpy (data->szDescription, "WAPI", WSADESCRIPTION_LEN); + strncpy (data->szSystemStatus, "groovy", WSASYS_STATUS_LEN); return(0); } +static gboolean +cleanup_close (gpointer handle, gpointer data) +{ + _wapi_handle_ops_close (handle, NULL); + return TRUE; +} + int WSACleanup(void) { - guint32 i; - #ifdef DEBUG - g_message(G_GNUC_PRETTY_FUNCTION ": cleaning up"); + g_message ("%s: cleaning up", __func__); #endif - if(--startup_count) { + if (--startup_count) { /* Do nothing */ return(0); } - - /* Close down all sockets */ - for(i=0; ilen; i++) { - WapiHandle *handle; - handle=g_ptr_array_index(sockets, i); - handle->ops->close(handle); - } - - g_ptr_array_free(sockets, FALSE); - sockets=NULL; - + _wapi_handle_foreach (WAPI_HANDLE_SOCKET, cleanup_close, NULL); return(0); } static void error_init(void) { - pthread_key_create(&error_key, NULL); + int ret; + + ret = pthread_key_create (&error_key, NULL); + g_assert (ret == 0); } void WSASetLastError(int error) { - pthread_once(&error_key_once, error_init); - pthread_setspecific(error_key, GINT_TO_POINTER(error)); + int ret; + + mono_once (&error_key_once, error_init); + ret = pthread_setspecific (error_key, GINT_TO_POINTER(error)); + g_assert (ret == 0); } int WSAGetLastError(void) @@ -133,288 +157,197 @@ int WSAGetLastError(void) int err; void *errptr; - pthread_once(&error_key_once, error_init); - errptr=pthread_getspecific(error_key); - err=GPOINTER_TO_INT(errptr); + mono_once (&error_key_once, error_init); + errptr = pthread_getspecific (error_key); + err = GPOINTER_TO_INT(errptr); return(err); } -int closesocket(WapiHandle *handle) +int closesocket(guint32 fd) { - struct _WapiHandle_socket *socket_handle=(struct _WapiHandle_socket *)handle; - int ret; + gpointer handle = GUINT_TO_POINTER (fd); - if(startup_count==0) { - WSASetLastError(WSANOTINITIALISED); - return(SOCKET_ERROR); + if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) { + WSASetLastError (WSAENOTSOCK); + return(0); } - if(handle->type!=WAPI_HANDLE_SOCKET) { - WSASetLastError(WSAENOTSOCK); - return(SOCKET_ERROR); + _wapi_handle_unref (handle); + return(0); +} + +guint32 _wapi_accept(guint32 fd, struct sockaddr *addr, socklen_t *addrlen) +{ + gpointer handle = GUINT_TO_POINTER (fd); + gpointer new_handle; + int new_fd; + + if (startup_count == 0) { + WSASetLastError (WSANOTINITIALISED); + return(INVALID_SOCKET); } - g_ptr_array_remove_fast(sockets, handle); + if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) { + WSASetLastError (WSAENOTSOCK); + return(INVALID_SOCKET); + } - ret=close(socket_handle->fd); - if(ret==-1) { + do { + new_fd = accept (fd, addr, addrlen); + } while (new_fd == -1 && errno == EINTR && + !_wapi_thread_cur_apc_pending()); + + if (new_fd == -1) { + gint errnum = errno; #ifdef DEBUG - g_message(G_GNUC_PRETTY_FUNCTION ": close error: %s", - strerror(errno)); + g_message ("%s: accept error: %s", __func__, strerror(errno)); #endif - switch(errno) { - case EBADF: - WSASetLastError(WSAENOTSOCK); - break; - case EINTR: - WSASetLastError(WSAEINTR); - break; - case EIO: - default: - g_warning(G_GNUC_PRETTY_FUNCTION ": Need to translate [%s] into winsock error", strerror(errno)); - break; - } + errnum = errno_to_WSA (errnum, __func__); + WSASetLastError (errnum); - return(SOCKET_ERROR); - } - return(ret); -} - -WapiHandle *_wapi_accept(WapiHandle *handle, struct sockaddr *addr, socklen_t *addrlen) -{ - struct _WapiHandle_socket *socket_handle=(struct _WapiHandle_socket *)handle; - struct _WapiHandle_socket *new_socket_handle; - WapiHandle *new_handle; - int fd; - - if(startup_count==0) { - WSASetLastError(WSANOTINITIALISED); return(INVALID_SOCKET); } - - fd=accept(socket_handle->fd, addr, addrlen); - if(fd==-1) { + + if (new_fd >= _wapi_fd_reserve) { #ifdef DEBUG - g_message(G_GNUC_PRETTY_FUNCTION ": accept error: %s", - strerror(errno)); + g_message ("%s: File descriptor is too big", __func__); #endif - switch(errno) { -#if EAGAIN != EWOULDBLOCK - case EAGAIN: -#endif - case EWOULDBLOCK: - WSASetLastError(WSAEWOULDBLOCK); - break; - case EBADF: - break; - case ENOTSOCK: - WSASetLastError(WSAENOTSOCK); - break; - case EOPNOTSUPP: - WSASetLastError(WSAEOPNOTSUPP); - break; - case EFAULT: - WSASetLastError(WSAEFAULT); - break; - case EPERM: - WSASetLastError(WSAENETDOWN); - break; - case ENOBUFS: - case ENOMEM: - WSASetLastError(WSAENOBUFS); - break; - case EMFILE: - WSASetLastError(WSAEMFILE); - break; - case EINVAL: - WSASetLastError(WSAEINVAL); - break; - case ENOSR: - case ECONNABORTED: - case ESOCKTNOSUPPORT: - case EPROTONOSUPPORT: - case ETIMEDOUT: -#ifdef ERESTARTSYS - case ERESTARTSYS: -#endif - WSASetLastError(WSAENETDOWN); - break; - default: - g_warning(G_GNUC_PRETTY_FUNCTION ": Need to translate [%s] into winsock error", strerror(errno)); - break; - } + WSASetLastError (WSASYSCALLFAILURE); + + close (new_fd); return(INVALID_SOCKET); } - - new_socket_handle=g_new0(struct _WapiHandle_socket, 1); - new_handle=(WapiHandle *)new_socket_handle; - - _WAPI_HANDLE_INIT(new_handle, WAPI_HANDLE_SOCKET, socket_ops); - - new_socket_handle->fd=fd; - + + new_handle = _wapi_handle_new_fd (WAPI_HANDLE_SOCKET, new_fd, NULL); + if(new_handle == _WAPI_HANDLE_INVALID) { + g_warning ("%s: error creating socket handle", __func__); + WSASetLastError (ERROR_GEN_FAILURE); + return(INVALID_SOCKET); + } + #ifdef DEBUG - g_message(G_GNUC_PRETTY_FUNCTION - ": returning newly accepted socket handle %p with fd %d", - new_handle, new_socket_handle->fd); + g_message ("%s: returning newly accepted socket handle %p with", + __func__, new_handle); #endif - - return(new_handle); + + return(new_fd); } -int _wapi_bind(WapiHandle *handle, struct sockaddr *my_addr, socklen_t addrlen) +int _wapi_bind(guint32 fd, struct sockaddr *my_addr, socklen_t addrlen) { - struct _WapiHandle_socket *socket_handle=(struct _WapiHandle_socket *)handle; + gpointer handle = GUINT_TO_POINTER (fd); int ret; - if(startup_count==0) { - WSASetLastError(WSANOTINITIALISED); + if (startup_count == 0) { + WSASetLastError (WSANOTINITIALISED); + return(SOCKET_ERROR); + } + + if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) { + WSASetLastError (WSAENOTSOCK); return(SOCKET_ERROR); } - ret=bind(socket_handle->fd, my_addr, addrlen); - if(ret==-1) { + ret = bind (fd, my_addr, addrlen); + if (ret == -1) { + gint errnum = errno; #ifdef DEBUG - g_message(G_GNUC_PRETTY_FUNCTION ": bind error: %s", - strerror(errno)); + g_message ("%s: bind error: %s", __func__, strerror(errno)); #endif - - switch(errno) { - case EINVAL: - WSASetLastError(WSAEINVAL); - break; - case EACCES: - WSASetLastError(WSAEACCES); - break; - case EBADF: - case ENOTSOCK: - WSASetLastError(WSAENOTSOCK); - break; - - /* The following apply to Unix domain sockets */ - case EFAULT: - WSASetLastError(WSAEFAULT); - break; - case EROFS: - case ENAMETOOLONG: - case ENOENT: - case ENOMEM: - case ENOTDIR: - case ELOOP: - default: - g_warning(G_GNUC_PRETTY_FUNCTION ": Need to translate [%s] into winsock error", strerror(errno)); - break; - } + errnum = errno_to_WSA (errnum, __func__); + WSASetLastError (errnum); return(SOCKET_ERROR); } return(ret); } -int _wapi_connect(WapiHandle *handle, const struct sockaddr *serv_addr, socklen_t addrlen) +int _wapi_connect(guint32 fd, const struct sockaddr *serv_addr, + socklen_t addrlen) { - struct _WapiHandle_socket *socket_handle=(struct _WapiHandle_socket *)handle; + gpointer handle = GUINT_TO_POINTER (fd); int ret; + gint errnum; - if(startup_count==0) { - WSASetLastError(WSANOTINITIALISED); + if (startup_count == 0) { + WSASetLastError (WSANOTINITIALISED); return(SOCKET_ERROR); } - ret=connect(socket_handle->fd, serv_addr, addrlen); - if(ret==-1) { + if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) { + WSASetLastError (WSAENOTSOCK); + return(SOCKET_ERROR); + } + + do { + ret = connect (fd, serv_addr, addrlen); + } while (ret==-1 && errno==EINTR && !_wapi_thread_cur_apc_pending()); + + if (ret == -1 && errno == EACCES) { + /* Try setting SO_BROADCAST and connecting again, but + * keep the original errno + */ + int true=1; + + errnum = errno; + + ret = setsockopt (fd, SOL_SOCKET, SO_BROADCAST, &true, + sizeof(true)); + if (ret == 0) { + do { + ret = connect (fd, serv_addr, addrlen); + } while (ret==-1 && errno==EINTR && + !_wapi_thread_cur_apc_pending()); + } + } else if (ret == -1) { + errnum = errno; + } + + if (ret == -1) { #ifdef DEBUG - g_message(G_GNUC_PRETTY_FUNCTION ": bind error: %s", - strerror(errno)); + g_message ("%s: connect error: %s", __func__, + strerror (errnum)); #endif + errnum = errno_to_WSA (errnum, __func__); + if (errnum == WSAEINPROGRESS) + errnum = WSAEWOULDBLOCK; /* see bug #73053 */ - switch(errno) { - case EBADF: - case ENOTSOCK: - WSASetLastError(WSAENOTSOCK); - break; - case EFAULT: - WSASetLastError(WSAEFAULT); - break; - case EISCONN: - WSASetLastError(WSAEISCONN); - break; - case ECONNREFUSED: - WSASetLastError(WSAECONNREFUSED); - break; - case ETIMEDOUT: - WSASetLastError(WSAETIMEDOUT); - break; - case ENETUNREACH: - WSASetLastError(WSAENETUNREACH); - break; - case EADDRINUSE: - WSASetLastError(WSAEADDRINUSE); - break; - case EINPROGRESS: - WSASetLastError(WSAEINPROGRESS); - break; - case EALREADY: - WSASetLastError(WSAEALREADY); - break; - case EAFNOSUPPORT: - WSASetLastError(WSAEAFNOSUPPORT); - break; - case EACCES: - case EPERM: - WSASetLastError(WSAEACCES); - break; - case EAGAIN: - default: - g_warning(G_GNUC_PRETTY_FUNCTION ": Need to translate [%s] into winsock error", strerror(errno)); - break; - } + WSASetLastError (errnum); return(SOCKET_ERROR); } return(ret); } -int _wapi_getpeername(WapiHandle *handle, struct sockaddr *name, socklen_t *namelen) +int _wapi_getpeername(guint32 fd, struct sockaddr *name, socklen_t *namelen) { - struct _WapiHandle_socket *socket_handle=(struct _WapiHandle_socket *)handle; + gpointer handle = GUINT_TO_POINTER (fd); int ret; - if(startup_count==0) { - WSASetLastError(WSANOTINITIALISED); + if (startup_count == 0) { + WSASetLastError (WSANOTINITIALISED); + return(SOCKET_ERROR); + } + + if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) { + WSASetLastError (WSAENOTSOCK); return(SOCKET_ERROR); } - ret=getpeername(socket_handle->fd, name, namelen); - if(ret==-1) { + ret = getpeername (fd, name, namelen); + if (ret == -1) { + gint errnum = errno; #ifdef DEBUG - g_message(G_GNUC_PRETTY_FUNCTION ": getpeername error: %s", - strerror(errno)); + g_message ("%s: getpeername error: %s", __func__, + strerror (errno)); #endif - switch(errno) { - case EBADF: - case ENOTSOCK: - WSASetLastError(WSAENOTSOCK); - break; - case ENOTCONN: - WSASetLastError(WSAENOTCONN); - break; - case ENOBUFS: - /* not documented */ - WSASetLastError(WSAENOBUFS); - break; - case EFAULT: - WSASetLastError(WSAEFAULT); - break; - default: - g_warning(G_GNUC_PRETTY_FUNCTION ": Need to translate [%s] into winsock error", strerror(errno)); - break; - } + errnum = errno_to_WSA (errnum, __func__); + WSASetLastError (errnum); return(SOCKET_ERROR); } @@ -422,39 +355,31 @@ int _wapi_getpeername(WapiHandle *handle, struct sockaddr *name, socklen_t *name return(ret); } -int _wapi_getsockname(WapiHandle *handle, struct sockaddr *name, socklen_t *namelen) +int _wapi_getsockname(guint32 fd, struct sockaddr *name, socklen_t *namelen) { - struct _WapiHandle_socket *socket_handle=(struct _WapiHandle_socket *)handle; + gpointer handle = GUINT_TO_POINTER (fd); int ret; - if(startup_count==0) { - WSASetLastError(WSANOTINITIALISED); + if (startup_count == 0) { + WSASetLastError (WSANOTINITIALISED); + return(SOCKET_ERROR); + } + + if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) { + WSASetLastError (WSAENOTSOCK); return(SOCKET_ERROR); } - ret=getsockname(socket_handle->fd, name, namelen); - if(ret==-1) { + ret = getsockname (fd, name, namelen); + if (ret == -1) { + gint errnum = errno; #ifdef DEBUG - g_message(G_GNUC_PRETTY_FUNCTION ": getsockname error: %s", - strerror(errno)); + g_message ("%s: getsockname error: %s", __func__, + strerror (errno)); #endif - switch(errno) { - case EBADF: - case ENOTSOCK: - WSASetLastError(WSAENOTSOCK); - break; - case ENOBUFS: - /* not documented */ - WSASetLastError(WSAENOBUFS); - break; - case EFAULT: - WSASetLastError(WSAEFAULT); - break; - default: - g_warning(G_GNUC_PRETTY_FUNCTION ": Need to translate [%s] into winsock error", strerror(errno)); - break; - } + errnum = errno_to_WSA (errnum, __func__); + WSASetLastError (errnum); return(SOCKET_ERROR); } @@ -462,77 +387,76 @@ int _wapi_getsockname(WapiHandle *handle, struct sockaddr *name, socklen_t *name return(ret); } -int _wapi_getsockopt(WapiHandle *handle, int level, int optname, void *optval, socklen_t *optlen) +int _wapi_getsockopt(guint32 fd, int level, int optname, void *optval, + socklen_t *optlen) { - struct _WapiHandle_socket *socket_handle=(struct _WapiHandle_socket *)handle; + gpointer handle = GUINT_TO_POINTER (fd); int ret; - - if(startup_count==0) { - WSASetLastError(WSANOTINITIALISED); + struct timeval tv; + void *tmp_val; + + if (startup_count == 0) { + WSASetLastError (WSANOTINITIALISED); return(SOCKET_ERROR); } - ret=getsockopt(socket_handle->fd, level, optname, optval, optlen); - if(ret==-1) { + if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) { + WSASetLastError (WSAENOTSOCK); + return(SOCKET_ERROR); + } + + tmp_val = optval; + if (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO) { + tmp_val = &tv; + *optlen = sizeof (tv); + } + + ret = getsockopt (fd, level, optname, tmp_val, optlen); + if (ret == -1) { + gint errnum = errno; #ifdef DEBUG - g_message(G_GNUC_PRETTY_FUNCTION ": getsockopt error: %s", - strerror(errno)); + g_message ("%s: getsockopt error: %s", __func__, + strerror (errno)); #endif - switch(errno) { - case EBADF: - case ENOTSOCK: - WSASetLastError(WSAENOTSOCK); - break; - case ENOPROTOOPT: - WSASetLastError(WSAENOPROTOOPT); - break; - case EFAULT: - WSASetLastError(WSAEFAULT); - break; - default: - g_warning(G_GNUC_PRETTY_FUNCTION ": Need to translate [%s] into winsock error", strerror(errno)); - break; - } + errnum = errno_to_WSA (errnum, __func__); + WSASetLastError (errnum); return(SOCKET_ERROR); } + + if (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO) { + *((int *) optval) = tv.tv_sec * 1000 + tv.tv_usec; + *optlen = sizeof (int); + } return(ret); } -int _wapi_listen(WapiHandle *handle, int backlog) +int _wapi_listen(guint32 fd, int backlog) { - struct _WapiHandle_socket *socket_handle=(struct _WapiHandle_socket *)handle; + gpointer handle = GUINT_TO_POINTER (fd); int ret; - if(startup_count==0) { - WSASetLastError(WSANOTINITIALISED); + if (startup_count == 0) { + WSASetLastError (WSANOTINITIALISED); return(SOCKET_ERROR); } - ret=listen(socket_handle->fd, backlog); - if(ret==-1) { + if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) { + WSASetLastError (WSAENOTSOCK); + return(SOCKET_ERROR); + } + + ret = listen (fd, backlog); + if (ret == -1) { + gint errnum = errno; #ifdef DEBUG - g_message(G_GNUC_PRETTY_FUNCTION ": listen error: %s", - strerror(errno)); + g_message ("%s: listen error: %s", __func__, strerror (errno)); #endif - switch(errno) { - case EADDRINUSE: - WSASetLastError(WSAEADDRINUSE); - break; - case EBADF: - case ENOTSOCK: - WSASetLastError(WSAENOTSOCK); - break; - case EOPNOTSUPP: - WSASetLastError(WSAEOPNOTSUPP); - break; - default: - g_warning(G_GNUC_PRETTY_FUNCTION ": Need to translate [%s] into winsock error", strerror(errno)); - break; - } + errnum = errno_to_WSA (errnum, __func__); + WSASetLastError (errnum); return(SOCKET_ERROR); } @@ -540,208 +464,188 @@ int _wapi_listen(WapiHandle *handle, int backlog) return(0); } -int _wapi_recv(WapiHandle *handle, void *buf, size_t len, int flags) +int _wapi_recv(guint32 fd, void *buf, size_t len, int recv_flags) { - return(_wapi_recvfrom(handle, buf, len, flags, NULL, 0)); + return(_wapi_recvfrom (fd, buf, len, recv_flags, NULL, 0)); } -int _wapi_recvfrom(WapiHandle *handle, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen) +int _wapi_recvfrom(guint32 fd, void *buf, size_t len, int recv_flags, + struct sockaddr *from, socklen_t *fromlen) { - struct _WapiHandle_socket *socket_handle=(struct _WapiHandle_socket *)handle; +#ifndef HAVE_MSG_NOSIGNAL + void (*old_sigpipe)(int); // old SIGPIPE handler +#endif + gpointer handle = GUINT_TO_POINTER (fd); int ret; - if(startup_count==0) { - WSASetLastError(WSANOTINITIALISED); + if (startup_count == 0) { + WSASetLastError (WSANOTINITIALISED); + return(SOCKET_ERROR); + } + + if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) { + WSASetLastError (WSAENOTSOCK); return(SOCKET_ERROR); } - ret=recvfrom(socket_handle->fd, buf, len, flags, from, fromlen); - if(ret==-1) { +#ifdef HAVE_MSG_NOSIGNAL + do { + ret = recvfrom (fd, buf, len, recv_flags | MSG_NOSIGNAL, from, + fromlen); + } while (ret == -1 && errno == EINTR && + !_wapi_thread_cur_apc_pending ()); +#else + old_sigpipe = signal (SIGPIPE, SIG_IGN); + do { + ret = recvfrom (fd, buf, len, recv_flags, from, fromlen); + } while (ret == -1 && errno == EINTR && + !_wapi_thread_cur_apc_pending ()); + signal (SIGPIPE, old_sigpipe); +#endif + + if (ret == -1) { + gint errnum = errno; #ifdef DEBUG - g_message(G_GNUC_PRETTY_FUNCTION ": recv error: %s", - strerror(errno)); + g_message ("%s: recv error: %s", __func__, strerror(errno)); #endif - switch(errno) { - case EBADF: - case ENOTSOCK: - WSASetLastError(WSAENOTSOCK); - break; - case ECONNREFUSED: - /* Not documented */ - WSASetLastError(WSAECONNREFUSED); - break; - case ENOTCONN: - WSASetLastError(WSAENOTCONN); - break; - case EAGAIN: - WSASetLastError(WSAEWOULDBLOCK); - break; - case EINTR: - WSASetLastError(WSAEINTR); - break; - case EFAULT: - WSASetLastError(WSAEFAULT); - break; - case EINVAL: - WSASetLastError(WSAEINVAL); - break; - default: - g_warning(G_GNUC_PRETTY_FUNCTION ": Need to translate [%s] into winsock error", strerror(errno)); - break; - } + errnum = errno_to_WSA (errnum, __func__); + WSASetLastError (errnum); return(SOCKET_ERROR); } return(ret); } -int _wapi_send(WapiHandle *handle, const void *msg, size_t len, int flags) +int _wapi_send(guint32 fd, const void *msg, size_t len, int send_flags) { - struct _WapiHandle_socket *socket_handle=(struct _WapiHandle_socket *)handle; +#ifndef HAVE_MSG_NOSIGNAL + void (*old_sigpipe)(int); // old SIGPIPE handler +#endif + gpointer handle = GUINT_TO_POINTER (fd); int ret; - if(startup_count==0) { - WSASetLastError(WSANOTINITIALISED); + if (startup_count == 0) { + WSASetLastError (WSANOTINITIALISED); return(SOCKET_ERROR); } - ret=send(socket_handle->fd, msg, len, flags); - if(ret==-1) { + if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) { + WSASetLastError (WSAENOTSOCK); + return(SOCKET_ERROR); + } + +#ifdef HAVE_MSG_NOSIGNAL + do { + ret = send (fd, msg, len, send_flags | MSG_NOSIGNAL); + } while (ret == -1 && errno == EINTR && + !_wapi_thread_cur_apc_pending ()); +#else + old_sigpipe = signal (SIGPIPE, SIG_IGN); + do { + ret = send (fd, msg, len, send_flags); + } while (ret == -1 && errno == EINTR && + !_wapi_thread_cur_apc_pending ()); + signal (SIGPIPE, old_sigpipe); +#endif + if (ret == -1) { + gint errnum = errno; #ifdef DEBUG - g_message(G_GNUC_PRETTY_FUNCTION ": send error: %s", - strerror(errno)); + g_message ("%s: send error: %s", __func__, strerror (errno)); #endif - switch(errno) { - case EBADF: - case ENOTSOCK: - WSASetLastError(WSAENOTSOCK); - break; - case EFAULT: - WSASetLastError(WSAEFAULT); - break; - case EMSGSIZE: - WSASetLastError(WSAEMSGSIZE); - break; -#if EAGAIN != EWOULDBLOCK - case EAGAIN: -#endif - case EWOULDBLOCK: - WSASetLastError(WSAEWOULDBLOCK); - break; - case ENOBUFS: - WSASetLastError(WSAENOBUFS); - break; - case EINTR: - WSASetLastError(WSAEINTR); - break; - case EINVAL: - WSASetLastError(WSAEINVAL); - break; - case EPIPE: - WSASetLastError(WSAESHUTDOWN); - break; - case ENOMEM: - default: - g_warning(G_GNUC_PRETTY_FUNCTION ": Need to translate [%s] into winsock error", strerror(errno)); - break; - } + errnum = errno_to_WSA (errnum, __func__); + WSASetLastError (errnum); return(SOCKET_ERROR); } return(ret); } -int _wapi_sendto(WapiHandle *handle, const void *msg, size_t len, int flags, const struct sockaddr *to, socklen_t tolen) +int _wapi_sendto(guint32 fd, const void *msg, size_t len, int send_flags, + const struct sockaddr *to, socklen_t tolen) { - struct _WapiHandle_socket *socket_handle=(struct _WapiHandle_socket *)handle; +#ifndef HAVE_MSG_NOSIGNAL + void (*old_sigpipe)(int); // old SIGPIPE handler +#endif + gpointer handle = GUINT_TO_POINTER (fd); int ret; - if(startup_count==0) { - WSASetLastError(WSANOTINITIALISED); + if (startup_count == 0) { + WSASetLastError (WSANOTINITIALISED); return(SOCKET_ERROR); } - ret=sendto(socket_handle->fd, msg, len, flags, to, tolen); - if(ret==-1) { + if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) { + WSASetLastError (WSAENOTSOCK); + return(SOCKET_ERROR); + } + +#ifdef HAVE_MSG_NOSIGNAL + do { + ret = sendto (fd, msg, len, send_flags | MSG_NOSIGNAL, to, + tolen); + } while (ret == -1 && errno == EINTR && + !_wapi_thread_cur_apc_pending ()); +#else + old_sigpipe = signal (SIGPIPE, SIG_IGN); + do { + ret = sendto (fd, msg, len, send_flags, to, tolen); + } while (ret == -1 && errno == EINTR && + !_wapi_thread_cur_apc_pending ()); + signal (SIGPIPE, old_sigpipe); +#endif + if (ret == -1) { + gint errnum = errno; #ifdef DEBUG - g_message(G_GNUC_PRETTY_FUNCTION ": send error: %s", - strerror(errno)); + g_message ("%s: send error: %s", __func__, strerror (errno)); #endif - switch(errno) { - case EBADF: - case ENOTSOCK: - WSASetLastError(WSAENOTSOCK); - break; - case EFAULT: - WSASetLastError(WSAEFAULT); - break; - case EMSGSIZE: - WSASetLastError(WSAEMSGSIZE); - break; -#if EAGAIN != EWOULDBLOCK - case EAGAIN: -#endif - case EWOULDBLOCK: - WSASetLastError(WSAEWOULDBLOCK); - break; - case ENOBUFS: - WSASetLastError(WSAENOBUFS); - break; - case EINTR: - WSASetLastError(WSAEINTR); - break; - case EINVAL: - WSASetLastError(WSAEINVAL); - break; - case EPIPE: - WSASetLastError(WSAESHUTDOWN); - break; - case ENOMEM: - default: - g_warning(G_GNUC_PRETTY_FUNCTION ": Need to translate [%s] into winsock error", strerror(errno)); - break; - } + errnum = errno_to_WSA (errnum, __func__); + WSASetLastError (errnum); return(SOCKET_ERROR); } return(ret); } -int _wapi_setsockopt(WapiHandle *handle, int level, int optname, const void *optval, socklen_t optlen) +int _wapi_setsockopt(guint32 fd, int level, int optname, + const void *optval, socklen_t optlen) { - struct _WapiHandle_socket *socket_handle=(struct _WapiHandle_socket *)handle; + gpointer handle = GUINT_TO_POINTER (fd); int ret; + const void *tmp_val; + struct timeval tv; - if(startup_count==0) { - WSASetLastError(WSANOTINITIALISED); + if (startup_count == 0) { + WSASetLastError (WSANOTINITIALISED); return(SOCKET_ERROR); } - ret=setsockopt(socket_handle->fd, level, optname, optval, optlen); - if(ret==-1) { + if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) { + WSASetLastError (WSAENOTSOCK); + return(SOCKET_ERROR); + } + + tmp_val = optval; + if (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO) { + int ms = *((int *) optval); + tv.tv_sec = ms / 1000; + tv.tv_usec = ms % 1000; + tmp_val = &tv; + optlen = sizeof (tv); + } + + ret = setsockopt (fd, level, optname, tmp_val, optlen); + if (ret == -1) { + gint errnum = errno; #ifdef DEBUG - g_message(G_GNUC_PRETTY_FUNCTION ": setsockopt error: %s", - strerror(errno)); + g_message ("%s: setsockopt error: %s", __func__, + strerror (errno)); #endif - switch(errno) { - case EBADF: - case ENOTSOCK: - WSASetLastError(WSAENOTSOCK); - break; - case ENOPROTOOPT: - WSASetLastError(WSAENOPROTOOPT); - break; - case EFAULT: - WSASetLastError(WSAEFAULT); - break; - default: - g_warning(G_GNUC_PRETTY_FUNCTION ": Need to translate [%s] into winsock error", strerror(errno)); - break; - } + errnum = errno_to_WSA (errnum, __func__); + WSASetLastError (errnum); return(SOCKET_ERROR); } @@ -749,35 +653,31 @@ int _wapi_setsockopt(WapiHandle *handle, int level, int optname, const void *opt return(ret); } -int _wapi_shutdown(WapiHandle *handle, int how) +int _wapi_shutdown(guint32 fd, int how) { - struct _WapiHandle_socket *socket_handle=(struct _WapiHandle_socket *)handle; + gpointer handle = GUINT_TO_POINTER (fd); int ret; - if(startup_count==0) { - WSASetLastError(WSANOTINITIALISED); + if (startup_count == 0) { + WSASetLastError (WSANOTINITIALISED); return(SOCKET_ERROR); } - ret=shutdown(socket_handle->fd, how); - if(ret==-1) { + if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) { + WSASetLastError (WSAENOTSOCK); + return(SOCKET_ERROR); + } + + ret = shutdown (fd, how); + if (ret == -1) { + gint errnum = errno; #ifdef DEBUG - g_message(G_GNUC_PRETTY_FUNCTION ": shutdown error: %s", - strerror(errno)); + g_message ("%s: shutdown error: %s", __func__, + strerror (errno)); #endif - switch(errno) { - case EBADF: - case ENOTSOCK: - WSASetLastError(WSAENOTSOCK); - break; - case ENOTCONN: - WSASetLastError(WSAENOTCONN); - break; - default: - g_warning(G_GNUC_PRETTY_FUNCTION ": Need to translate [%s] into winsock error", strerror(errno)); - break; - } + errnum = errno_to_WSA (errnum, __func__); + WSASetLastError (errnum); return(SOCKET_ERROR); } @@ -785,72 +685,91 @@ int _wapi_shutdown(WapiHandle *handle, int how) return(ret); } -WapiHandle *_wapi_socket(int domain, int type, int protocol) +guint32 _wapi_socket(int domain, int type, int protocol, void *unused, + guint32 unused2, guint32 unused3) { - struct _WapiHandle_socket *socket_handle; - WapiHandle *handle; + gpointer handle; int fd; - fd=socket(domain, type, protocol); - if(fd==-1) { + fd = socket (domain, type, protocol); + if (fd == -1 && domain == AF_INET && type == SOCK_RAW && + protocol == 0) { + /* Retry with protocol == 4 (see bug #54565) */ + fd = socket (AF_INET, SOCK_RAW, 4); + } + + if (fd == -1) { + gint errnum = errno; #ifdef DEBUG - g_message(G_GNUC_PRETTY_FUNCTION ": socket error: %s", strerror(errno)); + g_message ("%s: socket error: %s", __func__, strerror (errno)); #endif + errnum = errno_to_WSA (errnum, __func__); + WSASetLastError (errnum); return(INVALID_SOCKET); } + + if (fd >= _wapi_fd_reserve) { +#ifdef DEBUG + g_message ("%s: File descriptor is too big", __func__); +#endif + + WSASetLastError (WSASYSCALLFAILURE); + close (fd); + + return(INVALID_SOCKET); + } - socket_handle=g_new0(struct _WapiHandle_socket, 1); - handle=(WapiHandle *)socket_handle; - - _WAPI_HANDLE_INIT(handle, WAPI_HANDLE_SOCKET, socket_ops); - socket_handle->fd=fd; + mono_once (&socket_ops_once, socket_ops_init); + handle = _wapi_handle_new_fd (WAPI_HANDLE_SOCKET, fd, NULL); + if (handle == _WAPI_HANDLE_INVALID) { + g_warning ("%s: error creating socket handle", __func__); + return(INVALID_SOCKET); + } + #ifdef DEBUG - g_message(G_GNUC_PRETTY_FUNCTION - ": returning socket handle %p with fd %d", handle, - socket_handle->fd); + g_message ("%s: returning socket handle %p", __func__, handle); #endif - return(handle); + return(fd); } struct hostent *_wapi_gethostbyname(const char *hostname) { struct hostent *he; - - if(startup_count==0) { - WSASetLastError(WSANOTINITIALISED); + if (startup_count == 0) { + WSASetLastError (WSANOTINITIALISED); return(NULL); } - he=gethostbyname(hostname); - if(he==NULL) { + he = gethostbyname (hostname); + if (he == NULL) { #ifdef DEBUG - g_message(G_GNUC_PRETTY_FUNCTION ": listen error: %s", - strerror(errno)); + g_message ("%s: gethostbyname error: %s", __func__, + strerror (h_errno)); #endif switch(h_errno) { case HOST_NOT_FOUND: - WSASetLastError(WSAHOST_NOT_FOUND); + WSASetLastError (WSAHOST_NOT_FOUND); break; #if NO_ADDRESS != NO_DATA case NO_ADDRESS: #endif case NO_DATA: - WSASetLastError(WSANO_DATA); + WSASetLastError (WSANO_DATA); break; case NO_RECOVERY: - WSASetLastError(WSANO_RECOVERY); + WSASetLastError (WSANO_RECOVERY); break; case TRY_AGAIN: - WSASetLastError(WSATRY_AGAIN); + WSASetLastError (WSATRY_AGAIN); break; default: - g_warning(G_GNUC_PRETTY_FUNCTION ": Need to translate [%s] into winsock error", strerror(errno)); + g_warning ("%s: Need to translate %d into winsock error", __func__, h_errno); break; } } @@ -858,52 +777,112 @@ struct hostent *_wapi_gethostbyname(const char *hostname) return(he); } -int ioctlsocket(WapiHandle *handle, gint32 command, gpointer arg) +int +WSAIoctl (guint32 fd, gint32 command, + gchar *input, gint i_len, + gchar *output, gint o_len, glong *written, + void *unused1, void *unused2) +{ + gpointer handle = GUINT_TO_POINTER (fd); + int ret; + gchar *buffer = NULL; + + if (startup_count == 0) { + WSASetLastError (WSANOTINITIALISED); + return(SOCKET_ERROR); + } + + if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) { + WSASetLastError (WSAENOTSOCK); + return SOCKET_ERROR; + } + + if (i_len > 0) { + buffer = g_memdup (input, i_len); + } + + ret = ioctl (fd, command, buffer); + if (ret == -1) { + gint errnum = errno; +#ifdef DEBUG + g_message("%s: WSAIoctl error: %s", __func__, + strerror (errno)); +#endif + + errnum = errno_to_WSA (errnum, __func__); + WSASetLastError (errnum); + g_free (buffer); + + return(SOCKET_ERROR); + } + + if (buffer == NULL) { + *written = 0; + } else { + /* We just copy the buffer to the output. Some ioctls + * don't even output any data, but, well... + */ + i_len = (i_len > o_len) ? o_len : i_len; + memcpy (output, buffer, i_len); + g_free (buffer); + *written = i_len; + } + + return(0); +} + +int ioctlsocket(guint32 fd, gint32 command, gpointer arg) { - struct _WapiHandle_socket *socket_handle=(struct _WapiHandle_socket *)handle; + gpointer handle = GUINT_TO_POINTER (fd); int ret; - if(startup_count==0) { - WSASetLastError(WSANOTINITIALISED); + if (startup_count == 0) { + WSASetLastError (WSANOTINITIALISED); return(SOCKET_ERROR); } - if(handle->type!=WAPI_HANDLE_SOCKET) { - WSASetLastError(WSAENOTSOCK); + if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) { + WSASetLastError (WSAENOTSOCK); return(SOCKET_ERROR); } - if(command!=FIONBIO && - command!=FIONREAD && - command!=SIOCATMARK) { + if (command != FIONBIO && + command != FIONREAD && + command != SIOCATMARK) { /* Not listed in the MSDN specs, but ioctl(2) returns * this if command is invalid */ - WSASetLastError(WSAEINVAL); + WSASetLastError (WSAEINVAL); return(SOCKET_ERROR); } - ret=ioctl(socket_handle->fd, command, arg); - if(ret==-1) { +#ifdef O_NONBLOCK + /* This works better than ioctl(...FIONBIO...) on Linux (it causes + * connect to return EINPROGRESS, but the ioctl doesn't seem to) + */ + if (command == FIONBIO) { + ret = fcntl (fd, F_GETFL, 0); + if (ret != -1) { + if (*(gboolean *)arg) { + ret |= O_NONBLOCK; + } else { + ret &= ~O_NONBLOCK; + } + ret = fcntl (fd, F_SETFL, ret); + } + } else +#endif /* O_NONBLOCK */ + { + ret = ioctl (fd, command, arg); + } + if (ret == -1) { + gint errnum = errno; #ifdef DEBUG - g_message(G_GNUC_PRETTY_FUNCTION ": ioctl error: %s", - strerror(errno)); + g_message ("%s: ioctl error: %s", __func__, strerror (errno)); #endif - switch(errno) { - case ENOTTY: - case EBADF: - WSASetLastError(WSAENOTSOCK); - break; - case EFAULT: - WSASetLastError(WSAEFAULT); - break; - case EINVAL: - WSASetLastError(WSAEINVAL); - break; - default: - g_warning(G_GNUC_PRETTY_FUNCTION ": Need to translate [%s] into winsock error", strerror(errno)); - break; - } + + errnum = errno_to_WSA (errnum, __func__); + WSASetLastError (errnum); return(SOCKET_ERROR); } @@ -916,34 +895,24 @@ int _wapi_select(int nfds G_GNUC_UNUSED, fd_set *readfds, fd_set *writefds, { int ret; - if(startup_count==0) { - WSASetLastError(WSANOTINITIALISED); + if (startup_count == 0) { + WSASetLastError (WSANOTINITIALISED); return(SOCKET_ERROR); } - ret=select(getdtablesize(), readfds, writefds, exceptfds, timeout); - if(ret==-1) { + do { + ret = select(getdtablesize (), readfds, writefds, exceptfds, + timeout); + } while (ret == -1 && errno == EINTR && + !_wapi_thread_cur_apc_pending ()); + + if (ret == -1) { + gint errnum = errno; #ifdef DEBUG - g_message(G_GNUC_PRETTY_FUNCTION ": select error: %s", - strerror(errno)); + g_message ("%s: select error: %s", __func__, strerror (errno)); #endif - switch(errno) { - case EBADF: - WSASetLastError(WSAENOTSOCK); - break; - case EINTR: - WSASetLastError(WSAEINTR); - break; - case EINVAL: - WSASetLastError(WSAEINVAL); - break; - case ENOMEM: - WSASetLastError(WSAEFAULT); - break; - default: - g_warning(G_GNUC_PRETTY_FUNCTION ": Need to translate [%s] into winsock error", strerror(errno)); - break; - } + errnum = errno_to_WSA (errnum, __func__); + WSASetLastError (errnum); return(SOCKET_ERROR); } @@ -951,24 +920,39 @@ int _wapi_select(int nfds G_GNUC_UNUSED, fd_set *readfds, fd_set *writefds, return(ret); } -void _wapi_FD_CLR(WapiHandle *handle, fd_set *set) +void _wapi_FD_CLR(guint32 fd, fd_set *set) { - struct _WapiHandle_socket *socket_handle=(struct _WapiHandle_socket *)handle; + gpointer handle = GUINT_TO_POINTER (fd); + + if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) { + WSASetLastError (WSAENOTSOCK); + return; + } - FD_CLR(socket_handle->fd, set); + FD_CLR (fd, set); } -int _wapi_FD_ISSET(WapiHandle *handle, fd_set *set) +int _wapi_FD_ISSET(guint32 fd, fd_set *set) { - struct _WapiHandle_socket *socket_handle=(struct _WapiHandle_socket *)handle; + gpointer handle = GUINT_TO_POINTER (fd); + + if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) { + WSASetLastError (WSAENOTSOCK); + return(0); + } - return(FD_ISSET(socket_handle->fd, set)); + return(FD_ISSET (fd, set)); } -void _wapi_FD_SET(WapiHandle *handle, fd_set *set) +void _wapi_FD_SET(guint32 fd, fd_set *set) { - struct _WapiHandle_socket *socket_handle=(struct _WapiHandle_socket *)handle; + gpointer handle = GUINT_TO_POINTER (fd); + + if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) { + WSASetLastError (WSAENOTSOCK); + return; + } - FD_SET(socket_handle->fd, set); + FD_SET (fd, set); }