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_posix.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/files/file_util.h" | |
18 #include "base/logging.h" | |
19 #include "base/message_loop/message_loop.h" | |
20 #include "base/metrics/histogram_macros.h" | |
21 #include "base/posix/eintr_wrapper.h" | |
22 #include "base/rand_util.h" | |
23 #include "base/trace_event/trace_event.h" | |
24 #include "net/base/io_buffer.h" | |
25 #include "net/base/ip_address.h" | |
26 #include "net/base/ip_endpoint.h" | |
27 #include "net/base/net_errors.h" | |
28 #include "net/base/network_activity_monitor.h" | |
29 #include "net/base/sockaddr_storage.h" | |
30 #include "net/log/net_log.h" | |
31 #include "net/log/net_log_event_type.h" | |
32 #include "net/log/net_log_source.h" | |
33 #include "net/log/net_log_source_type.h" | |
34 #include "net/socket/socket_descriptor.h" | |
35 #include "net/udp/udp_net_log_parameters.h" | |
36 | |
37 #if defined(OS_ANDROID) | |
38 #include <dlfcn.h> | |
39 // This was added in Lollipop to dlfcn.h | |
40 #define RTLD_NOLOAD 4 | |
41 #include "base/android/build_info.h" | |
42 #include "base/native_library.h" | |
43 #include "base/strings/utf_string_conversions.h" | |
44 #endif | |
45 | |
46 namespace net { | |
47 | |
48 namespace { | |
49 | |
50 const int kBindRetries = 10; | |
51 const int kPortStart = 1024; | |
52 const int kPortEnd = 65535; | |
53 | |
54 #if defined(OS_MACOSX) | |
55 | |
56 // Returns IPv4 address in network order. | |
57 int GetIPv4AddressFromIndex(int socket, uint32_t index, uint32_t* address) { | |
58 if (!index) { | |
59 *address = htonl(INADDR_ANY); | |
60 return OK; | |
61 } | |
62 ifreq ifr; | |
63 ifr.ifr_addr.sa_family = AF_INET; | |
64 if (!if_indextoname(index, ifr.ifr_name)) | |
65 return MapSystemError(errno); | |
66 int rv = ioctl(socket, SIOCGIFADDR, &ifr); | |
67 if (rv == -1) | |
68 return MapSystemError(errno); | |
69 *address = reinterpret_cast<sockaddr_in*>(&ifr.ifr_addr)->sin_addr.s_addr; | |
70 return OK; | |
71 } | |
72 | |
73 #endif // OS_MACOSX | |
74 | |
75 } // namespace | |
76 | |
77 UDPSocketPosix::UDPSocketPosix(DatagramSocket::BindType bind_type, | |
78 const RandIntCallback& rand_int_cb, | |
79 net::NetLog* net_log, | |
80 const net::NetLogSource& source) | |
81 : socket_(kInvalidSocket), | |
82 addr_family_(0), | |
83 is_connected_(false), | |
84 socket_options_(SOCKET_OPTION_MULTICAST_LOOP), | |
85 multicast_interface_(0), | |
86 multicast_time_to_live_(1), | |
87 bind_type_(bind_type), | |
88 rand_int_cb_(rand_int_cb), | |
89 read_watcher_(this), | |
90 write_watcher_(this), | |
91 read_buf_len_(0), | |
92 recv_from_address_(NULL), | |
93 write_buf_len_(0), | |
94 net_log_(NetLogWithSource::Make(net_log, NetLogSourceType::UDP_SOCKET)), | |
95 bound_network_(NetworkChangeNotifier::kInvalidNetworkHandle) { | |
96 net_log_.BeginEvent(NetLogEventType::SOCKET_ALIVE, | |
97 source.ToEventParametersCallback()); | |
98 if (bind_type == DatagramSocket::RANDOM_BIND) | |
99 DCHECK(!rand_int_cb.is_null()); | |
100 } | |
101 | |
102 UDPSocketPosix::~UDPSocketPosix() { | |
103 Close(); | |
104 net_log_.EndEvent(NetLogEventType::SOCKET_ALIVE); | |
105 } | |
106 | |
107 int UDPSocketPosix::Open(AddressFamily address_family) { | |
108 DCHECK(CalledOnValidThread()); | |
109 DCHECK_EQ(socket_, kInvalidSocket); | |
110 | |
111 addr_family_ = ConvertAddressFamily(address_family); | |
112 socket_ = CreatePlatformSocket(addr_family_, SOCK_DGRAM, 0); | |
113 if (socket_ == kInvalidSocket) | |
114 return MapSystemError(errno); | |
115 if (!base::SetNonBlocking(socket_)) { | |
116 const int err = MapSystemError(errno); | |
117 Close(); | |
118 return err; | |
119 } | |
120 return OK; | |
121 } | |
122 | |
123 void UDPSocketPosix::Close() { | |
124 DCHECK(CalledOnValidThread()); | |
125 | |
126 if (socket_ == kInvalidSocket) | |
127 return; | |
128 | |
129 // Zero out any pending read/write callback state. | |
130 read_buf_ = NULL; | |
131 read_buf_len_ = 0; | |
132 read_callback_.Reset(); | |
133 recv_from_address_ = NULL; | |
134 write_buf_ = NULL; | |
135 write_buf_len_ = 0; | |
136 write_callback_.Reset(); | |
137 send_to_address_.reset(); | |
138 | |
139 bool ok = read_socket_watcher_.StopWatchingFileDescriptor(); | |
140 DCHECK(ok); | |
141 ok = write_socket_watcher_.StopWatchingFileDescriptor(); | |
142 DCHECK(ok); | |
143 | |
144 PCHECK(IGNORE_EINTR(close(socket_)) == 0); | |
145 | |
146 socket_ = kInvalidSocket; | |
147 addr_family_ = 0; | |
148 is_connected_ = false; | |
149 } | |
150 | |
151 int UDPSocketPosix::GetPeerAddress(IPEndPoint* address) const { | |
152 DCHECK(CalledOnValidThread()); | |
153 DCHECK(address); | |
154 if (!is_connected()) | |
155 return ERR_SOCKET_NOT_CONNECTED; | |
156 | |
157 if (!remote_address_.get()) { | |
158 SockaddrStorage storage; | |
159 if (getpeername(socket_, storage.addr, &storage.addr_len)) | |
160 return MapSystemError(errno); | |
161 std::unique_ptr<IPEndPoint> address(new IPEndPoint()); | |
162 if (!address->FromSockAddr(storage.addr, storage.addr_len)) | |
163 return ERR_ADDRESS_INVALID; | |
164 remote_address_.reset(address.release()); | |
165 } | |
166 | |
167 *address = *remote_address_; | |
168 return OK; | |
169 } | |
170 | |
171 int UDPSocketPosix::GetLocalAddress(IPEndPoint* address) const { | |
172 DCHECK(CalledOnValidThread()); | |
173 DCHECK(address); | |
174 if (!is_connected()) | |
175 return ERR_SOCKET_NOT_CONNECTED; | |
176 | |
177 if (!local_address_.get()) { | |
178 SockaddrStorage storage; | |
179 if (getsockname(socket_, storage.addr, &storage.addr_len)) | |
180 return MapSystemError(errno); | |
181 std::unique_ptr<IPEndPoint> address(new IPEndPoint()); | |
182 if (!address->FromSockAddr(storage.addr, storage.addr_len)) | |
183 return ERR_ADDRESS_INVALID; | |
184 local_address_.reset(address.release()); | |
185 net_log_.AddEvent( | |
186 NetLogEventType::UDP_LOCAL_ADDRESS, | |
187 CreateNetLogUDPConnectCallback(local_address_.get(), bound_network_)); | |
188 } | |
189 | |
190 *address = *local_address_; | |
191 return OK; | |
192 } | |
193 | |
194 int UDPSocketPosix::Read(IOBuffer* buf, | |
195 int buf_len, | |
196 const CompletionCallback& callback) { | |
197 return RecvFrom(buf, buf_len, NULL, callback); | |
198 } | |
199 | |
200 int UDPSocketPosix::RecvFrom(IOBuffer* buf, | |
201 int buf_len, | |
202 IPEndPoint* address, | |
203 const CompletionCallback& callback) { | |
204 DCHECK(CalledOnValidThread()); | |
205 DCHECK_NE(kInvalidSocket, socket_); | |
206 CHECK(read_callback_.is_null()); | |
207 DCHECK(!recv_from_address_); | |
208 DCHECK(!callback.is_null()); // Synchronous operation not supported | |
209 DCHECK_GT(buf_len, 0); | |
210 | |
211 int nread = InternalRecvFrom(buf, buf_len, address); | |
212 if (nread != ERR_IO_PENDING) | |
213 return nread; | |
214 | |
215 if (!base::MessageLoopForIO::current()->WatchFileDescriptor( | |
216 socket_, true, base::MessageLoopForIO::WATCH_READ, | |
217 &read_socket_watcher_, &read_watcher_)) { | |
218 PLOG(ERROR) << "WatchFileDescriptor failed on read"; | |
219 int result = MapSystemError(errno); | |
220 LogRead(result, NULL, 0, NULL); | |
221 return result; | |
222 } | |
223 | |
224 read_buf_ = buf; | |
225 read_buf_len_ = buf_len; | |
226 recv_from_address_ = address; | |
227 read_callback_ = callback; | |
228 return ERR_IO_PENDING; | |
229 } | |
230 | |
231 int UDPSocketPosix::Write(IOBuffer* buf, | |
232 int buf_len, | |
233 const CompletionCallback& callback) { | |
234 return SendToOrWrite(buf, buf_len, NULL, callback); | |
235 } | |
236 | |
237 int UDPSocketPosix::SendTo(IOBuffer* buf, | |
238 int buf_len, | |
239 const IPEndPoint& address, | |
240 const CompletionCallback& callback) { | |
241 return SendToOrWrite(buf, buf_len, &address, callback); | |
242 } | |
243 | |
244 int UDPSocketPosix::SendToOrWrite(IOBuffer* buf, | |
245 int buf_len, | |
246 const IPEndPoint* address, | |
247 const CompletionCallback& callback) { | |
248 DCHECK(CalledOnValidThread()); | |
249 DCHECK_NE(kInvalidSocket, socket_); | |
250 CHECK(write_callback_.is_null()); | |
251 DCHECK(!callback.is_null()); // Synchronous operation not supported | |
252 DCHECK_GT(buf_len, 0); | |
253 | |
254 int result = InternalSendTo(buf, buf_len, address); | |
255 if (result != ERR_IO_PENDING) | |
256 return result; | |
257 | |
258 if (!base::MessageLoopForIO::current()->WatchFileDescriptor( | |
259 socket_, true, base::MessageLoopForIO::WATCH_WRITE, | |
260 &write_socket_watcher_, &write_watcher_)) { | |
261 DVLOG(1) << "WatchFileDescriptor failed on write, errno " << errno; | |
262 int result = MapSystemError(errno); | |
263 LogWrite(result, NULL, NULL); | |
264 return result; | |
265 } | |
266 | |
267 write_buf_ = buf; | |
268 write_buf_len_ = buf_len; | |
269 DCHECK(!send_to_address_.get()); | |
270 if (address) { | |
271 send_to_address_.reset(new IPEndPoint(*address)); | |
272 } | |
273 write_callback_ = callback; | |
274 return ERR_IO_PENDING; | |
275 } | |
276 | |
277 int UDPSocketPosix::Connect(const IPEndPoint& address) { | |
278 DCHECK_NE(socket_, kInvalidSocket); | |
279 net_log_.BeginEvent(NetLogEventType::UDP_CONNECT, | |
280 CreateNetLogUDPConnectCallback(&address, bound_network_)); | |
281 int rv = InternalConnect(address); | |
282 net_log_.EndEventWithNetErrorCode(NetLogEventType::UDP_CONNECT, rv); | |
283 is_connected_ = (rv == OK); | |
284 return rv; | |
285 } | |
286 | |
287 int UDPSocketPosix::InternalConnect(const IPEndPoint& address) { | |
288 DCHECK(CalledOnValidThread()); | |
289 DCHECK(!is_connected()); | |
290 DCHECK(!remote_address_.get()); | |
291 | |
292 int rv = 0; | |
293 if (bind_type_ == DatagramSocket::RANDOM_BIND) { | |
294 // Construct IPAddress of appropriate size (IPv4 or IPv6) of 0s, | |
295 // representing INADDR_ANY or in6addr_any. | |
296 size_t addr_size = address.GetSockAddrFamily() == AF_INET | |
297 ? IPAddress::kIPv4AddressSize | |
298 : IPAddress::kIPv6AddressSize; | |
299 rv = RandomBind(IPAddress::AllZeros(addr_size)); | |
300 } | |
301 // else connect() does the DatagramSocket::DEFAULT_BIND | |
302 | |
303 if (rv < 0) { | |
304 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.UdpSocketRandomBindErrorCode", -rv); | |
305 return rv; | |
306 } | |
307 | |
308 SockaddrStorage storage; | |
309 if (!address.ToSockAddr(storage.addr, &storage.addr_len)) | |
310 return ERR_ADDRESS_INVALID; | |
311 | |
312 rv = HANDLE_EINTR(connect(socket_, storage.addr, storage.addr_len)); | |
313 if (rv < 0) | |
314 return MapSystemError(errno); | |
315 | |
316 remote_address_.reset(new IPEndPoint(address)); | |
317 return rv; | |
318 } | |
319 | |
320 int UDPSocketPosix::Bind(const IPEndPoint& address) { | |
321 DCHECK_NE(socket_, kInvalidSocket); | |
322 DCHECK(CalledOnValidThread()); | |
323 DCHECK(!is_connected()); | |
324 | |
325 int rv = SetMulticastOptions(); | |
326 if (rv < 0) | |
327 return rv; | |
328 | |
329 rv = DoBind(address); | |
330 if (rv < 0) | |
331 return rv; | |
332 | |
333 is_connected_ = true; | |
334 local_address_.reset(); | |
335 return rv; | |
336 } | |
337 | |
338 int UDPSocketPosix::BindToNetwork( | |
339 NetworkChangeNotifier::NetworkHandle network) { | |
340 DCHECK_NE(socket_, kInvalidSocket); | |
341 DCHECK(CalledOnValidThread()); | |
342 DCHECK(!is_connected()); | |
343 if (network == NetworkChangeNotifier::kInvalidNetworkHandle) | |
344 return ERR_INVALID_ARGUMENT; | |
345 #if defined(OS_ANDROID) | |
346 // Android prior to Lollipop didn't have support for binding sockets to | |
347 // networks. | |
348 if (base::android::BuildInfo::GetInstance()->sdk_int() < | |
349 base::android::SDK_VERSION_LOLLIPOP) { | |
350 return ERR_NOT_IMPLEMENTED; | |
351 } | |
352 int rv; | |
353 // On Android M and newer releases use supported NDK API. On Android L use | |
354 // setNetworkForSocket from libnetd_client.so. | |
355 if (base::android::BuildInfo::GetInstance()->sdk_int() >= | |
356 base::android::SDK_VERSION_MARSHMALLOW) { | |
357 // See declaration of android_setsocknetwork() here: | |
358 // http://androidxref.com/6.0.0_r1/xref/development/ndk/platforms/android-M/
include/android/multinetwork.h#65 | |
359 // Function cannot be called directly as it will cause app to fail to load | |
360 // on pre-marshmallow devices. | |
361 typedef int (*MarshmallowSetNetworkForSocket)(int64_t netId, int socketFd); | |
362 static MarshmallowSetNetworkForSocket marshmallowSetNetworkForSocket; | |
363 // This is racy, but all racers should come out with the same answer so it | |
364 // shouldn't matter. | |
365 if (!marshmallowSetNetworkForSocket) { | |
366 base::FilePath file(base::GetNativeLibraryName("android")); | |
367 void* dl = dlopen(file.value().c_str(), RTLD_NOW); | |
368 marshmallowSetNetworkForSocket = | |
369 reinterpret_cast<MarshmallowSetNetworkForSocket>( | |
370 dlsym(dl, "android_setsocknetwork")); | |
371 } | |
372 if (!marshmallowSetNetworkForSocket) | |
373 return ERR_NOT_IMPLEMENTED; | |
374 rv = marshmallowSetNetworkForSocket(network, socket_); | |
375 if (rv) | |
376 rv = errno; | |
377 } else { | |
378 // NOTE(pauljensen): This does rely on Android implementation details, but | |
379 // they won't change because Lollipop is already released. | |
380 typedef int (*LollipopSetNetworkForSocket)(unsigned netId, int socketFd); | |
381 static LollipopSetNetworkForSocket lollipopSetNetworkForSocket; | |
382 // This is racy, but all racers should come out with the same answer so it | |
383 // shouldn't matter. | |
384 if (!lollipopSetNetworkForSocket) { | |
385 // Android's netd client library should always be loaded in our address | |
386 // space as it shims socket() which was used to create |socket_|. | |
387 base::FilePath file(base::GetNativeLibraryName("netd_client")); | |
388 // Use RTLD_NOW to match Android's prior loading of the library: | |
389 // http://androidxref.com/6.0.0_r5/xref/bionic/libc/bionic/NetdClient.cpp#
37 | |
390 // Use RTLD_NOLOAD to assert that the library is already loaded and | |
391 // avoid doing any disk IO. | |
392 void* dl = dlopen(file.value().c_str(), RTLD_NOW | RTLD_NOLOAD); | |
393 lollipopSetNetworkForSocket = | |
394 reinterpret_cast<LollipopSetNetworkForSocket>( | |
395 dlsym(dl, "setNetworkForSocket")); | |
396 } | |
397 if (!lollipopSetNetworkForSocket) | |
398 return ERR_NOT_IMPLEMENTED; | |
399 rv = -lollipopSetNetworkForSocket(network, socket_); | |
400 } | |
401 // If |network| has since disconnected, |rv| will be ENONET. Surface this as | |
402 // ERR_NETWORK_CHANGED, rather than MapSystemError(ENONET) which gives back | |
403 // the less descriptive ERR_FAILED. | |
404 if (rv == ENONET) | |
405 return ERR_NETWORK_CHANGED; | |
406 if (rv == 0) | |
407 bound_network_ = network; | |
408 return MapSystemError(rv); | |
409 #else | |
410 NOTIMPLEMENTED(); | |
411 return ERR_NOT_IMPLEMENTED; | |
412 #endif | |
413 } | |
414 | |
415 int UDPSocketPosix::SetReceiveBufferSize(int32_t size) { | |
416 DCHECK_NE(socket_, kInvalidSocket); | |
417 DCHECK(CalledOnValidThread()); | |
418 int rv = setsockopt(socket_, SOL_SOCKET, SO_RCVBUF, | |
419 reinterpret_cast<const char*>(&size), sizeof(size)); | |
420 return rv == 0 ? OK : MapSystemError(errno); | |
421 } | |
422 | |
423 int UDPSocketPosix::SetSendBufferSize(int32_t size) { | |
424 DCHECK_NE(socket_, kInvalidSocket); | |
425 DCHECK(CalledOnValidThread()); | |
426 int rv = setsockopt(socket_, SOL_SOCKET, SO_SNDBUF, | |
427 reinterpret_cast<const char*>(&size), sizeof(size)); | |
428 return rv == 0 ? OK : MapSystemError(errno); | |
429 } | |
430 | |
431 int UDPSocketPosix::SetDoNotFragment() { | |
432 DCHECK_NE(socket_, kInvalidSocket); | |
433 DCHECK(CalledOnValidThread()); | |
434 | |
435 #if !defined(IP_PMTUDISC_DO) | |
436 return ERR_NOT_IMPLEMENTED; | |
437 #else | |
438 if (addr_family_ == AF_INET6) { | |
439 int val = IPV6_PMTUDISC_DO; | |
440 if (setsockopt(socket_, IPPROTO_IPV6, IPV6_MTU_DISCOVER, &val, | |
441 sizeof(val)) != 0) { | |
442 return MapSystemError(errno); | |
443 } | |
444 | |
445 int v6_only = false; | |
446 socklen_t v6_only_len = sizeof(v6_only); | |
447 if (getsockopt(socket_, IPPROTO_IPV6, IPV6_V6ONLY, &v6_only, | |
448 &v6_only_len) != 0) { | |
449 return MapSystemError(errno); | |
450 } | |
451 | |
452 if (v6_only) | |
453 return OK; | |
454 } | |
455 | |
456 int val = IP_PMTUDISC_DO; | |
457 int rv = setsockopt(socket_, IPPROTO_IP, IP_MTU_DISCOVER, &val, sizeof(val)); | |
458 return rv == 0 ? OK : MapSystemError(errno); | |
459 #endif | |
460 } | |
461 | |
462 int UDPSocketPosix::AllowAddressReuse() { | |
463 DCHECK_NE(socket_, kInvalidSocket); | |
464 DCHECK(CalledOnValidThread()); | |
465 DCHECK(!is_connected()); | |
466 int true_value = 1; | |
467 int rv = setsockopt( | |
468 socket_, SOL_SOCKET, SO_REUSEADDR, &true_value, sizeof(true_value)); | |
469 return rv == 0 ? OK : MapSystemError(errno); | |
470 } | |
471 | |
472 int UDPSocketPosix::SetBroadcast(bool broadcast) { | |
473 DCHECK_NE(socket_, kInvalidSocket); | |
474 DCHECK(CalledOnValidThread()); | |
475 int value = broadcast ? 1 : 0; | |
476 int rv; | |
477 #if defined(OS_MACOSX) | |
478 // SO_REUSEPORT on OSX permits multiple processes to each receive | |
479 // UDP multicast or broadcast datagrams destined for the bound | |
480 // port. | |
481 // This is only being set on OSX because its behavior is platform dependent | |
482 // and we are playing it safe by only setting it on platforms where things | |
483 // break. | |
484 rv = setsockopt(socket_, SOL_SOCKET, SO_REUSEPORT, &value, sizeof(value)); | |
485 if (rv != 0) | |
486 return MapSystemError(errno); | |
487 #endif // defined(OS_MACOSX) | |
488 rv = setsockopt(socket_, SOL_SOCKET, SO_BROADCAST, &value, sizeof(value)); | |
489 | |
490 return rv == 0 ? OK : MapSystemError(errno); | |
491 } | |
492 | |
493 void UDPSocketPosix::ReadWatcher::OnFileCanReadWithoutBlocking(int) { | |
494 TRACE_EVENT0("net", | |
495 "UDPSocketPosix::ReadWatcher::OnFileCanReadWithoutBlocking"); | |
496 if (!socket_->read_callback_.is_null()) | |
497 socket_->DidCompleteRead(); | |
498 } | |
499 | |
500 void UDPSocketPosix::WriteWatcher::OnFileCanWriteWithoutBlocking(int) { | |
501 if (!socket_->write_callback_.is_null()) | |
502 socket_->DidCompleteWrite(); | |
503 } | |
504 | |
505 void UDPSocketPosix::DoReadCallback(int rv) { | |
506 DCHECK_NE(rv, ERR_IO_PENDING); | |
507 DCHECK(!read_callback_.is_null()); | |
508 | |
509 // since Run may result in Read being called, clear read_callback_ up front. | |
510 CompletionCallback c = read_callback_; | |
511 read_callback_.Reset(); | |
512 c.Run(rv); | |
513 } | |
514 | |
515 void UDPSocketPosix::DoWriteCallback(int rv) { | |
516 DCHECK_NE(rv, ERR_IO_PENDING); | |
517 DCHECK(!write_callback_.is_null()); | |
518 | |
519 // since Run may result in Write being called, clear write_callback_ up front. | |
520 CompletionCallback c = write_callback_; | |
521 write_callback_.Reset(); | |
522 c.Run(rv); | |
523 } | |
524 | |
525 void UDPSocketPosix::DidCompleteRead() { | |
526 int result = | |
527 InternalRecvFrom(read_buf_.get(), read_buf_len_, recv_from_address_); | |
528 if (result != ERR_IO_PENDING) { | |
529 read_buf_ = NULL; | |
530 read_buf_len_ = 0; | |
531 recv_from_address_ = NULL; | |
532 bool ok = read_socket_watcher_.StopWatchingFileDescriptor(); | |
533 DCHECK(ok); | |
534 DoReadCallback(result); | |
535 } | |
536 } | |
537 | |
538 void UDPSocketPosix::LogRead(int result, | |
539 const char* bytes, | |
540 socklen_t addr_len, | |
541 const sockaddr* addr) const { | |
542 if (result < 0) { | |
543 net_log_.AddEventWithNetErrorCode(NetLogEventType::UDP_RECEIVE_ERROR, | |
544 result); | |
545 return; | |
546 } | |
547 | |
548 if (net_log_.IsCapturing()) { | |
549 DCHECK(addr_len > 0); | |
550 DCHECK(addr); | |
551 | |
552 IPEndPoint address; | |
553 bool is_address_valid = address.FromSockAddr(addr, addr_len); | |
554 net_log_.AddEvent(NetLogEventType::UDP_BYTES_RECEIVED, | |
555 CreateNetLogUDPDataTranferCallback( | |
556 result, bytes, is_address_valid ? &address : NULL)); | |
557 } | |
558 | |
559 NetworkActivityMonitor::GetInstance()->IncrementBytesReceived(result); | |
560 } | |
561 | |
562 void UDPSocketPosix::DidCompleteWrite() { | |
563 int result = | |
564 InternalSendTo(write_buf_.get(), write_buf_len_, send_to_address_.get()); | |
565 | |
566 if (result != ERR_IO_PENDING) { | |
567 write_buf_ = NULL; | |
568 write_buf_len_ = 0; | |
569 send_to_address_.reset(); | |
570 write_socket_watcher_.StopWatchingFileDescriptor(); | |
571 DoWriteCallback(result); | |
572 } | |
573 } | |
574 | |
575 void UDPSocketPosix::LogWrite(int result, | |
576 const char* bytes, | |
577 const IPEndPoint* address) const { | |
578 if (result < 0) { | |
579 net_log_.AddEventWithNetErrorCode(NetLogEventType::UDP_SEND_ERROR, result); | |
580 return; | |
581 } | |
582 | |
583 if (net_log_.IsCapturing()) { | |
584 net_log_.AddEvent( | |
585 NetLogEventType::UDP_BYTES_SENT, | |
586 CreateNetLogUDPDataTranferCallback(result, bytes, address)); | |
587 } | |
588 | |
589 NetworkActivityMonitor::GetInstance()->IncrementBytesSent(result); | |
590 } | |
591 | |
592 int UDPSocketPosix::InternalRecvFrom(IOBuffer* buf, | |
593 int buf_len, | |
594 IPEndPoint* address) { | |
595 int bytes_transferred; | |
596 int flags = 0; | |
597 | |
598 SockaddrStorage storage; | |
599 | |
600 bytes_transferred = | |
601 HANDLE_EINTR(recvfrom(socket_, | |
602 buf->data(), | |
603 buf_len, | |
604 flags, | |
605 storage.addr, | |
606 &storage.addr_len)); | |
607 int result; | |
608 if (bytes_transferred >= 0) { | |
609 result = bytes_transferred; | |
610 if (address && !address->FromSockAddr(storage.addr, storage.addr_len)) | |
611 result = ERR_ADDRESS_INVALID; | |
612 } else { | |
613 result = MapSystemError(errno); | |
614 } | |
615 if (result != ERR_IO_PENDING) | |
616 LogRead(result, buf->data(), storage.addr_len, storage.addr); | |
617 return result; | |
618 } | |
619 | |
620 int UDPSocketPosix::InternalSendTo(IOBuffer* buf, | |
621 int buf_len, | |
622 const IPEndPoint* address) { | |
623 SockaddrStorage storage; | |
624 struct sockaddr* addr = storage.addr; | |
625 if (!address) { | |
626 addr = NULL; | |
627 storage.addr_len = 0; | |
628 } else { | |
629 if (!address->ToSockAddr(storage.addr, &storage.addr_len)) { | |
630 int result = ERR_ADDRESS_INVALID; | |
631 LogWrite(result, NULL, NULL); | |
632 return result; | |
633 } | |
634 } | |
635 | |
636 int result = HANDLE_EINTR(sendto(socket_, | |
637 buf->data(), | |
638 buf_len, | |
639 0, | |
640 addr, | |
641 storage.addr_len)); | |
642 if (result < 0) | |
643 result = MapSystemError(errno); | |
644 if (result != ERR_IO_PENDING) | |
645 LogWrite(result, buf->data(), address); | |
646 return result; | |
647 } | |
648 | |
649 int UDPSocketPosix::SetMulticastOptions() { | |
650 if (!(socket_options_ & SOCKET_OPTION_MULTICAST_LOOP)) { | |
651 int rv; | |
652 if (addr_family_ == AF_INET) { | |
653 u_char loop = 0; | |
654 rv = setsockopt(socket_, IPPROTO_IP, IP_MULTICAST_LOOP, | |
655 &loop, sizeof(loop)); | |
656 } else { | |
657 u_int loop = 0; | |
658 rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, | |
659 &loop, sizeof(loop)); | |
660 } | |
661 if (rv < 0) | |
662 return MapSystemError(errno); | |
663 } | |
664 if (multicast_time_to_live_ != IP_DEFAULT_MULTICAST_TTL) { | |
665 int rv; | |
666 if (addr_family_ == AF_INET) { | |
667 u_char ttl = multicast_time_to_live_; | |
668 rv = setsockopt(socket_, IPPROTO_IP, IP_MULTICAST_TTL, | |
669 &ttl, sizeof(ttl)); | |
670 } else { | |
671 // Signed integer. -1 to use route default. | |
672 int ttl = multicast_time_to_live_; | |
673 rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, | |
674 &ttl, sizeof(ttl)); | |
675 } | |
676 if (rv < 0) | |
677 return MapSystemError(errno); | |
678 } | |
679 if (multicast_interface_ != 0) { | |
680 switch (addr_family_) { | |
681 case AF_INET: { | |
682 #if !defined(OS_MACOSX) | |
683 ip_mreqn mreq; | |
684 mreq.imr_ifindex = multicast_interface_; | |
685 mreq.imr_address.s_addr = htonl(INADDR_ANY); | |
686 #else | |
687 ip_mreq mreq; | |
688 int error = GetIPv4AddressFromIndex(socket_, multicast_interface_, | |
689 &mreq.imr_interface.s_addr); | |
690 if (error != OK) | |
691 return error; | |
692 #endif | |
693 int rv = setsockopt(socket_, IPPROTO_IP, IP_MULTICAST_IF, | |
694 reinterpret_cast<const char*>(&mreq), sizeof(mreq)); | |
695 if (rv) | |
696 return MapSystemError(errno); | |
697 break; | |
698 } | |
699 case AF_INET6: { | |
700 uint32_t interface_index = multicast_interface_; | |
701 int rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_MULTICAST_IF, | |
702 reinterpret_cast<const char*>(&interface_index), | |
703 sizeof(interface_index)); | |
704 if (rv) | |
705 return MapSystemError(errno); | |
706 break; | |
707 } | |
708 default: | |
709 NOTREACHED() << "Invalid address family"; | |
710 return ERR_ADDRESS_INVALID; | |
711 } | |
712 } | |
713 return OK; | |
714 } | |
715 | |
716 int UDPSocketPosix::DoBind(const IPEndPoint& address) { | |
717 SockaddrStorage storage; | |
718 if (!address.ToSockAddr(storage.addr, &storage.addr_len)) | |
719 return ERR_ADDRESS_INVALID; | |
720 int rv = bind(socket_, storage.addr, storage.addr_len); | |
721 if (rv == 0) | |
722 return OK; | |
723 int last_error = errno; | |
724 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.UdpSocketBindErrorFromPosix", last_error); | |
725 #if defined(OS_CHROMEOS) | |
726 if (last_error == EINVAL) | |
727 return ERR_ADDRESS_IN_USE; | |
728 #elif defined(OS_MACOSX) | |
729 if (last_error == EADDRNOTAVAIL) | |
730 return ERR_ADDRESS_IN_USE; | |
731 #endif | |
732 return MapSystemError(last_error); | |
733 } | |
734 | |
735 int UDPSocketPosix::RandomBind(const IPAddress& address) { | |
736 DCHECK(bind_type_ == DatagramSocket::RANDOM_BIND && !rand_int_cb_.is_null()); | |
737 | |
738 for (int i = 0; i < kBindRetries; ++i) { | |
739 int rv = DoBind(IPEndPoint(address, | |
740 rand_int_cb_.Run(kPortStart, kPortEnd))); | |
741 if (rv != ERR_ADDRESS_IN_USE) | |
742 return rv; | |
743 } | |
744 return DoBind(IPEndPoint(address, 0)); | |
745 } | |
746 | |
747 int UDPSocketPosix::JoinGroup(const IPAddress& group_address) const { | |
748 DCHECK(CalledOnValidThread()); | |
749 if (!is_connected()) | |
750 return ERR_SOCKET_NOT_CONNECTED; | |
751 | |
752 switch (group_address.size()) { | |
753 case IPAddress::kIPv4AddressSize: { | |
754 if (addr_family_ != AF_INET) | |
755 return ERR_ADDRESS_INVALID; | |
756 | |
757 #if !defined(OS_MACOSX) | |
758 ip_mreqn mreq; | |
759 mreq.imr_ifindex = multicast_interface_; | |
760 mreq.imr_address.s_addr = htonl(INADDR_ANY); | |
761 #else | |
762 ip_mreq mreq; | |
763 int error = GetIPv4AddressFromIndex(socket_, multicast_interface_, | |
764 &mreq.imr_interface.s_addr); | |
765 if (error != OK) | |
766 return error; | |
767 #endif | |
768 memcpy(&mreq.imr_multiaddr, group_address.bytes().data(), | |
769 IPAddress::kIPv4AddressSize); | |
770 int rv = setsockopt(socket_, IPPROTO_IP, IP_ADD_MEMBERSHIP, | |
771 &mreq, sizeof(mreq)); | |
772 if (rv < 0) | |
773 return MapSystemError(errno); | |
774 return OK; | |
775 } | |
776 case IPAddress::kIPv6AddressSize: { | |
777 if (addr_family_ != AF_INET6) | |
778 return ERR_ADDRESS_INVALID; | |
779 ipv6_mreq mreq; | |
780 mreq.ipv6mr_interface = multicast_interface_; | |
781 memcpy(&mreq.ipv6mr_multiaddr, group_address.bytes().data(), | |
782 IPAddress::kIPv6AddressSize); | |
783 int rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_JOIN_GROUP, | |
784 &mreq, sizeof(mreq)); | |
785 if (rv < 0) | |
786 return MapSystemError(errno); | |
787 return OK; | |
788 } | |
789 default: | |
790 NOTREACHED() << "Invalid address family"; | |
791 return ERR_ADDRESS_INVALID; | |
792 } | |
793 } | |
794 | |
795 int UDPSocketPosix::LeaveGroup(const IPAddress& group_address) const { | |
796 DCHECK(CalledOnValidThread()); | |
797 | |
798 if (!is_connected()) | |
799 return ERR_SOCKET_NOT_CONNECTED; | |
800 | |
801 switch (group_address.size()) { | |
802 case IPAddress::kIPv4AddressSize: { | |
803 if (addr_family_ != AF_INET) | |
804 return ERR_ADDRESS_INVALID; | |
805 ip_mreq mreq; | |
806 mreq.imr_interface.s_addr = INADDR_ANY; | |
807 memcpy(&mreq.imr_multiaddr, group_address.bytes().data(), | |
808 IPAddress::kIPv4AddressSize); | |
809 int rv = setsockopt(socket_, IPPROTO_IP, IP_DROP_MEMBERSHIP, | |
810 &mreq, sizeof(mreq)); | |
811 if (rv < 0) | |
812 return MapSystemError(errno); | |
813 return OK; | |
814 } | |
815 case IPAddress::kIPv6AddressSize: { | |
816 if (addr_family_ != AF_INET6) | |
817 return ERR_ADDRESS_INVALID; | |
818 ipv6_mreq mreq; | |
819 mreq.ipv6mr_interface = 0; // 0 indicates default multicast interface. | |
820 memcpy(&mreq.ipv6mr_multiaddr, group_address.bytes().data(), | |
821 IPAddress::kIPv6AddressSize); | |
822 int rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_LEAVE_GROUP, | |
823 &mreq, sizeof(mreq)); | |
824 if (rv < 0) | |
825 return MapSystemError(errno); | |
826 return OK; | |
827 } | |
828 default: | |
829 NOTREACHED() << "Invalid address family"; | |
830 return ERR_ADDRESS_INVALID; | |
831 } | |
832 } | |
833 | |
834 int UDPSocketPosix::SetMulticastInterface(uint32_t interface_index) { | |
835 DCHECK(CalledOnValidThread()); | |
836 if (is_connected()) | |
837 return ERR_SOCKET_IS_CONNECTED; | |
838 multicast_interface_ = interface_index; | |
839 return OK; | |
840 } | |
841 | |
842 int UDPSocketPosix::SetMulticastTimeToLive(int time_to_live) { | |
843 DCHECK(CalledOnValidThread()); | |
844 if (is_connected()) | |
845 return ERR_SOCKET_IS_CONNECTED; | |
846 | |
847 if (time_to_live < 0 || time_to_live > 255) | |
848 return ERR_INVALID_ARGUMENT; | |
849 multicast_time_to_live_ = time_to_live; | |
850 return OK; | |
851 } | |
852 | |
853 int UDPSocketPosix::SetMulticastLoopbackMode(bool loopback) { | |
854 DCHECK(CalledOnValidThread()); | |
855 if (is_connected()) | |
856 return ERR_SOCKET_IS_CONNECTED; | |
857 | |
858 if (loopback) | |
859 socket_options_ |= SOCKET_OPTION_MULTICAST_LOOP; | |
860 else | |
861 socket_options_ &= ~SOCKET_OPTION_MULTICAST_LOOP; | |
862 return OK; | |
863 } | |
864 | |
865 int UDPSocketPosix::SetDiffServCodePoint(DiffServCodePoint dscp) { | |
866 if (dscp == DSCP_NO_CHANGE) { | |
867 return OK; | |
868 } | |
869 int rv; | |
870 int dscp_and_ecn = dscp << 2; | |
871 if (addr_family_ == AF_INET) { | |
872 rv = setsockopt(socket_, IPPROTO_IP, IP_TOS, | |
873 &dscp_and_ecn, sizeof(dscp_and_ecn)); | |
874 } else { | |
875 rv = setsockopt(socket_, IPPROTO_IPV6, IPV6_TCLASS, | |
876 &dscp_and_ecn, sizeof(dscp_and_ecn)); | |
877 } | |
878 if (rv < 0) | |
879 return MapSystemError(errno); | |
880 | |
881 return OK; | |
882 } | |
883 | |
884 void UDPSocketPosix::DetachFromThread() { | |
885 base::NonThreadSafe::DetachFromThread(); | |
886 } | |
887 | |
888 } // namespace net | |
OLD | NEW |