⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 autodial.c

📁 WinCE5.0部分核心源码
💻 C
📖 第 1 页 / 共 3 页
字号:
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// This source code is licensed under Microsoft Shared Source License
// Version 1.0 for Windows CE.
// For a copy of the license visit http://go.microsoft.com/fwlink/?LinkId=3223.
//
/*--
Module Name: autodial.c
Abstract: Autodialer functions
--*/

#include <autodprv.h>
#include <iphlpapi.h>

#include <Windev.h>


// Debug zones
#define ZONE_INIT          DEBUGZONE(0)
#define ZONE_CONNECTION    DEBUGZONE(11)
#define ZONE_IDLETIMEOUT   DEBUGZONE(12)
#define ZONE_FUNCTION      DEBUGZONE(13)
#define ZONE_WARN          DEBUGZONE(14)
#define ZONE_ERROR         DEBUGZONE(15)

#define STATE_OFF			0
#define STATE_ON			1
#define STATE_STARTING_UP	2
#define STATE_SHUTTING_DOWN	3

// FILETIME (100-ns intervals) to milleseonds (10 x 1000)
#define FILETIME_TO_MILLISECONDS  10000


#ifdef DEBUG
#define    myleave(e)    { ASSERT(dwRet != 0); err = e; goto done; }
#define    myretleave(r,e) { dwRet = r; err = e;  goto done; }
#else
#define    myleave(e)       { ASSERT(dwRet != 0);  goto done;}
#define    myretleave(r,e)  { dwRet = r; goto done; }
#endif


typedef struct
{
	HRASCONN 	m_hRasConn;					// Global connection context
	TCHAR       szRasEntryName[RAS_MaxEntryName + 1];

	// Used to determine when to end the connection.
	__int64    	m_ftIdleTimeout;			// amount of time before we hang up, measure in filetime.
	HANDLE  	m_hTimerThread;				// Handle to created timer thread
	HANDLE      m_hTimerEvent;              // Event to fire.
	DWORD 		m_dwBytesTxRx;				// Total # of bytes sent and received
	__int64		m_ftLastActivity;			// Treated as FILETIME, last time bytes were sent

	DWORD		m_dwRedialAttempts;         // # of times we'll try to go throug redial cycle
	DWORD		m_dwRedialPauseTime;        // Sleep this many ms between calls

	BOOL        m_fEnableOnPublicInterface;
	 
	// Used for FAIL_RETRY_WAIT monitoring
	__int64     m_ftFailRetryWait;           // Registry configured amount of time to wait on.
	int 		m_iLastFailIndex;               
	__int64     g_ftLastFailTime;		     // Element treated as FILETIME 
 }
AUTODIAL_CONNECTION_INFO, *PAUTODIAL_CONNECTION_INFO;


// Global variables
AUTODIAL_CONNECTION_INFO g_AutoDialConn;
DWORD            g_fState;
CRITICAL_SECTION g_GlobalCS;
BOOL			 g_fAutodialInitialized;
HINSTANCE        g_hInstance;


// Function definitions
DWORD AutoDialConnect(RASDIALPARAMS *pRasDialParams);
DWORD AutoDialEndConnectionInternal(BOOL fTimedOut);
DWORD AutodialReadRegistrySettings(TCHAR *szDialRasEntryName, TCHAR *pszEntryName1, TCHAR *pszEntryName2, AUTODIAL_CONNECTION_INFO *pConnInfo);
BOOL GetConnectedStatus(TCHAR *szEntryName, RASCONNSTATUS *lpRasConn, HRASCONN *phRasConn);
DWORD CheckConnected(TCHAR *szEntryName);
DWORD HangUpIdleConnectionThread(LPVOID lpv);
void SetFailTime(void);
DWORD DetermineIfAutodialConnectionsActive(RASCONNSTATUS *lpRasConnStatus, TCHAR *szRasName, HRASCONN *phRasConn);
void SetAsPublicInterface(TCHAR *szEntryName);
BOOL CheckFailRetry(void);

#if defined(DEBUG) && defined (UNDER_CE)
  DBGPARAM dpCurSettings = {
    TEXT("Autodial"), {
    TEXT("Init"),TEXT("Unused"),TEXT("Unused"),TEXT("Unused"),
    TEXT("Unused"),TEXT("Unused"),TEXT("Unused"),
    TEXT("Unused"),TEXT("Unused"),TEXT("Unused"),TEXT("Unused"),
    TEXT("Connection"),TEXT("IdleTimeout"),TEXT("Function"),TEXT("Warning"),TEXT("Error") },
    0x8801
  };
#endif


//***********************************************************************
// AutoDial Functions
//***********************************************************************

#define MAX_HANGUP_RETRIES             50
void MyHangUp(LPHRASCONN phRasConn)
{
	int i;
	RASCONNSTATUS RasConnStatus;
	RasConnStatus.dwSize = sizeof(RASCONNSTATUS);

	RasHangUp(*phRasConn);
	for (i = 0; i < MAX_HANGUP_RETRIES; i++)
	{
		if (ERROR_INVALID_HANDLE == RasGetConnectStatus(*phRasConn,&RasConnStatus))
			break;
		Sleep(1000);
	}
	ASSERT ( i != MAX_HANGUP_RETRIES);

	*phRasConn = 0;
}



// This function is called when network services start up to initialize
// the Autodial members.

// Note:  Calls to AutoDialInitializeModule and AutoDialCleanupModule
//        must be syncronized by the function calling it.  However,
//        thread syncronization for AutodialStartConnection and 
//        AutoDialEndConnection are done by Autodial itself.

DWORD AutoDialInitializeModule(void)
{
	DEBUGMSG(ZONE_FUNCTION,(TEXT("AutoDial:+AutoDialInitializeModule\r\n")));

	if (!g_fAutodialInitialized)
	{
		memset(&g_AutoDialConn,0,sizeof(g_AutoDialConn));
		g_fState = STATE_OFF;
		g_AutoDialConn.m_iLastFailIndex  = 0;
		InitializeCriticalSection(&g_GlobalCS);
		
		if (g_AutoDialConn.m_hTimerEvent = CreateEvent(NULL,FALSE,FALSE,NULL))
			g_fAutodialInitialized = TRUE;
		StatusInit(g_hInstance);
	}

	DEBUGMSG(ZONE_FUNCTION,(TEXT("AutoDial:-AutoDialInitializeModule\r\n")));
	return g_fAutodialInitialized ? ERROR_SUCCESS : ERROR_RASAUTO_CANNOT_INITIALIZE;
}

// Called when shutting down AutoDial services.  After calling this function
// it will be necessary to call AutoDialInitializeModule again to use AutoDial.

DWORD AutoDialCleanupModule(void)
{
	DEBUGMSG(ZONE_FUNCTION,(TEXT("AutoDial:+AutoDialCleanupModule\r\n")));

	g_fAutodialInitialized = FALSE;
	if (g_AutoDialConn.m_hRasConn)
		AutoDialEndConnectionInternal(FALSE);

	DeleteCriticalSection(&g_GlobalCS);
	CloseHandle(g_AutoDialConn.m_hTimerEvent);

	StatusUninit(g_hInstance);

	DEBUGMSG(ZONE_FUNCTION,(TEXT("AutoDial:-AutoDialCleanupModule\r\n")));
	return ERROR_SUCCESS;
}


// NAT calls this routine when it is unable to deliver a packet
// The routine loads values from the registry to see who to dial and 
// attempts to create a connection using RasDial if: 
//     1)  The registry key is valid  
//     2)  AutoDial has been enabled
//     3)  We haven't failed 3 times in a row within a brief time span

// szDialRasEntryName is set to non-NULL if we wish to initiate a dial using
// the given RAS conn name and ignore the registry values.

DWORD AutoDialStartConnection(TCHAR *szDialRasEntryName)
{
#ifdef DEBUG
	DWORD           err = 0;
#endif
	DWORD 			dwRet = 0;
	TCHAR 			szEntryName1[RAS_MaxEntryName + 1];
	TCHAR 			szEntryName2[RAS_MaxEntryName + 1];
	RASDIALPARAMS 	RasDialParams1;
	RASDIALPARAMS 	RasDialParams2;
	RASDIALPARAMS 	*pRasDialParams;
	DWORD			i;
	BOOL			fExecute = FALSE;

	DEBUGMSG(ZONE_FUNCTION,(TEXT("AutoDial:+AutoDialStartConnection\r\n")));
	ASSERT(!szDialRasEntryName || _tcslen(szDialRasEntryName) < RAS_MaxEntryName);

	if (!g_fAutodialInitialized)
	{
		DEBUGMSG(ZONE_ERROR,(TEXT("Autodial: AutoDialInitializeModule must be called before AutoDialStartConnection\r\n")));
		ASSERT(0);
		return ERROR_RASAUTO_CANNOT_INITIALIZE;
	}

	EnterCriticalSection(&g_GlobalCS);
	if (STATE_OFF == g_fState)
	{
		g_fState = STATE_STARTING_UP;
		fExecute = TRUE;
	}

	// It's possible we've lost the connection but are still in the STATE_ON
	else if (STATE_ON == g_fState && g_AutoDialConn.m_hRasConn)
	{
		RASCONNSTATUS 	RasConnStatus;
		RasConnStatus.dwSize = sizeof(RasConnStatus);

		if (ERROR_SUCCESS == RasGetConnectStatus(g_AutoDialConn.m_hRasConn,&RasConnStatus))
		{
			if (RASCS_Disconnected == RasConnStatus.rasconnstate)
			{
				MyHangUp(&g_AutoDialConn.m_hRasConn);

				g_fState = STATE_STARTING_UP;
				fExecute = TRUE;
			}
		}
	}
	// Note:  We leave the critical section here and rely on the g_fState so
	// that if another thread tries to call this function it will immediatly
	// receive an error (ERROR_DIAL_ALREADY_IN_PROGRESS) and won't be
	// blocked on the CS potentially waiting for RasDial() to complete.
	LeaveCriticalSection(&g_GlobalCS);

	if (!fExecute)
	{
		// We only allow 1 autodial connection at the same time.
		// Do not goto done, the cleanup code assumes we have fExecute = TRUE
	
		DEBUGMSG(ZONE_ERROR,(TEXT("AutoDial:AutoDialStartConnection failed -- another connection is active\r\n")));
		return ERROR_DIAL_ALREADY_IN_PROGRESS;
	}

	if (g_AutoDialConn.m_hTimerThread)
	{
		SetEvent(g_AutoDialConn.m_hTimerEvent);
		WaitForSingleObject(g_AutoDialConn.m_hTimerThread,INFINITE);
		CloseHandle(g_AutoDialConn.m_hTimerThread);
		g_AutoDialConn.m_hTimerThread = 0;
	}
	
	ASSERT(g_fState == STATE_STARTING_UP);
	ASSERT(g_AutoDialConn.m_hTimerThread == 0);
   	
	if (dwRet = AutodialReadRegistrySettings(szDialRasEntryName,szEntryName1,szEntryName2,&g_AutoDialConn))
		myleave(10);

	ASSERT( (szDialRasEntryName && !szEntryName1[0] && !szEntryName2[0]) ||
	        (!szDialRasEntryName && szEntryName1[0]));

	if ( ! CheckFailRetry())
		myretleave(ERROR_DISCONNECTION,3);  // just set the best RAS err code we can

	// It's possible that szEntryName has been connected through another application
	// already, in which case we don't try to RasDial on it.
	if (szDialRasEntryName && (dwRet = CheckConnected(szDialRasEntryName)))
		myleave(20);
	
	if (szEntryName1[0] && (dwRet = CheckConnected(szEntryName1)))
		myleave(30);

	if (szEntryName2[0] && (dwRet = CheckConnected(szEntryName2)))
		myleave(40);
		
	RasDialParams1.dwSize = sizeof(RASDIALPARAMS);

	if (szDialRasEntryName)
		_tcsncpy(RasDialParams1.szEntryName,szDialRasEntryName,RAS_MaxEntryName);
	else
		_tcsncpy(RasDialParams1.szEntryName,szEntryName1,RAS_MaxEntryName);

	if (szEntryName2[0])
	{
		RasDialParams2.dwSize = sizeof(RASDIALPARAMS);
		_tcsncpy(RasDialParams2.szEntryName,szEntryName2,RAS_MaxEntryName);
	}
	
	for (i = 0; i < g_AutoDialConn.m_dwRedialAttempts + 1; i++)
	{
		dwRet = AutoDialConnect(pRasDialParams = &RasDialParams1);
		if (!dwRet)
			break;

		if (szEntryName2[0])
		{
			dwRet = AutoDialConnect(pRasDialParams = &RasDialParams2);
			if (!dwRet)
				break;
		}

		// If we're not on final redial attempt, and if pause time was set.
		if (g_AutoDialConn.m_dwRedialPauseTime && i != g_AutoDialConn.m_dwRedialAttempts)
		{
			DEBUGMSG(ZONE_WARN,(TEXT("AutoDial: Connection attempt # %d failed, will sleep %d millisecs before attempting again\r\n"),
								  i,g_AutoDialConn.m_dwRedialPauseTime));
			Sleep(g_AutoDialConn.m_dwRedialPauseTime);
		}
	}

	// We only set fail time if our attempt to make a connection has failed,
	// we don't set this for misconfigured registry settings.
	if (i == g_AutoDialConn.m_dwRedialAttempts + 1)
	{
		DEBUGMSG(ZONE_ERROR,(TEXT("AutoDial: Unable to connect, RasError = %d\r\n"),dwRet));
		SetFailTime();
		myleave(50);
	}

done:
	ASSERT (g_fState == STATE_STARTING_UP);

#ifdef DEBUG
	if (dwRet)
		DEBUGMSG(ZONE_ERROR,(TEXT("AutoDial:StartConnection failed, returning = %d\r\n"),err,dwRet));
	else
		DEBUGMSG(ZONE_CONNECTION,(TEXT("AutoDial:StartConnection SUCCESS!\r\n")));
#endif // 0

	// Don't need CS around this because our state is STATE_STARTING_UP, no other
	// threads can modify g_fState when it's this value.
	if (dwRet)
	{
		g_fState = STATE_OFF;
	}
	else
	{
		GetCurrentFT((FILETIME*) &g_AutoDialConn.m_ftLastActivity);
		g_AutoDialConn.m_hTimerThread = CreateThread(NULL,0,HangUpIdleConnectionThread, NULL, 0, NULL);
		_tcsncpy(g_AutoDialConn.szRasEntryName,pRasDialParams->szEntryName,RAS_MaxEntryName);

#if defined (DEBUG)
		// If CreateThread fails just means we won't have an idle watch dog, 
		// all other parts of the connection will still run OK.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -