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
27 int
lws_send_pipe_choked(struct lws * wsi)28 lws_send_pipe_choked(struct lws *wsi)
29 {
30 struct lws *wsi_eff = wsi;
31 fd_set writefds;
32 struct timeval tv = { 0, 0 };
33 int n;
34 #if defined(LWS_WITH_HTTP2)
35 wsi_eff = lws_get_network_wsi(wsi);
36 #endif
37
38 /* the fact we checked implies we avoided back-to-back writes */
39 wsi_eff->could_have_pending = 0;
40
41 /* treat the fact we got a truncated send pending as if we're choked */
42 if (lws_has_buffered_out(wsi)
43 #if defined(LWS_WITH_HTTP_STREAM_COMPRESSION)
44 || wsi->http.comp_ctx.buflist_comp ||
45 wsi->http.comp_ctx.may_have_more
46 #endif
47 )
48 return 1;
49
50 FD_ZERO(&writefds);
51 FD_SET(wsi_eff->desc.sockfd, &writefds);
52
53 n = select(wsi_eff->desc.sockfd + 1, NULL, &writefds, NULL, &tv);
54 if (n < 0)
55 return 1; /* choked */
56
57 return !n; /* n = 0 = not writable = choked */
58 }
59
60 int
lws_poll_listen_fd(struct lws_pollfd * fd)61 lws_poll_listen_fd(struct lws_pollfd *fd)
62 {
63 fd_set readfds;
64 struct timeval tv = { 0, 0 };
65
66 FD_ZERO(&readfds);
67 FD_SET(fd->fd, &readfds);
68
69 return select(fd->fd + 1, &readfds, NULL, NULL, &tv);
70 }
71
72 int
lws_plat_set_nonblocking(lws_sockfd_type fd)73 lws_plat_set_nonblocking(lws_sockfd_type fd)
74 {
75 return fcntl(fd, F_SETFL, O_NONBLOCK) < 0;
76 }
77
78 int
lws_plat_set_socket_options(struct lws_vhost * vhost,int fd,int unix_skt)79 lws_plat_set_socket_options(struct lws_vhost *vhost, int fd, int unix_skt)
80 {
81 int optval = 1;
82 socklen_t optlen = sizeof(optval);
83
84 #if defined(__APPLE__) || \
85 defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \
86 defined(__NetBSD__) || \
87 defined(__OpenBSD__)
88 struct protoent *tcp_proto;
89 #endif
90
91 if (vhost->ka_time) {
92 /* enable keepalive on this socket */
93 optval = 1;
94 if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE,
95 (const void *)&optval, optlen) < 0)
96 return 1;
97
98 #if defined(__APPLE__) || \
99 defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \
100 defined(__NetBSD__) || \
101 defined(__CYGWIN__) || defined(__OpenBSD__) || defined (__sun)
102
103 /*
104 * didn't find a way to set these per-socket, need to
105 * tune kernel systemwide values
106 */
107 #else
108 /* set the keepalive conditions we want on it too */
109 optval = vhost->ka_time;
110 if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE,
111 (const void *)&optval, optlen) < 0)
112 return 1;
113
114 optval = vhost->ka_interval;
115 if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL,
116 (const void *)&optval, optlen) < 0)
117 return 1;
118
119 optval = vhost->ka_probes;
120 if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT,
121 (const void *)&optval, optlen) < 0)
122 return 1;
123 #endif
124 }
125
126 /* Disable Nagle */
127 optval = 1;
128 if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &optval, optlen) < 0)
129 return 1;
130
131 return lws_plat_set_nonblocking(fd);
132 }
133
134 /* cast a struct sockaddr_in6 * into addr for ipv6 */
135
136 int
lws_interface_to_sa(int ipv6,const char * ifname,struct sockaddr_in * addr,size_t addrlen)137 lws_interface_to_sa(int ipv6, const char *ifname, struct sockaddr_in *addr,
138 size_t addrlen)
139 {
140 #if 0
141 int rc = LWS_ITOSA_NOT_EXIST;
142
143 struct ifaddrs *ifr;
144 struct ifaddrs *ifc;
145 #ifdef LWS_WITH_IPV6
146 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr;
147 #endif
148
149 getifaddrs(&ifr);
150 for (ifc = ifr; ifc != NULL && rc; ifc = ifc->ifa_next) {
151 if (!ifc->ifa_addr)
152 continue;
153
154 lwsl_info(" interface %s vs %s\n", ifc->ifa_name, ifname);
155
156 if (strcmp(ifc->ifa_name, ifname))
157 continue;
158
159 switch (ifc->ifa_addr->sa_family) {
160 case AF_INET:
161 #ifdef LWS_WITH_IPV6
162 if (ipv6) {
163 /* map IPv4 to IPv6 */
164 memset((char *)&addr6->sin6_addr, 0,
165 sizeof(struct in6_addr));
166 addr6->sin6_addr.s6_addr[10] = 0xff;
167 addr6->sin6_addr.s6_addr[11] = 0xff;
168 memcpy(&addr6->sin6_addr.s6_addr[12],
169 &((struct sockaddr_in *)ifc->ifa_addr)->sin_addr,
170 sizeof(struct in_addr));
171 } else
172 #endif
173 memcpy(addr,
174 (struct sockaddr_in *)ifc->ifa_addr,
175 sizeof(struct sockaddr_in));
176 break;
177 #ifdef LWS_WITH_IPV6
178 case AF_INET6:
179 memcpy(&addr6->sin6_addr,
180 &((struct sockaddr_in6 *)ifc->ifa_addr)->sin6_addr,
181 sizeof(struct in6_addr));
182 break;
183 #endif
184 default:
185 continue;
186 }
187 rc = LWS_ITOSA_USABLE;
188 }
189
190 freeifaddrs(ifr);
191
192 if (rc == LWS_ITOSA_NOT_EXIST) {
193 /* check if bind to IP address */
194 #ifdef LWS_WITH_IPV6
195 if (inet_pton(AF_INET6, ifname, &addr6->sin6_addr) == 1)
196 rc = LWS_ITOSA_USABLE;
197 else
198 #endif
199 if (inet_pton(AF_INET, ifname, &addr->sin_addr) == 1)
200 rc = LWS_ITOSA_USABLE;
201 }
202
203 return rc;
204 #endif
205
206 return LWS_ITOSA_NOT_EXIST;
207 }
208
209 const char *
lws_plat_inet_ntop(int af,const void * src,char * dst,int cnt)210 lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)
211 {
212 return inet_ntop(af, src, dst, cnt);
213 }
214
215 int
lws_plat_inet_pton(int af,const char * src,void * dst)216 lws_plat_inet_pton(int af, const char *src, void *dst)
217 {
218 return 1; // inet_pton(af, src, dst);
219 }
220
221 int
lws_plat_ifname_to_hwaddr(int fd,const char * ifname,uint8_t * hwaddr,int len)222 lws_plat_ifname_to_hwaddr(int fd, const char *ifname, uint8_t *hwaddr, int len)
223 {
224 lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
225
226 return -1;
227 }
228
229 int
lws_plat_rawudp_broadcast(uint8_t * p,const uint8_t * canned,int canned_len,int n,int fd,const char * iface)230 lws_plat_rawudp_broadcast(uint8_t *p, const uint8_t *canned, int canned_len,
231 int n, int fd, const char *iface)
232 {
233 lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
234
235 return -1;
236 }
237
238 int
lws_plat_if_up(const char * ifname,int fd,int up)239 lws_plat_if_up(const char *ifname, int fd, int up)
240 {
241 lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
242
243 return -1;
244 }
245
246 int
lws_plat_BINDTODEVICE(lws_sockfd_type fd,const char * ifname)247 lws_plat_BINDTODEVICE(lws_sockfd_type fd, const char *ifname)
248 {
249 lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
250
251 return -1;
252 }
253
254 int
lws_plat_ifconfig_ip(const char * ifname,int fd,uint8_t * ip,uint8_t * mask_ip,uint8_t * gateway_ip)255 lws_plat_ifconfig_ip(const char *ifname, int fd, uint8_t *ip, uint8_t *mask_ip,
256 uint8_t *gateway_ip)
257 {
258 lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
259
260 return -1;
261 }
262