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(&current, 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(&current, &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), &current, <=))
242                         memcpy(&(timcb->at), &current, 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, &current, 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