客户端代码阅读"/>
QUIC代理客户端代码阅读
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);//拿到一些基本信息后创建一个clientMyQuicToyClient *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_); }//协商MTUint32_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 MBconst uint32_t kStreamMaxRecvWindowSize = 6 * 1024 * 1024; // 6 MBif (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);
//创建UDPsocketint 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服务器还注册了这个fdfd_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;}//返回连接层的connectreturn session()->connection()->connected();
}
更多推荐
QUIC代理客户端代码阅读
发布评论