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
8 /* INCLUDES ******************************************************************/
11 /* DATA **********************************************************************/
13 /* FUNCTIONS *****************************************************************/
17 SockSocket(INT AddressFamily
,
26 PSOCKET_INFORMATION
*NewSocket
)
29 UNICODE_STRING TransportName
;
30 PVOID HelperDllContext
;
31 PHELPER_DATA HelperData
= NULL
;
33 PFILE_FULL_EA_INFORMATION Ea
= NULL
;
34 PAFD_CREATE_PACKET AfdPacket
;
35 SOCKET Handle
= INVALID_SOCKET
;
36 PSOCKET_INFORMATION Socket
= NULL
;
37 BOOLEAN LockInit
= FALSE
;
39 DWORD SizeOfEa
, SocketLength
;
40 OBJECT_ATTRIBUTES ObjectAttributes
;
41 UNICODE_STRING DevName
;
42 LARGE_INTEGER GroupData
;
43 DWORD CreateOptions
= 0;
44 IO_STATUS_BLOCK IoStatusBlock
;
45 PWAH_HANDLE WahHandle
;
47 CHAR AfdPacketBuffer
[96];
49 /* Initialize the transport name */
50 RtlInitUnicodeString(&TransportName
, NULL
);
52 /* Get Helper Data and Transport */
53 ErrorCode
= SockGetTdiName(&AddressFamily
,
65 if (ErrorCode
!= NO_ERROR
) goto error
;
67 /* Figure out the socket context structure size */
68 SocketLength
= sizeof(*Socket
) + (HelperData
->MinWSAddressLength
* 2);
70 /* Allocate a socket */
71 Socket
= SockAllocateHeapRoutine(SockPrivateHeap
, 0, SocketLength
);
74 /* Couldn't create it; we need to tell WSH so it can cleanup */
75 if (HelperEvents
& WSH_NOTIFY_CLOSE
)
77 HelperData
->WSHNotify(HelperDllContext
,
85 ErrorCode
= WSAENOBUFS
;
90 RtlZeroMemory(Socket
, SocketLength
);
92 Socket
->Handle
= INVALID_SOCKET
;
93 Socket
->SharedData
.State
= SocketUndefined
;
94 Socket
->SharedData
.AddressFamily
= AddressFamily
;
95 Socket
->SharedData
.SocketType
= SocketType
;
96 Socket
->SharedData
.Protocol
= Protocol
;
97 Socket
->ProviderId
= *ProviderId
;
98 Socket
->HelperContext
= HelperDllContext
;
99 Socket
->HelperData
= HelperData
;
100 Socket
->HelperEvents
= HelperEvents
;
101 Socket
->LocalAddress
= (PVOID
)(Socket
+ 1);
102 Socket
->SharedData
.SizeOfLocalAddress
= HelperData
->MaxWSAddressLength
;
103 Socket
->RemoteAddress
= (PVOID
)((ULONG_PTR
)Socket
->LocalAddress
+
104 HelperData
->MaxWSAddressLength
);
105 Socket
->SharedData
.SizeOfRemoteAddress
= HelperData
->MaxWSAddressLength
;
106 Socket
->SharedData
.UseDelayedAcceptance
= HelperData
->UseDelayedAcceptance
;
107 Socket
->SharedData
.CreateFlags
= dwFlags
;
108 Socket
->SharedData
.CatalogEntryId
= CatalogEntryId
;
109 Socket
->SharedData
.ServiceFlags1
= ServiceFlags
;
110 Socket
->SharedData
.ProviderFlags
= ProviderFlags
;
111 Socket
->SharedData
.GroupID
= g
;
112 Socket
->SharedData
.GroupType
= 0;
113 Socket
->SharedData
.UseSAN
= FALSE
;
114 Socket
->SanData
= NULL
;
115 Socket
->DontUseSan
= FALSE
;
117 /* Initialize the socket lock */
118 InitializeCriticalSection(&Socket
->Lock
);
122 SizeOfPacket
= TransportName
.Length
+ sizeof(*AfdPacket
) + sizeof(WCHAR
);
125 SizeOfEa
= SizeOfPacket
+ sizeof(*Ea
) + AFD_PACKET_COMMAND_LENGTH
;
127 /* See if our stack buffer is big enough to hold it */
128 if (SizeOfEa
<= sizeof(AfdPacketBuffer
))
131 Ea
= (PFILE_FULL_EA_INFORMATION
)AfdPacketBuffer
;
135 /* Allocate from heap */
136 Ea
= SockAllocateHeapRoutine(SockPrivateHeap
, 0, SizeOfEa
);
140 ErrorCode
= WSAENOBUFS
;
146 Ea
->NextEntryOffset
= 0;
148 Ea
->EaNameLength
= AFD_PACKET_COMMAND_LENGTH
;
149 RtlCopyMemory(Ea
->EaName
, AfdCommand
, AFD_PACKET_COMMAND_LENGTH
+ 1);
150 Ea
->EaValueLength
= SizeOfPacket
;
152 /* Set up AFD Packet */
153 AfdPacket
= (PAFD_CREATE_PACKET
)(Ea
->EaName
+ Ea
->EaNameLength
+ 1);
154 AfdPacket
->SizeOfTransportName
= TransportName
.Length
;
155 RtlCopyMemory(AfdPacket
->TransportName
,
156 TransportName
.Buffer
,
157 TransportName
.Length
+ sizeof(WCHAR
));
158 AfdPacket
->EndpointFlags
= 0;
160 /* Set up Endpoint Flags */
161 if ((Socket
->SharedData
.ServiceFlags1
& XP1_CONNECTIONLESS
))
163 /* Check the Socket Type */
164 if ((SocketType
!= SOCK_DGRAM
) && (SocketType
!= SOCK_RAW
))
166 /* Only RAW or UDP can be Connectionless */
167 ErrorCode
= WSAEINVAL
;
171 /* Set the flag for AFD */
172 AfdPacket
->EndpointFlags
|= AFD_ENDPOINT_CONNECTIONLESS
;
175 if ((Socket
->SharedData
.ServiceFlags1
& XP1_MESSAGE_ORIENTED
))
177 /* Check if this is a Stream Socket */
178 if (SocketType
== SOCK_STREAM
)
180 /* Check if we actually support this */
181 if (!(Socket
->SharedData
.ServiceFlags1
& XP1_PSEUDO_STREAM
))
183 /* The Provider doesn't support Message Oriented Streams */
184 ErrorCode
= WSAEINVAL
;
189 /* Set the flag for AFD */
190 AfdPacket
->EndpointFlags
|= AFD_ENDPOINT_MESSAGE_ORIENTED
;
193 /* If this is a Raw Socket, let AFD know */
194 if (SocketType
== SOCK_RAW
) AfdPacket
->EndpointFlags
|= AFD_ENDPOINT_RAW
;
196 /* Check if we are a Multipoint Control/Data Root or Leaf */
197 if (dwFlags
& (WSA_FLAG_MULTIPOINT_C_ROOT
|
198 WSA_FLAG_MULTIPOINT_C_LEAF
|
199 WSA_FLAG_MULTIPOINT_D_ROOT
|
200 WSA_FLAG_MULTIPOINT_D_LEAF
))
202 /* First make sure we support Multipoint */
203 if (!(Socket
->SharedData
.ServiceFlags1
& XP1_SUPPORT_MULTIPOINT
))
205 /* The Provider doesn't actually support Multipoint */
206 ErrorCode
= WSAEINVAL
;
210 /* Set the flag for AFD */
211 AfdPacket
->EndpointFlags
|= AFD_ENDPOINT_MULTIPOINT
;
213 /* Check if we are a Control Plane Root */
214 if (dwFlags
& WSA_FLAG_MULTIPOINT_C_ROOT
)
216 /* Check if we actually support this or if we're already a leaf */
217 if ((!(Socket
->SharedData
.ServiceFlags1
&
218 XP1_MULTIPOINT_CONTROL_PLANE
)) ||
219 ((dwFlags
& WSA_FLAG_MULTIPOINT_C_LEAF
)))
221 ErrorCode
= WSAEINVAL
;
225 /* Set the flag for AFD */
226 AfdPacket
->EndpointFlags
|= AFD_ENDPOINT_C_ROOT
;
229 /* Check if we a Data Plane Root */
230 if (dwFlags
& WSA_FLAG_MULTIPOINT_D_ROOT
)
232 /* Check if we actually support this or if we're already a leaf */
233 if ((!(Socket
->SharedData
.ServiceFlags1
&
234 XP1_MULTIPOINT_DATA_PLANE
)) ||
235 ((dwFlags
& WSA_FLAG_MULTIPOINT_D_LEAF
)))
237 ErrorCode
= WSAEINVAL
;
241 /* Set the flag for AFD */
242 AfdPacket
->EndpointFlags
|= AFD_ENDPOINT_D_ROOT
;
246 /* Set the group ID */
247 AfdPacket
->GroupID
= g
;
249 /* Set up Object Attributes */
250 RtlInitUnicodeString(&DevName
, L
"\\Device\\Afd\\Endpoint");
251 InitializeObjectAttributes(&ObjectAttributes
,
253 OBJ_CASE_INSENSITIVE
| OBJ_INHERIT
,
257 /* Check if we're not using Overlapped I/O */
258 if (!(dwFlags
& WSA_FLAG_OVERLAPPED
))
260 /* Set Synchronous I/O */
261 CreateOptions
= FILE_SYNCHRONOUS_IO_NONALERT
;
264 /* Acquire the global lock */
265 SockAcquireRwLockShared(&SocketGlobalLock
);
267 /* Create the Socket */
268 Status
= NtCreateFile((PHANDLE
)&Handle
,
269 GENERIC_READ
| GENERIC_WRITE
| SYNCHRONIZE
,
274 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
279 if (!NT_SUCCESS(Status
))
281 /* Release the lock and fail */
282 SockReleaseRwLockShared(&SocketGlobalLock
);
283 ErrorCode
= NtStatusToSocketError(Status
);
288 Socket
->Handle
= Handle
;
290 /* Check if a group was given */
293 /* Get Group Id and Type */
294 ErrorCode
= SockGetInformation(Socket
,
295 AFD_INFO_GROUP_ID_TYPE
,
303 Socket
->SharedData
.GroupID
= GroupData
.u
.LowPart
;
304 Socket
->SharedData
.GroupType
= GroupData
.u
.HighPart
;
307 /* Check if we need to get the window sizes */
308 if (!SockSendBufferWindow
)
310 /* Get send window size */
311 SockGetInformation(Socket
,
312 AFD_INFO_SEND_WINDOW_SIZE
,
316 &SockSendBufferWindow
,
319 /* Get receive window size */
320 SockGetInformation(Socket
,
321 AFD_INFO_RECEIVE_WINDOW_SIZE
,
325 &SockReceiveBufferWindow
,
329 /* Save window sizes */
330 Socket
->SharedData
.SizeOfRecvBuffer
= SockReceiveBufferWindow
;
331 Socket
->SharedData
.SizeOfSendBuffer
= SockSendBufferWindow
;
333 /* Insert it into our table */
334 WahHandle
= WahInsertHandleContext(SockContextTable
, &Socket
->WshContext
);
336 /* We can release the lock now */
337 SockReleaseRwLockShared(&SocketGlobalLock
);
339 /* Check if the handles don't match for some reason */
340 if (WahHandle
!= &Socket
->WshContext
)
342 /* Do they not match? */
345 /* They don't... someone must've used CloseHandle */
346 SockDereferenceSocket((PSOCKET_INFORMATION
)WahHandle
);
348 /* Use the correct handle now */
349 WahHandle
= &Socket
->WshContext
;
353 /* It's not that they don't match: we don't have one at all! */
354 ErrorCode
= WSAENOBUFS
;
360 /* Check if we can free the transport name */
361 if ((SocketType
== SOCK_RAW
) && (TransportName
.Buffer
))
364 RtlFreeHeap(RtlGetProcessHeap(), 0, TransportName
.Buffer
);
367 /* Check if we have the EA from the heap */
368 if ((Ea
) && (Ea
!= (PVOID
)AfdPacketBuffer
))
371 RtlFreeHeap(SockPrivateHeap
, 0, Ea
);
374 /* Check if this is actually success */
375 if (ErrorCode
!= NO_ERROR
)
377 /* Check if we have a socket by now */
380 /* Tell the Helper DLL we're closing it */
381 SockNotifyHelperDll(Socket
, WSH_NOTIFY_CLOSE
);
383 /* Close its handle if it's valid */
384 if (Socket
->WshContext
.Handle
!= INVALID_HANDLE_VALUE
)
386 NtClose(Socket
->WshContext
.Handle
);
389 /* Delete its lock */
390 if (LockInit
) DeleteCriticalSection(&Socket
->Lock
);
392 /* Remove our socket reference */
393 SockDereferenceSocket(Socket
);
396 RtlFreeHeap(SockPrivateHeap
, 0, Socket
);
400 /* Return Socket and error code */
407 SockCloseSocket(IN PSOCKET_INFORMATION Socket
)
410 PWINSOCK_TEB_DATA ThreadData
= NtCurrentTeb()->WinSockData
;
411 IO_STATUS_BLOCK IoStatusBlock
;
413 AFD_DISCONNECT_INFO DisconnectInfo
;
414 SOCKET_STATE OldState
;
416 ULONG SendsInProgress
;
418 BOOLEAN ActiveConnect
;
420 /* Lock the socket */
421 EnterCriticalSection(&Socket
->Lock
);
423 /* If a Close is already in Process... */
424 if (Socket
->SharedData
.State
== SocketClosed
)
426 /* Release lock and fail */
427 LeaveCriticalSection(&Socket
->Lock
);
431 /* Save the old state and set the new one to closed */
432 OldState
= Socket
->SharedData
.State
;
433 Socket
->SharedData
.State
= SocketClosed
;
435 /* Check if the socket has an active async data */
436 ActiveConnect
= (Socket
->AsyncData
!= NULL
);
438 /* We're done with the socket, release the lock */
439 LeaveCriticalSection(&Socket
->Lock
);
442 * If SO_LINGER is ON and the Socket was connected or had an active async
443 * connect context, then we'll disconnect it. Note that we won't do this
444 * for connection-less (UDP/RAW) sockets or if a send shutdown is active.
446 if ((OldState
== SocketConnected
|| ActiveConnect
) &&
447 !(Socket
->SharedData
.SendShutdown
) &&
448 !MSAFD_IS_DGRAM_SOCK(Socket
) &&
449 (Socket
->SharedData
.LingerData
.l_onoff
))
451 /* We need to respect the timeout */
453 LingerWait
= Socket
->SharedData
.LingerData
.l_linger
* 1000;
455 /* Loop until no more sends are pending, within the timeout */
458 /* Find out how many Sends are in Progress */
459 if (SockGetInformation(Socket
,
460 AFD_INFO_SENDS_IN_PROGRESS
,
467 /* Bail out if anything but NO_ERROR */
472 /* Bail out if no more sends are pending */
473 if (!SendsInProgress
) break;
476 * We have to execute a sleep, so it's kind of like
477 * a block. If the socket is Nonblock, we cannot
478 * go on since asyncronous operation is expected
479 * and we cannot offer it
481 if (Socket
->SharedData
.NonBlocking
)
483 /* Acquire the socket lock */
484 EnterCriticalSection(&Socket
->Lock
);
486 /* Restore the socket state */
487 Socket
->SharedData
.State
= OldState
;
489 /* Release the lock again */
490 LeaveCriticalSection(&Socket
->Lock
);
492 /* Fail with error code */
493 return WSAEWOULDBLOCK
;
496 /* Now we can sleep, and decrement the linger wait */
498 * FIXME: It seems Windows does some funky acceleration
499 * since the waiting seems to be longer and longer. I
500 * don't think this improves performance so much, so we
501 * wait a fixed time instead.
504 LingerWait
-= SleepWait
;
508 * We have reached the timeout or sends are over.
509 * Disconnect if the timeout has been reached.
513 /* There is no timeout, and this is an abortive disconnect */
514 DisconnectInfo
.Timeout
= RtlConvertLongToLargeInteger(0);
515 DisconnectInfo
.DisconnectType
= AFD_DISCONNECT_ABORT
;
518 Status
= NtDeviceIoControlFile(Socket
->WshContext
.Handle
,
519 ThreadData
->EventHandle
,
523 IOCTL_AFD_DISCONNECT
,
525 sizeof(DisconnectInfo
),
528 /* Check if the operation is pending */
529 if (Status
== STATUS_PENDING
)
531 /* Wait for completion */
532 SockWaitForSingleObject(ThreadData
->EventHandle
,
534 !Socket
->SharedData
.LingerData
.l_onoff
?
535 NO_BLOCKING_HOOK
: ALWAYS_BLOCKING_HOOK
,
539 Status
= IoStatusBlock
.Status
;
542 /* We actually accept errors, unless the driver wasn't ready */
543 if (Status
== STATUS_DEVICE_NOT_READY
)
545 /* This is the equivalent of a WOULDBLOCK, which we fail */
546 /* Acquire the socket lock */
547 EnterCriticalSection(&Socket
->Lock
);
549 /* Restore the socket state */
550 Socket
->SharedData
.State
= OldState
;
552 /* Release the lock again */
553 LeaveCriticalSection(&Socket
->Lock
);
555 /* Fail with error code */
556 return WSAEWOULDBLOCK
;
561 /* Acquire the global lock to protect the handle table */
562 SockAcquireRwLockShared(&SocketGlobalLock
);
564 /* Protect the socket too */
565 EnterCriticalSection(&Socket
->Lock
);
567 /* Notify the Helper DLL of Socket Closure */
568 ErrorCode
= SockNotifyHelperDll(Socket
, WSH_NOTIFY_CLOSE
);
571 Socket
->HelperContext
= NULL
;
572 Socket
->SharedData
.AsyncDisabledEvents
= -1;
573 if (Socket
->TdiAddressHandle
)
575 /* Close and forget the handle */
576 NtClose(Socket
->TdiAddressHandle
);
577 Socket
->TdiAddressHandle
= NULL
;
579 if (Socket
->TdiConnectionHandle
)
581 /* Close and forget the handle */
582 NtClose(Socket
->TdiConnectionHandle
);
583 Socket
->TdiConnectionHandle
= NULL
;
586 /* Remove the handle from the table */
587 ErrorCode
= WahRemoveHandleContext(SockContextTable
, &Socket
->WshContext
);
588 if (ErrorCode
== NO_ERROR
)
590 /* Close the socket's handle */
591 NtClose(Socket
->WshContext
.Handle
);
593 /* Dereference the socket */
594 SockDereferenceSocket(Socket
);
598 /* This isn't a socket anymore, or something */
599 ErrorCode
= WSAENOTSOCK
;
602 /* Release both locks */
603 LeaveCriticalSection(&Socket
->Lock
);
604 SockReleaseRwLockShared(&SocketGlobalLock
);
612 WSPSocket(INT AddressFamily
,
615 LPWSAPROTOCOL_INFOW lpProtocolInfo
,
621 SOCKET Handle
= INVALID_SOCKET
;
623 DWORD ServiceFlags
, ProviderFlags
;
624 PWINSOCK_TEB_DATA ThreadData
;
625 PSOCKET_INFORMATION Socket
;
629 ErrorCode
= SockEnterApiFast(&ThreadData
);
630 if (ErrorCode
!= NO_ERROR
)
633 *lpErrno
= ErrorCode
;
634 return INVALID_SOCKET
;
637 /* Get the catalog ID */
638 CatalogId
= lpProtocolInfo
->dwCatalogEntryId
;
640 /* Check if this is a duplication */
641 if(lpProtocolInfo
->dwProviderReserved
)
643 /* Get the duplicate handle */
644 Handle
= (SOCKET
)lpProtocolInfo
->dwProviderReserved
;
646 /* Get our structure for it */
647 Socket
= SockFindAndReferenceSocket(Handle
, TRUE
);
650 /* Tell Winsock about it */
651 Socket
->Handle
= SockUpcallTable
->lpWPUModifyIFSHandle(CatalogId
,
654 /* Check if we got an invalid handle back */
655 if(Socket
->Handle
== INVALID_SOCKET
)
657 /* Restore it for the error path */
658 Socket
->Handle
= Handle
;
663 /* The duplicate handle is invalid */
664 ErrorCode
= WSAEINVAL
;
671 /* See if the address family should be recovered from the protocl info */
672 if (!AddressFamily
|| AddressFamily
== FROM_PROTOCOL_INFO
)
674 /* Use protocol info data */
675 AddressFamily
= lpProtocolInfo
->iAddressFamily
;
678 /* See if the address family should be recovered from the protocl info */
679 if(!SocketType
|| SocketType
== FROM_PROTOCOL_INFO
)
681 /* Use protocol info data */
682 SocketType
= lpProtocolInfo
->iSocketType
;
685 /* See if the address family should be recovered from the protocl info */
686 if(Protocol
== FROM_PROTOCOL_INFO
)
688 /* Use protocol info data */
689 Protocol
= lpProtocolInfo
->iProtocol
;
692 /* Save the service, provider flags and provider ID */
693 ServiceFlags
= lpProtocolInfo
->dwServiceFlags1
;
694 ProviderFlags
= lpProtocolInfo
->dwProviderFlags
;
695 ProviderId
= lpProtocolInfo
->ProviderId
;
697 /* Create the actual socket */
698 ErrorCode
= SockSocket(AddressFamily
,
708 if (ErrorCode
== ERROR_SUCCESS
)
710 /* Acquire the socket lock */
711 EnterCriticalSection(&Socket
->Lock
);
713 /* Set status to opened */
714 Socket
->SharedData
.State
= SocketOpen
;
716 /* Create the Socket Context */
717 ErrorCode
= SockSetHandleContext(Socket
);
718 if (ErrorCode
!= NO_ERROR
)
720 /* Release the lock, close the socket and fail */
721 LeaveCriticalSection(&Socket
->Lock
);
722 SockCloseSocket(Socket
);
727 Handle
= SockUpcallTable
->lpWPUModifyIFSHandle(Socket
->SharedData
.CatalogEntryId
,
728 (SOCKET
)Socket
->WshContext
.Handle
,
731 /* Does Winsock not like it? */
732 if (Handle
== INVALID_SOCKET
)
734 /* Release the lock, close the socket and fail */
735 LeaveCriticalSection(&Socket
->Lock
);
736 SockCloseSocket(Socket
);
740 /* Release the lock */
741 LeaveCriticalSection(&Socket
->Lock
);
745 /* Write return code */
746 *lpErrno
= ErrorCode
;
748 /* Check if we have a socket and dereference it */
749 if (Socket
) SockDereferenceSocket(Socket
);
757 WSPCloseSocket(IN SOCKET Handle
,
761 PSOCKET_INFORMATION Socket
;
762 PWINSOCK_TEB_DATA ThreadData
;
765 ErrorCode
= SockEnterApiFast(&ThreadData
);
766 if (ErrorCode
!= NO_ERROR
)
769 *lpErrno
= ErrorCode
;
773 /* Get the socket structure */
774 Socket
= SockFindAndReferenceSocket(Handle
, TRUE
);
778 *lpErrno
= WSAENOTSOCK
;
783 ErrorCode
= SockCloseSocket(Socket
);
785 /* Remove the final reference */
786 SockDereferenceSocket(Socket
);
788 /* Check if we got here by error */
789 if (ErrorCode
!= NO_ERROR
)
792 *lpErrno
= ErrorCode
;