我的新版dns加速器出炉啦!!!欢迎提出意见和建议
http://www.0xaa55.com/forum.php?mod=viewthread&tid=1265&extra=很多人可能看过我这个帖子《对彗星DNS加速器的分析(一)(二)》,在其中我详细描述了张慧星的dns加速器实现原理,在这个礼拜,今天我刚刚自己实现出来,取得初步成果,这1500行代码用boost和stl一气呵成,
预期可以支持ipv6 dns,批量测试/停止,解析域名镜像(如google),支持大dns库和自定义dns库,甚至以后和代理功能结合到一起。
由于是初稿,因此有bug,这里贴出源码,给出工程,望和大家一起探讨改进之处,理论上说这个工具会是很强大的!
效果图:
工程地址:http://pan.baidu.com/s/1jGsvAoI
关于这个工具欢迎有兴趣研究这方面的各路高手一起和我探讨
重要代码:
functions.h
#pragma once
#ifndef FASTERDNS_COMMONHEADER
#define FASTERDNS_COMMONHEADER
#endif
#include <string>
#include <vector>
#include <boost/asio.hpp>
#include <boost/function.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread.hpp>
#include <boost/thread/detail/thread_group.hpp>
#include <deque>
#include <set>
#include "sqlite3.h"
#define DATABASE "dnss.db"
#define CSVDATA "nameservers.csv"
class testSpeedData//每轮测试所用数据
{
public:
testSpeedData(char* _ip, char* _location) :ip(_ip), location(_location)
{
responsetime = 0;
testtime = 0;
lefttime = 0;
failtime = 0;
timeout = 0;
}
public:
std::string ip;//DNS地址
std::string location;//所在地
int responsetime;//总响应时间
int testtime;//总测试次数
int lefttime;//剩余次数
int failtime;//失败次数
int timeout;//超时时间
};
typedef int(*DBCALLBACK)(void *NotUsed, int argc, char **argv, char **azColName);
typedef std::vector<std::string> spliter;
typedef std::vector<std::pair<std::string,std::string>> dbData;
//数据库相关
bool doadddata(dbData* dataparam, HWND progctrl);
bool dodeldata(std::vector<std::string>* dataparam, HWND progctrl);
bool getcount(int& count);
bool getdata(std::vector<testSpeedData>* dataparam, HWND listctrl, HWND statu, boost::mutex* mu);
//网络操作相关
bool dohttpconnect(const std::string& ip, uint32_t& timeout);
bool dodnsconnect(const std::string& ip, uint32_t& timeout, std::vector<uint8_t>& bufferdata);
void makedns(std::vector<uint8_t>& bufferdata, const std::string& testdomain);
void replaceXid(std::vector<uint8_t>& bufferdata, uint16_t Xid);
void resolveAnswer(std::vector<uint8_t>& bufferdata, std::set<std::string>& resolvedip, int originlen);
//系统设置相关
bool getinterface(std::vector<std::string>& interfaces);
bool setinterface(std::vector<std::string>& interfaces, std::vector<std::string>& addresss, HWND progctrl);
enum
{
//解析CSV数据文件
CSV_IP = 0,
CSV_NAME,
CSV_COUNTRYID,
CSV_CITY,
CSV_MAX,
//解析普通数据文件
COM_IP = 0,
COM_LOCATION,
COM_MAX,
//端口
PORT_HTTP = 80,
PORT_DNS = 53,
//DNS包
SIZE_DNSHEADER = sizeof(DNS_HEADER),
SIZE_DNSTAILER = 5,
//值域
INIT_THREADNUM = 1,
LOW_THREADNUM = 0,
HIGH_THREADNUM = 1000,
INIT_TIMEOUT = 1000,
LOW_TIMEOUT = 10,
HIGH_TIMEOUT = 10000,
INIT_TESTNUM = 1,
LOW_TESTNUM = 0,
HIGH_TESTNUM = 100,
//显示列
COL_IP = 0,
COL_LOC,
COL_RES,//平均响应时间
COL_FAIL,//失败次数/总次数
//其他
IDC_PROGRESS = 12345,
MAX_DOMAIN_LENGTH = 256,
MAXS_RECVNUM = 65536,
HTTP_CONNECTTIME = 5000,
TIMER1_ID=10000,
};
class ipcontainer:public boost::noncopyable
{
public:
static ipcontainer& getInstance();
bool adddata(const std::string& ip, const std::string& addr);
bool deldata(const std::string& ip);
bool getdata(std::vector<testSpeedData>* dataparam,HWND listctrl);
bool getcount(int& pcount);
virtual ~ipcontainer();
private:
ipcontainer();
static int getdatacallback(void *NotUsed, int argc, char **argv, char **azColName);
static int getcountcallback(void *NotUsed, int argc, char **argv, char **azColName);
private:
sqlite3* db;
static int* pcount;
static std::vector<testSpeedData>* testdata;
static HWND pwnd;
};
template<typename D>
class ThreadPool
{
public:
ThreadPool(boost::mutex& _mu) :mu(_mu)
{
threadnum = 0;
task = NULL;
}
virtual ~ThreadPool()
{
if (ppio)
{
for (int i = 0; i < threadnum; i++)
delete ppio;
delete[]ppio;
}
}
bool Attach(int _threadnum, std::deque<int>* _task, std::vector<D>* _dataarray, HWND _listview)
{
if (!_task || _task->empty() || !_dataarray)
return false;//任务未结束
task = _task;
dataarray = _dataarray;
threadnum = _threadnum;
listview = _listview;
ppio = new boost::asio::io_service*;
if (!ppio)
return false;
for (int i = 0; i < threadnum; i++)
{
ppio = new boost::asio::io_service;
if (!ppio)//模拟new[]的行为,释放之前成功分配的内存
{
for (int j = i-1; j >= 0; j--)
delete ppio;
delete[]ppio;
return false;
}
}
return true;
}
bool Exec(void(*f)(int, std::vector<D>*, HWND))
{
try
{
boost::thread_group tg;
//建立线程组
for (int i = 0; i < threadnum; i++)
{
tg.create_thread(boost::bind(&ThreadPool::wrapper, this, ppio,f));
}
//等待所有任务执行完毕
tg.join_all();
}
catch (...)
{
//确保释放new
return false;
}
return true;
}
private:
//用于将task里的任务分配各给threadnum个活动线程,分配时要进行线程同步
void wrapper(boost::asio::io_service* service, void(*f)(int, std::vector<D>*, HWND))
{
while (true)
{
mu.lock();
if (task->empty())
{
mu.unlock();
return;
}
service->post(boost::bind(f, task->front(), dataarray, listview));
task->pop_front();
mu.unlock();
service->run();
service->reset();
}
}
private:
int threadnum;
HWND listview;
boost::mutex& mu;//分配任务用锁
std::deque<int>* task;//要分配的总任务索引
std::vector<D>* dataarray;//原始数据
boost::asio::io_service** ppio;//耗费的线程资源
};
#pragma pack(push)
#pragma pack(2)
typedef struct _DNSANSWER_HEADER
{
WORD Name;
WORD Type;
WORD Class;
DWORD Timetolive;
WORD Datalength;
}DNSANSWER_HEADER, *PDNSANSWER_HEADER;
#pragma pack(pop)
#define DNS_BYTE_FLIP_ANSWERHEADER_COUNTS(pHeader)\
{\
PDNSANSWER_HEADER _head = (pHeader); \
INLINE_HTONS(_head->Name, _head->Name);\
INLINE_HTONS(_head->Type, _head->Type); \
INLINE_HTONS(_head->Class, _head->Class); \
INLINE_HTONS(_head->Timetolive, _head->Timetolive); \
INLINE_HTONS(_head->Datalength, _head->Datalength); \
}
class udpclient//只为做超时处理
{
public:
udpclient(const boost::asio::ip::udp::endpoint& listen_endpoint) :socket_(io_service_, listen_endpoint), deadline_(io_service_)
{
deadline_.expires_at(boost::posix_time::pos_infin);
check_deadline();
}
std::size_t receive(const boost::asio::mutable_buffer& buffer, boost::posix_time::time_duration timeout, boost::system::error_code& ec)
{
deadline_.expires_from_now(timeout);
ec = boost::asio::error::would_block;
std::size_t length = 0;
socket_.async_receive(boost::asio::buffer(buffer), boost::bind(&udpclient::handle_receive, _1, _2, &ec, &length));
do io_service_.run_one(); while (ec == boost::asio::error::would_block);
return length;
}
private:
void check_deadline()
{
if (deadline_.expires_at() <= boost::asio::deadline_timer::traits_type::now())
{
socket_.cancel();
deadline_.expires_at(boost::posix_time::pos_infin);
}
deadline_.async_wait(boost::bind(&udpclient::check_deadline, this));
}
static void handle_receive(const boost::system::error_code& ec, std::size_t length,
boost::system::error_code* out_ec, std::size_t* out_length)
{
*out_ec = ec;
*out_length = length;
}
private:
boost::asio::io_service io_service_;
boost::asio::deadline_timer deadline_;
public:
boost::asio::ip::udp::socket socket_;
};
class tcpclient//只为做超时处理
{
public:
tcpclient() :socket_(io_service_), deadline_(io_service_)
{
deadline_.expires_at(boost::posix_time::pos_infin);
check_deadline();
}
void connect(const boost::asio::ip::tcp::endpoint ep, boost::posix_time::time_duration timeout, boost::system::error_code& ec)
{
deadline_.expires_from_now(timeout);
ec = boost::asio::error::would_block;
socket_.async_connect(ep,boost::bind(&tcpclient::handle_connect, _1, &ec));
do io_service_.run_one(); while (ec == boost::asio::error::would_block);
}
private:
void check_deadline()
{
if (deadline_.expires_at() <= boost::asio::deadline_timer::traits_type::now())
{
socket_.cancel();
deadline_.expires_at(boost::posix_time::pos_infin);
}
deadline_.async_wait(boost::bind(&tcpclient::check_deadline, this));
}
static void handle_connect(const boost::system::error_code& ec, boost::system::error_code* out_ec)
{
*out_ec = ec;
}
private:
boost::asio::io_service io_service_;
boost::asio::deadline_timer deadline_;
public:
boost::asio::ip::tcp::socket socket_;
};
fasterdnsdlg.cpp
// FasterDNSDlg.cpp : 实现文件
//
#include "stdafx.h"
#include "FasterDNS.h"
#include "FasterDNSDlg.h"
#include "SetDnsDlg.h"
#include "afxdialogex.h"
#include <boost/scoped_ptr.hpp>
#include <boost/bind.hpp>
#include <boost/thread.hpp>
#include <boost/range.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/xpressive/xpressive.hpp>
#include <boost/asio.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/format.hpp>
#include <queue>
#include <fstream>
#include <set>
#include "functions.h"
#include <stdlib.h>
#include "ShowIp.h"
#include "GlobalSetting.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
CFasterDNSDlg::CFasterDNSDlg(CWnd* pParent /*=NULL*/)
: CDialogEx(CFasterDNSDlg::IDD, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CFasterDNSDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CFasterDNSDlg, CDialogEx)
ON_WM_PAINT()
ON_BN_CLICKED(IDC_ADDDNS, &CFasterDNSDlg::OnBnClickedAddDNS)
ON_NOTIFY(LVN_GETDISPINFO, IDC_IPLIST, &CFasterDNSDlg::OnLvnGetdispinfoIplist)
ON_COMMAND(ID_ABOUT, &CFasterDNSDlg::OnAbout)
ON_COMMAND(ID_SETDNS, &CFasterDNSDlg::OnSetdns)
ON_NOTIFY(HDN_ITEMCLICK, 0, &CFasterDNSDlg::OnHdnItemclickIplist)
ON_NOTIFY(NM_RCLICK, IDC_IPLIST, &CFasterDNSDlg::OnNMRClickIplist)
ON_COMMAND(ID_DELDNS, &CFasterDNSDlg::OnDeldns)
ON_BN_CLICKED(IDC_ALLINONE, &CFasterDNSDlg::OnBnClickedAllinone)
ON_BN_CLICKED(IDC_START, &CFasterDNSDlg::OnBnClickedStart)
ON_BN_CLICKED(IDC_STOP, &CFasterDNSDlg::OnBnClickedStop)
ON_BN_CLICKED(IDC_VIEWIP, &CFasterDNSDlg::OnBnClickedViewip)
ON_WM_TIMER()
ON_COMMAND(ID_ADDDNS, &CFasterDNSDlg::OnAdddns)
ON_COMMAND(ID_MODIFY, &CFasterDNSDlg::OnModify)
ON_COMMAND(ID_STARTALL, &CFasterDNSDlg::OnStartall)
ON_COMMAND(ID_STOPALL, &CFasterDNSDlg::OnStopall)
ON_COMMAND(ID_TESTIP, &CFasterDNSDlg::OnTestip)
ON_COMMAND(ID_EXIT, &CFasterDNSDlg::OnExit)
ON_COMMAND(ID_ALLINONE, &CFasterDNSDlg::OnAllinone)
ON_COMMAND(ID_START, &CFasterDNSDlg::OnStart)
ON_COMMAND(ID_STOP, &CFasterDNSDlg::OnStop)
END_MESSAGE_MAP()
BOOL CFasterDNSDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标
m_list = (CListCtrl*)GetDlgItem(IDC_IPLIST);
m_list->SendMessage(LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_FULLROWSELECT, LVS_EX_FULLROWSELECT);
RECT rt;
m_list->GetClientRect(&rt);
m_list->InsertColumn(COL_IP, "DNS地址", LVCFMT_LEFT, rt.right / 5);
m_list->InsertColumn(COL_LOC, "所在地", LVCFMT_LEFT, rt.right / 5);
m_list->InsertColumn(COL_RES, "响应时间", LVCFMT_LEFT, rt.right / 5);
m_list->InsertColumn(COL_FAIL, "失败率", LVCFMT_LEFT, rt.right / 5);
boost::thread(boost::bind(getdata, &dataarray, m_list->m_hWnd, GetDlgItem(IDC_STATU)->m_hWnd, &datamutex));
issorting = false;
maxtask = 0;
repeattime = 3;
threadnum = 3;
timeout = 1000;
SetDlgItemText(IDC_DOMAIN, "www.microsoft.com");
SetTimer(TIMER1_ID, 1000, NULL);
return TRUE;// 除非将焦点设置到控件,否则返回 TRUE
}
void CFasterDNSDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // 用于绘制的设备上下文
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialogEx::OnPaint();
}
}
void CFasterDNSDlg::OnBnClickedAddDNS()
{
CFileDialogdlg(TRUE, NULL, NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, "*.*", NULL);
if (IDOK == dlg.DoModal())
{
//读取文件,解析出ip
std::fstream file;
std::string line;
dbData toadd;
boost::asio::ip::address addr;
spliter splitvec;
//获取大小
file.open(dlg.GetPathName(), std::ios::in);
file.seekg(0,std::ios::end);
int totalsize = file.tellg();
file.seekg(0,std::ios::beg);
CProgressCtrl m_progctrl;
m_progctrl.Create(WS_CHILD | WS_VISIBLE, CRect(0, 0, 400, 50), this,
IDC_PROGRESS);
m_progctrl.SetRange(0, 100);
boost::mutex::scoped_lock mdata(datamutex);
if (dlg.GetFileName() == CSVDATA)
{
getline(file, line);//跳过第一行
while (!file.eof())
{
int pos2 = file.tellg();
m_progctrl.SetPos(int(100*(double)file.tellg()/totalsize));
getline(file, line);
boost::split(splitvec, line, boost::is_any_of(","));
try
{
if (splitvec.size() < CSV_MAX)
throw "Error";
addr = addr.from_string(splitvec);
}
catch (...)
{
break;
}
LVITEM item = { 0 };
item.mask = LVIF_TEXT;
item.iItem = dataarray.size();
item.lParam = item.iItem;
item.pszText = LPSTR_TEXTCALLBACK;
dataarray.push_back(testSpeedData((char*)splitvec.c_str(), (char*)(splitvec + " " + splitvec).c_str()));
m_list->InsertItem(&item);
toadd.push_back(make_pair(splitvec, splitvec + " " + splitvec));
}
}
else
{//普通文件,ip地址和位置信息用逗号分隔
while (!file.eof())
{
m_progctrl.SetPos(int(100*(double)file.tellg() / totalsize));
getline(file, line);
boost::split(splitvec, line, boost::is_any_of(","));
try
{
if (splitvec.size() < COM_MAX)
throw "Error";
addr = addr.from_string(splitvec);
}
catch (...)
{
break;
}
LVITEM item = { 0 };
item.mask = LVIF_TEXT;
item.iItem = dataarray.size();
item.lParam = item.iItem;
item.pszText = LPSTR_TEXTCALLBACK;
dataarray.push_back(testSpeedData((char*)splitvec.c_str(), (char*)splitvec.c_str()));
m_list->InsertItem(&item);
toadd.push_back(make_pair(splitvec, splitvec));
}
}
file.close();
ProgressThread("正在添加",doadddata,&toadd);
}
}
template<typename F,typename D>
void CFasterDNSDlg::ProgressThread(LPCTSTR wndname,F& threadfunc,D paramdata)
{
CProgressCtrl m_progctrl;
m_progctrl.Create(WS_CHILD | WS_VISIBLE | PBS_SMOOTH, CRect(0, 0, 400, 50), this, IDC_PROGRESS);
m_progctrl.SetRange(0, 100);
m_progctrl.SetWindowText(wndname);
//绑定进度条到threadfunc,抽象出逻辑使在其内部动态更新进度条
boost::packaged_task<bool> pt(boost::bind(threadfunc, paramdata, m_progctrl.m_hWnd));
boost::unique_future<bool> uf = pt.get_future();
boost::thread(boost::move(pt));
uf.wait();
if (uf.get())
SetDlgItemText(IDC_STATU, "操作成功!");
else
SetDlgItemText(IDC_STATU, "操作失败!");
}
char toformat;
void CFasterDNSDlg::OnLvnGetdispinfoIplist(NMHDR *pNMHDR, LRESULT *pResult)
{//刷新数据
NMLVDISPINFO *pDispInfo = reinterpret_cast<NMLVDISPINFO*>(pNMHDR);
// TODO:在此添加控件通知处理程序代码
int index = pDispInfo->item.iItem;
if (dataarray.size() == 0 || index > dataarray.size() - 1)
return;
testSpeedData& cur = dataarray;
switch (pDispInfo->item.iSubItem)
{
case COL_IP:
pDispInfo->item.pszText = (char*)cur.ip.c_str();
break;
case COL_LOC:
pDispInfo->item.pszText = (char*)cur.location.c_str();
break;
case COL_RES:
if (cur.responsetime == 0)
pDispInfo->item.pszText = "未测速";
else if (cur.testtime == cur.failtime)
pDispInfo->item.pszText = "测速失败";
else
{
sprintf_s(toformat, "%d ms", cur.responsetime / (cur.testtime - cur.failtime));
pDispInfo->item.pszText = toformat;
}
break;
case COL_FAIL:
if (dataarray.testtime == 0)
pDispInfo->item.pszText = "未测速";
else
{
sprintf_s(toformat, "%d/%d", cur.failtime, cur.testtime);
pDispInfo->item.pszText = toformat;
}
break;
}
*pResult = 0;
}
void CFasterDNSDlg::OnAbout()
{
AfxMessageBox("该程序在‘彗星DNS优化器’基础上修改得到,增加了数据库,有望未来支持ipv6\r\n作者:lichao890427 qq:571652571");
}
void CFasterDNSDlg::OnSetdns()
{//显示网卡窗口
std::vector<std::string> selip;
int uSelectedCount = m_list->GetSelectedCount();
int nItem = -1;
if (uSelectedCount > 0)
{
for (int i = 0; i < uSelectedCount; i++)
{
nItem = m_list->GetNextItem(nItem, LVNI_SELECTED);
selip.push_back(dataarray.ip);
}
boost::thread(boost::bind(&CFasterDNSDlg::DoDNSConnection, this));
}
CSetDnsDlg setdns(selip);
setdns.DoModal();
}
bool CompareIP(testSpeedData& lParam1, testSpeedData& lParam2)
{
using namespace boost::asio;
ip::address& addr1 = ip::address::from_string(lParam1.ip);
ip::address& addr2 = ip::address::from_string(lParam2.ip);
if (addr1.is_v4())
{
if (addr2.is_v4())
{
return addr1.to_v4().to_ulong() < addr2.to_v4().to_ulong();
}
else
return true;
}
else
{
return false;
}
}
bool CompareLOC(testSpeedData& lParam1, testSpeedData& lParam2)
{
return lParam1.location < lParam2.location;
}
bool CompareRES(testSpeedData& lParam1, testSpeedData& lParam2)
{
if (lParam1.failtime || lParam1.lefttime)
return true;
else if (lParam2.failtime || lParam2.lefttime)
return false;
else if (!lParam1.testtime || !lParam2.testtime)
return lParam1.testtime < lParam2.testtime;
else
return lParam1.responsetime / lParam1.testtime < lParam2.responsetime / lParam2.testtime;
}
void CFasterDNSDlg::DoSort(bool(*f)(testSpeedData&, testSpeedData&))
{
if (issorting)
{
AfxMessageBox("排序尚未完成!");
return;
}
boost::mutex::scoped_lock mdata(datamutex);
SetDlgItemText(IDC_STATU, "正在排序");
issorting = true;
std::sort(dataarray.begin(), dataarray.end(), f);
for (int i = 0; i < dataarray.size(); i++)
{
LVITEM item = { 0 };
item.mask = LVIF_TEXT;
item.iItem = i;
item.pszText = LPSTR_TEXTCALLBACK;
m_list->SendMessage(LVM_SETITEMTEXT, i, (LPARAM)&item);
}
SetDlgItemText(IDC_STATU, "排序完毕");
issorting = false;
}
void CFasterDNSDlg::OnHdnItemclickIplist(NMHDR *pNMHDR, LRESULT *pResult)
{//排序
LPNMHEADER phdr = reinterpret_cast<LPNMHEADER>(pNMHDR);
switch (phdr->iItem)
{//不要直接修改listview,而是先修改和listview绑定的data,再通知listview
case COL_IP:
boost::thread(boost::bind(&CFasterDNSDlg::DoSort, this, CompareIP));
break;
case COL_LOC:
boost::thread(boost::bind(&CFasterDNSDlg::DoSort, this, CompareLOC));
break;
case COL_RES:
boost::thread(boost::bind(&CFasterDNSDlg::DoSort, this, CompareRES));
break;
case COL_FAIL:
break;
}
*pResult = 0;
}
void CFasterDNSDlg::OnNMRClickIplist(NMHDR *pNMHDR, LRESULT *pResult)
{//右键弹出菜单
LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
CMenu menu;
menu.LoadMenu(IDR_POPUPMENU);
CMenu* pPopup = menu.GetSubMenu(0);
POINT pt;
GetCursorPos(&pt);
pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_LEFTBUTTON, pt.x, pt.y, this);
*pResult = 0;
}
void CFasterDNSDlg::OnDeldns()
{//删除dns,先从数据库中删,再重新加载数据
int uSelectedCount = m_list->GetSelectedCount();
int nItem = -1;
if (uSelectedCount > 0)
{
boost::mutex::scoped_lock mdata(datamutex);
std::vector<std::string> temp;
for (int i = 0; i < uSelectedCount; i++)
{
nItem = m_list->GetNextItem(nItem, LVNI_SELECTED);
temp.push_back(dataarray.ip);
}
dodeldata(&temp, m_list->m_hWnd);
dataarray.clear();
m_list->DeleteAllItems();
boost::thread(boost::bind(getdata, &dataarray, m_list->m_hWnd, GetDlgItem(IDC_STATU)->m_hWnd, &datamutex));
}
}
std::set<std::string> resolvedip;
std::string domain="www.microsoft.com";
void testFunc(int index, std::vector<testSpeedData>* rawdata, HWND listview)
{
testSpeedData& curdata = (*rawdata).at(index);
std::vector<uint8_t> bufferdata;
bool got = false;
while (curdata.lefttime)
{
makedns(bufferdata, domain);
int originlen = bufferdata.size();//发送包大小,用于定位返回answer
replaceXid(bufferdata, rand() & 0xFFFF);
uint32_t usedtime = curdata.timeout;
if (!dodnsconnect(curdata.ip, usedtime, bufferdata))
curdata.failtime++;
else
{
curdata.responsetime += usedtime;
if (!got)
{//解析返回包
resolveAnswer(bufferdata, resolvedip, originlen);
got = true;
}
}
curdata.lefttime--;
}
//刷新listview
LVITEM item = { 0 };
item.mask = LVIF_TEXT;
item.iItem = index;
item.pszText = LPSTR_TEXTCALLBACK;
SendMessage(listview, LVM_SETITEMTEXT, index, (LPARAM)&item);
}
void CFasterDNSDlg::OnTimer(UINT_PTR nIDEvent)
{
char status;
sprintf_s(status,"%06d/%06d/%06d", task.size(), maxtask, dataarray.size());
SetDlgItemText(IDC_TESTPROG, status);
CDialogEx::OnTimer(nIDEvent);
}
void CFasterDNSDlg::DoDNSConnection()
{//设置testSpeedData
maxtask = task.size();
CString domaina;
GetDlgItemText(IDC_DOMAIN, domaina);
::domain = (LPCTSTR)domaina;
resolvedip.clear();
ThreadPool<testSpeedData> newtaskset(taskmutex);
newtaskset.Attach(threadnum, &task, &dataarray,m_list->m_hWnd);
newtaskset.Exec(testFunc);
OnBnClickedViewip();
}
void CFasterDNSDlg::InitOne(testSpeedData& obj)
{//初始化单个数据
obj.failtime = 0;
obj.lefttime = repeattime;
obj.responsetime = 0;
obj.testtime = repeattime;
obj.timeout = timeout;
}
void CFasterDNSDlg::OnBnClickedAllinone()
{
boost::mutex::scoped_lock mtask(taskmutex);
//list和data绑定,数据更改通过data更新list而不直接操作list,因此该锁同时绑定data和list
if (!task.empty())
{
AfxMessageBox("测试尚未结束,请先停止测试");
return;
}
int nCount = m_list->GetItemCount();
task.clear();
for (int i = 0; i < nCount; i++)
{
task.push_back(i);
}
boost::thread(boost::bind(&CFasterDNSDlg::DoDNSConnection, this));
}
void CFasterDNSDlg::OnBnClickedStart()
{//测试选中
boost::mutex::scoped_lock mtask(taskmutex);
if (!task.empty())
{
AfxMessageBox("测试尚未结束,请先停止测试");
return;
}
int uSelectedCount = m_list->GetSelectedCount();
int nItem = -1;
if (uSelectedCount > 0)
{
task.clear();
for (int i = 0; i < uSelectedCount; i++)
{
nItem = m_list->GetNextItem(nItem, LVNI_SELECTED);
InitOne(dataarray);
task.push_back(nItem);
}
boost::thread(boost::bind(&CFasterDNSDlg::DoDNSConnection, this));
}
}
void CFasterDNSDlg::OnBnClickedStop()
{
//停止当前任务意味着清除剩余分配任务task
boost::mutex::scoped_lock mio(taskmutex);
//使用同一个锁保证不和分配任务线程操作冲突
task.clear();
}
void CFasterDNSDlg::OnBnClickedViewip()
{
CShowIp ipdlg(domain, resolvedip);
ipdlg.DoModal();
}
void CFasterDNSDlg::OnAdddns()
{
OnBnClickedAddDNS();
}
void CFasterDNSDlg::OnModify()
{
CGlobalSetting settings(threadnum, timeout, repeattime);
settings.DoModal();
}
void CFasterDNSDlg::OnStartall()
{
OnBnClickedAllinone();
}
void CFasterDNSDlg::OnStopall()
{
OnBnClickedStop();
}
void CFasterDNSDlg::OnTestip()
{
OnBnClickedViewip();
}
void CFasterDNSDlg::OnExit()
{
SendMessage(WM_CLOSE, 0, 0);
}
void CFasterDNSDlg::OnAllinone()
{
OnBnClickedAllinone();
}
void CFasterDNSDlg::OnStart()
{
OnBnClickedStart();
}
void CFasterDNSDlg::OnStop()
{
OnBnClickedStop();
}
functions.cpp
#include "stdafx.h"
#include <boost/function.hpp>
#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include <boost/bind.hpp>
#include <boost/date_time.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/format.hpp>
#include <boost/system/error_code.hpp>
#include <vector>
#include <set>
#include <winsock.h>
#include <stdint.h>
#include <iphlpapi.h>
#include <windows.h>
#include "functions.h"
#include "sqlite3.h"
#pragma comment(lib,"sqlite3.lib")
#pragma comment(lib,"iphlpapi.lib")
/************************************************************************/
/* 单例模式获取实例 */
/************************************************************************/
std::vector<testSpeedData>* ipcontainer::testdata = NULL;
int* ipcontainer::pcount = NULL;
HWND ipcontainer::pwnd = NULL;
ipcontainer& ipcontainer::getInstance()
{
boost::mutex mio;
boost::mutex::scoped_lock lock(mio);
static ipcontainer container;
return container;
}
/************************************************************************/
/* 向数据库中增加dns数据
ip:待添加dns服务器ip地址(非域名) addr:待添加dns服务器地理位置 */
/************************************************************************/
bool ipcontainer::adddata(const std::string& ip, const std::string& addr)
{
int status = SQLITE_OK;
char* zErrMsg = NULL;
std::string toadd = "insert into dnss values ('" + ip + "','" + addr + "')";
try
{
status = sqlite3_exec(db, toadd.c_str(), NULL, NULL, &zErrMsg);
if (status != SQLITE_OK)
throw "Add failed!";
}
catch (...)
{
return false;
}
return true;
}
/************************************************************************/
/* 从数据库中删除dns数据
ip:待删除dns服务器ip地址(非域名) */
/************************************************************************/
bool ipcontainer::deldata(const std::string& ip)
{
int status = SQLITE_OK;
char* zErrMsg = NULL;
std::string toadd = "delete from dnss where ipaddr = '" + ip + "'";
try
{
status = sqlite3_exec(db, toadd.c_str(), NULL, NULL, &zErrMsg);
if (status != SQLITE_OK)
throw "Del failed!";
}
catch (...)
{
return false;
}
return true;
}
/************************************************************************/
/* 获取dns数据总入口
dataparam:存放获得数据结果 */
/************************************************************************/
bool ipcontainer::getdata(std::vector<testSpeedData>* dataparam, HWND listctrl)
{
try
{
ipcontainer::testdata = dataparam;
ipcontainer::pwnd = listctrl;
int status = SQLITE_OK;
char* zErrMsg = NULL;
status = sqlite3_exec(db, "select * from dnss", getdatacallback, NULL, &zErrMsg);
if (status != SQLITE_OK)
throw "Get failed!";
}
catch (...)
{
ipcontainer::testdata = NULL;
ipcontainer::pwnd = NULL;
return false;
}
ipcontainer::testdata = NULL;
ipcontainer::pwnd = NULL;
return true;
}
/************************************************************************/
/* 获取dns数据记录总数 */
/************************************************************************/
bool ipcontainer::getcount(int& count)
{
try
{
ipcontainer::pcount = &count;
int status = SQLITE_OK;
char* zErrMsg = NULL;
status = sqlite3_exec(db, "select count(*) from dnss", getcountcallback, NULL, &zErrMsg);
if (status != SQLITE_OK)
throw "Get failed!";
}
catch (...)
{
ipcontainer::pcount = NULL;
return false;
}
ipcontainer::pcount = NULL;
return true;
}
/************************************************************************/
/* 析构时关闭数据库 */
/************************************************************************/
ipcontainer::~ipcontainer()
{
ipcontainer::testdata = NULL;
ipcontainer::pcount = NULL;
ipcontainer::pwnd = NULL;
sqlite3_close(db);
db = NULL;
}
/************************************************************************/
/* 构造函数打开数据库 */
/************************************************************************/
ipcontainer::ipcontainer()
{
int status = SQLITE_OK;
db = NULL;
status = sqlite3_open(DATABASE, &db);
if (status != SQLITE_OK)
throw "Open failed!";
}
/************************************************************************/
/* 获取记录数据数组的回调函数,用于获取记录数据数组
argc:获得条目个数=2 argv:ip argv:location */
/************************************************************************/
int ipcontainer::getdatacallback(void *NotUsed, int argc, char **argv, char **azColName)
{
LVITEM item = { 0 };
item.mask = LVIF_TEXT;
item.iItem = ipcontainer::testdata->size();
item.lParam = item.iItem;
item.pszText = LPSTR_TEXTCALLBACK;
ipcontainer::testdata->push_back(testSpeedData(argv, argv));
SendMessage(pwnd, LVM_INSERTITEM, 0, (LPARAM)&item);
return 0;
}
/************************************************************************/
/* 获取记录条目的回调函数,用于得到记录条目
argc:获得条目个数=1 argv:记录条目 */
/************************************************************************/
int ipcontainer::getcountcallback(void *NotUsed, int argc, char **argv, char **azColName)
{
try
{
*ipcontainer::pcount = boost::lexical_cast<int>(argv);
}
catch (...)
{
*ipcontainer::pcount = 0;
}
return 0;
}
/************************************************************************/
/* 增加dns数据总入口
setpos:设置进度显示回调函数 dataparam:要添加的数据阵列*/
/************************************************************************/
bool doadddata(dbData* dataparam, HWND progctrl)
{
int size = dataparam->size() / 100;
int i = 0, j = 0;
SendMessage(progctrl, PBM_SETPOS, 0, 0);
try
{
dbData::const_iterator itor = dataparam->begin();
ipcontainer& container=ipcontainer::getInstance();
while (itor != dataparam->end())
{
container.adddata(itor->first, itor->second);
++itor;
++i;
if (i >= size)
{
i = 0;
SendMessage(progctrl, PBM_SETPOS, ++j, 0);
}
}
}
catch (...)
{
//发生错误
return false;
}
return true;
}
/************************************************************************/
/* 删除dns数据总入口
setpos:设置进度显示回调函数 dataparam:要删除的数据阵列*/
/************************************************************************/
bool dodeldata(std::vector<std::string>* dataparam, HWND progctrl)
{
int size = dataparam->size() / 100;
int i = 0, j = 0;
SendMessage(progctrl, PBM_SETPOS, 0, 0);
try
{
std::vector<std::string>::iterator itor = dataparam->begin();
ipcontainer& container = ipcontainer::getInstance();
while (itor != dataparam->end())
{
container.deldata(*itor);
++itor;
++i;
if (i >= size)
{
i = 0;
SendMessage(progctrl, PBM_SETPOS, ++j, 0);
}
}
}
catch (...)
{
//发生错误
return false;
}
return true;
}
/************************************************************************/
/* 尝试http连接
ip:要测试连通性的地址 timeout:超时返回 */
/************************************************************************/
bool dohttpconnect(const std::string& ip,uint32_t& timeout)
{//ip不能是域名 timeout同时用于设置超时和计时
using namespace boost::asio;
using namespace boost::posix_time;
try
{
tcpclient c;
boost::system::error_code ec;
setsockopt(c.socket_.native(), SOL_SOCKET, SO_RCVTIMEO, (const char*)timeout, sizeof(timeout));
ip::tcp::endpoint ep(ip::address::from_string(ip), PORT_HTTP);
ptime ptStart = microsec_clock::local_time();
c.connect(ep, boost::posix_time::millisec(timeout), ec);
if (ec.value())
throw "error";
ptime ptEnd = microsec_clock::local_time();
timeout = (int32_t)(ptEnd - ptStart).total_milliseconds();
}
catch (...)
{
return false;
}
return true;
}
/************************************************************************/
/* 尝试dns连接
ip:要测试连通性的地址 timeout:超时返回
bufferdata:用于发送和接收数据 */
/************************************************************************/
bool dodnsconnect(const std::string& ip, uint32_t& timeout,std::vector<uint8_t>& bufferdata)
{//bufferdata用于输入和输出 ip为服务器地址
using namespace boost::asio;
using namespace boost::posix_time;
try
{
udpclient c(ip::udp::endpoint(ip::udp::v4(), rand() & 0x7FFF + 0x8000));
boost::system::error_code ec;
setsockopt(c.socket_.native(), SOL_SOCKET, SO_RCVTIMEO, (const char*)timeout, sizeof(timeout));
setsockopt(c.socket_.native(), SOL_SOCKET, SO_BROADCAST, "\0\0\0\0", 4);
ip::udp::endpoint ep(ip::address::from_string(ip), PORT_DNS);
c.socket_.send_to(buffer((bufferdata)),ep);
bufferdata.clear();
bufferdata.resize(MAXS_RECVNUM);
ptime ptStart = microsec_clock::local_time();
c.receive(buffer(bufferdata), boost::posix_time::millisec(timeout), ec);
if (ec.value())
throw "error";
ptime ptEnd = microsec_clock::local_time();
timeout = (int32_t)(ptEnd - ptStart).total_milliseconds();
}
catch (...)
{
return false;
}
return true;
}
/************************************************************************/
/* 构造dns数据包
bufferdata:用于存储构造数据包结果
testdomain:用于验证的域名,不能用ip地址 */
/************************************************************************/
void makedns(std::vector<uint8_t>& bufferdata, const std::string& testdomain)
{//testip为验证ip,此函数用于testip更换时;Xid更换时用replaceXid
bufferdata.resize(sizeof(DNS_HEADER));
DNS_HEADER* pheader = (DNS_HEADER*)bufferdata.data();
memset(pheader, 0, sizeof(DNS_HEADER));
pheader->RecursionDesired = 1;
pheader->QuestionCount = 1;//查询一个域名
DNS_BYTE_FLIP_HEADER_COUNTS(pheader);
boost::asio::ip::address addr;
spliter splitvec;
boost::split(splitvec, testdomain, boost::is_any_of("."));
for (spliter::iterator itor = splitvec.begin(); itor != splitvec.end(); ++itor)
{
bufferdata.push_back((*itor).length());
bufferdata.insert(bufferdata.end(), (*itor).begin(),(*itor).end());
}
uint8_t tailer = { 0x00, 0x00, 0x01, 0x00, 0x01 };
bufferdata.insert(bufferdata.end(), tailer, tailer+SIZE_DNSTAILER);
}
/************************************************************************/
/* 修改dns数据包的TransactionID,考虑优化使用
bufferdata:待修改数据 Xid:新的TransactionID */
/************************************************************************/
void replaceXid(std::vector<uint8_t>& bufferdata, uint16_t Xid)
{
((DNS_HEADER*)bufferdata.data())->Xid = htons(Xid);
}
/************************************************************************/
/*从返回包结果中解析获取到的地址
bufferdata:服务器返回的待解析数据 resolveip:存储结果
originlen:发送包大小*/
/************************************************************************/
void resolveAnswer(std::vector<uint8_t>& bufferdata, std::set<std::string>& resolvedip, int originlen)
{
DNS_HEADER* pheader = (DNS_HEADER*)bufferdata.data();
DNS_BYTE_FLIP_HEADER_COUNTS(pheader);
uint8_t* ptr = (uint8_t*)pheader + originlen;
for (int i = 0; i < pheader->AnswerCount; i++)
{
DNSANSWER_HEADER* aheader = (DNSANSWER_HEADER*)ptr;
DNS_BYTE_FLIP_ANSWERHEADER_COUNTS(aheader);
if(aheader->Type == 1)//A:host address
{
BYTE* cdata = (BYTE*)aheader + sizeof(DNSANSWER_HEADER);
if (aheader->Datalength == 4)//ipv4
{
char temp;
sprintf_s(temp, "%d.%d.%d.%d", cdata, cdata, cdata, cdata);
resolvedip.insert(std::string(temp));
}
else if (aheader->Datalength == 6)//ipv6
{
//v6的没有条件研究呢。。。
}
}
ptr += aheader->Datalength + sizeof(DNSANSWER_HEADER);
}
}
/************************************************************************/
/* 获取网卡适配器
interfaces:存储结果 */
/************************************************************************/
bool getinterface(std::vector<std::string>& interfaces)
{
DWORD dwRetVal = 0;
ULONG outBufLen = 15000;
LPVOID lpMsgBuf = NULL;
PIP_ADAPTER_ADDRESSES pAddress = NULL;
interfaces.clear();
do
{
pAddress = (IP_ADAPTER_ADDRESSES*)HeapAlloc(GetProcessHeap(), 0, outBufLen);
if (pAddress == NULL)
return false;
dwRetVal = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, NULL, pAddress, &outBufLen);
if (dwRetVal == ERROR_BUFFER_OVERFLOW)
{
HeapFree(GetProcessHeap(), 0, pAddress);
pAddress = NULL;
}
} while (dwRetVal == ERROR_BUFFER_OVERFLOW);
if (dwRetVal != NO_ERROR)
return false;
PIP_ADAPTER_ADDRESSES pCurrAddresses = pAddress;
while (pCurrAddresses)
{
HKEY hkResult;
std::string query = "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\";
query += pCurrAddresses->AdapterName;
query += "\\Connection\\";
dwRetVal = RegOpenKey(HKEY_LOCAL_MACHINE, query.c_str(), &hkResult);
if (dwRetVal == ERROR_SUCCESS)
{
char buffer;
LONG cbData = 256;
dwRetVal = RegQueryValue(hkResult, "Name", buffer, &cbData);
if (dwRetVal == ERROR_SUCCESS)
{
interfaces.push_back((char*)buffer);
}
}
pCurrAddresses = pCurrAddresses->Next;
}
if (pAddress)
HeapFree(GetProcessHeap(), 0, pAddress);
return true;
}
/************************************************************************/
/* 设置指定网卡适配器dns
setpos:设置进度显示回调函数 interfaces:待设置适配器
address为点分十进制地址 */
/************************************************************************/
bool setinterface(std::vector<std::string>& interfaces, std::vector<std::string>& addresss, HWND progctrl)
{
using namespace boost::asio;
STARTUPINFO StartupInfo = { 0 };
PROCESS_INFORMATION ProcessInfo = { 0 };
StartupInfo.cb = sizeof(STARTUPINFO);
StartupInfo.dwFlags = STARTF_USESHOWWINDOW;
StartupInfo.wShowWindow = SW_HIDE;
std::string cmd;
int count = 0;
SendMessage(progctrl, PBM_SETPOS, 0, 0);
for (std::vector<std::string>::iterator itori = interfaces.begin(); itori != interfaces.end(); ++itori)
{
BOOL bRet;
cmd = "netsh interface ipv4 set dns name=\"" + *itori + "\" source=static addr=none";
//清除DNS设置
bRet=CreateProcess(NULL, (char*)cmd.c_str(), NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &StartupInfo, &ProcessInfo);
if (!bRet)
return false;
if (ProcessInfo.hProcess)
WaitForSingleObject(ProcessInfo.hProcess, INFINITE);
cmd = "netsh interface ipv6 set dns name=\"" + *itori + "\" source=static addr=none";
bRet = CreateProcess(NULL, (char*)cmd.c_str(), NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &StartupInfo, &ProcessInfo);
if (!bRet)
return false;
if (ProcessInfo.hProcess)
WaitForSingleObject(ProcessInfo.hProcess, INFINITE);
SendMessage(progctrl, PBM_SETPOS, int(100 * (float)count++ / interfaces.size()), 0);
SetWindowText(progctrl, ("正在清除设置 " + *itori).c_str());
for (std::vector<std::string>::iterator itora = addresss.begin(); itora != interfaces.end(); ++itora)
{
if ((ip::address::from_string(*itora)).is_v4())
cmd = "netsh interface ipv4 add dns name=\"" + *itori + "\" addr=" + *itora;
else
cmd = "netsh interface ipv6 add dns name=\"" + *itori + "\" addr=" + *itora;
SetWindowText(progctrl, ("正在设置 " + *itora).c_str());
bRet = CreateProcess(NULL, (char*)cmd.c_str(), NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &StartupInfo, &ProcessInfo);
if (!bRet)
return false;
if (ProcessInfo.hProcess)
WaitForSingleObject(ProcessInfo.hProcess, INFINITE);
}
}
return true;
}
/************************************************************************/
/* 封装getcount */
/************************************************************************/
bool getcount(int& count)
{
try
{
ipcontainer::getInstance().getcount(count);
}
catch (...)
{
return false;
}
return true;
}
/************************************************************************/
/* 封装getdata */
/************************************************************************/
bool getdata(std::vector<testSpeedData>* dataparam, HWND listctrl, HWND statu, boost::mutex* mu)
{
boost::mutex::scoped_lock mdata(*mu);
SetWindowText(statu, "正在初始化数据!");
try
{
ipcontainer::getInstance().getdata(dataparam, listctrl);
}
catch (...)
{
return false;
}
SetWindowText(statu, "初始化完毕!");
return true;
}
完整工程:http://pan.baidu.com/s/1dDrjRDB
页:
[1]