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