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