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

  1. #include "mbftpch.h"
  2. #include "nullmdm.h"
  3. // #undef TRACE_OUT
  4. // #define TRACE_OUT WARNING_OUT
  5. BYTE g_szNULLMStartString[] = "NULLMDM";
  6. ULONG g_nConnID = 0;
  7. DWORD __stdcall TPhysWorkerThreadProc(void *lpv);
  8. CNullModem::CNullModem(HINSTANCE hDllInst)
  9. :
  10. m_fInitialized(FALSE),
  11. m_hDllInst(hDllInst),
  12. m_pfnCallback(NULL),
  13. m_fListening(FALSE),
  14. m_hwnd(NULL),
  15. m_nTransportID(0),
  16. m_nConnectionID(0),
  17. m_dwThreadID(0),
  18. m_hThread(NULL),
  19. m_hevtOverlapped(NULL),
  20. m_dwEventMask(0),
  21. m_fCommPortInUse(FALSE)
  22. {
  23. ::ZeroMemory(&m_Line, sizeof(m_Line));
  24. ::ZeroMemory(&m_Overlapped, sizeof(m_Overlapped));
  25. ::ZeroMemory(&m_DefaultTimeouts, sizeof(m_DefaultTimeouts));
  26. m_hevtOverlapped = ::CreateEvent(NULL, TRUE, FALSE, NULL); // manual reset
  27. ASSERT(NULL != m_hevtOverlapped);
  28. }
  29. CNullModem::~CNullModem(void)
  30. {
  31. if (m_fInitialized)
  32. {
  33. TPhysTerminate();
  34. }
  35. if (NULL != m_hevtOverlapped)
  36. {
  37. ::CloseHandle(m_hevtOverlapped);
  38. }
  39. }
  40. //////////////////////////////////////////////////////////////////////////////
  41. // TPhysInitialize
  42. //////////////////////////////////////////////////////////////////////////////
  43. TPhysicalError CNullModem::TPhysInitialize
  44. (
  45. TPhysCallback callback,
  46. UINT nTransportID
  47. )
  48. {
  49. const char *pszNULLMClassName = "COMMWndClass";
  50. TPhysicalError rc = TPHYS_SUCCESS;
  51. TRACE_OUT(("TPhysInitialize"));
  52. //
  53. // If we have already been initialized then this is a reinit call from
  54. // the node controller so just do nothing.
  55. //
  56. if (! m_fInitialized)
  57. {
  58. //
  59. // zero out the SESSION INFO structure
  60. //
  61. ::ZeroMemory(&m_Line, sizeof(m_Line));
  62. //
  63. // Store control information
  64. //
  65. m_pfnCallback = callback;
  66. m_nTransportID = nTransportID;
  67. m_fInitialized = TRUE;
  68. m_nConnectionID = ++g_nConnID;
  69. //
  70. // Create a window so we can decouple to the node controller context
  71. // Register the main window class. Since it is invisible, leave
  72. // the wndclass structure sparse.
  73. //
  74. WNDCLASS wc;
  75. ::ZeroMemory(&wc, sizeof(wc));
  76. wc.style = 0;
  77. wc.lpfnWndProc = TPhysWndProc;
  78. wc.cbClsExtra = 0;
  79. wc.cbWndExtra = 0;
  80. wc.hInstance = m_hDllInst;
  81. wc.hIcon = NULL;
  82. wc.hCursor = NULL;
  83. wc.hbrBackground = NULL;
  84. wc.lpszMenuName = NULL;
  85. wc.lpszClassName = pszNULLMClassName;
  86. ::RegisterClass(&wc);
  87. //
  88. // Create the main window.
  89. //
  90. m_hwnd = ::CreateWindow(
  91. pszNULLMClassName, // See RegisterClass() call.
  92. NULL, // It's invisible!
  93. 0, // Window style.
  94. 0, // Default horizontal position.
  95. 0, // Default vertical position.
  96. 0, // Default width.
  97. 0, // Default height.
  98. NULL, // No parent.
  99. NULL, // No menu.
  100. m_hDllInst, // This instance owns this window.
  101. NULL // Pointer not needed.
  102. );
  103. if (NULL == m_hwnd)
  104. {
  105. ERROR_OUT(( "Failed to create wnd"));
  106. return(TPHYS_RESULT_FAIL);
  107. }
  108. // rc = g_lpfnPTPhysicalInit(TPhysDriverCallback, NULL);
  109. ASSERT(TPHYS_SUCCESS == rc);
  110. }
  111. return rc;
  112. }
  113. //////////////////////////////////////////////////////////////////////////////////
  114. // TPhysTerminate
  115. //
  116. // The node controller is shutting down
  117. // Destroy our window and clean up transports.
  118. //////////////////////////////////////////////////////////////////////////////////
  119. TPhysicalError CNullModem::TPhysTerminate(void)
  120. {
  121. TRACE_OUT(("TPhysTerminate"));
  122. if (! m_fInitialized)
  123. {
  124. return(TPHYS_RESULT_NOT_INITIALIZED);
  125. }
  126. //
  127. // Clean up the PSTN transport
  128. //
  129. // g_lpfnPTPhysicalCleanup();
  130. //
  131. // Destroy the window
  132. //
  133. if (NULL != m_hwnd)
  134. {
  135. ::DestroyWindow(m_hwnd);
  136. m_hwnd = NULL;
  137. }
  138. m_pfnCallback = NULL;
  139. m_nTransportID = 0;
  140. m_fInitialized = FALSE;
  141. return(TPHYS_SUCCESS);
  142. }
  143. //////////////////////////////////////////////////////////////////////////////
  144. // TPhysConnectRequest
  145. //
  146. // The node controller wants to place a call and has determined that it
  147. // first needs a physical modem connection. Make a call and flag an
  148. // outgoing call so that when the call comes active we can tell the modem
  149. // transport to begin negotiation.
  150. //////////////////////////////////////////////////////////////////////////////
  151. TPhysicalError CNullModem::TPhysConnectRequest(LPSTR pszComPort)
  152. {
  153. TPhysicalError rc = TPHYS_SUCCESS;
  154. HANDLE hCommLink;
  155. DCB dcb;
  156. DWORD dwWritten;
  157. TRACE_OUT(("TPhysConnectRequest"));
  158. if (! m_fInitialized)
  159. {
  160. ERROR_OUT(("NULL MODEM OOB not initialized"));
  161. return TPHYS_RESULT_NOT_INITIALIZED;
  162. }
  163. //
  164. // Select a comm port for the call.
  165. //
  166. if (CALL_STATE_IDLE == m_Line.eCallState || CALL_STATE_DROP == m_Line.eCallState)
  167. {
  168. //
  169. // Also prime our local copy of the conninfo structure for use in callbacks
  170. //
  171. m_Line.connInfo.resultCode = 0;
  172. m_Line.connInfo.connectionID = m_nConnectionID;
  173. }
  174. else
  175. {
  176. ERROR_OUT(("No comm port is available"));
  177. return TPHYS_RESULT_COMM_PORT_BUSY;
  178. }
  179. // lonchanc: From now on, we can bail out thru the common exit point
  180. // because the cleanup checks for m_fCommPortInUse.
  181. //
  182. // Only alow one at at time
  183. //
  184. // lonchanc: g_COMM_Thread_Users is starting from -1
  185. // why can we simply use a flag???
  186. if (m_fCommPortInUse)
  187. {
  188. ERROR_OUT(("TPhysConnectRequest: Waiting for a previous null mode connection"));
  189. rc = TPHYS_RESULT_WAITING_FOR_CONNECTION;
  190. goto bail;
  191. }
  192. m_fCommPortInUse = TRUE;
  193. //
  194. // Open the comm port
  195. //
  196. hCommLink = ::CreateFile(pszComPort,
  197. GENERIC_READ | GENERIC_WRITE,
  198. 0, // exclusive access
  199. NULL, // no security attrs
  200. OPEN_EXISTING,
  201. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, // overlapped I/O
  202. NULL );
  203. if (hCommLink == INVALID_HANDLE_VALUE)
  204. {
  205. ERROR_OUT(("TPhysConnectRequest: CreateFile failed. err=%d", ::GetLastError()));
  206. rc = TPHYS_RESULT_COMM_PORT_BUSY;
  207. goto bail;
  208. }
  209. m_Line.hCommLink = hCommLink;
  210. //
  211. // remember the default timeouts
  212. //
  213. ::GetCommTimeouts(hCommLink, &m_DefaultTimeouts);
  214. //
  215. // Let the other side know that we are trying to connect
  216. //
  217. if (! ::EscapeCommFunction(hCommLink, SETDTR))
  218. {
  219. ERROR_OUT(("TPhysConnectRequest: Unable to Set DTR: err=%d", ::GetLastError()));
  220. }
  221. ::ZeroMemory(&m_Overlapped, sizeof(m_Overlapped));
  222. m_Overlapped.hEvent = m_hevtOverlapped;
  223. m_dwEventMask = 0;
  224. ::ResetEvent(m_hevtOverlapped);
  225. if (! ::WriteFile(hCommLink, g_szNULLMStartString, sizeof(g_szNULLMStartString),
  226. &dwWritten, &m_Overlapped))
  227. {
  228. DWORD dwErr = ::GetLastError();
  229. if (ERROR_IO_PENDING != dwErr)
  230. {
  231. ERROR_OUT(("TPhysConnectRequest: WriteFile failed. err=%d", dwErr));
  232. ::ResetEvent(m_hevtOverlapped);
  233. rc = TPHYS_RESULT_COMM_PORT_BUSY;
  234. goto bail;
  235. }
  236. else
  237. {
  238. DWORD dwWait = ::WaitForSingleObject(m_hevtOverlapped, INFINITE);
  239. BOOL fRet = ::GetOverlappedResult(hCommLink, &m_Overlapped, &dwWritten, TRUE);
  240. ASSERT(fRet);
  241. ASSERT(dwWritten == sizeof(g_szNULLMStartString));
  242. }
  243. }
  244. else
  245. {
  246. ASSERT(dwWritten == sizeof(g_szNULLMStartString));
  247. }
  248. ::ResetEvent(m_hevtOverlapped);
  249. //
  250. // Get the default dcb
  251. //
  252. ::ZeroMemory(&dcb, sizeof(dcb));
  253. ::GetCommState(hCommLink, &dcb);
  254. dcb.BaudRate = 19200; // Default: BaudRate
  255. //
  256. // Set our state so we can get notification in the comm port
  257. //
  258. dcb.DCBlength = sizeof(DCB);
  259. dcb.fBinary = 1; // binary mode, no EOF check
  260. dcb.fParity = 0; // enable parity checking
  261. dcb.fOutxCtsFlow = 1; // CTS output flow control
  262. dcb.fOutxDsrFlow = 0; // DSR output flow control
  263. dcb.fDtrControl = DTR_CONTROL_ENABLE; // DTR flow control type
  264. dcb.fDsrSensitivity = 0; // DSR sensitivity
  265. dcb.fTXContinueOnXoff = 0; // XOFF continues Tx
  266. dcb.fOutX = 0; // XON/XOFF out flow control
  267. dcb.fInX = 0; // XON/XOFF in flow control
  268. dcb.fErrorChar = 0; // enable error replacement
  269. dcb.fNull = 0; // enable null stripping
  270. dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;// RTS flow control
  271. dcb.XonLim = 0; // transmit XON threshold
  272. dcb.XoffLim = 0; // transmit XOFF threshold
  273. dcb.fErrorChar = 0; // enable error replacement
  274. dcb.fNull = 0; // enable null stripping
  275. dcb.fAbortOnError = 0; // abort reads/writes on error
  276. ::SetCommState(hCommLink, &dcb);
  277. ::PurgeComm(hCommLink, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);
  278. m_Line.eCallState = CALL_STATE_MAKE;
  279. m_Line.hevtCall = m_hevtOverlapped;
  280. m_Line.pstnHandle = (PHYSICAL_HANDLE) hCommLink;
  281. m_Line.fCaller = TRUE;
  282. if (! ::SetCommMask(hCommLink,
  283. EV_RXCHAR | // Any Character received
  284. EV_CTS | // CTS changed state
  285. EV_DSR | // DSR changed state
  286. EV_RLSD| // RLSD changed state
  287. EV_RXFLAG)) // Certain character
  288. {
  289. ERROR_OUT(("TPhysConnectRequest: Unable to SetCommMask: err=%d", ::GetLastError()));
  290. }
  291. ::ZeroMemory(&m_Overlapped, sizeof(m_Overlapped));
  292. m_Overlapped.hEvent = m_hevtOverlapped;
  293. m_dwEventMask = 0;
  294. ::ResetEvent(m_hevtOverlapped);
  295. if (! ::WaitCommEvent(hCommLink, &m_dwEventMask, &m_Overlapped))
  296. {
  297. DWORD dwErr = ::GetLastError();
  298. if (ERROR_IO_PENDING != dwErr)
  299. {
  300. ERROR_OUT(("TPhysConnectRequest: WaitCommEvent failed, err=%d", dwErr));
  301. m_fCommPortInUse = FALSE;
  302. }
  303. }
  304. #if 1
  305. WorkerThreadProc();
  306. #else
  307. //
  308. // If the comm thread doesn't exist, create it now.
  309. //
  310. // lonchanc: I am not sure that the thread will exist, because
  311. // the while loop inside the thread will exit if m_fCommPortInUse is false.
  312. // If m_fCommPortInUse is true, then we should bail out already.
  313. //
  314. ASSERT(NULL == m_hThread);
  315. //
  316. // We need to create another thread that will wait on comm events.
  317. //
  318. m_hThread = ::CreateThread(NULL, 0, TPhysWorkerThreadProc, this, 0, &m_dwThreadID);
  319. ASSERT(NULL != m_hThread);
  320. #endif
  321. bail:
  322. return(rc);
  323. }
  324. //////////////////////////////////////////////////////////////////////////////
  325. // TPhysDisconnect
  326. //
  327. // The node controller wants us to bring the call down now. We must first
  328. // ask the transports to close down their physicall connection.
  329. //
  330. // Note that in the case of the PSTN transport we use a NOWAIT call which
  331. // completes syncronously. Because we will not get a follow on confirm
  332. // we simulate one from here. If we switch to using WAIT mode then
  333. // take the event generation code out!
  334. //////////////////////////////////////////////////////////////////////////////
  335. TPhysicalError CNullModem::TPhysDisconnect(void)
  336. {
  337. TRACE_OUT(("TPhysDisconnect"));
  338. if (! m_fInitialized)
  339. {
  340. ERROR_OUT(( "Not initialised"));
  341. return(TPHYS_RESULT_NOT_INITIALIZED);
  342. }
  343. TRACE_OUT(("Disconnect call, state %u", m_Line.eCallState));
  344. //
  345. // Otherwise it must be a pstn call in progress so end that. Note
  346. // that NC may still think it is MODEM, but we still need to close
  347. // PSTN.
  348. //
  349. // g_lpfnPTPhysicalDisconnectRequest(m_aLines[lineID].pstnHandle, TPHYSICAL_NO_WAIT);
  350. ::PostMessage(m_hwnd, WM_TPHYS_DISCONNECT_CONFIRM, (WPARAM) this, m_Line.pstnHandle);
  351. //
  352. // close the comport
  353. //
  354. DropCall();
  355. return(TPHYS_SUCCESS);
  356. }
  357. //////////////////////////////////////////////////////////////////////////////
  358. // TPhysListen/TPhysUnlisten
  359. //
  360. // NULLMMAN does very little with listen/unlisten, just sets a state variable
  361. // that is interrogated to see if we should accept incoming calls.
  362. //
  363. // NOTE - This is different from the Listen/Unlisten that is used to tell
  364. // the PSTN transport about the presence of an incoming call.
  365. //////////////////////////////////////////////////////////////////////////////
  366. TPhysicalError CNullModem::TPhysListen(void)
  367. {
  368. TRACE_OUT(("TPhysListen"));
  369. if (! m_fInitialized)
  370. {
  371. ERROR_OUT(("TPhysListen: not initialized"));
  372. return(TPHYS_RESULT_NOT_INITIALIZED);
  373. }
  374. m_fListening = TRUE;
  375. return(TPHYS_SUCCESS);
  376. }
  377. TPhysicalError CNullModem::TPhysUnlisten(void)
  378. {
  379. TRACE_OUT(("TPhysUnlisten"));
  380. if (! m_fInitialized)
  381. {
  382. ERROR_OUT(("TPhysUnlisten: not initialized"));
  383. return(TPHYS_RESULT_NOT_INITIALIZED);
  384. }
  385. m_fListening = FALSE;
  386. return(TPHYS_SUCCESS);
  387. }
  388. //////////////////////////////////////////////////////////////////////////////
  389. // DropCall - close the comm port
  390. /////////////////////////////////////////////////////////////////////////////
  391. void CNullModem::DropCall(void)
  392. {
  393. TRACE_OUT(("DropCall"));
  394. //
  395. // close the device handle
  396. //
  397. if (NULL != m_Line.hCommLink)
  398. {
  399. CALL_STATE eCallState = m_Line.eCallState;
  400. m_Line.eCallState = CALL_STATE_IDLE;
  401. //
  402. // If this call is connected it is not using the comm thread
  403. //
  404. if (eCallState != CALL_STATE_CONNECTED)
  405. {
  406. m_fCommPortInUse = FALSE;
  407. }
  408. //
  409. // restore comm timeouts
  410. //
  411. SetCommTimeouts(m_Line.hCommLink, &m_DefaultTimeouts);
  412. TRACE_OUT(("Closing device handle %x", m_Line.hCommLink));
  413. ::CloseHandle(m_Line.hCommLink);
  414. m_Line.hCommLink = NULL;
  415. }
  416. }
  417. //////////////////////////////////////////////////////////////////////////////
  418. //
  419. // FUNCTION: PSTNCallback
  420. //
  421. // DESCRIPTION:
  422. //
  423. // PSTN callback function, called by the PSTN driver with the resuts of
  424. // TPhysical operations
  425. //
  426. // See MCATTPRT.H for definitions of the parameters
  427. //
  428. //////////////////////////////////////////////////////////////////////////////
  429. TPhysicalError CALLBACK TPhysDriverCallback(USHORT msg, ULONG lParam, void *userData)
  430. {
  431. TRACE_OUT(("NULLM_PSTNCallback"));
  432. TRACE_OUT(("Hit TPhysical callback, %x %lx %lx", msg, lParam, userData));
  433. CNullModem *p = (CNullModem *) userData;
  434. BOOL fRet = ::PostMessage(p->GetHwnd(), msg, (WPARAM) p, lParam);
  435. ASSERT(fRet);
  436. return TPHYS_SUCCESS;
  437. }
  438. //////////////////////////////////////////////////////////////////////////////
  439. //
  440. // FUNCTION:TPhysWndProc
  441. //
  442. // Window procedure used to decouple callback requests
  443. //
  444. //////////////////////////////////////////////////////////////////////////////
  445. LRESULT CALLBACK TPhysWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  446. {
  447. CNullModem *p = (CNullModem *) wParam;
  448. if (uMsg >= WM_APP)
  449. {
  450. return p->TPhysProcessMessage(uMsg, lParam);
  451. }
  452. return ::DefWindowProc(hwnd, uMsg, wParam, lParam);
  453. }
  454. LRESULT CNullModem::TPhysProcessMessage(UINT uMsg, LPARAM lParam)
  455. {
  456. USHORT rc;
  457. USHORT reason;
  458. ULONG status;
  459. LINE_INFO *pLine;
  460. if (WM_TPHYS_STATUS_INDICATION == uMsg)
  461. {
  462. return 0;
  463. }
  464. ASSERT(lParam == (LPARAM) m_Line.pstnHandle);
  465. switch (uMsg)
  466. {
  467. case WM_TPHYS_CONNECT_INDICATION:
  468. TRACE_OUT(("got a WM_TPHYS_CONNECT_INDICATION"));
  469. m_Line.connInfo.resultCode = TPHYS_RESULT_INUSE;
  470. m_Line.eCallState = CALL_STATE_CONNECTED;
  471. if (NULL != m_pfnCallback)
  472. {
  473. (*m_pfnCallback)(WM_TPHYS_CONNECT_CONFIRM, &m_Line.connInfo, m_nTransportID);
  474. }
  475. break;
  476. case WM_TPHYS_CONNECT_CONFIRM:
  477. //
  478. // The transport has connected OK! We will take the line
  479. // back when the transport pulls DTR down
  480. //
  481. TRACE_OUT(("got a WM_TPHYS_CONNECT_CONFIRM"));
  482. m_Line.connInfo.resultCode = TPHYS_RESULT_SUCCESS_ALTERNATE;
  483. m_Line.eCallState = CALL_STATE_CONNECTED;
  484. if (NULL != m_pfnCallback)
  485. {
  486. (*m_pfnCallback)(WM_TPHYS_CONNECT_CONFIRM, &m_Line.connInfo, m_nTransportID);
  487. }
  488. break;
  489. case WM_TPHYS_DISCONNECT_INDICATION:
  490. case WM_TPHYS_DISCONNECT_CONFIRM:
  491. //
  492. // If the disconnect is the result of a failed connect request
  493. // then tell the NC of the failure (Otherwise it is a
  494. // successful disconnect)
  495. //
  496. if (WM_TPHYS_DISCONNECT_INDICATION == uMsg)
  497. {
  498. TRACE_OUT(("WM_TPHYS_DISCONNECT_INDICATION, %ld", lParam));
  499. }
  500. else
  501. {
  502. TRACE_OUT(("WM_TPHYS_DISCONNECT_CONFIRM, %ld", lParam));
  503. }
  504. if ((m_Line.eCallState == CALL_STATE_MAKE) ||
  505. (m_Line.eCallState == CALL_STATE_ANSWER) ||
  506. (m_Line.eCallState == CALL_STATE_CONNECTED))
  507. {
  508. TRACE_OUT(( "T120 connection attempt has failed"));
  509. if (m_Line.fCaller)
  510. {
  511. m_Line.connInfo.resultCode = TPHYS_RESULT_CONNECT_FAILED;
  512. if (NULL != m_pfnCallback)
  513. {
  514. (*m_pfnCallback)(WM_TPHYS_CONNECT_CONFIRM, &m_Line.connInfo, m_nTransportID);
  515. }
  516. }
  517. DropCall();
  518. }
  519. else
  520. {
  521. //
  522. // The transport has disconnected OK. We can take the line
  523. // back as soon as the unlisten returns
  524. //
  525. TRACE_OUT(("T120 has disconnected - unlistening"));
  526. if (! m_Line.fCaller)
  527. {
  528. // g_lpfnPTPhysicalUnlisten(m_Line.pstnHandle);
  529. }
  530. else
  531. {
  532. //
  533. // We only drop the call for outgoing requests - leave
  534. // incoming calls to drop when the line goes down
  535. //
  536. DropCall();
  537. }
  538. }
  539. break;
  540. }
  541. return 0;
  542. }
  543. //////////////////////////////////////////////////////////////////////////////
  544. // SetConnectedPort
  545. //
  546. // Waits for comm port changes
  547. //////////////////////////////////////////////////////////////////////////////
  548. void CNullModem::SetConnectedPort(void)
  549. {
  550. DCB dcb;
  551. TRACE_OUT(("SetConnectedPort"));
  552. ::ZeroMemory(&dcb, sizeof(dcb));
  553. //
  554. // Set comm mask and state
  555. //
  556. ::SetCommMask(m_Line.hCommLink, 0); // RLSD changed state
  557. ::GetCommState(m_Line.hCommLink, &dcb);
  558. dcb.DCBlength = sizeof(DCB);
  559. dcb.fBinary = 1; // binary mode, no EOF check
  560. dcb.fOutxDsrFlow = 0; // DSR output flow control
  561. dcb.fDsrSensitivity = 0; // DSR sensitivity
  562. dcb.fTXContinueOnXoff = 0; // XOFF continues Tx
  563. dcb.fOutX = 0; // XON/XOFF out flow control
  564. dcb.fInX = 0; // XON/XOFF in flow control
  565. dcb.fErrorChar = 0; // enable error replacement
  566. dcb.fNull = 0; // enable null stripping
  567. dcb.XonLim = 0; // transmit XON threshold
  568. dcb.XoffLim = 0; // transmit XOFF threshold
  569. ::SetCommState(m_Line.hCommLink, &dcb);
  570. }
  571. //////////////////////////////////////////////////////////////////////////////
  572. // WaitForConnection
  573. //
  574. // Waits for comm port changes
  575. //////////////////////////////////////////////////////////////////////////////
  576. BOOL CNullModem::WaitForConnection(void)
  577. {
  578. BOOL fRet = FALSE;
  579. TRACE_OUT(("WaitForConnection"));
  580. while (TRUE)
  581. {
  582. DWORD dwWait = ::WaitForSingleObject(m_hevtOverlapped, COMM_PORT_TIMEOUT);
  583. TRACE_OUT(("WaitForConnection: WaitForSingleObject returns %d", dwWait));
  584. ::ResetEvent(m_hevtOverlapped);
  585. if (dwWait == WAIT_ABANDONED || dwWait == WAIT_TIMEOUT || dwWait == WAIT_FAILED)
  586. {
  587. DropCall();
  588. m_fCommPortInUse = FALSE;
  589. ERROR_OUT(("WaitForConnection: Unable to WaitCommEvent: error = %d", ::GetLastError()));
  590. goto Failure;
  591. }
  592. ASSERT(m_hevtOverlapped == m_Line.hevtCall);
  593. if (CALL_STATE_MAKE != m_Line.eCallState && CALL_STATE_ANSWER != m_Line.eCallState)
  594. {
  595. ERROR_OUT(("WaitForConnection: Got a bad event = %d", m_hevtOverlapped));
  596. goto Failure;
  597. }
  598. TRACE_OUT(("WaitForConnection: m_dwEventMask = %d", m_dwEventMask));
  599. switch (m_Line.eCallState)
  600. {
  601. case CALL_STATE_MAKE:
  602. {
  603. //
  604. // The other side was connected and cleared DTR
  605. //
  606. if (m_dwEventMask & (EV_RXCHAR))
  607. {
  608. ::EscapeCommFunction(m_Line.hCommLink, CLRDTR);
  609. ::EscapeCommFunction(m_Line.hCommLink, SETDTR);
  610. SetConnectedPort();
  611. m_Line.fCaller = FALSE;
  612. goto Success;
  613. }
  614. //
  615. // The other side just connected
  616. //
  617. else
  618. if(m_dwEventMask & (EV_DSR | EV_RLSD | EV_CTS))
  619. {
  620. //
  621. // Change the state of this connection so we dont get here again
  622. //
  623. m_Line.eCallState = CALL_STATE_ANSWER;
  624. //
  625. // Wait sometime so the other side can transition to the wait state
  626. //
  627. ::Sleep(2000);
  628. //
  629. // Tell the other side we connected before
  630. //
  631. ::EscapeCommFunction(m_Line.hCommLink, SETBREAK);
  632. ::ZeroMemory(&m_Overlapped, sizeof(m_Overlapped));
  633. m_Overlapped.hEvent = m_Line.hevtCall;
  634. m_dwEventMask = 0;
  635. ::ResetEvent(m_Overlapped.hEvent);
  636. if (! ::WaitCommEvent(m_Line.hCommLink, &m_dwEventMask, &m_Overlapped))
  637. {
  638. DWORD dwErr = ::GetLastError();
  639. if (ERROR_IO_PENDING != dwErr)
  640. {
  641. ERROR_OUT(("TPhysConnectRequest: Unable to WaitCommEvent: error = %d", dwErr));
  642. DropCall();
  643. goto Failure;
  644. }
  645. }
  646. }
  647. }
  648. break;
  649. case CALL_STATE_ANSWER:
  650. {
  651. ::EscapeCommFunction(m_Line.hCommLink, CLRBREAK);
  652. SetConnectedPort();
  653. goto Success;
  654. }
  655. break;
  656. }
  657. } // while
  658. Success:
  659. fRet = TRUE;
  660. Failure:
  661. return fRet;
  662. }
  663. //////////////////////////////////////////////////////////////////////////////
  664. // COMMThread
  665. //
  666. // Waits for comm port changes
  667. //////////////////////////////////////////////////////////////////////////////
  668. DWORD __stdcall TPhysWorkerThreadProc(void *lParam)
  669. {
  670. return ((CNullModem *) lParam)->WorkerThreadProc();
  671. }
  672. DWORD CNullModem::WorkerThreadProc(void)
  673. {
  674. ULONG rc = 0;
  675. ULONG dwResult;
  676. TRACE_OUT(("TPhysWorkerThreadProc"));
  677. while (m_fCommPortInUse)
  678. {
  679. //
  680. // Wait for connection to happen
  681. //
  682. if (WaitForConnection())
  683. {
  684. SetBuffers();
  685. SetTimeouts();
  686. //
  687. // Call T120 physicall request
  688. //
  689. if (m_Line.fCaller)
  690. {
  691. // rc = g_lpfnPTPhysicalConnectRequest(0, // CALL_CONTROL_MANUAL
  692. // &m_Line.hCommLink, NULL, &m_Line.pstnHandle);
  693. }
  694. else
  695. {
  696. m_Line.connInfo.connectionID = m_nConnectionID;
  697. m_Line.connInfo.resultCode = TPHYS_SUCCESS;
  698. if (NULL != m_pfnCallback)
  699. {
  700. (*m_pfnCallback)(WM_TPHYS_CONNECT_INDICATION, &m_Line.connInfo, m_nTransportID);
  701. }
  702. // rc = g_lpfnPTPhysicalListen(0, // CALL_CONTROL_MANUAL
  703. // &m_Line.hCommLink, NULL, &m_Line.pstnHandle);
  704. }
  705. if (rc != 0)
  706. {
  707. TRACE_OUT(( "Failed COMM connect, rc %d",rc));
  708. m_Line.connInfo.resultCode = TPHYS_RESULT_CONNECT_FAILED;
  709. if (NULL != m_pfnCallback)
  710. {
  711. (*m_pfnCallback)(WM_TPHYS_CONNECT_CONFIRM, &m_Line.connInfo, m_nTransportID);
  712. }
  713. DropCall();
  714. }
  715. else
  716. {
  717. m_Line.eCallState = CALL_STATE_CONNECTED;
  718. m_Line.connInfo.resultCode = TPHYS_SUCCESS;
  719. //
  720. // This comm port doesn't need the thread anymore
  721. //
  722. m_fCommPortInUse = FALSE;
  723. }
  724. }
  725. else
  726. {
  727. TRACE_OUT(( "Failed COMM connect, rc %d",rc));
  728. m_Line.connInfo.resultCode = TPHYS_RESULT_CONNECT_FAILED;
  729. if (NULL != m_pfnCallback)
  730. {
  731. (*m_pfnCallback)(WM_TPHYS_CONNECT_CONFIRM, &m_Line.connInfo, m_nTransportID);
  732. }
  733. //
  734. // Something went wrong in the wait, get out of the loop
  735. //
  736. break;
  737. }
  738. }
  739. //
  740. // We are going down.
  741. //
  742. if (NULL != m_hThread)
  743. {
  744. ::CloseHandle(m_hThread);
  745. m_hThread = NULL;
  746. }
  747. return 0;
  748. }
  749. void CNullModem::SetBuffers(void)
  750. {
  751. BOOL fRet = ::SetupComm(m_Line.hCommLink, /* rx */ 10240, /* tx */ 1024);
  752. ASSERT(fRet);
  753. }
  754. void CNullModem::SetTimeouts(void)
  755. {
  756. COMMTIMEOUTS com_timeouts;
  757. ::ZeroMemory(&com_timeouts, sizeof(com_timeouts));
  758. com_timeouts.ReadIntervalTimeout = 10;
  759. com_timeouts.ReadTotalTimeoutMultiplier = 0;
  760. com_timeouts.ReadTotalTimeoutConstant = 100;
  761. com_timeouts.WriteTotalTimeoutMultiplier = 0;
  762. com_timeouts.WriteTotalTimeoutConstant = 10000;
  763. BOOL fRet = ::SetCommTimeouts(m_Line.hCommLink, &com_timeouts);
  764. ASSERT(fRet);
  765. }