1 /*
2 * Copyright (c) 2006, Stefan Walter
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * * Redistributions of source code must retain the above
10 * copyright notice, this list of conditions and the
11 * following disclaimer.
12 * * Redistributions in binary form must reproduce the
13 * above copyright notice, this list of conditions and
14 * the following disclaimer in the documentation and/or
15 * other materials provided with the distribution.
16 * * The names of contributors to this software may not be
17 * used to endorse or promote products derived from this
18 * software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
31 * DAMAGE.
32 */
33
34 #include "usuals.h"
35 #include <errno.h>
36 #include <sys/time.h>
37 #include <err.h>
38
39 #include "server-mainloop.h"
40
41 #define timeval_to_ms(tv) \
42 ((((uint64_t)(tv).tv_sec) * 1000L) + (((uint64_t)(tv).tv_usec) / 1000L))
43
44 typedef struct _socket_callback
45 {
46 int fd;
47 server_socket_callback callback;
48 void* arg;
49
50 struct _socket_callback* next;
51 }
52 socket_callback;
53
54 typedef struct _timer_callback
55 {
56 struct timeval at;
57 struct timeval interval;
58 server_timer_callback callback;
59 void* arg;
60
61 struct _timer_callback* next;
62 }
63 timer_callback;
64
65 typedef struct _server_context
66 {
67 int stopped;
68 fd_set read_fds;
69 fd_set write_fds;
70 int max_fd;
71 socket_callback* callbacks;
72 timer_callback* timers;
73 }
74 server_context;
75
76 /* Global context */
77 static server_context ctx;
78
79 static int
add_timer(struct timeval at,int period_ms,server_timer_callback callback,void * arg)80 add_timer(struct timeval at, int period_ms, server_timer_callback callback, void* arg)
81 {
82 struct timeval interval;
83 timer_callback* cb;
84
85 ASSERT(period_ms >= 0);
86 ASSERT(callback != NULL);
87
88 if (period_ms == 0)
89 {
90 timerclear(&interval); /* one-shot */
91 }
92 else
93 {
94 interval.tv_sec = period_ms / 1000;
95 interval.tv_usec = (period_ms % 1000) * 1000; /* into micro seconds */
96 }
97
98 cb = (timer_callback*)calloc(1, sizeof(*cb));
99 if(!cb)
100 {
101 errno = ENOMEM;
102 return -1;
103 }
104
105 memcpy(&cb->at, &at, sizeof(cb->at));
106 memcpy(&cb->interval, &interval, sizeof(cb->interval));
107
108 cb->callback = callback;
109 cb->arg = arg;
110
111 cb->next = ctx.timers;
112 ctx.timers = cb;
113
114 return 0;
115 }
116
117 static timer_callback*
remove_timer(timer_callback * timcb)118 remove_timer(timer_callback* timcb)
119 {
120 timer_callback* cb;
121 timer_callback* next;
122
123 if(!ctx.timers)
124 return NULL;
125
126 /* First in list */;
127 if(ctx.timers == timcb)
128 {
129 cb = ctx.timers;
130 ctx.timers = ctx.timers->next;
131 free(cb);
132 return ctx.timers;
133 }
134
135 /* One ahead processing of rest */
136 for(cb = ctx.timers; cb->next; cb = cb->next)
137 {
138 if(cb->next == timcb)
139 {
140 next = cb->next->next;
141 free(cb->next);
142 cb->next = next;
143 return cb->next;
144 }
145 }
146
147 /* Couldn't remove, return self */
148 return timcb;
149 }
150
151 void
server_init()152 server_init()
153 {
154 memset(&ctx, 0, sizeof (ctx));
155 FD_ZERO(&ctx.read_fds);
156 FD_ZERO(&ctx.write_fds);
157
158 ctx.max_fd = -1;
159 ctx.stopped = 1;
160 ctx.callbacks = NULL;
161 ctx.timers = NULL;
162 }
163
164 void
server_uninit()165 server_uninit()
166 {
167 timer_callback* timcb;
168 timer_callback* timn;
169 socket_callback* sockcb;
170 socket_callback* sockn;
171
172 for(timcb = ctx.timers; timcb; timcb = timn)
173 {
174 timn = timcb->next;
175 free(timcb);
176 }
177
178 ctx.timers = NULL;
179
180 for(sockcb = ctx.callbacks; sockcb; sockcb = sockn)
181 {
182 sockn = sockcb->next;
183 free(sockcb);
184 }
185
186 ctx.callbacks = NULL;
187 }
188
189 uint64_t
server_get_time()190 server_get_time()
191 {
192 struct timeval tv;
193 if(gettimeofday(&tv, NULL) == -1)
194 return 0L;
195 return timeval_to_ms(tv);
196 }
197
198 int
server_run()199 server_run()
200 {
201 struct timeval* timeout;
202 struct timeval tv, current;
203 timer_callback* timcb;
204 socket_callback* sockcb;
205 fd_set rfds, wfds;
206 int r;
207
208 /* No watches have been set */
209 ASSERT(ctx.max_fd > -1);
210
211 ctx.stopped = 0;
212
213 while(!ctx.stopped)
214 {
215 /* Watch for the various fds */
216 memcpy(&rfds, &ctx.read_fds, sizeof(rfds));
217 memcpy(&wfds, &ctx.write_fds, sizeof(wfds));
218
219 /* Prepare for timers */
220 timeout = NULL;
221 if(gettimeofday(¤t, NULL) == -1)
222 return -1;
223
224 /* Cycle through timers */
225 for(timcb = ctx.timers; timcb; )
226 {
227 ASSERT(timcb->callback);
228
229 /* Call any timers that have already passed */
230 if(timercmp(¤t, &timcb->at, >=))
231 {
232 /* Convert to milliseconds, and make the call */
233 r = (timcb->callback)(timeval_to_ms(current), timcb->arg);
234
235 /* Reset timer if so desired */
236 if (r == 1 && timerisset(&timcb->interval))
237 {
238 timeradd(&timcb->at, &timcb->interval, &timcb->at);
239
240 /* If the new timeout has already passed, reset it to current time */
241 if(timercmp(&(timcb->at), ¤t, <=))
242 memcpy(&(timcb->at), ¤t, sizeof(timcb->at));
243 }
244 else
245 {
246 timcb = remove_timer(timcb);
247 continue;
248 }
249 }
250
251 /* Get soonest timer */
252 if (!timeout || timercmp(&timcb->at, timeout, <))
253 timeout = &timcb->at;
254
255 timcb = timcb->next;
256 }
257
258 /* Convert to an offset */
259 if(timeout)
260 {
261 memcpy(&tv, timeout, sizeof(tv));
262 timeout = &tv;
263 timersub(timeout, ¤t, timeout);
264 }
265
266 r = select(ctx.max_fd, &rfds, &wfds, NULL, timeout);
267 if (r < 0)
268 {
269 /* Interrupted so try again, and possibly exit */
270 if (errno == EINTR)
271 continue;
272
273 /* Programmer errors */
274 ASSERT (errno != EBADF);
275 ASSERT (errno != EINVAL);
276 return r;
277 }
278
279 /* Timeout, just jump to timeout processing */
280 if(r == 0)
281 continue;
282
283 for(sockcb = ctx.callbacks; sockcb; sockcb = sockcb->next)
284 {
285 ASSERT(sockcb->fd != -1);
286
287 /* Call any that are set */
288 if (FD_ISSET(sockcb->fd, &rfds))
289 (sockcb->callback)(sockcb->fd, SERVER_READ, sockcb->arg);
290 if (FD_ISSET(sockcb->fd, &wfds))
291 (sockcb->callback)(sockcb->fd, SERVER_WRITE, sockcb->arg);
292 }
293 }
294
295 return 0;
296 }
297
298 void
server_stop()299 server_stop()
300 {
301 ctx.stopped = 1;
302 }
303
304 int
server_stopped()305 server_stopped()
306 {
307 return ctx.stopped;
308 }
309
310 int
server_watch(int fd,int type,server_socket_callback callback,void * arg)311 server_watch(int fd, int type, server_socket_callback callback, void* arg)
312 {
313 socket_callback* cb;
314 ASSERT(type != 0);
315 ASSERT(fd != -1);
316 ASSERT(callback != NULL);
317
318 cb = (socket_callback*)calloc(sizeof(*cb), 1);
319 if(!cb)
320 {
321 errno = ENOMEM;
322 return -1;
323 }
324
325 cb->fd = fd;
326 cb->callback = callback;
327 cb->arg = arg;
328
329 cb->next = ctx.callbacks;
330 ctx.callbacks = cb;
331
332 if (type & SERVER_READ)
333 FD_SET(fd, &ctx.read_fds);
334 if (type & SERVER_WRITE)
335 FD_SET(fd, &ctx.write_fds);
336
337 if(fd >= ctx.max_fd)
338 ctx.max_fd = fd + 1;
339
340 return 0;
341 }
342
343 void
server_unwatch(int fd)344 server_unwatch(int fd)
345 {
346 socket_callback* cb;
347 socket_callback* next;
348
349 ASSERT(fd != -1);
350
351 FD_CLR(fd, &ctx.read_fds);
352 FD_CLR(fd, &ctx.write_fds);
353
354 if(!ctx.callbacks)
355 return;
356
357 /* First in list */;
358 if(ctx.callbacks->fd == fd)
359 {
360 cb = ctx.callbacks;
361 ctx.callbacks = ctx.callbacks->next;
362 free(cb);
363 }
364
365 if(!ctx.callbacks)
366 return;
367
368 /* One ahead processing of rest */
369 cb = ctx.callbacks;
370 while(cb->next)
371 {
372 if(cb->next->fd == fd)
373 {
374 next = cb->next;
375 cb->next = cb->next->next;
376 free(next);
377 }
378 else
379 {
380 cb = cb->next;
381 }
382 }
383 }
384
385 int
server_timer(int period_ms,server_timer_callback callback,void * arg)386 server_timer(int period_ms, server_timer_callback callback, void* arg)
387 {
388 struct timeval interval;
389 struct timeval at;
390 struct timeval now;
391 if (gettimeofday(&now, NULL) == -1) {
392 err(1, "gettimeofday failed");
393 }
394
395 interval.tv_sec = period_ms / 1000;
396 interval.tv_usec = (period_ms % 1000) * 1000; /* into micro seconds */
397
398 at = now;
399 timeradd(&at, &interval, &at);
400
401 return add_timer(at, period_ms, callback, arg);
402 }
403
404 int
server_timer_at(struct timeval at,int period_ms,server_timer_callback callback,void * arg)405 server_timer_at(struct timeval at, int period_ms, server_timer_callback callback, void* arg)
406 {
407 return add_timer(at, period_ms, callback, arg);
408 }
409