Introduce global timed handlers
There are situations when applications need more predictable timed handlers that don't depend on connection status. Other usecase of the global handlers is to manage offline connections, for example, reconnect after a disconnection.
This commit is contained in:
@@ -3,6 +3,9 @@
|
|||||||
- SCRAM-SHA-256 and SCRAM-SHA-512 support
|
- SCRAM-SHA-256 and SCRAM-SHA-512 support
|
||||||
- c-ares support
|
- c-ares support
|
||||||
- LibreSSL support
|
- LibreSSL support
|
||||||
|
- Introduced global timed handlers that fire periodically regardless of
|
||||||
|
connections status, such a handler can be used to implement deferred
|
||||||
|
re-connection
|
||||||
- examples/register implements XEP-0077
|
- examples/register implements XEP-0077
|
||||||
- Fixed issue with IPv6 on Windows (#153)
|
- Fixed issue with IPv6 on Windows (#153)
|
||||||
- Improved portability across systems such as Haiku, Windows
|
- Improved portability across systems such as Haiku, Windows
|
||||||
@@ -13,6 +16,8 @@
|
|||||||
- xmpp_conn_is_disconnected()
|
- xmpp_conn_is_disconnected()
|
||||||
- xmpp_stanza_add_child_ex()
|
- xmpp_stanza_add_child_ex()
|
||||||
- xmpp_stanza_get_context()
|
- xmpp_stanza_get_context()
|
||||||
|
- xmpp_global_timed_handler_add()
|
||||||
|
- xmpp_global_timed_handler_delete()
|
||||||
|
|
||||||
0.9.3
|
0.9.3
|
||||||
- PLAIN mechanism is used only when no other mechanisms are supported
|
- PLAIN mechanism is used only when no other mechanisms are supported
|
||||||
|
|||||||
63
src/common.h
63
src/common.h
@@ -29,6 +29,38 @@
|
|||||||
#include "rand.h"
|
#include "rand.h"
|
||||||
#include "snprintf.h"
|
#include "snprintf.h"
|
||||||
|
|
||||||
|
/** handlers **/
|
||||||
|
|
||||||
|
typedef struct _xmpp_handlist_t xmpp_handlist_t;
|
||||||
|
struct _xmpp_handlist_t {
|
||||||
|
/* common members */
|
||||||
|
int user_handler;
|
||||||
|
int (*handler)();
|
||||||
|
void *userdata;
|
||||||
|
int enabled; /* handlers are added disabled and enabled after the
|
||||||
|
* handler chain is processed to prevent stanzas from
|
||||||
|
* getting processed by newly added handlers */
|
||||||
|
xmpp_handlist_t *next;
|
||||||
|
|
||||||
|
union {
|
||||||
|
/* timed handlers */
|
||||||
|
struct {
|
||||||
|
unsigned long period;
|
||||||
|
uint64_t last_stamp;
|
||||||
|
};
|
||||||
|
/* id handlers */
|
||||||
|
struct {
|
||||||
|
char *id;
|
||||||
|
};
|
||||||
|
/* normal handlers */
|
||||||
|
struct {
|
||||||
|
char *ns;
|
||||||
|
char *name;
|
||||||
|
char *type;
|
||||||
|
};
|
||||||
|
} u;
|
||||||
|
};
|
||||||
|
|
||||||
/** run-time context **/
|
/** run-time context **/
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@@ -49,6 +81,7 @@ struct _xmpp_ctx_t {
|
|||||||
xmpp_rand_t *rand;
|
xmpp_rand_t *rand;
|
||||||
xmpp_loop_status_t loop_status;
|
xmpp_loop_status_t loop_status;
|
||||||
xmpp_connlist_t *connlist;
|
xmpp_connlist_t *connlist;
|
||||||
|
xmpp_handlist_t *timed_handlers;
|
||||||
|
|
||||||
unsigned long timeout;
|
unsigned long timeout;
|
||||||
};
|
};
|
||||||
@@ -100,36 +133,6 @@ struct _xmpp_send_queue_t {
|
|||||||
xmpp_send_queue_t *next;
|
xmpp_send_queue_t *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct _xmpp_handlist_t xmpp_handlist_t;
|
|
||||||
struct _xmpp_handlist_t {
|
|
||||||
/* common members */
|
|
||||||
int user_handler;
|
|
||||||
int (*handler)();
|
|
||||||
void *userdata;
|
|
||||||
int enabled; /* handlers are added disabled and enabled after the
|
|
||||||
* handler chain is processed to prevent stanzas from
|
|
||||||
* getting processed by newly added handlers */
|
|
||||||
xmpp_handlist_t *next;
|
|
||||||
|
|
||||||
union {
|
|
||||||
/* timed handlers */
|
|
||||||
struct {
|
|
||||||
unsigned long period;
|
|
||||||
uint64_t last_stamp;
|
|
||||||
};
|
|
||||||
/* id handlers */
|
|
||||||
struct {
|
|
||||||
char *id;
|
|
||||||
};
|
|
||||||
/* normal handlers */
|
|
||||||
struct {
|
|
||||||
char *ns;
|
|
||||||
char *name;
|
|
||||||
char *type;
|
|
||||||
};
|
|
||||||
} u;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define UNUSED(x) ((void)(x))
|
#define UNUSED(x) ((void)(x))
|
||||||
|
|
||||||
#define MAX_DOMAIN_LEN 256
|
#define MAX_DOMAIN_LEN 256
|
||||||
|
|||||||
@@ -419,6 +419,7 @@ xmpp_ctx_t *xmpp_ctx_new(const xmpp_mem_t *const mem,
|
|||||||
ctx->log = log;
|
ctx->log = log;
|
||||||
|
|
||||||
ctx->connlist = NULL;
|
ctx->connlist = NULL;
|
||||||
|
ctx->timed_handlers = NULL;
|
||||||
ctx->loop_status = XMPP_LOOP_NOTSTARTED;
|
ctx->loop_status = XMPP_LOOP_NOTSTARTED;
|
||||||
ctx->rand = xmpp_rand_new(ctx);
|
ctx->rand = xmpp_rand_new(ctx);
|
||||||
ctx->timeout = EVENT_LOOP_DEFAULT_TIMEOUT;
|
ctx->timeout = EVENT_LOOP_DEFAULT_TIMEOUT;
|
||||||
|
|||||||
127
src/handler.c
127
src/handler.c
@@ -24,6 +24,8 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "ostypes.h"
|
#include "ostypes.h"
|
||||||
|
|
||||||
|
typedef int (*xmpp_void_handler)();
|
||||||
|
|
||||||
/* Remove item from the list pointed by head, but don't free it.
|
/* Remove item from the list pointed by head, but don't free it.
|
||||||
* There can be a situation when user's handler deletes another handler which
|
* There can be a situation when user's handler deletes another handler which
|
||||||
* is the previous in the list. handler_fire_stanza() and handler_fire_timed()
|
* is the previous in the list. handler_fire_stanza() and handler_fire_timed()
|
||||||
@@ -35,16 +37,12 @@
|
|||||||
*/
|
*/
|
||||||
static void _handler_item_remove(xmpp_handlist_t **head, xmpp_handlist_t *item)
|
static void _handler_item_remove(xmpp_handlist_t **head, xmpp_handlist_t *item)
|
||||||
{
|
{
|
||||||
xmpp_handlist_t *i = *head;
|
while (*head) {
|
||||||
|
if (*head == item) {
|
||||||
if (i == item)
|
*head = item->next;
|
||||||
*head = item->next;
|
break;
|
||||||
else if (i != NULL) {
|
|
||||||
while (i->next != NULL && i->next != item)
|
|
||||||
i = i->next;
|
|
||||||
if (i->next == item) {
|
|
||||||
i->next = item->next;
|
|
||||||
}
|
}
|
||||||
|
head = &(*head)->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,7 +189,7 @@ uint64_t handler_fire_timed(xmpp_ctx_t *const ctx)
|
|||||||
if (!ret) {
|
if (!ret) {
|
||||||
/* delete handler if it returned false */
|
/* delete handler if it returned false */
|
||||||
_handler_item_remove(&conn->timed_handlers, item);
|
_handler_item_remove(&conn->timed_handlers, item);
|
||||||
xmpp_free(conn->ctx, item);
|
xmpp_free(ctx, item);
|
||||||
}
|
}
|
||||||
} else if (min > (item->u.period - elapsed))
|
} else if (min > (item->u.period - elapsed))
|
||||||
min = item->u.period - elapsed;
|
min = item->u.period - elapsed;
|
||||||
@@ -202,6 +200,34 @@ uint64_t handler_fire_timed(xmpp_ctx_t *const ctx)
|
|||||||
connitem = connitem->next;
|
connitem = connitem->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check timed handlers in context. These handlers fire periodically
|
||||||
|
* regardless of connections state.
|
||||||
|
* TODO Reduce copy-paste.
|
||||||
|
*/
|
||||||
|
item = ctx->timed_handlers;
|
||||||
|
while (item) {
|
||||||
|
next = item->next;
|
||||||
|
timestamp = time_stamp();
|
||||||
|
elapsed = time_elapsed(item->u.last_stamp, timestamp);
|
||||||
|
if (elapsed >= item->u.period) {
|
||||||
|
/* fire! */
|
||||||
|
item->u.last_stamp = timestamp;
|
||||||
|
ret =
|
||||||
|
((xmpp_global_timed_handler)item->handler)(ctx, item->userdata);
|
||||||
|
/* list may be changed during execution of a handler */
|
||||||
|
next = item->next;
|
||||||
|
if (!ret) {
|
||||||
|
/* delete handler if it returned false */
|
||||||
|
_handler_item_remove(&ctx->timed_handlers, item);
|
||||||
|
xmpp_free(ctx, item);
|
||||||
|
}
|
||||||
|
} else if (min > (item->u.period - elapsed))
|
||||||
|
min = item->u.period - elapsed;
|
||||||
|
|
||||||
|
item = next;
|
||||||
|
}
|
||||||
|
|
||||||
return min;
|
return min;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -224,18 +250,19 @@ void handler_reset_timed(xmpp_conn_t *conn, int user_only)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _timed_handler_add(xmpp_conn_t *const conn,
|
static void _timed_handler_add(xmpp_ctx_t *ctx,
|
||||||
xmpp_timed_handler handler,
|
xmpp_handlist_t **handlers_list,
|
||||||
|
xmpp_void_handler handler,
|
||||||
const unsigned long period,
|
const unsigned long period,
|
||||||
void *const userdata,
|
void *const userdata,
|
||||||
const int user_handler)
|
const int user_handler)
|
||||||
{
|
{
|
||||||
xmpp_handlist_t *item, *tail;
|
xmpp_handlist_t *item;
|
||||||
|
|
||||||
/* 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 = *handlers_list; item; item = item->next) {
|
||||||
if (item->handler == handler && item->userdata == userdata) {
|
if (item->handler == handler && item->userdata == userdata) {
|
||||||
xmpp_warn(conn->ctx, "xmpp", "Timed handler already exists.");
|
xmpp_warn(ctx, "xmpp", "Timed handler already exists.");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -243,7 +270,7 @@ static void _timed_handler_add(xmpp_conn_t *const conn,
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
/* build new item */
|
/* build new item */
|
||||||
item = xmpp_alloc(conn->ctx, sizeof(xmpp_handlist_t));
|
item = xmpp_alloc(ctx, sizeof(xmpp_handlist_t));
|
||||||
if (!item)
|
if (!item)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -251,19 +278,29 @@ static void _timed_handler_add(xmpp_conn_t *const conn,
|
|||||||
item->handler = handler;
|
item->handler = handler;
|
||||||
item->userdata = userdata;
|
item->userdata = userdata;
|
||||||
item->enabled = 0;
|
item->enabled = 0;
|
||||||
item->next = NULL;
|
|
||||||
|
|
||||||
item->u.period = period;
|
item->u.period = period;
|
||||||
item->u.last_stamp = time_stamp();
|
item->u.last_stamp = time_stamp();
|
||||||
|
|
||||||
/* append item to list */
|
/* append item to list */
|
||||||
if (!conn->timed_handlers)
|
item->next = *handlers_list;
|
||||||
conn->timed_handlers = item;
|
*handlers_list = item;
|
||||||
else {
|
}
|
||||||
tail = conn->timed_handlers;
|
|
||||||
while (tail->next)
|
static void _timed_handler_delete(xmpp_ctx_t *ctx,
|
||||||
tail = tail->next;
|
xmpp_handlist_t **handlers_list,
|
||||||
tail->next = item;
|
xmpp_void_handler handler)
|
||||||
|
{
|
||||||
|
xmpp_handlist_t *item;
|
||||||
|
|
||||||
|
while (*handlers_list) {
|
||||||
|
item = *handlers_list;
|
||||||
|
if (item->handler == handler) {
|
||||||
|
*handlers_list = item->next;
|
||||||
|
xmpp_free(ctx, item);
|
||||||
|
} else {
|
||||||
|
handlers_list = &item->next;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -277,27 +314,7 @@ static void _timed_handler_add(xmpp_conn_t *const conn,
|
|||||||
void xmpp_timed_handler_delete(xmpp_conn_t *const conn,
|
void xmpp_timed_handler_delete(xmpp_conn_t *const conn,
|
||||||
xmpp_timed_handler handler)
|
xmpp_timed_handler handler)
|
||||||
{
|
{
|
||||||
xmpp_handlist_t *item, *prev;
|
_timed_handler_delete(conn->ctx, &conn->timed_handlers, handler);
|
||||||
|
|
||||||
if (!conn->timed_handlers)
|
|
||||||
return;
|
|
||||||
|
|
||||||
prev = NULL;
|
|
||||||
item = conn->timed_handlers;
|
|
||||||
while (item) {
|
|
||||||
if (item->handler == handler) {
|
|
||||||
if (prev)
|
|
||||||
prev->next = item->next;
|
|
||||||
else
|
|
||||||
conn->timed_handlers = item->next;
|
|
||||||
|
|
||||||
xmpp_free(conn->ctx, item);
|
|
||||||
item = prev ? prev->next : conn->timed_handlers;
|
|
||||||
} else {
|
|
||||||
prev = item;
|
|
||||||
item = item->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _id_handler_add(xmpp_conn_t *const conn,
|
static void _id_handler_add(xmpp_conn_t *const conn,
|
||||||
@@ -524,7 +541,8 @@ void xmpp_timed_handler_add(xmpp_conn_t *const conn,
|
|||||||
const unsigned long period,
|
const unsigned long period,
|
||||||
void *const userdata)
|
void *const userdata)
|
||||||
{
|
{
|
||||||
_timed_handler_add(conn, handler, period, userdata, 1);
|
_timed_handler_add(conn->ctx, &conn->timed_handlers, handler, period,
|
||||||
|
userdata, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Add a timed system handler.
|
/** Add a timed system handler.
|
||||||
@@ -541,7 +559,8 @@ void handler_add_timed(xmpp_conn_t *const conn,
|
|||||||
const unsigned long period,
|
const unsigned long period,
|
||||||
void *const userdata)
|
void *const userdata)
|
||||||
{
|
{
|
||||||
_timed_handler_add(conn, handler, period, userdata, 0);
|
_timed_handler_add(conn->ctx, &conn->timed_handlers, handler, period,
|
||||||
|
userdata, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Add an id based stanza handler.
|
/** Add an id based stanza handler.
|
||||||
@@ -713,3 +732,17 @@ void handler_system_delete_all(xmpp_conn_t *conn)
|
|||||||
if (iter)
|
if (iter)
|
||||||
hash_iter_release(iter);
|
hash_iter_release(iter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void xmpp_global_timed_handler_add(xmpp_ctx_t *const ctx,
|
||||||
|
xmpp_global_timed_handler handler,
|
||||||
|
const unsigned long period,
|
||||||
|
void *const userdata)
|
||||||
|
{
|
||||||
|
_timed_handler_add(ctx, &ctx->timed_handlers, handler, period, userdata, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void xmpp_global_timed_handler_delete(xmpp_ctx_t *const ctx,
|
||||||
|
xmpp_global_timed_handler handler)
|
||||||
|
{
|
||||||
|
_timed_handler_delete(ctx, &ctx->timed_handlers, handler);
|
||||||
|
}
|
||||||
|
|||||||
13
strophe.h
13
strophe.h
@@ -279,7 +279,7 @@ void xmpp_send_raw(xmpp_conn_t *const conn,
|
|||||||
|
|
||||||
/* handlers */
|
/* handlers */
|
||||||
|
|
||||||
/* if the handle returns false it is removed */
|
/* if the handler returns false it is removed */
|
||||||
typedef int (*xmpp_timed_handler)(xmpp_conn_t *const conn,
|
typedef int (*xmpp_timed_handler)(xmpp_conn_t *const conn,
|
||||||
void *const userdata);
|
void *const userdata);
|
||||||
|
|
||||||
@@ -290,6 +290,17 @@ void xmpp_timed_handler_add(xmpp_conn_t *const conn,
|
|||||||
void xmpp_timed_handler_delete(xmpp_conn_t *const conn,
|
void xmpp_timed_handler_delete(xmpp_conn_t *const conn,
|
||||||
xmpp_timed_handler handler);
|
xmpp_timed_handler handler);
|
||||||
|
|
||||||
|
/* if the handler returns false it is removed */
|
||||||
|
typedef int (*xmpp_global_timed_handler)(xmpp_ctx_t *const ctx,
|
||||||
|
void *const userdata);
|
||||||
|
|
||||||
|
void xmpp_global_timed_handler_add(xmpp_ctx_t *const ctx,
|
||||||
|
xmpp_global_timed_handler handler,
|
||||||
|
const unsigned long period,
|
||||||
|
void *const userdata);
|
||||||
|
void xmpp_global_timed_handler_delete(xmpp_ctx_t *const ctx,
|
||||||
|
xmpp_global_timed_handler handler);
|
||||||
|
|
||||||
/* if the handler returns false it is removed */
|
/* if the handler returns false it is removed */
|
||||||
typedef int (*xmpp_handler)(xmpp_conn_t *const conn,
|
typedef int (*xmpp_handler)(xmpp_conn_t *const conn,
|
||||||
xmpp_stanza_t *const stanza,
|
xmpp_stanza_t *const stanza,
|
||||||
|
|||||||
Reference in New Issue
Block a user