1、首先是从配置问价中读取配置信息,读取配置文件的代码如下,可留着备用
//从配置文件中读取数据 配置文件所在的位置 /src/client_config.ini
DEFINE_QUIC_COMMAND_LINE_FLAG(std::string,
client_ini_file,
"client_config.ini",
"Path to the certificate chain.");
std::string ini=GetQuicFlag(FLAGS_client_ini_file);
ini_t *config= ini_load(ini.c_str());
if(!config){
return 0;
}
//拿到了目的地址、以及连接的数目
std::string dest(ini_get(config, "client", "dest"));
std::string tunip(ini_get(config, "client", "tunip"));
std::string nic(ini_get(config, "client", "nic"));//多少个连接数
std::unique_ptr<ProxyClientBackend> backend(new ProxyClientBackend(dest));
int num = std::stoi(nic);
for(int i=0;i<num;i++){
//分别将两个连接的IP也给读了出来
std::string key="nicip"+std::to_string(i+1);
//读到client_config.ini配置文件中的ip地址
std::string value(ini_get(config, "client", key.c_str()));
backend->LocalIpAddress(value);
}
std::cout<<dest<<" "<<tunip<<std::endl;
ini_free(config);//使用结束还需要释放
2、根据传入的目的地址创建一个ProxyClientBackend对象
std::unique_ptr<ProxyClientBackend> backend(new ProxyClientBackend(dest));
接着又创建了一个ProxyClient对象,因为ProxyClientBackend继承了MyQuicBackend类,所以可以用这种方法来创建
std::unique_ptr<ProxyClient> client(new ProxyClient(backend.get()));
ProxyClient::ProxyClient(MyQuicBackend *backend){
backend_=backend;
epoll_server_.reset(new QuicEpollServer());//创建了一个epoll服务器
alarm_factory_.reset(new QuicEpollAlarmFactory(epoll_server_.get()));
clock_.reset(new QuicEpollClock(epoll_server_.get()));
//创建一个factory对象
factory_.reset(new MyProxyClientFactory(this,backend_));
看一下这个MyQuicContext,里面就是包含了一些基本的信息
class MyQuicContext{
public:
virtual ~MyQuicContext(){}
virtual QuicClock *clock()=0;
virtual QuicAlarmFactory* alarm_factory() =0;
virtual QuicEpollServer* epoll_server() =0;
virtual base::PlatformThreadId context_id() =0;
template <class Closure,
typename std::enable_if<!std::is_convertible<
Closure,
std::unique_ptr<QueuedTask>>::value>::type* = nullptr>
void PostTask(Closure&& closure){
PostInnerTask(NewClosure(std::forward<Closure>(closure)));
}
protected:
virtual void PostInnerTask(std::unique_ptr<QueuedTask> task)=0;
};
2、客户端程序中是需要配置默认路由,到达目的地数据引入大tun设备上面去
int ret=configure_route(ROUTE_ADD,tun_name.c_str(),dest.c_str(),32);
int configure_route(RouteCommand add,const char* dev,const char *dst,int masklen){
char cmd[kRouteBufferSize];
uint32_t ip;
::inet_pton(AF_INET,dst,(void*)&ip);
ip=ntohl(ip);
uint32_t mask = 0xffffffff << (32-masklen);
ip=(ip)&mask;
ip=htonl(ip);
char ip4[20]={0};
::inet_ntop(AF_INET, (void *)&ip, ip4, 16);
QUIC_LOG(INFO)<<ip4;
if(add==ROUTE_ADD){
//设置到达目的的ip走tun设备
sprintf(cmd, "ip route add %s/%d dev %s", ip4, masklen, dev);
}else{
//完事儿还需要删除这条路由规则
sprintf(cmd, "ip route del %s/%d dev %s", ip4, masklen, dev);
}
int res=system(cmd);
if ( res< 0){
QUIC_LOG(ERROR)<<"route add error";
return -1;
}
return 0;
}
3、接下来就进入到handleEvent程序
while (m_running){
client->HandleEvent();
}
//
void ProxyClient::HandleEvent(){
if(context_id_==base::kInvalidThreadId){
context_id_=base::PlatformThread::CurrentId();
}
HandleInactiveClient();//删除失效的 处理非失效的
std::deque <RequestClientConfig> requests;
{
//加锁、交换链
QuicWriterMutexLock lock(&request_mutex_);
requests.swap(requests_);
}
if(requests.size()>0){
while(!requests.empty()){
auto it=requests.begin();
QuicIpAddress local=(*it).local;
size_t length=(*it).length;
const char *data=(*it).join_indication;
requests.erase(it);
//拿到一些基本信息后创建一个client
MyQuicToyClient *client=new MyQuicToyClient(factory_.get());
client->set_notifier(this);
//绑定地址
client->set_bind_to_address(local);
//创建一个字符串
std::string indication(data,length);
if(length>0){
client->JoinIndication(indication);
}
//初始化和建立连接的过程
int ret=client->InitialAndConnect();
if(ret!=0){
delete client;
}else{
active_clients_.insert(client);
}
}
}
std::deque<std::unique_ptr<QueuedTask>> tasks;
{
QuicWriterMutexLock lock(&task_mutex_);
tasks.swap(queued_tasks_);
}
while(!tasks.empty()){
tasks.front()->Run();
tasks.pop_front();
}
epoll_server_->WaitForEventsAndExecuteCallbacks();
}
//看看这个建立连接的过程
int MyQuicToyClient::InitialAndConnect() {
std::string host = GetQuicFlag(FLAGS_host);
if (host.empty()) {
return 1;
}
int port = GetQuicFlag(FLAGS_port);
if (port == 0) {
return 1;
}
quic::ParsedQuicVersionVector versions = quic::CurrentSupportedVersions();
std::string quic_version_string = GetQuicFlag(FLAGS_quic_version);
if (GetQuicFlag(FLAGS_quic_ietf_draft)) {
quic::QuicVersionInitializeSupportForIetfDraft();
versions = {};
for (const ParsedQuicVersion& version : AllSupportedVersions()) {
if (version.HasIetfQuicFrames() &&
version.handshake_protocol == quic::PROTOCOL_TLS1_3) {
versions.push_back(version);
}
}
quic::QuicEnableVersion(versions[0]);
} else if (!quic_version_string.empty()) {
quic::ParsedQuicVersion parsed_quic_version =
quic::ParseQuicVersionString(quic_version_string);
if (parsed_quic_version.transport_version ==
quic::QUIC_VERSION_UNSUPPORTED) {
return 1;
}
versions = {parsed_quic_version};
quic::QuicEnableVersion(parsed_quic_version);
}
if (GetQuicFlag(FLAGS_force_version_negotiation)) {
versions.insert(versions.begin(),
quic::QuicVersionReservedForNegotiation());
}
//版本协商
std::unique_ptr<quic::ProofVerifier> proof_verifier=std::make_unique<FakeProofVerifier>();
//校验证书 包含这一些版本协商、证书等信息
//创建一个客户端,并尝试着连接
// Build the client, and try to connect.
client_= client_factory_->CreateClient(this,
host, port, versions, std::move(proof_verifier));
if (client_ == nullptr){
std::cerr << "Failed to create client." << std::endl;
return 1;
}
client_->set_requester(this);
//绑定地址
if(bind_to_address_.IsInitialized()){
std::cout<<"bind addr "<<bind_to_address_<<std::endl;
client_->set_bind_to_address(bind_to_address_);
}
//协商MTU
int32_t initial_mtu = GetQuicFlag(FLAGS_initial_mtu);
client_->set_initial_max_packet_length(
initial_mtu != 0 ? initial_mtu : quic::kDefaultMaxPacketSize);
if (!client_->Initialize()) {
std::cerr << "Failed to initialize client." << std::endl;
return 1;
}
/**
bool QuicClientBase::Initialize() {
num_sent_client_hellos_ = 0;
connection_error_ = QUIC_NO_ERROR;
connected_or_attempting_connect_ = false;
// If an initial flow control window has not explicitly been set, then use the
// same values that Chrome uses.
const uint32_t kSessionMaxRecvWindowSize = 15 * 1024 * 1024; // 15 MB
const uint32_t kStreamMaxRecvWindowSize = 6 * 1024 * 1024; // 6 MB
if (config()->GetInitialStreamFlowControlWindowToSend() ==
kDefaultFlowControlSendWindow) {
config()->SetInitialStreamFlowControlWindowToSend(kStreamMaxRecvWindowSize);
}
if (config()->GetInitialSessionFlowControlWindowToSend() ==
kDefaultFlowControlSendWindow) {
config()->SetInitialSessionFlowControlWindowToSend(
kSessionMaxRecvWindowSize);
}
//这里面出现了创建UDP绑定
if (!network_helper_->CreateUDPSocketAndBind(server_address_,
bind_to_address_, local_port_)) {
return false;
}
initialized_ = true;
return true;
}
*/
//cofigure epoll, 50ms unwanted.
//client_->epoll_server()->set_timeout_in_us(0);
/*if (!client_->Connect()) {
quic::QuicErrorCode error = client_->session()->error();
if (error == quic::QUIC_INVALID_VERSION) {
std::cerr << "Server talks QUIC, but none of the versions supported by "
<< "this client: " << ParsedQuicVersionVectorToString(versions)
<< std::endl;
// 0: No error.
// 20: Failed to connect due to QUIC_INVALID_VERSION.
return GetQuicFlag(FLAGS_version_mismatch_ok) ? 0 : 20;
}
std::cerr << "Failed to connect to " << host << ":" << port
<< ". Error: " << quic::QuicErrorCodeToString(error) << std::endl;
return 1;
}*/
client_->AsynConnect();
//std::cerr << "Connected to " << host << ":" << port << std::endl;
return 0;
}
看看client的建立过程
//包含着对端的IP、端口、版本等一一些信息
client_= client_factory_->CreateClient(this,
host, port, versions, std::move(proof_verifier));
std::unique_ptr<MyQuicClient> MyQuicClientFactory::CreateClient(
QuicSession::Visitor *owner,
std::string host_for_lookup,
uint16_t port,
ParsedQuicVersionVector versions,
std::unique_ptr<ProofVerifier> verifier) {
QuicSocketAddress addr =
tools::LookupAddress(host_for_lookup, quiche::QuicheStrCat(port));
if (!addr.IsInitialized()) {
QUIC_LOG(ERROR) << "Unable to resolve address: " << host_for_lookup;
return nullptr;
}
QuicServerId server_id(host_for_lookup, port, false);
return std::make_unique<MyQuicClient>(owner,addr, server_id, versions,
context_,backend_,std::move(verifier));
}
//至此、客户端算是建立成功
//看看QUIC底层的UDP创建和绑定的过程
CreateUDPSocketAndBind(server_address_,bind_to_address_, local_port_)
bool QuicClientEpollNetworkHelper::CreateUDPSocketAndBind(
QuicSocketAddress server_address,
QuicIpAddress bind_to_address,
int bind_to_port) {
epoll_server_->set_timeout_in_us(50 * 1000);
//创建UDPsocket
int fd = CreateUDPSocket(server_address, &overflow_supported_);
if (fd < 0) {
return false;
}
QuicSocketAddress client_address;
if (bind_to_address.IsInitialized()) {
client_address = QuicSocketAddress(bind_to_address, client_->local_port());
} else if (server_address.host().address_family() == IpAddressFamily::IP_V4) {
client_address = QuicSocketAddress(QuicIpAddress::Any4(), bind_to_port);
} else {
client_address = QuicSocketAddress(QuicIpAddress::Any6(), bind_to_port);
}
sockaddr_storage addr = client_address.generic_address();
int rc = bind(fd, reinterpret_cast<sockaddr*>(&addr), sizeof(addr));
if (rc < 0) {
QUIC_LOG(ERROR) << "Bind failed: " << strerror(errno)
<< " bind_to_address:" << bind_to_address
<< ", bind_to_port:" << bind_to_port
<< ", client_address:" << client_address;
return false;
}
if (client_address.FromSocket(fd) != 0) {
QUIC_LOG(ERROR) << "Unable to get self address. Error: "
<< strerror(errno);
}
epoll服务器还注册了这个fd
fd_address_map_[fd] = client_address;
epoll_server_->RegisterFD(fd, this, kEpollFlags);
return true;
}
最后剩下这个 client_->AsynConnect();连接
client_->AsynConnect()
bool MyQuicClient::AsynConnect(){
if (!connected()){//判断是否连接上
StartConnect();
}
if (session() == nullptr) {
QUIC_BUG << "Missing session after Connect";
return false;
}
//返回连接层的connect
return session()->connection()->connected();
}