OLD | NEW |
| (Empty) |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 #if !defined(DART_IO_DISABLED) | |
6 | |
7 #include "platform/globals.h" | |
8 #if defined(HOST_OS_LINUX) | |
9 | |
10 #include "bin/socket_base.h" | |
11 | |
12 #include <errno.h> // NOLINT | |
13 #include <ifaddrs.h> // NOLINT | |
14 #include <net/if.h> // NOLINT | |
15 #include <netinet/tcp.h> // NOLINT | |
16 #include <stdio.h> // NOLINT | |
17 #include <stdlib.h> // NOLINT | |
18 #include <string.h> // NOLINT | |
19 #include <sys/stat.h> // NOLINT | |
20 #include <unistd.h> // NOLINT | |
21 | |
22 #include "bin/fdutils.h" | |
23 #include "bin/file.h" | |
24 #include "bin/socket_base_linux.h" | |
25 #include "bin/thread.h" | |
26 #include "platform/signal_blocker.h" | |
27 | |
28 namespace dart { | |
29 namespace bin { | |
30 | |
31 SocketAddress::SocketAddress(struct sockaddr* sa) { | |
32 ASSERT(INET6_ADDRSTRLEN >= INET_ADDRSTRLEN); | |
33 if (!SocketBase::FormatNumericAddress(*reinterpret_cast<RawAddr*>(sa), | |
34 as_string_, INET6_ADDRSTRLEN)) { | |
35 as_string_[0] = 0; | |
36 } | |
37 socklen_t salen = GetAddrLength(*reinterpret_cast<RawAddr*>(sa)); | |
38 memmove(reinterpret_cast<void*>(&addr_), sa, salen); | |
39 } | |
40 | |
41 | |
42 bool SocketBase::FormatNumericAddress(const RawAddr& addr, | |
43 char* address, | |
44 int len) { | |
45 socklen_t salen = SocketAddress::GetAddrLength(addr); | |
46 return (NO_RETRY_EXPECTED(getnameinfo(&addr.addr, salen, address, len, NULL, | |
47 0, NI_NUMERICHOST) == 0)); | |
48 } | |
49 | |
50 | |
51 bool SocketBase::IsBindError(intptr_t error_number) { | |
52 return error_number == EADDRINUSE || error_number == EADDRNOTAVAIL || | |
53 error_number == EINVAL; | |
54 } | |
55 | |
56 | |
57 intptr_t SocketBase::Available(intptr_t fd) { | |
58 return FDUtils::AvailableBytes(fd); | |
59 } | |
60 | |
61 | |
62 intptr_t SocketBase::Read(intptr_t fd, void* buffer, intptr_t num_bytes) { | |
63 ASSERT(fd >= 0); | |
64 ssize_t read_bytes = TEMP_FAILURE_RETRY(read(fd, buffer, num_bytes)); | |
65 ASSERT(EAGAIN == EWOULDBLOCK); | |
66 if ((read_bytes == -1) && (errno == EWOULDBLOCK)) { | |
67 // If the read would block we need to retry and therefore return 0 | |
68 // as the number of bytes written. | |
69 read_bytes = 0; | |
70 } | |
71 return read_bytes; | |
72 } | |
73 | |
74 | |
75 intptr_t SocketBase::RecvFrom(intptr_t fd, | |
76 void* buffer, | |
77 intptr_t num_bytes, | |
78 RawAddr* addr) { | |
79 ASSERT(fd >= 0); | |
80 socklen_t addr_len = sizeof(addr->ss); | |
81 ssize_t read_bytes = TEMP_FAILURE_RETRY( | |
82 recvfrom(fd, buffer, num_bytes, 0, &addr->addr, &addr_len)); | |
83 if ((read_bytes == -1) && (errno == EWOULDBLOCK)) { | |
84 // If the read would block we need to retry and therefore return 0 | |
85 // as the number of bytes written. | |
86 read_bytes = 0; | |
87 } | |
88 return read_bytes; | |
89 } | |
90 | |
91 | |
92 intptr_t SocketBase::Write(intptr_t fd, | |
93 const void* buffer, | |
94 intptr_t num_bytes) { | |
95 ASSERT(fd >= 0); | |
96 ssize_t written_bytes = TEMP_FAILURE_RETRY(write(fd, buffer, num_bytes)); | |
97 ASSERT(EAGAIN == EWOULDBLOCK); | |
98 if ((written_bytes == -1) && (errno == EWOULDBLOCK)) { | |
99 // If the would block we need to retry and therefore return 0 as | |
100 // the number of bytes written. | |
101 written_bytes = 0; | |
102 } | |
103 return written_bytes; | |
104 } | |
105 | |
106 | |
107 intptr_t SocketBase::SendTo(intptr_t fd, | |
108 const void* buffer, | |
109 intptr_t num_bytes, | |
110 const RawAddr& addr) { | |
111 ASSERT(fd >= 0); | |
112 ssize_t written_bytes = | |
113 TEMP_FAILURE_RETRY(sendto(fd, buffer, num_bytes, 0, &addr.addr, | |
114 SocketAddress::GetAddrLength(addr))); | |
115 ASSERT(EAGAIN == EWOULDBLOCK); | |
116 if ((written_bytes == -1) && (errno == EWOULDBLOCK)) { | |
117 // If the would block we need to retry and therefore return 0 as | |
118 // the number of bytes written. | |
119 written_bytes = 0; | |
120 } | |
121 return written_bytes; | |
122 } | |
123 | |
124 | |
125 intptr_t SocketBase::GetPort(intptr_t fd) { | |
126 ASSERT(fd >= 0); | |
127 RawAddr raw; | |
128 socklen_t size = sizeof(raw); | |
129 if (NO_RETRY_EXPECTED(getsockname(fd, &raw.addr, &size))) { | |
130 return 0; | |
131 } | |
132 return SocketAddress::GetAddrPort(raw); | |
133 } | |
134 | |
135 | |
136 SocketAddress* SocketBase::GetRemotePeer(intptr_t fd, intptr_t* port) { | |
137 ASSERT(fd >= 0); | |
138 RawAddr raw; | |
139 socklen_t size = sizeof(raw); | |
140 if (NO_RETRY_EXPECTED(getpeername(fd, &raw.addr, &size))) { | |
141 return NULL; | |
142 } | |
143 *port = SocketAddress::GetAddrPort(raw); | |
144 return new SocketAddress(&raw.addr); | |
145 } | |
146 | |
147 | |
148 void SocketBase::GetError(intptr_t fd, OSError* os_error) { | |
149 int len = sizeof(errno); | |
150 int err = 0; | |
151 VOID_NO_RETRY_EXPECTED(getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, | |
152 reinterpret_cast<socklen_t*>(&len))); | |
153 errno = err; | |
154 os_error->SetCodeAndMessage(OSError::kSystem, errno); | |
155 } | |
156 | |
157 | |
158 int SocketBase::GetType(intptr_t fd) { | |
159 struct stat64 buf; | |
160 int result = TEMP_FAILURE_RETRY(fstat64(fd, &buf)); | |
161 if (result == -1) { | |
162 return -1; | |
163 } | |
164 if (S_ISCHR(buf.st_mode)) { | |
165 return File::kTerminal; | |
166 } | |
167 if (S_ISFIFO(buf.st_mode)) { | |
168 return File::kPipe; | |
169 } | |
170 if (S_ISREG(buf.st_mode)) { | |
171 return File::kFile; | |
172 } | |
173 return File::kOther; | |
174 } | |
175 | |
176 | |
177 intptr_t SocketBase::GetStdioHandle(intptr_t num) { | |
178 return num; | |
179 } | |
180 | |
181 | |
182 AddressList<SocketAddress>* SocketBase::LookupAddress(const char* host, | |
183 int type, | |
184 OSError** os_error) { | |
185 // Perform a name lookup for a host name. | |
186 struct addrinfo hints; | |
187 memset(&hints, 0, sizeof(hints)); | |
188 hints.ai_family = SocketAddress::FromType(type); | |
189 hints.ai_socktype = SOCK_STREAM; | |
190 hints.ai_flags = AI_ADDRCONFIG; | |
191 hints.ai_protocol = IPPROTO_TCP; | |
192 struct addrinfo* info = NULL; | |
193 int status = NO_RETRY_EXPECTED(getaddrinfo(host, 0, &hints, &info)); | |
194 if (status != 0) { | |
195 // We failed, try without AI_ADDRCONFIG. This can happen when looking up | |
196 // e.g. '::1', when there are no global IPv6 addresses. | |
197 hints.ai_flags = 0; | |
198 status = NO_RETRY_EXPECTED(getaddrinfo(host, 0, &hints, &info)); | |
199 if (status != 0) { | |
200 ASSERT(*os_error == NULL); | |
201 *os_error = | |
202 new OSError(status, gai_strerror(status), OSError::kGetAddressInfo); | |
203 return NULL; | |
204 } | |
205 } | |
206 intptr_t count = 0; | |
207 for (struct addrinfo* c = info; c != NULL; c = c->ai_next) { | |
208 if ((c->ai_family == AF_INET) || (c->ai_family == AF_INET6)) { | |
209 count++; | |
210 } | |
211 } | |
212 intptr_t i = 0; | |
213 AddressList<SocketAddress>* addresses = new AddressList<SocketAddress>(count); | |
214 for (struct addrinfo* c = info; c != NULL; c = c->ai_next) { | |
215 if ((c->ai_family == AF_INET) || (c->ai_family == AF_INET6)) { | |
216 addresses->SetAt(i, new SocketAddress(c->ai_addr)); | |
217 i++; | |
218 } | |
219 } | |
220 freeaddrinfo(info); | |
221 return addresses; | |
222 } | |
223 | |
224 | |
225 bool SocketBase::ReverseLookup(const RawAddr& addr, | |
226 char* host, | |
227 intptr_t host_len, | |
228 OSError** os_error) { | |
229 ASSERT(host_len >= NI_MAXHOST); | |
230 int status = NO_RETRY_EXPECTED( | |
231 getnameinfo(&addr.addr, SocketAddress::GetAddrLength(addr), host, | |
232 host_len, NULL, 0, NI_NAMEREQD)); | |
233 if (status != 0) { | |
234 ASSERT(*os_error == NULL); | |
235 *os_error = | |
236 new OSError(status, gai_strerror(status), OSError::kGetAddressInfo); | |
237 return false; | |
238 } | |
239 return true; | |
240 } | |
241 | |
242 | |
243 bool SocketBase::ParseAddress(int type, const char* address, RawAddr* addr) { | |
244 int result; | |
245 if (type == SocketAddress::TYPE_IPV4) { | |
246 result = NO_RETRY_EXPECTED(inet_pton(AF_INET, address, &addr->in.sin_addr)); | |
247 } else { | |
248 ASSERT(type == SocketAddress::TYPE_IPV6); | |
249 result = | |
250 NO_RETRY_EXPECTED(inet_pton(AF_INET6, address, &addr->in6.sin6_addr)); | |
251 } | |
252 return (result == 1); | |
253 } | |
254 | |
255 | |
256 static bool ShouldIncludeIfaAddrs(struct ifaddrs* ifa, int lookup_family) { | |
257 if (ifa->ifa_addr == NULL) { | |
258 // OpenVPN's virtual device tun0. | |
259 return false; | |
260 } | |
261 int family = ifa->ifa_addr->sa_family; | |
262 return ((lookup_family == family) || | |
263 (((lookup_family == AF_UNSPEC) && | |
264 ((family == AF_INET) || (family == AF_INET6))))); | |
265 } | |
266 | |
267 | |
268 bool SocketBase::ListInterfacesSupported() { | |
269 return true; | |
270 } | |
271 | |
272 | |
273 AddressList<InterfaceSocketAddress>* SocketBase::ListInterfaces( | |
274 int type, | |
275 OSError** os_error) { | |
276 struct ifaddrs* ifaddr; | |
277 | |
278 int status = NO_RETRY_EXPECTED(getifaddrs(&ifaddr)); | |
279 if (status != 0) { | |
280 ASSERT(*os_error == NULL); | |
281 *os_error = | |
282 new OSError(status, gai_strerror(status), OSError::kGetAddressInfo); | |
283 return NULL; | |
284 } | |
285 | |
286 int lookup_family = SocketAddress::FromType(type); | |
287 | |
288 intptr_t count = 0; | |
289 for (struct ifaddrs* ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { | |
290 if (ShouldIncludeIfaAddrs(ifa, lookup_family)) { | |
291 count++; | |
292 } | |
293 } | |
294 | |
295 AddressList<InterfaceSocketAddress>* addresses = | |
296 new AddressList<InterfaceSocketAddress>(count); | |
297 int i = 0; | |
298 for (struct ifaddrs* ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { | |
299 if (ShouldIncludeIfaAddrs(ifa, lookup_family)) { | |
300 char* ifa_name = DartUtils::ScopedCopyCString(ifa->ifa_name); | |
301 addresses->SetAt( | |
302 i, new InterfaceSocketAddress(ifa->ifa_addr, ifa_name, | |
303 if_nametoindex(ifa->ifa_name))); | |
304 i++; | |
305 } | |
306 } | |
307 freeifaddrs(ifaddr); | |
308 return addresses; | |
309 } | |
310 | |
311 | |
312 void SocketBase::Close(intptr_t fd) { | |
313 ASSERT(fd >= 0); | |
314 VOID_TEMP_FAILURE_RETRY(close(fd)); | |
315 } | |
316 | |
317 | |
318 bool SocketBase::GetNoDelay(intptr_t fd, bool* enabled) { | |
319 int on; | |
320 socklen_t len = sizeof(on); | |
321 int err = NO_RETRY_EXPECTED(getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, | |
322 reinterpret_cast<void*>(&on), &len)); | |
323 if (err == 0) { | |
324 *enabled = (on == 1); | |
325 } | |
326 return (err == 0); | |
327 } | |
328 | |
329 | |
330 bool SocketBase::SetNoDelay(intptr_t fd, bool enabled) { | |
331 int on = enabled ? 1 : 0; | |
332 return NO_RETRY_EXPECTED(setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, | |
333 reinterpret_cast<char*>(&on), | |
334 sizeof(on))) == 0; | |
335 } | |
336 | |
337 | |
338 bool SocketBase::GetMulticastLoop(intptr_t fd, | |
339 intptr_t protocol, | |
340 bool* enabled) { | |
341 uint8_t on; | |
342 socklen_t len = sizeof(on); | |
343 int level = protocol == SocketAddress::TYPE_IPV4 ? IPPROTO_IP : IPPROTO_IPV6; | |
344 int optname = protocol == SocketAddress::TYPE_IPV4 ? IP_MULTICAST_LOOP | |
345 : IPV6_MULTICAST_LOOP; | |
346 if (NO_RETRY_EXPECTED(getsockopt(fd, level, optname, | |
347 reinterpret_cast<char*>(&on), &len)) == 0) { | |
348 *enabled = (on == 1); | |
349 return true; | |
350 } | |
351 return false; | |
352 } | |
353 | |
354 | |
355 bool SocketBase::SetMulticastLoop(intptr_t fd, | |
356 intptr_t protocol, | |
357 bool enabled) { | |
358 int on = enabled ? 1 : 0; | |
359 int level = protocol == SocketAddress::TYPE_IPV4 ? IPPROTO_IP : IPPROTO_IPV6; | |
360 int optname = protocol == SocketAddress::TYPE_IPV4 ? IP_MULTICAST_LOOP | |
361 : IPV6_MULTICAST_LOOP; | |
362 return NO_RETRY_EXPECTED(setsockopt( | |
363 fd, level, optname, reinterpret_cast<char*>(&on), sizeof(on))) == | |
364 0; | |
365 } | |
366 | |
367 | |
368 bool SocketBase::GetMulticastHops(intptr_t fd, intptr_t protocol, int* value) { | |
369 uint8_t v; | |
370 socklen_t len = sizeof(v); | |
371 int level = protocol == SocketAddress::TYPE_IPV4 ? IPPROTO_IP : IPPROTO_IPV6; | |
372 int optname = protocol == SocketAddress::TYPE_IPV4 ? IP_MULTICAST_TTL | |
373 : IPV6_MULTICAST_HOPS; | |
374 if (NO_RETRY_EXPECTED(getsockopt(fd, level, optname, | |
375 reinterpret_cast<char*>(&v), &len)) == 0) { | |
376 *value = v; | |
377 return true; | |
378 } | |
379 return false; | |
380 } | |
381 | |
382 | |
383 bool SocketBase::SetMulticastHops(intptr_t fd, intptr_t protocol, int value) { | |
384 int v = value; | |
385 int level = protocol == SocketAddress::TYPE_IPV4 ? IPPROTO_IP : IPPROTO_IPV6; | |
386 int optname = protocol == SocketAddress::TYPE_IPV4 ? IP_MULTICAST_TTL | |
387 : IPV6_MULTICAST_HOPS; | |
388 return NO_RETRY_EXPECTED(setsockopt( | |
389 fd, level, optname, reinterpret_cast<char*>(&v), sizeof(v))) == 0; | |
390 } | |
391 | |
392 | |
393 bool SocketBase::GetBroadcast(intptr_t fd, bool* enabled) { | |
394 int on; | |
395 socklen_t len = sizeof(on); | |
396 int err = NO_RETRY_EXPECTED(getsockopt(fd, SOL_SOCKET, SO_BROADCAST, | |
397 reinterpret_cast<char*>(&on), &len)); | |
398 if (err == 0) { | |
399 *enabled = (on == 1); | |
400 } | |
401 return (err == 0); | |
402 } | |
403 | |
404 | |
405 bool SocketBase::SetBroadcast(intptr_t fd, bool enabled) { | |
406 int on = enabled ? 1 : 0; | |
407 return NO_RETRY_EXPECTED(setsockopt(fd, SOL_SOCKET, SO_BROADCAST, | |
408 reinterpret_cast<char*>(&on), | |
409 sizeof(on))) == 0; | |
410 } | |
411 | |
412 | |
413 bool SocketBase::JoinMulticast(intptr_t fd, | |
414 const RawAddr& addr, | |
415 const RawAddr&, | |
416 int interfaceIndex) { | |
417 int proto = addr.addr.sa_family == AF_INET ? IPPROTO_IP : IPPROTO_IPV6; | |
418 struct group_req mreq; | |
419 mreq.gr_interface = interfaceIndex; | |
420 memmove(&mreq.gr_group, &addr.ss, SocketAddress::GetAddrLength(addr)); | |
421 return NO_RETRY_EXPECTED( | |
422 setsockopt(fd, proto, MCAST_JOIN_GROUP, &mreq, sizeof(mreq))) == 0; | |
423 } | |
424 | |
425 | |
426 bool SocketBase::LeaveMulticast(intptr_t fd, | |
427 const RawAddr& addr, | |
428 const RawAddr&, | |
429 int interfaceIndex) { | |
430 int proto = addr.addr.sa_family == AF_INET ? IPPROTO_IP : IPPROTO_IPV6; | |
431 struct group_req mreq; | |
432 mreq.gr_interface = interfaceIndex; | |
433 memmove(&mreq.gr_group, &addr.ss, SocketAddress::GetAddrLength(addr)); | |
434 return NO_RETRY_EXPECTED(setsockopt(fd, proto, MCAST_LEAVE_GROUP, &mreq, | |
435 sizeof(mreq))) == 0; | |
436 } | |
437 | |
438 } // namespace bin | |
439 } // namespace dart | |
440 | |
441 #endif // defined(HOST_OS_LINUX) | |
442 | |
443 #endif // !defined(DART_IO_DISABLED) | |
OLD | NEW |