Home | History | Annotate | Download | only in p2p
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "content/browser/renderer_host/p2p/socket_host.h"
      6 
      7 #include "base/sys_byteorder.h"
      8 #include "content/browser/renderer_host/p2p/socket_host_tcp.h"
      9 #include "content/browser/renderer_host/p2p/socket_host_tcp_server.h"
     10 #include "content/browser/renderer_host/p2p/socket_host_udp.h"
     11 #include "content/browser/renderer_host/render_process_host_impl.h"
     12 #include "content/public/browser/browser_thread.h"
     13 #include "crypto/hmac.h"
     14 #include "third_party/libjingle/source/talk/base/asyncpacketsocket.h"
     15 #include "third_party/libjingle/source/talk/base/byteorder.h"
     16 #include "third_party/libjingle/source/talk/base/messagedigest.h"
     17 #include "third_party/libjingle/source/talk/p2p/base/stun.h"
     18 
     19 namespace {
     20 
     21 const uint32 kStunMagicCookie = 0x2112A442;
     22 const int kMinRtpHdrLen = 12;
     23 const int kRtpExtnHdrLen = 4;
     24 const int kDtlsRecordHeaderLen = 13;
     25 const int kTurnChannelHdrLen = 4;
     26 const int kAbsSendTimeExtnLen = 3;
     27 const int kOneByteHdrLen = 1;
     28 
     29 // Fake auth tag written by the render process if external authentication is
     30 // enabled. HMAC in packet will be compared against this value before updating
     31 // packet with actual HMAC value.
     32 static const unsigned char kFakeAuthTag[10] = {
     33     0xba, 0xdd, 0xba, 0xdd, 0xba, 0xdd, 0xba, 0xdd, 0xba, 0xdd
     34 };
     35 
     36 bool IsTurnChannelData(const char* data) {
     37   return ((*data & 0xC0) == 0x40);
     38 }
     39 
     40 bool IsDtlsPacket(const char* data, int len) {
     41   const uint8* u = reinterpret_cast<const uint8*>(data);
     42   return (len >= kDtlsRecordHeaderLen && (u[0] > 19 && u[0] < 64));
     43 }
     44 
     45 bool IsRtcpPacket(const char* data) {
     46   int type = (static_cast<uint8>(data[1]) & 0x7F);
     47   return (type >= 64 && type < 96);
     48 }
     49 
     50 bool IsTurnSendIndicationPacket(const char* data) {
     51   uint16 type = talk_base::GetBE16(data);
     52   return (type == cricket::TURN_SEND_INDICATION);
     53 }
     54 
     55 bool IsRtpPacket(const char* data, int len) {
     56   return ((*data & 0xC0) == 0x80);
     57 }
     58 
     59 // Verifies rtp header and message length.
     60 bool ValidateRtpHeader(const char* rtp, int length, size_t* header_length) {
     61   if (header_length)
     62     *header_length = 0;
     63 
     64   int cc_count = rtp[0] & 0x0F;
     65   int rtp_hdr_len_without_extn = kMinRtpHdrLen + 4 * cc_count;
     66   if (rtp_hdr_len_without_extn > length) {
     67     return false;
     68   }
     69 
     70   // If extension bit is not set, we are done with header processing, as input
     71   // length is verified above.
     72   if (!(rtp[0] & 0x10)) {
     73     if (header_length)
     74       *header_length = rtp_hdr_len_without_extn;
     75 
     76     return true;
     77   }
     78 
     79   rtp += rtp_hdr_len_without_extn;
     80 
     81   // Getting extension profile length.
     82   // Length is in 32 bit words.
     83   uint16 extn_length = talk_base::GetBE16(rtp + 2) * 4;
     84 
     85   // Verify input length against total header size.
     86   if (rtp_hdr_len_without_extn + kRtpExtnHdrLen + extn_length > length) {
     87     return false;
     88   }
     89 
     90   if (header_length)
     91     *header_length = rtp_hdr_len_without_extn + kRtpExtnHdrLen + extn_length;
     92   return true;
     93 }
     94 
     95 void UpdateAbsSendTimeExtnValue(char* extn_data, int len,
     96                                 uint32 abs_send_time) {
     97   // Absolute send time in RTP streams.
     98   //
     99   // The absolute send time is signaled to the receiver in-band using the
    100   // general mechanism for RTP header extensions [RFC5285]. The payload
    101   // of this extension (the transmitted value) is a 24-bit unsigned integer
    102   // containing the sender's current time in seconds as a fixed point number
    103   // with 18 bits fractional part.
    104   //
    105   // The form of the absolute send time extension block:
    106   //
    107   //    0                   1                   2                   3
    108   //    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    109   //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    110   //   |  ID   | len=2 |              absolute send time               |
    111   //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    112   DCHECK_EQ(len, kAbsSendTimeExtnLen);
    113   // Now() has resolution ~1-15ms, using HighResNow(). But it is warned not to
    114   // use it unless necessary, as it is expensive than Now().
    115   uint32 now_second = abs_send_time;
    116   if (!now_second) {
    117     uint64 now_us =
    118         (base::TimeTicks::HighResNow() - base::TimeTicks()).InMicroseconds();
    119     // Convert second to 24-bit unsigned with 18 bit fractional part
    120     now_second =
    121         ((now_us << 18) / base::Time::kMicrosecondsPerSecond) & 0x00FFFFFF;
    122   }
    123   // TODO(mallinath) - Add SetBE24 to byteorder.h in libjingle.
    124   extn_data[0] = static_cast<uint8>(now_second >> 16);
    125   extn_data[1] = static_cast<uint8>(now_second >> 8);
    126   extn_data[2] = static_cast<uint8>(now_second);
    127 }
    128 
    129 // Assumes |len| is actual packet length + tag length. Updates HMAC at end of
    130 // the RTP packet.
    131 void UpdateRtpAuthTag(char* rtp, int len,
    132                       const talk_base::PacketOptions& options) {
    133   // If there is no key, return.
    134   if (options.packet_time_params.srtp_auth_key.empty())
    135     return;
    136 
    137   size_t tag_length = options.packet_time_params.srtp_auth_tag_len;
    138   char* auth_tag = rtp + (len - tag_length);
    139 
    140   // We should have a fake HMAC value @ auth_tag.
    141   DCHECK_EQ(0, memcmp(auth_tag, kFakeAuthTag, tag_length));
    142 
    143   crypto::HMAC hmac(crypto::HMAC::SHA1);
    144   if (!hmac.Init(reinterpret_cast<const unsigned char*>(
    145         &options.packet_time_params.srtp_auth_key[0]),
    146         options.packet_time_params.srtp_auth_key.size())) {
    147     NOTREACHED();
    148     return;
    149   }
    150 
    151   if (hmac.DigestLength() < tag_length) {
    152     NOTREACHED();
    153     return;
    154   }
    155 
    156   // Copy ROC after end of rtp packet.
    157   memcpy(auth_tag, &options.packet_time_params.srtp_packet_index, 4);
    158   // Authentication of a RTP packet will have RTP packet + ROC size.
    159   int auth_required_length = len - tag_length + 4;
    160 
    161   unsigned char output[64];
    162   if (!hmac.Sign(base::StringPiece(rtp, auth_required_length),
    163                  output, sizeof(output))) {
    164     NOTREACHED();
    165     return;
    166   }
    167   // Copy HMAC from output to packet. This is required as auth tag length
    168   // may not be equal to the actual HMAC length.
    169   memcpy(auth_tag, output, tag_length);
    170 }
    171 
    172 }  // namespace
    173 
    174 namespace content {
    175 
    176 namespace packet_processing_helpers {
    177 
    178 bool ApplyPacketOptions(char* data, int length,
    179                         const talk_base::PacketOptions& options,
    180                         uint32 abs_send_time) {
    181   DCHECK(data != NULL);
    182   DCHECK(length > 0);
    183   // if there is no valid |rtp_sendtime_extension_id| and |srtp_auth_key| in
    184   // PacketOptions, nothing to be updated in this packet.
    185   if (options.packet_time_params.rtp_sendtime_extension_id == -1 &&
    186       options.packet_time_params.srtp_auth_key.empty()) {
    187     return true;
    188   }
    189 
    190   DCHECK(!IsDtlsPacket(data, length));
    191   DCHECK(!IsRtcpPacket(data));
    192 
    193   // If there is a srtp auth key present then packet must be a RTP packet.
    194   // RTP packet may have been wrapped in a TURN Channel Data or
    195   // TURN send indication.
    196   int rtp_start_pos;
    197   int rtp_length;
    198   if (!GetRtpPacketStartPositionAndLength(
    199       data, length, &rtp_start_pos, &rtp_length)) {
    200     // This method should never return false.
    201     NOTREACHED();
    202     return false;
    203   }
    204 
    205   // Skip to rtp packet.
    206   char* start = data + rtp_start_pos;
    207   // If packet option has non default value (-1) for sendtime extension id,
    208   // then we should parse the rtp packet to update the timestamp. Otherwise
    209   // just calculate HMAC and update packet with it.
    210   if (options.packet_time_params.rtp_sendtime_extension_id != -1) {
    211     UpdateRtpAbsSendTimeExtn(
    212         start, rtp_length,
    213         options.packet_time_params.rtp_sendtime_extension_id, abs_send_time);
    214   }
    215 
    216   UpdateRtpAuthTag(start, rtp_length, options);
    217   return true;
    218 }
    219 
    220 bool GetRtpPacketStartPositionAndLength(const char* packet,
    221                                         int length,
    222                                         int* rtp_start_pos,
    223                                         int* rtp_packet_length) {
    224   int rtp_begin, rtp_length;
    225   if (IsTurnChannelData(packet)) {
    226     // Turn Channel Message header format.
    227     //   0                   1                   2                   3
    228     //  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    229     // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    230     // |         Channel Number        |            Length             |
    231     // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    232     // |                                                               |
    233     // /                       Application Data                        /
    234     // /                                                               /
    235     // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    236     if (length < kTurnChannelHdrLen) {
    237       return false;
    238     }
    239 
    240     rtp_begin = kTurnChannelHdrLen;
    241     rtp_length = talk_base::GetBE16(&packet[2]);
    242     if (length < rtp_length + kTurnChannelHdrLen) {
    243       return false;
    244     }
    245   } else if (IsTurnSendIndicationPacket(packet)) {
    246     if (length <= P2PSocketHost::kStunHeaderSize) {
    247       // Message must be greater than 20 bytes, if it's carrying any payload.
    248       return false;
    249     }
    250     // Validate STUN message length.
    251     int stun_msg_len = talk_base::GetBE16(&packet[2]);
    252     if (stun_msg_len + P2PSocketHost::kStunHeaderSize != length) {
    253       return false;
    254     }
    255 
    256     // First skip mandatory stun header which is of 20 bytes.
    257     rtp_begin = P2PSocketHost::kStunHeaderSize;
    258     // Loop through STUN attributes until we find STUN DATA attribute.
    259     const char* start = packet + rtp_begin;
    260     bool data_attr_present = false;
    261     while ((packet + rtp_begin) - start < stun_msg_len) {
    262       // Keep reading STUN attributes until we hit DATA attribute.
    263       // Attribute will be a TLV structure.
    264       // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    265       // |         Type                  |            Length             |
    266       // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    267       // |                         Value (variable)                ....
    268       // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    269       // The value in the length field MUST contain the length of the Value
    270       // part of the attribute, prior to padding, measured in bytes.  Since
    271       // STUN aligns attributes on 32-bit boundaries, attributes whose content
    272       // is not a multiple of 4 bytes are padded with 1, 2, or 3 bytes of
    273       // padding so that its value contains a multiple of 4 bytes.  The
    274       // padding bits are ignored, and may be any value.
    275       uint16 attr_type, attr_length;
    276       // Getting attribute type and length.
    277       attr_type = talk_base::GetBE16(&packet[rtp_begin]);
    278       attr_length = talk_base::GetBE16(
    279           &packet[rtp_begin + sizeof(attr_type)]);
    280       // Checking for bogus attribute length.
    281       if (length < attr_length + rtp_begin) {
    282         return false;
    283       }
    284 
    285       if (attr_type != cricket::STUN_ATTR_DATA) {
    286         rtp_begin += sizeof(attr_type) + sizeof(attr_length) + attr_length;
    287         if ((attr_length % 4) != 0) {
    288           rtp_begin += (4 - (attr_length % 4));
    289         }
    290         continue;
    291       }
    292 
    293       data_attr_present = true;
    294       rtp_begin += 4;  // Skip STUN_DATA_ATTR header.
    295       rtp_length = attr_length;
    296       // One final check of length before exiting.
    297       if (length < rtp_length + rtp_begin) {
    298         return false;
    299       }
    300       // We found STUN_DATA_ATTR. We can skip parsing rest of the packet.
    301       break;
    302     }
    303 
    304     if (!data_attr_present) {
    305       // There is no data attribute present in the message. We can't do anything
    306       // with the message.
    307       return false;
    308     }
    309 
    310   } else {
    311     // This is a raw RTP packet.
    312     rtp_begin = 0;
    313     rtp_length = length;
    314   }
    315 
    316   // Making sure we have a valid RTP packet at the end.
    317   if (!(rtp_length < kMinRtpHdrLen) &&
    318       IsRtpPacket(packet + rtp_begin, rtp_length) &&
    319       ValidateRtpHeader(packet + rtp_begin, rtp_length, NULL)) {
    320     *rtp_start_pos = rtp_begin;
    321     *rtp_packet_length = rtp_length;
    322     return true;
    323   }
    324   return false;
    325 }
    326 
    327 // ValidateRtpHeader must be called before this method to make sure, we have
    328 // a sane rtp packet.
    329 bool UpdateRtpAbsSendTimeExtn(char* rtp, int length,
    330                               int extension_id, uint32 abs_send_time) {
    331   //  0                   1                   2                   3
    332   //  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    333   // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    334   // |V=2|P|X|  CC   |M|     PT      |       sequence number         |
    335   // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    336   // |                           timestamp                           |
    337   // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    338   // |           synchronization source (SSRC) identifier            |
    339   // +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
    340   // |            contributing source (CSRC) identifiers             |
    341   // |                             ....                              |
    342   // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    343 
    344   // Return if extension bit is not set.
    345   if (!(rtp[0] & 0x10)) {
    346     return true;
    347   }
    348 
    349   int cc_count = rtp[0] & 0x0F;
    350   int rtp_hdr_len_without_extn = kMinRtpHdrLen + 4 * cc_count;
    351 
    352   rtp += rtp_hdr_len_without_extn;
    353 
    354   // Getting extension profile ID and length.
    355   uint16 profile_id = talk_base::GetBE16(rtp);
    356   // Length is in 32 bit words.
    357   uint16 extn_length = talk_base::GetBE16(rtp + 2) * 4;
    358 
    359   rtp += kRtpExtnHdrLen;  // Moving past extn header.
    360 
    361   bool found = false;
    362   // WebRTC is using one byte header extension.
    363   // TODO(mallinath) - Handle two byte header extension.
    364   if (profile_id == 0xBEDE) {  // OneByte extension header
    365     //  0
    366     //  0 1 2 3 4 5 6 7
    367     // +-+-+-+-+-+-+-+-+
    368     // |  ID   |  len  |
    369     // +-+-+-+-+-+-+-+-+
    370 
    371     //  0                   1                   2                   3
    372     //  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    373     // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    374     // |       0xBE    |    0xDE       |           length=3            |
    375     // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    376     // |  ID   | L=0   |     data      |  ID   |  L=1  |   data...
    377     // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    378     //       ...data   |    0 (pad)    |    0 (pad)    |  ID   | L=3   |
    379     // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    380     // |                          data                                 |
    381     // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    382     char* extn_start = rtp;
    383     while (rtp - extn_start < extn_length) {
    384       const int id = (*rtp & 0xF0) >> 4;
    385       const int len = (*rtp & 0x0F) + 1;
    386       // The 4-bit length is the number minus one of data bytes of this header
    387       // extension element following the one-byte header.
    388       if (id == extension_id) {
    389         UpdateAbsSendTimeExtnValue(rtp + kOneByteHdrLen, len, abs_send_time);
    390         found = true;
    391         break;
    392       }
    393       rtp += kOneByteHdrLen + len;
    394       // Counting padding bytes.
    395       while ((*rtp == 0) && (rtp - extn_start < extn_length)) {
    396         ++rtp;
    397       }
    398     }
    399   }
    400   return found;
    401 }
    402 
    403 }  // packet_processing_helpers
    404 
    405 P2PSocketHost::P2PSocketHost(IPC::Sender* message_sender, int socket_id)
    406     : message_sender_(message_sender),
    407       id_(socket_id),
    408       state_(STATE_UNINITIALIZED),
    409       dump_incoming_rtp_packet_(false),
    410       dump_outgoing_rtp_packet_(false),
    411       weak_ptr_factory_(this) {
    412 }
    413 
    414 P2PSocketHost::~P2PSocketHost() { }
    415 
    416 // Verifies that the packet |data| has a valid STUN header.
    417 // static
    418 bool P2PSocketHost::GetStunPacketType(
    419     const char* data, int data_size, StunMessageType* type) {
    420 
    421   if (data_size < kStunHeaderSize)
    422     return false;
    423 
    424   uint32 cookie = base::NetToHost32(*reinterpret_cast<const uint32*>(data + 4));
    425   if (cookie != kStunMagicCookie)
    426     return false;
    427 
    428   uint16 length = base::NetToHost16(*reinterpret_cast<const uint16*>(data + 2));
    429   if (length != data_size - kStunHeaderSize)
    430     return false;
    431 
    432   int message_type = base::NetToHost16(*reinterpret_cast<const uint16*>(data));
    433 
    434   // Verify that the type is known:
    435   switch (message_type) {
    436     case STUN_BINDING_REQUEST:
    437     case STUN_BINDING_RESPONSE:
    438     case STUN_BINDING_ERROR_RESPONSE:
    439     case STUN_SHARED_SECRET_REQUEST:
    440     case STUN_SHARED_SECRET_RESPONSE:
    441     case STUN_SHARED_SECRET_ERROR_RESPONSE:
    442     case STUN_ALLOCATE_REQUEST:
    443     case STUN_ALLOCATE_RESPONSE:
    444     case STUN_ALLOCATE_ERROR_RESPONSE:
    445     case STUN_SEND_REQUEST:
    446     case STUN_SEND_RESPONSE:
    447     case STUN_SEND_ERROR_RESPONSE:
    448     case STUN_DATA_INDICATION:
    449       *type = static_cast<StunMessageType>(message_type);
    450       return true;
    451 
    452     default:
    453       return false;
    454   }
    455 }
    456 
    457 // static
    458 bool P2PSocketHost::IsRequestOrResponse(StunMessageType type) {
    459   return type == STUN_BINDING_REQUEST || type == STUN_BINDING_RESPONSE ||
    460       type == STUN_ALLOCATE_REQUEST || type == STUN_ALLOCATE_RESPONSE;
    461 }
    462 
    463 // static
    464 P2PSocketHost* P2PSocketHost::Create(IPC::Sender* message_sender,
    465                                      int socket_id,
    466                                      P2PSocketType type,
    467                                      net::URLRequestContextGetter* url_context,
    468                                      P2PMessageThrottler* throttler) {
    469   switch (type) {
    470     case P2P_SOCKET_UDP:
    471       return new P2PSocketHostUdp(message_sender, socket_id, throttler);
    472     case P2P_SOCKET_TCP_SERVER:
    473       return new P2PSocketHostTcpServer(
    474           message_sender, socket_id, P2P_SOCKET_TCP_CLIENT);
    475 
    476     case P2P_SOCKET_STUN_TCP_SERVER:
    477       return new P2PSocketHostTcpServer(
    478           message_sender, socket_id, P2P_SOCKET_STUN_TCP_CLIENT);
    479 
    480     case P2P_SOCKET_TCP_CLIENT:
    481     case P2P_SOCKET_SSLTCP_CLIENT:
    482     case P2P_SOCKET_TLS_CLIENT:
    483       return new P2PSocketHostTcp(message_sender, socket_id, type, url_context);
    484 
    485     case P2P_SOCKET_STUN_TCP_CLIENT:
    486     case P2P_SOCKET_STUN_SSLTCP_CLIENT:
    487     case P2P_SOCKET_STUN_TLS_CLIENT:
    488       return new P2PSocketHostStunTcp(
    489           message_sender, socket_id, type, url_context);
    490   }
    491 
    492   NOTREACHED();
    493   return NULL;
    494 }
    495 
    496 void P2PSocketHost::StartRtpDump(
    497     bool incoming,
    498     bool outgoing,
    499     const RenderProcessHost::WebRtcRtpPacketCallback& packet_callback) {
    500   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    501   DCHECK(!packet_callback.is_null());
    502   DCHECK(incoming || outgoing);
    503 
    504   if (incoming)
    505     dump_incoming_rtp_packet_ = true;
    506 
    507   if (outgoing)
    508     dump_outgoing_rtp_packet_ = true;
    509 
    510   packet_dump_callback_ = packet_callback;
    511 }
    512 
    513 void P2PSocketHost::StopRtpDump(bool incoming, bool outgoing) {
    514   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    515   DCHECK(incoming || outgoing);
    516 
    517   if (incoming)
    518     dump_incoming_rtp_packet_ = false;
    519 
    520   if (outgoing)
    521     dump_outgoing_rtp_packet_ = false;
    522 
    523   if (!dump_incoming_rtp_packet_ && !dump_outgoing_rtp_packet_)
    524     packet_dump_callback_.Reset();
    525 }
    526 
    527 void P2PSocketHost::DumpRtpPacket(const char* packet,
    528                                   size_t length,
    529                                   bool incoming) {
    530   if (IsDtlsPacket(packet, length) || IsRtcpPacket(packet))
    531     return;
    532 
    533   int rtp_packet_pos = 0;
    534   int rtp_packet_length = length;
    535   if (!packet_processing_helpers::GetRtpPacketStartPositionAndLength(
    536           packet, length, &rtp_packet_pos, &rtp_packet_length))
    537     return;
    538 
    539   packet += rtp_packet_pos;
    540 
    541   size_t header_length = 0;
    542   bool valid = ValidateRtpHeader(packet, rtp_packet_length, &header_length);
    543   if (!valid) {
    544     DCHECK(false);
    545     return;
    546   }
    547 
    548   scoped_ptr<uint8[]> header_buffer(new uint8[header_length]);
    549   memcpy(header_buffer.get(), packet, header_length);
    550 
    551   // Posts to the IO thread as the data members should be accessed on the IO
    552   // thread only.
    553   BrowserThread::PostTask(BrowserThread::IO,
    554                           FROM_HERE,
    555                           base::Bind(&P2PSocketHost::DumpRtpPacketOnIOThread,
    556                                      weak_ptr_factory_.GetWeakPtr(),
    557                                      Passed(&header_buffer),
    558                                      header_length,
    559                                      rtp_packet_length,
    560                                      incoming));
    561 }
    562 
    563 void P2PSocketHost::DumpRtpPacketOnIOThread(scoped_ptr<uint8[]> packet_header,
    564                                             size_t header_length,
    565                                             size_t packet_length,
    566                                             bool incoming) {
    567   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    568 
    569   if ((incoming && !dump_incoming_rtp_packet_) ||
    570       (!incoming && !dump_outgoing_rtp_packet_) ||
    571       packet_dump_callback_.is_null()) {
    572     return;
    573   }
    574 
    575   // |packet_dump_callback_| must be called on the UI thread.
    576   BrowserThread::PostTask(BrowserThread::UI,
    577                           FROM_HERE,
    578                           base::Bind(packet_dump_callback_,
    579                                      Passed(&packet_header),
    580                                      header_length,
    581                                      packet_length,
    582                                      incoming));
    583 }
    584 
    585 }  // namespace content
    586