|
|
#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;
}
//
// Set RCV and SND buffers to zero
// for details look up bug# WinSE 31054, 691666 (read both 35928 and 33546).
//
ULONG Option = 0; setsockopt( Socket, SOL_SOCKET, SO_SNDBUF, (PCHAR)&Option, sizeof(Option) ); Option = 0; setsockopt( Socket, SOL_SOCKET, SO_SNDBUF, (PCHAR)&Option, sizeof(Option) );
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); }
|