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 (mono_w32handle_get_type (sock) != MONO_W32HANDLE_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; }
static int _wapi_sendmsg(guint32 fd, const struct msghdr *msg, int send_flags) { gpointer handle = GUINT_TO_POINTER (fd); int ret; MonoThreadInfo *info = mono_thread_info_current (); if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) { WSASetLastError (WSAENOTSOCK); return(SOCKET_ERROR); } do { ret = sendmsg (fd, msg, send_flags); } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info)); if (ret == -1) { gint errnum = errno; MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: sendmsg error: %s", __func__, strerror (errno)); errnum = errno_to_WSA (errnum, __func__); WSASetLastError (errnum); return(SOCKET_ERROR); } return(ret); }
int mono_w32socket_sendto (SOCKET sock, const char *buf, int len, int flags, const struct sockaddr *to, int tolen, gboolean blocking) { gpointer handle; int ret; MonoThreadInfo *info; handle = GUINT_TO_POINTER (sock); if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) { mono_w32socket_set_last_error (WSAENOTSOCK); return SOCKET_ERROR; } info = mono_thread_info_current (); do { ret = sendto (sock, buf, len, flags, to, tolen); } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info)); if (ret == -1) { gint errnum = errno; mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: send error: %s", __func__, g_strerror (errno)); mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); return SOCKET_ERROR; } return ret; }
gint mono_w32socket_set_blocking (SOCKET socket, gboolean blocking) { #ifdef O_NONBLOCK gint ret; gpointer handle; handle = GINT_TO_POINTER (socket); if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) { mono_w32socket_set_last_error (WSAENOTSOCK); return SOCKET_ERROR; } /* This works better than ioctl(...FIONBIO...) * on Linux (it causes connect to return * EINPROGRESS, but the ioctl doesn't seem to) */ ret = fcntl (socket, F_GETFL, 0); if (ret != -1) ret = fcntl (socket, F_SETFL, blocking ? (ret & (~O_NONBLOCK)) : (ret | (O_NONBLOCK))); if (ret == -1) { gint errnum = errno; mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: ioctl error: %s", __func__, g_strerror (errno)); mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); return SOCKET_ERROR; } return 0; #else mono_w32socket_set_last_error (ERROR_NOT_SUPPORTED); return SOCKET_ERROR; #endif /* O_NONBLOCK */ }
MonoBoolean ves_icall_System_Threading_Semaphore_ReleaseSemaphore_internal (gpointer handle, gint32 releaseCount, gint32 *prevcount) { MonoW32HandleType type; MonoW32HandleSemaphore *sem_handle; int thr_ret; MonoBoolean ret; if (!handle) { SetLastError (ERROR_INVALID_HANDLE); return FALSE; } switch (type = mono_w32handle_get_type (handle)) { case MONO_W32HANDLE_SEM: case MONO_W32HANDLE_NAMEDSEM: break; default: SetLastError (ERROR_INVALID_HANDLE); return FALSE; } if (!mono_w32handle_lookup (handle, type, (gpointer *)&sem_handle)) { g_warning ("%s: error looking up sem handle %p", __func__, handle); return FALSE; } mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: releasing %s handle %p", __func__, mono_w32handle_ops_typename (type), handle); thr_ret = mono_w32handle_lock_handle (handle); g_assert (thr_ret == 0); /* Do this before checking for count overflow, because overflowing * max is a listed technique for finding the current value */ if (prevcount) *prevcount = sem_handle->val; /* No idea why max is signed, but thats the spec :-( */ if (sem_handle->val + releaseCount > (guint32)sem_handle->max) { mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: %s handle %p val %d count %d max %d, max value would be exceeded", __func__, mono_w32handle_ops_typename (type), handle, sem_handle->val, releaseCount, sem_handle->max); ret = FALSE; } else { mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: %s handle %p val %d count %d max %d", __func__, mono_w32handle_ops_typename (type), handle, sem_handle->val, releaseCount, sem_handle->max); sem_handle->val += releaseCount; mono_w32handle_set_signal_state (handle, TRUE, TRUE); ret = TRUE; } thr_ret = mono_w32handle_unlock_handle (handle); g_assert (thr_ret == 0); return ret; }
static gboolean cleanup_close (gpointer handle, gpointer data, gpointer user_data) { if (mono_w32handle_get_type (handle) == MONO_W32HANDLE_SOCKET) mono_w32handle_force_close (handle, data); return FALSE; }
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; MonoThreadInfo *info = mono_thread_info_current (); if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) { WSASetLastError (WSAENOTSOCK); return(SOCKET_ERROR); } do { ret = recvfrom (fd, buf, len, recv_flags, from, fromlen); } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info)); 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 = mono_w32handle_lookup (handle, MONO_W32HANDLE_SOCKET, (gpointer *)&socket_handle); if (ok == FALSE || socket_handle->still_readable != 1) { ret = -1; errno = EINTR; } } if (ret == -1) { gint errnum = errno; MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: recv error: %s", __func__, strerror(errno)); errnum = errno_to_WSA (errnum, __func__); WSASetLastError (errnum); return(SOCKET_ERROR); } return(ret); }
int closesocket(guint32 fd) { gpointer handle = GUINT_TO_POINTER (fd); if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) { WSASetLastError (WSAENOTSOCK); return(0); } mono_w32handle_unref (handle); return(0); }
void _wapi_FD_SET(guint32 fd, fd_set *set) { gpointer handle = GUINT_TO_POINTER (fd); if (fd >= FD_SETSIZE) { WSASetLastError (WSAEINVAL); return; } if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) { WSASetLastError (WSAENOTSOCK); return; } FD_SET (fd, set); }
static gboolean search_callback (gpointer handle, gpointer handle_specific, gpointer user_data) { SearchData *search_data = (SearchData*) user_data; if (search_data->type != mono_w32handle_get_type (handle)) return FALSE; if (!search_data->search_user_callback (handle, search_data->search_user_data)) return FALSE; mono_w32handle_ref (handle); search_data->handle = handle; search_data->handle_specific = handle_specific; return TRUE; }
static gboolean mono_w32handle_namespace_search_handle_callback (gpointer handle, gpointer data, gpointer user_data) { NamespaceSearchHandleData *search_data; MonoW32HandleType type; MonoW32HandleNamespace *sharedns; type = mono_w32handle_get_type (handle); if (!has_namespace (type)) return FALSE; search_data = (NamespaceSearchHandleData*) user_data; switch (type) { case MONO_W32HANDLE_NAMEDMUTEX: sharedns = mono_w32mutex_get_namespace ((MonoW32HandleNamedMutex*) data); break; case MONO_W32HANDLE_NAMEDSEM: sharedns = mono_w32semaphore_get_namespace ((MonoW32HandleNamedSemaphore*) data); break; case MONO_W32HANDLE_NAMEDEVENT: sharedns = mono_w32event_get_namespace ((MonoW32HandleNamedEvent*) data); break; default: g_assert_not_reached (); } if (strcmp (sharedns->name, search_data->name) == 0) { if (type != search_data->type) { /* Its the wrong type, so fail now */ mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p matches name but is wrong type: %s", __func__, handle, mono_w32handle_get_typename (type)); search_data->ret = INVALID_HANDLE_VALUE; } else { mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: handle %p matches name and type", __func__, handle); /* we do not want the handle to be destroyed before we return it */ mono_w32handle_ref (handle); search_data->ret = handle; } return TRUE; } return FALSE; }
int _wapi_bind(guint32 fd, struct sockaddr *my_addr, socklen_t addrlen) { gpointer handle = GUINT_TO_POINTER (fd); int ret; if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) { WSASetLastError (WSAENOTSOCK); return(SOCKET_ERROR); } ret = bind (fd, my_addr, addrlen); if (ret == -1) { gint errnum = errno; MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: bind 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; MonoThreadInfo *info = mono_thread_info_current (); if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) { WSASetLastError (WSAENOTSOCK); return(SOCKET_ERROR); } do { ret = recvmsg (fd, msg, recv_flags); } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info)); if (ret == 0) { /* see _wapi_recvfrom */ ok = mono_w32handle_lookup (handle, MONO_W32HANDLE_SOCKET, (gpointer *)&socket_handle); if (ok == FALSE || socket_handle->still_readable != 1) { ret = -1; errno = EINTR; } } if (ret == -1) { gint errnum = errno; MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: recvmsg 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 (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) { WSASetLastError (WSAENOTSOCK); return(SOCKET_ERROR); } if (how == SHUT_RD || how == SHUT_RDWR) { ok = mono_w32handle_lookup (handle, MONO_W32HANDLE_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; MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: shutdown error: %s", __func__, strerror (errno)); errnum = errno_to_WSA (errnum, __func__); WSASetLastError (errnum); return(SOCKET_ERROR); } return(ret); }
gint mono_w32socket_getsockname (SOCKET sock, struct sockaddr *name, socklen_t *namelen) { gpointer handle; gint ret; handle = GUINT_TO_POINTER (sock); if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) { mono_w32socket_set_last_error (WSAENOTSOCK); return SOCKET_ERROR; } ret = getsockname (sock, name, namelen); if (ret == -1) { gint errnum = errno; mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: getsockname error: %s", __func__, g_strerror (errno)); mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); return SOCKET_ERROR; } return 0; }
gint mono_w32socket_listen (SOCKET sock, gint backlog) { gpointer handle; gint ret; handle = GUINT_TO_POINTER (sock); if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) { mono_w32socket_set_last_error (WSAENOTSOCK); return SOCKET_ERROR; } ret = listen (sock, backlog); if (ret == -1) { gint errnum = errno; mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: listen error: %s", __func__, g_strerror (errno)); mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); return SOCKET_ERROR; } return 0; }
gint mono_w32socket_get_available (SOCKET socket, guint64 *amount) { gint ret; gpointer handle; handle = GINT_TO_POINTER (socket); if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) { mono_w32socket_set_last_error (WSAENOTSOCK); return SOCKET_ERROR; } #if defined (PLATFORM_MACOSX) // ioctl (socket, 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 (socket, SOL_SOCKET, SO_NREAD, (gulong*) amount, &optlen); #else ret = ioctl (socket, FIONREAD, (gulong*) amount); #endif if (ret == -1) { gint errnum = errno; mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: ioctl error: %s", __func__, g_strerror (errno)); mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); return SOCKET_ERROR; } return 0; }
int _wapi_listen(guint32 fd, int backlog) { gpointer handle = GUINT_TO_POINTER (fd); int ret; if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) { WSASetLastError (WSAENOTSOCK); return(SOCKET_ERROR); } ret = listen (fd, backlog); if (ret == -1) { gint errnum = errno; MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: listen error: %s", __func__, strerror (errno)); errnum = errno_to_WSA (errnum, __func__); WSASetLastError (errnum); return(SOCKET_ERROR); } return(0); }
int mono_w32socket_sendbuffers (SOCKET sock, WSABUF *buffers, guint32 count, guint32 *sent, guint32 flags, gpointer overlapped, gpointer complete, gboolean blocking) { struct msghdr hdr; MonoThreadInfo *info; gpointer handle; gint ret; g_assert (overlapped == NULL); g_assert (complete == NULL); handle = GUINT_TO_POINTER (sock); if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) { mono_w32socket_set_last_error (WSAENOTSOCK); return SOCKET_ERROR; } info = mono_thread_info_current (); wsabuf_to_msghdr (buffers, count, &hdr); do { ret = sendmsg (sock, &hdr, flags); } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info)); msghdr_iov_free (&hdr); if (ret == -1) { gint errnum = errno; mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: sendmsg error: %s", __func__, g_strerror (errno)); mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); return SOCKET_ERROR; } *sent = ret; return 0; }
int mono_w32socket_send (SOCKET sock, char *buf, int len, int flags, gboolean blocking) { gpointer handle; int ret; MonoThreadInfo *info; handle = GUINT_TO_POINTER (sock); if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) { mono_w32socket_set_last_error (WSAENOTSOCK); return SOCKET_ERROR; } info = mono_thread_info_current (); do { ret = send (sock, buf, len, flags); } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info)); if (ret == -1) { gint errnum = errno; mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: send error: %s", __func__, g_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 (sock, F_GETFL, 0); if (ret != -1 && (ret & O_NONBLOCK) == 0) errnum = ETIMEDOUT; } #endif /* O_NONBLOCK */ mono_w32socket_set_last_error (mono_w32socket_convert_error (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; MonoThreadInfo *info = mono_thread_info_current (); if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) { WSASetLastError (WSAENOTSOCK); return(SOCKET_ERROR); } do { ret = send (fd, msg, len, send_flags); } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info)); if (ret == -1) { gint errnum = errno; MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%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); }
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; MonoThreadInfo *info = mono_thread_info_current (); if (addr != NULL && *addrlen < sizeof(struct sockaddr)) { WSASetLastError (WSAEFAULT); return(INVALID_SOCKET); } if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) { WSASetLastError (WSAENOTSOCK); return(INVALID_SOCKET); } ok = mono_w32handle_lookup (handle, MONO_W32HANDLE_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 && !mono_thread_info_is_interrupt_state (info)); if (new_fd == -1) { gint errnum = errno; MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: accept error: %s", __func__, strerror(errno)); errnum = errno_to_WSA (errnum, __func__); WSASetLastError (errnum); return(INVALID_SOCKET); } if (new_fd >= mono_w32handle_fd_reserve) { MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%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 = mono_w32handle_new_fd (MONO_W32HANDLE_SOCKET, new_fd, &new_socket_handle); if(new_handle == INVALID_HANDLE_VALUE) { g_warning ("%s: error creating socket handle", __func__); WSASetLastError (ERROR_GEN_FAILURE); return(INVALID_SOCKET); } MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: returning newly accepted socket handle %p with", __func__, new_handle); return(new_fd); }
gint mono_w32socket_ioctl (SOCKET sock, gint32 command, gchar *input, gint inputlen, gchar *output, gint outputlen, glong *written) { gpointer handle; gint ret; gchar *buffer; handle = GUINT_TO_POINTER (sock); if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) { mono_w32socket_set_last_error (WSAENOTSOCK); return SOCKET_ERROR; } if (command == 0xC8000006 /* SIO_GET_EXTENSION_FUNCTION_POINTER */) { gint i; GUID *guid; if (inputlen < sizeof(GUID)) { /* As far as I can tell, windows doesn't * actually set an error here... */ mono_w32socket_set_last_error (WSAEINVAL); return SOCKET_ERROR; } if (outputlen < sizeof(gpointer)) { /* Or here... */ mono_w32socket_set_last_error (WSAEINVAL); return SOCKET_ERROR; } if (output == NULL) { /* Or here */ mono_w32socket_set_last_error (WSAEINVAL); return SOCKET_ERROR; } guid = (GUID*) input; for (i = 0; extension_functions[i].func; i++) { if (memcmp (guid, &extension_functions[i].guid, sizeof(GUID)) == 0) { memcpy (output, &extension_functions[i].func, sizeof(gpointer)); *written = sizeof(gpointer); return 0; } } mono_w32socket_set_last_error (WSAEINVAL); return SOCKET_ERROR; } if (command == 0x98000004 /* SIO_KEEPALIVE_VALS */) { guint32 onoff; if (inputlen < 3 * sizeof (guint32)) { mono_w32socket_set_last_error (WSAEINVAL); return SOCKET_ERROR; } onoff = *((guint32*) input); ret = setsockopt (sock, SOL_SOCKET, SO_KEEPALIVE, &onoff, sizeof (guint32)); if (ret < 0) { mono_w32socket_set_last_error (mono_w32socket_convert_error (errno)); return SOCKET_ERROR; } #if defined(TCP_KEEPIDLE) && defined(TCP_KEEPINTVL) if (onoff != 0) { /* Values are in ms, but we need s */ guint32 keepalivetime, keepaliveinterval, rem; keepalivetime = *(((guint32*) input) + 1); keepaliveinterval = *(((guint32*) input) + 2); /* keepalivetime and keepaliveinterval are > 0 (checked in managed code) */ rem = keepalivetime % 1000; keepalivetime /= 1000; if (keepalivetime == 0 || rem >= 500) keepalivetime++; ret = setsockopt (sock, IPPROTO_TCP, TCP_KEEPIDLE, &keepalivetime, sizeof (guint32)); if (ret == 0) { rem = keepaliveinterval % 1000; keepaliveinterval /= 1000; if (keepaliveinterval == 0 || rem >= 500) keepaliveinterval++; ret = setsockopt (sock, IPPROTO_TCP, TCP_KEEPINTVL, &keepaliveinterval, sizeof (guint32)); } if (ret != 0) { mono_w32socket_set_last_error (mono_w32socket_convert_error (errno)); return SOCKET_ERROR; } return 0; } #endif return 0; } buffer = inputlen > 0 ? (gchar*) g_memdup (input, inputlen) : NULL; ret = ioctl (sock, command, buffer); if (ret == -1) { g_free (buffer); gint errnum = errno; mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: WSAIoctl error: %s", __func__, g_strerror (errno)); mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); return SOCKET_ERROR; } if (!buffer) { *written = 0; return 0; } /* We just copy the buffer to the output. Some ioctls * don't even output any data, but, well... * * NB windows returns WSAEFAULT if outputlen is too small */ inputlen = (inputlen > outputlen) ? outputlen : inputlen; if (inputlen > 0 && output != NULL) memcpy (output, buffer, inputlen); g_free (buffer); *written = inputlen; return 0; }
gint mono_w32socket_setsockopt (SOCKET sock, gint level, gint optname, const gpointer optval, socklen_t optlen) { gpointer handle; gint ret; gpointer tmp_val; #if defined (__linux__) /* This has its address taken so it cannot be moved to the if block which uses it */ gint bufsize = 0; #endif struct timeval tv; handle = GUINT_TO_POINTER (sock); if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) { mono_w32socket_set_last_error (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 (sock, level, optname, tmp_val, optlen); if (ret == -1) { gint errnum = errno; mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: setsockopt error: %s", __func__, g_strerror (errno)); mono_w32socket_set_last_error (mono_w32socket_convert_error (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 (sock, level, SO_TYPE, &type, &type_len)) { if (type == SOCK_DGRAM || type == SOCK_STREAM) setsockopt (sock, level, SO_REUSEPORT, tmp_val, optlen); } } #endif return ret; }
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 (mono_w32handle_get_type (handle) != MONO_W32HANDLE_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; MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%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 = mono_w32handle_lookup (handle, MONO_W32HANDLE_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); }
BOOL mono_w32socket_transmit_file (SOCKET sock, gpointer file_handle, TRANSMIT_FILE_BUFFERS *buffers, guint32 flags, gboolean blocking) { MonoThreadInfo *info; gpointer handle; gint file; gssize ret; #if defined(HAVE_SENDFILE) && (defined(__linux__) || defined(DARWIN)) struct stat statbuf; #else gchar *buffer; #endif handle = GUINT_TO_POINTER (sock); if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_SOCKET) { mono_w32socket_set_last_error (WSAENOTSOCK); return FALSE; } /* Write the header */ if (buffers != NULL && buffers->Head != NULL && buffers->HeadLength > 0) { ret = mono_w32socket_send (sock, buffers->Head, buffers->HeadLength, 0, FALSE); if (ret == SOCKET_ERROR) return FALSE; } info = mono_thread_info_current (); file = GPOINTER_TO_INT (file_handle); #if defined(HAVE_SENDFILE) && (defined(__linux__) || defined(DARWIN)) ret = fstat (file, &statbuf); if (ret == -1) { gint errnum = errno; mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); return SOCKET_ERROR; } do { #ifdef __linux__ ret = sendfile (sock, 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 */ ret = sendfile (file, sock, 0, &statbuf.st_size, NULL, 0); #endif } while (ret != -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info)); #else buffer = g_malloc (SF_BUFFER_SIZE); do { do { ret = read (file, buffer, SF_BUFFER_SIZE); } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info)); if (ret == -1 || ret == 0) break; do { ret = send (sock, buffer, ret, 0); /* short sends? enclose this in a loop? */ } while (ret == -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info)); } while (ret != -1 && errno == EINTR && !mono_thread_info_is_interrupt_state (info)); g_free (buffer); #endif if (ret == -1) { gint errnum = errno; mono_w32socket_set_last_error (mono_w32socket_convert_error (errnum)); return FALSE; } /* Write the tail */ if (buffers != NULL && buffers->Tail != NULL && buffers->TailLength > 0) { ret = mono_w32socket_send (sock, buffers->Tail, buffers->TailLength, 0, FALSE); if (ret == SOCKET_ERROR) return FALSE; } if ((flags & TF_DISCONNECT) == TF_DISCONNECT) mono_w32handle_close (handle); return TRUE; }
int ioctlsocket(guint32 fd, unsigned long command, gpointer arg) { gpointer handle = GUINT_TO_POINTER (fd); int ret; if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_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; MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: ioctl error: %s", __func__, strerror (errno)); errnum = errno_to_WSA (errnum, __func__); WSASetLastError (errnum); return(SOCKET_ERROR); } 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; MonoThreadInfo *info = mono_thread_info_current (); if (mono_w32handle_get_type (handle) != MONO_W32HANDLE_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) { MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%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 = mono_w32handle_lookup (handle, MONO_W32HANDLE_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 && !mono_thread_info_is_interrupt_state (info)) { if (errno != EINTR) { errnum = errno_to_WSA (errno, __func__); MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%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__); MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%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 = mono_w32handle_lookup (handle, MONO_W32HANDLE_SOCKET, (gpointer *)&socket_handle); if (ok == FALSE) { g_warning ("%s: error looking up socket handle %p", __func__, handle); } else { socket_handle->saved_error = errnum; } MONO_TRACE (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: connect getsockopt returned error: %s", __func__, strerror (so_error)); WSASetLastError (errnum); return(SOCKET_ERROR); } } return(0); }
MonoBoolean ves_icall_System_Threading_Mutex_ReleaseMutex_internal (gpointer handle) { MonoW32HandleType type; MonoW32HandleMutex *mutex_handle; pthread_t tid; gboolean ret; if (handle == NULL) { mono_w32error_set_last (ERROR_INVALID_HANDLE); return FALSE; } switch (type = mono_w32handle_get_type (handle)) { case MONO_W32HANDLE_MUTEX: case MONO_W32HANDLE_NAMEDMUTEX: break; default: mono_w32error_set_last (ERROR_INVALID_HANDLE); return FALSE; } if (!mono_w32handle_lookup (handle, type, (gpointer *)&mutex_handle)) { g_warning ("%s: error looking up %s handle %p", __func__, mono_w32handle_get_typename (type), handle); return FALSE; } mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: releasing %s handle %p, tid: %p recursion: %d", __func__, mono_w32handle_get_typename (type), handle, (gpointer) mutex_handle->tid, mutex_handle->recursion); mono_w32handle_lock_handle (handle); tid = pthread_self (); if (mutex_handle->abandoned) { // The Win32 ReleaseMutex() function returns TRUE for abandoned mutexes ret = TRUE; } else if (!pthread_equal (mutex_handle->tid, tid)) { ret = FALSE; mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: we don't own %s handle %p (owned by %ld, me %ld)", __func__, mono_w32handle_get_typename (type), handle, (long)mutex_handle->tid, (long)tid); } else { ret = TRUE; /* OK, we own this mutex */ mutex_handle->recursion--; if (mutex_handle->recursion == 0) { thread_disown_mutex (mono_thread_internal_current (), handle); mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: unlocking %s handle %p, tid: %p recusion : %d", __func__, mono_w32handle_get_typename (type), handle, (gpointer) mutex_handle->tid, mutex_handle->recursion); mutex_handle->tid = 0; mono_w32handle_set_signal_state (handle, TRUE, FALSE); } } mono_w32handle_unlock_handle (handle); return ret; }
void mono_w32mutex_abandon (void) { MonoInternalThread *internal; g_assert (mono_thread_internal_current_is_attached ()); internal = mono_thread_internal_current (); g_assert (internal); if (!internal->owned_mutexes) return; while (internal->owned_mutexes->len) { MonoW32HandleType type; MonoW32HandleMutex *mutex_handle; MonoNativeThreadId tid; gpointer handle; handle = g_ptr_array_index (internal->owned_mutexes, 0); switch (type = mono_w32handle_get_type (handle)) { case MONO_W32HANDLE_MUTEX: case MONO_W32HANDLE_NAMEDMUTEX: break; default: g_assert_not_reached (); } if (!mono_w32handle_lookup (handle, type, (gpointer *)&mutex_handle)) { g_error ("%s: error looking up %s handle %p", __func__, mono_w32handle_get_typename (type), handle); } mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: abandoning %s handle %p", __func__, mono_w32handle_get_typename (type), handle); tid = MONO_UINT_TO_NATIVE_THREAD_ID (internal->tid); if (!pthread_equal (mutex_handle->tid, tid)) g_error ("%s: trying to release mutex %p acquired by thread %p from thread %p", __func__, handle, (gpointer) mutex_handle->tid, (gpointer) tid); mono_w32handle_lock_handle (handle); mutex_handle->recursion = 0; mutex_handle->tid = 0; mutex_handle->abandoned = TRUE; mono_w32handle_set_signal_state (handle, TRUE, FALSE); thread_disown_mutex (internal, handle); mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_IO_LAYER, "%s: abandoned %s handle %p", __func__, mono_w32handle_get_typename (type), handle); mono_w32handle_unlock_handle (handle); } g_ptr_array_free (internal->owned_mutexes, TRUE); internal->owned_mutexes = NULL; }