#include "sm.h"
union xhashv
{
void **val;
sess_t *sess_val;
};
static mod_ret_t _session_in_router(mod_instance_t mi, pkt_t pkt) {
sm_t sm = mi->mod->mm->sm;
int ns, attr;
jid_t jid;
sess_t sess = (sess_t) NULL;
mod_ret_t ret;
if(pkt->nad->ecur <= 1 || (ns = nad_find_namespace(pkt->nad, 1, uri_SESSION, NULL)) < 0)
return mod_PASS;
if(pkt->type & pkt_SESS_FAILED) {
pkt_free(pkt);
return mod_HANDLED;
}
if(pkt->type & pkt_SESS) {
ns = nad_find_namespace(pkt->nad, 1, uri_SESSION, NULL);
attr = nad_find_attr(pkt->nad, 1, -1, "target", NULL);
if(attr < 0 && pkt->type != pkt_SESS_END) {
nad_set_attr(pkt->nad, 1, ns, "failed", "1", 1);
sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0));
pkt->nad = NULL;
pkt_free(pkt);
return mod_HANDLED;
}
if(pkt->type == pkt_SESS) {
jid = jid_new(sm->pc, NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr));
if(jid != NULL)
sess = sess_start(sm, jid);
if(jid == NULL || sess == NULL) {
nad_set_attr(pkt->nad, 1, ns, "failed", "1", 1);
sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0));
pkt->nad = NULL;
pkt_free(pkt);
if(jid != NULL)
jid_free(jid);
return mod_HANDLED;
}
strcpy(sess->c2s, pkt->rfrom->domain);
attr = nad_find_attr(pkt->nad, 1, ns, "c2s", NULL);
snprintf(sess->c2s_id, 10, "%.*s", NAD_AVAL_L(pkt->nad, attr), NAD_AVAL(pkt->nad, attr));
nad_set_attr(pkt->nad, 1, ns, "sm", sess->sm_id, 0);
nad_set_attr(pkt->nad, 1, -1, "action", "started", 7);
sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0));
pkt->nad = NULL;
pkt_free(pkt);
jid_free(jid);
return mod_HANDLED;
}
if(pkt->type == pkt_SESS_CREATE) {
jid = jid_new(sm->pc, NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr));
if(jid == NULL || user_create(sm, jid) != 0) {
nad_set_attr(pkt->nad, 1, ns, "failed", "1", 1);
sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0));
pkt->nad = NULL;
pkt_free(pkt);
if(jid != NULL)
jid_free(jid);
return mod_HANDLED;
}
nad_set_attr(pkt->nad, 1, -1, "action", "created", 7);
sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0));
pkt->nad = NULL;
pkt_free(pkt);
jid_free(jid);
return mod_HANDLED;
}
if(pkt->type == pkt_SESS_DELETE) {
jid = jid_new(sm->pc, NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr));
if(jid == NULL) {
pkt_free(pkt);
return mod_HANDLED;
}
user_delete(sm, jid);
nad_set_attr(pkt->nad, 1, -1, "action", "deleted", 7);
sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0));
pkt->nad = NULL;
pkt_free(pkt);
jid_free(jid);
return mod_HANDLED;
}
attr = nad_find_attr(pkt->nad, 1, ns, "sm", NULL);
if(attr < 0) {
log_debug(ZONE, "no session id, bouncing");
nad_set_attr(pkt->nad, 1, ns, "failed", "1", 1);
sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0));
pkt->nad = NULL;
pkt_free(pkt);
return mod_HANDLED;
}
sess = xhash_getx(sm->sessions, NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr));
if(sess == NULL) {
log_debug(ZONE, "session %.*s doesn't exist, bouncing", NAD_AVAL_L(pkt->nad, attr), NAD_AVAL(pkt->nad, attr));
nad_set_attr(pkt->nad, 1, ns, "failed", "1", 1);
sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0));
pkt->nad = NULL;
pkt_free(pkt);
return mod_HANDLED;
}
attr = nad_find_attr(pkt->nad, 1, ns, "c2s", NULL);
if(attr >= 0 && (strlen(sess->c2s_id) != NAD_AVAL_L(pkt->nad, attr) || strncmp(sess->c2s_id, NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr)) != 0)) {
log_debug(ZONE, "invalid sender on route from %s for session %s (should be %s)", pkt->rfrom->domain, sess->sm_id, sess->c2s_id);
pkt_free(pkt);
return mod_HANDLED;
}
if(pkt->type == pkt_SESS_END) {
sm_c2s_action(sess, "ended", NULL);
sess_end(sess);
pkt_free(pkt);
return mod_HANDLED;
}
log_debug(ZONE, "unknown session packet, dropping");
pkt_free(pkt);
return mod_HANDLED;
}
attr = nad_find_attr(pkt->nad, 1, ns, "sm", NULL);
if(attr < 0) {
log_debug(ZONE, "no session id, bouncing");
nad_set_attr(pkt->nad, 1, ns, "failed", "1", 1);
sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0));
pkt->nad = NULL;
pkt_free(pkt);
return mod_HANDLED;
}
sess = xhash_getx(sm->sessions, NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr));
if(sess == NULL) {
log_debug(ZONE, "session %.*s doesn't exist, bouncing", NAD_AVAL_L(pkt->nad, attr), NAD_AVAL(pkt->nad, attr));
nad_set_attr(pkt->nad, 1, ns, "failed", "1", 1);
sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0));
pkt->nad = NULL;
pkt_free(pkt);
return mod_HANDLED;
}
attr = nad_find_attr(pkt->nad, 1, ns, "c2s", NULL);
if(attr >= 0 && (strlen(sess->c2s_id) != NAD_AVAL_L(pkt->nad, attr) || strncmp(sess->c2s_id, NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr)) != 0)) {
log_debug(ZONE, "invalid sender on route from %s for session %s (should be %s)", jid_full(pkt->rfrom), sess->sm_id, sess->c2s_id);
pkt_free(pkt);
return mod_HANDLED;
}
pkt->source = sess;
ret = mm_in_sess(pkt->sm->mm, sess, pkt);
switch(ret) {
case mod_HANDLED:
break;
case mod_PASS:
ret = -stanza_err_FEATURE_NOT_IMPLEMENTED;
default:
pkt_sess(pkt_error(pkt, -ret), sess);
break;
}
return mod_HANDLED;
}
static mod_ret_t _session_pkt_router(mod_instance_t mi, pkt_t pkt) {
sess_t sess;
union xhashv xhv;
if(pkt->from == NULL || !(pkt->rtype & route_ADV) || pkt->rtype != route_ADV_UN)
return mod_PASS;
log_debug(ZONE, "component '%s' went offline, checking for sessions held there", jid_full(pkt->from));
xhv.sess_val = &sess;
if(xhash_iter_first(mi->mod->mm->sm->sessions))
while (xhash_iter_get(mi->mod->mm->sm->sessions, NULL, xhv.val)) {
if(strcmp(sess->c2s, pkt->from->domain) == 0)
sess_end(sess);
else
xhash_iter_next(mi->mod->mm->sm->sessions);
}
return mod_PASS;
}
int session_init(mod_instance_t mi, char *arg) {
if(mi->mod->init) return 0;
mi->mod->in_router = _session_in_router;
mi->mod->pkt_router = _session_pkt_router;
return 0;
}