Refactors gesture conversion functions to ui/events/blink
[chromium-blink-merge.git] / net / udp / udp_socket_libevent.cc
blob04fd8a9691481e31c40849b05b051292cdac0f89
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/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_log.h"
26 #include "net/base/net_util.h"
27 #include "net/base/network_activity_monitor.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 if (IGNORE_EINTR(close(socket_)) == -1) {
131 int last_error = errno;
132 base::debug::Alias(&last_error);
133 // Crash on any error other than EIO.
134 PCHECK(last_error == EIO);
137 socket_ = kInvalidSocket;
138 addr_family_ = 0;
139 is_connected_ = false;
142 int UDPSocketLibevent::GetPeerAddress(IPEndPoint* address) const {
143 DCHECK(CalledOnValidThread());
144 DCHECK(address);
145 if (!is_connected())
146 return ERR_SOCKET_NOT_CONNECTED;
148 if (!remote_address_.get()) {
149 SockaddrStorage storage;
150 if (getpeername(socket_, storage.addr, &storage.addr_len))
151 return MapSystemError(errno);
152 scoped_ptr<IPEndPoint> address(new IPEndPoint());
153 if (!address->FromSockAddr(storage.addr, storage.addr_len))
154 return ERR_ADDRESS_INVALID;
155 remote_address_.reset(address.release());
158 *address = *remote_address_;
159 return OK;
162 int UDPSocketLibevent::GetLocalAddress(IPEndPoint* address) const {
163 DCHECK(CalledOnValidThread());
164 DCHECK(address);
165 if (!is_connected())
166 return ERR_SOCKET_NOT_CONNECTED;
168 if (!local_address_.get()) {
169 SockaddrStorage storage;
170 if (getsockname(socket_, storage.addr, &storage.addr_len))
171 return MapSystemError(errno);
172 scoped_ptr<IPEndPoint> address(new IPEndPoint());
173 if (!address->FromSockAddr(storage.addr, storage.addr_len))
174 return ERR_ADDRESS_INVALID;
175 local_address_.reset(address.release());
176 net_log_.AddEvent(NetLog::TYPE_UDP_LOCAL_ADDRESS,
177 CreateNetLogUDPConnectCallback(local_address_.get()));
180 *address = *local_address_;
181 return OK;
184 int UDPSocketLibevent::Read(IOBuffer* buf,
185 int buf_len,
186 const CompletionCallback& callback) {
187 return RecvFrom(buf, buf_len, NULL, callback);
190 int UDPSocketLibevent::RecvFrom(IOBuffer* buf,
191 int buf_len,
192 IPEndPoint* address,
193 const CompletionCallback& callback) {
194 DCHECK(CalledOnValidThread());
195 DCHECK_NE(kInvalidSocket, socket_);
196 CHECK(read_callback_.is_null());
197 DCHECK(!recv_from_address_);
198 DCHECK(!callback.is_null()); // Synchronous operation not supported
199 DCHECK_GT(buf_len, 0);
201 int nread = InternalRecvFrom(buf, buf_len, address);
202 if (nread != ERR_IO_PENDING)
203 return nread;
205 if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
206 socket_, true, base::MessageLoopForIO::WATCH_READ,
207 &read_socket_watcher_, &read_watcher_)) {
208 PLOG(ERROR) << "WatchFileDescriptor failed on read";
209 int result = MapSystemError(errno);
210 LogRead(result, NULL, 0, NULL);
211 return result;
214 read_buf_ = buf;
215 read_buf_len_ = buf_len;
216 recv_from_address_ = address;
217 read_callback_ = callback;
218 return ERR_IO_PENDING;
221 int UDPSocketLibevent::Write(IOBuffer* buf,
222 int buf_len,
223 const CompletionCallback& callback) {
224 return SendToOrWrite(buf, buf_len, NULL, callback);
227 int UDPSocketLibevent::SendTo(IOBuffer* buf,
228 int buf_len,
229 const IPEndPoint& address,
230 const CompletionCallback& callback) {
231 return SendToOrWrite(buf, buf_len, &address, callback);
234 int UDPSocketLibevent::SendToOrWrite(IOBuffer* buf,
235 int buf_len,
236 const IPEndPoint* address,
237 const CompletionCallback& callback) {
238 DCHECK(CalledOnValidThread());
239 DCHECK_NE(kInvalidSocket, socket_);
240 CHECK(write_callback_.is_null());
241 DCHECK(!callback.is_null()); // Synchronous operation not supported
242 DCHECK_GT(buf_len, 0);
244 int result = InternalSendTo(buf, buf_len, address);
245 if (result != ERR_IO_PENDING)
246 return result;
248 if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
249 socket_, true, base::MessageLoopForIO::WATCH_WRITE,
250 &write_socket_watcher_, &write_watcher_)) {
251 DVLOG(1) << "WatchFileDescriptor failed on write, errno " << errno;
252 int result = MapSystemError(errno);
253 LogWrite(result, NULL, NULL);
254 return result;
257 write_buf_ = buf;
258 write_buf_len_ = buf_len;
259 DCHECK(!send_to_address_.get());
260 if (address) {
261 send_to_address_.reset(new IPEndPoint(*address));
263 write_callback_ = callback;
264 return ERR_IO_PENDING;
267 int UDPSocketLibevent::Connect(const IPEndPoint& address) {
268 DCHECK_NE(socket_, kInvalidSocket);
269 net_log_.BeginEvent(NetLog::TYPE_UDP_CONNECT,
270 CreateNetLogUDPConnectCallback(&address));
271 int rv = InternalConnect(address);
272 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_UDP_CONNECT, rv);
273 is_connected_ = (rv == OK);
274 return rv;
277 int UDPSocketLibevent::InternalConnect(const IPEndPoint& address) {
278 DCHECK(CalledOnValidThread());
279 DCHECK(!is_connected());
280 DCHECK(!remote_address_.get());
282 int rv = 0;
283 if (bind_type_ == DatagramSocket::RANDOM_BIND) {
284 // Construct IPAddressNumber of appropriate size (IPv4 or IPv6) of 0s,
285 // representing INADDR_ANY or in6addr_any.
286 size_t addr_size = address.GetSockAddrFamily() == AF_INET ?
287 kIPv4AddressSize : kIPv6AddressSize;
288 IPAddressNumber addr_any(addr_size);
289 rv = RandomBind(addr_any);
291 // else connect() does the DatagramSocket::DEFAULT_BIND
293 if (rv < 0) {
294 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.UdpSocketRandomBindErrorCode", -rv);
295 return rv;
298 SockaddrStorage storage;
299 if (!address.ToSockAddr(storage.addr, &storage.addr_len))
300 return ERR_ADDRESS_INVALID;
302 rv = HANDLE_EINTR(connect(socket_, storage.addr, storage.addr_len));
303 if (rv < 0)
304 return MapSystemError(errno);
306 remote_address_.reset(new IPEndPoint(address));
307 return rv;
310 int UDPSocketLibevent::Bind(const IPEndPoint& address) {
311 DCHECK_NE(socket_, kInvalidSocket);
312 DCHECK(CalledOnValidThread());
313 DCHECK(!is_connected());
315 int rv = SetMulticastOptions();
316 if (rv < 0)
317 return rv;
319 rv = DoBind(address);
320 if (rv < 0)
321 return rv;
323 is_connected_ = true;
324 local_address_.reset();
325 return rv;
328 int UDPSocketLibevent::SetReceiveBufferSize(int32 size) {
329 DCHECK_NE(socket_, kInvalidSocket);
330 DCHECK(CalledOnValidThread());
331 int rv = setsockopt(socket_, SOL_SOCKET, SO_RCVBUF,
332 reinterpret_cast<const char*>(&size), sizeof(size));
333 return rv == 0 ? OK : MapSystemError(errno);
336 int UDPSocketLibevent::SetSendBufferSize(int32 size) {
337 DCHECK_NE(socket_, kInvalidSocket);
338 DCHECK(CalledOnValidThread());
339 int rv = setsockopt(socket_, SOL_SOCKET, SO_SNDBUF,
340 reinterpret_cast<const char*>(&size), sizeof(size));
341 return rv == 0 ? OK : MapSystemError(errno);
344 int UDPSocketLibevent::AllowAddressReuse() {
345 DCHECK_NE(socket_, kInvalidSocket);
346 DCHECK(CalledOnValidThread());
347 DCHECK(!is_connected());
348 int true_value = 1;
349 int rv = setsockopt(
350 socket_, SOL_SOCKET, SO_REUSEADDR, &true_value, sizeof(true_value));
351 return rv == 0 ? OK : MapSystemError(errno);
354 int UDPSocketLibevent::SetBroadcast(bool broadcast) {
355 DCHECK_NE(socket_, kInvalidSocket);
356 DCHECK(CalledOnValidThread());
357 int value = broadcast ? 1 : 0;
358 int rv;
359 #if defined(OS_MACOSX)
360 // SO_REUSEPORT on OSX permits multiple processes to each receive
361 // UDP multicast or broadcast datagrams destined for the bound
362 // port.
363 rv = setsockopt(socket_, SOL_SOCKET, SO_REUSEPORT, &value, sizeof(value));
364 #else
365 rv = setsockopt(socket_, SOL_SOCKET, SO_BROADCAST, &value, sizeof(value));
366 #endif // defined(OS_MACOSX)
367 return rv == 0 ? OK : MapSystemError(errno);
370 void UDPSocketLibevent::ReadWatcher::OnFileCanReadWithoutBlocking(int) {
371 if (!socket_->read_callback_.is_null())
372 socket_->DidCompleteRead();
375 void UDPSocketLibevent::WriteWatcher::OnFileCanWriteWithoutBlocking(int) {
376 if (!socket_->write_callback_.is_null())
377 socket_->DidCompleteWrite();
380 void UDPSocketLibevent::DoReadCallback(int rv) {
381 DCHECK_NE(rv, ERR_IO_PENDING);
382 DCHECK(!read_callback_.is_null());
384 // since Run may result in Read being called, clear read_callback_ up front.
385 CompletionCallback c = read_callback_;
386 read_callback_.Reset();
387 c.Run(rv);
390 void UDPSocketLibevent::DoWriteCallback(int rv) {
391 DCHECK_NE(rv, ERR_IO_PENDING);
392 DCHECK(!write_callback_.is_null());
394 // since Run may result in Write being called, clear write_callback_ up front.
395 CompletionCallback c = write_callback_;
396 write_callback_.Reset();
397 c.Run(rv);
400 void UDPSocketLibevent::DidCompleteRead() {
401 int result =
402 InternalRecvFrom(read_buf_.get(), read_buf_len_, recv_from_address_);
403 if (result != ERR_IO_PENDING) {
404 read_buf_ = NULL;
405 read_buf_len_ = 0;
406 recv_from_address_ = NULL;
407 bool ok = read_socket_watcher_.StopWatchingFileDescriptor();
408 DCHECK(ok);
409 DoReadCallback(result);
413 void UDPSocketLibevent::LogRead(int result,
414 const char* bytes,
415 socklen_t addr_len,
416 const sockaddr* addr) const {
417 if (result < 0) {
418 net_log_.AddEventWithNetErrorCode(NetLog::TYPE_UDP_RECEIVE_ERROR, result);
419 return;
422 if (net_log_.IsLogging()) {
423 DCHECK(addr_len > 0);
424 DCHECK(addr);
426 IPEndPoint address;
427 bool is_address_valid = address.FromSockAddr(addr, addr_len);
428 net_log_.AddEvent(
429 NetLog::TYPE_UDP_BYTES_RECEIVED,
430 CreateNetLogUDPDataTranferCallback(
431 result, bytes,
432 is_address_valid ? &address : NULL));
435 NetworkActivityMonitor::GetInstance()->IncrementBytesReceived(result);
438 void UDPSocketLibevent::DidCompleteWrite() {
439 int result =
440 InternalSendTo(write_buf_.get(), write_buf_len_, send_to_address_.get());
442 if (result != ERR_IO_PENDING) {
443 write_buf_ = NULL;
444 write_buf_len_ = 0;
445 send_to_address_.reset();
446 write_socket_watcher_.StopWatchingFileDescriptor();
447 DoWriteCallback(result);
451 void UDPSocketLibevent::LogWrite(int result,
452 const char* bytes,
453 const IPEndPoint* address) const {
454 if (result < 0) {
455 net_log_.AddEventWithNetErrorCode(NetLog::TYPE_UDP_SEND_ERROR, result);
456 return;
459 if (net_log_.IsLogging()) {
460 net_log_.AddEvent(
461 NetLog::TYPE_UDP_BYTES_SENT,
462 CreateNetLogUDPDataTranferCallback(result, bytes, address));
465 NetworkActivityMonitor::GetInstance()->IncrementBytesSent(result);
468 int UDPSocketLibevent::InternalRecvFrom(IOBuffer* buf, int buf_len,
469 IPEndPoint* address) {
470 int bytes_transferred;
471 int flags = 0;
473 SockaddrStorage storage;
475 bytes_transferred =
476 HANDLE_EINTR(recvfrom(socket_,
477 buf->data(),
478 buf_len,
479 flags,
480 storage.addr,
481 &storage.addr_len));
482 int result;
483 if (bytes_transferred >= 0) {
484 result = bytes_transferred;
485 if (address && !address->FromSockAddr(storage.addr, storage.addr_len))
486 result = ERR_ADDRESS_INVALID;
487 } else {
488 result = MapSystemError(errno);
490 if (result != ERR_IO_PENDING)
491 LogRead(result, buf->data(), storage.addr_len, storage.addr);
492 return result;
495 int UDPSocketLibevent::InternalSendTo(IOBuffer* buf, int buf_len,
496 const IPEndPoint* address) {
497 SockaddrStorage storage;
498 struct sockaddr* addr = storage.addr;
499 if (!address) {
500 addr = NULL;
501 storage.addr_len = 0;
502 } else {
503 if (!address->ToSockAddr(storage.addr, &storage.addr_len)) {
504 int result = ERR_ADDRESS_INVALID;
505 LogWrite(result, NULL, NULL);
506 return result;
510 int result = HANDLE_EINTR(sendto(socket_,
511 buf->data(),
512 buf_len,
514 addr,
515 storage.addr_len));
516 if (result < 0)
517 result = MapSystemError(errno);
518 if (result != ERR_IO_PENDING)
519 LogWrite(result, buf->data(), address);
520 return result;
523 int UDPSocketLibevent::SetMulticastOptions() {
524 if (!(socket_options_ & SOCKET_OPTION_MULTICAST_LOOP)) {
525 int rv;
526 if (addr_family_ == AF_INET) {
527 u_char loop = 0;
528 rv = setsockopt(socket_, IPPROTO_IP, IP_MULTICAST_LOOP,
529 &loop, sizeof(loop));
530 } else {
531 u_int loop = 0;
532 rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
533 &loop, sizeof(loop));
535 if (rv < 0)
536 return MapSystemError(errno);
538 if (multicast_time_to_live_ != IP_DEFAULT_MULTICAST_TTL) {
539 int rv;
540 if (addr_family_ == AF_INET) {
541 u_char ttl = multicast_time_to_live_;
542 rv = setsockopt(socket_, IPPROTO_IP, IP_MULTICAST_TTL,
543 &ttl, sizeof(ttl));
544 } else {
545 // Signed integer. -1 to use route default.
546 int ttl = multicast_time_to_live_;
547 rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
548 &ttl, sizeof(ttl));
550 if (rv < 0)
551 return MapSystemError(errno);
553 if (multicast_interface_ != 0) {
554 switch (addr_family_) {
555 case AF_INET: {
556 #if !defined(OS_MACOSX)
557 ip_mreqn mreq;
558 mreq.imr_ifindex = multicast_interface_;
559 mreq.imr_address.s_addr = htonl(INADDR_ANY);
560 #else
561 ip_mreq mreq;
562 int error = GetIPv4AddressFromIndex(socket_, multicast_interface_,
563 &mreq.imr_interface.s_addr);
564 if (error != OK)
565 return error;
566 #endif
567 int rv = setsockopt(socket_, IPPROTO_IP, IP_MULTICAST_IF,
568 reinterpret_cast<const char*>(&mreq), sizeof(mreq));
569 if (rv)
570 return MapSystemError(errno);
571 break;
573 case AF_INET6: {
574 uint32 interface_index = multicast_interface_;
575 int rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_MULTICAST_IF,
576 reinterpret_cast<const char*>(&interface_index),
577 sizeof(interface_index));
578 if (rv)
579 return MapSystemError(errno);
580 break;
582 default:
583 NOTREACHED() << "Invalid address family";
584 return ERR_ADDRESS_INVALID;
587 return OK;
590 int UDPSocketLibevent::DoBind(const IPEndPoint& address) {
591 SockaddrStorage storage;
592 if (!address.ToSockAddr(storage.addr, &storage.addr_len))
593 return ERR_ADDRESS_INVALID;
594 int rv = bind(socket_, storage.addr, storage.addr_len);
595 if (rv == 0)
596 return OK;
597 int last_error = errno;
598 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.UdpSocketBindErrorFromPosix", last_error);
599 #if defined(OS_CHROMEOS)
600 if (last_error == EINVAL)
601 return ERR_ADDRESS_IN_USE;
602 #elif defined(OS_MACOSX)
603 if (last_error == EADDRNOTAVAIL)
604 return ERR_ADDRESS_IN_USE;
605 #endif
606 return MapSystemError(last_error);
609 int UDPSocketLibevent::RandomBind(const IPAddressNumber& address) {
610 DCHECK(bind_type_ == DatagramSocket::RANDOM_BIND && !rand_int_cb_.is_null());
612 for (int i = 0; i < kBindRetries; ++i) {
613 int rv = DoBind(IPEndPoint(address,
614 rand_int_cb_.Run(kPortStart, kPortEnd)));
615 if (rv == OK || rv != ERR_ADDRESS_IN_USE)
616 return rv;
618 return DoBind(IPEndPoint(address, 0));
621 int UDPSocketLibevent::JoinGroup(const IPAddressNumber& group_address) const {
622 DCHECK(CalledOnValidThread());
623 if (!is_connected())
624 return ERR_SOCKET_NOT_CONNECTED;
626 switch (group_address.size()) {
627 case kIPv4AddressSize: {
628 if (addr_family_ != AF_INET)
629 return ERR_ADDRESS_INVALID;
631 #if !defined(OS_MACOSX)
632 ip_mreqn mreq;
633 mreq.imr_ifindex = multicast_interface_;
634 mreq.imr_address.s_addr = htonl(INADDR_ANY);
635 #else
636 ip_mreq mreq;
637 int error = GetIPv4AddressFromIndex(socket_, multicast_interface_,
638 &mreq.imr_interface.s_addr);
639 if (error != OK)
640 return error;
641 #endif
642 memcpy(&mreq.imr_multiaddr, &group_address[0], kIPv4AddressSize);
643 int rv = setsockopt(socket_, IPPROTO_IP, IP_ADD_MEMBERSHIP,
644 &mreq, sizeof(mreq));
645 if (rv < 0)
646 return MapSystemError(errno);
647 return OK;
649 case kIPv6AddressSize: {
650 if (addr_family_ != AF_INET6)
651 return ERR_ADDRESS_INVALID;
652 ipv6_mreq mreq;
653 mreq.ipv6mr_interface = multicast_interface_;
654 memcpy(&mreq.ipv6mr_multiaddr, &group_address[0], kIPv6AddressSize);
655 int rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_JOIN_GROUP,
656 &mreq, sizeof(mreq));
657 if (rv < 0)
658 return MapSystemError(errno);
659 return OK;
661 default:
662 NOTREACHED() << "Invalid address family";
663 return ERR_ADDRESS_INVALID;
667 int UDPSocketLibevent::LeaveGroup(const IPAddressNumber& group_address) const {
668 DCHECK(CalledOnValidThread());
670 if (!is_connected())
671 return ERR_SOCKET_NOT_CONNECTED;
673 switch (group_address.size()) {
674 case kIPv4AddressSize: {
675 if (addr_family_ != AF_INET)
676 return ERR_ADDRESS_INVALID;
677 ip_mreq mreq;
678 mreq.imr_interface.s_addr = INADDR_ANY;
679 memcpy(&mreq.imr_multiaddr, &group_address[0], kIPv4AddressSize);
680 int rv = setsockopt(socket_, IPPROTO_IP, IP_DROP_MEMBERSHIP,
681 &mreq, sizeof(mreq));
682 if (rv < 0)
683 return MapSystemError(errno);
684 return OK;
686 case kIPv6AddressSize: {
687 if (addr_family_ != AF_INET6)
688 return ERR_ADDRESS_INVALID;
689 ipv6_mreq mreq;
690 mreq.ipv6mr_interface = 0; // 0 indicates default multicast interface.
691 memcpy(&mreq.ipv6mr_multiaddr, &group_address[0], kIPv6AddressSize);
692 int rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
693 &mreq, sizeof(mreq));
694 if (rv < 0)
695 return MapSystemError(errno);
696 return OK;
698 default:
699 NOTREACHED() << "Invalid address family";
700 return ERR_ADDRESS_INVALID;
704 int UDPSocketLibevent::SetMulticastInterface(uint32 interface_index) {
705 DCHECK(CalledOnValidThread());
706 if (is_connected())
707 return ERR_SOCKET_IS_CONNECTED;
708 multicast_interface_ = interface_index;
709 return OK;
712 int UDPSocketLibevent::SetMulticastTimeToLive(int time_to_live) {
713 DCHECK(CalledOnValidThread());
714 if (is_connected())
715 return ERR_SOCKET_IS_CONNECTED;
717 if (time_to_live < 0 || time_to_live > 255)
718 return ERR_INVALID_ARGUMENT;
719 multicast_time_to_live_ = time_to_live;
720 return OK;
723 int UDPSocketLibevent::SetMulticastLoopbackMode(bool loopback) {
724 DCHECK(CalledOnValidThread());
725 if (is_connected())
726 return ERR_SOCKET_IS_CONNECTED;
728 if (loopback)
729 socket_options_ |= SOCKET_OPTION_MULTICAST_LOOP;
730 else
731 socket_options_ &= ~SOCKET_OPTION_MULTICAST_LOOP;
732 return OK;
735 int UDPSocketLibevent::SetDiffServCodePoint(DiffServCodePoint dscp) {
736 if (dscp == DSCP_NO_CHANGE) {
737 return OK;
739 int rv;
740 int dscp_and_ecn = dscp << 2;
741 if (addr_family_ == AF_INET) {
742 rv = setsockopt(socket_, IPPROTO_IP, IP_TOS,
743 &dscp_and_ecn, sizeof(dscp_and_ecn));
744 } else {
745 rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_TCLASS,
746 &dscp_and_ecn, sizeof(dscp_and_ecn));
748 if (rv < 0)
749 return MapSystemError(errno);
751 return OK;
754 void UDPSocketLibevent::DetachFromThread() {
755 base::NonThreadSafe::DetachFromThread();
758 } // namespace net