Chromium Code Reviews| Index: webrtc/p2p/base/turnport.cc |
| diff --git a/webrtc/p2p/base/turnport.cc b/webrtc/p2p/base/turnport.cc |
| index 5e88365a83d615bdbc2e19ffe62694444ee20039..f4f40fcd0f7a55f1016f6eabd0b06f02ba0ae35b 100644 |
| --- a/webrtc/p2p/base/turnport.cc |
| +++ b/webrtc/p2p/base/turnport.cc |
| @@ -137,6 +137,9 @@ class TurnEntry : public sigslot::has_slots<> { |
| TurnPort* port() { return port_; } |
| int channel_id() const { return channel_id_; } |
| + // For testing only. |
| + void set_channel_id(int channel_id) { channel_id_ = channel_id; } |
| + |
| const rtc::SocketAddress& address() const { return ext_addr_; } |
| BindState state() const { return state_; } |
| @@ -155,8 +158,10 @@ class TurnEntry : public sigslot::has_slots<> { |
| void OnCreatePermissionSuccess(); |
| void OnCreatePermissionError(StunMessage* response, int code); |
| + void OnCreatePermissionTimeout(); |
| void OnChannelBindSuccess(); |
| void OnChannelBindError(StunMessage* response, int code); |
| + void OnChannelBindTimeout(); |
| // Signal sent when TurnEntry is destroyed. |
| sigslot::signal1<TurnEntry*> SignalDestroyed; |
| @@ -464,6 +469,13 @@ Connection* TurnPort::CreateConnection(const Candidate& address, |
| return NULL; |
| } |
| +void TurnPort::DestroyConnection(const rtc::SocketAddress& address) { |
|
pthatcher1
2015/12/08 20:04:20
Should it return a bool of whether or not it was d
honghaiz3
2015/12/10 17:58:30
Done
|
| + Connection* conn = GetConnection(address); |
| + if (conn != nullptr) { |
| + conn->Destroy(); |
| + } |
| +} |
| + |
| int TurnPort::SetOption(rtc::Socket::Option opt, int value) { |
| if (!socket_) { |
| // If socket is not created yet, these options will be applied during socket |
| @@ -696,34 +708,45 @@ void TurnPort::OnAllocateError() { |
| // We will send SignalPortError asynchronously as this can be sent during |
| // port initialization. This way it will not be blocking other port |
| // creation. |
| - thread()->Post(this, MSG_ERROR); |
| + thread()->Post(this, MSG_ALLOCATE_ERROR); |
| +} |
| + |
| +void TurnPort::OnTurnRefreshError() { |
| + // Stop the port from creating new connections. |
| + state_ = STATE_DISCONNECTED; |
| + // Delete all existing connections; stop sending data. |
| + for (auto kv : connections()) { |
| + kv.second->Destroy(); |
| + } |
|
pthatcher1
2015/12/08 20:04:20
Should we have a TunrPort::Close method that does
honghaiz3
2015/12/10 17:58:30
Done.
|
| } |
| void TurnPort::OnMessage(rtc::Message* message) { |
| - if (message->message_id == MSG_ERROR) { |
| - SignalPortError(this); |
| - return; |
| - } else if (message->message_id == MSG_ALLOCATE_MISMATCH) { |
| - OnAllocateMismatch(); |
| - return; |
| - } else if (message->message_id == MSG_TRY_ALTERNATE_SERVER) { |
| - if (server_address().proto == PROTO_UDP) { |
| - // Send another allocate request to alternate server, with the received |
| - // realm and nonce values. |
| - SendRequest(new TurnAllocateRequest(this), 0); |
| - } else { |
| - // Since it's TCP, we have to delete the connected socket and reconnect |
| - // with the alternate server. PrepareAddress will send stun binding once |
| - // the new socket is connected. |
| - ASSERT(server_address().proto == PROTO_TCP); |
| - ASSERT(!SharedSocket()); |
| - delete socket_; |
| - socket_ = NULL; |
| - PrepareAddress(); |
| - } |
| - return; |
| + switch (message->message_id) { |
| + case MSG_ALLOCATE_ERROR: |
| + SignalPortError(this); |
| + break; |
| + case MSG_ALLOCATE_MISMATCH: |
| + OnAllocateMismatch(); |
| + break; |
| + case MSG_TRY_ALTERNATE_SERVER: |
| + if (server_address().proto == PROTO_UDP) { |
| + // Send another allocate request to alternate server, with the received |
| + // realm and nonce values. |
| + SendRequest(new TurnAllocateRequest(this), 0); |
| + } else { |
| + // Since it's TCP, we have to delete the connected socket and reconnect |
| + // with the alternate server. PrepareAddress will send stun binding once |
| + // the new socket is connected. |
| + ASSERT(server_address().proto == PROTO_TCP); |
| + ASSERT(!SharedSocket()); |
| + delete socket_; |
| + socket_ = NULL; |
| + PrepareAddress(); |
| + } |
| + break; |
| + default: |
| + Port::OnMessage(message); |
| } |
| - Port::OnMessage(message); |
| } |
| void TurnPort::OnAllocateRequestTimeout() { |
| @@ -958,6 +981,16 @@ void TurnPort::CancelEntryDestruction(TurnEntry* entry) { |
| entry->set_destruction_timestamp(0); |
| } |
| +bool TurnPort::SetEntryChannelId(const rtc::SocketAddress& address, |
| + int channel_id) { |
| + TurnEntry* entry = FindEntry(address); |
|
pthatcher1
2015/12/08 20:04:19
Can we just make FindEntry callable by the unit te
honghaiz3
2015/12/10 17:58:30
If we do that, we will need to make TurnEntry acce
|
| + if (!entry) { |
| + return false; |
| + } |
| + entry->set_channel_id(channel_id); |
| + return true; |
| +} |
| + |
| TurnAllocateRequest::TurnAllocateRequest(TurnPort* port) |
| : StunRequest(new TurnMessage()), |
| port_(port) { |
| @@ -1171,16 +1204,13 @@ void TurnRefreshRequest::OnResponse(StunMessage* response) { |
| // Schedule a refresh based on the returned lifetime value. |
| port_->ScheduleRefresh(lifetime_attr->value()); |
| + // Result code 0 means the refresh request is successful. |
| + port_->SignalTurnRefreshResult(port_, 0); |
|
pthatcher1
2015/12/08 20:04:19
Can we make a name constant for it? kTurnRefreshS
honghaiz3
2015/12/10 17:58:30
used name RESULT_SUCCESS_CODE. also used this for
|
| } |
| void TurnRefreshRequest::OnErrorResponse(StunMessage* response) { |
| const StunErrorCodeAttribute* error_code = response->GetErrorCode(); |
| - LOG_J(LS_INFO, port_) << "Received TURN refresh error response" |
| - << ", id=" << rtc::hex_encode(id()) |
| - << ", code=" << error_code->code() |
| - << ", rtt=" << Elapsed(); |
| - |
| if (error_code->code() == STUN_ERROR_STALE_NONCE) { |
| if (port_->UpdateNonce(response)) { |
| // Send RefreshRequest immediately. |
| @@ -1191,11 +1221,14 @@ void TurnRefreshRequest::OnErrorResponse(StunMessage* response) { |
| << ", id=" << rtc::hex_encode(id()) |
| << ", code=" << error_code->code() |
| << ", rtt=" << Elapsed(); |
| + port_->OnTurnRefreshError(); |
| + port_->SignalTurnRefreshResult(port_, error_code->code()); |
| } |
| } |
| void TurnRefreshRequest::OnTimeout() { |
| LOG_J(LS_WARNING, port_) << "TURN refresh timeout " << rtc::hex_encode(id()); |
| + port_->OnTurnRefreshError(); |
| } |
| TurnCreatePermissionRequest::TurnCreatePermissionRequest( |
| @@ -1248,6 +1281,9 @@ void TurnCreatePermissionRequest::OnErrorResponse(StunMessage* response) { |
| void TurnCreatePermissionRequest::OnTimeout() { |
| LOG_J(LS_WARNING, port_) << "TURN create permission timeout " |
| << rtc::hex_encode(id()); |
| + if (entry_) { |
| + entry_->OnCreatePermissionTimeout(); |
| + } |
| } |
| void TurnCreatePermissionRequest::OnEntryDestroyed(TurnEntry* entry) { |
| @@ -1315,6 +1351,9 @@ void TurnChannelBindRequest::OnErrorResponse(StunMessage* response) { |
| void TurnChannelBindRequest::OnTimeout() { |
| LOG_J(LS_WARNING, port_) << "TURN channel bind timeout " |
| << rtc::hex_encode(id()); |
| + if (entry_) { |
| + entry_->OnChannelBindTimeout(); |
| + } |
| } |
| void TurnChannelBindRequest::OnEntryDestroyed(TurnEntry* entry) { |
| @@ -1396,11 +1435,16 @@ void TurnEntry::OnCreatePermissionError(StunMessage* response, int code) { |
| SendCreatePermissionRequest(0); |
| } |
| } else { |
| + port_->DestroyConnection(ext_addr_); |
| // Send signal with error code. |
| port_->SignalCreatePermissionResult(port_, ext_addr_, code); |
| } |
| } |
| +void TurnEntry::OnCreatePermissionTimeout() { |
| + port_->DestroyConnection(ext_addr_); |
| +} |
| + |
| void TurnEntry::OnChannelBindSuccess() { |
| LOG_J(LS_INFO, port_) << "Channel bind for " << ext_addr_.ToSensitiveString() |
| << " succeeded"; |
| @@ -1409,14 +1453,21 @@ void TurnEntry::OnChannelBindSuccess() { |
| } |
| void TurnEntry::OnChannelBindError(StunMessage* response, int code) { |
| - // TODO(mallinath) - Implement handling of error response for channel |
| - // bind request as per http://tools.ietf.org/html/rfc5766#section-11.3 |
| + // If the channel bind fails due to errors other than STATE_NONCE, |
| + // we just destroy the connection and rely on ICE restart to re-establish |
| + // the connection. |
| if (code == STUN_ERROR_STALE_NONCE) { |
| if (port_->UpdateNonce(response)) { |
| // Send channel bind request with fresh nonce. |
| SendChannelBindRequest(0); |
| } |
| + } else { |
| + state_ = STATE_UNBOUND; |
| + port_->DestroyConnection(ext_addr_); |
| } |
| } |
| - |
| +void TurnEntry::OnChannelBindTimeout() { |
| + state_ = STATE_UNBOUND; |
| + port_->DestroyConnection(ext_addr_); |
| +} |
| } // namespace cricket |