ChromeOS: Allow partial (uptime only) Uptime.Logout UMA metrics.
[chromium-blink-merge.git] / net / udp / udp_socket_libevent.cc
blob7db3f96dd128fb1f6d8c61e951b37455f0349fe4
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 <netdb.h>
10 #include <net/if.h>
11 #include <netinet/in.h>
12 #include <sys/ioctl.h>
13 #include <sys/socket.h>
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"
31 namespace net {
33 namespace {
35 const int kBindRetries = 10;
36 const int kPortStart = 1024;
37 const int kPortEnd = 65535;
39 #if defined(OS_MACOSX)
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;
47 ifreq ifr;
48 ifr.ifr_addr.sa_family = AF_INET;
49 if (!if_indextoname(index, ifr.ifr_name))
50 return MapSystemError(errno);
51 int rv = ioctl(socket, SIOCGIFADDR, &ifr);
52 if (rv == -1)
53 return MapSystemError(errno);
54 *address = reinterpret_cast<sockaddr_in*>(&ifr.ifr_addr)->sin_addr.s_addr;
55 return OK;
58 #endif // OS_MACOSX
60 } // namespace
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());
86 UDPSocketLibevent::~UDPSocketLibevent() {
87 Close();
88 net_log_.EndEvent(NetLog::TYPE_SOCKET_ALIVE);
91 void UDPSocketLibevent::Close() {
92 DCHECK(CalledOnValidThread());
94 if (!is_connected())
95 return;
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();
107 bool ok = read_socket_watcher_.StopWatchingFileDescriptor();
108 DCHECK(ok);
109 ok = write_socket_watcher_.StopWatchingFileDescriptor();
110 DCHECK(ok);
112 if (IGNORE_EINTR(close(socket_)) < 0)
113 PLOG(ERROR) << "close";
115 socket_ = kInvalidSocket;
116 addr_family_ = 0;
119 int UDPSocketLibevent::GetPeerAddress(IPEndPoint* address) const {
120 DCHECK(CalledOnValidThread());
121 DCHECK(address);
122 if (!is_connected())
123 return ERR_SOCKET_NOT_CONNECTED;
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_ADDRESS_INVALID;
132 remote_address_.reset(address.release());
135 *address = *remote_address_;
136 return OK;
139 int UDPSocketLibevent::GetLocalAddress(IPEndPoint* address) const {
140 DCHECK(CalledOnValidThread());
141 DCHECK(address);
142 if (!is_connected())
143 return ERR_SOCKET_NOT_CONNECTED;
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_ADDRESS_INVALID;
152 local_address_.reset(address.release());
153 net_log_.AddEvent(NetLog::TYPE_UDP_LOCAL_ADDRESS,
154 CreateNetLogUDPConnectCallback(local_address_.get()));
157 *address = *local_address_;
158 return OK;
161 int UDPSocketLibevent::Read(IOBuffer* buf,
162 int buf_len,
163 const CompletionCallback& callback) {
164 return RecvFrom(buf, buf_len, NULL, callback);
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);
178 int nread = InternalRecvFrom(buf, buf_len, address);
179 if (nread != ERR_IO_PENDING)
180 return nread;
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;
191 read_buf_ = buf;
192 read_buf_len_ = buf_len;
193 recv_from_address_ = address;
194 read_callback_ = callback;
195 return ERR_IO_PENDING;
198 int UDPSocketLibevent::Write(IOBuffer* buf,
199 int buf_len,
200 const CompletionCallback& callback) {
201 return SendToOrWrite(buf, buf_len, NULL, callback);
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);
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);
221 int result = InternalSendTo(buf, buf_len, address);
222 if (result != ERR_IO_PENDING)
223 return result;
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;
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));
240 write_callback_ = callback;
241 return ERR_IO_PENDING;
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;
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;
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);
271 // else connect() does the DatagramSocket::DEFAULT_BIND
273 if (rv < 0) {
274 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.UdpSocketRandomBindErrorCode", -rv);
275 Close();
276 return rv;
279 SockaddrStorage storage;
280 if (!address.ToSockAddr(storage.addr, &storage.addr_len)) {
281 Close();
282 return ERR_ADDRESS_INVALID;
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;
293 remote_address_.reset(new IPEndPoint(address));
294 return rv;
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;
304 rv = SetSocketOptions();
305 if (rv < 0) {
306 Close();
307 return rv;
309 rv = DoBind(address);
310 if (rv < 0) {
311 Close();
312 return rv;
314 local_address_.reset();
315 return rv;
318 int 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 int last_error = errno;
323 DCHECK(!rv) << "Could not set socket receive buffer size: " << last_error;
324 return rv == 0 ? OK : MapSystemError(last_error);
327 int UDPSocketLibevent::SetSendBufferSize(int32 size) {
328 DCHECK(CalledOnValidThread());
329 int rv = setsockopt(socket_, SOL_SOCKET, SO_SNDBUF,
330 reinterpret_cast<const char*>(&size), sizeof(size));
331 int last_error = errno;
332 DCHECK(!rv) << "Could not set socket send buffer size: " << last_error;
333 return rv == 0 ? OK : MapSystemError(last_error);
336 void UDPSocketLibevent::AllowAddressReuse() {
337 DCHECK(CalledOnValidThread());
338 DCHECK(!is_connected());
340 socket_options_ |= SOCKET_OPTION_REUSE_ADDRESS;
343 void UDPSocketLibevent::AllowBroadcast() {
344 DCHECK(CalledOnValidThread());
345 DCHECK(!is_connected());
347 socket_options_ |= SOCKET_OPTION_BROADCAST;
350 void UDPSocketLibevent::ReadWatcher::OnFileCanReadWithoutBlocking(int) {
351 if (!socket_->read_callback_.is_null())
352 socket_->DidCompleteRead();
355 void UDPSocketLibevent::WriteWatcher::OnFileCanWriteWithoutBlocking(int) {
356 if (!socket_->write_callback_.is_null())
357 socket_->DidCompleteWrite();
360 void UDPSocketLibevent::DoReadCallback(int rv) {
361 DCHECK_NE(rv, ERR_IO_PENDING);
362 DCHECK(!read_callback_.is_null());
364 // since Run may result in Read being called, clear read_callback_ up front.
365 CompletionCallback c = read_callback_;
366 read_callback_.Reset();
367 c.Run(rv);
370 void UDPSocketLibevent::DoWriteCallback(int rv) {
371 DCHECK_NE(rv, ERR_IO_PENDING);
372 DCHECK(!write_callback_.is_null());
374 // since Run may result in Write being called, clear write_callback_ up front.
375 CompletionCallback c = write_callback_;
376 write_callback_.Reset();
377 c.Run(rv);
380 void UDPSocketLibevent::DidCompleteRead() {
381 int result =
382 InternalRecvFrom(read_buf_.get(), read_buf_len_, recv_from_address_);
383 if (result != ERR_IO_PENDING) {
384 read_buf_ = NULL;
385 read_buf_len_ = 0;
386 recv_from_address_ = NULL;
387 bool ok = read_socket_watcher_.StopWatchingFileDescriptor();
388 DCHECK(ok);
389 DoReadCallback(result);
393 void UDPSocketLibevent::LogRead(int result,
394 const char* bytes,
395 socklen_t addr_len,
396 const sockaddr* addr) const {
397 if (result < 0) {
398 net_log_.AddEventWithNetErrorCode(NetLog::TYPE_UDP_RECEIVE_ERROR, result);
399 return;
402 if (net_log_.IsLogging()) {
403 DCHECK(addr_len > 0);
404 DCHECK(addr);
406 IPEndPoint address;
407 bool is_address_valid = address.FromSockAddr(addr, addr_len);
408 net_log_.AddEvent(
409 NetLog::TYPE_UDP_BYTES_RECEIVED,
410 CreateNetLogUDPDataTranferCallback(
411 result, bytes,
412 is_address_valid ? &address : NULL));
415 base::StatsCounter read_bytes("udp.read_bytes");
416 read_bytes.Add(result);
419 int UDPSocketLibevent::CreateSocket(int addr_family) {
420 addr_family_ = addr_family;
421 socket_ = CreatePlatformSocket(addr_family_, SOCK_DGRAM, 0);
422 if (socket_ == kInvalidSocket)
423 return MapSystemError(errno);
424 if (SetNonBlocking(socket_)) {
425 const int err = MapSystemError(errno);
426 Close();
427 return err;
429 return OK;
432 void UDPSocketLibevent::DidCompleteWrite() {
433 int result =
434 InternalSendTo(write_buf_.get(), write_buf_len_, send_to_address_.get());
436 if (result != ERR_IO_PENDING) {
437 write_buf_ = NULL;
438 write_buf_len_ = 0;
439 send_to_address_.reset();
440 write_socket_watcher_.StopWatchingFileDescriptor();
441 DoWriteCallback(result);
445 void UDPSocketLibevent::LogWrite(int result,
446 const char* bytes,
447 const IPEndPoint* address) const {
448 if (result < 0) {
449 net_log_.AddEventWithNetErrorCode(NetLog::TYPE_UDP_SEND_ERROR, result);
450 return;
453 if (net_log_.IsLogging()) {
454 net_log_.AddEvent(
455 NetLog::TYPE_UDP_BYTES_SENT,
456 CreateNetLogUDPDataTranferCallback(result, bytes, address));
459 base::StatsCounter write_bytes("udp.write_bytes");
460 write_bytes.Add(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::SetSocketOptions() {
519 int true_value = 1;
520 if (socket_options_ & SOCKET_OPTION_REUSE_ADDRESS) {
521 int rv = setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, &true_value,
522 sizeof(true_value));
523 if (rv < 0)
524 return MapSystemError(errno);
526 if (socket_options_ & SOCKET_OPTION_BROADCAST) {
527 int rv;
528 #if defined(OS_MACOSX)
529 // SO_REUSEPORT on OSX permits multiple processes to each receive
530 // UDP multicast or broadcast datagrams destined for the bound
531 // port.
532 rv = setsockopt(socket_, SOL_SOCKET, SO_REUSEPORT, &true_value,
533 sizeof(true_value));
534 #else
535 rv = setsockopt(socket_, SOL_SOCKET, SO_BROADCAST, &true_value,
536 sizeof(true_value));
537 #endif // defined(OS_MACOSX)
538 if (rv < 0)
539 return MapSystemError(errno);
542 if (!(socket_options_ & SOCKET_OPTION_MULTICAST_LOOP)) {
543 int rv;
544 if (addr_family_ == AF_INET) {
545 u_char loop = 0;
546 rv = setsockopt(socket_, IPPROTO_IP, IP_MULTICAST_LOOP,
547 &loop, sizeof(loop));
548 } else {
549 u_int loop = 0;
550 rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
551 &loop, sizeof(loop));
553 if (rv < 0)
554 return MapSystemError(errno);
556 if (multicast_time_to_live_ != IP_DEFAULT_MULTICAST_TTL) {
557 int rv;
558 if (addr_family_ == AF_INET) {
559 u_char ttl = multicast_time_to_live_;
560 rv = setsockopt(socket_, IPPROTO_IP, IP_MULTICAST_TTL,
561 &ttl, sizeof(ttl));
562 } else {
563 // Signed integer. -1 to use route default.
564 int ttl = multicast_time_to_live_;
565 rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
566 &ttl, sizeof(ttl));
568 if (rv < 0)
569 return MapSystemError(errno);
571 if (multicast_interface_ != 0) {
572 switch (addr_family_) {
573 case AF_INET: {
574 #if !defined(OS_MACOSX)
575 ip_mreqn mreq;
576 mreq.imr_ifindex = multicast_interface_;
577 mreq.imr_address.s_addr = htonl(INADDR_ANY);
578 #else
579 ip_mreq mreq;
580 int error = GetIPv4AddressFromIndex(socket_, multicast_interface_,
581 &mreq.imr_interface.s_addr);
582 if (error != OK)
583 return error;
584 #endif
585 int rv = setsockopt(socket_, IPPROTO_IP, IP_MULTICAST_IF,
586 reinterpret_cast<const char*>(&mreq), sizeof(mreq));
587 if (rv)
588 return MapSystemError(errno);
589 break;
591 case AF_INET6: {
592 uint32 interface_index = multicast_interface_;
593 int rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_MULTICAST_IF,
594 reinterpret_cast<const char*>(&interface_index),
595 sizeof(interface_index));
596 if (rv)
597 return MapSystemError(errno);
598 break;
600 default:
601 NOTREACHED() << "Invalid address family";
602 return ERR_ADDRESS_INVALID;
605 return OK;
608 int UDPSocketLibevent::DoBind(const IPEndPoint& address) {
609 SockaddrStorage storage;
610 if (!address.ToSockAddr(storage.addr, &storage.addr_len))
611 return ERR_ADDRESS_INVALID;
612 int rv = bind(socket_, storage.addr, storage.addr_len);
613 if (rv == 0)
614 return OK;
615 int last_error = errno;
616 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.UdpSocketBindErrorFromPosix", last_error);
617 #if defined(OS_CHROMEOS)
618 if (last_error == EINVAL)
619 return ERR_ADDRESS_IN_USE;
620 #elif defined(OS_MACOSX)
621 if (last_error == EADDRNOTAVAIL)
622 return ERR_ADDRESS_IN_USE;
623 #endif
624 return MapSystemError(last_error);
627 int UDPSocketLibevent::RandomBind(const IPAddressNumber& address) {
628 DCHECK(bind_type_ == DatagramSocket::RANDOM_BIND && !rand_int_cb_.is_null());
630 for (int i = 0; i < kBindRetries; ++i) {
631 int rv = DoBind(IPEndPoint(address,
632 rand_int_cb_.Run(kPortStart, kPortEnd)));
633 if (rv == OK || rv != ERR_ADDRESS_IN_USE)
634 return rv;
636 return DoBind(IPEndPoint(address, 0));
639 int UDPSocketLibevent::JoinGroup(const IPAddressNumber& group_address) const {
640 DCHECK(CalledOnValidThread());
641 if (!is_connected())
642 return ERR_SOCKET_NOT_CONNECTED;
644 switch (group_address.size()) {
645 case kIPv4AddressSize: {
646 if (addr_family_ != AF_INET)
647 return ERR_ADDRESS_INVALID;
649 #if !defined(OS_MACOSX)
650 ip_mreqn mreq;
651 mreq.imr_ifindex = multicast_interface_;
652 mreq.imr_address.s_addr = htonl(INADDR_ANY);
653 #else
654 ip_mreq mreq;
655 int error = GetIPv4AddressFromIndex(socket_, multicast_interface_,
656 &mreq.imr_interface.s_addr);
657 if (error != OK)
658 return error;
659 #endif
660 memcpy(&mreq.imr_multiaddr, &group_address[0], kIPv4AddressSize);
661 int rv = setsockopt(socket_, IPPROTO_IP, IP_ADD_MEMBERSHIP,
662 &mreq, sizeof(mreq));
663 if (rv < 0)
664 return MapSystemError(errno);
665 return OK;
667 case kIPv6AddressSize: {
668 if (addr_family_ != AF_INET6)
669 return ERR_ADDRESS_INVALID;
670 ipv6_mreq mreq;
671 mreq.ipv6mr_interface = multicast_interface_;
672 memcpy(&mreq.ipv6mr_multiaddr, &group_address[0], kIPv6AddressSize);
673 int rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_JOIN_GROUP,
674 &mreq, sizeof(mreq));
675 if (rv < 0)
676 return MapSystemError(errno);
677 return OK;
679 default:
680 NOTREACHED() << "Invalid address family";
681 return ERR_ADDRESS_INVALID;
685 int UDPSocketLibevent::LeaveGroup(const IPAddressNumber& group_address) const {
686 DCHECK(CalledOnValidThread());
688 if (!is_connected())
689 return ERR_SOCKET_NOT_CONNECTED;
691 switch (group_address.size()) {
692 case kIPv4AddressSize: {
693 if (addr_family_ != AF_INET)
694 return ERR_ADDRESS_INVALID;
695 ip_mreq mreq;
696 mreq.imr_interface.s_addr = INADDR_ANY;
697 memcpy(&mreq.imr_multiaddr, &group_address[0], kIPv4AddressSize);
698 int rv = setsockopt(socket_, IPPROTO_IP, IP_DROP_MEMBERSHIP,
699 &mreq, sizeof(mreq));
700 if (rv < 0)
701 return MapSystemError(errno);
702 return OK;
704 case kIPv6AddressSize: {
705 if (addr_family_ != AF_INET6)
706 return ERR_ADDRESS_INVALID;
707 ipv6_mreq mreq;
708 mreq.ipv6mr_interface = 0; // 0 indicates default multicast interface.
709 memcpy(&mreq.ipv6mr_multiaddr, &group_address[0], kIPv6AddressSize);
710 int rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
711 &mreq, sizeof(mreq));
712 if (rv < 0)
713 return MapSystemError(errno);
714 return OK;
716 default:
717 NOTREACHED() << "Invalid address family";
718 return ERR_ADDRESS_INVALID;
722 int UDPSocketLibevent::SetMulticastInterface(uint32 interface_index) {
723 DCHECK(CalledOnValidThread());
724 if (is_connected())
725 return ERR_SOCKET_IS_CONNECTED;
726 multicast_interface_ = interface_index;
727 return OK;
730 int UDPSocketLibevent::SetMulticastTimeToLive(int time_to_live) {
731 DCHECK(CalledOnValidThread());
732 if (is_connected())
733 return ERR_SOCKET_IS_CONNECTED;
735 if (time_to_live < 0 || time_to_live > 255)
736 return ERR_INVALID_ARGUMENT;
737 multicast_time_to_live_ = time_to_live;
738 return OK;
741 int UDPSocketLibevent::SetMulticastLoopbackMode(bool loopback) {
742 DCHECK(CalledOnValidThread());
743 if (is_connected())
744 return ERR_SOCKET_IS_CONNECTED;
746 if (loopback)
747 socket_options_ |= SOCKET_OPTION_MULTICAST_LOOP;
748 else
749 socket_options_ &= ~SOCKET_OPTION_MULTICAST_LOOP;
750 return OK;
753 int UDPSocketLibevent::SetDiffServCodePoint(DiffServCodePoint dscp) {
754 if (dscp == DSCP_NO_CHANGE) {
755 return OK;
757 int rv;
758 int dscp_and_ecn = dscp << 2;
759 if (addr_family_ == AF_INET) {
760 rv = setsockopt(socket_, IPPROTO_IP, IP_TOS,
761 &dscp_and_ecn, sizeof(dscp_and_ecn));
762 } else {
763 rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_TCLASS,
764 &dscp_and_ecn, sizeof(dscp_and_ecn));
766 if (rv < 0)
767 return MapSystemError(errno);
769 return OK;
772 void UDPSocketLibevent::DetachFromThread() {
773 base::NonThreadSafe::DetachFromThread();
776 } // namespace net