498 lines
14 KiB
C++
498 lines
14 KiB
C++
#include "mbftpch.h"
|
|
|
|
#if defined(TEST_PLUGABLE) && defined(_DEBUG)
|
|
|
|
#include "plugable.h"
|
|
#include "iplgxprt.h"
|
|
#include "it120xprt.h"
|
|
#include "nullmdm.h"
|
|
|
|
extern HINSTANCE g_hDllInst;
|
|
|
|
#define PLUGABLE_PORT_NUMBER 522 // ULS server port number
|
|
|
|
IT120PluggableTransport *g_pPluggableTransport = NULL;
|
|
|
|
#ifdef USE_SOCKET
|
|
SOCKET g_hListenSocket = INVALID_SOCKET;
|
|
#endif
|
|
|
|
|
|
typedef struct
|
|
{
|
|
LPSTR pszHostName;
|
|
#ifdef USE_SOCKET
|
|
SOCKET hSocket;
|
|
#else
|
|
CNullModem *pModem;
|
|
#endif
|
|
HANDLE hevtRead;
|
|
HANDLE hevtWrite;
|
|
HANDLE hevtClose;
|
|
char szConnID[64];
|
|
}
|
|
HOST_INFO;
|
|
|
|
#define NUM_HOSTS 2
|
|
#define TOP_PROVIDER_ID 0
|
|
|
|
ULONG g_nMyHostID = (ULONG) -1;
|
|
HOST_INFO g_aHostInfo[NUM_HOSTS];
|
|
|
|
char g_szMyHostName[64];
|
|
|
|
PLUGXPRT_PARAMETERS g_PluggableParams;
|
|
|
|
#ifdef USE_SOCKET
|
|
SOCKET CreateListenSocket(HWND hwnd);
|
|
SOCKET CreateConnectSocket(HWND hwnd, LPSTR pszHostName);
|
|
#else
|
|
CNullModem * CreateListenModem(void);
|
|
void CloseListenModem(CNullModem *p);
|
|
CNullModem * CreateConnectModem(LPSTR pszHostName);
|
|
void CloseConnectModem(CNullModem *p);
|
|
#endif
|
|
|
|
|
|
void OnPluggableBegin(HWND hwnd)
|
|
{
|
|
#ifdef USE_SOCKET
|
|
WSADATA wsa_data;
|
|
WORD version_requested = MAKEWORD (1,1);
|
|
int error = ::WSAStartup(version_requested, &wsa_data);
|
|
ASSERT(error == 0);
|
|
g_hListenSocket = INVALID_SOCKET;
|
|
#endif
|
|
|
|
::ZeroMemory(g_aHostInfo, sizeof(g_aHostInfo));
|
|
g_aHostInfo[0].pszHostName = "lonchanc";
|
|
g_aHostInfo[1].pszHostName = "lon1";
|
|
// g_aHostInfo[2].pszHostName = "lonchanc_nt";
|
|
for (ULONG i = 0; i < NUM_HOSTS; i++)
|
|
{
|
|
g_aHostInfo[i].szConnID[0] = '\0';
|
|
#ifdef USE_SOCKET
|
|
g_aHostInfo[i].hSocket = INVALID_SOCKET;
|
|
#else
|
|
g_aHostInfo[i].pModem = NULL;
|
|
#endif
|
|
g_aHostInfo[i].hevtRead = ::CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
g_aHostInfo[i].hevtWrite = ::CreateEvent(NULL, FALSE, FALSE, NULL);;
|
|
g_aHostInfo[i].hevtClose = ::CreateEvent(NULL, FALSE, FALSE, NULL);;
|
|
ASSERT(g_aHostInfo[i].hevtRead && g_aHostInfo[i].hevtWrite && g_aHostInfo[i].hevtClose);
|
|
}
|
|
|
|
T120Error rc = ::T120_CreatePluggableTransport(&g_pPluggableTransport);
|
|
ASSERT(T120_NO_ERROR == rc);
|
|
|
|
g_pPluggableTransport->ResetConnCounter();
|
|
g_pPluggableTransport->DisableWinsock();
|
|
|
|
gethostname(g_szMyHostName, 64);
|
|
TRACE_OUT(("OnPluggableScript: HostName=%s", g_szMyHostName));
|
|
for (i = 0; i < NUM_HOSTS; i++)
|
|
{
|
|
if (! ::lstrcmpi(g_aHostInfo[i].pszHostName, g_szMyHostName))
|
|
{
|
|
g_nMyHostID = i;
|
|
break;
|
|
}
|
|
}
|
|
ASSERT(i < NUM_HOSTS);
|
|
ASSERT(g_nMyHostID < NUM_HOSTS);
|
|
|
|
::ZeroMemory(&g_PluggableParams, sizeof(g_PluggableParams));
|
|
g_PluggableParams.cbStructSize = sizeof(g_PluggableParams);
|
|
g_PluggableParams.dwFlags = PSTN_PARAM__CALL_CONTROL |
|
|
PSTN_PARAM__READ_FILE_BUFFER_SIZE |
|
|
PSTN_PARAM__PHYSICAL_LAYER_SEND_BUFFER_SIZE |
|
|
PSTN_PARAM__PHSYICAL_LAYER_RECV_BUFFER_SIZE |
|
|
PSTN_PARAM__MAX_T200_TIMEOUT_COUNT_IN_Q922 |
|
|
PSTN_PARAM__T203_TIMEOUT_IN_Q922;
|
|
g_PluggableParams.eCallControl = PLUGXPRT_PSTN_CALL_CONTROL_MANUAL;
|
|
g_PluggableParams.cbReadFileBufferSize = 10240; // 10K
|
|
g_PluggableParams.cbPhysicalLayerSendBufferSize = 1024; // 1K
|
|
g_PluggableParams.cbPhysicalLayerReceiveBufferSize = 10240; // 10K
|
|
g_PluggableParams.cMaximumT200TimeoutsInQ922 = 5;
|
|
g_PluggableParams.nT203TimeoutInQ922 = 600;
|
|
|
|
if (TOP_PROVIDER_ID == g_nMyHostID)
|
|
{
|
|
for (i = 0; i < NUM_HOSTS; i++)
|
|
{
|
|
if (i != g_nMyHostID)
|
|
{
|
|
#ifdef USE_SOCKET
|
|
g_aHostInfo[i].hSocket = ::CreateConnectSocket(hwnd, g_aHostInfo[i].pszHostName);
|
|
ASSERT(INVALID_SOCKET != g_aHostInfo[i].hSocket);
|
|
#else
|
|
g_aHostInfo[i].pModem = ::CreateConnectModem(g_aHostInfo[i].pszHostName);
|
|
ASSERT(NULL != g_aHostInfo[i].pModem);
|
|
#endif
|
|
|
|
HANDLE hCommLink = NULL;
|
|
#ifdef USE_SOCKET
|
|
BOOL fRet = ::DuplicateHandle(::GetCurrentProcess(), (HANDLE) g_aHostInfo[i].hSocket,
|
|
#else
|
|
BOOL fRet = ::DuplicateHandle(::GetCurrentProcess(), g_aHostInfo[i].pModem->GetCommLink(),
|
|
#endif
|
|
::GetCurrentProcess(), &hCommLink,
|
|
0, FALSE, DUPLICATE_SAME_ACCESS);
|
|
ASSERT(fRet);
|
|
|
|
rc = g_pPluggableTransport->CreateConnection(
|
|
g_aHostInfo[i].szConnID,
|
|
PLUGXPRT_CALLER, // caller
|
|
hCommLink,
|
|
g_aHostInfo[i].hevtRead,
|
|
g_aHostInfo[i].hevtWrite,
|
|
g_aHostInfo[i].hevtClose,
|
|
FRAMING_LEGACY_PSTN,
|
|
&g_PluggableParams);
|
|
ASSERT(T120_NO_ERROR == rc);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#ifdef USE_SOCKET
|
|
g_hListenSocket = ::CreateListenSocket(hwnd);
|
|
#else
|
|
g_aHostInfo[i].pModem = ::CreateListenModem();
|
|
ASSERT(NULL != g_aHostInfo[i].pModem);
|
|
|
|
HANDLE hCommLink = NULL;
|
|
BOOL fRet = ::DuplicateHandle(::GetCurrentProcess(), g_aHostInfo[i].pModem->GetCommLink(),
|
|
::GetCurrentProcess(), &hCommLink,
|
|
0, FALSE, DUPLICATE_SAME_ACCESS);
|
|
ASSERT(fRet);
|
|
|
|
T120Error rc = g_pPluggableTransport->CreateConnection(
|
|
g_aHostInfo[i].szConnID,
|
|
PLUGXPRT_CALLEE, // callee
|
|
hCommLink,
|
|
g_aHostInfo[i].hevtRead,
|
|
g_aHostInfo[i].hevtWrite,
|
|
g_aHostInfo[i].hevtClose,
|
|
FRAMING_LEGACY_PSTN,
|
|
&g_PluggableParams);
|
|
ASSERT(T120_NO_ERROR == rc);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
|
|
void OnPluggableEnd(void)
|
|
{
|
|
#ifdef USE_SOCKET
|
|
if (INVALID_SOCKET != g_hListenSocket)
|
|
{
|
|
::closesocket(g_hListenSocket);
|
|
}
|
|
for (ULONG i = 0; i < NUM_HOSTS; i++)
|
|
{
|
|
if (INVALID_SOCKET != g_aHostInfo[i].hSocket)
|
|
{
|
|
::closesocket(g_aHostInfo[i].hSocket);
|
|
}
|
|
}
|
|
#else
|
|
for (ULONG i = 0; i < NUM_HOSTS; i++)
|
|
{
|
|
if (i != g_nMyHostID)
|
|
{
|
|
CloseConnectModem(g_aHostInfo[i].pModem);
|
|
}
|
|
else
|
|
{
|
|
CloseListenModem(g_aHostInfo[i].pModem);
|
|
}
|
|
g_aHostInfo[i].pModem = NULL;
|
|
}
|
|
|
|
#endif
|
|
|
|
g_pPluggableTransport->EnableWinsock();
|
|
g_pPluggableTransport->ReleaseInterface();
|
|
g_pPluggableTransport = NULL;
|
|
|
|
#ifdef USE_SOCKET
|
|
::WSACleanup();
|
|
#endif
|
|
}
|
|
|
|
|
|
LRESULT OnPluggableSocket(HWND hwnd, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
#ifdef USE_SOCKET
|
|
/* This message is generated by WinSock */
|
|
SOCKET hSocket = (SOCKET) wParam;
|
|
ULONG event = WSAGETSELECTEVENT(lParam);
|
|
ULONG error = WSAGETSELECTERROR(lParam);
|
|
ULONG nIdx = (ULONG) -1;
|
|
|
|
if (hSocket != g_hListenSocket)
|
|
{
|
|
for (ULONG i = 0; i < NUM_HOSTS; i++)
|
|
{
|
|
if (hSocket == g_aHostInfo[i].hSocket)
|
|
{
|
|
nIdx = i;
|
|
break;
|
|
}
|
|
}
|
|
ASSERT(nIdx < NUM_HOSTS);
|
|
}
|
|
else
|
|
{
|
|
nIdx = TOP_PROVIDER_ID;
|
|
}
|
|
|
|
/* We disconnect whenever a socket command generates an error message */
|
|
if (error)
|
|
{
|
|
TRACE_OUT(("OnPluggableSocket: error %d on socket (%d). Event: %d", error, hSocket, event));
|
|
}
|
|
|
|
/* We get FD_CLOSE when the socket is closed by the remote site. */
|
|
if (event & FD_CLOSE)
|
|
{
|
|
TRACE_OUT(("OnPluggableSocket FD_CLOSE(%d)", hSocket));
|
|
::SetEvent(g_aHostInfo[nIdx].hevtClose);
|
|
}
|
|
|
|
/* We get FD_READ when there is data available for us to read. */
|
|
if (event & FD_READ)
|
|
{
|
|
TRACE_OUT(("OnPluggableSocket FD_READ(%d)", hSocket));
|
|
::SetEvent(g_aHostInfo[nIdx].hevtRead);
|
|
}
|
|
|
|
/* We get FD_WRITE when there is space available to write data to WinSock */
|
|
if (event & FD_WRITE)
|
|
{
|
|
TRACE_OUT(("OnPluggableSocket FD_WRITE(%d)", hSocket));
|
|
::SetEvent(g_aHostInfo[nIdx].hevtWrite);
|
|
}
|
|
|
|
/* We get FD_CONNECT when connecting to a remote site */
|
|
if (event & FD_CONNECT)
|
|
{
|
|
TRACE_OUT(("OnPluggableSocket FD_CONNECT(%d)", hSocket));
|
|
// ::SetEvent(g_aHostInfo[nIdx].hevtWrite);
|
|
}
|
|
|
|
/* We get FD_ACCEPT when a remote site is connecting with us */
|
|
if (event & FD_ACCEPT)
|
|
{
|
|
TRACE_OUT(("OnPluggableSocket FD_ACCEPT(%d)", hSocket));
|
|
ASSERT(nIdx == TOP_PROVIDER_ID);
|
|
|
|
SOCKADDR_IN socket_control;
|
|
int size = sizeof(socket_control);
|
|
g_aHostInfo[nIdx].hSocket = ::accept(g_hListenSocket, (struct sockaddr *) &socket_control, &size);
|
|
ASSERT(INVALID_SOCKET != g_aHostInfo[nIdx].hSocket);
|
|
|
|
int nRet = ::WSAAsyncSelect(g_aHostInfo[nIdx].hSocket, hwnd,
|
|
WM_PLUGABLE_SOCKET,
|
|
FD_READ | FD_WRITE | FD_CLOSE | FD_CONNECT);
|
|
ASSERT(SOCKET_ERROR != nRet);
|
|
|
|
HANDLE hCommLink = NULL;
|
|
BOOL fRet = ::DuplicateHandle(::GetCurrentProcess(), (HANDLE) g_aHostInfo[nIdx].hSocket,
|
|
::GetCurrentProcess(), &hCommLink,
|
|
0, FALSE, DUPLICATE_SAME_ACCESS);
|
|
ASSERT(fRet);
|
|
|
|
T120Error rc = g_pPluggableTransport->CreateConnection(
|
|
g_aHostInfo[nIdx].szConnID,
|
|
PLUGXPRT_CALLEE, // callee
|
|
hCommLink,
|
|
g_aHostInfo[nIdx].hevtRead,
|
|
g_aHostInfo[nIdx].hevtWrite,
|
|
g_aHostInfo[nIdx].hevtClose,
|
|
FRAMING_LEGACY_PSTN,
|
|
&g_PluggableParams);
|
|
ASSERT(T120_NO_ERROR == rc);
|
|
|
|
// ::SetEvent(g_aHostInfo[nIdx].hevtWrite);
|
|
}
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* void CreateListenSocket (VOID)
|
|
*
|
|
* Functional Description
|
|
* This function sets up a listening socket.
|
|
* returns INVALID_SOCKET if there is any error.
|
|
*/
|
|
#ifdef USE_SOCKET
|
|
SOCKET CreateListenSocket(HWND hwnd)
|
|
{
|
|
SOCKADDR_IN socket_control;
|
|
SOCKET socket_number;
|
|
|
|
// Create the listening socket.
|
|
socket_number = ::socket(AF_INET, SOCK_STREAM, 0);
|
|
ASSERT(INVALID_SOCKET != socket_number);
|
|
|
|
// The listen socket only waits for FD_ACCEPT msgs.
|
|
int nRet = ::WSAAsyncSelect(socket_number, hwnd, WM_PLUGABLE_SOCKET, FD_ACCEPT);
|
|
ASSERT(SOCKET_ERROR != nRet);
|
|
|
|
/*
|
|
* Load the socket control structure with the parameters necessary.
|
|
* - Internet socket
|
|
* - Let it assign any address to this socket
|
|
* - Assign our port number
|
|
*/
|
|
socket_control.sin_family = AF_INET;
|
|
socket_control.sin_addr.s_addr = INADDR_ANY;
|
|
socket_control.sin_port = htons ( PLUGABLE_PORT_NUMBER );
|
|
|
|
/* Issue the bind call */
|
|
nRet = ::bind(socket_number, (LPSOCKADDR) &socket_control, sizeof(SOCKADDR_IN));
|
|
ASSERT(SOCKET_ERROR != nRet);
|
|
|
|
/*
|
|
* Issue a listen to WinSock to tell it we are willing to accept calls.
|
|
* This is a non-blocking listen, therefore we will receive FD_ACCEPT
|
|
* if someone is trying to call us.
|
|
*/
|
|
nRet =::listen(socket_number, 3 /* LISTEN_QUEUE_SIZE */);
|
|
ASSERT(SOCKET_ERROR != nRet);
|
|
|
|
return socket_number;
|
|
}
|
|
#else
|
|
CNullModem * CreateListenModem(void)
|
|
{
|
|
DBG_SAVE_FILE_LINE
|
|
CNullModem *p = new CNullModem(g_hDllInst);
|
|
ASSERT(NULL != p);
|
|
|
|
TPhysicalError rc;
|
|
|
|
rc = p->TPhysInitialize(NULL, 1);
|
|
ASSERT(TPHYS_SUCCESS == rc);
|
|
|
|
rc = p->TPhysConnectRequest("COM1");
|
|
ASSERT(TPHYS_SUCCESS == rc);
|
|
|
|
rc = p->TPhysListen();
|
|
ASSERT(TPHYS_SUCCESS == rc);
|
|
|
|
return p;
|
|
}
|
|
void CloseListenModem(CNullModem *p)
|
|
{
|
|
if (NULL != p)
|
|
{
|
|
TPhysicalError rc;
|
|
|
|
rc = p->TPhysUnlisten();
|
|
ASSERT(TPHYS_SUCCESS == rc);
|
|
|
|
rc = p->TPhysDisconnect();
|
|
ASSERT(TPHYS_SUCCESS == rc);
|
|
|
|
rc = p->TPhysTerminate();
|
|
ASSERT(TPHYS_SUCCESS == rc);
|
|
|
|
delete p;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
#ifdef USE_SOCKET
|
|
SOCKET CreateConnectSocket(HWND hwnd, LPSTR pszHostName)
|
|
{
|
|
SOCKET socket_number;
|
|
u_short uPort = PLUGABLE_PORT_NUMBER;
|
|
PHOSTENT phe = NULL;
|
|
SOCKADDR_IN socket_control;
|
|
DWORD dwIPAddress;
|
|
|
|
socket_number = ::socket(AF_INET, SOCK_STREAM, 0);
|
|
ASSERT(INVALID_SOCKET != socket_number);
|
|
|
|
/* Enable Tx and Rx messages to the window */
|
|
int nRet = ::WSAAsyncSelect(socket_number, hwnd, WM_PLUGABLE_SOCKET,
|
|
FD_READ | FD_WRITE | FD_CLOSE);
|
|
ASSERT(SOCKET_ERROR != nRet);
|
|
|
|
// fill in other info in SockAddr
|
|
::ZeroMemory(&socket_control, sizeof(socket_control));
|
|
socket_control.sin_family = AF_INET;
|
|
socket_control.sin_port = htons (PLUGABLE_PORT_NUMBER);
|
|
|
|
// get server's IP address
|
|
dwIPAddress = ::inet_addr(pszHostName);
|
|
if (dwIPAddress != INADDR_NONE)
|
|
{
|
|
*((PDWORD) &socket_control.sin_addr) = dwIPAddress;
|
|
}
|
|
else
|
|
{
|
|
phe = ::gethostbyname(pszHostName);
|
|
ASSERT(NULL != phe);
|
|
|
|
::CopyMemory(&socket_control.sin_addr, phe->h_addr, phe->h_length);
|
|
}
|
|
|
|
/* Attempt a connection to the remote site */
|
|
nRet = ::connect(socket_number, (const struct sockaddr *) &socket_control, sizeof(socket_control));
|
|
ASSERT(SOCKET_ERROR != nRet || WSAEWOULDBLOCK == ::WSAGetLastError());
|
|
|
|
return socket_number;
|
|
}
|
|
#else
|
|
CNullModem * CreateConnectModem(LPSTR pszHostName)
|
|
{
|
|
DBG_SAVE_FILE_LINE
|
|
CNullModem *p = new CNullModem(g_hDllInst);
|
|
ASSERT(NULL != p);
|
|
|
|
TPhysicalError rc;
|
|
|
|
rc = p->TPhysInitialize(NULL, 1);
|
|
ASSERT(TPHYS_SUCCESS == rc);
|
|
|
|
rc = p->TPhysConnectRequest("COM1");
|
|
ASSERT(TPHYS_SUCCESS == rc);
|
|
|
|
rc = p->TPhysListen();
|
|
ASSERT(TPHYS_SUCCESS == rc);
|
|
|
|
return p;
|
|
}
|
|
void CloseConnectModem(CNullModem *p)
|
|
{
|
|
if (NULL != p)
|
|
{
|
|
TPhysicalError rc;
|
|
|
|
rc = p->TPhysUnlisten();
|
|
ASSERT(TPHYS_SUCCESS == rc);
|
|
|
|
rc = p->TPhysDisconnect();
|
|
ASSERT(TPHYS_SUCCESS == rc);
|
|
|
|
rc = p->TPhysTerminate();
|
|
ASSERT(TPHYS_SUCCESS == rc);
|
|
|
|
delete p;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
#endif // TEST_PLUGABLE
|
|
|