Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / net / udp / udp_socket_posix.cc
blob3b60bf214cc1f306146f90076a72f768eb15ad9d
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_posix.h"
7 #include <errno.h>
8 #include <fcntl.h>
9 #include <net/if.h>
10 #include <netdb.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_util.h"
26 #include "net/base/network_activity_monitor.h"
27 #include "net/log/net_log.h"
28 #include "net/socket/socket_descriptor.h"
29 #include "net/udp/udp_net_log_parameters.h"
32 namespace net {
34 namespace {
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){
44 if (!index) {
45 *address = htonl(INADDR_ANY);
46 return OK;
48 ifreq ifr;
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);
53 if (rv == -1)
54 return MapSystemError(errno);
55 *address = reinterpret_cast<sockaddr_in*>(&ifr.ifr_addr)->sin_addr.s_addr;
56 return OK;
59 #endif // OS_MACOSX
61 } // namespace
63 UDPSocketPosix::UDPSocketPosix(DatagramSocket::BindType bind_type,
64 const RandIntCallback& rand_int_cb,
65 net::NetLog* net_log,
66 const net::NetLog::Source& source)
67 : socket_(kInvalidSocket),
68 addr_family_(0),
69 is_connected_(false),
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),
75 read_watcher_(this),
76 write_watcher_(this),
77 read_buf_len_(0),
78 recv_from_address_(NULL),
79 write_buf_len_(0),
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 UDPSocketPosix::~UDPSocketPosix() {
88 Close();
89 net_log_.EndEvent(NetLog::TYPE_SOCKET_ALIVE);
92 int UDPSocketPosix::Open(AddressFamily address_family) {
93 DCHECK(CalledOnValidThread());
94 DCHECK_EQ(socket_, kInvalidSocket);
96 addr_family_ = ConvertAddressFamily(address_family);
97 socket_ = CreatePlatformSocket(addr_family_, SOCK_DGRAM, 0);
98 if (socket_ == kInvalidSocket)
99 return MapSystemError(errno);
100 if (SetNonBlocking(socket_)) {
101 const int err = MapSystemError(errno);
102 Close();
103 return err;
105 return OK;
108 void UDPSocketPosix::Close() {
109 DCHECK(CalledOnValidThread());
111 if (socket_ == kInvalidSocket)
112 return;
114 // Zero out any pending read/write callback state.
115 read_buf_ = NULL;
116 read_buf_len_ = 0;
117 read_callback_.Reset();
118 recv_from_address_ = NULL;
119 write_buf_ = NULL;
120 write_buf_len_ = 0;
121 write_callback_.Reset();
122 send_to_address_.reset();
124 bool ok = read_socket_watcher_.StopWatchingFileDescriptor();
125 DCHECK(ok);
126 ok = write_socket_watcher_.StopWatchingFileDescriptor();
127 DCHECK(ok);
129 PCHECK(IGNORE_EINTR(close(socket_)) == 0);
131 socket_ = kInvalidSocket;
132 addr_family_ = 0;
133 is_connected_ = false;
136 int UDPSocketPosix::GetPeerAddress(IPEndPoint* address) const {
137 DCHECK(CalledOnValidThread());
138 DCHECK(address);
139 if (!is_connected())
140 return ERR_SOCKET_NOT_CONNECTED;
142 if (!remote_address_.get()) {
143 SockaddrStorage storage;
144 if (getpeername(socket_, storage.addr, &storage.addr_len))
145 return MapSystemError(errno);
146 scoped_ptr<IPEndPoint> address(new IPEndPoint());
147 if (!address->FromSockAddr(storage.addr, storage.addr_len))
148 return ERR_ADDRESS_INVALID;
149 remote_address_.reset(address.release());
152 *address = *remote_address_;
153 return OK;
156 int UDPSocketPosix::GetLocalAddress(IPEndPoint* address) const {
157 DCHECK(CalledOnValidThread());
158 DCHECK(address);
159 if (!is_connected())
160 return ERR_SOCKET_NOT_CONNECTED;
162 if (!local_address_.get()) {
163 SockaddrStorage storage;
164 if (getsockname(socket_, storage.addr, &storage.addr_len))
165 return MapSystemError(errno);
166 scoped_ptr<IPEndPoint> address(new IPEndPoint());
167 if (!address->FromSockAddr(storage.addr, storage.addr_len))
168 return ERR_ADDRESS_INVALID;
169 local_address_.reset(address.release());
170 net_log_.AddEvent(NetLog::TYPE_UDP_LOCAL_ADDRESS,
171 CreateNetLogUDPConnectCallback(local_address_.get()));
174 *address = *local_address_;
175 return OK;
178 int UDPSocketPosix::Read(IOBuffer* buf,
179 int buf_len,
180 const CompletionCallback& callback) {
181 return RecvFrom(buf, buf_len, NULL, callback);
184 int UDPSocketPosix::RecvFrom(IOBuffer* buf,
185 int buf_len,
186 IPEndPoint* address,
187 const CompletionCallback& callback) {
188 DCHECK(CalledOnValidThread());
189 DCHECK_NE(kInvalidSocket, socket_);
190 CHECK(read_callback_.is_null());
191 DCHECK(!recv_from_address_);
192 DCHECK(!callback.is_null()); // Synchronous operation not supported
193 DCHECK_GT(buf_len, 0);
195 int nread = InternalRecvFrom(buf, buf_len, address);
196 if (nread != ERR_IO_PENDING)
197 return nread;
199 if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
200 socket_, true, base::MessageLoopForIO::WATCH_READ,
201 &read_socket_watcher_, &read_watcher_)) {
202 PLOG(ERROR) << "WatchFileDescriptor failed on read";
203 int result = MapSystemError(errno);
204 LogRead(result, NULL, 0, NULL);
205 return result;
208 read_buf_ = buf;
209 read_buf_len_ = buf_len;
210 recv_from_address_ = address;
211 read_callback_ = callback;
212 return ERR_IO_PENDING;
215 int UDPSocketPosix::Write(IOBuffer* buf,
216 int buf_len,
217 const CompletionCallback& callback) {
218 return SendToOrWrite(buf, buf_len, NULL, callback);
221 int UDPSocketPosix::SendTo(IOBuffer* buf,
222 int buf_len,
223 const IPEndPoint& address,
224 const CompletionCallback& callback) {
225 return SendToOrWrite(buf, buf_len, &address, callback);
228 int UDPSocketPosix::SendToOrWrite(IOBuffer* buf,
229 int buf_len,
230 const IPEndPoint* address,
231 const CompletionCallback& callback) {
232 DCHECK(CalledOnValidThread());
233 DCHECK_NE(kInvalidSocket, socket_);
234 CHECK(write_callback_.is_null());
235 DCHECK(!callback.is_null()); // Synchronous operation not supported
236 DCHECK_GT(buf_len, 0);
238 int result = InternalSendTo(buf, buf_len, address);
239 if (result != ERR_IO_PENDING)
240 return result;
242 if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
243 socket_, true, base::MessageLoopForIO::WATCH_WRITE,
244 &write_socket_watcher_, &write_watcher_)) {
245 DVLOG(1) << "WatchFileDescriptor failed on write, errno " << errno;
246 int result = MapSystemError(errno);
247 LogWrite(result, NULL, NULL);
248 return result;
251 write_buf_ = buf;
252 write_buf_len_ = buf_len;
253 DCHECK(!send_to_address_.get());
254 if (address) {
255 send_to_address_.reset(new IPEndPoint(*address));
257 write_callback_ = callback;
258 return ERR_IO_PENDING;
261 int UDPSocketPosix::Connect(const IPEndPoint& address) {
262 DCHECK_NE(socket_, kInvalidSocket);
263 net_log_.BeginEvent(NetLog::TYPE_UDP_CONNECT,
264 CreateNetLogUDPConnectCallback(&address));
265 int rv = InternalConnect(address);
266 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_UDP_CONNECT, rv);
267 is_connected_ = (rv == OK);
268 return rv;
271 int UDPSocketPosix::InternalConnect(const IPEndPoint& address) {
272 DCHECK(CalledOnValidThread());
273 DCHECK(!is_connected());
274 DCHECK(!remote_address_.get());
276 int rv = 0;
277 if (bind_type_ == DatagramSocket::RANDOM_BIND) {
278 // Construct IPAddressNumber of appropriate size (IPv4 or IPv6) of 0s,
279 // representing INADDR_ANY or in6addr_any.
280 size_t addr_size = address.GetSockAddrFamily() == AF_INET ?
281 kIPv4AddressSize : kIPv6AddressSize;
282 IPAddressNumber addr_any(addr_size);
283 rv = RandomBind(addr_any);
285 // else connect() does the DatagramSocket::DEFAULT_BIND
287 if (rv < 0) {
288 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.UdpSocketRandomBindErrorCode", -rv);
289 return rv;
292 SockaddrStorage storage;
293 if (!address.ToSockAddr(storage.addr, &storage.addr_len))
294 return ERR_ADDRESS_INVALID;
296 rv = HANDLE_EINTR(connect(socket_, storage.addr, storage.addr_len));
297 if (rv < 0)
298 return MapSystemError(errno);
300 remote_address_.reset(new IPEndPoint(address));
301 return rv;
304 int UDPSocketPosix::Bind(const IPEndPoint& address) {
305 DCHECK_NE(socket_, kInvalidSocket);
306 DCHECK(CalledOnValidThread());
307 DCHECK(!is_connected());
309 int rv = SetMulticastOptions();
310 if (rv < 0)
311 return rv;
313 rv = DoBind(address);
314 if (rv < 0)
315 return rv;
317 is_connected_ = true;
318 local_address_.reset();
319 return rv;
322 int UDPSocketPosix::SetReceiveBufferSize(int32 size) {
323 DCHECK_NE(socket_, kInvalidSocket);
324 DCHECK(CalledOnValidThread());
325 int rv = setsockopt(socket_, SOL_SOCKET, SO_RCVBUF,
326 reinterpret_cast<const char*>(&size), sizeof(size));
327 return rv == 0 ? OK : MapSystemError(errno);
330 int UDPSocketPosix::SetSendBufferSize(int32 size) {
331 DCHECK_NE(socket_, kInvalidSocket);
332 DCHECK(CalledOnValidThread());
333 int rv = setsockopt(socket_, SOL_SOCKET, SO_SNDBUF,
334 reinterpret_cast<const char*>(&size), sizeof(size));
335 return rv == 0 ? OK : MapSystemError(errno);
338 int UDPSocketPosix::AllowAddressReuse() {
339 DCHECK_NE(socket_, kInvalidSocket);
340 DCHECK(CalledOnValidThread());
341 DCHECK(!is_connected());
342 int true_value = 1;
343 int rv = setsockopt(
344 socket_, SOL_SOCKET, SO_REUSEADDR, &true_value, sizeof(true_value));
345 return rv == 0 ? OK : MapSystemError(errno);
348 int UDPSocketPosix::SetBroadcast(bool broadcast) {
349 DCHECK_NE(socket_, kInvalidSocket);
350 DCHECK(CalledOnValidThread());
351 int value = broadcast ? 1 : 0;
352 int rv;
353 #if defined(OS_MACOSX)
354 // SO_REUSEPORT on OSX permits multiple processes to each receive
355 // UDP multicast or broadcast datagrams destined for the bound
356 // port.
357 rv = setsockopt(socket_, SOL_SOCKET, SO_REUSEPORT, &value, sizeof(value));
358 #else
359 rv = setsockopt(socket_, SOL_SOCKET, SO_BROADCAST, &value, sizeof(value));
360 #endif // defined(OS_MACOSX)
361 return rv == 0 ? OK : MapSystemError(errno);
364 void UDPSocketPosix::ReadWatcher::OnFileCanReadWithoutBlocking(int) {
365 if (!socket_->read_callback_.is_null())
366 socket_->DidCompleteRead();
369 void UDPSocketPosix::WriteWatcher::OnFileCanWriteWithoutBlocking(int) {
370 if (!socket_->write_callback_.is_null())
371 socket_->DidCompleteWrite();
374 void UDPSocketPosix::DoReadCallback(int rv) {
375 DCHECK_NE(rv, ERR_IO_PENDING);
376 DCHECK(!read_callback_.is_null());
378 // since Run may result in Read being called, clear read_callback_ up front.
379 CompletionCallback c = read_callback_;
380 read_callback_.Reset();
381 c.Run(rv);
384 void UDPSocketPosix::DoWriteCallback(int rv) {
385 DCHECK_NE(rv, ERR_IO_PENDING);
386 DCHECK(!write_callback_.is_null());
388 // since Run may result in Write being called, clear write_callback_ up front.
389 CompletionCallback c = write_callback_;
390 write_callback_.Reset();
391 c.Run(rv);
394 void UDPSocketPosix::DidCompleteRead() {
395 int result =
396 InternalRecvFrom(read_buf_.get(), read_buf_len_, recv_from_address_);
397 if (result != ERR_IO_PENDING) {
398 read_buf_ = NULL;
399 read_buf_len_ = 0;
400 recv_from_address_ = NULL;
401 bool ok = read_socket_watcher_.StopWatchingFileDescriptor();
402 DCHECK(ok);
403 DoReadCallback(result);
407 void UDPSocketPosix::LogRead(int result,
408 const char* bytes,
409 socklen_t addr_len,
410 const sockaddr* addr) const {
411 if (result < 0) {
412 net_log_.AddEventWithNetErrorCode(NetLog::TYPE_UDP_RECEIVE_ERROR, result);
413 return;
416 if (net_log_.IsCapturing()) {
417 DCHECK(addr_len > 0);
418 DCHECK(addr);
420 IPEndPoint address;
421 bool is_address_valid = address.FromSockAddr(addr, addr_len);
422 net_log_.AddEvent(
423 NetLog::TYPE_UDP_BYTES_RECEIVED,
424 CreateNetLogUDPDataTranferCallback(
425 result, bytes,
426 is_address_valid ? &address : NULL));
429 NetworkActivityMonitor::GetInstance()->IncrementBytesReceived(result);
432 void UDPSocketPosix::DidCompleteWrite() {
433 int result =
434 InternalSendTo(write_buf_.get(), write_buf_len_, send_to_address_.get());
436 if (result != ERR_IO_PENDING) {
437 write_buf_ = NULL;
438 write_buf_len_ = 0;
439 send_to_address_.reset();
440 write_socket_watcher_.StopWatchingFileDescriptor();
441 DoWriteCallback(result);
445 void UDPSocketPosix::LogWrite(int result,
446 const char* bytes,
447 const IPEndPoint* address) const {
448 if (result < 0) {
449 net_log_.AddEventWithNetErrorCode(NetLog::TYPE_UDP_SEND_ERROR, result);
450 return;
453 if (net_log_.IsCapturing()) {
454 net_log_.AddEvent(
455 NetLog::TYPE_UDP_BYTES_SENT,
456 CreateNetLogUDPDataTranferCallback(result, bytes, address));
459 NetworkActivityMonitor::GetInstance()->IncrementBytesSent(result);
462 int UDPSocketPosix::InternalRecvFrom(IOBuffer* buf,
463 int buf_len,
464 IPEndPoint* address) {
465 int bytes_transferred;
466 int flags = 0;
468 SockaddrStorage storage;
470 bytes_transferred =
471 HANDLE_EINTR(recvfrom(socket_,
472 buf->data(),
473 buf_len,
474 flags,
475 storage.addr,
476 &storage.addr_len));
477 int result;
478 if (bytes_transferred >= 0) {
479 result = bytes_transferred;
480 if (address && !address->FromSockAddr(storage.addr, storage.addr_len))
481 result = ERR_ADDRESS_INVALID;
482 } else {
483 result = MapSystemError(errno);
485 if (result != ERR_IO_PENDING)
486 LogRead(result, buf->data(), storage.addr_len, storage.addr);
487 return result;
490 int UDPSocketPosix::InternalSendTo(IOBuffer* buf,
491 int buf_len,
492 const IPEndPoint* address) {
493 SockaddrStorage storage;
494 struct sockaddr* addr = storage.addr;
495 if (!address) {
496 addr = NULL;
497 storage.addr_len = 0;
498 } else {
499 if (!address->ToSockAddr(storage.addr, &storage.addr_len)) {
500 int result = ERR_ADDRESS_INVALID;
501 LogWrite(result, NULL, NULL);
502 return result;
506 int result = HANDLE_EINTR(sendto(socket_,
507 buf->data(),
508 buf_len,
510 addr,
511 storage.addr_len));
512 if (result < 0)
513 result = MapSystemError(errno);
514 if (result != ERR_IO_PENDING)
515 LogWrite(result, buf->data(), address);
516 return result;
519 int UDPSocketPosix::SetMulticastOptions() {
520 if (!(socket_options_ & SOCKET_OPTION_MULTICAST_LOOP)) {
521 int rv;
522 if (addr_family_ == AF_INET) {
523 u_char loop = 0;
524 rv = setsockopt(socket_, IPPROTO_IP, IP_MULTICAST_LOOP,
525 &loop, sizeof(loop));
526 } else {
527 u_int loop = 0;
528 rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
529 &loop, sizeof(loop));
531 if (rv < 0)
532 return MapSystemError(errno);
534 if (multicast_time_to_live_ != IP_DEFAULT_MULTICAST_TTL) {
535 int rv;
536 if (addr_family_ == AF_INET) {
537 u_char ttl = multicast_time_to_live_;
538 rv = setsockopt(socket_, IPPROTO_IP, IP_MULTICAST_TTL,
539 &ttl, sizeof(ttl));
540 } else {
541 // Signed integer. -1 to use route default.
542 int ttl = multicast_time_to_live_;
543 rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
544 &ttl, sizeof(ttl));
546 if (rv < 0)
547 return MapSystemError(errno);
549 if (multicast_interface_ != 0) {
550 switch (addr_family_) {
551 case AF_INET: {
552 #if !defined(OS_MACOSX)
553 ip_mreqn mreq;
554 mreq.imr_ifindex = multicast_interface_;
555 mreq.imr_address.s_addr = htonl(INADDR_ANY);
556 #else
557 ip_mreq mreq;
558 int error = GetIPv4AddressFromIndex(socket_, multicast_interface_,
559 &mreq.imr_interface.s_addr);
560 if (error != OK)
561 return error;
562 #endif
563 int rv = setsockopt(socket_, IPPROTO_IP, IP_MULTICAST_IF,
564 reinterpret_cast<const char*>(&mreq), sizeof(mreq));
565 if (rv)
566 return MapSystemError(errno);
567 break;
569 case AF_INET6: {
570 uint32 interface_index = multicast_interface_;
571 int rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_MULTICAST_IF,
572 reinterpret_cast<const char*>(&interface_index),
573 sizeof(interface_index));
574 if (rv)
575 return MapSystemError(errno);
576 break;
578 default:
579 NOTREACHED() << "Invalid address family";
580 return ERR_ADDRESS_INVALID;
583 return OK;
586 int UDPSocketPosix::DoBind(const IPEndPoint& address) {
587 SockaddrStorage storage;
588 if (!address.ToSockAddr(storage.addr, &storage.addr_len))
589 return ERR_ADDRESS_INVALID;
590 int rv = bind(socket_, storage.addr, storage.addr_len);
591 if (rv == 0)
592 return OK;
593 int last_error = errno;
594 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.UdpSocketBindErrorFromPosix", last_error);
595 #if defined(OS_CHROMEOS)
596 if (last_error == EINVAL)
597 return ERR_ADDRESS_IN_USE;
598 #elif defined(OS_MACOSX)
599 if (last_error == EADDRNOTAVAIL)
600 return ERR_ADDRESS_IN_USE;
601 #endif
602 return MapSystemError(last_error);
605 int UDPSocketPosix::RandomBind(const IPAddressNumber& address) {
606 DCHECK(bind_type_ == DatagramSocket::RANDOM_BIND && !rand_int_cb_.is_null());
608 for (int i = 0; i < kBindRetries; ++i) {
609 int rv = DoBind(IPEndPoint(address,
610 rand_int_cb_.Run(kPortStart, kPortEnd)));
611 if (rv == OK || rv != ERR_ADDRESS_IN_USE)
612 return rv;
614 return DoBind(IPEndPoint(address, 0));
617 int UDPSocketPosix::JoinGroup(const IPAddressNumber& group_address) const {
618 DCHECK(CalledOnValidThread());
619 if (!is_connected())
620 return ERR_SOCKET_NOT_CONNECTED;
622 switch (group_address.size()) {
623 case kIPv4AddressSize: {
624 if (addr_family_ != AF_INET)
625 return ERR_ADDRESS_INVALID;
627 #if !defined(OS_MACOSX)
628 ip_mreqn mreq;
629 mreq.imr_ifindex = multicast_interface_;
630 mreq.imr_address.s_addr = htonl(INADDR_ANY);
631 #else
632 ip_mreq mreq;
633 int error = GetIPv4AddressFromIndex(socket_, multicast_interface_,
634 &mreq.imr_interface.s_addr);
635 if (error != OK)
636 return error;
637 #endif
638 memcpy(&mreq.imr_multiaddr, &group_address[0], kIPv4AddressSize);
639 int rv = setsockopt(socket_, IPPROTO_IP, IP_ADD_MEMBERSHIP,
640 &mreq, sizeof(mreq));
641 if (rv < 0)
642 return MapSystemError(errno);
643 return OK;
645 case kIPv6AddressSize: {
646 if (addr_family_ != AF_INET6)
647 return ERR_ADDRESS_INVALID;
648 ipv6_mreq mreq;
649 mreq.ipv6mr_interface = multicast_interface_;
650 memcpy(&mreq.ipv6mr_multiaddr, &group_address[0], kIPv6AddressSize);
651 int rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_JOIN_GROUP,
652 &mreq, sizeof(mreq));
653 if (rv < 0)
654 return MapSystemError(errno);
655 return OK;
657 default:
658 NOTREACHED() << "Invalid address family";
659 return ERR_ADDRESS_INVALID;
663 int UDPSocketPosix::LeaveGroup(const IPAddressNumber& group_address) const {
664 DCHECK(CalledOnValidThread());
666 if (!is_connected())
667 return ERR_SOCKET_NOT_CONNECTED;
669 switch (group_address.size()) {
670 case kIPv4AddressSize: {
671 if (addr_family_ != AF_INET)
672 return ERR_ADDRESS_INVALID;
673 ip_mreq mreq;
674 mreq.imr_interface.s_addr = INADDR_ANY;
675 memcpy(&mreq.imr_multiaddr, &group_address[0], kIPv4AddressSize);
676 int rv = setsockopt(socket_, IPPROTO_IP, IP_DROP_MEMBERSHIP,
677 &mreq, sizeof(mreq));
678 if (rv < 0)
679 return MapSystemError(errno);
680 return OK;
682 case kIPv6AddressSize: {
683 if (addr_family_ != AF_INET6)
684 return ERR_ADDRESS_INVALID;
685 ipv6_mreq mreq;
686 mreq.ipv6mr_interface = 0; // 0 indicates default multicast interface.
687 memcpy(&mreq.ipv6mr_multiaddr, &group_address[0], kIPv6AddressSize);
688 int rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
689 &mreq, sizeof(mreq));
690 if (rv < 0)
691 return MapSystemError(errno);
692 return OK;
694 default:
695 NOTREACHED() << "Invalid address family";
696 return ERR_ADDRESS_INVALID;
700 int UDPSocketPosix::SetMulticastInterface(uint32 interface_index) {
701 DCHECK(CalledOnValidThread());
702 if (is_connected())
703 return ERR_SOCKET_IS_CONNECTED;
704 multicast_interface_ = interface_index;
705 return OK;
708 int UDPSocketPosix::SetMulticastTimeToLive(int time_to_live) {
709 DCHECK(CalledOnValidThread());
710 if (is_connected())
711 return ERR_SOCKET_IS_CONNECTED;
713 if (time_to_live < 0 || time_to_live > 255)
714 return ERR_INVALID_ARGUMENT;
715 multicast_time_to_live_ = time_to_live;
716 return OK;
719 int UDPSocketPosix::SetMulticastLoopbackMode(bool loopback) {
720 DCHECK(CalledOnValidThread());
721 if (is_connected())
722 return ERR_SOCKET_IS_CONNECTED;
724 if (loopback)
725 socket_options_ |= SOCKET_OPTION_MULTICAST_LOOP;
726 else
727 socket_options_ &= ~SOCKET_OPTION_MULTICAST_LOOP;
728 return OK;
731 int UDPSocketPosix::SetDiffServCodePoint(DiffServCodePoint dscp) {
732 if (dscp == DSCP_NO_CHANGE) {
733 return OK;
735 int rv;
736 int dscp_and_ecn = dscp << 2;
737 if (addr_family_ == AF_INET) {
738 rv = setsockopt(socket_, IPPROTO_IP, IP_TOS,
739 &dscp_and_ecn, sizeof(dscp_and_ecn));
740 } else {
741 rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_TCLASS,
742 &dscp_and_ecn, sizeof(dscp_and_ecn));
744 if (rv < 0)
745 return MapSystemError(errno);
747 return OK;
750 void UDPSocketPosix::DetachFromThread() {
751 base::NonThreadSafe::DetachFromThread();
754 } // namespace net