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"
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"
31 #if defined(OS_MACOSX) && !defined(OS_IOS)
32 // Needed temporarily to debug crbug.com/461246.
33 // TODO(sergeyu): Remove once the bug is resolved.
36 #endif // defined(OS_MACOSX) && !defined(OS_IOS)
42 const int kBindRetries
= 10;
43 const int kPortStart
= 1024;
44 const int kPortEnd
= 65535;
46 #if defined(OS_MACOSX)
48 // Returns IPv4 address in network order.
49 int GetIPv4AddressFromIndex(int socket
, uint32 index
, uint32
* address
){
51 *address
= htonl(INADDR_ANY
);
55 ifr
.ifr_addr
.sa_family
= AF_INET
;
56 if (!if_indextoname(index
, ifr
.ifr_name
))
57 return MapSystemError(errno
);
58 int rv
= ioctl(socket
, SIOCGIFADDR
, &ifr
);
60 return MapSystemError(errno
);
61 *address
= reinterpret_cast<sockaddr_in
*>(&ifr
.ifr_addr
)->sin_addr
.s_addr
;
67 #if defined(OS_MACOSX) && !defined(OS_IOS)
69 // On OSX the file descriptor is guarded to detect the cause of
70 // crbug.com/461246. guarded API is supported only on newer versions of OSX,
71 // so the symbols need to be resolved dynamically.
72 // TODO(sergeyu): Removed this code once the bug is resolved.
74 typedef uint64_t guardid_t
;
76 typedef int (*GuardedCloseNpFunction
)(int fd
, const guardid_t
* guard
);
77 typedef int (*ChangeFdguardNpFunction
)(int fd
,
78 const guardid_t
* guard
,
80 const guardid_t
* nguard
,
84 GuardedCloseNpFunction g_guarded_close_np
= nullptr;
85 ChangeFdguardNpFunction g_change_fdguard_np
= nullptr;
87 pthread_once_t g_guarded_functions_once
= PTHREAD_ONCE_INIT
;
89 void InitGuardedFunctions() {
90 void* libsystem_handle
=
91 dlopen("/usr/lib/libSystem.dylib", RTLD_LAZY
| RTLD_LOCAL
| RTLD_NOLOAD
);
92 if (libsystem_handle
) {
93 g_guarded_close_np
= reinterpret_cast<GuardedCloseNpFunction
>(
94 dlsym(libsystem_handle
, "guarded_close_np"));
95 g_change_fdguard_np
= reinterpret_cast<ChangeFdguardNpFunction
>(
96 dlsym(libsystem_handle
, "change_fdguard_np"));
98 // If for any reason only one of the functions is found, set both of them to
100 if (!g_guarded_close_np
|| !g_change_fdguard_np
) {
101 g_guarded_close_np
= nullptr;
102 g_change_fdguard_np
= nullptr;
107 int change_fdguard_np(int fd
,
108 const guardid_t
* guard
,
110 const guardid_t
* nguard
,
113 CHECK_EQ(pthread_once(&g_guarded_functions_once
, InitGuardedFunctions
), 0);
114 // Older version of OSX may not support guarded API.
115 if (!g_change_fdguard_np
)
117 return g_change_fdguard_np(fd
, guard
, flags
, nguard
, nflags
, fdflagsp
);
120 int guarded_close_np(int fd
, const guardid_t
* guard
) {
121 // Older version of OSX may not support guarded API.
122 if (!g_guarded_close_np
)
125 return g_guarded_close_np(fd
, guard
);
128 const unsigned int GUARD_CLOSE
= 1u << 0;
129 const unsigned int GUARD_DUP
= 1u << 1;
131 const guardid_t kSocketFdGuard
= 0xD712BC0BC9A4EAD4;
133 #endif // defined(OS_MACOSX) && !defined(OS_IOS)
137 UDPSocketLibevent::UDPSocketLibevent(
138 DatagramSocket::BindType bind_type
,
139 const RandIntCallback
& rand_int_cb
,
140 net::NetLog
* net_log
,
141 const net::NetLog::Source
& source
)
142 : socket_(kInvalidSocket
),
144 is_connected_(false),
145 socket_options_(SOCKET_OPTION_MULTICAST_LOOP
),
146 multicast_interface_(0),
147 multicast_time_to_live_(1),
148 bind_type_(bind_type
),
149 rand_int_cb_(rand_int_cb
),
151 write_watcher_(this),
153 recv_from_address_(NULL
),
155 net_log_(BoundNetLog::Make(net_log
, NetLog::SOURCE_UDP_SOCKET
)) {
156 net_log_
.BeginEvent(NetLog::TYPE_SOCKET_ALIVE
,
157 source
.ToEventParametersCallback());
158 if (bind_type
== DatagramSocket::RANDOM_BIND
)
159 DCHECK(!rand_int_cb
.is_null());
162 UDPSocketLibevent::~UDPSocketLibevent() {
164 net_log_
.EndEvent(NetLog::TYPE_SOCKET_ALIVE
);
167 int UDPSocketLibevent::Open(AddressFamily address_family
) {
168 DCHECK(CalledOnValidThread());
169 DCHECK_EQ(socket_
, kInvalidSocket
);
171 addr_family_
= ConvertAddressFamily(address_family
);
172 socket_
= CreatePlatformSocket(addr_family_
, SOCK_DGRAM
, 0);
173 if (socket_
== kInvalidSocket
)
174 return MapSystemError(errno
);
175 #if defined(OS_MACOSX) && !defined(OS_IOS)
176 PCHECK(change_fdguard_np(socket_
, NULL
, 0, &kSocketFdGuard
,
177 GUARD_CLOSE
| GUARD_DUP
, NULL
) == 0);
178 #endif // defined(OS_MACOSX) && !defined(OS_IOS)
179 if (SetNonBlocking(socket_
)) {
180 const int err
= MapSystemError(errno
);
187 void UDPSocketLibevent::Close() {
188 DCHECK(CalledOnValidThread());
190 if (socket_
== kInvalidSocket
)
193 // Zero out any pending read/write callback state.
196 read_callback_
.Reset();
197 recv_from_address_
= NULL
;
200 write_callback_
.Reset();
201 send_to_address_
.reset();
203 bool ok
= read_socket_watcher_
.StopWatchingFileDescriptor();
205 ok
= write_socket_watcher_
.StopWatchingFileDescriptor();
208 #if defined(OS_MACOSX) && !defined(OS_IOS)
209 PCHECK(IGNORE_EINTR(guarded_close_np(socket_
, &kSocketFdGuard
)) == 0);
211 PCHECK(IGNORE_EINTR(close(socket_
)) == 0);
212 #endif // defined(OS_MACOSX) && !defined(OS_IOS)
214 socket_
= kInvalidSocket
;
216 is_connected_
= false;
219 int UDPSocketLibevent::GetPeerAddress(IPEndPoint
* address
) const {
220 DCHECK(CalledOnValidThread());
223 return ERR_SOCKET_NOT_CONNECTED
;
225 if (!remote_address_
.get()) {
226 SockaddrStorage storage
;
227 if (getpeername(socket_
, storage
.addr
, &storage
.addr_len
))
228 return MapSystemError(errno
);
229 scoped_ptr
<IPEndPoint
> address(new IPEndPoint());
230 if (!address
->FromSockAddr(storage
.addr
, storage
.addr_len
))
231 return ERR_ADDRESS_INVALID
;
232 remote_address_
.reset(address
.release());
235 *address
= *remote_address_
;
239 int UDPSocketLibevent::GetLocalAddress(IPEndPoint
* address
) const {
240 DCHECK(CalledOnValidThread());
243 return ERR_SOCKET_NOT_CONNECTED
;
245 if (!local_address_
.get()) {
246 SockaddrStorage storage
;
247 if (getsockname(socket_
, storage
.addr
, &storage
.addr_len
))
248 return MapSystemError(errno
);
249 scoped_ptr
<IPEndPoint
> address(new IPEndPoint());
250 if (!address
->FromSockAddr(storage
.addr
, storage
.addr_len
))
251 return ERR_ADDRESS_INVALID
;
252 local_address_
.reset(address
.release());
253 net_log_
.AddEvent(NetLog::TYPE_UDP_LOCAL_ADDRESS
,
254 CreateNetLogUDPConnectCallback(local_address_
.get()));
257 *address
= *local_address_
;
261 int UDPSocketLibevent::Read(IOBuffer
* buf
,
263 const CompletionCallback
& callback
) {
264 return RecvFrom(buf
, buf_len
, NULL
, callback
);
267 int UDPSocketLibevent::RecvFrom(IOBuffer
* buf
,
270 const CompletionCallback
& callback
) {
271 DCHECK(CalledOnValidThread());
272 DCHECK_NE(kInvalidSocket
, socket_
);
273 CHECK(read_callback_
.is_null());
274 DCHECK(!recv_from_address_
);
275 DCHECK(!callback
.is_null()); // Synchronous operation not supported
276 DCHECK_GT(buf_len
, 0);
278 int nread
= InternalRecvFrom(buf
, buf_len
, address
);
279 if (nread
!= ERR_IO_PENDING
)
282 if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
283 socket_
, true, base::MessageLoopForIO::WATCH_READ
,
284 &read_socket_watcher_
, &read_watcher_
)) {
285 PLOG(ERROR
) << "WatchFileDescriptor failed on read";
286 int result
= MapSystemError(errno
);
287 LogRead(result
, NULL
, 0, NULL
);
292 read_buf_len_
= buf_len
;
293 recv_from_address_
= address
;
294 read_callback_
= callback
;
295 return ERR_IO_PENDING
;
298 int UDPSocketLibevent::Write(IOBuffer
* buf
,
300 const CompletionCallback
& callback
) {
301 return SendToOrWrite(buf
, buf_len
, NULL
, callback
);
304 int UDPSocketLibevent::SendTo(IOBuffer
* buf
,
306 const IPEndPoint
& address
,
307 const CompletionCallback
& callback
) {
308 return SendToOrWrite(buf
, buf_len
, &address
, callback
);
311 int UDPSocketLibevent::SendToOrWrite(IOBuffer
* buf
,
313 const IPEndPoint
* address
,
314 const CompletionCallback
& callback
) {
315 DCHECK(CalledOnValidThread());
316 DCHECK_NE(kInvalidSocket
, socket_
);
317 CHECK(write_callback_
.is_null());
318 DCHECK(!callback
.is_null()); // Synchronous operation not supported
319 DCHECK_GT(buf_len
, 0);
321 int result
= InternalSendTo(buf
, buf_len
, address
);
322 if (result
!= ERR_IO_PENDING
)
325 if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
326 socket_
, true, base::MessageLoopForIO::WATCH_WRITE
,
327 &write_socket_watcher_
, &write_watcher_
)) {
328 DVLOG(1) << "WatchFileDescriptor failed on write, errno " << errno
;
329 int result
= MapSystemError(errno
);
330 LogWrite(result
, NULL
, NULL
);
335 write_buf_len_
= buf_len
;
336 DCHECK(!send_to_address_
.get());
338 send_to_address_
.reset(new IPEndPoint(*address
));
340 write_callback_
= callback
;
341 return ERR_IO_PENDING
;
344 int UDPSocketLibevent::Connect(const IPEndPoint
& address
) {
345 DCHECK_NE(socket_
, kInvalidSocket
);
346 net_log_
.BeginEvent(NetLog::TYPE_UDP_CONNECT
,
347 CreateNetLogUDPConnectCallback(&address
));
348 int rv
= InternalConnect(address
);
349 net_log_
.EndEventWithNetErrorCode(NetLog::TYPE_UDP_CONNECT
, rv
);
350 is_connected_
= (rv
== OK
);
354 int UDPSocketLibevent::InternalConnect(const IPEndPoint
& address
) {
355 DCHECK(CalledOnValidThread());
356 DCHECK(!is_connected());
357 DCHECK(!remote_address_
.get());
360 if (bind_type_
== DatagramSocket::RANDOM_BIND
) {
361 // Construct IPAddressNumber of appropriate size (IPv4 or IPv6) of 0s,
362 // representing INADDR_ANY or in6addr_any.
363 size_t addr_size
= address
.GetSockAddrFamily() == AF_INET
?
364 kIPv4AddressSize
: kIPv6AddressSize
;
365 IPAddressNumber
addr_any(addr_size
);
366 rv
= RandomBind(addr_any
);
368 // else connect() does the DatagramSocket::DEFAULT_BIND
371 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.UdpSocketRandomBindErrorCode", -rv
);
375 SockaddrStorage storage
;
376 if (!address
.ToSockAddr(storage
.addr
, &storage
.addr_len
))
377 return ERR_ADDRESS_INVALID
;
379 rv
= HANDLE_EINTR(connect(socket_
, storage
.addr
, storage
.addr_len
));
381 return MapSystemError(errno
);
383 remote_address_
.reset(new IPEndPoint(address
));
387 int UDPSocketLibevent::Bind(const IPEndPoint
& address
) {
388 DCHECK_NE(socket_
, kInvalidSocket
);
389 DCHECK(CalledOnValidThread());
390 DCHECK(!is_connected());
392 int rv
= SetMulticastOptions();
396 rv
= DoBind(address
);
400 is_connected_
= true;
401 local_address_
.reset();
405 int UDPSocketLibevent::SetReceiveBufferSize(int32 size
) {
406 DCHECK_NE(socket_
, kInvalidSocket
);
407 DCHECK(CalledOnValidThread());
408 int rv
= setsockopt(socket_
, SOL_SOCKET
, SO_RCVBUF
,
409 reinterpret_cast<const char*>(&size
), sizeof(size
));
410 return rv
== 0 ? OK
: MapSystemError(errno
);
413 int UDPSocketLibevent::SetSendBufferSize(int32 size
) {
414 DCHECK_NE(socket_
, kInvalidSocket
);
415 DCHECK(CalledOnValidThread());
416 int rv
= setsockopt(socket_
, SOL_SOCKET
, SO_SNDBUF
,
417 reinterpret_cast<const char*>(&size
), sizeof(size
));
418 return rv
== 0 ? OK
: MapSystemError(errno
);
421 int UDPSocketLibevent::AllowAddressReuse() {
422 DCHECK_NE(socket_
, kInvalidSocket
);
423 DCHECK(CalledOnValidThread());
424 DCHECK(!is_connected());
427 socket_
, SOL_SOCKET
, SO_REUSEADDR
, &true_value
, sizeof(true_value
));
428 return rv
== 0 ? OK
: MapSystemError(errno
);
431 int UDPSocketLibevent::SetBroadcast(bool broadcast
) {
432 DCHECK_NE(socket_
, kInvalidSocket
);
433 DCHECK(CalledOnValidThread());
434 int value
= broadcast
? 1 : 0;
436 #if defined(OS_MACOSX)
437 // SO_REUSEPORT on OSX permits multiple processes to each receive
438 // UDP multicast or broadcast datagrams destined for the bound
440 rv
= setsockopt(socket_
, SOL_SOCKET
, SO_REUSEPORT
, &value
, sizeof(value
));
442 rv
= setsockopt(socket_
, SOL_SOCKET
, SO_BROADCAST
, &value
, sizeof(value
));
443 #endif // defined(OS_MACOSX)
444 return rv
== 0 ? OK
: MapSystemError(errno
);
447 void UDPSocketLibevent::ReadWatcher::OnFileCanReadWithoutBlocking(int) {
448 if (!socket_
->read_callback_
.is_null())
449 socket_
->DidCompleteRead();
452 void UDPSocketLibevent::WriteWatcher::OnFileCanWriteWithoutBlocking(int) {
453 if (!socket_
->write_callback_
.is_null())
454 socket_
->DidCompleteWrite();
457 void UDPSocketLibevent::DoReadCallback(int rv
) {
458 DCHECK_NE(rv
, ERR_IO_PENDING
);
459 DCHECK(!read_callback_
.is_null());
461 // since Run may result in Read being called, clear read_callback_ up front.
462 CompletionCallback c
= read_callback_
;
463 read_callback_
.Reset();
467 void UDPSocketLibevent::DoWriteCallback(int rv
) {
468 DCHECK_NE(rv
, ERR_IO_PENDING
);
469 DCHECK(!write_callback_
.is_null());
471 // since Run may result in Write being called, clear write_callback_ up front.
472 CompletionCallback c
= write_callback_
;
473 write_callback_
.Reset();
477 void UDPSocketLibevent::DidCompleteRead() {
479 InternalRecvFrom(read_buf_
.get(), read_buf_len_
, recv_from_address_
);
480 if (result
!= ERR_IO_PENDING
) {
483 recv_from_address_
= NULL
;
484 bool ok
= read_socket_watcher_
.StopWatchingFileDescriptor();
486 DoReadCallback(result
);
490 void UDPSocketLibevent::LogRead(int result
,
493 const sockaddr
* addr
) const {
495 net_log_
.AddEventWithNetErrorCode(NetLog::TYPE_UDP_RECEIVE_ERROR
, result
);
499 if (net_log_
.IsLogging()) {
500 DCHECK(addr_len
> 0);
504 bool is_address_valid
= address
.FromSockAddr(addr
, addr_len
);
506 NetLog::TYPE_UDP_BYTES_RECEIVED
,
507 CreateNetLogUDPDataTranferCallback(
509 is_address_valid
? &address
: NULL
));
512 NetworkActivityMonitor::GetInstance()->IncrementBytesReceived(result
);
515 void UDPSocketLibevent::DidCompleteWrite() {
517 InternalSendTo(write_buf_
.get(), write_buf_len_
, send_to_address_
.get());
519 if (result
!= ERR_IO_PENDING
) {
522 send_to_address_
.reset();
523 write_socket_watcher_
.StopWatchingFileDescriptor();
524 DoWriteCallback(result
);
528 void UDPSocketLibevent::LogWrite(int result
,
530 const IPEndPoint
* address
) const {
532 net_log_
.AddEventWithNetErrorCode(NetLog::TYPE_UDP_SEND_ERROR
, result
);
536 if (net_log_
.IsLogging()) {
538 NetLog::TYPE_UDP_BYTES_SENT
,
539 CreateNetLogUDPDataTranferCallback(result
, bytes
, address
));
542 NetworkActivityMonitor::GetInstance()->IncrementBytesSent(result
);
545 int UDPSocketLibevent::InternalRecvFrom(IOBuffer
* buf
, int buf_len
,
546 IPEndPoint
* address
) {
547 int bytes_transferred
;
550 SockaddrStorage storage
;
553 HANDLE_EINTR(recvfrom(socket_
,
560 if (bytes_transferred
>= 0) {
561 result
= bytes_transferred
;
562 if (address
&& !address
->FromSockAddr(storage
.addr
, storage
.addr_len
))
563 result
= ERR_ADDRESS_INVALID
;
565 result
= MapSystemError(errno
);
567 if (result
!= ERR_IO_PENDING
)
568 LogRead(result
, buf
->data(), storage
.addr_len
, storage
.addr
);
572 int UDPSocketLibevent::InternalSendTo(IOBuffer
* buf
, int buf_len
,
573 const IPEndPoint
* address
) {
574 SockaddrStorage storage
;
575 struct sockaddr
* addr
= storage
.addr
;
578 storage
.addr_len
= 0;
580 if (!address
->ToSockAddr(storage
.addr
, &storage
.addr_len
)) {
581 int result
= ERR_ADDRESS_INVALID
;
582 LogWrite(result
, NULL
, NULL
);
587 int result
= HANDLE_EINTR(sendto(socket_
,
594 result
= MapSystemError(errno
);
595 if (result
!= ERR_IO_PENDING
)
596 LogWrite(result
, buf
->data(), address
);
600 int UDPSocketLibevent::SetMulticastOptions() {
601 if (!(socket_options_
& SOCKET_OPTION_MULTICAST_LOOP
)) {
603 if (addr_family_
== AF_INET
) {
605 rv
= setsockopt(socket_
, IPPROTO_IP
, IP_MULTICAST_LOOP
,
606 &loop
, sizeof(loop
));
609 rv
= setsockopt(socket_
, IPPROTO_IPV6
, IPV6_MULTICAST_LOOP
,
610 &loop
, sizeof(loop
));
613 return MapSystemError(errno
);
615 if (multicast_time_to_live_
!= IP_DEFAULT_MULTICAST_TTL
) {
617 if (addr_family_
== AF_INET
) {
618 u_char ttl
= multicast_time_to_live_
;
619 rv
= setsockopt(socket_
, IPPROTO_IP
, IP_MULTICAST_TTL
,
622 // Signed integer. -1 to use route default.
623 int ttl
= multicast_time_to_live_
;
624 rv
= setsockopt(socket_
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
,
628 return MapSystemError(errno
);
630 if (multicast_interface_
!= 0) {
631 switch (addr_family_
) {
633 #if !defined(OS_MACOSX)
635 mreq
.imr_ifindex
= multicast_interface_
;
636 mreq
.imr_address
.s_addr
= htonl(INADDR_ANY
);
639 int error
= GetIPv4AddressFromIndex(socket_
, multicast_interface_
,
640 &mreq
.imr_interface
.s_addr
);
644 int rv
= setsockopt(socket_
, IPPROTO_IP
, IP_MULTICAST_IF
,
645 reinterpret_cast<const char*>(&mreq
), sizeof(mreq
));
647 return MapSystemError(errno
);
651 uint32 interface_index
= multicast_interface_
;
652 int rv
= setsockopt(socket_
, IPPROTO_IPV6
, IPV6_MULTICAST_IF
,
653 reinterpret_cast<const char*>(&interface_index
),
654 sizeof(interface_index
));
656 return MapSystemError(errno
);
660 NOTREACHED() << "Invalid address family";
661 return ERR_ADDRESS_INVALID
;
667 int UDPSocketLibevent::DoBind(const IPEndPoint
& address
) {
668 SockaddrStorage storage
;
669 if (!address
.ToSockAddr(storage
.addr
, &storage
.addr_len
))
670 return ERR_ADDRESS_INVALID
;
671 int rv
= bind(socket_
, storage
.addr
, storage
.addr_len
);
674 int last_error
= errno
;
675 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.UdpSocketBindErrorFromPosix", last_error
);
676 #if defined(OS_CHROMEOS)
677 if (last_error
== EINVAL
)
678 return ERR_ADDRESS_IN_USE
;
679 #elif defined(OS_MACOSX)
680 if (last_error
== EADDRNOTAVAIL
)
681 return ERR_ADDRESS_IN_USE
;
683 return MapSystemError(last_error
);
686 int UDPSocketLibevent::RandomBind(const IPAddressNumber
& address
) {
687 DCHECK(bind_type_
== DatagramSocket::RANDOM_BIND
&& !rand_int_cb_
.is_null());
689 for (int i
= 0; i
< kBindRetries
; ++i
) {
690 int rv
= DoBind(IPEndPoint(address
,
691 rand_int_cb_
.Run(kPortStart
, kPortEnd
)));
692 if (rv
== OK
|| rv
!= ERR_ADDRESS_IN_USE
)
695 return DoBind(IPEndPoint(address
, 0));
698 int UDPSocketLibevent::JoinGroup(const IPAddressNumber
& group_address
) const {
699 DCHECK(CalledOnValidThread());
701 return ERR_SOCKET_NOT_CONNECTED
;
703 switch (group_address
.size()) {
704 case kIPv4AddressSize
: {
705 if (addr_family_
!= AF_INET
)
706 return ERR_ADDRESS_INVALID
;
708 #if !defined(OS_MACOSX)
710 mreq
.imr_ifindex
= multicast_interface_
;
711 mreq
.imr_address
.s_addr
= htonl(INADDR_ANY
);
714 int error
= GetIPv4AddressFromIndex(socket_
, multicast_interface_
,
715 &mreq
.imr_interface
.s_addr
);
719 memcpy(&mreq
.imr_multiaddr
, &group_address
[0], kIPv4AddressSize
);
720 int rv
= setsockopt(socket_
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
,
721 &mreq
, sizeof(mreq
));
723 return MapSystemError(errno
);
726 case kIPv6AddressSize
: {
727 if (addr_family_
!= AF_INET6
)
728 return ERR_ADDRESS_INVALID
;
730 mreq
.ipv6mr_interface
= multicast_interface_
;
731 memcpy(&mreq
.ipv6mr_multiaddr
, &group_address
[0], kIPv6AddressSize
);
732 int rv
= setsockopt(socket_
, IPPROTO_IPV6
, IPV6_JOIN_GROUP
,
733 &mreq
, sizeof(mreq
));
735 return MapSystemError(errno
);
739 NOTREACHED() << "Invalid address family";
740 return ERR_ADDRESS_INVALID
;
744 int UDPSocketLibevent::LeaveGroup(const IPAddressNumber
& group_address
) const {
745 DCHECK(CalledOnValidThread());
748 return ERR_SOCKET_NOT_CONNECTED
;
750 switch (group_address
.size()) {
751 case kIPv4AddressSize
: {
752 if (addr_family_
!= AF_INET
)
753 return ERR_ADDRESS_INVALID
;
755 mreq
.imr_interface
.s_addr
= INADDR_ANY
;
756 memcpy(&mreq
.imr_multiaddr
, &group_address
[0], kIPv4AddressSize
);
757 int rv
= setsockopt(socket_
, IPPROTO_IP
, IP_DROP_MEMBERSHIP
,
758 &mreq
, sizeof(mreq
));
760 return MapSystemError(errno
);
763 case kIPv6AddressSize
: {
764 if (addr_family_
!= AF_INET6
)
765 return ERR_ADDRESS_INVALID
;
767 mreq
.ipv6mr_interface
= 0; // 0 indicates default multicast interface.
768 memcpy(&mreq
.ipv6mr_multiaddr
, &group_address
[0], kIPv6AddressSize
);
769 int rv
= setsockopt(socket_
, IPPROTO_IPV6
, IPV6_LEAVE_GROUP
,
770 &mreq
, sizeof(mreq
));
772 return MapSystemError(errno
);
776 NOTREACHED() << "Invalid address family";
777 return ERR_ADDRESS_INVALID
;
781 int UDPSocketLibevent::SetMulticastInterface(uint32 interface_index
) {
782 DCHECK(CalledOnValidThread());
784 return ERR_SOCKET_IS_CONNECTED
;
785 multicast_interface_
= interface_index
;
789 int UDPSocketLibevent::SetMulticastTimeToLive(int time_to_live
) {
790 DCHECK(CalledOnValidThread());
792 return ERR_SOCKET_IS_CONNECTED
;
794 if (time_to_live
< 0 || time_to_live
> 255)
795 return ERR_INVALID_ARGUMENT
;
796 multicast_time_to_live_
= time_to_live
;
800 int UDPSocketLibevent::SetMulticastLoopbackMode(bool loopback
) {
801 DCHECK(CalledOnValidThread());
803 return ERR_SOCKET_IS_CONNECTED
;
806 socket_options_
|= SOCKET_OPTION_MULTICAST_LOOP
;
808 socket_options_
&= ~SOCKET_OPTION_MULTICAST_LOOP
;
812 int UDPSocketLibevent::SetDiffServCodePoint(DiffServCodePoint dscp
) {
813 if (dscp
== DSCP_NO_CHANGE
) {
817 int dscp_and_ecn
= dscp
<< 2;
818 if (addr_family_
== AF_INET
) {
819 rv
= setsockopt(socket_
, IPPROTO_IP
, IP_TOS
,
820 &dscp_and_ecn
, sizeof(dscp_and_ecn
));
822 rv
= setsockopt(socket_
, IPPROTO_IPV6
, IPV6_TCLASS
,
823 &dscp_and_ecn
, sizeof(dscp_and_ecn
));
826 return MapSystemError(errno
);
831 void UDPSocketLibevent::DetachFromThread() {
832 base::NonThreadSafe::DetachFromThread();