 Chromium Code Reviews
 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 "net/udp/udp_socket_libevent.h" | 5 #include "net/udp/udp_socket_libevent.h" | 
| 6 | 6 | 
| 7 #include <errno.h> | 7 #include <errno.h> | 
| 8 #include <fcntl.h> | 8 #include <fcntl.h> | 
| 9 #include <netdb.h> | 9 #include <netdb.h> | 
| 10 #include <sys/socket.h> | 10 #include <sys/socket.h> | 
| (...skipping 23 matching lines...) Expand all Loading... | |
| 34 } // namespace net | 34 } // namespace net | 
| 35 | 35 | 
| 36 namespace net { | 36 namespace net { | 
| 37 | 37 | 
| 38 UDPSocketLibevent::UDPSocketLibevent( | 38 UDPSocketLibevent::UDPSocketLibevent( | 
| 39 DatagramSocket::BindType bind_type, | 39 DatagramSocket::BindType bind_type, | 
| 40 const RandIntCallback& rand_int_cb, | 40 const RandIntCallback& rand_int_cb, | 
| 41 net::NetLog* net_log, | 41 net::NetLog* net_log, | 
| 42 const net::NetLog::Source& source) | 42 const net::NetLog::Source& source) | 
| 43 : socket_(kInvalidSocket), | 43 : socket_(kInvalidSocket), | 
| 44 sock_addr_family_(0), | |
| 44 socket_options_(0), | 45 socket_options_(0), | 
| 46 multicast_time_to_live_(1), | |
| 47 multicast_loopback_mode_(true), | |
| 45 bind_type_(bind_type), | 48 bind_type_(bind_type), | 
| 46 rand_int_cb_(rand_int_cb), | 49 rand_int_cb_(rand_int_cb), | 
| 47 read_watcher_(this), | 50 read_watcher_(this), | 
| 48 write_watcher_(this), | 51 write_watcher_(this), | 
| 49 read_buf_len_(0), | 52 read_buf_len_(0), | 
| 50 recv_from_address_(NULL), | 53 recv_from_address_(NULL), | 
| 51 write_buf_len_(0), | 54 write_buf_len_(0), | 
| 52 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_UDP_SOCKET)) { | 55 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_UDP_SOCKET)) { | 
| 53 net_log_.BeginEvent(NetLog::TYPE_SOCKET_ALIVE, | 56 net_log_.BeginEvent(NetLog::TYPE_SOCKET_ALIVE, | 
| 54 source.ToEventParametersCallback()); | 57 source.ToEventParametersCallback()); | 
| (...skipping 301 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 356 CreateNetLogUDPDataTranferCallback( | 359 CreateNetLogUDPDataTranferCallback( | 
| 357 result, bytes, | 360 result, bytes, | 
| 358 is_address_valid ? &address : NULL)); | 361 is_address_valid ? &address : NULL)); | 
| 359 } | 362 } | 
| 360 | 363 | 
| 361 base::StatsCounter read_bytes("udp.read_bytes"); | 364 base::StatsCounter read_bytes("udp.read_bytes"); | 
| 362 read_bytes.Add(result); | 365 read_bytes.Add(result); | 
| 363 } | 366 } | 
| 364 | 367 | 
| 365 int UDPSocketLibevent::CreateSocket(const IPEndPoint& address) { | 368 int UDPSocketLibevent::CreateSocket(const IPEndPoint& address) { | 
| 366 socket_ = socket(address.GetSockAddrFamily(), SOCK_DGRAM, 0); | 369 sock_addr_family_ = address.GetSockAddrFamily(); | 
| 370 socket_ = socket(sock_addr_family_, SOCK_DGRAM, 0); | |
| 367 if (socket_ == kInvalidSocket) | 371 if (socket_ == kInvalidSocket) | 
| 368 return MapSystemError(errno); | 372 return MapSystemError(errno); | 
| 369 if (SetNonBlocking(socket_)) { | 373 if (SetNonBlocking(socket_)) { | 
| 370 const int err = MapSystemError(errno); | 374 const int err = MapSystemError(errno); | 
| 371 Close(); | 375 Close(); | 
| 372 return err; | 376 return err; | 
| 373 } | 377 } | 
| 374 return OK; | 378 return OK; | 
| 375 } | 379 } | 
| 376 | 380 | 
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 469 return MapSystemError(errno); | 473 return MapSystemError(errno); | 
| 470 } | 474 } | 
| 471 if (socket_options_ & SOCKET_OPTION_BROADCAST) { | 475 if (socket_options_ & SOCKET_OPTION_BROADCAST) { | 
| 472 int rv; | 476 int rv; | 
| 473 #if defined(OS_MACOSX) | 477 #if defined(OS_MACOSX) | 
| 474 // SO_REUSEPORT on OSX permits multiple processes to each receive | 478 // SO_REUSEPORT on OSX permits multiple processes to each receive | 
| 475 // UDP multicast or broadcast datagrams destined for the bound | 479 // UDP multicast or broadcast datagrams destined for the bound | 
| 476 // port. | 480 // port. | 
| 477 rv = setsockopt(socket_, SOL_SOCKET, SO_REUSEPORT, &true_value, | 481 rv = setsockopt(socket_, SOL_SOCKET, SO_REUSEPORT, &true_value, | 
| 478 sizeof(true_value)); | 482 sizeof(true_value)); | 
| 483 #else | |
| 484 rv = setsockopt(socket_, SOL_SOCKET, SO_BROADCAST, &true_value, | |
| 485 sizeof(true_value)); | |
| 
mmenke
2013/04/16 18:09:49
This needs to be done on OSX, too.
 
Bei Zhang
2013/04/17 17:53:03
It's done in the other #if branch.
 | |
| 486 #endif // defined(OS_MACOSX) | |
| 479 if (rv < 0) | 487 if (rv < 0) | 
| 480 return MapSystemError(errno); | 488 return MapSystemError(errno); | 
| 481 #endif // defined(OS_MACOSX) | 489 } | 
| 482 rv = setsockopt(socket_, SOL_SOCKET, SO_BROADCAST, &true_value, | 490 if (multicast_time_to_live_ != 1) { | 
| 483 sizeof(true_value)); | 491 int rv = SetMulticastTimeToLive(multicast_time_to_live_); | 
| 484 if (rv < 0) | 492 if (rv != OK) | 
| 485 return MapSystemError(errno); | 493 return rv; | 
| 494 } | |
| 495 if (!multicast_loopback_mode_) { | |
| 496 int rv = SetMulticastLoopbackMode(multicast_loopback_mode_); | |
| 497 if (rv != OK) | |
| 498 return rv; | |
| 486 } | 499 } | 
| 487 return OK; | 500 return OK; | 
| 488 } | 501 } | 
| 489 | 502 | 
| 490 int UDPSocketLibevent::DoBind(const IPEndPoint& address) { | 503 int UDPSocketLibevent::DoBind(const IPEndPoint& address) { | 
| 491 SockaddrStorage storage; | 504 SockaddrStorage storage; | 
| 492 if (!address.ToSockAddr(storage.addr, &storage.addr_len)) | 505 if (!address.ToSockAddr(storage.addr, &storage.addr_len)) | 
| 493 return ERR_UNEXPECTED; | 506 return ERR_UNEXPECTED; | 
| 494 int rv = bind(socket_, storage.addr, storage.addr_len); | 507 int rv = bind(socket_, storage.addr, storage.addr_len); | 
| 495 return rv < 0 ? MapSystemError(errno) : rv; | 508 return rv < 0 ? MapSystemError(errno) : rv; | 
| 496 } | 509 } | 
| 497 | 510 | 
| 498 int UDPSocketLibevent::RandomBind(const IPEndPoint& address) { | 511 int UDPSocketLibevent::RandomBind(const IPEndPoint& address) { | 
| 499 DCHECK(bind_type_ == DatagramSocket::RANDOM_BIND && !rand_int_cb_.is_null()); | 512 DCHECK(bind_type_ == DatagramSocket::RANDOM_BIND && !rand_int_cb_.is_null()); | 
| 500 | 513 | 
| 501 // Construct IPAddressNumber of appropriate size (IPv4 or IPv6) of 0s. | 514 // Construct IPAddressNumber of appropriate size (IPv4 or IPv6) of 0s. | 
| 502 IPAddressNumber ip(address.address().size()); | 515 IPAddressNumber ip(address.address().size()); | 
| 503 | 516 | 
| 504 for (int i = 0; i < kBindRetries; ++i) { | 517 for (int i = 0; i < kBindRetries; ++i) { | 
| 505 int rv = DoBind(IPEndPoint(ip, rand_int_cb_.Run(kPortStart, kPortEnd))); | 518 int rv = DoBind(IPEndPoint(ip, rand_int_cb_.Run(kPortStart, kPortEnd))); | 
| 506 if (rv == OK || rv != ERR_ADDRESS_IN_USE) | 519 if (rv == OK || rv != ERR_ADDRESS_IN_USE) | 
| 507 return rv; | 520 return rv; | 
| 508 } | 521 } | 
| 509 return DoBind(IPEndPoint(ip, 0)); | 522 return DoBind(IPEndPoint(ip, 0)); | 
| 510 } | 523 } | 
| 511 | 524 | 
| 525 int UDPSocketLibevent::JoinGroup( | |
| 526 const net::IPAddressNumber& group_address) const { | |
| 527 DCHECK(CalledOnValidThread()); | |
| 528 DCHECK(is_connected()); | |
| 529 | |
| 530 int rv = -1; | |
| 
mmenke
2013/04/16 18:09:49
Sending a -1 through MapSystemError on fall throug
 
Bei Zhang
2013/04/17 17:53:03
Done.
 | |
| 531 switch (group_address.size()) { | |
| 532 case kIPv4AddressSize: { | |
| 533 if (sock_addr_family_ != AF_INET) | |
| 534 return ERR_ADDRESS_INVALID; | |
| 535 ip_mreq mreq; | |
| 536 memset(&mreq, 0, sizeof(mreq)); | |
| 537 memcpy(&mreq.imr_multiaddr, &group_address[0], kIPv4AddressSize); | |
| 
mmenke
2013/04/16 18:09:49
Seems like we should be explicitely using IN_ADDRA
 
Bei Zhang
2013/04/17 17:53:03
Done.
 | |
| 538 rv = setsockopt(socket_, IPPROTO_IP, IP_ADD_MEMBERSHIP, | |
| 539 &mreq, sizeof(mreq)); | |
| 540 break; | |
| 541 } | |
| 542 case kIPv6AddressSize: { | |
| 543 if (sock_addr_family_ != AF_INET6) | |
| 544 return ERR_ADDRESS_INVALID; | |
| 545 ipv6_mreq mreq; | |
| 546 memset(&mreq, 0, sizeof(mreq)); | |
| 547 memcpy(&mreq.ipv6mr_multiaddr, &group_address[0], kIPv6AddressSize); | |
| 548 rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_JOIN_GROUP, | |
| 549 &mreq, sizeof(mreq)); | |
| 
mmenke
2013/04/16 18:09:49
Seems like we should be explicitely using in6addr_
 
Bei Zhang
2013/04/17 17:53:03
Done.
 | |
| 550 break; | |
| 551 } | |
| 552 } | |
| 553 | |
| 554 return MapSystemError(rv); | |
| 555 } | |
| 556 | |
| 557 int UDPSocketLibevent::LeaveGroup( | |
| 558 const net::IPAddressNumber& group_address) const { | |
| 559 DCHECK(CalledOnValidThread()); | |
| 560 DCHECK(is_connected()); | |
| 561 | |
| 562 int rv = -1; | |
| 563 switch (group_address.size()) { | |
| 564 case kIPv4AddressSize: { | |
| 565 if (sock_addr_family_ != AF_INET) | |
| 566 return ERR_ADDRESS_INVALID; | |
| 567 ip_mreq mreq; | |
| 568 memset(&mreq, 0, sizeof(mreq)); | |
| 569 memcpy(&mreq.imr_multiaddr, &group_address[0], kIPv4AddressSize); | |
| 570 rv = setsockopt(socket_, IPPROTO_IP, IP_DROP_MEMBERSHIP, | |
| 571 &mreq, sizeof(mreq)); | |
| 572 break; | |
| 573 } | |
| 574 case kIPv6AddressSize: { | |
| 575 if (sock_addr_family_ != AF_INET6) | |
| 576 return ERR_ADDRESS_INVALID; | |
| 577 ipv6_mreq mreq; | |
| 578 memset(&mreq, 0, sizeof(mreq)); | |
| 579 memcpy(&mreq.ipv6mr_multiaddr, &group_address[0], kIPv6AddressSize); | |
| 580 rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_LEAVE_GROUP, | |
| 581 &mreq, sizeof(mreq)); | |
| 582 break; | |
| 583 } | |
| 584 } | |
| 585 | |
| 586 return MapSystemError(rv); | |
| 587 } | |
| 588 | |
| 589 int UDPSocketLibevent::SetMulticastTimeToLive(int time_to_live) { | |
| 590 DCHECK(CalledOnValidThread()); | |
| 591 if (time_to_live < 0 || time_to_live > 255) | |
| 592 return ERR_INVALID_ARGUMENT; | |
| 593 if (is_connected()) { | |
| 
mmenke
2013/04/16 18:09:49
Do we need these to be dynamically configurable?
 
Bei Zhang
2013/04/17 17:53:03
I thought about this for a while. I think you are
 | |
| 594 uint8 ttl = time_to_live; | |
| 595 int ip_family = sock_addr_family_ == AF_INET ? IPPROTO_IP : IPPROTO_IPV6; | |
| 596 return MapSystemError(setsockopt(socket_, | |
| 597 ip_family, | |
| 598 IP_MULTICAST_TTL, | |
| 599 &ttl, sizeof(ttl))); | |
| 600 } else { | |
| 
mmenke
2013/04/16 18:09:49
Preferred style in Chrome is not to have an else h
 
Bei Zhang
2013/04/17 17:53:03
Done.
 | |
| 601 multicast_time_to_live_ = time_to_live; | |
| 602 return OK; | |
| 603 } | |
| 604 } | |
| 605 | |
| 606 int UDPSocketLibevent::SetMulticastLoopbackMode(bool loopback) { | |
| 607 DCHECK(CalledOnValidThread()); | |
| 608 if (is_connected()) { | |
| 609 uint8 loop = loopback; | |
| 610 int ip_family = sock_addr_family_ == AF_INET ? IPPROTO_IP : IPPROTO_IPV6; | |
| 611 return MapSystemError(setsockopt(socket_, | |
| 612 ip_family, | |
| 613 IP_MULTICAST_LOOP, | |
| 614 &loop, sizeof(loop))); | |
| 615 } else { | |
| 616 multicast_loopback_mode_ = loopback; | |
| 617 return OK; | |
| 618 } | |
| 619 } | |
| 512 } // namespace net | 620 } // namespace net | 
| OLD | NEW |