port forced service checking from libuv
[platform/upstream/libwebsockets.git] / lib / libuv.c
1 /*
2  * libwebsockets - small server side websockets and web server implementation
3  *
4  * Copyright (C) 2010-2016 Andy Green <andy@warmcat.com>
5  *
6  *  This library is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU Lesser General Public
8  *  License as published by the Free Software Foundation:
9  *  version 2.1 of the License.
10  *
11  *  This library is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  *  Lesser General Public License for more details.
15  *
16  *  You should have received a copy of the GNU Lesser General Public
17  *  License along with this library; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19  *  MA  02110-1301  USA
20  */
21
22 #include "private-libwebsockets.h"
23
24 void
25 lws_feature_status_libuv(struct lws_context_creation_info *info)
26 {
27         if (lws_check_opt(info->options, LWS_SERVER_OPTION_LIBUV))
28                 lwsl_notice("libuv support compiled in and enabled\n");
29         else
30                 lwsl_notice("libuv support compiled in but disabled\n");
31 }
32
33 static void
34 lws_uv_idle(uv_idle_t *handle
35 #if UV_VERSION_MAJOR == 0
36                 , int status
37 #endif
38 )
39 {
40         struct lws_context_per_thread *pt = lws_container_of(handle,
41                                         struct lws_context_per_thread, uv_idle);
42
43         lwsl_debug("%s\n", __func__);
44
45         /*
46          * is there anybody with pending stuff that needs service forcing?
47          */
48         if (!lws_service_adjust_timeout(pt->context, 1, pt->tid)) {
49                 /* -1 timeout means just do forced service */
50                 lws_plat_service_tsi(pt->context, -1, pt->tid);
51                 /* still somebody left who wants forced service? */
52                 if (!lws_service_adjust_timeout(pt->context, 1, pt->tid))
53                         /* yes... come back again later */
54                         lwsl_debug("%s: done again\n", __func__);
55                 return;
56         }
57
58         /* there is nobody who needs service forcing, shut down idle */
59         uv_idle_stop(handle);
60
61         lwsl_debug("%s: done stop\n", __func__);
62 }
63
64 static void
65 lws_io_cb(uv_poll_t *watcher, int status, int revents)
66 {
67         struct lws_io_watcher *lws_io = lws_container_of(watcher,
68                                         struct lws_io_watcher, uv_watcher);
69         struct lws *wsi = lws_container_of(lws_io, struct lws, w_read);
70         struct lws_context *context = lws_io->context;
71         struct lws_pollfd eventfd;
72
73 #if defined(WIN32) || defined(_WIN32)
74         eventfd.fd = watcher->socket;
75 #else
76         eventfd.fd = watcher->io_watcher.fd;
77 #endif
78         eventfd.events = 0;
79         eventfd.revents = 0;
80
81         if (status < 0) {
82                 /* at this point status will be an UV error, like UV_EBADF,
83                 we treat all errors as LWS_POLLHUP */
84
85                 /* you might want to return; instead of servicing the fd in some cases */
86                 if (status == UV_EAGAIN)
87                         return;
88
89                 eventfd.events |= LWS_POLLHUP;
90                 eventfd.revents |= LWS_POLLHUP;
91         } else {
92                 if (revents & UV_READABLE) {
93                         eventfd.events |= LWS_POLLIN;
94                         eventfd.revents |= LWS_POLLIN;
95                 }
96                 if (revents & UV_WRITABLE) {
97                         eventfd.events |= LWS_POLLOUT;
98                         eventfd.revents |= LWS_POLLOUT;
99                 }
100         }
101         lws_service_fd(context, &eventfd);
102
103         uv_idle_start(&context->pt[(int)wsi->tsi].uv_idle, lws_uv_idle);
104 }
105
106 LWS_VISIBLE void
107 lws_uv_sigint_cb(uv_signal_t *watcher, int signum)
108 {
109         lwsl_err("internal signal handler caught signal %d\n", signum);
110         lws_libuv_stop(watcher->data);
111 }
112
113 LWS_VISIBLE int
114 lws_uv_sigint_cfg(struct lws_context *context, int use_uv_sigint,
115                   uv_signal_cb cb)
116 {
117         context->use_ev_sigint = use_uv_sigint;
118         if (cb)
119                 context->lws_uv_sigint_cb = cb;
120         else
121                 context->lws_uv_sigint_cb = &lws_uv_sigint_cb;
122
123         return 0;
124 }
125
126 static void
127 lws_uv_timeout_cb(uv_timer_t *timer
128 #if UV_VERSION_MAJOR == 0
129                 , int status
130 #endif
131 )
132 {
133         struct lws_context_per_thread *pt = lws_container_of(timer,
134                         struct lws_context_per_thread, uv_timeout_watcher);
135
136         if (pt->context->requested_kill)
137                 return;
138
139         lwsl_debug("%s\n", __func__);
140
141         lws_service_fd_tsi(pt->context, NULL, pt->tid);
142 }
143
144 static const int sigs[] = { SIGINT, SIGTERM, SIGSEGV, SIGFPE };
145
146 LWS_VISIBLE int
147 lws_uv_initloop(struct lws_context *context, uv_loop_t *loop, int tsi)
148 {
149         struct lws_context_per_thread *pt = &context->pt[tsi];
150         struct lws_vhost *vh = context->vhost_list;
151         int status = 0, n, ns;
152
153         if (!loop) {
154                 loop = lws_malloc(sizeof(*loop));
155                 if (!loop) {
156                         lwsl_err("OOM\n");
157                         return -1;
158                 }
159 #if UV_VERSION_MAJOR > 0
160                 uv_loop_init(loop);
161 #else
162                 lwsl_err("This libuv is too old to work...\n");
163                 return 1;
164 #endif
165                 pt->ev_loop_foreign = 0;
166         } else {
167                 lwsl_notice(" Using foreign event loop...\n");
168                 pt->ev_loop_foreign = 1;
169         }
170
171         pt->io_loop_uv = loop;
172         uv_idle_init(loop, &pt->uv_idle);
173
174         ns = ARRAY_SIZE(sigs);
175         if (lws_check_opt(context->options, LWS_SERVER_OPTION_UV_NO_SIGSEGV_SIGFPE_SPIN))
176                 ns = 2;
177
178         if (pt->context->use_ev_sigint) {
179                 assert(ns <= ARRAY_SIZE(pt->signals));
180                 for (n = 0; n < ns; n++) {
181                         uv_signal_init(loop, &pt->signals[n]);
182                         pt->signals[n].data = pt->context;
183                         uv_signal_start(&pt->signals[n],
184                                         context->lws_uv_sigint_cb, sigs[n]);
185                 }
186         }
187
188         /*
189          * Initialize the accept wsi read watcher with all the listening sockets
190          * and register a callback for read operations
191          *
192          * We have to do it here because the uv loop(s) are not
193          * initialized until after context creation.
194          */
195         while (vh) {
196                 if (vh->lserv_wsi) {
197                         vh->lserv_wsi->w_read.context = context;
198                         n = uv_poll_init_socket(pt->io_loop_uv,
199                                                 &vh->lserv_wsi->w_read.uv_watcher,
200                                                 vh->lserv_wsi->sock);
201                         if (n) {
202                                 lwsl_err("uv_poll_init failed %d, sockfd=%p\n",
203                                         n, (void *)(long)vh->lserv_wsi->sock);
204
205                                 return -1;
206                         }
207                         lws_libuv_io(vh->lserv_wsi, LWS_EV_START | LWS_EV_READ);
208                 }
209                 vh = vh->vhost_next;
210         }
211
212         uv_timer_init(pt->io_loop_uv, &pt->uv_timeout_watcher);
213         uv_timer_start(&pt->uv_timeout_watcher, lws_uv_timeout_cb, 10, 1000);
214
215         return status;
216 }
217
218 static void lws_uv_close_cb(uv_handle_t *handle)
219 {
220         //lwsl_err("%s: handle %p\n", __func__, handle);
221 }
222
223 static void lws_uv_walk_cb(uv_handle_t *handle, void *arg)
224 {
225         uv_close(handle, lws_uv_close_cb);
226 }
227
228 void
229 lws_libuv_destroyloop(struct lws_context *context, int tsi)
230 {
231         struct lws_context_per_thread *pt = &context->pt[tsi];
232         int m, budget = 100, ns;
233
234         if (!lws_check_opt(context->options, LWS_SERVER_OPTION_LIBUV))
235                 return;
236
237         if (!pt->io_loop_uv)
238                 return;
239
240         if (context->use_ev_sigint) {
241                 uv_signal_stop(&pt->w_sigint.uv_watcher);
242
243                 ns = ARRAY_SIZE(sigs);
244                 if (lws_check_opt(context->options, LWS_SERVER_OPTION_UV_NO_SIGSEGV_SIGFPE_SPIN))
245                         ns = 2;
246
247                 for (m = 0; m < ns; m++) {
248                         uv_signal_stop(&pt->signals[m]);
249                         uv_close((uv_handle_t *)&pt->signals[m], lws_uv_close_cb);
250                 }
251         }
252
253         uv_timer_stop(&pt->uv_timeout_watcher);
254         uv_close((uv_handle_t *)&pt->uv_timeout_watcher, lws_uv_close_cb);
255
256         uv_idle_stop(&pt->uv_idle);
257         uv_close((uv_handle_t *)&pt->uv_idle, lws_uv_close_cb);
258
259         while (budget-- && uv_run(pt->io_loop_uv, UV_RUN_NOWAIT))
260                 ;
261
262         if (pt->ev_loop_foreign)
263                 return;
264
265         uv_stop(pt->io_loop_uv);
266
267         uv_walk(pt->io_loop_uv, lws_uv_walk_cb, NULL);
268
269         while (uv_run(pt->io_loop_uv, UV_RUN_NOWAIT))
270                 ;
271 #if UV_VERSION_MAJOR > 0
272         m = uv_loop_close(pt->io_loop_uv);
273         if (m == UV_EBUSY)
274                 lwsl_err("%s: uv_loop_close: UV_EBUSY\n", __func__);
275 #endif
276         lws_free(pt->io_loop_uv);
277 }
278
279 void
280 lws_libuv_accept(struct lws *wsi, lws_sockfd_type accept_fd)
281 {
282         struct lws_context *context = lws_get_context(wsi);
283         struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
284
285         if (!LWS_LIBUV_ENABLED(context))
286                 return;
287
288         lwsl_debug("%s: new wsi %p\n", __func__, wsi);
289
290         wsi->w_read.context = context;
291
292         uv_poll_init_socket(pt->io_loop_uv, &wsi->w_read.uv_watcher, accept_fd);
293 }
294
295 void
296 lws_libuv_io(struct lws *wsi, int flags)
297 {
298         struct lws_context *context = lws_get_context(wsi);
299         struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
300 #if defined(WIN32) || defined(_WIN32)
301         int current_events = wsi->w_read.uv_watcher.events &
302                              (UV_READABLE | UV_WRITABLE);
303 #else
304         int current_events = wsi->w_read.uv_watcher.io_watcher.pevents &
305                              (UV_READABLE | UV_WRITABLE);
306 #endif
307         struct lws_io_watcher *w = &wsi->w_read;
308
309         if (!LWS_LIBUV_ENABLED(context))
310                 return;
311
312         // lwsl_notice("%s: wsi: %p, flags:0x%x\n", __func__, wsi, flags);
313
314         if (!pt->io_loop_uv) {
315                 lwsl_info("%s: no io loop yet\n", __func__);
316                 return;
317         }
318
319         if (!((flags & (LWS_EV_START | LWS_EV_STOP)) &&
320               (flags & (LWS_EV_READ | LWS_EV_WRITE)))) {
321                 lwsl_err("%s: assert: flags %d", __func__, flags);
322                 assert(0);
323         }
324
325         if (flags & LWS_EV_START) {
326                 if (flags & LWS_EV_WRITE)
327                         current_events |= UV_WRITABLE;
328
329                 if (flags & LWS_EV_READ)
330                         current_events |= UV_READABLE;
331
332                 uv_poll_start(&w->uv_watcher, current_events, lws_io_cb);
333         } else {
334                 if (flags & LWS_EV_WRITE)
335                         current_events &= ~UV_WRITABLE;
336
337                 if (flags & LWS_EV_READ)
338                         current_events &= ~UV_READABLE;
339
340                 if (!(current_events & (UV_READABLE | UV_WRITABLE)))
341                         uv_poll_stop(&w->uv_watcher);
342                 else
343                         uv_poll_start(&w->uv_watcher, current_events,
344                                       lws_io_cb);
345         }
346 }
347
348 int
349 lws_libuv_init_fd_table(struct lws_context *context)
350 {
351         int n;
352
353         if (!LWS_LIBUV_ENABLED(context))
354                 return 0;
355
356         for (n = 0; n < context->count_threads; n++)
357                 context->pt[n].w_sigint.context = context;
358
359         return 1;
360 }
361
362 LWS_VISIBLE void
363 lws_libuv_run(const struct lws_context *context, int tsi)
364 {
365         if (context->pt[tsi].io_loop_uv && LWS_LIBUV_ENABLED(context))
366                 uv_run(context->pt[tsi].io_loop_uv, 0);
367 }
368
369 static void
370 lws_libuv_kill(const struct lws_context *context)
371 {
372         int n;
373
374         for (n = 0; n < context->count_threads; n++)
375                 if (context->pt[n].io_loop_uv &&
376                     LWS_LIBUV_ENABLED(context) &&
377                     !context->pt[n].ev_loop_foreign)
378                         uv_stop(context->pt[n].io_loop_uv);
379 }
380
381 /*
382  * This does not actually stop the event loop.  The reason is we have to pass
383  * libuv handle closures through its event loop.  So this tries to close all
384  * wsi, and set a flag; when all the wsi closures are finalized then we
385  * actually stop the libuv event loops.
386  */
387
388 LWS_VISIBLE void
389 lws_libuv_stop(struct lws_context *context)
390 {
391         struct lws_context_per_thread *pt;
392         int n, m;
393
394         if (context->requested_kill)
395                 return;
396
397         context->requested_kill = 1;
398
399         m = context->count_threads;
400         context->being_destroyed = 1;
401
402         while (m--) {
403                 pt = &context->pt[m];
404
405                 for (n = 0; (unsigned int)n < context->pt[m].fds_count; n++) {
406                         struct lws *wsi = wsi_from_fd(context, pt->fds[n].fd);
407
408                         if (!wsi)
409                                 continue;
410                         lws_close_free_wsi(wsi,
411                                 LWS_CLOSE_STATUS_NOSTATUS_CONTEXT_DESTROY
412                                 /* no protocol close */);
413                         n--;
414                 }
415         }
416
417         lwsl_info("%s: feels everything closed\n", __func__);
418         if (context->count_wsi_allocated == 0)
419                 lws_libuv_kill(context);
420 }
421
422 LWS_VISIBLE uv_loop_t *
423 lws_uv_getloop(struct lws_context *context, int tsi)
424 {
425         if (context->pt[tsi].io_loop_uv && LWS_LIBUV_ENABLED(context))
426                 return context->pt[tsi].io_loop_uv;
427
428         return NULL;
429 }
430
431 static void
432 lws_libuv_closewsi(uv_handle_t* handle)
433 {
434         struct lws *n = NULL, *wsi = (struct lws *)(((char *)handle) -
435                           (char *)(&n->w_read.uv_watcher));
436         struct lws_context *context = lws_get_context(wsi);
437
438         lws_close_free_wsi_final(wsi);
439
440         if (context->requested_kill && context->count_wsi_allocated == 0)
441                 lws_libuv_kill(context);
442 }
443
444 void
445 lws_libuv_closehandle(struct lws *wsi)
446 {
447         struct lws_context *context = lws_get_context(wsi);
448
449         /* required to defer actual deletion until libuv has processed it */
450
451         uv_close((uv_handle_t*)&wsi->w_read.uv_watcher, lws_libuv_closewsi);
452
453         if (context->requested_kill && context->count_wsi_allocated == 0)
454                 lws_libuv_kill(context);
455 }
456
457 #if defined(LWS_WITH_PLUGINS) && (UV_VERSION_MAJOR > 0)
458
459 LWS_VISIBLE int
460 lws_plat_plugins_init(struct lws_context * context, const char * const *d)
461 {
462         struct lws_plugin_capability lcaps;
463         struct lws_plugin *plugin;
464         lws_plugin_init_func initfunc;
465         int m, ret = 0;
466         void *v;
467         uv_dirent_t dent;
468         uv_fs_t req;
469         char path[256];
470         uv_loop_t loop;
471         uv_lib_t lib;
472
473         lib.errmsg = NULL;
474         lib.handle = NULL;
475
476         uv_loop_init(&loop);
477
478         lwsl_notice("  Plugins:\n");
479
480         while (d && *d) {
481
482                 lwsl_notice("  Scanning %s\n", *d);
483                 m =uv_fs_scandir(&loop, &req, *d, 0, NULL);
484                 if (m < 1) {
485                         lwsl_err("Scandir on %s failed\n", *d);
486                         return 1;
487                 }
488
489                 while (uv_fs_scandir_next(&req, &dent) != UV_EOF) {
490                         if (strlen(dent.name) < 7)
491                                 continue;
492
493                         lwsl_notice("   %s\n", dent.name);
494
495                         lws_snprintf(path, sizeof(path) - 1, "%s/%s", *d, dent.name);
496                         if (uv_dlopen(path, &lib)) {
497                                 uv_dlerror(&lib);
498                                 lwsl_err("Error loading DSO: %s\n", lib.errmsg);
499                                 goto bail;
500                         }
501                         /* we could open it, can we get his init function? */
502 #if !defined(WIN32)
503                         m = lws_snprintf(path, sizeof(path) - 1, "init_%s",
504                                      dent.name + 3 /* snip lib... */);
505                         path[m - 3] = '\0'; /* snip the .so */
506 #else
507                         m = lws_snprintf(path, sizeof(path) - 1, "init_%s",
508                                      dent.name);
509                         path[m - 4] = '\0'; /* snip the .dll */
510 #endif
511                         if (uv_dlsym(&lib, path, &v)) {
512                                 uv_dlerror(&lib);
513                                 lwsl_err("Failed to get init on %s: %s",
514                                                 dent.name, lib.errmsg);
515                                 goto bail;
516                         }
517                         initfunc = (lws_plugin_init_func)v;
518                         lcaps.api_magic = LWS_PLUGIN_API_MAGIC;
519                         m = initfunc(context, &lcaps);
520                         if (m) {
521                                 lwsl_err("Initializing %s failed %d\n", dent.name, m);
522                                 goto skip;
523                         }
524
525                         plugin = lws_malloc(sizeof(*plugin));
526                         if (!plugin) {
527                                 lwsl_err("OOM\n");
528                                 goto bail;
529                         }
530                         plugin->list = context->plugin_list;
531                         context->plugin_list = plugin;
532                         strncpy(plugin->name, dent.name, sizeof(plugin->name) - 1);
533                         plugin->name[sizeof(plugin->name) - 1] = '\0';
534                         plugin->lib = lib;
535                         plugin->caps = lcaps;
536                         context->plugin_protocol_count += lcaps.count_protocols;
537                         context->plugin_extension_count += lcaps.count_extensions;
538
539                         continue;
540
541 skip:
542                         uv_dlclose(&lib);
543                 }
544 bail:
545                 uv_fs_req_cleanup(&req);
546                 d++;
547         }
548
549         uv_loop_close(&loop);
550
551         return ret;
552
553 }
554
555 LWS_VISIBLE int
556 lws_plat_plugins_destroy(struct lws_context * context)
557 {
558         struct lws_plugin *plugin = context->plugin_list, *p;
559         lws_plugin_destroy_func func;
560         char path[256];
561         void *v;
562         int m;
563
564         if (!plugin)
565                 return 0;
566
567         // lwsl_notice("%s\n", __func__);
568
569         while (plugin) {
570                 p = plugin;
571 #if !defined(WIN32)
572                 m = lws_snprintf(path, sizeof(path) - 1, "destroy_%s", plugin->name + 3);
573                 path[m - 3] = '\0';
574 #else
575                 m = lws_snprintf(path, sizeof(path) - 1, "destroy_%s", plugin->name);
576                 path[m - 4] = '\0';
577 #endif
578
579                 if (uv_dlsym(&plugin->lib, path, &v)) {
580                         uv_dlerror(&plugin->lib);
581                         lwsl_err("Failed to get init on %s: %s",
582                                         plugin->name, plugin->lib.errmsg);
583                 } else {
584                         func = (lws_plugin_destroy_func)v;
585                         m = func(context);
586                         if (m)
587                                 lwsl_err("Destroying %s failed %d\n",
588                                                 plugin->name, m);
589                 }
590
591                 uv_dlclose(&p->lib);
592                 plugin = p->list;
593                 p->list = NULL;
594                 free(p);
595         }
596
597         context->plugin_list = NULL;
598
599         return 0;
600 }
601
602 #endif
603