1// Copyright (c) 2012, 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_ANDROID)
7
8#include "bin/socket.h"
9
10#include <errno.h> // NOLINT
11
12#include "bin/fdutils.h"
13#include "platform/signal_blocker.h"
14#include "platform/syslog.h"
15
16namespace dart {
17namespace bin {
18
19Socket::Socket(intptr_t fd)
20 : ReferenceCounted(),
21 fd_(fd),
22 isolate_port_(Dart_GetMainPortId()),
23 port_(ILLEGAL_PORT),
24 udp_receive_buffer_(NULL) {}
25
26void Socket::CloseFd() {
27 SetClosedFd();
28}
29
30void Socket::SetClosedFd() {
31 fd_ = kClosedFd;
32}
33
34static intptr_t Create(const RawAddr& addr) {
35 intptr_t fd;
36 fd = NO_RETRY_EXPECTED(socket(addr.ss.ss_family, SOCK_STREAM, 0));
37 if (fd < 0) {
38 return -1;
39 }
40 if (!FDUtils::SetCloseOnExec(fd) || !FDUtils::SetNonBlocking(fd)) {
41 FDUtils::SaveErrorAndClose(fd);
42 return -1;
43 }
44 return fd;
45}
46
47static intptr_t Connect(intptr_t fd, const RawAddr& addr) {
48 intptr_t result = TEMP_FAILURE_RETRY(
49 connect(fd, &addr.addr, SocketAddress::GetAddrLength(addr)));
50 if ((result == 0) || (errno == EINPROGRESS)) {
51 return fd;
52 }
53 FDUtils::SaveErrorAndClose(fd);
54 return -1;
55}
56
57intptr_t Socket::CreateConnect(const RawAddr& addr) {
58 intptr_t fd = Create(addr);
59 if (fd < 0) {
60 return fd;
61 }
62
63 return Connect(fd, addr);
64}
65
66intptr_t Socket::CreateUnixDomainConnect(const RawAddr& addr) {
67 intptr_t fd = Create(addr);
68 if (fd < 0) {
69 return fd;
70 }
71 intptr_t result = TEMP_FAILURE_RETRY(connect(
72 fd, (struct sockaddr*)&addr.un, SocketAddress::GetAddrLength(addr)));
73 if (result == 0 || errno == EAGAIN) {
74 return fd;
75 }
76 FDUtils::SaveErrorAndClose(fd);
77 return -1;
78}
79
80intptr_t Socket::CreateBindConnect(const RawAddr& addr,
81 const RawAddr& source_addr) {
82 intptr_t fd = Create(addr);
83 if (fd < 0) {
84 return fd;
85 }
86
87 intptr_t result = TEMP_FAILURE_RETRY(
88 bind(fd, &source_addr.addr, SocketAddress::GetAddrLength(source_addr)));
89 if (result != 0) {
90 FDUtils::SaveErrorAndClose(fd);
91 return -1;
92 }
93
94 return Connect(fd, addr);
95}
96
97intptr_t Socket::CreateUnixDomainBindConnect(const RawAddr& addr,
98 const RawAddr& source_addr) {
99 intptr_t fd = Create(addr);
100 if (fd < 0) {
101 return fd;
102 }
103
104 intptr_t result = TEMP_FAILURE_RETRY(
105 bind(fd, &source_addr.addr, SocketAddress::GetAddrLength(source_addr)));
106 if (result != 0) {
107 FDUtils::SaveErrorAndClose(fd);
108 return -1;
109 }
110
111 result = TEMP_FAILURE_RETRY(connect(fd, (struct sockaddr*)&addr.un,
112 SocketAddress::GetAddrLength(addr)));
113 if (result == 0 || errno == EAGAIN) {
114 return fd;
115 }
116 FDUtils::SaveErrorAndClose(fd);
117 return -1;
118}
119
120intptr_t Socket::CreateBindDatagram(const RawAddr& addr,
121 bool reuseAddress,
122 bool reusePort,
123 int ttl) {
124 intptr_t fd;
125
126 fd = NO_RETRY_EXPECTED(socket(addr.addr.sa_family, SOCK_DGRAM, IPPROTO_UDP));
127 if (fd < 0) {
128 return -1;
129 }
130
131 if (!FDUtils::SetCloseOnExec(fd)) {
132 FDUtils::SaveErrorAndClose(fd);
133 return -1;
134 }
135
136 if (reuseAddress) {
137 int optval = 1;
138 VOID_NO_RETRY_EXPECTED(
139 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)));
140 }
141
142 if (reusePort) {
143 // ignore reusePort - not supported on this platform.
144 Syslog::PrintErr(
145 "Dart Socket ERROR: %s:%d: `reusePort` not supported for "
146 "Android.",
147 __FILE__, __LINE__);
148 }
149
150 if (!SocketBase::SetMulticastHops(fd,
151 addr.addr.sa_family == AF_INET
152 ? SocketAddress::TYPE_IPV4
153 : SocketAddress::TYPE_IPV6,
154 ttl)) {
155 FDUtils::SaveErrorAndClose(fd);
156 return -1;
157 }
158
159 if (NO_RETRY_EXPECTED(
160 bind(fd, &addr.addr, SocketAddress::GetAddrLength(addr))) < 0) {
161 FDUtils::SaveErrorAndClose(fd);
162 return -1;
163 }
164
165 if (!FDUtils::SetNonBlocking(fd)) {
166 FDUtils::SaveErrorAndClose(fd);
167 return -1;
168 }
169 return fd;
170}
171
172intptr_t ServerSocket::CreateBindListen(const RawAddr& addr,
173 intptr_t backlog,
174 bool v6_only) {
175 intptr_t fd;
176
177 fd = NO_RETRY_EXPECTED(socket(addr.ss.ss_family, SOCK_STREAM, 0));
178 if (fd < 0) {
179 return -1;
180 }
181
182 if (!FDUtils::SetCloseOnExec(fd)) {
183 FDUtils::SaveErrorAndClose(fd);
184 return -1;
185 }
186
187 int optval = 1;
188 VOID_NO_RETRY_EXPECTED(
189 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)));
190
191 if (addr.ss.ss_family == AF_INET6) {
192 optval = v6_only ? 1 : 0;
193 VOID_NO_RETRY_EXPECTED(
194 setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &optval, sizeof(optval)));
195 }
196
197 if (NO_RETRY_EXPECTED(
198 bind(fd, &addr.addr, SocketAddress::GetAddrLength(addr))) < 0) {
199 FDUtils::SaveErrorAndClose(fd);
200 return -1;
201 }
202
203 // Test for invalid socket port 65535 (some browsers disallow it).
204 if ((SocketAddress::GetAddrPort(addr)) == 0 &&
205 (SocketBase::GetPort(fd) == 65535)) {
206 // Don't close the socket until we have created a new socket, ensuring
207 // that we do not get the bad port number again.
208 intptr_t new_fd = CreateBindListen(addr, backlog, v6_only);
209 FDUtils::SaveErrorAndClose(fd);
210 return new_fd;
211 }
212
213 if (NO_RETRY_EXPECTED(listen(fd, backlog > 0 ? backlog : SOMAXCONN)) != 0) {
214 FDUtils::SaveErrorAndClose(fd);
215 return -1;
216 }
217
218 if (!FDUtils::SetNonBlocking(fd)) {
219 FDUtils::SaveErrorAndClose(fd);
220 return -1;
221 }
222 return fd;
223}
224
225intptr_t ServerSocket::CreateUnixDomainBindListen(const RawAddr& addr,
226 intptr_t backlog) {
227 intptr_t fd = Create(addr);
228 if (NO_RETRY_EXPECTED(bind(fd, (struct sockaddr*)&addr.un,
229 SocketAddress::GetAddrLength(addr))) < 0) {
230 FDUtils::SaveErrorAndClose(fd);
231 return -1;
232 }
233 if (NO_RETRY_EXPECTED(listen(fd, backlog > 0 ? backlog : SOMAXCONN)) != 0) {
234 FDUtils::SaveErrorAndClose(fd);
235 return -1;
236 }
237 return fd;
238}
239
240bool ServerSocket::StartAccept(intptr_t fd) {
241 USE(fd);
242 return true;
243}
244
245static bool IsTemporaryAcceptError(int error) {
246 // On Android a number of protocol errors should be treated as EAGAIN.
247 // These are the ones for TCP/IP.
248 return (error == EAGAIN) || (error == ENETDOWN) || (error == EPROTO) ||
249 (error == ENOPROTOOPT) || (error == EHOSTDOWN) || (error == ENONET) ||
250 (error == EHOSTUNREACH) || (error == EOPNOTSUPP) ||
251 (error == ENETUNREACH);
252}
253
254intptr_t ServerSocket::Accept(intptr_t fd) {
255 intptr_t socket;
256 struct sockaddr clientaddr;
257 socklen_t addrlen = sizeof(clientaddr);
258 socket = TEMP_FAILURE_RETRY(accept(fd, &clientaddr, &addrlen));
259 if (socket == -1) {
260 if (IsTemporaryAcceptError(errno)) {
261 // We need to signal to the caller that this is actually not an
262 // error. We got woken up from the poll on the listening socket,
263 // but there is no connection ready to be accepted.
264 ASSERT(kTemporaryFailure != -1);
265 socket = kTemporaryFailure;
266 }
267 } else {
268 if (!FDUtils::SetCloseOnExec(socket)) {
269 FDUtils::SaveErrorAndClose(socket);
270 return -1;
271 }
272 if (!FDUtils::SetNonBlocking(socket)) {
273 FDUtils::SaveErrorAndClose(socket);
274 return -1;
275 }
276 }
277 return socket;
278}
279
280} // namespace bin
281} // namespace dart
282
283#endif // defined(HOST_OS_ANDROID)
284