glib.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513
  1. /*
  2. * libwebsockets - small server side websockets and web server implementation
  3. *
  4. * Copyright (C) 2010 - 2020 Andy Green <[email protected]>
  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. #include "private-lib-core.h"
  25. #include <glib-unix.h>
  26. #include "private-lib-event-libs-glib.h"
  27. #if !defined(G_SOURCE_FUNC)
  28. #define G_SOURCE_FUNC(f) ((GSourceFunc) (void (*)(void)) (f))
  29. #endif
  30. #define pt_to_priv_glib(_pt) ((struct lws_pt_eventlibs_glib *)(_pt)->evlib_pt)
  31. #define wsi_to_priv_glib(_w) ((struct lws_wsi_eventlibs_glib *)(_w)->evlib_wsi)
  32. #define wsi_to_subclass(_w) (wsi_to_priv_glib(_w)->w_read.source)
  33. #define wsi_to_gsource(_w) ((GSource *)wsi_to_subclass(_w))
  34. #define pt_to_loop(_pt) (pt_to_priv_glib(_pt)->loop)
  35. #define pt_to_g_main_context(_pt) g_main_loop_get_context(pt_to_loop(_pt))
  36. #define lws_gs_valid(t) (t.gs)
  37. #define lws_gs_destroy(t) if (lws_gs_valid(t)) { \
  38. g_source_destroy(t.gs); \
  39. g_source_unref(t.gs); \
  40. t.gs = NULL; t.tag = 0; }
  41. static gboolean
  42. lws_glib_idle_timer_cb(void *p);
  43. static gboolean
  44. lws_glib_hrtimer_cb(void *p);
  45. static gboolean
  46. lws_glib_check(GSource *src)
  47. {
  48. struct lws_io_watcher_glib_subclass *sub =
  49. (struct lws_io_watcher_glib_subclass *)src;
  50. return !!g_source_query_unix_fd(src, sub->tag);
  51. }
  52. /*
  53. * These helpers attach only to the main_context that belongs to the pt's glib
  54. * mainloop. The simpler g_timeout_add() and g_idle_add() are forbidden
  55. * because they implicitly choose the default main context to attach to
  56. * instead of specifically the loop bound to the pt.
  57. *
  58. * https://developer.gnome.org/programming-guidelines/unstable/main-contexts.html.en#what-is-gmaincontext
  59. */
  60. static int
  61. lws_glib_set_idle(struct lws_context_per_thread *pt)
  62. {
  63. if (lws_gs_valid(pt_to_priv_glib(pt)->idle))
  64. return 0;
  65. pt_to_priv_glib(pt)->idle.gs = g_idle_source_new();
  66. if (!pt_to_priv_glib(pt)->idle.gs)
  67. return 1;
  68. g_source_set_callback(pt_to_priv_glib(pt)->idle.gs,
  69. lws_glib_idle_timer_cb, pt, NULL);
  70. pt_to_priv_glib(pt)->idle.tag = g_source_attach(
  71. pt_to_priv_glib(pt)->idle.gs, pt_to_g_main_context(pt));
  72. return 0;
  73. }
  74. static int
  75. lws_glib_set_timeout(struct lws_context_per_thread *pt, unsigned int ms)
  76. {
  77. lws_gs_destroy(pt_to_priv_glib(pt)->hrtimer);
  78. pt_to_priv_glib(pt)->hrtimer.gs = g_timeout_source_new(ms);
  79. if (!pt_to_priv_glib(pt)->hrtimer.gs)
  80. return 1;
  81. g_source_set_callback(pt_to_priv_glib(pt)->hrtimer.gs,
  82. lws_glib_hrtimer_cb, pt, NULL);
  83. pt_to_priv_glib(pt)->hrtimer.tag = g_source_attach(
  84. pt_to_priv_glib(pt)->hrtimer.gs,
  85. pt_to_g_main_context(pt));
  86. return 0;
  87. }
  88. static gboolean
  89. lws_glib_dispatch(GSource *src, GSourceFunc x, gpointer userData)
  90. {
  91. struct lws_io_watcher_glib_subclass *sub =
  92. (struct lws_io_watcher_glib_subclass *)src;
  93. struct lws_context_per_thread *pt;
  94. struct lws_pollfd eventfd;
  95. GIOCondition cond;
  96. cond = g_source_query_unix_fd(src, sub->tag);
  97. eventfd.revents = cond;
  98. /* translate from glib event namespace to platform */
  99. if (cond & G_IO_IN)
  100. eventfd.revents |= LWS_POLLIN;
  101. if (cond & G_IO_OUT)
  102. eventfd.revents |= LWS_POLLOUT;
  103. if (cond & G_IO_ERR)
  104. eventfd.revents |= LWS_POLLHUP;
  105. if (cond & G_IO_HUP)
  106. eventfd.revents |= LWS_POLLHUP;
  107. eventfd.events = eventfd.revents;
  108. eventfd.fd = sub->wsi->desc.sockfd;
  109. lwsl_debug("%s: wsi %p: fd %d, events %d\n", __func__, sub->wsi,
  110. eventfd.fd, eventfd.revents);
  111. pt = &sub->wsi->a.context->pt[(int)sub->wsi->tsi];
  112. if (pt->is_destroyed)
  113. return G_SOURCE_CONTINUE;
  114. lws_service_fd_tsi(sub->wsi->a.context, &eventfd, sub->wsi->tsi);
  115. if (!lws_gs_valid(pt_to_priv_glib(pt)->idle))
  116. lws_glib_set_idle(pt);
  117. if (pt->destroy_self)
  118. lws_context_destroy(pt->context);
  119. return G_SOURCE_CONTINUE;
  120. }
  121. static const GSourceFuncs lws_glib_source_ops = {
  122. .prepare = NULL,
  123. .check = lws_glib_check,
  124. .dispatch = lws_glib_dispatch,
  125. .finalize = NULL,
  126. };
  127. /*
  128. * This is the callback for a timer object that is set to the earliest scheduled
  129. * lws event... it services any lws scheduled events that are ready, and then
  130. * resets the event loop timer to the earliest remaining event, if any.
  131. */
  132. static gboolean
  133. lws_glib_hrtimer_cb(void *p)
  134. {
  135. struct lws_context_per_thread *pt = (struct lws_context_per_thread *)p;
  136. unsigned int ms;
  137. lws_usec_t us;
  138. lws_pt_lock(pt, __func__);
  139. lws_gs_destroy(pt_to_priv_glib(pt)->hrtimer);
  140. us = __lws_sul_service_ripe(pt->pt_sul_owner, LWS_COUNT_PT_SUL_OWNERS,
  141. lws_now_usecs());
  142. if (us) {
  143. ms = us / LWS_US_PER_MS;
  144. if (!ms)
  145. ms = 1;
  146. lws_glib_set_timeout(pt, ms);
  147. }
  148. lws_pt_unlock(pt);
  149. lws_glib_set_idle(pt);
  150. return FALSE; /* stop it repeating */
  151. }
  152. static gboolean
  153. lws_glib_idle_timer_cb(void *p)
  154. {
  155. struct lws_context_per_thread *pt = (struct lws_context_per_thread *)p;
  156. if (pt->is_destroyed)
  157. return FALSE;
  158. lws_service_do_ripe_rxflow(pt);
  159. lws_glib_hrtimer_cb(pt);
  160. /*
  161. * is there anybody with pending stuff that needs service forcing?
  162. */
  163. if (!lws_service_adjust_timeout(pt->context, 1, pt->tid)) {
  164. /* -1 timeout means just do forced service */
  165. _lws_plat_service_forced_tsi(pt->context, pt->tid);
  166. /* still somebody left who wants forced service? */
  167. if (!lws_service_adjust_timeout(pt->context, 1, pt->tid))
  168. return TRUE;
  169. }
  170. if (pt->destroy_self)
  171. lws_context_destroy(pt->context);
  172. /*
  173. * For glib, this disables the idle callback. Otherwise we keep
  174. * coming back here immediately endlessly.
  175. *
  176. * We reenable the idle callback on the next network or scheduled event
  177. */
  178. lws_gs_destroy(pt_to_priv_glib(pt)->idle);
  179. return FALSE;
  180. }
  181. void
  182. lws_glib_sigint_cb(void *ctx)
  183. {
  184. struct lws_context_per_thread *pt = ctx;
  185. pt->inside_service = 1;
  186. if (pt->context->eventlib_signal_cb) {
  187. pt->context->eventlib_signal_cb(NULL, 0);
  188. return;
  189. }
  190. if (!pt->event_loop_foreign)
  191. g_main_loop_quit(pt_to_loop(pt));
  192. }
  193. static int
  194. elops_init_context_glib(struct lws_context *context,
  195. const struct lws_context_creation_info *info)
  196. {
  197. // int n;
  198. context->eventlib_signal_cb = info->signal_cb;
  199. // for (n = 0; n < context->count_threads; n++)
  200. // pt_to_priv_glib(&context->pt[n])->w_sigint.context = context;
  201. return 0;
  202. }
  203. static int
  204. elops_accept_glib(struct lws *wsi)
  205. {
  206. struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
  207. struct lws_wsi_eventlibs_glib *wsipr = wsi_to_priv_glib(wsi);
  208. int fd;
  209. assert(!wsi_to_subclass(wsi));
  210. wsi_to_subclass(wsi) = (struct lws_io_watcher_glib_subclass *)
  211. g_source_new((GSourceFuncs *)&lws_glib_source_ops,
  212. sizeof(*wsi_to_subclass(wsi)));
  213. if (!wsi_to_subclass(wsi))
  214. return 1;
  215. wsipr->w_read.context = wsi->a.context;
  216. wsi_to_subclass(wsi)->wsi = wsi;
  217. if (wsi->role_ops->file_handle)
  218. fd = wsi->desc.filefd;
  219. else
  220. fd = wsi->desc.sockfd;
  221. wsi_to_subclass(wsi)->tag = g_source_add_unix_fd(wsi_to_gsource(wsi),
  222. fd, (GIOCondition)LWS_POLLIN);
  223. wsipr->w_read.actual_events = LWS_POLLIN;
  224. g_source_set_callback(wsi_to_gsource(wsi),
  225. G_SOURCE_FUNC(lws_service_fd), wsi->a.context, NULL);
  226. g_source_attach(wsi_to_gsource(wsi), pt_to_g_main_context(pt));
  227. return 0;
  228. }
  229. static int
  230. elops_init_pt_glib(struct lws_context *context, void *_loop, int tsi)
  231. {
  232. struct lws_context_per_thread *pt = &context->pt[tsi];
  233. struct lws_pt_eventlibs_glib *ptpr = pt_to_priv_glib(pt);
  234. struct lws_vhost *vh = context->vhost_list;
  235. GMainLoop *loop = (GMainLoop *)_loop;
  236. if (!loop)
  237. loop = g_main_loop_new(NULL, 0);
  238. else
  239. context->pt[tsi].event_loop_foreign = 1;
  240. if (!loop) {
  241. lwsl_err("%s: creating glib loop failed\n", __func__);
  242. return -1;
  243. }
  244. ptpr->loop = loop;
  245. /*
  246. * Initialize all events with the listening sockets
  247. * and register a callback for read operations
  248. */
  249. while (vh) {
  250. if (vh->lserv_wsi)
  251. elops_accept_glib(vh->lserv_wsi);
  252. vh = vh->vhost_next;
  253. }
  254. lws_glib_set_idle(pt);
  255. /* Register the signal watcher unless it's a foreign loop */
  256. if (pt->event_loop_foreign)
  257. return 0;
  258. ptpr->sigint.tag = g_unix_signal_add(SIGINT,
  259. G_SOURCE_FUNC(lws_glib_sigint_cb), pt);
  260. return 0;
  261. }
  262. /*
  263. * We are changing the event wait for this guy
  264. */
  265. static void
  266. elops_io_glib(struct lws *wsi, int flags)
  267. {
  268. struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
  269. struct lws_wsi_eventlibs_glib *wsipr = wsi_to_priv_glib(wsi);
  270. GIOCondition cond = wsipr->w_read.actual_events | G_IO_ERR;
  271. if (!pt_to_loop(pt) || wsi->a.context->being_destroyed ||
  272. pt->is_destroyed)
  273. return;
  274. if (!wsi_to_subclass(wsi))
  275. return;
  276. /*
  277. * We are being given individual set / clear operations using
  278. * LWS_EV_ common namespace, convert them to glib namespace bitfield
  279. */
  280. if (flags & LWS_EV_READ) {
  281. if (flags & LWS_EV_STOP)
  282. cond &= ~(G_IO_IN | G_IO_HUP);
  283. else
  284. cond |= G_IO_IN | G_IO_HUP;
  285. }
  286. if (flags & LWS_EV_WRITE) {
  287. if (flags & LWS_EV_STOP)
  288. cond &= ~G_IO_OUT;
  289. else
  290. cond |= G_IO_OUT;
  291. }
  292. wsipr->w_read.actual_events = cond;
  293. lwsl_debug("%s: wsi %p, fd %d, 0x%x/0x%x\n", __func__, wsi,
  294. wsi->desc.sockfd, flags, (int)cond);
  295. g_source_modify_unix_fd(wsi_to_gsource(wsi), wsi_to_subclass(wsi)->tag,
  296. cond);
  297. }
  298. static void
  299. elops_run_pt_glib(struct lws_context *context, int tsi)
  300. {
  301. struct lws_context_per_thread *pt = &context->pt[tsi];
  302. if (pt_to_loop(pt))
  303. g_main_loop_run(pt_to_loop(pt));
  304. }
  305. static void
  306. elops_destroy_wsi_glib(struct lws *wsi)
  307. {
  308. struct lws_context_per_thread *pt;
  309. if (!wsi)
  310. return;
  311. pt = &wsi->a.context->pt[(int)wsi->tsi];
  312. if (pt->is_destroyed)
  313. return;
  314. if (!wsi_to_gsource(wsi))
  315. return;
  316. if (wsi_to_subclass(wsi)->tag) {
  317. g_source_remove_unix_fd(wsi_to_gsource(wsi),
  318. wsi_to_subclass(wsi)->tag);
  319. wsi_to_subclass(wsi)->tag = NULL;
  320. }
  321. g_source_destroy(wsi_to_gsource(wsi));
  322. g_source_unref(wsi_to_gsource(wsi));
  323. wsi_to_subclass(wsi) = NULL;
  324. }
  325. static void
  326. elops_destroy_pt_glib(struct lws_context *context, int tsi)
  327. {
  328. struct lws_context_per_thread *pt = &context->pt[tsi];
  329. struct lws_pt_eventlibs_glib *ptpr = pt_to_priv_glib(pt);
  330. struct lws_vhost *vh = context->vhost_list;
  331. if (!pt_to_loop(pt))
  332. return;
  333. /*
  334. * Free all events with the listening sockets
  335. */
  336. while (vh) {
  337. if (vh->lserv_wsi)
  338. elops_destroy_wsi_glib(vh->lserv_wsi);
  339. vh = vh->vhost_next;
  340. }
  341. lws_gs_destroy(ptpr->idle);
  342. lws_gs_destroy(ptpr->hrtimer);
  343. if (!pt->event_loop_foreign) {
  344. g_main_loop_quit(pt_to_loop(pt));
  345. lws_gs_destroy(ptpr->sigint);
  346. g_main_loop_unref(pt_to_loop(pt));
  347. }
  348. pt_to_loop(pt) = NULL;
  349. }
  350. static int
  351. elops_destroy_context2_glib(struct lws_context *context)
  352. {
  353. struct lws_context_per_thread *pt = &context->pt[0];
  354. int n;
  355. for (n = 0; n < (int)context->count_threads; n++) {
  356. if (!pt->event_loop_foreign)
  357. g_main_loop_quit(pt_to_loop(pt));
  358. pt++;
  359. }
  360. return 0;
  361. }
  362. static int
  363. elops_wsi_logical_close_glib(struct lws *wsi)
  364. {
  365. elops_destroy_wsi_glib(wsi);
  366. return 0;
  367. }
  368. static const struct lws_event_loop_ops event_loop_ops_glib = {
  369. /* name */ "glib",
  370. /* init_context */ elops_init_context_glib,
  371. /* destroy_context1 */ NULL,
  372. /* destroy_context2 */ elops_destroy_context2_glib,
  373. /* init_vhost_listen_wsi */ elops_accept_glib,
  374. /* init_pt */ elops_init_pt_glib,
  375. /* wsi_logical_close */ elops_wsi_logical_close_glib,
  376. /* check_client_connect_ok */ NULL,
  377. /* close_handle_manually */ NULL,
  378. /* accept */ elops_accept_glib,
  379. /* io */ elops_io_glib,
  380. /* run_pt */ elops_run_pt_glib,
  381. /* destroy_pt */ elops_destroy_pt_glib,
  382. /* destroy wsi */ elops_destroy_wsi_glib,
  383. /* flags */ LELOF_DESTROY_FINAL,
  384. /* evlib_size_ctx */ 0,
  385. /* evlib_size_pt */ sizeof(struct lws_pt_eventlibs_glib),
  386. /* evlib_size_vh */ 0,
  387. /* evlib_size_wsi */ sizeof(struct lws_io_watcher_glib),
  388. };
  389. #if defined(LWS_WITH_EVLIB_PLUGINS)
  390. LWS_VISIBLE
  391. #endif
  392. const lws_plugin_evlib_t evlib_glib = {
  393. .hdr = {
  394. "glib event loop",
  395. "lws_evlib_plugin",
  396. LWS_PLUGIN_API_MAGIC
  397. },
  398. .ops = &event_loop_ops_glib
  399. };