#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; }