webrtc-m79-peerconnection_client-收集 relay candidate_02

// 在前面收集 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, &timestamp); /
  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 响应的流程

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值