Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

283 lines
8.6 KiB

#include "stdafx.h"
#include "sockinfo.h"
SOCKET_INFO::SOCKET_INFO (void)
: Socket (INVALID_SOCKET)
{
ZeroMemory (&LocalAddress, sizeof (SOCKADDR_IN));
ZeroMemory (&RemoteAddress, sizeof (SOCKADDR_IN));
ZeroMemory (&TrivialRedirectDestAddress, sizeof (SOCKADDR_IN));
ZeroMemory (&TrivialRedirectSourceAddress, sizeof (SOCKADDR_IN));
IsNatRedirectActive = FALSE;
}
void
SOCKET_INFO::Init (
IN SOCKET ArgSocket,
IN SOCKADDR_IN * ArgLocalAddress,
IN SOCKADDR_IN * ArgRemoteAddress)
{
assert (Socket == INVALID_SOCKET);
assert (ArgSocket != INVALID_SOCKET);
assert (ArgLocalAddress);
assert (ArgRemoteAddress);
Socket = ArgSocket;
LocalAddress = *ArgLocalAddress;
RemoteAddress = *ArgRemoteAddress;
}
int SOCKET_INFO::Init (
IN SOCKET ArgSocket,
IN SOCKADDR_IN * ArgRemoteAddress)
{
INT AddressLength;
assert (Socket == INVALID_SOCKET);
assert (ArgSocket != INVALID_SOCKET);
AddressLength = sizeof (SOCKADDR_IN);
if (getsockname (ArgSocket, (SOCKADDR *) &LocalAddress, &AddressLength)) {
return WSAGetLastError();
}
Socket = ArgSocket;
RemoteAddress = *ArgRemoteAddress;
return ERROR_SUCCESS;
}
BOOLEAN
SOCKET_INFO::IsSocketValid (void) {
return Socket != INVALID_SOCKET;
}
void
SOCKET_INFO::SetListenInfo (
IN SOCKET ListenSocket,
IN SOCKADDR_IN * ListenAddress)
{
assert (Socket == INVALID_SOCKET);
assert (ListenSocket != INVALID_SOCKET);
assert (ListenAddress);
Socket = ListenSocket;
LocalAddress = *ListenAddress;
}
int
SOCKET_INFO::Connect(
IN SOCKADDR_IN * ArgRemoteAddress)
{
int Status;
DWORD LocalToRemoteInterfaceAddress;
INT AddressSize = sizeof (SOCKADDR_IN);
BOOL KeepaliveOption;
assert (Socket == INVALID_SOCKET);
assert (ArgRemoteAddress);
Status = GetBestInterfaceAddress (
ntohl (ArgRemoteAddress -> sin_addr.s_addr),
&LocalToRemoteInterfaceAddress);
if (ERROR_SUCCESS != Status) {
DebugF (_T("Q931: Failed to get best interface for the destination %08X:%04X.\n"),
SOCKADDR_IN_PRINTF (ArgRemoteAddress));
return Status;
}
LocalAddress.sin_family = AF_INET;
LocalAddress.sin_addr.s_addr = htonl (LocalToRemoteInterfaceAddress);
LocalAddress.sin_port = htons (0);
Socket = WSASocket (AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
if (Socket == INVALID_SOCKET) {
Status = WSAGetLastError ();
DebugF( _T("Q931: Destination %08X:%04X, failed to create socket"),
SOCKADDR_IN_PRINTF (ArgRemoteAddress));
DumpError (Status);
return Status;
}
if (SOCKET_ERROR == bind(Socket, (PSOCKADDR)&LocalAddress, AddressSize)) {
Status = WSAGetLastError ();
DebugLastError (_T("Q931: Failed to bind dest socket.\n"));
goto cleanup;
}
// Set keepalive on the socket
KeepaliveOption = TRUE;
if (SOCKET_ERROR == setsockopt (Socket, SOL_SOCKET, SO_KEEPALIVE,
(PCHAR) &KeepaliveOption, sizeof (KeepaliveOption)))
{
Status = WSAGetLastError ();
DebugLastError (_T("Q931: Failed to set keepalive on the dest socket.\n"));
goto cleanup;
}
if (getsockname (Socket, (struct sockaddr *)&LocalAddress, &AddressSize)) {
Status = WSAGetLastError ();
DebugLastError (_T("Q931: Failed to get name of TCP socket.\n"));
goto cleanup;
}
// Create a trivial redirect. This is used to disallow interception of
// Q.931 connect-attempts by more general Q.931 dynamic port redirect established
// during initialization of the proxy. As a side effect it helps to puncture
// the firewall for both H.245 and Q.931 if the firewall is enabled.
Status = CreateTrivialNatRedirect(
ArgRemoteAddress,
&LocalAddress,
0
);
if(Status != S_OK) {
goto cleanup;
}
RemoteAddress = *ArgRemoteAddress;
// connect to the target server
// -XXX- make this asynchronous some day!!!
Status = connect (Socket, (SOCKADDR *) ArgRemoteAddress, sizeof (SOCKADDR_IN));
if(Status) {
Status = WSAGetLastError ();
goto cleanup;
}
Status = EventMgrBindIoHandle (Socket);
if (Status != S_OK) {
goto cleanup;
}
return ERROR_SUCCESS;
cleanup:
Clear(TRUE);
return Status;
}
HRESULT SOCKET_INFO::CreateTrivialNatRedirect (
IN SOCKADDR_IN * ArgTrivialRedirectDestAddress,
IN SOCKADDR_IN * ArgTrivialRedirectSourceAddress,
IN ULONG RestrictedAdapterIndex)
{
HRESULT Status = S_OK;
ULONG ErrorCode;
ULONG RedirectFlags = NatRedirectFlagLoopback;
_ASSERTE(ArgTrivialRedirectDestAddress);
_ASSERTE(ArgTrivialRedirectSourceAddress);
// Save redirect information. It will be needed when time comes to cancel the redirect.
TrivialRedirectDestAddress.sin_addr.s_addr = ArgTrivialRedirectDestAddress->sin_addr.s_addr;
TrivialRedirectDestAddress.sin_port = ArgTrivialRedirectDestAddress->sin_port;
TrivialRedirectSourceAddress.sin_addr.s_addr = ArgTrivialRedirectSourceAddress->sin_addr.s_addr;
TrivialRedirectSourceAddress.sin_port = ArgTrivialRedirectSourceAddress->sin_port;
if(RestrictedAdapterIndex) {
RedirectFlags |= NatRedirectFlagRestrictAdapter;
}
ErrorCode = NatCreateRedirectEx (
NatHandle,
RedirectFlags,
IPPROTO_TCP,
TrivialRedirectDestAddress.sin_addr.s_addr, // destination address
TrivialRedirectDestAddress.sin_port, // destination port
TrivialRedirectSourceAddress.sin_addr.s_addr, // source addresss
TrivialRedirectSourceAddress.sin_port, // source port
TrivialRedirectDestAddress.sin_addr.s_addr, // new destination address
TrivialRedirectDestAddress.sin_port, // new destination port
TrivialRedirectSourceAddress.sin_addr.s_addr, // new source address
TrivialRedirectSourceAddress.sin_port, // new source port
RestrictedAdapterIndex, // restricted adapter index
NULL, // completion routine
NULL, // completion context
NULL); // notify event
if( NO_ERROR != ErrorCode) {
Status = GetLastErrorAsResult();
DebugF (_T("H323: Failed to set up trivial redirect (%08X:%04X -> %08X:%04X) => (%08X:%04X -> %08X:%04X). Error - %d.\n"),
SOCKADDR_IN_PRINTF(&TrivialRedirectSourceAddress), SOCKADDR_IN_PRINTF(&TrivialRedirectDestAddress),
SOCKADDR_IN_PRINTF(&TrivialRedirectSourceAddress), SOCKADDR_IN_PRINTF(&TrivialRedirectDestAddress),
ErrorCode);
}
else {
DebugF (_T("H323: Set up trivial redirect (%08X:%04X -> %08X:%04X) => (%08X:%04X -> %08X:%04X).\n"),
SOCKADDR_IN_PRINTF(&TrivialRedirectSourceAddress), SOCKADDR_IN_PRINTF(&TrivialRedirectDestAddress),
SOCKADDR_IN_PRINTF(&TrivialRedirectSourceAddress), SOCKADDR_IN_PRINTF(&TrivialRedirectDestAddress));
IsNatRedirectActive = TRUE;
}
return Status;
}
void SOCKET_INFO::Clear (BOOL CancelTrivialRedirect)
{
if (Socket != INVALID_SOCKET) {
closesocket (Socket);
Socket = INVALID_SOCKET;
}
if (CancelTrivialRedirect && IsNatRedirectActive) {
DebugF (_T("H323: Cancelling trivial redirect (%08X:%04X -> %08X:%04X) => (%08X:%04X -> %08X:%04X).\n"),
SOCKADDR_IN_PRINTF(&TrivialRedirectSourceAddress), SOCKADDR_IN_PRINTF(&TrivialRedirectDestAddress),
SOCKADDR_IN_PRINTF(&TrivialRedirectSourceAddress), SOCKADDR_IN_PRINTF(&TrivialRedirectDestAddress));
NatCancelRedirect (
NatHandle,
IPPROTO_TCP,
TrivialRedirectDestAddress.sin_addr.s_addr, // destination address
TrivialRedirectDestAddress.sin_port, // destination port
TrivialRedirectSourceAddress.sin_addr.s_addr, // source addresss
TrivialRedirectSourceAddress.sin_port, // source port
TrivialRedirectDestAddress.sin_addr.s_addr, // new destination address
TrivialRedirectDestAddress.sin_port, // new destination port
TrivialRedirectSourceAddress.sin_addr.s_addr, // new source address
TrivialRedirectSourceAddress.sin_port // new source port
);
IsNatRedirectActive = FALSE;
}
}
SOCKET_INFO::~SOCKET_INFO (void)
{
Clear(TRUE);
}