|
|
/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
buffsock.cxx
Abstract:
Implements the BUFFERED_SOCKET class.
Author:
Keith Moore (keithmo) 02-Dec-1996
Revision History:
--*/
#include "precomp.hxx"
#pragma hdrstop
//
// Private constants.
//
#define BUFFER_LENGTH 4096 // bytes
#define ALLOC_MEM(cb) (PVOID)::LocalAlloc(LPTR, (cb))
#define FREE_MEM(p) (VOID)::LocalFree((HLOCAL)(p))
//
// Private types.
//
//
// Private globals.
//
LONG BUFFERED_SOCKET::m_InitCount = -1;
//
// Private prototypes.
//
//
// Public functions.
//
BUFFERED_SOCKET::BUFFERED_SOCKET() {
m_Socket = INVALID_SOCKET; m_Buffer = NULL; m_BufferLength = 0; m_BytesAvailable = NULL; m_Offset = 0; m_Initialized = FALSE;
} // BUFFERED_SOCKET::BUFFERED_SOCKET()
BUFFERED_SOCKET::~BUFFERED_SOCKET() {
if( m_Socket != INVALID_SOCKET ) {
::closesocket( m_Socket );
}
if( m_Buffer != NULL ) {
FREE_MEM( m_Buffer );
}
if( ::InterlockedDecrement( &BUFFERED_SOCKET::m_InitCount ) == -1 ) {
::WSACleanup();
}
} // BUFFERED_SOCKET::~BUFFERED_SOCKET()
INT BUFFERED_SOCKET::InitializeClient( LPSTR HostName, USHORT Port ) {
LPHOSTENT hostent; INT result; SOCKADDR_IN addr;
result = CommonInitialize();
if( result != 0 ) {
return result;
}
addr.sin_family = AF_INET; addr.sin_port = htons( Port ); addr.sin_addr.s_addr = ::inet_addr( HostName );
if( addr.sin_addr.s_addr == INADDR_NONE ) {
hostent = ::gethostbyname( HostName );
if( hostent == NULL ) {
return ::WSAGetLastError();
}
addr.sin_addr.s_addr = *(PULONG)hostent->h_addr_list[0];
}
return InitializeClient( &addr );
} // BUFFERED_SOCKET::InitializeClient
INT BUFFERED_SOCKET::InitializeClient( LPSOCKADDR_IN HostAddress ) {
INT result;
result = CommonInitialize();
if( result != 0 ) {
return result;
}
if( m_Socket == INVALID_SOCKET ) {
m_Socket = ::socket( AF_INET, SOCK_STREAM, 0 );
if( m_Socket == INVALID_SOCKET ) {
return ::WSAGetLastError();
}
}
if( ::connect( m_Socket, (SOCKADDR *)HostAddress, sizeof(*HostAddress) ) == SOCKET_ERROR ) {
return ::WSAGetLastError();
}
return InitializeClient( m_Socket );
} // BUFFERED_SOCKET::InitializeClient
INT BUFFERED_SOCKET::InitializeClient( SOCKET Socket ) {
INT result;
result = CommonInitialize();
if( result != 0 ) {
return result;
}
m_Socket = Socket;
return 0;
} // BUFFERED_SOCKET::InitializeClient
INT BUFFERED_SOCKET::InitializeServer( USHORT Port ) {
INT result; SOCKET tmpSocket; SOCKADDR_IN addr;
result = CommonInitialize();
if( result != 0 ) {
return result;
}
tmpSocket = ::socket( AF_INET, SOCK_STREAM, 0 );
if( tmpSocket == INVALID_SOCKET ) {
return ::WSAGetLastError();
}
addr.sin_family = AF_INET; addr.sin_port = htons( Port ); addr.sin_addr.s_addr = INADDR_ANY;
result = ::bind( tmpSocket, (SOCKADDR *)&addr, sizeof(addr) );
if( result == SOCKET_ERROR ) {
result = ::WSAGetLastError(); ::closesocket( tmpSocket ); return result;
}
result = ::listen( tmpSocket, 1 );
if( result == SOCKET_ERROR ) {
result = ::WSAGetLastError(); ::closesocket( tmpSocket ); return result;
}
m_Socket = ::accept( tmpSocket, NULL, NULL );
if( m_Socket == INVALID_SOCKET ) {
result = ::WSAGetLastError(); ::closesocket( tmpSocket ); return result;
}
::closesocket( tmpSocket ); return 0;
} // BUFFERED_SOCKET::InitializeClient
INT BUFFERED_SOCKET::Send( PVOID Buffer, LPDWORD BufferLength ) {
INT result;
result = ::send( m_Socket, (CHAR *)Buffer, (INT)*BufferLength, 0 );
if( result == SOCKET_ERROR ) {
return ::WSAGetLastError();
}
*BufferLength = (DWORD)result; return 0;
} // BUFFERED_SOCKET::Send
INT BUFFERED_SOCKET::Recv( PVOID Buffer, LPDWORD BufferLength ) {
INT result;
result = ::recv( m_Socket, (CHAR *)Buffer, (INT)*BufferLength, 0 );
if( result == SOCKET_ERROR ) {
return ::WSAGetLastError();
}
*BufferLength = (DWORD)result; return 0;
} // BUFFERED_SOCKET::Recv
INT BUFFERED_SOCKET::SendFrame( PVOID Buffer, LPDWORD BufferLength ) {
INT result; WSABUF buffers[2];
buffers[0].len = sizeof(DWORD); buffers[0].buf = (CHAR *)BufferLength; buffers[1].len = *BufferLength; buffers[1].buf = (CHAR *)Buffer;
result = ::WSASend( m_Socket, buffers, 2, BufferLength, 0, NULL, NULL );
if( result == SOCKET_ERROR ) {
return ::WSAGetLastError();
}
*BufferLength -= sizeof(DWORD); return 0;
} // BUFFERED_SOCKET::SendFrame
INT BUFFERED_SOCKET::RecvFrame( PVOID Buffer, LPDWORD BufferLength ) {
INT result; DWORD frameLength;
result = BufferedRecv( &frameLength, sizeof(frameLength) );
if( result != 0 ) {
return result;
}
if( frameLength > *BufferLength ) {
return WSAEMSGSIZE;
}
result = BufferedRecv( Buffer, frameLength );
if( result != 0 ) {
return result;
}
*BufferLength = frameLength; return 0;
} // BUFFERED_SOCKET::RecvFrom
INT BUFFERED_SOCKET::SendBlob( PIIS_CRYPTO_BLOB Blob ) {
DWORD length;
length = IISCryptoGetBlobLength( Blob );
return SendFrame( (PVOID)Blob, &length );
} // BUFFERED_SOCKET::SendFrame
INT BUFFERED_SOCKET::RecvBlob( PIIS_CRYPTO_BLOB * ppBlob ) {
INT result; DWORD blobLength; PIIS_CRYPTO_BLOB blob;
result = BufferedRecv( &blobLength, sizeof(blobLength) );
if( result != 0 ) {
return result;
}
blob = (PIIS_CRYPTO_BLOB)ALLOC_MEM(blobLength);
if( blob == NULL ) {
return WSAENOBUFS;
}
result = BufferedRecv( blob, blobLength );
if( result != 0 ) {
return result;
}
*ppBlob = blob; return 0;
} // BUFFERED_SOCKET::RecvFrom
//
// Private functions.
//
INT BUFFERED_SOCKET::BufferedRecv( PVOID Buffer, DWORD BufferLength ) {
PCHAR buffer = (PCHAR)Buffer; DWORD bytesToCopy; INT result;
while( BufferLength > 0 ) {
if( m_BytesAvailable == 0 ) {
m_BytesAvailable = m_BufferLength; result = Recv( m_Buffer, &m_BytesAvailable );
if( result != 0 ) {
return result;
}
if( m_BytesAvailable == 0 ) {
return WSAEMSGSIZE;
}
m_Offset = 0;
}
bytesToCopy = min( m_BytesAvailable, BufferLength );
memcpy( buffer, (PCHAR)m_Buffer + m_Offset, bytesToCopy );
m_Offset += bytesToCopy; m_BytesAvailable -= bytesToCopy; BufferLength -= bytesToCopy;
}
return 0;
} // BUFFERED_SOCKET::BufferedRecv
INT BUFFERED_SOCKET::CommonInitialize() {
INT result = 0; WSADATA data;
if( m_Initialized ) {
return 0;
}
if( m_Buffer == NULL ) {
m_Buffer = ALLOC_MEM( BUFFER_LENGTH );
if( m_Buffer == NULL ) {
return WSAENOBUFS;
}
}
m_BufferLength = BUFFER_LENGTH; m_BytesAvailable = 0; m_Offset = 0;
if( ::InterlockedIncrement( &BUFFERED_SOCKET::m_InitCount ) == 0 ) {
result = ::WSAStartup( 0x0202, &data );
}
m_Initialized = ( result == 0 );
return result;
} // BUFFERED_SOCKET::CommonInitialize
|