C++实现VPN工具之代码示例
创建、连接、挂断、删除VPN实现起来并不难,下面给出一套比较完整的代码。该段代码只是示例代码,但是已经通过了编译,对API的使用和VPN操作步骤是没问题的。具体每个API代表的意义可以参看《C++实现VPN工具之常用API函数》。代码中的OutputString只是起查看消息的作用,当成messagebox理解就行。到此篇总结,VPN工具实现的学习基本上就结束了。
#include "ras.h"
#pragma comment(lib, "rasapi32.lib")
typedef struct VPNPARAMS
{
WCHAR szDescription[ RAS_MaxEntryName + 1 ];
WCHAR szServer[ RAS_MaxPhoneNumber + 1 ];
WCHAR szUserName[ UNLEN + 1 ];
WCHAR szPassword[ PWLEN + 1 ];
WCHAR szDomain[ DNLEN + 1 ];
HANDLE hTerminalEvent;
};
#include "stdafx.h"
#include "vpn.h"
RASDIALPARAMS RasDialParams;
HRASCONN m_hRasConn;
HANDLE g_TerminalEvent;
void OutputString( char *lpFmt, ... )
{
char buff[1024];
va_list arglist;
va_start( arglist, lpFmt );
_vsnprintf( buff, sizeof buff, lpFmt, arglist );
va_end( arglist );
OutputDebugStringA(buff);
}
inline void InitRASIP (RASIPADDR& rasIP)
{
rasIP.a =0;
rasIP.b =0;
rasIP.c =0;
rasIP.d =0;
}
//VPN链接过程中返回的步骤信息
void RasDialFunc(UINT unMsg, RASCONNSTATE rasconnstate, DWORD dwError)
{
wchar_t szRasString[256]; // Buffer for storing the error string
if (dwError) // Error occurred
{
RasGetErrorString((UINT)dwError, szRasString, 256);
OutputString("Error: %d - %s\n",dwError, szRasString);
SetEvent(g_TerminalEvent);
return;
}
// Map each of the states of RasDial() and display on the screen
// the next state that RasDial() is entering
switch (rasconnstate)
{
// Running States
case RASCS_OpenPort:
OutputString ("Opening port...\n");
break;
case RASCS_PortOpened:
OutputString ("Port opened.\n");
break;
case RASCS_ConnectDevice:
OutputString ("Connecting device...\n");
break;
case RASCS_DeviceConnected:
OutputString ("Device connected.\n");
break;
case RASCS_AllDevicesConnected:
OutputString ("All devices connected.\n");
break;
case RASCS_Authenticate:
OutputString ("Authenticating...\n");
break;
case RASCS_AuthNotify:
OutputString ("Authentication notify.\n");
break;
case RASCS_AuthRetry:
OutputString ("Retrying authentication...\n");
break;
case RASCS_AuthCallback:
OutputString ("Authentication callback...\n");
break;
case RASCS_AuthChangePassword:
OutputString ("Change password...\n");
break;
case RASCS_AuthProject:
OutputString ("Projection phase started...\n");
break;
case RASCS_AuthLinkSpeed:
OutputString ("Negotiating speed...\n");
break;
case RASCS_AuthAck:
OutputString ("Authentication acknowledge...\n");
break;
case RASCS_ReAuthenticate:
OutputString ("Retrying Authentication...\n");
break;
case RASCS_Authenticated:
OutputString ("Authentication complete.\n");
break;
case RASCS_PrepareForCallback:
OutputString ("Preparing for callback...\n");
break;
case RASCS_WaitForModemReset:
OutputString ("Waiting for modem reset...\n");
break;
case RASCS_WaitForCallback:
OutputString ("Waiting for callback...\n");
break;
case RASCS_Projected:
OutputString ("Projection completed.\n");
break;
#if (WINVER >= 0x400)
case RASCS_StartAuthentication:
OutputString ("Starting authentication...\n");
break;
case RASCS_CallbackComplete:
OutputString ("Callback complete.\n");
break;
case RASCS_LogonNetwork:
OutputString ("Logon to the network.\n");
break;
#endif
case RASCS_SubEntryConnected:
OutputString ("Subentry connected.\n");
break;
case RASCS_SubEntryDisconnected:
OutputString ("Subentry disconnected.\n");
break;
// The RAS Paused States will not occur because
// we did not use the RASDIALEXTENSIONS structure
// to set the RDEOPT_PausedState option flag.
// The Paused States are:
// RASCS_RetryAuthentication:
// RASCS_CallbackSetByCaller:
// RASCS_PasswordExpired:
// Terminal States
case RASCS_Connected:
OutputString ("Connection completed.\n");
OutputString ("连接成功\n");
SetEvent(g_TerminalEvent);
break;
case RASCS_Disconnected:
OutputString ("Disconnecting...\n");
SetEvent(g_TerminalEvent);
break;
default:
OutputString ("Unknown Status = %d\n", rasconnstate);
break;
}
}
//创建一个VPN链接,并保存VPN链接信息到电话薄
BOOL CreateRasEntry(const wchar_t *pszEntryName, const wchar_t *pszServerName, const wchar_t *pszUserName,
const wchar_t *pszPassWord)
{
RASENTRY rasEntry;
DWORD rasEntrySize, dwResult;
rasEntrySize = sizeof(rasEntry);
memset(&rasEntry, 0, sizeof(rasEntry));
DWORD lpcb = 0;
DWORD lpcDevices;
RASDEVINFO* lpRasDevInfo;
RASDEVINFO rasdevinfo;
RasEnumDevices(NULL, &lpcb, &lpcDevices);
lpRasDevInfo = (LPRASDEVINFO) GlobalAlloc(GPTR, lpcb);
lpRasDevInfo->dwSize = sizeof(RASDEVINFO);
//获得所有具有R A S能力的设备名及类型
RasEnumDevices(lpRasDevInfo, &lpcb, &lpcDevices);
lstrcpy (rasdevinfo.szDeviceName, lpRasDevInfo->szDeviceName);
lstrcpy (rasdevinfo.szDeviceType, lpRasDevInfo->szDeviceType);
rasEntry.dwSize = sizeof (RASENTRY);
rasEntry.dwfOptions = RASEO_RequireMsEncryptedPw | RASEO_RequireDataEncryption | RASEO_ModemLights | RASEO_ShowDialingProgress;
rasEntry.dwAlternateOffset = 0;
rasEntry.dwCountryID = 86;
rasEntry.dwCountryCode = 86;
// rasEntry.dwDialExtraPercent = 75;
// rasEntry.dwDialExtraSampleSeconds = 120;
// rasEntry.dwDialMode = 1;
rasEntry.dwfNetProtocols = 4;
// rasEntry.dwfOptions = 1024262928;
rasEntry.dwfOptions2 = 367;
rasEntry.dwFramingProtocol = 1;
rasEntry.dwHangUpExtraPercent = 10;
rasEntry.dwHangUpExtraSampleSeconds = 120;
rasEntry.dwRedialCount = 3;
rasEntry.dwRedialPause = 60;
rasEntry.dwType = RASET_Vpn;
rasEntry.dwFrameSize = 0;
rasEntry.dwfNetProtocols = RASNP_Ip; // TCP/IP
rasEntry.dwFramingProtocol = RASFP_Ppp; //PPP
rasEntry.dwChannels = 0;
rasEntry.dwReserved1 = 0;
rasEntry.dwReserved2 = 0;
// Strings
lstrcpy (rasEntry.szAreaCode, L"");
lstrcpy (rasEntry.szScript, L"");
lstrcpy (rasEntry.szAutodialDll, L"");
lstrcpy (rasEntry.szAutodialFunc, L"");
lstrcpy (rasEntry.szX25PadType, L"");
lstrcpy (rasEntry.szX25Address, L"");
lstrcpy (rasEntry.szX25Facilities, L"");
lstrcpy (rasEntry.szX25UserData, L"");
//strcpy (rasEntry.szDeviceType, rasdevinfo.szDeviceType );
//strcpy (rasEntry.szDeviceName, rasdevinfo.szDeviceName);
//strcpy (rasEntry.szDeviceName,"WAN 微型端口 (L2TP)");
//strcpy (rasEntry.szDeviceType, "vpn");
//strcpy (rasEntry.szLocalPhoneNumber,lpszIPAddress);// "60.190.168.108")lstrcpy(rasEntry.szLocalPhoneNumber, pszServerName); ;//服务器地址或域名
lstrcpy(rasEntry.szDeviceType, RASDT_Vpn);
lstrcpy(rasEntry.szDeviceName, TEXT("RAS VPN Line 0"));
rasEntry.dwVpnStrategy = VS_Default; //vpn类型
rasEntry.dwEncryptionType = ET_Optional; //数据加密类型
// IP addresses
InitRASIP (rasEntry.ipaddr);
InitRASIP (rasEntry.ipaddrDns);
InitRASIP (rasEntry.ipaddrDnsAlt);
InitRASIP (rasEntry.ipaddrWins);
InitRASIP (rasEntry.ipaddrWinsAlt);
dwResult = RasSetEntryProperties(NULL, pszEntryName, &rasEntry, sizeof(rasEntry), NULL, 0);
if (dwResult != 0)
{
OutputString("RasSetEntryProperties %s failed error=%d\n", pszEntryName, dwResult);
return FALSE;
}
RASDIALPARAMS rdParams;
ZeroMemory(&rdParams, sizeof(RASDIALPARAMS));
rdParams.dwSize = sizeof(RASDIALPARAMS);
lstrcpy(rdParams.szEntryName, pszEntryName);
lstrcpy(rdParams.szUserName, pszUserName);
lstrcpy(rdParams.szPassword, pszPassWord);
DWORD dwRet = RasSetEntryDialParams(NULL, &rdParams, FALSE);
if(dwRet == 0)
return TRUE;
else
return FALSE;
}
//链接一个VPN
BOOL ConenectVPN(LPVOID lparam)
{
RASCONNSTATUS RasConnStatus;
HRASCONN hRasConn;
DWORD Ret;
DWORD tcLast;
VPNPARAMS VPNParams;
memcpy(&VPNParams, lparam, sizeof(VPNPARAMS));
// Create the event that indicates a terminal state
if ((g_TerminalEvent = CreateEvent(NULL, FALSE, FALSE, NULL)) == NULL)
{
OutputString("CreateEvent failed with error %d\n", GetLastError());
return FALSE;
}
RasDialParams.dwSize = sizeof(RASDIALPARAMS);
lstrcpy(RasDialParams.szEntryName, VPNParams.szDescription);
lstrcpy(RasDialParams.szPhoneNumber, VPNParams.szServer);
lstrcpy(RasDialParams.szUserName, VPNParams.szUserName);
lstrcpy(RasDialParams.szPassword, VPNParams.szPassword);
lstrcpy(RasDialParams.szDomain, VPNParams.szDomain);
CreateRasEntry(RasDialParams.szEntryName, RasDialParams.szPhoneNumber,
RasDialParams.szUserName, RasDialParams.szPassword);
// Dial out asynchronously using RasDial()
OutputString("Dialing... %s\n", RasDialParams.szPhoneNumber);
hRasConn = NULL;
if (Ret = RasDial(NULL, NULL, &RasDialParams, 0, &RasDialFunc, &hRasConn))
{
RasDeleteEntry(NULL, RasDialParams.szEntryName);
return FALSE;
}
// Wait for RasDial to complete or enter a paused state
Ret = WaitForSingleObject(g_TerminalEvent, 50000);
switch(Ret)
{
case WAIT_TIMEOUT:
// RasDial timed out
OutputString("RasDial Timed out...\n");
case WAIT_OBJECT_0:
// Normal completion or Ras Error encountered
WaitForSingleObject(VPNParams.hTerminalEvent, INFINITE); // 等待断开
break;
}
OutputString("Calling RasHangUp...\n");
if (Ret = RasHangUp(hRasConn))
{
OutputString("RasHangUp failed with error %d\n", Ret);
//return FALSE;
}
RasConnStatus.dwSize = sizeof(RASCONNSTATUS);
tcLast = GetTickCount() + 10000;
while((RasGetConnectStatus(hRasConn, &RasConnStatus)
!= ERROR_INVALID_HANDLE) && (tcLast > GetTickCount()))
{
Sleep(50);
}
//RasDeleteEntry(NULL, RasDialParams.szEntryName);
}
//获取VPN的链接状态
bool IsConnect(void)
{
if(NULL != m_hRasConn)
{
RASCONNSTATUS rasConStatus;
rasConStatus.dwSize = sizeof(RASCONNSTATUS);
RasGetConnectStatus(m_hRasConn,&rasConStatus);
if(RASCS_Connected == rasConStatus.rasconnstate)
{
return true;
}
}
return false;
}
//挂断VPN链接
bool HangUp()
{
int index; // An integer index
DWORD dwError, // Error code from a function call
dwRasConnSize, // Size of RasConn in bytes
dwNumConnections; // Number of connections found
RASCONN RasConn[20]; // Buffer for connection state data
// Assume the maximum number of entries is 20.
// Assume no more than 20 connections.
RasConn[0].dwSize = sizeof (RASCONN);
dwRasConnSize = 20 * sizeof (RASCONN);
//返回指向VPN数组的指针 Find all connections.
if (dwError = RasEnumConnections (RasConn, &dwRasConnSize, &dwNumConnections))
{
return false;
}
// If there are no connections, return zero.
if (!dwNumConnections)
{
return false;
}
// Terminate all of the remote access connections.
for (index = 0; index < (int)dwNumConnections; ++index)
{
//这样做主要是不想关掉usb连接,因为通过这种方法得到的连接中包括了USB同步的连接。
if (wcsstr(RasConn[index].szEntryName,_T("MyLink"))!=NULL)
{
if (dwError = RasHangUp (RasConn[index].hrasconn))
{
return false;
}
}
}
return TRUE;
}
//删除建立的VPN拨号
BOOL DeleteEntry()
{
RasDeleteEntry(NULL, RasDialParams.szEntryName);
return TRUE;
}
C++实现VPN工具之代码示例的更多相关文章
- mysql连接池的使用工具类代码示例
mysql连接池代码工具示例(scala): import java.sql.{Connection,PreparedStatement,ResultSet} import org.apache.co ...
- [转]如何利用ndk-stack工具查看so库的调用堆栈【代码示例】?
如何利用ndk-stack工具查看so库的调用堆栈[代码示例]? http://hi.baidu.com/subo4110/item/d00395b3bf63e4432bebe36d Step1:An ...
- 开发工具类API调用的代码示例合集:六位图片验证码生成、四位图片验证码生成、简单验证码识别等
以下示例代码适用于 www.apishop.net 网站下的API,使用本文提及的接口调用代码示例前,您需要先申请相应的API服务. 六位图片验证码生成:包括纯数字.小写字母.大写字母.大小写混合.数 ...
- Python实现各种排序算法的代码示例总结
Python实现各种排序算法的代码示例总结 作者:Donald Knuth 字体:[增加 减小] 类型:转载 时间:2015-12-11我要评论 这篇文章主要介绍了Python实现各种排序算法的代码示 ...
- Java基础知识强化之IO流笔记72:NIO之 NIO核心组件(NIO使用代码示例)
1.Java NIO 由以下几个核心部分组成: Channels(通道) Buffers(缓冲区) Selectors(选择器) 虽然Java NIO 中除此之外还有很多类和组件,Channel,Bu ...
- 转:CodeCube提供可共享、可运行的代码示例
CodeCube是一个新服务和开源项目,旨在让开发者能够通过浏览器以一种安全的方式分享并运行代码示例从而提升协作. 最初发布的服务可以从codecube.io上获取,支持Ruby.Python.Go及 ...
- 天气类API调用的代码示例合集:全国天气预报、实时空气质量数据查询、PM2.5空气质量指数等
以下示例代码适用于 www.apishop.net 网站下的API,使用本文提及的接口调用代码示例前,您需要先申请相应的API服务. 全国天气预报:数据来自国家气象局,可根据地名.经纬度GPS.IP查 ...
- 位置信息类API调用的代码示例合集:中国省市区查询、经纬度地址转换、POI检索等
以下示例代码适用于 www.apishop.net 网站下的API,使用本文提及的接口调用代码示例前,您需要先申请相应的API服务. 中国省市区查询:2017最新中国省市区地址 经纬度地址转换:经纬度 ...
- 通讯服务类API调用的代码示例合集:短信服务、手机号归属地查询、电信基站查询等
以下示例代码适用于 www.apishop.net 网站下的API,使用本文提及的接口调用代码示例前,您需要先申请相应的API服务. 短信服务:通知类和验证码短信,全国三网合一通道,5秒内到达,费用低 ...
随机推荐
- PHP7的安装
PHP7和HHVM比较PHP7的在真实场景的性能确实已经和HHVM相当, 在一些场景甚至超过了HHVM.HHVM的运维复杂, 是多线程模型, 这就代表着如果一个线程导致crash了, 那么整个服务就挂 ...
- python递归理解图
递归:下一级只能return给自己的上一级. import re val="9-2*5/3+7/3*99/4*2998+10*568/14" val="9-2*5/3+7 ...
- linux下文件结束符
linux下文件结束符,我试过了所有的linux,发现其文件的结束符都是以0a即LF结束的,这个是操作系统规定的,windows下是\r\n符结束,希望可以帮助大家. -------------转:来 ...
- JSF页面中使用js函数回调后台bean方法并获取返回值的方法
由于primefaces在国内使用的并不是太多,因此,国内对jsf做系统.详细的介绍的资料很少,即使有一些资料,也仅仅是对国外资料的简单翻译或者是仅仅讲表面现象(皮毛而已),它们的语句甚至还是错误的, ...
- winxp可以禁用的服务
要注意的是: 虽然某个服务你设置成了手动, 而且在services.msc中好像也没有启动, 但是并不表示这个服务不可以被启动 因为某些软件, 可能在程序内部进行了编程的设置, 它可以在内部去启动 服 ...
- CF467D Fedor and Essay 建图DFS
Codeforces Round #267 (Div. 2) CF#267D D - Fedor and Essay D. Fedor and Essay time limit per test ...
- 系统研究Airbnb开源项目airflow
开源项目airflow的一点研究 调研了一些几个调度系统, airflow 更满意一些. 花了些时间写了这个博文, 这应该是国内技术圈中最早系统性研究airflow的文章了. 转载请注明出处 htt ...
- 点击自动显示/隐藏DIV代码。(简单实用)
注:本文由Colin撰写,版权所有!转载请注明原文地址,谢谢合作! 很多时候我们需要将DIV的信息默认为隐藏状态,只有当用户点击时才显示DIV中包含的提示文字.这类效果在互联网上应用得很多,但实现的方 ...
- 必须知道的.net(字段、属性和方法)
1.字段 通常定义为private(封装原则) 2.属性(property) 通常定义为public,表示类的对外成员.具有可读可写属性,通过get和set访问器实现 3.索引器(indexer) C ...
- iOS中AOP与Method Swizzling 项目中的应用
引子:项目中需要对按钮点击事件进行统计分析,现在项目中就是在按钮的响应代码中添加点击事件,非常繁琐.所以使用了AOP(面向切面编程),将统计的业务逻辑统一抽离出来. 项目中添加的开源库:https:/ ...