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/logging.h"
17 #include "base/message_loop/message_loop.h"
18 #include "base/metrics/stats_counters.h"
19 #include "base/posix/eintr_wrapper.h"
20 #include "base/rand_util.h"
21 #include "net/base/io_buffer.h"
22 #include "net/base/ip_endpoint.h"
23 #include "net/base/net_errors.h"
24 #include "net/base/net_log.h"
25 #include "net/base/net_util.h"
26 #include "net/socket/socket_descriptor.h"
27 #include "net/udp/udp_net_log_parameters.h"
34 const int kBindRetries
= 10;
35 const int kPortStart
= 1024;
36 const int kPortEnd
= 65535;
38 #if defined(OS_MACOSX)
40 // Returns IPv4 address in network order.
41 int GetIPv4AddressFromIndex(int socket
, uint32 index
, uint32
* address
){
43 *address
= htonl(INADDR_ANY
);
47 ifr
.ifr_addr
.sa_family
= AF_INET
;
48 if (!if_indextoname(index
, ifr
.ifr_name
))
50 int rv
= ioctl(socket
, SIOCGIFADDR
, &ifr
);
52 return MapSystemError(rv
);
53 *address
= reinterpret_cast<sockaddr_in
*>(&ifr
.ifr_addr
)->sin_addr
.s_addr
;
61 UDPSocketLibevent::UDPSocketLibevent(
62 DatagramSocket::BindType bind_type
,
63 const RandIntCallback
& rand_int_cb
,
65 const net::NetLog::Source
& source
)
66 : socket_(kInvalidSocket
),
68 socket_options_(SOCKET_OPTION_MULTICAST_LOOP
),
69 multicast_interface_(0),
70 multicast_time_to_live_(1),
71 bind_type_(bind_type
),
72 rand_int_cb_(rand_int_cb
),
76 recv_from_address_(NULL
),
78 net_log_(BoundNetLog::Make(net_log
, NetLog::SOURCE_UDP_SOCKET
)) {
79 net_log_
.BeginEvent(NetLog::TYPE_SOCKET_ALIVE
,
80 source
.ToEventParametersCallback());
81 if (bind_type
== DatagramSocket::RANDOM_BIND
)
82 DCHECK(!rand_int_cb
.is_null());
85 UDPSocketLibevent::~UDPSocketLibevent() {
87 net_log_
.EndEvent(NetLog::TYPE_SOCKET_ALIVE
);
90 void UDPSocketLibevent::Close() {
91 DCHECK(CalledOnValidThread());
96 // Zero out any pending read/write callback state.
99 read_callback_
.Reset();
100 recv_from_address_
= NULL
;
103 write_callback_
.Reset();
104 send_to_address_
.reset();
106 bool ok
= read_socket_watcher_
.StopWatchingFileDescriptor();
108 ok
= write_socket_watcher_
.StopWatchingFileDescriptor();
111 if (IGNORE_EINTR(close(socket_
)) < 0)
112 PLOG(ERROR
) << "close";
114 socket_
= kInvalidSocket
;
118 int UDPSocketLibevent::GetPeerAddress(IPEndPoint
* address
) const {
119 DCHECK(CalledOnValidThread());
122 return ERR_SOCKET_NOT_CONNECTED
;
124 if (!remote_address_
.get()) {
125 SockaddrStorage storage
;
126 if (getpeername(socket_
, storage
.addr
, &storage
.addr_len
))
127 return MapSystemError(errno
);
128 scoped_ptr
<IPEndPoint
> address(new IPEndPoint());
129 if (!address
->FromSockAddr(storage
.addr
, storage
.addr_len
))
131 remote_address_
.reset(address
.release());
134 *address
= *remote_address_
;
138 int UDPSocketLibevent::GetLocalAddress(IPEndPoint
* address
) const {
139 DCHECK(CalledOnValidThread());
142 return ERR_SOCKET_NOT_CONNECTED
;
144 if (!local_address_
.get()) {
145 SockaddrStorage storage
;
146 if (getsockname(socket_
, storage
.addr
, &storage
.addr_len
))
147 return MapSystemError(errno
);
148 scoped_ptr
<IPEndPoint
> address(new IPEndPoint());
149 if (!address
->FromSockAddr(storage
.addr
, storage
.addr_len
))
151 local_address_
.reset(address
.release());
152 net_log_
.AddEvent(NetLog::TYPE_UDP_LOCAL_ADDRESS
,
153 CreateNetLogUDPConnectCallback(local_address_
.get()));
156 *address
= *local_address_
;
160 int UDPSocketLibevent::Read(IOBuffer
* buf
,
162 const CompletionCallback
& callback
) {
163 return RecvFrom(buf
, buf_len
, NULL
, callback
);
166 int UDPSocketLibevent::RecvFrom(IOBuffer
* buf
,
169 const CompletionCallback
& callback
) {
170 DCHECK(CalledOnValidThread());
171 DCHECK_NE(kInvalidSocket
, socket_
);
172 DCHECK(read_callback_
.is_null());
173 DCHECK(!recv_from_address_
);
174 DCHECK(!callback
.is_null()); // Synchronous operation not supported
175 DCHECK_GT(buf_len
, 0);
177 int nread
= InternalRecvFrom(buf
, buf_len
, address
);
178 if (nread
!= ERR_IO_PENDING
)
181 if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
182 socket_
, true, base::MessageLoopForIO::WATCH_READ
,
183 &read_socket_watcher_
, &read_watcher_
)) {
184 PLOG(ERROR
) << "WatchFileDescriptor failed on read";
185 int result
= MapSystemError(errno
);
186 LogRead(result
, NULL
, 0, NULL
);
191 read_buf_len_
= buf_len
;
192 recv_from_address_
= address
;
193 read_callback_
= callback
;
194 return ERR_IO_PENDING
;
197 int UDPSocketLibevent::Write(IOBuffer
* buf
,
199 const CompletionCallback
& callback
) {
200 return SendToOrWrite(buf
, buf_len
, NULL
, callback
);
203 int UDPSocketLibevent::SendTo(IOBuffer
* buf
,
205 const IPEndPoint
& address
,
206 const CompletionCallback
& callback
) {
207 return SendToOrWrite(buf
, buf_len
, &address
, callback
);
210 int UDPSocketLibevent::SendToOrWrite(IOBuffer
* buf
,
212 const IPEndPoint
* address
,
213 const CompletionCallback
& callback
) {
214 DCHECK(CalledOnValidThread());
215 DCHECK_NE(kInvalidSocket
, socket_
);
216 DCHECK(write_callback_
.is_null());
217 DCHECK(!callback
.is_null()); // Synchronous operation not supported
218 DCHECK_GT(buf_len
, 0);
220 int result
= InternalSendTo(buf
, buf_len
, address
);
221 if (result
!= ERR_IO_PENDING
)
224 if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
225 socket_
, true, base::MessageLoopForIO::WATCH_WRITE
,
226 &write_socket_watcher_
, &write_watcher_
)) {
227 DVLOG(1) << "WatchFileDescriptor failed on write, errno " << errno
;
228 int result
= MapSystemError(errno
);
229 LogWrite(result
, NULL
, NULL
);
234 write_buf_len_
= buf_len
;
235 DCHECK(!send_to_address_
.get());
237 send_to_address_
.reset(new IPEndPoint(*address
));
239 write_callback_
= callback
;
240 return ERR_IO_PENDING
;
243 int UDPSocketLibevent::Connect(const IPEndPoint
& address
) {
244 net_log_
.BeginEvent(NetLog::TYPE_UDP_CONNECT
,
245 CreateNetLogUDPConnectCallback(&address
));
246 int rv
= InternalConnect(address
);
249 net_log_
.EndEventWithNetErrorCode(NetLog::TYPE_UDP_CONNECT
, rv
);
253 int UDPSocketLibevent::InternalConnect(const IPEndPoint
& address
) {
254 DCHECK(CalledOnValidThread());
255 DCHECK(!is_connected());
256 DCHECK(!remote_address_
.get());
257 int rv
= CreateSocket(address
);
261 if (bind_type_
== DatagramSocket::RANDOM_BIND
)
262 rv
= RandomBind(address
);
263 // else connect() does the DatagramSocket::DEFAULT_BIND
270 SockaddrStorage storage
;
271 if (!address
.ToSockAddr(storage
.addr
, &storage
.addr_len
)) {
273 return ERR_ADDRESS_INVALID
;
276 rv
= HANDLE_EINTR(connect(socket_
, storage
.addr
, storage
.addr_len
));
278 // Close() may change the current errno. Map errno beforehand.
279 int result
= MapSystemError(errno
);
284 remote_address_
.reset(new IPEndPoint(address
));
288 int UDPSocketLibevent::Bind(const IPEndPoint
& address
) {
289 DCHECK(CalledOnValidThread());
290 DCHECK(!is_connected());
291 int rv
= CreateSocket(address
);
295 rv
= SetSocketOptions();
300 rv
= DoBind(address
);
305 local_address_
.reset();
309 bool UDPSocketLibevent::SetReceiveBufferSize(int32 size
) {
310 DCHECK(CalledOnValidThread());
311 int rv
= setsockopt(socket_
, SOL_SOCKET
, SO_RCVBUF
,
312 reinterpret_cast<const char*>(&size
), sizeof(size
));
313 DCHECK(!rv
) << "Could not set socket receive buffer size: " << errno
;
317 bool UDPSocketLibevent::SetSendBufferSize(int32 size
) {
318 DCHECK(CalledOnValidThread());
319 int rv
= setsockopt(socket_
, SOL_SOCKET
, SO_SNDBUF
,
320 reinterpret_cast<const char*>(&size
), sizeof(size
));
321 DCHECK(!rv
) << "Could not set socket send buffer size: " << errno
;
325 void UDPSocketLibevent::AllowAddressReuse() {
326 DCHECK(CalledOnValidThread());
327 DCHECK(!is_connected());
329 socket_options_
|= SOCKET_OPTION_REUSE_ADDRESS
;
332 void UDPSocketLibevent::AllowBroadcast() {
333 DCHECK(CalledOnValidThread());
334 DCHECK(!is_connected());
336 socket_options_
|= SOCKET_OPTION_BROADCAST
;
339 void UDPSocketLibevent::ReadWatcher::OnFileCanReadWithoutBlocking(int) {
340 if (!socket_
->read_callback_
.is_null())
341 socket_
->DidCompleteRead();
344 void UDPSocketLibevent::WriteWatcher::OnFileCanWriteWithoutBlocking(int) {
345 if (!socket_
->write_callback_
.is_null())
346 socket_
->DidCompleteWrite();
349 void UDPSocketLibevent::DoReadCallback(int rv
) {
350 DCHECK_NE(rv
, ERR_IO_PENDING
);
351 DCHECK(!read_callback_
.is_null());
353 // since Run may result in Read being called, clear read_callback_ up front.
354 CompletionCallback c
= read_callback_
;
355 read_callback_
.Reset();
359 void UDPSocketLibevent::DoWriteCallback(int rv
) {
360 DCHECK_NE(rv
, ERR_IO_PENDING
);
361 DCHECK(!write_callback_
.is_null());
363 // since Run may result in Write being called, clear write_callback_ up front.
364 CompletionCallback c
= write_callback_
;
365 write_callback_
.Reset();
369 void UDPSocketLibevent::DidCompleteRead() {
371 InternalRecvFrom(read_buf_
.get(), read_buf_len_
, recv_from_address_
);
372 if (result
!= ERR_IO_PENDING
) {
375 recv_from_address_
= NULL
;
376 bool ok
= read_socket_watcher_
.StopWatchingFileDescriptor();
378 DoReadCallback(result
);
382 void UDPSocketLibevent::LogRead(int result
,
385 const sockaddr
* addr
) const {
387 net_log_
.AddEventWithNetErrorCode(NetLog::TYPE_UDP_RECEIVE_ERROR
, result
);
391 if (net_log_
.IsLoggingAllEvents()) {
392 DCHECK(addr_len
> 0);
396 bool is_address_valid
= address
.FromSockAddr(addr
, addr_len
);
398 NetLog::TYPE_UDP_BYTES_RECEIVED
,
399 CreateNetLogUDPDataTranferCallback(
401 is_address_valid
? &address
: NULL
));
404 base::StatsCounter
read_bytes("udp.read_bytes");
405 read_bytes
.Add(result
);
408 int UDPSocketLibevent::CreateSocket(const IPEndPoint
& address
) {
409 addr_family_
= address
.GetSockAddrFamily();
410 socket_
= CreatePlatformSocket(addr_family_
, SOCK_DGRAM
, 0);
411 if (socket_
== kInvalidSocket
)
412 return MapSystemError(errno
);
413 if (SetNonBlocking(socket_
)) {
414 const int err
= MapSystemError(errno
);
421 void UDPSocketLibevent::DidCompleteWrite() {
423 InternalSendTo(write_buf_
.get(), write_buf_len_
, send_to_address_
.get());
425 if (result
!= ERR_IO_PENDING
) {
428 send_to_address_
.reset();
429 write_socket_watcher_
.StopWatchingFileDescriptor();
430 DoWriteCallback(result
);
434 void UDPSocketLibevent::LogWrite(int result
,
436 const IPEndPoint
* address
) const {
438 net_log_
.AddEventWithNetErrorCode(NetLog::TYPE_UDP_SEND_ERROR
, result
);
442 if (net_log_
.IsLoggingAllEvents()) {
444 NetLog::TYPE_UDP_BYTES_SENT
,
445 CreateNetLogUDPDataTranferCallback(result
, bytes
, address
));
448 base::StatsCounter
write_bytes("udp.write_bytes");
449 write_bytes
.Add(result
);
452 int UDPSocketLibevent::InternalRecvFrom(IOBuffer
* buf
, int buf_len
,
453 IPEndPoint
* address
) {
454 int bytes_transferred
;
457 SockaddrStorage storage
;
460 HANDLE_EINTR(recvfrom(socket_
,
467 if (bytes_transferred
>= 0) {
468 result
= bytes_transferred
;
469 if (address
&& !address
->FromSockAddr(storage
.addr
, storage
.addr_len
))
472 result
= MapSystemError(errno
);
474 if (result
!= ERR_IO_PENDING
)
475 LogRead(result
, buf
->data(), storage
.addr_len
, storage
.addr
);
479 int UDPSocketLibevent::InternalSendTo(IOBuffer
* buf
, int buf_len
,
480 const IPEndPoint
* address
) {
481 SockaddrStorage storage
;
482 struct sockaddr
* addr
= storage
.addr
;
485 storage
.addr_len
= 0;
487 if (!address
->ToSockAddr(storage
.addr
, &storage
.addr_len
)) {
488 int result
= ERR_FAILED
;
489 LogWrite(result
, NULL
, NULL
);
494 int result
= HANDLE_EINTR(sendto(socket_
,
501 result
= MapSystemError(errno
);
502 if (result
!= ERR_IO_PENDING
)
503 LogWrite(result
, buf
->data(), address
);
507 int UDPSocketLibevent::SetSocketOptions() {
509 if (socket_options_
& SOCKET_OPTION_REUSE_ADDRESS
) {
510 int rv
= setsockopt(socket_
, SOL_SOCKET
, SO_REUSEADDR
, &true_value
,
513 return MapSystemError(errno
);
515 if (socket_options_
& SOCKET_OPTION_BROADCAST
) {
517 #if defined(OS_MACOSX)
518 // SO_REUSEPORT on OSX permits multiple processes to each receive
519 // UDP multicast or broadcast datagrams destined for the bound
521 rv
= setsockopt(socket_
, SOL_SOCKET
, SO_REUSEPORT
, &true_value
,
524 rv
= setsockopt(socket_
, SOL_SOCKET
, SO_BROADCAST
, &true_value
,
526 #endif // defined(OS_MACOSX)
528 return MapSystemError(errno
);
531 if (!(socket_options_
& SOCKET_OPTION_MULTICAST_LOOP
)) {
533 if (addr_family_
== AF_INET
) {
535 rv
= setsockopt(socket_
, IPPROTO_IP
, IP_MULTICAST_LOOP
,
536 &loop
, sizeof(loop
));
539 rv
= setsockopt(socket_
, IPPROTO_IPV6
, IPV6_MULTICAST_LOOP
,
540 &loop
, sizeof(loop
));
543 return MapSystemError(errno
);
545 if (multicast_time_to_live_
!= IP_DEFAULT_MULTICAST_TTL
) {
547 if (addr_family_
== AF_INET
) {
548 u_char ttl
= multicast_time_to_live_
;
549 rv
= setsockopt(socket_
, IPPROTO_IP
, IP_MULTICAST_TTL
,
552 // Signed integer. -1 to use route default.
553 int ttl
= multicast_time_to_live_
;
554 rv
= setsockopt(socket_
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
,
558 return MapSystemError(errno
);
560 if (multicast_interface_
!= 0) {
561 switch (addr_family_
) {
563 #if !defined(OS_MACOSX)
565 mreq
.imr_ifindex
= multicast_interface_
;
566 mreq
.imr_address
.s_addr
= htonl(INADDR_ANY
);
569 int error
= GetIPv4AddressFromIndex(socket_
, multicast_interface_
,
570 &mreq
.imr_interface
.s_addr
);
574 int rv
= setsockopt(socket_
, IPPROTO_IP
, IP_MULTICAST_IF
,
575 reinterpret_cast<const char*>(&mreq
), sizeof(mreq
));
577 return MapSystemError(errno
);
581 uint32 interface_index
= multicast_interface_
;
582 int rv
= setsockopt(socket_
, IPPROTO_IPV6
, IPV6_MULTICAST_IF
,
583 reinterpret_cast<const char*>(&interface_index
),
584 sizeof(interface_index
));
586 return MapSystemError(errno
);
590 NOTREACHED() << "Invalid address family";
591 return ERR_ADDRESS_INVALID
;
597 int UDPSocketLibevent::DoBind(const IPEndPoint
& address
) {
598 SockaddrStorage storage
;
599 if (!address
.ToSockAddr(storage
.addr
, &storage
.addr_len
))
600 return ERR_ADDRESS_INVALID
;
601 int rv
= bind(socket_
, storage
.addr
, storage
.addr_len
);
602 return rv
< 0 ? MapSystemError(errno
) : rv
;
605 int UDPSocketLibevent::RandomBind(const IPEndPoint
& address
) {
606 DCHECK(bind_type_
== DatagramSocket::RANDOM_BIND
&& !rand_int_cb_
.is_null());
608 // Construct IPAddressNumber of appropriate size (IPv4 or IPv6) of 0s.
609 IPAddressNumber
ip(address
.address().size());
611 for (int i
= 0; i
< kBindRetries
; ++i
) {
612 int rv
= DoBind(IPEndPoint(ip
, rand_int_cb_
.Run(kPortStart
, kPortEnd
)));
613 if (rv
== OK
|| rv
!= ERR_ADDRESS_IN_USE
)
616 return DoBind(IPEndPoint(ip
, 0));
619 int UDPSocketLibevent::JoinGroup(const IPAddressNumber
& group_address
) const {
620 DCHECK(CalledOnValidThread());
622 return ERR_SOCKET_NOT_CONNECTED
;
624 switch (group_address
.size()) {
625 case kIPv4AddressSize
: {
626 if (addr_family_
!= AF_INET
)
627 return ERR_ADDRESS_INVALID
;
629 #if !defined(OS_MACOSX)
631 mreq
.imr_ifindex
= multicast_interface_
;
632 mreq
.imr_address
.s_addr
= htonl(INADDR_ANY
);
635 int error
= GetIPv4AddressFromIndex(socket_
, multicast_interface_
,
636 &mreq
.imr_interface
.s_addr
);
640 memcpy(&mreq
.imr_multiaddr
, &group_address
[0], kIPv4AddressSize
);
641 int rv
= setsockopt(socket_
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
,
642 &mreq
, sizeof(mreq
));
644 return MapSystemError(errno
);
647 case kIPv6AddressSize
: {
648 if (addr_family_
!= AF_INET6
)
649 return ERR_ADDRESS_INVALID
;
651 mreq
.ipv6mr_interface
= multicast_interface_
;
652 memcpy(&mreq
.ipv6mr_multiaddr
, &group_address
[0], kIPv6AddressSize
);
653 int rv
= setsockopt(socket_
, IPPROTO_IPV6
, IPV6_JOIN_GROUP
,
654 &mreq
, sizeof(mreq
));
656 return MapSystemError(errno
);
660 NOTREACHED() << "Invalid address family";
661 return ERR_ADDRESS_INVALID
;
665 int UDPSocketLibevent::LeaveGroup(const IPAddressNumber
& group_address
) const {
666 DCHECK(CalledOnValidThread());
669 return ERR_SOCKET_NOT_CONNECTED
;
671 switch (group_address
.size()) {
672 case kIPv4AddressSize
: {
673 if (addr_family_
!= AF_INET
)
674 return ERR_ADDRESS_INVALID
;
676 mreq
.imr_interface
.s_addr
= INADDR_ANY
;
677 memcpy(&mreq
.imr_multiaddr
, &group_address
[0], kIPv4AddressSize
);
678 int rv
= setsockopt(socket_
, IPPROTO_IP
, IP_DROP_MEMBERSHIP
,
679 &mreq
, sizeof(mreq
));
681 return MapSystemError(errno
);
684 case kIPv6AddressSize
: {
685 if (addr_family_
!= AF_INET6
)
686 return ERR_ADDRESS_INVALID
;
688 mreq
.ipv6mr_interface
= 0; // 0 indicates default multicast interface.
689 memcpy(&mreq
.ipv6mr_multiaddr
, &group_address
[0], kIPv6AddressSize
);
690 int rv
= setsockopt(socket_
, IPPROTO_IPV6
, IPV6_LEAVE_GROUP
,
691 &mreq
, sizeof(mreq
));
693 return MapSystemError(errno
);
697 NOTREACHED() << "Invalid address family";
698 return ERR_ADDRESS_INVALID
;
702 int UDPSocketLibevent::SetMulticastInterface(uint32 interface_index
) {
703 DCHECK(CalledOnValidThread());
705 return ERR_SOCKET_IS_CONNECTED
;
706 multicast_interface_
= interface_index
;
710 int UDPSocketLibevent::SetMulticastTimeToLive(int time_to_live
) {
711 DCHECK(CalledOnValidThread());
713 return ERR_SOCKET_IS_CONNECTED
;
715 if (time_to_live
< 0 || time_to_live
> 255)
716 return ERR_INVALID_ARGUMENT
;
717 multicast_time_to_live_
= time_to_live
;
721 int UDPSocketLibevent::SetMulticastLoopbackMode(bool loopback
) {
722 DCHECK(CalledOnValidThread());
724 return ERR_SOCKET_IS_CONNECTED
;
727 socket_options_
|= SOCKET_OPTION_MULTICAST_LOOP
;
729 socket_options_
&= ~SOCKET_OPTION_MULTICAST_LOOP
;
733 int UDPSocketLibevent::SetDiffServCodePoint(DiffServCodePoint dscp
) {
734 if (dscp
== DSCP_NO_CHANGE
) {
738 int dscp_and_ecn
= dscp
<< 2;
739 if (addr_family_
== AF_INET
) {
740 rv
= setsockopt(socket_
, IPPROTO_IP
, IP_TOS
,
741 &dscp_and_ecn
, sizeof(dscp_and_ecn
));
743 rv
= setsockopt(socket_
, IPPROTO_IPV6
, IPV6_TCLASS
,
744 &dscp_and_ecn
, sizeof(dscp_and_ecn
));
747 return MapSystemError(errno
);