forked from jbagg/QtZeroConf
226 lines
5.1 KiB
C
226 lines
5.1 KiB
C
/***
|
|
This file is part of avahi.
|
|
|
|
avahi is free software; you can redistribute it and/or modify it
|
|
under the terms of the GNU Lesser General Public License as
|
|
published by the Free Software Foundation; either version 2.1 of the
|
|
License, or (at your option) any later version.
|
|
|
|
avahi is distributed in the hope that it will be useful, but WITHOUT
|
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
|
|
Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
License along with avahi; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
|
USA.
|
|
***/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
#include <assert.h>
|
|
#include <stdlib.h>
|
|
|
|
#include <avahi-common/timeval.h>
|
|
#include <avahi-common/malloc.h>
|
|
|
|
#include "timeeventq.h"
|
|
#include "log.h"
|
|
|
|
struct AvahiTimeEvent {
|
|
AvahiTimeEventQueue *queue;
|
|
AvahiPrioQueueNode *node;
|
|
struct timeval expiry;
|
|
struct timeval last_run;
|
|
AvahiTimeEventCallback callback;
|
|
void* userdata;
|
|
};
|
|
|
|
struct AvahiTimeEventQueue {
|
|
const AvahiPoll *poll_api;
|
|
AvahiPrioQueue *prioq;
|
|
AvahiTimeout *timeout;
|
|
};
|
|
|
|
static int compare(const void* _a, const void* _b) {
|
|
const AvahiTimeEvent *a = _a, *b = _b;
|
|
int ret;
|
|
|
|
if ((ret = avahi_timeval_compare(&a->expiry, &b->expiry)) != 0)
|
|
return ret;
|
|
|
|
/* If both exevents are scheduled for the same time, put the entry
|
|
* that has been run earlier the last time first. */
|
|
return avahi_timeval_compare(&a->last_run, &b->last_run);
|
|
}
|
|
|
|
static AvahiTimeEvent* time_event_queue_root(AvahiTimeEventQueue *q) {
|
|
assert(q);
|
|
|
|
return q->prioq->root ? q->prioq->root->data : NULL;
|
|
}
|
|
|
|
static void update_timeout(AvahiTimeEventQueue *q) {
|
|
AvahiTimeEvent *e;
|
|
assert(q);
|
|
|
|
if ((e = time_event_queue_root(q)))
|
|
q->poll_api->timeout_update(q->timeout, &e->expiry);
|
|
else
|
|
q->poll_api->timeout_update(q->timeout, NULL);
|
|
}
|
|
|
|
static void expiration_event(AVAHI_GCC_UNUSED AvahiTimeout *timeout, void *userdata) {
|
|
AvahiTimeEventQueue *q = userdata;
|
|
AvahiTimeEvent *e;
|
|
|
|
if ((e = time_event_queue_root(q))) {
|
|
struct timeval now;
|
|
|
|
gettimeofday(&now, NULL);
|
|
|
|
/* Check if expired */
|
|
if (avahi_timeval_compare(&now, &e->expiry) >= 0) {
|
|
|
|
/* Make sure to move the entry away from the front */
|
|
e->last_run = now;
|
|
avahi_prio_queue_shuffle(q->prioq, e->node);
|
|
|
|
/* Run it */
|
|
assert(e->callback);
|
|
e->callback(e, e->userdata);
|
|
|
|
update_timeout(q);
|
|
return;
|
|
}
|
|
}
|
|
|
|
avahi_log_debug(__FILE__": Strange, expiration_event() called, but nothing really happened.");
|
|
update_timeout(q);
|
|
}
|
|
|
|
static void fix_expiry_time(AvahiTimeEvent *e) {
|
|
struct timeval now;
|
|
assert(e);
|
|
|
|
return; /*** DO WE REALLY NEED THIS? ***/
|
|
|
|
gettimeofday(&now, NULL);
|
|
|
|
if (avahi_timeval_compare(&now, &e->expiry) > 0)
|
|
e->expiry = now;
|
|
}
|
|
|
|
AvahiTimeEventQueue* avahi_time_event_queue_new(const AvahiPoll *poll_api) {
|
|
AvahiTimeEventQueue *q;
|
|
|
|
if (!(q = avahi_new(AvahiTimeEventQueue, 1))) {
|
|
avahi_log_error(__FILE__": Out of memory");
|
|
goto oom;
|
|
}
|
|
|
|
q->poll_api = poll_api;
|
|
|
|
if (!(q->prioq = avahi_prio_queue_new(compare)))
|
|
goto oom;
|
|
|
|
if (!(q->timeout = poll_api->timeout_new(poll_api, NULL, expiration_event, q)))
|
|
goto oom;
|
|
|
|
return q;
|
|
|
|
oom:
|
|
|
|
if (q) {
|
|
avahi_free(q);
|
|
|
|
if (q->prioq)
|
|
avahi_prio_queue_free(q->prioq);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void avahi_time_event_queue_free(AvahiTimeEventQueue *q) {
|
|
AvahiTimeEvent *e;
|
|
|
|
assert(q);
|
|
|
|
while ((e = time_event_queue_root(q)))
|
|
avahi_time_event_free(e);
|
|
avahi_prio_queue_free(q->prioq);
|
|
|
|
q->poll_api->timeout_free(q->timeout);
|
|
|
|
avahi_free(q);
|
|
}
|
|
|
|
AvahiTimeEvent* avahi_time_event_new(
|
|
AvahiTimeEventQueue *q,
|
|
const struct timeval *timeval,
|
|
AvahiTimeEventCallback callback,
|
|
void* userdata) {
|
|
|
|
AvahiTimeEvent *e;
|
|
|
|
assert(q);
|
|
assert(callback);
|
|
assert(userdata);
|
|
|
|
if (!(e = avahi_new(AvahiTimeEvent, 1))) {
|
|
avahi_log_error(__FILE__": Out of memory");
|
|
return NULL; /* OOM */
|
|
}
|
|
|
|
e->queue = q;
|
|
e->callback = callback;
|
|
e->userdata = userdata;
|
|
|
|
if (timeval)
|
|
e->expiry = *timeval;
|
|
else {
|
|
e->expiry.tv_sec = 0;
|
|
e->expiry.tv_usec = 0;
|
|
}
|
|
|
|
fix_expiry_time(e);
|
|
|
|
e->last_run.tv_sec = 0;
|
|
e->last_run.tv_usec = 0;
|
|
|
|
if (!(e->node = avahi_prio_queue_put(q->prioq, e))) {
|
|
avahi_free(e);
|
|
return NULL;
|
|
}
|
|
|
|
update_timeout(q);
|
|
return e;
|
|
}
|
|
|
|
void avahi_time_event_free(AvahiTimeEvent *e) {
|
|
AvahiTimeEventQueue *q;
|
|
assert(e);
|
|
|
|
q = e->queue;
|
|
|
|
avahi_prio_queue_remove(q->prioq, e->node);
|
|
avahi_free(e);
|
|
|
|
update_timeout(q);
|
|
}
|
|
|
|
void avahi_time_event_update(AvahiTimeEvent *e, const struct timeval *timeval) {
|
|
assert(e);
|
|
assert(timeval);
|
|
|
|
e->expiry = *timeval;
|
|
fix_expiry_time(e);
|
|
avahi_prio_queue_shuffle(e->queue->prioq, e->node);
|
|
|
|
update_timeout(e->queue);
|
|
}
|
|
|