Flutter Engine
The Flutter Engine
socket_macos.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_MACOS)
7
8#include "bin/socket.h"
9
10#include <errno.h> // NOLINT
11
12#include "bin/fdutils.h"
14
15namespace dart {
16namespace bin {
17
18Socket::Socket(intptr_t fd)
19 : ReferenceCounted(),
20 fd_(fd),
21 isolate_port_(Dart_GetMainPortId()),
22 port_(ILLEGAL_PORT),
23 udp_receive_buffer_(nullptr) {}
24
25void Socket::CloseFd() {
26 SetClosedFd();
27}
28
29void Socket::SetClosedFd() {
30 fd_ = kClosedFd;
31}
32
33static intptr_t Create(const RawAddr& addr) {
34 intptr_t fd;
35 fd = NO_RETRY_EXPECTED(socket(addr.ss.ss_family, SOCK_STREAM, 0));
36 if (fd < 0) {
37 return -1;
38 }
39 if (!FDUtils::SetCloseOnExec(fd)) {
40 FDUtils::SaveErrorAndClose(fd);
41 return -1;
42 }
43 if (!FDUtils::SetNonBlocking(fd)) {
44 FDUtils::SaveErrorAndClose(fd);
45 return -1;
46 }
47 // Don't raise SIGPIPE when attempting to write to a connection which has
48 // already closed.
49 int optval = 1;
51 setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)));
52 return fd;
53}
54
55static intptr_t Connect(intptr_t fd, const RawAddr& addr) {
56 intptr_t result = TEMP_FAILURE_RETRY(
57 connect(fd, &addr.addr, SocketAddress::GetAddrLength(addr)));
58 if ((result == 0) || (errno == EINPROGRESS)) {
59 return fd;
60 }
61 FDUtils::SaveErrorAndClose(fd);
62 return -1;
63}
64
65intptr_t Socket::CreateConnect(const RawAddr& addr) {
66 intptr_t fd = Create(addr);
67 if (fd < 0) {
68 return fd;
69 }
70
71 return Connect(fd, addr);
72}
73
74intptr_t Socket::CreateUnixDomainConnect(const RawAddr& addr) {
75 intptr_t fd = Create(addr);
76 if (fd < 0) {
77 return fd;
78 }
79 return Connect(fd, addr);
80}
81
82intptr_t Socket::CreateBindConnect(const RawAddr& addr,
83 const RawAddr& source_addr) {
84 intptr_t fd = Create(addr);
85 if (fd < 0) {
86 return fd;
87 }
88
89 intptr_t result = TEMP_FAILURE_RETRY(
90 bind(fd, &source_addr.addr, SocketAddress::GetAddrLength(source_addr)));
91 if (result != 0) {
92 FDUtils::SaveErrorAndClose(fd);
93 return -1;
94 }
95
96 return Connect(fd, addr);
97}
98
99intptr_t Socket::CreateUnixDomainBindConnect(const RawAddr& addr,
100 const RawAddr& source_addr) {
101 intptr_t fd = Create(addr);
102 if (fd < 0) {
103 return fd;
104 }
105
106 intptr_t result = TEMP_FAILURE_RETRY(
107 bind(fd, &source_addr.addr, SocketAddress::GetAddrLength(source_addr)));
108 if (result != 0) {
109 FDUtils::SaveErrorAndClose(fd);
110 return -1;
111 }
112
113 return Connect(fd, addr);
114}
115
116intptr_t Socket::CreateBindDatagram(const RawAddr& addr,
117 bool reuseAddress,
118 bool reusePort,
119 int ttl) {
120 intptr_t fd;
121
122 fd = NO_RETRY_EXPECTED(socket(addr.addr.sa_family, SOCK_DGRAM, IPPROTO_UDP));
123 if (fd < 0) {
124 return -1;
125 }
126
127 if (!FDUtils::SetCloseOnExec(fd)) {
128 FDUtils::SaveErrorAndClose(fd);
129 return -1;
130 }
131
132 if (reuseAddress) {
133 int optval = 1;
135 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)));
136 }
137
138 if (reusePort) {
139 int optval = 1;
141 setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval)));
142 }
143
144 if (!SocketBase::SetMulticastHops(fd,
145 addr.addr.sa_family == AF_INET
146 ? SocketAddress::TYPE_IPV4
147 : SocketAddress::TYPE_IPV6,
148 ttl)) {
149 FDUtils::SaveErrorAndClose(fd);
150 return -1;
151 }
152
153 // Don't raise SIGPIPE when attempting to write to a connection which has
154 // already closed.
155 int optval = 1;
157 setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)));
158
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 = TEMP_FAILURE_RETRY(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;
189 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)));
190
191 // Don't raise SIGPIPE when attempting to write to a connection which has
192 // already closed.
193 optval = 1;
195 setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)));
196
197 if (addr.ss.ss_family == AF_INET6) {
198 optval = v6_only ? 1 : 0;
200 setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &optval, sizeof(optval)));
201 }
202
204 bind(fd, &addr.addr, SocketAddress::GetAddrLength(addr))) < 0) {
205 FDUtils::SaveErrorAndClose(fd);
206 return -1;
207 }
208
209 // Test for invalid socket port 65535 (some browsers disallow it).
210 if ((SocketAddress::GetAddrPort(addr) == 0) &&
211 (SocketBase::GetPort(fd) == 65535)) {
212 // Don't close the socket until we have created a new socket, ensuring
213 // that we do not get the bad port number again.
214 intptr_t new_fd = CreateBindListen(addr, backlog, v6_only);
215 FDUtils::SaveErrorAndClose(fd);
216 return new_fd;
217 }
218
219 if (NO_RETRY_EXPECTED(listen(fd, backlog > 0 ? backlog : SOMAXCONN)) != 0) {
220 FDUtils::SaveErrorAndClose(fd);
221 return -1;
222 }
223
224 if (!FDUtils::SetNonBlocking(fd)) {
225 FDUtils::SaveErrorAndClose(fd);
226 return -1;
227 }
228 return fd;
229}
230
231intptr_t ServerSocket::CreateUnixDomainBindListen(const RawAddr& addr,
232 intptr_t backlog) {
233 intptr_t fd;
234 fd = NO_RETRY_EXPECTED(socket(addr.ss.ss_family, SOCK_STREAM, 0));
235 if (fd < 0) {
236 return -1;
237 }
238
239 if (!FDUtils::SetCloseOnExec(fd)) {
240 FDUtils::SaveErrorAndClose(fd);
241 return -1;
242 }
243
245 bind(fd, &addr.addr, SocketAddress::GetAddrLength(addr))) < 0) {
246 FDUtils::SaveErrorAndClose(fd);
247 return -1;
248 }
249
250 if (NO_RETRY_EXPECTED(listen(fd, backlog > 0 ? backlog : SOMAXCONN)) != 0) {
251 FDUtils::SaveErrorAndClose(fd);
252 return -1;
253 }
254
255 if (!FDUtils::SetNonBlocking(fd)) {
256 FDUtils::SaveErrorAndClose(fd);
257 return -1;
258 }
259 return fd;
260}
261
262bool ServerSocket::StartAccept(intptr_t fd) {
263 USE(fd);
264 return true;
265}
266
267intptr_t ServerSocket::Accept(intptr_t fd) {
268 intptr_t socket;
269 struct sockaddr clientaddr;
270 socklen_t addrlen = sizeof(clientaddr);
271 socket = TEMP_FAILURE_RETRY(accept(fd, &clientaddr, &addrlen));
272 if (socket == -1) {
273 if (errno == EAGAIN) {
274 // We need to signal to the caller that this is actually not an
275 // error. We got woken up from the poll on the listening socket,
276 // but there is no connection ready to be accepted.
277 ASSERT(kTemporaryFailure != -1);
278 socket = kTemporaryFailure;
279 }
280 } else {
281 if (!FDUtils::SetCloseOnExec(socket)) {
282 FDUtils::SaveErrorAndClose(socket);
283 return -1;
284 }
285 if (!FDUtils::SetNonBlocking(socket)) {
286 FDUtils::SaveErrorAndClose(socket);
287 return -1;
288 }
289 }
290 return socket;
291}
292
293} // namespace bin
294} // namespace dart
295
296#endif // defined(DART_HOST_OS_MACOS)
static sk_sp< Effect > Create()
Definition: RefCntTest.cpp:117
Socket(intptr_t fd)
#define ILLEGAL_PORT
Definition: dart_api.h:1535
#define ASSERT(E)
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)