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 socket_options_(0), | 44 addr_family_(0), |
| 45 socket_options_(SOCKET_OPTION_MULTICAST_LOOP), |
| 46 multicast_time_to_live_(1), |
45 bind_type_(bind_type), | 47 bind_type_(bind_type), |
46 rand_int_cb_(rand_int_cb), | 48 rand_int_cb_(rand_int_cb), |
47 read_watcher_(this), | 49 read_watcher_(this), |
48 write_watcher_(this), | 50 write_watcher_(this), |
49 read_buf_len_(0), | 51 read_buf_len_(0), |
50 recv_from_address_(NULL), | 52 recv_from_address_(NULL), |
51 write_buf_len_(0), | 53 write_buf_len_(0), |
52 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_UDP_SOCKET)) { | 54 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_UDP_SOCKET)) { |
53 net_log_.BeginEvent(NetLog::TYPE_SOCKET_ALIVE, | 55 net_log_.BeginEvent(NetLog::TYPE_SOCKET_ALIVE, |
54 source.ToEventParametersCallback()); | 56 source.ToEventParametersCallback()); |
(...skipping 301 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
356 CreateNetLogUDPDataTranferCallback( | 358 CreateNetLogUDPDataTranferCallback( |
357 result, bytes, | 359 result, bytes, |
358 is_address_valid ? &address : NULL)); | 360 is_address_valid ? &address : NULL)); |
359 } | 361 } |
360 | 362 |
361 base::StatsCounter read_bytes("udp.read_bytes"); | 363 base::StatsCounter read_bytes("udp.read_bytes"); |
362 read_bytes.Add(result); | 364 read_bytes.Add(result); |
363 } | 365 } |
364 | 366 |
365 int UDPSocketLibevent::CreateSocket(const IPEndPoint& address) { | 367 int UDPSocketLibevent::CreateSocket(const IPEndPoint& address) { |
366 socket_ = socket(address.GetSockAddrFamily(), SOCK_DGRAM, 0); | 368 addr_family_ = address.GetSockAddrFamily(); |
| 369 socket_ = socket(addr_family_, SOCK_DGRAM, 0); |
367 if (socket_ == kInvalidSocket) | 370 if (socket_ == kInvalidSocket) |
368 return MapSystemError(errno); | 371 return MapSystemError(errno); |
369 if (SetNonBlocking(socket_)) { | 372 if (SetNonBlocking(socket_)) { |
370 const int err = MapSystemError(errno); | 373 const int err = MapSystemError(errno); |
371 Close(); | 374 Close(); |
372 return err; | 375 return err; |
373 } | 376 } |
374 return OK; | 377 return OK; |
375 } | 378 } |
376 | 379 |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
469 return MapSystemError(errno); | 472 return MapSystemError(errno); |
470 } | 473 } |
471 if (socket_options_ & SOCKET_OPTION_BROADCAST) { | 474 if (socket_options_ & SOCKET_OPTION_BROADCAST) { |
472 int rv; | 475 int rv; |
473 #if defined(OS_MACOSX) | 476 #if defined(OS_MACOSX) |
474 // SO_REUSEPORT on OSX permits multiple processes to each receive | 477 // SO_REUSEPORT on OSX permits multiple processes to each receive |
475 // UDP multicast or broadcast datagrams destined for the bound | 478 // UDP multicast or broadcast datagrams destined for the bound |
476 // port. | 479 // port. |
477 rv = setsockopt(socket_, SOL_SOCKET, SO_REUSEPORT, &true_value, | 480 rv = setsockopt(socket_, SOL_SOCKET, SO_REUSEPORT, &true_value, |
478 sizeof(true_value)); | 481 sizeof(true_value)); |
479 if (rv < 0) | 482 #else |
480 return MapSystemError(errno); | |
481 #endif // defined(OS_MACOSX) | |
482 rv = setsockopt(socket_, SOL_SOCKET, SO_BROADCAST, &true_value, | 483 rv = setsockopt(socket_, SOL_SOCKET, SO_BROADCAST, &true_value, |
483 sizeof(true_value)); | 484 sizeof(true_value)); |
| 485 #endif // defined(OS_MACOSX) |
484 if (rv < 0) | 486 if (rv < 0) |
485 return MapSystemError(errno); | 487 return MapSystemError(errno); |
486 } | 488 } |
| 489 |
| 490 if (!(socket_options_ & SOCKET_OPTION_MULTICAST_LOOP)) { |
| 491 int rv; |
| 492 if (addr_family_ == AF_INET) { |
| 493 u_char loop = 0; |
| 494 rv = setsockopt(socket_, IPPROTO_IP, IP_MULTICAST_LOOP, |
| 495 &loop, sizeof(loop)); |
| 496 } else { |
| 497 u_int loop = 0; |
| 498 rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, |
| 499 &loop, sizeof(loop)); |
| 500 } |
| 501 if (rv < 0) |
| 502 return MapSystemError(errno); |
| 503 } |
| 504 if (multicast_time_to_live_ != IP_DEFAULT_MULTICAST_TTL) { |
| 505 int rv; |
| 506 if (addr_family_ == AF_INET) { |
| 507 u_char ttl = multicast_time_to_live_; |
| 508 rv = setsockopt(socket_, IPPROTO_IP, IP_MULTICAST_TTL, |
| 509 &ttl, sizeof(ttl)); |
| 510 } else { |
| 511 // Signed interger. -1 to use route default. |
| 512 int ttl = multicast_time_to_live_; |
| 513 rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, |
| 514 &ttl, sizeof(ttl)); |
| 515 } |
| 516 if (rv < 0) |
| 517 return MapSystemError(errno); |
| 518 } |
487 return OK; | 519 return OK; |
488 } | 520 } |
489 | 521 |
490 int UDPSocketLibevent::DoBind(const IPEndPoint& address) { | 522 int UDPSocketLibevent::DoBind(const IPEndPoint& address) { |
491 SockaddrStorage storage; | 523 SockaddrStorage storage; |
492 if (!address.ToSockAddr(storage.addr, &storage.addr_len)) | 524 if (!address.ToSockAddr(storage.addr, &storage.addr_len)) |
493 return ERR_UNEXPECTED; | 525 return ERR_UNEXPECTED; |
494 int rv = bind(socket_, storage.addr, storage.addr_len); | 526 int rv = bind(socket_, storage.addr, storage.addr_len); |
495 return rv < 0 ? MapSystemError(errno) : rv; | 527 return rv < 0 ? MapSystemError(errno) : rv; |
496 } | 528 } |
497 | 529 |
498 int UDPSocketLibevent::RandomBind(const IPEndPoint& address) { | 530 int UDPSocketLibevent::RandomBind(const IPEndPoint& address) { |
499 DCHECK(bind_type_ == DatagramSocket::RANDOM_BIND && !rand_int_cb_.is_null()); | 531 DCHECK(bind_type_ == DatagramSocket::RANDOM_BIND && !rand_int_cb_.is_null()); |
500 | 532 |
501 // Construct IPAddressNumber of appropriate size (IPv4 or IPv6) of 0s. | 533 // Construct IPAddressNumber of appropriate size (IPv4 or IPv6) of 0s. |
502 IPAddressNumber ip(address.address().size()); | 534 IPAddressNumber ip(address.address().size()); |
503 | 535 |
504 for (int i = 0; i < kBindRetries; ++i) { | 536 for (int i = 0; i < kBindRetries; ++i) { |
505 int rv = DoBind(IPEndPoint(ip, rand_int_cb_.Run(kPortStart, kPortEnd))); | 537 int rv = DoBind(IPEndPoint(ip, rand_int_cb_.Run(kPortStart, kPortEnd))); |
506 if (rv == OK || rv != ERR_ADDRESS_IN_USE) | 538 if (rv == OK || rv != ERR_ADDRESS_IN_USE) |
507 return rv; | 539 return rv; |
508 } | 540 } |
509 return DoBind(IPEndPoint(ip, 0)); | 541 return DoBind(IPEndPoint(ip, 0)); |
510 } | 542 } |
511 | 543 |
| 544 int UDPSocketLibevent::JoinGroup(const IPAddressNumber& group_address) const { |
| 545 DCHECK(CalledOnValidThread()); |
| 546 DCHECK(is_connected()); |
| 547 |
| 548 switch (group_address.size()) { |
| 549 case kIPv4AddressSize: { |
| 550 if (addr_family_ != AF_INET) |
| 551 return ERR_ADDRESS_INVALID; |
| 552 ip_mreq mreq; |
| 553 mreq.imr_interface.s_addr = INADDR_ANY; |
| 554 memcpy(&mreq.imr_multiaddr, &group_address[0], kIPv4AddressSize); |
| 555 int rv = setsockopt(socket_, IPPROTO_IP, IP_ADD_MEMBERSHIP, |
| 556 &mreq, sizeof(mreq)); |
| 557 if (rv < 0) |
| 558 return MapSystemError(errno); |
| 559 return OK; |
| 560 } |
| 561 case kIPv6AddressSize: { |
| 562 if (addr_family_ != AF_INET6) |
| 563 return ERR_ADDRESS_INVALID; |
| 564 ipv6_mreq mreq; |
| 565 mreq.ipv6mr_interface = 0; // 0 indicates default multicast interface. |
| 566 memcpy(&mreq.ipv6mr_multiaddr, &group_address[0], kIPv6AddressSize); |
| 567 int rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_JOIN_GROUP, |
| 568 &mreq, sizeof(mreq)); |
| 569 if (rv < 0) |
| 570 return MapSystemError(errno); |
| 571 return OK; |
| 572 } |
| 573 default: |
| 574 NOTREACHED() << "Invalid address family"; |
| 575 return ERR_ADDRESS_INVALID; |
| 576 } |
| 577 } |
| 578 |
| 579 int UDPSocketLibevent::LeaveGroup(const IPAddressNumber& group_address) const { |
| 580 DCHECK(CalledOnValidThread()); |
| 581 DCHECK(is_connected()); |
| 582 |
| 583 switch (group_address.size()) { |
| 584 case kIPv4AddressSize: { |
| 585 if (addr_family_ != AF_INET) |
| 586 return ERR_ADDRESS_INVALID; |
| 587 ip_mreq mreq; |
| 588 mreq.imr_interface.s_addr = INADDR_ANY; |
| 589 memcpy(&mreq.imr_multiaddr, &group_address[0], kIPv4AddressSize); |
| 590 int rv = setsockopt(socket_, IPPROTO_IP, IP_DROP_MEMBERSHIP, |
| 591 &mreq, sizeof(mreq)); |
| 592 if (rv < 0) |
| 593 return MapSystemError(errno); |
| 594 return OK; |
| 595 } |
| 596 case kIPv6AddressSize: { |
| 597 if (addr_family_ != AF_INET6) |
| 598 return ERR_ADDRESS_INVALID; |
| 599 ipv6_mreq mreq; |
| 600 mreq.ipv6mr_interface = 0; // 0 indicates default multicast interface. |
| 601 memcpy(&mreq.ipv6mr_multiaddr, &group_address[0], kIPv6AddressSize); |
| 602 int rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_LEAVE_GROUP, |
| 603 &mreq, sizeof(mreq)); |
| 604 if (rv < 0) |
| 605 return MapSystemError(errno); |
| 606 return OK; |
| 607 } |
| 608 default: |
| 609 NOTREACHED() << "Invalid address family"; |
| 610 return ERR_ADDRESS_INVALID; |
| 611 } |
| 612 } |
| 613 |
| 614 int UDPSocketLibevent::SetMulticastTimeToLive(int time_to_live) { |
| 615 DCHECK(CalledOnValidThread()); |
| 616 DCHECK(!is_connected()); |
| 617 if (time_to_live < 0 || time_to_live > 255) |
| 618 return ERR_INVALID_ARGUMENT; |
| 619 multicast_time_to_live_ = time_to_live; |
| 620 return OK; |
| 621 } |
| 622 |
| 623 int UDPSocketLibevent::SetMulticastLoopbackMode(bool loopback) { |
| 624 DCHECK(CalledOnValidThread()); |
| 625 DCHECK(!is_connected()); |
| 626 if (loopback) |
| 627 socket_options_ |= SOCKET_OPTION_MULTICAST_LOOP; |
| 628 else |
| 629 socket_options_ &= ~SOCKET_OPTION_MULTICAST_LOOP; |
| 630 return OK; |
| 631 } |
512 } // namespace net | 632 } // namespace net |
OLD | NEW |