Roll src/third_party/skia ff271c2:b679ca8
[chromium-blink-merge.git] / net / udp / udp_socket_libevent.cc
blob82597777b58c63d30b55508d59864d461f26bd67
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 <net/if.h>
10 #include <netdb.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.
34 #include <dlfcn.h>
35 #include <pthread.h>
36 #endif // defined(OS_MACOSX) && !defined(OS_IOS)
38 namespace net {
40 namespace {
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){
50 if (!index) {
51 *address = htonl(INADDR_ANY);
52 return OK;
54 ifreq ifr;
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);
59 if (rv == -1)
60 return MapSystemError(errno);
61 *address = reinterpret_cast<sockaddr_in*>(&ifr.ifr_addr)->sin_addr.s_addr;
62 return OK;
65 #endif // OS_MACOSX
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,
79 u_int flags,
80 const guardid_t* nguard,
81 u_int nflags,
82 int* fdflagsp);
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
99 // nullptr.
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,
109 u_int flags,
110 const guardid_t* nguard,
111 u_int nflags,
112 int* fdflagsp) {
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)
116 return 0;
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)
123 return close(fd);
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)
135 } // namespace
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),
143 addr_family_(0),
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),
150 read_watcher_(this),
151 write_watcher_(this),
152 read_buf_len_(0),
153 recv_from_address_(NULL),
154 write_buf_len_(0),
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() {
163 Close();
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);
181 Close();
182 return err;
184 return OK;
187 void UDPSocketLibevent::Close() {
188 DCHECK(CalledOnValidThread());
190 if (socket_ == kInvalidSocket)
191 return;
193 // Zero out any pending read/write callback state.
194 read_buf_ = NULL;
195 read_buf_len_ = 0;
196 read_callback_.Reset();
197 recv_from_address_ = NULL;
198 write_buf_ = NULL;
199 write_buf_len_ = 0;
200 write_callback_.Reset();
201 send_to_address_.reset();
203 bool ok = read_socket_watcher_.StopWatchingFileDescriptor();
204 DCHECK(ok);
205 ok = write_socket_watcher_.StopWatchingFileDescriptor();
206 DCHECK(ok);
208 #if defined(OS_MACOSX) && !defined(OS_IOS)
209 PCHECK(IGNORE_EINTR(guarded_close_np(socket_, &kSocketFdGuard)) == 0);
210 #else
211 PCHECK(IGNORE_EINTR(close(socket_)) == 0);
212 #endif // defined(OS_MACOSX) && !defined(OS_IOS)
214 socket_ = kInvalidSocket;
215 addr_family_ = 0;
216 is_connected_ = false;
219 int UDPSocketLibevent::GetPeerAddress(IPEndPoint* address) const {
220 DCHECK(CalledOnValidThread());
221 DCHECK(address);
222 if (!is_connected())
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_;
236 return OK;
239 int UDPSocketLibevent::GetLocalAddress(IPEndPoint* address) const {
240 DCHECK(CalledOnValidThread());
241 DCHECK(address);
242 if (!is_connected())
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_;
258 return OK;
261 int UDPSocketLibevent::Read(IOBuffer* buf,
262 int buf_len,
263 const CompletionCallback& callback) {
264 return RecvFrom(buf, buf_len, NULL, callback);
267 int UDPSocketLibevent::RecvFrom(IOBuffer* buf,
268 int buf_len,
269 IPEndPoint* address,
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)
280 return nread;
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);
288 return result;
291 read_buf_ = buf;
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,
299 int buf_len,
300 const CompletionCallback& callback) {
301 return SendToOrWrite(buf, buf_len, NULL, callback);
304 int UDPSocketLibevent::SendTo(IOBuffer* buf,
305 int buf_len,
306 const IPEndPoint& address,
307 const CompletionCallback& callback) {
308 return SendToOrWrite(buf, buf_len, &address, callback);
311 int UDPSocketLibevent::SendToOrWrite(IOBuffer* buf,
312 int buf_len,
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)
323 return result;
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);
331 return result;
334 write_buf_ = buf;
335 write_buf_len_ = buf_len;
336 DCHECK(!send_to_address_.get());
337 if (address) {
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);
351 return rv;
354 int UDPSocketLibevent::InternalConnect(const IPEndPoint& address) {
355 DCHECK(CalledOnValidThread());
356 DCHECK(!is_connected());
357 DCHECK(!remote_address_.get());
359 int rv = 0;
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
370 if (rv < 0) {
371 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.UdpSocketRandomBindErrorCode", -rv);
372 return 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));
380 if (rv < 0)
381 return MapSystemError(errno);
383 remote_address_.reset(new IPEndPoint(address));
384 return rv;
387 int UDPSocketLibevent::Bind(const IPEndPoint& address) {
388 DCHECK_NE(socket_, kInvalidSocket);
389 DCHECK(CalledOnValidThread());
390 DCHECK(!is_connected());
392 int rv = SetMulticastOptions();
393 if (rv < 0)
394 return rv;
396 rv = DoBind(address);
397 if (rv < 0)
398 return rv;
400 is_connected_ = true;
401 local_address_.reset();
402 return rv;
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());
425 int true_value = 1;
426 int rv = setsockopt(
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;
435 int rv;
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
439 // port.
440 rv = setsockopt(socket_, SOL_SOCKET, SO_REUSEPORT, &value, sizeof(value));
441 #else
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();
464 c.Run(rv);
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();
474 c.Run(rv);
477 void UDPSocketLibevent::DidCompleteRead() {
478 int result =
479 InternalRecvFrom(read_buf_.get(), read_buf_len_, recv_from_address_);
480 if (result != ERR_IO_PENDING) {
481 read_buf_ = NULL;
482 read_buf_len_ = 0;
483 recv_from_address_ = NULL;
484 bool ok = read_socket_watcher_.StopWatchingFileDescriptor();
485 DCHECK(ok);
486 DoReadCallback(result);
490 void UDPSocketLibevent::LogRead(int result,
491 const char* bytes,
492 socklen_t addr_len,
493 const sockaddr* addr) const {
494 if (result < 0) {
495 net_log_.AddEventWithNetErrorCode(NetLog::TYPE_UDP_RECEIVE_ERROR, result);
496 return;
499 if (net_log_.IsLogging()) {
500 DCHECK(addr_len > 0);
501 DCHECK(addr);
503 IPEndPoint address;
504 bool is_address_valid = address.FromSockAddr(addr, addr_len);
505 net_log_.AddEvent(
506 NetLog::TYPE_UDP_BYTES_RECEIVED,
507 CreateNetLogUDPDataTranferCallback(
508 result, bytes,
509 is_address_valid ? &address : NULL));
512 NetworkActivityMonitor::GetInstance()->IncrementBytesReceived(result);
515 void UDPSocketLibevent::DidCompleteWrite() {
516 int result =
517 InternalSendTo(write_buf_.get(), write_buf_len_, send_to_address_.get());
519 if (result != ERR_IO_PENDING) {
520 write_buf_ = NULL;
521 write_buf_len_ = 0;
522 send_to_address_.reset();
523 write_socket_watcher_.StopWatchingFileDescriptor();
524 DoWriteCallback(result);
528 void UDPSocketLibevent::LogWrite(int result,
529 const char* bytes,
530 const IPEndPoint* address) const {
531 if (result < 0) {
532 net_log_.AddEventWithNetErrorCode(NetLog::TYPE_UDP_SEND_ERROR, result);
533 return;
536 if (net_log_.IsLogging()) {
537 net_log_.AddEvent(
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;
548 int flags = 0;
550 SockaddrStorage storage;
552 bytes_transferred =
553 HANDLE_EINTR(recvfrom(socket_,
554 buf->data(),
555 buf_len,
556 flags,
557 storage.addr,
558 &storage.addr_len));
559 int result;
560 if (bytes_transferred >= 0) {
561 result = bytes_transferred;
562 if (address && !address->FromSockAddr(storage.addr, storage.addr_len))
563 result = ERR_ADDRESS_INVALID;
564 } else {
565 result = MapSystemError(errno);
567 if (result != ERR_IO_PENDING)
568 LogRead(result, buf->data(), storage.addr_len, storage.addr);
569 return result;
572 int UDPSocketLibevent::InternalSendTo(IOBuffer* buf, int buf_len,
573 const IPEndPoint* address) {
574 SockaddrStorage storage;
575 struct sockaddr* addr = storage.addr;
576 if (!address) {
577 addr = NULL;
578 storage.addr_len = 0;
579 } else {
580 if (!address->ToSockAddr(storage.addr, &storage.addr_len)) {
581 int result = ERR_ADDRESS_INVALID;
582 LogWrite(result, NULL, NULL);
583 return result;
587 int result = HANDLE_EINTR(sendto(socket_,
588 buf->data(),
589 buf_len,
591 addr,
592 storage.addr_len));
593 if (result < 0)
594 result = MapSystemError(errno);
595 if (result != ERR_IO_PENDING)
596 LogWrite(result, buf->data(), address);
597 return result;
600 int UDPSocketLibevent::SetMulticastOptions() {
601 if (!(socket_options_ & SOCKET_OPTION_MULTICAST_LOOP)) {
602 int rv;
603 if (addr_family_ == AF_INET) {
604 u_char loop = 0;
605 rv = setsockopt(socket_, IPPROTO_IP, IP_MULTICAST_LOOP,
606 &loop, sizeof(loop));
607 } else {
608 u_int loop = 0;
609 rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
610 &loop, sizeof(loop));
612 if (rv < 0)
613 return MapSystemError(errno);
615 if (multicast_time_to_live_ != IP_DEFAULT_MULTICAST_TTL) {
616 int rv;
617 if (addr_family_ == AF_INET) {
618 u_char ttl = multicast_time_to_live_;
619 rv = setsockopt(socket_, IPPROTO_IP, IP_MULTICAST_TTL,
620 &ttl, sizeof(ttl));
621 } else {
622 // Signed integer. -1 to use route default.
623 int ttl = multicast_time_to_live_;
624 rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
625 &ttl, sizeof(ttl));
627 if (rv < 0)
628 return MapSystemError(errno);
630 if (multicast_interface_ != 0) {
631 switch (addr_family_) {
632 case AF_INET: {
633 #if !defined(OS_MACOSX)
634 ip_mreqn mreq;
635 mreq.imr_ifindex = multicast_interface_;
636 mreq.imr_address.s_addr = htonl(INADDR_ANY);
637 #else
638 ip_mreq mreq;
639 int error = GetIPv4AddressFromIndex(socket_, multicast_interface_,
640 &mreq.imr_interface.s_addr);
641 if (error != OK)
642 return error;
643 #endif
644 int rv = setsockopt(socket_, IPPROTO_IP, IP_MULTICAST_IF,
645 reinterpret_cast<const char*>(&mreq), sizeof(mreq));
646 if (rv)
647 return MapSystemError(errno);
648 break;
650 case AF_INET6: {
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));
655 if (rv)
656 return MapSystemError(errno);
657 break;
659 default:
660 NOTREACHED() << "Invalid address family";
661 return ERR_ADDRESS_INVALID;
664 return OK;
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);
672 if (rv == 0)
673 return OK;
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;
682 #endif
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)
693 return rv;
695 return DoBind(IPEndPoint(address, 0));
698 int UDPSocketLibevent::JoinGroup(const IPAddressNumber& group_address) const {
699 DCHECK(CalledOnValidThread());
700 if (!is_connected())
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)
709 ip_mreqn mreq;
710 mreq.imr_ifindex = multicast_interface_;
711 mreq.imr_address.s_addr = htonl(INADDR_ANY);
712 #else
713 ip_mreq mreq;
714 int error = GetIPv4AddressFromIndex(socket_, multicast_interface_,
715 &mreq.imr_interface.s_addr);
716 if (error != OK)
717 return error;
718 #endif
719 memcpy(&mreq.imr_multiaddr, &group_address[0], kIPv4AddressSize);
720 int rv = setsockopt(socket_, IPPROTO_IP, IP_ADD_MEMBERSHIP,
721 &mreq, sizeof(mreq));
722 if (rv < 0)
723 return MapSystemError(errno);
724 return OK;
726 case kIPv6AddressSize: {
727 if (addr_family_ != AF_INET6)
728 return ERR_ADDRESS_INVALID;
729 ipv6_mreq mreq;
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));
734 if (rv < 0)
735 return MapSystemError(errno);
736 return OK;
738 default:
739 NOTREACHED() << "Invalid address family";
740 return ERR_ADDRESS_INVALID;
744 int UDPSocketLibevent::LeaveGroup(const IPAddressNumber& group_address) const {
745 DCHECK(CalledOnValidThread());
747 if (!is_connected())
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;
754 ip_mreq mreq;
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));
759 if (rv < 0)
760 return MapSystemError(errno);
761 return OK;
763 case kIPv6AddressSize: {
764 if (addr_family_ != AF_INET6)
765 return ERR_ADDRESS_INVALID;
766 ipv6_mreq mreq;
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));
771 if (rv < 0)
772 return MapSystemError(errno);
773 return OK;
775 default:
776 NOTREACHED() << "Invalid address family";
777 return ERR_ADDRESS_INVALID;
781 int UDPSocketLibevent::SetMulticastInterface(uint32 interface_index) {
782 DCHECK(CalledOnValidThread());
783 if (is_connected())
784 return ERR_SOCKET_IS_CONNECTED;
785 multicast_interface_ = interface_index;
786 return OK;
789 int UDPSocketLibevent::SetMulticastTimeToLive(int time_to_live) {
790 DCHECK(CalledOnValidThread());
791 if (is_connected())
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;
797 return OK;
800 int UDPSocketLibevent::SetMulticastLoopbackMode(bool loopback) {
801 DCHECK(CalledOnValidThread());
802 if (is_connected())
803 return ERR_SOCKET_IS_CONNECTED;
805 if (loopback)
806 socket_options_ |= SOCKET_OPTION_MULTICAST_LOOP;
807 else
808 socket_options_ &= ~SOCKET_OPTION_MULTICAST_LOOP;
809 return OK;
812 int UDPSocketLibevent::SetDiffServCodePoint(DiffServCodePoint dscp) {
813 if (dscp == DSCP_NO_CHANGE) {
814 return OK;
816 int rv;
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));
821 } else {
822 rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_TCLASS,
823 &dscp_and_ecn, sizeof(dscp_and_ecn));
825 if (rv < 0)
826 return MapSystemError(errno);
828 return OK;
831 void UDPSocketLibevent::DetachFromThread() {
832 base::NonThreadSafe::DetachFromThread();
835 } // namespace net