1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "net/udp/udp_socket_libevent.h"
11 #include <netinet/in.h>
12 #include <sys/ioctl.h>
13 #include <sys/socket.h>
15 #include "base/callback.h"
16 #include "base/logging.h"
17 #include "base/message_loop/message_loop.h"
18 #include "base/metrics/sparse_histogram.h"
19 #include "base/metrics/stats_counters.h"
20 #include "base/posix/eintr_wrapper.h"
21 #include "base/rand_util.h"
22 #include "net/base/io_buffer.h"
23 #include "net/base/ip_endpoint.h"
24 #include "net/base/net_errors.h"
25 #include "net/base/net_log.h"
26 #include "net/base/net_util.h"
27 #include "net/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
),
70 socket_options_(SOCKET_OPTION_MULTICAST_LOOP
),
71 multicast_interface_(0),
72 multicast_time_to_live_(1),
73 bind_type_(bind_type
),
74 rand_int_cb_(rand_int_cb
),
78 recv_from_address_(NULL
),
80 net_log_(BoundNetLog::Make(net_log
, NetLog::SOURCE_UDP_SOCKET
)) {
81 net_log_
.BeginEvent(NetLog::TYPE_SOCKET_ALIVE
,
82 source
.ToEventParametersCallback());
83 if (bind_type
== DatagramSocket::RANDOM_BIND
)
84 DCHECK(!rand_int_cb
.is_null());
87 UDPSocketLibevent::~UDPSocketLibevent() {
89 net_log_
.EndEvent(NetLog::TYPE_SOCKET_ALIVE
);
92 void UDPSocketLibevent::Close() {
93 DCHECK(CalledOnValidThread());
98 // Zero out any pending read/write callback state.
101 read_callback_
.Reset();
102 recv_from_address_
= NULL
;
105 write_callback_
.Reset();
106 send_to_address_
.reset();
108 bool ok
= read_socket_watcher_
.StopWatchingFileDescriptor();
110 ok
= write_socket_watcher_
.StopWatchingFileDescriptor();
113 if (IGNORE_EINTR(close(socket_
)) < 0)
114 PLOG(ERROR
) << "close";
116 socket_
= kInvalidSocket
;
120 int UDPSocketLibevent::GetPeerAddress(IPEndPoint
* address
) const {
121 DCHECK(CalledOnValidThread());
124 return ERR_SOCKET_NOT_CONNECTED
;
126 if (!remote_address_
.get()) {
127 SockaddrStorage storage
;
128 if (getpeername(socket_
, storage
.addr
, &storage
.addr_len
))
129 return MapSystemError(errno
);
130 scoped_ptr
<IPEndPoint
> address(new IPEndPoint());
131 if (!address
->FromSockAddr(storage
.addr
, storage
.addr_len
))
132 return ERR_ADDRESS_INVALID
;
133 remote_address_
.reset(address
.release());
136 *address
= *remote_address_
;
140 int UDPSocketLibevent::GetLocalAddress(IPEndPoint
* address
) const {
141 DCHECK(CalledOnValidThread());
144 return ERR_SOCKET_NOT_CONNECTED
;
146 if (!local_address_
.get()) {
147 SockaddrStorage storage
;
148 if (getsockname(socket_
, storage
.addr
, &storage
.addr_len
))
149 return MapSystemError(errno
);
150 scoped_ptr
<IPEndPoint
> address(new IPEndPoint());
151 if (!address
->FromSockAddr(storage
.addr
, storage
.addr_len
))
152 return ERR_ADDRESS_INVALID
;
153 local_address_
.reset(address
.release());
154 net_log_
.AddEvent(NetLog::TYPE_UDP_LOCAL_ADDRESS
,
155 CreateNetLogUDPConnectCallback(local_address_
.get()));
158 *address
= *local_address_
;
162 int UDPSocketLibevent::Read(IOBuffer
* buf
,
164 const CompletionCallback
& callback
) {
165 return RecvFrom(buf
, buf_len
, NULL
, callback
);
168 int UDPSocketLibevent::RecvFrom(IOBuffer
* buf
,
171 const CompletionCallback
& callback
) {
172 DCHECK(CalledOnValidThread());
173 DCHECK_NE(kInvalidSocket
, socket_
);
174 CHECK(read_callback_
.is_null());
175 DCHECK(!recv_from_address_
);
176 DCHECK(!callback
.is_null()); // Synchronous operation not supported
177 DCHECK_GT(buf_len
, 0);
179 int nread
= InternalRecvFrom(buf
, buf_len
, address
);
180 if (nread
!= ERR_IO_PENDING
)
183 if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
184 socket_
, true, base::MessageLoopForIO::WATCH_READ
,
185 &read_socket_watcher_
, &read_watcher_
)) {
186 PLOG(ERROR
) << "WatchFileDescriptor failed on read";
187 int result
= MapSystemError(errno
);
188 LogRead(result
, NULL
, 0, NULL
);
193 read_buf_len_
= buf_len
;
194 recv_from_address_
= address
;
195 read_callback_
= callback
;
196 return ERR_IO_PENDING
;
199 int UDPSocketLibevent::Write(IOBuffer
* buf
,
201 const CompletionCallback
& callback
) {
202 return SendToOrWrite(buf
, buf_len
, NULL
, callback
);
205 int UDPSocketLibevent::SendTo(IOBuffer
* buf
,
207 const IPEndPoint
& address
,
208 const CompletionCallback
& callback
) {
209 return SendToOrWrite(buf
, buf_len
, &address
, callback
);
212 int UDPSocketLibevent::SendToOrWrite(IOBuffer
* buf
,
214 const IPEndPoint
* address
,
215 const CompletionCallback
& callback
) {
216 DCHECK(CalledOnValidThread());
217 DCHECK_NE(kInvalidSocket
, socket_
);
218 CHECK(write_callback_
.is_null());
219 DCHECK(!callback
.is_null()); // Synchronous operation not supported
220 DCHECK_GT(buf_len
, 0);
222 int result
= InternalSendTo(buf
, buf_len
, address
);
223 if (result
!= ERR_IO_PENDING
)
226 if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
227 socket_
, true, base::MessageLoopForIO::WATCH_WRITE
,
228 &write_socket_watcher_
, &write_watcher_
)) {
229 DVLOG(1) << "WatchFileDescriptor failed on write, errno " << errno
;
230 int result
= MapSystemError(errno
);
231 LogWrite(result
, NULL
, NULL
);
236 write_buf_len_
= buf_len
;
237 DCHECK(!send_to_address_
.get());
239 send_to_address_
.reset(new IPEndPoint(*address
));
241 write_callback_
= callback
;
242 return ERR_IO_PENDING
;
245 int UDPSocketLibevent::Connect(const IPEndPoint
& address
) {
246 net_log_
.BeginEvent(NetLog::TYPE_UDP_CONNECT
,
247 CreateNetLogUDPConnectCallback(&address
));
248 int rv
= InternalConnect(address
);
251 net_log_
.EndEventWithNetErrorCode(NetLog::TYPE_UDP_CONNECT
, rv
);
255 int UDPSocketLibevent::InternalConnect(const IPEndPoint
& address
) {
256 DCHECK(CalledOnValidThread());
257 DCHECK(!is_connected());
258 DCHECK(!remote_address_
.get());
259 int addr_family
= address
.GetSockAddrFamily();
260 int rv
= CreateSocket(addr_family
);
264 if (bind_type_
== DatagramSocket::RANDOM_BIND
) {
265 // Construct IPAddressNumber of appropriate size (IPv4 or IPv6) of 0s,
266 // representing INADDR_ANY or in6addr_any.
268 addr_family
== AF_INET
? kIPv4AddressSize
: kIPv6AddressSize
;
269 IPAddressNumber
addr_any(addr_size
);
270 rv
= RandomBind(addr_any
);
272 // else connect() does the DatagramSocket::DEFAULT_BIND
275 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.UdpSocketRandomBindErrorCode", -rv
);
280 SockaddrStorage storage
;
281 if (!address
.ToSockAddr(storage
.addr
, &storage
.addr_len
)) {
283 return ERR_ADDRESS_INVALID
;
286 rv
= HANDLE_EINTR(connect(socket_
, storage
.addr
, storage
.addr_len
));
288 // Close() may change the current errno. Map errno beforehand.
289 int result
= MapSystemError(errno
);
294 remote_address_
.reset(new IPEndPoint(address
));
298 int UDPSocketLibevent::Bind(const IPEndPoint
& address
) {
299 DCHECK(CalledOnValidThread());
300 DCHECK(!is_connected());
301 int rv
= CreateSocket(address
.GetSockAddrFamily());
305 rv
= SetSocketOptions();
310 rv
= DoBind(address
);
315 local_address_
.reset();
319 int UDPSocketLibevent::SetReceiveBufferSize(int32 size
) {
320 DCHECK(CalledOnValidThread());
321 int rv
= setsockopt(socket_
, SOL_SOCKET
, SO_RCVBUF
,
322 reinterpret_cast<const char*>(&size
), sizeof(size
));
323 int last_error
= errno
;
324 DCHECK(!rv
) << "Could not set socket receive buffer size: " << last_error
;
325 return rv
== 0 ? OK
: MapSystemError(last_error
);
328 int UDPSocketLibevent::SetSendBufferSize(int32 size
) {
329 DCHECK(CalledOnValidThread());
330 int rv
= setsockopt(socket_
, SOL_SOCKET
, SO_SNDBUF
,
331 reinterpret_cast<const char*>(&size
), sizeof(size
));
332 int last_error
= errno
;
333 DCHECK(!rv
) << "Could not set socket send buffer size: " << last_error
;
334 return rv
== 0 ? OK
: MapSystemError(last_error
);
337 void UDPSocketLibevent::AllowAddressReuse() {
338 DCHECK(CalledOnValidThread());
339 DCHECK(!is_connected());
341 socket_options_
|= SOCKET_OPTION_REUSE_ADDRESS
;
344 void UDPSocketLibevent::AllowBroadcast() {
345 DCHECK(CalledOnValidThread());
346 DCHECK(!is_connected());
348 socket_options_
|= SOCKET_OPTION_BROADCAST
;
351 void UDPSocketLibevent::ReadWatcher::OnFileCanReadWithoutBlocking(int) {
352 if (!socket_
->read_callback_
.is_null())
353 socket_
->DidCompleteRead();
356 void UDPSocketLibevent::WriteWatcher::OnFileCanWriteWithoutBlocking(int) {
357 if (!socket_
->write_callback_
.is_null())
358 socket_
->DidCompleteWrite();
361 void UDPSocketLibevent::DoReadCallback(int rv
) {
362 DCHECK_NE(rv
, ERR_IO_PENDING
);
363 DCHECK(!read_callback_
.is_null());
365 // since Run may result in Read being called, clear read_callback_ up front.
366 CompletionCallback c
= read_callback_
;
367 read_callback_
.Reset();
371 void UDPSocketLibevent::DoWriteCallback(int rv
) {
372 DCHECK_NE(rv
, ERR_IO_PENDING
);
373 DCHECK(!write_callback_
.is_null());
375 // since Run may result in Write being called, clear write_callback_ up front.
376 CompletionCallback c
= write_callback_
;
377 write_callback_
.Reset();
381 void UDPSocketLibevent::DidCompleteRead() {
383 InternalRecvFrom(read_buf_
.get(), read_buf_len_
, recv_from_address_
);
384 if (result
!= ERR_IO_PENDING
) {
387 recv_from_address_
= NULL
;
388 bool ok
= read_socket_watcher_
.StopWatchingFileDescriptor();
390 DoReadCallback(result
);
394 void UDPSocketLibevent::LogRead(int result
,
397 const sockaddr
* addr
) const {
399 net_log_
.AddEventWithNetErrorCode(NetLog::TYPE_UDP_RECEIVE_ERROR
, result
);
403 if (net_log_
.IsLogging()) {
404 DCHECK(addr_len
> 0);
408 bool is_address_valid
= address
.FromSockAddr(addr
, addr_len
);
410 NetLog::TYPE_UDP_BYTES_RECEIVED
,
411 CreateNetLogUDPDataTranferCallback(
413 is_address_valid
? &address
: NULL
));
416 base::StatsCounter
read_bytes("udp.read_bytes");
417 read_bytes
.Add(result
);
418 NetworkActivityMonitor::GetInstance()->IncrementBytesReceived(result
);
421 int UDPSocketLibevent::CreateSocket(int addr_family
) {
422 addr_family_
= addr_family
;
423 socket_
= CreatePlatformSocket(addr_family_
, SOCK_DGRAM
, 0);
424 if (socket_
== kInvalidSocket
)
425 return MapSystemError(errno
);
426 if (SetNonBlocking(socket_
)) {
427 const int err
= MapSystemError(errno
);
434 void UDPSocketLibevent::DidCompleteWrite() {
436 InternalSendTo(write_buf_
.get(), write_buf_len_
, send_to_address_
.get());
438 if (result
!= ERR_IO_PENDING
) {
441 send_to_address_
.reset();
442 write_socket_watcher_
.StopWatchingFileDescriptor();
443 DoWriteCallback(result
);
447 void UDPSocketLibevent::LogWrite(int result
,
449 const IPEndPoint
* address
) const {
451 net_log_
.AddEventWithNetErrorCode(NetLog::TYPE_UDP_SEND_ERROR
, result
);
455 if (net_log_
.IsLogging()) {
457 NetLog::TYPE_UDP_BYTES_SENT
,
458 CreateNetLogUDPDataTranferCallback(result
, bytes
, address
));
461 base::StatsCounter
write_bytes("udp.write_bytes");
462 write_bytes
.Add(result
);
463 NetworkActivityMonitor::GetInstance()->IncrementBytesSent(result
);
466 int UDPSocketLibevent::InternalRecvFrom(IOBuffer
* buf
, int buf_len
,
467 IPEndPoint
* address
) {
468 int bytes_transferred
;
471 SockaddrStorage storage
;
474 HANDLE_EINTR(recvfrom(socket_
,
481 if (bytes_transferred
>= 0) {
482 result
= bytes_transferred
;
483 if (address
&& !address
->FromSockAddr(storage
.addr
, storage
.addr_len
))
484 result
= ERR_ADDRESS_INVALID
;
486 result
= MapSystemError(errno
);
488 if (result
!= ERR_IO_PENDING
)
489 LogRead(result
, buf
->data(), storage
.addr_len
, storage
.addr
);
493 int UDPSocketLibevent::InternalSendTo(IOBuffer
* buf
, int buf_len
,
494 const IPEndPoint
* address
) {
495 SockaddrStorage storage
;
496 struct sockaddr
* addr
= storage
.addr
;
499 storage
.addr_len
= 0;
501 if (!address
->ToSockAddr(storage
.addr
, &storage
.addr_len
)) {
502 int result
= ERR_ADDRESS_INVALID
;
503 LogWrite(result
, NULL
, NULL
);
508 int result
= HANDLE_EINTR(sendto(socket_
,
515 result
= MapSystemError(errno
);
516 if (result
!= ERR_IO_PENDING
)
517 LogWrite(result
, buf
->data(), address
);
521 int UDPSocketLibevent::SetSocketOptions() {
523 if (socket_options_
& SOCKET_OPTION_REUSE_ADDRESS
) {
524 int rv
= setsockopt(socket_
, SOL_SOCKET
, SO_REUSEADDR
, &true_value
,
527 return MapSystemError(errno
);
529 if (socket_options_
& SOCKET_OPTION_BROADCAST
) {
531 #if defined(OS_MACOSX)
532 // SO_REUSEPORT on OSX permits multiple processes to each receive
533 // UDP multicast or broadcast datagrams destined for the bound
535 rv
= setsockopt(socket_
, SOL_SOCKET
, SO_REUSEPORT
, &true_value
,
538 rv
= setsockopt(socket_
, SOL_SOCKET
, SO_BROADCAST
, &true_value
,
540 #endif // defined(OS_MACOSX)
542 return MapSystemError(errno
);
545 if (!(socket_options_
& SOCKET_OPTION_MULTICAST_LOOP
)) {
547 if (addr_family_
== AF_INET
) {
549 rv
= setsockopt(socket_
, IPPROTO_IP
, IP_MULTICAST_LOOP
,
550 &loop
, sizeof(loop
));
553 rv
= setsockopt(socket_
, IPPROTO_IPV6
, IPV6_MULTICAST_LOOP
,
554 &loop
, sizeof(loop
));
557 return MapSystemError(errno
);
559 if (multicast_time_to_live_
!= IP_DEFAULT_MULTICAST_TTL
) {
561 if (addr_family_
== AF_INET
) {
562 u_char ttl
= multicast_time_to_live_
;
563 rv
= setsockopt(socket_
, IPPROTO_IP
, IP_MULTICAST_TTL
,
566 // Signed integer. -1 to use route default.
567 int ttl
= multicast_time_to_live_
;
568 rv
= setsockopt(socket_
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
,
572 return MapSystemError(errno
);
574 if (multicast_interface_
!= 0) {
575 switch (addr_family_
) {
577 #if !defined(OS_MACOSX)
579 mreq
.imr_ifindex
= multicast_interface_
;
580 mreq
.imr_address
.s_addr
= htonl(INADDR_ANY
);
583 int error
= GetIPv4AddressFromIndex(socket_
, multicast_interface_
,
584 &mreq
.imr_interface
.s_addr
);
588 int rv
= setsockopt(socket_
, IPPROTO_IP
, IP_MULTICAST_IF
,
589 reinterpret_cast<const char*>(&mreq
), sizeof(mreq
));
591 return MapSystemError(errno
);
595 uint32 interface_index
= multicast_interface_
;
596 int rv
= setsockopt(socket_
, IPPROTO_IPV6
, IPV6_MULTICAST_IF
,
597 reinterpret_cast<const char*>(&interface_index
),
598 sizeof(interface_index
));
600 return MapSystemError(errno
);
604 NOTREACHED() << "Invalid address family";
605 return ERR_ADDRESS_INVALID
;
611 int UDPSocketLibevent::DoBind(const IPEndPoint
& address
) {
612 SockaddrStorage storage
;
613 if (!address
.ToSockAddr(storage
.addr
, &storage
.addr_len
))
614 return ERR_ADDRESS_INVALID
;
615 int rv
= bind(socket_
, storage
.addr
, storage
.addr_len
);
618 int last_error
= errno
;
619 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.UdpSocketBindErrorFromPosix", last_error
);
620 #if defined(OS_CHROMEOS)
621 if (last_error
== EINVAL
)
622 return ERR_ADDRESS_IN_USE
;
623 #elif defined(OS_MACOSX)
624 if (last_error
== EADDRNOTAVAIL
)
625 return ERR_ADDRESS_IN_USE
;
627 return MapSystemError(last_error
);
630 int UDPSocketLibevent::RandomBind(const IPAddressNumber
& address
) {
631 DCHECK(bind_type_
== DatagramSocket::RANDOM_BIND
&& !rand_int_cb_
.is_null());
633 for (int i
= 0; i
< kBindRetries
; ++i
) {
634 int rv
= DoBind(IPEndPoint(address
,
635 rand_int_cb_
.Run(kPortStart
, kPortEnd
)));
636 if (rv
== OK
|| rv
!= ERR_ADDRESS_IN_USE
)
639 return DoBind(IPEndPoint(address
, 0));
642 int UDPSocketLibevent::JoinGroup(const IPAddressNumber
& group_address
) const {
643 DCHECK(CalledOnValidThread());
645 return ERR_SOCKET_NOT_CONNECTED
;
647 switch (group_address
.size()) {
648 case kIPv4AddressSize
: {
649 if (addr_family_
!= AF_INET
)
650 return ERR_ADDRESS_INVALID
;
652 #if !defined(OS_MACOSX)
654 mreq
.imr_ifindex
= multicast_interface_
;
655 mreq
.imr_address
.s_addr
= htonl(INADDR_ANY
);
658 int error
= GetIPv4AddressFromIndex(socket_
, multicast_interface_
,
659 &mreq
.imr_interface
.s_addr
);
663 memcpy(&mreq
.imr_multiaddr
, &group_address
[0], kIPv4AddressSize
);
664 int rv
= setsockopt(socket_
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
,
665 &mreq
, sizeof(mreq
));
667 return MapSystemError(errno
);
670 case kIPv6AddressSize
: {
671 if (addr_family_
!= AF_INET6
)
672 return ERR_ADDRESS_INVALID
;
674 mreq
.ipv6mr_interface
= multicast_interface_
;
675 memcpy(&mreq
.ipv6mr_multiaddr
, &group_address
[0], kIPv6AddressSize
);
676 int rv
= setsockopt(socket_
, IPPROTO_IPV6
, IPV6_JOIN_GROUP
,
677 &mreq
, sizeof(mreq
));
679 return MapSystemError(errno
);
683 NOTREACHED() << "Invalid address family";
684 return ERR_ADDRESS_INVALID
;
688 int UDPSocketLibevent::LeaveGroup(const IPAddressNumber
& group_address
) const {
689 DCHECK(CalledOnValidThread());
692 return ERR_SOCKET_NOT_CONNECTED
;
694 switch (group_address
.size()) {
695 case kIPv4AddressSize
: {
696 if (addr_family_
!= AF_INET
)
697 return ERR_ADDRESS_INVALID
;
699 mreq
.imr_interface
.s_addr
= INADDR_ANY
;
700 memcpy(&mreq
.imr_multiaddr
, &group_address
[0], kIPv4AddressSize
);
701 int rv
= setsockopt(socket_
, IPPROTO_IP
, IP_DROP_MEMBERSHIP
,
702 &mreq
, sizeof(mreq
));
704 return MapSystemError(errno
);
707 case kIPv6AddressSize
: {
708 if (addr_family_
!= AF_INET6
)
709 return ERR_ADDRESS_INVALID
;
711 mreq
.ipv6mr_interface
= 0; // 0 indicates default multicast interface.
712 memcpy(&mreq
.ipv6mr_multiaddr
, &group_address
[0], kIPv6AddressSize
);
713 int rv
= setsockopt(socket_
, IPPROTO_IPV6
, IPV6_LEAVE_GROUP
,
714 &mreq
, sizeof(mreq
));
716 return MapSystemError(errno
);
720 NOTREACHED() << "Invalid address family";
721 return ERR_ADDRESS_INVALID
;
725 int UDPSocketLibevent::SetMulticastInterface(uint32 interface_index
) {
726 DCHECK(CalledOnValidThread());
728 return ERR_SOCKET_IS_CONNECTED
;
729 multicast_interface_
= interface_index
;
733 int UDPSocketLibevent::SetMulticastTimeToLive(int time_to_live
) {
734 DCHECK(CalledOnValidThread());
736 return ERR_SOCKET_IS_CONNECTED
;
738 if (time_to_live
< 0 || time_to_live
> 255)
739 return ERR_INVALID_ARGUMENT
;
740 multicast_time_to_live_
= time_to_live
;
744 int UDPSocketLibevent::SetMulticastLoopbackMode(bool loopback
) {
745 DCHECK(CalledOnValidThread());
747 return ERR_SOCKET_IS_CONNECTED
;
750 socket_options_
|= SOCKET_OPTION_MULTICAST_LOOP
;
752 socket_options_
&= ~SOCKET_OPTION_MULTICAST_LOOP
;
756 int UDPSocketLibevent::SetDiffServCodePoint(DiffServCodePoint dscp
) {
757 if (dscp
== DSCP_NO_CHANGE
) {
761 int dscp_and_ecn
= dscp
<< 2;
762 if (addr_family_
== AF_INET
) {
763 rv
= setsockopt(socket_
, IPPROTO_IP
, IP_TOS
,
764 &dscp_and_ecn
, sizeof(dscp_and_ecn
));
766 rv
= setsockopt(socket_
, IPPROTO_IPV6
, IPV6_TCLASS
,
767 &dscp_and_ecn
, sizeof(dscp_and_ecn
));
770 return MapSystemError(errno
);
775 void UDPSocketLibevent::DetachFromThread() {
776 base::NonThreadSafe::DetachFromThread();