Handle client subscriptions in lookip plugin

This commit is contained in:
Martin Willi
2012-10-24 11:43:34 +02:00
parent 7650dd9a4f
commit bae50c7393
+89 -12
View File
@@ -24,6 +24,8 @@
#include <daemon.h> #include <daemon.h>
#include <threading/thread.h> #include <threading/thread.h>
#include <threading/mutex.h>
#include <utils/linked_list.h>
#include <processing/jobs/callback_job.h> #include <processing/jobs/callback_job.h>
#include "lookip_msg.h" #include "lookip_msg.h"
@@ -49,6 +51,16 @@ struct private_lookip_socket_t {
* lookip unix socket file descriptor * lookip unix socket file descriptor
*/ */
int socket; int socket;
/**
* List of registered listeners, as entry_t
*/
linked_list_t *clients;
/**
* Mutex to lock clients list
*/
mutex_t *mutex;
}; };
/** /**
@@ -94,41 +106,71 @@ static bool open_socket(private_lookip_socket_t *this)
} }
/** /**
* Listener callback data * Listener callback entry
*/ */
typedef struct { typedef struct {
/* FD to write to */ /* FD to write to */
int fd; int fd;
/* message type to send */ /* message type to send */
int type; int type;
} cb_data_t; /* back pointer to socket, only for subscriptions */
private_lookip_socket_t *this;
} entry_t;
/**
* Destroy entry
*/
static void entry_destroy(entry_t *this)
{
close(this->fd);
free(this);
}
/** /**
* Callback function for listener * Callback function for listener
*/ */
static bool listener_cb(cb_data_t *data, bool up, host_t *vip, static bool listener_cb(entry_t *entry, bool up, host_t *vip,
host_t *other, identification_t *id, char *name) host_t *other, identification_t *id, char *name)
{ {
lookip_response_t resp = { lookip_response_t resp = {
.type = data->type, .type = entry->type,
}; };
/* filter events */
if (up && entry->type == LOOKIP_NOTIFY_DOWN)
{
return TRUE;
}
if (!up && entry->type == LOOKIP_NOTIFY_UP)
{
return TRUE;
}
snprintf(resp.vip, sizeof(resp.vip), "%H", vip); snprintf(resp.vip, sizeof(resp.vip), "%H", vip);
snprintf(resp.ip, sizeof(resp.ip), "%H", other); snprintf(resp.ip, sizeof(resp.ip), "%H", other);
snprintf(resp.id, sizeof(resp.id), "%Y", id); snprintf(resp.id, sizeof(resp.id), "%Y", id);
snprintf(resp.name, sizeof(resp.name), "%s", name); snprintf(resp.name, sizeof(resp.name), "%s", name);
switch (send(data->fd, &resp, sizeof(resp), 0)) switch (send(entry->fd, &resp, sizeof(resp), 0))
{ {
case sizeof(resp): case sizeof(resp):
return TRUE; return TRUE;
case 0: case 0:
/* client disconnected, adios */ /* client disconnected, adios */
return FALSE; break;
default: default:
DBG1(DBG_CFG, "sending lookip response failed: %s", strerror(errno)); DBG1(DBG_CFG, "sending lookip response failed: %s", strerror(errno));
return FALSE; break;
} }
if (entry->this)
{ /* unregister listener */
entry->this->mutex->lock(entry->this->mutex);
entry->this->clients->remove(entry->this->clients, entry, NULL);
entry->this->mutex->unlock(entry->this->mutex);
entry_destroy(entry);
}
return FALSE;
} }
/** /**
@@ -136,7 +178,7 @@ static bool listener_cb(cb_data_t *data, bool up, host_t *vip,
*/ */
static void query(private_lookip_socket_t *this, int fd, lookip_request_t *req) static void query(private_lookip_socket_t *this, int fd, lookip_request_t *req)
{ {
cb_data_t data = { entry_t entry = {
.fd = fd, .fd = fd,
.type = LOOKIP_ENTRY, .type = LOOKIP_ENTRY,
}; };
@@ -149,17 +191,37 @@ static void query(private_lookip_socket_t *this, int fd, lookip_request_t *req)
if (vip) if (vip)
{ {
this->listener->lookup(this->listener, vip, this->listener->lookup(this->listener, vip,
(void*)listener_cb, &data); (void*)listener_cb, &entry);
vip->destroy(vip); vip->destroy(vip);
} }
} }
else else
{ /* dump */ { /* dump */
this->listener->lookup(this->listener, NULL, this->listener->lookup(this->listener, NULL,
(void*)listener_cb, &data); (void*)listener_cb, &entry);
} }
} }
/**
* Subscribe to virtual IP events
*/
static void subscribe(private_lookip_socket_t *this, int fd, int type)
{
entry_t *entry;
INIT(entry,
.fd = fd,
.type = type,
.this = this,
);
this->mutex->lock(this->mutex);
this->clients->insert_last(this->clients, entry);
this->mutex->unlock(this->mutex);
this->listener->add_listener(this->listener, (void*)listener_cb, entry);
}
/** /**
* Accept client connections, dispatch * Accept client connections, dispatch
*/ */
@@ -168,7 +230,7 @@ static job_requeue_t receive(private_lookip_socket_t *this)
struct sockaddr_un addr; struct sockaddr_un addr;
int fd, len = sizeof(addr); int fd, len = sizeof(addr);
lookip_request_t req; lookip_request_t req;
bool oldstate; bool oldstate, subscribed = FALSE;
oldstate = thread_cancelability(TRUE); oldstate = thread_cancelability(TRUE);
fd = accept(this->socket, (struct sockaddr*)&addr, &len); fd = accept(this->socket, (struct sockaddr*)&addr, &len);
@@ -192,6 +254,14 @@ static job_requeue_t receive(private_lookip_socket_t *this)
case LOOKIP_DUMP: case LOOKIP_DUMP:
query(this, fd, NULL); query(this, fd, NULL);
continue; continue;
case LOOKIP_REGISTER_UP:
subscribe(this, fd, LOOKIP_NOTIFY_UP);
subscribed = TRUE;
continue;
case LOOKIP_REGISTER_DOWN:
subscribe(this, fd, LOOKIP_NOTIFY_DOWN);
subscribed = TRUE;
continue;
case LOOKIP_END: case LOOKIP_END:
break; break;
default: default:
@@ -210,7 +280,10 @@ static job_requeue_t receive(private_lookip_socket_t *this)
} }
break; break;
} }
close(fd); if (!subscribed)
{ /* don't close if we queued the fd */
close(fd);
}
} }
else else
{ {
@@ -223,6 +296,8 @@ static job_requeue_t receive(private_lookip_socket_t *this)
METHOD(lookip_socket_t, destroy, void, METHOD(lookip_socket_t, destroy, void,
private_lookip_socket_t *this) private_lookip_socket_t *this)
{ {
this->clients->destroy_function(this->clients, (void*)entry_destroy);
this->mutex->destroy(this->mutex);
close(this->socket); close(this->socket);
free(this); free(this);
} }
@@ -239,6 +314,8 @@ lookip_socket_t *lookip_socket_create(lookip_listener_t *listener)
.destroy = _destroy, .destroy = _destroy,
}, },
.listener = listener, .listener = listener,
.clients = linked_list_create(),
.mutex = mutex_create(MUTEX_TYPE_DEFAULT),
); );
if (!open_socket(this)) if (!open_socket(this))