// 在前面收集 host candidate 后,会自动触发下一个 phase 收集 relay candidate ,因此会再次走到这里,不过这次是 PHASE_RELAY /
void AllocationSequence::OnMessage(rtc::Message* msg) {
RTC_DCHECK(rtc::Thread::Current() == session_->network_thread());
RTC_DCHECK(msg->message_id == MSG_ALLOCATION_PHASE);
const char* const PHASE_NAMES[kNumPhases] = {"Udp", "Relay", "Tcp"};
// Perform all of the phases in the current step.
RTC_LOG(LS_INFO) << network_->ToString()
<< ": Allocation Phase=" << PHASE_NAMES[phase_];
switch (phase_) {
case PHASE_UDP:
CreateUDPPorts(); //
CreateStunPorts(); ///
break;
case PHASE_RELAY:
CreateRelayPorts();///
break;
case PHASE_TCP:
CreateTCPPorts();
state_ = kCompleted;
break;
default:
RTC_NOTREACHED();
}
if (state() == kRunning) { 在 AllocationSequence::Start 中初始化 state_ 为 kRunning
++phase_; /// 递增之后就可以进入 PHASE_RELAY (值为 1)
session_->network_thread()->PostDelayed(RTC_FROM_HERE, 在一定的延时以后,继续执行下一个 phase 的 candidate 的收集
session_->allocator()->step_delay(), / PortAllocator::step_delay_ 在 PeerConnection::InitializePortAllocator_n 中初始化
this, MSG_ALLOCATION_PHASE); / port_allocator_->set_step_delay(cricket::kMinimumStepDelay); cricket::kMinimumStepDelay 为 50
} else {
// If all phases in AllocationSequence are completed, no allocation
// steps needed further. Canceling pending signal.
session_->network_thread()->Clear(this, MSG_ALLOCATION_PHASE);
SignalPortAllocationComplete(this);
}
}
void AllocationSequence::CreateRelayPorts() {
if (IsFlagSet(PORTALLOCATOR_DISABLE_RELAY)) {
RTC_LOG(LS_VERBOSE)
<< "AllocationSequence: Relay ports disabled, skipping.";
return;
}
// If BasicPortAllocatorSession::OnAllocate left relay ports enabled then we
// ought to have a relay list for them here.
RTC_DCHECK(config_);
RTC_DCHECK(!config_->relays.empty());
if (!(config_ && !config_->relays.empty())) {
RTC_LOG(LS_WARNING)
<< "AllocationSequence: No relay server configured, skipping.";
return;
}
for (RelayServerConfig& relay : config_->relays) {
CreateTurnPort(relay);
}
}
void AllocationSequence::CreateTurnPort(const RelayServerConfig& config) {
PortList::const_iterator relay_port;
for (relay_port = config.ports.begin(); relay_port != config.ports.end();
++relay_port) {
// Skip UDP connections to relay servers if it's disallowed.
if (IsFlagSet(PORTALLOCATOR_DISABLE_UDP_RELAY) &&
relay_port->proto == PROTO_UDP) {
continue;
}
// Do not create a port if the server address family is known and does
// not match the local IP address family.
int server_ip_family = relay_port->address.ipaddr().family();
int local_ip_family = network_->GetBestIP().family();
if (server_ip_family != AF_UNSPEC && server_ip_family != local_ip_family) {
RTC_LOG(LS_INFO)
<< "Server and local address families are not compatible. "
"Server address: "
<< relay_port->address.ipaddr().ToSensitiveString()
<< " Local address: " << network_->GetBestIP().ToSensitiveString();
continue;
}
CreateRelayPortArgs args;
args.network_thread = session_->network_thread();
args.socket_factory = session_->socket_factory();
args.network = network_;
args.username = session_->username();
args.password = session_->password();
args.server_address = &(*relay_port);
args.config = &config;
args.origin = session_->allocator()->origin();
args.turn_customizer = session_->allocator()->turn_customizer();
std::unique_ptr<cricket::Port> port;
// Shared socket mode must be enabled only for UDP based ports. Hence
// don't pass shared socket for ports which will create TCP sockets.
// TODO(mallinath) - Enable shared socket mode for TURN ports. Disabled
// due to webrtc bug https://code.google.com/p/webrtc/issues/detail?id=3537
if (IsFlagSet(PORTALLOCATOR_ENABLE_SHARED_SOCKET) && / 默认是 PORTALLOCATOR_ENABLE_SHARED_SOCKET 模式
relay_port->proto == PROTO_UDP && udp_socket_) { /// udp_socket_ 是 AsyncPacketSocket 指针,且该指针指向 AsyncUDPSocket
port = session_->allocator()->relay_port_factory()->Create( // session_->allocator() 就是 BasicPortAllocatorSession::allocator() ,返回 BasicPortAllocator
args, udp_socket_.get()); BasicPortAllocator::relay_port_factory() 可以返回 TurnPortFactory 或者其他定制的 factory
/ 这里返回的 port 实际上是 TurnPort
if (!port) {
RTC_LOG(LS_WARNING) << "Failed to create relay port with "
<< args.server_address->address.ToSensitiveString();
continue;
}
relay_ports_.push_back(port.get()); /// 将上面创建的 TurnPort 保存下来 /// 后面 AllocationSequence::OnReadPacket 会使用
// Listen to the port destroyed signal, to allow AllocationSequence to
// remove entrt from it's map.
port->SignalDestroyed.connect(this, &AllocationSequence::OnPortDestroyed);
} else {
port = session_->allocator()->relay_port_factory()->Create(
args, session_->allocator()->min_port(),
session_->allocator()->max_port());
if (!port) {
RTC_LOG(LS_WARNING) << "Failed to create relay port with "
<< args.server_address->address.ToSensitiveString();
continue;
}
}
RTC_DCHECK(port != NULL);
session_->AddAllocatedPort(port.release(), this, true); // BasicPortAllocatorSession::AddAllocatedPort
}
}
void BasicPortAllocator::InitRelayPortFactory(
RelayPortFactoryInterface* relay_port_factory) {
if (relay_port_factory != nullptr) {
relay_port_factory_ = relay_port_factory;
} else { /// class TurnPortFactory : public RelayPortFactoryInterface
default_relay_port_factory_.reset(new TurnPortFactory()); ///
relay_port_factory_ = default_relay_port_factory_.get();
}
}
RelayPortFactoryInterface* BasicPortAllocator::relay_port_factory() {
CheckRunOnValidThreadIfInitialized();
return relay_port_factory_; /// 返回的可以是上面创建的默认的 TurnPortFactory 也可以是自定义的
}
std::unique_ptr<Port> TurnPortFactory::Create(
const CreateRelayPortArgs& args,
rtc::AsyncPacketSocket* udp_socket) { udp_socket 实际上是指向 AsyncUDPSocket
auto port = TurnPort::CreateUnique(
args.network_thread, args.socket_factory, args.network, udp_socket,
args.username, args.password, *args.server_address,
args.config->credentials, args.config->priority, args.origin,
args.turn_customizer); / 返回的是 TurnPort
port->SetTlsCertPolicy(args.config->tls_cert_policy);
port->SetTurnLoggingId(args.config->turn_logging_id);
return std::move(port);
}
static std::unique_ptr<TurnPort> TurnPort::CreateUnique(
rtc::Thread* thread,
rtc::PacketSocketFactory* factory,
rtc::Network* network,
rtc::AsyncPacketSocket* socket, udp_socket 实际上是指向 AsyncUDPSocket
const std::string& username, // ice username.
const std::string& password, // ice password.
const ProtocolAddress& server_address,
const RelayCredentials& credentials,
int server_priority,
const std::string& origin,
webrtc::TurnCustomizer* customizer) {
return Create(thread, factory, network, socket, username, password,
server_address, credentials, server_priority, origin,
customizer);
}
// Create a TURN port using the shared UDP socket, |socket|.
static std::unique_ptr<TurnPort> TurnPort::Create(
rtc::Thread* thread,
rtc::PacketSocketFactory* factory,
rtc::Network* network,
rtc::AsyncPacketSocket* socket, udp_socket 实际上是指向 AsyncUDPSocket
const std::string& username, // ice username.
const std::string& password, // ice password.
const ProtocolAddress& server_address,
const RelayCredentials& credentials,
int server_priority,
const std::string& origin,
webrtc::TurnCustomizer* customizer) {
// Using `new` to access a non-public constructor.
return absl::WrapUnique(new TurnPort(
thread, factory, network, socket, username, password, server_address,
credentials, server_priority, origin, customizer));
}
TurnPort::TurnPort(rtc::Thread* thread,
rtc::PacketSocketFactory* factory,
rtc::Network* network,
rtc::AsyncPacketSocket* socket, udp_socket 实际上是指向 AsyncUDPSocket
const std::string& username,
const std::string& password,
const ProtocolAddress& server_address,
const RelayCredentials& credentials,
int server_priority,
const std::string& origin,
webrtc::TurnCustomizer* customizer)
: Port(thread, RELAY_PORT_TYPE, factory, network, username, password),
server_address_(server_address),
tls_cert_verifier_(nullptr),
credentials_(credentials),
socket_(socket),
resolver_(NULL),
error_(0),
stun_dscp_value_(rtc::DSCP_NO_CHANGE),
request_manager_(thread),
next_channel_number_(TURN_CHANNEL_NUMBER_START),
state_(STATE_CONNECTING),
server_priority_(server_priority),
allocate_mismatch_retries_(0),
turn_customizer_(customizer) {
request_manager_.SignalSendPacket.connect(this, &TurnPort::OnSendStunPacket); / 这个信号值得注意
request_manager_.set_origin(origin);
}
void BasicPortAllocatorSession::AddAllocatedPort(Port* port, 实际上是 TurnPort class TurnPort : public Port
AllocationSequence* seq,
bool prepare_address) {
RTC_DCHECK_RUN_ON(network_thread_);
if (!port)
return;
RTC_LOG(LS_INFO) << "Adding allocated port for " << content_name();
port->set_content_name(content_name());
port->set_component(component());
port->set_generation(generation());
if (allocator_->proxy().type != rtc::PROXY_NONE)
port->set_proxy(allocator_->user_agent(), allocator_->proxy());
port->set_send_retransmit_count_attribute(
(flags() & PORTALLOCATOR_ENABLE_STUN_RETRANSMIT_ATTRIBUTE) != 0);
PortData data(port, seq); // 此时的 port 指向的是 TurnPort
ports_.push_back(data);
port->SignalCandidateReady.connect(
this, &BasicPortAllocatorSession::OnCandidateReady);
port->SignalCandidateError.connect(
this, &BasicPortAllocatorSession::OnCandidateError);
port->SignalPortComplete.connect(this,
&BasicPortAllocatorSession::OnPortComplete);
port->SignalDestroyed.connect(this,
&BasicPortAllocatorSession::OnPortDestroyed);
port->SignalPortError.connect(this, &BasicPortAllocatorSession::OnPortError);
RTC_LOG(LS_INFO) << port->ToString() << ": Added port to allocator";
if (prepare_address)
port->PrepareAddress(); /// TurnPort::PrepareAddress
}
发送 TurnAllocateRequest 请求
void TurnPort::PrepareAddress() {
if (credentials_.username.empty() || credentials_.password.empty()) {
RTC_LOG(LS_ERROR) << "Allocation can't be started without setting the"
" TURN server credentials for the user.";
OnAllocateError(STUN_ERROR_UNAUTHORIZED,
"Missing TURN server credentials.");
return;
}
if (!server_address_.address.port()) {
// We will set default TURN port, if no port is set in the address.
server_address_.address.SetPort(TURN_DEFAULT_PORT);
}
if (server_address_.address.IsUnresolvedIP()) {
ResolveTurnAddress(server_address_.address);
} else {
// If protocol family of server address doesn't match with local, return.
if (!IsCompatibleAddress(server_address_.address)) {
RTC_LOG(LS_ERROR) << "IP address family does not match. server: "
<< server_address_.address.family()
<< " local: " << Network()->GetBestIP().family();
OnAllocateError(STUN_ERROR_GLOBAL_FAILURE,
"IP address family does not match.");
return;
}
// Insert the current address to prevent redirection pingpong.
attempted_server_addresses_.insert(server_address_.address);
RTC_LOG(LS_INFO) << ToString() << ": Trying to connect to TURN server via "
<< ProtoToString(server_address_.proto) << " @ "
<< server_address_.address.ToSensitiveString();
if (!CreateTurnClientSocket()) {
RTC_LOG(LS_ERROR) << "Failed to create TURN client socket";
OnAllocateError(SERVER_NOT_REACHABLE_ERROR,
"Failed to create TURN client socket.");
return;
}
if (server_address_.proto == PROTO_UDP) {
// If its UDP, send AllocateRequest now.
// For TCP and TLS AllcateRequest will be sent by OnSocketConnect.
SendRequest(new TurnAllocateRequest(this), 0); class TurnAllocateRequest : public StunRequest
}
}
}
bool TurnPort::CreateTurnClientSocket() {
RTC_DCHECK(!socket_ || SharedSocket());
if (server_address_.proto == PROTO_UDP && !SharedSocket()) {
socket_ = socket_factory()->CreateUdpSocket(
rtc::SocketAddress(Network()->GetBestIP(), 0), min_port(), max_port());
} else if (server_address_.proto == PROTO_TCP ||
server_address_.proto == PROTO_TLS) {
RTC_DCHECK(!SharedSocket());
int opts = rtc::PacketSocketFactory::OPT_STUN;
// Apply server address TLS and insecure bits to options.
if (server_address_.proto == PROTO_TLS) {
if (tls_cert_policy_ ==
TlsCertPolicy::TLS_CERT_POLICY_INSECURE_NO_CHECK) {
opts |= rtc::PacketSocketFactory::OPT_TLS_INSECURE;
} else {
opts |= rtc::PacketSocketFactory::OPT_TLS;
}
}
rtc::PacketSocketTcpOptions tcp_options;
tcp_options.opts = opts;
tcp_options.tls_alpn_protocols = tls_alpn_protocols_;
tcp_options.tls_elliptic_curves = tls_elliptic_curves_;
tcp_options.tls_cert_verifier = tls_cert_verifier_;
socket_ = socket_factory()->CreateClientTcpSocket(
rtc::SocketAddress(Network()->GetBestIP(), 0), server_address_.address,
proxy(), user_agent(), tcp_options);
}
if (!socket_) {
error_ = SOCKET_ERROR;
return false;
}
// Apply options if any.
for (SocketOptionsMap::iterator iter = socket_options_.begin();
iter != socket_options_.end(); ++iter) {
socket_->SetOption(iter->first, iter->second);
}
if (!SharedSocket()) {
// If socket is shared, AllocationSequence will receive the packet.
socket_->SignalReadPacket.connect(this, &TurnPort::OnReadPacket);
}
socket_->SignalReadyToSend.connect(this, &TurnPort::OnReadyToSend);
socket_ 是指向 AsyncUDPSocket 的 rtc::AsyncPacketSocket 的指针
socket_->SignalSentPacket.connect(this, &TurnPort::OnSentPacket); /
// TCP port is ready to send stun requests after the socket is connected,
// while UDP port is ready to do so once the socket is created.
if (server_address_.proto == PROTO_TCP ||
server_address_.proto == PROTO_TLS) {
socket_->SignalConnect.connect(this, &TurnPort::OnSocketConnect);
socket_->SignalClose.connect(this, &TurnPort::OnSocketClose);
} else {
state_ = STATE_CONNECTED;
}
return true;
}
void TurnPort::SendRequest(StunRequest* req, int delay) { /// 这里的 request 是 TurnAllocateRequest
request_manager_.SendDelayed(req, delay);
}
void StunRequestManager::SendDelayed(StunRequest* request, int delay) { 这里的 request 是 TurnAllocateRequest
request->set_manager(this);
RTC_DCHECK(requests_.find(request->id()) == requests_.end());
request->set_origin(origin_);
request->Construct();
requests_[request->id()] = request; 保存原始的消息,这里的 request 是 TurnAllocateRequest
if (delay > 0) {
thread_->PostDelayed(RTC_FROM_HERE, delay, request, MSG_STUN_SEND, NULL);
} else {
thread_->Send(RTC_FROM_HERE, request, MSG_STUN_SEND, NULL); //
}
}
void StunRequest::OnMessage(rtc::Message* pmsg) {
RTC_DCHECK(manager_ != NULL);
RTC_DCHECK(pmsg->message_id == MSG_STUN_SEND);
if (timeout_) {
OnTimeout();
delete this;
return;
}
tstamp_ = rtc::TimeMillis();
rtc::ByteBufferWriter buf;
msg_->Write(&buf);
manager_->SignalSendPacket(buf.Data(), buf.Length(), this);/// StunRequestManager->SignalSendPacket , 具体见 TurnPort::TurnPort
request_manager_.SignalSendPacket.connect(this, &TurnPort::OnSendStunPacket);
OnSent();
manager_->thread_->PostDelayed(RTC_FROM_HERE, resend_delay(), this,
MSG_STUN_SEND, NULL);
}
void TurnPort::OnSendStunPacket(const void* data,
size_t size,
StunRequest* request) {
RTC_DCHECK(connected());
rtc::PacketOptions options(StunDscpValue());
options.info_signaled_after_sent.packet_type = rtc::PacketType::kTurnMessage;
CopyPortInformationToPacketInfo(&options.info_signaled_after_sent);
if (Send(data, size, options) < 0) { //
RTC_LOG(LS_ERROR) << ToString() << ": Failed to send TURN message, error: "
<< socket_->GetError();
}
}
int TurnPort::Send(const void* data,
size_t len,
const rtc::PacketOptions& options) { socket_ 指向 AsyncUDPSocket
return socket_->SendTo(data, len, server_address_.address, options); /// AsyncUDPSocket::SendTo
}
int AsyncUDPSocket::SendTo(const void* pv,
size_t cb,
const SocketAddress& addr,
const rtc::PacketOptions& options) {
rtc::SentPacket sent_packet(options.packet_id, rtc::TimeMillis(),
options.info_signaled_after_sent);
CopySocketInformationToPacketInfo(cb, *this, true, &sent_packet.info); class SocketDispatcher : public Dispatcher, public PhysicalSocket
int ret = socket_->SendTo(pv, cb, addr); / socket_ 实际上就是 SocketDispatcher 的指针,具体见 BasicPacketSocketFactory::CreateUdpSocket
SignalSentPacket(this, sent_packet); / SocketDispatcher::SendTo 就是 PhysicalSocket::SendTo
return ret; / SignalSentPacket 来自 AsyncPacketSocket , 因为 class AsyncUDPSocket : public AsyncPacketSocket
} / 这里 SignalSentPacket 就会触发 TurnPort::OnSentPacket , 具体见 TurnPort::CreateTurnClientSocket
void TurnPort::OnSentPacket(rtc::AsyncPacketSocket* socket,
const rtc::SentPacket& sent_packet) {
PortInterface::SignalSentPacket(sent_packet); /// 这个地方下面有类似的分析, 具体见 UDPPort::OnSentPacket
}
接收 TurnAllocateRequest 响应 (第一次)
事件循环参考前面描述,这里直接借用前面分析的结果
void SocketDispatcher::OnEvent(uint32_t ff, int err) {
#if defined(WEBRTC_USE_EPOLL)
// Remember currently enabled events so we can combine multiple changes
// into one update call later.
// The signal handlers might re-enable events disabled here, so we can't
// keep a list of events to disable at the end of the method. This list
// would not be updated with the events enabled by the signal handlers.
StartBatchedEventUpdates();
#endif
// Make sure we deliver connect/accept first. Otherwise, consumers may see
// something like a READ followed by a CONNECT, which would be odd.
if ((ff & DE_CONNECT) != 0) {
DisableEvents(DE_CONNECT);
SignalConnectEvent(this);
}
if ((ff & DE_ACCEPT) != 0) {
DisableEvents(DE_ACCEPT);
SignalReadEvent(this);
}
if ((ff & DE_READ) != 0) {
DisableEvents(DE_READ);
SignalReadEvent(this);// 在 BasicPacketSocketFactory::CreateUdpSocket 中将 SocketDispatcher 的指针传递到了 AsyncUDPSocket ,
}// 并在 AsyncUDPSocket 的构造函数中设置了 SocketDispatcher 的 SignalReadEvent 和 SignalWriteEvent ,分别将其绑定到了 AsyncUDPSocket::OnReadEvent AsyncUDPSocket::OnWriteEvent
if ((ff & DE_WRITE) != 0) {
DisableEvents(DE_WRITE);
SignalWriteEvent(this);
}
if ((ff & DE_CLOSE) != 0) {
// The socket is now dead to us, so stop checking it.
SetEnabledEvents(0);
SignalCloseEvent(this, err);
}
#if defined(WEBRTC_USE_EPOLL)
FinishBatchedEventUpdates();
#endif
}
void AsyncUDPSocket::OnReadEvent(AsyncSocket* socket) {
RTC_DCHECK(socket_.get() == socket);
SocketAddress remote_addr;
int64_t timestamp;
int len = socket_->RecvFrom(buf_, size_, &remote_addr, ×tamp); /
if (len < 0) {
// An error here typically means we got an ICMP error in response to our
// send datagram, indicating the remote address was unreachable.
// When doing ICE, this kind of thing will often happen.
// TODO: Do something better like forwarding the error to the user.
SocketAddress local_addr = socket_->GetLocalAddress();
RTC_LOG(LS_INFO) << "AsyncUDPSocket[" << local_addr.ToSensitiveString()
<< "] receive failed with error " << socket_->GetError();
return;
}
// TODO: Make sure that we got all of the packet.
// If we did not, then we should resize our buffer to be large enough.
SignalReadPacket(this, buf_, static_cast<size_t>(len), remote_addr,
(timestamp > -1 ? timestamp : TimeMicros())); AsyncUDPSocket 的 SignalReadPacket 事件来自其父类 AsyncPacketSocket
} // AsyncPacketSocket 的 SignalReadPacket 事件是在 AllocationSequence::Init 中设置,将其绑定到了 AllocationSequence::OnReadPacket
void AllocationSequence::OnReadPacket(rtc::AsyncPacketSocket* socket,
const char* data,
size_t size,
const rtc::SocketAddress& remote_addr,
const int64_t& packet_time_us) {
RTC_DCHECK(socket == udp_socket_.get()); udp_socket_ 是 AsyncPacketSocket 指针,且该指针指向 AsyncUDPSocket
bool turn_port_found = false;
// Try to find the TurnPort that matches the remote address. Note that the
// message could be a STUN binding response if the TURN server is also used as
// a STUN server. We don't want to parse every message here to check if it is
// a STUN binding response, so we pass the message to TurnPort regardless of
// the message type. The TurnPort will just ignore the message since it will
// not find any request by transaction ID.
for (auto* port : relay_ports_) { / relay_ports_ 在前面 AllocationSequence::CreateTurnPort 设置用来保存 TurnPort
if (port->CanHandleIncomingPacketsFrom(remote_addr)) { /// TurnPort::CanHandleIncomingPacketsFrom
if (port->HandleIncomingPacket(socket, data, size, remote_addr, / TurnPort::HandleIncomingPacket
packet_time_us)) {
return;
}
turn_port_found = true;
}
}
if (udp_port_) { udp_port_ 是 UDPPort 指针(UDPPort内部包含 rtc::AsyncPacketSocket 指针,实际上指向 AsyncUDPSocket)
const ServerAddresses& stun_servers = udp_port_->server_addresses();
// Pass the packet to the UdpPort if there is no matching TurnPort, or if
// the TURN server is also a STUN server.
if (!turn_port_found ||
stun_servers.find(remote_addr) != stun_servers.end()) {
RTC_DCHECK(udp_port_->SharedSocket());
udp_port_->HandleIncomingPacket(socket, data, size, remote_addr,
packet_time_us); // UDPPort::HandleIncomingPacket
}
}
}
bool TurnPort::CanHandleIncomingPacketsFrom(
const rtc::SocketAddress& addr) const {
return server_address_.address == addr;
}
bool TurnPort::HandleIncomingPacket(rtc::AsyncPacketSocket* socket,
const char* data,
size_t size,
const rtc::SocketAddress& remote_addr,
int64_t packet_time_us) {
if (socket != socket_) {
// The packet was received on a shared socket after we've allocated a new
// socket for this TURN port.
return false;
}
// This is to guard against a STUN response from previous server after
// alternative server redirection. TODO(guoweis): add a unit test for this
// race condition.
if (remote_addr != server_address_.address) {
RTC_LOG(LS_WARNING) << ToString()
<< ": Discarding TURN message from unknown address: "
<< remote_addr.ToSensitiveString()
<< " server_address_: "
<< server_address_.address.ToSensitiveString();
return false;
}
// The message must be at least the size of a channel header.
if (size < TURN_CHANNEL_HEADER_SIZE) {
RTC_LOG(LS_WARNING) << ToString()
<< ": Received TURN message that was too short";
return false;
}
if (state_ == STATE_DISCONNECTED) {
RTC_LOG(LS_WARNING)
<< ToString()
<< ": Received TURN message while the TURN port is disconnected";
return false;
}
// Check the message type, to see if is a Channel Data message.
// The message will either be channel data, a TURN data indication, or
// a response to a previous request.
uint16_t msg_type = rtc::GetBE16(data);
if (IsTurnChannelData(msg_type)) {
HandleChannelData(msg_type, data, size, packet_time_us);
return true;
}
if (msg_type == TURN_DATA_INDICATION) {
HandleDataIndication(data, size, packet_time_us);
return true;
}
if (SharedSocket() && (msg_type == STUN_BINDING_RESPONSE ||
msg_type == STUN_BINDING_ERROR_RESPONSE)) {
RTC_LOG(LS_VERBOSE)
<< ToString()
<< ": Ignoring STUN binding response message on shared socket.";
return false;
}
// This must be a response for one of our requests.
// Check success responses, but not errors, for MESSAGE-INTEGRITY.
if (IsStunSuccessResponseType(msg_type) &&
!StunMessage::ValidateMessageIntegrity(data, size, hash())) {
RTC_LOG(LS_WARNING) << ToString()
<< ": Received TURN message with invalid "
"message integrity, msg_type: "
<< msg_type;
return true;
}
request_manager_.CheckResponse(data, size); /
return true;
}
bool StunRequestManager::CheckResponse(const char* data, size_t size) {
// Check the appropriate bytes of the stream to see if they match the
// transaction ID of a response we are expecting.
if (size < 20)
return false;
std::string id;
id.append(data + kStunTransactionIdOffset, kStunTransactionIdLength);
RequestMap::iterator iter = requests_.find(id); //
if (iter == requests_.end()) {
// TODO(pthatcher): Log unknown responses without being too spammy
// in the logs.
return false;
}
// Parse the STUN message and continue processing as usual.
rtc::ByteBufferReader buf(data, size);
std::unique_ptr<StunMessage> response(iter->second->msg_->CreateNew());
if (!response->Read(&buf)) {
RTC_LOG(LS_WARNING) << "Failed to read STUN response "
<< rtc::hex_encode(id);
return false;
}
return CheckResponse(response.get()); //
}
bool StunRequestManager::CheckResponse(StunMessage* msg) {
RequestMap::iterator iter = requests_.find(msg->transaction_id());
if (iter == requests_.end()) {
// TODO(pthatcher): Log unknown responses without being too spammy
// in the logs.
return false;
}
StunRequest* request = iter->second;
if (!msg->GetNonComprehendedAttributes().empty()) {
// If a response contains unknown comprehension-required attributes, it's
// simply discarded and the transaction is considered failed. See RFC5389
// sections 7.3.3 and 7.3.4.
RTC_LOG(LS_ERROR) << ": Discarding response due to unknown "
"comprehension-required attribute.";
delete request;
return false;
} else if (msg->type() == GetStunSuccessResponseType(request->type())) {
request->OnResponse(msg); / TurnAllocateRequest::OnResponse ///
} else if (msg->type() == GetStunErrorResponseType(request->type())) {
request->OnErrorResponse(msg); // 401 未授权 TurnAllocateRequest::OnErrorResponse
} else {
RTC_LOG(LERROR) << "Received response with wrong type: " << msg->type()
<< " (expecting "
<< GetStunSuccessResponseType(request->type()) << ")";
return false;
}
delete request;
return true;
}
void TurnAllocateRequest::OnErrorResponse(StunMessage* response) {
// Process error response according to RFC5766, Section 6.4.
int error_code = response->GetErrorCodeValue();
RTC_LOG(LS_INFO) << port_->ToString()
<< ": Received TURN allocate error response, id="
<< rtc::hex_encode(id()) << ", code=" << error_code
<< ", rtt=" << Elapsed();
switch (error_code) {
case STUN_ERROR_UNAUTHORIZED: // Unauthrorized.
OnAuthChallenge(response, error_code); // TurnAllocateRequest::OnAuthChallenge
break;
case STUN_ERROR_TRY_ALTERNATE:
OnTryAlternate(response, error_code);
break;
case STUN_ERROR_ALLOCATION_MISMATCH:
// We must handle this error async because trying to delete the socket in
// OnErrorResponse will cause a deadlock on the socket.
port_->thread()->Post(RTC_FROM_HERE, port_,
TurnPort::MSG_ALLOCATE_MISMATCH);
break;
default:
RTC_LOG(LS_WARNING) << port_->ToString()
<< ": Received TURN allocate error response, id="
<< rtc::hex_encode(id()) << ", code=" << error_code
<< ", rtt=" << Elapsed();
const StunErrorCodeAttribute* attr = response->GetErrorCode();
port_->OnAllocateError(error_code, attr ? attr->reason() : "");
}
}
void TurnAllocateRequest::OnAuthChallenge(StunMessage* response, int code) {
// If we failed to authenticate even after we sent our credentials, fail hard.
if (code == STUN_ERROR_UNAUTHORIZED && !port_->hash().empty()) {
RTC_LOG(LS_WARNING) << port_->ToString()
<< ": Failed to authenticate with the server "
"after challenge.";
const StunErrorCodeAttribute* attr = response->GetErrorCode();
port_->OnAllocateError(STUN_ERROR_UNAUTHORIZED, attr ? attr->reason() : "");
return;
}
// Check the mandatory attributes.
const StunByteStringAttribute* realm_attr =
response->GetByteString(STUN_ATTR_REALM);
if (!realm_attr) {
RTC_LOG(LS_WARNING) << port_->ToString()
<< ": Missing STUN_ATTR_REALM attribute in "
"allocate unauthorized response.";
return;
}
port_->set_realm(realm_attr->GetString()); / TurnPort::set_realm
const StunByteStringAttribute* nonce_attr =
response->GetByteString(STUN_ATTR_NONCE);
if (!nonce_attr) {
RTC_LOG(LS_WARNING) << port_->ToString()
<< ": Missing STUN_ATTR_NONCE attribute in "
"allocate unauthorized response.";
return;
}
port_->set_nonce(nonce_attr->GetString()); / TurnPort::set_nonce
// Send another allocate request, with the received realm and nonce values.
port_->SendRequest(new TurnAllocateRequest(port_), 0); 重新发送一个带有 realm nonce 参数的 TurnAllocateRequest
} 这个发送的流程和之前 TurnPort::PrepareAddress 中触发的发送流程一样,发送细节就不赘述了,下面就直接描述接收第二个 TurnAllocateRequest 响应的流程