OLD | NEW |
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 "content/browser/renderer_host/render_process_host_impl.h" | |
12 #include "content/public/browser/browser_thread.h" | |
13 #include "crypto/hmac.h" | 11 #include "crypto/hmac.h" |
14 #include "third_party/libjingle/source/talk/base/asyncpacketsocket.h" | 12 #include "third_party/libjingle/source/talk/base/asyncpacketsocket.h" |
15 #include "third_party/libjingle/source/talk/base/byteorder.h" | 13 #include "third_party/libjingle/source/talk/base/byteorder.h" |
16 #include "third_party/libjingle/source/talk/base/messagedigest.h" | 14 #include "third_party/libjingle/source/talk/base/messagedigest.h" |
17 #include "third_party/libjingle/source/talk/p2p/base/stun.h" | 15 #include "third_party/libjingle/source/talk/p2p/base/stun.h" |
18 | 16 |
19 namespace { | 17 namespace { |
20 | 18 |
21 const uint32 kStunMagicCookie = 0x2112A442; | 19 const uint32 kStunMagicCookie = 0x2112A442; |
22 const int kMinRtpHdrLen = 12; | 20 const int kMinRtpHdrLen = 12; |
(...skipping 27 matching lines...) Expand all Loading... |
50 bool IsTurnSendIndicationPacket(const char* data) { | 48 bool IsTurnSendIndicationPacket(const char* data) { |
51 uint16 type = talk_base::GetBE16(data); | 49 uint16 type = talk_base::GetBE16(data); |
52 return (type == cricket::TURN_SEND_INDICATION); | 50 return (type == cricket::TURN_SEND_INDICATION); |
53 } | 51 } |
54 | 52 |
55 bool IsRtpPacket(const char* data, int len) { | 53 bool IsRtpPacket(const char* data, int len) { |
56 return ((*data & 0xC0) == 0x80); | 54 return ((*data & 0xC0) == 0x80); |
57 } | 55 } |
58 | 56 |
59 // Verifies rtp header and message length. | 57 // Verifies rtp header and message length. |
60 bool ValidateRtpHeader(const char* rtp, int length, size_t* header_length) { | 58 bool ValidateRtpHeader(char* rtp, int length) { |
61 if (header_length) | |
62 *header_length = 0; | |
63 | |
64 int cc_count = rtp[0] & 0x0F; | 59 int cc_count = rtp[0] & 0x0F; |
65 int rtp_hdr_len_without_extn = kMinRtpHdrLen + 4 * cc_count; | 60 int rtp_hdr_len_without_extn = kMinRtpHdrLen + 4 * cc_count; |
66 if (rtp_hdr_len_without_extn > length) { | 61 if (rtp_hdr_len_without_extn > length) { |
67 return false; | 62 return false; |
68 } | 63 } |
69 | 64 |
70 // If extension bit is not set, we are done with header processing, as input | 65 // If extension bit is not set, we are done with header processing, as input |
71 // length is verified above. | 66 // length is verified above. |
72 if (!(rtp[0] & 0x10)) { | 67 if (!(rtp[0] & 0x10)) { |
73 if (header_length) | |
74 *header_length = rtp_hdr_len_without_extn; | |
75 | |
76 return true; | 68 return true; |
77 } | 69 } |
78 | 70 |
79 rtp += rtp_hdr_len_without_extn; | 71 rtp += rtp_hdr_len_without_extn; |
80 | 72 |
81 // Getting extension profile length. | 73 // Getting extension profile length. |
82 // Length is in 32 bit words. | 74 // Length is in 32 bit words. |
83 uint16 extn_length = talk_base::GetBE16(rtp + 2) * 4; | 75 uint16 extn_length = talk_base::GetBE16(rtp + 2) * 4; |
84 | 76 |
85 // Verify input length against total header size. | 77 // Verify input length against total header size. |
86 if (rtp_hdr_len_without_extn + kRtpExtnHdrLen + extn_length > length) { | 78 if (rtp_hdr_len_without_extn + kRtpExtnHdrLen + extn_length > length) { |
87 return false; | 79 return false; |
88 } | 80 } |
89 | |
90 if (header_length) | |
91 *header_length = rtp_hdr_len_without_extn + kRtpExtnHdrLen + extn_length; | |
92 return true; | 81 return true; |
93 } | 82 } |
94 | 83 |
95 void UpdateAbsSendTimeExtnValue(char* extn_data, int len, | 84 void UpdateAbsSendTimeExtnValue(char* extn_data, int len, |
96 uint32 abs_send_time) { | 85 uint32 abs_send_time) { |
97 // Absolute send time in RTP streams. | 86 // Absolute send time in RTP streams. |
98 // | 87 // |
99 // The absolute send time is signaled to the receiver in-band using the | 88 // The absolute send time is signaled to the receiver in-band using the |
100 // general mechanism for RTP header extensions [RFC5285]. The payload | 89 // general mechanism for RTP header extensions [RFC5285]. The payload |
101 // of this extension (the transmitted value) is a 24-bit unsigned integer | 90 // of this extension (the transmitted value) is a 24-bit unsigned integer |
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
210 if (options.packet_time_params.rtp_sendtime_extension_id != -1) { | 199 if (options.packet_time_params.rtp_sendtime_extension_id != -1) { |
211 UpdateRtpAbsSendTimeExtn( | 200 UpdateRtpAbsSendTimeExtn( |
212 start, rtp_length, | 201 start, rtp_length, |
213 options.packet_time_params.rtp_sendtime_extension_id, abs_send_time); | 202 options.packet_time_params.rtp_sendtime_extension_id, abs_send_time); |
214 } | 203 } |
215 | 204 |
216 UpdateRtpAuthTag(start, rtp_length, options); | 205 UpdateRtpAuthTag(start, rtp_length, options); |
217 return true; | 206 return true; |
218 } | 207 } |
219 | 208 |
220 bool GetRtpPacketStartPositionAndLength(const char* packet, | 209 bool GetRtpPacketStartPositionAndLength( |
221 int length, | 210 char* packet, int length, int* rtp_start_pos, int* rtp_packet_length) { |
222 int* rtp_start_pos, | |
223 int* rtp_packet_length) { | |
224 int rtp_begin, rtp_length; | 211 int rtp_begin, rtp_length; |
225 if (IsTurnChannelData(packet)) { | 212 if (IsTurnChannelData(packet)) { |
226 // Turn Channel Message header format. | 213 // Turn Channel Message header format. |
227 // 0 1 2 3 | 214 // 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 | 215 // 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 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 216 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
230 // | Channel Number | Length | | 217 // | Channel Number | Length | |
231 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 218 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
232 // | | | 219 // | | |
233 // / Application Data / | 220 // / Application Data / |
(...skipping 15 matching lines...) Expand all Loading... |
249 } | 236 } |
250 // Validate STUN message length. | 237 // Validate STUN message length. |
251 int stun_msg_len = talk_base::GetBE16(&packet[2]); | 238 int stun_msg_len = talk_base::GetBE16(&packet[2]); |
252 if (stun_msg_len + P2PSocketHost::kStunHeaderSize != length) { | 239 if (stun_msg_len + P2PSocketHost::kStunHeaderSize != length) { |
253 return false; | 240 return false; |
254 } | 241 } |
255 | 242 |
256 // First skip mandatory stun header which is of 20 bytes. | 243 // First skip mandatory stun header which is of 20 bytes. |
257 rtp_begin = P2PSocketHost::kStunHeaderSize; | 244 rtp_begin = P2PSocketHost::kStunHeaderSize; |
258 // Loop through STUN attributes until we find STUN DATA attribute. | 245 // Loop through STUN attributes until we find STUN DATA attribute. |
259 const char* start = packet + rtp_begin; | 246 char* start = packet + rtp_begin; |
260 bool data_attr_present = false; | 247 bool data_attr_present = false; |
261 while ((packet + rtp_begin) - start < stun_msg_len) { | 248 while ((packet + rtp_begin) - start < stun_msg_len) { |
262 // Keep reading STUN attributes until we hit DATA attribute. | 249 // Keep reading STUN attributes until we hit DATA attribute. |
263 // Attribute will be a TLV structure. | 250 // Attribute will be a TLV structure. |
264 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 251 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
265 // | Type | Length | | 252 // | Type | Length | |
266 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 253 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
267 // | Value (variable) .... | 254 // | Value (variable) .... |
268 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 255 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
269 // The value in the length field MUST contain the length of the Value | 256 // The value in the length field MUST contain the length of the Value |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
309 | 296 |
310 } else { | 297 } else { |
311 // This is a raw RTP packet. | 298 // This is a raw RTP packet. |
312 rtp_begin = 0; | 299 rtp_begin = 0; |
313 rtp_length = length; | 300 rtp_length = length; |
314 } | 301 } |
315 | 302 |
316 // Making sure we have a valid RTP packet at the end. | 303 // Making sure we have a valid RTP packet at the end. |
317 if (!(rtp_length < kMinRtpHdrLen) && | 304 if (!(rtp_length < kMinRtpHdrLen) && |
318 IsRtpPacket(packet + rtp_begin, rtp_length) && | 305 IsRtpPacket(packet + rtp_begin, rtp_length) && |
319 ValidateRtpHeader(packet + rtp_begin, rtp_length, NULL)) { | 306 ValidateRtpHeader(packet + rtp_begin, rtp_length)) { |
320 *rtp_start_pos = rtp_begin; | 307 *rtp_start_pos = rtp_begin; |
321 *rtp_packet_length = rtp_length; | 308 *rtp_packet_length = rtp_length; |
322 return true; | 309 return true; |
323 } | 310 } |
324 return false; | 311 return false; |
325 } | 312 } |
326 | 313 |
327 // ValidateRtpHeader must be called before this method to make sure, we have | 314 // ValidateRtpHeader must be called before this method to make sure, we have |
328 // a sane rtp packet. | 315 // a sane rtp packet. |
329 bool UpdateRtpAbsSendTimeExtn(char* rtp, int length, | 316 bool UpdateRtpAbsSendTimeExtn(char* rtp, int length, |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
395 while ((*rtp == 0) && (rtp - extn_start < extn_length)) { | 382 while ((*rtp == 0) && (rtp - extn_start < extn_length)) { |
396 ++rtp; | 383 ++rtp; |
397 } | 384 } |
398 } | 385 } |
399 } | 386 } |
400 return found; | 387 return found; |
401 } | 388 } |
402 | 389 |
403 } // packet_processing_helpers | 390 } // packet_processing_helpers |
404 | 391 |
405 P2PSocketHost::P2PSocketHost(IPC::Sender* message_sender, int socket_id) | 392 P2PSocketHost::P2PSocketHost(IPC::Sender* message_sender, |
| 393 int id) |
406 : message_sender_(message_sender), | 394 : message_sender_(message_sender), |
407 id_(socket_id), | 395 id_(id), |
408 state_(STATE_UNINITIALIZED), | 396 state_(STATE_UNINITIALIZED) { |
409 dump_incoming_rtp_packet_(false), | |
410 dump_outgoing_rtp_packet_(false), | |
411 weak_ptr_factory_(this) { | |
412 } | 397 } |
413 | 398 |
414 P2PSocketHost::~P2PSocketHost() { } | 399 P2PSocketHost::~P2PSocketHost() { } |
415 | 400 |
416 // Verifies that the packet |data| has a valid STUN header. | 401 // Verifies that the packet |data| has a valid STUN header. |
417 // static | 402 // static |
418 bool P2PSocketHost::GetStunPacketType( | 403 bool P2PSocketHost::GetStunPacketType( |
419 const char* data, int data_size, StunMessageType* type) { | 404 const char* data, int data_size, StunMessageType* type) { |
420 | 405 |
421 if (data_size < kStunHeaderSize) | 406 if (data_size < kStunHeaderSize) |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
454 } | 439 } |
455 } | 440 } |
456 | 441 |
457 // static | 442 // static |
458 bool P2PSocketHost::IsRequestOrResponse(StunMessageType type) { | 443 bool P2PSocketHost::IsRequestOrResponse(StunMessageType type) { |
459 return type == STUN_BINDING_REQUEST || type == STUN_BINDING_RESPONSE || | 444 return type == STUN_BINDING_REQUEST || type == STUN_BINDING_RESPONSE || |
460 type == STUN_ALLOCATE_REQUEST || type == STUN_ALLOCATE_RESPONSE; | 445 type == STUN_ALLOCATE_REQUEST || type == STUN_ALLOCATE_RESPONSE; |
461 } | 446 } |
462 | 447 |
463 // static | 448 // static |
464 P2PSocketHost* P2PSocketHost::Create(IPC::Sender* message_sender, | 449 P2PSocketHost* P2PSocketHost::Create( |
465 int socket_id, | 450 IPC::Sender* message_sender, int id, P2PSocketType type, |
466 P2PSocketType type, | 451 net::URLRequestContextGetter* url_context, |
467 net::URLRequestContextGetter* url_context, | 452 P2PMessageThrottler* throttler) { |
468 P2PMessageThrottler* throttler) { | |
469 switch (type) { | 453 switch (type) { |
470 case P2P_SOCKET_UDP: | 454 case P2P_SOCKET_UDP: |
471 return new P2PSocketHostUdp(message_sender, socket_id, throttler); | 455 return new P2PSocketHostUdp(message_sender, id, throttler); |
472 case P2P_SOCKET_TCP_SERVER: | 456 case P2P_SOCKET_TCP_SERVER: |
473 return new P2PSocketHostTcpServer( | 457 return new P2PSocketHostTcpServer( |
474 message_sender, socket_id, P2P_SOCKET_TCP_CLIENT); | 458 message_sender, id, P2P_SOCKET_TCP_CLIENT); |
475 | 459 |
476 case P2P_SOCKET_STUN_TCP_SERVER: | 460 case P2P_SOCKET_STUN_TCP_SERVER: |
477 return new P2PSocketHostTcpServer( | 461 return new P2PSocketHostTcpServer( |
478 message_sender, socket_id, P2P_SOCKET_STUN_TCP_CLIENT); | 462 message_sender, id, P2P_SOCKET_STUN_TCP_CLIENT); |
479 | 463 |
480 case P2P_SOCKET_TCP_CLIENT: | 464 case P2P_SOCKET_TCP_CLIENT: |
481 case P2P_SOCKET_SSLTCP_CLIENT: | 465 case P2P_SOCKET_SSLTCP_CLIENT: |
482 case P2P_SOCKET_TLS_CLIENT: | 466 case P2P_SOCKET_TLS_CLIENT: |
483 return new P2PSocketHostTcp(message_sender, socket_id, type, url_context); | 467 return new P2PSocketHostTcp(message_sender, id, type, url_context); |
484 | 468 |
485 case P2P_SOCKET_STUN_TCP_CLIENT: | 469 case P2P_SOCKET_STUN_TCP_CLIENT: |
486 case P2P_SOCKET_STUN_SSLTCP_CLIENT: | 470 case P2P_SOCKET_STUN_SSLTCP_CLIENT: |
487 case P2P_SOCKET_STUN_TLS_CLIENT: | 471 case P2P_SOCKET_STUN_TLS_CLIENT: |
488 return new P2PSocketHostStunTcp( | 472 return new P2PSocketHostStunTcp(message_sender, id, type, url_context); |
489 message_sender, socket_id, type, url_context); | |
490 } | 473 } |
491 | 474 |
492 NOTREACHED(); | 475 NOTREACHED(); |
493 return NULL; | 476 return NULL; |
494 } | 477 } |
495 | 478 |
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 packet_header.get(), | |
580 header_length, | |
581 packet_length, | |
582 incoming)); | |
583 } | |
584 | |
585 } // namespace content | 479 } // namespace content |
OLD | NEW |