Fix roslyn install with AOT disabled.
[mono-project.git] / mono / metadata / socket-io-windows.c
blob125dbeb9c4d7176dbf703e2c42e31a54421c975d
1 /*
2 * socket-io-windows.c: Windows specific socket code.
4 * Copyright 2016 Microsoft
5 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
6 */
7 #include <config.h>
8 #include <glib.h>
10 #include "mono/metadata/socket-io-windows-internals.h"
12 #define LOGDEBUG(...)
14 static gboolean set_blocking (SOCKET sock, gboolean block)
16 u_long non_block = block ? 0 : 1;
17 return ioctlsocket (sock, FIONBIO, &non_block) != SOCKET_ERROR;
20 static DWORD get_socket_timeout (SOCKET sock, int optname)
22 DWORD timeout = 0;
23 int optlen = sizeof (DWORD);
24 if (getsockopt (sock, SOL_SOCKET, optname, (char *)&timeout, &optlen) == SOCKET_ERROR) {
25 WSASetLastError (0);
26 return WSA_INFINITE;
28 if (timeout == 0)
29 timeout = WSA_INFINITE; // 0 means infinite
30 return timeout;
34 * Performs an alertable wait for the specified event (FD_ACCEPT_BIT,
35 * FD_CONNECT_BIT, FD_READ_BIT, FD_WRITE_BIT) on the specified socket.
36 * Returns TRUE if the event is fired without errors. Calls WSASetLastError()
37 * with WSAEINTR and returns FALSE if the thread is alerted. If the event is
38 * fired but with an error WSASetLastError() is called to set the error and the
39 * function returns FALSE.
41 static gboolean alertable_socket_wait (SOCKET sock, int event_bit)
43 static char *EVENT_NAMES[] = { "FD_READ", "FD_WRITE", NULL /*FD_OOB*/, "FD_ACCEPT", "FD_CONNECT", "FD_CLOSE" };
44 gboolean success = FALSE;
45 int error = -1;
46 DWORD timeout = WSA_INFINITE;
47 if (event_bit == FD_READ_BIT || event_bit == FD_WRITE_BIT) {
48 timeout = get_socket_timeout (sock, event_bit == FD_READ_BIT ? SO_RCVTIMEO : SO_SNDTIMEO);
50 WSASetLastError (0);
51 WSAEVENT event = WSACreateEvent ();
52 if (event != WSA_INVALID_EVENT) {
53 if (WSAEventSelect (sock, event, (1 << event_bit) | FD_CLOSE) != SOCKET_ERROR) {
54 LOGDEBUG (g_message ("%06d - Calling WSAWaitForMultipleEvents () on socket %d", GetCurrentThreadId (), sock));
55 DWORD ret = WSAWaitForMultipleEvents (1, &event, TRUE, timeout, TRUE);
56 if (ret == WSA_WAIT_IO_COMPLETION) {
57 LOGDEBUG (g_message ("%06d - WSAWaitForMultipleEvents () returned WSA_WAIT_IO_COMPLETION for socket %d", GetCurrentThreadId (), sock));
58 error = WSAEINTR;
59 } else if (ret == WSA_WAIT_TIMEOUT) {
60 error = WSAETIMEDOUT;
61 } else {
62 g_assert (ret == WSA_WAIT_EVENT_0);
63 WSANETWORKEVENTS ne = { 0 };
64 if (WSAEnumNetworkEvents (sock, event, &ne) != SOCKET_ERROR) {
65 if (ne.lNetworkEvents & (1 << event_bit) && ne.iErrorCode[event_bit]) {
66 LOGDEBUG (g_message ("%06d - %s error %d on socket %d", GetCurrentThreadId (), EVENT_NAMES[event_bit], ne.iErrorCode[event_bit], sock));
67 error = ne.iErrorCode[event_bit];
68 } else if (ne.lNetworkEvents & FD_CLOSE_BIT && ne.iErrorCode[FD_CLOSE_BIT]) {
69 LOGDEBUG (g_message ("%06d - FD_CLOSE error %d on socket %d", GetCurrentThreadId (), ne.iErrorCode[FD_CLOSE_BIT], sock));
70 error = ne.iErrorCode[FD_CLOSE_BIT];
71 } else {
72 LOGDEBUG (g_message ("%06d - WSAEnumNetworkEvents () finished successfully on socket %d", GetCurrentThreadId (), sock));
73 success = TRUE;
74 error = 0;
78 WSAEventSelect (sock, NULL, 0);
80 WSACloseEvent (event);
82 if (error != -1) {
83 WSASetLastError (error);
85 return success;
88 #define ALERTABLE_SOCKET_CALL(event_bit, blocking, repeat, ret, op, sock, ...) \
89 LOGDEBUG (g_message ("%06d - Performing %s " #op " () on socket %d", GetCurrentThreadId (), blocking ? "blocking" : "non-blocking", sock)); \
90 if (blocking) { \
91 if (set_blocking(sock, FALSE)) { \
92 while (-1 == (int) (ret = op (sock, __VA_ARGS__))) { \
93 int _error = WSAGetLastError ();\
94 if (_error != WSAEWOULDBLOCK && _error != WSA_IO_PENDING) \
95 break; \
96 if (!alertable_socket_wait (sock, event_bit) || !repeat) \
97 break; \
98 } \
99 int _saved_error = WSAGetLastError (); \
100 set_blocking (sock, TRUE); \
101 WSASetLastError (_saved_error); \
103 } else { \
104 ret = op (sock, __VA_ARGS__); \
106 int _saved_error = WSAGetLastError (); \
107 LOGDEBUG (g_message ("%06d - Finished %s " #op " () on socket %d (ret = %d, WSAGetLastError() = %d)", GetCurrentThreadId (), \
108 blocking ? "blocking" : "non-blocking", sock, ret, _saved_error)); \
109 WSASetLastError (_saved_error);
111 SOCKET alertable_accept (SOCKET s, struct sockaddr *addr, int *addrlen, gboolean blocking)
113 SOCKET newsock = INVALID_SOCKET;
114 ALERTABLE_SOCKET_CALL (FD_ACCEPT_BIT, blocking, TRUE, newsock, accept, s, addr, addrlen);
115 return newsock;
118 int alertable_connect (SOCKET s, const struct sockaddr *name, int namelen, gboolean blocking)
120 int ret = SOCKET_ERROR;
121 ALERTABLE_SOCKET_CALL (FD_CONNECT_BIT, blocking, FALSE, ret, connect, s, name, namelen);
122 ret = WSAGetLastError () != 0 ? SOCKET_ERROR : 0;
123 return ret;
126 int alertable_recv (SOCKET s, char *buf, int len, int flags, gboolean blocking)
128 int ret = SOCKET_ERROR;
129 ALERTABLE_SOCKET_CALL (FD_READ_BIT, blocking, TRUE, ret, recv, s, buf, len, flags);
130 return ret;
133 int alertable_recvfrom (SOCKET s, char *buf, int len, int flags, struct sockaddr *from, int *fromlen, gboolean blocking)
135 int ret = SOCKET_ERROR;
136 ALERTABLE_SOCKET_CALL (FD_READ_BIT, blocking, TRUE, ret, recvfrom, s, buf, len, flags, from, fromlen);
137 return ret;
140 int alertable_WSARecv (SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, LPDWORD lpNumberOfBytesRecvd, LPDWORD lpFlags, LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine, gboolean blocking)
142 int ret = SOCKET_ERROR;
143 ALERTABLE_SOCKET_CALL (FD_READ_BIT, blocking, TRUE, ret, WSARecv, s, lpBuffers, dwBufferCount, lpNumberOfBytesRecvd, lpFlags, lpOverlapped, lpCompletionRoutine);
144 return ret;
147 int alertable_send (SOCKET s, char *buf, int len, int flags, gboolean blocking)
149 int ret = SOCKET_ERROR;
150 ALERTABLE_SOCKET_CALL (FD_WRITE_BIT, blocking, FALSE, ret, send, s, buf, len, flags);
151 return ret;
154 int alertable_sendto (SOCKET s, const char *buf, int len, int flags, const struct sockaddr *to, int tolen, gboolean blocking)
156 int ret = SOCKET_ERROR;
157 ALERTABLE_SOCKET_CALL (FD_WRITE_BIT, blocking, FALSE, ret, sendto, s, buf, len, flags, to, tolen);
158 return ret;
161 int alertable_WSASend (SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, LPDWORD lpNumberOfBytesRecvd, DWORD lpFlags, LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine, gboolean blocking)
163 int ret = SOCKET_ERROR;
164 ALERTABLE_SOCKET_CALL (FD_WRITE_BIT, blocking, FALSE, ret, WSASend, s, lpBuffers, dwBufferCount, lpNumberOfBytesRecvd, lpFlags, lpOverlapped, lpCompletionRoutine);
165 return ret;
168 #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT)
169 BOOL alertable_TransmitFile (SOCKET hSocket, HANDLE hFile, DWORD nNumberOfBytesToWrite, DWORD nNumberOfBytesPerSend, LPOVERLAPPED lpOverlapped, LPTRANSMIT_FILE_BUFFERS lpTransmitBuffers, DWORD dwReserved, gboolean blocking)
171 LOGDEBUG (g_message ("%06d - Performing %s TransmitFile () on socket %d", GetCurrentThreadId (), blocking ? "blocking" : "non-blocking", hSocket));
173 int error = 0;
174 if (blocking) {
175 g_assert (lpOverlapped == NULL);
176 OVERLAPPED overlapped = { 0 };
177 overlapped.hEvent = WSACreateEvent ();
178 if (overlapped.hEvent == WSA_INVALID_EVENT)
179 return FALSE;
180 if (!TransmitFile (hSocket, hFile, nNumberOfBytesToWrite, nNumberOfBytesPerSend, &overlapped, lpTransmitBuffers, dwReserved)) {
181 error = WSAGetLastError ();
182 if (error == WSA_IO_PENDING) {
183 error = 0;
184 // NOTE: .NET's Socket.SendFile() doesn't honor the Socket's SendTimeout so we shouldn't either
185 DWORD ret = WaitForSingleObjectEx (overlapped.hEvent, INFINITE, TRUE);
186 if (ret == WAIT_IO_COMPLETION) {
187 LOGDEBUG (g_message ("%06d - WaitForSingleObjectEx () returned WSA_WAIT_IO_COMPLETION for socket %d", GetCurrentThreadId (), hSocket));
188 error = WSAEINTR;
189 } else if (ret == WAIT_TIMEOUT) {
190 error = WSAETIMEDOUT;
191 } else if (ret != WAIT_OBJECT_0) {
192 error = GetLastError ();
196 WSACloseEvent (overlapped.hEvent);
197 } else {
198 if (!TransmitFile (hSocket, hFile, nNumberOfBytesToWrite, nNumberOfBytesPerSend, lpOverlapped, lpTransmitBuffers, dwReserved)) {
199 error = WSAGetLastError ();
203 LOGDEBUG (g_message ("%06d - Finished %s TransmitFile () on socket %d (ret = %d, WSAGetLastError() = %d)", GetCurrentThreadId (), \
204 blocking ? "blocking" : "non-blocking", hSocket, error == 0, error));
205 WSASetLastError (error);
207 return error == 0;
209 #endif /* #if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT | HAVE_UWP_WINAPI_SUPPORT) */