1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "net/udp/udp_socket_libevent.h"
11 #include <netinet/in.h>
12 #include <sys/ioctl.h>
13 #include <sys/socket.h>
15 #include "base/callback.h"
16 #include "base/debug/alias.h"
17 #include "base/logging.h"
18 #include "base/message_loop/message_loop.h"
19 #include "base/metrics/sparse_histogram.h"
20 #include "base/posix/eintr_wrapper.h"
21 #include "base/rand_util.h"
22 #include "net/base/io_buffer.h"
23 #include "net/base/ip_endpoint.h"
24 #include "net/base/net_errors.h"
25 #include "net/base/net_log.h"
26 #include "net/base/net_util.h"
27 #include "net/base/network_activity_monitor.h"
28 #include "net/socket/socket_descriptor.h"
29 #include "net/udp/udp_net_log_parameters.h"
36 const int kBindRetries
= 10;
37 const int kPortStart
= 1024;
38 const int kPortEnd
= 65535;
40 #if defined(OS_MACOSX)
42 // Returns IPv4 address in network order.
43 int GetIPv4AddressFromIndex(int socket
, uint32 index
, uint32
* address
){
45 *address
= htonl(INADDR_ANY
);
49 ifr
.ifr_addr
.sa_family
= AF_INET
;
50 if (!if_indextoname(index
, ifr
.ifr_name
))
51 return MapSystemError(errno
);
52 int rv
= ioctl(socket
, SIOCGIFADDR
, &ifr
);
54 return MapSystemError(errno
);
55 *address
= reinterpret_cast<sockaddr_in
*>(&ifr
.ifr_addr
)->sin_addr
.s_addr
;
63 UDPSocketLibevent::UDPSocketLibevent(
64 DatagramSocket::BindType bind_type
,
65 const RandIntCallback
& rand_int_cb
,
67 const net::NetLog::Source
& source
)
68 : socket_(kInvalidSocket
),
71 socket_options_(SOCKET_OPTION_MULTICAST_LOOP
),
72 multicast_interface_(0),
73 multicast_time_to_live_(1),
74 bind_type_(bind_type
),
75 rand_int_cb_(rand_int_cb
),
79 recv_from_address_(NULL
),
81 net_log_(BoundNetLog::Make(net_log
, NetLog::SOURCE_UDP_SOCKET
)) {
82 net_log_
.BeginEvent(NetLog::TYPE_SOCKET_ALIVE
,
83 source
.ToEventParametersCallback());
84 if (bind_type
== DatagramSocket::RANDOM_BIND
)
85 DCHECK(!rand_int_cb
.is_null());
88 UDPSocketLibevent::~UDPSocketLibevent() {
90 net_log_
.EndEvent(NetLog::TYPE_SOCKET_ALIVE
);
93 int UDPSocketLibevent::Open(AddressFamily address_family
) {
94 DCHECK(CalledOnValidThread());
95 DCHECK_EQ(socket_
, kInvalidSocket
);
97 addr_family_
= ConvertAddressFamily(address_family
);
98 socket_
= CreatePlatformSocket(addr_family_
, SOCK_DGRAM
, 0);
99 if (socket_
== kInvalidSocket
)
100 return MapSystemError(errno
);
101 if (SetNonBlocking(socket_
)) {
102 const int err
= MapSystemError(errno
);
109 void UDPSocketLibevent::Close() {
110 DCHECK(CalledOnValidThread());
112 if (socket_
== kInvalidSocket
)
115 // Zero out any pending read/write callback state.
118 read_callback_
.Reset();
119 recv_from_address_
= NULL
;
122 write_callback_
.Reset();
123 send_to_address_
.reset();
125 bool ok
= read_socket_watcher_
.StopWatchingFileDescriptor();
127 ok
= write_socket_watcher_
.StopWatchingFileDescriptor();
130 if (IGNORE_EINTR(close(socket_
)) == -1) {
131 int last_error
= errno
;
132 base::debug::Alias(&last_error
);
133 // Crash on any error other than EIO.
134 PCHECK(last_error
== EIO
);
137 socket_
= kInvalidSocket
;
139 is_connected_
= false;
142 int UDPSocketLibevent::GetPeerAddress(IPEndPoint
* address
) const {
143 DCHECK(CalledOnValidThread());
146 return ERR_SOCKET_NOT_CONNECTED
;
148 if (!remote_address_
.get()) {
149 SockaddrStorage storage
;
150 if (getpeername(socket_
, storage
.addr
, &storage
.addr_len
))
151 return MapSystemError(errno
);
152 scoped_ptr
<IPEndPoint
> address(new IPEndPoint());
153 if (!address
->FromSockAddr(storage
.addr
, storage
.addr_len
))
154 return ERR_ADDRESS_INVALID
;
155 remote_address_
.reset(address
.release());
158 *address
= *remote_address_
;
162 int UDPSocketLibevent::GetLocalAddress(IPEndPoint
* address
) const {
163 DCHECK(CalledOnValidThread());
166 return ERR_SOCKET_NOT_CONNECTED
;
168 if (!local_address_
.get()) {
169 SockaddrStorage storage
;
170 if (getsockname(socket_
, storage
.addr
, &storage
.addr_len
))
171 return MapSystemError(errno
);
172 scoped_ptr
<IPEndPoint
> address(new IPEndPoint());
173 if (!address
->FromSockAddr(storage
.addr
, storage
.addr_len
))
174 return ERR_ADDRESS_INVALID
;
175 local_address_
.reset(address
.release());
176 net_log_
.AddEvent(NetLog::TYPE_UDP_LOCAL_ADDRESS
,
177 CreateNetLogUDPConnectCallback(local_address_
.get()));
180 *address
= *local_address_
;
184 int UDPSocketLibevent::Read(IOBuffer
* buf
,
186 const CompletionCallback
& callback
) {
187 return RecvFrom(buf
, buf_len
, NULL
, callback
);
190 int UDPSocketLibevent::RecvFrom(IOBuffer
* buf
,
193 const CompletionCallback
& callback
) {
194 DCHECK(CalledOnValidThread());
195 DCHECK_NE(kInvalidSocket
, socket_
);
196 CHECK(read_callback_
.is_null());
197 DCHECK(!recv_from_address_
);
198 DCHECK(!callback
.is_null()); // Synchronous operation not supported
199 DCHECK_GT(buf_len
, 0);
201 int nread
= InternalRecvFrom(buf
, buf_len
, address
);
202 if (nread
!= ERR_IO_PENDING
)
205 if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
206 socket_
, true, base::MessageLoopForIO::WATCH_READ
,
207 &read_socket_watcher_
, &read_watcher_
)) {
208 PLOG(ERROR
) << "WatchFileDescriptor failed on read";
209 int result
= MapSystemError(errno
);
210 LogRead(result
, NULL
, 0, NULL
);
215 read_buf_len_
= buf_len
;
216 recv_from_address_
= address
;
217 read_callback_
= callback
;
218 return ERR_IO_PENDING
;
221 int UDPSocketLibevent::Write(IOBuffer
* buf
,
223 const CompletionCallback
& callback
) {
224 return SendToOrWrite(buf
, buf_len
, NULL
, callback
);
227 int UDPSocketLibevent::SendTo(IOBuffer
* buf
,
229 const IPEndPoint
& address
,
230 const CompletionCallback
& callback
) {
231 return SendToOrWrite(buf
, buf_len
, &address
, callback
);
234 int UDPSocketLibevent::SendToOrWrite(IOBuffer
* buf
,
236 const IPEndPoint
* address
,
237 const CompletionCallback
& callback
) {
238 DCHECK(CalledOnValidThread());
239 DCHECK_NE(kInvalidSocket
, socket_
);
240 CHECK(write_callback_
.is_null());
241 DCHECK(!callback
.is_null()); // Synchronous operation not supported
242 DCHECK_GT(buf_len
, 0);
244 int result
= InternalSendTo(buf
, buf_len
, address
);
245 if (result
!= ERR_IO_PENDING
)
248 if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
249 socket_
, true, base::MessageLoopForIO::WATCH_WRITE
,
250 &write_socket_watcher_
, &write_watcher_
)) {
251 DVLOG(1) << "WatchFileDescriptor failed on write, errno " << errno
;
252 int result
= MapSystemError(errno
);
253 LogWrite(result
, NULL
, NULL
);
258 write_buf_len_
= buf_len
;
259 DCHECK(!send_to_address_
.get());
261 send_to_address_
.reset(new IPEndPoint(*address
));
263 write_callback_
= callback
;
264 return ERR_IO_PENDING
;
267 int UDPSocketLibevent::Connect(const IPEndPoint
& address
) {
268 DCHECK_NE(socket_
, kInvalidSocket
);
269 net_log_
.BeginEvent(NetLog::TYPE_UDP_CONNECT
,
270 CreateNetLogUDPConnectCallback(&address
));
271 int rv
= InternalConnect(address
);
272 net_log_
.EndEventWithNetErrorCode(NetLog::TYPE_UDP_CONNECT
, rv
);
273 is_connected_
= (rv
== OK
);
277 int UDPSocketLibevent::InternalConnect(const IPEndPoint
& address
) {
278 DCHECK(CalledOnValidThread());
279 DCHECK(!is_connected());
280 DCHECK(!remote_address_
.get());
283 if (bind_type_
== DatagramSocket::RANDOM_BIND
) {
284 // Construct IPAddressNumber of appropriate size (IPv4 or IPv6) of 0s,
285 // representing INADDR_ANY or in6addr_any.
286 size_t addr_size
= address
.GetSockAddrFamily() == AF_INET
?
287 kIPv4AddressSize
: kIPv6AddressSize
;
288 IPAddressNumber
addr_any(addr_size
);
289 rv
= RandomBind(addr_any
);
291 // else connect() does the DatagramSocket::DEFAULT_BIND
294 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.UdpSocketRandomBindErrorCode", -rv
);
298 SockaddrStorage storage
;
299 if (!address
.ToSockAddr(storage
.addr
, &storage
.addr_len
))
300 return ERR_ADDRESS_INVALID
;
302 rv
= HANDLE_EINTR(connect(socket_
, storage
.addr
, storage
.addr_len
));
304 return MapSystemError(errno
);
306 remote_address_
.reset(new IPEndPoint(address
));
310 int UDPSocketLibevent::Bind(const IPEndPoint
& address
) {
311 DCHECK_NE(socket_
, kInvalidSocket
);
312 DCHECK(CalledOnValidThread());
313 DCHECK(!is_connected());
315 int rv
= SetMulticastOptions();
319 rv
= DoBind(address
);
323 is_connected_
= true;
324 local_address_
.reset();
328 int UDPSocketLibevent::SetReceiveBufferSize(int32 size
) {
329 DCHECK_NE(socket_
, kInvalidSocket
);
330 DCHECK(CalledOnValidThread());
331 int rv
= setsockopt(socket_
, SOL_SOCKET
, SO_RCVBUF
,
332 reinterpret_cast<const char*>(&size
), sizeof(size
));
333 return rv
== 0 ? OK
: MapSystemError(errno
);
336 int UDPSocketLibevent::SetSendBufferSize(int32 size
) {
337 DCHECK_NE(socket_
, kInvalidSocket
);
338 DCHECK(CalledOnValidThread());
339 int rv
= setsockopt(socket_
, SOL_SOCKET
, SO_SNDBUF
,
340 reinterpret_cast<const char*>(&size
), sizeof(size
));
341 return rv
== 0 ? OK
: MapSystemError(errno
);
344 int UDPSocketLibevent::AllowAddressReuse() {
345 DCHECK_NE(socket_
, kInvalidSocket
);
346 DCHECK(CalledOnValidThread());
347 DCHECK(!is_connected());
350 socket_
, SOL_SOCKET
, SO_REUSEADDR
, &true_value
, sizeof(true_value
));
351 return rv
== 0 ? OK
: MapSystemError(errno
);
354 int UDPSocketLibevent::SetBroadcast(bool broadcast
) {
355 DCHECK_NE(socket_
, kInvalidSocket
);
356 DCHECK(CalledOnValidThread());
357 int value
= broadcast
? 1 : 0;
359 #if defined(OS_MACOSX)
360 // SO_REUSEPORT on OSX permits multiple processes to each receive
361 // UDP multicast or broadcast datagrams destined for the bound
363 rv
= setsockopt(socket_
, SOL_SOCKET
, SO_REUSEPORT
, &value
, sizeof(value
));
365 rv
= setsockopt(socket_
, SOL_SOCKET
, SO_BROADCAST
, &value
, sizeof(value
));
366 #endif // defined(OS_MACOSX)
367 return rv
== 0 ? OK
: MapSystemError(errno
);
370 void UDPSocketLibevent::ReadWatcher::OnFileCanReadWithoutBlocking(int) {
371 if (!socket_
->read_callback_
.is_null())
372 socket_
->DidCompleteRead();
375 void UDPSocketLibevent::WriteWatcher::OnFileCanWriteWithoutBlocking(int) {
376 if (!socket_
->write_callback_
.is_null())
377 socket_
->DidCompleteWrite();
380 void UDPSocketLibevent::DoReadCallback(int rv
) {
381 DCHECK_NE(rv
, ERR_IO_PENDING
);
382 DCHECK(!read_callback_
.is_null());
384 // since Run may result in Read being called, clear read_callback_ up front.
385 CompletionCallback c
= read_callback_
;
386 read_callback_
.Reset();
390 void UDPSocketLibevent::DoWriteCallback(int rv
) {
391 DCHECK_NE(rv
, ERR_IO_PENDING
);
392 DCHECK(!write_callback_
.is_null());
394 // since Run may result in Write being called, clear write_callback_ up front.
395 CompletionCallback c
= write_callback_
;
396 write_callback_
.Reset();
400 void UDPSocketLibevent::DidCompleteRead() {
402 InternalRecvFrom(read_buf_
.get(), read_buf_len_
, recv_from_address_
);
403 if (result
!= ERR_IO_PENDING
) {
406 recv_from_address_
= NULL
;
407 bool ok
= read_socket_watcher_
.StopWatchingFileDescriptor();
409 DoReadCallback(result
);
413 void UDPSocketLibevent::LogRead(int result
,
416 const sockaddr
* addr
) const {
418 net_log_
.AddEventWithNetErrorCode(NetLog::TYPE_UDP_RECEIVE_ERROR
, result
);
422 if (net_log_
.IsLogging()) {
423 DCHECK(addr_len
> 0);
427 bool is_address_valid
= address
.FromSockAddr(addr
, addr_len
);
429 NetLog::TYPE_UDP_BYTES_RECEIVED
,
430 CreateNetLogUDPDataTranferCallback(
432 is_address_valid
? &address
: NULL
));
435 NetworkActivityMonitor::GetInstance()->IncrementBytesReceived(result
);
438 void UDPSocketLibevent::DidCompleteWrite() {
440 InternalSendTo(write_buf_
.get(), write_buf_len_
, send_to_address_
.get());
442 if (result
!= ERR_IO_PENDING
) {
445 send_to_address_
.reset();
446 write_socket_watcher_
.StopWatchingFileDescriptor();
447 DoWriteCallback(result
);
451 void UDPSocketLibevent::LogWrite(int result
,
453 const IPEndPoint
* address
) const {
455 net_log_
.AddEventWithNetErrorCode(NetLog::TYPE_UDP_SEND_ERROR
, result
);
459 if (net_log_
.IsLogging()) {
461 NetLog::TYPE_UDP_BYTES_SENT
,
462 CreateNetLogUDPDataTranferCallback(result
, bytes
, address
));
465 NetworkActivityMonitor::GetInstance()->IncrementBytesSent(result
);
468 int UDPSocketLibevent::InternalRecvFrom(IOBuffer
* buf
, int buf_len
,
469 IPEndPoint
* address
) {
470 int bytes_transferred
;
473 SockaddrStorage storage
;
476 HANDLE_EINTR(recvfrom(socket_
,
483 if (bytes_transferred
>= 0) {
484 result
= bytes_transferred
;
485 if (address
&& !address
->FromSockAddr(storage
.addr
, storage
.addr_len
))
486 result
= ERR_ADDRESS_INVALID
;
488 result
= MapSystemError(errno
);
490 if (result
!= ERR_IO_PENDING
)
491 LogRead(result
, buf
->data(), storage
.addr_len
, storage
.addr
);
495 int UDPSocketLibevent::InternalSendTo(IOBuffer
* buf
, int buf_len
,
496 const IPEndPoint
* address
) {
497 SockaddrStorage storage
;
498 struct sockaddr
* addr
= storage
.addr
;
501 storage
.addr_len
= 0;
503 if (!address
->ToSockAddr(storage
.addr
, &storage
.addr_len
)) {
504 int result
= ERR_ADDRESS_INVALID
;
505 LogWrite(result
, NULL
, NULL
);
510 int result
= HANDLE_EINTR(sendto(socket_
,
517 result
= MapSystemError(errno
);
518 if (result
!= ERR_IO_PENDING
)
519 LogWrite(result
, buf
->data(), address
);
523 int UDPSocketLibevent::SetMulticastOptions() {
524 if (!(socket_options_
& SOCKET_OPTION_MULTICAST_LOOP
)) {
526 if (addr_family_
== AF_INET
) {
528 rv
= setsockopt(socket_
, IPPROTO_IP
, IP_MULTICAST_LOOP
,
529 &loop
, sizeof(loop
));
532 rv
= setsockopt(socket_
, IPPROTO_IPV6
, IPV6_MULTICAST_LOOP
,
533 &loop
, sizeof(loop
));
536 return MapSystemError(errno
);
538 if (multicast_time_to_live_
!= IP_DEFAULT_MULTICAST_TTL
) {
540 if (addr_family_
== AF_INET
) {
541 u_char ttl
= multicast_time_to_live_
;
542 rv
= setsockopt(socket_
, IPPROTO_IP
, IP_MULTICAST_TTL
,
545 // Signed integer. -1 to use route default.
546 int ttl
= multicast_time_to_live_
;
547 rv
= setsockopt(socket_
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
,
551 return MapSystemError(errno
);
553 if (multicast_interface_
!= 0) {
554 switch (addr_family_
) {
556 #if !defined(OS_MACOSX)
558 mreq
.imr_ifindex
= multicast_interface_
;
559 mreq
.imr_address
.s_addr
= htonl(INADDR_ANY
);
562 int error
= GetIPv4AddressFromIndex(socket_
, multicast_interface_
,
563 &mreq
.imr_interface
.s_addr
);
567 int rv
= setsockopt(socket_
, IPPROTO_IP
, IP_MULTICAST_IF
,
568 reinterpret_cast<const char*>(&mreq
), sizeof(mreq
));
570 return MapSystemError(errno
);
574 uint32 interface_index
= multicast_interface_
;
575 int rv
= setsockopt(socket_
, IPPROTO_IPV6
, IPV6_MULTICAST_IF
,
576 reinterpret_cast<const char*>(&interface_index
),
577 sizeof(interface_index
));
579 return MapSystemError(errno
);
583 NOTREACHED() << "Invalid address family";
584 return ERR_ADDRESS_INVALID
;
590 int UDPSocketLibevent::DoBind(const IPEndPoint
& address
) {
591 SockaddrStorage storage
;
592 if (!address
.ToSockAddr(storage
.addr
, &storage
.addr_len
))
593 return ERR_ADDRESS_INVALID
;
594 int rv
= bind(socket_
, storage
.addr
, storage
.addr_len
);
597 int last_error
= errno
;
598 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.UdpSocketBindErrorFromPosix", last_error
);
599 #if defined(OS_CHROMEOS)
600 if (last_error
== EINVAL
)
601 return ERR_ADDRESS_IN_USE
;
602 #elif defined(OS_MACOSX)
603 if (last_error
== EADDRNOTAVAIL
)
604 return ERR_ADDRESS_IN_USE
;
606 return MapSystemError(last_error
);
609 int UDPSocketLibevent::RandomBind(const IPAddressNumber
& address
) {
610 DCHECK(bind_type_
== DatagramSocket::RANDOM_BIND
&& !rand_int_cb_
.is_null());
612 for (int i
= 0; i
< kBindRetries
; ++i
) {
613 int rv
= DoBind(IPEndPoint(address
,
614 rand_int_cb_
.Run(kPortStart
, kPortEnd
)));
615 if (rv
== OK
|| rv
!= ERR_ADDRESS_IN_USE
)
618 return DoBind(IPEndPoint(address
, 0));
621 int UDPSocketLibevent::JoinGroup(const IPAddressNumber
& group_address
) const {
622 DCHECK(CalledOnValidThread());
624 return ERR_SOCKET_NOT_CONNECTED
;
626 switch (group_address
.size()) {
627 case kIPv4AddressSize
: {
628 if (addr_family_
!= AF_INET
)
629 return ERR_ADDRESS_INVALID
;
631 #if !defined(OS_MACOSX)
633 mreq
.imr_ifindex
= multicast_interface_
;
634 mreq
.imr_address
.s_addr
= htonl(INADDR_ANY
);
637 int error
= GetIPv4AddressFromIndex(socket_
, multicast_interface_
,
638 &mreq
.imr_interface
.s_addr
);
642 memcpy(&mreq
.imr_multiaddr
, &group_address
[0], kIPv4AddressSize
);
643 int rv
= setsockopt(socket_
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
,
644 &mreq
, sizeof(mreq
));
646 return MapSystemError(errno
);
649 case kIPv6AddressSize
: {
650 if (addr_family_
!= AF_INET6
)
651 return ERR_ADDRESS_INVALID
;
653 mreq
.ipv6mr_interface
= multicast_interface_
;
654 memcpy(&mreq
.ipv6mr_multiaddr
, &group_address
[0], kIPv6AddressSize
);
655 int rv
= setsockopt(socket_
, IPPROTO_IPV6
, IPV6_JOIN_GROUP
,
656 &mreq
, sizeof(mreq
));
658 return MapSystemError(errno
);
662 NOTREACHED() << "Invalid address family";
663 return ERR_ADDRESS_INVALID
;
667 int UDPSocketLibevent::LeaveGroup(const IPAddressNumber
& group_address
) const {
668 DCHECK(CalledOnValidThread());
671 return ERR_SOCKET_NOT_CONNECTED
;
673 switch (group_address
.size()) {
674 case kIPv4AddressSize
: {
675 if (addr_family_
!= AF_INET
)
676 return ERR_ADDRESS_INVALID
;
678 mreq
.imr_interface
.s_addr
= INADDR_ANY
;
679 memcpy(&mreq
.imr_multiaddr
, &group_address
[0], kIPv4AddressSize
);
680 int rv
= setsockopt(socket_
, IPPROTO_IP
, IP_DROP_MEMBERSHIP
,
681 &mreq
, sizeof(mreq
));
683 return MapSystemError(errno
);
686 case kIPv6AddressSize
: {
687 if (addr_family_
!= AF_INET6
)
688 return ERR_ADDRESS_INVALID
;
690 mreq
.ipv6mr_interface
= 0; // 0 indicates default multicast interface.
691 memcpy(&mreq
.ipv6mr_multiaddr
, &group_address
[0], kIPv6AddressSize
);
692 int rv
= setsockopt(socket_
, IPPROTO_IPV6
, IPV6_LEAVE_GROUP
,
693 &mreq
, sizeof(mreq
));
695 return MapSystemError(errno
);
699 NOTREACHED() << "Invalid address family";
700 return ERR_ADDRESS_INVALID
;
704 int UDPSocketLibevent::SetMulticastInterface(uint32 interface_index
) {
705 DCHECK(CalledOnValidThread());
707 return ERR_SOCKET_IS_CONNECTED
;
708 multicast_interface_
= interface_index
;
712 int UDPSocketLibevent::SetMulticastTimeToLive(int time_to_live
) {
713 DCHECK(CalledOnValidThread());
715 return ERR_SOCKET_IS_CONNECTED
;
717 if (time_to_live
< 0 || time_to_live
> 255)
718 return ERR_INVALID_ARGUMENT
;
719 multicast_time_to_live_
= time_to_live
;
723 int UDPSocketLibevent::SetMulticastLoopbackMode(bool loopback
) {
724 DCHECK(CalledOnValidThread());
726 return ERR_SOCKET_IS_CONNECTED
;
729 socket_options_
|= SOCKET_OPTION_MULTICAST_LOOP
;
731 socket_options_
&= ~SOCKET_OPTION_MULTICAST_LOOP
;
735 int UDPSocketLibevent::SetDiffServCodePoint(DiffServCodePoint dscp
) {
736 if (dscp
== DSCP_NO_CHANGE
) {
740 int dscp_and_ecn
= dscp
<< 2;
741 if (addr_family_
== AF_INET
) {
742 rv
= setsockopt(socket_
, IPPROTO_IP
, IP_TOS
,
743 &dscp_and_ecn
, sizeof(dscp_and_ecn
));
745 rv
= setsockopt(socket_
, IPPROTO_IPV6
, IPV6_TCLASS
,
746 &dscp_and_ecn
, sizeof(dscp_and_ecn
));
749 return MapSystemError(errno
);
754 void UDPSocketLibevent::DetachFromThread() {
755 base::NonThreadSafe::DetachFromThread();