QUIC - enable LargePostSmallBandwidthLargeBuffer unittest.
[chromium-blink-merge.git] / net / udp / udp_socket_libevent.cc
blobfaab9a451182f2e09150019b9e082f7fe2abb99e
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.
5 #include "net/udp/udp_socket_libevent.h"
7 #include <errno.h>
8 #include <fcntl.h>
9 #include <net/if.h>
10 #include <netdb.h>
11 #include <netinet/in.h>
12 #include <sys/ioctl.h>
13 #include <sys/socket.h>
15 #include "base/callback.h"
16 #include "base/debug/alias.h"
17 #include "base/logging.h"
18 #include "base/message_loop/message_loop.h"
19 #include "base/metrics/sparse_histogram.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_util.h"
26 #include "net/base/network_activity_monitor.h"
27 #include "net/log/net_log.h"
28 #include "net/socket/socket_descriptor.h"
29 #include "net/udp/udp_net_log_parameters.h"
32 namespace net {
34 namespace {
36 const int kBindRetries = 10;
37 const int kPortStart = 1024;
38 const int kPortEnd = 65535;
40 #if defined(OS_MACOSX)
42 // Returns IPv4 address in network order.
43 int GetIPv4AddressFromIndex(int socket, uint32 index, uint32* address){
44 if (!index) {
45 *address = htonl(INADDR_ANY);
46 return OK;
48 ifreq ifr;
49 ifr.ifr_addr.sa_family = AF_INET;
50 if (!if_indextoname(index, ifr.ifr_name))
51 return MapSystemError(errno);
52 int rv = ioctl(socket, SIOCGIFADDR, &ifr);
53 if (rv == -1)
54 return MapSystemError(errno);
55 *address = reinterpret_cast<sockaddr_in*>(&ifr.ifr_addr)->sin_addr.s_addr;
56 return OK;
59 #endif // OS_MACOSX
61 } // namespace
63 UDPSocketLibevent::UDPSocketLibevent(
64 DatagramSocket::BindType bind_type,
65 const RandIntCallback& rand_int_cb,
66 net::NetLog* net_log,
67 const net::NetLog::Source& source)
68 : socket_(kInvalidSocket),
69 addr_family_(0),
70 is_connected_(false),
71 socket_options_(SOCKET_OPTION_MULTICAST_LOOP),
72 multicast_interface_(0),
73 multicast_time_to_live_(1),
74 bind_type_(bind_type),
75 rand_int_cb_(rand_int_cb),
76 read_watcher_(this),
77 write_watcher_(this),
78 read_buf_len_(0),
79 recv_from_address_(NULL),
80 write_buf_len_(0),
81 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_UDP_SOCKET)) {
82 net_log_.BeginEvent(NetLog::TYPE_SOCKET_ALIVE,
83 source.ToEventParametersCallback());
84 if (bind_type == DatagramSocket::RANDOM_BIND)
85 DCHECK(!rand_int_cb.is_null());
88 UDPSocketLibevent::~UDPSocketLibevent() {
89 Close();
90 net_log_.EndEvent(NetLog::TYPE_SOCKET_ALIVE);
93 int UDPSocketLibevent::Open(AddressFamily address_family) {
94 DCHECK(CalledOnValidThread());
95 DCHECK_EQ(socket_, kInvalidSocket);
97 addr_family_ = ConvertAddressFamily(address_family);
98 socket_ = CreatePlatformSocket(addr_family_, SOCK_DGRAM, 0);
99 if (socket_ == kInvalidSocket)
100 return MapSystemError(errno);
101 if (SetNonBlocking(socket_)) {
102 const int err = MapSystemError(errno);
103 Close();
104 return err;
106 return OK;
109 void UDPSocketLibevent::Close() {
110 DCHECK(CalledOnValidThread());
112 if (socket_ == kInvalidSocket)
113 return;
115 // Zero out any pending read/write callback state.
116 read_buf_ = NULL;
117 read_buf_len_ = 0;
118 read_callback_.Reset();
119 recv_from_address_ = NULL;
120 write_buf_ = NULL;
121 write_buf_len_ = 0;
122 write_callback_.Reset();
123 send_to_address_.reset();
125 bool ok = read_socket_watcher_.StopWatchingFileDescriptor();
126 DCHECK(ok);
127 ok = write_socket_watcher_.StopWatchingFileDescriptor();
128 DCHECK(ok);
130 PCHECK(IGNORE_EINTR(close(socket_)) == 0);
132 socket_ = kInvalidSocket;
133 addr_family_ = 0;
134 is_connected_ = false;
137 int UDPSocketLibevent::GetPeerAddress(IPEndPoint* address) const {
138 DCHECK(CalledOnValidThread());
139 DCHECK(address);
140 if (!is_connected())
141 return ERR_SOCKET_NOT_CONNECTED;
143 if (!remote_address_.get()) {
144 SockaddrStorage storage;
145 if (getpeername(socket_, storage.addr, &storage.addr_len))
146 return MapSystemError(errno);
147 scoped_ptr<IPEndPoint> address(new IPEndPoint());
148 if (!address->FromSockAddr(storage.addr, storage.addr_len))
149 return ERR_ADDRESS_INVALID;
150 remote_address_.reset(address.release());
153 *address = *remote_address_;
154 return OK;
157 int UDPSocketLibevent::GetLocalAddress(IPEndPoint* address) const {
158 DCHECK(CalledOnValidThread());
159 DCHECK(address);
160 if (!is_connected())
161 return ERR_SOCKET_NOT_CONNECTED;
163 if (!local_address_.get()) {
164 SockaddrStorage storage;
165 if (getsockname(socket_, storage.addr, &storage.addr_len))
166 return MapSystemError(errno);
167 scoped_ptr<IPEndPoint> address(new IPEndPoint());
168 if (!address->FromSockAddr(storage.addr, storage.addr_len))
169 return ERR_ADDRESS_INVALID;
170 local_address_.reset(address.release());
171 net_log_.AddEvent(NetLog::TYPE_UDP_LOCAL_ADDRESS,
172 CreateNetLogUDPConnectCallback(local_address_.get()));
175 *address = *local_address_;
176 return OK;
179 int UDPSocketLibevent::Read(IOBuffer* buf,
180 int buf_len,
181 const CompletionCallback& callback) {
182 return RecvFrom(buf, buf_len, NULL, callback);
185 int UDPSocketLibevent::RecvFrom(IOBuffer* buf,
186 int buf_len,
187 IPEndPoint* address,
188 const CompletionCallback& callback) {
189 DCHECK(CalledOnValidThread());
190 DCHECK_NE(kInvalidSocket, socket_);
191 CHECK(read_callback_.is_null());
192 DCHECK(!recv_from_address_);
193 DCHECK(!callback.is_null()); // Synchronous operation not supported
194 DCHECK_GT(buf_len, 0);
196 int nread = InternalRecvFrom(buf, buf_len, address);
197 if (nread != ERR_IO_PENDING)
198 return nread;
200 if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
201 socket_, true, base::MessageLoopForIO::WATCH_READ,
202 &read_socket_watcher_, &read_watcher_)) {
203 PLOG(ERROR) << "WatchFileDescriptor failed on read";
204 int result = MapSystemError(errno);
205 LogRead(result, NULL, 0, NULL);
206 return result;
209 read_buf_ = buf;
210 read_buf_len_ = buf_len;
211 recv_from_address_ = address;
212 read_callback_ = callback;
213 return ERR_IO_PENDING;
216 int UDPSocketLibevent::Write(IOBuffer* buf,
217 int buf_len,
218 const CompletionCallback& callback) {
219 return SendToOrWrite(buf, buf_len, NULL, callback);
222 int UDPSocketLibevent::SendTo(IOBuffer* buf,
223 int buf_len,
224 const IPEndPoint& address,
225 const CompletionCallback& callback) {
226 return SendToOrWrite(buf, buf_len, &address, callback);
229 int UDPSocketLibevent::SendToOrWrite(IOBuffer* buf,
230 int buf_len,
231 const IPEndPoint* address,
232 const CompletionCallback& callback) {
233 DCHECK(CalledOnValidThread());
234 DCHECK_NE(kInvalidSocket, socket_);
235 CHECK(write_callback_.is_null());
236 DCHECK(!callback.is_null()); // Synchronous operation not supported
237 DCHECK_GT(buf_len, 0);
239 int result = InternalSendTo(buf, buf_len, address);
240 if (result != ERR_IO_PENDING)
241 return result;
243 if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
244 socket_, true, base::MessageLoopForIO::WATCH_WRITE,
245 &write_socket_watcher_, &write_watcher_)) {
246 DVLOG(1) << "WatchFileDescriptor failed on write, errno " << errno;
247 int result = MapSystemError(errno);
248 LogWrite(result, NULL, NULL);
249 return result;
252 write_buf_ = buf;
253 write_buf_len_ = buf_len;
254 DCHECK(!send_to_address_.get());
255 if (address) {
256 send_to_address_.reset(new IPEndPoint(*address));
258 write_callback_ = callback;
259 return ERR_IO_PENDING;
262 int UDPSocketLibevent::Connect(const IPEndPoint& address) {
263 DCHECK_NE(socket_, kInvalidSocket);
264 net_log_.BeginEvent(NetLog::TYPE_UDP_CONNECT,
265 CreateNetLogUDPConnectCallback(&address));
266 int rv = InternalConnect(address);
267 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_UDP_CONNECT, rv);
268 is_connected_ = (rv == OK);
269 return rv;
272 int UDPSocketLibevent::InternalConnect(const IPEndPoint& address) {
273 DCHECK(CalledOnValidThread());
274 DCHECK(!is_connected());
275 DCHECK(!remote_address_.get());
277 int rv = 0;
278 if (bind_type_ == DatagramSocket::RANDOM_BIND) {
279 // Construct IPAddressNumber of appropriate size (IPv4 or IPv6) of 0s,
280 // representing INADDR_ANY or in6addr_any.
281 size_t addr_size = address.GetSockAddrFamily() == AF_INET ?
282 kIPv4AddressSize : kIPv6AddressSize;
283 IPAddressNumber addr_any(addr_size);
284 rv = RandomBind(addr_any);
286 // else connect() does the DatagramSocket::DEFAULT_BIND
288 if (rv < 0) {
289 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.UdpSocketRandomBindErrorCode", -rv);
290 return rv;
293 SockaddrStorage storage;
294 if (!address.ToSockAddr(storage.addr, &storage.addr_len))
295 return ERR_ADDRESS_INVALID;
297 rv = HANDLE_EINTR(connect(socket_, storage.addr, storage.addr_len));
298 if (rv < 0)
299 return MapSystemError(errno);
301 remote_address_.reset(new IPEndPoint(address));
302 return rv;
305 int UDPSocketLibevent::Bind(const IPEndPoint& address) {
306 DCHECK_NE(socket_, kInvalidSocket);
307 DCHECK(CalledOnValidThread());
308 DCHECK(!is_connected());
310 int rv = SetMulticastOptions();
311 if (rv < 0)
312 return rv;
314 rv = DoBind(address);
315 if (rv < 0)
316 return rv;
318 is_connected_ = true;
319 local_address_.reset();
320 return rv;
323 int UDPSocketLibevent::SetReceiveBufferSize(int32 size) {
324 DCHECK_NE(socket_, kInvalidSocket);
325 DCHECK(CalledOnValidThread());
326 int rv = setsockopt(socket_, SOL_SOCKET, SO_RCVBUF,
327 reinterpret_cast<const char*>(&size), sizeof(size));
328 return rv == 0 ? OK : MapSystemError(errno);
331 int UDPSocketLibevent::SetSendBufferSize(int32 size) {
332 DCHECK_NE(socket_, kInvalidSocket);
333 DCHECK(CalledOnValidThread());
334 int rv = setsockopt(socket_, SOL_SOCKET, SO_SNDBUF,
335 reinterpret_cast<const char*>(&size), sizeof(size));
336 return rv == 0 ? OK : MapSystemError(errno);
339 int UDPSocketLibevent::AllowAddressReuse() {
340 DCHECK_NE(socket_, kInvalidSocket);
341 DCHECK(CalledOnValidThread());
342 DCHECK(!is_connected());
343 int true_value = 1;
344 int rv = setsockopt(
345 socket_, SOL_SOCKET, SO_REUSEADDR, &true_value, sizeof(true_value));
346 return rv == 0 ? OK : MapSystemError(errno);
349 int UDPSocketLibevent::SetBroadcast(bool broadcast) {
350 DCHECK_NE(socket_, kInvalidSocket);
351 DCHECK(CalledOnValidThread());
352 int value = broadcast ? 1 : 0;
353 int rv;
354 #if defined(OS_MACOSX)
355 // SO_REUSEPORT on OSX permits multiple processes to each receive
356 // UDP multicast or broadcast datagrams destined for the bound
357 // port.
358 rv = setsockopt(socket_, SOL_SOCKET, SO_REUSEPORT, &value, sizeof(value));
359 #else
360 rv = setsockopt(socket_, SOL_SOCKET, SO_BROADCAST, &value, sizeof(value));
361 #endif // defined(OS_MACOSX)
362 return rv == 0 ? OK : MapSystemError(errno);
365 void UDPSocketLibevent::ReadWatcher::OnFileCanReadWithoutBlocking(int) {
366 if (!socket_->read_callback_.is_null())
367 socket_->DidCompleteRead();
370 void UDPSocketLibevent::WriteWatcher::OnFileCanWriteWithoutBlocking(int) {
371 if (!socket_->write_callback_.is_null())
372 socket_->DidCompleteWrite();
375 void UDPSocketLibevent::DoReadCallback(int rv) {
376 DCHECK_NE(rv, ERR_IO_PENDING);
377 DCHECK(!read_callback_.is_null());
379 // since Run may result in Read being called, clear read_callback_ up front.
380 CompletionCallback c = read_callback_;
381 read_callback_.Reset();
382 c.Run(rv);
385 void UDPSocketLibevent::DoWriteCallback(int rv) {
386 DCHECK_NE(rv, ERR_IO_PENDING);
387 DCHECK(!write_callback_.is_null());
389 // since Run may result in Write being called, clear write_callback_ up front.
390 CompletionCallback c = write_callback_;
391 write_callback_.Reset();
392 c.Run(rv);
395 void UDPSocketLibevent::DidCompleteRead() {
396 int result =
397 InternalRecvFrom(read_buf_.get(), read_buf_len_, recv_from_address_);
398 if (result != ERR_IO_PENDING) {
399 read_buf_ = NULL;
400 read_buf_len_ = 0;
401 recv_from_address_ = NULL;
402 bool ok = read_socket_watcher_.StopWatchingFileDescriptor();
403 DCHECK(ok);
404 DoReadCallback(result);
408 void UDPSocketLibevent::LogRead(int result,
409 const char* bytes,
410 socklen_t addr_len,
411 const sockaddr* addr) const {
412 if (result < 0) {
413 net_log_.AddEventWithNetErrorCode(NetLog::TYPE_UDP_RECEIVE_ERROR, result);
414 return;
417 if (net_log_.IsCapturing()) {
418 DCHECK(addr_len > 0);
419 DCHECK(addr);
421 IPEndPoint address;
422 bool is_address_valid = address.FromSockAddr(addr, addr_len);
423 net_log_.AddEvent(
424 NetLog::TYPE_UDP_BYTES_RECEIVED,
425 CreateNetLogUDPDataTranferCallback(
426 result, bytes,
427 is_address_valid ? &address : NULL));
430 NetworkActivityMonitor::GetInstance()->IncrementBytesReceived(result);
433 void UDPSocketLibevent::DidCompleteWrite() {
434 int result =
435 InternalSendTo(write_buf_.get(), write_buf_len_, send_to_address_.get());
437 if (result != ERR_IO_PENDING) {
438 write_buf_ = NULL;
439 write_buf_len_ = 0;
440 send_to_address_.reset();
441 write_socket_watcher_.StopWatchingFileDescriptor();
442 DoWriteCallback(result);
446 void UDPSocketLibevent::LogWrite(int result,
447 const char* bytes,
448 const IPEndPoint* address) const {
449 if (result < 0) {
450 net_log_.AddEventWithNetErrorCode(NetLog::TYPE_UDP_SEND_ERROR, result);
451 return;
454 if (net_log_.IsCapturing()) {
455 net_log_.AddEvent(
456 NetLog::TYPE_UDP_BYTES_SENT,
457 CreateNetLogUDPDataTranferCallback(result, bytes, address));
460 NetworkActivityMonitor::GetInstance()->IncrementBytesSent(result);
463 int UDPSocketLibevent::InternalRecvFrom(IOBuffer* buf, int buf_len,
464 IPEndPoint* address) {
465 int bytes_transferred;
466 int flags = 0;
468 SockaddrStorage storage;
470 bytes_transferred =
471 HANDLE_EINTR(recvfrom(socket_,
472 buf->data(),
473 buf_len,
474 flags,
475 storage.addr,
476 &storage.addr_len));
477 int result;
478 if (bytes_transferred >= 0) {
479 result = bytes_transferred;
480 if (address && !address->FromSockAddr(storage.addr, storage.addr_len))
481 result = ERR_ADDRESS_INVALID;
482 } else {
483 result = MapSystemError(errno);
485 if (result != ERR_IO_PENDING)
486 LogRead(result, buf->data(), storage.addr_len, storage.addr);
487 return result;
490 int UDPSocketLibevent::InternalSendTo(IOBuffer* buf, int buf_len,
491 const IPEndPoint* address) {
492 SockaddrStorage storage;
493 struct sockaddr* addr = storage.addr;
494 if (!address) {
495 addr = NULL;
496 storage.addr_len = 0;
497 } else {
498 if (!address->ToSockAddr(storage.addr, &storage.addr_len)) {
499 int result = ERR_ADDRESS_INVALID;
500 LogWrite(result, NULL, NULL);
501 return result;
505 int result = HANDLE_EINTR(sendto(socket_,
506 buf->data(),
507 buf_len,
509 addr,
510 storage.addr_len));
511 if (result < 0)
512 result = MapSystemError(errno);
513 if (result != ERR_IO_PENDING)
514 LogWrite(result, buf->data(), address);
515 return result;
518 int UDPSocketLibevent::SetMulticastOptions() {
519 if (!(socket_options_ & SOCKET_OPTION_MULTICAST_LOOP)) {
520 int rv;
521 if (addr_family_ == AF_INET) {
522 u_char loop = 0;
523 rv = setsockopt(socket_, IPPROTO_IP, IP_MULTICAST_LOOP,
524 &loop, sizeof(loop));
525 } else {
526 u_int loop = 0;
527 rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
528 &loop, sizeof(loop));
530 if (rv < 0)
531 return MapSystemError(errno);
533 if (multicast_time_to_live_ != IP_DEFAULT_MULTICAST_TTL) {
534 int rv;
535 if (addr_family_ == AF_INET) {
536 u_char ttl = multicast_time_to_live_;
537 rv = setsockopt(socket_, IPPROTO_IP, IP_MULTICAST_TTL,
538 &ttl, sizeof(ttl));
539 } else {
540 // Signed integer. -1 to use route default.
541 int ttl = multicast_time_to_live_;
542 rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
543 &ttl, sizeof(ttl));
545 if (rv < 0)
546 return MapSystemError(errno);
548 if (multicast_interface_ != 0) {
549 switch (addr_family_) {
550 case AF_INET: {
551 #if !defined(OS_MACOSX)
552 ip_mreqn mreq;
553 mreq.imr_ifindex = multicast_interface_;
554 mreq.imr_address.s_addr = htonl(INADDR_ANY);
555 #else
556 ip_mreq mreq;
557 int error = GetIPv4AddressFromIndex(socket_, multicast_interface_,
558 &mreq.imr_interface.s_addr);
559 if (error != OK)
560 return error;
561 #endif
562 int rv = setsockopt(socket_, IPPROTO_IP, IP_MULTICAST_IF,
563 reinterpret_cast<const char*>(&mreq), sizeof(mreq));
564 if (rv)
565 return MapSystemError(errno);
566 break;
568 case AF_INET6: {
569 uint32 interface_index = multicast_interface_;
570 int rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_MULTICAST_IF,
571 reinterpret_cast<const char*>(&interface_index),
572 sizeof(interface_index));
573 if (rv)
574 return MapSystemError(errno);
575 break;
577 default:
578 NOTREACHED() << "Invalid address family";
579 return ERR_ADDRESS_INVALID;
582 return OK;
585 int UDPSocketLibevent::DoBind(const IPEndPoint& address) {
586 SockaddrStorage storage;
587 if (!address.ToSockAddr(storage.addr, &storage.addr_len))
588 return ERR_ADDRESS_INVALID;
589 int rv = bind(socket_, storage.addr, storage.addr_len);
590 if (rv == 0)
591 return OK;
592 int last_error = errno;
593 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.UdpSocketBindErrorFromPosix", last_error);
594 #if defined(OS_CHROMEOS)
595 if (last_error == EINVAL)
596 return ERR_ADDRESS_IN_USE;
597 #elif defined(OS_MACOSX)
598 if (last_error == EADDRNOTAVAIL)
599 return ERR_ADDRESS_IN_USE;
600 #endif
601 return MapSystemError(last_error);
604 int UDPSocketLibevent::RandomBind(const IPAddressNumber& address) {
605 DCHECK(bind_type_ == DatagramSocket::RANDOM_BIND && !rand_int_cb_.is_null());
607 for (int i = 0; i < kBindRetries; ++i) {
608 int rv = DoBind(IPEndPoint(address,
609 rand_int_cb_.Run(kPortStart, kPortEnd)));
610 if (rv == OK || rv != ERR_ADDRESS_IN_USE)
611 return rv;
613 return DoBind(IPEndPoint(address, 0));
616 int UDPSocketLibevent::JoinGroup(const IPAddressNumber& group_address) const {
617 DCHECK(CalledOnValidThread());
618 if (!is_connected())
619 return ERR_SOCKET_NOT_CONNECTED;
621 switch (group_address.size()) {
622 case kIPv4AddressSize: {
623 if (addr_family_ != AF_INET)
624 return ERR_ADDRESS_INVALID;
626 #if !defined(OS_MACOSX)
627 ip_mreqn mreq;
628 mreq.imr_ifindex = multicast_interface_;
629 mreq.imr_address.s_addr = htonl(INADDR_ANY);
630 #else
631 ip_mreq mreq;
632 int error = GetIPv4AddressFromIndex(socket_, multicast_interface_,
633 &mreq.imr_interface.s_addr);
634 if (error != OK)
635 return error;
636 #endif
637 memcpy(&mreq.imr_multiaddr, &group_address[0], kIPv4AddressSize);
638 int rv = setsockopt(socket_, IPPROTO_IP, IP_ADD_MEMBERSHIP,
639 &mreq, sizeof(mreq));
640 if (rv < 0)
641 return MapSystemError(errno);
642 return OK;
644 case kIPv6AddressSize: {
645 if (addr_family_ != AF_INET6)
646 return ERR_ADDRESS_INVALID;
647 ipv6_mreq mreq;
648 mreq.ipv6mr_interface = multicast_interface_;
649 memcpy(&mreq.ipv6mr_multiaddr, &group_address[0], kIPv6AddressSize);
650 int rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_JOIN_GROUP,
651 &mreq, sizeof(mreq));
652 if (rv < 0)
653 return MapSystemError(errno);
654 return OK;
656 default:
657 NOTREACHED() << "Invalid address family";
658 return ERR_ADDRESS_INVALID;
662 int UDPSocketLibevent::LeaveGroup(const IPAddressNumber& group_address) const {
663 DCHECK(CalledOnValidThread());
665 if (!is_connected())
666 return ERR_SOCKET_NOT_CONNECTED;
668 switch (group_address.size()) {
669 case kIPv4AddressSize: {
670 if (addr_family_ != AF_INET)
671 return ERR_ADDRESS_INVALID;
672 ip_mreq mreq;
673 mreq.imr_interface.s_addr = INADDR_ANY;
674 memcpy(&mreq.imr_multiaddr, &group_address[0], kIPv4AddressSize);
675 int rv = setsockopt(socket_, IPPROTO_IP, IP_DROP_MEMBERSHIP,
676 &mreq, sizeof(mreq));
677 if (rv < 0)
678 return MapSystemError(errno);
679 return OK;
681 case kIPv6AddressSize: {
682 if (addr_family_ != AF_INET6)
683 return ERR_ADDRESS_INVALID;
684 ipv6_mreq mreq;
685 mreq.ipv6mr_interface = 0; // 0 indicates default multicast interface.
686 memcpy(&mreq.ipv6mr_multiaddr, &group_address[0], kIPv6AddressSize);
687 int rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
688 &mreq, sizeof(mreq));
689 if (rv < 0)
690 return MapSystemError(errno);
691 return OK;
693 default:
694 NOTREACHED() << "Invalid address family";
695 return ERR_ADDRESS_INVALID;
699 int UDPSocketLibevent::SetMulticastInterface(uint32 interface_index) {
700 DCHECK(CalledOnValidThread());
701 if (is_connected())
702 return ERR_SOCKET_IS_CONNECTED;
703 multicast_interface_ = interface_index;
704 return OK;
707 int UDPSocketLibevent::SetMulticastTimeToLive(int time_to_live) {
708 DCHECK(CalledOnValidThread());
709 if (is_connected())
710 return ERR_SOCKET_IS_CONNECTED;
712 if (time_to_live < 0 || time_to_live > 255)
713 return ERR_INVALID_ARGUMENT;
714 multicast_time_to_live_ = time_to_live;
715 return OK;
718 int UDPSocketLibevent::SetMulticastLoopbackMode(bool loopback) {
719 DCHECK(CalledOnValidThread());
720 if (is_connected())
721 return ERR_SOCKET_IS_CONNECTED;
723 if (loopback)
724 socket_options_ |= SOCKET_OPTION_MULTICAST_LOOP;
725 else
726 socket_options_ &= ~SOCKET_OPTION_MULTICAST_LOOP;
727 return OK;
730 int UDPSocketLibevent::SetDiffServCodePoint(DiffServCodePoint dscp) {
731 if (dscp == DSCP_NO_CHANGE) {
732 return OK;
734 int rv;
735 int dscp_and_ecn = dscp << 2;
736 if (addr_family_ == AF_INET) {
737 rv = setsockopt(socket_, IPPROTO_IP, IP_TOS,
738 &dscp_and_ecn, sizeof(dscp_and_ecn));
739 } else {
740 rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_TCLASS,
741 &dscp_and_ecn, sizeof(dscp_and_ecn));
743 if (rv < 0)
744 return MapSystemError(errno);
746 return OK;
749 void UDPSocketLibevent::DetachFromThread() {
750 base::NonThreadSafe::DetachFromThread();
753 } // namespace net