📄 modem.c
字号:
if( (HANDLE)INVALID_DEVICE != pLineDev->hDevice )
{
try
{
//
// We (device.exe PSL) were the current process when the device
// was opened, so we need to be the owner for DevlineDrop and
// the CloseHandle() to work as expected.
//
dwPrevProcPerms = SetProcPermissions(-1);
SetHandleOwner((HANDLE) pLineDev->hDevice, GetCurrentProcess());
SetProcPermissions(dwPrevProcPerms);
// If a call is in progress, terminate it
if (fDoDrop) {
DEBUGMSG(ZONE_CALLS, (L"UNIMODEM:DevlineClose - Callstate x%X, dropping call\r\n", pLineDev->dwCallState));
LeaveCriticalSection(&pLineDev->OpenCS);
DevlineDrop(pLineDev);
EnterCriticalSection(&pLineDev->OpenCS);
}
CloseHandle( pLineDev->hDevice );
CloseHandle( pLineDev->hDevice_r0);
CloseHandle( pLineDev->hMdmLog);
NullifyLineDevice(pLineDev, FALSE); // Reinit the line device
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
// Oops, we must have hit a bad handle. Fall thru & release the CS.
dwPrevProcPerms = 0;
}
}
pLineDev->dwPendingID = INVALID_PENDINGID;
LeaveCriticalSection(&pLineDev->OpenCS);
if (dwPrevCallState != LINECALLSTATE_IDLE) {
pLineDev->htCall = hPrevCall;
NewCallState(pLineDev, LINECALLSTATE_IDLE, 0L);
pLineDev->htCall = NULL;
}
DEBUGMSG(ZONE_FUNC|ZONE_CALLS, (TEXT("UNIMODEM:-DevlineClose\r\n")));
return SUCCESS;
}
//
// Function to signal any threads stuck in WaitCommEvent
//
LONG
SignalCommMask(
PTLINEDEV pLineDev
)
{
LONG rc = 0;
DWORD dwPrevProcPerms;
EnterCriticalSection(&pLineDev->OpenCS);
if ((HANDLE)INVALID_DEVICE != pLineDev->hDevice) {
try {
if (!SetCommMask( pLineDev->hDevice, 0)) {
DEBUGMSG(ZONE_ERROR, (TEXT("UNIMODEM:SignalCommMask SetCommMask(0) failed %d\n"), GetLastError()));
//
// It could be the case that the app called CloseHandle on the handle it got from lineGetID.
// If so, then try to get it back or open it again.
//
if (pLineDev->hDevice != INVALID_HANDLE_VALUE) {
dwPrevProcPerms = SetProcPermissions(-1);
rc = SetHandleOwner((HANDLE) pLineDev->hDevice, GetCurrentProcess());
SetProcPermissions(dwPrevProcPerms);
//
// If we can't change the handle owner, then we'll have to open it again
//
if (0 == rc) {
if ((pLineDev->hDevice = CreateFile(pLineDev->szDeviceName, GENERIC_READ | GENERIC_WRITE, 0,
NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE) {
rc = LINEERR_OPERATIONFAILED;
} else {
rc = 0;
}
} else {
rc = 0;
}
if (0 == rc) {
DEBUGMSG(ZONE_ERROR, (TEXT("UNIMODEM:SignalCommMask recovered handle\n")));
SetCommMask(pLineDev->hDevice, 0);
}
} else {
rc = LINEERR_OPERATIONFAILED;
}
}
} except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
// Exception means bad handle, so we can't do anything to cancel call
rc = LINEERR_OPERATIONFAILED;
}
}
if ((HANDLE)INVALID_DEVICE != pLineDev->hDevice_r0) {
if (!SetCommMask( pLineDev->hDevice_r0, 0)) {
DEBUGMSG(ZONE_ERROR, (TEXT("UNIMODEM:SignalCommMask SetCommMask(r0) failed %d\n"), GetLastError()));
rc = LINEERR_OPERATIONFAILED;
}
}
pLineDev->dwWaitMask = 0;
LeaveCriticalSection(&pLineDev->OpenCS);
return rc;
} // SignalCommMask
void
MdmCommandMode(
PTLINEDEV pLineDev
)
{
DCB commDCB;
//
// Turn off hardware flow control while sending commands.
//
GetCommState( pLineDev->hDevice, &commDCB );
commDCB.fRtsControl = RTS_CONTROL_ENABLE;
commDCB.fOutxCtsFlow = 0;
SetCommState( pLineDev->hDevice, &commDCB );
}
typedef LRESULT (WINAPI * PFN_SENDMESSAGE)(HWND,UINT,WPARAM,LPARAM);
#define HANGUP_TIME 4000
void
DoHangUp(
PTLINEDEV pLineDev
)
{
DWORD dwWaitReturn;
static const UCHAR szEscapeCmd[] = "+++";
static const UCHAR szHangup[] = "ATH\r\n";
static const UCHAR szReset[] = "ATZ\r\n";
// If a TermCtrl is displayed, get rid of it.
if( pLineDev->hwTermCtrl )
{
PFN_SENDMESSAGE pfnSendMessage;
if (pfnSendMessage = (PFN_SENDMESSAGE)GetProcAddress(g_hCoreDLL, L"SendMessageW")) {
// send a WM_CLOSE to the handle
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:DoHangUp - WM_CLOSE TermWnd\r\n")));
pfnSendMessage (pLineDev->hwTermCtrl, WM_CLOSE, 0, 0);
}
}
SignalCommMask(pLineDev);
// We don't want to finish up before the dialer thread has
// done his thing. So wait for the CallComplete event that
// the thread sets before exiting. Lets assume he'll finish
// within 4 seconds or we just give up.
dwWaitReturn = WaitForSingleObject(pLineDev->hCallComplete, 4*1000);
#ifdef DEBUG
if( WAIT_TIMEOUT == dwWaitReturn )
DEBUGMSG(ZONE_CALLS | ZONE_ERROR,
(TEXT("UNIMODEM:DoHangUp - timeout waiting for call complete\r\n")));
#endif
// Drop the line, aborting any call in progress.
if ((HANDLE)INVALID_DEVICE != pLineDev->hDevice ) {
try
{
PurgeComm(pLineDev->hDevice, PURGE_RXCLEAR|PURGE_TXCLEAR);
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:DoHangUp - hanging up\r\n")));
// Make sure the modem hangs up, etc.
if(IS_NULL_MODEM(pLineDev) ) {
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:DoHangUp EscapeCommFunction - DTR off\r\n")));
EscapeCommFunction ( pLineDev->hDevice, CLRDTR);
Sleep( 400 );
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:DoHangUp EscapeCommFunction - DTR on\r\n")));
EscapeCommFunction ( pLineDev->hDevice, SETDTR);
Sleep( 200 );
} else {
MdmCommandMode(pLineDev);
pLineDev->dwWaitMask = EV_DEFAULT;
SetWatchdog(pLineDev, HANGUP_TIME);
MdmSendCommand(pLineDev, szEscapeCmd);
MdmGetResponse(pLineDev, (PUCHAR)szEscapeCmd, NOCS, CLOSING);
SetWatchdog(pLineDev, HANGUP_TIME);
MdmSendCommand(pLineDev, szHangup);
MdmGetResponse(pLineDev, (PUCHAR)szHangup, NOCS, CLOSING);
SetWatchdog(pLineDev, HANGUP_TIME/2);
MdmSendCommand(pLineDev, szReset);
MdmGetResponse(pLineDev, (PUCHAR)szReset, NOCS, CLOSING);
SetWatchdog(pLineDev, 0);
}
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:DoHangUp - hangup done\r\n")));
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
dwWaitReturn = 0;
}
if (PENDING_LINEDROP == pLineDev->dwPendingType) {
SetAsyncStatus(pLineDev, 0);
} else {
DEBUGMSG(ZONE_ERROR, (TEXT("UNIMODEM:DoHangUp - PendingType = %d\r\n"), pLineDev->dwPendingType));
}
}
#ifdef DEBUG
else
{
DEBUGMSG(ZONE_CALLS | ZONE_ERROR,
(TEXT("UNIMODEM:DoHangUp - handle invalid. Can't cancel call\r\n")));
}
#endif
}
//****************************************************************************
// DevlineDrop()
//
// Function: Emulate the TAPI lineDrop call.
//
//****************************************************************************
LONG
DevlineDrop (
PTLINEDEV pLineDev
)
{
DEBUGMSG(ZONE_FUNC|ZONE_CALLS,
(TEXT("UNIMODEM:+DevlineDrop\r\n")));
EnterCriticalSection(&pLineDev->OpenCS);
pLineDev->dwNumRings = 0;
// Don't unnecessarily attempt to drop
if ((LINECALLSTATE_DISCONNECTED == pLineDev->dwCallState ) || (LINECALLSTATE_IDLE == pLineDev->dwCallState )) {
switch(pLineDev->DevState) {
case DEVST_DISCONNECTED:
case DEVST_PORTLISTENINIT:
case DEVST_PORTLISTENING:
pLineDev->DevState = DEVST_DISCONNECTED;
LeaveCriticalSection(&pLineDev->OpenCS);
SetAsyncStatus(pLineDev, 0);
DEBUGMSG(ZONE_FUNC|ZONE_CALLS,
(TEXT("UNIMODEM:-DevlineDrop, line already dropped\r\n")));
return SUCCESS;
}
}
pLineDev->dwCallFlags |= CALL_DROPPING; // Flag that this call is going away
pLineDev->dwCallFlags &= ~CALL_ACTIVE;
// Do we need to do a hangup?
if (LINECALLSTATE_IDLE == pLineDev->dwCallState &&
DEVST_DISCONNECTED == pLineDev->DevState)
{
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:DevlineDrop - no action required\r\n")));
SetAsyncStatus(pLineDev, 0);
}
else
{
LeaveCriticalSection(&pLineDev->OpenCS);
DoHangUp(pLineDev);
EnterCriticalSection(&pLineDev->OpenCS);
};
if (pLineDev->dwCallFlags & CALL_ALLOCATED) {
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:DevlineDrop - sending LINECALLSTATE_IDLE\n")));
NewCallState(pLineDev, LINECALLSTATE_IDLE, 0L);
}
pLineDev->DevState = DEVST_DISCONNECTED;
pLineDev->dwCallState = LINECALLSTATE_IDLE;
pLineDev->dwCallFlags = 0;
LeaveCriticalSection(&pLineDev->OpenCS);
DEBUGMSG(ZONE_FUNC|ZONE_CALLS, (TEXT("UNIMODEM:-DevlineDrop\r\n")));
return SUCCESS;
}
LONG
DoDevlineDrop(
PTLINEDEV pLineDev
)
{
LONG rc;
rc = DevlineDrop(pLineDev);
SetAsyncStatus(pLineDev, 0);
return rc;
}
void
FreeNextCmd(
PTLINEDEV pLineDev
)
{
if (pLineDev->lpstrNextCmd) {
TSPIFree(pLineDev->lpstrNextCmd);
pLineDev->lpstrNextCmd = NULL;
}
}
//
// Wait for a disconnect on a connected modem. Send a LINE_CALLSTATE
// upon disconnect.
//
void
WatchForDisconnect(
PTLINEDEV pLineDev
)
{
DWORD Mask;
DWORD ModemStatus;
DWORD BaudRate;
DCB commDCB;
BOOL bExit;
DEBUGMSG(ZONE_FUNCTION|ZONE_CALLS, (TEXT("UNIMODEM:+WatchForDisconnect\n")));
DEBUGMSG(ZONE_CALLS, (L"UNIMODEM:WatchForDisconnect: Call(0x%x) is %s, CallState(0x%x) is %s\n",
pLineDev->dwCallFlags, (pLineDev->dwCallFlags & CALL_ACTIVE) ? L"ACTIVE" : L"NOT ACTIVE",
pLineDev->dwCallState, (pLineDev->dwCallState == LINECALLSTATE_CONNECTED) ? L"CONNECTED" : L"NOT CONNECTED"));
// Enable devconfig settings
GetCommState( pLineDev->hDevice, &commDCB );
BaudRate = commDCB.BaudRate; // Preserve connected baud rate
SetDCBfromDevMiniCfg(&commDCB, &(pLineDev->DevMiniCfg));
commDCB.BaudRate = BaudRate;
SetCommState( pLineDev->hDevice, &commDCB );
DEBUGMSG(ZONE_FUNCTION|ZONE_CALLS,
(TEXT("UNIMODEM:WatchForDisconnect - RTS Control %d, CTS Out Flow %d, XON/XOFF out/in %d/%d\r\n\r\n"),
commDCB.fRtsControl, commDCB.fOutxCtsFlow, commDCB.fOutX, commDCB.fInX));
EnterCriticalSection(&pLineDev->OpenCS);
bExit = (pLineDev->dwWaitMask == 0);
if (!bExit) {
SetCommMask(pLineDev->hDevice_r0, EV_RLSD);
}
LeaveCriticalSection(&pLineDev->OpenCS);
if (bExit) {
goto wfd_exit;
}
while ((pLineDev->dwCallState == LINECALLSTATE_CONNECTED) && (pLineDev->dwCallFlags & CALL_ACTIVE)) {
if (WaitCommEvent(pLineDev->hDevice_r0, &Mask, NULL )) {
//
// Remote disconnect detection
//
if (Mask & EV_RLSD) {
ModemStatus = 0;
if (GetCommModemStatus(pLineDev->hDevice_r0, &ModemStatus)) {
if (!(ModemStatus & MS_RLSD_ON)) {
DEBUGMSG(ZONE_CALLS, (TEXT("UNIMODEM:WatchForDisconnect RLSD went low\n")));
DoHangUp(pLineDev);
pLineDev->DevState = DEVST_DISCONNECTED;
pLineDev->dwCallFlags &= ~CALL_ACTIVE;
pLineDev->dwNumRings = 0;
NewCallState(pLineDev, LINECALLSTATE_DISCONNECTED, LINEDISCONNECTMODE_NORMAL);
NewCallState(pLineDev, LINECALLSTATE_IDLE, 0L);
break;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -