blob: a087439ca45c0c1a7fe21da0249008d10c9dd1d8 [file] [log] [blame]
Andy Greene40aa9b2014-04-02 21:02:54 +08001#include "private-libwebsockets.h"
2
Andy Green3a9f79e2015-03-04 16:16:41 +08003#include <pwd.h>
4#include <grp.h>
5
Andy Greenbfaea952014-03-31 11:01:32 +08006/*
7 * included from libwebsockets.c for unix builds
8 */
9
Andy Greene40aa9b2014-04-02 21:02:54 +080010unsigned long long time_in_microseconds(void)
Andy Greenbfaea952014-03-31 11:01:32 +080011{
12 struct timeval tv;
13 gettimeofday(&tv, NULL);
Imo Farcher97a748a2015-01-26 15:39:36 +080014 return ((unsigned long long)tv.tv_sec * 1000000LL) + tv.tv_usec;
Andy Greenbfaea952014-03-31 11:01:32 +080015}
16
Andy Green4b85c1d2015-12-04 11:08:32 +080017LWS_VISIBLE int lws_get_random(struct lws_context *context,
Andy Greenbfaea952014-03-31 11:01:32 +080018 void *buf, int len)
19{
20 return read(context->fd_random, (char *)buf, len);
21}
22
Andy Green4b85c1d2015-12-04 11:08:32 +080023LWS_VISIBLE int lws_send_pipe_choked(struct lws *wsi)
Andy Greenbfaea952014-03-31 11:01:32 +080024{
Andy Green4b85c1d2015-12-04 11:08:32 +080025 struct lws_pollfd fds;
Andy Greenbfaea952014-03-31 11:01:32 +080026
27 /* treat the fact we got a truncated send pending as if we're choked */
28 if (wsi->truncated_send_len)
29 return 1;
30
31 fds.fd = wsi->sock;
32 fds.events = POLLOUT;
33 fds.revents = 0;
34
35 if (poll(&fds, 1, 0) != 1)
36 return 1;
37
38 if ((fds.revents & POLLOUT) == 0)
39 return 1;
40
41 /* okay to send another packet without blocking */
42
43 return 0;
44}
45
Andy Greene40aa9b2014-04-02 21:02:54 +080046LWS_VISIBLE int
Andy Green4b85c1d2015-12-04 11:08:32 +080047lws_poll_listen_fd(struct lws_pollfd *fd)
Andy Greenbfaea952014-03-31 11:01:32 +080048{
49 return poll(fd, 1, 0);
50}
51
Andy Greene40aa9b2014-04-02 21:02:54 +080052/*
53 * This is just used to interrupt poll waiting
54 * we don't have to do anything with it.
55 */
Andy Greene40aa9b2014-04-02 21:02:54 +080056static void lws_sigusr2(int sig)
57{
58}
Andy Greenbfaea952014-03-31 11:01:32 +080059
Andy Greenbfaea952014-03-31 11:01:32 +080060/**
Andy Green62304762015-12-04 08:43:54 +080061 * lws_cancel_service() - Cancel servicing of pending websocket activity
Andy Greenbfaea952014-03-31 11:01:32 +080062 * @context: Websocket context
63 *
Andy Green62304762015-12-04 08:43:54 +080064 * This function let a call to lws_service() waiting for a timeout
Andy Greenbfaea952014-03-31 11:01:32 +080065 * immediately return.
66 */
67LWS_VISIBLE void
Andy Green4b85c1d2015-12-04 11:08:32 +080068lws_cancel_service(struct lws_context *context)
Andy Greenbfaea952014-03-31 11:01:32 +080069{
70 char buf = 0;
71
72 if (write(context->dummy_pipe_fds[1], &buf, sizeof(buf)) != 1)
73 lwsl_err("Cannot write to dummy pipe");
74}
75
76LWS_VISIBLE void lwsl_emit_syslog(int level, const char *line)
77{
78 int syslog_level = LOG_DEBUG;
79
80 switch (level) {
81 case LLL_ERR:
82 syslog_level = LOG_ERR;
83 break;
84 case LLL_WARN:
85 syslog_level = LOG_WARNING;
86 break;
87 case LLL_NOTICE:
88 syslog_level = LOG_NOTICE;
89 break;
90 case LLL_INFO:
91 syslog_level = LOG_INFO;
92 break;
93 }
94 syslog(syslog_level, "%s", line);
Andy Green158e8042014-04-02 14:25:10 +080095}
96
97LWS_VISIBLE int
Andy Green4b85c1d2015-12-04 11:08:32 +080098lws_plat_service(struct lws_context *context, int timeout_ms)
Andy Green158e8042014-04-02 14:25:10 +080099{
100 int n;
101 int m;
102 char buf;
Andy Green30edd912015-01-29 09:42:22 +0800103#ifdef LWS_OPENSSL_SUPPORT
Andy Green4b85c1d2015-12-04 11:08:32 +0800104 struct lws *wsi, *wsi_next;
Andy Green30edd912015-01-29 09:42:22 +0800105#endif
Andy Green158e8042014-04-02 14:25:10 +0800106
107 /* stay dead once we are dead */
108
Andy Greena717df22014-04-11 13:14:37 +0800109 if (!context)
Andy Green158e8042014-04-02 14:25:10 +0800110 return 1;
111
Andy Greena717df22014-04-11 13:14:37 +0800112 lws_libev_run(context);
113
Andy Green158e8042014-04-02 14:25:10 +0800114 context->service_tid = context->protocols[0].callback(context, NULL,
115 LWS_CALLBACK_GET_THREAD_ID, NULL, NULL, 0);
116
Andy Green609ec852014-10-09 08:29:22 +0800117#ifdef LWS_OPENSSL_SUPPORT
118 /* if we know we have non-network pending data, do not wait in poll */
Andy Green52815602015-01-29 08:36:18 +0800119 if (lws_ssl_anybody_has_buffered_read(context))
Andy Green609ec852014-10-09 08:29:22 +0800120 timeout_ms = 0;
121#endif
Andy Green158e8042014-04-02 14:25:10 +0800122 n = poll(context->fds, context->fds_count, timeout_ms);
123 context->service_tid = 0;
124
Andy Green609ec852014-10-09 08:29:22 +0800125#ifdef LWS_OPENSSL_SUPPORT
Andy Green52815602015-01-29 08:36:18 +0800126 if (!lws_ssl_anybody_has_buffered_read(context) && n == 0) {
Andy Green609ec852014-10-09 08:29:22 +0800127#else
Andy Green158e8042014-04-02 14:25:10 +0800128 if (n == 0) /* poll timeout */ {
Andy Green609ec852014-10-09 08:29:22 +0800129#endif
Andy Green62304762015-12-04 08:43:54 +0800130 lws_service_fd(context, NULL);
Andy Green158e8042014-04-02 14:25:10 +0800131 return 0;
132 }
133
134 if (n < 0) {
135 if (LWS_ERRNO != LWS_EINTR)
136 return -1;
137 return 0;
138 }
139
Andy Green52815602015-01-29 08:36:18 +0800140#ifdef LWS_OPENSSL_SUPPORT
141 /*
142 * For all guys with buffered SSL read data already saved up, if they
143 * are not flowcontrolled, fake their POLLIN status so they'll get
144 * service to use up the buffered incoming data, even though their
145 * network socket may have nothing
146 */
147
148 wsi = context->pending_read_list;
149 while (wsi) {
150 wsi_next = wsi->pending_read_list_next;
Thomas Greensladea2a4b0b2015-10-12 16:06:26 +0800151 context->fds[wsi->position_in_fds_table].revents |=
152 context->fds[wsi->position_in_fds_table].events & POLLIN;
153 if (context->fds[wsi->position_in_fds_table].revents & POLLIN) {
Andy Green52815602015-01-29 08:36:18 +0800154 /*
155 * he's going to get serviced now, take him off the
156 * list of guys with buffered SSL. If he still has some
157 * at the end of the service, he'll get put back on the
158 * list then.
159 */
160 lws_ssl_remove_wsi_from_buffered_list(context, wsi);
161 }
162 wsi = wsi_next;
163 }
164#endif
165
Andy Green158e8042014-04-02 14:25:10 +0800166 /* any socket with events to service? */
167
168 for (n = 0; n < context->fds_count; n++) {
Andy Green52815602015-01-29 08:36:18 +0800169
Andy Green158e8042014-04-02 14:25:10 +0800170 if (!context->fds[n].revents)
171 continue;
172
173 if (context->fds[n].fd == context->dummy_pipe_fds[0]) {
174 if (read(context->fds[n].fd, &buf, 1) != 1)
175 lwsl_err("Cannot read from dummy pipe.");
176 continue;
177 }
178
Andy Green62304762015-12-04 08:43:54 +0800179 m = lws_service_fd(context, &context->fds[n]);
Andy Green158e8042014-04-02 14:25:10 +0800180 if (m < 0)
181 return -1;
182 /* if something closed, retry this slot */
183 if (m)
184 n--;
185 }
186
187 return 0;
188}
189
Andy Greene40aa9b2014-04-02 21:02:54 +0800190LWS_VISIBLE int
Andy Green4b85c1d2015-12-04 11:08:32 +0800191lws_plat_set_socket_options(struct lws_context *context, int fd)
Andy Green158e8042014-04-02 14:25:10 +0800192{
193 int optval = 1;
194 socklen_t optlen = sizeof(optval);
195
geqd6827f72014-05-28 04:52:18 +0000196#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || \
197 defined(__OpenBSD__)
Andy Green158e8042014-04-02 14:25:10 +0800198 struct protoent *tcp_proto;
199#endif
200
201 if (context->ka_time) {
202 /* enable keepalive on this socket */
203 optval = 1;
204 if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE,
205 (const void *)&optval, optlen) < 0)
206 return 1;
207
geqd6827f72014-05-28 04:52:18 +0000208#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || \
209 defined(__CYGWIN__) || defined(__OpenBSD__)
Andy Green158e8042014-04-02 14:25:10 +0800210
211 /*
212 * didn't find a way to set these per-socket, need to
213 * tune kernel systemwide values
214 */
215#else
216 /* set the keepalive conditions we want on it too */
217 optval = context->ka_time;
Aurelian Popd07ea3b2014-07-29 15:36:06 +0300218 if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE,
Andy Green158e8042014-04-02 14:25:10 +0800219 (const void *)&optval, optlen) < 0)
220 return 1;
221
222 optval = context->ka_interval;
Aurelian Popd07ea3b2014-07-29 15:36:06 +0300223 if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL,
Andy Green158e8042014-04-02 14:25:10 +0800224 (const void *)&optval, optlen) < 0)
225 return 1;
226
227 optval = context->ka_probes;
Aurelian Popd07ea3b2014-07-29 15:36:06 +0300228 if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT,
Andy Green158e8042014-04-02 14:25:10 +0800229 (const void *)&optval, optlen) < 0)
230 return 1;
231#endif
232 }
233
234 /* Disable Nagle */
235 optval = 1;
geqd6827f72014-05-28 04:52:18 +0000236#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__NetBSD__) && \
237 !defined(__OpenBSD__)
Andy Greenabb48112014-11-30 13:06:09 +0800238 if (setsockopt(fd, SOL_TCP, TCP_NODELAY, (const void *)&optval, optlen) < 0)
239 return 1;
Andy Green158e8042014-04-02 14:25:10 +0800240#else
241 tcp_proto = getprotobyname("TCP");
Andy Greenabb48112014-11-30 13:06:09 +0800242 if (setsockopt(fd, tcp_proto->p_proto, TCP_NODELAY, &optval, optlen) < 0)
243 return 1;
Andy Green158e8042014-04-02 14:25:10 +0800244#endif
245
246 /* We are nonblocking... */
Andy Green956a08a2014-11-30 13:02:32 +0800247 if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
248 return 1;
Andy Green158e8042014-04-02 14:25:10 +0800249
250 return 0;
251}
252
Andy Greene40aa9b2014-04-02 21:02:54 +0800253LWS_VISIBLE void
254lws_plat_drop_app_privileges(struct lws_context_creation_info *info)
Andy Green158e8042014-04-02 14:25:10 +0800255{
Andy Green3a9f79e2015-03-04 16:16:41 +0800256 if (info->uid != -1) {
257 struct passwd *p = getpwuid(info->uid);
258
259 if (p) {
260 initgroups(p->pw_name, info->gid);
261 if (setuid(info->uid))
262 lwsl_warn("setuid: %s\n", strerror(LWS_ERRNO));
263 else
264 lwsl_notice(" Set privs to user '%s'\n", p->pw_name);
265 } else
266 lwsl_warn("getpwuid: unable to find uid %d", info->uid);
267 }
Andy Green158e8042014-04-02 14:25:10 +0800268 if (info->gid != -1)
269 if (setgid(info->gid))
270 lwsl_warn("setgid: %s\n", strerror(LWS_ERRNO));
Andy Green3a9f79e2015-03-04 16:16:41 +0800271
Andy Green158e8042014-04-02 14:25:10 +0800272}
273
Andy Greene40aa9b2014-04-02 21:02:54 +0800274LWS_VISIBLE int
Andy Green4b85c1d2015-12-04 11:08:32 +0800275lws_plat_init_lookup(struct lws_context *context)
=?UTF-8?q?Joakim=20S=C3=B6derberg?=caf7e3d2015-06-25 17:51:07 +0200276{
Andy Green4b85c1d2015-12-04 11:08:32 +0800277 context->lws_lookup = lws_zalloc(sizeof(struct lws *) * context->max_fds);
=?UTF-8?q?Joakim=20S=C3=B6derberg?=caf7e3d2015-06-25 17:51:07 +0200278 if (context->lws_lookup == NULL) {
279 lwsl_err(
280 "Unable to allocate lws_lookup array for %d connections\n",
281 context->max_fds);
282 return 1;
283 }
284
285 return 0;
286}
287
288LWS_VISIBLE int
Andy Green4b85c1d2015-12-04 11:08:32 +0800289lws_plat_init_fd_tables(struct lws_context *context)
Andy Green158e8042014-04-02 14:25:10 +0800290{
Pokrovskiy20636ec2015-04-21 00:53:59 -0700291 context->fd_random = open(SYSTEM_RANDOM_FILEPATH, O_RDONLY);
292 if (context->fd_random < 0) {
293 lwsl_err("Unable to open random device %s %d\n",
294 SYSTEM_RANDOM_FILEPATH, context->fd_random);
295 return 1;
296 }
297
Andy Greena717df22014-04-11 13:14:37 +0800298 if (lws_libev_init_fd_table(context))
299 /* libev handled it instead */
Andy Green158e8042014-04-02 14:25:10 +0800300 return 0;
Andy Greena717df22014-04-11 13:14:37 +0800301
Andy Green158e8042014-04-02 14:25:10 +0800302 if (pipe(context->dummy_pipe_fds)) {
303 lwsl_err("Unable to create pipe\n");
304 return 1;
305 }
306
307 /* use the read end of pipe as first item */
308 context->fds[0].fd = context->dummy_pipe_fds[0];
309 context->fds[0].events = LWS_POLLIN;
310 context->fds[0].revents = 0;
311 context->fds_count = 1;
Aurelian Popd07ea3b2014-07-29 15:36:06 +0300312
Andy Green158e8042014-04-02 14:25:10 +0800313 return 0;
314}
315
316static void sigpipe_handler(int x)
317{
318}
319
320
Andy Greene40aa9b2014-04-02 21:02:54 +0800321LWS_VISIBLE int
322lws_plat_context_early_init(void)
Andy Green158e8042014-04-02 14:25:10 +0800323{
324 sigset_t mask;
325
326 signal(SIGUSR2, lws_sigusr2);
327 sigemptyset(&mask);
328 sigaddset(&mask, SIGUSR2);
329
330 sigprocmask(SIG_BLOCK, &mask, NULL);
Aurelian Popd07ea3b2014-07-29 15:36:06 +0300331
Andy Green158e8042014-04-02 14:25:10 +0800332 signal(SIGPIPE, sigpipe_handler);
333
334 return 0;
335}
336
Andy Greene40aa9b2014-04-02 21:02:54 +0800337LWS_VISIBLE void
Andy Green4b85c1d2015-12-04 11:08:32 +0800338lws_plat_context_early_destroy(struct lws_context *context)
Andy Green158e8042014-04-02 14:25:10 +0800339{
340}
341
Andy Greene40aa9b2014-04-02 21:02:54 +0800342LWS_VISIBLE void
Andy Green4b85c1d2015-12-04 11:08:32 +0800343lws_plat_context_late_destroy(struct lws_context *context)
Andy Green158e8042014-04-02 14:25:10 +0800344{
=?UTF-8?q?Joakim=20S=C3=B6derberg?=caf7e3d2015-06-25 17:51:07 +0200345 if (context->lws_lookup)
346 lws_free(context->lws_lookup);
347
Andy Green158e8042014-04-02 14:25:10 +0800348 close(context->dummy_pipe_fds[0]);
349 close(context->dummy_pipe_fds[1]);
350 close(context->fd_random);
351}
352
353/* cast a struct sockaddr_in6 * into addr for ipv6 */
354
Andy Greene40aa9b2014-04-02 21:02:54 +0800355LWS_VISIBLE int
Andy Green4b85c1d2015-12-04 11:08:32 +0800356interface_to_sa(struct lws_context *context,
Andy Green158e8042014-04-02 14:25:10 +0800357 const char *ifname, struct sockaddr_in *addr, size_t addrlen)
358{
359 int rc = -1;
360
361 struct ifaddrs *ifr;
362 struct ifaddrs *ifc;
363#ifdef LWS_USE_IPV6
364 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr;
365#endif
366
367 getifaddrs(&ifr);
368 for (ifc = ifr; ifc != NULL && rc; ifc = ifc->ifa_next) {
369 if (!ifc->ifa_addr)
370 continue;
371
372 lwsl_info(" interface %s vs %s\n", ifc->ifa_name, ifname);
373
374 if (strcmp(ifc->ifa_name, ifname))
375 continue;
376
377 switch (ifc->ifa_addr->sa_family) {
378 case AF_INET:
379#ifdef LWS_USE_IPV6
380 if (LWS_IPV6_ENABLED(context)) {
381 /* map IPv4 to IPv6 */
382 bzero((char *)&addr6->sin6_addr,
383 sizeof(struct in6_addr));
384 addr6->sin6_addr.s6_addr[10] = 0xff;
385 addr6->sin6_addr.s6_addr[11] = 0xff;
386 memcpy(&addr6->sin6_addr.s6_addr[12],
387 &((struct sockaddr_in *)ifc->ifa_addr)->sin_addr,
388 sizeof(struct in_addr));
389 } else
390#endif
391 memcpy(addr,
392 (struct sockaddr_in *)ifc->ifa_addr,
393 sizeof(struct sockaddr_in));
394 break;
395#ifdef LWS_USE_IPV6
396 case AF_INET6:
Andy Green158e8042014-04-02 14:25:10 +0800397 memcpy(&addr6->sin6_addr,
398 &((struct sockaddr_in6 *)ifc->ifa_addr)->sin6_addr,
399 sizeof(struct in6_addr));
400 break;
401#endif
402 default:
403 continue;
404 }
405 rc = 0;
406 }
407
408 freeifaddrs(ifr);
Aurelian Popd07ea3b2014-07-29 15:36:06 +0300409
vpeter47cc7ae42014-04-27 12:32:15 +0200410 if (rc == -1) {
411 /* check if bind to IP adddress */
412#ifdef LWS_USE_IPV6
413 if (inet_pton(AF_INET6, ifname, &addr6->sin6_addr) == 1)
414 rc = 0;
415 else
416#endif
417 if (inet_pton(AF_INET, ifname, &addr->sin_addr) == 1)
418 rc = 0;
419 }
420
Andy Green158e8042014-04-02 14:25:10 +0800421 return rc;
422}
423
Andy Greene40aa9b2014-04-02 21:02:54 +0800424LWS_VISIBLE void
Andy Green4b85c1d2015-12-04 11:08:32 +0800425lws_plat_insert_socket_into_fds(struct lws_context *context,
426 struct lws *wsi)
Andy Green158e8042014-04-02 14:25:10 +0800427{
Andy Greena717df22014-04-11 13:14:37 +0800428 lws_libev_io(context, wsi, LWS_EV_START | LWS_EV_READ);
Andy Green158e8042014-04-02 14:25:10 +0800429 context->fds[context->fds_count++].revents = 0;
430}
431
Andy Greene40aa9b2014-04-02 21:02:54 +0800432LWS_VISIBLE void
Andy Green4b85c1d2015-12-04 11:08:32 +0800433lws_plat_delete_socket_from_fds(struct lws_context *context,
434 struct lws *wsi, int m)
Andy Green158e8042014-04-02 14:25:10 +0800435{
436}
437
Andy Greene40aa9b2014-04-02 21:02:54 +0800438LWS_VISIBLE void
Andy Green4b85c1d2015-12-04 11:08:32 +0800439lws_plat_service_periodic(struct lws_context *context)
Andy Green158e8042014-04-02 14:25:10 +0800440{
441 /* if our parent went down, don't linger around */
442 if (context->started_with_parent &&
443 kill(context->started_with_parent, 0) < 0)
444 kill(getpid(), SIGTERM);
445}
446
Andy Greene40aa9b2014-04-02 21:02:54 +0800447LWS_VISIBLE int
Andy Green4b85c1d2015-12-04 11:08:32 +0800448lws_plat_change_pollfd(struct lws_context *context,
449 struct lws *wsi, struct lws_pollfd *pfd)
Andy Green158e8042014-04-02 14:25:10 +0800450{
451 return 0;
452}
453
Andy Greene40aa9b2014-04-02 21:02:54 +0800454LWS_VISIBLE int
455lws_plat_open_file(const char* filename, unsigned long* filelen)
Andy Green158e8042014-04-02 14:25:10 +0800456{
457 struct stat stat_buf;
458 int ret = open(filename, O_RDONLY);
459
460 if (ret < 0)
461 return LWS_INVALID_FILE;
462
Andy Green24109f42014-11-30 13:03:45 +0800463 if (fstat(ret, &stat_buf) < 0) {
464 close(ret);
465 return LWS_INVALID_FILE;
466 }
Andy Green158e8042014-04-02 14:25:10 +0800467 *filelen = stat_buf.st_size;
468 return ret;
Andy Green1cd3ba62014-04-02 23:03:23 +0800469}
Andy Greena654fc02014-04-03 07:16:40 +0800470
Andy Green1cd3ba62014-04-02 23:03:23 +0800471LWS_VISIBLE const char *
472lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)
Aurelian Popd07ea3b2014-07-29 15:36:06 +0300473{
Andy Green1cd3ba62014-04-02 23:03:23 +0800474 return inet_ntop(af, src, dst, cnt);
475}