windows-nt/Source/XPSP1/NT/enduser/netmeeting/t120/mst120/socket.cpp
2020-09-26 16:20:57 +08:00

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 ( TCP_PORT_NUMBER );
/* 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;
}