/src/libwebsockets/lib/plat/unix/unix-sockets.c
Line | Count | Source |
1 | | /* |
2 | | * libwebsockets - small server side websockets and web server implementation |
3 | | * |
4 | | * Copyright (C) 2010 - 2023 Andy Green <andy@warmcat.com> |
5 | | * |
6 | | * Permission is hereby granted, free of charge, to any person obtaining a copy |
7 | | * of this software and associated documentation files (the "Software"), to |
8 | | * deal in the Software without restriction, including without limitation the |
9 | | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or |
10 | | * sell copies of the Software, and to permit persons to whom the Software is |
11 | | * furnished to do so, subject to the following conditions: |
12 | | * |
13 | | * The above copyright notice and this permission notice shall be included in |
14 | | * all copies or substantial portions of the Software. |
15 | | * |
16 | | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
17 | | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
18 | | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
19 | | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
20 | | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
21 | | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
22 | | * IN THE SOFTWARE. |
23 | | */ |
24 | | |
25 | | #if !defined(_GNU_SOURCE) |
26 | | #define _GNU_SOURCE |
27 | | #endif |
28 | | #include "private-lib-core.h" |
29 | | |
30 | | #if defined(LWS_HAVE_LINUX_IPV6_H) |
31 | | #include <linux/ipv6.h> |
32 | | #endif |
33 | | |
34 | | #include <sys/ioctl.h> |
35 | | |
36 | | #if !defined(LWS_DETECTED_PLAT_IOS) |
37 | | #include <net/route.h> |
38 | | #endif |
39 | | |
40 | | #include <net/if.h> |
41 | | |
42 | | #include <pwd.h> |
43 | | #include <grp.h> |
44 | | |
45 | | #if defined(LWS_WITH_MBEDTLS) |
46 | | #if defined(LWS_HAVE_MBEDTLS_NET_SOCKETS) |
47 | | #include "mbedtls/net_sockets.h" |
48 | | #else |
49 | | #include "mbedtls/net.h" |
50 | | #endif |
51 | | #endif |
52 | | |
53 | | #include <netinet/ip.h> |
54 | | |
55 | | int |
56 | | lws_send_pipe_choked(struct lws *wsi) |
57 | 0 | { |
58 | 0 | struct lws_pollfd fds; |
59 | 0 | struct lws *wsi_eff; |
60 | |
|
61 | | #if !defined(LWS_WITHOUT_EXTENSIONS) |
62 | | if (wsi->ws && wsi->ws->tx_draining_ext) |
63 | | return 1; |
64 | | #endif |
65 | |
|
66 | 0 | #if defined(LWS_WITH_HTTP2) |
67 | 0 | wsi_eff = lws_get_network_wsi(wsi); |
68 | | #else |
69 | | wsi_eff = wsi; |
70 | | #endif |
71 | | |
72 | | /* the fact we checked implies we avoided back-to-back writes */ |
73 | 0 | wsi_eff->could_have_pending = 0; |
74 | | |
75 | | /* treat the fact we got a truncated send pending as if we're choked */ |
76 | 0 | if (lws_has_buffered_out(wsi_eff) |
77 | | #if defined(LWS_WITH_HTTP_STREAM_COMPRESSION) |
78 | | ||wsi->http.comp_ctx.buflist_comp || |
79 | | wsi->http.comp_ctx.may_have_more |
80 | | #endif |
81 | 0 | ) |
82 | 0 | return 1; |
83 | | |
84 | 0 | fds.fd = wsi_eff->desc.sockfd; |
85 | 0 | fds.events = POLLOUT; |
86 | 0 | fds.revents = 0; |
87 | |
|
88 | 0 | if (poll(&fds, 1, 0) != 1) |
89 | 0 | return 1; |
90 | | |
91 | 0 | if ((fds.revents & POLLOUT) == 0) |
92 | 0 | return 1; |
93 | | |
94 | | /* okay to send another packet without blocking */ |
95 | | |
96 | 0 | return 0; |
97 | 0 | } |
98 | | |
99 | | int |
100 | | lws_plat_set_nonblocking(lws_sockfd_type fd) |
101 | 0 | { |
102 | 0 | return fcntl(fd, F_SETFL, O_NONBLOCK) < 0; |
103 | 0 | } |
104 | | |
105 | | int |
106 | | lws_plat_set_socket_options(struct lws_vhost *vhost, int fd, int unix_skt) |
107 | 0 | { |
108 | 0 | int optval = 1; |
109 | 0 | socklen_t optlen = sizeof(optval); |
110 | |
|
111 | | #if defined(__APPLE__) || \ |
112 | | defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \ |
113 | | defined(__NetBSD__) || \ |
114 | | defined(__OpenBSD__) || \ |
115 | | defined(__HAIKU__) |
116 | | struct protoent *tcp_proto; |
117 | | #endif |
118 | |
|
119 | 0 | (void)fcntl(fd, F_SETFD, FD_CLOEXEC); |
120 | |
|
121 | 0 | if (!unix_skt && vhost->ka_time) { |
122 | | /* enable keepalive on this socket */ |
123 | 0 | optval = 1; |
124 | 0 | if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, |
125 | 0 | (const void *)&optval, optlen) < 0) |
126 | 0 | return 1; |
127 | | |
128 | | #if defined(__APPLE__) || \ |
129 | | defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \ |
130 | | defined(__NetBSD__) || \ |
131 | | defined(__CYGWIN__) || defined(__OpenBSD__) || defined (__sun) || \ |
132 | | defined(__HAIKU__) |
133 | | |
134 | | /* |
135 | | * didn't find a way to set these per-socket, need to |
136 | | * tune kernel systemwide values |
137 | | */ |
138 | | #else |
139 | | /* set the keepalive conditions we want on it too */ |
140 | | |
141 | 0 | #if defined(LWS_HAVE_TCP_USER_TIMEOUT) |
142 | 0 | optval = 1000 * (vhost->ka_time + |
143 | 0 | (vhost->ka_interval * vhost->ka_probes)); |
144 | 0 | if (setsockopt(fd, IPPROTO_TCP, TCP_USER_TIMEOUT, |
145 | 0 | (const void *)&optval, optlen) < 0) |
146 | 0 | return 1; |
147 | 0 | #endif |
148 | 0 | optval = vhost->ka_time; |
149 | 0 | if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, |
150 | 0 | (const void *)&optval, optlen) < 0) |
151 | 0 | return 1; |
152 | | |
153 | 0 | optval = vhost->ka_interval; |
154 | 0 | if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, |
155 | 0 | (const void *)&optval, optlen) < 0) |
156 | 0 | return 1; |
157 | | |
158 | 0 | optval = vhost->ka_probes; |
159 | 0 | if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, |
160 | 0 | (const void *)&optval, optlen) < 0) |
161 | 0 | return 1; |
162 | 0 | #endif |
163 | 0 | } |
164 | | |
165 | 0 | #if defined(SO_BINDTODEVICE) |
166 | 0 | if (!unix_skt && vhost->bind_iface && vhost->iface) { |
167 | 0 | lwsl_info("binding listen skt to %s using SO_BINDTODEVICE\n", vhost->iface); |
168 | 0 | if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, vhost->iface, |
169 | 0 | (socklen_t)strlen(vhost->iface)) < 0) { |
170 | 0 | lwsl_warn("Failed to bind to device %s\n", vhost->iface); |
171 | 0 | return 1; |
172 | 0 | } |
173 | 0 | } |
174 | 0 | #endif |
175 | | |
176 | | /* Disable Nagle */ |
177 | 0 | optval = 1; |
178 | | #if defined (__sun) || defined(__QNX__) || defined(__NuttX__) |
179 | | if (!unix_skt && setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (const void *)&optval, optlen) < 0) |
180 | | return 1; |
181 | | #elif !defined(__APPLE__) && \ |
182 | | !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__) && \ |
183 | | !defined(__NetBSD__) && \ |
184 | | !defined(__OpenBSD__) && \ |
185 | | !defined(__HAIKU__) |
186 | 0 | if (!unix_skt && setsockopt(fd, SOL_TCP, TCP_NODELAY, (const void *)&optval, optlen) < 0) |
187 | 0 | return 1; |
188 | | #else |
189 | | tcp_proto = getprotobyname("TCP"); |
190 | | if (!unix_skt && setsockopt(fd, tcp_proto->p_proto, TCP_NODELAY, &optval, optlen) < 0) |
191 | | return 1; |
192 | | #endif |
193 | | |
194 | 0 | return lws_plat_set_nonblocking(fd); |
195 | 0 | } |
196 | | |
197 | | #if !defined(__NuttX__) |
198 | | static const int ip_opt_lws_flags[] = { |
199 | | LCCSCF_IP_LOW_LATENCY, LCCSCF_IP_HIGH_THROUGHPUT |
200 | | #if !defined(__OpenBSD__) && !defined(__sun) && !defined(__QNX__) |
201 | | , LCCSCF_IP_HIGH_RELIABILITY |
202 | | , LCCSCF_IP_LOW_COST |
203 | | #endif |
204 | | }, ip_opt_val[] = { |
205 | | IPTOS_LOWDELAY, IPTOS_THROUGHPUT |
206 | | #if !defined(__OpenBSD__) && !defined(__sun) && !defined(__QNX__) |
207 | | , IPTOS_RELIABILITY |
208 | | , IPTOS_MINCOST |
209 | | #endif |
210 | | }; |
211 | | #if !defined(LWS_WITH_NO_LOGS) |
212 | | static const char *ip_opt_names[] = { |
213 | | "LOWDELAY", "THROUGHPUT" |
214 | | #if !defined(__OpenBSD__) && !defined(__sun) && !defined(__QNX__) |
215 | | , "RELIABILITY" |
216 | | , "MINCOST" |
217 | | #endif |
218 | | }; |
219 | | #endif |
220 | | #endif |
221 | | |
222 | | int |
223 | | lws_plat_set_socket_options_ip(lws_sockfd_type fd, uint8_t pri, int lws_flags) |
224 | 0 | { |
225 | 0 | int optval = (int)pri, ret = 0, n; |
226 | 0 | socklen_t optlen = sizeof(optval); |
227 | 0 | #if (_LWS_ENABLED_LOGS & LLL_WARN) |
228 | 0 | int en; |
229 | 0 | #endif |
230 | |
|
231 | | #if 0 |
232 | | #if defined(TCP_FASTOPEN_CONNECT) |
233 | | optval = 1; |
234 | | if (setsockopt(fd, IPPROTO_TCP, TCP_FASTOPEN_CONNECT, (void *)&optval, |
235 | | sizeof(optval))) |
236 | | lwsl_warn("%s: FASTOPEN_CONNECT failed\n", __func__); |
237 | | optval = (int)pri; |
238 | | #endif |
239 | | #endif |
240 | |
|
241 | 0 | #if !defined(__APPLE__) && \ |
242 | 0 | !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__) && \ |
243 | 0 | !defined(__NetBSD__) && \ |
244 | 0 | !defined(__OpenBSD__) && \ |
245 | 0 | !defined(__sun) && \ |
246 | 0 | !defined(__HAIKU__) && \ |
247 | 0 | !defined(__CYGWIN__) && \ |
248 | 0 | !defined(__QNX__) && \ |
249 | 0 | !defined(__NuttX__) |
250 | | |
251 | | /* the BSDs don't have SO_PRIORITY */ |
252 | |
|
253 | 0 | if (pri) { /* 0 is the default already */ |
254 | 0 | if (setsockopt(fd, SOL_SOCKET, SO_PRIORITY, |
255 | 0 | (const void *)&optval, optlen) < 0) { |
256 | 0 | #if (_LWS_ENABLED_LOGS & LLL_WARN) |
257 | 0 | en = errno; |
258 | 0 | lwsl_warn("%s: unable to set socket pri %d: errno %d\n", |
259 | 0 | __func__, (int)pri, en); |
260 | 0 | #endif |
261 | 0 | ret = 1; |
262 | 0 | } else |
263 | 0 | lwsl_notice("%s: set pri %u\n", __func__, pri); |
264 | 0 | } |
265 | 0 | #endif |
266 | |
|
267 | 0 | if (lws_flags & LCCSCF_ALLOW_REUSE_ADDR) { |
268 | 0 | optval = 1; |
269 | 0 | if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, |
270 | 0 | (const void *)&optval, optlen) < 0) { |
271 | 0 | #if (_LWS_ENABLED_LOGS & LLL_WARN) |
272 | 0 | en = errno; |
273 | 0 | lwsl_warn("%s: unable to reuse local addresses: errno %d\n", |
274 | 0 | __func__, en); |
275 | 0 | #endif |
276 | 0 | ret = 1; |
277 | 0 | } else |
278 | 0 | lwsl_notice("%s: set reuse addresses\n", __func__); |
279 | 0 | } |
280 | | |
281 | |
|
282 | 0 | if (lws_flags & LCCSCF_IPV6_PREFER_PUBLIC_ADDR) { |
283 | 0 | #if defined(LWS_WITH_IPV6) && defined(IPV6_PREFER_SRC_PUBLIC) |
284 | 0 | optval = IPV6_PREFER_SRC_PUBLIC; |
285 | |
|
286 | 0 | if (setsockopt(fd, IPPROTO_IPV6, IPV6_ADDR_PREFERENCES, |
287 | 0 | (const void *)&optval, optlen) < 0) { |
288 | 0 | #if (_LWS_ENABLED_LOGS & LLL_WARN) |
289 | 0 | en = errno; |
290 | 0 | lwsl_warn("%s: unable to set IPV6_PREFER_SRC_PUBLIC: errno %d\n", |
291 | 0 | __func__, en); |
292 | 0 | #endif |
293 | 0 | ret = 1; |
294 | 0 | } else |
295 | 0 | lwsl_notice("%s: set IPV6_PREFER_SRC_PUBLIC\n", __func__); |
296 | | #else |
297 | | lwsl_err("%s: IPV6_PREFER_SRC_PUBLIC UNIMPLEMENTED on this platform\n", __func__); |
298 | | #endif |
299 | 0 | } |
300 | | |
301 | |
|
302 | 0 | #if !defined(__NuttX__) |
303 | | /* array size differs by platform */ |
304 | 0 | for (n = 0; n < (int)LWS_ARRAY_SIZE(ip_opt_lws_flags); n++) { |
305 | 0 | if (!(lws_flags & ip_opt_lws_flags[n])) |
306 | 0 | continue; |
307 | | |
308 | 0 | optval = (int)ip_opt_val[n]; |
309 | 0 | if (setsockopt(fd, IPPROTO_IP, IP_TOS, (const void *)&optval, |
310 | 0 | optlen) < 0) { |
311 | 0 | #if !defined(LWS_WITH_NO_LOGS) |
312 | 0 | en = errno; |
313 | 0 | lwsl_warn("%s: unable to set %s: errno %d\n", __func__, |
314 | 0 | ip_opt_names[n], en); |
315 | 0 | #endif |
316 | 0 | ret = 1; |
317 | 0 | } else |
318 | 0 | lwsl_notice("%s: set ip flag %s\n", __func__, |
319 | 0 | ip_opt_names[n]); |
320 | 0 | } |
321 | 0 | #endif |
322 | |
|
323 | 0 | return ret; |
324 | 0 | } |
325 | | |
326 | | /* cast a struct sockaddr_in6 * into addr for ipv6 */ |
327 | | |
328 | | enum { |
329 | | IP_SCORE_NONE, |
330 | | IP_SCORE_NONNATIVE, |
331 | | IP_SCORE_IPV6_SCOPE_BASE, |
332 | | /* ipv6 scopes */ |
333 | | IP_SCORE_GLOBAL_NATIVE = 18 |
334 | | }; |
335 | | |
336 | | int |
337 | | lws_interface_to_sa(int ipv6, const char *ifname, struct sockaddr_in *addr, |
338 | | size_t addrlen) |
339 | 0 | { |
340 | 0 | int rc = LWS_ITOSA_NOT_EXIST; |
341 | |
|
342 | 0 | struct ifaddrs *ifr; |
343 | 0 | struct ifaddrs *ifc; |
344 | 0 | #if defined(LWS_WITH_IPV6) |
345 | 0 | struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr; |
346 | 0 | unsigned long sco = IP_SCORE_NONE; |
347 | 0 | unsigned long ts; |
348 | 0 | const uint8_t *p; |
349 | 0 | #endif |
350 | |
|
351 | 0 | if (getifaddrs(&ifr)) { |
352 | 0 | lwsl_err("%s: unable to getifaddrs: errno %d\n", __func__, errno); |
353 | |
|
354 | 0 | return LWS_ITOSA_USABLE; |
355 | 0 | } |
356 | 0 | for (ifc = ifr; ifc != NULL; ifc = ifc->ifa_next) { |
357 | 0 | if (!ifc->ifa_addr || !ifc->ifa_name) |
358 | 0 | continue; |
359 | | |
360 | 0 | lwsl_debug(" interface %s vs %s (fam %d) ipv6 %d\n", |
361 | 0 | ifc->ifa_name, ifname, |
362 | 0 | ifc->ifa_addr->sa_family, ipv6); |
363 | |
|
364 | 0 | if (strcmp(ifc->ifa_name, ifname)) |
365 | 0 | continue; |
366 | | |
367 | 0 | switch (ifc->ifa_addr->sa_family) { |
368 | 0 | #if defined(AF_PACKET) |
369 | 0 | case AF_PACKET: |
370 | | /* interface exists but is not usable */ |
371 | 0 | if (rc == LWS_ITOSA_NOT_EXIST) |
372 | 0 | rc = LWS_ITOSA_NOT_USABLE; |
373 | 0 | continue; |
374 | 0 | #endif |
375 | | |
376 | 0 | case AF_INET: |
377 | 0 | #if defined(LWS_WITH_IPV6) |
378 | 0 | if (ipv6) { |
379 | | /* any existing solution is better than this */ |
380 | 0 | if (sco != IP_SCORE_NONE) |
381 | 0 | break; |
382 | 0 | sco = IP_SCORE_NONNATIVE; |
383 | 0 | rc = LWS_ITOSA_USABLE; |
384 | | /* map IPv4 to IPv6 */ |
385 | 0 | memset((char *)&addr6->sin6_addr, 0, |
386 | 0 | sizeof(struct in6_addr)); |
387 | 0 | addr6->sin6_addr.s6_addr[10] = 0xff; |
388 | 0 | addr6->sin6_addr.s6_addr[11] = 0xff; |
389 | 0 | memcpy(&addr6->sin6_addr.s6_addr[12], |
390 | 0 | &((struct sockaddr_in *)ifc->ifa_addr)->sin_addr, |
391 | 0 | sizeof(struct in_addr)); |
392 | 0 | lwsl_debug("%s: uplevelling ipv4 bind to ipv6\n", __func__); |
393 | 0 | break; |
394 | 0 | } |
395 | | |
396 | 0 | sco = IP_SCORE_GLOBAL_NATIVE; |
397 | 0 | #endif |
398 | 0 | rc = LWS_ITOSA_USABLE; |
399 | 0 | memcpy(addr, (struct sockaddr_in *)ifc->ifa_addr, |
400 | 0 | sizeof(struct sockaddr_in)); |
401 | 0 | break; |
402 | 0 | #if defined(LWS_WITH_IPV6) |
403 | 0 | case AF_INET6: |
404 | 0 | p = (const uint8_t *) |
405 | 0 | &((struct sockaddr_in6 *)ifc->ifa_addr)->sin6_addr; |
406 | 0 | ts = IP_SCORE_IPV6_SCOPE_BASE; |
407 | 0 | if (p[0] == 0xff) |
408 | 0 | ts = (unsigned long)(IP_SCORE_IPV6_SCOPE_BASE + (p[1] & 0xf)); |
409 | |
|
410 | 0 | if (sco >= ts) |
411 | 0 | break; |
412 | | |
413 | 0 | sco = ts; |
414 | 0 | rc = LWS_ITOSA_USABLE; |
415 | |
|
416 | 0 | memcpy(&addr6->sin6_addr, |
417 | 0 | &((struct sockaddr_in6 *)ifc->ifa_addr)->sin6_addr, |
418 | 0 | sizeof(struct in6_addr)); |
419 | 0 | break; |
420 | 0 | #endif |
421 | 0 | default: |
422 | 0 | break; |
423 | 0 | } |
424 | 0 | } |
425 | | |
426 | 0 | freeifaddrs(ifr); |
427 | |
|
428 | 0 | if (rc && |
429 | 0 | !lws_sa46_parse_numeric_address(ifname, (lws_sockaddr46 *)addr)) |
430 | 0 | rc = LWS_ITOSA_USABLE; |
431 | |
|
432 | 0 | return rc; |
433 | 0 | } |
434 | | |
435 | | |
436 | | const char * |
437 | | lws_plat_inet_ntop(int af, const void *src, char *dst, socklen_t cnt) |
438 | 0 | { |
439 | 0 | return inet_ntop(af, src, dst, cnt); |
440 | 0 | } |
441 | | |
442 | | int |
443 | | lws_plat_inet_pton(int af, const char *src, void *dst) |
444 | 0 | { |
445 | 0 | return inet_pton(af, src, dst); |
446 | 0 | } |
447 | | |
448 | | int |
449 | | lws_plat_ifname_to_hwaddr(int fd, const char *ifname, uint8_t *hwaddr, int len) |
450 | 0 | { |
451 | 0 | #if defined(__linux__) |
452 | 0 | struct ifreq i; |
453 | |
|
454 | 0 | memset(&i, 0, sizeof(i)); |
455 | 0 | lws_strncpy(i.ifr_name, ifname, sizeof(i.ifr_name)); |
456 | |
|
457 | 0 | if (ioctl(fd, SIOCGIFHWADDR, &i) < 0) |
458 | 0 | return -1; |
459 | | |
460 | 0 | memcpy(hwaddr, &i.ifr_hwaddr.sa_data, 6); |
461 | |
|
462 | 0 | return 6; |
463 | | #else |
464 | | lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__); |
465 | | |
466 | | return -1; |
467 | | #endif |
468 | 0 | } |
469 | | |
470 | | int |
471 | | lws_plat_rawudp_broadcast(uint8_t *p, const uint8_t *canned, size_t canned_len, |
472 | | size_t n, int fd, const char *iface) |
473 | 0 | { |
474 | 0 | #if defined(__linux__) |
475 | 0 | struct sockaddr_ll sll; |
476 | 0 | uint16_t *p16 = (uint16_t *)p; |
477 | 0 | uint32_t ucs = 0; |
478 | |
|
479 | 0 | memcpy(p, canned, canned_len); |
480 | |
|
481 | 0 | p[2] = (uint8_t)(n >> 8); |
482 | 0 | p[3] = (uint8_t)(n); |
483 | |
|
484 | 0 | while (p16 < (uint16_t *)(p + 20)) |
485 | 0 | ucs = ucs + (uint32_t)(ntohs((uint16_t)(*p16++))); |
486 | |
|
487 | 0 | ucs += ucs >> 16; |
488 | 0 | ucs ^= 0xffff; |
489 | |
|
490 | 0 | p[10] = (uint8_t)(ucs >> 8); |
491 | 0 | p[11] = (uint8_t)(ucs); |
492 | 0 | p[24] = (uint8_t)((n - 20) >> 8); |
493 | 0 | p[25] = (uint8_t)((n - 20)); |
494 | |
|
495 | 0 | memset(&sll, 0, sizeof(sll)); |
496 | 0 | sll.sll_family = AF_PACKET; |
497 | 0 | sll.sll_protocol = (uint16_t)(htons((uint16_t)0x800)); |
498 | 0 | sll.sll_halen = 6; |
499 | 0 | sll.sll_ifindex = (int)if_nametoindex(iface); |
500 | 0 | memset(sll.sll_addr, 0xff, 6); |
501 | |
|
502 | 0 | return (int)sendto(fd, p, n, 0, (struct sockaddr *)&sll, sizeof(sll)); |
503 | | #else |
504 | | lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__); |
505 | | |
506 | | return -1; |
507 | | #endif |
508 | 0 | } |
509 | | |
510 | | int |
511 | | lws_plat_if_up(const char *ifname, int fd, int up) |
512 | 0 | { |
513 | 0 | #if defined(__linux__) |
514 | 0 | struct ifreq ifr; |
515 | |
|
516 | 0 | memset(&ifr, 0, sizeof(ifr)); |
517 | 0 | lws_strncpy(ifr.ifr_name, ifname, IFNAMSIZ); |
518 | |
|
519 | 0 | if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) { |
520 | 0 | lwsl_err("%s: SIOCGIFFLAGS fail\n", __func__); |
521 | 0 | return 1; |
522 | 0 | } |
523 | | |
524 | 0 | if (up) |
525 | 0 | ifr.ifr_flags |= IFF_UP; |
526 | 0 | else |
527 | 0 | ifr.ifr_flags &= ~IFF_UP; |
528 | |
|
529 | 0 | if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0) { |
530 | 0 | lwsl_err("%s: SIOCSIFFLAGS fail\n", __func__); |
531 | 0 | return 1; |
532 | 0 | } |
533 | | |
534 | 0 | return 0; |
535 | | #else |
536 | | lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__); |
537 | | |
538 | | return -1; |
539 | | #endif |
540 | 0 | } |
541 | | |
542 | | int |
543 | | lws_plat_BINDTODEVICE(lws_sockfd_type fd, const char *ifname) |
544 | 0 | { |
545 | 0 | #if defined(__linux__) |
546 | 0 | struct ifreq i; |
547 | |
|
548 | 0 | memset(&i, 0, sizeof(i)); |
549 | 0 | i.ifr_addr.sa_family = AF_INET; |
550 | 0 | lws_strncpy(i.ifr_ifrn.ifrn_name, ifname, |
551 | 0 | sizeof(i.ifr_ifrn.ifrn_name)); |
552 | 0 | if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &i, sizeof(i)) < 0) { |
553 | 0 | lwsl_notice("%s: failed %d\n", __func__, LWS_ERRNO); |
554 | 0 | return 1; |
555 | 0 | } |
556 | | |
557 | 0 | return 0; |
558 | | #else |
559 | | lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__); |
560 | | |
561 | | return -1; |
562 | | #endif |
563 | 0 | } |
564 | | |
565 | | int |
566 | | lws_plat_ifconfig(int fd, lws_dhcpc_ifstate_t *is) |
567 | 0 | { |
568 | 0 | #if defined(__linux__) |
569 | 0 | struct rtentry route; |
570 | 0 | struct ifreq ifr; |
571 | |
|
572 | 0 | memset(&ifr, 0, sizeof(ifr)); |
573 | 0 | memset(&route, 0, sizeof(route)); |
574 | |
|
575 | 0 | lws_strncpy(ifr.ifr_name, is->ifname, IFNAMSIZ); |
576 | |
|
577 | 0 | lws_plat_if_up(is->ifname, fd, 0); |
578 | |
|
579 | 0 | memcpy(&ifr.ifr_addr, &is->sa46[LWSDH_SA46_IP], sizeof(struct sockaddr)); |
580 | 0 | if (ioctl(fd, SIOCSIFADDR, &ifr) < 0) { |
581 | 0 | lwsl_err("%s: SIOCSIFADDR fail\n", __func__); |
582 | 0 | return 1; |
583 | 0 | } |
584 | | |
585 | 0 | if (is->sa46[LWSDH_SA46_IP].sa4.sin_family == AF_INET) { |
586 | 0 | struct sockaddr_in sin; |
587 | |
|
588 | 0 | memset(&sin, 0, sizeof(sin)); |
589 | 0 | sin.sin_family = AF_INET; |
590 | 0 | sin.sin_addr.s_addr = *(uint32_t *)&is->nums[LWSDH_IPV4_SUBNET_MASK]; |
591 | 0 | memcpy(&ifr.ifr_addr, &sin, sizeof(struct sockaddr)); |
592 | 0 | if (ioctl(fd, SIOCSIFNETMASK, &ifr) < 0) { |
593 | 0 | lwsl_err("%s: SIOCSIFNETMASK fail\n", __func__); |
594 | 0 | return 1; |
595 | 0 | } |
596 | | |
597 | 0 | lws_plat_if_up(is->ifname, fd, 1); |
598 | |
|
599 | 0 | memcpy(&route.rt_gateway, |
600 | 0 | &is->sa46[LWSDH_SA46_IPV4_ROUTER].sa4, |
601 | 0 | sizeof(struct sockaddr)); |
602 | |
|
603 | 0 | sin.sin_addr.s_addr = 0; |
604 | 0 | memcpy(&route.rt_dst, &sin, sizeof(struct sockaddr)); |
605 | 0 | memcpy(&route.rt_genmask, &sin, sizeof(struct sockaddr)); |
606 | |
|
607 | 0 | route.rt_flags = RTF_UP | RTF_GATEWAY; |
608 | 0 | route.rt_metric = 100; |
609 | 0 | route.rt_dev = (char *)is->ifname; |
610 | |
|
611 | 0 | if (ioctl(fd, SIOCADDRT, &route) < 0) { |
612 | 0 | lwsl_err("%s: SIOCADDRT 0x%x fail: %d\n", __func__, |
613 | 0 | (unsigned int)htonl(*(uint32_t *)&is-> |
614 | 0 | sa46[LWSDH_SA46_IPV4_ROUTER]. |
615 | 0 | sa4.sin_addr.s_addr), LWS_ERRNO); |
616 | 0 | return 1; |
617 | 0 | } |
618 | 0 | } else |
619 | 0 | lws_plat_if_up(is->ifname, fd, 1); |
620 | | |
621 | 0 | return 0; |
622 | | #else |
623 | | lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__); |
624 | | |
625 | | return -1; |
626 | | #endif |
627 | 0 | } |
628 | | |
629 | | int |
630 | | lws_plat_vhost_tls_client_ctx_init(struct lws_vhost *vhost) |
631 | 0 | { |
632 | 0 | return 0; |
633 | 0 | } |
634 | | |
635 | | #if defined(LWS_WITH_MBEDTLS) |
636 | | int |
637 | | lws_plat_mbedtls_net_send(void *ctx, const uint8_t *buf, size_t len) |
638 | | { |
639 | | int fd = ((mbedtls_net_context *) ctx)->MBEDTLS_PRIVATE_V30_ONLY(fd); |
640 | | int ret; |
641 | | |
642 | | if (fd < 0) |
643 | | return MBEDTLS_ERR_NET_INVALID_CONTEXT; |
644 | | |
645 | | ret = (int)write(fd, buf, len); |
646 | | if (ret >= 0) |
647 | | return ret; |
648 | | |
649 | | if (errno == EAGAIN || errno == EWOULDBLOCK) |
650 | | return MBEDTLS_ERR_SSL_WANT_WRITE; |
651 | | |
652 | | if (errno == EPIPE || errno == ECONNRESET) |
653 | | return MBEDTLS_ERR_NET_CONN_RESET; |
654 | | |
655 | | if( errno == EINTR ) |
656 | | return MBEDTLS_ERR_SSL_WANT_WRITE; |
657 | | |
658 | | return MBEDTLS_ERR_NET_SEND_FAILED; |
659 | | } |
660 | | |
661 | | int |
662 | | lws_plat_mbedtls_net_recv(void *ctx, unsigned char *buf, size_t len) |
663 | | { |
664 | | int fd = ((mbedtls_net_context *) ctx)->MBEDTLS_PRIVATE_V30_ONLY(fd); |
665 | | int ret; |
666 | | |
667 | | if (fd < 0) |
668 | | return MBEDTLS_ERR_NET_INVALID_CONTEXT; |
669 | | |
670 | | ret = (int)read(fd, buf, len); |
671 | | if (ret >= 0) |
672 | | return ret; |
673 | | |
674 | | if (errno == EAGAIN || errno == EWOULDBLOCK) |
675 | | return MBEDTLS_ERR_SSL_WANT_READ; |
676 | | |
677 | | if (errno == EPIPE || errno == ECONNRESET) |
678 | | return MBEDTLS_ERR_NET_CONN_RESET; |
679 | | |
680 | | if (errno == EINTR) |
681 | | return MBEDTLS_ERR_SSL_WANT_READ; |
682 | | |
683 | | return MBEDTLS_ERR_NET_RECV_FAILED; |
684 | | } |
685 | | #endif |