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

/* ComSend -- Text sending routines for HyperACCESS
*
* Copyright 1994 by Hilgraeve Inc. -- Monroe, MI
* All rights reserved
*
* $Revision: 8 $
* $Date: 7/12/02 10:45a $
*/
#include <windows.h>
#pragma hdrstop
// #define DEBUGSTR
#include "stdtyp.h"
#include <tdll\assert.h>
#include "com.h"
#include "comdev.h"
#include "com.hh"
/* --- Internal prototypes --- */
static int ComSendCheck(const HCOM pstCom, const int fDataWaiting);
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* ComSendChar
*
* DESCRIPTION:
* Adds a character to the send buffer to be transmitted. The
* character will not actually be transferred to the transmit
* routines until the buffer fills up or a call to ComSendCharNow
* is made or a call to ComSendPush is made while the transmitter
* is not busy.
*
* ARGUMENTS:
* pstCom -- handle to comm session
* uchCode -- The character to be transmitted.
*
* RETURNS:
* COM_OK if the character is successfully buffered.
* COM_INVALID_HANDLE if invalid com handle
* COM_SEND_BUFFER_FULL if the buffer is full and the
* caller-supplied handshake function returns a code
* indicating that waiting data should be discarded.
*/
int ComSendChar(const HCOM pstCom, const TCHAR chCode)
{
assert(ComValidHandle(pstCom));
while (pstCom->nSBufrSize > 0 && (pstCom->nSendCount >= pstCom->nSBufrSize))
{
/* wait until there is room in buffer or we're told to give up. */
if (ComSendCheck(pstCom, TRUE) != COM_OK)
return FALSE;
if (pstCom->nSendCount >= pstCom->nSBufrSize)
(void)ComSndBufrWait(pstCom, 2);
}
/* Place char in buffer and assume it will get launched later. */
if(pstCom && &pstCom->puchSendPut)
{
*pstCom->puchSendPut++ = chCode;
++pstCom->nSendCount;
}
return TRUE;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* ComSendCharNow
*
* DESCRIPTION: Adds a character to the send buffer and then waits to make
* sure the send buffer gets passed to the transmission routine.
* This function does NOT wait until the character is actually
* transmitted. Handshaking may still delay actual transmission
* but no subsequent calls to any ComSend??? routines are needed
* to get the character on its way. ComSendWait can be used to
* wait until all characters are actually out the port.
*
* ARGUMENTS: pstCom -- handle to comm session
* chCode -- The character to be transmitted.
*
* RETURNS: COM_OK if the character is successfully buffered and passed to
* the transmission routines.
* COM_INVALID_HANDLE if invalid com handle
* COM_SEND_QUEUE_STUCK if the caller-supplied handshake function
* returns a code indicating that waiting data should be
* discarded before the buffer can be queued for transmission.
*/
int ComSendCharNow(const HCOM pstCom, const TCHAR chCode)
{
assert(ComValidHandle(pstCom));
while (pstCom->nSBufrSize > 0 && (pstCom->nSendCount >= pstCom->nSBufrSize))
{
/* buffer is full, wait until there is room or we are
* told to give up
*/
if (ComSendCheck(pstCom, TRUE) != COM_OK)
return FALSE;
if (pstCom->nSendCount >= pstCom->nSBufrSize)
ComSndBufrWait(pstCom, 2);
}
if(pstCom && pstCom->puchSendPut)
{
*pstCom->puchSendPut++ = chCode;
++pstCom->nSendCount;
/* wait until local buffer is passed to SndBufr or we are
* told to give up
*/
while (pstCom->nSendCount > 0)
{
// This will pass buffer to SndBufr as soon as possible
if (ComSendCheck(pstCom, TRUE) != COM_OK)
return FALSE;
if (pstCom->nSendCount > 0)
ComSndBufrWait(pstCom, 2);
}
}
return TRUE;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* ComSendPush
*
* DESCRIPTION: This routine should be called periodically by any code that
* uses ComSendChar() when there are no characters to be
* transmitted immediately. Calling this function accomplishes
* two things.
* 1. It will cause any buffered send characters to be passed to the actual
* transmission routines as soon as they are not busy.
* 2. It will cause the caller-registered handshake handler function to be
* called if transmission is suspended by handshaking.
*
* ARGUMENTS: pstCom -- handle to comm session
*
* RETURNS: same as ComSendCheck()
*/
int ComSendPush(const HCOM pstCom)
{
return ComSendCheck(pstCom, FALSE);
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* ComSendWait
*
* DESCRIPTION: This function waits until all buffered send data is actually
* passed to the transmit hardware or until the handshake handling
* function returns a code indicating that data should be discared.
*
* ARGUMENTS: pstCom -- handle to comm session
* none
*
* RETURNS: COM_OK if all data has been transmitted.
* COM_SEND_QUEUE_STUCK if a handshake handling function
* indicated that data should be discarded.
*/
int ComSendWait(const HCOM pstCom)
{
assert(ComValidHandle(pstCom));
while (pstCom->nSendCount > 0 || ComSndBufrWait(pstCom, 2) != COM_OK)
{
if (ComSendCheck(pstCom, FALSE) != COM_OK)
{
return COM_SEND_QUEUE_STUCK;
}
}
return COM_OK;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* ComSendClear
*
* DESCRIPTION: Clears all data waiting for tranmission, both in the local
* ComSend buffer and the SndBufr buffer currently being
* transmitted.
*
* ARGUMENTS: pstCom -- handle to comm session
*
* RETURNS: always returns COM_OK
*/
int ComSendClear(const HCOM pstCom)
{
assert(ComValidHandle(pstCom));
ComSndBufrClear(pstCom);
pstCom->puchSendPut = pstCom->puchSendBufr;
pstCom->nSendCount = 0;
return COM_OK;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* ComSendSetStatusFunction
*
* DESCRIPTION: Registers a function to be called to handle handshaking status
* displays, timeouts, etc. while sending.
*
* The registered function is called when it is registered, when it is being
* replaced, and during sending when a handshaking suspension is detected.
* Normally, the function is not called if transmission is not suspended.
* After being called one or more times with a suspension, though, it will
* be called one additional time after the suspension clears to allow the
* function to clear any visible indicators.
*
* The registered function is passed the following arguments
* usReason -- Contains a code indicating the reason the function
* was called. It will be one of:
* COMSEND_FIRSTCALL -- if function is being installed
* COMSEND_LASTCALL -- if function is being replaced
* COMSEND_DATA_WAITING -- if there is data waiting
* that will not fit in the send buffer.
* COMSEND_NORMAL -- if called due to handshake
* condition but no data is in danger of being lost.
* fusHsStatus -- A value contining bits which indicate what transmission
* is waiting for. The bits are defined in com.h as
* COMSB_WAIT_XXX.
* lDelay -- The amount of time in tenths of seconds since
* transmission was suspended. This time will not
* begin incrementing until there is data to transmit.
*
* The registered function should return a value indicating what action the
* ComSend routines should take regarding handshake suspensions:
* COMSEND_OK no action, if data is waiting, keep waiting
* COMSEND_GIVEUP if data is waiting, discard it and return
* from ComSend??? call.
* COMSEND_CLEAR_DATA discard all transmit buffers, this discards
* any data waiting in a ComSend command
* AND any data previously buffered.
* COMSEND_FORCE_CONTINUATION force data to be transmitted, if waiting
* for XON, pretend it was received. If
* waiting for hardware handshake, disable
* it. ComSend routine will continue trying
* to send any waiting data.
*
* ARGUMENTS: pstCom -- handle to comm session
* pfNewStatusFunct -- A pointer to a function matching the specs
* described above or NULL if a default, do-nothing function
* should be used. If the default function is used, ComSend
* commands will essentially wait forever to send data.
* ppfOldStatusFunct -- Address of pointer to put the pointer to
* the previously registered function
*
* RETURNS: COM_OK if everything went ok
* COM_INVALID_HANDLE if invalid com handle
*/
int ComSendSetStatusFunction(const HCOM pstCom, STATUSFUNCT pfNewStatusFunct,
STATUSFUNCT *ppfOldStatusFunct)
{
STATUSFUNCT pfHold = pstCom->pfUserFunction;
unsigned afXmitStatus;
long lHandshakeDelay;
assert(ComValidHandle(pstCom));
/* If user want's no status function, use an internal function to
* avoid constant checks for null
*/
if (pfNewStatusFunct == NULL)
{
pfNewStatusFunct = ComSendDefaultStatusFunction;
}
if (pfNewStatusFunct != pfHold)
{
ComSndBufrQuery(pstCom, &afXmitStatus, &lHandshakeDelay);
/* call old function to give it a change to clear up details */
(void)(*pfHold)(COMSEND_LASTCALL, afXmitStatus, lHandshakeDelay);
/* call new function so it can initialize */
pstCom->pfUserFunction = pfNewStatusFunct;
(void)(*(pstCom->pfUserFunction))(COMSEND_FIRSTCALL, afXmitStatus,
lHandshakeDelay);
}
if (ppfOldStatusFunct)
*ppfOldStatusFunct = pfHold;
return COM_OK;
}
/* * * * * * * * * * * *
* Private functions *
* * * * * * * * * * * */
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* ComSendDefaultStatusFunction
*
* DESCRIPTION: This function is used as the handshake handling function when
* no caller-supplied function is available, that is, at program
* start up or when the caller registeres the NULL function.
*
* ARGUMENTS: See description of handler in ComSendSetStatusFunction
*
* RETURNS: See description of handler in ComSendSetStatusFunction
*/
int ComSendDefaultStatusFunction(int iReason, unsigned afHsStatus,
long lDelay)
{
/* suppress complaints from lint and the compiler */
iReason = iReason;
afHsStatus = afHsStatus;
lDelay = lDelay;
/* This function does nothing, it is here to have something to point
* pfUserFunction to when ComSendSetStatusFunction is called with
* NULL argument.
*/
return COM_OK;
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* ComSendCheck
*
* DESCRIPTION: This function is used internally to keep the flow of
* transmitted data moving. It handles setting up and calling the
* handshake handling functions and getting the local transmit
* buffer passed to the SndBufr routines when they are ready.
*
* ARGUMENTS: pstCom -- handle to comm session
* fDataWaiting -- TRUE if being called by a function that has
* data to place in the send buffer when the buffer is full.
*
* RETURNS: COM_OK if the calling function should continue waiting for
* space in the transmit buffer.
* COM_INVALID_HANDLE if invalid com handle
* COM_SEND_QUEUE_STUCK if the calling function should discard
* any unbuffered data and return.
*/
static int ComSendCheck(const HCOM pstCom, const int fDataWaiting)
{
int fResult = TRUE;
unsigned afXmitStatus;
long lHandshakeDelay;
if (ComSndBufrBusy(pstCom) != COM_OK)
{
ComSndBufrQuery(pstCom, &afXmitStatus, &lHandshakeDelay);
if (afXmitStatus != 0)
{
switch((*(pstCom->pfUserFunction))(fDataWaiting ?
COMSEND_DATA_WAITING : COMSEND_NORMAL,
afXmitStatus, lHandshakeDelay))
{
case COMSEND_OK:
break;
case COMSEND_GIVEUP:
fResult = FALSE;
break;
case COMSEND_CLEAR_DATA:
ComSendClear(pstCom);
fResult = FALSE;
break;
#if 0 //* this should be replaced with a more general mechanism
case COMSEND_FORCE_CONTINUATION:
if (bittest(afXmitStatus, COMSB_WAIT_XON))
ComSendXon(pstCom);
else if (bittest(afXmitStatus,
(COMSB_WAIT_CTS | COMSB_WAIT_DSR | COMSB_WAIT_DCD)))
{
// TODO: this will be replaced by ComSndBufrForce or such
// (VOID)ComDisableHHS(pstCom);
}
else if (bittest(afXmitStatus, COMSB_WAIT_BUSY))
{
ComSendClear(pstCom);
fResult = FALSE;
}
break;
#endif
default:
assert(FALSE);
break;
}
pstCom->fUserCalled = TRUE;
}
else if (pstCom->fUserCalled)
{
(void)(*(pstCom->pfUserFunction))(COMSEND_NORMAL, 0, 0L);
pstCom->fUserCalled = FALSE;
}
}
else
{
int rc = COM_OK;
if (pstCom->nSendCount > 0)
{
rc = ComSndBufrSend(pstCom, pstCom->puchSendBufr, pstCom->nSendCount, 1);
assert(rc == COM_OK);
if (rc == COM_OK)
{
pstCom->puchSendBufr = pstCom->puchSendPut =
((pstCom->puchSendBufr == pstCom->puchSendBufr1) ?
pstCom->puchSendBufr2 :
pstCom->puchSendBufr1);
pstCom->nSendCount = 0;
}
else if (rc == COM_PORT_NOT_OPEN)
{
#if !defined(NDEBUG)
MessageBox(NULL,
"Attempting to send data when not connected. Unable to send data.",
NULL,
MB_OK | MB_ICONINFORMATION | MB_TASKMODAL);
#endif // !defined(NDEBUG)
//
// TODO:REV 4/26/2002 We need to disconnect here with loss of carrier.
//
//NotifyClient(pstCom->hSession, EVENT_LOST_CONNECTION,
// CNCT_LOSTCARRIER | (sessQueryExit(pstCom->hSession) ? DISCNCT_EXIT : 0 ));
ComSendClear(pstCom);
fResult = FALSE;
}
}
if (pstCom->fUserCalled)
{
(void)(*(pstCom->pfUserFunction))(COMSEND_NORMAL, 0, 0L);
pstCom->fUserCalled = FALSE;
}
}
return(fResult ? COM_OK : COM_SEND_QUEUE_STUCK);
}
/********************** end of comsend.c ***********************/