Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(73)

Side by Side Diff: net/udp/udp_socket_libevent.cc

Issue 992733002: Remove //net (except for Android test stuff) and sdch (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « net/udp/udp_socket_libevent.h ('k') | net/udp/udp_socket_perftest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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.
4
5 #include "net/udp/udp_socket_libevent.h"
6
7 #include <errno.h>
8 #include <fcntl.h>
9 #include <netdb.h>
10 #include <net/if.h>
11 #include <netinet/in.h>
12 #include <sys/ioctl.h>
13 #include <sys/socket.h>
14
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/posix/eintr_wrapper.h"
20 #include "base/rand_util.h"
21 #include "net/base/io_buffer.h"
22 #include "net/base/ip_endpoint.h"
23 #include "net/base/net_errors.h"
24 #include "net/base/net_log.h"
25 #include "net/base/net_util.h"
26 #include "net/base/network_activity_monitor.h"
27 #include "net/socket/socket_descriptor.h"
28 #include "net/udp/udp_net_log_parameters.h"
29
30
31 namespace net {
32
33 namespace {
34
35 const int kBindRetries = 10;
36 const int kPortStart = 1024;
37 const int kPortEnd = 65535;
38
39 #if defined(OS_MACOSX)
40
41 // Returns IPv4 address in network order.
42 int GetIPv4AddressFromIndex(int socket, uint32 index, uint32* address){
43 if (!index) {
44 *address = htonl(INADDR_ANY);
45 return OK;
46 }
47 ifreq ifr;
48 ifr.ifr_addr.sa_family = AF_INET;
49 if (!if_indextoname(index, ifr.ifr_name))
50 return MapSystemError(errno);
51 int rv = ioctl(socket, SIOCGIFADDR, &ifr);
52 if (rv == -1)
53 return MapSystemError(errno);
54 *address = reinterpret_cast<sockaddr_in*>(&ifr.ifr_addr)->sin_addr.s_addr;
55 return OK;
56 }
57
58 #endif // OS_MACOSX
59
60 } // namespace
61
62 UDPSocketLibevent::UDPSocketLibevent(
63 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());
85 }
86
87 UDPSocketLibevent::~UDPSocketLibevent() {
88 Close();
89 net_log_.EndEvent(NetLog::TYPE_SOCKET_ALIVE);
90 }
91
92 int UDPSocketLibevent::Open(AddressFamily address_family) {
93 DCHECK(CalledOnValidThread());
94 DCHECK_EQ(socket_, kInvalidSocket);
95
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;
104 }
105 return OK;
106 }
107
108 void UDPSocketLibevent::Close() {
109 DCHECK(CalledOnValidThread());
110
111 if (socket_ == kInvalidSocket)
112 return;
113
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();
123
124 bool ok = read_socket_watcher_.StopWatchingFileDescriptor();
125 DCHECK(ok);
126 ok = write_socket_watcher_.StopWatchingFileDescriptor();
127 DCHECK(ok);
128
129 PCHECK(0 == IGNORE_EINTR(close(socket_)));
130
131 socket_ = kInvalidSocket;
132 addr_family_ = 0;
133 is_connected_ = false;
134 }
135
136 int UDPSocketLibevent::GetPeerAddress(IPEndPoint* address) const {
137 DCHECK(CalledOnValidThread());
138 DCHECK(address);
139 if (!is_connected())
140 return ERR_SOCKET_NOT_CONNECTED;
141
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());
150 }
151
152 *address = *remote_address_;
153 return OK;
154 }
155
156 int UDPSocketLibevent::GetLocalAddress(IPEndPoint* address) const {
157 DCHECK(CalledOnValidThread());
158 DCHECK(address);
159 if (!is_connected())
160 return ERR_SOCKET_NOT_CONNECTED;
161
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()));
172 }
173
174 *address = *local_address_;
175 return OK;
176 }
177
178 int UDPSocketLibevent::Read(IOBuffer* buf,
179 int buf_len,
180 const CompletionCallback& callback) {
181 return RecvFrom(buf, buf_len, NULL, callback);
182 }
183
184 int UDPSocketLibevent::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);
194
195 int nread = InternalRecvFrom(buf, buf_len, address);
196 if (nread != ERR_IO_PENDING)
197 return nread;
198
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;
206 }
207
208 read_buf_ = buf;
209 read_buf_len_ = buf_len;
210 recv_from_address_ = address;
211 read_callback_ = callback;
212 return ERR_IO_PENDING;
213 }
214
215 int UDPSocketLibevent::Write(IOBuffer* buf,
216 int buf_len,
217 const CompletionCallback& callback) {
218 return SendToOrWrite(buf, buf_len, NULL, callback);
219 }
220
221 int UDPSocketLibevent::SendTo(IOBuffer* buf,
222 int buf_len,
223 const IPEndPoint& address,
224 const CompletionCallback& callback) {
225 return SendToOrWrite(buf, buf_len, &address, callback);
226 }
227
228 int UDPSocketLibevent::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);
237
238 int result = InternalSendTo(buf, buf_len, address);
239 if (result != ERR_IO_PENDING)
240 return result;
241
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;
249 }
250
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));
256 }
257 write_callback_ = callback;
258 return ERR_IO_PENDING;
259 }
260
261 int UDPSocketLibevent::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;
269 }
270
271 int UDPSocketLibevent::InternalConnect(const IPEndPoint& address) {
272 DCHECK(CalledOnValidThread());
273 DCHECK(!is_connected());
274 DCHECK(!remote_address_.get());
275
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);
284 }
285 // else connect() does the DatagramSocket::DEFAULT_BIND
286
287 if (rv < 0) {
288 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.UdpSocketRandomBindErrorCode", -rv);
289 return rv;
290 }
291
292 SockaddrStorage storage;
293 if (!address.ToSockAddr(storage.addr, &storage.addr_len))
294 return ERR_ADDRESS_INVALID;
295
296 rv = HANDLE_EINTR(connect(socket_, storage.addr, storage.addr_len));
297 if (rv < 0)
298 return MapSystemError(errno);
299
300 remote_address_.reset(new IPEndPoint(address));
301 return rv;
302 }
303
304 int UDPSocketLibevent::Bind(const IPEndPoint& address) {
305 DCHECK_NE(socket_, kInvalidSocket);
306 DCHECK(CalledOnValidThread());
307 DCHECK(!is_connected());
308
309 int rv = SetMulticastOptions();
310 if (rv < 0)
311 return rv;
312
313 rv = DoBind(address);
314 if (rv < 0)
315 return rv;
316
317 is_connected_ = true;
318 local_address_.reset();
319 return rv;
320 }
321
322 int UDPSocketLibevent::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);
328 }
329
330 int UDPSocketLibevent::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);
336 }
337
338 int UDPSocketLibevent::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);
346 }
347
348 int UDPSocketLibevent::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);
362 }
363
364 void UDPSocketLibevent::ReadWatcher::OnFileCanReadWithoutBlocking(int) {
365 if (!socket_->read_callback_.is_null())
366 socket_->DidCompleteRead();
367 }
368
369 void UDPSocketLibevent::WriteWatcher::OnFileCanWriteWithoutBlocking(int) {
370 if (!socket_->write_callback_.is_null())
371 socket_->DidCompleteWrite();
372 }
373
374 void UDPSocketLibevent::DoReadCallback(int rv) {
375 DCHECK_NE(rv, ERR_IO_PENDING);
376 DCHECK(!read_callback_.is_null());
377
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);
382 }
383
384 void UDPSocketLibevent::DoWriteCallback(int rv) {
385 DCHECK_NE(rv, ERR_IO_PENDING);
386 DCHECK(!write_callback_.is_null());
387
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);
392 }
393
394 void UDPSocketLibevent::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);
404 }
405 }
406
407 void UDPSocketLibevent::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;
414 }
415
416 if (net_log_.IsLogging()) {
417 DCHECK(addr_len > 0);
418 DCHECK(addr);
419
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));
427 }
428
429 NetworkActivityMonitor::GetInstance()->IncrementBytesReceived(result);
430 }
431
432 void UDPSocketLibevent::DidCompleteWrite() {
433 int result =
434 InternalSendTo(write_buf_.get(), write_buf_len_, send_to_address_.get());
435
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);
442 }
443 }
444
445 void UDPSocketLibevent::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;
451 }
452
453 if (net_log_.IsLogging()) {
454 net_log_.AddEvent(
455 NetLog::TYPE_UDP_BYTES_SENT,
456 CreateNetLogUDPDataTranferCallback(result, bytes, address));
457 }
458
459 NetworkActivityMonitor::GetInstance()->IncrementBytesSent(result);
460 }
461
462 int UDPSocketLibevent::InternalRecvFrom(IOBuffer* buf, int buf_len,
463 IPEndPoint* address) {
464 int bytes_transferred;
465 int flags = 0;
466
467 SockaddrStorage storage;
468
469 bytes_transferred =
470 HANDLE_EINTR(recvfrom(socket_,
471 buf->data(),
472 buf_len,
473 flags,
474 storage.addr,
475 &storage.addr_len));
476 int result;
477 if (bytes_transferred >= 0) {
478 result = bytes_transferred;
479 if (address && !address->FromSockAddr(storage.addr, storage.addr_len))
480 result = ERR_ADDRESS_INVALID;
481 } else {
482 result = MapSystemError(errno);
483 }
484 if (result != ERR_IO_PENDING)
485 LogRead(result, buf->data(), storage.addr_len, storage.addr);
486 return result;
487 }
488
489 int UDPSocketLibevent::InternalSendTo(IOBuffer* buf, int buf_len,
490 const IPEndPoint* address) {
491 SockaddrStorage storage;
492 struct sockaddr* addr = storage.addr;
493 if (!address) {
494 addr = NULL;
495 storage.addr_len = 0;
496 } else {
497 if (!address->ToSockAddr(storage.addr, &storage.addr_len)) {
498 int result = ERR_ADDRESS_INVALID;
499 LogWrite(result, NULL, NULL);
500 return result;
501 }
502 }
503
504 int result = HANDLE_EINTR(sendto(socket_,
505 buf->data(),
506 buf_len,
507 0,
508 addr,
509 storage.addr_len));
510 if (result < 0)
511 result = MapSystemError(errno);
512 if (result != ERR_IO_PENDING)
513 LogWrite(result, buf->data(), address);
514 return result;
515 }
516
517 int UDPSocketLibevent::SetMulticastOptions() {
518 if (!(socket_options_ & SOCKET_OPTION_MULTICAST_LOOP)) {
519 int rv;
520 if (addr_family_ == AF_INET) {
521 u_char loop = 0;
522 rv = setsockopt(socket_, IPPROTO_IP, IP_MULTICAST_LOOP,
523 &loop, sizeof(loop));
524 } else {
525 u_int loop = 0;
526 rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
527 &loop, sizeof(loop));
528 }
529 if (rv < 0)
530 return MapSystemError(errno);
531 }
532 if (multicast_time_to_live_ != IP_DEFAULT_MULTICAST_TTL) {
533 int rv;
534 if (addr_family_ == AF_INET) {
535 u_char ttl = multicast_time_to_live_;
536 rv = setsockopt(socket_, IPPROTO_IP, IP_MULTICAST_TTL,
537 &ttl, sizeof(ttl));
538 } else {
539 // Signed integer. -1 to use route default.
540 int ttl = multicast_time_to_live_;
541 rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
542 &ttl, sizeof(ttl));
543 }
544 if (rv < 0)
545 return MapSystemError(errno);
546 }
547 if (multicast_interface_ != 0) {
548 switch (addr_family_) {
549 case AF_INET: {
550 #if !defined(OS_MACOSX)
551 ip_mreqn mreq;
552 mreq.imr_ifindex = multicast_interface_;
553 mreq.imr_address.s_addr = htonl(INADDR_ANY);
554 #else
555 ip_mreq mreq;
556 int error = GetIPv4AddressFromIndex(socket_, multicast_interface_,
557 &mreq.imr_interface.s_addr);
558 if (error != OK)
559 return error;
560 #endif
561 int rv = setsockopt(socket_, IPPROTO_IP, IP_MULTICAST_IF,
562 reinterpret_cast<const char*>(&mreq), sizeof(mreq));
563 if (rv)
564 return MapSystemError(errno);
565 break;
566 }
567 case AF_INET6: {
568 uint32 interface_index = multicast_interface_;
569 int rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_MULTICAST_IF,
570 reinterpret_cast<const char*>(&interface_index),
571 sizeof(interface_index));
572 if (rv)
573 return MapSystemError(errno);
574 break;
575 }
576 default:
577 NOTREACHED() << "Invalid address family";
578 return ERR_ADDRESS_INVALID;
579 }
580 }
581 return OK;
582 }
583
584 int UDPSocketLibevent::DoBind(const IPEndPoint& address) {
585 SockaddrStorage storage;
586 if (!address.ToSockAddr(storage.addr, &storage.addr_len))
587 return ERR_ADDRESS_INVALID;
588 int rv = bind(socket_, storage.addr, storage.addr_len);
589 if (rv == 0)
590 return OK;
591 int last_error = errno;
592 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.UdpSocketBindErrorFromPosix", last_error);
593 #if defined(OS_CHROMEOS)
594 if (last_error == EINVAL)
595 return ERR_ADDRESS_IN_USE;
596 #elif defined(OS_MACOSX)
597 if (last_error == EADDRNOTAVAIL)
598 return ERR_ADDRESS_IN_USE;
599 #endif
600 return MapSystemError(last_error);
601 }
602
603 int UDPSocketLibevent::RandomBind(const IPAddressNumber& address) {
604 DCHECK(bind_type_ == DatagramSocket::RANDOM_BIND && !rand_int_cb_.is_null());
605
606 for (int i = 0; i < kBindRetries; ++i) {
607 int rv = DoBind(IPEndPoint(address,
608 rand_int_cb_.Run(kPortStart, kPortEnd)));
609 if (rv == OK || rv != ERR_ADDRESS_IN_USE)
610 return rv;
611 }
612 return DoBind(IPEndPoint(address, 0));
613 }
614
615 int UDPSocketLibevent::JoinGroup(const IPAddressNumber& group_address) const {
616 DCHECK(CalledOnValidThread());
617 if (!is_connected())
618 return ERR_SOCKET_NOT_CONNECTED;
619
620 switch (group_address.size()) {
621 case kIPv4AddressSize: {
622 if (addr_family_ != AF_INET)
623 return ERR_ADDRESS_INVALID;
624
625 #if !defined(OS_MACOSX)
626 ip_mreqn mreq;
627 mreq.imr_ifindex = multicast_interface_;
628 mreq.imr_address.s_addr = htonl(INADDR_ANY);
629 #else
630 ip_mreq mreq;
631 int error = GetIPv4AddressFromIndex(socket_, multicast_interface_,
632 &mreq.imr_interface.s_addr);
633 if (error != OK)
634 return error;
635 #endif
636 memcpy(&mreq.imr_multiaddr, &group_address[0], kIPv4AddressSize);
637 int rv = setsockopt(socket_, IPPROTO_IP, IP_ADD_MEMBERSHIP,
638 &mreq, sizeof(mreq));
639 if (rv < 0)
640 return MapSystemError(errno);
641 return OK;
642 }
643 case kIPv6AddressSize: {
644 if (addr_family_ != AF_INET6)
645 return ERR_ADDRESS_INVALID;
646 ipv6_mreq mreq;
647 mreq.ipv6mr_interface = multicast_interface_;
648 memcpy(&mreq.ipv6mr_multiaddr, &group_address[0], kIPv6AddressSize);
649 int rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_JOIN_GROUP,
650 &mreq, sizeof(mreq));
651 if (rv < 0)
652 return MapSystemError(errno);
653 return OK;
654 }
655 default:
656 NOTREACHED() << "Invalid address family";
657 return ERR_ADDRESS_INVALID;
658 }
659 }
660
661 int UDPSocketLibevent::LeaveGroup(const IPAddressNumber& group_address) const {
662 DCHECK(CalledOnValidThread());
663
664 if (!is_connected())
665 return ERR_SOCKET_NOT_CONNECTED;
666
667 switch (group_address.size()) {
668 case kIPv4AddressSize: {
669 if (addr_family_ != AF_INET)
670 return ERR_ADDRESS_INVALID;
671 ip_mreq mreq;
672 mreq.imr_interface.s_addr = INADDR_ANY;
673 memcpy(&mreq.imr_multiaddr, &group_address[0], kIPv4AddressSize);
674 int rv = setsockopt(socket_, IPPROTO_IP, IP_DROP_MEMBERSHIP,
675 &mreq, sizeof(mreq));
676 if (rv < 0)
677 return MapSystemError(errno);
678 return OK;
679 }
680 case kIPv6AddressSize: {
681 if (addr_family_ != AF_INET6)
682 return ERR_ADDRESS_INVALID;
683 ipv6_mreq mreq;
684 mreq.ipv6mr_interface = 0; // 0 indicates default multicast interface.
685 memcpy(&mreq.ipv6mr_multiaddr, &group_address[0], kIPv6AddressSize);
686 int rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
687 &mreq, sizeof(mreq));
688 if (rv < 0)
689 return MapSystemError(errno);
690 return OK;
691 }
692 default:
693 NOTREACHED() << "Invalid address family";
694 return ERR_ADDRESS_INVALID;
695 }
696 }
697
698 int UDPSocketLibevent::SetMulticastInterface(uint32 interface_index) {
699 DCHECK(CalledOnValidThread());
700 if (is_connected())
701 return ERR_SOCKET_IS_CONNECTED;
702 multicast_interface_ = interface_index;
703 return OK;
704 }
705
706 int UDPSocketLibevent::SetMulticastTimeToLive(int time_to_live) {
707 DCHECK(CalledOnValidThread());
708 if (is_connected())
709 return ERR_SOCKET_IS_CONNECTED;
710
711 if (time_to_live < 0 || time_to_live > 255)
712 return ERR_INVALID_ARGUMENT;
713 multicast_time_to_live_ = time_to_live;
714 return OK;
715 }
716
717 int UDPSocketLibevent::SetMulticastLoopbackMode(bool loopback) {
718 DCHECK(CalledOnValidThread());
719 if (is_connected())
720 return ERR_SOCKET_IS_CONNECTED;
721
722 if (loopback)
723 socket_options_ |= SOCKET_OPTION_MULTICAST_LOOP;
724 else
725 socket_options_ &= ~SOCKET_OPTION_MULTICAST_LOOP;
726 return OK;
727 }
728
729 int UDPSocketLibevent::SetDiffServCodePoint(DiffServCodePoint dscp) {
730 if (dscp == DSCP_NO_CHANGE) {
731 return OK;
732 }
733 int rv;
734 int dscp_and_ecn = dscp << 2;
735 if (addr_family_ == AF_INET) {
736 rv = setsockopt(socket_, IPPROTO_IP, IP_TOS,
737 &dscp_and_ecn, sizeof(dscp_and_ecn));
738 } else {
739 rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_TCLASS,
740 &dscp_and_ecn, sizeof(dscp_and_ecn));
741 }
742 if (rv < 0)
743 return MapSystemError(errno);
744
745 return OK;
746 }
747
748 void UDPSocketLibevent::DetachFromThread() {
749 base::NonThreadSafe::DetachFromThread();
750 }
751
752 } // namespace net
OLDNEW
« no previous file with comments | « net/udp/udp_socket_libevent.h ('k') | net/udp/udp_socket_perftest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698