- Build fixes
[reactos.git] / dll / win32 / mswsock / msafd / eventsel.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Winsock 2 SPI
4 * FILE: lib/mswsock/lib/init.c
5 * PURPOSE: DLL Initialization
6 */
7
8 /* INCLUDES ******************************************************************/
9 #include "msafd.h"
10
11 /* DATA **********************************************************************/
12
13 typedef struct _SOCK_EVENT_MAPPING
14 {
15 ULONG AfdBit;
16 ULONG WinsockBit;
17 } SOCK_EVENT_MAPPING, *PSOCK_EVENT_MAPPING;
18
19 SOCK_EVENT_MAPPING PollEventMapping[] =
20 {
21 {AFD_EVENT_RECEIVE_BIT, FD_READ_BIT},
22 {AFD_EVENT_SEND_BIT, FD_WRITE_BIT},
23 {AFD_EVENT_OOB_RECEIVE_BIT, FD_OOB_BIT},
24 {AFD_EVENT_ACCEPT_BIT, FD_ACCEPT_BIT},
25 {AFD_EVENT_QOS_BIT, FD_QOS_BIT},
26 {AFD_EVENT_GROUP_QOS_BIT, FD_GROUP_QOS_BIT},
27 {AFD_EVENT_ROUTING_INTERFACE_CHANGE_BIT, FD_ROUTING_INTERFACE_CHANGE_BIT},
28 {AFD_EVENT_ADDRESS_LIST_CHANGE_BIT, FD_ADDRESS_LIST_CHANGE_BIT}
29 };
30
31 /* FUNCTIONS *****************************************************************/
32
33 INT
34 WSPAPI
35 SockEventSelectHelper(IN PSOCKET_INFORMATION Socket,
36 IN WSAEVENT EventObject,
37 IN LONG Events)
38 {
39 IO_STATUS_BLOCK IoStatusBlock;
40 AFD_EVENT_SELECT_INFO PollInfo;
41 NTSTATUS Status;
42 PWINSOCK_TEB_DATA ThreadData = NtCurrentTeb()->WinSockData;
43
44 /* Acquire the lock */
45 EnterCriticalSection(&Socket->Lock);
46
47 /* Set Structure Info */
48 PollInfo.EventObject = EventObject;
49 PollInfo.Events = 0;
50
51 /* Set receive event */
52 if (Events & FD_READ) PollInfo.Events |= AFD_EVENT_RECEIVE;
53
54 /* Set write event */
55 if (Events & FD_WRITE) PollInfo.Events |= AFD_EVENT_SEND;
56
57 /* Set out-of-band (OOB) receive event */
58 if (Events & FD_OOB) PollInfo.Events |= AFD_EVENT_OOB_RECEIVE;
59
60 /* Set accept event */
61 if (Events & FD_ACCEPT) PollInfo.Events |= AFD_EVENT_ACCEPT;
62
63 /* Send Quality-of-Service (QOS) event */
64 if (Events & FD_QOS) PollInfo.Events |= AFD_EVENT_QOS;
65
66 /* Send Group Quality-of-Service (QOS) event */
67 if (Events & FD_GROUP_QOS) PollInfo.Events |= AFD_EVENT_GROUP_QOS;
68
69 /* Send connect event. Note, this also includes connect failures */
70 if (Events & FD_CONNECT) PollInfo.Events |= AFD_EVENT_CONNECT |
71 AFD_EVENT_CONNECT_FAIL;
72
73 /* Send close event. Note, this includes both aborts and disconnects */
74 if (Events & FD_CLOSE) PollInfo.Events |= AFD_EVENT_DISCONNECT |
75 AFD_EVENT_ABORT;
76
77 /* Send PnP events related to live network hardware changes */
78 if (Events & FD_ROUTING_INTERFACE_CHANGE)
79 {
80 PollInfo.Events |= AFD_EVENT_ROUTING_INTERFACE_CHANGE;
81 }
82 if (Events & FD_ADDRESS_LIST_CHANGE)
83 {
84 PollInfo.Events |= AFD_EVENT_ADDRESS_LIST_CHANGE;
85 }
86
87 /* Send IOCTL */
88 Status = NtDeviceIoControlFile(Socket->WshContext.Handle,
89 ThreadData->EventHandle,
90 NULL,
91 NULL,
92 &IoStatusBlock,
93 IOCTL_AFD_EVENT_SELECT,
94 &PollInfo,
95 sizeof(PollInfo),
96 NULL,
97 0);
98 /* Check if we need to wait */
99 if (Status == STATUS_PENDING)
100 {
101 /* Wait for completion */
102 SockWaitForSingleObject(ThreadData->EventHandle,
103 Socket->Handle,
104 NO_BLOCKING_HOOK,
105 NO_TIMEOUT);
106
107 /* Get new status */
108 Status = IoStatusBlock.Status;
109 }
110
111 /* Check for error */
112 if (!NT_SUCCESS(Status))
113 {
114 /* Fail */
115 LeaveCriticalSection(&Socket->Lock);
116 return NtStatusToSocketError(Status);
117 }
118
119 /* Set Socket Data*/
120 Socket->EventObject = EventObject;
121 Socket->NetworkEvents = Events;
122
123 /* Release lock and return success */
124 LeaveCriticalSection(&Socket->Lock);
125 return NO_ERROR;
126 }
127
128 INT
129 WSPAPI
130 WSPEventSelect(SOCKET Handle,
131 WSAEVENT hEventObject,
132 LONG lNetworkEvents,
133 LPINT lpErrno)
134 {
135 PSOCKET_INFORMATION Socket;
136 PWINSOCK_TEB_DATA ThreadData;
137 INT ErrorCode;
138 BOOLEAN BlockMode;
139
140 /* Enter prolog */
141 ErrorCode = SockEnterApiFast(&ThreadData);
142 if (ErrorCode != NO_ERROR)
143 {
144 /* Fail */
145 *lpErrno = ErrorCode;
146 return SOCKET_ERROR;
147 }
148
149 /* Get the socket structure */
150 Socket = SockFindAndReferenceSocket(Handle, TRUE);
151 if (!Socket)
152 {
153 /* Fail */
154 ErrorCode = WSAENOTSOCK;
155 goto error;
156 }
157
158 /* Set Socket to Non-Blocking */
159 BlockMode = TRUE;
160 ErrorCode = SockSetInformation(Socket,
161 AFD_INFO_BLOCKING_MODE,
162 &BlockMode,
163 NULL,
164 NULL);
165 if (ErrorCode != NO_ERROR) goto error;
166
167 /* AFD was notified, set it locally as well */
168 Socket->SharedData.NonBlocking = TRUE;
169
170 /* Check if there is an async select in progress */
171 if (Socket->EventObject)
172 {
173 /* Lock the socket */
174 EnterCriticalSection(&Socket->Lock);
175
176 /* Erase all data */
177 Socket->SharedData.hWnd = NULL;
178 Socket->SharedData.wMsg = 0;
179 Socket->SharedData.AsyncEvents = 0;
180
181 /* Unbalance the sequence number so the request will fail */
182 Socket->SharedData.SequenceNumber++;
183
184 /* Give socket access back */
185 LeaveCriticalSection(&Socket->Lock);
186 }
187
188 /* Make sure the flags are valid */
189 if ((lNetworkEvents & ~FD_ALL_EVENTS))
190 {
191 /* More then the possible combination, fail */
192 ErrorCode = WSAEINVAL;
193 goto error;
194 }
195
196 /* Call the helper */
197 ErrorCode = SockEventSelectHelper(Socket, hEventObject, lNetworkEvents);
198
199 error:
200 /* Dereference the socket, if we have one here */
201 if (Socket) SockDereferenceSocket(Socket);
202
203 /* Check for error */
204 if (ErrorCode != NO_ERROR)
205 {
206 /* Fail */
207 *lpErrno = ErrorCode;
208 return SOCKET_ERROR;
209 }
210
211 /* Return success */
212 return NO_ERROR;
213 }
214
215 INT
216 WSPAPI
217 WSPEnumNetworkEvents(IN SOCKET Handle,
218 IN WSAEVENT hEventObject,
219 OUT LPWSANETWORKEVENTS lpNetworkEvents,
220 OUT LPINT lpErrno)
221 {
222 AFD_ENUM_NETWORK_EVENTS_INFO EventInfo;
223 IO_STATUS_BLOCK IoStatusBlock;
224 PSOCKET_INFORMATION Socket;
225 PWINSOCK_TEB_DATA ThreadData;
226 INT ErrorCode;
227 NTSTATUS Status, EventStatus;
228 PSOCK_EVENT_MAPPING EventMapping;
229 ULONG i;
230
231 /* Enter prolog */
232 ErrorCode = SockEnterApiFast(&ThreadData);
233 if (ErrorCode != NO_ERROR)
234 {
235 /* Fail */
236 *lpErrno = ErrorCode;
237 return SOCKET_ERROR;
238 }
239
240 /* Get the socket structure */
241 Socket = SockFindAndReferenceSocket(Handle, TRUE);
242 if (!Socket)
243 {
244 /* Fail */
245 ErrorCode = WSAENOTSOCK;
246 goto error;
247 }
248
249 /* Make sure we got a pointer */
250 if (!lpNetworkEvents)
251 {
252 /* Fail */
253 ErrorCode = WSAEINVAL;
254 goto error;
255 }
256
257 /* Lock the socket */
258 EnterCriticalSection(&Socket->Lock);
259
260 /* Send IOCTL */
261 Status = NtDeviceIoControlFile((HANDLE)Handle,
262 ThreadData->EventHandle,
263 NULL,
264 NULL,
265 &IoStatusBlock,
266 IOCTL_AFD_ENUM_NETWORK_EVENTS,
267 hEventObject,
268 0,
269 &EventInfo,
270 sizeof(EventInfo));
271
272 /* Check if we need to wait */
273 if (Status == STATUS_PENDING)
274 {
275 /* Wait for completion */
276 SockWaitForSingleObject(ThreadData->EventHandle,
277 Socket->Handle,
278 NO_BLOCKING_HOOK,
279 NO_TIMEOUT);
280
281 /* Get new status */
282 Status = IoStatusBlock.Status;
283 }
284
285 /* Check for error */
286 if (!NT_SUCCESS(Status))
287 {
288 /* Fail */
289 ErrorCode = NtStatusToSocketError(Status);
290 goto error;
291 }
292
293 /* Set Events to wait for */
294 lpNetworkEvents->lNetworkEvents = 0;
295
296 /* Set our Event Mapping structure */
297 EventMapping = PollEventMapping;
298
299 /* Loop it */
300 for (i = 0; i < (sizeof(PollEventMapping) / 2 * sizeof(ULONG)); i++)
301 {
302 /* First check if we have a match for this bit */
303 if (EventInfo.PollEvents & (1 << EventMapping->AfdBit))
304 {
305 /* Match found, write the equivalent bit */
306 lpNetworkEvents->lNetworkEvents |= (1 << EventMapping->WinsockBit);
307
308 /* Now get the status */
309 EventStatus = EventInfo.EventStatus[EventMapping->AfdBit];
310
311 /* Check if it failed */
312 if (!NT_SUCCESS(Status))
313 {
314 /* Write the Winsock status code directly */
315 lpNetworkEvents->iErrorCode[EventMapping->WinsockBit] = NtStatusToSocketError(EventStatus);
316 }
317 else
318 {
319 /* Write success */
320 lpNetworkEvents->iErrorCode[EventMapping->WinsockBit] = NO_ERROR;
321 }
322
323 /* Move to the next mapping array */
324 EventMapping++;
325 }
326
327 /* Handle the special cases with two flags. Start with connect */
328 if (EventInfo.PollEvents & AFD_EVENT_CONNECT)
329 {
330 /* Set the equivalent bit */
331 lpNetworkEvents->lNetworkEvents |= FD_CONNECT;
332
333 /* Now get the status */
334 EventStatus = EventInfo.EventStatus[AFD_EVENT_CONNECT_BIT];
335
336 /* Check if it failed */
337 if (!NT_SUCCESS(Status))
338 {
339 /* Write the Winsock status code directly */
340 lpNetworkEvents->iErrorCode[FD_CONNECT_BIT] = NtStatusToSocketError(EventStatus);
341 }
342 else
343 {
344 /* Write success */
345 lpNetworkEvents->iErrorCode[FD_CONNECT_BIT] = NO_ERROR;
346 }
347 }
348 else if (EventInfo.PollEvents & AFD_EVENT_CONNECT_FAIL)
349 {
350 /* Do the same thing, but for the failure */
351 lpNetworkEvents->lNetworkEvents |= FD_CONNECT;
352
353 /* Now get the status */
354 EventStatus = EventInfo.EventStatus[AFD_EVENT_CONNECT_FAIL_BIT];
355
356 /* Check if it failed */
357 if (!NT_SUCCESS(Status))
358 {
359 /* Write the Winsock status code directly */
360 lpNetworkEvents->iErrorCode[FD_CONNECT_BIT] = NtStatusToSocketError(EventStatus);
361 }
362 else
363 {
364 /* Write success */
365 lpNetworkEvents->iErrorCode[FD_CONNECT_BIT] = NO_ERROR;
366 }
367 }
368
369 /* Now handle Abort/Disconnect */
370 if (EventInfo.PollEvents & AFD_EVENT_ABORT)
371 {
372 /* Set the equivalent bit */
373 lpNetworkEvents->lNetworkEvents |= FD_CLOSE;
374
375 /* Now get the status */
376 EventStatus = EventInfo.EventStatus[AFD_EVENT_ABORT_BIT];
377
378 /* Check if it failed */
379 if (!NT_SUCCESS(Status))
380 {
381 /* Write the Winsock status code directly */
382 lpNetworkEvents->iErrorCode[FD_CLOSE_BIT] = NtStatusToSocketError(EventStatus);
383 }
384 else
385 {
386 /* Write success */
387 lpNetworkEvents->iErrorCode[FD_CLOSE_BIT] = NO_ERROR;
388 }
389 }
390 else if (EventInfo.PollEvents & AFD_EVENT_DISCONNECT)
391 {
392 /* Do the same thing, but for the failure */
393 lpNetworkEvents->lNetworkEvents |= FD_CLOSE;
394
395 /* Now get the status */
396 EventStatus = EventInfo.EventStatus[AFD_EVENT_DISCONNECT_BIT];
397
398 /* Check if it failed */
399 if (!NT_SUCCESS(Status))
400 {
401 /* Write the Winsock status code directly */
402 lpNetworkEvents->iErrorCode[FD_CLOSE_BIT] = NtStatusToSocketError(EventStatus);
403 }
404 else
405 {
406 /* Write success */
407 lpNetworkEvents->iErrorCode[FD_CLOSE_BIT] = NO_ERROR;
408 }
409 }
410 }
411
412 error:
413 /* Dereference the socket, if we have one here */
414 if (Socket) SockDereferenceSocket(Socket);
415
416 /* Check for error */
417 if (ErrorCode != NO_ERROR)
418 {
419 /* Fail */
420 *lpErrno = ErrorCode;
421 return SOCKET_ERROR;
422 }
423
424 /* Return success */
425 return NO_ERROR;
426 }
427