OLD | NEW |
| (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 <net/if.h> | |
10 #include <netdb.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/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" | |
30 | |
31 | |
32 namespace net { | |
33 | |
34 namespace { | |
35 | |
36 const int kBindRetries = 10; | |
37 const int kPortStart = 1024; | |
38 const int kPortEnd = 65535; | |
39 | |
40 #if defined(OS_MACOSX) | |
41 | |
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; | |
47 } | |
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; | |
57 } | |
58 | |
59 #endif // OS_MACOSX | |
60 | |
61 } // namespace | |
62 | |
63 UDPSocketLibevent::UDPSocketLibevent( | |
64 DatagramSocket::BindType bind_type, | |
65 const RandIntCallback& rand_int_cb, | |
66 net::NetLog* net_log, | |
67 const net::NetLog::Source& source) | |
68 : socket_(kInvalidSocket), | |
69 addr_family_(0), | |
70 is_connected_(false), | |
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), | |
76 read_watcher_(this), | |
77 write_watcher_(this), | |
78 read_buf_len_(0), | |
79 recv_from_address_(NULL), | |
80 write_buf_len_(0), | |
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()); | |
86 } | |
87 | |
88 UDPSocketLibevent::~UDPSocketLibevent() { | |
89 Close(); | |
90 net_log_.EndEvent(NetLog::TYPE_SOCKET_ALIVE); | |
91 } | |
92 | |
93 int UDPSocketLibevent::Open(AddressFamily address_family) { | |
94 DCHECK(CalledOnValidThread()); | |
95 DCHECK_EQ(socket_, kInvalidSocket); | |
96 | |
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); | |
103 Close(); | |
104 return err; | |
105 } | |
106 return OK; | |
107 } | |
108 | |
109 void UDPSocketLibevent::Close() { | |
110 DCHECK(CalledOnValidThread()); | |
111 | |
112 if (socket_ == kInvalidSocket) | |
113 return; | |
114 | |
115 // Zero out any pending read/write callback state. | |
116 read_buf_ = NULL; | |
117 read_buf_len_ = 0; | |
118 read_callback_.Reset(); | |
119 recv_from_address_ = NULL; | |
120 write_buf_ = NULL; | |
121 write_buf_len_ = 0; | |
122 write_callback_.Reset(); | |
123 send_to_address_.reset(); | |
124 | |
125 bool ok = read_socket_watcher_.StopWatchingFileDescriptor(); | |
126 DCHECK(ok); | |
127 ok = write_socket_watcher_.StopWatchingFileDescriptor(); | |
128 DCHECK(ok); | |
129 | |
130 PCHECK(IGNORE_EINTR(close(socket_)) == 0); | |
131 | |
132 socket_ = kInvalidSocket; | |
133 addr_family_ = 0; | |
134 is_connected_ = false; | |
135 } | |
136 | |
137 int UDPSocketLibevent::GetPeerAddress(IPEndPoint* address) const { | |
138 DCHECK(CalledOnValidThread()); | |
139 DCHECK(address); | |
140 if (!is_connected()) | |
141 return ERR_SOCKET_NOT_CONNECTED; | |
142 | |
143 if (!remote_address_.get()) { | |
144 SockaddrStorage storage; | |
145 if (getpeername(socket_, storage.addr, &storage.addr_len)) | |
146 return MapSystemError(errno); | |
147 scoped_ptr<IPEndPoint> address(new IPEndPoint()); | |
148 if (!address->FromSockAddr(storage.addr, storage.addr_len)) | |
149 return ERR_ADDRESS_INVALID; | |
150 remote_address_.reset(address.release()); | |
151 } | |
152 | |
153 *address = *remote_address_; | |
154 return OK; | |
155 } | |
156 | |
157 int UDPSocketLibevent::GetLocalAddress(IPEndPoint* address) const { | |
158 DCHECK(CalledOnValidThread()); | |
159 DCHECK(address); | |
160 if (!is_connected()) | |
161 return ERR_SOCKET_NOT_CONNECTED; | |
162 | |
163 if (!local_address_.get()) { | |
164 SockaddrStorage storage; | |
165 if (getsockname(socket_, storage.addr, &storage.addr_len)) | |
166 return MapSystemError(errno); | |
167 scoped_ptr<IPEndPoint> address(new IPEndPoint()); | |
168 if (!address->FromSockAddr(storage.addr, storage.addr_len)) | |
169 return ERR_ADDRESS_INVALID; | |
170 local_address_.reset(address.release()); | |
171 net_log_.AddEvent(NetLog::TYPE_UDP_LOCAL_ADDRESS, | |
172 CreateNetLogUDPConnectCallback(local_address_.get())); | |
173 } | |
174 | |
175 *address = *local_address_; | |
176 return OK; | |
177 } | |
178 | |
179 int UDPSocketLibevent::Read(IOBuffer* buf, | |
180 int buf_len, | |
181 const CompletionCallback& callback) { | |
182 return RecvFrom(buf, buf_len, NULL, callback); | |
183 } | |
184 | |
185 int UDPSocketLibevent::RecvFrom(IOBuffer* buf, | |
186 int buf_len, | |
187 IPEndPoint* address, | |
188 const CompletionCallback& callback) { | |
189 DCHECK(CalledOnValidThread()); | |
190 DCHECK_NE(kInvalidSocket, socket_); | |
191 CHECK(read_callback_.is_null()); | |
192 DCHECK(!recv_from_address_); | |
193 DCHECK(!callback.is_null()); // Synchronous operation not supported | |
194 DCHECK_GT(buf_len, 0); | |
195 | |
196 int nread = InternalRecvFrom(buf, buf_len, address); | |
197 if (nread != ERR_IO_PENDING) | |
198 return nread; | |
199 | |
200 if (!base::MessageLoopForIO::current()->WatchFileDescriptor( | |
201 socket_, true, base::MessageLoopForIO::WATCH_READ, | |
202 &read_socket_watcher_, &read_watcher_)) { | |
203 PLOG(ERROR) << "WatchFileDescriptor failed on read"; | |
204 int result = MapSystemError(errno); | |
205 LogRead(result, NULL, 0, NULL); | |
206 return result; | |
207 } | |
208 | |
209 read_buf_ = buf; | |
210 read_buf_len_ = buf_len; | |
211 recv_from_address_ = address; | |
212 read_callback_ = callback; | |
213 return ERR_IO_PENDING; | |
214 } | |
215 | |
216 int UDPSocketLibevent::Write(IOBuffer* buf, | |
217 int buf_len, | |
218 const CompletionCallback& callback) { | |
219 return SendToOrWrite(buf, buf_len, NULL, callback); | |
220 } | |
221 | |
222 int UDPSocketLibevent::SendTo(IOBuffer* buf, | |
223 int buf_len, | |
224 const IPEndPoint& address, | |
225 const CompletionCallback& callback) { | |
226 return SendToOrWrite(buf, buf_len, &address, callback); | |
227 } | |
228 | |
229 int UDPSocketLibevent::SendToOrWrite(IOBuffer* buf, | |
230 int buf_len, | |
231 const IPEndPoint* address, | |
232 const CompletionCallback& callback) { | |
233 DCHECK(CalledOnValidThread()); | |
234 DCHECK_NE(kInvalidSocket, socket_); | |
235 CHECK(write_callback_.is_null()); | |
236 DCHECK(!callback.is_null()); // Synchronous operation not supported | |
237 DCHECK_GT(buf_len, 0); | |
238 | |
239 int result = InternalSendTo(buf, buf_len, address); | |
240 if (result != ERR_IO_PENDING) | |
241 return result; | |
242 | |
243 if (!base::MessageLoopForIO::current()->WatchFileDescriptor( | |
244 socket_, true, base::MessageLoopForIO::WATCH_WRITE, | |
245 &write_socket_watcher_, &write_watcher_)) { | |
246 DVLOG(1) << "WatchFileDescriptor failed on write, errno " << errno; | |
247 int result = MapSystemError(errno); | |
248 LogWrite(result, NULL, NULL); | |
249 return result; | |
250 } | |
251 | |
252 write_buf_ = buf; | |
253 write_buf_len_ = buf_len; | |
254 DCHECK(!send_to_address_.get()); | |
255 if (address) { | |
256 send_to_address_.reset(new IPEndPoint(*address)); | |
257 } | |
258 write_callback_ = callback; | |
259 return ERR_IO_PENDING; | |
260 } | |
261 | |
262 int UDPSocketLibevent::Connect(const IPEndPoint& address) { | |
263 DCHECK_NE(socket_, kInvalidSocket); | |
264 net_log_.BeginEvent(NetLog::TYPE_UDP_CONNECT, | |
265 CreateNetLogUDPConnectCallback(&address)); | |
266 int rv = InternalConnect(address); | |
267 net_log_.EndEventWithNetErrorCode(NetLog::TYPE_UDP_CONNECT, rv); | |
268 is_connected_ = (rv == OK); | |
269 return rv; | |
270 } | |
271 | |
272 int UDPSocketLibevent::InternalConnect(const IPEndPoint& address) { | |
273 DCHECK(CalledOnValidThread()); | |
274 DCHECK(!is_connected()); | |
275 DCHECK(!remote_address_.get()); | |
276 | |
277 int rv = 0; | |
278 if (bind_type_ == DatagramSocket::RANDOM_BIND) { | |
279 // Construct IPAddressNumber of appropriate size (IPv4 or IPv6) of 0s, | |
280 // representing INADDR_ANY or in6addr_any. | |
281 size_t addr_size = address.GetSockAddrFamily() == AF_INET ? | |
282 kIPv4AddressSize : kIPv6AddressSize; | |
283 IPAddressNumber addr_any(addr_size); | |
284 rv = RandomBind(addr_any); | |
285 } | |
286 // else connect() does the DatagramSocket::DEFAULT_BIND | |
287 | |
288 if (rv < 0) { | |
289 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.UdpSocketRandomBindErrorCode", -rv); | |
290 return rv; | |
291 } | |
292 | |
293 SockaddrStorage storage; | |
294 if (!address.ToSockAddr(storage.addr, &storage.addr_len)) | |
295 return ERR_ADDRESS_INVALID; | |
296 | |
297 rv = HANDLE_EINTR(connect(socket_, storage.addr, storage.addr_len)); | |
298 if (rv < 0) | |
299 return MapSystemError(errno); | |
300 | |
301 remote_address_.reset(new IPEndPoint(address)); | |
302 return rv; | |
303 } | |
304 | |
305 int UDPSocketLibevent::Bind(const IPEndPoint& address) { | |
306 DCHECK_NE(socket_, kInvalidSocket); | |
307 DCHECK(CalledOnValidThread()); | |
308 DCHECK(!is_connected()); | |
309 | |
310 int rv = SetMulticastOptions(); | |
311 if (rv < 0) | |
312 return rv; | |
313 | |
314 rv = DoBind(address); | |
315 if (rv < 0) | |
316 return rv; | |
317 | |
318 is_connected_ = true; | |
319 local_address_.reset(); | |
320 return rv; | |
321 } | |
322 | |
323 int UDPSocketLibevent::SetReceiveBufferSize(int32 size) { | |
324 DCHECK_NE(socket_, kInvalidSocket); | |
325 DCHECK(CalledOnValidThread()); | |
326 int rv = setsockopt(socket_, SOL_SOCKET, SO_RCVBUF, | |
327 reinterpret_cast<const char*>(&size), sizeof(size)); | |
328 return rv == 0 ? OK : MapSystemError(errno); | |
329 } | |
330 | |
331 int UDPSocketLibevent::SetSendBufferSize(int32 size) { | |
332 DCHECK_NE(socket_, kInvalidSocket); | |
333 DCHECK(CalledOnValidThread()); | |
334 int rv = setsockopt(socket_, SOL_SOCKET, SO_SNDBUF, | |
335 reinterpret_cast<const char*>(&size), sizeof(size)); | |
336 return rv == 0 ? OK : MapSystemError(errno); | |
337 } | |
338 | |
339 int UDPSocketLibevent::AllowAddressReuse() { | |
340 DCHECK_NE(socket_, kInvalidSocket); | |
341 DCHECK(CalledOnValidThread()); | |
342 DCHECK(!is_connected()); | |
343 int true_value = 1; | |
344 int rv = setsockopt( | |
345 socket_, SOL_SOCKET, SO_REUSEADDR, &true_value, sizeof(true_value)); | |
346 return rv == 0 ? OK : MapSystemError(errno); | |
347 } | |
348 | |
349 int UDPSocketLibevent::SetBroadcast(bool broadcast) { | |
350 DCHECK_NE(socket_, kInvalidSocket); | |
351 DCHECK(CalledOnValidThread()); | |
352 int value = broadcast ? 1 : 0; | |
353 int rv; | |
354 #if defined(OS_MACOSX) | |
355 // SO_REUSEPORT on OSX permits multiple processes to each receive | |
356 // UDP multicast or broadcast datagrams destined for the bound | |
357 // port. | |
358 rv = setsockopt(socket_, SOL_SOCKET, SO_REUSEPORT, &value, sizeof(value)); | |
359 #else | |
360 rv = setsockopt(socket_, SOL_SOCKET, SO_BROADCAST, &value, sizeof(value)); | |
361 #endif // defined(OS_MACOSX) | |
362 return rv == 0 ? OK : MapSystemError(errno); | |
363 } | |
364 | |
365 void UDPSocketLibevent::ReadWatcher::OnFileCanReadWithoutBlocking(int) { | |
366 if (!socket_->read_callback_.is_null()) | |
367 socket_->DidCompleteRead(); | |
368 } | |
369 | |
370 void UDPSocketLibevent::WriteWatcher::OnFileCanWriteWithoutBlocking(int) { | |
371 if (!socket_->write_callback_.is_null()) | |
372 socket_->DidCompleteWrite(); | |
373 } | |
374 | |
375 void UDPSocketLibevent::DoReadCallback(int rv) { | |
376 DCHECK_NE(rv, ERR_IO_PENDING); | |
377 DCHECK(!read_callback_.is_null()); | |
378 | |
379 // since Run may result in Read being called, clear read_callback_ up front. | |
380 CompletionCallback c = read_callback_; | |
381 read_callback_.Reset(); | |
382 c.Run(rv); | |
383 } | |
384 | |
385 void UDPSocketLibevent::DoWriteCallback(int rv) { | |
386 DCHECK_NE(rv, ERR_IO_PENDING); | |
387 DCHECK(!write_callback_.is_null()); | |
388 | |
389 // since Run may result in Write being called, clear write_callback_ up front. | |
390 CompletionCallback c = write_callback_; | |
391 write_callback_.Reset(); | |
392 c.Run(rv); | |
393 } | |
394 | |
395 void UDPSocketLibevent::DidCompleteRead() { | |
396 int result = | |
397 InternalRecvFrom(read_buf_.get(), read_buf_len_, recv_from_address_); | |
398 if (result != ERR_IO_PENDING) { | |
399 read_buf_ = NULL; | |
400 read_buf_len_ = 0; | |
401 recv_from_address_ = NULL; | |
402 bool ok = read_socket_watcher_.StopWatchingFileDescriptor(); | |
403 DCHECK(ok); | |
404 DoReadCallback(result); | |
405 } | |
406 } | |
407 | |
408 void UDPSocketLibevent::LogRead(int result, | |
409 const char* bytes, | |
410 socklen_t addr_len, | |
411 const sockaddr* addr) const { | |
412 if (result < 0) { | |
413 net_log_.AddEventWithNetErrorCode(NetLog::TYPE_UDP_RECEIVE_ERROR, result); | |
414 return; | |
415 } | |
416 | |
417 if (net_log_.IsCapturing()) { | |
418 DCHECK(addr_len > 0); | |
419 DCHECK(addr); | |
420 | |
421 IPEndPoint address; | |
422 bool is_address_valid = address.FromSockAddr(addr, addr_len); | |
423 net_log_.AddEvent( | |
424 NetLog::TYPE_UDP_BYTES_RECEIVED, | |
425 CreateNetLogUDPDataTranferCallback( | |
426 result, bytes, | |
427 is_address_valid ? &address : NULL)); | |
428 } | |
429 | |
430 NetworkActivityMonitor::GetInstance()->IncrementBytesReceived(result); | |
431 } | |
432 | |
433 void UDPSocketLibevent::DidCompleteWrite() { | |
434 int result = | |
435 InternalSendTo(write_buf_.get(), write_buf_len_, send_to_address_.get()); | |
436 | |
437 if (result != ERR_IO_PENDING) { | |
438 write_buf_ = NULL; | |
439 write_buf_len_ = 0; | |
440 send_to_address_.reset(); | |
441 write_socket_watcher_.StopWatchingFileDescriptor(); | |
442 DoWriteCallback(result); | |
443 } | |
444 } | |
445 | |
446 void UDPSocketLibevent::LogWrite(int result, | |
447 const char* bytes, | |
448 const IPEndPoint* address) const { | |
449 if (result < 0) { | |
450 net_log_.AddEventWithNetErrorCode(NetLog::TYPE_UDP_SEND_ERROR, result); | |
451 return; | |
452 } | |
453 | |
454 if (net_log_.IsCapturing()) { | |
455 net_log_.AddEvent( | |
456 NetLog::TYPE_UDP_BYTES_SENT, | |
457 CreateNetLogUDPDataTranferCallback(result, bytes, address)); | |
458 } | |
459 | |
460 NetworkActivityMonitor::GetInstance()->IncrementBytesSent(result); | |
461 } | |
462 | |
463 int UDPSocketLibevent::InternalRecvFrom(IOBuffer* buf, int buf_len, | |
464 IPEndPoint* address) { | |
465 int bytes_transferred; | |
466 int flags = 0; | |
467 | |
468 SockaddrStorage storage; | |
469 | |
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); | |
484 } | |
485 if (result != ERR_IO_PENDING) | |
486 LogRead(result, buf->data(), storage.addr_len, storage.addr); | |
487 return result; | |
488 } | |
489 | |
490 int UDPSocketLibevent::InternalSendTo(IOBuffer* buf, int buf_len, | |
491 const IPEndPoint* address) { | |
492 SockaddrStorage storage; | |
493 struct sockaddr* addr = storage.addr; | |
494 if (!address) { | |
495 addr = NULL; | |
496 storage.addr_len = 0; | |
497 } else { | |
498 if (!address->ToSockAddr(storage.addr, &storage.addr_len)) { | |
499 int result = ERR_ADDRESS_INVALID; | |
500 LogWrite(result, NULL, NULL); | |
501 return result; | |
502 } | |
503 } | |
504 | |
505 int result = HANDLE_EINTR(sendto(socket_, | |
506 buf->data(), | |
507 buf_len, | |
508 0, | |
509 addr, | |
510 storage.addr_len)); | |
511 if (result < 0) | |
512 result = MapSystemError(errno); | |
513 if (result != ERR_IO_PENDING) | |
514 LogWrite(result, buf->data(), address); | |
515 return result; | |
516 } | |
517 | |
518 int UDPSocketLibevent::SetMulticastOptions() { | |
519 if (!(socket_options_ & SOCKET_OPTION_MULTICAST_LOOP)) { | |
520 int rv; | |
521 if (addr_family_ == AF_INET) { | |
522 u_char loop = 0; | |
523 rv = setsockopt(socket_, IPPROTO_IP, IP_MULTICAST_LOOP, | |
524 &loop, sizeof(loop)); | |
525 } else { | |
526 u_int loop = 0; | |
527 rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, | |
528 &loop, sizeof(loop)); | |
529 } | |
530 if (rv < 0) | |
531 return MapSystemError(errno); | |
532 } | |
533 if (multicast_time_to_live_ != IP_DEFAULT_MULTICAST_TTL) { | |
534 int rv; | |
535 if (addr_family_ == AF_INET) { | |
536 u_char ttl = multicast_time_to_live_; | |
537 rv = setsockopt(socket_, IPPROTO_IP, IP_MULTICAST_TTL, | |
538 &ttl, sizeof(ttl)); | |
539 } else { | |
540 // Signed integer. -1 to use route default. | |
541 int ttl = multicast_time_to_live_; | |
542 rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, | |
543 &ttl, sizeof(ttl)); | |
544 } | |
545 if (rv < 0) | |
546 return MapSystemError(errno); | |
547 } | |
548 if (multicast_interface_ != 0) { | |
549 switch (addr_family_) { | |
550 case AF_INET: { | |
551 #if !defined(OS_MACOSX) | |
552 ip_mreqn mreq; | |
553 mreq.imr_ifindex = multicast_interface_; | |
554 mreq.imr_address.s_addr = htonl(INADDR_ANY); | |
555 #else | |
556 ip_mreq mreq; | |
557 int error = GetIPv4AddressFromIndex(socket_, multicast_interface_, | |
558 &mreq.imr_interface.s_addr); | |
559 if (error != OK) | |
560 return error; | |
561 #endif | |
562 int rv = setsockopt(socket_, IPPROTO_IP, IP_MULTICAST_IF, | |
563 reinterpret_cast<const char*>(&mreq), sizeof(mreq)); | |
564 if (rv) | |
565 return MapSystemError(errno); | |
566 break; | |
567 } | |
568 case AF_INET6: { | |
569 uint32 interface_index = multicast_interface_; | |
570 int rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_MULTICAST_IF, | |
571 reinterpret_cast<const char*>(&interface_index), | |
572 sizeof(interface_index)); | |
573 if (rv) | |
574 return MapSystemError(errno); | |
575 break; | |
576 } | |
577 default: | |
578 NOTREACHED() << "Invalid address family"; | |
579 return ERR_ADDRESS_INVALID; | |
580 } | |
581 } | |
582 return OK; | |
583 } | |
584 | |
585 int UDPSocketLibevent::DoBind(const IPEndPoint& address) { | |
586 SockaddrStorage storage; | |
587 if (!address.ToSockAddr(storage.addr, &storage.addr_len)) | |
588 return ERR_ADDRESS_INVALID; | |
589 int rv = bind(socket_, storage.addr, storage.addr_len); | |
590 if (rv == 0) | |
591 return OK; | |
592 int last_error = errno; | |
593 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.UdpSocketBindErrorFromPosix", last_error); | |
594 #if defined(OS_CHROMEOS) | |
595 if (last_error == EINVAL) | |
596 return ERR_ADDRESS_IN_USE; | |
597 #elif defined(OS_MACOSX) | |
598 if (last_error == EADDRNOTAVAIL) | |
599 return ERR_ADDRESS_IN_USE; | |
600 #endif | |
601 return MapSystemError(last_error); | |
602 } | |
603 | |
604 int UDPSocketLibevent::RandomBind(const IPAddressNumber& address) { | |
605 DCHECK(bind_type_ == DatagramSocket::RANDOM_BIND && !rand_int_cb_.is_null()); | |
606 | |
607 for (int i = 0; i < kBindRetries; ++i) { | |
608 int rv = DoBind(IPEndPoint(address, | |
609 rand_int_cb_.Run(kPortStart, kPortEnd))); | |
610 if (rv == OK || rv != ERR_ADDRESS_IN_USE) | |
611 return rv; | |
612 } | |
613 return DoBind(IPEndPoint(address, 0)); | |
614 } | |
615 | |
616 int UDPSocketLibevent::JoinGroup(const IPAddressNumber& group_address) const { | |
617 DCHECK(CalledOnValidThread()); | |
618 if (!is_connected()) | |
619 return ERR_SOCKET_NOT_CONNECTED; | |
620 | |
621 switch (group_address.size()) { | |
622 case kIPv4AddressSize: { | |
623 if (addr_family_ != AF_INET) | |
624 return ERR_ADDRESS_INVALID; | |
625 | |
626 #if !defined(OS_MACOSX) | |
627 ip_mreqn mreq; | |
628 mreq.imr_ifindex = multicast_interface_; | |
629 mreq.imr_address.s_addr = htonl(INADDR_ANY); | |
630 #else | |
631 ip_mreq mreq; | |
632 int error = GetIPv4AddressFromIndex(socket_, multicast_interface_, | |
633 &mreq.imr_interface.s_addr); | |
634 if (error != OK) | |
635 return error; | |
636 #endif | |
637 memcpy(&mreq.imr_multiaddr, &group_address[0], kIPv4AddressSize); | |
638 int rv = setsockopt(socket_, IPPROTO_IP, IP_ADD_MEMBERSHIP, | |
639 &mreq, sizeof(mreq)); | |
640 if (rv < 0) | |
641 return MapSystemError(errno); | |
642 return OK; | |
643 } | |
644 case kIPv6AddressSize: { | |
645 if (addr_family_ != AF_INET6) | |
646 return ERR_ADDRESS_INVALID; | |
647 ipv6_mreq mreq; | |
648 mreq.ipv6mr_interface = multicast_interface_; | |
649 memcpy(&mreq.ipv6mr_multiaddr, &group_address[0], kIPv6AddressSize); | |
650 int rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_JOIN_GROUP, | |
651 &mreq, sizeof(mreq)); | |
652 if (rv < 0) | |
653 return MapSystemError(errno); | |
654 return OK; | |
655 } | |
656 default: | |
657 NOTREACHED() << "Invalid address family"; | |
658 return ERR_ADDRESS_INVALID; | |
659 } | |
660 } | |
661 | |
662 int UDPSocketLibevent::LeaveGroup(const IPAddressNumber& group_address) const { | |
663 DCHECK(CalledOnValidThread()); | |
664 | |
665 if (!is_connected()) | |
666 return ERR_SOCKET_NOT_CONNECTED; | |
667 | |
668 switch (group_address.size()) { | |
669 case kIPv4AddressSize: { | |
670 if (addr_family_ != AF_INET) | |
671 return ERR_ADDRESS_INVALID; | |
672 ip_mreq mreq; | |
673 mreq.imr_interface.s_addr = INADDR_ANY; | |
674 memcpy(&mreq.imr_multiaddr, &group_address[0], kIPv4AddressSize); | |
675 int rv = setsockopt(socket_, IPPROTO_IP, IP_DROP_MEMBERSHIP, | |
676 &mreq, sizeof(mreq)); | |
677 if (rv < 0) | |
678 return MapSystemError(errno); | |
679 return OK; | |
680 } | |
681 case kIPv6AddressSize: { | |
682 if (addr_family_ != AF_INET6) | |
683 return ERR_ADDRESS_INVALID; | |
684 ipv6_mreq mreq; | |
685 mreq.ipv6mr_interface = 0; // 0 indicates default multicast interface. | |
686 memcpy(&mreq.ipv6mr_multiaddr, &group_address[0], kIPv6AddressSize); | |
687 int rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_LEAVE_GROUP, | |
688 &mreq, sizeof(mreq)); | |
689 if (rv < 0) | |
690 return MapSystemError(errno); | |
691 return OK; | |
692 } | |
693 default: | |
694 NOTREACHED() << "Invalid address family"; | |
695 return ERR_ADDRESS_INVALID; | |
696 } | |
697 } | |
698 | |
699 int UDPSocketLibevent::SetMulticastInterface(uint32 interface_index) { | |
700 DCHECK(CalledOnValidThread()); | |
701 if (is_connected()) | |
702 return ERR_SOCKET_IS_CONNECTED; | |
703 multicast_interface_ = interface_index; | |
704 return OK; | |
705 } | |
706 | |
707 int UDPSocketLibevent::SetMulticastTimeToLive(int time_to_live) { | |
708 DCHECK(CalledOnValidThread()); | |
709 if (is_connected()) | |
710 return ERR_SOCKET_IS_CONNECTED; | |
711 | |
712 if (time_to_live < 0 || time_to_live > 255) | |
713 return ERR_INVALID_ARGUMENT; | |
714 multicast_time_to_live_ = time_to_live; | |
715 return OK; | |
716 } | |
717 | |
718 int UDPSocketLibevent::SetMulticastLoopbackMode(bool loopback) { | |
719 DCHECK(CalledOnValidThread()); | |
720 if (is_connected()) | |
721 return ERR_SOCKET_IS_CONNECTED; | |
722 | |
723 if (loopback) | |
724 socket_options_ |= SOCKET_OPTION_MULTICAST_LOOP; | |
725 else | |
726 socket_options_ &= ~SOCKET_OPTION_MULTICAST_LOOP; | |
727 return OK; | |
728 } | |
729 | |
730 int UDPSocketLibevent::SetDiffServCodePoint(DiffServCodePoint dscp) { | |
731 if (dscp == DSCP_NO_CHANGE) { | |
732 return OK; | |
733 } | |
734 int rv; | |
735 int dscp_and_ecn = dscp << 2; | |
736 if (addr_family_ == AF_INET) { | |
737 rv = setsockopt(socket_, IPPROTO_IP, IP_TOS, | |
738 &dscp_and_ecn, sizeof(dscp_and_ecn)); | |
739 } else { | |
740 rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_TCLASS, | |
741 &dscp_and_ecn, sizeof(dscp_and_ecn)); | |
742 } | |
743 if (rv < 0) | |
744 return MapSystemError(errno); | |
745 | |
746 return OK; | |
747 } | |
748 | |
749 void UDPSocketLibevent::DetachFromThread() { | |
750 base::NonThreadSafe::DetachFromThread(); | |
751 } | |
752 | |
753 } // namespace net | |
OLD | NEW |