Leaked source code of windows server 2003
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.

449 lines
14 KiB

  1. /* ComSend -- Text sending routines for HyperACCESS
  2. *
  3. * Copyright 1994 by Hilgraeve Inc. -- Monroe, MI
  4. * All rights reserved
  5. *
  6. * $Revision: 8 $
  7. * $Date: 7/12/02 10:45a $
  8. */
  9. #include <windows.h>
  10. #pragma hdrstop
  11. // #define DEBUGSTR
  12. #include "stdtyp.h"
  13. #include <tdll\assert.h>
  14. #include "com.h"
  15. #include "comdev.h"
  16. #include "com.hh"
  17. /* --- Internal prototypes --- */
  18. static int ComSendCheck(const HCOM pstCom, const int fDataWaiting);
  19. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  20. * ComSendChar
  21. *
  22. * DESCRIPTION:
  23. * Adds a character to the send buffer to be transmitted. The
  24. * character will not actually be transferred to the transmit
  25. * routines until the buffer fills up or a call to ComSendCharNow
  26. * is made or a call to ComSendPush is made while the transmitter
  27. * is not busy.
  28. *
  29. * ARGUMENTS:
  30. * pstCom -- handle to comm session
  31. * uchCode -- The character to be transmitted.
  32. *
  33. * RETURNS:
  34. * COM_OK if the character is successfully buffered.
  35. * COM_INVALID_HANDLE if invalid com handle
  36. * COM_SEND_BUFFER_FULL if the buffer is full and the
  37. * caller-supplied handshake function returns a code
  38. * indicating that waiting data should be discarded.
  39. */
  40. int ComSendChar(const HCOM pstCom, const TCHAR chCode)
  41. {
  42. assert(ComValidHandle(pstCom));
  43. while (pstCom->nSBufrSize > 0 && (pstCom->nSendCount >= pstCom->nSBufrSize))
  44. {
  45. /* wait until there is room in buffer or we're told to give up. */
  46. if (ComSendCheck(pstCom, TRUE) != COM_OK)
  47. return FALSE;
  48. if (pstCom->nSendCount >= pstCom->nSBufrSize)
  49. (void)ComSndBufrWait(pstCom, 2);
  50. }
  51. /* Place char in buffer and assume it will get launched later. */
  52. if(pstCom && &pstCom->puchSendPut)
  53. {
  54. *pstCom->puchSendPut++ = chCode;
  55. ++pstCom->nSendCount;
  56. }
  57. return TRUE;
  58. }
  59. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  60. * ComSendCharNow
  61. *
  62. * DESCRIPTION: Adds a character to the send buffer and then waits to make
  63. * sure the send buffer gets passed to the transmission routine.
  64. * This function does NOT wait until the character is actually
  65. * transmitted. Handshaking may still delay actual transmission
  66. * but no subsequent calls to any ComSend??? routines are needed
  67. * to get the character on its way. ComSendWait can be used to
  68. * wait until all characters are actually out the port.
  69. *
  70. * ARGUMENTS: pstCom -- handle to comm session
  71. * chCode -- The character to be transmitted.
  72. *
  73. * RETURNS: COM_OK if the character is successfully buffered and passed to
  74. * the transmission routines.
  75. * COM_INVALID_HANDLE if invalid com handle
  76. * COM_SEND_QUEUE_STUCK if the caller-supplied handshake function
  77. * returns a code indicating that waiting data should be
  78. * discarded before the buffer can be queued for transmission.
  79. */
  80. int ComSendCharNow(const HCOM pstCom, const TCHAR chCode)
  81. {
  82. assert(ComValidHandle(pstCom));
  83. while (pstCom->nSBufrSize > 0 && (pstCom->nSendCount >= pstCom->nSBufrSize))
  84. {
  85. /* buffer is full, wait until there is room or we are
  86. * told to give up
  87. */
  88. if (ComSendCheck(pstCom, TRUE) != COM_OK)
  89. return FALSE;
  90. if (pstCom->nSendCount >= pstCom->nSBufrSize)
  91. ComSndBufrWait(pstCom, 2);
  92. }
  93. if(pstCom && pstCom->puchSendPut)
  94. {
  95. *pstCom->puchSendPut++ = chCode;
  96. ++pstCom->nSendCount;
  97. /* wait until local buffer is passed to SndBufr or we are
  98. * told to give up
  99. */
  100. while (pstCom->nSendCount > 0)
  101. {
  102. // This will pass buffer to SndBufr as soon as possible
  103. if (ComSendCheck(pstCom, TRUE) != COM_OK)
  104. return FALSE;
  105. if (pstCom->nSendCount > 0)
  106. ComSndBufrWait(pstCom, 2);
  107. }
  108. }
  109. return TRUE;
  110. }
  111. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  112. * ComSendPush
  113. *
  114. * DESCRIPTION: This routine should be called periodically by any code that
  115. * uses ComSendChar() when there are no characters to be
  116. * transmitted immediately. Calling this function accomplishes
  117. * two things.
  118. * 1. It will cause any buffered send characters to be passed to the actual
  119. * transmission routines as soon as they are not busy.
  120. * 2. It will cause the caller-registered handshake handler function to be
  121. * called if transmission is suspended by handshaking.
  122. *
  123. * ARGUMENTS: pstCom -- handle to comm session
  124. *
  125. * RETURNS: same as ComSendCheck()
  126. */
  127. int ComSendPush(const HCOM pstCom)
  128. {
  129. return ComSendCheck(pstCom, FALSE);
  130. }
  131. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  132. * ComSendWait
  133. *
  134. * DESCRIPTION: This function waits until all buffered send data is actually
  135. * passed to the transmit hardware or until the handshake handling
  136. * function returns a code indicating that data should be discared.
  137. *
  138. * ARGUMENTS: pstCom -- handle to comm session
  139. * none
  140. *
  141. * RETURNS: COM_OK if all data has been transmitted.
  142. * COM_SEND_QUEUE_STUCK if a handshake handling function
  143. * indicated that data should be discarded.
  144. */
  145. int ComSendWait(const HCOM pstCom)
  146. {
  147. assert(ComValidHandle(pstCom));
  148. while (pstCom->nSendCount > 0 || ComSndBufrWait(pstCom, 2) != COM_OK)
  149. {
  150. if (ComSendCheck(pstCom, FALSE) != COM_OK)
  151. {
  152. return COM_SEND_QUEUE_STUCK;
  153. }
  154. }
  155. return COM_OK;
  156. }
  157. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  158. * ComSendClear
  159. *
  160. * DESCRIPTION: Clears all data waiting for tranmission, both in the local
  161. * ComSend buffer and the SndBufr buffer currently being
  162. * transmitted.
  163. *
  164. * ARGUMENTS: pstCom -- handle to comm session
  165. *
  166. * RETURNS: always returns COM_OK
  167. */
  168. int ComSendClear(const HCOM pstCom)
  169. {
  170. assert(ComValidHandle(pstCom));
  171. ComSndBufrClear(pstCom);
  172. pstCom->puchSendPut = pstCom->puchSendBufr;
  173. pstCom->nSendCount = 0;
  174. return COM_OK;
  175. }
  176. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  177. * ComSendSetStatusFunction
  178. *
  179. * DESCRIPTION: Registers a function to be called to handle handshaking status
  180. * displays, timeouts, etc. while sending.
  181. *
  182. * The registered function is called when it is registered, when it is being
  183. * replaced, and during sending when a handshaking suspension is detected.
  184. * Normally, the function is not called if transmission is not suspended.
  185. * After being called one or more times with a suspension, though, it will
  186. * be called one additional time after the suspension clears to allow the
  187. * function to clear any visible indicators.
  188. *
  189. * The registered function is passed the following arguments
  190. * usReason -- Contains a code indicating the reason the function
  191. * was called. It will be one of:
  192. * COMSEND_FIRSTCALL -- if function is being installed
  193. * COMSEND_LASTCALL -- if function is being replaced
  194. * COMSEND_DATA_WAITING -- if there is data waiting
  195. * that will not fit in the send buffer.
  196. * COMSEND_NORMAL -- if called due to handshake
  197. * condition but no data is in danger of being lost.
  198. * fusHsStatus -- A value contining bits which indicate what transmission
  199. * is waiting for. The bits are defined in com.h as
  200. * COMSB_WAIT_XXX.
  201. * lDelay -- The amount of time in tenths of seconds since
  202. * transmission was suspended. This time will not
  203. * begin incrementing until there is data to transmit.
  204. *
  205. * The registered function should return a value indicating what action the
  206. * ComSend routines should take regarding handshake suspensions:
  207. * COMSEND_OK no action, if data is waiting, keep waiting
  208. * COMSEND_GIVEUP if data is waiting, discard it and return
  209. * from ComSend??? call.
  210. * COMSEND_CLEAR_DATA discard all transmit buffers, this discards
  211. * any data waiting in a ComSend command
  212. * AND any data previously buffered.
  213. * COMSEND_FORCE_CONTINUATION force data to be transmitted, if waiting
  214. * for XON, pretend it was received. If
  215. * waiting for hardware handshake, disable
  216. * it. ComSend routine will continue trying
  217. * to send any waiting data.
  218. *
  219. * ARGUMENTS: pstCom -- handle to comm session
  220. * pfNewStatusFunct -- A pointer to a function matching the specs
  221. * described above or NULL if a default, do-nothing function
  222. * should be used. If the default function is used, ComSend
  223. * commands will essentially wait forever to send data.
  224. * ppfOldStatusFunct -- Address of pointer to put the pointer to
  225. * the previously registered function
  226. *
  227. * RETURNS: COM_OK if everything went ok
  228. * COM_INVALID_HANDLE if invalid com handle
  229. */
  230. int ComSendSetStatusFunction(const HCOM pstCom, STATUSFUNCT pfNewStatusFunct,
  231. STATUSFUNCT *ppfOldStatusFunct)
  232. {
  233. STATUSFUNCT pfHold = pstCom->pfUserFunction;
  234. unsigned afXmitStatus;
  235. long lHandshakeDelay;
  236. assert(ComValidHandle(pstCom));
  237. /* If user want's no status function, use an internal function to
  238. * avoid constant checks for null
  239. */
  240. if (pfNewStatusFunct == NULL)
  241. {
  242. pfNewStatusFunct = ComSendDefaultStatusFunction;
  243. }
  244. if (pfNewStatusFunct != pfHold)
  245. {
  246. ComSndBufrQuery(pstCom, &afXmitStatus, &lHandshakeDelay);
  247. /* call old function to give it a change to clear up details */
  248. (void)(*pfHold)(COMSEND_LASTCALL, afXmitStatus, lHandshakeDelay);
  249. /* call new function so it can initialize */
  250. pstCom->pfUserFunction = pfNewStatusFunct;
  251. (void)(*(pstCom->pfUserFunction))(COMSEND_FIRSTCALL, afXmitStatus,
  252. lHandshakeDelay);
  253. }
  254. if (ppfOldStatusFunct)
  255. *ppfOldStatusFunct = pfHold;
  256. return COM_OK;
  257. }
  258. /* * * * * * * * * * * *
  259. * Private functions *
  260. * * * * * * * * * * * */
  261. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  262. * ComSendDefaultStatusFunction
  263. *
  264. * DESCRIPTION: This function is used as the handshake handling function when
  265. * no caller-supplied function is available, that is, at program
  266. * start up or when the caller registeres the NULL function.
  267. *
  268. * ARGUMENTS: See description of handler in ComSendSetStatusFunction
  269. *
  270. * RETURNS: See description of handler in ComSendSetStatusFunction
  271. */
  272. int ComSendDefaultStatusFunction(int iReason, unsigned afHsStatus,
  273. long lDelay)
  274. {
  275. /* suppress complaints from lint and the compiler */
  276. iReason = iReason;
  277. afHsStatus = afHsStatus;
  278. lDelay = lDelay;
  279. /* This function does nothing, it is here to have something to point
  280. * pfUserFunction to when ComSendSetStatusFunction is called with
  281. * NULL argument.
  282. */
  283. return COM_OK;
  284. }
  285. /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  286. * ComSendCheck
  287. *
  288. * DESCRIPTION: This function is used internally to keep the flow of
  289. * transmitted data moving. It handles setting up and calling the
  290. * handshake handling functions and getting the local transmit
  291. * buffer passed to the SndBufr routines when they are ready.
  292. *
  293. * ARGUMENTS: pstCom -- handle to comm session
  294. * fDataWaiting -- TRUE if being called by a function that has
  295. * data to place in the send buffer when the buffer is full.
  296. *
  297. * RETURNS: COM_OK if the calling function should continue waiting for
  298. * space in the transmit buffer.
  299. * COM_INVALID_HANDLE if invalid com handle
  300. * COM_SEND_QUEUE_STUCK if the calling function should discard
  301. * any unbuffered data and return.
  302. */
  303. static int ComSendCheck(const HCOM pstCom, const int fDataWaiting)
  304. {
  305. int fResult = TRUE;
  306. unsigned afXmitStatus;
  307. long lHandshakeDelay;
  308. if (ComSndBufrBusy(pstCom) != COM_OK)
  309. {
  310. ComSndBufrQuery(pstCom, &afXmitStatus, &lHandshakeDelay);
  311. if (afXmitStatus != 0)
  312. {
  313. switch((*(pstCom->pfUserFunction))(fDataWaiting ?
  314. COMSEND_DATA_WAITING : COMSEND_NORMAL,
  315. afXmitStatus, lHandshakeDelay))
  316. {
  317. case COMSEND_OK:
  318. break;
  319. case COMSEND_GIVEUP:
  320. fResult = FALSE;
  321. break;
  322. case COMSEND_CLEAR_DATA:
  323. ComSendClear(pstCom);
  324. fResult = FALSE;
  325. break;
  326. #if 0 //* this should be replaced with a more general mechanism
  327. case COMSEND_FORCE_CONTINUATION:
  328. if (bittest(afXmitStatus, COMSB_WAIT_XON))
  329. ComSendXon(pstCom);
  330. else if (bittest(afXmitStatus,
  331. (COMSB_WAIT_CTS | COMSB_WAIT_DSR | COMSB_WAIT_DCD)))
  332. {
  333. // TODO: this will be replaced by ComSndBufrForce or such
  334. // (VOID)ComDisableHHS(pstCom);
  335. }
  336. else if (bittest(afXmitStatus, COMSB_WAIT_BUSY))
  337. {
  338. ComSendClear(pstCom);
  339. fResult = FALSE;
  340. }
  341. break;
  342. #endif
  343. default:
  344. assert(FALSE);
  345. break;
  346. }
  347. pstCom->fUserCalled = TRUE;
  348. }
  349. else if (pstCom->fUserCalled)
  350. {
  351. (void)(*(pstCom->pfUserFunction))(COMSEND_NORMAL, 0, 0L);
  352. pstCom->fUserCalled = FALSE;
  353. }
  354. }
  355. else
  356. {
  357. int rc = COM_OK;
  358. if (pstCom->nSendCount > 0)
  359. {
  360. rc = ComSndBufrSend(pstCom, pstCom->puchSendBufr, pstCom->nSendCount, 1);
  361. assert(rc == COM_OK);
  362. if (rc == COM_OK)
  363. {
  364. pstCom->puchSendBufr = pstCom->puchSendPut =
  365. ((pstCom->puchSendBufr == pstCom->puchSendBufr1) ?
  366. pstCom->puchSendBufr2 :
  367. pstCom->puchSendBufr1);
  368. pstCom->nSendCount = 0;
  369. }
  370. else if (rc == COM_PORT_NOT_OPEN)
  371. {
  372. #if !defined(NDEBUG)
  373. MessageBox(NULL,
  374. "Attempting to send data when not connected. Unable to send data.",
  375. NULL,
  376. MB_OK | MB_ICONINFORMATION | MB_TASKMODAL);
  377. #endif // !defined(NDEBUG)
  378. //
  379. // TODO:REV 4/26/2002 We need to disconnect here with loss of carrier.
  380. //
  381. //NotifyClient(pstCom->hSession, EVENT_LOST_CONNECTION,
  382. // CNCT_LOSTCARRIER | (sessQueryExit(pstCom->hSession) ? DISCNCT_EXIT : 0 ));
  383. ComSendClear(pstCom);
  384. fResult = FALSE;
  385. }
  386. }
  387. if (pstCom->fUserCalled)
  388. {
  389. (void)(*(pstCom->pfUserFunction))(COMSEND_NORMAL, 0, 0L);
  390. pstCom->fUserCalled = FALSE;
  391. }
  392. }
  393. return(fResult ? COM_OK : COM_SEND_QUEUE_STUCK);
  394. }
  395. /********************** end of comsend.c ***********************/