summaryrefslogtreecommitdiff
path: root/src/pluto/timer.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/pluto/timer.c')
-rw-r--r--src/pluto/timer.c875
1 files changed, 452 insertions, 423 deletions
diff --git a/src/pluto/timer.c b/src/pluto/timer.c
index aea293098..ecbee740f 100644
--- a/src/pluto/timer.c
+++ b/src/pluto/timer.c
@@ -11,8 +11,6 @@
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
- *
- * RCSID $Id: timer.c 3252 2007-10-06 21:24:50Z andreas $
*/
#include <stdio.h>
@@ -26,36 +24,39 @@
#include <freeswan.h>
+#include <library.h>
+#include <crypto/rngs/rng.h>
+
#include "constants.h"
#include "defs.h"
#include "connections.h"
#include "state.h"
#include "demux.h"
-#include "ipsec_doi.h" /* needs demux.h and state.h */
+#include "ipsec_doi.h" /* needs demux.h and state.h */
#include "kernel.h"
#include "server.h"
#include "log.h"
-#include "rnd.h"
#include "timer.h"
#include "whack.h"
#include "nat_traversal.h"
-/* monotonic version of time(3) */
-time_t
-now(void)
+/**
+ * monotonic version of time(3)
+ */
+time_t now(void)
{
- static time_t delta = 0
- , last_time = 0;
- time_t n = time((time_t)NULL);
-
- passert(n != (time_t)-1);
- if (last_time > n)
- {
- plog("time moved backwards %ld seconds", (long)(last_time - n));
- delta += last_time - n;
- }
- last_time = n;
- return n + delta;
+ static time_t delta = 0
+ , last_time = 0;
+ time_t n = time((time_t)NULL);
+
+ passert(n != (time_t)-1);
+ if (last_time > n)
+ {
+ plog("time moved backwards %ld seconds", (long)(last_time - n));
+ delta += last_time - n;
+ }
+ last_time = n;
+ return n + delta;
}
/* This file has the event handling routines. Events are
@@ -66,467 +67,495 @@ now(void)
static struct event *evlist = (struct event *) NULL;
-/*
+/**
* This routine places an event in the event list.
*/
-void
-event_schedule(enum event_type type, time_t tm, struct state *st)
+void event_schedule(enum event_type type, time_t tm, struct state *st)
{
- struct event *ev = alloc_thing(struct event, "struct event in event_schedule()");
-
- ev->ev_type = type;
- ev->ev_time = tm + now();
- ev->ev_state = st;
-
- /* If the event is associated with a state, put a backpointer to the
- * event in the state object, so we can find and delete the event
- * if we need to (for example, if we receive a reply).
- */
- if (st != NULL)
- {
- if (type == EVENT_DPD || type == EVENT_DPD_TIMEOUT)
+ struct event *ev = malloc_thing(struct event);
+
+ ev->ev_type = type;
+ ev->ev_time = tm + now();
+ ev->ev_state = st;
+
+ /* If the event is associated with a state, put a backpointer to the
+ * event in the state object, so we can find and delete the event
+ * if we need to (for example, if we receive a reply).
+ */
+ if (st != NULL)
+ {
+ if (type == EVENT_DPD || type == EVENT_DPD_TIMEOUT)
+ {
+ passert(st->st_dpd_event == NULL);
+ st->st_dpd_event = ev;
+ }
+ else
+ {
+ passert(st->st_event == NULL);
+ st->st_event = ev;
+ }
+ }
+
+ DBG(DBG_CONTROL,
+ if (st == NULL)
+ DBG_log("inserting event %N, timeout in %lu seconds"
+ , timer_event_names, type, (unsigned long)tm);
+ else
+ DBG_log("inserting event %N, timeout in %lu seconds for #%lu"
+ , timer_event_names, type, (unsigned long)tm
+ , ev->ev_state->st_serialno));
+
+ if (evlist == (struct event *) NULL
+ || evlist->ev_time >= ev->ev_time)
{
- passert(st->st_dpd_event == NULL);
- st->st_dpd_event = ev;
+ ev->ev_next = evlist;
+ evlist = ev;
}
else
{
- passert(st->st_event == NULL);
- st->st_event = ev;
- }
- }
+ struct event *evt;
- DBG(DBG_CONTROL,
- if (st == NULL)
- DBG_log("inserting event %s, timeout in %lu seconds"
- , enum_show(&timer_event_names, type), (unsigned long)tm);
- else
- DBG_log("inserting event %s, timeout in %lu seconds for #%lu"
- , enum_show(&timer_event_names, type), (unsigned long)tm
- , ev->ev_state->st_serialno));
-
- if (evlist == (struct event *) NULL
- || evlist->ev_time >= ev->ev_time)
- {
- ev->ev_next = evlist;
- evlist = ev;
- }
- else
- {
- struct event *evt;
-
- for (evt = evlist; evt->ev_next != NULL; evt = evt->ev_next)
- if (evt->ev_next->ev_time >= ev->ev_time)
- break;
-
-#ifdef NEVER /* this seems to be overkill */
- DBG(DBG_CONTROL,
- if (evt->ev_state == NULL)
- DBG_log("event added after event %s"
- , enum_show(&timer_event_names, evt->ev_type));
- else
- DBG_log("event added after event %s for #%lu"
- , enum_show(&timer_event_names, evt->ev_type)
- , evt->ev_state->st_serialno));
+ for (evt = evlist; evt->ev_next != NULL; evt = evt->ev_next)
+ if (evt->ev_next->ev_time >= ev->ev_time)
+ break;
+
+#ifdef NEVER /* this seems to be overkill */
+ DBG(DBG_CONTROL,
+ if (evt->ev_state == NULL)
+ DBG_log("event added after event %N"
+ , timer_event_names, evt->ev_type);
+ else
+ DBG_log("event added after event %N for #%lu"
+ , timer_event_names, evt->ev_type,
+ , evt->ev_state->st_serialno));
#endif /* NEVER */
- ev->ev_next = evt->ev_next;
- evt->ev_next = ev;
- }
+ ev->ev_next = evt->ev_next;
+ evt->ev_next = ev;
+ }
+}
+
+/**
+ * Generate the secret value for responder cookies, and
+ * schedule an event for refresh.
+ */
+void init_secret(void)
+{
+ rng_t *rng;
+
+ rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG);
+ rng->get_bytes(rng, sizeof(secret_of_the_day), secret_of_the_day);
+ rng->destroy(rng);
+ event_schedule(EVENT_REINIT_SECRET, EVENT_REINIT_SECRET_DELAY, NULL);
}
-/*
+/**
* Handle the first event on the list.
*/
-void
-handle_timer_event(void)
+void handle_timer_event(void)
{
- time_t tm;
- struct event *ev = evlist;
- int type;
- struct state *st;
- struct connection *c = NULL;
- ip_address peer;
-
- if (ev == (struct event *) NULL) /* Just paranoid */
- {
- DBG(DBG_CONTROL, DBG_log("empty event list, yet we're called"));
- return;
- }
-
- type = ev->ev_type;
- st = ev->ev_state;
-
- tm = now();
-
- if (tm < ev->ev_time)
- {
- DBG(DBG_CONTROL, DBG_log("called while no event expired (%lu/%lu, %s)"
- , (unsigned long)tm, (unsigned long)ev->ev_time
- , enum_show(&timer_event_names, type)));
-
- /* This will happen if the most close-to-expire event was
- * a retransmission or cleanup, and we received a packet
- * at the same time as the event expired. Due to the processing
- * order in call_server(), the packet processing will happen first,
- * and the event will be removed.
- */
- return;
- }
-
- evlist = evlist->ev_next; /* Ok, we'll handle this event */
-
- DBG(DBG_CONTROL,
- if (evlist != (struct event *) NULL)
- DBG_log("event after this is %s in %ld seconds"
- , enum_show(&timer_event_names, evlist->ev_type)
- , (long) (evlist->ev_time - tm)));
-
- /* for state-associated events, pick up the state pointer
- * and remove the backpointer from the state object.
- * We'll eventually either schedule a new event, or delete the state.
- */
- passert(GLOBALS_ARE_RESET());
- if (st != NULL)
- {
- c = st->st_connection;
- if (type == EVENT_DPD || type == EVENT_DPD_TIMEOUT)
+ time_t tm;
+ struct event *ev = evlist;
+ int type;
+ struct state *st;
+ struct connection *c = NULL;
+ ip_address peer;
+
+ if (ev == (struct event *) NULL) /* Just paranoid */
{
- passert(st->st_dpd_event == ev);
- st->st_dpd_event = NULL;
+ DBG(DBG_CONTROL, DBG_log("empty event list, yet we're called"));
+ return;
}
- else
+
+ type = ev->ev_type;
+ st = ev->ev_state;
+
+ tm = now();
+
+ if (tm < ev->ev_time)
{
- passert(st->st_event == ev);
- st->st_event = NULL;
+ DBG(DBG_CONTROL, DBG_log("called while no event expired (%lu/%lu, %N)"
+ , (unsigned long)tm, (unsigned long)ev->ev_time
+ , timer_event_names, type));
+
+ /* This will happen if the most close-to-expire event was
+ * a retransmission or cleanup, and we received a packet
+ * at the same time as the event expired. Due to the processing
+ * order in call_server(), the packet processing will happen first,
+ * and the event will be removed.
+ */
+ return;
}
- peer = c->spd.that.host_addr;
- set_cur_state(st);
- }
-
- switch (type)
- {
- case EVENT_REINIT_SECRET:
- passert(st == NULL);
- DBG(DBG_CONTROL, DBG_log("event EVENT_REINIT_SECRET handled"));
- init_secret();
- break;
-#ifdef KLIPS
- case EVENT_SHUNT_SCAN:
- passert(st == NULL);
- scan_proc_shunts();
- break;
-#endif
+ evlist = evlist->ev_next; /* Ok, we'll handle this event */
- case EVENT_LOG_DAILY:
- daily_log_event();
- break;
-
- case EVENT_RETRANSMIT:
- /* Time to retransmit, or give up.
- *
- * Generally, we'll only try to send the message
- * MAXIMUM_RETRANSMISSIONS times. Each time we double
- * our patience.
- *
- * As a special case, if this is the first initiating message
- * of a Main Mode exchange, and we have been directed to try
- * forever, we'll extend the number of retransmissions to
- * MAXIMUM_RETRANSMISSIONS_INITIAL times, with all these
- * extended attempts having the same patience. The intention
- * is to reduce the bother when nobody is home.
- */
- {
- time_t delay = 0;
-
- DBG(DBG_CONTROL, DBG_log(
- "handling event EVENT_RETRANSMIT for %s \"%s\" #%lu"
- , ip_str(&peer), c->name, st->st_serialno));
-
- if (st->st_retransmit < MAXIMUM_RETRANSMISSIONS)
- delay = EVENT_RETRANSMIT_DELAY_0 << (st->st_retransmit + 1);
- else if (st->st_state == STATE_MAIN_I1
- && c->sa_keying_tries == 0
- && st->st_retransmit < MAXIMUM_RETRANSMISSIONS_INITIAL)
- delay = EVENT_RETRANSMIT_DELAY_0 << MAXIMUM_RETRANSMISSIONS;
-
- if (delay != 0)
+ DBG(DBG_CONTROL,
+ if (evlist != (struct event *) NULL)
+ DBG_log("event after this is %N in %ld seconds"
+ , timer_event_names, evlist->ev_type
+ , (long) (evlist->ev_time - tm)));
+
+ /* for state-associated events, pick up the state pointer
+ * and remove the backpointer from the state object.
+ * We'll eventually either schedule a new event, or delete the state.
+ */
+ passert(GLOBALS_ARE_RESET());
+ if (st != NULL)
+ {
+ c = st->st_connection;
+ if (type == EVENT_DPD || type == EVENT_DPD_TIMEOUT)
{
- st->st_retransmit++;
- whack_log(RC_RETRANSMISSION
- , "%s: retransmission; will wait %lus for response"
- , enum_name(&state_names, st->st_state)
- , (unsigned long)delay);
- send_packet(st, "EVENT_RETRANSMIT");
- event_schedule(EVENT_RETRANSMIT, delay, st);
+ passert(st->st_dpd_event == ev);
+ st->st_dpd_event = NULL;
}
- else
+ else
{
- /* check if we've tried rekeying enough times.
- * st->st_try == 0 means that this should be the only try.
- * c->sa_keying_tries == 0 means that there is no limit.
- */
- unsigned long try = st->st_try;
- unsigned long try_limit = c->sa_keying_tries;
- const char *details = "";
-
- switch (st->st_state)
- {
- case STATE_MAIN_I3:
- details = ". Possible authentication failure:"
- " no acceptable response to our"
- " first encrypted message";
- break;
- case STATE_MAIN_I1:
- details = ". No response (or no acceptable response) to our"
- " first IKE message";
- break;
- case STATE_QUICK_I1:
- if (c->newest_ipsec_sa == SOS_NOBODY)
- details = ". No acceptable response to our"
- " first Quick Mode message:"
- " perhaps peer likes no proposal";
+ passert(st->st_event == ev);
+ st->st_event = NULL;
+ }
+ peer = c->spd.that.host_addr;
+ set_cur_state(st);
+ }
+
+ switch (type)
+ {
+ case EVENT_REINIT_SECRET:
+ passert(st == NULL);
+ DBG(DBG_CONTROL, DBG_log("event EVENT_REINIT_SECRET handled"));
+ init_secret();
break;
- default:
+
+#ifdef KLIPS
+ case EVENT_SHUNT_SCAN:
+ passert(st == NULL);
+ scan_proc_shunts();
break;
- }
- loglog(RC_NORETRANSMISSION
- , "max number of retransmissions (%d) reached %s%s"
- , st->st_retransmit
- , enum_show(&state_names, st->st_state), details);
- if (try != 0 && try != try_limit)
- {
- /* A lot like EVENT_SA_REPLACE, but over again.
- * Since we know that st cannot be in use,
- * we can delete it right away.
- */
- char story[80]; /* arbitrary limit */
+#endif
- try++;
- snprintf(story, sizeof(story), try_limit == 0
- ? "starting keying attempt %ld of an unlimited number"
- : "starting keying attempt %ld of at most %ld"
- , try, try_limit);
+ case EVENT_LOG_DAILY:
+ daily_log_event();
+ break;
- if (st->st_whack_sock != NULL_FD)
+ case EVENT_RETRANSMIT:
+ /* Time to retransmit, or give up.
+ *
+ * Generally, we'll only try to send the message
+ * MAXIMUM_RETRANSMISSIONS times. Each time we double
+ * our patience.
+ *
+ * As a special case, if this is the first initiating message
+ * of a Main Mode exchange, and we have been directed to try
+ * forever, we'll extend the number of retransmissions to
+ * MAXIMUM_RETRANSMISSIONS_INITIAL times, with all these
+ * extended attempts having the same patience. The intention
+ * is to reduce the bother when nobody is home.
+ */
{
- /* Release whack because the observer will get bored. */
- loglog(RC_COMMENT, "%s, but releasing whack"
- , story);
- release_pending_whacks(st, story);
+ time_t delay = 0;
+
+ DBG(DBG_CONTROL, DBG_log(
+ "handling event EVENT_RETRANSMIT for %s \"%s\" #%lu"
+ , ip_str(&peer), c->name, st->st_serialno));
+
+ if (st->st_retransmit < MAXIMUM_RETRANSMISSIONS)
+ delay = EVENT_RETRANSMIT_DELAY_0 << (st->st_retransmit + 1);
+ else if (st->st_state == STATE_MAIN_I1
+ && c->sa_keying_tries == 0
+ && st->st_retransmit < MAXIMUM_RETRANSMISSIONS_INITIAL)
+ delay = EVENT_RETRANSMIT_DELAY_0 << MAXIMUM_RETRANSMISSIONS;
+
+ if (delay != 0)
+ {
+ st->st_retransmit++;
+ whack_log(RC_RETRANSMISSION
+ , "%s: retransmission; will wait %lus for response"
+ , enum_name(&state_names, st->st_state)
+ , (unsigned long)delay);
+ send_packet(st, "EVENT_RETRANSMIT");
+ event_schedule(EVENT_RETRANSMIT, delay, st);
+ }
+ else
+ {
+ /* check if we've tried rekeying enough times.
+ * st->st_try == 0 means that this should be the only try.
+ * c->sa_keying_tries == 0 means that there is no limit.
+ */
+ unsigned long try = st->st_try;
+ unsigned long try_limit = c->sa_keying_tries;
+ const char *details = "";
+
+ switch (st->st_state)
+ {
+ case STATE_MAIN_I3:
+ details = ". Possible authentication failure:"
+ " no acceptable response to our"
+ " first encrypted message";
+ break;
+ case STATE_MAIN_I1:
+ details = ". No response (or no acceptable response) to our"
+ " first IKE message";
+ break;
+ case STATE_QUICK_I1:
+ if (c->newest_ipsec_sa == SOS_NOBODY)
+ details = ". No acceptable response to our"
+ " first Quick Mode message:"
+ " perhaps peer likes no proposal";
+ break;
+ default:
+ break;
+ }
+ loglog(RC_NORETRANSMISSION
+ , "max number of retransmissions (%d) reached %s%s"
+ , st->st_retransmit
+ , enum_show(&state_names, st->st_state), details);
+ if (try != 0 && try != try_limit)
+ {
+ /* A lot like EVENT_SA_REPLACE, but over again.
+ * Since we know that st cannot be in use,
+ * we can delete it right away.
+ */
+ char story[80]; /* arbitrary limit */
+
+ try++;
+ snprintf(story, sizeof(story), try_limit == 0
+ ? "starting keying attempt %ld of an unlimited number"
+ : "starting keying attempt %ld of at most %ld"
+ , try, try_limit);
+
+ if (st->st_whack_sock != NULL_FD)
+ {
+ /* Release whack because the observer will get bored. */
+ loglog(RC_COMMENT, "%s, but releasing whack"
+ , story);
+ release_pending_whacks(st, story);
+ }
+ else
+ {
+ /* no whack: just log to syslog */
+ plog("%s", story);
+ }
+ ipsecdoi_replace(st, try);
+ }
+ delete_state(st);
+ }
}
- else
+ break;
+
+ case EVENT_SA_REPLACE:
+ case EVENT_SA_REPLACE_IF_USED:
{
- /* no whack: just log to syslog */
- plog("%s", story);
+ so_serial_t newest = IS_PHASE1(st->st_state)
+ ? c->newest_isakmp_sa : c->newest_ipsec_sa;
+
+ if (newest != st->st_serialno
+ && newest != SOS_NOBODY)
+ {
+ /* not very interesting: no need to replace */
+ DBG(DBG_LIFECYCLE
+ , plog("not replacing stale %s SA: #%lu will do"
+ , IS_PHASE1(st->st_state)? "ISAKMP" : "IPsec"
+ , newest));
+ }
+ else if (type == EVENT_SA_REPLACE_IF_USED
+ && st->st_outbound_time <= tm - c->sa_rekey_margin)
+ {
+ /* we observed no recent use: no need to replace
+ *
+ * The sampling effects mean that st_outbound_time
+ * could be up to SHUNT_SCAN_INTERVAL more recent
+ * than actual traffic because the sampler looks at change
+ * over that interval.
+ * st_outbound_time could also not yet reflect traffic
+ * in the last SHUNT_SCAN_INTERVAL.
+ * We expect that SHUNT_SCAN_INTERVAL is smaller than
+ * c->sa_rekey_margin so that the effects of this will
+ * be unimportant.
+ * This is just an optimization: correctness is not
+ * at stake.
+ *
+ * Note: we are abusing the DBG mechanism to control
+ * normal log output.
+ */
+ DBG(DBG_LIFECYCLE
+ , plog("not replacing stale %s SA: inactive for %lus"
+ , IS_PHASE1(st->st_state)? "ISAKMP" : "IPsec"
+ , (unsigned long)(tm - st->st_outbound_time)));
+ }
+ else
+ {
+ DBG(DBG_LIFECYCLE
+ , plog("replacing stale %s SA"
+ , IS_PHASE1(st->st_state)? "ISAKMP" : "IPsec"));
+ ipsecdoi_replace(st, 1);
+ }
+ delete_dpd_event(st);
+ event_schedule(EVENT_SA_EXPIRE, st->st_margin, st);
}
- ipsecdoi_replace(st, try);
- }
- delete_state(st);
- }
- }
- break;
-
- case EVENT_SA_REPLACE:
- case EVENT_SA_REPLACE_IF_USED:
- {
- so_serial_t newest = IS_PHASE1(st->st_state)
- ? c->newest_isakmp_sa : c->newest_ipsec_sa;
-
- if (newest != st->st_serialno
- && newest != SOS_NOBODY)
- {
- /* not very interesting: no need to replace */
- DBG(DBG_LIFECYCLE
- , plog("not replacing stale %s SA: #%lu will do"
- , IS_PHASE1(st->st_state)? "ISAKMP" : "IPsec"
- , newest));
- }
- else if (type == EVENT_SA_REPLACE_IF_USED
- && st->st_outbound_time <= tm - c->sa_rekey_margin)
- {
- /* we observed no recent use: no need to replace
- *
- * The sampling effects mean that st_outbound_time
- * could be up to SHUNT_SCAN_INTERVAL more recent
- * than actual traffic because the sampler looks at change
- * over that interval.
- * st_outbound_time could also not yet reflect traffic
- * in the last SHUNT_SCAN_INTERVAL.
- * We expect that SHUNT_SCAN_INTERVAL is smaller than
- * c->sa_rekey_margin so that the effects of this will
- * be unimportant.
- * This is just an optimization: correctness is not
- * at stake.
- *
- * Note: we are abusing the DBG mechanism to control
- * normal log output.
- */
- DBG(DBG_LIFECYCLE
- , plog("not replacing stale %s SA: inactive for %lus"
- , IS_PHASE1(st->st_state)? "ISAKMP" : "IPsec"
- , (unsigned long)(tm - st->st_outbound_time)));
- }
- else
- {
- DBG(DBG_LIFECYCLE
- , plog("replacing stale %s SA"
- , IS_PHASE1(st->st_state)? "ISAKMP" : "IPsec"));
- ipsecdoi_replace(st, 1);
- }
- delete_dpd_event(st);
- event_schedule(EVENT_SA_EXPIRE, st->st_margin, st);
- }
- break;
+ break;
- case EVENT_SA_EXPIRE:
- {
- const char *satype;
- so_serial_t latest;
+ case EVENT_SA_EXPIRE:
+ {
+ const char *satype;
+ so_serial_t latest;
+
+ if (IS_PHASE1(st->st_state))
+ {
+ satype = "ISAKMP";
+ latest = c->newest_isakmp_sa;
+ }
+ else
+ {
+ satype = "IPsec";
+ latest = c->newest_ipsec_sa;
+ }
+
+ if (st->st_serialno != latest)
+ {
+ /* not very interesting: already superseded */
+ DBG(DBG_LIFECYCLE
+ , plog("%s SA expired (superseded by #%lu)"
+ , satype, latest));
+ }
+ else
+ {
+ plog("%s SA expired (%s)", satype
+ , (c->policy & POLICY_DONT_REKEY)
+ ? "--dontrekey"
+ : "LATEST!"
+ );
+ }
+ }
+ /* FALLTHROUGH */
+ case EVENT_SO_DISCARD:
+ /* Delete this state object. It must be in the hash table. */
+ delete_state(st);
+ break;
- if (IS_PHASE1(st->st_state))
- {
- satype = "ISAKMP";
- latest = c->newest_isakmp_sa;
- }
- else
- {
- satype = "IPsec";
- latest = c->newest_ipsec_sa;
- }
+ case EVENT_DPD:
+ dpd_outI(st);
+ break;
+ case EVENT_DPD_TIMEOUT:
+ dpd_timeout(st);
+ break;
+ case EVENT_NAT_T_KEEPALIVE:
+ nat_traversal_ka_event();
+ break;
+ default:
+ loglog(RC_LOG_SERIOUS, "INTERNAL ERROR: ignoring unknown expiring event %N"
+ , timer_event_names, type);
+ }
- if (st->st_serialno != latest)
- {
- /* not very interesting: already superseded */
- DBG(DBG_LIFECYCLE
- , plog("%s SA expired (superseded by #%lu)"
- , satype, latest));
- }
- else
- {
- plog("%s SA expired (%s)", satype
- , (c->policy & POLICY_DONT_REKEY)
- ? "--dontrekey"
- : "LATEST!"
- );
- }
- }
- /* FALLTHROUGH */
- case EVENT_SO_DISCARD:
- /* Delete this state object. It must be in the hash table. */
- delete_state(st);
- break;
-
- case EVENT_DPD:
- dpd_outI(st);
- break;
- case EVENT_DPD_TIMEOUT:
- dpd_timeout(st);
- break;
- case EVENT_NAT_T_KEEPALIVE:
- nat_traversal_ka_event();
- break;
- default:
- loglog(RC_LOG_SERIOUS, "INTERNAL ERROR: ignoring unknown expiring event %s"
- , enum_show(&timer_event_names, type));
- }
-
- pfree(ev);
- reset_cur_state();
+ free(ev);
+ reset_cur_state();
}
-/*
+/**
* Return the time until the next event in the queue
* expires (never negative), or -1 if no jobs in queue.
*/
-long
-next_event(void)
+long next_event(void)
{
- time_t tm;
+ time_t tm;
+
+ if (evlist == (struct event *) NULL)
+ return -1;
- if (evlist == (struct event *) NULL)
- return -1;
+ tm = now();
- tm = now();
+ DBG(DBG_CONTROL,
+ if (evlist->ev_state == NULL)
+ DBG_log("next event %N in %ld seconds"
+ , timer_event_names, evlist->ev_type
+ , (long)evlist->ev_time - (long)tm);
+ else
+ DBG_log("next event %N in %ld seconds for #%lu"
+ , timer_event_names, evlist->ev_type
+ , (long)evlist->ev_time - (long)tm
+ , evlist->ev_state->st_serialno));
- DBG(DBG_CONTROL,
- if (evlist->ev_state == NULL)
- DBG_log("next event %s in %ld seconds"
- , enum_show(&timer_event_names, evlist->ev_type)
- , (long)evlist->ev_time - (long)tm);
+ if (evlist->ev_time - tm <= 0)
+ return 0;
else
- DBG_log("next event %s in %ld seconds for #%lu"
- , enum_show(&timer_event_names, evlist->ev_type)
- , (long)evlist->ev_time - (long)tm
- , evlist->ev_state->st_serialno));
-
- if (evlist->ev_time - tm <= 0)
- return 0;
- else
- return evlist->ev_time - tm;
+ return evlist->ev_time - tm;
}
-/*
+/**
* Delete an event.
*/
-void
-delete_event(struct state *st)
+void delete_event(struct state *st)
{
- if (st->st_event != (struct event *) NULL)
- {
- struct event **ev;
-
- for (ev = &evlist; ; ev = &(*ev)->ev_next)
+ if (st->st_event != (struct event *) NULL)
{
- if (*ev == NULL)
- {
- DBG(DBG_CONTROL, DBG_log("event %s to be deleted not found",
- enum_show(&timer_event_names, st->st_event->ev_type)));
- break;
- }
- if ((*ev) == st->st_event)
- {
- *ev = (*ev)->ev_next;
-
- if (st->st_event->ev_type == EVENT_RETRANSMIT)
- st->st_retransmit = 0;
- pfree(st->st_event);
- st->st_event = (struct event *) NULL;
-
- break;
- }
+ struct event **ev;
+
+ for (ev = &evlist; ; ev = &(*ev)->ev_next)
+ {
+ if (*ev == NULL)
+ {
+ DBG(DBG_CONTROL, DBG_log("event %N to be deleted not found",
+ timer_event_names, st->st_event->ev_type));
+ break;
+ }
+ if ((*ev) == st->st_event)
+ {
+ *ev = (*ev)->ev_next;
+
+ if (st->st_event->ev_type == EVENT_RETRANSMIT)
+ {
+ st->st_retransmit = 0;
+ }
+ free(st->st_event);
+ st->st_event = (struct event *) NULL;
+
+ break;
+ }
+ }
}
- }
}
-/*
+/**
* Delete a DPD event.
*/
-void
-delete_dpd_event(struct state *st)
+void delete_dpd_event(struct state *st)
{
- if (st->st_dpd_event != (struct event *) NULL)
- {
- struct event **ev;
-
- for (ev = &evlist; ; ev = &(*ev)->ev_next)
- {
- if (*ev == NULL)
- {
- DBG(DBG_CONTROL, DBG_log("event %s to be deleted not found",
- enum_show(&timer_event_names, st->st_dpd_event->ev_type)));
- break;
- }
- if ((*ev) == st->st_dpd_event)
- {
- *ev = (*ev)->ev_next;
- pfree(st->st_dpd_event);
- st->st_dpd_event = (struct event *) NULL;
- break;
- }
- }
- }
+ if (st->st_dpd_event != (struct event *) NULL)
+ {
+ struct event **ev;
+
+ for (ev = &evlist; ; ev = &(*ev)->ev_next)
+ {
+ if (*ev == NULL)
+ {
+ DBG(DBG_CONTROL, DBG_log("event %N to be deleted not found",
+ timer_event_names, st->st_dpd_event->ev_type));
+ break;
+ }
+ if ((*ev) == st->st_dpd_event)
+ {
+ *ev = (*ev)->ev_next;
+ free(st->st_dpd_event);
+ st->st_dpd_event = (struct event *) NULL;
+ break;
+ }
+ }
+ }
}
+/**
+ * Free remaining events
+ */
+void free_events(void)
+{
+ struct event *ev_tmp, *ev;
+
+ ev = evlist;
+ evlist = NULL;
+
+ while (ev)
+ {
+ ev_tmp = ev;
+ ev = ev->ev_next;
+ free(ev_tmp);
+ }
+}