You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1903 lines
54 KiB
1903 lines
54 KiB
#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 = NmLoadLibrary("kernel32.dll",TRUE);
|
|
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, TRUE))
|
|
{
|
|
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: GetPluggableConnectionByLegacyHandle failed" ));
|
|
delete td;
|
|
}
|
|
}
|
|
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 = NmLoadLibrary("MST123.DLL",FALSE);
|
|
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;
|
|
}
|
|
|
|
|
|
|