void UDPPort::SendStunBindingRequest(const rtc::SocketAddress& stun_addr){if(stun_addr.IsUnresolvedIP()){ResolveStunAddress(stun_addr);}elseif(socket_->GetState()== rtc::AsyncPacketSocket::STATE_BOUND){// Check if |server_addr_| is compatible with the port's ip.if(IsCompatibleAddress(stun_addr)){
requests_.Send(newStunBindingRequest(this, stun_addr, rtc::TimeMillis()));}else{// Since we can't send stun messages to the server, we should mark this// port ready.RTC_LOG(LS_WARNING)<<"STUN server address is incompatible.";OnStunBindingOrResolveRequestFailed(stun_addr);}}}
// Communicates using the address on the outside of a NAT.classUDPPort:public Port {
StunRequestManager requests_;};
conclusion
向一个可以兼容的stun server发送Binding Request
requests_是UDPPort的一个成员变量
// Handles a binding request sent to the STUN server.classStunBindingRequest:public StunRequest {voidOnResponse(StunMessage* response) override {const StunAddressAttribute* addr_attr =
response->GetAddress(STUN_ATTR_MAPPED_ADDRESS);if(!addr_attr){RTC_LOG(LS_ERROR)<<"Binding response missing mapped address.";}elseif(addr_attr->family()!= STUN_ADDRESS_IPV4 &&
addr_attr->family()!= STUN_ADDRESS_IPV6){RTC_LOG(LS_ERROR)<<"Binding address has bad family";}else{
rtc::SocketAddress addr(addr_attr->ipaddr(), addr_attr->port());
port_->OnStunBindingRequestSucceeded(this->Elapsed(), server_addr_, addr);}// The keep-alive requests will be stopped after its lifetime has passed.if(WithinLifetime(rtc::TimeMillis())){
port_->requests_.SendDelayed(newStunBindingRequest(port_, server_addr_, start_time_),
port_->stun_keepalive_delay());}}};
// Communicates using the address on the outside of a NAT.classUDPPort:public Port {// If this is a low-cost network, it will keep on sending STUN binding// requests indefinitely to keep the NAT binding alive. Otherwise, stop// sending STUN binding requests after HIGH_COST_PORT_KEEPALIVE_LIFETIME.intGetStunKeepaliveLifetime(){return(network_cost()>= rtc::kNetworkCostHigh)? HIGH_COST_PORT_KEEPALIVE_LIFETIME
: INFINITE_LIFETIME;}};
conclusion
向stun server发送Binding Request请求,返回的Response在这里处理
如果是成功,会得到server reflex ip 和 port,然后调用OnStunBindingRequestSuccessed
// Communicates using the address on the outside of a NAT.classUDPPort:public Port {// Below methods handles binding request responses.voidOnStunBindingRequestSucceeded(int rtt_ms,const rtc::SocketAddress& stun_server_addr,const rtc::SocketAddress& stun_reflected_addr);voidOnStunBindingOrResolveRequestFailed(const rtc::SocketAddress& stun_server_addr);};classStunPort:public UDPPort {};
conclusion
UDPPort和StunPort的耦合性很高
OnStunBindingRequestSucceeded处理成功的response
typedef std::set<rtc::SocketAddress> ServerAddresses;// Communicates using the address on the outside of a NAT.classUDPPort:public Port {
ServerAddresses server_addresses_;
ServerAddresses bind_request_succeeded_servers_;
ServerAddresses bind_request_failed_servers_;};
conclusion
这三个地址分别是
所有stun server地址
binding request成功的stun server
binding request失败的stun server
void UDPPort::OnStunBindingRequestSucceeded(int rtt_ms,const rtc::SocketAddress& stun_server_addr,const rtc::SocketAddress& stun_reflected_addr){
bind_request_succeeded_servers_.insert(stun_server_addr);// If socket is shared and |stun_reflected_addr| is equal to local socket// address, or if the same address has been added by another STUN server,// then discarding the stun address.// For STUN, related address is the local socket address.if((!SharedSocket()|| stun_reflected_addr != socket_->GetLocalAddress())&&!HasCandidateWithAddress(stun_reflected_addr)){
rtc::SocketAddress related_address = socket_->GetLocalAddress();// If we can't stamp the related address correctly, empty it to avoid leak.if(!MaybeSetDefaultLocalAddress(&related_address)){
related_address =
rtc::EmptySocketAddressWithFamily(related_address.family());}
rtc::StringBuilder url;
url <<"stun:"<< stun_server_addr.ipaddr().ToString()<<":"<< stun_server_addr.port();AddAddress(stun_reflected_addr, socket_->GetLocalAddress(), related_address,
UDP_PROTOCOL_NAME,"","", STUN_PORT_TYPE,
ICE_TYPE_PREFERENCE_SRFLX,0, url.str(),false);}}
conclusion
stun的reflex地址插入到bind_request_succeeded_servers_
AddAddress
// Represents a local communication mechanism that can be used to create// connections to similar mechanisms of the other client. Subclasses of this// one add support for specific mechanisms like local UDP ports.classPort:public PortInterface,public rtc::MessageHandler,public sigslot::has_slots<>{voidAddAddress(const rtc::SocketAddress& address,const rtc::SocketAddress& base_address,const rtc::SocketAddress& related_address,const std::string& protocol,const std::string& relay_protocol,const std::string& tcptype,const std::string& type,uint32_t type_preference,uint32_t relay_preference,const std::string& url,bool is_final);};
conclusion
这里const std::string& url,要注意,没有的是要deprecated的函数
扩展:一共有三处调用这个函数
就是这里的stun binding request打洞成功
在relay_port.cc里,就是用于turn转发的address
在stun_port.cc里,收集的本地地址
收集turn地址
void TurnPort::OnAllocateSuccess(const rtc::SocketAddress& address,const rtc::SocketAddress& stun_address){
state_ = STATE_READY;
rtc::SocketAddress related_address = stun_address;// For relayed candidate, Base is the candidate itself.AddAddress(address,// Candidate address.
address,// Base address.
related_address,// Related address.
UDP_PROTOCOL_NAME,ProtoToString(server_address_.proto),// The first hop protocol."",// TCP canddiate type, empty for turn candidates.
RELAY_PORT_TYPE,GetRelayPreference(server_address_.proto),
server_priority_,ReconstructedServerUrl(),true);}
收集本地地址
void UDPPort::OnLocalAddressReady(rtc::AsyncPacketSocket* socket,const rtc::SocketAddress& address){// When adapter enumeration is disabled and binding to the any address, the// default local address will be issued as a candidate instead if// |emit_local_for_anyaddress| is true. This is to allow connectivity for// applications which absolutely requires a HOST candidate.
rtc::SocketAddress addr = address;// If MaybeSetDefaultLocalAddress fails, we keep the "any" IP so that at// least the port is listening.MaybeSetDefaultLocalAddress(&addr);AddAddress(addr, addr, rtc::SocketAddress(), UDP_PROTOCOL_NAME,"","",
LOCAL_PORT_TYPE, ICE_TYPE_PREFERENCE_HOST,0,"",false);MaybePrepareStunCandidate();}