1/*
2 * libwebsockets - small server side websockets and web server implementation
3 *
4 * Copyright (C) 2010 - 2019 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#include "private-lib-core.h"
26#include <errno.h>
27#if defined(LWS_WITH_MBEDTLS)
28#if defined(LWS_HAVE_MBEDTLS_NET_SOCKETS)
29#include "mbedtls/net_sockets.h"
30#else
31#include "mbedtls/net.h"
32#endif
33#endif
34
35int
36lws_send_pipe_choked(struct lws *wsi)
37{
38	struct lws *wsi_eff = wsi;
39	fd_set writefds;
40	struct timeval tv = { 0, 0 };
41	int n;
42#if defined(LWS_WITH_HTTP2)
43	wsi_eff = lws_get_network_wsi(wsi);
44#endif
45
46	/* the fact we checked implies we avoided back-to-back writes */
47	wsi_eff->could_have_pending = 0;
48
49	/* treat the fact we got a truncated send pending as if we're choked */
50	if (lws_has_buffered_out(wsi)
51#if defined(LWS_WITH_HTTP_STREAM_COMPRESSION)
52	    || wsi->http.comp_ctx.buflist_comp ||
53	       wsi->http.comp_ctx.may_have_more
54#endif
55	)
56		return 1;
57
58	FD_ZERO(&writefds);
59	FD_SET(wsi_eff->desc.sockfd, &writefds);
60
61	n = select(wsi_eff->desc.sockfd + 1, NULL, &writefds, NULL, &tv);
62	if (n < 0)
63		return 1; /* choked */
64
65	return !n; /* n = 0 = not writable = choked */
66}
67
68int
69lws_poll_listen_fd(struct lws_pollfd *fd)
70{
71	fd_set readfds;
72	struct timeval tv = { 0, 0 };
73
74	FD_ZERO(&readfds);
75	FD_SET(fd->fd, &readfds);
76
77	return select(fd->fd + 1, &readfds, NULL, NULL, &tv);
78}
79
80int
81lws_plat_set_nonblocking(lws_sockfd_type fd)
82{
83	return fcntl(fd, F_SETFL, O_NONBLOCK) < 0;
84}
85
86int
87lws_plat_set_socket_options(struct lws_vhost *vhost, int fd, int unix_skt)
88{
89	int optval = 1;
90	socklen_t optlen = sizeof(optval);
91
92#if defined(__APPLE__) || \
93    defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \
94    defined(__NetBSD__) || \
95    defined(__OpenBSD__)
96	struct protoent *tcp_proto;
97#endif
98
99	if (vhost->ka_time) {
100		/* enable keepalive on this socket */
101		optval = 1;
102		if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE,
103			       (const void *)&optval, optlen) < 0)
104			return 1;
105
106#if defined(__APPLE__) || \
107    defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \
108    defined(__NetBSD__) || \
109        defined(__CYGWIN__) || defined(__OpenBSD__) || defined (__sun)
110
111		/*
112		 * didn't find a way to set these per-socket, need to
113		 * tune kernel systemwide values
114		 */
115#else
116		/* set the keepalive conditions we want on it too */
117		optval = vhost->ka_time;
118		if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE,
119			       (const void *)&optval, optlen) < 0)
120			return 1;
121
122		optval = vhost->ka_interval;
123		if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL,
124			       (const void *)&optval, optlen) < 0)
125			return 1;
126
127		optval = vhost->ka_probes;
128		if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT,
129			       (const void *)&optval, optlen) < 0)
130			return 1;
131#endif
132	}
133
134	/* Disable Nagle */
135	optval = 1;
136	if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &optval, optlen) < 0)
137		return 1;
138
139	return lws_plat_set_nonblocking(fd);
140}
141
142static const int ip_opt_lws_flags[] = {
143	LCCSCF_IP_LOW_LATENCY, LCCSCF_IP_HIGH_THROUGHPUT,
144	LCCSCF_IP_HIGH_RELIABILITY, LCCSCF_IP_LOW_COST
145}, ip_opt_val[] = {
146	IPTOS_LOWDELAY, IPTOS_THROUGHPUT, IPTOS_RELIABILITY, IPTOS_MINCOST
147};
148#if !defined(LWS_WITH_NO_LOGS)
149static const char *ip_opt_names[] = {
150	"LOWDELAY", "THROUGHPUT", "RELIABILITY", "MINCOST"
151};
152#endif
153
154int
155lws_plat_set_socket_options_ip(lws_sockfd_type fd, uint8_t pri, int lws_flags)
156{
157	int optval = (int)pri, ret = 0, n;
158	socklen_t optlen = sizeof(optval);
159#if !defined(LWS_WITH_NO_LOGS)
160	int en;
161#endif
162
163#if defined(SO_PRIORITY)
164	if (pri) { /* 0 is the default already */
165		if (setsockopt(fd, SOL_SOCKET, SO_PRIORITY,
166				(const void *)&optval, optlen) < 0) {
167#if !defined(LWS_WITH_NO_LOGS)
168			en = errno;
169			lwsl_warn("%s: unable to set socket pri %d: errno %d\n",
170				  __func__, (int)pri, en);
171#endif
172			ret = 1;
173		} else
174			lwsl_notice("%s: set pri %u\n", __func__, pri);
175	}
176#endif
177
178	for (n = 0; n < 4; n++) {
179		if (!(lws_flags & ip_opt_lws_flags[n]))
180			continue;
181
182		optval = (int)ip_opt_val[n];
183		if (setsockopt(fd, IPPROTO_IP, IP_TOS, (const void *)&optval,
184			       optlen) < 0) {
185#if !defined(LWS_WITH_NO_LOGS)
186			en = errno;
187			lwsl_warn("%s: unable to set %s: errno %d\n", __func__,
188				  ip_opt_names[n], en);
189#endif
190			ret = 1;
191		} else
192			lwsl_notice("%s: set ip flag %s\n", __func__,
193				    ip_opt_names[n]);
194	}
195
196	return ret;
197}
198
199/* cast a struct sockaddr_in6 * into addr for ipv6 */
200
201int
202lws_interface_to_sa(int ipv6, const char *ifname, struct sockaddr_in *addr,
203		    size_t addrlen)
204{
205#if 0
206	int rc = LWS_ITOSA_NOT_EXIST;
207
208	struct ifaddrs *ifr;
209	struct ifaddrs *ifc;
210#ifdef LWS_WITH_IPV6
211	struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr;
212#endif
213
214	getifaddrs(&ifr);
215	for (ifc = ifr; ifc != NULL && rc; ifc = ifc->ifa_next) {
216		if (!ifc->ifa_addr)
217			continue;
218
219		lwsl_info(" interface %s vs %s\n", ifc->ifa_name, ifname);
220
221		if (strcmp(ifc->ifa_name, ifname))
222			continue;
223
224		switch (ifc->ifa_addr->sa_family) {
225		case AF_INET:
226#ifdef LWS_WITH_IPV6
227			if (ipv6) {
228				/* map IPv4 to IPv6 */
229				memset((char *)&addr6->sin6_addr, 0,
230						sizeof(struct in6_addr));
231				addr6->sin6_addr.s6_addr[10] = 0xff;
232				addr6->sin6_addr.s6_addr[11] = 0xff;
233				memcpy(&addr6->sin6_addr.s6_addr[12],
234					&((struct sockaddr_in *)ifc->ifa_addr)->sin_addr,
235							sizeof(struct in_addr));
236			} else
237#endif
238				memcpy(addr,
239					(struct sockaddr_in *)ifc->ifa_addr,
240						    sizeof(struct sockaddr_in));
241			break;
242#ifdef LWS_WITH_IPV6
243		case AF_INET6:
244			memcpy(&addr6->sin6_addr,
245			  &((struct sockaddr_in6 *)ifc->ifa_addr)->sin6_addr,
246						       sizeof(struct in6_addr));
247			break;
248#endif
249		default:
250			continue;
251		}
252		rc = LWS_ITOSA_USABLE;
253	}
254
255	freeifaddrs(ifr);
256
257	if (rc == LWS_ITOSA_NOT_EXIST) {
258		/* check if bind to IP address */
259#ifdef LWS_WITH_IPV6
260		if (inet_pton(AF_INET6, ifname, &addr6->sin6_addr) == 1)
261			rc = LWS_ITOSA_USABLE;
262		else
263#endif
264		if (inet_pton(AF_INET, ifname, &addr->sin_addr) == 1)
265			rc = LWS_ITOSA_USABLE;
266	}
267
268	return rc;
269#endif
270
271	return LWS_ITOSA_NOT_EXIST;
272}
273
274const char *
275lws_plat_inet_ntop(int af, const void *src, char *dst, socklen_t cnt)
276{
277	return inet_ntop(af, src, dst, cnt);
278}
279
280int
281lws_plat_inet_pton(int af, const char *src, void *dst)
282{
283	return 1; //  inet_pton(af, src, dst);
284}
285
286int
287lws_plat_ifname_to_hwaddr(int fd, const char *ifname, uint8_t *hwaddr, int len)
288{
289	lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
290
291	return -1;
292}
293
294int
295lws_plat_rawudp_broadcast(uint8_t *p, const uint8_t *canned, size_t canned_len,
296			  size_t n, int fd, const char *iface)
297{
298	lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
299
300	return -1;
301}
302
303int
304lws_plat_if_up(const char *ifname, int fd, int up)
305{
306	lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
307
308	return -1;
309}
310
311int
312lws_plat_BINDTODEVICE(lws_sockfd_type fd, const char *ifname)
313{
314	lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
315
316	return -1;
317}
318
319int
320lws_plat_ifconfig(int fd, lws_dhcpc_ifstate_t *is)
321{
322	lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
323
324	return -1;
325}
326
327int
328lws_plat_vhost_tls_client_ctx_init(struct lws_vhost *vhost)
329{
330	return 0;
331}
332
333#if defined(LWS_WITH_MBEDTLS)
334int
335lws_plat_mbedtls_net_send(void *ctx, const uint8_t *buf, size_t len)
336{
337	int fd = ((mbedtls_net_context *) ctx)->fd;
338	int ret;
339
340	if (fd < 0)
341		return MBEDTLS_ERR_NET_INVALID_CONTEXT;
342
343	ret = write(fd, buf, len);
344	if (ret >= 0)
345		return ret;
346
347	if (errno == EAGAIN || errno == EWOULDBLOCK)
348		return MBEDTLS_ERR_SSL_WANT_WRITE;
349
350	if (errno == EPIPE || errno == ECONNRESET)
351		return MBEDTLS_ERR_NET_CONN_RESET;
352
353	if( errno == EINTR )
354		return MBEDTLS_ERR_SSL_WANT_WRITE;
355
356	return MBEDTLS_ERR_NET_SEND_FAILED;
357}
358
359int
360lws_plat_mbedtls_net_recv(void *ctx, unsigned char *buf, size_t len)
361{
362	int fd = ((mbedtls_net_context *) ctx)->fd;
363	int ret;
364
365	if (fd < 0)
366		return MBEDTLS_ERR_NET_INVALID_CONTEXT;
367
368	ret = (int)read(fd, buf, len);
369	if (ret >= 0)
370		return ret;
371
372	if (errno == EAGAIN || errno == EWOULDBLOCK)
373		return MBEDTLS_ERR_SSL_WANT_READ;
374
375	if (errno == EPIPE || errno == ECONNRESET)
376		return MBEDTLS_ERR_NET_CONN_RESET;
377
378	if (errno == EINTR || !errno)
379		return MBEDTLS_ERR_SSL_WANT_READ;
380
381	return MBEDTLS_ERR_NET_RECV_FAILED;
382}
383#endif
384
385