Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(460)

Side by Side Diff: content/browser/renderer_host/p2p/socket_host.cc

Issue 159353002: This CL adds methods to manipulate RTP header extension, particularly (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Updating TS in SendTime extension header Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/browser/renderer_host/p2p/socket_host.h" 5 #include "content/browser/renderer_host/p2p/socket_host.h"
6 6
7 #include "base/sys_byteorder.h" 7 #include "base/sys_byteorder.h"
8 #include "content/browser/renderer_host/p2p/socket_host_tcp.h" 8 #include "content/browser/renderer_host/p2p/socket_host_tcp.h"
9 #include "content/browser/renderer_host/p2p/socket_host_tcp_server.h" 9 #include "content/browser/renderer_host/p2p/socket_host_tcp_server.h"
10 #include "content/browser/renderer_host/p2p/socket_host_udp.h" 10 #include "content/browser/renderer_host/p2p/socket_host_udp.h"
11 #include "third_party/libjingle/source/talk/base/byteorder.h"
12 #include "third_party/libjingle/source/talk/p2p/base/stun.h"
13 #include "third_party/libjingle/source/talk/base/messagedigest.h"
14 #include "third_party/libjingle/source/talk/base/scoped_ptr.h"
11 15
12 namespace { 16 namespace {
13 const uint32 kStunMagicCookie = 0x2112A442; 17 const uint32 kStunMagicCookie = 0x2112A442;
18 const int kMinRtpHdrLen = 12;
19 const int kDtlsRecordHeaderLen = 13;
20 const int kTurnChannelHdrLen = 4;
21 const int kRtpExtnHdrLen = 4;
22 const int kAbsSendTimeExtnLen = 3;
23 const int kOneByteHdrLen = 1;
24
25 bool IsTurnChannelData(const char* data) {
26 uint16 type = talk_base::GetBE16(data);
27 return ((type & 0xC000) == 0x4000); // MSB are 0b01
28 }
29
30 bool IsDtlsPacket(const char* data, int len) {
juberti2 2014/02/14 01:53:27 need to think about whether this can be demuxed fr
Mallinath (Gone from Chromium) 2014/02/19 18:52:24 I don't think we need any of these methods now. O
31 const uint8* u = reinterpret_cast<const uint8*>(data);
32 return (len >= kDtlsRecordHeaderLen && (u[0] > 19 && u[0] < 64));
33 }
34
35 bool IsRtcpPacket(const char* data) {
36 int type = (static_cast<uint8>(data[1]) & 0x7F);
37 return (type >= 64 && type < 96);
38 }
39
40 bool IsStunPacket(const char* data) {
41 uint16 type = talk_base::GetBE16(data);
42 return !(type & 0xC000);
43 }
44
45 const size_t kBlockSize = 64; // valid for SHA-256 and down
46
47 class HmacCalculator {
juberti2 2014/02/14 01:53:27 Is there no Chrome class to do this? Or can you us
Mallinath (Gone from Chromium) 2014/02/14 02:19:07 ComputeHmac takes only one input. For RTP we have
48 public:
49 HmacCalculator();
50 ~HmacCalculator() {}
51
52 bool Init(const void* key, size_t key_len);
53 void Update(const void* input, size_t in_len);
54 void Compute(void* output, size_t out_len);
55
56 private:
57 size_t block_len;
58 scoped_ptr<uint8[]> o_pad_;
59 scoped_ptr<uint8[]> i_pad_;
60 scoped_ptr<uint8[]> inner_;
61 scoped_ptr<talk_base::MessageDigest> digest_;
62 };
63
64 HmacCalculator::HmacCalculator()
65 : digest_(talk_base::MessageDigestFactory::Create(
66 talk_base::DIGEST_SHA_1)) {
67 }
68
69 bool HmacCalculator::Init(const void* key, size_t key_len) {
70 if (!digest_) {
71 return false;
72 }
73 block_len = kBlockSize;
74 if (digest_->Size() > 32) {
75 return false;
76 }
77
78 // Copy the key to a block-sized buffer to simplify padding.
79 // If the key is longer than a block, hash it and use the result instead.
80 talk_base::scoped_ptr<uint8[]> new_key(new uint8[block_len]);
81 if (key_len > block_len) {
82 talk_base::ComputeDigest(digest_.get(), key, key_len,
83 new_key.get(), block_len);
84 memset(new_key.get() + digest_->Size(), 0, block_len - digest_->Size());
85 } else {
86 memcpy(new_key.get(), key, key_len);
87 memset(new_key.get() + key_len, 0, block_len - key_len);
88 }
89
90 // Set up the padding from the key, salting appropriately for each padding.
91 o_pad_.reset(new uint8[block_len]);
92 i_pad_.reset(new uint8[block_len]);
93 for (size_t i = 0; i < block_len; ++i) {
94 o_pad_[i] = 0x5c ^ new_key[i];
95 i_pad_[i] = 0x36 ^ new_key[i];
96 }
97 // Inner hash; hash the inner padding, and then the input buffer.
98 inner_.reset(new uint8[digest_->Size()]);
99 digest_->Update(i_pad_.get(), block_len);
100 return true;
101 }
102
103 void HmacCalculator::Update(const void* input, size_t in_len) {
104 digest_->Update(input, in_len);
105 }
106
107 void HmacCalculator::Compute(void* output, size_t out_len) {
108 // Outer hash; hash the outer padding, and then the result of the inner hash.
109 digest_->Update(o_pad_.get(), block_len);
110 digest_->Update(inner_.get(), digest_->Size());
111 digest_->Finish(output, out_len);
112 }
113
14 } // namespace 114 } // namespace
15 115
16 namespace content { 116 namespace content {
17 117
18 P2PSocketHost::P2PSocketHost(IPC::Sender* message_sender, 118 P2PSocketHost::P2PSocketHost(IPC::Sender* message_sender,
19 int id) 119 int id)
20 : message_sender_(message_sender), 120 : message_sender_(message_sender),
21 id_(id), 121 id_(id),
22 state_(STATE_UNINITIALIZED) { 122 state_(STATE_UNINITIALIZED),
123 rtp_sendtime_extn_id_(3) {
juberti2 2014/02/14 01:53:27 this will come down in each packet, right?
Mallinath (Gone from Chromium) 2014/02/14 02:19:07 yea absolutely, this was just for testing purpose.
23 } 124 }
24 125
25 P2PSocketHost::~P2PSocketHost() { } 126 P2PSocketHost::~P2PSocketHost() { }
26 127
27 // Verifies that the packet |data| has a valid STUN header. 128 // Verifies that the packet |data| has a valid STUN header.
28 // static 129 // static
29 bool P2PSocketHost::GetStunPacketType( 130 bool P2PSocketHost::GetStunPacketType(
30 const char* data, int data_size, StunMessageType* type) { 131 const char* data, int data_size, StunMessageType* type) {
31 132
32 if (data_size < kStunHeaderSize) 133 if (data_size < kStunHeaderSize)
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
95 case P2P_SOCKET_STUN_TCP_CLIENT: 196 case P2P_SOCKET_STUN_TCP_CLIENT:
96 case P2P_SOCKET_STUN_SSLTCP_CLIENT: 197 case P2P_SOCKET_STUN_SSLTCP_CLIENT:
97 case P2P_SOCKET_STUN_TLS_CLIENT: 198 case P2P_SOCKET_STUN_TLS_CLIENT:
98 return new P2PSocketHostStunTcp(message_sender, id, type, url_context); 199 return new P2PSocketHostStunTcp(message_sender, id, type, url_context);
99 } 200 }
100 201
101 NOTREACHED(); 202 NOTREACHED();
102 return NULL; 203 return NULL;
103 } 204 }
104 205
206 void P2PSocketHost::MaybeUpdateRtpSendTimeExtn(const char* data, int len) {
juberti2 2014/02/14 09:23:56 probably don't want the data pointer to be const i
Mallinath (Gone from Chromium) 2014/02/18 22:40:57 Done.
207 int raw_packet_len = len;
208 const char* start = data;
Mallinath (Gone from Chromium) 2014/02/14 01:29:01 We can always return without doing anything, if Pa
209
210 // Packet can't be less than RTP header size.
211 if (raw_packet_len < kMinRtpHdrLen) {
212 // Not a valid RTP packet.
213 return;
214 }
215
216 // If the packet is a DTLS packet, no need to proceed further.
217 if (IsDtlsPacket(start, len)) {
218 return;
219 }
220
221 // If packet is a stun packet, most likely it's not a media packet.
222 // Do we need to care about STUN DATA Indication?
juberti2 2014/02/14 01:53:27 yes, unfortunately. until we finish channel bind,
Mallinath (Gone from Chromium) 2014/02/14 02:19:07 sure. On 2014/02/14 01:53:27, juberti2 wrote:
223 if (IsStunPacket(start)) {
224 return;
225 }
226
227 // AbsSendTime extension is only in a RTP packet.
228 if (IsRtcpPacket(start)) {
juberti2 2014/02/14 01:53:27 i think you can do this right before ParseRtpPacke
Mallinath (Gone from Chromium) 2014/02/18 22:40:57 Done.
229 return;
230 }
231
232 // Now we need to start inspecting the packet.
233 if (IsTurnChannelData(start)) {
234 start += kTurnChannelHdrLen;
235 raw_packet_len -= kTurnChannelHdrLen;
236 }
237
238 // Skip if the wrapped packet is RTCP packet.
239 if (IsRtcpPacket(start)) {
240 // Update the HMAC and return
241 return;
242 }
243
244 if (ParseRtpPacket(start, raw_packet_len)) {
245 // Update HMAC and return.
246 }
247 }
248
249 bool P2PSocketHost::ParseRtpPacket(const char* data, int in_len) {
juberti2 2014/02/14 01:53:27 Parse is probably not the right term here, since y
Mallinath (Gone from Chromium) 2014/02/18 22:40:57 Done.
250 // 0 1 2 3
251 // 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
252 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
253 // |V=2|P|X| CC |M| PT | sequence number |
254 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
255 // | timestamp |
256 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
257 // | synchronization source (SSRC) identifier |
258 // +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
259 // | contributing source (CSRC) identifiers |
260 // | .... |
261 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
262
263 int cc_count = data[0] & 0x0F;
264 int rtp_hdr_len = kMinRtpHdrLen + 4 * cc_count;
juberti2 2014/02/14 01:53:27 this is confusing since it doesnt include the full
Mallinath (Gone from Chromium) 2014/02/18 22:40:57 Done.
265 if (rtp_hdr_len > in_len) {
266 DCHECK(false);
267 return false;
268 }
269
270 bool X = (data[0] & 0x10);
271 if (!X) // Return if extension bit is not set.
272 return true;
273
274 data += rtp_hdr_len; // Includes RTP extension header.
275
276 // Getting extension profile ID and length.
277 uint16 profile_id = talk_base::GetBE16(data);
278 // Length is in 32 bit words.
279 uint16 extn_length = talk_base::GetBE16(data + 2) * 4;
juberti2 2014/02/14 01:53:27 double check that the length is still good now tha
Mallinath (Gone from Chromium) 2014/02/18 22:40:57 Done.
280 data += kRtpExtnHdrLen; // Moving past extn header.
281
282 // WebRTC is using one byte header extension.
283 // TODO(mallinath) - Handle two byte header extension.
284 if (profile_id && 0xBEDE) { // OneByte extension header
juberti2 2014/02/14 01:53:27 ==, not &&
Mallinath (Gone from Chromium) 2014/02/18 22:40:57 Done.
285 // 0
286 // 0 1 2 3 4 5 6 7
287 // +-+-+-+-+-+-+-+-+
288 // | ID | len |
289 // +-+-+-+-+-+-+-+-+
290
291 // 0 1 2 3
292 // 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
293 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
294 // | 0xBE | 0xDE | length=3 |
295 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
296 // | ID | L=0 | data | ID | L=1 | data...
297 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
298 // ...data | 0 (pad) | 0 (pad) | ID | L=3 |
299 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
300 // | data |
301 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
302 uint16 consumed = 0;
303 while(extn_length - consumed > 0) {
304 const int id = (*data & 0xF0) >> 4;
305 const int len = (*data & 0x0F) + 1;
306 // The 4-bit length is the number minus one of data bytes of this header
307 // extension element following the one-byte header.
308 if (id == rtp_sendtime_extn_id_) {
Solis 2014/02/14 10:05:29 IIUC rtp_sendtime_extn_id_ is the only P2PSocketHo
Mallinath (Gone from Chromium) 2014/02/18 22:40:57 Yea, this I added for testing purpose. Extension i
309 UpdateRtpSendTimeExtn(data + kOneByteHdrLen, len);
310 }
311 consumed += kOneByteHdrLen + len;
312 // Count padding bytes
313 consumed += SkipPaddingBytes(data + consumed, extn_length - consumed);
juberti2 2014/02/14 01:53:27 this seems overly complicated - feels like you cou
Mallinath (Gone from Chromium) 2014/02/18 22:40:57 Done.
314 data += consumed;
315 }
316 }
317 return true;
318 }
319
320 int P2PSocketHost::SkipPaddingBytes(const char* data, int len) {
321 int zero_bytes = 0;
322 int consumed = 0;
323 while (len - consumed > 0) {
324 if (*data != 0) {
325 return zero_bytes;
326 }
327 ++consumed;
328 ++data;
329 ++zero_bytes;
330 }
331 return zero_bytes;
332 }
333
334 void P2PSocketHost::UpdateRtpSendTimeExtn(const char* data, int len) {
Stefan 2014/02/14 09:02:44 Would prefer UpdateRtpAbsSendTimeExtension
Mallinath (Gone from Chromium) 2014/02/18 22:40:57 Done.
335 // Absolute send time in RTP streams.
336 //
337 // The absolute send time is signaled to the receiver in-band using the
338 // general mechanism for RTP header extensions [RFC5285]. The payload
339 // of this extension (the transmitted value) is a 24-bit unsigned integer
340 // containing the sender's current time in seconds as a fixed point number
341 // with 18 bits fractional part.
342 //
343 // The form of the absolute send time extension block:
344 //
345 // 0 1 2 3
346 // 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
347 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
348 // | ID | len=2 | absolute send time |
349 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
350 DCHECK_EQ(len, kAbsSendTimeExtnLen);
351 // Convert micro second to 24-bit unsigned with 18 bit
352 // fractional part
353 uint32 now_second = base::Time::Now().ToInternalValue() /
Stefan 2014/02/14 09:02:44 Chromium doesn't recommend using this method. I'm
Mallinath (Gone from Chromium) 2014/02/18 22:40:57 I think you got confused with base::TimeDelta. Tim
Stefan 2014/02/19 08:17:32 Looks like it says the same n Time::ToInternalValu
Mallinath (Gone from Chromium) 2014/02/19 18:52:24 Ok, I was thinking the discouragement is only for
354 base::Time::kMicrosecondsPerSecond;
355 now_second = (now_second << 18) & 0x00FFFFFF;
356 // This is done to avoid passing a non-const pointer in all places. This way
357 // we can avoid manipulation everywhere than where it's required.
Solis 2014/02/14 10:05:29 IMO that's broken. If MaybeUpdateRtpSendTimeExtn()
Mallinath (Gone from Chromium) 2014/02/18 22:40:57 Done.
358 char* data_ptr = const_cast<char*> (data);
359 // TODO(mallinath) - Add SetBE24 to byteorder.h in libjingle.
360 data_ptr[0] = static_cast<uint8>(now_second >> 16);
361 data_ptr[1] = static_cast<uint8>(now_second >> 8);
362 data_ptr[2] = static_cast<uint8>(now_second);
363 }
364
365 // Assumes |len| is actual packet length + tag length.
366 #if 0
367 void P2PSocketHost::UpdateHmac(const uint8* packet, int len,
368 const talk_base::PacketOptions& options) {
369 uint8* auth_start = packet;
370 uint8* auth_tag = packet + (len - options.tag_len);
371 HmacCalculator hmac;
372 if (!hmac.Init(options.key, options.key_len)) {
373 DCHECK(false);
374 return;
375 }
376 hmac.Update(packet, len - options.key_len);
377 hmac.Update(options.srtp_packet_index, 4);
378 hmac.Compute(auth_tag, options.tag_len);
juberti2 2014/02/14 01:53:27 don't forget that the tag is shorter than the tota
Mallinath (Gone from Chromium) 2014/02/19 18:52:24 Done.
379 }
380 #endif
381
105 } // namespace content 382 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698