mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 18:15:11 +00:00
Implemented WSPCloseSocket.
svn path=/trunk/; revision=12232
This commit is contained in:
parent
9367e001e8
commit
28bce6709b
2 changed files with 122 additions and 4 deletions
|
@ -49,7 +49,7 @@ typedef struct _SOCK_SHARED_INFO {
|
||||||
INT Protocol;
|
INT Protocol;
|
||||||
INT SizeOfLocalAddress;
|
INT SizeOfLocalAddress;
|
||||||
INT SizeOfRemoteAddress;
|
INT SizeOfRemoteAddress;
|
||||||
ULONG LingerData;
|
struct linger LingerData;
|
||||||
ULONG SendTimeout;
|
ULONG SendTimeout;
|
||||||
ULONG RecvTimeout;
|
ULONG RecvTimeout;
|
||||||
ULONG SizeOfRecvBuffer;
|
ULONG SizeOfRecvBuffer;
|
||||||
|
|
|
@ -284,7 +284,7 @@ DWORD MsafdReturnWithErrno( NTSTATUS Status, LPINT Errno, DWORD Received,
|
||||||
INT
|
INT
|
||||||
WSPAPI
|
WSPAPI
|
||||||
WSPCloseSocket(
|
WSPCloseSocket(
|
||||||
IN SOCKET s,
|
IN SOCKET Handle,
|
||||||
OUT LPINT lpErrno)
|
OUT LPINT lpErrno)
|
||||||
/*
|
/*
|
||||||
* FUNCTION: Closes an open socket
|
* FUNCTION: Closes an open socket
|
||||||
|
@ -295,9 +295,127 @@ WSPCloseSocket(
|
||||||
* NO_ERROR, or SOCKET_ERROR if the socket could not be closed
|
* NO_ERROR, or SOCKET_ERROR if the socket could not be closed
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
return 0;
|
IO_STATUS_BLOCK IoStatusBlock;
|
||||||
}
|
PSOCKET_INFORMATION Socket = NULL;
|
||||||
|
NTSTATUS Status;
|
||||||
|
HANDLE SockEvent;
|
||||||
|
AFD_DISCONNECT_INFO DisconnectInfo;
|
||||||
|
SOCKET_STATE OldState;
|
||||||
|
|
||||||
|
/* Create the Wait Event */
|
||||||
|
Status = NtCreateEvent(&SockEvent,
|
||||||
|
GENERIC_READ | GENERIC_WRITE,
|
||||||
|
NULL,
|
||||||
|
1,
|
||||||
|
FALSE);
|
||||||
|
|
||||||
|
if(!NT_SUCCESS(Status)) return SOCKET_ERROR;
|
||||||
|
|
||||||
|
/* Get the Socket Structure associate to this Socket*/
|
||||||
|
Socket = GetSocketStructure(Handle);
|
||||||
|
|
||||||
|
/* If a Close is already in Process, give up */
|
||||||
|
if (Socket->SharedData.State == SocketClosed) {
|
||||||
|
*lpErrno = WSAENOTSOCK;
|
||||||
|
return SOCKET_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the state to close */
|
||||||
|
OldState = Socket->SharedData.State;
|
||||||
|
Socket->SharedData.State = SocketClosed;
|
||||||
|
|
||||||
|
/* If SO_LINGER is ON and the Socket is connected, we need to disconnect */
|
||||||
|
/* FIXME: Should we do this on Datagram Sockets too? */
|
||||||
|
if ((OldState == SocketConnected) && (Socket->SharedData.LingerData.l_onoff)) {
|
||||||
|
ULONG LingerWait;
|
||||||
|
ULONG SendsInProgress;
|
||||||
|
ULONG SleepWait;
|
||||||
|
|
||||||
|
/* We need to respect the timeout */
|
||||||
|
SleepWait = 100;
|
||||||
|
LingerWait = Socket->SharedData.LingerData.l_linger * 1000;
|
||||||
|
|
||||||
|
/* Loop until no more sends are pending, within the timeout */
|
||||||
|
while (LingerWait) {
|
||||||
|
|
||||||
|
/* Find out how many Sends are in Progress */
|
||||||
|
if (GetSocketInformation(Socket,
|
||||||
|
AFD_INFO_SENDS_IN_PROGRESS,
|
||||||
|
&SendsInProgress,
|
||||||
|
NULL)) {
|
||||||
|
/* Bail out if anything but NO_ERROR */
|
||||||
|
LingerWait = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Bail out if no more sends are pending */
|
||||||
|
if (!SendsInProgress) break;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We have to execute a sleep, so it's kind of like
|
||||||
|
* a block. If the socket is Nonblock, we cannot
|
||||||
|
* go on since asyncronous operation is expected
|
||||||
|
* and we cannot offer it
|
||||||
|
*/
|
||||||
|
if (Socket->SharedData.NonBlocking) {
|
||||||
|
Socket->SharedData.State = OldState;
|
||||||
|
*lpErrno = WSAEWOULDBLOCK;
|
||||||
|
return SOCKET_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now we can sleep, and decrement the linger wait */
|
||||||
|
/*
|
||||||
|
* FIXME: It seems Windows does some funky acceleration
|
||||||
|
* since the waiting seems to be longer and longer. I
|
||||||
|
* don't think this improves performance so much, so we
|
||||||
|
* wait a fixed time instead.
|
||||||
|
*/
|
||||||
|
Sleep(SleepWait);
|
||||||
|
LingerWait -= SleepWait;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We have reached the timeout or sends are over.
|
||||||
|
* Disconnect if the timeout has been reached.
|
||||||
|
*/
|
||||||
|
if (LingerWait <= 0) {
|
||||||
|
|
||||||
|
DisconnectInfo.Timeout = RtlConvertLongToLargeInteger(0);
|
||||||
|
DisconnectInfo.DisconnectType = AFD_DISCONNECT_ABORT;
|
||||||
|
|
||||||
|
/* Send IOCTL */
|
||||||
|
Status = NtDeviceIoControlFile((HANDLE)Handle,
|
||||||
|
SockEvent,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
&IoStatusBlock,
|
||||||
|
IOCTL_AFD_DISCONNECT,
|
||||||
|
&DisconnectInfo,
|
||||||
|
sizeof(DisconnectInfo),
|
||||||
|
NULL,
|
||||||
|
0);
|
||||||
|
|
||||||
|
/* Wait for return */
|
||||||
|
if (Status == STATUS_PENDING) {
|
||||||
|
WaitForSingleObject(SockEvent, INFINITE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIXME: We should notify the Helper DLL of WSH_NOTIFY_CLOSE */
|
||||||
|
|
||||||
|
/* Cleanup Time! */
|
||||||
|
Socket->HelperContext = NULL;
|
||||||
|
Socket->SharedData.AsyncDisabledEvents = -1;
|
||||||
|
NtClose(Socket->TdiAddressHandle);
|
||||||
|
Socket->TdiAddressHandle = NULL;
|
||||||
|
NtClose(Socket->TdiConnectionHandle);
|
||||||
|
Socket->TdiConnectionHandle = NULL;
|
||||||
|
|
||||||
|
/* Close the handle */
|
||||||
|
NtClose((HANDLE)Handle);
|
||||||
|
return NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
INT
|
INT
|
||||||
WSPAPI
|
WSPAPI
|
||||||
|
|
Loading…
Reference in a new issue