Explicitly add python-numpy dependency to install-build-deps.
[chromium-blink-merge.git] / net / udp / udp_socket_libevent.cc
blob2dffff3a31090eafbda962472c2840d0d3ceca2e
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/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 socket_options_(SOCKET_OPTION_MULTICAST_LOOP),
71 multicast_interface_(0),
72 multicast_time_to_live_(1),
73 bind_type_(bind_type),
74 rand_int_cb_(rand_int_cb),
75 read_watcher_(this),
76 write_watcher_(this),
77 read_buf_len_(0),
78 recv_from_address_(NULL),
79 write_buf_len_(0),
80 net_log_(BoundNetLog::Make(net_log, NetLog::SOURCE_UDP_SOCKET)) {
81 net_log_.BeginEvent(NetLog::TYPE_SOCKET_ALIVE,
82 source.ToEventParametersCallback());
83 if (bind_type == DatagramSocket::RANDOM_BIND)
84 DCHECK(!rand_int_cb.is_null());
87 UDPSocketLibevent::~UDPSocketLibevent() {
88 Close();
89 net_log_.EndEvent(NetLog::TYPE_SOCKET_ALIVE);
92 void UDPSocketLibevent::Close() {
93 DCHECK(CalledOnValidThread());
95 if (!is_connected())
96 return;
98 // Zero out any pending read/write callback state.
99 read_buf_ = NULL;
100 read_buf_len_ = 0;
101 read_callback_.Reset();
102 recv_from_address_ = NULL;
103 write_buf_ = NULL;
104 write_buf_len_ = 0;
105 write_callback_.Reset();
106 send_to_address_.reset();
108 bool ok = read_socket_watcher_.StopWatchingFileDescriptor();
109 DCHECK(ok);
110 ok = write_socket_watcher_.StopWatchingFileDescriptor();
111 DCHECK(ok);
113 if (IGNORE_EINTR(close(socket_)) < 0)
114 PLOG(ERROR) << "close";
116 socket_ = kInvalidSocket;
117 addr_family_ = 0;
120 int UDPSocketLibevent::GetPeerAddress(IPEndPoint* address) const {
121 DCHECK(CalledOnValidThread());
122 DCHECK(address);
123 if (!is_connected())
124 return ERR_SOCKET_NOT_CONNECTED;
126 if (!remote_address_.get()) {
127 SockaddrStorage storage;
128 if (getpeername(socket_, storage.addr, &storage.addr_len))
129 return MapSystemError(errno);
130 scoped_ptr<IPEndPoint> address(new IPEndPoint());
131 if (!address->FromSockAddr(storage.addr, storage.addr_len))
132 return ERR_ADDRESS_INVALID;
133 remote_address_.reset(address.release());
136 *address = *remote_address_;
137 return OK;
140 int UDPSocketLibevent::GetLocalAddress(IPEndPoint* address) const {
141 DCHECK(CalledOnValidThread());
142 DCHECK(address);
143 if (!is_connected())
144 return ERR_SOCKET_NOT_CONNECTED;
146 if (!local_address_.get()) {
147 SockaddrStorage storage;
148 if (getsockname(socket_, storage.addr, &storage.addr_len))
149 return MapSystemError(errno);
150 scoped_ptr<IPEndPoint> address(new IPEndPoint());
151 if (!address->FromSockAddr(storage.addr, storage.addr_len))
152 return ERR_ADDRESS_INVALID;
153 local_address_.reset(address.release());
154 net_log_.AddEvent(NetLog::TYPE_UDP_LOCAL_ADDRESS,
155 CreateNetLogUDPConnectCallback(local_address_.get()));
158 *address = *local_address_;
159 return OK;
162 int UDPSocketLibevent::Read(IOBuffer* buf,
163 int buf_len,
164 const CompletionCallback& callback) {
165 return RecvFrom(buf, buf_len, NULL, callback);
168 int UDPSocketLibevent::RecvFrom(IOBuffer* buf,
169 int buf_len,
170 IPEndPoint* address,
171 const CompletionCallback& callback) {
172 DCHECK(CalledOnValidThread());
173 DCHECK_NE(kInvalidSocket, socket_);
174 CHECK(read_callback_.is_null());
175 DCHECK(!recv_from_address_);
176 DCHECK(!callback.is_null()); // Synchronous operation not supported
177 DCHECK_GT(buf_len, 0);
179 int nread = InternalRecvFrom(buf, buf_len, address);
180 if (nread != ERR_IO_PENDING)
181 return nread;
183 if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
184 socket_, true, base::MessageLoopForIO::WATCH_READ,
185 &read_socket_watcher_, &read_watcher_)) {
186 PLOG(ERROR) << "WatchFileDescriptor failed on read";
187 int result = MapSystemError(errno);
188 LogRead(result, NULL, 0, NULL);
189 return result;
192 read_buf_ = buf;
193 read_buf_len_ = buf_len;
194 recv_from_address_ = address;
195 read_callback_ = callback;
196 return ERR_IO_PENDING;
199 int UDPSocketLibevent::Write(IOBuffer* buf,
200 int buf_len,
201 const CompletionCallback& callback) {
202 return SendToOrWrite(buf, buf_len, NULL, callback);
205 int UDPSocketLibevent::SendTo(IOBuffer* buf,
206 int buf_len,
207 const IPEndPoint& address,
208 const CompletionCallback& callback) {
209 return SendToOrWrite(buf, buf_len, &address, callback);
212 int UDPSocketLibevent::SendToOrWrite(IOBuffer* buf,
213 int buf_len,
214 const IPEndPoint* address,
215 const CompletionCallback& callback) {
216 DCHECK(CalledOnValidThread());
217 DCHECK_NE(kInvalidSocket, socket_);
218 CHECK(write_callback_.is_null());
219 DCHECK(!callback.is_null()); // Synchronous operation not supported
220 DCHECK_GT(buf_len, 0);
222 int result = InternalSendTo(buf, buf_len, address);
223 if (result != ERR_IO_PENDING)
224 return result;
226 if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
227 socket_, true, base::MessageLoopForIO::WATCH_WRITE,
228 &write_socket_watcher_, &write_watcher_)) {
229 DVLOG(1) << "WatchFileDescriptor failed on write, errno " << errno;
230 int result = MapSystemError(errno);
231 LogWrite(result, NULL, NULL);
232 return result;
235 write_buf_ = buf;
236 write_buf_len_ = buf_len;
237 DCHECK(!send_to_address_.get());
238 if (address) {
239 send_to_address_.reset(new IPEndPoint(*address));
241 write_callback_ = callback;
242 return ERR_IO_PENDING;
245 int UDPSocketLibevent::Connect(const IPEndPoint& address) {
246 net_log_.BeginEvent(NetLog::TYPE_UDP_CONNECT,
247 CreateNetLogUDPConnectCallback(&address));
248 int rv = InternalConnect(address);
249 if (rv != OK)
250 Close();
251 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_UDP_CONNECT, rv);
252 return rv;
255 int UDPSocketLibevent::InternalConnect(const IPEndPoint& address) {
256 DCHECK(CalledOnValidThread());
257 DCHECK(!is_connected());
258 DCHECK(!remote_address_.get());
259 int addr_family = address.GetSockAddrFamily();
260 int rv = CreateSocket(addr_family);
261 if (rv < 0)
262 return rv;
264 if (bind_type_ == DatagramSocket::RANDOM_BIND) {
265 // Construct IPAddressNumber of appropriate size (IPv4 or IPv6) of 0s,
266 // representing INADDR_ANY or in6addr_any.
267 size_t addr_size =
268 addr_family == AF_INET ? kIPv4AddressSize : kIPv6AddressSize;
269 IPAddressNumber addr_any(addr_size);
270 rv = RandomBind(addr_any);
272 // else connect() does the DatagramSocket::DEFAULT_BIND
274 if (rv < 0) {
275 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.UdpSocketRandomBindErrorCode", -rv);
276 Close();
277 return rv;
280 SockaddrStorage storage;
281 if (!address.ToSockAddr(storage.addr, &storage.addr_len)) {
282 Close();
283 return ERR_ADDRESS_INVALID;
286 rv = HANDLE_EINTR(connect(socket_, storage.addr, storage.addr_len));
287 if (rv < 0) {
288 // Close() may change the current errno. Map errno beforehand.
289 int result = MapSystemError(errno);
290 Close();
291 return result;
294 remote_address_.reset(new IPEndPoint(address));
295 return rv;
298 int UDPSocketLibevent::Bind(const IPEndPoint& address) {
299 DCHECK(CalledOnValidThread());
300 DCHECK(!is_connected());
301 int rv = CreateSocket(address.GetSockAddrFamily());
302 if (rv < 0)
303 return rv;
305 rv = SetSocketOptions();
306 if (rv < 0) {
307 Close();
308 return rv;
310 rv = DoBind(address);
311 if (rv < 0) {
312 Close();
313 return rv;
315 local_address_.reset();
316 return rv;
319 int UDPSocketLibevent::SetReceiveBufferSize(int32 size) {
320 DCHECK(CalledOnValidThread());
321 int rv = setsockopt(socket_, SOL_SOCKET, SO_RCVBUF,
322 reinterpret_cast<const char*>(&size), sizeof(size));
323 int last_error = errno;
324 DCHECK(!rv) << "Could not set socket receive buffer size: " << last_error;
325 return rv == 0 ? OK : MapSystemError(last_error);
328 int UDPSocketLibevent::SetSendBufferSize(int32 size) {
329 DCHECK(CalledOnValidThread());
330 int rv = setsockopt(socket_, SOL_SOCKET, SO_SNDBUF,
331 reinterpret_cast<const char*>(&size), sizeof(size));
332 int last_error = errno;
333 DCHECK(!rv) << "Could not set socket send buffer size: " << last_error;
334 return rv == 0 ? OK : MapSystemError(last_error);
337 void UDPSocketLibevent::AllowAddressReuse() {
338 DCHECK(CalledOnValidThread());
339 DCHECK(!is_connected());
341 socket_options_ |= SOCKET_OPTION_REUSE_ADDRESS;
344 void UDPSocketLibevent::AllowBroadcast() {
345 DCHECK(CalledOnValidThread());
346 DCHECK(!is_connected());
348 socket_options_ |= SOCKET_OPTION_BROADCAST;
351 void UDPSocketLibevent::ReadWatcher::OnFileCanReadWithoutBlocking(int) {
352 if (!socket_->read_callback_.is_null())
353 socket_->DidCompleteRead();
356 void UDPSocketLibevent::WriteWatcher::OnFileCanWriteWithoutBlocking(int) {
357 if (!socket_->write_callback_.is_null())
358 socket_->DidCompleteWrite();
361 void UDPSocketLibevent::DoReadCallback(int rv) {
362 DCHECK_NE(rv, ERR_IO_PENDING);
363 DCHECK(!read_callback_.is_null());
365 // since Run may result in Read being called, clear read_callback_ up front.
366 CompletionCallback c = read_callback_;
367 read_callback_.Reset();
368 c.Run(rv);
371 void UDPSocketLibevent::DoWriteCallback(int rv) {
372 DCHECK_NE(rv, ERR_IO_PENDING);
373 DCHECK(!write_callback_.is_null());
375 // since Run may result in Write being called, clear write_callback_ up front.
376 CompletionCallback c = write_callback_;
377 write_callback_.Reset();
378 c.Run(rv);
381 void UDPSocketLibevent::DidCompleteRead() {
382 int result =
383 InternalRecvFrom(read_buf_.get(), read_buf_len_, recv_from_address_);
384 if (result != ERR_IO_PENDING) {
385 read_buf_ = NULL;
386 read_buf_len_ = 0;
387 recv_from_address_ = NULL;
388 bool ok = read_socket_watcher_.StopWatchingFileDescriptor();
389 DCHECK(ok);
390 DoReadCallback(result);
394 void UDPSocketLibevent::LogRead(int result,
395 const char* bytes,
396 socklen_t addr_len,
397 const sockaddr* addr) const {
398 if (result < 0) {
399 net_log_.AddEventWithNetErrorCode(NetLog::TYPE_UDP_RECEIVE_ERROR, result);
400 return;
403 if (net_log_.IsLogging()) {
404 DCHECK(addr_len > 0);
405 DCHECK(addr);
407 IPEndPoint address;
408 bool is_address_valid = address.FromSockAddr(addr, addr_len);
409 net_log_.AddEvent(
410 NetLog::TYPE_UDP_BYTES_RECEIVED,
411 CreateNetLogUDPDataTranferCallback(
412 result, bytes,
413 is_address_valid ? &address : NULL));
416 base::StatsCounter read_bytes("udp.read_bytes");
417 read_bytes.Add(result);
418 NetworkActivityMonitor::GetInstance()->IncrementBytesReceived(result);
421 int UDPSocketLibevent::CreateSocket(int addr_family) {
422 addr_family_ = addr_family;
423 socket_ = CreatePlatformSocket(addr_family_, SOCK_DGRAM, 0);
424 if (socket_ == kInvalidSocket)
425 return MapSystemError(errno);
426 if (SetNonBlocking(socket_)) {
427 const int err = MapSystemError(errno);
428 Close();
429 return err;
431 return OK;
434 void UDPSocketLibevent::DidCompleteWrite() {
435 int result =
436 InternalSendTo(write_buf_.get(), write_buf_len_, send_to_address_.get());
438 if (result != ERR_IO_PENDING) {
439 write_buf_ = NULL;
440 write_buf_len_ = 0;
441 send_to_address_.reset();
442 write_socket_watcher_.StopWatchingFileDescriptor();
443 DoWriteCallback(result);
447 void UDPSocketLibevent::LogWrite(int result,
448 const char* bytes,
449 const IPEndPoint* address) const {
450 if (result < 0) {
451 net_log_.AddEventWithNetErrorCode(NetLog::TYPE_UDP_SEND_ERROR, result);
452 return;
455 if (net_log_.IsLogging()) {
456 net_log_.AddEvent(
457 NetLog::TYPE_UDP_BYTES_SENT,
458 CreateNetLogUDPDataTranferCallback(result, bytes, address));
461 base::StatsCounter write_bytes("udp.write_bytes");
462 write_bytes.Add(result);
463 NetworkActivityMonitor::GetInstance()->IncrementBytesSent(result);
466 int UDPSocketLibevent::InternalRecvFrom(IOBuffer* buf, int buf_len,
467 IPEndPoint* address) {
468 int bytes_transferred;
469 int flags = 0;
471 SockaddrStorage storage;
473 bytes_transferred =
474 HANDLE_EINTR(recvfrom(socket_,
475 buf->data(),
476 buf_len,
477 flags,
478 storage.addr,
479 &storage.addr_len));
480 int result;
481 if (bytes_transferred >= 0) {
482 result = bytes_transferred;
483 if (address && !address->FromSockAddr(storage.addr, storage.addr_len))
484 result = ERR_ADDRESS_INVALID;
485 } else {
486 result = MapSystemError(errno);
488 if (result != ERR_IO_PENDING)
489 LogRead(result, buf->data(), storage.addr_len, storage.addr);
490 return result;
493 int UDPSocketLibevent::InternalSendTo(IOBuffer* buf, int buf_len,
494 const IPEndPoint* address) {
495 SockaddrStorage storage;
496 struct sockaddr* addr = storage.addr;
497 if (!address) {
498 addr = NULL;
499 storage.addr_len = 0;
500 } else {
501 if (!address->ToSockAddr(storage.addr, &storage.addr_len)) {
502 int result = ERR_ADDRESS_INVALID;
503 LogWrite(result, NULL, NULL);
504 return result;
508 int result = HANDLE_EINTR(sendto(socket_,
509 buf->data(),
510 buf_len,
512 addr,
513 storage.addr_len));
514 if (result < 0)
515 result = MapSystemError(errno);
516 if (result != ERR_IO_PENDING)
517 LogWrite(result, buf->data(), address);
518 return result;
521 int UDPSocketLibevent::SetSocketOptions() {
522 int true_value = 1;
523 if (socket_options_ & SOCKET_OPTION_REUSE_ADDRESS) {
524 int rv = setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, &true_value,
525 sizeof(true_value));
526 if (rv < 0)
527 return MapSystemError(errno);
529 if (socket_options_ & SOCKET_OPTION_BROADCAST) {
530 int rv;
531 #if defined(OS_MACOSX)
532 // SO_REUSEPORT on OSX permits multiple processes to each receive
533 // UDP multicast or broadcast datagrams destined for the bound
534 // port.
535 rv = setsockopt(socket_, SOL_SOCKET, SO_REUSEPORT, &true_value,
536 sizeof(true_value));
537 #else
538 rv = setsockopt(socket_, SOL_SOCKET, SO_BROADCAST, &true_value,
539 sizeof(true_value));
540 #endif // defined(OS_MACOSX)
541 if (rv < 0)
542 return MapSystemError(errno);
545 if (!(socket_options_ & SOCKET_OPTION_MULTICAST_LOOP)) {
546 int rv;
547 if (addr_family_ == AF_INET) {
548 u_char loop = 0;
549 rv = setsockopt(socket_, IPPROTO_IP, IP_MULTICAST_LOOP,
550 &loop, sizeof(loop));
551 } else {
552 u_int loop = 0;
553 rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
554 &loop, sizeof(loop));
556 if (rv < 0)
557 return MapSystemError(errno);
559 if (multicast_time_to_live_ != IP_DEFAULT_MULTICAST_TTL) {
560 int rv;
561 if (addr_family_ == AF_INET) {
562 u_char ttl = multicast_time_to_live_;
563 rv = setsockopt(socket_, IPPROTO_IP, IP_MULTICAST_TTL,
564 &ttl, sizeof(ttl));
565 } else {
566 // Signed integer. -1 to use route default.
567 int ttl = multicast_time_to_live_;
568 rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
569 &ttl, sizeof(ttl));
571 if (rv < 0)
572 return MapSystemError(errno);
574 if (multicast_interface_ != 0) {
575 switch (addr_family_) {
576 case AF_INET: {
577 #if !defined(OS_MACOSX)
578 ip_mreqn mreq;
579 mreq.imr_ifindex = multicast_interface_;
580 mreq.imr_address.s_addr = htonl(INADDR_ANY);
581 #else
582 ip_mreq mreq;
583 int error = GetIPv4AddressFromIndex(socket_, multicast_interface_,
584 &mreq.imr_interface.s_addr);
585 if (error != OK)
586 return error;
587 #endif
588 int rv = setsockopt(socket_, IPPROTO_IP, IP_MULTICAST_IF,
589 reinterpret_cast<const char*>(&mreq), sizeof(mreq));
590 if (rv)
591 return MapSystemError(errno);
592 break;
594 case AF_INET6: {
595 uint32 interface_index = multicast_interface_;
596 int rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_MULTICAST_IF,
597 reinterpret_cast<const char*>(&interface_index),
598 sizeof(interface_index));
599 if (rv)
600 return MapSystemError(errno);
601 break;
603 default:
604 NOTREACHED() << "Invalid address family";
605 return ERR_ADDRESS_INVALID;
608 return OK;
611 int UDPSocketLibevent::DoBind(const IPEndPoint& address) {
612 SockaddrStorage storage;
613 if (!address.ToSockAddr(storage.addr, &storage.addr_len))
614 return ERR_ADDRESS_INVALID;
615 int rv = bind(socket_, storage.addr, storage.addr_len);
616 if (rv == 0)
617 return OK;
618 int last_error = errno;
619 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.UdpSocketBindErrorFromPosix", last_error);
620 #if defined(OS_CHROMEOS)
621 if (last_error == EINVAL)
622 return ERR_ADDRESS_IN_USE;
623 #elif defined(OS_MACOSX)
624 if (last_error == EADDRNOTAVAIL)
625 return ERR_ADDRESS_IN_USE;
626 #endif
627 return MapSystemError(last_error);
630 int UDPSocketLibevent::RandomBind(const IPAddressNumber& address) {
631 DCHECK(bind_type_ == DatagramSocket::RANDOM_BIND && !rand_int_cb_.is_null());
633 for (int i = 0; i < kBindRetries; ++i) {
634 int rv = DoBind(IPEndPoint(address,
635 rand_int_cb_.Run(kPortStart, kPortEnd)));
636 if (rv == OK || rv != ERR_ADDRESS_IN_USE)
637 return rv;
639 return DoBind(IPEndPoint(address, 0));
642 int UDPSocketLibevent::JoinGroup(const IPAddressNumber& group_address) const {
643 DCHECK(CalledOnValidThread());
644 if (!is_connected())
645 return ERR_SOCKET_NOT_CONNECTED;
647 switch (group_address.size()) {
648 case kIPv4AddressSize: {
649 if (addr_family_ != AF_INET)
650 return ERR_ADDRESS_INVALID;
652 #if !defined(OS_MACOSX)
653 ip_mreqn mreq;
654 mreq.imr_ifindex = multicast_interface_;
655 mreq.imr_address.s_addr = htonl(INADDR_ANY);
656 #else
657 ip_mreq mreq;
658 int error = GetIPv4AddressFromIndex(socket_, multicast_interface_,
659 &mreq.imr_interface.s_addr);
660 if (error != OK)
661 return error;
662 #endif
663 memcpy(&mreq.imr_multiaddr, &group_address[0], kIPv4AddressSize);
664 int rv = setsockopt(socket_, IPPROTO_IP, IP_ADD_MEMBERSHIP,
665 &mreq, sizeof(mreq));
666 if (rv < 0)
667 return MapSystemError(errno);
668 return OK;
670 case kIPv6AddressSize: {
671 if (addr_family_ != AF_INET6)
672 return ERR_ADDRESS_INVALID;
673 ipv6_mreq mreq;
674 mreq.ipv6mr_interface = multicast_interface_;
675 memcpy(&mreq.ipv6mr_multiaddr, &group_address[0], kIPv6AddressSize);
676 int rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_JOIN_GROUP,
677 &mreq, sizeof(mreq));
678 if (rv < 0)
679 return MapSystemError(errno);
680 return OK;
682 default:
683 NOTREACHED() << "Invalid address family";
684 return ERR_ADDRESS_INVALID;
688 int UDPSocketLibevent::LeaveGroup(const IPAddressNumber& group_address) const {
689 DCHECK(CalledOnValidThread());
691 if (!is_connected())
692 return ERR_SOCKET_NOT_CONNECTED;
694 switch (group_address.size()) {
695 case kIPv4AddressSize: {
696 if (addr_family_ != AF_INET)
697 return ERR_ADDRESS_INVALID;
698 ip_mreq mreq;
699 mreq.imr_interface.s_addr = INADDR_ANY;
700 memcpy(&mreq.imr_multiaddr, &group_address[0], kIPv4AddressSize);
701 int rv = setsockopt(socket_, IPPROTO_IP, IP_DROP_MEMBERSHIP,
702 &mreq, sizeof(mreq));
703 if (rv < 0)
704 return MapSystemError(errno);
705 return OK;
707 case kIPv6AddressSize: {
708 if (addr_family_ != AF_INET6)
709 return ERR_ADDRESS_INVALID;
710 ipv6_mreq mreq;
711 mreq.ipv6mr_interface = 0; // 0 indicates default multicast interface.
712 memcpy(&mreq.ipv6mr_multiaddr, &group_address[0], kIPv6AddressSize);
713 int rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
714 &mreq, sizeof(mreq));
715 if (rv < 0)
716 return MapSystemError(errno);
717 return OK;
719 default:
720 NOTREACHED() << "Invalid address family";
721 return ERR_ADDRESS_INVALID;
725 int UDPSocketLibevent::SetMulticastInterface(uint32 interface_index) {
726 DCHECK(CalledOnValidThread());
727 if (is_connected())
728 return ERR_SOCKET_IS_CONNECTED;
729 multicast_interface_ = interface_index;
730 return OK;
733 int UDPSocketLibevent::SetMulticastTimeToLive(int time_to_live) {
734 DCHECK(CalledOnValidThread());
735 if (is_connected())
736 return ERR_SOCKET_IS_CONNECTED;
738 if (time_to_live < 0 || time_to_live > 255)
739 return ERR_INVALID_ARGUMENT;
740 multicast_time_to_live_ = time_to_live;
741 return OK;
744 int UDPSocketLibevent::SetMulticastLoopbackMode(bool loopback) {
745 DCHECK(CalledOnValidThread());
746 if (is_connected())
747 return ERR_SOCKET_IS_CONNECTED;
749 if (loopback)
750 socket_options_ |= SOCKET_OPTION_MULTICAST_LOOP;
751 else
752 socket_options_ &= ~SOCKET_OPTION_MULTICAST_LOOP;
753 return OK;
756 int UDPSocketLibevent::SetDiffServCodePoint(DiffServCodePoint dscp) {
757 if (dscp == DSCP_NO_CHANGE) {
758 return OK;
760 int rv;
761 int dscp_and_ecn = dscp << 2;
762 if (addr_family_ == AF_INET) {
763 rv = setsockopt(socket_, IPPROTO_IP, IP_TOS,
764 &dscp_and_ecn, sizeof(dscp_and_ecn));
765 } else {
766 rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_TCLASS,
767 &dscp_and_ecn, sizeof(dscp_and_ecn));
769 if (rv < 0)
770 return MapSystemError(errno);
772 return OK;
775 void UDPSocketLibevent::DetachFromThread() {
776 base::NonThreadSafe::DetachFromThread();
779 } // namespace net