📄 dial.c
字号:
while (MODEM_IGNORE == ModemResp)
{
if (bOpened) {
if (!LineNotDropped(pLineDev, OrigDevState)) {
break;
}
}
try
{
ModemStat = 0;
if (bInCS) {
//
// To help avoid missing signals from SignalControlThread, stay in CS as long
// as possible before calling WaitCommEvent.
//
LeaveCriticalSection(&pLineDev->OpenCS);
bInCS = FALSE;
}
bStatus = WaitCommEvent(pLineDev->hDevice, &ModemStat, NULL);
//
// Look for signals from SignalControlThread
//
if (pLineDev->dwPendingType != OrigPendingOp) {
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:MdmGetResponse %s interrupted %s\n"),PendingOpName(pLineDev->dwPendingType) , PendingOpName(OrigPendingOp)));
switch (pLineDev->dwPendingType){
case PENDING_LINEDROP:
ModemResp = MODEM_ABORT;
break;
default:
ModemResp = MODEM_FAILURE;
break;
} // endswitch
goto mgr_exit;
}
if (pLineDev->bWatchdogTimedOut) {
pLineDev->bWatchdogTimedOut = FALSE;
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:MdmGetResponse - Watchdog timed out\n")));
ModemResp = MODEM_EXIT;
goto mgr_exit;
}
if (FALSE == bStatus) {
dwLen = GetLastError();
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:MdmGetResponse - WaitCommEvent failed %d\n"), dwLen));
ModemResp = MODEM_EXIT;
goto mgr_exit;
}
if (ModemStat) {
#ifdef DEBUG
DisplayModemStatus(ModemStat);
#endif
if (ModemStat & EV_ERR) {
if (ClearCommError(pLineDev->hDevice, &dwLen, NULL)) {
#ifdef DEBUG
if (dwLen) {
DisplayCommError(dwLen);
}
} else {
dwLen = GetLastError();
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:MdmGetResponse ClearCommError failed %d\n"), dwLen));
#endif
}
}
if( ModemStat & EV_RING) {
ModemResp = MODEM_RING;
}
if (ModemStat & EV_RXCHAR) {
if (bOpened) {
if (!LineNotDropped(pLineDev, OrigDevState)) {
break;
}
}
if (!ReadFile (pLineDev->hDevice, (LPVOID)InBuf, sizeof(InBuf)-1, &dwLen, 0)) {
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:MdmGetResponse - ReadFile failed %d\n"), GetLastError()));
ModemResp = MODEM_EXIT;
goto mgr_exit;
}
// If we didn't read much data, retry to make sure we have all of it.
if ( dwLen < LOW_COMPLETE_READ_THRESHOLD) {
DWORD dwNewLen;
// Sleep here to give the other threads ( IRCOMM ... ) time to procoess
Sleep(50);
// Null terminate for the debug output
InBuf[dwLen] = 0;
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:First MdmGetResponse Response = %a\n"), InBuf));
// Read from the port again
if (ReadFile (pLineDev->hDevice, (LPVOID)(InBuf+dwLen), sizeof(InBuf)-1-dwLen, &dwNewLen, 0)) {
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:MdmGetResponse - Second ReadFile succeeded. %i characters recovered\n"),dwNewLen));
dwLen += dwNewLen;
}
}
InBuf[dwLen] = 0;
WriteModemLog(pLineDev, (PUCHAR)InBuf, MDMLOG_RESPONSE);
#ifdef DEBUG_RESPONSES
if (dwLen) {
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:MdmGetResponse Response = %a\n"), InBuf));
}
#endif
// Now lets process each response as they arrive
for( i=0; i<(int)dwLen; i++ )
{
ModemResponse[ModemResponseIndex] = InBuf[i];
if( IS_NULL_MODEM(pLineDev) )
{
//
// Only allow one response per call to MdmGetResponse for a DCC connection
//
ModemResp = MODEM_FAILURE;
//
// Are we client or server?
//
if (pLineDev->dwPendingType == PENDING_LINEMAKECALL) {
pchDCC = (PUCHAR)pchDCCResp;
DCCResp = MODEM_CONNECT;
} else {
pchDCC = (PUCHAR)pchDCCCmd;
DCCResp = MODEM_RING;
}
dwDCCLen = strlen(pchDCC);
if( ModemResponse[ModemResponseIndex] == pchDCC[ModemResponseIndex] )
{
ModemResponseIndex++;
// characters match so far, see if we have a complete response.
if( ModemResponseIndex >= dwDCCLen )
{
// OK, we got a full response. Zero terminate it and exit
ModemResponse[ModemResponseIndex] = 0;
// No need to call response handler, we already did all the work.
ModemResp = DCCResp;
DEBUGMSG (ZONE_CALLS, (TEXT("UNIMODEM:MdmGetResponse Null Response detected\r\n")));
break;
}
}
else // character mismatch - restart scan sequence.
{
// If character is 'C', it might be first character of the actual
// response. Any other case means that all data up to here is useless
// so we should toss it. This is only true because 'C' appears only as
// the first character of a response, and never after that.
ModemResponseIndex = 0;
if (pchDCC[0] == InBuf[i])
{
ModemResponse[ModemResponseIndex] = InBuf[i];
ModemResponseIndex++;
}
}
}
else
{
if( (CR == InBuf[i]) ||
(LF == InBuf[i]) ||
((DWORD)i == dwLen-1) ||
((pLineDev->dwMaxCmd - 1) <= ModemResponseIndex) )
{
// have a complete response (or max length). Now we parse it.
ModemResponse[ModemResponseIndex] = 0; // Lets Zero Terminate the string
ModemResp = ModemResponseHandler( pLineDev, ModemResponse, pszCommand );
switch (ModemResp) {
case MODEM_CARRIER:
ParseConnectSpeed(pLineDev, ModemResponse);
// fall through!!!
case MODEM_PROTOCOL:
case MODEM_PROGRESS:
NewCallState(pLineDev, LINECALLSTATE_PROCEEDING, 0L);
if (i < (int)(dwLen - 1)) {
ModemResponseIndex = 0; // Start a new response
ModemResp = MODEM_IGNORE;
}
break;
case MODEM_UNKNOWN:
case MODEM_IGNORE:
ModemResponseIndex = 0; // Start a new response
ModemResp = MODEM_IGNORE;
break;
case MODEM_CONNECT:
ParseConnectSpeed(pLineDev, ModemResponse);
// fall through
default:
goto mgr_exit;
}
ModemResponseIndex = 0; // Start a new response
}
else
{
ModemResponseIndex++; //Add another character to the string
}
}
}
}
}
else
{
// A zero ModemStat is an error, and indicates that the
// waitcommevent was stopped by our watchdog or linedrop.
ModemResp = MODEM_FAILURE;
DEBUGMSG (ZONE_CALLS, (TEXT("UNIMODEM:MdmGetResponse - Timeout\r\n")));
goto mgr_exit;
}
DEBUGMSG(ZONE_FUNC|ZONE_CALLS, (TEXT("UNIMODEM:MdmGetResponse %s\n"), ResponseName(ModemResp)));
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
// Must have been a bad handle. Give up
ModemResp = MODEM_FAILURE;
DEBUGMSG (ZONE_FUNC|ZONE_CALLS,
(TEXT("UNIMODEM:MdmGetResponse - Exception. Handle \r\n"),
pLineDev->hDevice ));
}
}
mgr_exit:
EnterCriticalSection(&pLineDev->OpenCS);
pLineDev->dwWaitMask = EV_DEFAULT;
LeaveCriticalSection(&pLineDev->OpenCS);
if (bInCS) {
LeaveCriticalSection(&pLineDev->OpenCS);
}
DEBUGMSG(ZONE_FUNC, (TEXT("UNIMODEM:-MdmGetResponse %s\r\n"), ResponseName(ModemResp)));
return ModemResp;
}
//
// There were cases where the ModemWatchdog thread would not make it to the WaitForSingleObject
// before the next SetWatchdog happened. This would leave two or more watchdogs runnning at the
// same time which leads to all kinds of problems. Now SetWatchdog passes a UNIMODEM_WATCHDOG_INFO
// structure to the thread and the watchdog checks that it is the current one before aborting
// any pending operations.
//
typedef struct _UNIMODEM_WATCHDOG_INFO {
PTLINEDEV pLineDev;
DWORD dwTimeout;
DWORD dwThisWatchdog;
} UNIMODEM_WATCHDOG_INFO, * PUNIMODEM_WATCHDOG_INFO;
// **********************************************************************
//
// This is the dialer/answer watchdog thread. It is created by the dialer thread.
// Its purpose is to wait for a specified interval, or until signalled by
// the dialer. If the wait times out, then the watchdog calls into the
// COM port driver, causing the waitcommevent in the dialer thread to
// return.
//
// **********************************************************************
void
ModemWatchdog(
PUNIMODEM_WATCHDOG_INFO pWDInfo
)
{
DWORD RetCode;
BOOL bAbort;
PTLINEDEV pLineDev;
DWORD dwTimeout;
DWORD dwThisWatchdog;
pLineDev = pWDInfo->pLineDev;
dwTimeout = pWDInfo->dwTimeout;
dwThisWatchdog = pWDInfo->dwThisWatchdog;
TSPIFree(pWDInfo);
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:+ModemWatchdog(%d) - timeout set to %d seconds (ends %d)\r\n"),
dwThisWatchdog, dwTimeout/1000, GetTickCount() + dwTimeout));
// Wait for the specified interval.
RetCode = WaitForSingleObject( pLineDev->hTimeoutEvent, dwTimeout );
if ((dwThisWatchdog == pLineDev->dwCurWatchdog) && ( WAIT_TIMEOUT == RetCode )) {
pLineDev->bWatchdogTimedOut = TRUE;
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:ModemWatchdog(%d) *** %s TIMEOUT at %d\n"),
dwThisWatchdog, GetPendingName(pLineDev->dwPendingType), GetTickCount()));
// We need to stop the waitcommevent. Note that we set the
// mask to 0, which will cause any subsequent waitcommevent
// calls to also return immediately.
SignalCommMask(pLineDev);
switch (pLineDev->dwPendingType) {
case PENDING_LINEMAKECALL:
//
// Allow retries for DCC connections and ModemInit()
//
if (IS_NULL_MODEM(pLineDev)) {
bAbort = FALSE;
} else {
bAbort = (pLineDev->MdmState != MDMST_INITIALIZING);
}
break;
case PENDING_LINEANSWER:
NewCallState(pLineDev, LINECALLSTATE_DISCONNECTED, LINEDISCONNECTMODE_UNKNOWN);
NewCallState(pLineDev, LINECALLSTATE_IDLE, 0L);
bAbort = TRUE;
break;
case PENDING_LINEDIAL:
bAbort = TRUE;
break;
case PENDING_LINEDROP:
// Don't fail lineDrop due to timeouts
SetEvent(pLineDev->hCallComplete);
// FALLTHROUGH
default:
bAbort = FALSE;
break;
}
// We set an event when we are done so that DevLineDrop can
// continue with his cleanup.
if (bAbort) {
SetEvent(pLineDev->hCallComplete);
SetAsyncStatus(pLineDev, LINEERR_OPERATIONFAILED);
}
}
#ifdef DEBUG
else {
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:ModemWatchdog(%d) cancelled at %d\r\n"), dwThisWatchdog, GetTickCount()));
}
#endif
// This is a one shot timeout. The thread should go away as
// soon as the timer expires or is signalled/cancelled.
}
// **********************************************************************
// Wrapper function to start the watchdog.
// Note that a timeout of 0 cancels the current watchdog.
// **********************************************************************
DWORD
SetWatchdog(
PTLINEDEV pLineDev,
DWORD dwTimeout
)
{
HANDLE hThread;
PUNIMODEM_WATCHDOG_INFO pWDInfo;
pLineDev->dwCurWatchdog++;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -