webrtc ice (rfc5245) 实现


webrtc的ICE符合rfc5245标准协议。该协议的链接为:https://tools.ietf.org/html/rfc5245

每个终端都有一系列传输地址(包括传输协议、IP地址和端口)的候选,可以用来和其他端点进行通信。其中可能包括:
1、直接和网络接口联系的传输地址(host address)
2、经过NAT转换的传输地址,即反射地址(server reflective address)
3、TURN服务器分配的中继地址(relay address)

虽然潜在要求任意一个主叫Client的候选地址都能用来和被叫Client的候选地址进行通信。但是实际中发现有许多组合是无法工作的。举例来说,如果主叫Client和被叫Client都在NAT之后而且不处于同一内网,他们的直接地址就无法进行通信。ICE的目的就是为了发现哪一对候选地址的组合可以工作,并且通过系统的方法对所有组合进行测试(用一种精心挑选的顺序)。

在rfc5245定义里面,实现ICE一共有六个步骤:收集候选地址、连通性测试、候选排序、冻结候选、检查的安全性、ICE结束。webrtc结合实际应用,优化这六步为如下五步:收集候选地址、在信令通道中交换候选选项、执行连接检查、选定并启动媒体。

1、实现收集候选地址核心函数:BasicPortAllocatorSession::DoAllocate

2、在信令通道中交换候选选项:发送本端的候选选项核心函数:AllocationSequence::EnableProtocol

                                                 接收远端的候选选项核心函数:PeerConnection::AddIceCandidate

3、执行连接检查核心函数: P2PTransportChannel::SortConnectionsAndUpdateState

4、选定并启动媒体核心函数:P2PTransportChannel::OnReadyToSend

                                             过程中检测有变化时:P2PTransportChannel::SwitchSelectedConnection

一、收集候选地址

1、获取turn、stun服务器信息处理流程

Conductor::InitializePeerConnection

->Conductor::CreatePeerConnection
->PeerConnectionFactory::CreatePeerConnection
->PeerConnection::Initialize
->PeerConnection::InitializePortAllocator_n//这个函数解析配置信息,确定探测类型及参数。

->PortAllocator::SetConfiguration//这里配置服务器信息。

2、生效turn、stun服务器处理流程

WebRtcSessionDescriptionFactory::OnMessage

->Conductor::OnSuccess
->PeerConnection::SetLocalDescription   (session_->MaybeStartGathering())
->WebRtcSession::MaybeStartGathering
->TransportController::MaybeStartGathering
->TransportController::MaybeStartGathering_n
->P2PTransportChannel::MaybeStartGathering
AddAllocatorSession(allocator_->CreateSession());//注册信号量
allocator_sessions_.back()->StartGettingPorts(); //启动Port资源申请消息

当P2PTransportChannel::MaybeStartGathering函数调用BasicPortAllocatorSession::StartGettingPorts后,就会启动MSG_CONFIG_START消息处理流程。开始收集本端的candidates信息。

3、Port资源申请状态机

enum {
  MSG_CONFIG_START,
  MSG_CONFIG_READY,
  MSG_ALLOCATE,
  MSG_ALLOCATION_PHASE,
  MSG_SEQUENCEOBJECTS_CREATED,
  MSG_CONFIG_STOP,
};

4、Port状态机接口函数

void BasicPortAllocatorSession::OnMessage(rtc::Message *message) {
  switch (message->message_id) {
  case MSG_CONFIG_START:
    GetPortConfigurations();
    break;
  case MSG_CONFIG_READY:
    OnConfigReady(static_cast<PortConfiguration*>(message->pdata));
    break;
  case MSG_ALLOCATE:
    OnAllocate();
    break;
  case MSG_SEQUENCEOBJECTS_CREATED:
    OnAllocationSequenceObjectsCreated();
    break;
  case MSG_CONFIG_STOP:
    OnConfigStop();
    break;
  default:
    RTC_NOTREACHED();
  }
}

1、MSG_CONFIG_START:申请stun配置文件信息,在配置文件中增加turn信息。配置OK后 ,向消息队列发送ready消息。
2、MSG_CONFIG_READY:push在START里面创建的配置信息到configs_,向消息队列发送MSG_ALLOCATE消息。
3、MSG_ALLOCATE:在这里会创建Port资源,收集candidates信息。
AllocationSequence* sequence =new AllocationSequence();//申请AllocationSequence类
sequence->SignalPortAllocationComplete.connect();//注册信号量
sequence->Init();//启动给自己发送MSG_ALLOCATION_PHASE消息队列
sequence->Start();
sequences_.push_back(sequence);
4、MSG_ALLOCATION_PHASE:Port申请处理流程

void AllocationSequence::OnMessage(rtc::Message* msg) {
  RTC_DCHECK(msg->message_id == MSG_ALLOCATION_PHASE);
  // Perform all of the phases in the current step.
  switch (phase_) {
    case PHASE_UDP:
      CreateUDPPorts();//申请udp port资源
      CreateStunPorts();//申请 stun port资源
      EnableProtocol(PROTO_UDP);
      break;
    case PHASE_RELAY:
      CreateRelayPorts();//申请GTURN或TURN port资源
      break;
    case PHASE_TCP:
      CreateTCPPorts();//申请TCP Port资源
      EnableProtocol(PROTO_TCP);
      break;
    case PHASE_SSLTCP:
      state_ = kCompleted;//不需要继续探测,停止给自己发MSG_ALLOCATION_PHASE消息
      EnableProtocol(PROTO_SSLTCP);
      break;
  }
  if (state() == kRunning) {
    ++phase_;//更新探测阶段
    session_->network_thread()->PostDelayed(RTC_FROM_HERE,MSG_ALLOCATION_PHASE);//给自己发消息。
  } else {
    session_->network_thread()->Clear(this, MSG_ALLOCATION_PHASE);//清除给自己发消息资源
    SignalPortAllocationComplete(this);//发送信号量,知会需要探测的Port资源都已经申请完毕。
  }
}

5、发送candidates信息给对端:每次调用EnableProtocol函数,就是将本地的Candidates信息,发送给对端的Client
AllocationSequence::EnableProtocol
->BasicPortAllocatorSession::OnProtocolEnabled
->SignalCandidatesReady
->P2PTransportChannel::OnCandidatesReady
->SignalCandidateGathered
->TransportController::OnChannelCandidateGathered_n
->SignalCandidatesGathered
->WebRtcSession::OnTransportControllerCandidatesGathered
->Conductor::OnIceCandidate
->Conductor::SendMessage
->PeerConnectionClient::SendToPeer
Port资源申请结束后,通过信号量传递该信息:
SignalPortAllocationComplete信号量触发调用
BasicPortAllocatorSession::OnPortAllocationComplete

二、接收对端候选选项

当主叫Client获得了它全部的候选地址,把它们按优先级从高到低排序后通过信令通道(SDP offer)发送给被叫Client。被叫Client收到后做同样的事,然后通过响应发给主叫Client。最后,每个agent都拥有了自己和对方的候选地址。它们共同组成CANDIDATE PAIRS(候选地址对)。client通过CANDIDATE PAIRS发送给对端STUN request来检查它们。

1、处理HTTP的POST/message里面的SDP信令


Conductor::OnMessageFromPeer

->PeerConnection::SetRemoteDescription
->WebRtcSession::SetRemoteDescription
->WebRtcSession::UpdateSessionState
->WebRtcSession::PushdownTransportDescription
->WebRtcSession::PushdownRemoteTransportDescription
->TransportController::SetRemoteTransportDescription
->TransportController::SetRemoteTransportDescription_n
->JsepTransport::SetRemoteTransportDescription
->JsepTransport::ApplyRemoteTransportDescription
->P2PTransportChannel::SetRemoteIceParameters

->P2PTransportChannel::RequestSortAndStateUpdate

->P2PTransportChannel::SortConnectionsAndUpdateState

2、处理HTTP的POST/message里面的Candidate信令


Conductor::OnMessageFromPeer

->PeerConnection::AddIceCandidate
->WebRtcSession::ProcessIceMessage
->WebRtcSession::UseCandidate
->TransportController::AddRemoteCandidates
->TransportController::AddRemoteCandidates_n
->P2PTransportChannel::AddRemoteCandidate
->P2PTransportChannel::SortConnectionsAndUpdateState
->P2PTransportChannel::MaybeSwitchSelectedConnection
->P2PTransportChannel::SwitchSelectedConnection

    SignalReadyToSend  SignalSelectedCandidatePairChanged


三、执行连接检查

可以参考该状态机。当连接检查失败,会启动重新收集candidate信息。

// messages for queuing up work for ourselves
enum {
  MSG_SORT_AND_UPDATE_STATE = 1,
  MSG_CHECK_AND_PING,
  MSG_REGATHER_ON_FAILED_NETWORKS,
  MSG_REGATHER_ON_ALL_NETWORKS
};

四、选择选定的对并启动媒体

进行探测,收到对端的报文的时候,就会发送该信号量,选定传输方式。

AsyncUDPSocket::OnReadEvent发送信号量SignalReadPacket

->AllocationSequence::OnReadPacket

->UDPPort::HandleIncomingPacket
->UDPPort::OnReadPacket
->Connection::OnReadPacket
->StunRequestManager::CheckResponse
->ConnectionRequest::OnResponse
->Connection::OnConnectionRequestResponse
::Connection::ReceivedPingResponse[set_write_state(STATE_WRITABLE)]
::Connection::MaybeUpdateLocalCandidate[SignalStateChange]


UpdateNetworkCost->SignalStateChange:

在多网卡时,对wifi、4G、vpn等类型设置不同权重值。当检测出权重高的网络可以通的时候,进行切换。

set_connected->SignalStateChange   TCP链接成功后,会发送这个信号。
UpdateReceiving->SignalStateChange
HandleBindingRequest->SignalStateChange

五、心跳检测

(加密时传输密钥,暂时没有接触到)



猜你喜欢

转载自blog.csdn.net/crystalshaw/article/details/80804225
ice