1/*
2   Unix SMB/CIFS implementation.
3   main select loop and event handling
4   wrapper for http://liboop.org/
5
6   Copyright (C) Stefan Metzmacher 2005
7
8     ** NOTE! The following LGPL license applies to the tevent
9     ** library. This does NOT imply that all of Samba is released
10     ** under the LGPL
11
12   This library is free software; you can redistribute it and/or
13   modify it under the terms of the GNU Lesser General Public
14   License as published by the Free Software Foundation; either
15   version 3 of the License, or (at your option) any later version.
16
17   This library is distributed in the hope that it will be useful,
18   but WITHOUT ANY WARRANTY; without even the implied warranty of
19   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20   Lesser General Public License for more details.
21
22   You should have received a copy of the GNU Lesser General Public
23   License along with this library; if not, see <http://www.gnu.org/licenses/>.
24*/
25
26#include "events.h"
27#include "events_internal.h"
28
29#include <oop.h>
30
31/*
32 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
33
34 NOTE: this code compiles fine, but is completly *UNTESTED*
35       and is only commited as example
36
37 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
38*/
39
40static int oop_event_context_destructor(struct tevent_context *ev)
41{
42	oop_source_sys *oop_sys = ev->additional_data;
43
44	oop_sys_delete(oop_sys);
45
46	return 0;
47}
48
49/*
50  create a oop_event_context structure.
51*/
52static int oop_event_context_init(struct tevent_context *ev, void *private_data)
53{
54	oop_source_sys *oop_sys = private_data;
55
56	if (!oop_sys) {
57		oop_sys = oop_sys_new();
58		if (!oop_sys) {
59			return -1;
60		}
61
62		talloc_set_destructor(ev, oop_event_context_destructor);
63	}
64
65	ev->additional_data = oop_sys;
66
67	return 0;
68}
69
70static void *oop_event_fd_handler(oop_source *oop, int fd, oop_event oop_type, void *ptr)
71{
72	struct tevent_fd *fde = ptr;
73
74	if (fd != fde->fd) return OOP_ERROR;
75
76	switch(oop_type) {
77		case OOP_READ:
78			fde->handler(fde->event_ctx, fde, EVENT_FD_READ, fde->private_data);
79			return OOP_CONTINUE;
80		case OOP_WRITE:
81			fde->handler(fde->event_ctx, fde, EVENT_FD_WRITE, fde->private_data);
82			return OOP_CONTINUE;
83		case OOP_EXCEPTION:
84			return OOP_ERROR;
85		case OOP_NUM_EVENTS:
86			return OOP_ERROR;
87	}
88
89	return OOP_ERROR;
90}
91
92/*
93  destroy an fd_event
94*/
95static int oop_event_fd_destructor(struct tevent_fd *fde)
96{
97	struct tevent_context *ev = fde->event_ctx;
98	oop_source_sys *oop_sys = ev->additional_data;
99	oop_source *oop = oop_sys_source(oop_sys);
100
101	if (fde->flags & EVENT_FD_READ)
102		oop->cancel_fd(oop, fde->fd, OOP_READ);
103	if (fde->flags & EVENT_FD_WRITE)
104		oop->cancel_fd(oop, fde->fd, OOP_WRITE);
105
106	if (fde->flags & EVENT_FD_AUTOCLOSE) {
107		close(fde->fd);
108		fde->fd = -1;
109	}
110
111	return 0;
112}
113
114/*
115  add a fd based event
116  return NULL on failure (memory allocation error)
117*/
118static struct tevent_fd *oop_event_add_fd(struct tevent_context *ev, TALLOC_CTX *mem_ctx,
119					 int fd, uint16_t flags,
120					 event_fd_handler_t handler,
121					 void *private_data)
122{
123	struct tevent_fd *fde;
124	oop_source_sys *oop_sys = ev->additional_data;
125	oop_source *oop = oop_sys_source(oop_sys);
126
127	fde = talloc(mem_ctx?mem_ctx:ev, struct tevent_fd);
128	if (!fde) return NULL;
129
130	fde->event_ctx		= ev;
131	fde->fd			= fd;
132	fde->flags		= flags;
133	fde->handler		= handler;
134	fde->private_data	= private_data;
135	fde->additional_flags	= 0;
136	fde->additional_data	= NULL;
137
138	if (fde->flags & EVENT_FD_READ)
139		oop->on_fd(oop, fde->fd, OOP_READ, oop_event_fd_handler, fde);
140	if (fde->flags & EVENT_FD_WRITE)
141		oop->on_fd(oop, fde->fd, OOP_WRITE, oop_event_fd_handler, fde);
142
143	talloc_set_destructor(fde, oop_event_fd_destructor);
144
145	return fde;
146}
147
148/*
149  return the fd event flags
150*/
151static uint16_t oop_event_get_fd_flags(struct tevent_fd *fde)
152{
153	return fde->flags;
154}
155
156/*
157  set the fd event flags
158*/
159static void oop_event_set_fd_flags(struct tevent_fd *fde, uint16_t flags)
160{
161	oop_source_sys *oop_sys;
162	oop_source *oop;
163
164	oop_sys = fde->event_ctx->additional_data;
165	oop = oop_sys_source(oop_sys);
166
167	if ((fde->flags & EVENT_FD_READ)&&(!(flags & EVENT_FD_READ)))
168		oop->cancel_fd(oop, fde->fd, OOP_READ);
169
170	if ((!(fde->flags & EVENT_FD_READ))&&(flags & EVENT_FD_READ))
171		oop->on_fd(oop, fde->fd, OOP_READ, oop_event_fd_handler, fde);
172
173	if ((fde->flags & EVENT_FD_WRITE)&&(!(flags & EVENT_FD_WRITE)))
174		oop->cancel_fd(oop, fde->fd, OOP_WRITE);
175
176	if ((!(fde->flags & EVENT_FD_WRITE))&&(flags & EVENT_FD_WRITE))
177		oop->on_fd(oop, fde->fd, OOP_WRITE, oop_event_fd_handler, fde);
178
179	fde->flags = flags;
180}
181
182static int oop_event_timed_destructor(struct tevent_timer *te);
183
184static int oop_event_timed_deny_destructor(struct tevent_timer *te)
185{
186	return -1;
187}
188
189static void *oop_event_timed_handler(oop_source *oop, struct timeval t, void *ptr)
190{
191	struct tevent_timer *te = ptr;
192
193	/* deny the handler to free the event */
194	talloc_set_destructor(te, oop_event_timed_deny_destructor);
195	te->handler(te->event_ctx, te, t, te->private_data);
196
197	talloc_set_destructor(te, oop_event_timed_destructor);
198	talloc_free(te);
199
200	return OOP_CONTINUE;
201}
202
203/*
204  destroy a timed event
205*/
206static int oop_event_timed_destructor(struct tevent_timer *te)
207{
208	struct tevent_context *ev = te->event_ctx;
209	oop_source_sys *oop_sys = ev->additional_data;
210	oop_source *oop = oop_sys_source(oop_sys);
211
212	oop->cancel_time(oop, te->next_event, oop_event_timed_handler, te);
213
214	return 0;
215}
216
217/*
218  add a timed event
219  return NULL on failure (memory allocation error)
220*/
221static struct tevent_timer *oop_event_add_timed(struct tevent_context *ev, TALLOC_CTX *mem_ctx,
222					       struct timeval next_event,
223					       event_timed_handler_t handler,
224					       void *private_data)
225{
226	oop_source_sys *oop_sys = ev->additional_data;
227	oop_source *oop = oop_sys_source(oop_sys);
228	struct tevent_timer *te;
229
230	te = talloc(mem_ctx?mem_ctx:ev, struct tevent_timer);
231	if (te == NULL) return NULL;
232
233	te->event_ctx		= ev;
234	te->next_event		= next_event;
235	te->handler		= handler;
236	te->private_data	= private_data;
237	te->additional_data	= NULL;
238
239	oop->on_time(oop, te->next_event, oop_event_timed_handler, te);
240
241	talloc_set_destructor(te, oop_event_timed_destructor);
242
243	return te;
244}
245
246/*
247  do a single event loop using the events defined in ev
248*/
249static int oop_event_loop_once(struct tevent_context *ev)
250{
251	void *oop_ret;
252	oop_source_sys *oop_sys = ev->additional_data;
253
254	oop_ret = oop_sys_run_once(oop_sys);
255	if (oop_ret == OOP_CONTINUE) {
256		return 0;
257	}
258
259	return -1;
260}
261
262/*
263  return on failure or (with 0) if all fd events are removed
264*/
265static int oop_event_loop_wait(struct tevent_context *ev)
266{
267	void *oop_ret;
268	oop_source_sys *oop_sys = ev->additional_data;
269
270	oop_ret = oop_sys_run(oop_sys);
271	if (oop_ret == OOP_CONTINUE) {
272		return 0;
273	}
274
275	return -1;
276}
277
278static const struct event_ops event_oop_ops = {
279	.context_init	= oop_event_context_init,
280	.add_fd		= oop_event_add_fd,
281	.get_fd_flags	= oop_event_get_fd_flags,
282	.set_fd_flags	= oop_event_set_fd_flags,
283	.add_timer	= oop_event_add_timed,
284	.add_signal	= common_event_add_signal,
285	.loop_once	= oop_event_loop_once,
286	.loop_wait	= oop_event_loop_wait,
287};
288
289const struct event_ops *event_liboop_get_ops(void)
290{
291	return &event_oop_ops;
292}
293