/*
 
RASLaunch.c : module to manage RAS connections
 
 
  17/06/97
 
  Author: Christophe Roguet
*/
 
 
#include <NET\RASLaunch.h>
#include <winbase.h>
#include <ras.h>
#include <raserror.h>
#include <winsock.h>
 
 
 
 
/* two macros to obtain a string that is the name of a DLL entry */
 
#define MakeFunctionName(n) (MakeFunctionName2(n))
#define MakeFunctionName2(n) (#n)
 
int RASLoadRAS(), RASUnloadRAS(), RASLoadIP(), RASUnloadIP();
 
 
 
/****************************************************************/
/****************************************************************/
/****************************************************************/
/****************************************************************/
/****************************************************************/
 
/* global variables */
 
/* flag: has the module be initialized ? */
 
static char gs_bIsInitialized = 0;
 
/* handle to the RAS DLL */
 
static HINSTANCE gs_hRASAPI_DLL = NULL;
 
/* pointers to the RAS DLL functions that we use */
 
static DWORD (APIENTRY *gs_pfndwRasEnumEntries)(LPTSTR, LPTSTR, LPRASENTRYNAME, LPDWORD, LPDWORD) = NULL;
static DWORD (APIENTRY *gs_pfndwRasEnumConnections)(LPRASCONN, LPDWORD, LPDWORD) = NULL;
static DWORD (APIENTRY *gs_pfndwRasGetConnectStatus)(HRASCONN, LPRASCONNSTATUS) = NULL;
static DWORD (APIENTRY *gs_pfndwRasGetEntryDialParams)(LPTSTR, LPRASDIALPARAMS, LPBOOL) = NULL;
static DWORD (APIENTRY *gs_pfndwRasDial)(LPRASDIALEXTENSIONS, LPTSTR, LPRASDIALPARAMS, DWORD, LPVOID, LPHRASCONN) = NULL;
static DWORD (APIENTRY *gs_pfndwRasHangUp)(HRASCONN) = NULL;
static DWORD (APIENTRY *gs_pfndwRasGetErrorString)(UINT, LPTSTR, DWORD) = NULL;
 
/****************************************************************/
/* RAS_Init()													*/
/****************************************************************/
 
int RAS_Init()
 
{
	if( !(gs_bIsInitialized & RASInitialized) && RASLoadRAS()==0)
		gs_bIsInitialized|=RASInitialized;
 
	if( !(gs_bIsInitialized & IPInitialized) && RASLoadIP()==0)
		gs_bIsInitialized|=IPInitialized;
 
	return gs_bIsInitialized;
}
 
/****************************************************************/
/* RAS_Exit()													*/
/*  0: success													*/
/****************************************************************/
 
int RAS_Exit()
 
{
	int RASUnloadOK, IPUnloadOK;
	if(gs_bIsInitialized & RASInitialized) {
		RASUnloadOK=RASUnloadRAS();
		if(RASUnloadOK==0)
			gs_bIsInitialized&=~RASInitialized;
	}
 
	if(gs_bIsInitialized & IPInitialized) {
		IPUnloadOK=RASUnloadIP();
		if(IPUnloadOK==0)
			gs_bIsInitialized&=~IPInitialized;
	}
 
	return RASUnloadOK | IPUnloadOK;
}
 
/****************************************************************/
 
/****************************************************************/
/* RASLoadRAS														*/
/* Attach the process to the RAS DLL							*/
/* return value:												*/
/*  0: success													*/
/* -1: failure													*/
/****************************************************************/
 
int RASLoadRAS(void)
 
{
	long lErrorCode;
	gs_hRASAPI_DLL=LoadLibrary("RASAPI32.DLL");
 
	if(gs_hRASAPI_DLL==NULL) {
		lErrorCode=GetLastError();
		return -1;
	}
 
	gs_pfndwRasEnumEntries=(DWORD (APIENTRY*)(LPTSTR, LPTSTR, LPRASENTRYNAME, LPDWORD, LPDWORD))
		GetProcAddress(gs_hRASAPI_DLL, MakeFunctionName(RasEnumEntries));
	if(gs_pfndwRasEnumEntries==NULL) {
		lErrorCode=GetLastError();
		return -1;
	}
	
	gs_pfndwRasEnumConnections=(DWORD (APIENTRY*)(LPRASCONN, LPDWORD, LPDWORD))
		GetProcAddress(gs_hRASAPI_DLL,  MakeFunctionName(RasEnumConnections));
	if(gs_pfndwRasEnumConnections==NULL) {
		lErrorCode=GetLastError();
		return -1;
	}
	
	gs_pfndwRasGetConnectStatus=(DWORD (APIENTRY*)(HRASCONN, LPRASCONNSTATUS))
		GetProcAddress(gs_hRASAPI_DLL,  MakeFunctionName(RasGetConnectStatus));
	if(gs_pfndwRasGetConnectStatus==NULL) {
		lErrorCode=GetLastError();
		return -1;
	}
	
	gs_pfndwRasGetEntryDialParams=(DWORD (APIENTRY*)(LPTSTR, LPRASDIALPARAMS, LPBOOL))
		GetProcAddress(gs_hRASAPI_DLL, MakeFunctionName(RasGetEntryDialParams));
	if(gs_pfndwRasGetEntryDialParams==NULL) {
		lErrorCode=GetLastError();
		return -1;
	}
	
	gs_pfndwRasDial=(DWORD (APIENTRY*)(LPRASDIALEXTENSIONS, LPTSTR, LPRASDIALPARAMS, DWORD, LPVOID, LPHRASCONN))
		GetProcAddress(gs_hRASAPI_DLL, MakeFunctionName(RasDial));
	if(gs_pfndwRasDial==NULL) {
		lErrorCode=GetLastError();
		return -1;
	}
	
	gs_pfndwRasHangUp=(DWORD (APIENTRY*)(HRASCONN))
		GetProcAddress(gs_hRASAPI_DLL, MakeFunctionName(RasHangUp));
	if(gs_pfndwRasHangUp==NULL) {
		lErrorCode=GetLastError();
		return -1;
	}
	
	gs_pfndwRasGetErrorString=(DWORD (APIENTRY*)(UINT, LPTSTR, DWORD))
		GetProcAddress(gs_hRASAPI_DLL, MakeFunctionName(RasGetErrorString));
	if(gs_pfndwRasGetErrorString==NULL) {
		lErrorCode=GetLastError();
		return -1;
	}
	
 
	return 0;
}
 
/****************************************************************/
/* RASUnloadRAS()													*/
/* Detach from the RAS DLL										*/
/* return value:												*/
/*  0: success													*/
/* -1: failure													*/
/****************************************************************/
 
int RASUnloadRAS(void)
 
{
	long lErrorCode;
 
	if(FreeLibrary(gs_hRASAPI_DLL)==FALSE) {
		lErrorCode=GetLastError();
		return -1;
	}
 
	gs_hRASAPI_DLL=NULL;
 
	gs_pfndwRasEnumEntries=(DWORD (APIENTRY*)(LPTSTR, LPTSTR, LPRASENTRYNAME, LPDWORD, LPDWORD))
		0L;
	gs_pfndwRasEnumConnections=(DWORD (APIENTRY*)(LPRASCONN, LPDWORD, LPDWORD))
		0L;
	gs_pfndwRasGetConnectStatus=(DWORD (APIENTRY*)(HRASCONN, LPRASCONNSTATUS))
		0L;
	gs_pfndwRasGetEntryDialParams=(DWORD (APIENTRY*)(LPTSTR, LPRASDIALPARAMS, LPBOOL))
		0L;
	gs_pfndwRasDial=(DWORD (APIENTRY*)(LPRASDIALEXTENSIONS, LPTSTR, LPRASDIALPARAMS, DWORD, LPVOID, LPHRASCONN))
		0L;
	gs_pfndwRasHangUp=(DWORD (APIENTRY*)(HRASCONN))
		0L;
	gs_pfndwRasGetErrorString=(DWORD (APIENTRY*)(UINT, LPTSTR, DWORD))
		0L;
 
	return 0;
}
 
/****************************************************************/
/****************************************************************/
/****************************************************************/
/****************************************************************/
/****************************************************************/
/****************************************************************/
 
/* RAS callback function declaration */
 
VOID APIENTRY RASNotifier(UINT , RASCONNSTATE , DWORD );
 
/* handle to the RAS connection */
 
static HRASCONN gs_hConnection=INVALID_HANDLE_VALUE;
 
 
/****************************************************************/
/* RASScanEntries												*/
/* to list the available RAS connections						*/
/* return value:												*/
/* -1: no more available entry									*/
/*  0: an entry has been found									*/
/****************************************************************/
 
int RASScanEntries(char bStart, char *pcName, int iSize)
 
{
	static DWORD s_dwBufferSize=0;
	static DWORD s_dwNumberOfWrittenEntries=0;
	static LPRASENTRYNAME s_pBuffer=0;
	DWORD dwReturnValue;
	static DWORD s_dwCurrentEntry=0;
	
	if( !(gs_bIsInitialized & RASInitialized) )
		return -1;
 
	if(bStart) {
		s_dwCurrentEntry=0;
 
		if(s_pBuffer!=0)
			free(s_pBuffer);
 
		s_dwBufferSize=sizeof(RASENTRYNAME);
 
		s_pBuffer=(LPRASENTRYNAME)malloc(s_dwBufferSize);
 
		s_pBuffer->dwSize=sizeof(RASENTRYNAME);
 
		dwReturnValue=gs_pfndwRasEnumEntries(NULL, NULL, s_pBuffer, &s_dwBufferSize, &s_dwNumberOfWrittenEntries);
 
		while(dwReturnValue==ERROR_BUFFER_TOO_SMALL || dwReturnValue==ERROR_NOT_ENOUGH_MEMORY) {
			free(s_pBuffer);
			s_pBuffer=(LPRASENTRYNAME)malloc(s_dwBufferSize);
			s_pBuffer->dwSize=sizeof(RASENTRYNAME);
			dwReturnValue=gs_pfndwRasEnumEntries(NULL, NULL, s_pBuffer, &s_dwBufferSize, &s_dwNumberOfWrittenEntries);
		}
 
		if(dwReturnValue!=0) {
			free(s_pBuffer);
			s_pBuffer=0;
			return -1;
		}
 
	}
 
	if(s_dwCurrentEntry<s_dwNumberOfWrittenEntries) {
		strncpy(pcName,	s_pBuffer[s_dwCurrentEntry].szEntryName, iSize-1);
		s_dwCurrentEntry++;
		return 0;
	} else {
		if(s_pBuffer!=0) {
			free(s_pBuffer);
			s_pBuffer=0;
		}
		return -1;
	}
}
 
/****************************************************************/
/* RASScanConnections											*/
/* to list the active RAS connections							*/
/* return value:												*/
/* -1: no more active connection								*/
/*  0: an active connection has been found						*/
/****************************************************************/
 
int RASScanConnections(char bStart, char *pcName, int iSize, int *iState)
 
{
	static DWORD s_dwBufferSize=0;
	static DWORD s_dwNumberOfWrittenConnections=0;
	static LPRASCONN s_pBuffer=0;
	DWORD dwReturnValue;
	static DWORD s_dwCurrentConnection=0;
	RASCONNSTATUS stRasConnStatus;
	
	if( !(gs_bIsInitialized & RASInitialized) )
		return -1;
 
	if(bStart) {
		s_dwCurrentConnection=0;
 
		if(s_pBuffer!=0)
			free(s_pBuffer);
 
		s_dwBufferSize=sizeof(RASCONN);
 
		s_pBuffer=(LPRASCONN)malloc(s_dwBufferSize);
 
		s_pBuffer->dwSize=sizeof(RASCONN);
 
		dwReturnValue=gs_pfndwRasEnumConnections(s_pBuffer, &s_dwBufferSize, &s_dwNumberOfWrittenConnections);
 
		while(dwReturnValue==ERROR_BUFFER_TOO_SMALL || dwReturnValue==ERROR_NOT_ENOUGH_MEMORY) {
			free(s_pBuffer);
			s_pBuffer=(LPRASCONN)malloc(s_dwBufferSize);
			s_pBuffer->dwSize=sizeof(RASCONN);
			dwReturnValue=gs_pfndwRasEnumConnections(s_pBuffer, &s_dwBufferSize, &s_dwNumberOfWrittenConnections);
		}
 
		if(dwReturnValue!=0) {
			free(s_pBuffer);
			s_pBuffer=0;
			return -1;
		}
 
	}
 
	if(s_dwCurrentConnection<s_dwNumberOfWrittenConnections) {
		strncpy(pcName,	s_pBuffer[s_dwCurrentConnection].szEntryName, iSize-1);
		stRasConnStatus.dwSize=sizeof(RASCONNSTATUS);
		dwReturnValue=gs_pfndwRasGetConnectStatus(	s_pBuffer[s_dwCurrentConnection].hrasconn,
											&stRasConnStatus);
		if(dwReturnValue==0) {
/*			*iState=stRasConnStatus.rasconnstate;*/
			switch(stRasConnStatus.rasconnstate) {
			case RASCS_Connected:
				*iState=myRAS_CONNECTED;
				break;
			case RASCS_Disconnected:
				*iState=myRAS_DISCONNECTED;
				break;
			default:
				*iState=myRAS_UNKNOWN;
				break;
			}
		} else {
			if(dwReturnValue==ERROR_INVALID_HANDLE)
				*iState=myRAS_IDLE;
			else
				*iState=myRAS_ERROR;
		}
		s_dwCurrentConnection++;
		return 0;
	} else {
		if(s_pBuffer!=0) {
			free(s_pBuffer);
			s_pBuffer=0;
		}
		return -1;
	}
}
 
/****************************************************************/
/* RASStartConnection											*/
/* launches the module RAS connection							*/
/****************************************************************/
 
int RASGetConnectionAccount(const char *pcEntryName, char *pcAccountName, char *pcPassword)
 
{
	RASDIALPARAMS stDialParams;
	BOOL bPasswordRetrieved;
	DWORD dwErrorCode;
 
	if( !(gs_bIsInitialized & RASInitialized) )
		return -1;
 
	memset(&stDialParams, 0, sizeof(RASDIALPARAMS));
 
	stDialParams.dwSize=sizeof(RASDIALPARAMS);
	strncpy(stDialParams.szEntryName, pcEntryName, RAS_MaxEntryName);
 
	dwErrorCode=gs_pfndwRasGetEntryDialParams(NULL, &stDialParams, &bPasswordRetrieved);
 
	if(bPasswordRetrieved) {
		strcpy(pcAccountName, stDialParams.szUserName);
		strcpy(pcPassword, stDialParams.szPassword);
		return 0;
	} else {
		*pcAccountName='\0';
		*pcPassword='\0';
		return -1;
	}
 
}
 
 
/****************************************************************/
/* RASStartConnection											*/
/* launches the module RAS connection							*/
/****************************************************************/
 
int RASStartConnection(const char *pcEntryName, const char *pcAccountName, const char *pcPassword)
 
{
	RASDIALPARAMS stDialParams;
	BOOL bPasswordRetrieved;
	DWORD dwErrorCode;
 
	if( !(gs_bIsInitialized & RASInitialized) )
		return -1;
 
	memset(&stDialParams, 0, sizeof(RASDIALPARAMS));
 
	stDialParams.dwSize=sizeof(RASDIALPARAMS);
	strncpy(stDialParams.szEntryName, pcEntryName, RAS_MaxEntryName);
 
	dwErrorCode=gs_pfndwRasGetEntryDialParams(NULL, &stDialParams, &bPasswordRetrieved);
 
	if(dwErrorCode!=0)
		return -1;
 
	/* if an account name is provided, use this one instead of the retrieved one */
 
	if(pcAccountName!=NULL) {
		strncpy(stDialParams.szUserName, pcAccountName, UNLEN);
		strncpy(stDialParams.szPassword, pcPassword, PWLEN);
	}
 
	dwErrorCode=gs_pfndwRasDial(NULL, NULL, &stDialParams, 0, RASNotifier, &gs_hConnection);
 
	if(dwErrorCode!=0)
		return -1;
 
	return 0;
}
 
/****************************************************************/
/* RASGetConnectionState										*/
/* get the status of the module connection						*/
/* return value:												*/
/****************************************************************/
int RASGetConnectionState()
 
{
	RASCONNSTATUS stRasConnStatus;
	DWORD dwReturnValue;
 
	if( !(gs_bIsInitialized & RASInitialized) )
		return -1;
 
	dwReturnValue=gs_pfndwRasGetConnectStatus(	gs_hConnection,	&stRasConnStatus);
 
	if(dwReturnValue==0) {
/*		return stRasConnStatus.rasconnstate;*/
		switch(stRasConnStatus.rasconnstate) {
		case RASCS_Connected:
			return myRAS_CONNECTED;
			break;
		case RASCS_Disconnected:
			return myRAS_DISCONNECTED;
			break;
		default:
			return myRAS_UNKNOWN;
			break;
		}
	}
 
	if(dwReturnValue==ERROR_INVALID_HANDLE)
		return myRAS_IDLE;
 
	return myRAS_ERROR;
}
 
/****************************************************************/
/* RASCloseConnection											*/
/* initiate the closing of the module RAS connection			*/
/* return value:												*/
/*  0: success													*/
/* -1: failure													*/
/****************************************************************/
 
int RASCloseConnection()
 
{
	DWORD dwErrorCode;
 
	if( !(gs_bIsInitialized & RASInitialized) )
		return -1;
 
	dwErrorCode=gs_pfndwRasHangUp(gs_hConnection);
 
	if(dwErrorCode==0)
		return 0;
	else
		return -1;
}
 
/****************************************************************/
/* RASNotifier													*/
/* RAS Callback Function										*/
/* only useful for debug purpose								*/
/****************************************************************/
 
static VOID APIENTRY RASNotifier(UINT unMsg, RASCONNSTATE rasconnstate, DWORD dwError)
 
{
	static char acErrorMsg[256];
	if(dwError) {
		gs_pfndwRasGetErrorString(dwError, acErrorMsg, sizeof(acErrorMsg));
	}
}
 
/****************************************************************/
/****************************************************************/
/****************************************************************/
/****************************************************************/
/****************************************************************/
/****************************************************************/
 
 
/*		set of functions to test the IP connectivity			*/
 
 
	static HANDLE gs_hWinsockDll = NULL;
	static char gs_bWinsockStarted = 0;
 
	static int (PASCAL *gs_pfniWSAStartup)(WORD, LPWSADATA) = NULL;
	static int (PASCAL *gs_pfniWSACleanup)(void) = NULL;
	static int (PASCAL *gs_pfniWSAGetLastError)(void) = NULL;
	static SOCKET (PASCAL *gs_pfnisocket)(int, int, int) = NULL;
	static int (PASCAL *gs_pfniclosesocket)(SOCKET) = NULL;
	static int (PASCAL *gs_pfniconnect)(SOCKET, const struct sockaddr FAR *, int) = NULL;
	static unsigned short (PASCAL *gs_pfnushtons)(unsigned short) = NULL;
	static unsigned long (PASCAL *gs_pfnulinet_addr)(const char FAR *) = NULL;
	static struct hostent FAR *(PASCAL *gs_pfnpstgethostbyname)(const char FAR *) = NULL;
	static int (PASCAL *gs_pfniioctlsocket)(SOCKET, long, u_long FAR *);
	static int (PASCAL *gs_pfniselect)(int, fd_set FAR *, fd_set FAR *, fd_set FAR *, const struct timeval FAR *);
	static int FAR (PASCAL *gs_pfni__WSAFDIsSet)(SOCKET, fd_set FAR *);
 
 
	static int gs_iConnectivityState = -1;
	static SOCKET gs_sd = INVALID_SOCKET;
	static struct sockaddr_in gs_stTargetAddr;
 
/****************************************************************/
/* RASLoadIP()													*/
/* Attach to the winsock DLL									*/
/* return value:												*/
/* 0 : success													*/
/* -1: failure													*/
/****************************************************************/
 
int RASLoadIP()
 
{
	WSADATA stWSAData;
 
	gs_hWinsockDll=LoadLibrary("WSOCK32.DLL");
 
	if(gs_hWinsockDll==NULL)
		return -1; /* the winsock DLL is not present on this computer */
 
	gs_pfniWSAStartup=(int (PASCAL *)(WORD, LPWSADATA))GetProcAddress(gs_hWinsockDll, MakeFunctionName(WSAStartup));
	gs_pfniWSACleanup=(int (PASCAL *)(void))GetProcAddress(gs_hWinsockDll, MakeFunctionName(WSACleanup));
	gs_pfniWSAGetLastError=(int (PASCAL *)(void))GetProcAddress(gs_hWinsockDll, MakeFunctionName(WSAGetLastError));
	gs_pfnisocket=(SOCKET (PASCAL *)(int, int, int))GetProcAddress(gs_hWinsockDll, MakeFunctionName(socket));
	gs_pfniclosesocket=(int (PASCAL *)(SOCKET))GetProcAddress(gs_hWinsockDll, MakeFunctionName(closesocket));
	gs_pfniconnect=(int (PASCAL *)(SOCKET, const struct sockaddr FAR *, int))GetProcAddress(gs_hWinsockDll, MakeFunctionName(connect));
	gs_pfnushtons=(unsigned short (PASCAL *)(unsigned short))GetProcAddress(gs_hWinsockDll, MakeFunctionName(htons));
	gs_pfnulinet_addr=(unsigned long (PASCAL *)(const char FAR *))GetProcAddress(gs_hWinsockDll, MakeFunctionName(inet_addr));
	gs_pfnpstgethostbyname=(struct hostent FAR * (PASCAL *)(const char FAR *))GetProcAddress(gs_hWinsockDll, MakeFunctionName(gethostbyname));
	gs_pfniioctlsocket=(int (PASCAL *)(SOCKET, long, u_long FAR *))GetProcAddress(gs_hWinsockDll, MakeFunctionName(ioctlsocket));
	gs_pfniselect=(int (PASCAL *)(int, fd_set FAR *, fd_set FAR *, fd_set FAR *, const struct timeval FAR *))GetProcAddress(gs_hWinsockDll, MakeFunctionName(select));
 
	gs_pfni__WSAFDIsSet=(int FAR (PASCAL *)(SOCKET, fd_set FAR *))GetProcAddress(gs_hWinsockDll, MakeFunctionName(__WSAFDIsSet));
 
	if(gs_pfniWSAStartup(MAKEWORD(1,1), &stWSAData)) {
		RASUnloadIP();
		return -2; /* can't negotiate DLL version */
	}
 
	gs_bWinsockStarted=~0;
 
	return 0;
}
 
/****************************************************************/
/* RASUnloadIP()												*/
/* Detach from the winsock DLL									*/
/* return value:												*/
/* 0 : success													*/
/* -1: failure													*/
/****************************************************************/
 
int RASUnloadIP()
 
{
	/* long lErrorCode; */
 
	/* delete the connect thread */
 
	if(gs_sd!=INVALID_SOCKET) {
		gs_pfniclosesocket(gs_sd);
		gs_sd=INVALID_SOCKET;
	}
 
	/* deregister from the winsock DLL and unload it */
 
	if(gs_bWinsockStarted)
		if(gs_pfniWSACleanup())
			return -1;
		else
			gs_bWinsockStarted=0;
 
	if(FreeLibrary(gs_hWinsockDll)==FALSE)
		return -1;
 
	gs_hWinsockDll=NULL;
 
	gs_pfniWSAStartup=(int (PASCAL *)(WORD, LPWSADATA))NULL;
	gs_pfniWSACleanup=(int (PASCAL *)(void))NULL;
	gs_pfniWSAGetLastError=(int (PASCAL *)(void))NULL;
	gs_pfnisocket=(SOCKET (PASCAL *)(int, int, int))NULL;
	gs_pfniclosesocket=(int (PASCAL *)(SOCKET))NULL;
	gs_pfniconnect=(int (PASCAL *)(SOCKET, const struct sockaddr FAR *, int))NULL;
	gs_pfnushtons=(unsigned short (PASCAL *)(unsigned short))NULL;
	gs_pfnulinet_addr=(unsigned long (PASCAL *)(const char FAR *))NULL;
	gs_pfnpstgethostbyname=(struct hostent FAR * (PASCAL *)(const char FAR *))NULL;
	gs_pfniioctlsocket=(int (PASCAL *)(SOCKET, long, u_long FAR *))GetProcAddress(gs_hWinsockDll, MakeFunctionName(ioctlsocket));
	gs_pfniselect=(int (PASCAL *)(int, fd_set FAR *, fd_set FAR *, fd_set FAR *, const struct timeval FAR *))NULL;
 
	gs_pfni__WSAFDIsSet=(int FAR (PASCAL *)(SOCKET, fd_set FAR *))NULL;
 
 
	return 0;
}
 
/****************************************************************/
/* TouchTarget													*/
/****************************************************************/
 
int RASTouchTarget(const char *acTargetAddr)
 
{
 
    struct hostent *entry;
 
	long lErrorCode;
 
	int iReturnValue;
 
	unsigned long ulMode;
 
	if( !(gs_bIsInitialized & IPInitialized) )
		return myRAS_NotInitialized;
 
	if(gs_sd!=INVALID_SOCKET)
		return myRAS_Busy; /* a search is in progress */
 
	iReturnValue=myRAS_IPUnavailable; /* TCP/IP is not installed on the computer */
 
	/* create a TCP socket and try to connect it to the target address */
 
	gs_sd=gs_pfnisocket(PF_INET, SOCK_STREAM, 0);
 
	if(gs_sd>0) {
 
		iReturnValue=0; /* the target address can be reached */
 
		gs_stTargetAddr.sin_family = AF_INET;
		gs_stTargetAddr.sin_port = gs_pfnushtons (80); /* www port, but any socket number should do */
		gs_stTargetAddr.sin_addr.s_addr = gs_pfnulinet_addr(acTargetAddr);
 
		if(gs_stTargetAddr.sin_addr.s_addr==INADDR_NONE) {
		/* if the address is not a correct numeric address, ask a DNS to translate it */
 
			entry=gs_pfnpstgethostbyname(acTargetAddr);
 
			if(entry==NULL) { /* the supplied address is not correct */
				gs_pfniclosesocket(gs_sd);
				gs_sd=INVALID_SOCKET;
				iReturnValue=myRAS_InvalidAddress;
			} else 
				gs_stTargetAddr.sin_addr = *(struct in_addr *)(entry->h_addr_list[0]);
		}
 
		if(iReturnValue==0) {
 
			iReturnValue=myRAS_InternalError; /* unable to start connecting */
 
			/* set non blocking mode on the socket */
			ulMode=~0;
 
			if(gs_pfniioctlsocket(gs_sd, FIONBIO, &ulMode)==SOCKET_ERROR) {
				lErrorCode=gs_pfniWSAGetLastError();
			} else {
				iReturnValue=0; /* the test operation is proceeding */
 
				if(gs_pfniconnect(gs_sd, (struct sockaddr *)&gs_stTargetAddr, sizeof(gs_stTargetAddr))==SOCKET_ERROR) {
					lErrorCode=gs_pfniWSAGetLastError();
					/* should be WSAEWOULDBLOCK */
				}
				
			}		
 
		}
	}
 
	if(iReturnValue!=0)
		gs_iConnectivityState=-1;
	else
		gs_iConnectivityState=myRAS_Testing;
 
	return iReturnValue;
}
 
/****************************************************************/
 
int RASCancelTouch()
 
{
	if(gs_sd==INVALID_SOCKET)
		return -1;
 
	gs_pfniclosesocket(gs_sd);
	gs_sd=INVALID_SOCKET;
 
	gs_iConnectivityState=myRAS_Canceled;
 
	return 0;
}
 
/****************************************************************/
 
int RASGetConnectivity()
 
{
	long lErrorCode;
 
	fd_set WriteFD, ExceptionFD;
	static struct timeval timeout = {0, 0};
 
	int iNumberOfEvents;
 
	/* is a connect operation in progress ? */
 
	if(gs_sd==INVALID_SOCKET)
		return gs_iConnectivityState;
 
	/* has the connect operation finished ? */
 
	FD_ZERO(&WriteFD);
	FD_ZERO(&ExceptionFD);
	FD_SET(gs_sd, &WriteFD);
	FD_SET(gs_sd, &ExceptionFD);
 
	iNumberOfEvents=gs_pfniselect(0, NULL, &WriteFD, &ExceptionFD, &timeout);
 
	if(iNumberOfEvents==SOCKET_ERROR) {
		lErrorCode=gs_pfniWSAGetLastError();
		return -1;
	}
 
	if(iNumberOfEvents>0) {
		if(gs_pfni__WSAFDIsSet(gs_sd, &WriteFD))
			gs_iConnectivityState=myRAS_Connectable;
		else if(gs_pfni__WSAFDIsSet(gs_sd, &ExceptionFD))
			gs_iConnectivityState=myRAS_NotConnectable;
		else
			gs_iConnectivityState=-1;
 
		gs_pfniclosesocket(gs_sd);
		gs_sd=INVALID_SOCKET;
	}
 
	return gs_iConnectivityState;
}
 
/****************************************************************/
