Chromium Code Reviews| 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) { |
| 59 int cc_count = rtp[0] & 0x0F; | 61 int cc_count = rtp[0] & 0x0F; |
| 60 int rtp_hdr_len_without_extn = kMinRtpHdrLen + 4 * cc_count; | 62 int rtp_hdr_len_without_extn = kMinRtpHdrLen + 4 * cc_count; |
| 61 if (rtp_hdr_len_without_extn > length) { | 63 if (rtp_hdr_len_without_extn > length) { |
| 62 return false; | 64 return false; |
| 63 } | 65 } |
| 64 | 66 |
| 65 // If extension bit is not set, we are done with header processing, as input | 67 // If extension bit is not set, we are done with header processing, as input |
| 66 // length is verified above. | 68 // length is verified above. |
| 67 if (!(rtp[0] & 0x10)) { | 69 if (!(rtp[0] & 0x10)) { |
| 70 if (header_length) | |
| 71 *header_length = rtp_hdr_len_without_extn; | |
| 72 | |
| 68 return true; | 73 return true; |
| 69 } | 74 } |
| 70 | 75 |
| 71 rtp += rtp_hdr_len_without_extn; | 76 rtp += rtp_hdr_len_without_extn; |
| 72 | 77 |
| 73 // Getting extension profile length. | 78 // Getting extension profile length. |
| 74 // Length is in 32 bit words. | 79 // Length is in 32 bit words. |
| 75 uint16 extn_length = talk_base::GetBE16(rtp + 2) * 4; | 80 uint16 extn_length = talk_base::GetBE16(rtp + 2) * 4; |
| 76 | 81 |
| 77 // Verify input length against total header size. | 82 // Verify input length against total header size. |
| 78 if (rtp_hdr_len_without_extn + kRtpExtnHdrLen + extn_length > length) { | 83 if (rtp_hdr_len_without_extn + kRtpExtnHdrLen + extn_length > length) { |
| 79 return false; | 84 return false; |
| 80 } | 85 } |
| 86 | |
| 87 if (header_length) | |
| 88 *header_length = rtp_hdr_len_without_extn + kRtpExtnHdrLen + extn_length; | |
| 81 return true; | 89 return true; |
| 82 } | 90 } |
| 83 | 91 |
| 84 void UpdateAbsSendTimeExtnValue(char* extn_data, int len, | 92 void UpdateAbsSendTimeExtnValue(char* extn_data, int len, |
| 85 uint32 abs_send_time) { | 93 uint32 abs_send_time) { |
| 86 // Absolute send time in RTP streams. | 94 // Absolute send time in RTP streams. |
| 87 // | 95 // |
| 88 // The absolute send time is signaled to the receiver in-band using the | 96 // The absolute send time is signaled to the receiver in-band using the |
| 89 // general mechanism for RTP header extensions [RFC5285]. The payload | 97 // general mechanism for RTP header extensions [RFC5285]. The payload |
| 90 // of this extension (the transmitted value) is a 24-bit unsigned integer | 98 // 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) { | 207 if (options.packet_time_params.rtp_sendtime_extension_id != -1) { |
| 200 UpdateRtpAbsSendTimeExtn( | 208 UpdateRtpAbsSendTimeExtn( |
| 201 start, rtp_length, | 209 start, rtp_length, |
| 202 options.packet_time_params.rtp_sendtime_extension_id, abs_send_time); | 210 options.packet_time_params.rtp_sendtime_extension_id, abs_send_time); |
| 203 } | 211 } |
| 204 | 212 |
| 205 UpdateRtpAuthTag(start, rtp_length, options); | 213 UpdateRtpAuthTag(start, rtp_length, options); |
| 206 return true; | 214 return true; |
| 207 } | 215 } |
| 208 | 216 |
| 209 bool GetRtpPacketStartPositionAndLength( | 217 bool GetRtpPacketStartPositionAndLength(const char* packet, |
| 210 char* packet, int length, int* rtp_start_pos, int* rtp_packet_length) { | 218 int length, |
| 219 int* rtp_start_pos, | |
| 220 int* rtp_packet_length) { | |
| 211 int rtp_begin, rtp_length; | 221 int rtp_begin, rtp_length; |
| 212 if (IsTurnChannelData(packet)) { | 222 if (IsTurnChannelData(packet)) { |
| 213 // Turn Channel Message header format. | 223 // Turn Channel Message header format. |
| 214 // 0 1 2 3 | 224 // 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 | 225 // 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 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 226 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 217 // | Channel Number | Length | | 227 // | Channel Number | Length | |
| 218 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 228 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 219 // | | | 229 // | | |
| 220 // / Application Data / | 230 // / Application Data / |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 236 } | 246 } |
| 237 // Validate STUN message length. | 247 // Validate STUN message length. |
| 238 int stun_msg_len = talk_base::GetBE16(&packet[2]); | 248 int stun_msg_len = talk_base::GetBE16(&packet[2]); |
| 239 if (stun_msg_len + P2PSocketHost::kStunHeaderSize != length) { | 249 if (stun_msg_len + P2PSocketHost::kStunHeaderSize != length) { |
| 240 return false; | 250 return false; |
| 241 } | 251 } |
| 242 | 252 |
| 243 // First skip mandatory stun header which is of 20 bytes. | 253 // First skip mandatory stun header which is of 20 bytes. |
| 244 rtp_begin = P2PSocketHost::kStunHeaderSize; | 254 rtp_begin = P2PSocketHost::kStunHeaderSize; |
| 245 // Loop through STUN attributes until we find STUN DATA attribute. | 255 // Loop through STUN attributes until we find STUN DATA attribute. |
| 246 char* start = packet + rtp_begin; | 256 const char* start = packet + rtp_begin; |
| 247 bool data_attr_present = false; | 257 bool data_attr_present = false; |
| 248 while ((packet + rtp_begin) - start < stun_msg_len) { | 258 while ((packet + rtp_begin) - start < stun_msg_len) { |
| 249 // Keep reading STUN attributes until we hit DATA attribute. | 259 // Keep reading STUN attributes until we hit DATA attribute. |
| 250 // Attribute will be a TLV structure. | 260 // Attribute will be a TLV structure. |
| 251 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 261 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 252 // | Type | Length | | 262 // | Type | Length | |
| 253 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 263 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 254 // | Value (variable) .... | 264 // | Value (variable) .... |
| 255 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 265 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 256 // The value in the length field MUST contain the length of the Value | 266 // 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 | 306 |
| 297 } else { | 307 } else { |
| 298 // This is a raw RTP packet. | 308 // This is a raw RTP packet. |
| 299 rtp_begin = 0; | 309 rtp_begin = 0; |
| 300 rtp_length = length; | 310 rtp_length = length; |
| 301 } | 311 } |
| 302 | 312 |
| 303 // Making sure we have a valid RTP packet at the end. | 313 // Making sure we have a valid RTP packet at the end. |
| 304 if (!(rtp_length < kMinRtpHdrLen) && | 314 if (!(rtp_length < kMinRtpHdrLen) && |
| 305 IsRtpPacket(packet + rtp_begin, rtp_length) && | 315 IsRtpPacket(packet + rtp_begin, rtp_length) && |
| 306 ValidateRtpHeader(packet + rtp_begin, rtp_length)) { | 316 ValidateRtpHeader(packet + rtp_begin, rtp_length, NULL)) { |
| 307 *rtp_start_pos = rtp_begin; | 317 *rtp_start_pos = rtp_begin; |
| 308 *rtp_packet_length = rtp_length; | 318 *rtp_packet_length = rtp_length; |
| 309 return true; | 319 return true; |
| 310 } | 320 } |
| 311 return false; | 321 return false; |
| 312 } | 322 } |
| 313 | 323 |
| 314 // ValidateRtpHeader must be called before this method to make sure, we have | 324 // ValidateRtpHeader must be called before this method to make sure, we have |
| 315 // a sane rtp packet. | 325 // a sane rtp packet. |
| 316 bool UpdateRtpAbsSendTimeExtn(char* rtp, int length, | 326 bool UpdateRtpAbsSendTimeExtn(char* rtp, int length, |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 383 ++rtp; | 393 ++rtp; |
| 384 } | 394 } |
| 385 } | 395 } |
| 386 } | 396 } |
| 387 return found; | 397 return found; |
| 388 } | 398 } |
| 389 | 399 |
| 390 } // packet_processing_helpers | 400 } // packet_processing_helpers |
| 391 | 401 |
| 392 P2PSocketHost::P2PSocketHost(IPC::Sender* message_sender, | 402 P2PSocketHost::P2PSocketHost(IPC::Sender* message_sender, |
| 393 int id) | 403 int socket_id, |
| 404 int render_process_host_id) | |
| 394 : message_sender_(message_sender), | 405 : message_sender_(message_sender), |
| 395 id_(id), | 406 id_(socket_id), |
| 396 state_(STATE_UNINITIALIZED) { | 407 render_process_host_id_(render_process_host_id), |
| 408 state_(STATE_UNINITIALIZED), | |
| 409 dump_incoming_rtp_packet_(false), | |
| 410 dump_outgoing_rtp_packet_(false) { | |
| 397 } | 411 } |
| 398 | 412 |
| 399 P2PSocketHost::~P2PSocketHost() { } | 413 P2PSocketHost::~P2PSocketHost() { } |
| 400 | 414 |
| 401 // Verifies that the packet |data| has a valid STUN header. | 415 // Verifies that the packet |data| has a valid STUN header. |
| 402 // static | 416 // static |
| 403 bool P2PSocketHost::GetStunPacketType( | 417 bool P2PSocketHost::GetStunPacketType( |
| 404 const char* data, int data_size, StunMessageType* type) { | 418 const char* data, int data_size, StunMessageType* type) { |
| 405 | 419 |
| 406 if (data_size < kStunHeaderSize) | 420 if (data_size < kStunHeaderSize) |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 439 } | 453 } |
| 440 } | 454 } |
| 441 | 455 |
| 442 // static | 456 // static |
| 443 bool P2PSocketHost::IsRequestOrResponse(StunMessageType type) { | 457 bool P2PSocketHost::IsRequestOrResponse(StunMessageType type) { |
| 444 return type == STUN_BINDING_REQUEST || type == STUN_BINDING_RESPONSE || | 458 return type == STUN_BINDING_REQUEST || type == STUN_BINDING_RESPONSE || |
| 445 type == STUN_ALLOCATE_REQUEST || type == STUN_ALLOCATE_RESPONSE; | 459 type == STUN_ALLOCATE_REQUEST || type == STUN_ALLOCATE_RESPONSE; |
| 446 } | 460 } |
| 447 | 461 |
| 448 // static | 462 // static |
| 449 P2PSocketHost* P2PSocketHost::Create( | 463 P2PSocketHost* P2PSocketHost::Create(IPC::Sender* message_sender, |
| 450 IPC::Sender* message_sender, int id, P2PSocketType type, | 464 int socket_id, |
| 451 net::URLRequestContextGetter* url_context, | 465 int render_process_host_id, |
| 452 P2PMessageThrottler* throttler) { | 466 P2PSocketType type, |
| 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( |
| 472 message_sender, socket_id, render_process_host_id, throttler); | |
| 456 case P2P_SOCKET_TCP_SERVER: | 473 case P2P_SOCKET_TCP_SERVER: |
| 457 return new P2PSocketHostTcpServer( | 474 return new P2PSocketHostTcpServer(message_sender, |
| 458 message_sender, id, P2P_SOCKET_TCP_CLIENT); | 475 socket_id, |
| 476 render_process_host_id, | |
| 477 P2P_SOCKET_TCP_CLIENT); | |
| 459 | 478 |
| 460 case P2P_SOCKET_STUN_TCP_SERVER: | 479 case P2P_SOCKET_STUN_TCP_SERVER: |
| 461 return new P2PSocketHostTcpServer( | 480 return new P2PSocketHostTcpServer(message_sender, |
| 462 message_sender, id, P2P_SOCKET_STUN_TCP_CLIENT); | 481 socket_id, |
| 482 render_process_host_id, | |
| 483 P2P_SOCKET_STUN_TCP_CLIENT); | |
| 463 | 484 |
| 464 case P2P_SOCKET_TCP_CLIENT: | 485 case P2P_SOCKET_TCP_CLIENT: |
| 465 case P2P_SOCKET_SSLTCP_CLIENT: | 486 case P2P_SOCKET_SSLTCP_CLIENT: |
| 466 case P2P_SOCKET_TLS_CLIENT: | 487 case P2P_SOCKET_TLS_CLIENT: |
| 467 return new P2PSocketHostTcp(message_sender, id, type, url_context); | 488 return new P2PSocketHostTcp( |
| 489 message_sender, socket_id, render_process_host_id, type, url_context); | |
| 468 | 490 |
| 469 case P2P_SOCKET_STUN_TCP_CLIENT: | 491 case P2P_SOCKET_STUN_TCP_CLIENT: |
| 470 case P2P_SOCKET_STUN_SSLTCP_CLIENT: | 492 case P2P_SOCKET_STUN_SSLTCP_CLIENT: |
| 471 case P2P_SOCKET_STUN_TLS_CLIENT: | 493 case P2P_SOCKET_STUN_TLS_CLIENT: |
| 472 return new P2PSocketHostStunTcp(message_sender, id, type, url_context); | 494 return new P2PSocketHostStunTcp( |
| 495 message_sender, socket_id, render_process_host_id, type, url_context); | |
| 473 } | 496 } |
| 474 | 497 |
| 475 NOTREACHED(); | 498 NOTREACHED(); |
| 476 return NULL; | 499 return NULL; |
| 477 } | 500 } |
| 478 | 501 |
| 502 void P2PSocketHost::StartRtpDump(bool incoming, bool outgoing) { | |
| 503 dump_incoming_rtp_packet_ = incoming; | |
| 504 dump_outgoing_rtp_packet_ = outgoing; | |
| 505 } | |
| 506 | |
| 507 void P2PSocketHost::StopRtpDump(bool incoming, bool outgoing) { | |
| 508 dump_incoming_rtp_packet_ = !incoming; | |
| 509 dump_outgoing_rtp_packet_ = !outgoing; | |
| 510 } | |
| 511 | |
| 512 // static | |
| 513 void P2PSocketHost::DumpRtpPacketOnUIThread(scoped_ptr<char[]> packet_header, | |
| 514 size_t header_length, | |
| 515 size_t packet_length, | |
| 516 bool incoming, | |
| 517 int render_process_host_id) { | |
| 518 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 519 | |
| 520 content::RenderProcessHostImpl* render_process_host_impl = | |
| 521 static_cast<content::RenderProcessHostImpl*>( | |
| 522 content::RenderProcessHost::FromID(render_process_host_id)); | |
| 523 | |
| 524 if (render_process_host_impl) { | |
| 525 render_process_host_impl->OnRtpPacket( | |
| 526 reinterpret_cast<const uint8*>(packet_header.get()), | |
| 527 header_length, | |
| 528 packet_length, | |
| 529 incoming); | |
| 530 } | |
| 531 } | |
| 532 | |
| 533 void P2PSocketHost::DumpRtpPacket(const char* packet, | |
| 534 size_t length, | |
| 535 bool incoming) { | |
| 536 if (IsDtlsPacket(packet, length) || IsRtcpPacket(packet)) | |
| 537 return; | |
| 538 | |
| 539 int rtp_packet_pos = 0; | |
| 540 int rtp_packet_length = length; | |
| 541 if (!packet_processing_helpers::GetRtpPacketStartPositionAndLength( | |
| 542 packet, length, &rtp_packet_pos, &rtp_packet_length)) | |
| 543 return; | |
| 544 | |
| 545 packet += rtp_packet_pos; | |
| 546 | |
| 547 size_t header_length = 0; | |
| 548 bool valid = ValidateRtpHeader(packet, rtp_packet_length, &header_length); | |
| 549 if (!valid) | |
| 550 return; | |
|
Mallinath (Gone from Chromium)
2014/05/14 00:57:01
add a DCHECK before returning.
jiayl
2014/05/14 18:59:12
Done.
| |
| 551 | |
| 552 scoped_ptr<char[]> header_copy(new char[header_length]); | |
| 553 memcpy(header_copy.get(), packet, header_length); | |
| 554 | |
| 555 BrowserThread::PostTask(BrowserThread::UI, | |
| 556 FROM_HERE, | |
| 557 base::Bind(&P2PSocketHost::DumpRtpPacketOnUIThread, | |
| 558 base::Passed(&header_copy), | |
| 559 header_length, | |
| 560 length, | |
| 561 incoming, | |
| 562 render_process_host_id_)); | |
| 563 } | |
| 564 | |
| 479 } // namespace content | 565 } // namespace content |
| OLD | NEW |