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 <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 | |
OLD | NEW |