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