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