]> git.meshlink.io Git - catta/blob - avahi-core/timeeventq.c
* fix a bad memory access bug in avahi_strndup()
[catta] / avahi-core / timeeventq.c
1 /* $Id$ */
2
3 /***
4   This file is part of avahi.
5  
6   avahi is free software; you can redistribute it and/or modify it
7   under the terms of the GNU Lesser General Public License as
8   published by the Free Software Foundation; either version 2.1 of the
9   License, or (at your option) any later version.
10  
11   avahi is distributed in the hope that it will be useful, but WITHOUT
12   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13   or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
14   Public License for more details.
15  
16   You should have received a copy of the GNU Lesser General Public
17   License along with avahi; if not, write to the Free Software
18   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19   USA.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <assert.h>
27 #include <stdlib.h>
28
29 #include <avahi-common/timeval.h>
30 #include <avahi-common/malloc.h>
31
32 #include "timeeventq.h"
33 #include "log.h"
34
35 struct AvahiTimeEvent {
36     AvahiTimeEventQueue *queue;
37     AvahiPrioQueueNode *node;
38     struct timeval expiry;
39     struct timeval last_run;
40     AvahiTimeEventCallback callback;
41     void* userdata;
42 };
43
44 struct AvahiTimeEventQueue {
45     const AvahiPoll *poll_api;
46     AvahiPrioQueue *prioq;
47     AvahiTimeout *timeout;
48 };
49
50 static int compare(const void* _a, const void* _b) {
51     const AvahiTimeEvent *a = _a,  *b = _b;
52     int ret;
53
54     if ((ret = avahi_timeval_compare(&a->expiry, &b->expiry)) != 0)
55         return ret;
56
57     /* If both exevents are scheduled for the same time, put the entry
58      * that has been run earlier the last time first. */
59     return avahi_timeval_compare(&a->last_run, &b->last_run);
60 }
61
62 static void update_timeout(AvahiTimeEventQueue *q) {
63     AvahiTimeEvent *e;
64     assert(q);
65
66     if ((e = avahi_time_event_queue_root(q)))
67         q->poll_api->timeout_update(q->timeout, &e->expiry);
68     else
69         q->poll_api->timeout_update(q->timeout, NULL);
70 }
71
72 static void expiration_event(AvahiTimeout *timeout, void *userdata) {
73     AvahiTimeEventQueue *q = userdata;
74     AvahiTimeEvent *e;
75
76     if ((e = avahi_time_event_queue_root(q))) {
77         struct timeval now;
78
79         gettimeofday(&now, NULL);
80     
81         /* Check if expired */
82         if (avahi_timeval_compare(&now, &e->expiry) >= 0) {
83
84             /* Make sure to move the entry away from the front */
85             e->last_run = now;
86             avahi_prio_queue_shuffle(q->prioq, e->node);
87
88             /* Run it */
89             assert(e->callback);
90             e->callback(e, e->userdata);
91
92             update_timeout(q);
93             return;
94         } 
95     }
96
97     avahi_log_debug(__FILE__": Strange, expiration_event() called, but nothing really happened.");
98     update_timeout(q);
99 }
100
101 static void fix_expiry_time(AvahiTimeEvent *e) {
102     struct timeval now;
103     assert(e);
104
105     return; /*** DO WE REALLY NEED THIS? ***/
106
107     gettimeofday(&now, NULL);
108
109     if (avahi_timeval_compare(&now, &e->expiry) > 0)
110         e->expiry = now;
111 }
112
113 AvahiTimeEventQueue* avahi_time_event_queue_new(const AvahiPoll *poll_api) {
114     AvahiTimeEventQueue *q;
115
116     if (!(q = avahi_new(AvahiTimeEventQueue, 1))) {
117         avahi_log_error(__FILE__": Out of memory");
118         goto oom;
119     }
120
121     q->poll_api = poll_api;
122
123     if (!(q->prioq = avahi_prio_queue_new(compare)))
124         goto oom;
125
126     if (!(q->timeout = poll_api->timeout_new(poll_api, NULL, expiration_event, q))) 
127         goto oom;
128     
129     return q;
130
131 oom:
132
133     if (q) {
134         avahi_free(q);
135
136         if (q->prioq)
137             avahi_prio_queue_free(q->prioq);
138     }
139     
140     return NULL;
141 }
142
143 void avahi_time_event_queue_free(AvahiTimeEventQueue *q) {
144     AvahiTimeEvent *e;
145     
146     assert(q);
147
148     while ((e = avahi_time_event_queue_root(q)))
149         avahi_time_event_free(e);
150     avahi_prio_queue_free(q->prioq);
151
152     q->poll_api->timeout_free(q->timeout);
153     
154     avahi_free(q);
155 }
156
157 AvahiTimeEvent* avahi_time_event_new(
158     AvahiTimeEventQueue *q,
159     const struct timeval *timeval,
160     AvahiTimeEventCallback callback,
161     void* userdata) {
162     
163     AvahiTimeEvent *e;
164     
165     assert(q);
166     assert(callback);
167     assert(userdata);
168
169     if (!(e = avahi_new(AvahiTimeEvent, 1))) {
170         avahi_log_error(__FILE__": Out of memory");
171         return NULL; /* OOM */
172     }
173     
174     e->queue = q;
175     e->callback = callback;
176     e->userdata = userdata;
177
178     if (timeval)
179         e->expiry = *timeval;
180     else {
181         e->expiry.tv_sec = 0;
182         e->expiry.tv_usec = 0;
183     }
184     
185     fix_expiry_time(e);
186     
187     e->last_run.tv_sec = 0;
188     e->last_run.tv_usec = 0;
189
190     if (!(e->node = avahi_prio_queue_put(q->prioq, e))) {
191         avahi_free(e);
192         return NULL;
193     }
194
195     update_timeout(q);
196     return e;
197 }
198
199 void avahi_time_event_free(AvahiTimeEvent *e) {
200     AvahiTimeEventQueue *q;
201     assert(e);
202
203     q = e->queue;
204
205     avahi_prio_queue_remove(q->prioq, e->node);
206     avahi_free(e);
207
208     update_timeout(q);
209 }
210
211 void avahi_time_event_update(AvahiTimeEvent *e, const struct timeval *timeval) {
212     assert(e);
213     assert(timeval);
214
215     e->expiry = *timeval;
216     fix_expiry_time(e);
217     avahi_prio_queue_shuffle(e->queue->prioq, e->node);
218     
219     update_timeout(e->queue);
220 }
221
222 AvahiTimeEvent* avahi_time_event_queue_root(AvahiTimeEventQueue *q) {
223     assert(q);
224
225     return q->prioq->root ? q->prioq->root->data : NULL;
226 }
227
228 AvahiTimeEvent* avahi_time_event_next(AvahiTimeEvent *e) {
229     assert(e);
230
231     return e->node->next->data;
232 }
233
234