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_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); }
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); }
gboolean TransmitFile (guint32 socket, gpointer file, guint32 bytes_to_write, guint32 bytes_per_send, WapiOverlapped *ol, WapiTransmitFileBuffers *buffers, guint32 flags) { gpointer sock = GUINT_TO_POINTER (socket); gint ret; if (_wapi_handle_type (sock) != WAPI_HANDLE_SOCKET) { WSASetLastError (WSAENOTSOCK); return FALSE; } /* Write the header */ if (buffers != NULL && buffers->Head != NULL && buffers->HeadLength > 0) { ret = _wapi_send (socket, buffers->Head, buffers->HeadLength, 0); if (ret == SOCKET_ERROR) return FALSE; } ret = wapi_sendfile (socket, file, bytes_to_write, bytes_per_send, flags); if (ret == SOCKET_ERROR) return FALSE; /* Write the tail */ if (buffers != NULL && buffers->Tail != NULL && buffers->TailLength > 0) { ret = _wapi_send (socket, buffers->Tail, buffers->TailLength, 0); if (ret == SOCKET_ERROR) return FALSE; } if ((flags & TF_DISCONNECT) == TF_DISCONNECT) closesocket (socket); return TRUE; }
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); }
void _wapi_thread_set_termination_details (gpointer handle, guint32 exitstatus) { struct _WapiHandle_thread *thread_handle; gboolean ok; int thr_ret; if (_wapi_handle_issignalled (handle) || _wapi_handle_type (handle) == WAPI_HANDLE_UNUSED) { /* We must have already deliberately finished with * this thread, so don't do any more now */ return; } #ifdef DEBUG g_message ("%s: Thread %p terminating", __func__, handle); #endif _wapi_thread_abandon_mutexes (handle); ok = _wapi_lookup_handle (handle, WAPI_HANDLE_THREAD, (gpointer *)&thread_handle); if (ok == FALSE) { g_warning ("%s: error looking up thread handle %p", __func__, handle); return; } pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_handle, handle); thr_ret = _wapi_handle_lock_handle (handle); g_assert (thr_ret == 0); thread_handle->exitstatus = exitstatus; thread_handle->state = THREAD_STATE_EXITED; MONO_SEM_DESTROY (&thread_handle->suspend_sem); g_ptr_array_free (thread_handle->owned_mutexes, TRUE); _wapi_handle_set_signal_state (handle, TRUE, TRUE); thr_ret = _wapi_handle_unlock_handle (handle); g_assert (thr_ret == 0); pthread_cleanup_pop (0); #ifdef DEBUG g_message("%s: Recording thread handle %p id %ld status as %d", __func__, handle, thread_handle->id, exitstatus); #endif /* The thread is no longer active, so unref it */ _wapi_handle_unref (handle); }
int closesocket(guint32 fd) { gpointer handle = GUINT_TO_POINTER (fd); if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) { WSASetLastError (WSAENOTSOCK); return(0); } _wapi_handle_unref (handle); return(0); }
/* When a thread exits, any mutexes it still holds need to be * signalled. This function must not be called with the shared handle * lock held, as namedmutex_abandon () will try to acquire it */ void _wapi_mutex_abandon (gpointer data, pid_t pid, pthread_t tid) { WapiHandleType type = _wapi_handle_type (data); if (type == WAPI_HANDLE_MUTEX) { mutex_abandon (data, pid, tid); } else if (type == WAPI_HANDLE_NAMEDMUTEX) { namedmutex_abandon (data, pid, tid); } else { g_assert_not_reached (); } }
static gboolean own_if_owned(gpointer handle) { gboolean ret = FALSE; if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle))) { if (_wapi_handle_trylock_shared_handles () == EBUSY) { return (FALSE); } } if (_wapi_handle_ops_isowned (handle)) { _wapi_handle_ops_own (handle); ret = TRUE; } if (_WAPI_SHARED_HANDLE (_wapi_handle_type (handle))) { _wapi_handle_unlock_shared_handles (); } return(ret); }
void _wapi_FD_SET(guint32 fd, fd_set *set) { gpointer handle = GUINT_TO_POINTER (fd); if (fd >= FD_SETSIZE) { WSASetLastError (WSAEINVAL); return; } if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) { WSASetLastError (WSAENOTSOCK); return; } FD_SET (fd, set); }
int _wapi_bind(guint32 fd, struct sockaddr *my_addr, socklen_t addrlen) { gpointer handle = GUINT_TO_POINTER (fd); int ret; if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) { WSASetLastError (WSAENOTSOCK); return(SOCKET_ERROR); } ret = bind (fd, my_addr, addrlen); if (ret == -1) { gint errnum = errno; DEBUG ("%s: bind error: %s", __func__, strerror(errno)); errnum = errno_to_WSA (errnum, __func__); WSASetLastError (errnum); return(SOCKET_ERROR); } return(ret); }
int _wapi_shutdown(guint32 fd, int how) { struct _WapiHandle_socket *socket_handle; gboolean ok; gpointer handle = GUINT_TO_POINTER (fd); int ret; if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) { WSASetLastError (WSAENOTSOCK); return(SOCKET_ERROR); } if (how == SHUT_RD || how == SHUT_RDWR) { 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(SOCKET_ERROR); } socket_handle->still_readable = 0; } ret = shutdown (fd, how); if (ret == -1) { gint errnum = errno; DEBUG ("%s: shutdown 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); }
int _wapi_listen(guint32 fd, int backlog) { gpointer handle = GUINT_TO_POINTER (fd); int ret; if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) { WSASetLastError (WSAENOTSOCK); return(SOCKET_ERROR); } ret = listen (fd, backlog); if (ret == -1) { gint errnum = errno; DEBUG ("%s: listen error: %s", __func__, strerror (errno)); errnum = errno_to_WSA (errnum, __func__); WSASetLastError (errnum); return(SOCKET_ERROR); } return(0); }
int _wapi_getsockname(guint32 fd, struct sockaddr *name, socklen_t *namelen) { gpointer handle = GUINT_TO_POINTER (fd); int ret; if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) { WSASetLastError (WSAENOTSOCK); return(SOCKET_ERROR); } ret = getsockname (fd, name, namelen); if (ret == -1) { gint errnum = errno; MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: getsockname error: %s", __func__, strerror (errno)); errnum = errno_to_WSA (errnum, __func__); WSASetLastError (errnum); return(SOCKET_ERROR); } return(ret); }
/** * WaitForMultipleObjectsEx: * @numobjects: The number of objects in @handles. The maximum allowed * is %MAXIMUM_WAIT_OBJECTS. * @handles: An array of object handles. Duplicates are not allowed. * @waitall: If %TRUE, this function waits until all of the handles * are signalled. If %FALSE, this function returns when any object is * signalled. * @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 one or more of @handles is * signalled, or @timeout ms elapses. If @timeout is zero, the state * of each item of @handles is tested and the function returns * immediately. If @timeout is %INFINITE, the function waits forever. * * Return value: %WAIT_OBJECT_0 to %WAIT_OBJECT_0 + @numobjects - 1 - * if @waitall is %TRUE, indicates that all objects are signalled. If * @waitall is %FALSE, the return value minus %WAIT_OBJECT_0 indicates * the first index into @handles of the objects that are signalled. * %WAIT_ABANDONED_0 to %WAIT_ABANDONED_0 + @numobjects - 1 - if * @waitall is %TRUE, indicates that all objects are signalled, and at * least one object is an abandoned mutex object (See * WaitForSingleObject() for a description of abandoned mutexes.) If * @waitall is %FALSE, the return value minus %WAIT_ABANDONED_0 * indicates the first index into @handles of an abandoned mutex. * %WAIT_TIMEOUT - The @timeout interval elapsed and no objects in * @handles are signalled. %WAIT_FAILED - an error occurred. * %WAIT_IO_COMPLETION - the wait was ended by an APC. */ guint32 WaitForMultipleObjectsEx(guint32 numobjects, gpointer *handles, gboolean waitall, guint32 timeout, gboolean alertable) { gboolean duplicate = FALSE, bogustype = FALSE, done; guint32 count, lowest; guint i; guint32 ret; int thr_ret; gpointer current_thread = wapi_get_current_thread_handle (); guint32 retval; gboolean poll; gpointer sorted_handles [MAXIMUM_WAIT_OBJECTS]; gboolean apc_pending = FALSE; gint64 now, end; if (current_thread == NULL) { SetLastError (ERROR_INVALID_HANDLE); return(WAIT_FAILED); } if (numobjects > MAXIMUM_WAIT_OBJECTS) { MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Too many handles: %d", __func__, numobjects); return(WAIT_FAILED); } if (numobjects == 1) { return WaitForSingleObjectEx (handles [0], timeout, alertable); } /* Check for duplicates */ for (i = 0; i < numobjects; i++) { if (handles[i] == _WAPI_THREAD_CURRENT) { handles[i] = wapi_get_current_thread_handle (); if (handles[i] == NULL) { MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Handle %d bogus", __func__, i); bogustype = TRUE; break; } } if ((GPOINTER_TO_UINT (handles[i]) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) { MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Handle %d pseudo process", __func__, i); bogustype = TRUE; break; } if (_wapi_handle_test_capabilities (handles[i], WAPI_HANDLE_CAP_WAIT) == FALSE) { MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Handle %p can't be waited for", __func__, handles[i]); bogustype = TRUE; break; } sorted_handles [i] = handles [i]; _wapi_handle_ops_prewait (handles[i]); } qsort (sorted_handles, numobjects, sizeof (gpointer), g_direct_equal); for (i = 1; i < numobjects; i++) { if (sorted_handles [i - 1] == sorted_handles [i]) { duplicate = TRUE; break; } } if (duplicate == TRUE) { MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Returning due to duplicates", __func__); return(WAIT_FAILED); } if (bogustype == TRUE) { MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: Returning due to bogus type", __func__); return(WAIT_FAILED); } poll = FALSE; for (i = 0; i < numobjects; ++i) if (_wapi_handle_type (handles [i]) == WAPI_HANDLE_PROCESS || _WAPI_SHARED_HANDLE (_wapi_handle_type (handles[i]))) /* Can't wait for a process handle + another handle without polling */ poll = TRUE; done = test_and_own (numobjects, handles, waitall, &count, &lowest); if (done == TRUE) { return(WAIT_OBJECT_0+lowest); } if (timeout == 0) { return WAIT_TIMEOUT; } if (timeout != INFINITE) end = mono_100ns_ticks () + timeout * 1000 * 10; /* Have to wait for some or all handles to become signalled */ for (i = 0; i < numobjects; i++) { /* Add a reference, as we need to ensure the handle wont * disappear from under us while we're waiting in the loop * (not lock, as we don't want exclusive access here) */ _wapi_handle_ref (handles[i]); } while(1) { /* Prod all handles with prewait methods and * special-wait handles that aren't already signalled */ for (i = 0; i < numobjects; i++) { _wapi_handle_ops_prewait (handles[i]); if (_wapi_handle_test_capabilities (handles[i], WAPI_HANDLE_CAP_SPECIAL_WAIT) == TRUE && _wapi_handle_issignalled (handles[i]) == FALSE) { _wapi_handle_ops_special_wait (handles[i], 0, alertable); } } MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: locking signal mutex", __func__); thr_ret = _wapi_handle_lock_signal_mutex (); g_assert (thr_ret == 0); /* Check the signalled state of handles inside the critical section */ if (waitall) { done = TRUE; for (i = 0; i < numobjects; i++) if (!_wapi_handle_issignalled (handles [i])) done = FALSE; } else { done = FALSE; for (i = 0; i < numobjects; i++) if (_wapi_handle_issignalled (handles [i])) done = TRUE; } if (!done) { /* Enter the wait */ if (timeout == INFINITE) { ret = _wapi_handle_timedwait_signal (INFINITE, poll, &apc_pending); } else { now = mono_100ns_ticks (); if (end < now) { ret = WAIT_TIMEOUT; } else { ret = _wapi_handle_timedwait_signal ((end - now) / 10 / 1000, poll, &apc_pending); } } } else { /* No need to wait */ ret = 0; } MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unlocking signal mutex", __func__); thr_ret = _wapi_handle_unlock_signal_mutex (NULL); g_assert (thr_ret == 0); if (alertable && apc_pending) { retval = WAIT_IO_COMPLETION; break; } /* Check if everything is signalled, as we can't * guarantee to notice a shared signal even if the * wait timed out */ done = test_and_own (numobjects, handles, waitall, &count, &lowest); if (done == TRUE) { retval = WAIT_OBJECT_0+lowest; break; } else if (ret != 0) { /* Didn't get all handles, and there was a * timeout or other error */ MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: wait returned error: %s", __func__, strerror (ret)); if(ret==ETIMEDOUT) { retval = WAIT_TIMEOUT; } else { retval = WAIT_FAILED; } break; } } for (i = 0; i < numobjects; i++) { /* Unref everything we reffed above */ _wapi_handle_unref (handles[i]); } return retval; }
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 (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) { WSASetLastError (WSAENOTSOCK); return SOCKET_ERROR; } if (command == SIO_GET_EXTENSION_FUNCTION_POINTER) { int i = 0; WapiGuid *guid = (WapiGuid *)input; if (i_len < sizeof(WapiGuid)) { /* As far as I can tell, windows doesn't * actually set an error here... */ WSASetLastError (WSAEINVAL); return(SOCKET_ERROR); } if (o_len < sizeof(gpointer)) { /* Or here... */ WSASetLastError (WSAEINVAL); return(SOCKET_ERROR); } if (output == NULL) { /* Or here */ WSASetLastError (WSAEINVAL); return(SOCKET_ERROR); } while(extension_functions[i].func != NULL) { if (!memcmp (guid, &extension_functions[i].guid, sizeof(WapiGuid))) { memcpy (output, &extension_functions[i].func, sizeof(gpointer)); *written = sizeof(gpointer); return(0); } i++; } WSASetLastError (WSAEINVAL); 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); } ret = ioctl (fd, command, buffer); if (ret == -1) { gint errnum = errno; DEBUG("%s: WSAIoctl error: %s", __func__, strerror (errno)); 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... * * NB windows returns WSAEFAULT if o_len is too small */ i_len = (i_len > o_len) ? o_len : i_len; if (i_len > 0 && output != NULL) { memcpy (output, buffer, i_len); } g_free (buffer); *written = i_len; } return(0); }
/** * WaitForMultipleObjectsEx: * @numobjects: The number of objects in @handles. The maximum allowed * is %MAXIMUM_WAIT_OBJECTS. * @handles: An array of object handles. Duplicates are not allowed. * @waitall: If %TRUE, this function waits until all of the handles * are signalled. If %FALSE, this function returns when any object is * signalled. * @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 one or more of @handles is * signalled, or @timeout ms elapses. If @timeout is zero, the state * of each item of @handles is tested and the function returns * immediately. If @timeout is %INFINITE, the function waits forever. * * Return value: %WAIT_OBJECT_0 to %WAIT_OBJECT_0 + @numobjects - 1 - * if @waitall is %TRUE, indicates that all objects are signalled. If * @waitall is %FALSE, the return value minus %WAIT_OBJECT_0 indicates * the first index into @handles of the objects that are signalled. * %WAIT_ABANDONED_0 to %WAIT_ABANDONED_0 + @numobjects - 1 - if * @waitall is %TRUE, indicates that all objects are signalled, and at * least one object is an abandoned mutex object (See * WaitForSingleObject() for a description of abandoned mutexes.) If * @waitall is %FALSE, the return value minus %WAIT_ABANDONED_0 * indicates the first index into @handles of an abandoned mutex. * %WAIT_TIMEOUT - The @timeout interval elapsed and no objects in * @handles are signalled. %WAIT_FAILED - an error occurred. * %WAIT_IO_COMPLETION - the wait was ended by an APC. */ guint32 WaitForMultipleObjectsEx(guint32 numobjects, gpointer *handles, gboolean waitall, guint32 timeout, gboolean alertable) { GHashTable *dups; gboolean duplicate = FALSE, bogustype = FALSE, done; guint32 count, lowest; struct timespec abstime; guint i; guint32 ret; int thr_ret; gpointer current_thread = _wapi_thread_handle_from_id (pthread_self ()); guint32 retval; gboolean poll; if (current_thread == NULL) { SetLastError (ERROR_INVALID_HANDLE); return(WAIT_FAILED); } if (numobjects > MAXIMUM_WAIT_OBJECTS) { #ifdef DEBUG g_message ("%s: Too many handles: %d", __func__, numobjects); #endif return(WAIT_FAILED); } if (numobjects == 1) { return WaitForSingleObjectEx (handles [0], timeout, alertable); } /* Check for duplicates */ dups = g_hash_table_new (g_direct_hash, g_direct_equal); for (i = 0; i < numobjects; i++) { gpointer exists; if (handles[i] == _WAPI_THREAD_CURRENT) { handles[i] = _wapi_thread_handle_from_id (pthread_self ()); if (handles[i] == NULL) { #ifdef DEBUG g_message ("%s: Handle %d bogus", __func__, i); #endif bogustype = TRUE; break; } } if ((GPOINTER_TO_UINT (handles[i]) & _WAPI_PROCESS_UNHANDLED) == _WAPI_PROCESS_UNHANDLED) { #ifdef DEBUG g_message ("%s: Handle %d pseudo process", __func__, i); #endif bogustype = TRUE; break; } exists = g_hash_table_lookup (dups, handles[i]); if (exists != NULL) { #ifdef DEBUG g_message ("%s: Handle %p duplicated", __func__, handles[i]); #endif duplicate = TRUE; break; } if (_wapi_handle_test_capabilities (handles[i], WAPI_HANDLE_CAP_WAIT) == FALSE) { #ifdef DEBUG g_message ("%s: Handle %p can't be waited for", __func__, handles[i]); #endif bogustype = TRUE; break; } g_hash_table_insert (dups, handles[i], handles[i]); _wapi_handle_ops_prewait (handles[i]); } g_hash_table_destroy (dups); if (duplicate == TRUE) { #ifdef DEBUG g_message ("%s: Returning due to duplicates", __func__); #endif return(WAIT_FAILED); } if (bogustype == TRUE) { #ifdef DEBUG g_message ("%s: Returning due to bogus type", __func__); #endif return(WAIT_FAILED); } poll = FALSE; for (i = 0; i < numobjects; ++i) if (_wapi_handle_type (handles [i]) == WAPI_HANDLE_PROCESS) /* Can't wait for a process handle + another handle without polling */ poll = TRUE; done = test_and_own (numobjects, handles, waitall, &count, &lowest); if (done == TRUE) { return(WAIT_OBJECT_0+lowest); } if (timeout == 0) { return WAIT_TIMEOUT; } /* Have to wait for some or all handles to become signalled */ if(timeout!=INFINITE) { _wapi_calc_timeout (&abstime, timeout); } if (alertable && _wapi_thread_apc_pending (current_thread)) { _wapi_thread_dispatch_apc_queue (current_thread); return WAIT_IO_COMPLETION; } for (i = 0; i < numobjects; i++) { /* Add a reference, as we need to ensure the handle wont * disappear from under us while we're waiting in the loop * (not lock, as we don't want exclusive access here) */ _wapi_handle_ref (handles[i]); } while(1) { /* Prod all handles with prewait methods and * special-wait handles that aren't already signalled */ for (i = 0; i < numobjects; i++) { _wapi_handle_ops_prewait (handles[i]); if (_wapi_handle_test_capabilities (handles[i], WAPI_HANDLE_CAP_SPECIAL_WAIT) == TRUE && _wapi_handle_issignalled (handles[i]) == FALSE) { _wapi_handle_ops_special_wait (handles[i], 0); } } #ifdef DEBUG g_message ("%s: locking signal mutex", __func__); #endif pthread_cleanup_push ((void(*)(void *))_wapi_handle_unlock_signal_mutex, NULL); thr_ret = _wapi_handle_lock_signal_mutex (); g_assert (thr_ret == 0); /* Check the signalled state of handles inside the critical section */ if (waitall) { done = TRUE; for (i = 0; i < numobjects; i++) if (!_wapi_handle_issignalled (handles [i])) done = FALSE; } else { done = FALSE; for (i = 0; i < numobjects; i++) if (_wapi_handle_issignalled (handles [i])) done = TRUE; } if (!done) { /* Enter the wait */ if (timeout == INFINITE) { ret = _wapi_handle_wait_signal (poll); } else { ret = _wapi_handle_timedwait_signal (&abstime, poll); } } else { /* No need to wait */ ret = 0; } #ifdef DEBUG g_message ("%s: unlocking signal mutex", __func__); #endif thr_ret = _wapi_handle_unlock_signal_mutex (NULL); g_assert (thr_ret == 0); pthread_cleanup_pop (0); if (alertable && _wapi_thread_apc_pending (current_thread)) { _wapi_thread_dispatch_apc_queue (current_thread); retval = WAIT_IO_COMPLETION; break; } /* Check if everything is signalled, as we can't * guarantee to notice a shared signal even if the * wait timed out */ done = test_and_own (numobjects, handles, waitall, &count, &lowest); if (done == TRUE) { retval = WAIT_OBJECT_0+lowest; break; } else if (ret != 0) { /* Didn't get all handles, and there was a * timeout or other error */ #ifdef DEBUG g_message ("%s: wait returned error: %s", __func__, strerror (ret)); #endif if(ret==ETIMEDOUT) { retval = WAIT_TIMEOUT; } else { retval = WAIT_FAILED; } break; } } for (i = 0; i < numobjects; i++) { /* Unref everything we reffed above */ _wapi_handle_unref (handles[i]); } return retval; }
int _wapi_setsockopt(guint32 fd, int level, int optname, const void *optval, socklen_t optlen) { 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 (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) { WSASetLastError (WSAENOTSOCK); return(SOCKET_ERROR); } tmp_val = optval; if (level == SOL_SOCKET && (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)) { int ms = *((int *) optval); tv.tv_sec = ms / 1000; tv.tv_usec = (ms % 1000) * 1000; // micro from milli tmp_val = &tv; optlen = sizeof (tv); } #if defined (__linux__) else if (level == SOL_SOCKET && (optname == SO_SNDBUF || optname == SO_RCVBUF)) { /* According to socket(7) the Linux kernel doubles the * buffer sizes "to allow space for bookkeeping * overhead." */ bufsize = *((int *) optval); bufsize /= 2; tmp_val = &bufsize; } #endif ret = setsockopt (fd, level, optname, tmp_val, optlen); if (ret == -1) { gint errnum = errno; DEBUG ("%s: setsockopt error: %s", __func__, strerror (errno)); errnum = errno_to_WSA (errnum, __func__); WSASetLastError (errnum); return(SOCKET_ERROR); } #if defined (SO_REUSEPORT) /* BSD's and MacOS X multicast sockets also need SO_REUSEPORT when SO_REUSEADDR is requested. */ if (level == SOL_SOCKET && optname == SO_REUSEADDR) { int type; socklen_t type_len = sizeof (type); if (!getsockopt (fd, level, SO_TYPE, &type, &type_len)) { if (type == SOCK_DGRAM || type == SOCK_STREAM) setsockopt (fd, level, SO_REUSEPORT, tmp_val, optlen); } } #endif return(ret); }
int ioctlsocket(guint32 fd, unsigned long command, gpointer arg) { gpointer handle = GUINT_TO_POINTER (fd); int ret; if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) { WSASetLastError (WSAENOTSOCK); return(SOCKET_ERROR); } switch(command){ case FIONBIO: #ifdef O_NONBLOCK /* This works better than ioctl(...FIONBIO...) * on Linux (it causes connect to return * EINPROGRESS, but the ioctl doesn't seem to) */ 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); } break; #endif /* O_NONBLOCK */ /* Unused in Mono */ case SIOCATMARK: ret = ioctl (fd, command, arg); break; case FIONREAD: { #if defined (PLATFORM_MACOSX) // ioctl (fd, FIONREAD, XXX) returns the size of // the UDP header as well on // Darwin. // // Use getsockopt SO_NREAD instead to get the // right values for TCP and UDP. // // ai_canonname can be null in some cases on darwin, where the runtime assumes it will // be the value of the ip buffer. socklen_t optlen = sizeof (int); ret = getsockopt (fd, SOL_SOCKET, SO_NREAD, arg, &optlen); #else ret = ioctl (fd, command, arg); #endif break; } default: WSASetLastError (WSAEINVAL); return(SOCKET_ERROR); } if (ret == -1) { gint errnum = errno; DEBUG ("%s: ioctl error: %s", __func__, strerror (errno)); errnum = errno_to_WSA (errnum, __func__); 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); }
int _wapi_getsockopt(guint32 fd, int level, int optname, void *optval, socklen_t *optlen) { gpointer handle = GUINT_TO_POINTER (fd); int ret; struct timeval tv; void *tmp_val; struct _WapiHandle_socket *socket_handle; gboolean ok; if (_wapi_handle_type (handle) != WAPI_HANDLE_SOCKET) { WSASetLastError (WSAENOTSOCK); return(SOCKET_ERROR); } tmp_val = optval; if (level == SOL_SOCKET && (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; DEBUG ("%s: getsockopt error: %s", __func__, strerror (errno)); errnum = errno_to_WSA (errnum, __func__); WSASetLastError (errnum); return(SOCKET_ERROR); } if (level == SOL_SOCKET && (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)) { *((int *) optval) = tv.tv_sec * 1000 + (tv.tv_usec / 1000); // milli from micro *optlen = sizeof (int); } if (optname == SO_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); /* can't extract the last error */ *((int *) optval) = errno_to_WSA (*((int *)optval), __func__); } else { if (*((int *)optval) != 0) { *((int *) optval) = errno_to_WSA (*((int *)optval), __func__); socket_handle->saved_error = *((int *)optval); } else { *((int *)optval) = socket_handle->saved_error; } } } return(ret); }
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); }