handler: allow to add same handler callback with different userdata

According to #97. A single callback can distinguish different cases
using the userdata. Current implementation doesn't allow to delete a
particular couple (handler, userdata), but rather deletes all handlers
regardless of the userdata.
This commit is contained in:
Dmitry Podgorny
2016-12-02 18:52:30 +02:00
parent 80a7ea0b7c
commit 9a5fe8b96d

View File

@@ -40,14 +40,22 @@ void handler_fire_stanza(xmpp_conn_t * const conn,
/* call id handlers */ /* call id handlers */
id = xmpp_stanza_get_id(stanza); id = xmpp_stanza_get_id(stanza);
if (id) { if (id) {
/* enable all added handlers */
item = (xmpp_handlist_t *)hash_get(conn->id_handlers, id);
for (; item; item = item->next)
item->enabled = 1;
prev = NULL; prev = NULL;
item = (xmpp_handlist_t *)hash_get(conn->id_handlers, id); item = (xmpp_handlist_t *)hash_get(conn->id_handlers, id);
while (item) { while (item) {
xmpp_handlist_t *next = item->next; xmpp_handlist_t *next = item->next;
if (item->user_handler && !conn->authenticated) { /* don't fire user handlers until authentication succeeds and
and skip newly added handlers */
if ((item->user_handler && !conn->authenticated) || !item->enabled) {
prev = item;
item = next; item = next;
continue; continue;
} }
if (!((xmpp_handler)(item->handler))(conn, stanza, item->userdata)) { if (!((xmpp_handler)(item->handler))(conn, stanza, item->userdata)) {
@@ -80,15 +88,9 @@ void handler_fire_stanza(xmpp_conn_t * const conn,
prev = NULL; prev = NULL;
item = conn->handlers; item = conn->handlers;
while (item) { while (item) {
/* skip newly added handlers */ /* don't fire user handlers until authentication succeeds and
if (!item->enabled) { skip newly added handlers */
prev = item; if ((item->user_handler && !conn->authenticated) || !item->enabled) {
item = item->next;
continue;
}
/* don't call user handlers until authentication succeeds */
if (item->user_handler && !conn->authenticated) {
prev = item; prev = item;
item = item->next; item = item->next;
continue; continue;
@@ -114,10 +116,8 @@ void handler_fire_stanza(xmpp_conn_t * const conn,
if (item) { if (item) {
prev = item; prev = item;
item = item->next; item = item->next;
} else if (prev) } else
item = prev->next; item = prev ? prev->next : conn->handlers;
else
item = conn->handlers;
} }
} }
@@ -131,54 +131,58 @@ void handler_fire_stanza(xmpp_conn_t * const conn,
uint64_t handler_fire_timed(xmpp_ctx_t * const ctx) uint64_t handler_fire_timed(xmpp_ctx_t * const ctx)
{ {
xmpp_connlist_t *connitem; xmpp_connlist_t *connitem;
xmpp_handlist_t *handitem, *temp; xmpp_handlist_t *item, *prev;
int ret, fired; xmpp_conn_t *conn;
uint64_t elapsed, min; uint64_t elapsed, min;
int ret;
min = (uint64_t)(-1); min = (uint64_t)(-1);
connitem = ctx->connlist; connitem = ctx->connlist;
while (connitem) { while (connitem) {
if (connitem->conn->state != XMPP_STATE_CONNECTED) { conn = connitem->conn;
if (conn->state != XMPP_STATE_CONNECTED) {
connitem = connitem->next; connitem = connitem->next;
continue; continue;
} }
/* enable all handlers that were added */ /* enable all handlers that were added */
for (handitem = connitem->conn->timed_handlers; handitem; for (item = conn->timed_handlers; item; item = item->next)
handitem = handitem->next) item->enabled = 1;
handitem->enabled = 1;
handitem = connitem->conn->timed_handlers; prev = NULL;
while (handitem) { item = conn->timed_handlers;
/* skip newly added handlers */ while (item) {
if (!handitem->enabled) { /* don't fire user handlers until authentication succeeds and
handitem = handitem->next; skip newly added handlers */
if ((item->user_handler && !conn->authenticated) || !item->enabled) {
prev = item;
item = item->next;
continue; continue;
} }
/* only fire user handlers after authentication */ elapsed = time_elapsed(item->last_stamp, time_stamp());
if (handitem->user_handler && !connitem->conn->authenticated) { if (elapsed >= item->period) {
handitem = handitem->next;
continue;
}
fired = 0;
elapsed = time_elapsed(handitem->last_stamp, time_stamp());
if (elapsed >= handitem->period) {
/* fire! */ /* fire! */
fired = 1; item->last_stamp = time_stamp();
handitem->last_stamp = time_stamp(); ret = ((xmpp_timed_handler)item->handler)(conn, item->userdata);
ret = ((xmpp_timed_handler)handitem->handler)(connitem->conn, handitem->userdata); if (!ret) {
} else if (min > (handitem->period - elapsed)) /* delete handler if it returned false */
min = handitem->period - elapsed; if (prev)
prev->next = item->next;
else
conn->timed_handlers = item->next;
xmpp_free(conn->ctx, item);
item = NULL;
}
} else if (min > (item->period - elapsed))
min = item->period - elapsed;
temp = handitem; if (item) {
handitem = handitem->next; prev = item;
item = item->next;
/* delete handler if it returned false */ } else
if (fired && !ret) item = prev ? prev->next : conn->timed_handlers;
xmpp_timed_handler_delete(connitem->conn, temp->handler);
} }
connitem = connitem->next; connitem = connitem->next;
@@ -216,8 +220,10 @@ static void _timed_handler_add(xmpp_conn_t * const conn,
/* check if handler is already in the list */ /* check if handler is already in the list */
for (item = conn->timed_handlers; item; item = item->next) { for (item = conn->timed_handlers; item; item = item->next) {
if (item->handler == (void *)handler) if (item->handler == (void *)handler && item->userdata == userdata) {
xmpp_warn(conn->ctx, "xmpp", "Timed handler already exists.");
break; break;
}
} }
if (item) return; if (item) return;
@@ -262,19 +268,18 @@ void xmpp_timed_handler_delete(xmpp_conn_t * const conn,
prev = NULL; prev = NULL;
item = conn->timed_handlers; item = conn->timed_handlers;
while (item) { while (item) {
if (item->handler == (void *)handler) if (item->handler == (void *)handler) {
break; if (prev)
prev = item; prev->next = item->next;
item = item->next; else
} conn->timed_handlers = item->next;
if (item) { xmpp_free(conn->ctx, item);
if (prev) item = prev ? prev->next : conn->timed_handlers;
prev->next = item->next; } else {
else prev = item;
conn->timed_handlers = item->next; item = item->next;
}
xmpp_free(conn->ctx, item);
} }
} }
@@ -288,8 +293,10 @@ static void _id_handler_add(xmpp_conn_t * const conn,
/* check if handler is already in the list */ /* check if handler is already in the list */
item = (xmpp_handlist_t *)hash_get(conn->id_handlers, id); item = (xmpp_handlist_t *)hash_get(conn->id_handlers, id);
while (item) { while (item) {
if (item->handler == (void *)handler) if (item->handler == (void *)handler && item->userdata == userdata) {
xmpp_warn(conn->ctx, "xmpp", "Id handler already exists.");
break; break;
}
item = item->next; item = item->next;
} }
if (item) return; if (item) return;
@@ -333,29 +340,30 @@ void xmpp_id_handler_delete(xmpp_conn_t * const conn,
xmpp_handler handler, xmpp_handler handler,
const char * const id) const char * const id)
{ {
xmpp_handlist_t *item, *prev; xmpp_handlist_t *item, *prev, *next;
prev = NULL; prev = NULL;
item = (xmpp_handlist_t *)hash_get(conn->id_handlers, id); item = (xmpp_handlist_t *)hash_get(conn->id_handlers, id);
if (!item) return; if (!item) return;
while (item) { while (item) {
if (item->handler == (void *)handler) next = item->next;
break;
prev = item; if (item->handler == (void *)handler) {
item = item->next; if (prev)
} prev->next = next;
else {
hash_drop(conn->id_handlers, id);
hash_add(conn->id_handlers, id, next);
}
if (item) { xmpp_free(conn->ctx, item->id);
if (prev) xmpp_free(conn->ctx, item);
prev->next = item->next; item = next;
else { } else {
hash_drop(conn->id_handlers, id); prev = item;
hash_add(conn->id_handlers, id, item->next); item = next;
} }
xmpp_free(conn->ctx, item->id);
xmpp_free(conn->ctx, item);
} }
} }
@@ -371,8 +379,12 @@ static void _handler_add(xmpp_conn_t * const conn,
/* check if handler already in list */ /* check if handler already in list */
for (item = conn->handlers; item; item = item->next) { for (item = conn->handlers; item; item = item->next) {
if (item->handler == (void *)handler) /* same handler function can process different stanzas and
distinguish them according to userdata. */
if (item->handler == (void *)handler && item->userdata == userdata) {
xmpp_warn(conn->ctx, "xmpp", "Stanza handler already exists.");
break; break;
}
} }
if (item) return; if (item) return;
@@ -441,23 +453,21 @@ void xmpp_handler_delete(xmpp_conn_t * const conn,
prev = NULL; prev = NULL;
item = conn->handlers; item = conn->handlers;
while (item) { while (item) {
if (item->handler == (void *)handler) if (item->handler == (void *)handler) {
break; if (prev)
prev->next = item->next;
else
conn->handlers = item->next;
prev = item; if (item->ns) xmpp_free(conn->ctx, item->ns);
item = item->next; if (item->name) xmpp_free(conn->ctx, item->name);
} if (item->type) xmpp_free(conn->ctx, item->type);
xmpp_free(conn->ctx, item);
if (item) { item = prev ? prev->next : conn->handlers;
if (prev) } else {
prev->next = item->next; prev = item;
else item = item->next;
conn->handlers = item->next; }
if (item->ns) xmpp_free(conn->ctx, item->ns);
if (item->name) xmpp_free(conn->ctx, item->name);
if (item->type) xmpp_free(conn->ctx, item->type);
xmpp_free(conn->ctx, item);
} }
} }