Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

900 lines
29 KiB

#include "mbftpch.h"
#include "nullmdm.h"
// #undef TRACE_OUT
// #define TRACE_OUT WARNING_OUT
BYTE g_szNULLMStartString[] = "NULLMDM";
ULONG g_nConnID = 0;
DWORD __stdcall TPhysWorkerThreadProc(void *lpv);
CNullModem::CNullModem(HINSTANCE hDllInst)
:
m_fInitialized(FALSE),
m_hDllInst(hDllInst),
m_pfnCallback(NULL),
m_fListening(FALSE),
m_hwnd(NULL),
m_nTransportID(0),
m_nConnectionID(0),
m_dwThreadID(0),
m_hThread(NULL),
m_hevtOverlapped(NULL),
m_dwEventMask(0),
m_fCommPortInUse(FALSE)
{
::ZeroMemory(&m_Line, sizeof(m_Line));
::ZeroMemory(&m_Overlapped, sizeof(m_Overlapped));
::ZeroMemory(&m_DefaultTimeouts, sizeof(m_DefaultTimeouts));
m_hevtOverlapped = ::CreateEvent(NULL, TRUE, FALSE, NULL); // manual reset
ASSERT(NULL != m_hevtOverlapped);
}
CNullModem::~CNullModem(void)
{
if (m_fInitialized)
{
TPhysTerminate();
}
if (NULL != m_hevtOverlapped)
{
::CloseHandle(m_hevtOverlapped);
}
}
//////////////////////////////////////////////////////////////////////////////
// TPhysInitialize
//////////////////////////////////////////////////////////////////////////////
TPhysicalError CNullModem::TPhysInitialize
(
TPhysCallback callback,
UINT nTransportID
)
{
const char *pszNULLMClassName = "COMMWndClass";
TPhysicalError rc = TPHYS_SUCCESS;
TRACE_OUT(("TPhysInitialize"));
//
// If we have already been initialized then this is a reinit call from
// the node controller so just do nothing.
//
if (! m_fInitialized)
{
//
// zero out the SESSION INFO structure
//
::ZeroMemory(&m_Line, sizeof(m_Line));
//
// Store control information
//
m_pfnCallback = callback;
m_nTransportID = nTransportID;
m_fInitialized = TRUE;
m_nConnectionID = ++g_nConnID;
//
// Create a window so we can decouple to the node controller context
// Register the main window class. Since it is invisible, leave
// the wndclass structure sparse.
//
WNDCLASS wc;
::ZeroMemory(&wc, sizeof(wc));
wc.style = 0;
wc.lpfnWndProc = TPhysWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = m_hDllInst;
wc.hIcon = NULL;
wc.hCursor = NULL;
wc.hbrBackground = NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName = pszNULLMClassName;
::RegisterClass(&wc);
//
// Create the main window.
//
m_hwnd = ::CreateWindow(
pszNULLMClassName, // See RegisterClass() call.
NULL, // It's invisible!
0, // Window style.
0, // Default horizontal position.
0, // Default vertical position.
0, // Default width.
0, // Default height.
NULL, // No parent.
NULL, // No menu.
m_hDllInst, // This instance owns this window.
NULL // Pointer not needed.
);
if (NULL == m_hwnd)
{
ERROR_OUT(( "Failed to create wnd"));
return(TPHYS_RESULT_FAIL);
}
// rc = g_lpfnPTPhysicalInit(TPhysDriverCallback, NULL);
ASSERT(TPHYS_SUCCESS == rc);
}
return rc;
}
//////////////////////////////////////////////////////////////////////////////////
// TPhysTerminate
//
// The node controller is shutting down
// Destroy our window and clean up transports.
//////////////////////////////////////////////////////////////////////////////////
TPhysicalError CNullModem::TPhysTerminate(void)
{
TRACE_OUT(("TPhysTerminate"));
if (! m_fInitialized)
{
return(TPHYS_RESULT_NOT_INITIALIZED);
}
//
// Clean up the PSTN transport
//
// g_lpfnPTPhysicalCleanup();
//
// Destroy the window
//
if (NULL != m_hwnd)
{
::DestroyWindow(m_hwnd);
m_hwnd = NULL;
}
m_pfnCallback = NULL;
m_nTransportID = 0;
m_fInitialized = FALSE;
return(TPHYS_SUCCESS);
}
//////////////////////////////////////////////////////////////////////////////
// TPhysConnectRequest
//
// The node controller wants to place a call and has determined that it
// first needs a physical modem connection. Make a call and flag an
// outgoing call so that when the call comes active we can tell the modem
// transport to begin negotiation.
//////////////////////////////////////////////////////////////////////////////
TPhysicalError CNullModem::TPhysConnectRequest(LPSTR pszComPort)
{
TPhysicalError rc = TPHYS_SUCCESS;
HANDLE hCommLink;
DCB dcb;
DWORD dwWritten;
TRACE_OUT(("TPhysConnectRequest"));
if (! m_fInitialized)
{
ERROR_OUT(("NULL MODEM OOB not initialized"));
return TPHYS_RESULT_NOT_INITIALIZED;
}
//
// Select a comm port for the call.
//
if (CALL_STATE_IDLE == m_Line.eCallState || CALL_STATE_DROP == m_Line.eCallState)
{
//
// Also prime our local copy of the conninfo structure for use in callbacks
//
m_Line.connInfo.resultCode = 0;
m_Line.connInfo.connectionID = m_nConnectionID;
}
else
{
ERROR_OUT(("No comm port is available"));
return TPHYS_RESULT_COMM_PORT_BUSY;
}
// lonchanc: From now on, we can bail out thru the common exit point
// because the cleanup checks for m_fCommPortInUse.
//
// Only alow one at at time
//
// lonchanc: g_COMM_Thread_Users is starting from -1
// why can we simply use a flag???
if (m_fCommPortInUse)
{
ERROR_OUT(("TPhysConnectRequest: Waiting for a previous null mode connection"));
rc = TPHYS_RESULT_WAITING_FOR_CONNECTION;
goto bail;
}
m_fCommPortInUse = TRUE;
//
// Open the comm port
//
hCommLink = ::CreateFile(pszComPort,
GENERIC_READ | GENERIC_WRITE,
0, // exclusive access
NULL, // no security attrs
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, // overlapped I/O
NULL );
if (hCommLink == INVALID_HANDLE_VALUE)
{
ERROR_OUT(("TPhysConnectRequest: CreateFile failed. err=%d", ::GetLastError()));
rc = TPHYS_RESULT_COMM_PORT_BUSY;
goto bail;
}
m_Line.hCommLink = hCommLink;
//
// remember the default timeouts
//
::GetCommTimeouts(hCommLink, &m_DefaultTimeouts);
//
// Let the other side know that we are trying to connect
//
if (! ::EscapeCommFunction(hCommLink, SETDTR))
{
ERROR_OUT(("TPhysConnectRequest: Unable to Set DTR: err=%d", ::GetLastError()));
}
::ZeroMemory(&m_Overlapped, sizeof(m_Overlapped));
m_Overlapped.hEvent = m_hevtOverlapped;
m_dwEventMask = 0;
::ResetEvent(m_hevtOverlapped);
if (! ::WriteFile(hCommLink, g_szNULLMStartString, sizeof(g_szNULLMStartString),
&dwWritten, &m_Overlapped))
{
DWORD dwErr = ::GetLastError();
if (ERROR_IO_PENDING != dwErr)
{
ERROR_OUT(("TPhysConnectRequest: WriteFile failed. err=%d", dwErr));
::ResetEvent(m_hevtOverlapped);
rc = TPHYS_RESULT_COMM_PORT_BUSY;
goto bail;
}
else
{
DWORD dwWait = ::WaitForSingleObject(m_hevtOverlapped, INFINITE);
BOOL fRet = ::GetOverlappedResult(hCommLink, &m_Overlapped, &dwWritten, TRUE);
ASSERT(fRet);
ASSERT(dwWritten == sizeof(g_szNULLMStartString));
}
}
else
{
ASSERT(dwWritten == sizeof(g_szNULLMStartString));
}
::ResetEvent(m_hevtOverlapped);
//
// Get the default dcb
//
::ZeroMemory(&dcb, sizeof(dcb));
::GetCommState(hCommLink, &dcb);
dcb.BaudRate = 19200; // Default: BaudRate
//
// Set our state so we can get notification in the comm port
//
dcb.DCBlength = sizeof(DCB);
dcb.fBinary = 1; // binary mode, no EOF check
dcb.fParity = 0; // enable parity checking
dcb.fOutxCtsFlow = 1; // CTS output flow control
dcb.fOutxDsrFlow = 0; // DSR output flow control
dcb.fDtrControl = DTR_CONTROL_ENABLE; // DTR flow control type
dcb.fDsrSensitivity = 0; // DSR sensitivity
dcb.fTXContinueOnXoff = 0; // XOFF continues Tx
dcb.fOutX = 0; // XON/XOFF out flow control
dcb.fInX = 0; // XON/XOFF in flow control
dcb.fErrorChar = 0; // enable error replacement
dcb.fNull = 0; // enable null stripping
dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;// RTS flow control
dcb.XonLim = 0; // transmit XON threshold
dcb.XoffLim = 0; // transmit XOFF threshold
dcb.fErrorChar = 0; // enable error replacement
dcb.fNull = 0; // enable null stripping
dcb.fAbortOnError = 0; // abort reads/writes on error
::SetCommState(hCommLink, &dcb);
::PurgeComm(hCommLink, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);
m_Line.eCallState = CALL_STATE_MAKE;
m_Line.hevtCall = m_hevtOverlapped;
m_Line.pstnHandle = (PHYSICAL_HANDLE) hCommLink;
m_Line.fCaller = TRUE;
if (! ::SetCommMask(hCommLink,
EV_RXCHAR | // Any Character received
EV_CTS | // CTS changed state
EV_DSR | // DSR changed state
EV_RLSD| // RLSD changed state
EV_RXFLAG)) // Certain character
{
ERROR_OUT(("TPhysConnectRequest: Unable to SetCommMask: err=%d", ::GetLastError()));
}
::ZeroMemory(&m_Overlapped, sizeof(m_Overlapped));
m_Overlapped.hEvent = m_hevtOverlapped;
m_dwEventMask = 0;
::ResetEvent(m_hevtOverlapped);
if (! ::WaitCommEvent(hCommLink, &m_dwEventMask, &m_Overlapped))
{
DWORD dwErr = ::GetLastError();
if (ERROR_IO_PENDING != dwErr)
{
ERROR_OUT(("TPhysConnectRequest: WaitCommEvent failed, err=%d", dwErr));
m_fCommPortInUse = FALSE;
}
}
#if 1
WorkerThreadProc();
#else
//
// If the comm thread doesn't exist, create it now.
//
// lonchanc: I am not sure that the thread will exist, because
// the while loop inside the thread will exit if m_fCommPortInUse is false.
// If m_fCommPortInUse is true, then we should bail out already.
//
ASSERT(NULL == m_hThread);
//
// We need to create another thread that will wait on comm events.
//
m_hThread = ::CreateThread(NULL, 0, TPhysWorkerThreadProc, this, 0, &m_dwThreadID);
ASSERT(NULL != m_hThread);
#endif
bail:
return(rc);
}
//////////////////////////////////////////////////////////////////////////////
// TPhysDisconnect
//
// The node controller wants us to bring the call down now. We must first
// ask the transports to close down their physicall connection.
//
// Note that in the case of the PSTN transport we use a NOWAIT call which
// completes syncronously. Because we will not get a follow on confirm
// we simulate one from here. If we switch to using WAIT mode then
// take the event generation code out!
//////////////////////////////////////////////////////////////////////////////
TPhysicalError CNullModem::TPhysDisconnect(void)
{
TRACE_OUT(("TPhysDisconnect"));
if (! m_fInitialized)
{
ERROR_OUT(( "Not initialised"));
return(TPHYS_RESULT_NOT_INITIALIZED);
}
TRACE_OUT(("Disconnect call, state %u", m_Line.eCallState));
//
// Otherwise it must be a pstn call in progress so end that. Note
// that NC may still think it is MODEM, but we still need to close
// PSTN.
//
// g_lpfnPTPhysicalDisconnectRequest(m_aLines[lineID].pstnHandle, TPHYSICAL_NO_WAIT);
::PostMessage(m_hwnd, WM_TPHYS_DISCONNECT_CONFIRM, (WPARAM) this, m_Line.pstnHandle);
//
// close the comport
//
DropCall();
return(TPHYS_SUCCESS);
}
//////////////////////////////////////////////////////////////////////////////
// TPhysListen/TPhysUnlisten
//
// NULLMMAN does very little with listen/unlisten, just sets a state variable
// that is interrogated to see if we should accept incoming calls.
//
// NOTE - This is different from the Listen/Unlisten that is used to tell
// the PSTN transport about the presence of an incoming call.
//////////////////////////////////////////////////////////////////////////////
TPhysicalError CNullModem::TPhysListen(void)
{
TRACE_OUT(("TPhysListen"));
if (! m_fInitialized)
{
ERROR_OUT(("TPhysListen: not initialized"));
return(TPHYS_RESULT_NOT_INITIALIZED);
}
m_fListening = TRUE;
return(TPHYS_SUCCESS);
}
TPhysicalError CNullModem::TPhysUnlisten(void)
{
TRACE_OUT(("TPhysUnlisten"));
if (! m_fInitialized)
{
ERROR_OUT(("TPhysUnlisten: not initialized"));
return(TPHYS_RESULT_NOT_INITIALIZED);
}
m_fListening = FALSE;
return(TPHYS_SUCCESS);
}
//////////////////////////////////////////////////////////////////////////////
// DropCall - close the comm port
/////////////////////////////////////////////////////////////////////////////
void CNullModem::DropCall(void)
{
TRACE_OUT(("DropCall"));
//
// close the device handle
//
if (NULL != m_Line.hCommLink)
{
CALL_STATE eCallState = m_Line.eCallState;
m_Line.eCallState = CALL_STATE_IDLE;
//
// If this call is connected it is not using the comm thread
//
if (eCallState != CALL_STATE_CONNECTED)
{
m_fCommPortInUse = FALSE;
}
//
// restore comm timeouts
//
SetCommTimeouts(m_Line.hCommLink, &m_DefaultTimeouts);
TRACE_OUT(("Closing device handle %x", m_Line.hCommLink));
::CloseHandle(m_Line.hCommLink);
m_Line.hCommLink = NULL;
}
}
//////////////////////////////////////////////////////////////////////////////
//
// FUNCTION: PSTNCallback
//
// DESCRIPTION:
//
// PSTN callback function, called by the PSTN driver with the resuts of
// TPhysical operations
//
// See MCATTPRT.H for definitions of the parameters
//
//////////////////////////////////////////////////////////////////////////////
TPhysicalError CALLBACK TPhysDriverCallback(USHORT msg, ULONG lParam, void *userData)
{
TRACE_OUT(("NULLM_PSTNCallback"));
TRACE_OUT(("Hit TPhysical callback, %x %lx %lx", msg, lParam, userData));
CNullModem *p = (CNullModem *) userData;
BOOL fRet = ::PostMessage(p->GetHwnd(), msg, (WPARAM) p, lParam);
ASSERT(fRet);
return TPHYS_SUCCESS;
}
//////////////////////////////////////////////////////////////////////////////
//
// FUNCTION:TPhysWndProc
//
// Window procedure used to decouple callback requests
//
//////////////////////////////////////////////////////////////////////////////
LRESULT CALLBACK TPhysWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
CNullModem *p = (CNullModem *) wParam;
if (uMsg >= WM_APP)
{
return p->TPhysProcessMessage(uMsg, lParam);
}
return ::DefWindowProc(hwnd, uMsg, wParam, lParam);
}
LRESULT CNullModem::TPhysProcessMessage(UINT uMsg, LPARAM lParam)
{
USHORT rc;
USHORT reason;
ULONG status;
LINE_INFO *pLine;
if (WM_TPHYS_STATUS_INDICATION == uMsg)
{
return 0;
}
ASSERT(lParam == (LPARAM) m_Line.pstnHandle);
switch (uMsg)
{
case WM_TPHYS_CONNECT_INDICATION:
TRACE_OUT(("got a WM_TPHYS_CONNECT_INDICATION"));
m_Line.connInfo.resultCode = TPHYS_RESULT_INUSE;
m_Line.eCallState = CALL_STATE_CONNECTED;
if (NULL != m_pfnCallback)
{
(*m_pfnCallback)(WM_TPHYS_CONNECT_CONFIRM, &m_Line.connInfo, m_nTransportID);
}
break;
case WM_TPHYS_CONNECT_CONFIRM:
//
// The transport has connected OK! We will take the line
// back when the transport pulls DTR down
//
TRACE_OUT(("got a WM_TPHYS_CONNECT_CONFIRM"));
m_Line.connInfo.resultCode = TPHYS_RESULT_SUCCESS_ALTERNATE;
m_Line.eCallState = CALL_STATE_CONNECTED;
if (NULL != m_pfnCallback)
{
(*m_pfnCallback)(WM_TPHYS_CONNECT_CONFIRM, &m_Line.connInfo, m_nTransportID);
}
break;
case WM_TPHYS_DISCONNECT_INDICATION:
case WM_TPHYS_DISCONNECT_CONFIRM:
//
// If the disconnect is the result of a failed connect request
// then tell the NC of the failure (Otherwise it is a
// successful disconnect)
//
if (WM_TPHYS_DISCONNECT_INDICATION == uMsg)
{
TRACE_OUT(("WM_TPHYS_DISCONNECT_INDICATION, %ld", lParam));
}
else
{
TRACE_OUT(("WM_TPHYS_DISCONNECT_CONFIRM, %ld", lParam));
}
if ((m_Line.eCallState == CALL_STATE_MAKE) ||
(m_Line.eCallState == CALL_STATE_ANSWER) ||
(m_Line.eCallState == CALL_STATE_CONNECTED))
{
TRACE_OUT(( "T120 connection attempt has failed"));
if (m_Line.fCaller)
{
m_Line.connInfo.resultCode = TPHYS_RESULT_CONNECT_FAILED;
if (NULL != m_pfnCallback)
{
(*m_pfnCallback)(WM_TPHYS_CONNECT_CONFIRM, &m_Line.connInfo, m_nTransportID);
}
}
DropCall();
}
else
{
//
// The transport has disconnected OK. We can take the line
// back as soon as the unlisten returns
//
TRACE_OUT(("T120 has disconnected - unlistening"));
if (! m_Line.fCaller)
{
// g_lpfnPTPhysicalUnlisten(m_Line.pstnHandle);
}
else
{
//
// We only drop the call for outgoing requests - leave
// incoming calls to drop when the line goes down
//
DropCall();
}
}
break;
}
return 0;
}
//////////////////////////////////////////////////////////////////////////////
// SetConnectedPort
//
// Waits for comm port changes
//////////////////////////////////////////////////////////////////////////////
void CNullModem::SetConnectedPort(void)
{
DCB dcb;
TRACE_OUT(("SetConnectedPort"));
::ZeroMemory(&dcb, sizeof(dcb));
//
// Set comm mask and state
//
::SetCommMask(m_Line.hCommLink, 0); // RLSD changed state
::GetCommState(m_Line.hCommLink, &dcb);
dcb.DCBlength = sizeof(DCB);
dcb.fBinary = 1; // binary mode, no EOF check
dcb.fOutxDsrFlow = 0; // DSR output flow control
dcb.fDsrSensitivity = 0; // DSR sensitivity
dcb.fTXContinueOnXoff = 0; // XOFF continues Tx
dcb.fOutX = 0; // XON/XOFF out flow control
dcb.fInX = 0; // XON/XOFF in flow control
dcb.fErrorChar = 0; // enable error replacement
dcb.fNull = 0; // enable null stripping
dcb.XonLim = 0; // transmit XON threshold
dcb.XoffLim = 0; // transmit XOFF threshold
::SetCommState(m_Line.hCommLink, &dcb);
}
//////////////////////////////////////////////////////////////////////////////
// WaitForConnection
//
// Waits for comm port changes
//////////////////////////////////////////////////////////////////////////////
BOOL CNullModem::WaitForConnection(void)
{
BOOL fRet = FALSE;
TRACE_OUT(("WaitForConnection"));
while (TRUE)
{
DWORD dwWait = ::WaitForSingleObject(m_hevtOverlapped, COMM_PORT_TIMEOUT);
TRACE_OUT(("WaitForConnection: WaitForSingleObject returns %d", dwWait));
::ResetEvent(m_hevtOverlapped);
if (dwWait == WAIT_ABANDONED || dwWait == WAIT_TIMEOUT || dwWait == WAIT_FAILED)
{
DropCall();
m_fCommPortInUse = FALSE;
ERROR_OUT(("WaitForConnection: Unable to WaitCommEvent: error = %d", ::GetLastError()));
goto Failure;
}
ASSERT(m_hevtOverlapped == m_Line.hevtCall);
if (CALL_STATE_MAKE != m_Line.eCallState && CALL_STATE_ANSWER != m_Line.eCallState)
{
ERROR_OUT(("WaitForConnection: Got a bad event = %d", m_hevtOverlapped));
goto Failure;
}
TRACE_OUT(("WaitForConnection: m_dwEventMask = %d", m_dwEventMask));
switch (m_Line.eCallState)
{
case CALL_STATE_MAKE:
{
//
// The other side was connected and cleared DTR
//
if (m_dwEventMask & (EV_RXCHAR))
{
::EscapeCommFunction(m_Line.hCommLink, CLRDTR);
::EscapeCommFunction(m_Line.hCommLink, SETDTR);
SetConnectedPort();
m_Line.fCaller = FALSE;
goto Success;
}
//
// The other side just connected
//
else
if(m_dwEventMask & (EV_DSR | EV_RLSD | EV_CTS))
{
//
// Change the state of this connection so we dont get here again
//
m_Line.eCallState = CALL_STATE_ANSWER;
//
// Wait sometime so the other side can transition to the wait state
//
::Sleep(2000);
//
// Tell the other side we connected before
//
::EscapeCommFunction(m_Line.hCommLink, SETBREAK);
::ZeroMemory(&m_Overlapped, sizeof(m_Overlapped));
m_Overlapped.hEvent = m_Line.hevtCall;
m_dwEventMask = 0;
::ResetEvent(m_Overlapped.hEvent);
if (! ::WaitCommEvent(m_Line.hCommLink, &m_dwEventMask, &m_Overlapped))
{
DWORD dwErr = ::GetLastError();
if (ERROR_IO_PENDING != dwErr)
{
ERROR_OUT(("TPhysConnectRequest: Unable to WaitCommEvent: error = %d", dwErr));
DropCall();
goto Failure;
}
}
}
}
break;
case CALL_STATE_ANSWER:
{
::EscapeCommFunction(m_Line.hCommLink, CLRBREAK);
SetConnectedPort();
goto Success;
}
break;
}
} // while
Success:
fRet = TRUE;
Failure:
return fRet;
}
//////////////////////////////////////////////////////////////////////////////
// COMMThread
//
// Waits for comm port changes
//////////////////////////////////////////////////////////////////////////////
DWORD __stdcall TPhysWorkerThreadProc(void *lParam)
{
return ((CNullModem *) lParam)->WorkerThreadProc();
}
DWORD CNullModem::WorkerThreadProc(void)
{
ULONG rc = 0;
ULONG dwResult;
TRACE_OUT(("TPhysWorkerThreadProc"));
while (m_fCommPortInUse)
{
//
// Wait for connection to happen
//
if (WaitForConnection())
{
SetBuffers();
SetTimeouts();
//
// Call T120 physicall request
//
if (m_Line.fCaller)
{
// rc = g_lpfnPTPhysicalConnectRequest(0, // CALL_CONTROL_MANUAL
// &m_Line.hCommLink, NULL, &m_Line.pstnHandle);
}
else
{
m_Line.connInfo.connectionID = m_nConnectionID;
m_Line.connInfo.resultCode = TPHYS_SUCCESS;
if (NULL != m_pfnCallback)
{
(*m_pfnCallback)(WM_TPHYS_CONNECT_INDICATION, &m_Line.connInfo, m_nTransportID);
}
// rc = g_lpfnPTPhysicalListen(0, // CALL_CONTROL_MANUAL
// &m_Line.hCommLink, NULL, &m_Line.pstnHandle);
}
if (rc != 0)
{
TRACE_OUT(( "Failed COMM connect, rc %d",rc));
m_Line.connInfo.resultCode = TPHYS_RESULT_CONNECT_FAILED;
if (NULL != m_pfnCallback)
{
(*m_pfnCallback)(WM_TPHYS_CONNECT_CONFIRM, &m_Line.connInfo, m_nTransportID);
}
DropCall();
}
else
{
m_Line.eCallState = CALL_STATE_CONNECTED;
m_Line.connInfo.resultCode = TPHYS_SUCCESS;
//
// This comm port doesn't need the thread anymore
//
m_fCommPortInUse = FALSE;
}
}
else
{
TRACE_OUT(( "Failed COMM connect, rc %d",rc));
m_Line.connInfo.resultCode = TPHYS_RESULT_CONNECT_FAILED;
if (NULL != m_pfnCallback)
{
(*m_pfnCallback)(WM_TPHYS_CONNECT_CONFIRM, &m_Line.connInfo, m_nTransportID);
}
//
// Something went wrong in the wait, get out of the loop
//
break;
}
}
//
// We are going down.
//
if (NULL != m_hThread)
{
::CloseHandle(m_hThread);
m_hThread = NULL;
}
return 0;
}
void CNullModem::SetBuffers(void)
{
BOOL fRet = ::SetupComm(m_Line.hCommLink, /* rx */ 10240, /* tx */ 1024);
ASSERT(fRet);
}
void CNullModem::SetTimeouts(void)
{
COMMTIMEOUTS com_timeouts;
::ZeroMemory(&com_timeouts, sizeof(com_timeouts));
com_timeouts.ReadIntervalTimeout = 10;
com_timeouts.ReadTotalTimeoutMultiplier = 0;
com_timeouts.ReadTotalTimeoutConstant = 100;
com_timeouts.WriteTotalTimeoutMultiplier = 0;
com_timeouts.WriteTotalTimeoutConstant = 10000;
BOOL fRet = ::SetCommTimeouts(m_Line.hCommLink, &com_timeouts);
ASSERT(fRet);
}