1*6777b538SAndroid Build Coastguard Worker // Copyright 2012 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker
5*6777b538SAndroid Build Coastguard Worker #include "build/build_config.h"
6*6777b538SAndroid Build Coastguard Worker
7*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_APPLE)
8*6777b538SAndroid Build Coastguard Worker // This must be defined before including <netinet/in.h>
9*6777b538SAndroid Build Coastguard Worker // to use IPV6_DONTFRAG, one of the IPv6 Sockets option introduced by RFC 3542
10*6777b538SAndroid Build Coastguard Worker #define __APPLE_USE_RFC_3542
11*6777b538SAndroid Build Coastguard Worker #endif // BUILDFLAG(IS_APPLE)
12*6777b538SAndroid Build Coastguard Worker
13*6777b538SAndroid Build Coastguard Worker #include "net/socket/udp_socket_posix.h"
14*6777b538SAndroid Build Coastguard Worker
15*6777b538SAndroid Build Coastguard Worker #include <errno.h>
16*6777b538SAndroid Build Coastguard Worker #include <fcntl.h>
17*6777b538SAndroid Build Coastguard Worker #include <net/if.h>
18*6777b538SAndroid Build Coastguard Worker #include <netdb.h>
19*6777b538SAndroid Build Coastguard Worker #include <netinet/in.h>
20*6777b538SAndroid Build Coastguard Worker #include <sys/ioctl.h>
21*6777b538SAndroid Build Coastguard Worker #include <sys/socket.h>
22*6777b538SAndroid Build Coastguard Worker
23*6777b538SAndroid Build Coastguard Worker #include <memory>
24*6777b538SAndroid Build Coastguard Worker
25*6777b538SAndroid Build Coastguard Worker #include "base/debug/alias.h"
26*6777b538SAndroid Build Coastguard Worker #include "base/feature_list.h"
27*6777b538SAndroid Build Coastguard Worker #include "base/files/file_util.h"
28*6777b538SAndroid Build Coastguard Worker #include "base/functional/bind.h"
29*6777b538SAndroid Build Coastguard Worker #include "base/functional/callback.h"
30*6777b538SAndroid Build Coastguard Worker #include "base/functional/callback_helpers.h"
31*6777b538SAndroid Build Coastguard Worker #include "base/logging.h"
32*6777b538SAndroid Build Coastguard Worker #include "base/posix/eintr_wrapper.h"
33*6777b538SAndroid Build Coastguard Worker #include "base/rand_util.h"
34*6777b538SAndroid Build Coastguard Worker #include "base/task/current_thread.h"
35*6777b538SAndroid Build Coastguard Worker #include "base/task/thread_pool.h"
36*6777b538SAndroid Build Coastguard Worker #include "build/chromeos_buildflags.h"
37*6777b538SAndroid Build Coastguard Worker #include "net/base/cronet_buildflags.h"
38*6777b538SAndroid Build Coastguard Worker #include "net/base/features.h"
39*6777b538SAndroid Build Coastguard Worker #include "net/base/io_buffer.h"
40*6777b538SAndroid Build Coastguard Worker #include "net/base/ip_address.h"
41*6777b538SAndroid Build Coastguard Worker #include "net/base/ip_endpoint.h"
42*6777b538SAndroid Build Coastguard Worker #include "net/base/net_errors.h"
43*6777b538SAndroid Build Coastguard Worker #include "net/base/network_activity_monitor.h"
44*6777b538SAndroid Build Coastguard Worker #include "net/base/sockaddr_storage.h"
45*6777b538SAndroid Build Coastguard Worker #include "net/base/trace_constants.h"
46*6777b538SAndroid Build Coastguard Worker #include "net/base/tracing.h"
47*6777b538SAndroid Build Coastguard Worker #include "net/log/net_log.h"
48*6777b538SAndroid Build Coastguard Worker #include "net/log/net_log_event_type.h"
49*6777b538SAndroid Build Coastguard Worker #include "net/log/net_log_source.h"
50*6777b538SAndroid Build Coastguard Worker #include "net/log/net_log_source_type.h"
51*6777b538SAndroid Build Coastguard Worker #include "net/socket/socket_descriptor.h"
52*6777b538SAndroid Build Coastguard Worker #include "net/socket/socket_options.h"
53*6777b538SAndroid Build Coastguard Worker #include "net/socket/socket_tag.h"
54*6777b538SAndroid Build Coastguard Worker #include "net/socket/udp_net_log_parameters.h"
55*6777b538SAndroid Build Coastguard Worker #include "net/traffic_annotation/network_traffic_annotation.h"
56*6777b538SAndroid Build Coastguard Worker
57*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_ANDROID)
58*6777b538SAndroid Build Coastguard Worker #include "base/native_library.h"
59*6777b538SAndroid Build Coastguard Worker #include "net/android/network_library.h"
60*6777b538SAndroid Build Coastguard Worker #endif // BUILDFLAG(IS_ANDROID)
61*6777b538SAndroid Build Coastguard Worker
62*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_MAC)
63*6777b538SAndroid Build Coastguard Worker #include "base/mac/mac_util.h"
64*6777b538SAndroid Build Coastguard Worker #endif // BUILDFLAG(IS_MAC)
65*6777b538SAndroid Build Coastguard Worker
66*6777b538SAndroid Build Coastguard Worker namespace net {
67*6777b538SAndroid Build Coastguard Worker
68*6777b538SAndroid Build Coastguard Worker namespace {
69*6777b538SAndroid Build Coastguard Worker
70*6777b538SAndroid Build Coastguard Worker const int kBindRetries = 10;
71*6777b538SAndroid Build Coastguard Worker const int kPortStart = 1024;
72*6777b538SAndroid Build Coastguard Worker const int kPortEnd = 65535;
73*6777b538SAndroid Build Coastguard Worker const int kActivityMonitorBytesThreshold = 65535;
74*6777b538SAndroid Build Coastguard Worker const int kActivityMonitorMinimumSamplesForThroughputEstimate = 2;
75*6777b538SAndroid Build Coastguard Worker const base::TimeDelta kActivityMonitorMsThreshold = base::Milliseconds(100);
76*6777b538SAndroid Build Coastguard Worker
77*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_APPLE) && !BUILDFLAG(CRONET_BUILD)
78*6777b538SAndroid Build Coastguard Worker
79*6777b538SAndroid Build Coastguard Worker // On macOS, the file descriptor is guarded to detect the cause of
80*6777b538SAndroid Build Coastguard Worker // https://crbug.com/640281. The guard mechanism is a private interface, so
81*6777b538SAndroid Build Coastguard Worker // these functions, types, and constants are not defined in any public header,
82*6777b538SAndroid Build Coastguard Worker // but with these declarations, it's possible to link against these symbols and
83*6777b538SAndroid Build Coastguard Worker // directly call into the functions that will be available at run time.
84*6777b538SAndroid Build Coastguard Worker
85*6777b538SAndroid Build Coastguard Worker // Declarations from 12.3 xnu-8020.101.4/bsd/sys/guarded.h (not in the SDK).
86*6777b538SAndroid Build Coastguard Worker extern "C" {
87*6777b538SAndroid Build Coastguard Worker
88*6777b538SAndroid Build Coastguard Worker using guardid_t = uint64_t;
89*6777b538SAndroid Build Coastguard Worker
90*6777b538SAndroid Build Coastguard Worker const unsigned int GUARD_CLOSE = 1u << 0;
91*6777b538SAndroid Build Coastguard Worker const unsigned int GUARD_DUP = 1u << 1;
92*6777b538SAndroid Build Coastguard Worker
93*6777b538SAndroid Build Coastguard Worker int guarded_close_np(int fd, const guardid_t* guard);
94*6777b538SAndroid Build Coastguard Worker int change_fdguard_np(int fd,
95*6777b538SAndroid Build Coastguard Worker const guardid_t* guard,
96*6777b538SAndroid Build Coastguard Worker unsigned int guardflags,
97*6777b538SAndroid Build Coastguard Worker const guardid_t* nguard,
98*6777b538SAndroid Build Coastguard Worker unsigned int nguardflags,
99*6777b538SAndroid Build Coastguard Worker int* fdflagsp);
100*6777b538SAndroid Build Coastguard Worker
101*6777b538SAndroid Build Coastguard Worker } // extern "C"
102*6777b538SAndroid Build Coastguard Worker
103*6777b538SAndroid Build Coastguard Worker const guardid_t kSocketFdGuard = 0xD712BC0BC9A4EAD4;
104*6777b538SAndroid Build Coastguard Worker
105*6777b538SAndroid Build Coastguard Worker #endif // BUILDFLAG(IS_APPLE) && !BUILDFLAG(CRONET_BUILD)
106*6777b538SAndroid Build Coastguard Worker
GetSocketFDHash(int fd)107*6777b538SAndroid Build Coastguard Worker int GetSocketFDHash(int fd) {
108*6777b538SAndroid Build Coastguard Worker return fd ^ 1595649551;
109*6777b538SAndroid Build Coastguard Worker }
110*6777b538SAndroid Build Coastguard Worker
111*6777b538SAndroid Build Coastguard Worker } // namespace
112*6777b538SAndroid Build Coastguard Worker
UDPSocketPosix(DatagramSocket::BindType bind_type,net::NetLog * net_log,const net::NetLogSource & source)113*6777b538SAndroid Build Coastguard Worker UDPSocketPosix::UDPSocketPosix(DatagramSocket::BindType bind_type,
114*6777b538SAndroid Build Coastguard Worker net::NetLog* net_log,
115*6777b538SAndroid Build Coastguard Worker const net::NetLogSource& source)
116*6777b538SAndroid Build Coastguard Worker : socket_(kInvalidSocket),
117*6777b538SAndroid Build Coastguard Worker bind_type_(bind_type),
118*6777b538SAndroid Build Coastguard Worker read_socket_watcher_(FROM_HERE),
119*6777b538SAndroid Build Coastguard Worker write_socket_watcher_(FROM_HERE),
120*6777b538SAndroid Build Coastguard Worker read_watcher_(this),
121*6777b538SAndroid Build Coastguard Worker write_watcher_(this),
122*6777b538SAndroid Build Coastguard Worker net_log_(NetLogWithSource::Make(net_log, NetLogSourceType::UDP_SOCKET)),
123*6777b538SAndroid Build Coastguard Worker bound_network_(handles::kInvalidNetworkHandle),
124*6777b538SAndroid Build Coastguard Worker always_update_bytes_received_(base::FeatureList::IsEnabled(
125*6777b538SAndroid Build Coastguard Worker features::kUdpSocketPosixAlwaysUpdateBytesReceived)) {
126*6777b538SAndroid Build Coastguard Worker net_log_.BeginEventReferencingSource(NetLogEventType::SOCKET_ALIVE, source);
127*6777b538SAndroid Build Coastguard Worker }
128*6777b538SAndroid Build Coastguard Worker
UDPSocketPosix(DatagramSocket::BindType bind_type,NetLogWithSource source_net_log)129*6777b538SAndroid Build Coastguard Worker UDPSocketPosix::UDPSocketPosix(DatagramSocket::BindType bind_type,
130*6777b538SAndroid Build Coastguard Worker NetLogWithSource source_net_log)
131*6777b538SAndroid Build Coastguard Worker : socket_(kInvalidSocket),
132*6777b538SAndroid Build Coastguard Worker bind_type_(bind_type),
133*6777b538SAndroid Build Coastguard Worker read_socket_watcher_(FROM_HERE),
134*6777b538SAndroid Build Coastguard Worker write_socket_watcher_(FROM_HERE),
135*6777b538SAndroid Build Coastguard Worker read_watcher_(this),
136*6777b538SAndroid Build Coastguard Worker write_watcher_(this),
137*6777b538SAndroid Build Coastguard Worker net_log_(source_net_log),
138*6777b538SAndroid Build Coastguard Worker bound_network_(handles::kInvalidNetworkHandle),
139*6777b538SAndroid Build Coastguard Worker always_update_bytes_received_(base::FeatureList::IsEnabled(
140*6777b538SAndroid Build Coastguard Worker features::kUdpSocketPosixAlwaysUpdateBytesReceived)) {
141*6777b538SAndroid Build Coastguard Worker net_log_.BeginEventReferencingSource(NetLogEventType::SOCKET_ALIVE,
142*6777b538SAndroid Build Coastguard Worker net_log_.source());
143*6777b538SAndroid Build Coastguard Worker }
144*6777b538SAndroid Build Coastguard Worker
~UDPSocketPosix()145*6777b538SAndroid Build Coastguard Worker UDPSocketPosix::~UDPSocketPosix() {
146*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
147*6777b538SAndroid Build Coastguard Worker Close();
148*6777b538SAndroid Build Coastguard Worker net_log_.EndEvent(NetLogEventType::SOCKET_ALIVE);
149*6777b538SAndroid Build Coastguard Worker }
150*6777b538SAndroid Build Coastguard Worker
Open(AddressFamily address_family)151*6777b538SAndroid Build Coastguard Worker int UDPSocketPosix::Open(AddressFamily address_family) {
152*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
153*6777b538SAndroid Build Coastguard Worker DCHECK_EQ(socket_, kInvalidSocket);
154*6777b538SAndroid Build Coastguard Worker
155*6777b538SAndroid Build Coastguard Worker auto owned_socket_count = TryAcquireGlobalUDPSocketCount();
156*6777b538SAndroid Build Coastguard Worker if (owned_socket_count.empty())
157*6777b538SAndroid Build Coastguard Worker return ERR_INSUFFICIENT_RESOURCES;
158*6777b538SAndroid Build Coastguard Worker
159*6777b538SAndroid Build Coastguard Worker owned_socket_count_ = std::move(owned_socket_count);
160*6777b538SAndroid Build Coastguard Worker addr_family_ = ConvertAddressFamily(address_family);
161*6777b538SAndroid Build Coastguard Worker socket_ = CreatePlatformSocket(addr_family_, SOCK_DGRAM, 0);
162*6777b538SAndroid Build Coastguard Worker if (socket_ == kInvalidSocket) {
163*6777b538SAndroid Build Coastguard Worker owned_socket_count_.Reset();
164*6777b538SAndroid Build Coastguard Worker return MapSystemError(errno);
165*6777b538SAndroid Build Coastguard Worker }
166*6777b538SAndroid Build Coastguard Worker
167*6777b538SAndroid Build Coastguard Worker return ConfigureOpenedSocket();
168*6777b538SAndroid Build Coastguard Worker }
169*6777b538SAndroid Build Coastguard Worker
AdoptOpenedSocket(AddressFamily address_family,int socket)170*6777b538SAndroid Build Coastguard Worker int UDPSocketPosix::AdoptOpenedSocket(AddressFamily address_family,
171*6777b538SAndroid Build Coastguard Worker int socket) {
172*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
173*6777b538SAndroid Build Coastguard Worker DCHECK_EQ(socket_, kInvalidSocket);
174*6777b538SAndroid Build Coastguard Worker auto owned_socket_count = TryAcquireGlobalUDPSocketCount();
175*6777b538SAndroid Build Coastguard Worker if (owned_socket_count.empty()) {
176*6777b538SAndroid Build Coastguard Worker return ERR_INSUFFICIENT_RESOURCES;
177*6777b538SAndroid Build Coastguard Worker }
178*6777b538SAndroid Build Coastguard Worker
179*6777b538SAndroid Build Coastguard Worker owned_socket_count_ = std::move(owned_socket_count);
180*6777b538SAndroid Build Coastguard Worker socket_ = socket;
181*6777b538SAndroid Build Coastguard Worker addr_family_ = ConvertAddressFamily(address_family);
182*6777b538SAndroid Build Coastguard Worker return ConfigureOpenedSocket();
183*6777b538SAndroid Build Coastguard Worker }
184*6777b538SAndroid Build Coastguard Worker
ConfigureOpenedSocket()185*6777b538SAndroid Build Coastguard Worker int UDPSocketPosix::ConfigureOpenedSocket() {
186*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_APPLE) && !BUILDFLAG(CRONET_BUILD)
187*6777b538SAndroid Build Coastguard Worker PCHECK(change_fdguard_np(socket_, nullptr, 0, &kSocketFdGuard,
188*6777b538SAndroid Build Coastguard Worker GUARD_CLOSE | GUARD_DUP, nullptr) == 0);
189*6777b538SAndroid Build Coastguard Worker #endif // BUILDFLAG(IS_APPLE) && !BUILDFLAG(CRONET_BUILD)
190*6777b538SAndroid Build Coastguard Worker socket_hash_ = GetSocketFDHash(socket_);
191*6777b538SAndroid Build Coastguard Worker if (!base::SetNonBlocking(socket_)) {
192*6777b538SAndroid Build Coastguard Worker const int err = MapSystemError(errno);
193*6777b538SAndroid Build Coastguard Worker Close();
194*6777b538SAndroid Build Coastguard Worker return err;
195*6777b538SAndroid Build Coastguard Worker }
196*6777b538SAndroid Build Coastguard Worker if (tag_ != SocketTag())
197*6777b538SAndroid Build Coastguard Worker tag_.Apply(socket_);
198*6777b538SAndroid Build Coastguard Worker
199*6777b538SAndroid Build Coastguard Worker return OK;
200*6777b538SAndroid Build Coastguard Worker }
201*6777b538SAndroid Build Coastguard Worker
Increment(uint32_t bytes)202*6777b538SAndroid Build Coastguard Worker void UDPSocketPosix::ReceivedActivityMonitor::Increment(uint32_t bytes) {
203*6777b538SAndroid Build Coastguard Worker if (!bytes)
204*6777b538SAndroid Build Coastguard Worker return;
205*6777b538SAndroid Build Coastguard Worker bool timer_running = timer_.IsRunning();
206*6777b538SAndroid Build Coastguard Worker bytes_ += bytes;
207*6777b538SAndroid Build Coastguard Worker increments_++;
208*6777b538SAndroid Build Coastguard Worker // Allow initial updates to make sure throughput estimator has
209*6777b538SAndroid Build Coastguard Worker // enough samples to generate a value. (low water mark)
210*6777b538SAndroid Build Coastguard Worker // Or once the bytes threshold has be met. (high water mark)
211*6777b538SAndroid Build Coastguard Worker if (increments_ < kActivityMonitorMinimumSamplesForThroughputEstimate ||
212*6777b538SAndroid Build Coastguard Worker bytes_ > kActivityMonitorBytesThreshold) {
213*6777b538SAndroid Build Coastguard Worker Update();
214*6777b538SAndroid Build Coastguard Worker if (timer_running)
215*6777b538SAndroid Build Coastguard Worker timer_.Reset();
216*6777b538SAndroid Build Coastguard Worker }
217*6777b538SAndroid Build Coastguard Worker if (!timer_running) {
218*6777b538SAndroid Build Coastguard Worker timer_.Start(FROM_HERE, kActivityMonitorMsThreshold, this,
219*6777b538SAndroid Build Coastguard Worker &UDPSocketPosix::ReceivedActivityMonitor::OnTimerFired);
220*6777b538SAndroid Build Coastguard Worker }
221*6777b538SAndroid Build Coastguard Worker }
222*6777b538SAndroid Build Coastguard Worker
Update()223*6777b538SAndroid Build Coastguard Worker void UDPSocketPosix::ReceivedActivityMonitor::Update() {
224*6777b538SAndroid Build Coastguard Worker if (!bytes_)
225*6777b538SAndroid Build Coastguard Worker return;
226*6777b538SAndroid Build Coastguard Worker activity_monitor::IncrementBytesReceived(bytes_);
227*6777b538SAndroid Build Coastguard Worker bytes_ = 0;
228*6777b538SAndroid Build Coastguard Worker }
229*6777b538SAndroid Build Coastguard Worker
OnClose()230*6777b538SAndroid Build Coastguard Worker void UDPSocketPosix::ReceivedActivityMonitor::OnClose() {
231*6777b538SAndroid Build Coastguard Worker timer_.Stop();
232*6777b538SAndroid Build Coastguard Worker Update();
233*6777b538SAndroid Build Coastguard Worker }
234*6777b538SAndroid Build Coastguard Worker
OnTimerFired()235*6777b538SAndroid Build Coastguard Worker void UDPSocketPosix::ReceivedActivityMonitor::OnTimerFired() {
236*6777b538SAndroid Build Coastguard Worker increments_ = 0;
237*6777b538SAndroid Build Coastguard Worker if (!bytes_) {
238*6777b538SAndroid Build Coastguard Worker // Can happen if the socket has been idle and have had no
239*6777b538SAndroid Build Coastguard Worker // increments since the timer previously fired. Don't bother
240*6777b538SAndroid Build Coastguard Worker // keeping the timer running in this case.
241*6777b538SAndroid Build Coastguard Worker timer_.Stop();
242*6777b538SAndroid Build Coastguard Worker return;
243*6777b538SAndroid Build Coastguard Worker }
244*6777b538SAndroid Build Coastguard Worker Update();
245*6777b538SAndroid Build Coastguard Worker }
246*6777b538SAndroid Build Coastguard Worker
Close()247*6777b538SAndroid Build Coastguard Worker void UDPSocketPosix::Close() {
248*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
249*6777b538SAndroid Build Coastguard Worker
250*6777b538SAndroid Build Coastguard Worker owned_socket_count_.Reset();
251*6777b538SAndroid Build Coastguard Worker
252*6777b538SAndroid Build Coastguard Worker if (socket_ == kInvalidSocket)
253*6777b538SAndroid Build Coastguard Worker return;
254*6777b538SAndroid Build Coastguard Worker
255*6777b538SAndroid Build Coastguard Worker // Zero out any pending read/write callback state.
256*6777b538SAndroid Build Coastguard Worker read_buf_.reset();
257*6777b538SAndroid Build Coastguard Worker read_buf_len_ = 0;
258*6777b538SAndroid Build Coastguard Worker read_callback_.Reset();
259*6777b538SAndroid Build Coastguard Worker recv_from_address_ = nullptr;
260*6777b538SAndroid Build Coastguard Worker write_buf_.reset();
261*6777b538SAndroid Build Coastguard Worker write_buf_len_ = 0;
262*6777b538SAndroid Build Coastguard Worker write_callback_.Reset();
263*6777b538SAndroid Build Coastguard Worker send_to_address_.reset();
264*6777b538SAndroid Build Coastguard Worker
265*6777b538SAndroid Build Coastguard Worker bool ok = read_socket_watcher_.StopWatchingFileDescriptor();
266*6777b538SAndroid Build Coastguard Worker DCHECK(ok);
267*6777b538SAndroid Build Coastguard Worker ok = write_socket_watcher_.StopWatchingFileDescriptor();
268*6777b538SAndroid Build Coastguard Worker DCHECK(ok);
269*6777b538SAndroid Build Coastguard Worker
270*6777b538SAndroid Build Coastguard Worker // Verify that |socket_| hasn't been corrupted. Needed to debug
271*6777b538SAndroid Build Coastguard Worker // crbug.com/906005.
272*6777b538SAndroid Build Coastguard Worker CHECK_EQ(socket_hash_, GetSocketFDHash(socket_));
273*6777b538SAndroid Build Coastguard Worker TRACE_EVENT("base", perfetto::StaticString{"CloseSocketUDP"});
274*6777b538SAndroid Build Coastguard Worker
275*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_APPLE) && !BUILDFLAG(CRONET_BUILD)
276*6777b538SAndroid Build Coastguard Worker // Attempt to clear errors on the socket so that they are not returned by
277*6777b538SAndroid Build Coastguard Worker // close(). This seems to be effective at clearing some, but not all,
278*6777b538SAndroid Build Coastguard Worker // EPROTOTYPE errors. See https://crbug.com/1151048.
279*6777b538SAndroid Build Coastguard Worker int value = 0;
280*6777b538SAndroid Build Coastguard Worker socklen_t value_len = sizeof(value);
281*6777b538SAndroid Build Coastguard Worker HANDLE_EINTR(getsockopt(socket_, SOL_SOCKET, SO_ERROR, &value, &value_len));
282*6777b538SAndroid Build Coastguard Worker
283*6777b538SAndroid Build Coastguard Worker if (IGNORE_EINTR(guarded_close_np(socket_, &kSocketFdGuard)) != 0) {
284*6777b538SAndroid Build Coastguard Worker // There is a bug in the Mac OS kernel that it can return an ENOTCONN or
285*6777b538SAndroid Build Coastguard Worker // EPROTOTYPE error. In this case we don't know whether the file descriptor
286*6777b538SAndroid Build Coastguard Worker // is still allocated or not. We cannot safely close the file descriptor
287*6777b538SAndroid Build Coastguard Worker // because it may have been reused by another thread in the meantime. We may
288*6777b538SAndroid Build Coastguard Worker // leak file handles here and cause a crash indirectly later. See
289*6777b538SAndroid Build Coastguard Worker // https://crbug.com/1151048.
290*6777b538SAndroid Build Coastguard Worker PCHECK(errno == ENOTCONN || errno == EPROTOTYPE);
291*6777b538SAndroid Build Coastguard Worker }
292*6777b538SAndroid Build Coastguard Worker #else
293*6777b538SAndroid Build Coastguard Worker PCHECK(IGNORE_EINTR(close(socket_)) == 0);
294*6777b538SAndroid Build Coastguard Worker #endif // BUILDFLAG(IS_APPLE) && !BUILDFLAG(CRONET_BUILD)
295*6777b538SAndroid Build Coastguard Worker
296*6777b538SAndroid Build Coastguard Worker socket_ = kInvalidSocket;
297*6777b538SAndroid Build Coastguard Worker addr_family_ = 0;
298*6777b538SAndroid Build Coastguard Worker is_connected_ = false;
299*6777b538SAndroid Build Coastguard Worker tag_ = SocketTag();
300*6777b538SAndroid Build Coastguard Worker
301*6777b538SAndroid Build Coastguard Worker received_activity_monitor_.OnClose();
302*6777b538SAndroid Build Coastguard Worker }
303*6777b538SAndroid Build Coastguard Worker
GetPeerAddress(IPEndPoint * address) const304*6777b538SAndroid Build Coastguard Worker int UDPSocketPosix::GetPeerAddress(IPEndPoint* address) const {
305*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
306*6777b538SAndroid Build Coastguard Worker DCHECK(address);
307*6777b538SAndroid Build Coastguard Worker if (!is_connected())
308*6777b538SAndroid Build Coastguard Worker return ERR_SOCKET_NOT_CONNECTED;
309*6777b538SAndroid Build Coastguard Worker
310*6777b538SAndroid Build Coastguard Worker if (!remote_address_.get()) {
311*6777b538SAndroid Build Coastguard Worker SockaddrStorage storage;
312*6777b538SAndroid Build Coastguard Worker if (getpeername(socket_, storage.addr, &storage.addr_len))
313*6777b538SAndroid Build Coastguard Worker return MapSystemError(errno);
314*6777b538SAndroid Build Coastguard Worker auto endpoint = std::make_unique<IPEndPoint>();
315*6777b538SAndroid Build Coastguard Worker if (!endpoint->FromSockAddr(storage.addr, storage.addr_len))
316*6777b538SAndroid Build Coastguard Worker return ERR_ADDRESS_INVALID;
317*6777b538SAndroid Build Coastguard Worker remote_address_ = std::move(endpoint);
318*6777b538SAndroid Build Coastguard Worker }
319*6777b538SAndroid Build Coastguard Worker
320*6777b538SAndroid Build Coastguard Worker *address = *remote_address_;
321*6777b538SAndroid Build Coastguard Worker return OK;
322*6777b538SAndroid Build Coastguard Worker }
323*6777b538SAndroid Build Coastguard Worker
GetLocalAddress(IPEndPoint * address) const324*6777b538SAndroid Build Coastguard Worker int UDPSocketPosix::GetLocalAddress(IPEndPoint* address) const {
325*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
326*6777b538SAndroid Build Coastguard Worker DCHECK(address);
327*6777b538SAndroid Build Coastguard Worker if (!is_connected())
328*6777b538SAndroid Build Coastguard Worker return ERR_SOCKET_NOT_CONNECTED;
329*6777b538SAndroid Build Coastguard Worker
330*6777b538SAndroid Build Coastguard Worker if (!local_address_.get()) {
331*6777b538SAndroid Build Coastguard Worker SockaddrStorage storage;
332*6777b538SAndroid Build Coastguard Worker if (getsockname(socket_, storage.addr, &storage.addr_len))
333*6777b538SAndroid Build Coastguard Worker return MapSystemError(errno);
334*6777b538SAndroid Build Coastguard Worker auto endpoint = std::make_unique<IPEndPoint>();
335*6777b538SAndroid Build Coastguard Worker if (!endpoint->FromSockAddr(storage.addr, storage.addr_len))
336*6777b538SAndroid Build Coastguard Worker return ERR_ADDRESS_INVALID;
337*6777b538SAndroid Build Coastguard Worker local_address_ = std::move(endpoint);
338*6777b538SAndroid Build Coastguard Worker net_log_.AddEvent(NetLogEventType::UDP_LOCAL_ADDRESS, [&] {
339*6777b538SAndroid Build Coastguard Worker return CreateNetLogUDPConnectParams(*local_address_, bound_network_);
340*6777b538SAndroid Build Coastguard Worker });
341*6777b538SAndroid Build Coastguard Worker }
342*6777b538SAndroid Build Coastguard Worker
343*6777b538SAndroid Build Coastguard Worker *address = *local_address_;
344*6777b538SAndroid Build Coastguard Worker return OK;
345*6777b538SAndroid Build Coastguard Worker }
346*6777b538SAndroid Build Coastguard Worker
Read(IOBuffer * buf,int buf_len,CompletionOnceCallback callback)347*6777b538SAndroid Build Coastguard Worker int UDPSocketPosix::Read(IOBuffer* buf,
348*6777b538SAndroid Build Coastguard Worker int buf_len,
349*6777b538SAndroid Build Coastguard Worker CompletionOnceCallback callback) {
350*6777b538SAndroid Build Coastguard Worker return RecvFrom(buf, buf_len, nullptr, std::move(callback));
351*6777b538SAndroid Build Coastguard Worker }
352*6777b538SAndroid Build Coastguard Worker
RecvFrom(IOBuffer * buf,int buf_len,IPEndPoint * address,CompletionOnceCallback callback)353*6777b538SAndroid Build Coastguard Worker int UDPSocketPosix::RecvFrom(IOBuffer* buf,
354*6777b538SAndroid Build Coastguard Worker int buf_len,
355*6777b538SAndroid Build Coastguard Worker IPEndPoint* address,
356*6777b538SAndroid Build Coastguard Worker CompletionOnceCallback callback) {
357*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
358*6777b538SAndroid Build Coastguard Worker DCHECK_NE(kInvalidSocket, socket_);
359*6777b538SAndroid Build Coastguard Worker CHECK(read_callback_.is_null());
360*6777b538SAndroid Build Coastguard Worker DCHECK(!recv_from_address_);
361*6777b538SAndroid Build Coastguard Worker DCHECK(!callback.is_null()); // Synchronous operation not supported
362*6777b538SAndroid Build Coastguard Worker DCHECK_GT(buf_len, 0);
363*6777b538SAndroid Build Coastguard Worker
364*6777b538SAndroid Build Coastguard Worker int nread = InternalRecvFrom(buf, buf_len, address);
365*6777b538SAndroid Build Coastguard Worker if (nread != ERR_IO_PENDING)
366*6777b538SAndroid Build Coastguard Worker return nread;
367*6777b538SAndroid Build Coastguard Worker
368*6777b538SAndroid Build Coastguard Worker if (!base::CurrentIOThread::Get()->WatchFileDescriptor(
369*6777b538SAndroid Build Coastguard Worker socket_, true, base::MessagePumpForIO::WATCH_READ,
370*6777b538SAndroid Build Coastguard Worker &read_socket_watcher_, &read_watcher_)) {
371*6777b538SAndroid Build Coastguard Worker PLOG(ERROR) << "WatchFileDescriptor failed on read";
372*6777b538SAndroid Build Coastguard Worker int result = MapSystemError(errno);
373*6777b538SAndroid Build Coastguard Worker LogRead(result, nullptr, 0, nullptr);
374*6777b538SAndroid Build Coastguard Worker return result;
375*6777b538SAndroid Build Coastguard Worker }
376*6777b538SAndroid Build Coastguard Worker
377*6777b538SAndroid Build Coastguard Worker read_buf_ = buf;
378*6777b538SAndroid Build Coastguard Worker read_buf_len_ = buf_len;
379*6777b538SAndroid Build Coastguard Worker recv_from_address_ = address;
380*6777b538SAndroid Build Coastguard Worker read_callback_ = std::move(callback);
381*6777b538SAndroid Build Coastguard Worker return ERR_IO_PENDING;
382*6777b538SAndroid Build Coastguard Worker }
383*6777b538SAndroid Build Coastguard Worker
Write(IOBuffer * buf,int buf_len,CompletionOnceCallback callback,const NetworkTrafficAnnotationTag & traffic_annotation)384*6777b538SAndroid Build Coastguard Worker int UDPSocketPosix::Write(
385*6777b538SAndroid Build Coastguard Worker IOBuffer* buf,
386*6777b538SAndroid Build Coastguard Worker int buf_len,
387*6777b538SAndroid Build Coastguard Worker CompletionOnceCallback callback,
388*6777b538SAndroid Build Coastguard Worker const NetworkTrafficAnnotationTag& traffic_annotation) {
389*6777b538SAndroid Build Coastguard Worker return SendToOrWrite(buf, buf_len, nullptr, std::move(callback));
390*6777b538SAndroid Build Coastguard Worker }
391*6777b538SAndroid Build Coastguard Worker
SendTo(IOBuffer * buf,int buf_len,const IPEndPoint & address,CompletionOnceCallback callback)392*6777b538SAndroid Build Coastguard Worker int UDPSocketPosix::SendTo(IOBuffer* buf,
393*6777b538SAndroid Build Coastguard Worker int buf_len,
394*6777b538SAndroid Build Coastguard Worker const IPEndPoint& address,
395*6777b538SAndroid Build Coastguard Worker CompletionOnceCallback callback) {
396*6777b538SAndroid Build Coastguard Worker return SendToOrWrite(buf, buf_len, &address, std::move(callback));
397*6777b538SAndroid Build Coastguard Worker }
398*6777b538SAndroid Build Coastguard Worker
SendToOrWrite(IOBuffer * buf,int buf_len,const IPEndPoint * address,CompletionOnceCallback callback)399*6777b538SAndroid Build Coastguard Worker int UDPSocketPosix::SendToOrWrite(IOBuffer* buf,
400*6777b538SAndroid Build Coastguard Worker int buf_len,
401*6777b538SAndroid Build Coastguard Worker const IPEndPoint* address,
402*6777b538SAndroid Build Coastguard Worker CompletionOnceCallback callback) {
403*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
404*6777b538SAndroid Build Coastguard Worker DCHECK_NE(kInvalidSocket, socket_);
405*6777b538SAndroid Build Coastguard Worker CHECK(write_callback_.is_null());
406*6777b538SAndroid Build Coastguard Worker DCHECK(!callback.is_null()); // Synchronous operation not supported
407*6777b538SAndroid Build Coastguard Worker DCHECK_GT(buf_len, 0);
408*6777b538SAndroid Build Coastguard Worker
409*6777b538SAndroid Build Coastguard Worker if (int result = InternalSendTo(buf, buf_len, address);
410*6777b538SAndroid Build Coastguard Worker result != ERR_IO_PENDING) {
411*6777b538SAndroid Build Coastguard Worker return result;
412*6777b538SAndroid Build Coastguard Worker }
413*6777b538SAndroid Build Coastguard Worker
414*6777b538SAndroid Build Coastguard Worker if (!base::CurrentIOThread::Get()->WatchFileDescriptor(
415*6777b538SAndroid Build Coastguard Worker socket_, true, base::MessagePumpForIO::WATCH_WRITE,
416*6777b538SAndroid Build Coastguard Worker &write_socket_watcher_, &write_watcher_)) {
417*6777b538SAndroid Build Coastguard Worker DVPLOG(1) << "WatchFileDescriptor failed on write";
418*6777b538SAndroid Build Coastguard Worker int result = MapSystemError(errno);
419*6777b538SAndroid Build Coastguard Worker LogWrite(result, nullptr, nullptr);
420*6777b538SAndroid Build Coastguard Worker return result;
421*6777b538SAndroid Build Coastguard Worker }
422*6777b538SAndroid Build Coastguard Worker
423*6777b538SAndroid Build Coastguard Worker write_buf_ = buf;
424*6777b538SAndroid Build Coastguard Worker write_buf_len_ = buf_len;
425*6777b538SAndroid Build Coastguard Worker DCHECK(!send_to_address_.get());
426*6777b538SAndroid Build Coastguard Worker if (address) {
427*6777b538SAndroid Build Coastguard Worker send_to_address_ = std::make_unique<IPEndPoint>(*address);
428*6777b538SAndroid Build Coastguard Worker }
429*6777b538SAndroid Build Coastguard Worker write_callback_ = std::move(callback);
430*6777b538SAndroid Build Coastguard Worker return ERR_IO_PENDING;
431*6777b538SAndroid Build Coastguard Worker }
432*6777b538SAndroid Build Coastguard Worker
Connect(const IPEndPoint & address)433*6777b538SAndroid Build Coastguard Worker int UDPSocketPosix::Connect(const IPEndPoint& address) {
434*6777b538SAndroid Build Coastguard Worker DCHECK_NE(socket_, kInvalidSocket);
435*6777b538SAndroid Build Coastguard Worker net_log_.BeginEvent(NetLogEventType::UDP_CONNECT, [&] {
436*6777b538SAndroid Build Coastguard Worker return CreateNetLogUDPConnectParams(address, bound_network_);
437*6777b538SAndroid Build Coastguard Worker });
438*6777b538SAndroid Build Coastguard Worker int rv = SetMulticastOptions();
439*6777b538SAndroid Build Coastguard Worker if (rv != OK)
440*6777b538SAndroid Build Coastguard Worker return rv;
441*6777b538SAndroid Build Coastguard Worker rv = InternalConnect(address);
442*6777b538SAndroid Build Coastguard Worker net_log_.EndEventWithNetErrorCode(NetLogEventType::UDP_CONNECT, rv);
443*6777b538SAndroid Build Coastguard Worker is_connected_ = (rv == OK);
444*6777b538SAndroid Build Coastguard Worker if (rv != OK)
445*6777b538SAndroid Build Coastguard Worker tag_ = SocketTag();
446*6777b538SAndroid Build Coastguard Worker return rv;
447*6777b538SAndroid Build Coastguard Worker }
448*6777b538SAndroid Build Coastguard Worker
InternalConnect(const IPEndPoint & address)449*6777b538SAndroid Build Coastguard Worker int UDPSocketPosix::InternalConnect(const IPEndPoint& address) {
450*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
451*6777b538SAndroid Build Coastguard Worker DCHECK(!is_connected());
452*6777b538SAndroid Build Coastguard Worker DCHECK(!remote_address_.get());
453*6777b538SAndroid Build Coastguard Worker
454*6777b538SAndroid Build Coastguard Worker int rv = 0;
455*6777b538SAndroid Build Coastguard Worker if (bind_type_ == DatagramSocket::RANDOM_BIND) {
456*6777b538SAndroid Build Coastguard Worker // Construct IPAddress of appropriate size (IPv4 or IPv6) of 0s,
457*6777b538SAndroid Build Coastguard Worker // representing INADDR_ANY or in6addr_any.
458*6777b538SAndroid Build Coastguard Worker size_t addr_size = address.GetSockAddrFamily() == AF_INET
459*6777b538SAndroid Build Coastguard Worker ? IPAddress::kIPv4AddressSize
460*6777b538SAndroid Build Coastguard Worker : IPAddress::kIPv6AddressSize;
461*6777b538SAndroid Build Coastguard Worker rv = RandomBind(IPAddress::AllZeros(addr_size));
462*6777b538SAndroid Build Coastguard Worker }
463*6777b538SAndroid Build Coastguard Worker // else connect() does the DatagramSocket::DEFAULT_BIND
464*6777b538SAndroid Build Coastguard Worker
465*6777b538SAndroid Build Coastguard Worker if (rv < 0) {
466*6777b538SAndroid Build Coastguard Worker return rv;
467*6777b538SAndroid Build Coastguard Worker }
468*6777b538SAndroid Build Coastguard Worker
469*6777b538SAndroid Build Coastguard Worker SockaddrStorage storage;
470*6777b538SAndroid Build Coastguard Worker if (!address.ToSockAddr(storage.addr, &storage.addr_len))
471*6777b538SAndroid Build Coastguard Worker return ERR_ADDRESS_INVALID;
472*6777b538SAndroid Build Coastguard Worker
473*6777b538SAndroid Build Coastguard Worker rv = HANDLE_EINTR(connect(socket_, storage.addr, storage.addr_len));
474*6777b538SAndroid Build Coastguard Worker if (rv < 0)
475*6777b538SAndroid Build Coastguard Worker return MapSystemError(errno);
476*6777b538SAndroid Build Coastguard Worker
477*6777b538SAndroid Build Coastguard Worker remote_address_ = std::make_unique<IPEndPoint>(address);
478*6777b538SAndroid Build Coastguard Worker return rv;
479*6777b538SAndroid Build Coastguard Worker }
480*6777b538SAndroid Build Coastguard Worker
Bind(const IPEndPoint & address)481*6777b538SAndroid Build Coastguard Worker int UDPSocketPosix::Bind(const IPEndPoint& address) {
482*6777b538SAndroid Build Coastguard Worker DCHECK_NE(socket_, kInvalidSocket);
483*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
484*6777b538SAndroid Build Coastguard Worker DCHECK(!is_connected());
485*6777b538SAndroid Build Coastguard Worker
486*6777b538SAndroid Build Coastguard Worker int rv = SetMulticastOptions();
487*6777b538SAndroid Build Coastguard Worker if (rv < 0)
488*6777b538SAndroid Build Coastguard Worker return rv;
489*6777b538SAndroid Build Coastguard Worker
490*6777b538SAndroid Build Coastguard Worker rv = DoBind(address);
491*6777b538SAndroid Build Coastguard Worker if (rv < 0)
492*6777b538SAndroid Build Coastguard Worker return rv;
493*6777b538SAndroid Build Coastguard Worker
494*6777b538SAndroid Build Coastguard Worker is_connected_ = true;
495*6777b538SAndroid Build Coastguard Worker local_address_.reset();
496*6777b538SAndroid Build Coastguard Worker return rv;
497*6777b538SAndroid Build Coastguard Worker }
498*6777b538SAndroid Build Coastguard Worker
BindToNetwork(handles::NetworkHandle network)499*6777b538SAndroid Build Coastguard Worker int UDPSocketPosix::BindToNetwork(handles::NetworkHandle network) {
500*6777b538SAndroid Build Coastguard Worker DCHECK_NE(socket_, kInvalidSocket);
501*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
502*6777b538SAndroid Build Coastguard Worker DCHECK(!is_connected());
503*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_ANDROID)
504*6777b538SAndroid Build Coastguard Worker int rv = net::android::BindToNetwork(socket_, network);
505*6777b538SAndroid Build Coastguard Worker if (rv == OK)
506*6777b538SAndroid Build Coastguard Worker bound_network_ = network;
507*6777b538SAndroid Build Coastguard Worker return rv;
508*6777b538SAndroid Build Coastguard Worker #else
509*6777b538SAndroid Build Coastguard Worker NOTIMPLEMENTED();
510*6777b538SAndroid Build Coastguard Worker return ERR_NOT_IMPLEMENTED;
511*6777b538SAndroid Build Coastguard Worker #endif
512*6777b538SAndroid Build Coastguard Worker }
513*6777b538SAndroid Build Coastguard Worker
SetReceiveBufferSize(int32_t size)514*6777b538SAndroid Build Coastguard Worker int UDPSocketPosix::SetReceiveBufferSize(int32_t size) {
515*6777b538SAndroid Build Coastguard Worker DCHECK_NE(socket_, kInvalidSocket);
516*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
517*6777b538SAndroid Build Coastguard Worker return SetSocketReceiveBufferSize(socket_, size);
518*6777b538SAndroid Build Coastguard Worker }
519*6777b538SAndroid Build Coastguard Worker
SetSendBufferSize(int32_t size)520*6777b538SAndroid Build Coastguard Worker int UDPSocketPosix::SetSendBufferSize(int32_t size) {
521*6777b538SAndroid Build Coastguard Worker DCHECK_NE(socket_, kInvalidSocket);
522*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
523*6777b538SAndroid Build Coastguard Worker return SetSocketSendBufferSize(socket_, size);
524*6777b538SAndroid Build Coastguard Worker }
525*6777b538SAndroid Build Coastguard Worker
SetDoNotFragment()526*6777b538SAndroid Build Coastguard Worker int UDPSocketPosix::SetDoNotFragment() {
527*6777b538SAndroid Build Coastguard Worker DCHECK_NE(socket_, kInvalidSocket);
528*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
529*6777b538SAndroid Build Coastguard Worker
530*6777b538SAndroid Build Coastguard Worker #if !defined(IP_PMTUDISC_DO) && !BUILDFLAG(IS_MAC)
531*6777b538SAndroid Build Coastguard Worker return ERR_NOT_IMPLEMENTED;
532*6777b538SAndroid Build Coastguard Worker
533*6777b538SAndroid Build Coastguard Worker // setsockopt(IP_DONTFRAG) is supported on macOS from Big Sur
534*6777b538SAndroid Build Coastguard Worker #elif BUILDFLAG(IS_MAC)
535*6777b538SAndroid Build Coastguard Worker if (base::mac::MacOSMajorVersion() < 11) {
536*6777b538SAndroid Build Coastguard Worker return ERR_NOT_IMPLEMENTED;
537*6777b538SAndroid Build Coastguard Worker }
538*6777b538SAndroid Build Coastguard Worker int val = 1;
539*6777b538SAndroid Build Coastguard Worker if (addr_family_ == AF_INET6) {
540*6777b538SAndroid Build Coastguard Worker int rv =
541*6777b538SAndroid Build Coastguard Worker setsockopt(socket_, IPPROTO_IPV6, IPV6_DONTFRAG, &val, sizeof(val));
542*6777b538SAndroid Build Coastguard Worker // IP_DONTFRAG is not supported on v4mapped addresses.
543*6777b538SAndroid Build Coastguard Worker return rv == 0 ? OK : MapSystemError(errno);
544*6777b538SAndroid Build Coastguard Worker }
545*6777b538SAndroid Build Coastguard Worker int rv = setsockopt(socket_, IPPROTO_IP, IP_DONTFRAG, &val, sizeof(val));
546*6777b538SAndroid Build Coastguard Worker return rv == 0 ? OK : MapSystemError(errno);
547*6777b538SAndroid Build Coastguard Worker
548*6777b538SAndroid Build Coastguard Worker #else
549*6777b538SAndroid Build Coastguard Worker if (addr_family_ == AF_INET6) {
550*6777b538SAndroid Build Coastguard Worker int val = IPV6_PMTUDISC_DO;
551*6777b538SAndroid Build Coastguard Worker if (setsockopt(socket_, IPPROTO_IPV6, IPV6_MTU_DISCOVER, &val,
552*6777b538SAndroid Build Coastguard Worker sizeof(val)) != 0) {
553*6777b538SAndroid Build Coastguard Worker return MapSystemError(errno);
554*6777b538SAndroid Build Coastguard Worker }
555*6777b538SAndroid Build Coastguard Worker
556*6777b538SAndroid Build Coastguard Worker int v6_only = false;
557*6777b538SAndroid Build Coastguard Worker socklen_t v6_only_len = sizeof(v6_only);
558*6777b538SAndroid Build Coastguard Worker if (getsockopt(socket_, IPPROTO_IPV6, IPV6_V6ONLY, &v6_only,
559*6777b538SAndroid Build Coastguard Worker &v6_only_len) != 0) {
560*6777b538SAndroid Build Coastguard Worker return MapSystemError(errno);
561*6777b538SAndroid Build Coastguard Worker }
562*6777b538SAndroid Build Coastguard Worker
563*6777b538SAndroid Build Coastguard Worker if (v6_only)
564*6777b538SAndroid Build Coastguard Worker return OK;
565*6777b538SAndroid Build Coastguard Worker }
566*6777b538SAndroid Build Coastguard Worker
567*6777b538SAndroid Build Coastguard Worker int val = IP_PMTUDISC_DO;
568*6777b538SAndroid Build Coastguard Worker int rv = setsockopt(socket_, IPPROTO_IP, IP_MTU_DISCOVER, &val, sizeof(val));
569*6777b538SAndroid Build Coastguard Worker return rv == 0 ? OK : MapSystemError(errno);
570*6777b538SAndroid Build Coastguard Worker #endif
571*6777b538SAndroid Build Coastguard Worker }
572*6777b538SAndroid Build Coastguard Worker
SetRecvTos()573*6777b538SAndroid Build Coastguard Worker int UDPSocketPosix::SetRecvTos() {
574*6777b538SAndroid Build Coastguard Worker DCHECK_NE(socket_, kInvalidSocket);
575*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
576*6777b538SAndroid Build Coastguard Worker
577*6777b538SAndroid Build Coastguard Worker unsigned int ecn = 1;
578*6777b538SAndroid Build Coastguard Worker if (addr_family_ == AF_INET6) {
579*6777b538SAndroid Build Coastguard Worker if (setsockopt(socket_, IPPROTO_IPV6, IPV6_RECVTCLASS, &ecn, sizeof(ecn)) !=
580*6777b538SAndroid Build Coastguard Worker 0) {
581*6777b538SAndroid Build Coastguard Worker return MapSystemError(errno);
582*6777b538SAndroid Build Coastguard Worker }
583*6777b538SAndroid Build Coastguard Worker
584*6777b538SAndroid Build Coastguard Worker int v6_only = false;
585*6777b538SAndroid Build Coastguard Worker socklen_t v6_only_len = sizeof(v6_only);
586*6777b538SAndroid Build Coastguard Worker if (getsockopt(socket_, IPPROTO_IPV6, IPV6_V6ONLY, &v6_only,
587*6777b538SAndroid Build Coastguard Worker &v6_only_len) != 0) {
588*6777b538SAndroid Build Coastguard Worker return MapSystemError(errno);
589*6777b538SAndroid Build Coastguard Worker }
590*6777b538SAndroid Build Coastguard Worker if (v6_only) {
591*6777b538SAndroid Build Coastguard Worker return OK;
592*6777b538SAndroid Build Coastguard Worker }
593*6777b538SAndroid Build Coastguard Worker }
594*6777b538SAndroid Build Coastguard Worker
595*6777b538SAndroid Build Coastguard Worker int rv = setsockopt(socket_, IPPROTO_IP, IP_RECVTOS, &ecn, sizeof(ecn));
596*6777b538SAndroid Build Coastguard Worker return rv == 0 ? OK : MapSystemError(errno);
597*6777b538SAndroid Build Coastguard Worker }
598*6777b538SAndroid Build Coastguard Worker
SetMsgConfirm(bool confirm)599*6777b538SAndroid Build Coastguard Worker void UDPSocketPosix::SetMsgConfirm(bool confirm) {
600*6777b538SAndroid Build Coastguard Worker #if !BUILDFLAG(IS_APPLE)
601*6777b538SAndroid Build Coastguard Worker if (confirm) {
602*6777b538SAndroid Build Coastguard Worker sendto_flags_ |= MSG_CONFIRM;
603*6777b538SAndroid Build Coastguard Worker } else {
604*6777b538SAndroid Build Coastguard Worker sendto_flags_ &= ~MSG_CONFIRM;
605*6777b538SAndroid Build Coastguard Worker }
606*6777b538SAndroid Build Coastguard Worker #endif // !BUILDFLAG(IS_APPLE)
607*6777b538SAndroid Build Coastguard Worker }
608*6777b538SAndroid Build Coastguard Worker
AllowAddressReuse()609*6777b538SAndroid Build Coastguard Worker int UDPSocketPosix::AllowAddressReuse() {
610*6777b538SAndroid Build Coastguard Worker DCHECK_NE(socket_, kInvalidSocket);
611*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
612*6777b538SAndroid Build Coastguard Worker DCHECK(!is_connected());
613*6777b538SAndroid Build Coastguard Worker return SetReuseAddr(socket_, true);
614*6777b538SAndroid Build Coastguard Worker }
615*6777b538SAndroid Build Coastguard Worker
SetBroadcast(bool broadcast)616*6777b538SAndroid Build Coastguard Worker int UDPSocketPosix::SetBroadcast(bool broadcast) {
617*6777b538SAndroid Build Coastguard Worker DCHECK_NE(socket_, kInvalidSocket);
618*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
619*6777b538SAndroid Build Coastguard Worker int value = broadcast ? 1 : 0;
620*6777b538SAndroid Build Coastguard Worker int rv;
621*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_APPLE)
622*6777b538SAndroid Build Coastguard Worker // SO_REUSEPORT on OSX permits multiple processes to each receive
623*6777b538SAndroid Build Coastguard Worker // UDP multicast or broadcast datagrams destined for the bound
624*6777b538SAndroid Build Coastguard Worker // port.
625*6777b538SAndroid Build Coastguard Worker // This is only being set on OSX because its behavior is platform dependent
626*6777b538SAndroid Build Coastguard Worker // and we are playing it safe by only setting it on platforms where things
627*6777b538SAndroid Build Coastguard Worker // break.
628*6777b538SAndroid Build Coastguard Worker rv = setsockopt(socket_, SOL_SOCKET, SO_REUSEPORT, &value, sizeof(value));
629*6777b538SAndroid Build Coastguard Worker if (rv != 0)
630*6777b538SAndroid Build Coastguard Worker return MapSystemError(errno);
631*6777b538SAndroid Build Coastguard Worker #endif // BUILDFLAG(IS_APPLE)
632*6777b538SAndroid Build Coastguard Worker rv = setsockopt(socket_, SOL_SOCKET, SO_BROADCAST, &value, sizeof(value));
633*6777b538SAndroid Build Coastguard Worker
634*6777b538SAndroid Build Coastguard Worker return rv == 0 ? OK : MapSystemError(errno);
635*6777b538SAndroid Build Coastguard Worker }
636*6777b538SAndroid Build Coastguard Worker
AllowAddressSharingForMulticast()637*6777b538SAndroid Build Coastguard Worker int UDPSocketPosix::AllowAddressSharingForMulticast() {
638*6777b538SAndroid Build Coastguard Worker DCHECK_NE(socket_, kInvalidSocket);
639*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
640*6777b538SAndroid Build Coastguard Worker DCHECK(!is_connected());
641*6777b538SAndroid Build Coastguard Worker
642*6777b538SAndroid Build Coastguard Worker int rv = AllowAddressReuse();
643*6777b538SAndroid Build Coastguard Worker if (rv != OK)
644*6777b538SAndroid Build Coastguard Worker return rv;
645*6777b538SAndroid Build Coastguard Worker
646*6777b538SAndroid Build Coastguard Worker #ifdef SO_REUSEPORT
647*6777b538SAndroid Build Coastguard Worker // Attempt to set SO_REUSEPORT if available. On some platforms, this is
648*6777b538SAndroid Build Coastguard Worker // necessary to allow the address to be fully shared between separate sockets.
649*6777b538SAndroid Build Coastguard Worker // On platforms where the option does not exist, SO_REUSEADDR should be
650*6777b538SAndroid Build Coastguard Worker // sufficient to share multicast packets if such sharing is at all possible.
651*6777b538SAndroid Build Coastguard Worker int value = 1;
652*6777b538SAndroid Build Coastguard Worker rv = setsockopt(socket_, SOL_SOCKET, SO_REUSEPORT, &value, sizeof(value));
653*6777b538SAndroid Build Coastguard Worker // Ignore errors that the option does not exist.
654*6777b538SAndroid Build Coastguard Worker if (rv != 0 && errno != ENOPROTOOPT)
655*6777b538SAndroid Build Coastguard Worker return MapSystemError(errno);
656*6777b538SAndroid Build Coastguard Worker #endif // SO_REUSEPORT
657*6777b538SAndroid Build Coastguard Worker
658*6777b538SAndroid Build Coastguard Worker return OK;
659*6777b538SAndroid Build Coastguard Worker }
660*6777b538SAndroid Build Coastguard Worker
OnFileCanReadWithoutBlocking(int)661*6777b538SAndroid Build Coastguard Worker void UDPSocketPosix::ReadWatcher::OnFileCanReadWithoutBlocking(int) {
662*6777b538SAndroid Build Coastguard Worker TRACE_EVENT(NetTracingCategory(),
663*6777b538SAndroid Build Coastguard Worker "UDPSocketPosix::ReadWatcher::OnFileCanReadWithoutBlocking");
664*6777b538SAndroid Build Coastguard Worker if (!socket_->read_callback_.is_null())
665*6777b538SAndroid Build Coastguard Worker socket_->DidCompleteRead();
666*6777b538SAndroid Build Coastguard Worker }
667*6777b538SAndroid Build Coastguard Worker
OnFileCanWriteWithoutBlocking(int)668*6777b538SAndroid Build Coastguard Worker void UDPSocketPosix::WriteWatcher::OnFileCanWriteWithoutBlocking(int) {
669*6777b538SAndroid Build Coastguard Worker if (!socket_->write_callback_.is_null())
670*6777b538SAndroid Build Coastguard Worker socket_->DidCompleteWrite();
671*6777b538SAndroid Build Coastguard Worker }
672*6777b538SAndroid Build Coastguard Worker
DoReadCallback(int rv)673*6777b538SAndroid Build Coastguard Worker void UDPSocketPosix::DoReadCallback(int rv) {
674*6777b538SAndroid Build Coastguard Worker DCHECK_NE(rv, ERR_IO_PENDING);
675*6777b538SAndroid Build Coastguard Worker DCHECK(!read_callback_.is_null());
676*6777b538SAndroid Build Coastguard Worker
677*6777b538SAndroid Build Coastguard Worker // Since Run() may result in Read() being called,
678*6777b538SAndroid Build Coastguard Worker // clear |read_callback_| up front.
679*6777b538SAndroid Build Coastguard Worker std::move(read_callback_).Run(rv);
680*6777b538SAndroid Build Coastguard Worker }
681*6777b538SAndroid Build Coastguard Worker
DoWriteCallback(int rv)682*6777b538SAndroid Build Coastguard Worker void UDPSocketPosix::DoWriteCallback(int rv) {
683*6777b538SAndroid Build Coastguard Worker DCHECK_NE(rv, ERR_IO_PENDING);
684*6777b538SAndroid Build Coastguard Worker DCHECK(!write_callback_.is_null());
685*6777b538SAndroid Build Coastguard Worker
686*6777b538SAndroid Build Coastguard Worker // Since Run() may result in Write() being called,
687*6777b538SAndroid Build Coastguard Worker // clear |write_callback_| up front.
688*6777b538SAndroid Build Coastguard Worker std::move(write_callback_).Run(rv);
689*6777b538SAndroid Build Coastguard Worker }
690*6777b538SAndroid Build Coastguard Worker
DidCompleteRead()691*6777b538SAndroid Build Coastguard Worker void UDPSocketPosix::DidCompleteRead() {
692*6777b538SAndroid Build Coastguard Worker int result =
693*6777b538SAndroid Build Coastguard Worker InternalRecvFrom(read_buf_.get(), read_buf_len_, recv_from_address_);
694*6777b538SAndroid Build Coastguard Worker if (result != ERR_IO_PENDING) {
695*6777b538SAndroid Build Coastguard Worker read_buf_.reset();
696*6777b538SAndroid Build Coastguard Worker read_buf_len_ = 0;
697*6777b538SAndroid Build Coastguard Worker recv_from_address_ = nullptr;
698*6777b538SAndroid Build Coastguard Worker bool ok = read_socket_watcher_.StopWatchingFileDescriptor();
699*6777b538SAndroid Build Coastguard Worker DCHECK(ok);
700*6777b538SAndroid Build Coastguard Worker DoReadCallback(result);
701*6777b538SAndroid Build Coastguard Worker }
702*6777b538SAndroid Build Coastguard Worker }
703*6777b538SAndroid Build Coastguard Worker
LogRead(int result,const char * bytes,socklen_t addr_len,const sockaddr * addr)704*6777b538SAndroid Build Coastguard Worker void UDPSocketPosix::LogRead(int result,
705*6777b538SAndroid Build Coastguard Worker const char* bytes,
706*6777b538SAndroid Build Coastguard Worker socklen_t addr_len,
707*6777b538SAndroid Build Coastguard Worker const sockaddr* addr) {
708*6777b538SAndroid Build Coastguard Worker if (result < 0) {
709*6777b538SAndroid Build Coastguard Worker net_log_.AddEventWithNetErrorCode(NetLogEventType::UDP_RECEIVE_ERROR,
710*6777b538SAndroid Build Coastguard Worker result);
711*6777b538SAndroid Build Coastguard Worker return;
712*6777b538SAndroid Build Coastguard Worker }
713*6777b538SAndroid Build Coastguard Worker
714*6777b538SAndroid Build Coastguard Worker if (net_log_.IsCapturing()) {
715*6777b538SAndroid Build Coastguard Worker DCHECK(addr_len > 0);
716*6777b538SAndroid Build Coastguard Worker DCHECK(addr);
717*6777b538SAndroid Build Coastguard Worker
718*6777b538SAndroid Build Coastguard Worker IPEndPoint address;
719*6777b538SAndroid Build Coastguard Worker bool is_address_valid = address.FromSockAddr(addr, addr_len);
720*6777b538SAndroid Build Coastguard Worker NetLogUDPDataTransfer(net_log_, NetLogEventType::UDP_BYTES_RECEIVED, result,
721*6777b538SAndroid Build Coastguard Worker bytes, is_address_valid ? &address : nullptr);
722*6777b538SAndroid Build Coastguard Worker }
723*6777b538SAndroid Build Coastguard Worker
724*6777b538SAndroid Build Coastguard Worker if (always_update_bytes_received_)
725*6777b538SAndroid Build Coastguard Worker activity_monitor::IncrementBytesReceived(result);
726*6777b538SAndroid Build Coastguard Worker else
727*6777b538SAndroid Build Coastguard Worker received_activity_monitor_.Increment(result);
728*6777b538SAndroid Build Coastguard Worker }
729*6777b538SAndroid Build Coastguard Worker
DidCompleteWrite()730*6777b538SAndroid Build Coastguard Worker void UDPSocketPosix::DidCompleteWrite() {
731*6777b538SAndroid Build Coastguard Worker int result =
732*6777b538SAndroid Build Coastguard Worker InternalSendTo(write_buf_.get(), write_buf_len_, send_to_address_.get());
733*6777b538SAndroid Build Coastguard Worker
734*6777b538SAndroid Build Coastguard Worker if (result != ERR_IO_PENDING) {
735*6777b538SAndroid Build Coastguard Worker write_buf_.reset();
736*6777b538SAndroid Build Coastguard Worker write_buf_len_ = 0;
737*6777b538SAndroid Build Coastguard Worker send_to_address_.reset();
738*6777b538SAndroid Build Coastguard Worker write_socket_watcher_.StopWatchingFileDescriptor();
739*6777b538SAndroid Build Coastguard Worker DoWriteCallback(result);
740*6777b538SAndroid Build Coastguard Worker }
741*6777b538SAndroid Build Coastguard Worker }
742*6777b538SAndroid Build Coastguard Worker
LogWrite(int result,const char * bytes,const IPEndPoint * address)743*6777b538SAndroid Build Coastguard Worker void UDPSocketPosix::LogWrite(int result,
744*6777b538SAndroid Build Coastguard Worker const char* bytes,
745*6777b538SAndroid Build Coastguard Worker const IPEndPoint* address) {
746*6777b538SAndroid Build Coastguard Worker if (result < 0) {
747*6777b538SAndroid Build Coastguard Worker net_log_.AddEventWithNetErrorCode(NetLogEventType::UDP_SEND_ERROR, result);
748*6777b538SAndroid Build Coastguard Worker return;
749*6777b538SAndroid Build Coastguard Worker }
750*6777b538SAndroid Build Coastguard Worker
751*6777b538SAndroid Build Coastguard Worker if (net_log_.IsCapturing()) {
752*6777b538SAndroid Build Coastguard Worker NetLogUDPDataTransfer(net_log_, NetLogEventType::UDP_BYTES_SENT, result,
753*6777b538SAndroid Build Coastguard Worker bytes, address);
754*6777b538SAndroid Build Coastguard Worker }
755*6777b538SAndroid Build Coastguard Worker }
756*6777b538SAndroid Build Coastguard Worker
757*6777b538SAndroid Build Coastguard Worker // TODO(crbug.com/1491628): Because InternalRecvFromConnectedSocket() uses
758*6777b538SAndroid Build Coastguard Worker // recvfrom() instead of recvmsg(), it cannot report received ECN marks for
759*6777b538SAndroid Build Coastguard Worker // QUIC ACK-ECN frames. It might be time to deprecate
760*6777b538SAndroid Build Coastguard Worker // experimental_recv_optimization_enabled_ if that experiment has run its
761*6777b538SAndroid Build Coastguard Worker // course.
InternalRecvFrom(IOBuffer * buf,int buf_len,IPEndPoint * address)762*6777b538SAndroid Build Coastguard Worker int UDPSocketPosix::InternalRecvFrom(IOBuffer* buf,
763*6777b538SAndroid Build Coastguard Worker int buf_len,
764*6777b538SAndroid Build Coastguard Worker IPEndPoint* address) {
765*6777b538SAndroid Build Coastguard Worker // If the socket is connected and the remote address is known
766*6777b538SAndroid Build Coastguard Worker // use the more efficient method that uses read() instead of recvmsg().
767*6777b538SAndroid Build Coastguard Worker if (experimental_recv_optimization_enabled_ && is_connected_ &&
768*6777b538SAndroid Build Coastguard Worker remote_address_) {
769*6777b538SAndroid Build Coastguard Worker return InternalRecvFromConnectedSocket(buf, buf_len, address);
770*6777b538SAndroid Build Coastguard Worker }
771*6777b538SAndroid Build Coastguard Worker return InternalRecvFromNonConnectedSocket(buf, buf_len, address);
772*6777b538SAndroid Build Coastguard Worker }
773*6777b538SAndroid Build Coastguard Worker
InternalRecvFromConnectedSocket(IOBuffer * buf,int buf_len,IPEndPoint * address)774*6777b538SAndroid Build Coastguard Worker int UDPSocketPosix::InternalRecvFromConnectedSocket(IOBuffer* buf,
775*6777b538SAndroid Build Coastguard Worker int buf_len,
776*6777b538SAndroid Build Coastguard Worker IPEndPoint* address) {
777*6777b538SAndroid Build Coastguard Worker DCHECK(is_connected_);
778*6777b538SAndroid Build Coastguard Worker DCHECK(remote_address_);
779*6777b538SAndroid Build Coastguard Worker int result;
780*6777b538SAndroid Build Coastguard Worker int bytes_transferred = HANDLE_EINTR(read(socket_, buf->data(), buf_len));
781*6777b538SAndroid Build Coastguard Worker if (bytes_transferred < 0) {
782*6777b538SAndroid Build Coastguard Worker result = MapSystemError(errno);
783*6777b538SAndroid Build Coastguard Worker if (result == ERR_IO_PENDING) {
784*6777b538SAndroid Build Coastguard Worker return result;
785*6777b538SAndroid Build Coastguard Worker }
786*6777b538SAndroid Build Coastguard Worker } else if (bytes_transferred == buf_len) {
787*6777b538SAndroid Build Coastguard Worker // NB: recv(..., MSG_TRUNC) would be a more reliable way to do this on
788*6777b538SAndroid Build Coastguard Worker // Linux, but isn't supported by POSIX.
789*6777b538SAndroid Build Coastguard Worker result = ERR_MSG_TOO_BIG;
790*6777b538SAndroid Build Coastguard Worker } else {
791*6777b538SAndroid Build Coastguard Worker result = bytes_transferred;
792*6777b538SAndroid Build Coastguard Worker if (address) {
793*6777b538SAndroid Build Coastguard Worker *address = *remote_address_.get();
794*6777b538SAndroid Build Coastguard Worker }
795*6777b538SAndroid Build Coastguard Worker }
796*6777b538SAndroid Build Coastguard Worker
797*6777b538SAndroid Build Coastguard Worker SockaddrStorage sock_addr;
798*6777b538SAndroid Build Coastguard Worker bool success =
799*6777b538SAndroid Build Coastguard Worker remote_address_->ToSockAddr(sock_addr.addr, &sock_addr.addr_len);
800*6777b538SAndroid Build Coastguard Worker DCHECK(success);
801*6777b538SAndroid Build Coastguard Worker LogRead(result, buf->data(), sock_addr.addr_len, sock_addr.addr);
802*6777b538SAndroid Build Coastguard Worker return result;
803*6777b538SAndroid Build Coastguard Worker }
804*6777b538SAndroid Build Coastguard Worker
InternalRecvFromNonConnectedSocket(IOBuffer * buf,int buf_len,IPEndPoint * address)805*6777b538SAndroid Build Coastguard Worker int UDPSocketPosix::InternalRecvFromNonConnectedSocket(IOBuffer* buf,
806*6777b538SAndroid Build Coastguard Worker int buf_len,
807*6777b538SAndroid Build Coastguard Worker IPEndPoint* address) {
808*6777b538SAndroid Build Coastguard Worker SockaddrStorage storage;
809*6777b538SAndroid Build Coastguard Worker struct iovec iov = {
810*6777b538SAndroid Build Coastguard Worker .iov_base = buf->data(),
811*6777b538SAndroid Build Coastguard Worker .iov_len = static_cast<size_t>(buf_len),
812*6777b538SAndroid Build Coastguard Worker };
813*6777b538SAndroid Build Coastguard Worker // control_buffer needs to be big enough to accommodate the maximum
814*6777b538SAndroid Build Coastguard Worker // conceivable number of CMSGs. Other (proprietary) Google QUIC code uses
815*6777b538SAndroid Build Coastguard Worker // 512 Bytes, re-used here.
816*6777b538SAndroid Build Coastguard Worker char control_buffer[512];
817*6777b538SAndroid Build Coastguard Worker struct msghdr msg = {
818*6777b538SAndroid Build Coastguard Worker .msg_name = storage.addr,
819*6777b538SAndroid Build Coastguard Worker .msg_namelen = storage.addr_len,
820*6777b538SAndroid Build Coastguard Worker .msg_iov = &iov,
821*6777b538SAndroid Build Coastguard Worker .msg_iovlen = 1,
822*6777b538SAndroid Build Coastguard Worker .msg_control = control_buffer,
823*6777b538SAndroid Build Coastguard Worker .msg_controllen = ABSL_ARRAYSIZE(control_buffer),
824*6777b538SAndroid Build Coastguard Worker };
825*6777b538SAndroid Build Coastguard Worker int result;
826*6777b538SAndroid Build Coastguard Worker int bytes_transferred = HANDLE_EINTR(recvmsg(socket_, &msg, 0));
827*6777b538SAndroid Build Coastguard Worker if (bytes_transferred < 0) {
828*6777b538SAndroid Build Coastguard Worker result = MapSystemError(errno);
829*6777b538SAndroid Build Coastguard Worker if (result == ERR_IO_PENDING) {
830*6777b538SAndroid Build Coastguard Worker return result;
831*6777b538SAndroid Build Coastguard Worker }
832*6777b538SAndroid Build Coastguard Worker } else {
833*6777b538SAndroid Build Coastguard Worker storage.addr_len = msg.msg_namelen;
834*6777b538SAndroid Build Coastguard Worker if (msg.msg_flags & MSG_TRUNC) {
835*6777b538SAndroid Build Coastguard Worker // NB: recvfrom(..., MSG_TRUNC, ...) would be a simpler way to do this on
836*6777b538SAndroid Build Coastguard Worker // Linux, but isn't supported by POSIX.
837*6777b538SAndroid Build Coastguard Worker result = ERR_MSG_TOO_BIG;
838*6777b538SAndroid Build Coastguard Worker } else if (address &&
839*6777b538SAndroid Build Coastguard Worker !address->FromSockAddr(storage.addr, storage.addr_len)) {
840*6777b538SAndroid Build Coastguard Worker result = ERR_ADDRESS_INVALID;
841*6777b538SAndroid Build Coastguard Worker } else {
842*6777b538SAndroid Build Coastguard Worker result = bytes_transferred;
843*6777b538SAndroid Build Coastguard Worker }
844*6777b538SAndroid Build Coastguard Worker last_tos_ = 0;
845*6777b538SAndroid Build Coastguard Worker if (bytes_transferred > 0 && msg.msg_controllen > 0) {
846*6777b538SAndroid Build Coastguard Worker for (struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg); cmsg != nullptr;
847*6777b538SAndroid Build Coastguard Worker cmsg = CMSG_NXTHDR(&msg, cmsg)) {
848*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_APPLE)
849*6777b538SAndroid Build Coastguard Worker if ((cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_RECVTOS) ||
850*6777b538SAndroid Build Coastguard Worker (cmsg->cmsg_level == IPPROTO_IPV6 &&
851*6777b538SAndroid Build Coastguard Worker cmsg->cmsg_type == IPV6_TCLASS)) {
852*6777b538SAndroid Build Coastguard Worker #else
853*6777b538SAndroid Build Coastguard Worker if ((cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_TOS) ||
854*6777b538SAndroid Build Coastguard Worker (cmsg->cmsg_level == IPPROTO_IPV6 &&
855*6777b538SAndroid Build Coastguard Worker cmsg->cmsg_type == IPV6_TCLASS)) {
856*6777b538SAndroid Build Coastguard Worker #endif // BUILDFLAG(IS_APPLE)
857*6777b538SAndroid Build Coastguard Worker last_tos_ = *(reinterpret_cast<uint8_t*>(CMSG_DATA(cmsg)));
858*6777b538SAndroid Build Coastguard Worker }
859*6777b538SAndroid Build Coastguard Worker }
860*6777b538SAndroid Build Coastguard Worker }
861*6777b538SAndroid Build Coastguard Worker }
862*6777b538SAndroid Build Coastguard Worker
863*6777b538SAndroid Build Coastguard Worker LogRead(result, buf->data(), storage.addr_len, storage.addr);
864*6777b538SAndroid Build Coastguard Worker return result;
865*6777b538SAndroid Build Coastguard Worker }
866*6777b538SAndroid Build Coastguard Worker
867*6777b538SAndroid Build Coastguard Worker int UDPSocketPosix::InternalSendTo(IOBuffer* buf,
868*6777b538SAndroid Build Coastguard Worker int buf_len,
869*6777b538SAndroid Build Coastguard Worker const IPEndPoint* address) {
870*6777b538SAndroid Build Coastguard Worker SockaddrStorage storage;
871*6777b538SAndroid Build Coastguard Worker struct sockaddr* addr = storage.addr;
872*6777b538SAndroid Build Coastguard Worker if (!address) {
873*6777b538SAndroid Build Coastguard Worker addr = nullptr;
874*6777b538SAndroid Build Coastguard Worker storage.addr_len = 0;
875*6777b538SAndroid Build Coastguard Worker } else {
876*6777b538SAndroid Build Coastguard Worker if (!address->ToSockAddr(storage.addr, &storage.addr_len)) {
877*6777b538SAndroid Build Coastguard Worker int result = ERR_ADDRESS_INVALID;
878*6777b538SAndroid Build Coastguard Worker LogWrite(result, nullptr, nullptr);
879*6777b538SAndroid Build Coastguard Worker return result;
880*6777b538SAndroid Build Coastguard Worker }
881*6777b538SAndroid Build Coastguard Worker }
882*6777b538SAndroid Build Coastguard Worker
883*6777b538SAndroid Build Coastguard Worker int result = HANDLE_EINTR(sendto(socket_, buf->data(), buf_len, sendto_flags_,
884*6777b538SAndroid Build Coastguard Worker addr, storage.addr_len));
885*6777b538SAndroid Build Coastguard Worker if (result < 0)
886*6777b538SAndroid Build Coastguard Worker result = MapSystemError(errno);
887*6777b538SAndroid Build Coastguard Worker if (result != ERR_IO_PENDING)
888*6777b538SAndroid Build Coastguard Worker LogWrite(result, buf->data(), address);
889*6777b538SAndroid Build Coastguard Worker return result;
890*6777b538SAndroid Build Coastguard Worker }
891*6777b538SAndroid Build Coastguard Worker
892*6777b538SAndroid Build Coastguard Worker int UDPSocketPosix::SetMulticastOptions() {
893*6777b538SAndroid Build Coastguard Worker if (!(socket_options_ & SOCKET_OPTION_MULTICAST_LOOP)) {
894*6777b538SAndroid Build Coastguard Worker int rv;
895*6777b538SAndroid Build Coastguard Worker if (addr_family_ == AF_INET) {
896*6777b538SAndroid Build Coastguard Worker u_char loop = 0;
897*6777b538SAndroid Build Coastguard Worker rv = setsockopt(socket_, IPPROTO_IP, IP_MULTICAST_LOOP,
898*6777b538SAndroid Build Coastguard Worker &loop, sizeof(loop));
899*6777b538SAndroid Build Coastguard Worker } else {
900*6777b538SAndroid Build Coastguard Worker u_int loop = 0;
901*6777b538SAndroid Build Coastguard Worker rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
902*6777b538SAndroid Build Coastguard Worker &loop, sizeof(loop));
903*6777b538SAndroid Build Coastguard Worker }
904*6777b538SAndroid Build Coastguard Worker if (rv < 0)
905*6777b538SAndroid Build Coastguard Worker return MapSystemError(errno);
906*6777b538SAndroid Build Coastguard Worker }
907*6777b538SAndroid Build Coastguard Worker if (multicast_time_to_live_ != IP_DEFAULT_MULTICAST_TTL) {
908*6777b538SAndroid Build Coastguard Worker int rv;
909*6777b538SAndroid Build Coastguard Worker if (addr_family_ == AF_INET) {
910*6777b538SAndroid Build Coastguard Worker u_char ttl = multicast_time_to_live_;
911*6777b538SAndroid Build Coastguard Worker rv = setsockopt(socket_, IPPROTO_IP, IP_MULTICAST_TTL,
912*6777b538SAndroid Build Coastguard Worker &ttl, sizeof(ttl));
913*6777b538SAndroid Build Coastguard Worker } else {
914*6777b538SAndroid Build Coastguard Worker // Signed integer. -1 to use route default.
915*6777b538SAndroid Build Coastguard Worker int ttl = multicast_time_to_live_;
916*6777b538SAndroid Build Coastguard Worker rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
917*6777b538SAndroid Build Coastguard Worker &ttl, sizeof(ttl));
918*6777b538SAndroid Build Coastguard Worker }
919*6777b538SAndroid Build Coastguard Worker if (rv < 0)
920*6777b538SAndroid Build Coastguard Worker return MapSystemError(errno);
921*6777b538SAndroid Build Coastguard Worker }
922*6777b538SAndroid Build Coastguard Worker if (multicast_interface_ != 0) {
923*6777b538SAndroid Build Coastguard Worker switch (addr_family_) {
924*6777b538SAndroid Build Coastguard Worker case AF_INET: {
925*6777b538SAndroid Build Coastguard Worker ip_mreqn mreq = {};
926*6777b538SAndroid Build Coastguard Worker mreq.imr_ifindex = multicast_interface_;
927*6777b538SAndroid Build Coastguard Worker mreq.imr_address.s_addr = htonl(INADDR_ANY);
928*6777b538SAndroid Build Coastguard Worker int rv = setsockopt(socket_, IPPROTO_IP, IP_MULTICAST_IF,
929*6777b538SAndroid Build Coastguard Worker reinterpret_cast<const char*>(&mreq), sizeof(mreq));
930*6777b538SAndroid Build Coastguard Worker if (rv)
931*6777b538SAndroid Build Coastguard Worker return MapSystemError(errno);
932*6777b538SAndroid Build Coastguard Worker break;
933*6777b538SAndroid Build Coastguard Worker }
934*6777b538SAndroid Build Coastguard Worker case AF_INET6: {
935*6777b538SAndroid Build Coastguard Worker uint32_t interface_index = multicast_interface_;
936*6777b538SAndroid Build Coastguard Worker int rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_MULTICAST_IF,
937*6777b538SAndroid Build Coastguard Worker reinterpret_cast<const char*>(&interface_index),
938*6777b538SAndroid Build Coastguard Worker sizeof(interface_index));
939*6777b538SAndroid Build Coastguard Worker if (rv)
940*6777b538SAndroid Build Coastguard Worker return MapSystemError(errno);
941*6777b538SAndroid Build Coastguard Worker break;
942*6777b538SAndroid Build Coastguard Worker }
943*6777b538SAndroid Build Coastguard Worker default:
944*6777b538SAndroid Build Coastguard Worker NOTREACHED() << "Invalid address family";
945*6777b538SAndroid Build Coastguard Worker return ERR_ADDRESS_INVALID;
946*6777b538SAndroid Build Coastguard Worker }
947*6777b538SAndroid Build Coastguard Worker }
948*6777b538SAndroid Build Coastguard Worker return OK;
949*6777b538SAndroid Build Coastguard Worker }
950*6777b538SAndroid Build Coastguard Worker
951*6777b538SAndroid Build Coastguard Worker int UDPSocketPosix::DoBind(const IPEndPoint& address) {
952*6777b538SAndroid Build Coastguard Worker SockaddrStorage storage;
953*6777b538SAndroid Build Coastguard Worker if (!address.ToSockAddr(storage.addr, &storage.addr_len))
954*6777b538SAndroid Build Coastguard Worker return ERR_ADDRESS_INVALID;
955*6777b538SAndroid Build Coastguard Worker int rv = bind(socket_, storage.addr, storage.addr_len);
956*6777b538SAndroid Build Coastguard Worker if (rv == 0)
957*6777b538SAndroid Build Coastguard Worker return OK;
958*6777b538SAndroid Build Coastguard Worker int last_error = errno;
959*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_CHROMEOS_ASH)
960*6777b538SAndroid Build Coastguard Worker if (last_error == EINVAL)
961*6777b538SAndroid Build Coastguard Worker return ERR_ADDRESS_IN_USE;
962*6777b538SAndroid Build Coastguard Worker #elif BUILDFLAG(IS_APPLE)
963*6777b538SAndroid Build Coastguard Worker if (last_error == EADDRNOTAVAIL)
964*6777b538SAndroid Build Coastguard Worker return ERR_ADDRESS_IN_USE;
965*6777b538SAndroid Build Coastguard Worker #endif
966*6777b538SAndroid Build Coastguard Worker return MapSystemError(last_error);
967*6777b538SAndroid Build Coastguard Worker }
968*6777b538SAndroid Build Coastguard Worker
969*6777b538SAndroid Build Coastguard Worker int UDPSocketPosix::RandomBind(const IPAddress& address) {
970*6777b538SAndroid Build Coastguard Worker DCHECK_EQ(bind_type_, DatagramSocket::RANDOM_BIND);
971*6777b538SAndroid Build Coastguard Worker
972*6777b538SAndroid Build Coastguard Worker for (int i = 0; i < kBindRetries; ++i) {
973*6777b538SAndroid Build Coastguard Worker int rv = DoBind(IPEndPoint(address, base::RandInt(kPortStart, kPortEnd)));
974*6777b538SAndroid Build Coastguard Worker if (rv != ERR_ADDRESS_IN_USE)
975*6777b538SAndroid Build Coastguard Worker return rv;
976*6777b538SAndroid Build Coastguard Worker }
977*6777b538SAndroid Build Coastguard Worker
978*6777b538SAndroid Build Coastguard Worker return DoBind(IPEndPoint(address, 0));
979*6777b538SAndroid Build Coastguard Worker }
980*6777b538SAndroid Build Coastguard Worker
981*6777b538SAndroid Build Coastguard Worker int UDPSocketPosix::JoinGroup(const IPAddress& group_address) const {
982*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
983*6777b538SAndroid Build Coastguard Worker if (!is_connected())
984*6777b538SAndroid Build Coastguard Worker return ERR_SOCKET_NOT_CONNECTED;
985*6777b538SAndroid Build Coastguard Worker
986*6777b538SAndroid Build Coastguard Worker switch (group_address.size()) {
987*6777b538SAndroid Build Coastguard Worker case IPAddress::kIPv4AddressSize: {
988*6777b538SAndroid Build Coastguard Worker if (addr_family_ != AF_INET)
989*6777b538SAndroid Build Coastguard Worker return ERR_ADDRESS_INVALID;
990*6777b538SAndroid Build Coastguard Worker ip_mreqn mreq = {};
991*6777b538SAndroid Build Coastguard Worker mreq.imr_ifindex = multicast_interface_;
992*6777b538SAndroid Build Coastguard Worker mreq.imr_address.s_addr = htonl(INADDR_ANY);
993*6777b538SAndroid Build Coastguard Worker memcpy(&mreq.imr_multiaddr, group_address.bytes().data(),
994*6777b538SAndroid Build Coastguard Worker IPAddress::kIPv4AddressSize);
995*6777b538SAndroid Build Coastguard Worker int rv = setsockopt(socket_, IPPROTO_IP, IP_ADD_MEMBERSHIP,
996*6777b538SAndroid Build Coastguard Worker &mreq, sizeof(mreq));
997*6777b538SAndroid Build Coastguard Worker if (rv < 0)
998*6777b538SAndroid Build Coastguard Worker return MapSystemError(errno);
999*6777b538SAndroid Build Coastguard Worker return OK;
1000*6777b538SAndroid Build Coastguard Worker }
1001*6777b538SAndroid Build Coastguard Worker case IPAddress::kIPv6AddressSize: {
1002*6777b538SAndroid Build Coastguard Worker if (addr_family_ != AF_INET6)
1003*6777b538SAndroid Build Coastguard Worker return ERR_ADDRESS_INVALID;
1004*6777b538SAndroid Build Coastguard Worker ipv6_mreq mreq;
1005*6777b538SAndroid Build Coastguard Worker mreq.ipv6mr_interface = multicast_interface_;
1006*6777b538SAndroid Build Coastguard Worker memcpy(&mreq.ipv6mr_multiaddr, group_address.bytes().data(),
1007*6777b538SAndroid Build Coastguard Worker IPAddress::kIPv6AddressSize);
1008*6777b538SAndroid Build Coastguard Worker int rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_JOIN_GROUP,
1009*6777b538SAndroid Build Coastguard Worker &mreq, sizeof(mreq));
1010*6777b538SAndroid Build Coastguard Worker if (rv < 0)
1011*6777b538SAndroid Build Coastguard Worker return MapSystemError(errno);
1012*6777b538SAndroid Build Coastguard Worker return OK;
1013*6777b538SAndroid Build Coastguard Worker }
1014*6777b538SAndroid Build Coastguard Worker default:
1015*6777b538SAndroid Build Coastguard Worker NOTREACHED() << "Invalid address family";
1016*6777b538SAndroid Build Coastguard Worker return ERR_ADDRESS_INVALID;
1017*6777b538SAndroid Build Coastguard Worker }
1018*6777b538SAndroid Build Coastguard Worker }
1019*6777b538SAndroid Build Coastguard Worker
1020*6777b538SAndroid Build Coastguard Worker int UDPSocketPosix::LeaveGroup(const IPAddress& group_address) const {
1021*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1022*6777b538SAndroid Build Coastguard Worker
1023*6777b538SAndroid Build Coastguard Worker if (!is_connected())
1024*6777b538SAndroid Build Coastguard Worker return ERR_SOCKET_NOT_CONNECTED;
1025*6777b538SAndroid Build Coastguard Worker
1026*6777b538SAndroid Build Coastguard Worker switch (group_address.size()) {
1027*6777b538SAndroid Build Coastguard Worker case IPAddress::kIPv4AddressSize: {
1028*6777b538SAndroid Build Coastguard Worker if (addr_family_ != AF_INET)
1029*6777b538SAndroid Build Coastguard Worker return ERR_ADDRESS_INVALID;
1030*6777b538SAndroid Build Coastguard Worker ip_mreqn mreq = {};
1031*6777b538SAndroid Build Coastguard Worker mreq.imr_ifindex = multicast_interface_;
1032*6777b538SAndroid Build Coastguard Worker mreq.imr_address.s_addr = INADDR_ANY;
1033*6777b538SAndroid Build Coastguard Worker memcpy(&mreq.imr_multiaddr, group_address.bytes().data(),
1034*6777b538SAndroid Build Coastguard Worker IPAddress::kIPv4AddressSize);
1035*6777b538SAndroid Build Coastguard Worker int rv = setsockopt(socket_, IPPROTO_IP, IP_DROP_MEMBERSHIP,
1036*6777b538SAndroid Build Coastguard Worker &mreq, sizeof(mreq));
1037*6777b538SAndroid Build Coastguard Worker if (rv < 0)
1038*6777b538SAndroid Build Coastguard Worker return MapSystemError(errno);
1039*6777b538SAndroid Build Coastguard Worker return OK;
1040*6777b538SAndroid Build Coastguard Worker }
1041*6777b538SAndroid Build Coastguard Worker case IPAddress::kIPv6AddressSize: {
1042*6777b538SAndroid Build Coastguard Worker if (addr_family_ != AF_INET6)
1043*6777b538SAndroid Build Coastguard Worker return ERR_ADDRESS_INVALID;
1044*6777b538SAndroid Build Coastguard Worker ipv6_mreq mreq;
1045*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_FUCHSIA)
1046*6777b538SAndroid Build Coastguard Worker mreq.ipv6mr_interface = multicast_interface_;
1047*6777b538SAndroid Build Coastguard Worker #else // BUILDFLAG(IS_FUCHSIA)
1048*6777b538SAndroid Build Coastguard Worker mreq.ipv6mr_interface = 0; // 0 indicates default multicast interface.
1049*6777b538SAndroid Build Coastguard Worker #endif // !BUILDFLAG(IS_FUCHSIA)
1050*6777b538SAndroid Build Coastguard Worker memcpy(&mreq.ipv6mr_multiaddr, group_address.bytes().data(),
1051*6777b538SAndroid Build Coastguard Worker IPAddress::kIPv6AddressSize);
1052*6777b538SAndroid Build Coastguard Worker int rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
1053*6777b538SAndroid Build Coastguard Worker &mreq, sizeof(mreq));
1054*6777b538SAndroid Build Coastguard Worker if (rv < 0)
1055*6777b538SAndroid Build Coastguard Worker return MapSystemError(errno);
1056*6777b538SAndroid Build Coastguard Worker return OK;
1057*6777b538SAndroid Build Coastguard Worker }
1058*6777b538SAndroid Build Coastguard Worker default:
1059*6777b538SAndroid Build Coastguard Worker NOTREACHED() << "Invalid address family";
1060*6777b538SAndroid Build Coastguard Worker return ERR_ADDRESS_INVALID;
1061*6777b538SAndroid Build Coastguard Worker }
1062*6777b538SAndroid Build Coastguard Worker }
1063*6777b538SAndroid Build Coastguard Worker
1064*6777b538SAndroid Build Coastguard Worker int UDPSocketPosix::SetMulticastInterface(uint32_t interface_index) {
1065*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1066*6777b538SAndroid Build Coastguard Worker if (is_connected())
1067*6777b538SAndroid Build Coastguard Worker return ERR_SOCKET_IS_CONNECTED;
1068*6777b538SAndroid Build Coastguard Worker multicast_interface_ = interface_index;
1069*6777b538SAndroid Build Coastguard Worker return OK;
1070*6777b538SAndroid Build Coastguard Worker }
1071*6777b538SAndroid Build Coastguard Worker
1072*6777b538SAndroid Build Coastguard Worker int UDPSocketPosix::SetMulticastTimeToLive(int time_to_live) {
1073*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1074*6777b538SAndroid Build Coastguard Worker if (is_connected())
1075*6777b538SAndroid Build Coastguard Worker return ERR_SOCKET_IS_CONNECTED;
1076*6777b538SAndroid Build Coastguard Worker
1077*6777b538SAndroid Build Coastguard Worker if (time_to_live < 0 || time_to_live > 255)
1078*6777b538SAndroid Build Coastguard Worker return ERR_INVALID_ARGUMENT;
1079*6777b538SAndroid Build Coastguard Worker multicast_time_to_live_ = time_to_live;
1080*6777b538SAndroid Build Coastguard Worker return OK;
1081*6777b538SAndroid Build Coastguard Worker }
1082*6777b538SAndroid Build Coastguard Worker
1083*6777b538SAndroid Build Coastguard Worker int UDPSocketPosix::SetMulticastLoopbackMode(bool loopback) {
1084*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1085*6777b538SAndroid Build Coastguard Worker if (is_connected())
1086*6777b538SAndroid Build Coastguard Worker return ERR_SOCKET_IS_CONNECTED;
1087*6777b538SAndroid Build Coastguard Worker
1088*6777b538SAndroid Build Coastguard Worker if (loopback)
1089*6777b538SAndroid Build Coastguard Worker socket_options_ |= SOCKET_OPTION_MULTICAST_LOOP;
1090*6777b538SAndroid Build Coastguard Worker else
1091*6777b538SAndroid Build Coastguard Worker socket_options_ &= ~SOCKET_OPTION_MULTICAST_LOOP;
1092*6777b538SAndroid Build Coastguard Worker return OK;
1093*6777b538SAndroid Build Coastguard Worker }
1094*6777b538SAndroid Build Coastguard Worker
1095*6777b538SAndroid Build Coastguard Worker int UDPSocketPosix::SetDiffServCodePoint(DiffServCodePoint dscp) {
1096*6777b538SAndroid Build Coastguard Worker return SetTos(dscp, ECN_NO_CHANGE);
1097*6777b538SAndroid Build Coastguard Worker }
1098*6777b538SAndroid Build Coastguard Worker
1099*6777b538SAndroid Build Coastguard Worker int UDPSocketPosix::SetTos(DiffServCodePoint dscp, EcnCodePoint ecn) {
1100*6777b538SAndroid Build Coastguard Worker if (dscp == DSCP_NO_CHANGE && ecn == ECN_NO_CHANGE) {
1101*6777b538SAndroid Build Coastguard Worker return OK;
1102*6777b538SAndroid Build Coastguard Worker }
1103*6777b538SAndroid Build Coastguard Worker int dscp_and_ecn = (dscp << 2) | ecn;
1104*6777b538SAndroid Build Coastguard Worker socklen_t size = sizeof(dscp_and_ecn);
1105*6777b538SAndroid Build Coastguard Worker if (dscp == DSCP_NO_CHANGE || ecn == ECN_NO_CHANGE) {
1106*6777b538SAndroid Build Coastguard Worker int rv;
1107*6777b538SAndroid Build Coastguard Worker if (addr_family_ == AF_INET) {
1108*6777b538SAndroid Build Coastguard Worker rv = getsockopt(socket_, IPPROTO_IP, IP_TOS, &dscp_and_ecn, &size);
1109*6777b538SAndroid Build Coastguard Worker } else {
1110*6777b538SAndroid Build Coastguard Worker rv = getsockopt(socket_, IPPROTO_IPV6, IPV6_TCLASS, &dscp_and_ecn, &size);
1111*6777b538SAndroid Build Coastguard Worker }
1112*6777b538SAndroid Build Coastguard Worker if (rv < 0) {
1113*6777b538SAndroid Build Coastguard Worker return MapSystemError(errno);
1114*6777b538SAndroid Build Coastguard Worker }
1115*6777b538SAndroid Build Coastguard Worker if (dscp == DSCP_NO_CHANGE) {
1116*6777b538SAndroid Build Coastguard Worker dscp_and_ecn &= ~ECN_LAST;
1117*6777b538SAndroid Build Coastguard Worker dscp_and_ecn |= ecn;
1118*6777b538SAndroid Build Coastguard Worker } else {
1119*6777b538SAndroid Build Coastguard Worker dscp_and_ecn &= ECN_LAST;
1120*6777b538SAndroid Build Coastguard Worker dscp_and_ecn |= (dscp << 2);
1121*6777b538SAndroid Build Coastguard Worker }
1122*6777b538SAndroid Build Coastguard Worker }
1123*6777b538SAndroid Build Coastguard Worker // Set the IPv4 option in all cases to support dual-stack sockets.
1124*6777b538SAndroid Build Coastguard Worker int rv = setsockopt(socket_, IPPROTO_IP, IP_TOS, &dscp_and_ecn,
1125*6777b538SAndroid Build Coastguard Worker sizeof(dscp_and_ecn));
1126*6777b538SAndroid Build Coastguard Worker if (addr_family_ == AF_INET6) {
1127*6777b538SAndroid Build Coastguard Worker // In the IPv6 case, the previous socksetopt may fail because of a lack of
1128*6777b538SAndroid Build Coastguard Worker // dual-stack support. Therefore ignore the previous return value.
1129*6777b538SAndroid Build Coastguard Worker rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_TCLASS,
1130*6777b538SAndroid Build Coastguard Worker &dscp_and_ecn, sizeof(dscp_and_ecn));
1131*6777b538SAndroid Build Coastguard Worker }
1132*6777b538SAndroid Build Coastguard Worker if (rv < 0)
1133*6777b538SAndroid Build Coastguard Worker return MapSystemError(errno);
1134*6777b538SAndroid Build Coastguard Worker return OK;
1135*6777b538SAndroid Build Coastguard Worker }
1136*6777b538SAndroid Build Coastguard Worker
1137*6777b538SAndroid Build Coastguard Worker int UDPSocketPosix::SetIPv6Only(bool ipv6_only) {
1138*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1139*6777b538SAndroid Build Coastguard Worker if (is_connected()) {
1140*6777b538SAndroid Build Coastguard Worker return ERR_SOCKET_IS_CONNECTED;
1141*6777b538SAndroid Build Coastguard Worker }
1142*6777b538SAndroid Build Coastguard Worker return net::SetIPv6Only(socket_, ipv6_only);
1143*6777b538SAndroid Build Coastguard Worker }
1144*6777b538SAndroid Build Coastguard Worker
1145*6777b538SAndroid Build Coastguard Worker void UDPSocketPosix::DetachFromThread() {
1146*6777b538SAndroid Build Coastguard Worker DETACH_FROM_THREAD(thread_checker_);
1147*6777b538SAndroid Build Coastguard Worker }
1148*6777b538SAndroid Build Coastguard Worker
1149*6777b538SAndroid Build Coastguard Worker void UDPSocketPosix::ApplySocketTag(const SocketTag& tag) {
1150*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1151*6777b538SAndroid Build Coastguard Worker if (socket_ != kInvalidSocket && tag != tag_) {
1152*6777b538SAndroid Build Coastguard Worker tag.Apply(socket_);
1153*6777b538SAndroid Build Coastguard Worker }
1154*6777b538SAndroid Build Coastguard Worker tag_ = tag;
1155*6777b538SAndroid Build Coastguard Worker }
1156*6777b538SAndroid Build Coastguard Worker
1157*6777b538SAndroid Build Coastguard Worker int UDPSocketPosix::SetIOSNetworkServiceType(int ios_network_service_type) {
1158*6777b538SAndroid Build Coastguard Worker if (ios_network_service_type == 0) {
1159*6777b538SAndroid Build Coastguard Worker return OK;
1160*6777b538SAndroid Build Coastguard Worker }
1161*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_IOS)
1162*6777b538SAndroid Build Coastguard Worker if (setsockopt(socket_, SOL_SOCKET, SO_NET_SERVICE_TYPE,
1163*6777b538SAndroid Build Coastguard Worker &ios_network_service_type, sizeof(ios_network_service_type))) {
1164*6777b538SAndroid Build Coastguard Worker return MapSystemError(errno);
1165*6777b538SAndroid Build Coastguard Worker }
1166*6777b538SAndroid Build Coastguard Worker #endif // BUILDFLAG(IS_IOS)
1167*6777b538SAndroid Build Coastguard Worker return OK;
1168*6777b538SAndroid Build Coastguard Worker }
1169*6777b538SAndroid Build Coastguard Worker
1170*6777b538SAndroid Build Coastguard Worker } // namespace net
1171