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 3 // found in the LICENSE file. 4 5 #include "net/udp/udp_socket_libevent.h" 6 7 #include <errno.h> 8 #include <fcntl.h> 9 #include <netdb.h> 10 #include <net/if.h> 11 #include <netinet/in.h> 12 #include <sys/ioctl.h> 13 #include <sys/socket.h> 14 15 #include "base/callback.h" 16 #include "base/logging.h" 17 #include "base/message_loop/message_loop.h" 18 #include "base/metrics/sparse_histogram.h" 19 #include "base/metrics/stats_counters.h" 20 #include "base/posix/eintr_wrapper.h" 21 #include "base/rand_util.h" 22 #include "net/base/io_buffer.h" 23 #include "net/base/ip_endpoint.h" 24 #include "net/base/net_errors.h" 25 #include "net/base/net_log.h" 26 #include "net/base/net_util.h" 27 #include "net/socket/socket_descriptor.h" 28 #include "net/udp/udp_net_log_parameters.h" 29 30 31 namespace net { 32 33 namespace { 34 35 const int kBindRetries = 10; 36 const int kPortStart = 1024; 37 const int kPortEnd = 65535; 38 39 #if defined(OS_MACOSX) 40 41 // Returns IPv4 address in network order. 42 int GetIPv4AddressFromIndex(int socket, uint32 index, uint32* address){ 43 if (!index) { 44 *address = htonl(INADDR_ANY); 45 return OK; 46 } 47 ifreq ifr; 48 ifr.ifr_addr.sa_family = AF_INET; 49 if (!if_indextoname(index, ifr.ifr_name)) 50 return ERR_FAILED; 51 int rv = ioctl(socket, SIOCGIFADDR, &ifr); 52 if (!rv) 53 return MapSystemError(rv); 54 *address = reinterpret_cast<sockaddr_in*>(&ifr.ifr_addr)->sin_addr.s_addr; 55 return OK; 56 } 57 58 #endif // OS_MACOSX 59 60 } // namespace 61 62 UDPSocketLibevent::UDPSocketLibevent( 63 DatagramSocket::BindType bind_type, 64 const RandIntCallback& rand_int_cb, 65 net::NetLog* net_log, 66 const net::NetLog::Source& source) 67 : socket_(kInvalidSocket), 68 addr_family_(0), 69 socket_options_(SOCKET_OPTION_MULTICAST_LOOP), 70 multicast_interface_(0), 71 multicast_time_to_live_(1), 72 bind_type_(bind_type), 73 rand_int_cb_(rand_int_cb), 74 read_watcher_(this), 75 write_watcher_(this), 76 read_buf_len_(0), 77 recv_from_address_(NULL), 78 write_buf_len_(0), 79 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_UDP_SOCKET)) { 80 net_log_.BeginEvent(NetLog::TYPE_SOCKET_ALIVE, 81 source.ToEventParametersCallback()); 82 if (bind_type == DatagramSocket::RANDOM_BIND) 83 DCHECK(!rand_int_cb.is_null()); 84 } 85 86 UDPSocketLibevent::~UDPSocketLibevent() { 87 Close(); 88 net_log_.EndEvent(NetLog::TYPE_SOCKET_ALIVE); 89 } 90 91 void UDPSocketLibevent::Close() { 92 DCHECK(CalledOnValidThread()); 93 94 if (!is_connected()) 95 return; 96 97 // Zero out any pending read/write callback state. 98 read_buf_ = NULL; 99 read_buf_len_ = 0; 100 read_callback_.Reset(); 101 recv_from_address_ = NULL; 102 write_buf_ = NULL; 103 write_buf_len_ = 0; 104 write_callback_.Reset(); 105 send_to_address_.reset(); 106 107 bool ok = read_socket_watcher_.StopWatchingFileDescriptor(); 108 DCHECK(ok); 109 ok = write_socket_watcher_.StopWatchingFileDescriptor(); 110 DCHECK(ok); 111 112 if (IGNORE_EINTR(close(socket_)) < 0) 113 PLOG(ERROR) << "close"; 114 115 socket_ = kInvalidSocket; 116 addr_family_ = 0; 117 } 118 119 int UDPSocketLibevent::GetPeerAddress(IPEndPoint* address) const { 120 DCHECK(CalledOnValidThread()); 121 DCHECK(address); 122 if (!is_connected()) 123 return ERR_SOCKET_NOT_CONNECTED; 124 125 if (!remote_address_.get()) { 126 SockaddrStorage storage; 127 if (getpeername(socket_, storage.addr, &storage.addr_len)) 128 return MapSystemError(errno); 129 scoped_ptr<IPEndPoint> address(new IPEndPoint()); 130 if (!address->FromSockAddr(storage.addr, storage.addr_len)) 131 return ERR_FAILED; 132 remote_address_.reset(address.release()); 133 } 134 135 *address = *remote_address_; 136 return OK; 137 } 138 139 int UDPSocketLibevent::GetLocalAddress(IPEndPoint* address) const { 140 DCHECK(CalledOnValidThread()); 141 DCHECK(address); 142 if (!is_connected()) 143 return ERR_SOCKET_NOT_CONNECTED; 144 145 if (!local_address_.get()) { 146 SockaddrStorage storage; 147 if (getsockname(socket_, storage.addr, &storage.addr_len)) 148 return MapSystemError(errno); 149 scoped_ptr<IPEndPoint> address(new IPEndPoint()); 150 if (!address->FromSockAddr(storage.addr, storage.addr_len)) 151 return ERR_FAILED; 152 local_address_.reset(address.release()); 153 net_log_.AddEvent(NetLog::TYPE_UDP_LOCAL_ADDRESS, 154 CreateNetLogUDPConnectCallback(local_address_.get())); 155 } 156 157 *address = *local_address_; 158 return OK; 159 } 160 161 int UDPSocketLibevent::Read(IOBuffer* buf, 162 int buf_len, 163 const CompletionCallback& callback) { 164 return RecvFrom(buf, buf_len, NULL, callback); 165 } 166 167 int UDPSocketLibevent::RecvFrom(IOBuffer* buf, 168 int buf_len, 169 IPEndPoint* address, 170 const CompletionCallback& callback) { 171 DCHECK(CalledOnValidThread()); 172 DCHECK_NE(kInvalidSocket, socket_); 173 DCHECK(read_callback_.is_null()); 174 DCHECK(!recv_from_address_); 175 DCHECK(!callback.is_null()); // Synchronous operation not supported 176 DCHECK_GT(buf_len, 0); 177 178 int nread = InternalRecvFrom(buf, buf_len, address); 179 if (nread != ERR_IO_PENDING) 180 return nread; 181 182 if (!base::MessageLoopForIO::current()->WatchFileDescriptor( 183 socket_, true, base::MessageLoopForIO::WATCH_READ, 184 &read_socket_watcher_, &read_watcher_)) { 185 PLOG(ERROR) << "WatchFileDescriptor failed on read"; 186 int result = MapSystemError(errno); 187 LogRead(result, NULL, 0, NULL); 188 return result; 189 } 190 191 read_buf_ = buf; 192 read_buf_len_ = buf_len; 193 recv_from_address_ = address; 194 read_callback_ = callback; 195 return ERR_IO_PENDING; 196 } 197 198 int UDPSocketLibevent::Write(IOBuffer* buf, 199 int buf_len, 200 const CompletionCallback& callback) { 201 return SendToOrWrite(buf, buf_len, NULL, callback); 202 } 203 204 int UDPSocketLibevent::SendTo(IOBuffer* buf, 205 int buf_len, 206 const IPEndPoint& address, 207 const CompletionCallback& callback) { 208 return SendToOrWrite(buf, buf_len, &address, callback); 209 } 210 211 int UDPSocketLibevent::SendToOrWrite(IOBuffer* buf, 212 int buf_len, 213 const IPEndPoint* address, 214 const CompletionCallback& callback) { 215 DCHECK(CalledOnValidThread()); 216 DCHECK_NE(kInvalidSocket, socket_); 217 DCHECK(write_callback_.is_null()); 218 DCHECK(!callback.is_null()); // Synchronous operation not supported 219 DCHECK_GT(buf_len, 0); 220 221 int result = InternalSendTo(buf, buf_len, address); 222 if (result != ERR_IO_PENDING) 223 return result; 224 225 if (!base::MessageLoopForIO::current()->WatchFileDescriptor( 226 socket_, true, base::MessageLoopForIO::WATCH_WRITE, 227 &write_socket_watcher_, &write_watcher_)) { 228 DVLOG(1) << "WatchFileDescriptor failed on write, errno " << errno; 229 int result = MapSystemError(errno); 230 LogWrite(result, NULL, NULL); 231 return result; 232 } 233 234 write_buf_ = buf; 235 write_buf_len_ = buf_len; 236 DCHECK(!send_to_address_.get()); 237 if (address) { 238 send_to_address_.reset(new IPEndPoint(*address)); 239 } 240 write_callback_ = callback; 241 return ERR_IO_PENDING; 242 } 243 244 int UDPSocketLibevent::Connect(const IPEndPoint& address) { 245 net_log_.BeginEvent(NetLog::TYPE_UDP_CONNECT, 246 CreateNetLogUDPConnectCallback(&address)); 247 int rv = InternalConnect(address); 248 if (rv != OK) 249 Close(); 250 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_UDP_CONNECT, rv); 251 return rv; 252 } 253 254 int UDPSocketLibevent::InternalConnect(const IPEndPoint& address) { 255 DCHECK(CalledOnValidThread()); 256 DCHECK(!is_connected()); 257 DCHECK(!remote_address_.get()); 258 int addr_family = address.GetSockAddrFamily(); 259 int rv = CreateSocket(addr_family); 260 if (rv < 0) 261 return rv; 262 263 if (bind_type_ == DatagramSocket::RANDOM_BIND) { 264 // Construct IPAddressNumber of appropriate size (IPv4 or IPv6) of 0s, 265 // representing INADDR_ANY or in6addr_any. 266 size_t addr_size = 267 addr_family == AF_INET ? kIPv4AddressSize : kIPv6AddressSize; 268 IPAddressNumber addr_any(addr_size); 269 rv = RandomBind(addr_any); 270 } 271 // else connect() does the DatagramSocket::DEFAULT_BIND 272 273 if (rv < 0) { 274 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.UdpSocketRandomBindErrorCode", rv); 275 Close(); 276 return rv; 277 } 278 279 SockaddrStorage storage; 280 if (!address.ToSockAddr(storage.addr, &storage.addr_len)) { 281 Close(); 282 return ERR_ADDRESS_INVALID; 283 } 284 285 rv = HANDLE_EINTR(connect(socket_, storage.addr, storage.addr_len)); 286 if (rv < 0) { 287 // Close() may change the current errno. Map errno beforehand. 288 int result = MapSystemError(errno); 289 Close(); 290 return result; 291 } 292 293 remote_address_.reset(new IPEndPoint(address)); 294 return rv; 295 } 296 297 int UDPSocketLibevent::Bind(const IPEndPoint& address) { 298 DCHECK(CalledOnValidThread()); 299 DCHECK(!is_connected()); 300 int rv = CreateSocket(address.GetSockAddrFamily()); 301 if (rv < 0) 302 return rv; 303 304 rv = SetSocketOptions(); 305 if (rv < 0) { 306 Close(); 307 return rv; 308 } 309 rv = DoBind(address); 310 if (rv < 0) { 311 Close(); 312 return rv; 313 } 314 local_address_.reset(); 315 return rv; 316 } 317 318 bool UDPSocketLibevent::SetReceiveBufferSize(int32 size) { 319 DCHECK(CalledOnValidThread()); 320 int rv = setsockopt(socket_, SOL_SOCKET, SO_RCVBUF, 321 reinterpret_cast<const char*>(&size), sizeof(size)); 322 DCHECK(!rv) << "Could not set socket receive buffer size: " << errno; 323 return rv == 0; 324 } 325 326 bool UDPSocketLibevent::SetSendBufferSize(int32 size) { 327 DCHECK(CalledOnValidThread()); 328 int rv = setsockopt(socket_, SOL_SOCKET, SO_SNDBUF, 329 reinterpret_cast<const char*>(&size), sizeof(size)); 330 DCHECK(!rv) << "Could not set socket send buffer size: " << errno; 331 return rv == 0; 332 } 333 334 void UDPSocketLibevent::AllowAddressReuse() { 335 DCHECK(CalledOnValidThread()); 336 DCHECK(!is_connected()); 337 338 socket_options_ |= SOCKET_OPTION_REUSE_ADDRESS; 339 } 340 341 void UDPSocketLibevent::AllowBroadcast() { 342 DCHECK(CalledOnValidThread()); 343 DCHECK(!is_connected()); 344 345 socket_options_ |= SOCKET_OPTION_BROADCAST; 346 } 347 348 void UDPSocketLibevent::ReadWatcher::OnFileCanReadWithoutBlocking(int) { 349 if (!socket_->read_callback_.is_null()) 350 socket_->DidCompleteRead(); 351 } 352 353 void UDPSocketLibevent::WriteWatcher::OnFileCanWriteWithoutBlocking(int) { 354 if (!socket_->write_callback_.is_null()) 355 socket_->DidCompleteWrite(); 356 } 357 358 void UDPSocketLibevent::DoReadCallback(int rv) { 359 DCHECK_NE(rv, ERR_IO_PENDING); 360 DCHECK(!read_callback_.is_null()); 361 362 // since Run may result in Read being called, clear read_callback_ up front. 363 CompletionCallback c = read_callback_; 364 read_callback_.Reset(); 365 c.Run(rv); 366 } 367 368 void UDPSocketLibevent::DoWriteCallback(int rv) { 369 DCHECK_NE(rv, ERR_IO_PENDING); 370 DCHECK(!write_callback_.is_null()); 371 372 // since Run may result in Write being called, clear write_callback_ up front. 373 CompletionCallback c = write_callback_; 374 write_callback_.Reset(); 375 c.Run(rv); 376 } 377 378 void UDPSocketLibevent::DidCompleteRead() { 379 int result = 380 InternalRecvFrom(read_buf_.get(), read_buf_len_, recv_from_address_); 381 if (result != ERR_IO_PENDING) { 382 read_buf_ = NULL; 383 read_buf_len_ = 0; 384 recv_from_address_ = NULL; 385 bool ok = read_socket_watcher_.StopWatchingFileDescriptor(); 386 DCHECK(ok); 387 DoReadCallback(result); 388 } 389 } 390 391 void UDPSocketLibevent::LogRead(int result, 392 const char* bytes, 393 socklen_t addr_len, 394 const sockaddr* addr) const { 395 if (result < 0) { 396 net_log_.AddEventWithNetErrorCode(NetLog::TYPE_UDP_RECEIVE_ERROR, result); 397 return; 398 } 399 400 if (net_log_.IsLoggingAllEvents()) { 401 DCHECK(addr_len > 0); 402 DCHECK(addr); 403 404 IPEndPoint address; 405 bool is_address_valid = address.FromSockAddr(addr, addr_len); 406 net_log_.AddEvent( 407 NetLog::TYPE_UDP_BYTES_RECEIVED, 408 CreateNetLogUDPDataTranferCallback( 409 result, bytes, 410 is_address_valid ? &address : NULL)); 411 } 412 413 base::StatsCounter read_bytes("udp.read_bytes"); 414 read_bytes.Add(result); 415 } 416 417 int UDPSocketLibevent::CreateSocket(int addr_family) { 418 addr_family_ = addr_family; 419 socket_ = CreatePlatformSocket(addr_family_, SOCK_DGRAM, 0); 420 if (socket_ == kInvalidSocket) 421 return MapSystemError(errno); 422 if (SetNonBlocking(socket_)) { 423 const int err = MapSystemError(errno); 424 Close(); 425 return err; 426 } 427 return OK; 428 } 429 430 void UDPSocketLibevent::DidCompleteWrite() { 431 int result = 432 InternalSendTo(write_buf_.get(), write_buf_len_, send_to_address_.get()); 433 434 if (result != ERR_IO_PENDING) { 435 write_buf_ = NULL; 436 write_buf_len_ = 0; 437 send_to_address_.reset(); 438 write_socket_watcher_.StopWatchingFileDescriptor(); 439 DoWriteCallback(result); 440 } 441 } 442 443 void UDPSocketLibevent::LogWrite(int result, 444 const char* bytes, 445 const IPEndPoint* address) const { 446 if (result < 0) { 447 net_log_.AddEventWithNetErrorCode(NetLog::TYPE_UDP_SEND_ERROR, result); 448 return; 449 } 450 451 if (net_log_.IsLoggingAllEvents()) { 452 net_log_.AddEvent( 453 NetLog::TYPE_UDP_BYTES_SENT, 454 CreateNetLogUDPDataTranferCallback(result, bytes, address)); 455 } 456 457 base::StatsCounter write_bytes("udp.write_bytes"); 458 write_bytes.Add(result); 459 } 460 461 int UDPSocketLibevent::InternalRecvFrom(IOBuffer* buf, int buf_len, 462 IPEndPoint* address) { 463 int bytes_transferred; 464 int flags = 0; 465 466 SockaddrStorage storage; 467 468 bytes_transferred = 469 HANDLE_EINTR(recvfrom(socket_, 470 buf->data(), 471 buf_len, 472 flags, 473 storage.addr, 474 &storage.addr_len)); 475 int result; 476 if (bytes_transferred >= 0) { 477 result = bytes_transferred; 478 if (address && !address->FromSockAddr(storage.addr, storage.addr_len)) 479 result = ERR_FAILED; 480 } else { 481 result = MapSystemError(errno); 482 } 483 if (result != ERR_IO_PENDING) 484 LogRead(result, buf->data(), storage.addr_len, storage.addr); 485 return result; 486 } 487 488 int UDPSocketLibevent::InternalSendTo(IOBuffer* buf, int buf_len, 489 const IPEndPoint* address) { 490 SockaddrStorage storage; 491 struct sockaddr* addr = storage.addr; 492 if (!address) { 493 addr = NULL; 494 storage.addr_len = 0; 495 } else { 496 if (!address->ToSockAddr(storage.addr, &storage.addr_len)) { 497 int result = ERR_FAILED; 498 LogWrite(result, NULL, NULL); 499 return result; 500 } 501 } 502 503 int result = HANDLE_EINTR(sendto(socket_, 504 buf->data(), 505 buf_len, 506 0, 507 addr, 508 storage.addr_len)); 509 if (result < 0) 510 result = MapSystemError(errno); 511 if (result != ERR_IO_PENDING) 512 LogWrite(result, buf->data(), address); 513 return result; 514 } 515 516 int UDPSocketLibevent::SetSocketOptions() { 517 int true_value = 1; 518 if (socket_options_ & SOCKET_OPTION_REUSE_ADDRESS) { 519 int rv = setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, &true_value, 520 sizeof(true_value)); 521 if (rv < 0) 522 return MapSystemError(errno); 523 } 524 if (socket_options_ & SOCKET_OPTION_BROADCAST) { 525 int rv; 526 #if defined(OS_MACOSX) 527 // SO_REUSEPORT on OSX permits multiple processes to each receive 528 // UDP multicast or broadcast datagrams destined for the bound 529 // port. 530 rv = setsockopt(socket_, SOL_SOCKET, SO_REUSEPORT, &true_value, 531 sizeof(true_value)); 532 #else 533 rv = setsockopt(socket_, SOL_SOCKET, SO_BROADCAST, &true_value, 534 sizeof(true_value)); 535 #endif // defined(OS_MACOSX) 536 if (rv < 0) 537 return MapSystemError(errno); 538 } 539 540 if (!(socket_options_ & SOCKET_OPTION_MULTICAST_LOOP)) { 541 int rv; 542 if (addr_family_ == AF_INET) { 543 u_char loop = 0; 544 rv = setsockopt(socket_, IPPROTO_IP, IP_MULTICAST_LOOP, 545 &loop, sizeof(loop)); 546 } else { 547 u_int loop = 0; 548 rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, 549 &loop, sizeof(loop)); 550 } 551 if (rv < 0) 552 return MapSystemError(errno); 553 } 554 if (multicast_time_to_live_ != IP_DEFAULT_MULTICAST_TTL) { 555 int rv; 556 if (addr_family_ == AF_INET) { 557 u_char ttl = multicast_time_to_live_; 558 rv = setsockopt(socket_, IPPROTO_IP, IP_MULTICAST_TTL, 559 &ttl, sizeof(ttl)); 560 } else { 561 // Signed integer. -1 to use route default. 562 int ttl = multicast_time_to_live_; 563 rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, 564 &ttl, sizeof(ttl)); 565 } 566 if (rv < 0) 567 return MapSystemError(errno); 568 } 569 if (multicast_interface_ != 0) { 570 switch (addr_family_) { 571 case AF_INET: { 572 #if !defined(OS_MACOSX) 573 ip_mreqn mreq; 574 mreq.imr_ifindex = multicast_interface_; 575 mreq.imr_address.s_addr = htonl(INADDR_ANY); 576 #else 577 ip_mreq mreq; 578 int error = GetIPv4AddressFromIndex(socket_, multicast_interface_, 579 &mreq.imr_interface.s_addr); 580 if (error != OK) 581 return error; 582 #endif 583 int rv = setsockopt(socket_, IPPROTO_IP, IP_MULTICAST_IF, 584 reinterpret_cast<const char*>(&mreq), sizeof(mreq)); 585 if (rv) 586 return MapSystemError(errno); 587 break; 588 } 589 case AF_INET6: { 590 uint32 interface_index = multicast_interface_; 591 int rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_MULTICAST_IF, 592 reinterpret_cast<const char*>(&interface_index), 593 sizeof(interface_index)); 594 if (rv) 595 return MapSystemError(errno); 596 break; 597 } 598 default: 599 NOTREACHED() << "Invalid address family"; 600 return ERR_ADDRESS_INVALID; 601 } 602 } 603 return OK; 604 } 605 606 int UDPSocketLibevent::DoBind(const IPEndPoint& address) { 607 SockaddrStorage storage; 608 if (!address.ToSockAddr(storage.addr, &storage.addr_len)) 609 return ERR_ADDRESS_INVALID; 610 int rv = bind(socket_, storage.addr, storage.addr_len); 611 if (rv == 0) 612 return OK; 613 int last_error = errno; 614 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.UdpSocketBindErrorFromPosix", last_error); 615 return MapSystemError(last_error); 616 } 617 618 int UDPSocketLibevent::RandomBind(const IPAddressNumber& address) { 619 DCHECK(bind_type_ == DatagramSocket::RANDOM_BIND && !rand_int_cb_.is_null()); 620 621 for (int i = 0; i < kBindRetries; ++i) { 622 int rv = DoBind(IPEndPoint(address, 623 rand_int_cb_.Run(kPortStart, kPortEnd))); 624 if (rv == OK || rv != ERR_ADDRESS_IN_USE) 625 return rv; 626 } 627 return DoBind(IPEndPoint(address, 0)); 628 } 629 630 int UDPSocketLibevent::JoinGroup(const IPAddressNumber& group_address) const { 631 DCHECK(CalledOnValidThread()); 632 if (!is_connected()) 633 return ERR_SOCKET_NOT_CONNECTED; 634 635 switch (group_address.size()) { 636 case kIPv4AddressSize: { 637 if (addr_family_ != AF_INET) 638 return ERR_ADDRESS_INVALID; 639 640 #if !defined(OS_MACOSX) 641 ip_mreqn mreq; 642 mreq.imr_ifindex = multicast_interface_; 643 mreq.imr_address.s_addr = htonl(INADDR_ANY); 644 #else 645 ip_mreq mreq; 646 int error = GetIPv4AddressFromIndex(socket_, multicast_interface_, 647 &mreq.imr_interface.s_addr); 648 if (error != OK) 649 return error; 650 #endif 651 memcpy(&mreq.imr_multiaddr, &group_address[0], kIPv4AddressSize); 652 int rv = setsockopt(socket_, IPPROTO_IP, IP_ADD_MEMBERSHIP, 653 &mreq, sizeof(mreq)); 654 if (rv < 0) 655 return MapSystemError(errno); 656 return OK; 657 } 658 case kIPv6AddressSize: { 659 if (addr_family_ != AF_INET6) 660 return ERR_ADDRESS_INVALID; 661 ipv6_mreq mreq; 662 mreq.ipv6mr_interface = multicast_interface_; 663 memcpy(&mreq.ipv6mr_multiaddr, &group_address[0], kIPv6AddressSize); 664 int rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_JOIN_GROUP, 665 &mreq, sizeof(mreq)); 666 if (rv < 0) 667 return MapSystemError(errno); 668 return OK; 669 } 670 default: 671 NOTREACHED() << "Invalid address family"; 672 return ERR_ADDRESS_INVALID; 673 } 674 } 675 676 int UDPSocketLibevent::LeaveGroup(const IPAddressNumber& group_address) const { 677 DCHECK(CalledOnValidThread()); 678 679 if (!is_connected()) 680 return ERR_SOCKET_NOT_CONNECTED; 681 682 switch (group_address.size()) { 683 case kIPv4AddressSize: { 684 if (addr_family_ != AF_INET) 685 return ERR_ADDRESS_INVALID; 686 ip_mreq mreq; 687 mreq.imr_interface.s_addr = INADDR_ANY; 688 memcpy(&mreq.imr_multiaddr, &group_address[0], kIPv4AddressSize); 689 int rv = setsockopt(socket_, IPPROTO_IP, IP_DROP_MEMBERSHIP, 690 &mreq, sizeof(mreq)); 691 if (rv < 0) 692 return MapSystemError(errno); 693 return OK; 694 } 695 case kIPv6AddressSize: { 696 if (addr_family_ != AF_INET6) 697 return ERR_ADDRESS_INVALID; 698 ipv6_mreq mreq; 699 mreq.ipv6mr_interface = 0; // 0 indicates default multicast interface. 700 memcpy(&mreq.ipv6mr_multiaddr, &group_address[0], kIPv6AddressSize); 701 int rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_LEAVE_GROUP, 702 &mreq, sizeof(mreq)); 703 if (rv < 0) 704 return MapSystemError(errno); 705 return OK; 706 } 707 default: 708 NOTREACHED() << "Invalid address family"; 709 return ERR_ADDRESS_INVALID; 710 } 711 } 712 713 int UDPSocketLibevent::SetMulticastInterface(uint32 interface_index) { 714 DCHECK(CalledOnValidThread()); 715 if (is_connected()) 716 return ERR_SOCKET_IS_CONNECTED; 717 multicast_interface_ = interface_index; 718 return OK; 719 } 720 721 int UDPSocketLibevent::SetMulticastTimeToLive(int time_to_live) { 722 DCHECK(CalledOnValidThread()); 723 if (is_connected()) 724 return ERR_SOCKET_IS_CONNECTED; 725 726 if (time_to_live < 0 || time_to_live > 255) 727 return ERR_INVALID_ARGUMENT; 728 multicast_time_to_live_ = time_to_live; 729 return OK; 730 } 731 732 int UDPSocketLibevent::SetMulticastLoopbackMode(bool loopback) { 733 DCHECK(CalledOnValidThread()); 734 if (is_connected()) 735 return ERR_SOCKET_IS_CONNECTED; 736 737 if (loopback) 738 socket_options_ |= SOCKET_OPTION_MULTICAST_LOOP; 739 else 740 socket_options_ &= ~SOCKET_OPTION_MULTICAST_LOOP; 741 return OK; 742 } 743 744 int UDPSocketLibevent::SetDiffServCodePoint(DiffServCodePoint dscp) { 745 if (dscp == DSCP_NO_CHANGE) { 746 return OK; 747 } 748 int rv; 749 int dscp_and_ecn = dscp << 2; 750 if (addr_family_ == AF_INET) { 751 rv = setsockopt(socket_, IPPROTO_IP, IP_TOS, 752 &dscp_and_ecn, sizeof(dscp_and_ecn)); 753 } else { 754 rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_TCLASS, 755 &dscp_and_ecn, sizeof(dscp_and_ecn)); 756 } 757 if (rv < 0) 758 return MapSystemError(errno); 759 760 return OK; 761 } 762 763 } // namespace net 764