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