Add a function to create a bookmark app from a WebApplicationInfo.
[chromium-blink-merge.git] / net / udp / udp_socket_libevent.cc
blob564627631a823b8e6c5efd7c9885e789aa056603
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 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;
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;
334 void UDPSocketLibevent::AllowAddressReuse() {
335 DCHECK(CalledOnValidThread());
336 DCHECK(!is_connected());
338 socket_options_ |= SOCKET_OPTION_REUSE_ADDRESS;
341 void UDPSocketLibevent::AllowBroadcast() {
342 DCHECK(CalledOnValidThread());
343 DCHECK(!is_connected());
345 socket_options_ |= SOCKET_OPTION_BROADCAST;
348 void UDPSocketLibevent::ReadWatcher::OnFileCanReadWithoutBlocking(int) {
349 if (!socket_->read_callback_.is_null())
350 socket_->DidCompleteRead();
353 void UDPSocketLibevent::WriteWatcher::OnFileCanWriteWithoutBlocking(int) {
354 if (!socket_->write_callback_.is_null())
355 socket_->DidCompleteWrite();
358 void UDPSocketLibevent::DoReadCallback(int rv) {
359 DCHECK_NE(rv, ERR_IO_PENDING);
360 DCHECK(!read_callback_.is_null());
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);
368 void UDPSocketLibevent::DoWriteCallback(int rv) {
369 DCHECK_NE(rv, ERR_IO_PENDING);
370 DCHECK(!write_callback_.is_null());
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);
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);
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;
400 if (net_log_.IsLogging()) {
401 DCHECK(addr_len > 0);
402 DCHECK(addr);
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));
413 base::StatsCounter read_bytes("udp.read_bytes");
414 read_bytes.Add(result);
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;
427 return OK;
430 void UDPSocketLibevent::DidCompleteWrite() {
431 int result =
432 InternalSendTo(write_buf_.get(), write_buf_len_, send_to_address_.get());
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);
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;
451 if (net_log_.IsLogging()) {
452 net_log_.AddEvent(
453 NetLog::TYPE_UDP_BYTES_SENT,
454 CreateNetLogUDPDataTranferCallback(result, bytes, address));
457 base::StatsCounter write_bytes("udp.write_bytes");
458 write_bytes.Add(result);
461 int UDPSocketLibevent::InternalRecvFrom(IOBuffer* buf, int buf_len,
462 IPEndPoint* address) {
463 int bytes_transferred;
464 int flags = 0;
466 SockaddrStorage storage;
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_ADDRESS_INVALID;
480 } else {
481 result = MapSystemError(errno);
483 if (result != ERR_IO_PENDING)
484 LogRead(result, buf->data(), storage.addr_len, storage.addr);
485 return result;
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_ADDRESS_INVALID;
498 LogWrite(result, NULL, NULL);
499 return result;
503 int result = HANDLE_EINTR(sendto(socket_,
504 buf->data(),
505 buf_len,
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;
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);
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);
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));
551 if (rv < 0)
552 return MapSystemError(errno);
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));
566 if (rv < 0)
567 return MapSystemError(errno);
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;
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;
598 default:
599 NOTREACHED() << "Invalid address family";
600 return ERR_ADDRESS_INVALID;
603 return OK;
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 #if defined(OS_CHROMEOS)
616 if (last_error == EINVAL)
617 return ERR_ADDRESS_IN_USE;
618 #elif defined(OS_MACOSX)
619 if (last_error == EADDRNOTAVAIL)
620 return ERR_ADDRESS_IN_USE;
621 #endif
622 return MapSystemError(last_error);
625 int UDPSocketLibevent::RandomBind(const IPAddressNumber& address) {
626 DCHECK(bind_type_ == DatagramSocket::RANDOM_BIND && !rand_int_cb_.is_null());
628 for (int i = 0; i < kBindRetries; ++i) {
629 int rv = DoBind(IPEndPoint(address,
630 rand_int_cb_.Run(kPortStart, kPortEnd)));
631 if (rv == OK || rv != ERR_ADDRESS_IN_USE)
632 return rv;
634 return DoBind(IPEndPoint(address, 0));
637 int UDPSocketLibevent::JoinGroup(const IPAddressNumber& group_address) const {
638 DCHECK(CalledOnValidThread());
639 if (!is_connected())
640 return ERR_SOCKET_NOT_CONNECTED;
642 switch (group_address.size()) {
643 case kIPv4AddressSize: {
644 if (addr_family_ != AF_INET)
645 return ERR_ADDRESS_INVALID;
647 #if !defined(OS_MACOSX)
648 ip_mreqn mreq;
649 mreq.imr_ifindex = multicast_interface_;
650 mreq.imr_address.s_addr = htonl(INADDR_ANY);
651 #else
652 ip_mreq mreq;
653 int error = GetIPv4AddressFromIndex(socket_, multicast_interface_,
654 &mreq.imr_interface.s_addr);
655 if (error != OK)
656 return error;
657 #endif
658 memcpy(&mreq.imr_multiaddr, &group_address[0], kIPv4AddressSize);
659 int rv = setsockopt(socket_, IPPROTO_IP, IP_ADD_MEMBERSHIP,
660 &mreq, sizeof(mreq));
661 if (rv < 0)
662 return MapSystemError(errno);
663 return OK;
665 case kIPv6AddressSize: {
666 if (addr_family_ != AF_INET6)
667 return ERR_ADDRESS_INVALID;
668 ipv6_mreq mreq;
669 mreq.ipv6mr_interface = multicast_interface_;
670 memcpy(&mreq.ipv6mr_multiaddr, &group_address[0], kIPv6AddressSize);
671 int rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_JOIN_GROUP,
672 &mreq, sizeof(mreq));
673 if (rv < 0)
674 return MapSystemError(errno);
675 return OK;
677 default:
678 NOTREACHED() << "Invalid address family";
679 return ERR_ADDRESS_INVALID;
683 int UDPSocketLibevent::LeaveGroup(const IPAddressNumber& group_address) const {
684 DCHECK(CalledOnValidThread());
686 if (!is_connected())
687 return ERR_SOCKET_NOT_CONNECTED;
689 switch (group_address.size()) {
690 case kIPv4AddressSize: {
691 if (addr_family_ != AF_INET)
692 return ERR_ADDRESS_INVALID;
693 ip_mreq mreq;
694 mreq.imr_interface.s_addr = INADDR_ANY;
695 memcpy(&mreq.imr_multiaddr, &group_address[0], kIPv4AddressSize);
696 int rv = setsockopt(socket_, IPPROTO_IP, IP_DROP_MEMBERSHIP,
697 &mreq, sizeof(mreq));
698 if (rv < 0)
699 return MapSystemError(errno);
700 return OK;
702 case kIPv6AddressSize: {
703 if (addr_family_ != AF_INET6)
704 return ERR_ADDRESS_INVALID;
705 ipv6_mreq mreq;
706 mreq.ipv6mr_interface = 0; // 0 indicates default multicast interface.
707 memcpy(&mreq.ipv6mr_multiaddr, &group_address[0], kIPv6AddressSize);
708 int rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
709 &mreq, sizeof(mreq));
710 if (rv < 0)
711 return MapSystemError(errno);
712 return OK;
714 default:
715 NOTREACHED() << "Invalid address family";
716 return ERR_ADDRESS_INVALID;
720 int UDPSocketLibevent::SetMulticastInterface(uint32 interface_index) {
721 DCHECK(CalledOnValidThread());
722 if (is_connected())
723 return ERR_SOCKET_IS_CONNECTED;
724 multicast_interface_ = interface_index;
725 return OK;
728 int UDPSocketLibevent::SetMulticastTimeToLive(int time_to_live) {
729 DCHECK(CalledOnValidThread());
730 if (is_connected())
731 return ERR_SOCKET_IS_CONNECTED;
733 if (time_to_live < 0 || time_to_live > 255)
734 return ERR_INVALID_ARGUMENT;
735 multicast_time_to_live_ = time_to_live;
736 return OK;
739 int UDPSocketLibevent::SetMulticastLoopbackMode(bool loopback) {
740 DCHECK(CalledOnValidThread());
741 if (is_connected())
742 return ERR_SOCKET_IS_CONNECTED;
744 if (loopback)
745 socket_options_ |= SOCKET_OPTION_MULTICAST_LOOP;
746 else
747 socket_options_ &= ~SOCKET_OPTION_MULTICAST_LOOP;
748 return OK;
751 int UDPSocketLibevent::SetDiffServCodePoint(DiffServCodePoint dscp) {
752 if (dscp == DSCP_NO_CHANGE) {
753 return OK;
755 int rv;
756 int dscp_and_ecn = dscp << 2;
757 if (addr_family_ == AF_INET) {
758 rv = setsockopt(socket_, IPPROTO_IP, IP_TOS,
759 &dscp_and_ecn, sizeof(dscp_and_ecn));
760 } else {
761 rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_TCLASS,
762 &dscp_and_ecn, sizeof(dscp_and_ecn));
764 if (rv < 0)
765 return MapSystemError(errno);
767 return OK;
770 void UDPSocketLibevent::DetachFromThread() {
771 base::NonThreadSafe::DetachFromThread();
774 } // namespace net