15976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org/* 25976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * libjingle 35976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * Copyright 2011, Google Inc. 45976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * Copyright 2011, RTFM, Inc. 55976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * 65976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * Redistribution and use in source and binary forms, with or without 75976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * modification, are permitted provided that the following conditions are met: 85976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * 95976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * 1. Redistributions of source code must retain the above copyright notice, 105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * this list of conditions and the following disclaimer. 115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * 2. Redistributions in binary form must reproduce the above copyright notice, 125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * this list of conditions and the following disclaimer in the documentation 135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * and/or other materials provided with the distribution. 145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * 3. The name of the author may not be used to endorse or promote products 155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * derived from this software without specific prior written permission. 165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * 175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org */ 285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/p2p/base/dtlstransportchannel.h" 305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/base/buffer.h" 325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/base/messagequeue.h" 335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/base/stream.h" 345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/base/sslstreamadapter.h" 355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/base/thread.h" 365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/p2p/base/common.h" 375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgnamespace cricket { 395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// We don't pull the RTP constants from rtputils.h, to avoid a layer violation. 415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstatic const size_t kDtlsRecordHeaderLen = 13; 425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstatic const size_t kMaxDtlsPacketLen = 2048; 435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstatic const size_t kMinRtpPacketLen = 12; 445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstatic bool IsDtlsPacket(const char* data, size_t len) { 465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org const uint8* u = reinterpret_cast<const uint8*>(data); 475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return (len >= kDtlsRecordHeaderLen && (u[0] > 19 && u[0] < 64)); 485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstatic bool IsRtpPacket(const char* data, size_t len) { 505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org const uint8* u = reinterpret_cast<const uint8*>(data); 515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return (len >= kMinRtpPacketLen && (u[0] & 0xC0) == 0x80); 525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgtalk_base::StreamResult StreamInterfaceChannel::Read(void* buffer, 555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org size_t buffer_len, 565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org size_t* read, 575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org int* error) { 585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (state_ == talk_base::SS_CLOSED) 595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return talk_base::SR_EOS; 605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (state_ == talk_base::SS_OPENING) 615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return talk_base::SR_BLOCK; 625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return fifo_.Read(buffer, buffer_len, read, error); 645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgtalk_base::StreamResult StreamInterfaceChannel::Write(const void* data, 675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org size_t data_len, 685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org size_t* written, 695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org int* error) { 705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // Always succeeds, since this is an unreliable transport anyway. 715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // TODO: Should this block if channel_'s temporarily unwritable? 725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org channel_->SendPacket(static_cast<const char*>(data), data_len); 735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (written) { 745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *written = data_len; 755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return talk_base::SR_SUCCESS; 775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool StreamInterfaceChannel::OnPacketReceived(const char* data, size_t size) { 805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // We force a read event here to ensure that we don't overflow our FIFO. 815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // Under high packet rate this can occur if we wait for the FIFO to post its 825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // own SE_READ. 835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org bool ret = (fifo_.WriteAll(data, size, NULL, NULL) == talk_base::SR_SUCCESS); 845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (ret) { 855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org SignalEvent(this, talk_base::SE_READ, 0); 865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return ret; 885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid StreamInterfaceChannel::OnEvent(talk_base::StreamInterface* stream, 915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org int sig, int err) { 925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org SignalEvent(this, sig, err); 935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgDtlsTransportChannelWrapper::DtlsTransportChannelWrapper( 965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org Transport* transport, 975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org TransportChannelImpl* channel) 985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org : TransportChannelImpl(channel->content_name(), channel->component()), 995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org transport_(transport), 1005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org worker_thread_(talk_base::Thread::Current()), 1015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org channel_(channel), 1025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org downward_(NULL), 1035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org dtls_state_(STATE_NONE), 1045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org local_identity_(NULL), 1055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org dtls_role_(talk_base::SSL_CLIENT) { 1065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org channel_->SignalReadableState.connect(this, 1075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org &DtlsTransportChannelWrapper::OnReadableState); 1085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org channel_->SignalWritableState.connect(this, 1095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org &DtlsTransportChannelWrapper::OnWritableState); 1105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org channel_->SignalReadPacket.connect(this, 1115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org &DtlsTransportChannelWrapper::OnReadPacket); 1125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org channel_->SignalReadyToSend.connect(this, 1135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org &DtlsTransportChannelWrapper::OnReadyToSend); 1145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org channel_->SignalRequestSignaling.connect(this, 1155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org &DtlsTransportChannelWrapper::OnRequestSignaling); 1165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org channel_->SignalCandidateReady.connect(this, 1175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org &DtlsTransportChannelWrapper::OnCandidateReady); 1185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org channel_->SignalCandidatesAllocationDone.connect(this, 1195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org &DtlsTransportChannelWrapper::OnCandidatesAllocationDone); 1205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org channel_->SignalRoleConflict.connect(this, 1215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org &DtlsTransportChannelWrapper::OnRoleConflict); 1225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org channel_->SignalRouteChange.connect(this, 1235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org &DtlsTransportChannelWrapper::OnRouteChange); 1245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 1255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 1265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgDtlsTransportChannelWrapper::~DtlsTransportChannelWrapper() { 1275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 1285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 1295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid DtlsTransportChannelWrapper::Connect() { 1305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // We should only get a single call to Connect. 1315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org ASSERT(dtls_state_ == STATE_NONE || 1325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org dtls_state_ == STATE_OFFERED || 1335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org dtls_state_ == STATE_ACCEPTED); 1345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org channel_->Connect(); 1355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 1365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 1375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid DtlsTransportChannelWrapper::Reset() { 1385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org channel_->Reset(); 1395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org set_writable(false); 1405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org set_readable(false); 1415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 1425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // Re-call SetupDtls() 1435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (!SetupDtls()) { 1445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org LOG_J(LS_ERROR, this) << "Error re-initializing DTLS"; 1455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org dtls_state_ = STATE_CLOSED; 1465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return; 1475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 1485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 1495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org dtls_state_ = STATE_ACCEPTED; 1505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 1515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 1523ca2c3528853f8a25fe42f0e998596ea5ce1f33dmallinath@webrtc.orgbool DtlsTransportChannelWrapper::SetLocalIdentity( 1533ca2c3528853f8a25fe42f0e998596ea5ce1f33dmallinath@webrtc.org talk_base::SSLIdentity* identity) { 1543ca2c3528853f8a25fe42f0e998596ea5ce1f33dmallinath@webrtc.org if (dtls_state_ == STATE_OPEN && identity == local_identity_) { 1553ca2c3528853f8a25fe42f0e998596ea5ce1f33dmallinath@webrtc.org return true; 1563ca2c3528853f8a25fe42f0e998596ea5ce1f33dmallinath@webrtc.org } 1573ca2c3528853f8a25fe42f0e998596ea5ce1f33dmallinath@webrtc.org 1585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // TODO(ekr@rtfm.com): Forbid this if Connect() has been called. 1595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (dtls_state_ != STATE_NONE) { 1605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org LOG_J(LS_ERROR, this) << "Can't set DTLS local identity in this state"; 1615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return false; 1625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 1635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 1645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (identity) { 1655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org local_identity_ = identity; 1665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org dtls_state_ = STATE_OFFERED; 1675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } else { 1685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org LOG_J(LS_INFO, this) << "NULL DTLS identity supplied. Not doing DTLS"; 1695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 1705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 1715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return true; 1725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 1735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 1743ca2c3528853f8a25fe42f0e998596ea5ce1f33dmallinath@webrtc.orgvoid DtlsTransportChannelWrapper::SetIceRole(IceRole role) { 1755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // TODO(ekr@rtfm.com): Forbid this if Connect() has been called. 1765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org ASSERT(dtls_state_ < STATE_ACCEPTED); 1775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 1785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // Set the role that is most conformant with RFC 5763, Section 5, bullet 1: 1795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // The endpoint that is the offerer MUST [...] be prepared to receive 1805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // a client_hello before it receives the answer. 1815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // (IOW, the offerer is the server, and the answerer is the client). 1823ca2c3528853f8a25fe42f0e998596ea5ce1f33dmallinath@webrtc.org dtls_role_ = (role == ICEROLE_CONTROLLING) ? 1835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org talk_base::SSL_SERVER : talk_base::SSL_CLIENT; 1845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 1853ca2c3528853f8a25fe42f0e998596ea5ce1f33dmallinath@webrtc.org channel_->SetIceRole(role); 1865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 1875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 1883ca2c3528853f8a25fe42f0e998596ea5ce1f33dmallinath@webrtc.orgbool DtlsTransportChannelWrapper::SetRemoteFingerprint( 1893ca2c3528853f8a25fe42f0e998596ea5ce1f33dmallinath@webrtc.org const std::string& digest_alg, 1903ca2c3528853f8a25fe42f0e998596ea5ce1f33dmallinath@webrtc.org const uint8* digest, 1913ca2c3528853f8a25fe42f0e998596ea5ce1f33dmallinath@webrtc.org size_t digest_len) { 1923ca2c3528853f8a25fe42f0e998596ea5ce1f33dmallinath@webrtc.org 1933ca2c3528853f8a25fe42f0e998596ea5ce1f33dmallinath@webrtc.org talk_base::Buffer remote_fingerprint_value(digest, digest_len); 1943ca2c3528853f8a25fe42f0e998596ea5ce1f33dmallinath@webrtc.org 1953ca2c3528853f8a25fe42f0e998596ea5ce1f33dmallinath@webrtc.org if ((dtls_state_ == STATE_OPEN) && 1963ca2c3528853f8a25fe42f0e998596ea5ce1f33dmallinath@webrtc.org (remote_fingerprint_value_ == remote_fingerprint_value)) { 1973ca2c3528853f8a25fe42f0e998596ea5ce1f33dmallinath@webrtc.org return true; 1983ca2c3528853f8a25fe42f0e998596ea5ce1f33dmallinath@webrtc.org } 1993ca2c3528853f8a25fe42f0e998596ea5ce1f33dmallinath@webrtc.org 2005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // Allow SetRemoteFingerprint with a NULL digest even if SetLocalIdentity 2015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // hasn't been called. 2025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (dtls_state_ > STATE_OFFERED || 2035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org (dtls_state_ == STATE_NONE && !digest_alg.empty())) { 2045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org LOG_J(LS_ERROR, this) << "Can't set DTLS remote settings in this state"; 2055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return false; 2065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 2075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 2085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (digest_alg.empty()) { 2095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org LOG_J(LS_INFO, this) << "Other side didn't support DTLS"; 2105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org dtls_state_ = STATE_NONE; 2115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return true; 2125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 2135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 2145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // At this point we know we are doing DTLS 2153ca2c3528853f8a25fe42f0e998596ea5ce1f33dmallinath@webrtc.org remote_fingerprint_value.TransferTo(&remote_fingerprint_value_); 2165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org remote_fingerprint_algorithm_ = digest_alg; 2175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 2185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (!SetupDtls()) { 2195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org dtls_state_ = STATE_CLOSED; 2205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return false; 2215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 2225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 2235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org dtls_state_ = STATE_ACCEPTED; 2245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return true; 2255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 2265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 2275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool DtlsTransportChannelWrapper::SetupDtls() { 2285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org StreamInterfaceChannel* downward = 2295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org new StreamInterfaceChannel(worker_thread_, channel_); 2305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 2315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org dtls_.reset(talk_base::SSLStreamAdapter::Create(downward)); 2325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (!dtls_) { 2335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org LOG_J(LS_ERROR, this) << "Failed to create DTLS adapter"; 2345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org delete downward; 2355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return false; 2365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 2375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 2385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org downward_ = downward; 2395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 2405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org dtls_->SetIdentity(local_identity_->GetReference()); 2415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org dtls_->SetMode(talk_base::SSL_MODE_DTLS); 2425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org dtls_->SetServerRole(dtls_role_); 2435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org dtls_->SignalEvent.connect(this, &DtlsTransportChannelWrapper::OnDtlsEvent); 2445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (!dtls_->SetPeerCertificateDigest( 2455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org remote_fingerprint_algorithm_, 2465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org reinterpret_cast<unsigned char *>(remote_fingerprint_value_.data()), 2475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org remote_fingerprint_value_.length())) { 2485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org LOG_J(LS_ERROR, this) << "Couldn't set DTLS certificate digest"; 2495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return false; 2505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 2515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 2525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // Set up DTLS-SRTP, if it's been enabled. 2535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (!srtp_ciphers_.empty()) { 2545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (!dtls_->SetDtlsSrtpCiphers(srtp_ciphers_)) { 2555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org LOG_J(LS_ERROR, this) << "Couldn't set DTLS-SRTP ciphers"; 2565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return false; 2575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 2585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } else { 2595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org LOG_J(LS_INFO, this) << "Not using DTLS"; 2605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 2615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 2625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org LOG_J(LS_INFO, this) << "DTLS setup complete"; 2635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return true; 2645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 2655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 2665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool DtlsTransportChannelWrapper::SetSrtpCiphers(const std::vector<std::string>& 2675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org ciphers) { 2685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // SRTP ciphers must be set before the DTLS handshake starts. 2695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // TODO(juberti): In multiplex situations, we may end up calling this function 2705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // once for each muxed channel. Depending on the order of calls, this may 2715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // result in slightly undesired results, e.g. 32 vs 80-bit MAC. The right way to 2725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // fix this would be for the TransportProxyChannels to intersect the ciphers 2735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // instead of overwriting, so that "80" followed by "32, 80" results in "80". 2745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (dtls_state_ != STATE_NONE && 2755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org dtls_state_ != STATE_OFFERED && 2765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org dtls_state_ != STATE_ACCEPTED) { 2775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org ASSERT(false); 2785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return false; 2795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 2805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 2815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org srtp_ciphers_ = ciphers; 2825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return true; 2835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 2845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 2855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool DtlsTransportChannelWrapper::GetSrtpCipher(std::string* cipher) { 2865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (dtls_state_ != STATE_OPEN) { 2875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return false; 2885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 2895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 2905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return dtls_->GetDtlsSrtpCipher(cipher); 2915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 2925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 2935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 2945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// Called from upper layers to send a media packet. 2955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgint DtlsTransportChannelWrapper::SendPacket(const char* data, size_t size, 2965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org int flags) { 2975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org int result = -1; 2985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 2995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org switch (dtls_state_) { 3005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org case STATE_OFFERED: 3015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // We don't know if we are doing DTLS yet, so we can't send a packet. 3025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // TODO(ekr@rtfm.com): assert here? 3035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org result = -1; 3045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org break; 3055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 3065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org case STATE_STARTED: 3075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org case STATE_ACCEPTED: 3085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // Can't send data until the connection is active 3095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org result = -1; 3105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org break; 3115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 3125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org case STATE_OPEN: 3135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (flags & PF_SRTP_BYPASS) { 3145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org ASSERT(!srtp_ciphers_.empty()); 3155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (!IsRtpPacket(data, size)) { 3165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org result = false; 3175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org break; 3185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 3195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 3205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org result = channel_->SendPacket(data, size); 3215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } else { 3225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org result = (dtls_->WriteAll(data, size, NULL, NULL) == 3235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org talk_base::SR_SUCCESS) ? static_cast<int>(size) : -1; 3245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 3255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org break; 3265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // Not doing DTLS. 3275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org case STATE_NONE: 3285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org result = channel_->SendPacket(data, size); 3295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org break; 3305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 3315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org case STATE_CLOSED: // Can't send anything when we're closed. 3325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return -1; 3335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 3345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 3355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return result; 3365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 3375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 3385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// The state transition logic here is as follows: 3395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// (1) If we're not doing DTLS-SRTP, then the state is just the 3405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// state of the underlying impl() 3415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// (2) If we're doing DTLS-SRTP: 3425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// - Prior to the DTLS handshake, the state is neither readable or 3435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// writable 3445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// - When the impl goes writable for the first time we 3455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// start the DTLS handshake 3465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// - Once the DTLS handshake completes, the state is that of the 3475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// impl again 3485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid DtlsTransportChannelWrapper::OnReadableState(TransportChannel* channel) { 3495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org ASSERT(talk_base::Thread::Current() == worker_thread_); 3505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org ASSERT(channel == channel_); 3515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org LOG_J(LS_VERBOSE, this) 3525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org << "DTLSTransportChannelWrapper: channel readable state changed"; 3535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 3545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (dtls_state_ == STATE_NONE || dtls_state_ == STATE_OPEN) { 3555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org set_readable(channel_->readable()); 3565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // Note: SignalReadableState fired by set_readable. 3575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 3585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 3595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 3605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid DtlsTransportChannelWrapper::OnWritableState(TransportChannel* channel) { 3615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org ASSERT(talk_base::Thread::Current() == worker_thread_); 3625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org ASSERT(channel == channel_); 3635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org LOG_J(LS_VERBOSE, this) 3645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org << "DTLSTransportChannelWrapper: channel writable state changed"; 3655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 3665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org switch (dtls_state_) { 3675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org case STATE_NONE: 3685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org case STATE_OPEN: 3695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org set_writable(channel_->writable()); 3705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // Note: SignalWritableState fired by set_writable. 3715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org break; 3725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 3735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org case STATE_OFFERED: 3745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // Do nothing 3755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org break; 3765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 3775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org case STATE_ACCEPTED: 3785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (!MaybeStartDtls()) { 3795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // This should never happen: 3805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // Because we are operating in a nonblocking mode and all 3815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // incoming packets come in via OnReadPacket(), which rejects 3825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // packets in this state, the incoming queue must be empty. We 3835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // ignore write errors, thus any errors must be because of 3845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // configuration and therefore are our fault. 3855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // Note that in non-debug configurations, failure in 3865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // MaybeStartDtls() changes the state to STATE_CLOSED. 3875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org ASSERT(false); 3885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 3895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org break; 3905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 3915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org case STATE_STARTED: 3925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // Do nothing 3935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org break; 3945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 3955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org case STATE_CLOSED: 3965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // Should not happen. Do nothing 3975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org break; 3985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 3995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 4005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 4015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid DtlsTransportChannelWrapper::OnReadPacket(TransportChannel* channel, 4025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org const char* data, size_t size, 4035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org int flags) { 4045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org ASSERT(talk_base::Thread::Current() == worker_thread_); 4055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org ASSERT(channel == channel_); 4065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org ASSERT(flags == 0); 4075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 4085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org switch (dtls_state_) { 4095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org case STATE_NONE: 4105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // We are not doing DTLS 4115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org SignalReadPacket(this, data, size, 0); 4125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org break; 4135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 4145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org case STATE_OFFERED: 4155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // Currently drop the packet, but we might in future 4165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // decide to take this as evidence that the other 4175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // side is ready to do DTLS and start the handshake 4185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // on our end 4195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org LOG_J(LS_WARNING, this) << "Received packet before we know if we are doing " 4205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org << "DTLS or not; dropping"; 4215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org break; 4225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 4235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org case STATE_ACCEPTED: 4245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // Drop packets received before DTLS has actually started 4255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org LOG_J(LS_INFO, this) << "Dropping packet received before DTLS started"; 4265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org break; 4275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 4285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org case STATE_STARTED: 4295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org case STATE_OPEN: 4305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // We should only get DTLS or SRTP packets; STUN's already been demuxed. 4315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // Is this potentially a DTLS packet? 4325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (IsDtlsPacket(data, size)) { 4335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (!HandleDtlsPacket(data, size)) { 4345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org LOG_J(LS_ERROR, this) << "Failed to handle DTLS packet"; 4355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return; 4365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 4375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } else { 4385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // Not a DTLS packet; our handshake should be complete by now. 4395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (dtls_state_ != STATE_OPEN) { 4405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org LOG_J(LS_ERROR, this) << "Received non-DTLS packet before DTLS complete"; 4415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return; 4425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 4435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 4445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // And it had better be a SRTP packet. 4455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (!IsRtpPacket(data, size)) { 4465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org LOG_J(LS_ERROR, this) << "Received unexpected non-DTLS packet"; 4475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return; 4485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 4495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 4505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // Sanity check. 4515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org ASSERT(!srtp_ciphers_.empty()); 4525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 4535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // Signal this upwards as a bypass packet. 4545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org SignalReadPacket(this, data, size, PF_SRTP_BYPASS); 4555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 4565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org break; 4575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org case STATE_CLOSED: 4585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // This shouldn't be happening. Drop the packet 4595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org break; 4605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 4615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 4625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 4635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid DtlsTransportChannelWrapper::OnReadyToSend(TransportChannel* channel) { 4645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (writable()) { 4655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org SignalReadyToSend(this); 4665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 4675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 4685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 4695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid DtlsTransportChannelWrapper::OnDtlsEvent(talk_base::StreamInterface* dtls, 4705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org int sig, int err) { 4715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org ASSERT(talk_base::Thread::Current() == worker_thread_); 4725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org ASSERT(dtls == dtls_.get()); 4735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (sig & talk_base::SE_OPEN) { 4745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // This is the first time. 4755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org LOG_J(LS_INFO, this) << "DTLS handshake complete"; 4765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (dtls_->GetState() == talk_base::SS_OPEN) { 4775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // The check for OPEN shouldn't be necessary but let's make 4785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // sure we don't accidentally frob the state if it's closed. 4795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org dtls_state_ = STATE_OPEN; 4805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 4815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org set_readable(true); 4825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org set_writable(true); 4835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 4845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 4855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (sig & talk_base::SE_READ) { 4865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org char buf[kMaxDtlsPacketLen]; 4875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org size_t read; 4885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (dtls_->Read(buf, sizeof(buf), &read, NULL) == talk_base::SR_SUCCESS) { 4895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org SignalReadPacket(this, buf, read, 0); 4905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 4915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 4925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (sig & talk_base::SE_CLOSE) { 4935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org ASSERT(sig == talk_base::SE_CLOSE); // SE_CLOSE should be by itself. 4945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (!err) { 4955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org LOG_J(LS_INFO, this) << "DTLS channel closed"; 4965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } else { 4975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org LOG_J(LS_INFO, this) << "DTLS channel error, code=" << err; 4985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 4995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 5005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org set_readable(false); 5015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org set_writable(false); 5025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org dtls_state_ = STATE_CLOSED; 5035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 5045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 5055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 5065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool DtlsTransportChannelWrapper::MaybeStartDtls() { 5075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (channel_->writable()) { 5085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (dtls_->StartSSLWithPeer()) { 5095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org LOG_J(LS_ERROR, this) << "Couldn't start DTLS handshake"; 5105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org dtls_state_ = STATE_CLOSED; 5115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return false; 5125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 5135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org LOG_J(LS_INFO, this) 5145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org << "DtlsTransportChannelWrapper: Started DTLS handshake"; 5155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 5165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org dtls_state_ = STATE_STARTED; 5175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 5185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return true; 5195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 5205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 5215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// Called from OnReadPacket when a DTLS packet is received. 5225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool DtlsTransportChannelWrapper::HandleDtlsPacket(const char* data, 5235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org size_t size) { 5245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // Sanity check we're not passing junk that 5255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // just looks like DTLS. 5265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org const uint8* tmp_data = reinterpret_cast<const uint8* >(data); 5275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org size_t tmp_size = size; 5285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org while (tmp_size > 0) { 5295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if (tmp_size < kDtlsRecordHeaderLen) 5305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return false; // Too short for the header 5315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 5325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org size_t record_len = (tmp_data[11] << 8) | (tmp_data[12]); 5335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org if ((record_len + kDtlsRecordHeaderLen) > tmp_size) 5345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return false; // Body too short 5355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 5365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org tmp_data += record_len + kDtlsRecordHeaderLen; 5375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org tmp_size -= record_len + kDtlsRecordHeaderLen; 5385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org } 5395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 5405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // Looks good. Pass to the SIC which ends up being passed to 5415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org // the DTLS stack. 5425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org return downward_->OnPacketReceived(data, size); 5435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 5445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 5455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid DtlsTransportChannelWrapper::OnRequestSignaling( 5465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org TransportChannelImpl* channel) { 5475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org ASSERT(channel == channel_); 5485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org SignalRequestSignaling(this); 5495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 5505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 5515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid DtlsTransportChannelWrapper::OnCandidateReady( 5525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org TransportChannelImpl* channel, const Candidate& c) { 5535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org ASSERT(channel == channel_); 5545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org SignalCandidateReady(this, c); 5555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 5565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 5575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid DtlsTransportChannelWrapper::OnCandidatesAllocationDone( 5585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org TransportChannelImpl* channel) { 5595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org ASSERT(channel == channel_); 5605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org SignalCandidatesAllocationDone(this); 5615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 5625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 5635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid DtlsTransportChannelWrapper::OnRoleConflict( 5645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org TransportChannelImpl* channel) { 5655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org ASSERT(channel == channel_); 5665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org SignalRoleConflict(this); 5675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 5685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 5695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid DtlsTransportChannelWrapper::OnRouteChange( 5705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org TransportChannel* channel, const Candidate& candidate) { 5715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org ASSERT(channel == channel_); 5725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org SignalRouteChange(this, candidate); 5735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} 5745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org 5755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org} // namespace cricket 576