windows-nt/Source/XPSP1/NT/net/rras/ip/nath323/emaccept.cpp

544 lines
17 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
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(