1 /*
2 * Authored by Alex Hultman, 2018-2021.
3 * Intellectual property of third-party.
4
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8
9 * http://www.apache.org/licenses/LICENSE-2.0
10
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 /* Todo: this file should lie in networking/bsd.c */
19
20 #include "libusockets.h"
21 #include "internal/internal.h"
22
23 #include <stdio.h>
24
25 #ifndef _WIN32
26 //#define _GNU_SOURCE
27 #include <sys/types.h>
28 #include <sys/socket.h>
29 #include <netinet/in.h>
30 #include <netinet/tcp.h>
31 #include <netdb.h>
32 #include <string.h>
33 #include <unistd.h>
34 #include <fcntl.h>
35 #include <errno.h>
36 #endif
37
apple_no_sigpipe(LIBUS_SOCKET_DESCRIPTOR fd)38 LIBUS_SOCKET_DESCRIPTOR apple_no_sigpipe(LIBUS_SOCKET_DESCRIPTOR fd) {
39 #ifdef __APPLE__
40 if (fd != LIBUS_SOCKET_ERROR) {
41 int no_sigpipe = 1;
42 setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &no_sigpipe, sizeof(int));
43 }
44 #endif
45 return fd;
46 }
47
bsd_set_nonblocking(LIBUS_SOCKET_DESCRIPTOR fd)48 LIBUS_SOCKET_DESCRIPTOR bsd_set_nonblocking(LIBUS_SOCKET_DESCRIPTOR fd) {
49 #ifdef _WIN32
50 /* Libuv will set windows sockets as non-blocking */
51 #else
52 fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
53 #endif
54 return fd;
55 }
56
bsd_socket_nodelay(LIBUS_SOCKET_DESCRIPTOR fd,int enabled)57 void bsd_socket_nodelay(LIBUS_SOCKET_DESCRIPTOR fd, int enabled) {
58 setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (void *) &enabled, sizeof(enabled));
59 }
60
bsd_socket_flush(LIBUS_SOCKET_DESCRIPTOR fd)61 void bsd_socket_flush(LIBUS_SOCKET_DESCRIPTOR fd) {
62 // Linux TCP_CORK has the same underlying corking mechanism as with MSG_MORE
63 #ifdef TCP_CORK
64 int enabled = 0;
65 setsockopt(fd, IPPROTO_TCP, TCP_CORK, &enabled, sizeof(int));
66 #endif
67 }
68
bsd_create_socket(int domain,int type,int protocol)69 LIBUS_SOCKET_DESCRIPTOR bsd_create_socket(int domain, int type, int protocol) {
70 // returns INVALID_SOCKET on error
71 int flags = 0;
72 #if defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK)
73 flags = SOCK_CLOEXEC | SOCK_NONBLOCK;
74 #endif
75
76 LIBUS_SOCKET_DESCRIPTOR created_fd = socket(domain, type | flags, protocol);
77
78 return bsd_set_nonblocking(apple_no_sigpipe(created_fd));
79 }
80
bsd_close_socket(LIBUS_SOCKET_DESCRIPTOR fd)81 void bsd_close_socket(LIBUS_SOCKET_DESCRIPTOR fd) {
82 #ifdef _WIN32
83 closesocket(fd);
84 #else
85 close(fd);
86 #endif
87 }
88
bsd_shutdown_socket(LIBUS_SOCKET_DESCRIPTOR fd)89 void bsd_shutdown_socket(LIBUS_SOCKET_DESCRIPTOR fd) {
90 #ifdef _WIN32
91 shutdown(fd, SD_SEND);
92 #else
93 shutdown(fd, SHUT_WR);
94 #endif
95 }
96
bsd_shutdown_socket_read(LIBUS_SOCKET_DESCRIPTOR fd)97 void bsd_shutdown_socket_read(LIBUS_SOCKET_DESCRIPTOR fd) {
98 #ifdef _WIN32
99 shutdown(fd, SD_RECEIVE);
100 #else
101 shutdown(fd, SHUT_RD);
102 #endif
103 }
104
internal_finalize_bsd_addr(struct bsd_addr_t * addr)105 void internal_finalize_bsd_addr(struct bsd_addr_t *addr) {
106 // parse, so to speak, the address
107 if (addr->mem.ss_family == AF_INET6) {
108 addr->ip = (char *) &((struct sockaddr_in6 *) addr)->sin6_addr;
109 addr->ip_length = sizeof(struct in6_addr);
110 addr->port = ntohs(((struct sockaddr_in6 *) addr)->sin6_port);
111 } else if (addr->mem.ss_family == AF_INET) {
112 addr->ip = (char *) &((struct sockaddr_in *) addr)->sin_addr;
113 addr->ip_length = sizeof(struct in_addr);
114 addr->port = ntohs(((struct sockaddr_in *) addr)->sin_port);
115 } else {
116 addr->ip_length = 0;
117 addr->port = -1;
118 }
119 }
120
bsd_local_addr(LIBUS_SOCKET_DESCRIPTOR fd,struct bsd_addr_t * addr)121 int bsd_local_addr(LIBUS_SOCKET_DESCRIPTOR fd, struct bsd_addr_t *addr) {
122 addr->len = sizeof(addr->mem);
123 if (getsockname(fd, (struct sockaddr *) &addr->mem, &addr->len)) {
124 return -1;
125 }
126 internal_finalize_bsd_addr(addr);
127 return 0;
128 }
129
bsd_remote_addr(LIBUS_SOCKET_DESCRIPTOR fd,struct bsd_addr_t * addr)130 int bsd_remote_addr(LIBUS_SOCKET_DESCRIPTOR fd, struct bsd_addr_t *addr) {
131 addr->len = sizeof(addr->mem);
132 if (getpeername(fd, (struct sockaddr *) &addr->mem, &addr->len)) {
133 return -1;
134 }
135 internal_finalize_bsd_addr(addr);
136 return 0;
137 }
138
bsd_addr_get_ip(struct bsd_addr_t * addr)139 char *bsd_addr_get_ip(struct bsd_addr_t *addr) {
140 return addr->ip;
141 }
142
bsd_addr_get_ip_length(struct bsd_addr_t * addr)143 int bsd_addr_get_ip_length(struct bsd_addr_t *addr) {
144 return addr->ip_length;
145 }
146
bsd_addr_get_port(struct bsd_addr_t * addr)147 int bsd_addr_get_port(struct bsd_addr_t *addr) {
148 return addr->port;
149 }
150
151 // called by dispatch_ready_poll
bsd_accept_socket(LIBUS_SOCKET_DESCRIPTOR fd,struct bsd_addr_t * addr)152 LIBUS_SOCKET_DESCRIPTOR bsd_accept_socket(LIBUS_SOCKET_DESCRIPTOR fd, struct bsd_addr_t *addr) {
153 LIBUS_SOCKET_DESCRIPTOR accepted_fd;
154 addr->len = sizeof(addr->mem);
155
156 #if defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK)
157 // Linux, FreeBSD
158 accepted_fd = accept4(fd, (struct sockaddr *) addr, &addr->len, SOCK_CLOEXEC | SOCK_NONBLOCK);
159 #else
160 // Windows, OS X
161 accepted_fd = accept(fd, (struct sockaddr *) addr, &addr->len);
162
163 #endif
164
165 /* We cannot rely on addr since it is not initialized if failed */
166 if (accepted_fd == LIBUS_SOCKET_ERROR) {
167 return LIBUS_SOCKET_ERROR;
168 }
169
170 internal_finalize_bsd_addr(addr);
171
172 return bsd_set_nonblocking(apple_no_sigpipe(accepted_fd));
173 }
174
bsd_recv(LIBUS_SOCKET_DESCRIPTOR fd,void * buf,int length,int flags)175 int bsd_recv(LIBUS_SOCKET_DESCRIPTOR fd, void *buf, int length, int flags) {
176 return recv(fd, buf, length, flags);
177 }
178
bsd_send(LIBUS_SOCKET_DESCRIPTOR fd,const char * buf,int length,int msg_more)179 int bsd_send(LIBUS_SOCKET_DESCRIPTOR fd, const char *buf, int length, int msg_more) {
180
181 // MSG_MORE (Linux), MSG_PARTIAL (Windows), TCP_NOPUSH (BSD)
182
183 #ifndef MSG_NOSIGNAL
184 #define MSG_NOSIGNAL 0
185 #endif
186
187 #ifdef MSG_MORE
188
189 // for Linux we do not want signals
190 return send(fd, buf, length, ((msg_more != 0) * MSG_MORE) | MSG_NOSIGNAL);
191
192 #else
193
194 // use TCP_NOPUSH
195
196 return send(fd, buf, length, MSG_NOSIGNAL);
197
198 #endif
199 }
200
bsd_would_block()201 int bsd_would_block() {
202 #ifdef _WIN32
203 return WSAGetLastError() == WSAEWOULDBLOCK;
204 #else
205 return errno == EWOULDBLOCK;// || errno == EAGAIN;
206 #endif
207 }
208
209 // return LIBUS_SOCKET_ERROR or the fd that represents listen socket
210 // listen both on ipv6 and ipv4
bsd_create_listen_socket(const char * host,int port,int options)211 LIBUS_SOCKET_DESCRIPTOR bsd_create_listen_socket(const char *host, int port, int options) {
212 struct addrinfo hints, *result;
213 memset(&hints, 0, sizeof(struct addrinfo));
214
215 hints.ai_flags = AI_PASSIVE;
216 hints.ai_family = AF_UNSPEC;
217 hints.ai_socktype = SOCK_STREAM;
218
219 char port_string[16];
220 snprintf(port_string, 16, "%d", port);
221
222 if (getaddrinfo(host, port_string, &hints, &result)) {
223 return LIBUS_SOCKET_ERROR;
224 }
225
226 LIBUS_SOCKET_DESCRIPTOR listenFd = LIBUS_SOCKET_ERROR;
227 struct addrinfo *listenAddr;
228 for (struct addrinfo *a = result; a && listenFd == LIBUS_SOCKET_ERROR; a = a->ai_next) {
229 if (a->ai_family == AF_INET6) {
230 listenFd = bsd_create_socket(a->ai_family, a->ai_socktype, a->ai_protocol);
231 listenAddr = a;
232 }
233 }
234
235 for (struct addrinfo *a = result; a && listenFd == LIBUS_SOCKET_ERROR; a = a->ai_next) {
236 if (a->ai_family == AF_INET) {
237 listenFd = bsd_create_socket(a->ai_family, a->ai_socktype, a->ai_protocol);
238 listenAddr = a;
239 }
240 }
241
242 if (listenFd == LIBUS_SOCKET_ERROR) {
243 freeaddrinfo(result);
244 return LIBUS_SOCKET_ERROR;
245 }
246
247 if (port != 0) {
248 /* Otherwise, always enable SO_REUSEPORT and SO_REUSEADDR _unless_ options specify otherwise */
249 #if /*defined(__linux) &&*/ defined(SO_REUSEPORT)
250 if (!(options & LIBUS_LISTEN_EXCLUSIVE_PORT)) {
251 int optval = 1;
252 setsockopt(listenFd, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval));
253 }
254 #endif
255 int enabled = 1;
256 setsockopt(listenFd, SOL_SOCKET, SO_REUSEADDR, (SETSOCKOPT_PTR_TYPE) &enabled, sizeof(enabled));
257 }
258
259 #ifdef IPV6_V6ONLY
260 int disabled = 0;
261 setsockopt(listenFd, IPPROTO_IPV6, IPV6_V6ONLY, (SETSOCKOPT_PTR_TYPE) &disabled, sizeof(disabled));
262 #endif
263
264 if (bind(listenFd, listenAddr->ai_addr, (socklen_t) listenAddr->ai_addrlen) || listen(listenFd, 512)) {
265 bsd_close_socket(listenFd);
266 freeaddrinfo(result);
267 return LIBUS_SOCKET_ERROR;
268 }
269
270 freeaddrinfo(result);
271 return listenFd;
272 }
273
bsd_create_connect_socket(const char * host,int port,const char * source_host,int options)274 LIBUS_SOCKET_DESCRIPTOR bsd_create_connect_socket(const char *host, int port, const char *source_host, int options) {
275 struct addrinfo hints, *result;
276 memset(&hints, 0, sizeof(struct addrinfo));
277 hints.ai_family = AF_UNSPEC;
278 hints.ai_socktype = SOCK_STREAM;
279
280 char port_string[16];
281 snprintf(port_string, 16, "%d", port);
282
283 if (getaddrinfo(host, port_string, &hints, &result) != 0) {
284 return LIBUS_SOCKET_ERROR;
285 }
286
287 LIBUS_SOCKET_DESCRIPTOR fd = bsd_create_socket(result->ai_family, result->ai_socktype, result->ai_protocol);
288 if (fd == LIBUS_SOCKET_ERROR) {
289 freeaddrinfo(result);
290 return LIBUS_SOCKET_ERROR;
291 }
292
293 if (source_host) {
294 struct addrinfo *interface_result;
295 if (!getaddrinfo(source_host, NULL, NULL, &interface_result)) {
296 int ret = bind(fd, interface_result->ai_addr, (socklen_t) interface_result->ai_addrlen);
297 freeaddrinfo(interface_result);
298 if (ret == LIBUS_SOCKET_ERROR) {
299 return LIBUS_SOCKET_ERROR;
300 }
301 }
302 }
303
304 connect(fd, result->ai_addr, (socklen_t) result->ai_addrlen);
305 freeaddrinfo(result);
306
307 return fd;
308 }
309