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 | |
16 | namespace dart { |
17 | namespace bin { |
18 | |
19 | Socket::Socket(intptr_t fd) |
20 | : ReferenceCounted(), |
21 | fd_(fd), |
22 | isolate_port_(Dart_GetMainPortId()), |
23 | port_(ILLEGAL_PORT), |
24 | udp_receive_buffer_(NULL) {} |
25 | |
26 | void Socket::CloseFd() { |
27 | SetClosedFd(); |
28 | } |
29 | |
30 | void Socket::SetClosedFd() { |
31 | fd_ = kClosedFd; |
32 | } |
33 | |
34 | static 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 | |
47 | static 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 | |
57 | intptr_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 | |
66 | intptr_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 | |
80 | intptr_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 | |
97 | intptr_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 | |
120 | intptr_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 | |
172 | intptr_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 | |
225 | intptr_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 | |
240 | bool ServerSocket::StartAccept(intptr_t fd) { |
241 | USE(fd); |
242 | return true; |
243 | } |
244 | |
245 | static 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 | |
254 | intptr_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 | |