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