static void _router_time_checks(router_t r) { component_t target; time_t now; union xhashv xhv; now = time(NULL); /* loop the components and distribute an space on idle connections*/ if(xhash_iter_first(r->components)) do { xhv.comp_val = ⌖ xhash_iter_get(r->components, NULL, NULL, xhv.val); if(r->check_keepalive > 0 && target->last_activity > 0 && now > target->last_activity + r->check_keepalive && target->s->state >= state_STREAM) { log_debug(ZONE, "sending keepalive for %d", target->fd->fd); sx_raw_write(target->s, " ", 1); } } while(xhash_iter_next(r->components)); return; }
static void _c2s_time_checks(c2s_t c2s) { sess_t sess; time_t now; union xhashv xhv; now = time(NULL); if(xhash_iter_first(c2s->sessions)) do { xhv.sess_val = &sess; xhash_iter_get(c2s->sessions, NULL, NULL, xhv.val); if(!sess->s) continue; if(c2s->io_check_idle > 0 && now > sess->last_activity + c2s->io_check_idle) { log_write(c2s->log, LOG_NOTICE, "[%d] [%s, port=%d] timed out", sess->fd->fd, sess->ip, sess->port); sx_error(sess->s, stream_err_HOST_GONE, "connection timed out"); sx_close(sess->s); continue; } if(c2s->io_check_keepalive > 0 && now > sess->last_activity + c2s->io_check_keepalive && sess->s->state >= state_STREAM) { log_debug(ZONE, "sending keepalive for %d", sess->fd->fd); sx_raw_write(sess->s, " ", 1); } if(sess->rate != NULL && sess->rate->bad != 0 && rate_check(sess->rate) != 0) { /* read the pending bytes when rate limit is no longer in effect */ log_debug(ZONE, "reading throttled %d", sess->fd->fd); sess->s->want_read = 1; sx_can_read(sess->s); } } while(xhash_iter_next(c2s->sessions)); }
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; }