384 lines
8.9 KiB
C++
384 lines
8.9 KiB
C++
#include "precomp.h"
|
|
DEBUG_FILEZONE(ZONE_T120_MSMCSTCP);
|
|
/* Socket.cpp
|
|
*
|
|
* Copyright (c) 1996 by Microsoft Corporation
|
|
*
|
|
* Abstract:
|
|
* This is the implementation of our socket constructor/destructor functions.
|
|
*
|
|
*/
|
|
#include "socket.h"
|
|
#include "plgxprt.h"
|
|
|
|
/* Size of listen queue */
|
|
#define LISTEN_QUEUE_SIZE 3
|
|
|
|
/* External definitions */
|
|
extern HWND TCP_Window_Handle;
|
|
extern PTransportInterface g_Transport;
|
|
|
|
/*
|
|
* void CreateAndConfigureListenSocket (VOID)
|
|
*
|
|
* Functional Description
|
|
* This function sets up a listening socket.
|
|
* returns INVALID_SOCKET if there is any error.
|
|
*/
|
|
SOCKET CreateAndConfigureListenSocket (VOID)
|
|
{
|
|
SOCKADDR_IN socket_control;
|
|
SOCKET Socket;
|
|
|
|
// Create the listening socket.
|
|
Socket = socket (AF_INET, SOCK_STREAM, 0);
|
|
|
|
if (Socket == INVALID_SOCKET) {
|
|
WARNING_OUT (("Socket: error creating listening socket (errno = %d)", WSAGetLastError()));
|
|
goto Error;
|
|
}
|
|
|
|
// The listen socket only waits for FD_ACCEPT msgs.
|
|
ASSERT(TCP_Window_Handle);
|
|
if (WSAAsyncSelect (Socket,
|
|
TCP_Window_Handle,
|
|
WM_SOCKET_NOTIFICATION,
|
|
FD_ACCEPT) != 0) {
|
|
|
|
WARNING_OUT (("CreateAndConfigureListenSocket: Error on WSAAsyncSelect = %d", WSAGetLastError()));
|
|
goto Error;
|
|
}
|
|
|
|
/*
|
|
* Load the socket control structure with the parameters necessary.
|
|
* - Internet socket
|
|
* - Let it assign any address to this socket
|
|
* - Assign our port number
|
|
*/
|
|
socket_control.sin_family = AF_INET;
|
|
socket_control.sin_addr.s_addr = INADDR_ANY;
|
|
socket_control.sin_port = htons ( DEFAULT_LISTEN_PORT );
|
|
|
|
/* Issue the bind call */
|
|
if (bind (Socket, (LPSOCKADDR) &socket_control, sizeof(SOCKADDR_IN)) != 0) {
|
|
WARNING_OUT (("Socket::Listen: bind failed: Unable to use WinSock"));
|
|
goto Error;
|
|
}
|
|
|
|
/*
|
|
* Issue a listen to WinSock to tell it we are willing to accept calls.
|
|
* This is a non-blocking listen, therefore we will receive FD_ACCEPT
|
|
* if someone is trying to call us.
|
|
*/
|
|
if (listen (Socket, LISTEN_QUEUE_SIZE) != 0) {
|
|
WARNING_OUT (("Socket::Listen: listen failed: Unable to use WinSock"));
|
|
goto Error;
|
|
}
|
|
ASSERT(Socket != INVALID_SOCKET);
|
|
|
|
return Socket;
|
|
|
|
Error:
|
|
|
|
if (INVALID_SOCKET != Socket)
|
|
{
|
|
::closesocket(Socket);
|
|
}
|
|
|
|
return INVALID_SOCKET;
|
|
}
|
|
|
|
|
|
/*
|
|
* PSocket newSocket (SOCKET socket_number)
|
|
*
|
|
* Functional Description:
|
|
* This is a constructor for the Socket object. It allocates the
|
|
* send and receive buffers and sets up internal variables.
|
|
*/
|
|
PSocket newSocket(TransportConnection XprtConn, PSecurityContext pSC)
|
|
{
|
|
if (IS_SOCKET(XprtConn))
|
|
{
|
|
return ::newSocketEx(XprtConn, pSC);
|
|
}
|
|
return g_pSocketList->FindByTransportConnection(XprtConn, TRUE);
|
|
}
|
|
|
|
|
|
PSocket newPluggableSocket(TransportConnection XprtConn)
|
|
{
|
|
PSocket pSocket = ::newSocketEx(XprtConn, NULL);
|
|
if (NULL != pSocket)
|
|
{
|
|
g_pSocketList->SafeAppend(pSocket);
|
|
}
|
|
return pSocket;
|
|
}
|
|
|
|
|
|
PSocket newSocketEx(TransportConnection XprtConn, PSecurityContext pSC)
|
|
{
|
|
BOOL fRet;
|
|
DBG_SAVE_FILE_LINE
|
|
PSocket pSocket = new CSocket(&fRet, XprtConn, pSC);
|
|
if (NULL != pSocket)
|
|
{
|
|
if (fRet)
|
|
{
|
|
return pSocket;
|
|
}
|
|
pSocket->Release();
|
|
}
|
|
ERROR_OUT(("newSocket: Unable to allocate memory for Socket struct, pSocket=0x%x", pSocket));
|
|
return NULL;
|
|
}
|
|
|
|
|
|
CSocket::CSocket(BOOL *_pfRet, TransportConnection _XprtConn, PSecurityContext _pSC)
|
|
:
|
|
CRefCount(MAKE_STAMP_ID('S','o','c','k')),
|
|
State(IS_SOCKET(_XprtConn) ? NOT_CONNECTED : SOCKET_CONNECTED),
|
|
SecState((NULL == _pSC) ? SC_UNDETERMINED : SC_SECURE),
|
|
pSC(_pSC),
|
|
Max_Packet_Length(DEFAULT_MAX_X224_SIZE),
|
|
Current_Length(0),
|
|
Data_Indication_Buffer(NULL),
|
|
Data_Indication_Length(0),
|
|
Read_State(READ_HEADER),
|
|
X224_Length(0),
|
|
bSpaceAllocated(FALSE),
|
|
Data_Memory(NULL),
|
|
fExtendedX224(FALSE),
|
|
fIncomingSecure(FALSE),
|
|
XprtConn(_XprtConn)
|
|
{
|
|
// assume failure
|
|
*_pfRet = FALSE;
|
|
|
|
// zero out sub structures
|
|
::ZeroMemory(&X224_Header, sizeof(X224_Header));
|
|
::ZeroMemory(&Retry_Info, sizeof(Retry_Info));
|
|
Remote_Address[0] = '\0';
|
|
|
|
if (IS_SOCKET(XprtConn))
|
|
{
|
|
if (INVALID_SOCKET == XprtConn.nLogicalHandle)
|
|
{
|
|
/* Create a STREAM socket (fully reliable, full duplex, and sequenced) */
|
|
if ((XprtConn.nLogicalHandle = ::socket(AF_INET, SOCK_STREAM, 0))
|
|
== INVALID_SOCKET)
|
|
{
|
|
ERROR_OUT (("CSocket: error acquiring INET socket # (errno = %d)", WSAGetLastError()));
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* Enable Tx and Rx messages to the window */
|
|
ASSERT(TCP_Window_Handle);
|
|
if (::WSAAsyncSelect(XprtConn.nLogicalHandle, TCP_Window_Handle,
|
|
WM_SOCKET_NOTIFICATION,
|
|
FD_READ | FD_WRITE | FD_CLOSE | FD_CONNECT) != 0)
|
|
{
|
|
WARNING_OUT (("CSocket: Error on WSAAsyncSelect = %d", WSAGetLastError()));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ASSERT(IS_PLUGGABLE(XprtConn));
|
|
CPluggableConnection *p = ::GetPluggableConnection(this);
|
|
if (NULL == p)
|
|
{
|
|
ERROR_OUT(("newSocket: Unable to find plugable transport (%d, %d)",
|
|
XprtConn.eType, XprtConn.nLogicalHandle));
|
|
return;
|
|
}
|
|
}
|
|
|
|
// success
|
|
*_pfRet = TRUE;
|
|
}
|
|
|
|
|
|
/*
|
|
* void freeSocket (PSocket, TransportConnection)
|
|
*
|
|
* Functional Description:
|
|
* This is a destructor for the Socket object. It frees the send
|
|
* and receive buffers and connection structure.
|
|
* It will also cleanup the listening socket. In this case,
|
|
* "pSocket" is set to NULL and "trash_packets" should be set to TRUE.
|
|
*/
|
|
void freeSocket(PSocket pSocket, TransportConnection XprtConn)
|
|
{
|
|
if (IS_SOCKET(XprtConn))
|
|
{
|
|
if (NULL != g_pSocketList)
|
|
{
|
|
g_pSocketList->SafeRemove(pSocket);
|
|
}
|
|
freeSocketEx(pSocket, XprtConn);
|
|
}
|
|
}
|
|
|
|
|
|
void freeListenSocket(TransportConnection XprtConn)
|
|
{
|
|
ASSERT(IS_SOCKET(XprtConn));
|
|
freeSocketEx(NULL, XprtConn);
|
|
}
|
|
|
|
|
|
void freePluggableSocket(PSocket pSocket)
|
|
{
|
|
freeSocketEx(pSocket, pSocket->XprtConn);
|
|
if (NULL != g_pSocketList)
|
|
{
|
|
g_pSocketList->SafeRemove(pSocket);
|
|
}
|
|
}
|
|
|
|
|
|
void freeSocketEx(PSocket pSocket, TransportConnection XprtConn)
|
|
{
|
|
// Either "pSocket" is NULL, or the socket is not invalid.
|
|
#ifdef _DEBUG
|
|
if (IS_SOCKET(XprtConn))
|
|
{
|
|
if (NULL != pSocket)
|
|
{
|
|
ASSERT(INVALID_SOCKET != pSocket->XprtConn.nLogicalHandle);
|
|
}
|
|
else
|
|
{
|
|
// it is a listen socket
|
|
ASSERT(INVALID_SOCKET != XprtConn.nLogicalHandle);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// Determine the socket number to use... Either the socket is the
|
|
// socket indicated in the PSocket structure, or it is a structure-less
|
|
// listen socket. Note: both cannot be valid!
|
|
|
|
if (IS_SOCKET(XprtConn))
|
|
{
|
|
SOCKET socket = (pSocket) ? pSocket->XprtConn.nLogicalHandle : XprtConn.nLogicalHandle;
|
|
XprtConn.nLogicalHandle = socket;
|
|
|
|
/* Disable notifications to our window */
|
|
if (::IsWindow(TCP_Window_Handle))
|
|
{
|
|
::WSAAsyncSelect(socket, TCP_Window_Handle, 0, 0);
|
|
}
|
|
}
|
|
|
|
if (pSocket != NULL)
|
|
{
|
|
pSocket->Release();
|
|
}
|
|
else
|
|
{
|
|
// This is the listening socket
|
|
::ShutdownAndClose (XprtConn, FALSE, 0);
|
|
}
|
|
}
|
|
|
|
|
|
CSocket::~CSocket(void)
|
|
{
|
|
switch (State)
|
|
{
|
|
case SOCKET_CONNECTED:
|
|
// case WAITING_FOR_DISCONNECT:
|
|
/* All physically connected states issue a shutdown() first */
|
|
::ShutdownAndClose(XprtConn, TRUE, SD_BOTH);
|
|
break;
|
|
|
|
case X224_CONNECTED:
|
|
// Shutdown disable reception only.
|
|
::ShutdownAndClose(XprtConn, TRUE, SD_RECEIVE);
|
|
break;
|
|
|
|
default:
|
|
::ShutdownAndClose(XprtConn, FALSE, 0);
|
|
break;
|
|
}
|
|
|
|
/* Free the structures */
|
|
FreeTransportBuffer();
|
|
delete pSC;
|
|
}
|
|
|
|
|
|
void CSocket::FreeTransportBuffer(void)
|
|
{
|
|
if (NULL != Data_Memory)
|
|
{
|
|
::FreeMemory(Data_Memory);
|
|
Data_Memory = NULL;
|
|
Data_Indication_Buffer = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void CSocketList::SafeAppend(PSocket pSocket)
|
|
{
|
|
::EnterCriticalSection(&g_csTransport);
|
|
if (! Find(pSocket))
|
|
{
|
|
Append(pSocket);
|
|
}
|
|
::LeaveCriticalSection(&g_csTransport);
|
|
}
|
|
|
|
|
|
BOOL CSocketList::SafeRemove(PSocket pSocket)
|
|
{
|
|
::EnterCriticalSection(&g_csTransport);
|
|
BOOL fRet = Remove(pSocket);
|
|
::LeaveCriticalSection(&g_csTransport);
|
|
return fRet;
|
|
}
|
|
|
|
|
|
PSocket CSocketList::FindByTransportConnection(TransportConnection XprtConn, BOOL fNoAddRef)
|
|
{
|
|
PSocket pSocket;
|
|
::EnterCriticalSection(&g_csTransport);
|
|
Reset();
|
|
while (NULL != (pSocket = Iterate()))
|
|
{
|
|
if (IS_SAME_TRANSPORT_CONNECTION(pSocket->XprtConn, XprtConn))
|
|
{
|
|
if (! fNoAddRef)
|
|
{
|
|
pSocket->AddRef();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
::LeaveCriticalSection(&g_csTransport);
|
|
return pSocket;
|
|
}
|
|
|
|
|
|
PSocket CSocketList::RemoveByTransportConnection(TransportConnection XprtConn)
|
|
{
|
|
PSocket pSocket;
|
|
::EnterCriticalSection(&g_csTransport);
|
|
Reset();
|
|
while (NULL != (pSocket = Iterate()))
|
|
{
|
|
if (IS_SAME_TRANSPORT_CONNECTION(pSocket->XprtConn, XprtConn))
|
|
{
|
|
Remove(pSocket);
|
|
break;
|
|
}
|
|
}
|
|
::LeaveCriticalSection(&g_csTransport);
|
|
return pSocket;
|
|
}
|
|
|