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

Side by Side Diff: content/browser/renderer_host/pepper/pepper_message_filter.cc

Issue 10993078: Use extensions socket permission for TCP/UDP socket APIs in Pepper (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fixed Android build Created 8 years, 1 month 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/pepper/pepper_message_filter.h" 5 #include "content/browser/renderer_host/pepper/pepper_message_filter.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/bind_helpers.h" 8 #include "base/bind_helpers.h"
9 #include "base/callback.h" 9 #include "base/callback.h"
10 #include "base/compiler_specific.h" 10 #include "base/compiler_specific.h"
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after
110 host_resolver_(host_resolver), 110 host_resolver_(host_resolver),
111 next_socket_id_(1), 111 next_socket_id_(1),
112 incognito_(false) { 112 incognito_(false) {
113 DCHECK(type == PLUGIN); 113 DCHECK(type == PLUGIN);
114 DCHECK(host_resolver); 114 DCHECK(host_resolver);
115 } 115 }
116 116
117 void PepperMessageFilter::OverrideThreadForMessage( 117 void PepperMessageFilter::OverrideThreadForMessage(
118 const IPC::Message& message, 118 const IPC::Message& message,
119 BrowserThread::ID* thread) { 119 BrowserThread::ID* thread) {
120 if (message.type() == PpapiHostMsg_PPBTCPSocket_Connect::ID || 120 if (message.type() == PpapiHostMsg_PPBTCPServerSocket_Listen::ID ||
121 message.type() == PpapiHostMsg_PPBTCPSocket_Connect::ID ||
121 message.type() == PpapiHostMsg_PPBTCPSocket_ConnectWithNetAddress::ID || 122 message.type() == PpapiHostMsg_PPBTCPSocket_ConnectWithNetAddress::ID ||
122 message.type() == PpapiHostMsg_PPBUDPSocket_Bind::ID || 123 message.type() == PpapiHostMsg_PPBUDPSocket_Bind::ID ||
123 message.type() == PpapiHostMsg_PPBTCPServerSocket_Listen::ID || 124 message.type() == PpapiHostMsg_PPBUDPSocket_SendTo::ID) {
124 message.type() == PpapiHostMsg_PPBHostResolver_Resolve::ID) {
125 *thread = BrowserThread::UI; 125 *thread = BrowserThread::UI;
126 } else if (message.type() == PepperMsg_GetDeviceID::ID) { 126 } else if (message.type() == PepperMsg_GetDeviceID::ID) {
127 *thread = BrowserThread::FILE; 127 *thread = BrowserThread::FILE;
128 } 128 }
129 } 129 }
130 130
131 bool PepperMessageFilter::OnMessageReceived(const IPC::Message& msg, 131 bool PepperMessageFilter::OnMessageReceived(const IPC::Message& msg,
132 bool* message_was_ok) { 132 bool* message_was_ok) {
133 bool handled = true; 133 bool handled = true;
134 IPC_BEGIN_MESSAGE_MAP_EX(PepperMessageFilter, msg, *message_was_ok) 134 IPC_BEGIN_MESSAGE_MAP_EX(PepperMessageFilter, msg, *message_was_ok)
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after
278 278
279 tcp_sockets_[*socket_id] = linked_ptr<PepperTCPSocket>( 279 tcp_sockets_[*socket_id] = linked_ptr<PepperTCPSocket>(
280 new PepperTCPSocket(this, routing_id, plugin_dispatcher_id, *socket_id)); 280 new PepperTCPSocket(this, routing_id, plugin_dispatcher_id, *socket_id));
281 } 281 }
282 282
283 void PepperMessageFilter::OnTCPConnect(int32 routing_id, 283 void PepperMessageFilter::OnTCPConnect(int32 routing_id,
284 uint32 socket_id, 284 uint32 socket_id,
285 const std::string& host, 285 const std::string& host,
286 uint16_t port) { 286 uint16_t port) {
287 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 287 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
288 content::SocketPermissionRequest params(
289 content::SocketPermissionRequest::TCP_CONNECT, host, port);
290 bool allowed = CanUseSocketAPIs(routing_id, params);
288 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, 291 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
289 base::Bind(&PepperMessageFilter::DoTCPConnect, this, 292 base::Bind(&PepperMessageFilter::DoTCPConnect, this,
290 CanUseSocketAPIs(routing_id), routing_id, socket_id, host, port)); 293 allowed, routing_id, socket_id, host, port));
291 } 294 }
292 295
293 void PepperMessageFilter::DoTCPConnect(bool allowed, 296 void PepperMessageFilter::DoTCPConnect(bool allowed,
294 int32 routing_id, 297 int32 routing_id,
295 uint32 socket_id, 298 uint32 socket_id,
296 const std::string& host, 299 const std::string& host,
297 uint16_t port) { 300 uint16_t port) {
298 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 301 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
299 TCPSocketMap::iterator iter = tcp_sockets_.find(socket_id); 302 TCPSocketMap::iterator iter = tcp_sockets_.find(socket_id);
300 if (iter == tcp_sockets_.end()) { 303 if (iter == tcp_sockets_.end()) {
301 NOTREACHED(); 304 NOTREACHED();
302 return; 305 return;
303 } 306 }
304 307
305 if (routing_id == iter->second->routing_id() && allowed) 308 if (routing_id == iter->second->routing_id() && allowed)
306 iter->second->Connect(host, port); 309 iter->second->Connect(host, port);
307 else 310 else
308 iter->second->SendConnectACKError(); 311 iter->second->SendConnectACKError();
309 } 312 }
310 313
311 void PepperMessageFilter::OnTCPConnectWithNetAddress( 314 void PepperMessageFilter::OnTCPConnectWithNetAddress(
312 int32 routing_id, 315 int32 routing_id,
313 uint32 socket_id, 316 uint32 socket_id,
314 const PP_NetAddress_Private& net_addr) { 317 const PP_NetAddress_Private& net_addr) {
315 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 318 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
319 bool allowed = CanUseSocketAPIs(routing_id, CreateSocketPermissionRequest(
320 content::SocketPermissionRequest::TCP_CONNECT, net_addr));
316 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, 321 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
317 base::Bind(&PepperMessageFilter::DoTCPConnectWithNetAddress, this, 322 base::Bind(&PepperMessageFilter::DoTCPConnectWithNetAddress, this,
318 CanUseSocketAPIs(routing_id), routing_id, socket_id, net_addr)); 323 allowed, routing_id, socket_id, net_addr));
319 } 324 }
320 325
321 void PepperMessageFilter::DoTCPConnectWithNetAddress( 326 void PepperMessageFilter::DoTCPConnectWithNetAddress(
322 bool allowed, 327 bool allowed,
323 int32 routing_id, 328 int32 routing_id,
324 uint32 socket_id, 329 uint32 socket_id,
325 const PP_NetAddress_Private& net_addr) { 330 const PP_NetAddress_Private& net_addr) {
326 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 331 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
327 TCPSocketMap::iterator iter = tcp_sockets_.find(socket_id); 332 TCPSocketMap::iterator iter = tcp_sockets_.find(socket_id);
328 if (iter == tcp_sockets_.end()) { 333 if (iter == tcp_sockets_.end()) {
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
424 default: 429 default:
425 NOTREACHED(); 430 NOTREACHED();
426 break; 431 break;
427 } 432 }
428 } 433 }
429 434
430 void PepperMessageFilter::OnUDPBind(int32 routing_id, 435 void PepperMessageFilter::OnUDPBind(int32 routing_id,
431 uint32 socket_id, 436 uint32 socket_id,
432 const PP_NetAddress_Private& addr) { 437 const PP_NetAddress_Private& addr) {
433 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 438 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
439 bool allowed = CanUseSocketAPIs(routing_id, CreateSocketPermissionRequest(
440 content::SocketPermissionRequest::UDP_BIND, addr));
434 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, 441 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
435 base::Bind(&PepperMessageFilter::DoUDPBind, this, 442 base::Bind(&PepperMessageFilter::DoUDPBind, this,
436 CanUseSocketAPIs(routing_id), routing_id, socket_id, addr)); 443 allowed, routing_id, socket_id, addr));
437 } 444 }
438 445
439 void PepperMessageFilter::DoUDPBind(bool allowed, 446 void PepperMessageFilter::DoUDPBind(bool allowed,
440 int32 routing_id, 447 int32 routing_id,
441 uint32 socket_id, 448 uint32 socket_id,
442 const PP_NetAddress_Private& addr) { 449 const PP_NetAddress_Private& addr) {
443 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 450 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
444 UDPSocketMap::iterator iter = udp_sockets_.find(socket_id); 451 UDPSocketMap::iterator iter = udp_sockets_.find(socket_id);
445 if (iter == udp_sockets_.end()) { 452 if (iter == udp_sockets_.end()) {
446 NOTREACHED(); 453 NOTREACHED();
447 return; 454 return;
448 } 455 }
449 456
450 if (routing_id == iter->second->routing_id() && allowed) 457 if (routing_id == iter->second->routing_id() && allowed)
451 iter->second->Bind(addr); 458 iter->second->Bind(addr);
452 else 459 else
453 iter->second->SendBindACKError(); 460 iter->second->SendBindACKError();
454 } 461 }
455 462
456 void PepperMessageFilter::OnUDPRecvFrom(uint32 socket_id, int32_t num_bytes) { 463 void PepperMessageFilter::OnUDPRecvFrom(uint32 socket_id, int32_t num_bytes) {
457 UDPSocketMap::iterator iter = udp_sockets_.find(socket_id); 464 UDPSocketMap::iterator iter = udp_sockets_.find(socket_id);
458 if (iter == udp_sockets_.end()) { 465 if (iter == udp_sockets_.end()) {
459 NOTREACHED(); 466 NOTREACHED();
460 return; 467 return;
461 } 468 }
462 469
463 iter->second->RecvFrom(num_bytes); 470 iter->second->RecvFrom(num_bytes);
464 } 471 }
465 472
466 void PepperMessageFilter::OnUDPSendTo(uint32 socket_id, 473 void PepperMessageFilter::OnUDPSendTo(int32 routing_id,
474 uint32 socket_id,
467 const std::string& data, 475 const std::string& data,
468 const PP_NetAddress_Private& addr) { 476 const PP_NetAddress_Private& addr) {
477 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
478 bool allowed = CanUseSocketAPIs(routing_id, CreateSocketPermissionRequest(
479 content::SocketPermissionRequest::UDP_SEND_TO, addr));
480 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
481 base::Bind(&PepperMessageFilter::DoUDPSendTo, this,
482 allowed, routing_id, socket_id, data, addr));
483
484 }
485
486 void PepperMessageFilter::DoUDPSendTo(bool allowed,
487 int32 routing_id,
488 uint32 socket_id,
489 const std::string& data,
490 const PP_NetAddress_Private& addr) {
491 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
469 UDPSocketMap::iterator iter = udp_sockets_.find(socket_id); 492 UDPSocketMap::iterator iter = udp_sockets_.find(socket_id);
470 if (iter == udp_sockets_.end()) { 493 if (iter == udp_sockets_.end()) {
471 NOTREACHED(); 494 NOTREACHED();
472 return; 495 return;
473 } 496 }
474 497
475 iter->second->SendTo(data, addr); 498 if (routing_id == iter->second->routing_id() && allowed)
499 iter->second->SendTo(data, addr);
500 else
501 iter->second->SendSendToACKError();
476 } 502 }
477 503
478 void PepperMessageFilter::OnUDPClose(uint32 socket_id) { 504 void PepperMessageFilter::OnUDPClose(uint32 socket_id) {
479 UDPSocketMap::iterator iter = udp_sockets_.find(socket_id); 505 UDPSocketMap::iterator iter = udp_sockets_.find(socket_id);
480 if (iter == udp_sockets_.end()) { 506 if (iter == udp_sockets_.end()) {
481 NOTREACHED(); 507 NOTREACHED();
482 return; 508 return;
483 } 509 }
484 510
485 // Destroy the UDPSocket instance will cancel any pending completion 511 // Destroy the UDPSocket instance will cancel any pending completion
486 // callback. From this point on, there won't be any messages associated with 512 // callback. From this point on, there won't be any messages associated with
487 // this socket sent to the plugin side. 513 // this socket sent to the plugin side.
488 udp_sockets_.erase(iter); 514 udp_sockets_.erase(iter);
489 } 515 }
490 516
491 void PepperMessageFilter::OnTCPServerListen(int32 routing_id, 517 void PepperMessageFilter::OnTCPServerListen(int32 routing_id,
492 uint32 plugin_dispatcher_id, 518 uint32 plugin_dispatcher_id,
493 PP_Resource socket_resource, 519 PP_Resource socket_resource,
494 const PP_NetAddress_Private& addr, 520 const PP_NetAddress_Private& addr,
495 int32_t backlog) { 521 int32_t backlog) {
496 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 522 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
523 bool allowed = CanUseSocketAPIs(routing_id, CreateSocketPermissionRequest(
524 content::SocketPermissionRequest::TCP_LISTEN, addr));
497 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, 525 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
498 base::Bind(&PepperMessageFilter::DoTCPServerListen, 526 base::Bind(&PepperMessageFilter::DoTCPServerListen,
499 this, 527 this,
500 CanUseSocketAPIs(routing_id), 528 allowed,
501 routing_id, 529 routing_id,
502 plugin_dispatcher_id, 530 plugin_dispatcher_id,
503 socket_resource, 531 socket_resource,
504 addr, 532 addr,
505 backlog)); 533 backlog));
506 } 534 }
507 535
508 void PepperMessageFilter::DoTCPServerListen(bool allowed, 536 void PepperMessageFilter::DoTCPServerListen(bool allowed,
509 int32 routing_id, 537 int32 routing_id,
510 uint32 plugin_dispatcher_id, 538 uint32 plugin_dispatcher_id,
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
545 } 573 }
546 iter->second->Accept(tcp_client_socket_routing_id); 574 iter->second->Accept(tcp_client_socket_routing_id);
547 } 575 }
548 576
549 void PepperMessageFilter::OnHostResolverResolve( 577 void PepperMessageFilter::OnHostResolverResolve(
550 int32 routing_id, 578 int32 routing_id,
551 uint32 plugin_dispatcher_id, 579 uint32 plugin_dispatcher_id,
552 uint32 host_resolver_id, 580 uint32 host_resolver_id,
553 const ppapi::HostPortPair& host_port, 581 const ppapi::HostPortPair& host_port,
554 const PP_HostResolver_Private_Hint& hint) { 582 const PP_HostResolver_Private_Hint& hint) {
555 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
556 BrowserThread::PostTask(
557 BrowserThread::IO, FROM_HERE,
558 base::Bind(&PepperMessageFilter::DoHostResolverResolve, this,
559 CanUseSocketAPIs(routing_id),
560 routing_id,
561 plugin_dispatcher_id,
562 host_resolver_id,
563 host_port,
564 hint));
565 }
566
567 void PepperMessageFilter::DoHostResolverResolve(
568 bool allowed,
569 int32 routing_id,
570 uint32 plugin_dispatcher_id,
571 uint32 host_resolver_id,
572 const ppapi::HostPortPair& host_port,
573 const PP_HostResolver_Private_Hint& hint) {
574 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 583 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
575 if (!allowed) {
576 SendHostResolverResolveACKError(routing_id,
577 plugin_dispatcher_id,
578 host_resolver_id);
579 return;
580 }
581
582 net::HostResolver::RequestInfo request_info( 584 net::HostResolver::RequestInfo request_info(
583 net::HostPortPair(host_port.host, host_port.port)); 585 net::HostPortPair(host_port.host, host_port.port));
584 586
585 net::AddressFamily address_family; 587 net::AddressFamily address_family;
586 switch (hint.family) { 588 switch (hint.family) {
587 case PP_NETADDRESSFAMILY_IPV4: 589 case PP_NETADDRESSFAMILY_IPV4:
588 address_family = net::ADDRESS_FAMILY_IPV4; 590 address_family = net::ADDRESS_FAMILY_IPV4;
589 break; 591 break;
590 case PP_NETADDRESSFAMILY_IPV6: 592 case PP_NETADDRESSFAMILY_IPV6:
591 address_family = net::ADDRESS_FAMILY_IPV6; 593 address_family = net::ADDRESS_FAMILY_IPV6;
(...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after
802 // the counter overflows. 804 // the counter overflows.
803 socket_id = next_socket_id_++; 805 socket_id = next_socket_id_++;
804 } while (socket_id == kInvalidSocketID || 806 } while (socket_id == kInvalidSocketID ||
805 tcp_sockets_.find(socket_id) != tcp_sockets_.end() || 807 tcp_sockets_.find(socket_id) != tcp_sockets_.end() ||
806 udp_sockets_.find(socket_id) != udp_sockets_.end() || 808 udp_sockets_.find(socket_id) != udp_sockets_.end() ||
807 tcp_server_sockets_.find(socket_id) != tcp_server_sockets_.end()); 809 tcp_server_sockets_.find(socket_id) != tcp_server_sockets_.end());
808 810
809 return socket_id; 811 return socket_id;
810 } 812 }
811 813
812 bool PepperMessageFilter::CanUseSocketAPIs(int32 render_id) { 814 bool PepperMessageFilter::CanUseSocketAPIs(int32 render_id,
815 const content::SocketPermissionRequest& params) {
813 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 816 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
814 if (process_type_ == PLUGIN) { 817 if (process_type_ == PLUGIN) {
815 // Always allow socket APIs for out-process plugins. 818 // Always allow socket APIs for out-process plugins.
816 return true; 819 return true;
817 } 820 }
818 821
819 RenderViewHostImpl* render_view_host = 822 RenderViewHostImpl* render_view_host =
820 RenderViewHostImpl::FromID(process_id_, render_id); 823 RenderViewHostImpl::FromID(process_id_, render_id);
821 if (!render_view_host) 824 if (!render_view_host)
822 return false; 825 return false;
823 826
824 SiteInstance* site_instance = render_view_host->GetSiteInstance(); 827 SiteInstance* site_instance = render_view_host->GetSiteInstance();
825 if (!site_instance) 828 if (!site_instance)
826 return false; 829 return false;
827 830
828 if (!GetContentClient()->browser()->AllowPepperSocketAPI( 831 if (!GetContentClient()->browser()->AllowPepperSocketAPI(
829 site_instance->GetBrowserContext(), 832 site_instance->GetBrowserContext(),
830 site_instance->GetSiteURL())) { 833 site_instance->GetSiteURL(),
834 params)) {
831 LOG(ERROR) << "Host " << site_instance->GetSiteURL().host() 835 LOG(ERROR) << "Host " << site_instance->GetSiteURL().host()
832 << " cannot use socket API"; 836 << " cannot use socket API or destination is not allowed";
833 return false; 837 return false;
834 } 838 }
835 839
836 return true; 840 return true;
837 } 841 }
838 842
843 content::SocketPermissionRequest
844 PepperMessageFilter::CreateSocketPermissionRequest(
845 content::SocketPermissionRequest::OperationType type,
846 const PP_NetAddress_Private& net_addr) {
847 std::string host = NetAddressPrivateImpl::DescribeNetAddress(net_addr, false);
848 int port = 0;
849 std::vector<unsigned char> address;
850 NetAddressPrivateImpl::NetAddressToIPEndPoint(net_addr, &address, &port);
851 return content::SocketPermissionRequest(type, host, port);
852 }
853
839 void PepperMessageFilter::GetAndSendNetworkList() { 854 void PepperMessageFilter::GetAndSendNetworkList() {
840 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 855 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
841 856
842 BrowserThread::PostBlockingPoolTask( 857 BrowserThread::PostBlockingPoolTask(
843 FROM_HERE, base::Bind(&PepperMessageFilter::DoGetNetworkList, this)); 858 FROM_HERE, base::Bind(&PepperMessageFilter::DoGetNetworkList, this));
844 } 859 }
845 860
846 void PepperMessageFilter::DoGetNetworkList() { 861 void PepperMessageFilter::DoGetNetworkList() {
847 scoped_ptr<net::NetworkInterfaceList> list(new net::NetworkInterfaceList()); 862 scoped_ptr<net::NetworkInterfaceList> list(new net::NetworkInterfaceList());
848 net::GetNetworkList(list.get()); 863 net::GetNetworkList(list.get());
(...skipping 28 matching lines...) Expand all
877 network_copy.mtu = 0; 892 network_copy.mtu = 0;
878 } 893 }
879 for (NetworkMonitorIdSet::iterator it = network_monitor_ids_.begin(); 894 for (NetworkMonitorIdSet::iterator it = network_monitor_ids_.begin();
880 it != network_monitor_ids_.end(); ++it) { 895 it != network_monitor_ids_.end(); ++it) {
881 Send(new PpapiMsg_PPBNetworkMonitor_NetworkList( 896 Send(new PpapiMsg_PPBNetworkMonitor_NetworkList(
882 ppapi::API_ID_PPB_NETWORKMANAGER_PRIVATE, *it, *list_copy)); 897 ppapi::API_ID_PPB_NETWORKMANAGER_PRIVATE, *it, *list_copy));
883 } 898 }
884 } 899 }
885 900
886 } // namespace content 901 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/renderer_host/pepper/pepper_message_filter.h ('k') | content/browser/renderer_host/pepper/pepper_udp_socket.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698