| Index: webrtc/p2p/base/turnport.cc
|
| diff --git a/webrtc/p2p/base/turnport.cc b/webrtc/p2p/base/turnport.cc
|
| index 4279b0fa5d0d4a36c97541af0089481da618d249..55b3b9479c26cee120055e85ff333219548b2d79 100644
|
| --- a/webrtc/p2p/base/turnport.cc
|
| +++ b/webrtc/p2p/base/turnport.cc
|
| @@ -38,6 +38,8 @@ static const size_t TURN_CHANNEL_HEADER_SIZE = 4U;
|
| // STUN_ERROR_ALLOCATION_MISMATCH error per rfc5766.
|
| static const size_t MAX_ALLOCATE_MISMATCH_RETRIES = 2;
|
|
|
| +static const int TURN_SUCCESS_RESULT_CODE = 0;
|
| +
|
| inline bool IsTurnChannelData(uint16_t msg_type) {
|
| return ((msg_type & 0xC000) == 0x4000); // MSB are 0b01
|
| }
|
| @@ -137,6 +139,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 +160,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 +471,15 @@ Connection* TurnPort::CreateConnection(const Candidate& address,
|
| return NULL;
|
| }
|
|
|
| +bool TurnPort::DestroyConnection(const rtc::SocketAddress& address) {
|
| + Connection* conn = GetConnection(address);
|
| + if (conn != nullptr) {
|
| + conn->Destroy();
|
| + return true;
|
| + }
|
| + return false;
|
| +}
|
| +
|
| int TurnPort::SetOption(rtc::Socket::Option opt, int value) {
|
| if (!socket_) {
|
| // If socket is not created yet, these options will be applied during socket
|
| @@ -698,34 +714,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::Close() {
|
| + // Stop the port from creating new connections.
|
| + state_ = STATE_DISCONNECTED;
|
| + // Delete all existing connections; stop sending data.
|
| + for (auto kv : connections()) {
|
| + kv.second->Destroy();
|
| + }
|
| }
|
|
|
| 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() {
|
| @@ -968,6 +995,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);
|
| + if (!entry) {
|
| + return false;
|
| + }
|
| + entry->set_channel_id(channel_id);
|
| + return true;
|
| +}
|
| +
|
| TurnAllocateRequest::TurnAllocateRequest(TurnPort* port)
|
| : StunRequest(new TurnMessage()),
|
| port_(port) {
|
| @@ -1181,16 +1218,12 @@ void TurnRefreshRequest::OnResponse(StunMessage* response) {
|
|
|
| // Schedule a refresh based on the returned lifetime value.
|
| port_->ScheduleRefresh(lifetime_attr->value());
|
| + port_->SignalTurnRefreshResult(port_, TURN_SUCCESS_RESULT_CODE);
|
| }
|
|
|
| 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.
|
| @@ -1201,11 +1234,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(
|
| @@ -1258,6 +1294,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) {
|
| @@ -1325,6 +1364,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) {
|
| @@ -1385,8 +1427,8 @@ void TurnEntry::OnCreatePermissionSuccess() {
|
| LOG_J(LS_INFO, port_) << "Create permission for "
|
| << ext_addr_.ToSensitiveString()
|
| << " succeeded";
|
| - // For success result code will be 0.
|
| - port_->SignalCreatePermissionResult(port_, ext_addr_, 0);
|
| + port_->SignalCreatePermissionResult(port_, ext_addr_,
|
| + TURN_SUCCESS_RESULT_CODE);
|
|
|
| // If |state_| is STATE_BOUND, the permission will be refreshed
|
| // by ChannelBindRequest.
|
| @@ -1406,6 +1448,7 @@ 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);
|
| Connection* c = port_->GetConnection(ext_addr_);
|
| @@ -1417,6 +1460,10 @@ void TurnEntry::OnCreatePermissionError(StunMessage* response, int code) {
|
| }
|
| }
|
|
|
| +void TurnEntry::OnCreatePermissionTimeout() {
|
| + port_->DestroyConnection(ext_addr_);
|
| +}
|
| +
|
| void TurnEntry::OnChannelBindSuccess() {
|
| LOG_J(LS_INFO, port_) << "Channel bind for " << ext_addr_.ToSensitiveString()
|
| << " succeeded";
|
| @@ -1425,14 +1472,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
|
|
|