Exemple #1
0
int _s2s_check_conn_routes(s2s_t s2s, conn_t conn, const char *direction)
{
  char *rkey;
  int rkeylen;
  conn_state_t state;
  time_t now, dialback_time;

  now = time(NULL);

  if(xhash_iter_first(conn->states))
     do {
           /* retrieve state in a separate operation, as sizeof(int) != sizeof(void *) on 64-bit platforms,
              so passing a pointer to state in xhash_iter_get is unsafe */
           xhash_iter_get(conn->states, (const char **) &rkey, &rkeylen, NULL);
           state = (conn_state_t) xhash_getx(conn->states, rkey, rkeylen);

           if (state == conn_INPROGRESS) {
              dialback_time = (time_t) xhash_getx(conn->states_time, rkey, rkeylen);

              if(now > dialback_time + s2s->check_queue) {
                 log_write(s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] dialback for %s route '%.*s' timed out", conn->fd->fd, conn->ip, conn->port, direction, rkeylen, rkey);

                 xhash_zapx(conn->states, rkey, rkeylen);
                 xhash_zapx(conn->states_time, rkey, rkeylen);

                 /* stream error */
                 sx_error(conn->s, stream_err_CONNECTION_TIMEOUT, "dialback timed out");

                 /* close connection as per XMPP/RFC3920 */
                 sx_close(conn->s);

                 /* indicate that we closed the connection */
                 return 0;
              }
           }
     } while(xhash_iter_next(conn->states));

  /* all ok */
  return 1;
}
Exemple #2
0
static void _router_route_unbind_walker(const char *key, int keylen, void *val, void *arg) {
    component_t comp = (component_t) arg;

    char * local_key;
    xhash_zapx(comp->r->log_sinks, key, keylen);
    local_key = (char *) malloc(keylen + 1);
    memcpy(local_key, key, keylen);
    local_key[keylen] = 0;
    _route_remove(comp->r->routes, local_key, comp);
    xhash_zapx(comp->routes, key, keylen);

    if(comp->r->default_route != NULL && strlen(comp->r->default_route) == keylen && strncmp(key, comp->r->default_route, keylen) == 0) {
        log_write(comp->r->log, LOG_NOTICE, "[%.*s] default route offline", keylen, key);
        free((void*)(comp->r->default_route));
        comp->r->default_route = NULL;
    }

    log_write(comp->r->log, LOG_NOTICE, "[%.*s] offline", keylen, key);

    /* deadvertise name */
    if(xhash_getx(comp->r->routes, key, keylen) == NULL)
        _router_advertise(comp->r, local_key, comp, 1);
    free(local_key);
}
Exemple #3
0
static void _s2s_time_checks(s2s_t s2s) {
    conn_t conn;
    time_t now;
    char *rkey, *key;
    int keylen;
    jqueue_t q;
    dnscache_t dns;
    char *c;
    int c_len;
    union xhashv xhv;

    now = time(NULL);

    /* queue expiry */
    if(s2s->check_queue > 0) {
        if(xhash_iter_first(s2s->outq))
            do {
                xhv.jq_val = &q;
                xhash_iter_get(s2s->outq, (const char **) &rkey, &keylen, xhv.val);

                log_debug(ZONE, "running time checks for %.*s", keylen, rkey);
                c = memchr(rkey, '/', keylen);
                c++;
                c_len = keylen - (c - rkey);

                /* dns lookup timeout check first */
                dns = xhash_getx(s2s->dnscache, c, c_len);
                if(dns != NULL && dns->pending) {
                    log_debug(ZONE, "dns lookup pending for %.*s", c_len, c);
                    if(now > dns->init_time + s2s->check_queue) {
                        log_write(s2s->log, LOG_NOTICE, "dns lookup for %.*s timed out", c_len, c);

                        /* bounce queue */
                        out_bounce_route_queue(s2s, rkey, keylen, stanza_err_REMOTE_SERVER_NOT_FOUND);

                        /* expire pending dns entry */
                        xhash_zap(s2s->dnscache, dns->name);
                        xhash_free(dns->results);
                        if (dns->query != NULL) {
                            if (dns->query->query != NULL)
                                dns_cancel(NULL, dns->query->query);
                            xhash_free(dns->query->hosts);
                            xhash_free(dns->query->results);
                            free(dns->query->name);
                            free(dns->query);
                        }
                        free(dns);
                    }

                    continue;
                }

                /* get the conn */
                conn = xhash_getx(s2s->out_dest, c, c_len);
                if(conn == NULL) {
                    if(jqueue_size(q) > 0) {
                       /* no pending conn? perhaps it failed? */
                       log_debug(ZONE, "no pending connection for %.*s, bouncing %i packets in queue", c_len, c, jqueue_size(q));

                       /* bounce queue */
                       out_bounce_route_queue(s2s, rkey, keylen, stanza_err_REMOTE_SERVER_TIMEOUT);
                    }

                    continue;
                }

                /* connect timeout check */
                if(!conn->online && now > conn->init_time + s2s->check_queue) {
                    dnsres_t bad;
                    char *ipport;

                    log_write(s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] connection to %s timed out", conn->fd->fd, conn->ip, conn->port, c);

                    if (s2s->dns_bad_timeout > 0) {
                        /* mark this host as bad */
                        ipport = dns_make_ipport(conn->ip, conn->port);
                        bad = xhash_get(s2s->dns_bad, ipport);
                        if (bad == NULL) {
                            bad = (dnsres_t) calloc(1, sizeof(struct dnsres_st));
                            bad->key = ipport;
                            xhash_put(s2s->dns_bad, ipport, bad);
                        } else {
                            free(ipport);
                        }
                        bad->expiry = time(NULL) + s2s->dns_bad_timeout;
                    }

                    /* close connection as per XMPP/RFC3920 */
                    /* the close function will retry or bounce the queue */
                    sx_close(conn->s);
                }
            } while(xhash_iter_next(s2s->outq));
    }

    /* expiry of connected routes in conn_INPROGRESS state */
    if(s2s->check_queue > 0) {

        /* outgoing connections */
        if(s2s->out_reuse) {
            if(xhash_iter_first(s2s->out_host))
                do {
                    xhv.conn_val = &conn;
                    xhash_iter_get(s2s->out_host, (const char **) &key, &keylen, xhv.val);
                    log_debug(ZONE, "checking dialback state for outgoing conn %.*s", keylen, key);
                    if (_s2s_check_conn_routes(s2s, conn, "outgoing")) {
                        log_debug(ZONE, "checking pending verify requests for outgoing conn %.*s", keylen, key);
                        if (conn->verify > 0 && now > conn->last_verify + s2s->check_queue) {
                            log_write(s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] dialback verify request timed out", conn->fd->fd, conn->ip, conn->port);
                            sx_error(conn->s, stream_err_CONNECTION_TIMEOUT, "dialback verify request timed out");
                            sx_close(conn->s);
                        }
                    }
                } while(xhash_iter_next(s2s->out_host));
        } else {
            if(xhash_iter_first(s2s->out_dest))
                do {
                    xhv.conn_val = &conn;
                    xhash_iter_get(s2s->out_dest, (const char **) &key, &keylen, xhv.val);
                    log_debug(ZONE, "checking dialback state for outgoing conn %s (%s)", conn->dkey, conn->key);
                    if (_s2s_check_conn_routes(s2s, conn, "outgoing")) {
                        log_debug(ZONE, "checking pending verify requests for outgoing conn %s (%s)", conn->dkey, conn->key);
                        if (conn->verify > 0 && now > conn->last_verify + s2s->check_queue) {
                            log_write(s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] dialback verify request timed out", conn->fd->fd, conn->ip, conn->port);
                            sx_error(conn->s, stream_err_CONNECTION_TIMEOUT, "dialback verify request timed out");
                            sx_close(conn->s);
                        }
                    }
                } while(xhash_iter_next(s2s->out_dest));
        }

        /* incoming open streams */
        if(xhash_iter_first(s2s->in))
            do {
                xhv.conn_val = &conn;
                xhash_iter_get(s2s->in, (const char **) &key, &keylen, xhv.val);

                log_debug(ZONE, "checking dialback state for incoming conn %.*s", keylen, key);
                if (_s2s_check_conn_routes(s2s, conn, "incoming"))
                    /* if the connection is still valid, check that dialbacks have been initiated */
                    if(!xhash_count(conn->states) && now > conn->init_time + s2s->check_queue) {
                        log_write(s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] no dialback started", conn->fd->fd, conn->ip, conn->port);
                        sx_error(conn->s, stream_err_CONNECTION_TIMEOUT, "no dialback initiated");
                        sx_close(conn->s);
                    }
            } while(xhash_iter_next(s2s->in));

        /* incoming open connections (not yet streams) */
        if(xhash_iter_first(s2s->in_accept))
            do {
                xhv.conn_val = &conn;
                xhash_iter_get(s2s->in_accept, (const char **) &key, &keylen, xhv.val);

                log_debug(ZONE, "checking stream connection state for incoming conn %i", conn->fd->fd);
                if(!conn->online && now > conn->init_time + s2s->check_queue) {
                    log_write(s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] stream initiation timed out", conn->fd->fd, conn->ip, conn->port);
                    sx_close(conn->s);
                }
            } while(xhash_iter_next(s2s->in_accept));

    }

    /* keepalives */
    if(s2s->out_reuse) {
        if(xhash_iter_first(s2s->out_host))
            do {
                xhv.conn_val = &conn;
                xhash_iter_get(s2s->out_host, NULL, NULL, xhv.val);

                if(s2s->check_keepalive > 0 && conn->last_activity > 0 && now > conn->last_activity + s2s->check_keepalive && conn->s->state >= state_STREAM) {
                    log_debug(ZONE, "sending keepalive for %d", conn->fd->fd);

                    sx_raw_write(conn->s, " ", 1);
                }
            } while(xhash_iter_next(s2s->out_host));
    } else {
        if(xhash_iter_first(s2s->out_dest))
            do {
                xhv.conn_val = &conn;
                xhash_iter_get(s2s->out_dest, NULL, NULL, xhv.val);

                if(s2s->check_keepalive > 0 && conn->last_activity > 0 && now > conn->last_activity + s2s->check_keepalive && conn->s->state >= state_STREAM) {
                    log_debug(ZONE, "sending keepalive for %d", conn->fd->fd);

                    sx_raw_write(conn->s, " ", 1);
                }
            } while(xhash_iter_next(s2s->out_dest));
    }

    /* idle timeouts - disconnect connections through which no packets have been sent for <idle> seconds */
    if(s2s->check_idle > 0) {

        /* outgoing connections */
        if(s2s->out_reuse) {
            if(xhash_iter_first(s2s->out_host))
                do {
                    xhv.conn_val = &conn;
                    xhash_iter_get(s2s->out_host, (const char **) &key, &keylen, xhv.val);
                    log_debug(ZONE, "checking idle state for %.*s", keylen, key);
                    if (conn->last_packet > 0 && now > conn->last_packet + s2s->check_idle && conn->s->state >= state_STREAM) {
                        log_write(s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] idle timeout", conn->fd->fd, conn->ip, conn->port);
                        sx_close(conn->s);
                    }
                } while(xhash_iter_next(s2s->out_host));
        } else {
            if(xhash_iter_first(s2s->out_dest))
                do {
                    xhv.conn_val = &conn;
                    xhash_iter_get(s2s->out_dest, (const char **) &key, &keylen, xhv.val);
                    log_debug(ZONE, "checking idle state for %s (%s)", conn->dkey, conn->key);
                    if (conn->last_packet > 0 && now > conn->last_packet + s2s->check_idle && conn->s->state >= state_STREAM) {
                        log_write(s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] idle timeout", conn->fd->fd, conn->ip, conn->port);
                        sx_close(conn->s);
                    }
                } while(xhash_iter_next(s2s->out_dest));
        }

        /* incoming connections */
        if(xhash_iter_first(s2s->in))
            do {
                xhv.conn_val = &conn;
                xhash_iter_get(s2s->in, (const char **) &key, &keylen, xhv.val);
                log_debug(ZONE, "checking idle state for %.*s", keylen, key);
                if (conn->last_packet > 0 && now > conn->last_packet + s2s->check_idle && conn->s->state >= state_STREAM) {
                    log_write(s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] idle timeout", conn->fd->fd, conn->ip, conn->port);
                    sx_close(conn->s);
                }
            } while(xhash_iter_next(s2s->in));

    }

    return;
}
Exemple #4
0
void *xhash_get(xht h, const char *key)
{
    if(h == NULL || key == NULL) return NULL;
    return xhash_getx(h,key,strlen(key));
}
Exemple #5
0
static mod_ret_t _session_in_router(mod_instance_t mi, pkt_t pkt) {
    sm_t sm = mi->mod->mm->sm;
    int ns, iq, elem, attr;
    jid_t jid;
    sess_t sess = (sess_t) NULL;
    mod_ret_t ret;

    /* if we've got this namespace, its from a c2s */
    if(pkt->nad->ecur <= 1 || (ns = nad_find_namespace(pkt->nad, 1, uri_SESSION, NULL)) < 0)
        return mod_PASS;

    /* don't bother if its a failure */
    if(pkt->type & pkt_SESS_FAILED) {
        /* !!! check failed=1, handle */
        pkt_free(pkt);
        return mod_HANDLED;
    }

    /* session commands */
    if(pkt->type & pkt_SESS) {

        ns = nad_find_namespace(pkt->nad, 1, uri_SESSION, NULL);

        /* only end can get away without a target */
        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;
        }

        /* session start */
        if(pkt->type == pkt_SESS) {
            jid = jid_new(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;
            }

            /* c2s component that is handling this session */
            strcpy(sess->c2s, pkt->rfrom->domain);

            /* remember what c2s calls us */
            attr = nad_find_attr(pkt->nad, 1, ns, "c2s", NULL);
            snprintf(sess->c2s_id, sizeof(sess->c2s_id), "%.*s", NAD_AVAL_L(pkt->nad, attr), NAD_AVAL(pkt->nad, attr));

            /* mark PBX session as fake */
            if(!strncmp("PBX", sess->c2s_id, 3)) {
                sess->fake = 1;
            }

            /* add our id */
            nad_set_attr(pkt->nad, 1, ns, "sm", sess->sm_id, 0);

            /* mark that it started OK */
            nad_set_attr(pkt->nad, 1, -1, "action", "started", 7);

			/* set this SM name */
			nad_set_attr(pkt->nad, 0, -1, "to", sm->id, 0);

			/* inform c2s */
            sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0));

            pkt->nad = NULL;
            pkt_free(pkt);
            jid_free(jid);

            return mod_HANDLED;
        }

        /* user create */
        if(pkt->type == pkt_SESS_CREATE) {
            jid = jid_new(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;
            }

            /* inform c2s */
            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;
        }

        /* user delete */
        if(pkt->type == pkt_SESS_DELETE) {
            jid = jid_new(NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr));
            if(jid == NULL) {
                pkt_free(pkt);
                return mod_HANDLED;
            }

            user_delete(sm, jid);

            /* inform c2s */
            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;
        }

        /* get the session id */
        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;
        }

        /* find the corresponding session */
        sess = xhash_getx(sm->sessions, NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr));

        /* active check */
        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;
        }

        /* make sure its from them */
        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;
        }

        /* session end */
        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;
    }

    /* otherwise, its a normal packet for the session */

/* #ifdef ENABLE_SUPERSEDED       // FIXME XXX TODO clients are not yet ready for this */
        /* check for RFC3920 session request *
         * with RFC3920bis it is unneeded *
         * session is activated by bind, so we just return back result */
        if((ns = nad_find_scoped_namespace(pkt->nad, uri_XSESSION, NULL)) >= 0 &&
           (iq = nad_find_elem(pkt->nad, 0, -1, "iq", 1)) >= 0 &&
           (elem = nad_find_elem(pkt->nad, iq, ns, "session", 1)) >= 0) {
            log_debug(ZONE, "session create request");
    
            /* build a result packet */
            nad_drop_elem(pkt->nad, elem);
            nad_set_attr(pkt->nad, iq, -1, "type", "result", 6);
    
            /* return the result */
            sx_nad_write(sm->router, stanza_tofrom(pkt->nad, 0));
    
            pkt->nad = NULL;
            pkt_free(pkt);
    
            return mod_HANDLED;
        }
/* #endif */
    /* get the session id */
    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;
    }

    /* find the corresponding session */
    sess = xhash_getx(sm->sessions, NAD_AVAL(pkt->nad, attr), NAD_AVAL_L(pkt->nad, attr));

    /* active check */
    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;
    }

    /* make sure its from them */
    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;
    }

    /* where it came from */
    pkt->source = sess;

    /* hand it to the modules */
    ret = mm_in_sess(pkt->sm->mm, sess, pkt);
    switch(ret) {
        case mod_HANDLED:
            break;

        case mod_PASS:
            /* ignore IQ result packets that haven't been handled - XMPP 9.2.3.4 */
            if(pkt->type == pkt_IQ_RESULT)
               break;
            else
               ret = -stanza_err_FEATURE_NOT_IMPLEMENTED;

        default:
            pkt_sess(pkt_error(pkt, -ret), sess);

            break;
    }

    return mod_HANDLED;
}