544 lines
17 KiB
C++
544 lines
17 KiB
C++
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1998 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
emaccept.cpp
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
Contains all the event manager routines which
|
|||
|
manage the overlapped accept operations.
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
User Mode - Win32
|
|||
|
|
|||
|
History:
|
|||
|
|
|||
|
1. created
|
|||
|
Ajay Chitturi (ajaych) 12-Jun-1998
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
///////////////////////////////////////////////////////////////////////////////
|
|||
|
// //
|
|||
|
// Include files //
|
|||
|
// //
|
|||
|
///////////////////////////////////////////////////////////////////////////////
|
|||
|
|
|||
|
#include "stdafx.h"
|
|||
|
|
|||
|
///////////////////////////////////////////////////////////////////////////////
|
|||
|
// //
|
|||
|
// Constants //
|
|||
|
// //
|
|||
|
///////////////////////////////////////////////////////////////////////////////
|
|||
|
|
|||
|
///////////////////////////////////////////////////////////////////////////////
|
|||
|
// //
|
|||
|
// Global Variables //
|
|||
|
// //
|
|||
|
///////////////////////////////////////////////////////////////////////////////
|
|||
|
|
|||
|
///////////////////////////////////////////////////////////////////////////////
|
|||
|
// //
|
|||
|
// Externally defined identifiers //
|
|||
|
// //
|
|||
|
///////////////////////////////////////////////////////////////////////////////
|
|||
|
|
|||
|
///////////////////////////////////////////////////////////////////////////////
|
|||
|
// //
|
|||
|
// Overlapped accept functions //
|
|||
|
// //
|
|||
|
///////////////////////////////////////////////////////////////////////////////
|
|||
|
|
|||
|
|
|||
|
HRESULT
|
|||
|
EventMgrCreateAcceptContext(
|
|||
|
IN OVERLAPPED_PROCESSOR *pOvProcessor,
|
|||
|
IN OUT struct sockaddr_in *pBindAddress,
|
|||
|
OUT PAcceptContext *ppAcceptCtxt
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function creates a socket, binds it to bindAddress and
|
|||
|
issues a listen. It creates the Accept I/O Context and returns
|
|||
|
it to the caller.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pOvProcessor - pointer to the overlapped processor object.
|
|||
|
Once the accept completes the callback of this object is
|
|||
|
called.
|
|||
|
|
|||
|
pBindAddress - pointer to the address to listen on.
|
|||
|
|
|||
|
ppAcceptCtxt - A new Accept I/O context is allocated initialized
|
|||
|
and returned through this OUT parameter.
|
|||
|
|
|||
|
Return Values:
|
|||
|
|
|||
|
Returns S_OK on success, E_OUTOFMEMORY if the memory allocator fails
|
|||
|
or E_FAIL if any of the Winsock functions fail.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
SOCKET listenSock;
|
|||
|
int Error;
|
|||
|
HRESULT Result;
|
|||
|
BOOL KeepaliveOption;
|
|||
|
PAcceptContext pAcceptCtxt;
|
|||
|
*ppAcceptCtxt = NULL;
|
|||
|
|
|||
|
// Create an overlapped socket
|
|||
|
listenSock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP,
|
|||
|
NULL, 0,
|
|||
|
WSA_FLAG_OVERLAPPED);
|
|||
|
|
|||
|
if (listenSock == INVALID_SOCKET)
|
|||
|
{
|
|||
|
Error = WSAGetLastError ();
|
|||
|
DebugF(_T("H323: 0x%x error creating listener socket error: %d pOvProcessor: %p.\n"),
|
|||
|
&pOvProcessor -> GetCallBridge (),
|
|||
|
Error, pOvProcessor);
|
|||
|
return HRESULT_FROM_WIN32 (Error);
|
|||
|
}
|
|||
|
|
|||
|
// Bind the socket to the listen address
|
|||
|
if (bind(listenSock,
|
|||
|
(struct sockaddr *)pBindAddress,
|
|||
|
sizeof(struct sockaddr_in)) == SOCKET_ERROR)
|
|||
|
{
|
|||
|
Error = WSAGetLastError ();
|
|||
|
DebugF (_T("H323: 0x%x bind() failed error: %d.\n"),
|
|||
|
&pOvProcessor -> GetCallBridge (),
|
|||
|
Error);
|
|||
|
closesocket(listenSock);
|
|||
|
listenSock = INVALID_SOCKET;
|
|||
|
return HRESULT_FROM_WIN32 (Error);
|
|||
|
}
|
|||
|
|
|||
|
// Set keepalive on the socket
|
|||
|
KeepaliveOption = TRUE;
|
|||
|
if (SOCKET_ERROR == setsockopt(listenSock, SOL_SOCKET,
|
|||
|
SO_KEEPALIVE, (PCHAR) &KeepaliveOption, sizeof (KeepaliveOption)))
|
|||
|
{
|
|||
|
Error = WSAGetLastError ();
|
|||
|
DebugF (_T("H323: 0x%x failed to set keepalive on listen socket. Error %d.\n"),
|
|||
|
&pOvProcessor -> GetCallBridge (),
|
|||
|
Error);
|
|||
|
closesocket(listenSock);
|
|||
|
listenSock = INVALID_SOCKET;
|
|||
|
return HRESULT_FROM_WIN32 (Error);
|
|||
|
}
|
|||
|
|
|||
|
// Bind the socket handle to the I/O completion port
|
|||
|
if (EventMgrBindIoHandle(listenSock) != S_OK)
|
|||
|
{
|
|||
|
DebugF (_T("H323: 0x%x binding socket:%d to IOCP failed.\n"),
|
|||
|
&pOvProcessor -> GetCallBridge (),
|
|||
|
listenSock);
|
|||
|
closesocket(listenSock);
|
|||
|
listenSock = INVALID_SOCKET;
|
|||
|
return E_FAIL;
|
|||
|
}
|
|||
|
|
|||
|
if (listen(listenSock, MAX_LISTEN_BACKLOG) == SOCKET_ERROR)
|
|||
|
{
|
|||
|
Error = WSAGetLastError ();
|
|||
|
DebugF (_T("H323: 0x%x listen() failed: 0x%x pOvProcessor; %p.\n"),
|
|||
|
&pOvProcessor -> GetCallBridge (),
|
|||
|
Error, pOvProcessor);
|
|||
|
closesocket(listenSock);
|
|||
|
listenSock = INVALID_SOCKET;
|
|||
|
return HRESULT_FROM_WIN32 (Error);
|
|||
|
}
|
|||
|
|
|||
|
// Allocate memory from a private heap for accept contexts
|
|||
|
pAcceptCtxt = (PAcceptContext) HeapAlloc (GetProcessHeap (),
|
|||
|
0, // No Flags
|
|||
|
sizeof(AcceptContext));
|
|||
|
if (!pAcceptCtxt)
|
|||
|
{
|
|||
|
DebugF (_T("H323: 0x%x could not allocate Accept context.\n"),
|
|||
|
&pOvProcessor -> GetCallBridge ());
|
|||
|
closesocket(listenSock);
|
|||
|
listenSock = INVALID_SOCKET;
|
|||
|
|
|||
|
return E_OUTOFMEMORY;
|
|||
|
}
|
|||
|
|
|||
|
memset(pAcceptCtxt, 0, sizeof(AcceptContext));
|
|||
|
pAcceptCtxt->ioCtxt.reqType = EMGR_OV_IO_REQ_ACCEPT;
|
|||
|
pAcceptCtxt->ioCtxt.pOvProcessor = pOvProcessor;
|
|||
|
pAcceptCtxt->listenSock = listenSock;
|
|||
|
pAcceptCtxt->acceptSock = INVALID_SOCKET;
|
|||
|
|
|||
|
*ppAcceptCtxt = pAcceptCtxt;
|
|||
|
return S_OK;
|
|||
|
} // EventMgrCreateAcceptContext
|
|||
|
|
|||
|
|
|||
|
void
|
|||
|
EventMgrFreeAcceptContext (
|
|||
|
PAcceptContext pAcceptCtxt
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function frees the pAcceptCtxt.
|
|||
|
OvProcessor is owned by the Call Bridge Machine and
|
|||
|
so we do not free it.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pAcceptCtxt - pointer to the AcceptCtxt to be freed.
|
|||
|
|
|||
|
Return Values:
|
|||
|
|
|||
|
This function has not return value.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
if (pAcceptCtxt->acceptSock != INVALID_SOCKET)
|
|||
|
{
|
|||
|
closesocket(pAcceptCtxt->acceptSock);
|
|||
|
pAcceptCtxt -> acceptSock = INVALID_SOCKET;
|
|||
|
}
|
|||
|
|
|||
|
HeapFree (GetProcessHeap (),
|
|||
|
0, // no flags
|
|||
|
pAcceptCtxt);
|
|||
|
} // EventMgrFreeAcceptContext
|
|||
|
|
|||
|
|
|||
|
HRESULT
|
|||
|
EventMgrIssueAcceptHelperFn(
|
|||
|
PAcceptContext pAcceptCtxt
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function issues an Asynchronous overlapped accept using
|
|||
|
AcceptEx(). The accept socket is created and stored in the
|
|||
|
Accept context before making the call to AcceptEx().
|
|||
|
|
|||
|
In case of an error, the caller needs to free pAcceptCtxt.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pAcceptCtxt - pointer to the Accept I/O context.
|
|||
|
|
|||
|
Return Values:
|
|||
|
|
|||
|
This function returns S_OK in case of success or E_FAIL
|
|||
|
in case of an error.
|
|||
|
CODEWORK: Need to convert Winsock errors to HRESULT and
|
|||
|
return them instead.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
SOCKET acceptSock;
|
|||
|
DWORD lastError, bytesRead;
|
|||
|
HRESULT Result;
|
|||
|
BOOL KeepaliveOption;
|
|||
|
|
|||
|
_ASSERTE(pAcceptCtxt);
|
|||
|
|
|||
|
// create an overlapped socket
|
|||
|
acceptSock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP,
|
|||
|
NULL, 0,
|
|||
|
WSA_FLAG_OVERLAPPED);
|
|||
|
|
|||
|
if (acceptSock == INVALID_SOCKET)
|
|||
|
{
|
|||
|
DebugF (_T("H323: 0x%x error creating accept socket: %d.\n"),
|
|||
|
&pAcceptCtxt -> ioCtxt.pOvProcessor -> GetCallBridge (),
|
|||
|
WSAGetLastError());
|
|||
|
return E_FAIL;
|
|||
|
}
|
|||
|
|
|||
|
pAcceptCtxt->acceptSock = acceptSock;
|
|||
|
|
|||
|
// Bind the socket handle to the I/O completion port
|
|||
|
if (EventMgrBindIoHandle(acceptSock) != S_OK)
|
|||
|
{
|
|||
|
DebugF (_T("H323: 0x%x binding socket:%d to IOCP failed.\n"),
|
|||
|
&pAcceptCtxt -> ioCtxt.pOvProcessor -> GetCallBridge (),
|
|||
|
acceptSock);
|
|||
|
return E_FAIL;
|
|||
|
}
|
|||
|
|
|||
|
memset(&pAcceptCtxt->ioCtxt.ov, 0, sizeof(OVERLAPPED));
|
|||
|
|
|||
|
// Set keepalive on the socket
|
|||
|
KeepaliveOption = TRUE;
|
|||
|
if (SOCKET_ERROR == setsockopt (acceptSock, SOL_SOCKET,
|
|||
|
SO_KEEPALIVE, (PCHAR) &KeepaliveOption, sizeof (KeepaliveOption)))
|
|||
|
{
|
|||
|
DebugF (_T("H323: 0x%x failed to set keepalive on accept socket. Error %d.\n"),
|
|||
|
&pAcceptCtxt -> ioCtxt.pOvProcessor -> GetCallBridge (),
|
|||
|
WSAGetLastError());
|
|||
|
return E_FAIL;
|
|||
|
}
|
|||
|
|
|||
|
pAcceptCtxt->ioCtxt.pOvProcessor->GetCallBridge().AddRef();
|
|||
|
|
|||
|
// Issue overlapped accept
|
|||
|
if (!AcceptEx(pAcceptCtxt->listenSock,
|
|||
|
acceptSock,
|
|||
|
pAcceptCtxt->addrBuf,
|
|||
|
0, // Read nothing from socket
|
|||
|
sizeof(struct sockaddr_in) + 16,
|
|||
|
sizeof(struct sockaddr_in) + 16,
|
|||
|
&bytesRead,
|
|||
|
&pAcceptCtxt->ioCtxt.ov))
|
|||
|
{
|
|||
|
lastError = WSAGetLastError();
|
|||
|
if (lastError != ERROR_IO_PENDING)
|
|||
|
{
|
|||
|
pAcceptCtxt->ioCtxt.pOvProcessor->GetCallBridge().Release();
|
|||
|
|
|||
|
// This means the overlapped AcceptEx() failed
|
|||
|
DebugF(_T("H323: 0x%x AcceptEx() failed error: %d listenSock: %d acceptSock: %d.\n"),
|
|||
|
&pAcceptCtxt -> ioCtxt.pOvProcessor -> GetCallBridge (),
|
|||
|
lastError, pAcceptCtxt->listenSock,
|
|||
|
pAcceptCtxt->acceptSock);
|
|||
|
return E_FAIL;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return S_OK;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
HRESULT
|
|||
|
EventMgrIssueAccept(
|
|||
|
IN DWORD bindIPAddress,
|
|||
|
IN OVERLAPPED_PROCESSOR &rOvProcessor,
|
|||
|
OUT WORD& rBindPort,
|
|||
|
OUT SOCKET& rListenSock
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function is exported to the Call Bridge machine for
|
|||
|
making an asynchronous accept request for H.245 connections.
|
|||
|
Once the accept is completed, the accept callback function on
|
|||
|
rOvProcessor is called.
|
|||
|
|
|||
|
This function calls bind() with on IP address "bindIPAddress"
|
|||
|
and port 0. Winsock allocates a free port which is got using
|
|||
|
getsockname(). This port is returned using the OUT param
|
|||
|
rBindPort.
|
|||
|
|
|||
|
This function also returns the listen socket using the OUT
|
|||
|
param rListenSock. The Call Bridge machine can use this
|
|||
|
socket to cancel the asynchronous Accept() request.
|
|||
|
Once this function succeeds only the Call bridge frees the
|
|||
|
listen socket.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
bindIPAddress - This is the IP address to listen on.
|
|||
|
This is in host byte order.
|
|||
|
|
|||
|
rOvProcessor - A reference to the Overlapped processor. This
|
|||
|
is stored in the Accept I/O context. Once the accept
|
|||
|
completes the AcceptCallback() on this object is called.
|
|||
|
|
|||
|
rBindPort - The port on which the listen is issued is returned
|
|||
|
through this OUT param. This function calls bind() with on
|
|||
|
IP address "bindIPAddress" and port 0. Winsock allocates a
|
|||
|
free port which is got using getsockname(). This port is
|
|||
|
returned using the OUT param rBindPort.
|
|||
|
The port returned is in host byte order.
|
|||
|
|
|||
|
rListenSock - The listening socket is returned through this OUT
|
|||
|
param. The Call Bridge machine can use this socket to cancel
|
|||
|
the asynchronous Accept() request. Once this function succeeds
|
|||
|
only the Call bridge frees the listen socket.
|
|||
|
|
|||
|
Return Values:
|
|||
|
|
|||
|
This function returns S_OK in case of success or E_FAIL
|
|||
|
in case of a failure.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PAcceptContext pAcceptCtxt;
|
|||
|
struct sockaddr_in bindAddress;
|
|||
|
HRESULT hRes;
|
|||
|
int bindAddressLen = sizeof(struct sockaddr_in);
|
|||
|
|
|||
|
memset(&bindAddress, 0, sizeof(bindAddress));
|
|||
|
|
|||
|
bindAddress.sin_family = AF_INET;
|
|||
|
bindAddress.sin_addr.s_addr = htonl(bindIPAddress);
|
|||
|
bindAddress.sin_port = htons(0);
|
|||
|
|
|||
|
hRes = EventMgrCreateAcceptContext(&rOvProcessor,
|
|||
|
&bindAddress, &pAcceptCtxt);
|
|||
|
if (hRes != S_OK)
|
|||
|
return hRes;
|
|||
|
|
|||
|
if (!pAcceptCtxt)
|
|||
|
return E_FAIL;
|
|||
|
|
|||
|
// Get the port
|
|||
|
if (getsockname(pAcceptCtxt->listenSock,
|
|||
|
(struct sockaddr *)&bindAddress,
|
|||
|
&bindAddressLen))
|
|||
|
{
|
|||
|
closesocket(pAcceptCtxt->listenSock);
|
|||
|
pAcceptCtxt->listenSock = INVALID_SOCKET;
|
|||
|
|
|||
|
EventMgrFreeAcceptContext(pAcceptCtxt);
|
|||
|
return E_FAIL;
|
|||
|
}
|
|||
|
|
|||
|
rBindPort = ntohs(bindAddress.sin_port);
|
|||
|
|
|||
|
hRes = EventMgrIssueAcceptHelperFn(pAcceptCtxt);
|
|||
|
|
|||
|
if (hRes != S_OK)
|
|||
|
{
|
|||
|
closesocket(pAcceptCtxt->listenSock);
|
|||
|
pAcceptCtxt->listenSock = INVALID_SOCKET;
|
|||
|
|
|||
|
EventMgrFreeAcceptContext(pAcceptCtxt);
|
|||
|
return hRes;
|
|||
|
}
|
|||
|
|
|||
|
rListenSock = pAcceptCtxt->listenSock;
|
|||
|
return S_OK;
|
|||
|
} // EventMgrIssueAccept
|
|||
|
|
|||
|
|
|||
|
void
|
|||
|
HandleAcceptCompletion(
|
|||
|
PAcceptContext pAcceptCtxt,
|
|||
|
DWORD status
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function is called by the event loop when an accept I/O completes.
|
|||
|
The Call Bridge Machine's accept callback function is called for
|
|||
|
H.245 connections.
|
|||
|
|
|||
|
This function always frees pAcceptCtxt if another accept is not issued.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
pAcceptCtxt - The Accept I/O context. This contains the overlapped
|
|||
|
context on which the accept callback is called in the case of
|
|||
|
H.245 connections and the listen and accept sockets.
|
|||
|
|
|||
|
status - This conveys the WIN32 error status.
|
|||
|
|
|||
|
Return Values:
|
|||
|
|
|||
|
This function does not return any error code. In case of an error,
|
|||
|
the call bridge machine is notified about the error in the callback.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
int locallen = sizeof(struct sockaddr_in);
|
|||
|
int remotelen = sizeof(struct sockaddr_in);
|
|||
|
struct sockaddr_in *pLocalAddr;
|
|||
|
struct sockaddr_in *pRemoteAddr;
|
|||
|
|
|||
|
// If H.245 call the accept callback on overlapped processor
|
|||
|
// and free the accept I/O context.
|
|||
|
// The listening socket is closed by the Call bridge machine.
|
|||
|
if (status == NO_ERROR)
|
|||
|
{
|
|||
|
if (setsockopt(pAcceptCtxt->acceptSock,
|
|||
|
SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
|
|||
|
(char*)(&pAcceptCtxt->listenSock),
|
|||
|
sizeof(SOCKET)) == SOCKET_ERROR)
|
|||
|
{
|
|||
|
DebugF (_T("H323: 0x%x setsockopt SO_UPDATE_ACCEPT_CONTEXT failed acceptSock: %d listenSock: %d err: %d.\n"),
|
|||
|
&pAcceptCtxt -> ioCtxt.pOvProcessor -> GetCallBridge (),
|
|||
|
pAcceptCtxt->acceptSock,
|
|||
|
pAcceptCtxt->listenSock,
|
|||
|
WSAGetLastError());
|
|||
|
|
|||
|
// make callback conveying the error
|
|||
|
|
|||
|
SOCKADDR_IN LocalAddress;
|
|||
|
SOCKADDR_IN RemoteAddress;
|
|||
|
|
|||
|
ZeroMemory (&LocalAddress, sizeof (SOCKADDR_IN));
|
|||
|
ZeroMemory (&RemoteAddress, sizeof (SOCKADDR_IN));
|
|||
|
|
|||
|
pAcceptCtxt->ioCtxt.pOvProcessor->AcceptCallback(
|
|||
|
WSAGetLastError(),
|
|||
|
INVALID_SOCKET,
|
|||
|
&LocalAddress,
|
|||
|
&RemoteAddress);
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
// This function does not return anything
|
|||
|
GetAcceptExSockaddrs(pAcceptCtxt->addrBuf, 0,
|
|||
|
sizeof(struct sockaddr_in) + 16,
|
|||
|
sizeof(struct sockaddr_in) + 16,
|
|||
|
(struct sockaddr**)&pLocalAddr,
|
|||
|
&locallen,
|
|||
|
(struct sockaddr**)&pRemoteAddr,
|
|||
|
&remotelen);
|
|||
|
|
|||
|
// make the callback
|
|||
|
pAcceptCtxt->ioCtxt.pOvProcessor->AcceptCallback(
|
|||
|
S_OK,
|
|||
|
pAcceptCtxt->acceptSock,
|
|||
|
pLocalAddr,
|
|||
|
pRemoteAddr);
|
|||
|
|
|||
|
// ownership of pAcceptCtxt -> acceptSock has been transferred,
|
|||
|
// so we need to make sure the acceptSock won't be used
|
|||
|
pAcceptCtxt -> acceptSock = INVALID_SOCKET;
|
|||
|
}
|
|||
|
|
|||
|
} // if (status == NO_ERROR)
|
|||
|
|
|||
|
else
|
|||
|
{
|
|||
|
DebugF (_T("H245: 0x%x error %d on accept callback.\n"),
|
|||
|
&pAcceptCtxt -> ioCtxt.pOvProcessor -> GetCallBridge (),
|
|||
|
status);
|
|||
|
|
|||
|
|
|||
|
SOCKADDR_IN LocalAddress;
|
|||
|
SOCKADDR_IN RemoteAddress;
|
|||
|
|
|||
|
ZeroMemory (&LocalAddress, sizeof (SOCKADDR_IN));
|
|||
|
ZeroMemory (&RemoteAddress, sizeof (SOCKADDR_IN));
|
|||
|
|
|||
|
// make callback conveying the error
|
|||
|
pAcceptCtxt->ioCtxt.pOvProcessor->AcceptCallback(
|
|||
|
HRESULT_FROM_WIN32_ERROR_CODE(status),
|
|||
|
INVALID_SOCKET,
|
|||
|
&LocalAddress,
|
|||
|
&RemoteAddress);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
EventMgrFreeAcceptContext (pAcceptCtxt);
|
|||
|
} // HandleAcceptCompletion(
|