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#include "private-lib-event-libs-libevent.h"
27
28#define pt_to_priv_event(_pt) ((struct lws_pt_eventlibs_libevent *)(_pt)->evlib_pt)
29#define wsi_to_priv_event(_w) ((struct lws_wsi_eventlibs_libevent *)(_w)->evlib_wsi)
30
31static void
32lws_event_hrtimer_cb(evutil_socket_t fd, short event, void *p)
33{
34	struct lws_context_per_thread *pt = (struct lws_context_per_thread *)p;
35	struct lws_pt_eventlibs_libevent *ptpr = pt_to_priv_event(pt);
36	struct timeval tv;
37	lws_usec_t us;
38
39	lws_pt_lock(pt, __func__);
40	us = __lws_sul_service_ripe(pt->pt_sul_owner, LWS_COUNT_PT_SUL_OWNERS,
41				    lws_now_usecs());
42	if (us) {
43#if defined(__APPLE__)
44		tv.tv_sec = (int)(us / LWS_US_PER_SEC);
45		tv.tv_usec = (int)(us - (tv.tv_sec * LWS_US_PER_SEC));
46#else
47		tv.tv_sec = (long)(us / LWS_US_PER_SEC);
48		tv.tv_usec = (long)(us - (tv.tv_sec * LWS_US_PER_SEC));
49#endif
50		evtimer_add(ptpr->hrtimer, &tv);
51	}
52	lws_pt_unlock(pt);
53}
54
55static void
56lws_event_idle_timer_cb(evutil_socket_t fd, short event, void *p)
57{
58	struct lws_context_per_thread *pt = (struct lws_context_per_thread *)p;
59	struct lws_pt_eventlibs_libevent *ptpr = pt_to_priv_event(pt);
60	struct timeval tv;
61	lws_usec_t us;
62
63	if (pt->is_destroyed)
64		return;
65
66	lws_service_do_ripe_rxflow(pt);
67
68	/*
69	 * is there anybody with pending stuff that needs service forcing?
70	 */
71	if (!lws_service_adjust_timeout(pt->context, 1, pt->tid)) {
72		/* -1 timeout means just do forced service */
73		_lws_plat_service_forced_tsi(pt->context, pt->tid);
74		/* still somebody left who wants forced service? */
75		if (!lws_service_adjust_timeout(pt->context, 1, pt->tid)) {
76			/* yes... come back again later */
77
78			tv.tv_sec = 0;
79			tv.tv_usec = 1000;
80			evtimer_add(ptpr->idle_timer, &tv);
81
82			return;
83		}
84	}
85
86	/* account for hrtimer */
87
88	lws_pt_lock(pt, __func__);
89	us = __lws_sul_service_ripe(pt->pt_sul_owner, LWS_COUNT_PT_SUL_OWNERS,
90				    lws_now_usecs());
91	if (us) {
92		tv.tv_sec = (suseconds_t)(us / LWS_US_PER_SEC);
93		tv.tv_usec = (suseconds_t)(us - (tv.tv_sec * LWS_US_PER_SEC));
94		evtimer_add(ptpr->hrtimer, &tv);
95	}
96	lws_pt_unlock(pt);
97
98	if (pt->destroy_self)
99		lws_context_destroy(pt->context);
100}
101
102static void
103lws_event_cb(evutil_socket_t sock_fd, short revents, void *ctx)
104{
105	struct lws_signal_watcher_libevent *lws_io =
106			(struct lws_signal_watcher_libevent *)ctx;
107	struct lws_context *context = lws_io->context;
108	struct lws_context_per_thread *pt;
109	struct lws_pollfd eventfd;
110	struct timeval tv;
111	struct lws *wsi;
112
113	if (revents & EV_TIMEOUT)
114		return;
115
116	/* !!! EV_CLOSED doesn't exist in libevent2 */
117#if LIBEVENT_VERSION_NUMBER < 0x02000000
118	if (revents & EV_CLOSED) {
119		event_del(lws_io->event.watcher);
120		event_free(lws_io->event.watcher);
121		return;
122	}
123#endif
124
125	eventfd.fd = sock_fd;
126	eventfd.events = 0;
127	eventfd.revents = 0;
128	if (revents & EV_READ) {
129		eventfd.events |= LWS_POLLIN;
130		eventfd.revents |= LWS_POLLIN;
131	}
132	if (revents & EV_WRITE) {
133		eventfd.events |= LWS_POLLOUT;
134		eventfd.revents |= LWS_POLLOUT;
135	}
136
137	wsi = wsi_from_fd(context, sock_fd);
138	if (!wsi)
139		return;
140
141	pt = &context->pt[(int)wsi->tsi];
142	if (pt->is_destroyed)
143		return;
144
145	lws_service_fd_tsi(context, &eventfd, wsi->tsi);
146
147	if (pt->destroy_self) {
148		lwsl_cx_notice(context, "pt destroy self coming true");
149		lws_context_destroy(pt->context);
150		return;
151	}
152
153	/* set the idle timer for 1ms ahead */
154
155	tv.tv_sec = 0;
156	tv.tv_usec = 1000;
157	evtimer_add(pt_to_priv_event(pt)->idle_timer, &tv);
158}
159
160void
161lws_event_sigint_cb(evutil_socket_t sock_fd, short revents, void *ctx)
162{
163	struct lws_context_per_thread *pt = ctx;
164	struct event *signal = pt_to_priv_event(pt)->w_sigint.watcher;
165
166	if (pt->context->eventlib_signal_cb) {
167		pt->context->eventlib_signal_cb((void *)(lws_intptr_t)sock_fd,
168						event_get_signal(signal));
169
170		return;
171	}
172	if (!pt->event_loop_foreign)
173		event_base_loopbreak(pt_to_priv_event(pt)->io_loop);
174}
175
176static int
177elops_listen_init_event(struct lws_dll2 *d, void *user)
178{
179	struct lws *wsi = lws_container_of(d, struct lws, listen_list);
180	struct lws_context *context = (struct lws_context *)user;
181	struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
182	struct lws_pt_eventlibs_libevent *ptpr = pt_to_priv_event(pt);
183	struct lws_io_watcher_libevent *w_read =
184					&(wsi_to_priv_event(wsi)->w_read);
185
186	w_read->context = context;
187	w_read->watcher = event_new(ptpr->io_loop, wsi->desc.sockfd,
188				(EV_READ | EV_PERSIST), lws_event_cb, w_read);
189	event_add(w_read->watcher, NULL);
190	w_read->set = 1;
191
192	return 0;
193}
194
195static int
196elops_init_pt_event(struct lws_context *context, void *_loop, int tsi)
197{
198	struct event_base *loop = (struct event_base *)_loop;
199	struct lws_context_per_thread *pt = &context->pt[tsi];
200	struct lws_pt_eventlibs_libevent *ptpr = pt_to_priv_event(pt);
201
202	lwsl_cx_info(context, "loop %p", _loop);
203
204	if (!loop)
205		loop = event_base_new();
206	else
207		context->pt[tsi].event_loop_foreign = 1;
208
209	if (!loop) {
210		lwsl_cx_err(context, "creating event base failed");
211
212		return -1;
213	}
214
215	ptpr->io_loop = loop;
216
217	lws_vhost_foreach_listen_wsi(context, context, elops_listen_init_event);
218
219	/* static event loop objects */
220
221	ptpr->hrtimer = event_new(loop, -1, EV_PERSIST,
222				      lws_event_hrtimer_cb, pt);
223
224	ptpr->idle_timer = event_new(loop, -1, 0,
225					 lws_event_idle_timer_cb, pt);
226	{
227		struct timeval tv;
228		tv.tv_sec = (long)0;
229		tv.tv_usec = (long)1000;
230		evtimer_add(ptpr->hrtimer, &tv);
231	}
232
233	/* Register the signal watcher unless it's a foreign loop */
234
235	if (pt->event_loop_foreign)
236		return 0;
237
238	ptpr->w_sigint.watcher = evsignal_new(loop, SIGINT,
239						  lws_event_sigint_cb, pt);
240	event_add(ptpr->w_sigint.watcher, NULL);
241
242	return 0;
243}
244
245static int
246elops_init_context_event(struct lws_context *context,
247			 const struct lws_context_creation_info *info)
248{
249	int n;
250
251	context->eventlib_signal_cb = info->signal_cb;
252
253	for (n = 0; n < context->count_threads; n++)
254		pt_to_priv_event(&context->pt[n])->w_sigint.context = context;
255
256	return 0;
257}
258
259static int
260elops_accept_event(struct lws *wsi)
261{
262	struct lws_context *context = lws_get_context(wsi);
263	struct lws_context_per_thread *pt;
264	struct lws_pt_eventlibs_libevent *ptpr;
265	struct lws_wsi_eventlibs_libevent *wpr = wsi_to_priv_event(wsi);
266       evutil_socket_t fd;
267
268	wpr->w_read.context = context;
269	wpr->w_write.context = context;
270
271	// Initialize the event
272	pt = &context->pt[(int)wsi->tsi];
273	ptpr = pt_to_priv_event(pt);
274
275	if (wsi->role_ops->file_handle)
276               fd = (evutil_socket_t)(ev_intptr_t) wsi->desc.filefd;
277	else
278		fd = wsi->desc.sockfd;
279
280	wpr->w_read.watcher = event_new(ptpr->io_loop, fd,
281			(EV_READ | EV_PERSIST), lws_event_cb, &wpr->w_read);
282	wpr->w_write.watcher = event_new(ptpr->io_loop, fd,
283			(EV_WRITE | EV_PERSIST), lws_event_cb, &wpr->w_write);
284
285	return 0;
286}
287
288static void
289elops_io_event(struct lws *wsi, unsigned int flags)
290{
291	struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi];
292	struct lws_pt_eventlibs_libevent *ptpr = pt_to_priv_event(pt);
293	struct lws_wsi_eventlibs_libevent *wpr = wsi_to_priv_event(wsi);
294
295	if (!ptpr->io_loop || wsi->a.context->being_destroyed ||
296	    pt->is_destroyed)
297		return;
298
299	assert((flags & (LWS_EV_START | LWS_EV_STOP)) &&
300	       (flags & (LWS_EV_READ | LWS_EV_WRITE)));
301
302	if (flags & LWS_EV_START) {
303		if ((flags & LWS_EV_WRITE) && !wpr->w_write.set) {
304			event_add(wpr->w_write.watcher, NULL);
305			wpr->w_write.set = 1;
306		}
307
308		if ((flags & LWS_EV_READ) && !wpr->w_read.set) {
309			event_add(wpr->w_read.watcher, NULL);
310			wpr->w_read.set = 1;
311		}
312	} else {
313		if ((flags & LWS_EV_WRITE) && wpr->w_write.set) {
314			event_del(wpr->w_write.watcher);
315			wpr->w_write.set = 0;
316		}
317
318		if ((flags & LWS_EV_READ) && wpr->w_read.set) {
319			event_del(wpr->w_read.watcher);
320			wpr->w_read.set = 0;
321		}
322	}
323}
324
325static void
326elops_run_pt_event(struct lws_context *context, int tsi)
327{
328	/* Run / Dispatch the event_base loop */
329	if (pt_to_priv_event(&context->pt[tsi])->io_loop)
330		event_base_dispatch(
331			pt_to_priv_event(&context->pt[tsi])->io_loop);
332}
333
334static int
335elops_listen_destroy_event(struct lws_dll2 *d, void *user)
336{
337	struct lws *wsi = lws_container_of(d, struct lws, listen_list);
338	struct lws_wsi_eventlibs_libevent *w = wsi_to_priv_event(wsi);
339
340	event_free(w->w_read.watcher);
341	w->w_read.watcher = NULL;
342	event_free(w->w_write.watcher);
343	w->w_write.watcher = NULL;
344
345	return 0;
346}
347
348static void
349elops_destroy_pt_event(struct lws_context *context, int tsi)
350{
351	struct lws_context_per_thread *pt = &context->pt[tsi];
352	struct lws_pt_eventlibs_libevent *ptpr = pt_to_priv_event(pt);
353
354	if (!ptpr->io_loop)
355		return;
356
357	lws_vhost_foreach_listen_wsi(context, context, elops_listen_destroy_event);
358
359	event_free(ptpr->hrtimer);
360	event_free(ptpr->idle_timer);
361
362	if (!pt->event_loop_foreign) {
363		event_del(ptpr->w_sigint.watcher);
364		event_free(ptpr->w_sigint.watcher);
365		event_base_loopexit(ptpr->io_loop, NULL);
366	//	event_base_free(pt->event.io_loop);
367	//	pt->event.io_loop = NULL;
368		lwsl_cx_notice(context, "set to exit loop");
369	}
370}
371
372static void
373elops_destroy_wsi_event(struct lws *wsi)
374{
375	struct lws_context_per_thread *pt;
376	struct lws_wsi_eventlibs_libevent *w;
377
378	if (!wsi)
379		return;
380
381	pt = &wsi->a.context->pt[(int)wsi->tsi];
382	if (pt->is_destroyed)
383		return;
384
385	w = wsi_to_priv_event(wsi);
386
387	if (w->w_read.watcher) {
388		event_free(w->w_read.watcher);
389		w->w_read.watcher = NULL;
390	}
391
392	if (w->w_write.watcher) {
393		event_free(w->w_write.watcher);
394		w->w_write.watcher = NULL;
395	}
396}
397
398static int
399elops_wsi_logical_close_event(struct lws *wsi)
400{
401	elops_destroy_wsi_event(wsi);
402
403	return 0;
404}
405
406static int
407elops_init_vhost_listen_wsi_event(struct lws *wsi)
408{
409	struct lws_context_per_thread *pt;
410	struct lws_pt_eventlibs_libevent *ptpr;
411	struct lws_wsi_eventlibs_libevent *w;
412       evutil_socket_t fd;
413
414	if (!wsi) {
415		assert(0);
416		return 0;
417	}
418
419	w = wsi_to_priv_event(wsi);
420
421	w->w_read.context = wsi->a.context;
422	w->w_write.context = wsi->a.context;
423
424	pt = &wsi->a.context->pt[(int)wsi->tsi];
425	ptpr = pt_to_priv_event(pt);
426
427	if (wsi->role_ops->file_handle)
428               fd = (evutil_socket_t) wsi->desc.filefd;
429	else
430		fd = wsi->desc.sockfd;
431
432	w->w_read.watcher = event_new(ptpr->io_loop, fd, (EV_READ | EV_PERSIST),
433				      lws_event_cb, &w->w_read);
434	w->w_write.watcher = event_new(ptpr->io_loop, fd,
435				       (EV_WRITE | EV_PERSIST),
436				       lws_event_cb, &w->w_write);
437
438	elops_io_event(wsi, LWS_EV_START | LWS_EV_READ);
439
440	return 0;
441}
442
443static int
444elops_destroy_context2_event(struct lws_context *context)
445{
446	struct lws_context_per_thread *pt;
447	struct lws_pt_eventlibs_libevent *ptpr;
448	int n, m;
449
450	for (n = 0; n < context->count_threads; n++) {
451		int budget = 1000;
452
453		pt = &context->pt[n];
454		ptpr = pt_to_priv_event(pt);
455
456		/* only for internal loops... */
457
458		if (pt->event_loop_foreign || !ptpr->io_loop)
459			continue;
460
461		if (!context->evlib_finalize_destroy_after_int_loops_stop) {
462			event_base_loopexit(ptpr->io_loop, NULL);
463			continue;
464		}
465		while (budget-- &&
466		       (m = event_base_loop(ptpr->io_loop, EVLOOP_NONBLOCK)))
467			;
468
469		lwsl_cx_info(context, "event_base_free");
470
471		event_base_free(ptpr->io_loop);
472		ptpr->io_loop = NULL;
473	}
474
475	return 0;
476}
477
478static const struct lws_event_loop_ops event_loop_ops_event = {
479	/* name */			"libevent",
480	/* init_context */		elops_init_context_event,
481	/* destroy_context1 */		NULL,
482	/* destroy_context2 */		elops_destroy_context2_event,
483	/* init_vhost_listen_wsi */	elops_init_vhost_listen_wsi_event,
484	/* init_pt */			elops_init_pt_event,
485	/* wsi_logical_close */		elops_wsi_logical_close_event,
486	/* check_client_connect_ok */	NULL,
487	/* close_handle_manually */	NULL,
488	/* accept */			elops_accept_event,
489	/* io */			elops_io_event,
490	/* run_pt */			elops_run_pt_event,
491	/* destroy_pt */		elops_destroy_pt_event,
492	/* destroy wsi */		elops_destroy_wsi_event,
493	/* foreign_thread */		NULL,
494
495	/* flags */			0,
496
497	/* evlib_size_ctx */	0,
498	/* evlib_size_pt */	sizeof(struct lws_pt_eventlibs_libevent),
499	/* evlib_size_vh */	0,
500	/* evlib_size_wsi */	sizeof(struct lws_wsi_eventlibs_libevent),
501};
502
503#if defined(LWS_WITH_EVLIB_PLUGINS)
504LWS_VISIBLE
505#endif
506const lws_plugin_evlib_t evlib_event = {
507	.hdr = {
508		"libevent event loop",
509		"lws_evlib_plugin",
510		LWS_BUILD_HASH,
511		LWS_PLUGIN_API_MAGIC
512	},
513
514	.ops	= &event_loop_ops_event
515};
516