From: Martin Willi Date: Wed, 3 Oct 2012 15:42:19 +0000 (+0200) Subject: Add a lookip function to register virtual IP notification listeners X-Git-Tag: 5.0.2dr4~312 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=1edaa79c060dad9064bd09c2e913900cd1f5c3e0;p=thirdparty%2Fstrongswan.git Add a lookip function to register virtual IP notification listeners --- diff --git a/src/libcharon/plugins/lookip/lookip_listener.c b/src/libcharon/plugins/lookip/lookip_listener.c index 77ad78ea75..9be4e09eab 100644 --- a/src/libcharon/plugins/lookip/lookip_listener.c +++ b/src/libcharon/plugins/lookip/lookip_listener.c @@ -17,6 +17,7 @@ #include #include +#include #include typedef struct private_lookip_listener_t private_lookip_listener_t; @@ -40,8 +41,23 @@ struct private_lookip_listener_t { * Hashtable with entries: host_t => entry_t */ hashtable_t *entries; + + /** + * List of registered listeners + */ + linked_list_t *listeners; }; +/** + * Listener entry + */ +typedef struct { + /** callback function */ + lookip_callback_t cb; + /** user data for callback */ + void *user; +} listener_entry_t; + /** * Hashtable entry */ @@ -84,6 +100,34 @@ static bool equals(host_t *a, host_t *b) return a->ip_equals(a, b); } +/** + * Compare callback that invokes up callback of all registered listeners + */ +static bool notify_up(listener_entry_t *listener, entry_t *entry) +{ + if (!listener->cb(listener->user, TRUE, entry->vip, entry->other, + entry->id, entry->name)) + { + free(listener); + return TRUE; + } + return FALSE; +} + +/** + * Compare callback that invokes down callback of all registered listeners + */ +static bool notify_down(listener_entry_t *listener, entry_t *entry) +{ + if (!listener->cb(listener->user, FALSE, entry->vip, entry->other, + entry->id, entry->name)) + { + free(listener); + return TRUE; + } + return FALSE; +} + /** * Add a new entry to the hashtable */ @@ -107,6 +151,10 @@ static void add_entry(private_lookip_listener_t *this, ike_sa_t *ike_sa) .name = strdup(ike_sa->get_name(ike_sa)), ); + this->lock->read_lock(this->lock); + this->listeners->remove(this->listeners, entry, (void*)notify_up); + this->lock->unlock(this->lock); + this->lock->write_lock(this->lock); entry = this->entries->put(this->entries, entry->vip, entry); this->lock->unlock(this->lock); @@ -135,6 +183,10 @@ static void remove_entry(private_lookip_listener_t *this, ike_sa_t *ike_sa) this->lock->unlock(this->lock); if (entry) { + this->lock->read_lock(this->lock); + this->listeners->remove(this->listeners, entry, (void*)notify_down); + this->lock->unlock(this->lock); + entry_destroy(entry); } } @@ -184,7 +236,7 @@ METHOD(lookip_listener_t, lookup, void, entry = this->entries->get(this->entries, vip); if (entry) { - cb(user, entry->vip, entry->other, entry->id, entry->name); + cb(user, TRUE, entry->vip, entry->other, entry->id, entry->name); } } else @@ -194,16 +246,32 @@ METHOD(lookip_listener_t, lookup, void, enumerator = this->entries->create_enumerator(this->entries); while (enumerator->enumerate(enumerator, &vip, &entry)) { - cb(user, entry->vip, entry->other, entry->id, entry->name); + cb(user, TRUE, entry->vip, entry->other, entry->id, entry->name); } enumerator->destroy(enumerator); } this->lock->unlock(this->lock); } +METHOD(lookip_listener_t, add_listener, void, + private_lookip_listener_t *this, lookip_callback_t cb, void *user) +{ + listener_entry_t *listener; + + INIT(listener, + .cb = cb, + .user = user, + ); + + this->lock->write_lock(this->lock); + this->listeners->insert_last(this->listeners, listener); + this->lock->unlock(this->lock); +} + METHOD(lookip_listener_t, destroy, void, private_lookip_listener_t *this) { + this->listeners->destroy_function(this->listeners, free); this->entries->destroy(this->entries); this->lock->destroy(this->lock); free(this); @@ -223,11 +291,13 @@ lookip_listener_t *lookip_listener_create() .ike_updown = _ike_updown, }, .lookup = _lookup, + .add_listener = _add_listener, .destroy = _destroy, }, .lock = rwlock_create(RWLOCK_TYPE_DEFAULT), .entries = hashtable_create((hashtable_hash_t)hash, (hashtable_equals_t)equals, 32), + .listeners = linked_list_create(), ); return &this->public; diff --git a/src/libcharon/plugins/lookip/lookip_listener.h b/src/libcharon/plugins/lookip/lookip_listener.h index eeb955ec61..63378fbb84 100644 --- a/src/libcharon/plugins/lookip/lookip_listener.h +++ b/src/libcharon/plugins/lookip/lookip_listener.h @@ -29,14 +29,15 @@ typedef struct lookip_listener_t lookip_listener_t; * Callback function to query virtual IP entries * * @param user user supplied pointer + * @param up TRUE if tunnels established, FALSE if closed * @param vip virtual IP of remote peer * @param other peer external IP * @param id peer identity * @param name associated connection name * @return TRUE to receive more results, FALSE to cancel */ -typedef bool (*lookip_callback_t)(void *user, host_t *vip, host_t *other, - identification_t *id, char *name); +typedef bool (*lookip_callback_t)(void *user, bool up, host_t *vip, + host_t *other, identification_t *id, char *name); /** * Listener collecting virtual IPs. @@ -51,6 +52,9 @@ struct lookip_listener_t { /** * Perform a lookup for a given virtual IP, invoke callback for matches. * + * The "up" parameter is always TRUE when the callback is invoked using + * lookup(). + * * @param vip virtual IP to look up, NULL to get all entries * @param cb callback function to invoke * @param user user data to pass to callback function @@ -58,6 +62,15 @@ struct lookip_listener_t { void (*lookup)(lookip_listener_t *this, host_t *vip, lookip_callback_t cb, void *user); + /** + * Register a listener function that gets notified about virtual IP changes. + * + * @param cb callback function to invoke + * @param user user data to pass to callback function + */ + void (*add_listener)(lookip_listener_t *this, + lookip_callback_t cb, void *user); + /** * Destroy a lookip_listener_t. */