• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "net/udp/udp_socket_libevent.h"
6 
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>
14 
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"
29 
30 
31 namespace net {
32 
33 namespace {
34 
35 const int kBindRetries = 10;
36 const int kPortStart = 1024;
37 const int kPortEnd = 65535;
38 
39 #if defined(OS_MACOSX)
40 
41 // Returns IPv4 address in network order.
GetIPv4AddressFromIndex(int socket,uint32 index,uint32 * address)42 int GetIPv4AddressFromIndex(int socket, uint32 index, uint32* address){
43   if (!index) {
44     *address = htonl(INADDR_ANY);
45     return OK;
46   }
47   ifreq ifr;
48   ifr.ifr_addr.sa_family = AF_INET;
49   if (!if_indextoname(index, ifr.ifr_name))
50     return ERR_FAILED;
51   int rv = ioctl(socket, SIOCGIFADDR, &ifr);
52   if (!rv)
53     return MapSystemError(rv);
54   *address = reinterpret_cast<sockaddr_in*>(&ifr.ifr_addr)->sin_addr.s_addr;
55   return OK;
56 }
57 
58 #endif  // OS_MACOSX
59 
60 }  // namespace
61 
UDPSocketLibevent(DatagramSocket::BindType bind_type,const RandIntCallback & rand_int_cb,net::NetLog * net_log,const net::NetLog::Source & source)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());
84 }
85 
~UDPSocketLibevent()86 UDPSocketLibevent::~UDPSocketLibevent() {
87   Close();
88   net_log_.EndEvent(NetLog::TYPE_SOCKET_ALIVE);
89 }
90 
Close()91 void UDPSocketLibevent::Close() {
92   DCHECK(CalledOnValidThread());
93 
94   if (!is_connected())
95     return;
96 
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();
106 
107   bool ok = read_socket_watcher_.StopWatchingFileDescriptor();
108   DCHECK(ok);
109   ok = write_socket_watcher_.StopWatchingFileDescriptor();
110   DCHECK(ok);
111 
112   if (IGNORE_EINTR(close(socket_)) < 0)
113     PLOG(ERROR) << "close";
114 
115   socket_ = kInvalidSocket;
116   addr_family_ = 0;
117 }
118 
GetPeerAddress(IPEndPoint * address) const119 int UDPSocketLibevent::GetPeerAddress(IPEndPoint* address) const {
120   DCHECK(CalledOnValidThread());
121   DCHECK(address);
122   if (!is_connected())
123     return ERR_SOCKET_NOT_CONNECTED;
124 
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_FAILED;
132     remote_address_.reset(address.release());
133   }
134 
135   *address = *remote_address_;
136   return OK;
137 }
138 
GetLocalAddress(IPEndPoint * address) const139 int UDPSocketLibevent::GetLocalAddress(IPEndPoint* address) const {
140   DCHECK(CalledOnValidThread());
141   DCHECK(address);
142   if (!is_connected())
143     return ERR_SOCKET_NOT_CONNECTED;
144 
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_FAILED;
152     local_address_.reset(address.release());
153     net_log_.AddEvent(NetLog::TYPE_UDP_LOCAL_ADDRESS,
154                       CreateNetLogUDPConnectCallback(local_address_.get()));
155   }
156 
157   *address = *local_address_;
158   return OK;
159 }
160 
Read(IOBuffer * buf,int buf_len,const CompletionCallback & callback)161 int UDPSocketLibevent::Read(IOBuffer* buf,
162                             int buf_len,
163                             const CompletionCallback& callback) {
164   return RecvFrom(buf, buf_len, NULL, callback);
165 }
166 
RecvFrom(IOBuffer * buf,int buf_len,IPEndPoint * address,const CompletionCallback & 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);
177 
178   int nread = InternalRecvFrom(buf, buf_len, address);
179   if (nread != ERR_IO_PENDING)
180     return nread;
181 
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;
189   }
190 
191   read_buf_ = buf;
192   read_buf_len_ = buf_len;
193   recv_from_address_ = address;
194   read_callback_ = callback;
195   return ERR_IO_PENDING;
196 }
197 
Write(IOBuffer * buf,int buf_len,const CompletionCallback & callback)198 int UDPSocketLibevent::Write(IOBuffer* buf,
199                              int buf_len,
200                              const CompletionCallback& callback) {
201   return SendToOrWrite(buf, buf_len, NULL, callback);
202 }
203 
SendTo(IOBuffer * buf,int buf_len,const IPEndPoint & address,const CompletionCallback & 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);
209 }
210 
SendToOrWrite(IOBuffer * buf,int buf_len,const IPEndPoint * address,const CompletionCallback & 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);
220 
221   int result = InternalSendTo(buf, buf_len, address);
222   if (result != ERR_IO_PENDING)
223     return result;
224 
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;
232   }
233 
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));
239   }
240   write_callback_ = callback;
241   return ERR_IO_PENDING;
242 }
243 
Connect(const IPEndPoint & address)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;
252 }
253 
InternalConnect(const IPEndPoint & address)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;
262 
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);
270   }
271   // else connect() does the DatagramSocket::DEFAULT_BIND
272 
273   if (rv < 0) {
274     UMA_HISTOGRAM_SPARSE_SLOWLY("Net.UdpSocketRandomBindErrorCode", rv);
275     Close();
276     return rv;
277   }
278 
279   SockaddrStorage storage;
280   if (!address.ToSockAddr(storage.addr, &storage.addr_len)) {
281     Close();
282     return ERR_ADDRESS_INVALID;
283   }
284 
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;
291   }
292 
293   remote_address_.reset(new IPEndPoint(address));
294   return rv;
295 }
296 
Bind(const IPEndPoint & address)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;
303 
304   rv = SetSocketOptions();
305   if (rv < 0) {
306     Close();
307     return rv;
308   }
309   rv = DoBind(address);
310   if (rv < 0) {
311     Close();
312     return rv;
313   }
314   local_address_.reset();
315   return rv;
316 }
317 
SetReceiveBufferSize(int32 size)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;
324 }
325 
SetSendBufferSize(int32 size)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;
332 }
333 
AllowAddressReuse()334 void UDPSocketLibevent::AllowAddressReuse() {
335   DCHECK(CalledOnValidThread());
336   DCHECK(!is_connected());
337 
338   socket_options_ |= SOCKET_OPTION_REUSE_ADDRESS;
339 }
340 
AllowBroadcast()341 void UDPSocketLibevent::AllowBroadcast() {
342   DCHECK(CalledOnValidThread());
343   DCHECK(!is_connected());
344 
345   socket_options_ |= SOCKET_OPTION_BROADCAST;
346 }
347 
OnFileCanReadWithoutBlocking(int)348 void UDPSocketLibevent::ReadWatcher::OnFileCanReadWithoutBlocking(int) {
349   if (!socket_->read_callback_.is_null())
350     socket_->DidCompleteRead();
351 }
352 
OnFileCanWriteWithoutBlocking(int)353 void UDPSocketLibevent::WriteWatcher::OnFileCanWriteWithoutBlocking(int) {
354   if (!socket_->write_callback_.is_null())
355     socket_->DidCompleteWrite();
356 }
357 
DoReadCallback(int rv)358 void UDPSocketLibevent::DoReadCallback(int rv) {
359   DCHECK_NE(rv, ERR_IO_PENDING);
360   DCHECK(!read_callback_.is_null());
361 
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);
366 }
367 
DoWriteCallback(int rv)368 void UDPSocketLibevent::DoWriteCallback(int rv) {
369   DCHECK_NE(rv, ERR_IO_PENDING);
370   DCHECK(!write_callback_.is_null());
371 
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);
376 }
377 
DidCompleteRead()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);
388   }
389 }
390 
LogRead(int result,const char * bytes,socklen_t addr_len,const sockaddr * addr) const391 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;
398   }
399 
400   if (net_log_.IsLoggingAllEvents()) {
401     DCHECK(addr_len > 0);
402     DCHECK(addr);
403 
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));
411   }
412 
413   base::StatsCounter read_bytes("udp.read_bytes");
414   read_bytes.Add(result);
415 }
416 
CreateSocket(int addr_family)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;
426   }
427   return OK;
428 }
429 
DidCompleteWrite()430 void UDPSocketLibevent::DidCompleteWrite() {
431   int result =
432       InternalSendTo(write_buf_.get(), write_buf_len_, send_to_address_.get());
433 
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);
440   }
441 }
442 
LogWrite(int result,const char * bytes,const IPEndPoint * address) const443 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;
449   }
450 
451   if (net_log_.IsLoggingAllEvents()) {
452     net_log_.AddEvent(
453         NetLog::TYPE_UDP_BYTES_SENT,
454         CreateNetLogUDPDataTranferCallback(result, bytes, address));
455   }
456 
457   base::StatsCounter write_bytes("udp.write_bytes");
458   write_bytes.Add(result);
459 }
460 
InternalRecvFrom(IOBuffer * buf,int buf_len,IPEndPoint * address)461 int UDPSocketLibevent::InternalRecvFrom(IOBuffer* buf, int buf_len,
462                                         IPEndPoint* address) {
463   int bytes_transferred;
464   int flags = 0;
465 
466   SockaddrStorage storage;
467 
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_FAILED;
480   } else {
481     result = MapSystemError(errno);
482   }
483   if (result != ERR_IO_PENDING)
484     LogRead(result, buf->data(), storage.addr_len, storage.addr);
485   return result;
486 }
487 
InternalSendTo(IOBuffer * buf,int buf_len,const IPEndPoint * address)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_FAILED;
498       LogWrite(result, NULL, NULL);
499       return result;
500     }
501   }
502 
503   int result = HANDLE_EINTR(sendto(socket_,
504                             buf->data(),
505                             buf_len,
506                             0,
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;
514 }
515 
SetSocketOptions()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);
523   }
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);
538   }
539 
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));
550     }
551     if (rv < 0)
552       return MapSystemError(errno);
553   }
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));
565     }
566     if (rv < 0)
567       return MapSystemError(errno);
568   }
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;
588       }
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;
597       }
598       default:
599         NOTREACHED() << "Invalid address family";
600         return ERR_ADDRESS_INVALID;
601     }
602   }
603   return OK;
604 }
605 
DoBind(const IPEndPoint & address)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   return MapSystemError(last_error);
616 }
617 
RandomBind(const IPAddressNumber & address)618 int UDPSocketLibevent::RandomBind(const IPAddressNumber& address) {
619   DCHECK(bind_type_ == DatagramSocket::RANDOM_BIND && !rand_int_cb_.is_null());
620 
621   for (int i = 0; i < kBindRetries; ++i) {
622     int rv = DoBind(IPEndPoint(address,
623                                rand_int_cb_.Run(kPortStart, kPortEnd)));
624     if (rv == OK || rv != ERR_ADDRESS_IN_USE)
625       return rv;
626   }
627   return DoBind(IPEndPoint(address, 0));
628 }
629 
JoinGroup(const IPAddressNumber & group_address) const630 int UDPSocketLibevent::JoinGroup(const IPAddressNumber& group_address) const {
631   DCHECK(CalledOnValidThread());
632   if (!is_connected())
633     return ERR_SOCKET_NOT_CONNECTED;
634 
635   switch (group_address.size()) {
636     case kIPv4AddressSize: {
637       if (addr_family_ != AF_INET)
638         return ERR_ADDRESS_INVALID;
639 
640 #if !defined(OS_MACOSX)
641       ip_mreqn mreq;
642       mreq.imr_ifindex = multicast_interface_;
643       mreq.imr_address.s_addr = htonl(INADDR_ANY);
644 #else
645       ip_mreq mreq;
646       int error = GetIPv4AddressFromIndex(socket_, multicast_interface_,
647                                             &mreq.imr_interface.s_addr);
648       if (error != OK)
649         return error;
650 #endif
651       memcpy(&mreq.imr_multiaddr, &group_address[0], kIPv4AddressSize);
652       int rv = setsockopt(socket_, IPPROTO_IP, IP_ADD_MEMBERSHIP,
653                           &mreq, sizeof(mreq));
654       if (rv < 0)
655         return MapSystemError(errno);
656       return OK;
657     }
658     case kIPv6AddressSize: {
659       if (addr_family_ != AF_INET6)
660         return ERR_ADDRESS_INVALID;
661       ipv6_mreq mreq;
662       mreq.ipv6mr_interface = multicast_interface_;
663       memcpy(&mreq.ipv6mr_multiaddr, &group_address[0], kIPv6AddressSize);
664       int rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_JOIN_GROUP,
665                           &mreq, sizeof(mreq));
666       if (rv < 0)
667         return MapSystemError(errno);
668       return OK;
669     }
670     default:
671       NOTREACHED() << "Invalid address family";
672       return ERR_ADDRESS_INVALID;
673   }
674 }
675 
LeaveGroup(const IPAddressNumber & group_address) const676 int UDPSocketLibevent::LeaveGroup(const IPAddressNumber& group_address) const {
677   DCHECK(CalledOnValidThread());
678 
679   if (!is_connected())
680     return ERR_SOCKET_NOT_CONNECTED;
681 
682   switch (group_address.size()) {
683     case kIPv4AddressSize: {
684       if (addr_family_ != AF_INET)
685         return ERR_ADDRESS_INVALID;
686       ip_mreq mreq;
687       mreq.imr_interface.s_addr = INADDR_ANY;
688       memcpy(&mreq.imr_multiaddr, &group_address[0], kIPv4AddressSize);
689       int rv = setsockopt(socket_, IPPROTO_IP, IP_DROP_MEMBERSHIP,
690                           &mreq, sizeof(mreq));
691       if (rv < 0)
692         return MapSystemError(errno);
693       return OK;
694     }
695     case kIPv6AddressSize: {
696       if (addr_family_ != AF_INET6)
697         return ERR_ADDRESS_INVALID;
698       ipv6_mreq mreq;
699       mreq.ipv6mr_interface = 0;  // 0 indicates default multicast interface.
700       memcpy(&mreq.ipv6mr_multiaddr, &group_address[0], kIPv6AddressSize);
701       int rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
702                           &mreq, sizeof(mreq));
703       if (rv < 0)
704         return MapSystemError(errno);
705       return OK;
706     }
707     default:
708       NOTREACHED() << "Invalid address family";
709       return ERR_ADDRESS_INVALID;
710   }
711 }
712 
SetMulticastInterface(uint32 interface_index)713 int UDPSocketLibevent::SetMulticastInterface(uint32 interface_index) {
714   DCHECK(CalledOnValidThread());
715   if (is_connected())
716     return ERR_SOCKET_IS_CONNECTED;
717   multicast_interface_ = interface_index;
718   return OK;
719 }
720 
SetMulticastTimeToLive(int time_to_live)721 int UDPSocketLibevent::SetMulticastTimeToLive(int time_to_live) {
722   DCHECK(CalledOnValidThread());
723   if (is_connected())
724     return ERR_SOCKET_IS_CONNECTED;
725 
726   if (time_to_live < 0 || time_to_live > 255)
727     return ERR_INVALID_ARGUMENT;
728   multicast_time_to_live_ = time_to_live;
729   return OK;
730 }
731 
SetMulticastLoopbackMode(bool loopback)732 int UDPSocketLibevent::SetMulticastLoopbackMode(bool loopback) {
733   DCHECK(CalledOnValidThread());
734   if (is_connected())
735     return ERR_SOCKET_IS_CONNECTED;
736 
737   if (loopback)
738     socket_options_ |= SOCKET_OPTION_MULTICAST_LOOP;
739   else
740     socket_options_ &= ~SOCKET_OPTION_MULTICAST_LOOP;
741   return OK;
742 }
743 
SetDiffServCodePoint(DiffServCodePoint dscp)744 int UDPSocketLibevent::SetDiffServCodePoint(DiffServCodePoint dscp) {
745   if (dscp == DSCP_NO_CHANGE) {
746     return OK;
747   }
748   int rv;
749   int dscp_and_ecn = dscp << 2;
750   if (addr_family_ == AF_INET) {
751     rv = setsockopt(socket_, IPPROTO_IP, IP_TOS,
752                     &dscp_and_ecn, sizeof(dscp_and_ecn));
753   } else {
754     rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_TCLASS,
755                     &dscp_and_ecn, sizeof(dscp_and_ecn));
756   }
757   if (rv < 0)
758     return MapSystemError(errno);
759 
760   return OK;
761 }
762 
763 }  // namespace net
764