static int _wapi_sendmsg(guint32 fd, const struct msghdr *msg, int send_flags) { gpointer handle = GUINT_TO_POINTER (fd); int ret; if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) { WSASetLastError (WSAENOTSOCK); return(SOCKET_ERROR); } do { ret = sendmsg (fd, msg, send_flags); } while (ret == -1 && errno == EINTR && !_wapi_thread_cur_apc_pending ()); if (ret == -1) { gint errnum = errno; DEBUG ("%s: sendmsg error: %s", __func__, strerror (errno)); errnum = errno_to_WSA (errnum, __func__); WSASetLastError (errnum); return(SOCKET_ERROR); } return(ret); }
static void socket_close (gpointer handle, gpointer data) { int ret; struct _WapiHandle_socket *socket_handle = (struct _WapiHandle_socket *)data; DEBUG ("%s: closing socket handle %p", __func__, handle); /* Shutdown the socket for reading, to interrupt any potential * receives that may be blocking for data. See bug 75705. */ shutdown (GPOINTER_TO_UINT (handle), SHUT_RD); do { ret = close (GPOINTER_TO_UINT(handle)); } while (ret == -1 && errno == EINTR && !_wapi_thread_cur_apc_pending ()); if (ret == -1) { gint errnum = errno; DEBUG ("%s: close error: %s", __func__, strerror (errno)); errnum = errno_to_WSA (errnum, __func__); if (!in_cleanup) WSASetLastError (errnum); } if (!in_cleanup) socket_handle->saved_error = 0; }
int _wapi_send(guint32 fd, const void *msg, size_t len, int send_flags) { gpointer handle = GUINT_TO_POINTER (fd); int ret; if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) { WSASetLastError (WSAENOTSOCK); return(SOCKET_ERROR); } do { ret = send (fd, msg, len, send_flags); } while (ret == -1 && errno == EINTR && !_wapi_thread_cur_apc_pending ()); if (ret == -1) { gint errnum = errno; 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); return(SOCKET_ERROR); } return(ret); }
int _wapi_sendto(guint32 fd, const void *msg, size_t len, int send_flags, const struct sockaddr *to, socklen_t tolen) { gpointer handle = GUINT_TO_POINTER (fd); int ret; if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) { WSASetLastError (WSAENOTSOCK); return(SOCKET_ERROR); } do { ret = sendto (fd, msg, len, send_flags, to, tolen); } while (ret == -1 && errno == EINTR && !_wapi_thread_cur_apc_pending ()); if (ret == -1) { gint errnum = errno; DEBUG ("%s: send error: %s", __func__, strerror (errno)); errnum = errno_to_WSA (errnum, __func__); WSASetLastError (errnum); return(SOCKET_ERROR); } return(ret); }
int _wapi_select(int nfds G_GNUC_UNUSED, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) { int ret, maxfd; for (maxfd = FD_SETSIZE-1; maxfd >= 0; maxfd--) { if ((readfds && FD_ISSET (maxfd, readfds)) || (writefds && FD_ISSET (maxfd, writefds)) || (exceptfds && FD_ISSET (maxfd, exceptfds))) { break; } } if (maxfd == -1) { WSASetLastError (WSAEINVAL); return(SOCKET_ERROR); } do { ret = select(maxfd + 1, readfds, writefds, exceptfds, timeout); } while (ret == -1 && errno == EINTR && !_wapi_thread_cur_apc_pending ()); if (ret == -1) { gint errnum = errno; DEBUG ("%s: select error: %s", __func__, strerror (errno)); errnum = errno_to_WSA (errnum, __func__); WSASetLastError (errnum); return(SOCKET_ERROR); } return(ret); }
int _wapi_recvfrom(guint32 fd, void *buf, size_t len, int recv_flags, struct sockaddr *from, socklen_t *fromlen) { gpointer handle = GUINT_TO_POINTER (fd); struct _WapiHandle_socket *socket_handle; gboolean ok; int ret; if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) { WSASetLastError (WSAENOTSOCK); return(SOCKET_ERROR); } do { ret = recvfrom (fd, buf, len, recv_flags, from, fromlen); } while (ret == -1 && errno == EINTR && !_wapi_thread_cur_apc_pending ()); if (ret == 0 && len > 0) { /* According to the Linux man page, recvfrom only * returns 0 when the socket has been shut down * cleanly. Turn this into an EINTR to simulate win32 * behaviour of returning EINTR when a socket is * closed while the recvfrom is blocking (we use a * shutdown() in socket_close() to trigger this.) See * bug 75705. */ /* Distinguish between the socket being shut down at * the local or remote ends, and reads that request 0 * bytes to be read */ /* If this returns FALSE, it means the socket has been * closed locally. If it returns TRUE, but * still_readable != 1 then shutdown * (SHUT_RD|SHUT_RDWR) has been called locally. */ ok = _wapi_lookup_handle (handle, WAPI_HANDLE_SOCKET, (gpointer *)&socket_handle); if (ok == FALSE || socket_handle->still_readable != 1) { ret = -1; errno = EINTR; } } if (ret == -1) { gint errnum = errno; DEBUG ("%s: recv error: %s", __func__, strerror(errno)); errnum = errno_to_WSA (errnum, __func__); WSASetLastError (errnum); return(SOCKET_ERROR); } return(ret); }
static int _wapi_recvmsg(guint32 fd, struct msghdr *msg, int recv_flags) { gpointer handle = GUINT_TO_POINTER (fd); struct _WapiHandle_socket *socket_handle; gboolean ok; int ret; if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) { WSASetLastError (WSAENOTSOCK); return(SOCKET_ERROR); } do { ret = recvmsg (fd, msg, recv_flags); } while (ret == -1 && errno == EINTR && !_wapi_thread_cur_apc_pending ()); if (ret == 0) { /* see _wapi_recvfrom */ ok = _wapi_lookup_handle (handle, WAPI_HANDLE_SOCKET, (gpointer *)&socket_handle); if (ok == FALSE || socket_handle->still_readable != 1) { ret = -1; errno = EINTR; } } if (ret == -1) { gint errnum = errno; DEBUG ("%s: recvmsg error: %s", __func__, strerror(errno)); errnum = errno_to_WSA (errnum, __func__); WSASetLastError (errnum); return(SOCKET_ERROR); } return(ret); }
/** * WaitForSingleObjectEx: * @handle: an object to wait for * @timeout: the maximum time in milliseconds to wait for * @alertable: if TRUE, the wait can be interrupted by an APC call * * This function returns when either @handle is signalled, or @timeout * ms elapses. If @timeout is zero, the object's state is tested and * the function returns immediately. If @timeout is %INFINITE, the * function waits forever. * * Return value: %WAIT_ABANDONED - @handle is a mutex that was not * released by the owning thread when it exited. Ownership of the * mutex object is granted to the calling thread and the mutex is set * to nonsignalled. %WAIT_OBJECT_0 - The state of @handle is * signalled. %WAIT_TIMEOUT - The @timeout interval elapsed and * @handle's state is still not signalled. %WAIT_FAILED - an error * occurred. %WAIT_IO_COMPLETION - the wait was ended by an APC. */ guint32 WaitForSingleObjectEx(gpointer handle, guint32 timeout, gboolean alertable) { guint32 ret, waited; int thr_ret; gboolean apc_pending = FALSE; gpointer current_thread = wapi_get_current_thread_handle (); gint64 now, end; if (current_thread == NULL) { SetLastError (ERROR_INVALID_HANDLE); return(WAIT_FAILED); } if (handle == _WAPI_THREAD_CURRENT) { handle = wapi_get_current_thread_handle (); if (handle == NULL) { SetLastError (ERROR_INVALID_HANDLE); return(WAIT_FAILED); } } if ((GPOINTER_TO_UINT (handle) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) { SetLastError (ERROR_INVALID_HANDLE); return(WAIT_FAILED); } if (_wapi_handle_test_capabilities (handle, WAPI_HANDLE_CAP_WAIT) == FALSE) { MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p can't be waited for", __func__, handle); return(WAIT_FAILED); } _wapi_handle_ops_prewait (handle); if (_wapi_handle_test_capabilities (handle, WAPI_HANDLE_CAP_SPECIAL_WAIT) == TRUE) { MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p has special wait", __func__, handle); ret = _wapi_handle_ops_special_wait (handle, timeout, alertable); if (alertable && _wapi_thread_cur_apc_pending ()) ret = WAIT_IO_COMPLETION; return ret; } MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: locking handle %p", __func__, handle); thr_ret = _wapi_handle_lock_handle (handle); g_assert (thr_ret == 0); if (_wapi_handle_test_capabilities (handle, WAPI_HANDLE_CAP_OWN) == TRUE) { if (own_if_owned (handle) == TRUE) { MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p already owned", __func__, handle); ret = WAIT_OBJECT_0; goto done; } } if (own_if_signalled (handle) == TRUE) { MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p already signalled", __func__, handle); ret=WAIT_OBJECT_0; goto done; } if (timeout == 0) { ret = WAIT_TIMEOUT; goto done; } if (timeout != INFINITE) end = mono_100ns_ticks () + timeout * 1000 * 10; do { /* Check before waiting on the condition, just in case */ _wapi_handle_ops_prewait (handle); if (own_if_signalled (handle)) { MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p signalled", __func__, handle); ret = WAIT_OBJECT_0; goto done; } if (timeout == INFINITE) { waited = _wapi_handle_timedwait_signal_handle (handle, INFINITE, alertable, FALSE, &apc_pending); } else { now = mono_100ns_ticks (); if (end < now) { ret = WAIT_TIMEOUT; goto done; } waited = _wapi_handle_timedwait_signal_handle (handle, (end - now) / 10 / 1000, alertable, FALSE, &apc_pending); } if(waited==0 && !apc_pending) { /* Condition was signalled, so hopefully * handle is signalled now. (It might not be * if someone else got in before us.) */ if (own_if_signalled (handle)) { MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p signalled", __func__, handle); ret=WAIT_OBJECT_0; goto done; } /* Better luck next time */ } } while(waited == 0 && !apc_pending); /* Timeout or other error */ MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: wait on handle %p error: %s", __func__, handle, strerror (waited)); ret = apc_pending ? WAIT_IO_COMPLETION : WAIT_TIMEOUT; done: MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unlocking handle %p", __func__, handle); thr_ret = _wapi_handle_unlock_handle (handle); g_assert (thr_ret == 0); return(ret); }
static gint wapi_sendfile (guint32 socket, gpointer fd, guint32 bytes_to_write, guint32 bytes_per_send, guint32 flags) { #if defined(HAVE_SENDFILE) && (defined(__linux__) || defined(DARWIN)) gint file = GPOINTER_TO_INT (fd); gint n; gint errnum; gssize res; struct stat statbuf; n = fstat (file, &statbuf); if (n == -1) { errnum = errno; errnum = errno_to_WSA (errnum, __func__); WSASetLastError (errnum); return SOCKET_ERROR; } do { #ifdef __linux__ res = sendfile (socket, file, NULL, statbuf.st_size); #elif defined(DARWIN) /* TODO: header/tail could be sent in the 5th argument */ /* TODO: Might not send the entire file for non-blocking sockets */ res = sendfile (file, socket, 0, &statbuf.st_size, NULL, 0); #endif } while (res != -1 && (errno == EINTR || errno == EAGAIN) && !_wapi_thread_cur_apc_pending ()); if (res == -1) { errnum = errno; errnum = errno_to_WSA (errnum, __func__); WSASetLastError (errnum); return SOCKET_ERROR; } #else /* Default implementation */ gint file = GPOINTER_TO_INT (fd); gchar *buffer; gint n; buffer = g_malloc (SF_BUFFER_SIZE); do { do { n = read (file, buffer, SF_BUFFER_SIZE); } while (n == -1 && errno == EINTR && !_wapi_thread_cur_apc_pending ()); if (n == -1) break; if (n == 0) { g_free (buffer); return 0; /* We're done reading */ } do { n = send (socket, buffer, n, 0); /* short sends? enclose this in a loop? */ } while (n == -1 && errno == EINTR && !_wapi_thread_cur_apc_pending ()); } while (n != -1); if (n == -1) { gint errnum = errno; errnum = errno_to_WSA (errnum, __func__); WSASetLastError (errnum); g_free (buffer); return SOCKET_ERROR; } g_free (buffer); #endif return 0; }
int _wapi_connect(guint32 fd, const struct sockaddr *serv_addr, socklen_t addrlen) { gpointer handle = GUINT_TO_POINTER (fd); struct _WapiHandle_socket *socket_handle; gboolean ok; gint errnum; if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) { WSASetLastError (WSAENOTSOCK); return(SOCKET_ERROR); } if (connect (fd, serv_addr, addrlen) == -1) { mono_pollfd fds; int so_error; socklen_t len; errnum = errno; if (errno != EINTR) { DEBUG ("%s: connect error: %s", __func__, strerror (errnum)); errnum = errno_to_WSA (errnum, __func__); if (errnum == WSAEINPROGRESS) errnum = WSAEWOULDBLOCK; /* see bug #73053 */ WSASetLastError (errnum); /* * On solaris x86 getsockopt (SO_ERROR) is not set after * connect () fails so we need to save this error. * * But don't do this for EWOULDBLOCK (bug 317315) */ if (errnum != WSAEWOULDBLOCK) { ok = _wapi_lookup_handle (handle, WAPI_HANDLE_SOCKET, (gpointer *)&socket_handle); if (ok == FALSE) { /* ECONNRESET means the socket was closed by another thread */ /* 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; } } return(SOCKET_ERROR); } fds.fd = fd; 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__); DEBUG ("%s: connect poll error: %s", __func__, strerror (errno)); WSASetLastError (errnum); return(SOCKET_ERROR); } } len = sizeof(so_error); if (getsockopt (fd, SOL_SOCKET, SO_ERROR, &so_error, &len) == -1) { errnum = errno_to_WSA (errno, __func__); DEBUG ("%s: connect getsockopt error: %s", __func__, strerror (errno)); WSASetLastError (errnum); return(SOCKET_ERROR); } if (so_error != 0) { errnum = errno_to_WSA (so_error, __func__); /* Need to save this socket error */ ok = _wapi_lookup_handle (handle, WAPI_HANDLE_SOCKET, (gpointer *)&socket_handle); if (ok == FALSE) { g_warning ("%s: error looking up socket handle %p", __func__, handle); } else { socket_handle->saved_error = errnum; } DEBUG ("%s: connect getsockopt returned error: %s", __func__, strerror (so_error)); WSASetLastError (errnum); return(SOCKET_ERROR); } } return(0); }
guint32 _wapi_accept(guint32 fd, struct sockaddr *addr, socklen_t *addrlen) { gpointer handle = GUINT_TO_POINTER (fd); gpointer new_handle; struct _WapiHandle_socket *socket_handle; struct _WapiHandle_socket new_socket_handle = {0}; gboolean ok; int new_fd; if (addr != NULL && *addrlen < sizeof(struct sockaddr)) { WSASetLastError (WSAEFAULT); return(INVALID_SOCKET); } if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) { WSASetLastError (WSAENOTSOCK); return(INVALID_SOCKET); } ok = _wapi_lookup_handle (handle, WAPI_HANDLE_SOCKET, (gpointer *)&socket_handle); if (ok == FALSE) { g_warning ("%s: error looking up socket handle %p", __func__, handle); WSASetLastError (WSAENOTSOCK); return(INVALID_SOCKET); } 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; DEBUG ("%s: accept error: %s", __func__, strerror(errno)); errnum = errno_to_WSA (errnum, __func__); WSASetLastError (errnum); return(INVALID_SOCKET); } if (new_fd >= _wapi_fd_reserve) { DEBUG ("%s: File descriptor is too big", __func__); WSASetLastError (WSASYSCALLFAILURE); close (new_fd); return(INVALID_SOCKET); } new_socket_handle.domain = socket_handle->domain; new_socket_handle.type = socket_handle->type; new_socket_handle.protocol = socket_handle->protocol; new_socket_handle.still_readable = 1; new_handle = _wapi_handle_new_fd (WAPI_HANDLE_SOCKET, new_fd, &new_socket_handle); if(new_handle == _WAPI_HANDLE_INVALID) { g_warning ("%s: error creating socket handle", __func__); WSASetLastError (ERROR_GEN_FAILURE); return(INVALID_SOCKET); } DEBUG ("%s: returning newly accepted socket handle %p with", __func__, new_handle); return(new_fd); }