blob: 52069cc9a3c35a232b8865f92d074f37bdfbe0be [file] [log] [blame]
Andy Greene40aa9b2014-04-02 21:02:54 +08001#include "private-libwebsockets.h"
2
Andy Greenbfaea952014-03-31 11:01:32 +08003/*
4 * included from libwebsockets.c for unix builds
5 */
6
Andy Greene40aa9b2014-04-02 21:02:54 +08007unsigned long long time_in_microseconds(void)
Andy Greenbfaea952014-03-31 11:01:32 +08008{
9 struct timeval tv;
10 gettimeofday(&tv, NULL);
Imo Farcher97a748a2015-01-26 15:39:36 +080011 return ((unsigned long long)tv.tv_sec * 1000000LL) + tv.tv_usec;
Andy Greenbfaea952014-03-31 11:01:32 +080012}
13
14LWS_VISIBLE int libwebsockets_get_random(struct libwebsocket_context *context,
15 void *buf, int len)
16{
17 return read(context->fd_random, (char *)buf, len);
18}
19
20LWS_VISIBLE int lws_send_pipe_choked(struct libwebsocket *wsi)
21{
22 struct libwebsocket_pollfd fds;
23
24 /* treat the fact we got a truncated send pending as if we're choked */
25 if (wsi->truncated_send_len)
26 return 1;
27
28 fds.fd = wsi->sock;
29 fds.events = POLLOUT;
30 fds.revents = 0;
31
32 if (poll(&fds, 1, 0) != 1)
33 return 1;
34
35 if ((fds.revents & POLLOUT) == 0)
36 return 1;
37
38 /* okay to send another packet without blocking */
39
40 return 0;
41}
42
Andy Greene40aa9b2014-04-02 21:02:54 +080043LWS_VISIBLE int
44lws_poll_listen_fd(struct libwebsocket_pollfd *fd)
Andy Greenbfaea952014-03-31 11:01:32 +080045{
46 return poll(fd, 1, 0);
47}
48
Andy Greene40aa9b2014-04-02 21:02:54 +080049/*
50 * This is just used to interrupt poll waiting
51 * we don't have to do anything with it.
52 */
Andy Greene40aa9b2014-04-02 21:02:54 +080053static void lws_sigusr2(int sig)
54{
55}
Andy Greenbfaea952014-03-31 11:01:32 +080056
Andy Greenbfaea952014-03-31 11:01:32 +080057/**
58 * libwebsocket_cancel_service() - Cancel servicing of pending websocket activity
59 * @context: Websocket context
60 *
61 * This function let a call to libwebsocket_service() waiting for a timeout
62 * immediately return.
63 */
64LWS_VISIBLE void
65libwebsocket_cancel_service(struct libwebsocket_context *context)
66{
67 char buf = 0;
68
69 if (write(context->dummy_pipe_fds[1], &buf, sizeof(buf)) != 1)
70 lwsl_err("Cannot write to dummy pipe");
71}
72
73LWS_VISIBLE void lwsl_emit_syslog(int level, const char *line)
74{
75 int syslog_level = LOG_DEBUG;
76
77 switch (level) {
78 case LLL_ERR:
79 syslog_level = LOG_ERR;
80 break;
81 case LLL_WARN:
82 syslog_level = LOG_WARNING;
83 break;
84 case LLL_NOTICE:
85 syslog_level = LOG_NOTICE;
86 break;
87 case LLL_INFO:
88 syslog_level = LOG_INFO;
89 break;
90 }
91 syslog(syslog_level, "%s", line);
Andy Green158e8042014-04-02 14:25:10 +080092}
93
94LWS_VISIBLE int
95lws_plat_service(struct libwebsocket_context *context, int timeout_ms)
96{
97 int n;
98 int m;
99 char buf;
Andy Green30edd912015-01-29 09:42:22 +0800100#ifdef LWS_OPENSSL_SUPPORT
Andy Green52815602015-01-29 08:36:18 +0800101 struct libwebsocket *wsi, *wsi_next;
Andy Green30edd912015-01-29 09:42:22 +0800102#endif
Andy Green158e8042014-04-02 14:25:10 +0800103
104 /* stay dead once we are dead */
105
Andy Greena717df22014-04-11 13:14:37 +0800106 if (!context)
Andy Green158e8042014-04-02 14:25:10 +0800107 return 1;
108
Andy Greena717df22014-04-11 13:14:37 +0800109 lws_libev_run(context);
110
Andy Green158e8042014-04-02 14:25:10 +0800111 context->service_tid = context->protocols[0].callback(context, NULL,
112 LWS_CALLBACK_GET_THREAD_ID, NULL, NULL, 0);
113
Andy Green609ec852014-10-09 08:29:22 +0800114#ifdef LWS_OPENSSL_SUPPORT
115 /* if we know we have non-network pending data, do not wait in poll */
Andy Green52815602015-01-29 08:36:18 +0800116 if (lws_ssl_anybody_has_buffered_read(context))
Andy Green609ec852014-10-09 08:29:22 +0800117 timeout_ms = 0;
118#endif
Andy Green158e8042014-04-02 14:25:10 +0800119 n = poll(context->fds, context->fds_count, timeout_ms);
120 context->service_tid = 0;
121
Andy Green609ec852014-10-09 08:29:22 +0800122#ifdef LWS_OPENSSL_SUPPORT
Andy Green52815602015-01-29 08:36:18 +0800123 if (!lws_ssl_anybody_has_buffered_read(context) && n == 0) {
Andy Green609ec852014-10-09 08:29:22 +0800124#else
Andy Green158e8042014-04-02 14:25:10 +0800125 if (n == 0) /* poll timeout */ {
Andy Green609ec852014-10-09 08:29:22 +0800126#endif
Andy Green158e8042014-04-02 14:25:10 +0800127 libwebsocket_service_fd(context, NULL);
128 return 0;
129 }
130
131 if (n < 0) {
132 if (LWS_ERRNO != LWS_EINTR)
133 return -1;
134 return 0;
135 }
136
Andy Green52815602015-01-29 08:36:18 +0800137#ifdef LWS_OPENSSL_SUPPORT
138 /*
139 * For all guys with buffered SSL read data already saved up, if they
140 * are not flowcontrolled, fake their POLLIN status so they'll get
141 * service to use up the buffered incoming data, even though their
142 * network socket may have nothing
143 */
144
145 wsi = context->pending_read_list;
146 while (wsi) {
147 wsi_next = wsi->pending_read_list_next;
148 context->fds[wsi->sock].revents |=
149 context->fds[wsi->sock].events & POLLIN;
150 if (context->fds[wsi->sock].revents & POLLIN) {
151 /*
152 * he's going to get serviced now, take him off the
153 * list of guys with buffered SSL. If he still has some
154 * at the end of the service, he'll get put back on the
155 * list then.
156 */
157 lws_ssl_remove_wsi_from_buffered_list(context, wsi);
158 }
159 wsi = wsi_next;
160 }
161#endif
162
Andy Green158e8042014-04-02 14:25:10 +0800163 /* any socket with events to service? */
164
165 for (n = 0; n < context->fds_count; n++) {
Andy Green52815602015-01-29 08:36:18 +0800166
Andy Green158e8042014-04-02 14:25:10 +0800167 if (!context->fds[n].revents)
168 continue;
169
170 if (context->fds[n].fd == context->dummy_pipe_fds[0]) {
171 if (read(context->fds[n].fd, &buf, 1) != 1)
172 lwsl_err("Cannot read from dummy pipe.");
173 continue;
174 }
175
176 m = libwebsocket_service_fd(context, &context->fds[n]);
177 if (m < 0)
178 return -1;
179 /* if something closed, retry this slot */
180 if (m)
181 n--;
182 }
183
184 return 0;
185}
186
Andy Greene40aa9b2014-04-02 21:02:54 +0800187LWS_VISIBLE int
188lws_plat_set_socket_options(struct libwebsocket_context *context, int fd)
Andy Green158e8042014-04-02 14:25:10 +0800189{
190 int optval = 1;
191 socklen_t optlen = sizeof(optval);
192
geqd6827f72014-05-28 04:52:18 +0000193#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || \
194 defined(__OpenBSD__)
Andy Green158e8042014-04-02 14:25:10 +0800195 struct protoent *tcp_proto;
196#endif
197
198 if (context->ka_time) {
199 /* enable keepalive on this socket */
200 optval = 1;
201 if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE,
202 (const void *)&optval, optlen) < 0)
203 return 1;
204
geqd6827f72014-05-28 04:52:18 +0000205#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || \
206 defined(__CYGWIN__) || defined(__OpenBSD__)
Andy Green158e8042014-04-02 14:25:10 +0800207
208 /*
209 * didn't find a way to set these per-socket, need to
210 * tune kernel systemwide values
211 */
212#else
213 /* set the keepalive conditions we want on it too */
214 optval = context->ka_time;
Aurelian Popd07ea3b2014-07-29 15:36:06 +0300215 if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE,
Andy Green158e8042014-04-02 14:25:10 +0800216 (const void *)&optval, optlen) < 0)
217 return 1;
218
219 optval = context->ka_interval;
Aurelian Popd07ea3b2014-07-29 15:36:06 +0300220 if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL,
Andy Green158e8042014-04-02 14:25:10 +0800221 (const void *)&optval, optlen) < 0)
222 return 1;
223
224 optval = context->ka_probes;
Aurelian Popd07ea3b2014-07-29 15:36:06 +0300225 if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT,
Andy Green158e8042014-04-02 14:25:10 +0800226 (const void *)&optval, optlen) < 0)
227 return 1;
228#endif
229 }
230
231 /* Disable Nagle */
232 optval = 1;
geqd6827f72014-05-28 04:52:18 +0000233#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__NetBSD__) && \
234 !defined(__OpenBSD__)
Andy Greenabb48112014-11-30 13:06:09 +0800235 if (setsockopt(fd, SOL_TCP, TCP_NODELAY, (const void *)&optval, optlen) < 0)
236 return 1;
Andy Green158e8042014-04-02 14:25:10 +0800237#else
238 tcp_proto = getprotobyname("TCP");
Andy Greenabb48112014-11-30 13:06:09 +0800239 if (setsockopt(fd, tcp_proto->p_proto, TCP_NODELAY, &optval, optlen) < 0)
240 return 1;
Andy Green158e8042014-04-02 14:25:10 +0800241#endif
242
243 /* We are nonblocking... */
Andy Green956a08a2014-11-30 13:02:32 +0800244 if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
245 return 1;
Andy Green158e8042014-04-02 14:25:10 +0800246
247 return 0;
248}
249
Andy Greene40aa9b2014-04-02 21:02:54 +0800250LWS_VISIBLE void
251lws_plat_drop_app_privileges(struct lws_context_creation_info *info)
Andy Green158e8042014-04-02 14:25:10 +0800252{
253 if (info->gid != -1)
254 if (setgid(info->gid))
255 lwsl_warn("setgid: %s\n", strerror(LWS_ERRNO));
256 if (info->uid != -1)
257 if (setuid(info->uid))
Aurelian Popd07ea3b2014-07-29 15:36:06 +0300258 lwsl_warn("setuid: %s\n", strerror(LWS_ERRNO));
Andy Green158e8042014-04-02 14:25:10 +0800259}
260
Andy Greene40aa9b2014-04-02 21:02:54 +0800261LWS_VISIBLE int
262lws_plat_init_fd_tables(struct libwebsocket_context *context)
Andy Green158e8042014-04-02 14:25:10 +0800263{
Andy Greena717df22014-04-11 13:14:37 +0800264 if (lws_libev_init_fd_table(context))
265 /* libev handled it instead */
Andy Green158e8042014-04-02 14:25:10 +0800266 return 0;
Andy Greena717df22014-04-11 13:14:37 +0800267
Andy Green158e8042014-04-02 14:25:10 +0800268 if (pipe(context->dummy_pipe_fds)) {
269 lwsl_err("Unable to create pipe\n");
270 return 1;
271 }
272
273 /* use the read end of pipe as first item */
274 context->fds[0].fd = context->dummy_pipe_fds[0];
275 context->fds[0].events = LWS_POLLIN;
276 context->fds[0].revents = 0;
277 context->fds_count = 1;
Aurelian Popd07ea3b2014-07-29 15:36:06 +0300278
Andy Green158e8042014-04-02 14:25:10 +0800279 context->fd_random = open(SYSTEM_RANDOM_FILEPATH, O_RDONLY);
280 if (context->fd_random < 0) {
281 lwsl_err("Unable to open random device %s %d\n",
282 SYSTEM_RANDOM_FILEPATH, context->fd_random);
283 return 1;
284 }
285
286 return 0;
287}
288
289static void sigpipe_handler(int x)
290{
291}
292
293
Andy Greene40aa9b2014-04-02 21:02:54 +0800294LWS_VISIBLE int
295lws_plat_context_early_init(void)
Andy Green158e8042014-04-02 14:25:10 +0800296{
297 sigset_t mask;
298
299 signal(SIGUSR2, lws_sigusr2);
300 sigemptyset(&mask);
301 sigaddset(&mask, SIGUSR2);
302
303 sigprocmask(SIG_BLOCK, &mask, NULL);
Aurelian Popd07ea3b2014-07-29 15:36:06 +0300304
Andy Green158e8042014-04-02 14:25:10 +0800305 signal(SIGPIPE, sigpipe_handler);
306
307 return 0;
308}
309
Andy Greene40aa9b2014-04-02 21:02:54 +0800310LWS_VISIBLE void
311lws_plat_context_early_destroy(struct libwebsocket_context *context)
Andy Green158e8042014-04-02 14:25:10 +0800312{
313}
314
Andy Greene40aa9b2014-04-02 21:02:54 +0800315LWS_VISIBLE void
316lws_plat_context_late_destroy(struct libwebsocket_context *context)
Andy Green158e8042014-04-02 14:25:10 +0800317{
318 close(context->dummy_pipe_fds[0]);
319 close(context->dummy_pipe_fds[1]);
320 close(context->fd_random);
321}
322
323/* cast a struct sockaddr_in6 * into addr for ipv6 */
324
Andy Greene40aa9b2014-04-02 21:02:54 +0800325LWS_VISIBLE int
Andy Green158e8042014-04-02 14:25:10 +0800326interface_to_sa(struct libwebsocket_context *context,
327 const char *ifname, struct sockaddr_in *addr, size_t addrlen)
328{
329 int rc = -1;
330
331 struct ifaddrs *ifr;
332 struct ifaddrs *ifc;
333#ifdef LWS_USE_IPV6
334 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr;
335#endif
336
337 getifaddrs(&ifr);
338 for (ifc = ifr; ifc != NULL && rc; ifc = ifc->ifa_next) {
339 if (!ifc->ifa_addr)
340 continue;
341
342 lwsl_info(" interface %s vs %s\n", ifc->ifa_name, ifname);
343
344 if (strcmp(ifc->ifa_name, ifname))
345 continue;
346
347 switch (ifc->ifa_addr->sa_family) {
348 case AF_INET:
349#ifdef LWS_USE_IPV6
350 if (LWS_IPV6_ENABLED(context)) {
351 /* map IPv4 to IPv6 */
352 bzero((char *)&addr6->sin6_addr,
353 sizeof(struct in6_addr));
354 addr6->sin6_addr.s6_addr[10] = 0xff;
355 addr6->sin6_addr.s6_addr[11] = 0xff;
356 memcpy(&addr6->sin6_addr.s6_addr[12],
357 &((struct sockaddr_in *)ifc->ifa_addr)->sin_addr,
358 sizeof(struct in_addr));
359 } else
360#endif
361 memcpy(addr,
362 (struct sockaddr_in *)ifc->ifa_addr,
363 sizeof(struct sockaddr_in));
364 break;
365#ifdef LWS_USE_IPV6
366 case AF_INET6:
Andy Green158e8042014-04-02 14:25:10 +0800367 memcpy(&addr6->sin6_addr,
368 &((struct sockaddr_in6 *)ifc->ifa_addr)->sin6_addr,
369 sizeof(struct in6_addr));
370 break;
371#endif
372 default:
373 continue;
374 }
375 rc = 0;
376 }
377
378 freeifaddrs(ifr);
Aurelian Popd07ea3b2014-07-29 15:36:06 +0300379
vpeter47cc7ae42014-04-27 12:32:15 +0200380 if (rc == -1) {
381 /* check if bind to IP adddress */
382#ifdef LWS_USE_IPV6
383 if (inet_pton(AF_INET6, ifname, &addr6->sin6_addr) == 1)
384 rc = 0;
385 else
386#endif
387 if (inet_pton(AF_INET, ifname, &addr->sin_addr) == 1)
388 rc = 0;
389 }
390
Andy Green158e8042014-04-02 14:25:10 +0800391 return rc;
392}
393
Andy Greene40aa9b2014-04-02 21:02:54 +0800394LWS_VISIBLE void
395lws_plat_insert_socket_into_fds(struct libwebsocket_context *context,
Andy Green158e8042014-04-02 14:25:10 +0800396 struct libwebsocket *wsi)
397{
Andy Greena717df22014-04-11 13:14:37 +0800398 lws_libev_io(context, wsi, LWS_EV_START | LWS_EV_READ);
Andy Green158e8042014-04-02 14:25:10 +0800399 context->fds[context->fds_count++].revents = 0;
400}
401
Andy Greene40aa9b2014-04-02 21:02:54 +0800402LWS_VISIBLE void
403lws_plat_delete_socket_from_fds(struct libwebsocket_context *context,
Andy Green158e8042014-04-02 14:25:10 +0800404 struct libwebsocket *wsi, int m)
405{
406}
407
Andy Greene40aa9b2014-04-02 21:02:54 +0800408LWS_VISIBLE void
409lws_plat_service_periodic(struct libwebsocket_context *context)
Andy Green158e8042014-04-02 14:25:10 +0800410{
411 /* if our parent went down, don't linger around */
412 if (context->started_with_parent &&
413 kill(context->started_with_parent, 0) < 0)
414 kill(getpid(), SIGTERM);
415}
416
Andy Greene40aa9b2014-04-02 21:02:54 +0800417LWS_VISIBLE int
418lws_plat_change_pollfd(struct libwebsocket_context *context,
Andy Green158e8042014-04-02 14:25:10 +0800419 struct libwebsocket *wsi, struct libwebsocket_pollfd *pfd)
420{
421 return 0;
422}
423
Andy Greene40aa9b2014-04-02 21:02:54 +0800424LWS_VISIBLE int
425lws_plat_open_file(const char* filename, unsigned long* filelen)
Andy Green158e8042014-04-02 14:25:10 +0800426{
427 struct stat stat_buf;
428 int ret = open(filename, O_RDONLY);
429
430 if (ret < 0)
431 return LWS_INVALID_FILE;
432
Andy Green24109f42014-11-30 13:03:45 +0800433 if (fstat(ret, &stat_buf) < 0) {
434 close(ret);
435 return LWS_INVALID_FILE;
436 }
Andy Green158e8042014-04-02 14:25:10 +0800437 *filelen = stat_buf.st_size;
438 return ret;
Andy Green1cd3ba62014-04-02 23:03:23 +0800439}
Andy Greena654fc02014-04-03 07:16:40 +0800440
Andy Green1cd3ba62014-04-02 23:03:23 +0800441#ifdef LWS_USE_IPV6
442LWS_VISIBLE const char *
443lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)
Aurelian Popd07ea3b2014-07-29 15:36:06 +0300444{
Andy Green1cd3ba62014-04-02 23:03:23 +0800445 return inet_ntop(af, src, dst, cnt);
446}
vpeter44dd8ada2014-04-27 13:28:22 +0200447#endif