windows-nt/Source/XPSP1/NT/termsrv/remdsk/rds/t120/mst120/plgxprt.cpp
2020-09-26 16:20:57 +08:00

1898 lines
52 KiB
C++
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "precomp.h"
#include "plgxprt.h"
// #undef TRACE_OUT
// #define TRACE_OUT WARNING_OUT
#define XPRT_CONN_ID_PREFIX "XPRT"
#define XPRT_CONN_ID_PREFIX_LEN 4
static UINT s_nConnID = 0;
CPluggableTransport *g_pPluggableTransport = NULL;
BOOL g_fWinsockDisabled = FALSE;
BOOL g_fPluggableTransportInitialized = FALSE;
DWORD g_dwPluggableTransportThreadID = 0;
HANDLE g_hevtUpdatePluggableTransport = FALSE;
CRITICAL_SECTION g_csTransport;
ILegacyTransport *g_pLegacyTransport = NULL;
HINSTANCE g_hlibMST123 = NULL;
BOOL EnsurePluggableTransportThread(void);
extern HWND TCP_Window_Handle;
extern SOCKET Listen_Socket;
extern SOCKET Listen_Socket_Secure;
extern PTransportInterface g_Transport;
extern UChar g_X224Header[];
extern void CloseListenSocket(void);
T120Error WINAPI T120_CreatePluggableTransport(IT120PluggableTransport **ppTransport)
{
if (NULL != ppTransport)
{
*ppTransport = NULL;
if (NULL == g_pPluggableTransport)
{
if (g_fPluggableTransportInitialized)
{
DBG_SAVE_FILE_LINE
*ppTransport = (CPluggableTransport *) new CPluggableTransport;
if (NULL != *ppTransport)
{
if (EnsurePluggableTransportThread())
{
return T120_NO_ERROR;
}
else
{
(*ppTransport)->ReleaseInterface();
*ppTransport = NULL;
}
}
return T120_ALLOCATION_FAILURE;
}
return T120_NOT_INITIALIZED;
}
return T120_ALREADY_INITIALIZED;
}
return T120_INVALID_PARAMETER;
}
CPluggableConnection::CPluggableConnection
(
PLUGXPRT_CALL_TYPE eCaller,
HANDLE hCommLink,
HANDLE hevtRead,
HANDLE hevtWrite,
HANDLE hevtClose,
PLUGXPRT_FRAMING eFraming,
PLUGXPRT_PARAMETERS *pParams,
T120Error *pRC
)
:
CRefCount(MAKE_STAMP_ID('P','X','P','C')),
m_eState(PLUGXPRT_UNKNOWN_STATE),
m_eCaller(eCaller),
m_hCommLink(hCommLink),
m_hevtRead(hevtRead),
m_hevtWrite(hevtWrite),
m_hevtClose(hevtClose),
m_eType(TRANSPORT_TYPE_PLUGGABLE_X224),
m_pSocket(NULL),
// Legacy tranport
m_nLegacyLogicalHandle(0),
// IO queue management for X.224 framing
m_hevtPendingRead(NULL),
m_hevtPendingWrite(NULL),
m_fPendingReadDone(FALSE),
m_cbPendingRead(0),
m_pbPendingRead(NULL),
m_cbPendingWrite(0),
m_pbPendingWrite(NULL),
m_OutBufQueue2(MAX_PLUGGABLE_OUT_BUF_SIZE)
{
TransportError err;
BOOL fCaller = (PLUGXPRT_CALLER == eCaller);
// X.224 only
::ZeroMemory(&m_OverlappedRead, sizeof(m_OverlappedRead));
::ZeroMemory(&m_OverlappedWrite, sizeof(m_OverlappedWrite));
// assign connection ID
::EnterCriticalSection(&g_csTransport);
if (s_nConnID > 0x7FFF)
{
s_nConnID = 0;
}
m_nConnID = ++s_nConnID;
::LeaveCriticalSection(&g_csTransport);
// create connection ID string
::CreateConnString(GetConnID(), m_szConnID);
// do framing specific initialization
switch (eFraming)
{
case FRAMING_X224:
m_eType = TRANSPORT_TYPE_PLUGGABLE_X224;
m_hevtPendingRead = ::CreateEvent(NULL, TRUE, FALSE, NULL); /* manual reset */
m_hevtPendingWrite = ::CreateEvent(NULL, TRUE, FALSE, NULL); /* manual reset */
ASSERT(NULL != m_hevtPendingRead && NULL != m_hevtPendingWrite);
*pRC = (NULL != m_hevtPendingRead && NULL != m_hevtPendingWrite)
? T120_NO_ERROR : T120_ALLOCATION_FAILURE;
break;
case FRAMING_LEGACY_PSTN:
m_eType = TRANSPORT_TYPE_PLUGGABLE_PSTN;
ASSERT(NULL != g_pLegacyTransport);
err = g_pLegacyTransport->TCreateTransportStack(fCaller, m_hCommLink, m_hevtClose, pParams);
ASSERT(TRANSPORT_NO_ERROR == err);
*pRC = (TRANSPORT_NO_ERROR == err) ? T120_NO_ERROR : T120_NO_TRANSPORT_STACKS;
break;
default:
ERROR_OUT(("CPluggableConnection: unknown framing %d", eFraming));
*pRC = T120_INVALID_PARAMETER;
break;
}
}
CPluggableConnection::~CPluggableConnection(void)
{
if (NULL != m_pSocket)
{
::freePluggableSocket(m_pSocket);
m_pSocket = NULL;
}
Shutdown();
if (TRANSPORT_TYPE_PLUGGABLE_PSTN == m_eType)
{
if (NULL != g_pLegacyTransport && NULL != m_hCommLink)
{
g_pLegacyTransport->TCloseTransportStack(m_hCommLink);
}
}
if (NULL != m_hCommLink)
{
::CloseHandle(m_hCommLink);
}
if (NULL != m_hevtRead)
{
::CloseHandle(m_hevtRead);
}
if (NULL != m_hevtWrite)
{
::CloseHandle(m_hevtWrite);
}
if (NULL != m_hevtClose)
{
::CloseHandle(m_hevtClose);
}
if (NULL != m_hevtPendingRead)
{
::CloseHandle(m_hevtPendingRead);
}
if (NULL != m_hevtPendingWrite)
{
::CloseHandle(m_hevtPendingWrite);
}
}
ULONG CreateConnString(int nConnID, char szConnID[])
{
return ::wsprintfA(szConnID, "%s: %u", XPRT_CONN_ID_PREFIX, nConnID);
}
UINT GetPluggableTransportConnID(LPCSTR pcszNodeAddress)
{
UINT nConnID = 0;
char szName[T120_CONNECTION_ID_LENGTH];
// make sure we have a clean buffer to start with
::ZeroMemory(szName, sizeof(szName));
// copy the address string
::lstrcpynA(szName, pcszNodeAddress, T120_CONNECTION_ID_LENGTH);
// make sure we have the semi-colon in place
if (':' == szName[XPRT_CONN_ID_PREFIX_LEN])
{
// compare the prefix string
szName[XPRT_CONN_ID_PREFIX_LEN] = '\0';
if (! lstrcmpA(szName, XPRT_CONN_ID_PREFIX))
{
LPSTR psz = &szName[XPRT_CONN_ID_PREFIX_LEN+1];
// get a space?
if (' ' == *psz++)
{
// now, have a number
if ('0' <= *psz && *psz <= '9')
{
while ('0' <= *psz && *psz <= '9')
{
nConnID = nConnID * 10 + (*psz++ - '0');
}
}
}
}
}
return nConnID;
}
BOOL IsValidPluggableTransportName(LPCSTR pcszNodeAddress)
{
return GetPluggableTransportConnID(pcszNodeAddress);
}
typedef BOOL (WINAPI *LPFN_CANCEL_IO) (HANDLE);
void CPluggableConnection::Shutdown(void)
{
TRACE_OUT(("CPluggableConnection::Shutdown"));
if (NULL != m_OverlappedRead.hEvent || NULL != m_OverlappedWrite.hEvent)
{
HINSTANCE hLib = ::LoadLibrary("kernel32.dll");
if (NULL != hLib)
{
LPFN_CANCEL_IO pfnCancelIo = (LPFN_CANCEL_IO) ::GetProcAddress(hLib, "CancelIo");
if (NULL != pfnCancelIo)
{
(*pfnCancelIo)(m_hCommLink);
}
::FreeLibrary(hLib);
}
m_OverlappedRead.hEvent = NULL;
m_OverlappedWrite.hEvent = NULL;
}
delete [] m_pbPendingRead;
m_pbPendingRead = NULL;
LPBYTE buffer;
while (NULL != (buffer = m_OutBufQueue2.Get()))
{
delete [] buffer;
}
}
T120Error CPluggableConnection::UpdateCommLink(HANDLE hCommLink)
{
T120Error rc;
::EnterCriticalSection(&g_csTransport);
switch (m_eState)
{
case PLUGXPRT_UNKNOWN_STATE:
case PLUGXPRT_DISCONNECTED:
Shutdown();
m_hCommLink = hCommLink;
rc = T120_NO_ERROR;
break;
default:
rc = T120_TRANSPORT_NOT_READY;
break;
}
::LeaveCriticalSection(&g_csTransport);
return rc;
}
CPluggableTransport::CPluggableTransport(void)
:
CRefCount(MAKE_STAMP_ID('X','P','R','T')),
m_pfnNotify(NULL),
m_pContext(NULL)
{
g_pPluggableTransport = this;
g_pLegacyTransport = NULL;
}
CPluggableTransport::~CPluggableTransport(void)
{
::PostThreadMessage(g_dwPluggableTransportThreadID, WM_QUIT, 0, 0);
CPluggableConnection *p;
::EnterCriticalSection(&g_csTransport);
while (NULL != (p = m_PluggableConnectionList.Get()))
{
p->Release();
}
::LeaveCriticalSection(&g_csTransport);
if (NULL != g_pLegacyTransport)
{
g_pLegacyTransport->TCleanup();
g_pLegacyTransport->ReleaseInterface();
g_pLegacyTransport = NULL;
}
if (NULL != g_hlibMST123)
{
::FreeLibrary(g_hlibMST123);
g_hlibMST123 = NULL;
}
g_pPluggableTransport = NULL;
}
void CPluggableTransport::ReleaseInterface(void)
{
UnAdvise();
CRefCount::Release();
}
T120Error CPluggableTransport::CreateConnection
(
char szConnID[], /* out */
PLUGXPRT_CALL_TYPE eCaller,
HANDLE hCommLink,
HANDLE hevtRead,
HANDLE hevtWrite,
HANDLE hevtClose,
PLUGXPRT_FRAMING eFraming,
PLUGXPRT_PARAMETERS *pParams
)
{
T120Error rc;
if (FRAMING_LEGACY_PSTN == eFraming)
{
if (! EnsureLegacyTransportLoaded())
{
return T120_NO_TRANSPORT_STACKS;
}
}
if (NULL != pParams)
{
if (sizeof(PLUGXPRT_PARAMETERS) != pParams->cbStructSize)
{
return T120_INVALID_PARAMETER;
}
}
DBG_SAVE_FILE_LINE
CPluggableConnection *p;
p = new CPluggableConnection(eCaller, hCommLink, hevtRead, hevtWrite, hevtClose,
eFraming, pParams, &rc);
if (NULL != p && T120_NO_ERROR == rc)
{
::lstrcpyA(szConnID, p->GetConnString());
::EnterCriticalSection(&g_csTransport);
m_PluggableConnectionList.Append(p);
::LeaveCriticalSection(&g_csTransport);
TransportConnection XprtConn;
XprtConn.eType = p->GetType();
XprtConn.nLogicalHandle = p->GetConnID();
PSocket pSocket = ::newPluggableSocket(XprtConn);
p->SetSocket(pSocket);
ASSERT(NULL != pSocket);
// update the events list to wait for in the plugable transport thread
::SetEvent(g_hevtUpdatePluggableTransport);
return T120_NO_ERROR;
}
if (NULL != p)
{
p->Release();
}
else
{
rc = T120_ALLOCATION_FAILURE;
}
return rc;
}
T120Error CPluggableTransport::UpdateConnection
(
LPSTR pszConnID,
HANDLE hCommLink
)
{
BOOL fFound = FALSE;
CPluggableConnection *p;
T120Error rc = GCC_INVALID_TRANSPORT;
::EnterCriticalSection(&g_csTransport);
m_PluggableConnectionList.Reset();
while (NULL != (p = m_PluggableConnectionList.Iterate()))
{
if (! ::lstrcmpA(p->GetConnString(), pszConnID))
{
rc = p->UpdateCommLink(hCommLink);
break;
}
}
::LeaveCriticalSection(&g_csTransport);
// update the events list to wait for in the plugable transport thread
::SetEvent(g_hevtUpdatePluggableTransport);
return rc;
}
T120Error CPluggableTransport::CloseConnection
(
LPSTR pszConnID
)
{
CPluggableConnection *p;
::EnterCriticalSection(&g_csTransport);
m_PluggableConnectionList.Reset();
while (NULL != (p = m_PluggableConnectionList.Iterate()))
{
if (! ::lstrcmpA(p->GetConnString(), pszConnID))
{
m_PluggableConnectionList.Remove(p);
break;
}
}
::LeaveCriticalSection(&g_csTransport);
// update the events list to wait for in the plugable transport thread
::SetEvent(g_hevtUpdatePluggableTransport);
if (NULL != p)
{
//
// do real work here
//
p->Release();
return T120_NO_ERROR;
}
return GCC_INVALID_TRANSPORT;
}
T120Error CPluggableTransport::EnableWinsock(void)
{
if (g_fWinsockDisabled)
{
g_fWinsockDisabled = FALSE;
//
// LONCHANC: create Listen_Socket if not done so...
//
if (INVALID_SOCKET == Listen_Socket)
{
Listen_Socket = ::CreateAndConfigureListenSocket();
}
}
return T120_NO_ERROR;
}
T120Error CPluggableTransport::DisableWinsock(void)
{
if (! g_fWinsockDisabled)
{
g_fWinsockDisabled = TRUE;
// close Listen_Socket...
::CloseListenSocket();
}
return T120_NO_ERROR;
}
void CPluggableTransport::Advise(LPFN_PLUGXPRT_CB pNotify, LPVOID pContext)
{
m_pfnNotify = pNotify;
m_pContext = pContext;
}
void CPluggableTransport::UnAdvise(void)
{
m_pfnNotify = NULL;
m_pContext = NULL;
}
void CPluggableTransport::ResetConnCounter(void)
{
s_nConnID = 0;
}
void CPluggableTransport::OnProtocolControl
(
TransportConnection XprtConn,
PLUGXPRT_STATE eState,
PLUGXPRT_RESULT eResult
)
{
if (IS_PLUGGABLE(XprtConn))
{
WARNING_OUT(("CPluggableTransport::OnProtocolControl: socket (%d, %d) is doing %d with result %d",
XprtConn.eType, XprtConn.nLogicalHandle, eState, eResult));
if (NULL != m_pfnNotify)
{
CPluggableConnection *p = GetPluggableConnection(XprtConn.nLogicalHandle);
if (NULL != p)
{
PLUGXPRT_MESSAGE Msg;
Msg.eState = eState;
Msg.pContext = m_pContext;
Msg.pszConnID = p->GetConnString();
// we only support X.224 level notifications
Msg.eProtocol = PLUGXPRT_PROTOCOL_X224;
Msg.eResult = eResult;
(*m_pfnNotify)(&Msg);
}
}
}
}
void OnProtocolControl
(
TransportConnection XprtConn,
PLUGXPRT_STATE eState,
PLUGXPRT_RESULT eResult
)
{
if (NULL != g_pPluggableTransport)
{
g_pPluggableTransport->OnProtocolControl(XprtConn, eState, eResult);
}
}
// called only in the plugable transport thread
// already in the critical section
ULONG CPluggableTransport::UpdateEvents(HANDLE *aHandles)
{
ULONG cHandles = 0;
CPluggableConnection *p;
::EnterCriticalSection(&g_csTransport);
m_PluggableConnectionList.Reset();
while (NULL != (p = m_PluggableConnectionList.Iterate()))
{
if (TRANSPORT_TYPE_PLUGGABLE_X224 == p->GetType())
{
aHandles[cHandles++] = p->GetReadEvent();
aHandles[cHandles++] = p->GetWriteEvent();
aHandles[cHandles++] = p->GetCloseEvent();
aHandles[cHandles++] = p->GetPendingReadEvent();
aHandles[cHandles++] = p->GetPendingWriteEvent();
}
}
::LeaveCriticalSection(&g_csTransport);
return cHandles;
}
// called only in the plugable transport thread
// already in the critical section
void CPluggableTransport::OnEventSignaled(HANDLE hevtSignaled)
{
CPluggableConnection *p;
BOOL fPostMessage, fFound;
WPARAM wParam;
LPARAM lParam;
::EnterCriticalSection(&g_csTransport);
m_PluggableConnectionList.Reset();
while (NULL != (p = m_PluggableConnectionList.Iterate()))
{
fFound = TRUE;
fPostMessage = FALSE;
wParam = MAKE_PLUGXPRT_WPARAM(p->GetConnID(), p->GetType());
if (hevtSignaled == p->GetReadEvent())
{
lParam = MAKE_PLUGXPRT_LPARAM(PLUGXPRT_EVENT_READ, PLUGXPRT_RESULT_SUCCESSFUL);
fPostMessage = TRUE;
}
else
if (hevtSignaled == p->GetWriteEvent())
{
lParam = MAKE_PLUGXPRT_LPARAM(PLUGXPRT_EVENT_WRITE, PLUGXPRT_RESULT_SUCCESSFUL);
fPostMessage = TRUE;
}
else
if (hevtSignaled == p->GetCloseEvent())
{
lParam = MAKE_PLUGXPRT_LPARAM(PLUGXPRT_EVENT_CLOSE, PLUGXPRT_RESULT_SUCCESSFUL);
fPostMessage = TRUE;
}
else
{
TransportConnection XprtConn;
XprtConn.eType = p->GetType();
XprtConn.nLogicalHandle = p->GetConnID();
if (hevtSignaled == p->GetPendingReadEvent())
{
TRACE_OUT(("OnEventSignaled: PendingREAD(%d, %d)", p->GetType(), p->GetConnID()));
if (p->OnPendingRead())
{
::ResetEvent(hevtSignaled);
// start next high-level read
p->NotifyHighLevelRead();
}
}
else
if (hevtSignaled == p->GetPendingWriteEvent())
{
TRACE_OUT(("OnEventSignaled: PendingWRITE(%d, %d)", p->GetType(), p->GetConnID()));
if (p->OnPendingWrite())
{
::ResetEvent(hevtSignaled);
// start next low-level write
p->NotifyWriteEvent();
}
}
else
{
fFound = FALSE;
}
}
if (fPostMessage)
{
BOOL fRet = ::PostMessage(TCP_Window_Handle, WM_PLUGGABLE_X224, wParam, lParam);
ASSERT(fRet);
}
if (fFound)
{
break;
}
} // while
::LeaveCriticalSection(&g_csTransport);
ASSERT(NULL != p);
}
// called only in the plugable transport thread
// already in the critical section
void CPluggableTransport::OnEventAbandoned(HANDLE hevtSignaled)
{
CPluggableConnection *p;
BOOL fFound;
WPARAM wParam;
LPARAM lParam;
::EnterCriticalSection(&g_csTransport);
m_PluggableConnectionList.Reset();
while (NULL != (p = m_PluggableConnectionList.Iterate()))
{
fFound = TRUE;
wParam = MAKE_PLUGXPRT_WPARAM(p->GetConnID(), p->GetType());
if (hevtSignaled == p->GetReadEvent())
{
lParam = MAKE_PLUGXPRT_LPARAM(PLUGXPRT_EVENT_READ, PLUGXPRT_RESULT_ABANDONED);
}
else
if (hevtSignaled == p->GetWriteEvent())
{
lParam = MAKE_PLUGXPRT_LPARAM(PLUGXPRT_EVENT_WRITE, PLUGXPRT_RESULT_ABANDONED);
}
else
if (hevtSignaled == p->GetCloseEvent())
{
lParam = MAKE_PLUGXPRT_LPARAM(PLUGXPRT_EVENT_CLOSE, PLUGXPRT_RESULT_ABANDONED);
}
else
if (hevtSignaled == p->GetPendingReadEvent())
{
lParam = MAKE_PLUGXPRT_LPARAM(PLUGXPRT_PENDING_EVENT, PLUGXPRT_RESULT_ABANDONED);
}
else
if (hevtSignaled == p->GetPendingWriteEvent())
{
lParam = MAKE_PLUGXPRT_LPARAM(PLUGXPRT_PENDING_EVENT, PLUGXPRT_RESULT_ABANDONED);
}
else
{
fFound = FALSE;
}
if (fFound)
{
m_PluggableConnectionList.Remove(p);
// update the events list to wait for in the plugable transport thread
::SetEvent(g_hevtUpdatePluggableTransport);
BOOL fRet = ::PostMessage(TCP_Window_Handle, WM_PLUGGABLE_X224, wParam, lParam);
ASSERT(fRet);
break;
}
} // while
::LeaveCriticalSection(&g_csTransport);
ASSERT(NULL != p);
}
CPluggableConnection * CPluggableTransport::GetPluggableConnection(PSocket pSocket)
{
CPluggableConnection *p;
::EnterCriticalSection(&g_csTransport);
m_PluggableConnectionList.Reset();
while (NULL != (p = m_PluggableConnectionList.Iterate()))
{
if (p->GetType() == pSocket->XprtConn.eType &&
p->GetConnID() == pSocket->XprtConn.nLogicalHandle)
{
break;
}
}
::LeaveCriticalSection(&g_csTransport);
return p;
}
CPluggableConnection * GetPluggableConnection(PSocket pSocket)
{
return (NULL != g_pPluggableTransport) ?
g_pPluggableTransport->GetPluggableConnection(pSocket) :
NULL;
}
CPluggableConnection * CPluggableTransport::GetPluggableConnection(UINT_PTR nConnID)
{
CPluggableConnection *p;
::EnterCriticalSection(&g_csTransport);
m_PluggableConnectionList.Reset();
while (NULL != (p = m_PluggableConnectionList.Iterate()))
{
if (p->GetConnID() == nConnID)
{
break;
}
}
::LeaveCriticalSection(&g_csTransport);
return p;
}
CPluggableConnection * GetPluggableConnection(UINT_PTR nConnID)
{
return (NULL != g_pPluggableTransport) ?
g_pPluggableTransport->GetPluggableConnection(nConnID) :
NULL;
}
CPluggableConnection * CPluggableTransport::GetPluggableConnection(HANDLE hCommLink)
{
CPluggableConnection *p;
::EnterCriticalSection(&g_csTransport);
m_PluggableConnectionList.Reset();
while (NULL != (p = m_PluggableConnectionList.Iterate()))
{
if (p->GetCommLink() == hCommLink)
{
break;
}
}
::LeaveCriticalSection(&g_csTransport);
return p;
}
CPluggableConnection * GetPluggableConnection(HANDLE hCommLink)
{
return (NULL != g_pPluggableTransport) ?
g_pPluggableTransport->GetPluggableConnection(hCommLink) :
NULL;
}
CPluggableConnection * CPluggableTransport::GetPluggableConnectionByLegacyHandle(LEGACY_HANDLE logical_handle)
{
CPluggableConnection *p;
::EnterCriticalSection(&g_csTransport);
m_PluggableConnectionList.Reset();
while (NULL != (p = m_PluggableConnectionList.Iterate()))
{
if (p->GetLegacyHandle() == logical_handle)
{
break;
}
}
::LeaveCriticalSection(&g_csTransport);
return p;
}
CPluggableConnection * GetPluggableConnectionByLegacyHandle(LEGACY_HANDLE logical_handle)
{
return (NULL != g_pPluggableTransport) ?
g_pPluggableTransport->GetPluggableConnectionByLegacyHandle(logical_handle) :
NULL;
}
// called in ERNC ConfMgr's constructor
BOOL InitializePluggableTransport(void)
{
if (! g_fPluggableTransportInitialized)
{
g_fWinsockDisabled = FALSE;
g_hevtUpdatePluggableTransport = ::CreateEvent(NULL, FALSE, FALSE, NULL);
if (NULL != g_hevtUpdatePluggableTransport)
{
g_fPluggableTransportInitialized = TRUE;
}
}
return g_fPluggableTransportInitialized;
}
// called in ERNC ConfMgr's destructor
void CleanupPluggableTransport(void)
{
if (g_fPluggableTransportInitialized)
{
g_fPluggableTransportInitialized = FALSE;
if (g_dwPluggableTransportThreadID)
{
::PostThreadMessage(g_dwPluggableTransportThreadID, WM_QUIT, 0, 0);
}
::EnterCriticalSection(&g_csTransport);
if (NULL != g_hevtUpdatePluggableTransport)
{
::CloseHandle(g_hevtUpdatePluggableTransport);
}
::LeaveCriticalSection(&g_csTransport);
}
}
DWORD __stdcall PluggableTransportThreadProc(LPVOID lpv)
{
MSG msg;
BOOL fContinueMainLoop = TRUE;
DWORD nEventSignaled;
ULONG cEvents;
HANDLE aEvents[MAX_PLUGXPRT_CONNECTIONS * MAX_PLUGXPRT_EVENTS + 1];
// signaling that the work hread has been started.
::SetEvent((HANDLE) lpv);
// set up initial event list, the first entry always for update event
cEvents = 1;
aEvents[0] = g_hevtUpdatePluggableTransport;
::SetEvent(g_hevtUpdatePluggableTransport);
// main loop
while (fContinueMainLoop)
{
// process any possible window and thread messages
while (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (WM_QUIT != msg.message)
{
::DispatchMessage(&msg);
}
else
{
fContinueMainLoop = FALSE;
break;
}
}
if (fContinueMainLoop)
{
nEventSignaled = ::MsgWaitForMultipleObjects(cEvents, aEvents, FALSE, INFINITE, QS_ALLINPUT);
::EnterCriticalSection(&g_csTransport);
if (NULL != g_pPluggableTransport)
{
switch (nEventSignaled)
{
case WAIT_OBJECT_0:
// update the event list
cEvents = 1 + g_pPluggableTransport->UpdateEvents(&aEvents[1]);
break;
case WAIT_TIMEOUT:
// impossible, do nothing
break;
default:
if (WAIT_OBJECT_0 + 1 <= nEventSignaled && nEventSignaled < WAIT_OBJECT_0 + cEvents)
{
g_pPluggableTransport->OnEventSignaled(aEvents[nEventSignaled - WAIT_OBJECT_0]);
}
else
if (WAIT_ABANDONED_0 + 1 <= nEventSignaled && nEventSignaled < WAIT_ABANDONED_0 + cEvents)
{
g_pPluggableTransport->OnEventAbandoned(aEvents[nEventSignaled - WAIT_OBJECT_0]);
}
break;
}
}
else
{
fContinueMainLoop = FALSE;
}
::LeaveCriticalSection(&g_csTransport);
}
} // while
g_dwPluggableTransportThreadID = 0;
return 0;
}
BOOL EnsurePluggableTransportThread(void)
{
BOOL fRet = TRUE;
if (! g_dwPluggableTransportThreadID)
{
fRet = FALSE;
HANDLE hSync = ::CreateEvent(NULL, FALSE, FALSE, NULL);
if (NULL != hSync)
{
HANDLE hThread = ::CreateThread(NULL, 0, PluggableTransportThreadProc, hSync, 0,
&g_dwPluggableTransportThreadID);
if (NULL != hThread)
{
::WaitForSingleObject(hSync, 5000); // 5 second
::CloseHandle(hThread);
fRet = TRUE;
}
::CloseHandle(hSync);
}
}
return fRet;
}
#if defined(TEST_PLUGGABLE) && defined(_DEBUG)
LPCSTR FakeNodeAddress(LPCSTR pcszNodeAddress)
{
char szAddr[64];
::lstrcpyA(szAddr, pcszNodeAddress);
for (LPSTR psz = &szAddr[0]; *psz; psz++)
{
if (*psz == ':')
{
*psz = '\0';
break;
}
}
if (! ::lstrcmp(szAddr, "157.59.12.93"))
{
pcszNodeAddress = "XPRT: 1";
}
else
if (! ::lstrcmp(szAddr, "157.59.13.194"))
{
pcszNodeAddress = "XPRT: 2";
}
else
if (! ::lstrcmp(szAddr, "157.59.10.198"))
{
pcszNodeAddress = "XPRT: 1";
}
else
{
ASSERT(0);
}
return pcszNodeAddress;
}
#endif
int SubmitPluggableRead(PSocket pSocket, LPBYTE buffer, int length, PLUGXPRT_RESULT *plug_rc)
{
TRACE_OUT(("SubmitPluggableRead"));
int nRet = SOCKET_ERROR;
*plug_rc = PLUGXPRT_RESULT_SUCCESSFUL;
CPluggableConnection *p = ::GetPluggableConnection(pSocket);
if (NULL != p)
{
nRet = p->Read(buffer, length, plug_rc);
}
else
{
WARNING_OUT(("SubmitPluggableRead: no such conn ID=%d", pSocket->XprtConn.nLogicalHandle));
}
return nRet;
}
int CPluggableConnection::Read(LPBYTE buffer, int length, PLUGXPRT_RESULT *plug_rc)
{
int cbRecv = SOCKET_ERROR;
*plug_rc = PLUGXPRT_RESULT_SUCCESSFUL;
::EnterCriticalSection(&g_csTransport);
if (NULL != m_OverlappedRead.hEvent)
{
// handle low-level pending read first
if (m_fPendingReadDone)
{
// copy the data from internal buffer to external buffer
if (length <= m_cbPendingRead)
{
// get as requested
cbRecv = length;
::CopyMemory(buffer, m_pbPendingRead, length);
m_cbPendingRead -= length;
if (m_cbPendingRead <= 0)
{
CleanupReadState();
}
else
{
// move the memory, do not use copymemory due to overlap
int cb = m_cbPendingRead;
LPBYTE pbDst = m_pbPendingRead;
LPBYTE pbSrc = &m_pbPendingRead[length];
while (cb--)
{
*pbDst++ = *pbSrc++;
}
}
}
else
{
// only get partial data
cbRecv = m_cbPendingRead;
::CopyMemory(buffer, m_pbPendingRead, m_cbPendingRead);
CleanupReadState();
}
// start next high-level read
NotifyHighLevelRead();
}
}
else
{
if (SetupReadState(length))
{
TRACE_OUT(("CPluggableConnection::Read: ReadFile(%d)", m_cbPendingRead));
DWORD dwRead = 0;
if (! ::ReadFile(m_hCommLink,
m_pbPendingRead,
m_cbPendingRead,
&dwRead,
&m_OverlappedRead))
{
DWORD dwErr = ::GetLastError();
if (ERROR_HANDLE_EOF != dwErr && ERROR_IO_PENDING != dwErr)
{
WARNING_OUT(("CPluggableConnection::Read: ReadFile failed, err=%d", dwErr));
CleanupReadState();
// disconnect at next tick
NotifyReadFailure();
*plug_rc = PLUGXPRT_RESULT_READ_FAILED;
}
}
else
{
// do nothing, treat it as WSAEWOULDBLOCK
}
}
else
{
ERROR_OUT(("CPluggableConnection::Read: failed to allocate memory (%d)", length));
// out of memory, try later
// do nothing, treat it as WSAEWOULDBLOCK
}
}
::LeaveCriticalSection(&g_csTransport);
return cbRecv;
}
BOOL CPluggableConnection::OnPendingRead(void)
{
TRACE_OUT(("CPluggableConnection::OnPendingRead"));
BOOL fRet = FALSE;
::EnterCriticalSection(&g_csTransport);
if (NULL != m_OverlappedRead.hEvent)
{
DWORD cbRead = 0;
if (::GetOverlappedResult(m_hCommLink, &m_OverlappedRead, &cbRead, FALSE))
{
if ((int) cbRead == m_cbPendingRead)
{
TRACE_OUT(("CPluggableConnection::OnPendingRead: Received %d bytes (required %d bytes) on socket (%d, %d).",
cbRead, m_cbPendingRead, m_eType, m_nConnID));
}
else
{
WARNING_OUT(("CPluggableConnection::OnPendingRead: Received %d bytes (required %d bytes) on socket (%d, %d).",
cbRead, m_cbPendingRead, m_eType, m_nConnID));
}
m_cbPendingRead = cbRead; // in case cbRead is smaller
m_fPendingReadDone = TRUE;
fRet = TRUE; // turn off event
}
else
{
DWORD dwErr = ::GetLastError();
if (ERROR_IO_INCOMPLETE == dwErr)
{
ASSERT(! cbRead);
}
else
{
TRACE_OUT(("CPluggableConnection::OnPendingRead: read failed %d", dwErr));
fRet = TRUE; // turn off event
// disconnect at next tick
NotifyReadFailure();
}
}
}
else
{
ERROR_OUT(("CPluggableConnection::OnPendingRead: no pending read event handle."));
fRet = TRUE; // turn off event
}
::LeaveCriticalSection(&g_csTransport);
return fRet;
}
void CPluggableConnection::NotifyHighLevelRead(void)
{
WPARAM wParam = MAKE_PLUGXPRT_WPARAM(m_nConnID, m_eType);
LPARAM lParam = MAKE_PLUGXPRT_LPARAM(PLUGXPRT_HIGH_LEVEL_READ, PLUGXPRT_RESULT_SUCCESSFUL);
BOOL fRet = ::PostMessage(TCP_Window_Handle, WM_PLUGGABLE_X224, wParam, lParam);
ASSERT(fRet);
}
void CPluggableConnection::NotifyReadFailure(void)
{
WPARAM wParam = MAKE_PLUGXPRT_WPARAM(m_nConnID, m_eType);
LPARAM lParam = MAKE_PLUGXPRT_LPARAM(PLUGXPRT_EVENT_READ, PLUGXPRT_RESULT_READ_FAILED);
BOOL fRet = ::PostMessage(TCP_Window_Handle, WM_PLUGGABLE_X224, wParam, lParam);
ASSERT(fRet);
}
void CPluggableConnection::NotifyWriteEvent(void)
{
WPARAM wParam = MAKE_PLUGXPRT_WPARAM(m_nConnID, m_eType);
LPARAM lParam = MAKE_PLUGXPRT_LPARAM(PLUGXPRT_EVENT_WRITE, PLUGXPRT_RESULT_SUCCESSFUL);
BOOL fRet = ::PostMessage(TCP_Window_Handle, WM_PLUGGABLE_X224, wParam, lParam);
ASSERT(fRet);
}
void CPluggableConnection::NotifyHighLevelWrite(void)
{
WPARAM wParam = MAKE_PLUGXPRT_WPARAM(m_nConnID, m_eType);
LPARAM lParam = MAKE_PLUGXPRT_LPARAM(PLUGXPRT_HIGH_LEVEL_WRITE, PLUGXPRT_RESULT_SUCCESSFUL);
BOOL fRet = ::PostMessage(TCP_Window_Handle, WM_PLUGGABLE_X224, wParam, lParam);
ASSERT(fRet);
}
void CPluggableConnection::NotifyWriteFailure(void)
{
WPARAM wParam = MAKE_PLUGXPRT_WPARAM(m_nConnID, m_eType);
LPARAM lParam = MAKE_PLUGXPRT_LPARAM(PLUGXPRT_EVENT_WRITE, PLUGXPRT_RESULT_WRITE_FAILED);
BOOL fRet = ::PostMessage(TCP_Window_Handle, WM_PLUGGABLE_X224, wParam, lParam);
ASSERT(fRet);
}
LPBYTE DuplicateBuffer(LPBYTE buffer, UINT length)
{
// DBG_SAVE_FILE_LINE
LPBYTE new_buffer = new BYTE[length];
if (NULL != new_buffer)
{
::CopyMemory(new_buffer, buffer, length);
}
return new_buffer;
}
int SubmitPluggableWrite(PSocket pSocket, LPBYTE buffer, int length, PLUGXPRT_RESULT *plug_rc)
{
TRACE_OUT(("SubmitPluggableWrite"));
int nRet = SOCKET_ERROR;
*plug_rc = PLUGXPRT_RESULT_SUCCESSFUL;
CPluggableConnection *p = ::GetPluggableConnection(pSocket);
if (NULL != p)
{
nRet = p->Write(buffer, length, plug_rc);
}
else
{
WARNING_OUT(("SubmitPluggableWrite: no such conn ID=%d", pSocket->XprtConn.nLogicalHandle));
}
return nRet;
}
int CPluggableConnection::Write(LPBYTE buffer, int length, PLUGXPRT_RESULT *plug_rc)
{
TRACE_OUT(("CPluggableConnection::Write"));
int cbSent = SOCKET_ERROR;
*plug_rc = PLUGXPRT_RESULT_SUCCESSFUL;
::EnterCriticalSection(&g_csTransport);
if (m_OutBufQueue2.GetCount() < MAX_PLUGGABLE_OUT_BUF_SIZE) // x4K
{
DBG_SAVE_FILE_LINE
buffer = ::DuplicateBuffer(buffer, length);
if (NULL != buffer)
{
cbSent = length;
m_OutBufQueue2.Append(length, buffer);
if (1 == m_OutBufQueue2.GetCount())
{
TRACE_OUT(("CPluggableConnection::Write: the only item in the queue"));
WriteTheFirst();
#if 0 // avoid another tick
// start next low-level write
WPARAM wParam = MAKE_PLUGXPRT_WPARAM(m_nConnID, m_eType);
LPARAM lParam = MAKE_PLUGXPRT_LPARAM(PLUGXPRT_EVENT_WRITE, PLUGXPRT_RESULT_SUCCESSFUL);
BOOL fRet = ::PostMessage(TCP_Window_Handle, WM_PLUGGABLE_X224, wParam, lParam);
ASSERT(fRet);
#endif
}
else
{
TRACE_OUT(("CPluggableConnection::Write: more items in the queue"));
}
}
else
{
ERROR_OUT(("CPluggableConnection::Write: failed to allocate memory (%d)", length));
// out of memory, try later
// do nothing, treat it as WSAEWOULDBLOCK
}
}
::LeaveCriticalSection(&g_csTransport);
return cbSent;
}
void CPluggableConnection::WriteTheFirst(void)
{
int length;
LPBYTE buffer;
TRACE_OUT(("CPluggableConnection::WriteTheFirst"));
::EnterCriticalSection(&g_csTransport);
if (NULL == m_OverlappedWrite.hEvent)
{
length = 0;
buffer = m_OutBufQueue2.PeekHead(&length);
if (NULL != buffer)
{
::ZeroMemory(&m_OverlappedWrite, sizeof(m_OverlappedWrite));
m_OverlappedWrite.hEvent = m_hevtPendingWrite;
m_pbPendingWrite = buffer;
m_cbPendingWrite = length;
TRACE_OUT(("CPluggableConnection::WriteTheFirst: WriteFile(%d)", length));
DWORD cbWritten = 0;
if (! ::WriteFile(m_hCommLink, buffer, length, &cbWritten, &m_OverlappedWrite))
{
DWORD dwErr = ::GetLastError();
if (ERROR_IO_PENDING != dwErr)
{
ERROR_OUT(("CPluggableConnection::WriteTheFirst: WriteFile failed, err=%d", dwErr));
CleanupWriteState();
m_OutBufQueue2.Get(); // dequeue the buffer which cannot be sent
NotifyWriteFailure();
}
else
{
// we are still in pending
// repeat the write event
NotifyWriteEvent();
}
}
}
else
{
TRACE_OUT(("CPluggableConnection::WriteTheFirst: queue is empty"));
// no more low-level write
m_pbPendingWrite = NULL;
CleanupWriteState();
// start next high-level write
NotifyHighLevelWrite();
}
}
else
{
TRACE_OUT(("CPluggableConnection::WriteTheFirst: still pending"));
// we are still in write pending, wake up the pending write
OnPendingWrite(); // check for pending write result
NotifyWriteEvent();
}
::LeaveCriticalSection(&g_csTransport);
}
void PluggableWriteTheFirst(TransportConnection XprtConn)
{
if (IS_PLUGGABLE(XprtConn))
{
CPluggableConnection *p = ::GetPluggableConnection(XprtConn.nLogicalHandle);
if (NULL != p)
{
p->WriteTheFirst();
}
else
{
ERROR_OUT(("PluggableWriteTheFirst: no such conn ID=%d", XprtConn.nLogicalHandle));
}
}
else
{
ERROR_OUT(("PluggableWriteTheFirst: not plugable connection"));
}
}
void PluggableShutdown(TransportConnection XprtConn)
{
if (IS_PLUGGABLE(XprtConn))
{
CPluggableConnection *p = ::GetPluggableConnection(XprtConn.nLogicalHandle);
if (NULL != p)
{
p->Shutdown();
}
else
{
ERROR_OUT(("PluggableShutdown: no such conn ID=%d", XprtConn.nLogicalHandle));
}
}
else
{
ERROR_OUT(("PluggableShutdown: not plugable connection"));
}
}
BOOL CPluggableConnection::OnPendingWrite(void)
{
TRACE_OUT(("CPluggableConnection::OnPendingWrite"));
BOOL fRet = FALSE;
BOOL fStartNextWrite = FALSE;
::EnterCriticalSection(&g_csTransport);
if (NULL != m_OverlappedWrite.hEvent)
{
DWORD cbWritten = 0;
if (::GetOverlappedResult(m_hCommLink, &m_OverlappedWrite, &cbWritten, FALSE))
{
TRACE_OUT(("CPluggableConnection::OnPendingWrite: Sent %d bytes (required %d bytes) on socket (%d, %d).",
cbWritten, m_cbPendingWrite, m_eType, m_nConnID));
if (cbWritten >= (DWORD) m_cbPendingWrite)
{
ASSERT(cbWritten == (DWORD) m_cbPendingWrite);
// remove the item from the queue
int length = 0;
LPBYTE buffer = m_OutBufQueue2.Get(&length);
ASSERT(length == m_cbPendingWrite);
ASSERT(buffer == m_pbPendingWrite);
CleanupWriteState();
fRet = TRUE; // turn off event
}
else
{
ERROR_OUT(("CPluggableConnection::OnPendingWrite: unexpected error, less data written %d (required %d)",
cbWritten, m_cbPendingWrite));
NotifyWriteFailure();
fRet = TRUE; // turn off event
}
}
else
{
DWORD dwErr = ::GetLastError();
if (ERROR_IO_INCOMPLETE == dwErr)
{
ASSERT(! cbWritten);
}
else
{
ERROR_OUT(("CPluggableConnection::OnPendingWrite: failed to write, err=%d", dwErr));
NotifyWriteFailure();
fRet = TRUE; // turn off event
}
}
}
else
{
// it is very possible that we hit this many times
fRet = TRUE;
}
::LeaveCriticalSection(&g_csTransport);
return fRet;
}
BOOL CPluggableConnection::SetupReadState(int length)
{
DBG_SAVE_FILE_LINE
LPBYTE buffer = new BYTE[length];
if (NULL != buffer)
{
m_pbPendingRead = buffer;
m_cbPendingRead = length;
m_fPendingReadDone = FALSE;
::ZeroMemory(&m_OverlappedRead, sizeof(m_OverlappedRead));
m_OverlappedRead.hEvent = m_hevtPendingRead;
}
else
{
CleanupReadState();
}
return (NULL != buffer);
}
void CPluggableConnection::CleanupReadState(void)
{
delete [] m_pbPendingRead;
m_pbPendingRead = NULL;
m_cbPendingRead = 0;
m_fPendingReadDone = FALSE;
::ZeroMemory(&m_OverlappedRead, sizeof(m_OverlappedRead));
}
void CPluggableConnection::CleanupWriteState(void)
{
delete [] m_pbPendingWrite;
m_pbPendingWrite = NULL;
m_cbPendingWrite = 0;
::ZeroMemory(&m_OverlappedWrite, sizeof(m_OverlappedWrite));
}
TransportError CALLBACK LegacyTransportCallback(ULONG nMsg, void *Param1, void *Param2)
{
if (Param2 == g_pPluggableTransport)
{
BOOL fPostMsg = FALSE;
WPARAM wParam = 0;
CPluggableConnection *p;
switch (nMsg)
{
case TRANSPORT_CONNECT_INDICATION:
TRACE_OUT(("LegacyTransportCallback::TRANSPORT_CONNECT_INDICATION"));
{
LegacyTransportID *pID = (LegacyTransportID *) Param1;
p = ::GetPluggableConnection(pID->hCommLink);
if (NULL != p)
{
p->SetLegacyHandle(pID->logical_handle);
{
PSocket pSocket = p->GetSocket();
ASSERT(NULL != pSocket);
if (NULL != pSocket)
{
pSocket->State = SOCKET_CONNECTED;
wParam = MAKE_PLUGXPRT_WPARAM(p->GetConnID(), TRANSPORT_TYPE_PLUGGABLE_PSTN);
fPostMsg = TRUE;
}
}
}
}
break;
case TRANSPORT_CONNECT_CONFIRM:
TRACE_OUT(("LegacyTransportCallback::TRANSPORT_CONNECT_CONFIRM"));
{
LegacyTransportID *pID = (LegacyTransportID *) Param1;
p = ::GetPluggableConnection(pID->hCommLink);
if (NULL != p)
{
ASSERT(p->GetLegacyHandle() == pID->logical_handle);
{
PSocket pSocket = p->GetSocket();
ASSERT(NULL != pSocket);
if (NULL != pSocket)
{
pSocket->State = X224_CONNECTED;
wParam = MAKE_PLUGXPRT_WPARAM(p->GetConnID(), TRANSPORT_TYPE_PLUGGABLE_PSTN);
fPostMsg = TRUE;
}
}
}
}
break;
case TRANSPORT_DISCONNECT_INDICATION:
TRACE_OUT(("LegacyTransportCallback::TRANSPORT_DISCONNECT_INDICATION"));
{
LegacyTransportID *pID = (LegacyTransportID *) Param1;
TransportConnection XprtConn;
XprtConn.eType = TRANSPORT_TYPE_PLUGGABLE_PSTN;
p = ::GetPluggableConnectionByLegacyHandle(pID->logical_handle);
if (NULL != p)
{
XprtConn.nLogicalHandle = p->GetConnID();
}
::OnProtocolControl(XprtConn, PLUGXPRT_DISCONNECTED);
fPostMsg = FALSE;
}
break;
case TRANSPORT_DATA_INDICATION:
TRACE_OUT(("LegacyTransportCallback::TRANSPORT_DATA_INDICATION"));
{
//
// This piece of data does not have X.224 framing
//
LegacyTransportData *pData = (LegacyTransportData *) Param1;
TRACE_OUT(("LegacyTransportCallback::pbData=0x%x, cbDataSize=%d", pData->pbData, pData->cbDataSize));
if (NULL != g_Transport)
{
DBG_SAVE_FILE_LINE
TransportData *td = new TransportData;
if (NULL != td)
{
td->transport_connection.eType = TRANSPORT_TYPE_PLUGGABLE_PSTN;
p = ::GetPluggableConnectionByLegacyHandle(pData->logical_handle);
if (NULL != p)
{
ULONG cbTotalSize = PROTOCOL_OVERHEAD_X224 + pData->cbDataSize;
td->transport_connection.nLogicalHandle = p->GetConnID();
DBG_SAVE_FILE_LINE
td->memory = ::AllocateMemory(NULL, cbTotalSize, RECV_PRIORITY);
if (NULL != td->memory)
{
td->user_data = td->memory->GetPointer();
td->user_data_length = cbTotalSize;
// take care of the X.224 header
::CopyMemory(td->user_data, g_X224Header, PROTOCOL_OVERHEAD_X224);
AddRFCSize(td->user_data, cbTotalSize);
// take care of the data
::CopyMemory(td->user_data + PROTOCOL_OVERHEAD_X224, pData->pbData, pData->cbDataSize);
wParam = (WPARAM) td;
fPostMsg = TRUE;
}
else
{
ERROR_OUT(("LegacyTransportCallback: failed to allocate memory, size=%d", cbTotalSize));
}
}
}
else
{
ERROR_OUT(("LegacyTransportCallback: failed to allocate TransportData"));
}
}
}
break;
default:
wParam = (WPARAM) Param1;
fPostMsg = TRUE;
break;
}
if (fPostMsg)
{
BOOL fRet = ::PostMessage(TCP_Window_Handle, WM_PLUGGABLE_PSTN, wParam, nMsg);
ASSERT(fRet);
}
}
return TRANSPORT_NO_ERROR;
}
void HandlePSTNCallback(WPARAM wParam, LPARAM lParam)
{
if (NULL != g_pPluggableTransport)
{
CPluggableConnection *p;
switch (lParam)
{
case TRANSPORT_CONNECT_INDICATION:
TRACE_OUT(("HandlePSTNCallback::TRANSPORT_CONNECT_INDICATION"));
if (NULL != g_Transport)
{
TransportConnection XprtConn;
XprtConn.nLogicalHandle = PLUGXPRT_WPARAM_TO_ID(wParam);
XprtConn.eType = (TransportType) PLUGXPRT_WPARAM_TO_TYPE(wParam);
::OnProtocolControl(XprtConn, PLUGXPRT_CONNECTED);
g_Transport->ConnectIndication(XprtConn);
}
break;
case TRANSPORT_CONNECT_CONFIRM:
TRACE_OUT(("HandlePSTNCallback::TRANSPORT_CONNECT_CONFIRM"));
if (NULL != g_Transport)
{
TransportConnection XprtConn;
XprtConn.nLogicalHandle = PLUGXPRT_WPARAM_TO_ID(wParam);
XprtConn.eType = (TransportType) PLUGXPRT_WPARAM_TO_TYPE(wParam);
::OnProtocolControl(XprtConn, PLUGXPRT_CONNECTED);
g_Transport->ConnectConfirm(XprtConn);
}
break;
case TRANSPORT_DATA_INDICATION:
TRACE_OUT(("HandlePSTNCallback::TRANSPORT_DATA_INDICATION"));
{
TransportData *td = (TransportData *) wParam;
if (NULL != g_Transport)
{
g_Transport->DataIndication(td);
}
delete td;
}
break;
case TRANSPORT_BUFFER_EMPTY_INDICATION:
TRACE_OUT(("HandlePSTNCallback::TRANSPORT_BUFFER_EMPTY_INDICATION"));
{
LEGACY_HANDLE logical_handle = (LEGACY_HANDLE) wParam;
TransportConnection XprtConn;
XprtConn.eType = TRANSPORT_TYPE_PLUGGABLE_PSTN;
p = ::GetPluggableConnectionByLegacyHandle(logical_handle);
if (NULL != p)
{
XprtConn.nLogicalHandle = p->GetConnID();
g_Transport->BufferEmptyIndication(XprtConn);
}
}
break;
default:
ERROR_OUT(("HandlePSTNCallback: unknown message=%d", lParam));
break;
}
}
}
BOOL CPluggableTransport::EnsureLegacyTransportLoaded(void)
{
if (NULL == g_pLegacyTransport)
{
g_hlibMST123 = ::LoadLibrary("MST123.DLL");
if (NULL != g_hlibMST123)
{
LPFN_T123_CreateTransportInterface pfn = (LPFN_T123_CreateTransportInterface)
::GetProcAddress(g_hlibMST123, LPSTR_T123_CreateTransportInterface);
if (NULL != pfn)
{
TransportError rc = (*pfn)(&g_pLegacyTransport);
if (TRANSPORT_NO_ERROR == rc)
{
ASSERT(NULL != g_pLegacyTransport);
// start to call initialize
rc = g_pLegacyTransport->TInitialize(LegacyTransportCallback, this);
ASSERT(TRANSPORT_NO_ERROR == rc);
if (TRANSPORT_NO_ERROR == rc)
{
return TRUE;
}
g_pLegacyTransport->TCleanup();
g_pLegacyTransport->ReleaseInterface();
g_pLegacyTransport = NULL;
}
}
::FreeLibrary(g_hlibMST123);
g_hlibMST123 = NULL;
}
return FALSE;
}
return TRUE;
}
TransportError CPluggableConnection::TConnectRequest(void)
{
TRACE_OUT(("CPluggableConnection::TConnectRequest"));
TransportError rc = TRANSPORT_NO_PLUGGABLE_CONNECTION;
if (NULL != g_pLegacyTransport)
{
TransportConnection XprtConn;
XprtConn.eType = m_eType;
XprtConn.nLogicalHandle = m_nConnID;
::OnProtocolControl(XprtConn, PLUGXPRT_CONNECTING);
rc = g_pLegacyTransport->TConnectRequest(&m_nLegacyLogicalHandle, m_hCommLink);
}
return rc;
}
TransportError CPluggableConnection::TDisconnectRequest(void)
{
TRACE_OUT(("CPluggableConnection::TDisconnectRequest"));
TransportError rc = TRANSPORT_NO_PLUGGABLE_CONNECTION;
if (NULL != g_pLegacyTransport)
{
TransportConnection XprtConn;
XprtConn.eType = m_eType;
XprtConn.nLogicalHandle = m_nConnID;
::OnProtocolControl(XprtConn, PLUGXPRT_DISCONNECTING);
::Sleep(600);
rc = g_pLegacyTransport->TDisconnectRequest(m_nLegacyLogicalHandle, TRUE);
}
return rc;
}
int CPluggableConnection::TDataRequest(LPBYTE pbData, ULONG cbDataSize, PLUGXPRT_RESULT *plug_rc)
{
TRACE_OUT(("CPluggableConnection::TDataRequest, pbData=0x%x, cbDataSize=%d", pbData, cbDataSize));
if (NULL != g_pLegacyTransport)
{
*plug_rc = PLUGXPRT_RESULT_SUCCESSFUL;
// skip X.224 framing
ASSERT(cbDataSize > PROTOCOL_OVERHEAD_X224);
TransportError rc;
rc = g_pLegacyTransport->TDataRequest(m_nLegacyLogicalHandle,
pbData + PROTOCOL_OVERHEAD_X224,
cbDataSize - PROTOCOL_OVERHEAD_X224);
if (TRANSPORT_NO_ERROR == rc)
{
TRACE_OUT(("CPluggableConnection::TDataRequest: sent data size=%d", cbDataSize));
return cbDataSize;
}
}
else
{
*plug_rc = PLUGXPRT_RESULT_WRITE_FAILED;
}
return SOCKET_ERROR;
}
TransportError TReceiveBufferAvailable(void)
{
TRACE_OUT(("CPluggableConnection::TReceiveBufferAvailable"));
TransportError rc = TRANSPORT_NO_PLUGGABLE_CONNECTION;
if (NULL != g_pLegacyTransport)
{
rc = g_pLegacyTransport->TReceiveBufferAvailable();
}
return rc;
}
TransportError CPluggableConnection::TPurgeRequest(void)
{
TRACE_OUT(("CPluggableConnection::TPurgeRequest"));
TransportError rc = TRANSPORT_NO_PLUGGABLE_CONNECTION;
if (NULL != g_pLegacyTransport)
{
rc = g_pLegacyTransport->TPurgeRequest(m_nLegacyLogicalHandle);
}
return rc;
}