/** unregister a global ns */ void sm_unregister_ns(sm_t sm, const char *uri) { int refcount = (int) (long) xhash_get(sm->xmlns_refcount, uri); if (refcount == 1) { xhash_zap(sm->xmlns, uri); xhash_zap(sm->xmlns_refcount, uri); } else if (refcount > 1) { xhash_put(sm->xmlns_refcount, uri, (void *) ((long) xhash_get(sm->xmlns_refcount, uri) - 1)); } }
/* * get group's descriptive name by it's text id * returned value needs to be freed by caller */ static const char *_roster_publish_get_group_name(sm_t sm, roster_publish_t rp, const char *groupid) { os_t os; os_object_t o; char *str; char *group; #ifndef NO_SM_CACHE _roster_publish_group_cache_t group_cached; #endif if(!groupid) return groupid; #ifndef NO_SM_CACHE /* check for remembered group value in cache */ if( rp->group_cache_ttl ) { if( rp->group_cache ) { group_cached = xhash_get(rp->group_cache, groupid); if( group_cached != NULL ) { if( (time(NULL) - group_cached->time) >= rp->group_cache_ttl ) { log_debug(ZONE,"group cache: expiring cached value for %s",groupid); xhash_zap(rp->group_cache, groupid); free(group_cached); } else { log_debug(ZONE,"group cache: returning cached value for %s",groupid); return strdup(group_cached->groupname); } } } else { log_debug(ZONE,"group cache: creating cache"); rp->group_cache = xhash_new(401); } } #endif if(storage_get(sm->st, "published-roster-groups", groupid, NULL, &os) == st_SUCCESS && os_iter_first(os)) { o = os_iter_object(os); if( os_object_get_str(os, o, "groupname", &str) && str ) { group=strdup(str); } else { group=NULL; } os_free(os); #ifndef NO_SM_CACHE if( rp->group_cache_ttl && group ) { log_debug(ZONE,"group cache: updating cache value for %s",groupid); group_cached = calloc(1, sizeof(struct _roster_publish_group_cache_st)); group_cached->time = time(NULL); group_cached->groupid = strdup(groupid); group_cached->groupname = strdup(group); xhash_put(rp->group_cache, group_cached->groupid, group_cached); } #endif return group; } else { return NULL; } }
static void _router_process_unbind(component_t comp, nad_t nad) { int attr; jid_t name; attr = nad_find_attr(nad, 0, -1, "name", NULL); if(attr < 0 || (name = jid_new(NAD_AVAL(nad, attr), NAD_AVAL_L(nad, attr))) == NULL) { log_debug(ZONE, "no or invalid 'name' on unbind packet, bouncing"); nad_set_attr(nad, 0, -1, "error", "400", 3); sx_nad_write(comp->s, nad); return; } if(xhash_get(comp->routes, name->domain) == NULL) { log_write(comp->r->log, LOG_NOTICE, "[%s, port=%d] tried to unbind '%s', but it's not bound to this component", comp->ip, comp->port, name->domain); nad_set_attr(nad, 0, -1, "name", NULL, 0); nad_set_attr(nad, 0, -1, "error", "404", 3); sx_nad_write(comp->s, nad); jid_free(name); return; } xhash_zap(comp->r->log_sinks, name->domain); _route_remove(comp->r->routes, name->domain, comp); xhash_zap(comp->routes, name->domain); if(comp->r->default_route != NULL && strcmp(comp->r->default_route, name->domain) == 0) { log_write(comp->r->log, LOG_NOTICE, "[%s] default route offline", name->domain); free((void*)(comp->r->default_route)); comp->r->default_route = NULL; } log_write(comp->r->log, LOG_NOTICE, "[%s] offline", name->domain); nad_set_attr(nad, 0, -1, "name", NULL, 0); sx_nad_write(comp->s, nad); /* deadvertise name */ if(xhash_get(comp->r->routes, name->domain) == NULL) _router_advertise(comp->r, name->domain, comp, 1); jid_free(name); }
/** unregister feature */ void feature_unregister(sm_t sm, const char *feature) { int refcount = (int) (long) xhash_get(sm->features, feature); log_debug(ZONE, "unregistering feature %s", feature); if (refcount == 1) { xhash_zap(sm->features, feature); } else if (refcount > 1) { xhash_put(sm->features, feature, (void *) ((long) refcount - 1)); } }
int at_register_iqns(ati ti, const char *ns, iqcb cb) { iqcb cur; log_debug(ZONE, "Registering callback for %s", ns); cur = xhash_get(ti->iq__callbacks, ns); if(cur) { xhash_zap(ti->iq__callbacks, ns); } xhash_put(ti->iq__callbacks, ns, cb); return; }
void dnsrv_process_xstream_io(int type, xmlnode x, void* arg) { dns_io di = (dns_io)arg; char* hostname = NULL; char* ipaddr = NULL; char* resendhost = NULL; dns_packet_list head = NULL; dns_packet_list heado = NULL; /* Node Format: <host ip="201.83.28.2">foo.org</host> */ if (type == XSTREAM_NODE) { log_debug(ZONE,"incoming resolution: %s",xmlnode2str(x)); hostname = xmlnode_get_data(x); /* whatever the response was, let's cache it */ xmlnode_free((xmlnode)xhash_get(di->cache_table,hostname)); /* free any old cache, shouldn't ever be any */ xmlnode_put_vattrib(x,"t",(void*)time(NULL)); xhash_put(di->cache_table,hostname,(void*)x); /* Get the hostname and look it up in the hashtable */ head = xhash_get(di->packet_table, hostname); /* Process the packet list */ if (head != NULL) { ipaddr = xmlnode_get_attrib(x, "ip"); resendhost = xmlnode_get_attrib(x, "to"); /* Remove the list from the hashtable */ xhash_zap(di->packet_table, hostname); /* Walk the list and insert IPs */ while(head != NULL) { heado = head; /* Move to next.. */ head = head->next; /* Deliver the packet */ dnsrv_resend(heado->packet->x, ipaddr, resendhost); } } /* Host name was not found, something is _TERRIBLY_ wrong! */ else log_debug(ZONE, "Resolved unknown host/ip request: %s\n", xmlnode2str(x)); return; /* we cached x above, so we don't free it below :) */ } xmlnode_free(x); }
result dnsrv_deliver(instance i, dpacket p, void* args) { dns_io di = (dns_io)args; xmlnode c; int timeout = di->cache_timeout; char *ip; jid to; /* if we get a route packet, it has to be to *us* and have the child as the real packet */ if(p->type == p_ROUTE) { if(j_strcmp(p->host,i->id) != 0 || (to = jid_new(p->p,xmlnode_get_attrib(xmlnode_get_firstchild(p->x),"to"))) == NULL) return r_ERR; p->x=xmlnode_get_firstchild(p->x); p->id = to; p->host = to->server; } /* Ensure this packet doesn't already have an IP */ if(xmlnode_get_attrib(p->x, "ip") || xmlnode_get_attrib(p->x, "iperror")) { log_notice(p->host, "dropping looping dns lookup request: %s", xmlnode2str(p->x)); xmlnode_free(p->x); return r_DONE; } /* try the cache first */ if((c = xhash_get(di->cache_table, p->host)) != NULL) { /* if there's no IP, cached failed lookup, time those out 10 times faster! (weird, I know, *shrug*) */ if((ip = xmlnode_get_attrib(c,"ip")) == NULL) timeout = timeout / 10; if((time(NULL) - (int)xmlnode_get_vattrib(c,"t")) > timeout) { /* timed out of the cache, lookup again */ xmlnode_free(c); xhash_zap(di->cache_table,p->host); }else{ /* yay, send back right from the cache */ dnsrv_resend(p->x, ip, xmlnode_get_attrib(c,"to")); return r_DONE; } } dnsrv_lookup(di, p); return r_DONE; }
static void _route_remove(xht hroutes, const char *name, component_t comp) { routes_t routes; int i; routes = xhash_get(hroutes, name); if(routes == NULL) return; if(routes->ncomp > 1) { for(i = 0; i < routes->ncomp; i++) { if(routes->comp[i] == comp) { if(i != routes->ncomp - 1) { routes->comp[i] = routes->comp[routes->ncomp - 1]; } routes->ncomp--; } } } else { jqueue_push(comp->r->deadroutes, (void *) routes, 0); xhash_zap(hroutes, name); } }
static void _sess_end_guts(sess_t sess) { sess_t scan; /* fake an unavailable presence from this session, so that modules and externals know we're gone */ if(sess->available || sess->A != NULL) mm_in_sess(sess->user->sm->mm, sess, pkt_create(sess->user->sm, "presence", "unavailable", NULL, NULL)); /* inform the modules */ mm_sess_end(sess->user->sm->mm, sess); /* unlink it from this users sessions */ if(sess->user->sessions == sess) sess->user->sessions = sess->next; else { for(scan = sess->user->sessions; scan != NULL && scan->next != sess; scan = scan->next); if(scan != NULL) scan->next = sess->next; } /* and from global sessions */ xhash_zap(sess->user->sm->sessions, sess->sm_id); }
/* callback for walking the connecting hash tree */ void _dnsrv_beat_packets(xht h, const char *key, void *data, void *arg) { dns_io di = (dns_io)arg; dns_packet_list n, l = (dns_packet_list)data; int now = time(NULL); int reap = 0; /* first, check the head */ if((now - l->stamp) > di->packet_timeout) { log_notice(l->packet->host,"timed out from dnsrv queue"); xhash_zap(di->packet_table,l->packet->host); reap = 1; }else{ while(l->next != NULL) { if((now - l->next->stamp) > di->packet_timeout) { reap = 1; n = l->next; l->next = NULL; /* chop off packets to be killed */ l = n; break; } l = l->next; } } if(reap == 0) return; /* time out individual queue'd packets */ while(l != NULL) { n = l->next; deliver_fail(l->packet,"Hostname Resolution Timeout"); l = n; } }
void nad_free(nad_t nad) { if(nad == NULL) return; #ifdef NAD_DEBUG _nad_ptr_check(__func__, nad); { char loc[24]; snprintf(loc, sizeof(loc), "%x", (int) nad); xhash_zap(_nad_alloc_tracked, loc); xhash_put(_nad_free_tracked, pstrdup(xhash_pool(_nad_free_tracked), loc), (void *) nad); } #endif /* Free nad */ free(nad->elems); free(nad->attrs); free(nad->cdata); free(nad->nss); free(nad->depths); #ifndef NAD_DEBUG free(nad); #endif }
int router_mio_callback(mio_t m, mio_action_t a, mio_fd_t fd, void *data, void *arg) { component_t comp = (component_t) arg; router_t r = (router_t) arg; struct sockaddr_storage sa; socklen_t namelen = sizeof(sa); int port, nbytes; switch(a) { case action_READ: log_debug(ZONE, "read action on fd %d", fd->fd); /* they did something */ comp->last_activity = time(NULL); ioctl(fd->fd, FIONREAD, &nbytes); if(nbytes == 0) { sx_kill(comp->s); return 0; } return sx_can_read(comp->s); case action_WRITE: log_debug(ZONE, "write action on fd %d", fd->fd); /* update activity timestamp */ comp->last_activity = time(NULL); return sx_can_write(comp->s); case action_CLOSE: log_debug(ZONE, "close action on fd %d", fd->fd); r = comp->r; log_write(r->log, LOG_NOTICE, "[%s, port=%d] disconnect", comp->ip, comp->port); /* unbind names */ xhash_walk(comp->routes, _router_route_unbind_walker, (void *) comp); /* deregister component */ xhash_zap(r->components, comp->ipport); xhash_free(comp->routes); if(comp->tq != NULL) /* !!! bounce packets */ jqueue_free(comp->tq); rate_free(comp->rate); jqueue_push(comp->r->dead, (void *) comp->s, 0); free(comp); break; case action_ACCEPT: log_debug(ZONE, "accept action on fd %d", fd->fd); getpeername(fd->fd, (struct sockaddr *) &sa, &namelen); port = j_inet_getport(&sa); log_write(r->log, LOG_NOTICE, "[%s, port=%d] connect", (char *) data, port); if(_router_accept_check(r, fd, (char *) data) != 0) return 1; comp = (component_t) calloc(1, sizeof(struct component_st)); comp->r = r; comp->fd = fd; snprintf(comp->ip, INET6_ADDRSTRLEN, "%s", (char *) data); comp->port = port; snprintf(comp->ipport, INET6_ADDRSTRLEN + 6, "%s:%d", comp->ip, comp->port); comp->s = sx_new(r->sx_env, fd->fd, _router_sx_callback, (void *) comp); mio_app(m, fd, router_mio_callback, (void *) comp); if(r->byte_rate_total != 0) comp->rate = rate_new(r->byte_rate_total, r->byte_rate_seconds, r->byte_rate_wait); comp->routes = xhash_new(51); /* register component */ log_debug(ZONE, "new component (%p) \"%s\"", comp, comp->ipport); xhash_put(r->components, comp->ipport, (void *) comp); #ifdef HAVE_SSL sx_server_init(comp->s, SX_SSL_STARTTLS_OFFER | SX_SASL_OFFER); #else sx_server_init(comp->s, SX_SASL_OFFER); #endif break; } return 0; }
int in_mio_callback(mio_t m, mio_action_t a, mio_fd_t fd, void *data, void *arg) { conn_t in = (conn_t) arg; s2s_t s2s = (s2s_t) arg; struct sockaddr_storage sa; int namelen = sizeof(sa), port, nbytes; char ipport[INET6_ADDRSTRLEN + 17]; switch(a) { case action_READ: log_debug(ZONE, "read action on fd %d", fd->fd); ioctl(fd->fd, FIONREAD, &nbytes); if(nbytes == 0) { sx_kill(in->s); return 0; } return sx_can_read(in->s); case action_WRITE: log_debug(ZONE, "write action on fd %d", fd->fd); return sx_can_write(in->s); case action_CLOSE: log_debug(ZONE, "close action on fd %d", fd->fd); /* !!! logging */ log_write(in->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] disconnect, packets: %i", fd->fd, in->ip, in->port, in->packet_count); jqueue_push(in->s2s->dead, (void *) in->s, 0); /* remove from open streams hash if online, or open connections if not */ if (in->online) xhash_zap(in->s2s->in, in->key); else { snprintf(ipport, INET6_ADDRSTRLEN + 16, "%s/%d", in->ip, in->port); xhash_zap(in->s2s->in_accept, ipport); } jqueue_push(in->s2s->dead_conn, (void *) in, 0); break; case action_ACCEPT: s2s = (s2s_t) arg; log_debug(ZONE, "accept action on fd %d", fd->fd); getpeername(fd->fd, (struct sockaddr *) &sa, &namelen); port = j_inet_getport(&sa); log_write(s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] incoming connection", fd->fd, (char *) data, port); /* new conn */ in = (conn_t) calloc(1, sizeof(struct conn_st)); in->s2s = s2s; strncpy(in->ip, (char *) data, INET6_ADDRSTRLEN); in->port = port; in->states = xhash_new(101); in->states_time = xhash_new(101); in->fd = fd; in->init_time = time(NULL); in->s = sx_new(s2s->sx_env, in->fd->fd, _in_sx_callback, (void *) in); mio_app(m, in->fd, in_mio_callback, (void *) in); if(s2s->stanza_size_limit != 0) in->s->rbytesmax = s2s->stanza_size_limit; /* add to incoming connections hash */ snprintf(ipport, INET6_ADDRSTRLEN + 16, "%s/%d", in->ip, in->port); xhash_put(s2s->in_accept, pstrdup(xhash_pool(s2s->in_accept),ipport), (void *) in); #ifdef HAVE_SSL sx_server_init(in->s, S2S_DB_HEADER | ((s2s->sx_ssl != NULL) ? SX_SSL_STARTTLS_OFFER : 0) ); #else sx_server_init(in->s, S2S_DB_HEADER); #endif break; } return 0; }
static int _in_sx_callback(sx_t s, sx_event_t e, void *data, void *arg) { conn_t in = (conn_t) arg; sx_buf_t buf = (sx_buf_t) data; int len; sx_error_t *sxe; nad_t nad; char ipport[INET6_ADDRSTRLEN + 17]; switch(e) { case event_WANT_READ: log_debug(ZONE, "want read"); mio_read(in->s2s->mio, in->fd); break; case event_WANT_WRITE: log_debug(ZONE, "want write"); mio_write(in->s2s->mio, in->fd); break; case event_READ: log_debug(ZONE, "reading from %d", in->fd->fd); /* do the read */ len = recv(in->fd->fd, buf->data, buf->len, 0); if(len < 0) { if(MIO_WOULDBLOCK) { buf->len = 0; return 0; } log_write(in->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] read error: %s (%d)", in->fd->fd, in->ip, in->port, MIO_STRERROR(MIO_ERROR), MIO_ERROR); sx_kill(s); return -1; } else if(len == 0) { /* they went away */ sx_kill(s); return -1; } log_debug(ZONE, "read %d bytes", len); buf->len = len; return len; case event_WRITE: log_debug(ZONE, "writing to %d", in->fd->fd); len = send(in->fd->fd, buf->data, buf->len, 0); if(len >= 0) { log_debug(ZONE, "%d bytes written", len); return len; } if(MIO_WOULDBLOCK) return 0; log_write(in->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] write error: %s (%d)", in->fd->fd, in->ip, in->port, MIO_STRERROR(MIO_ERROR), MIO_ERROR); sx_kill(s); return -1; case event_ERROR: sxe = (sx_error_t *) data; log_write(in->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] error: %s (%s)", in->fd->fd, in->ip, in->port, sxe->generic, sxe->specific); break; case event_STREAM: case event_OPEN: log_debug(ZONE, "STREAM or OPEN event from %s port %d (id %s)", in->ip, in->port, s->id); /* first time, bring them online */ if ((!in->online)||(strcmp(in->key,s->id)!=0)) { log_write(in->s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] incoming stream online (id %s)", in->fd->fd, in->ip, in->port, s->id); in->online = 1; /* record the id */ if (in->key != NULL) { log_debug(ZONE,"adding new SSL stream id %s for stream id %s", s->id, in->key); /* remove the initial (non-SSL) stream id from the in connections hash */ xhash_zap(in->s2s->in, in->key); free(in->key); } in->key = strdup(s->id); /* track it - add to open streams hash and remove from new connections hash */ xhash_put(in->s2s->in, in->key, (void *) in); snprintf(ipport, INET6_ADDRSTRLEN + 16, "%s/%d", in->ip, in->port); xhash_zap(in->s2s->in_accept, ipport); } break; case event_PACKET: /* we're counting packets */ in->packet_count++; in->s2s->packet_count++; nad = (nad_t) data; /* update last packet timestamp */ in->last_packet = time(NULL); /* dialback packets */ if(NAD_NURI_L(nad, NAD_ENS(nad, 0)) == strlen(uri_DIALBACK) && strncmp(uri_DIALBACK, NAD_NURI(nad, NAD_ENS(nad, 0)), strlen(uri_DIALBACK)) == 0) { /* only result and verify mean anything */ if(NAD_ENAME_L(nad, 0) == 6) { if(strncmp("result", NAD_ENAME(nad, 0), 6) == 0) { _in_result(in, nad); return 0; } if(strncmp("verify", NAD_ENAME(nad, 0), 6) == 0) { _in_verify(in, nad); return 0; } } log_debug(ZONE, "unknown dialback packet, dropping it"); nad_free(nad); return 0; } /* * not dialback, so it has to be a normal-ish jabber packet: * - jabber:client or jabber:server * - message, presence or iq * - has to and from attributes */ if(!( /* must be jabber:client or jabber:server */ NAD_ENS(nad, 0) >= 0 && ((NAD_NURI_L(nad, NAD_ENS(nad, 0)) == strlen(uri_CLIENT) && strncmp(uri_CLIENT, NAD_NURI(nad, NAD_ENS(nad, 0)), strlen(uri_CLIENT)) == 0) || (NAD_NURI_L(nad, NAD_ENS(nad, 0)) == strlen(uri_SERVER) && strncmp(uri_SERVER, NAD_NURI(nad, NAD_ENS(nad, 0)), strlen(uri_SERVER)) == 0)) && ( /* can be message */ (NAD_ENAME_L(nad, 0) == 7 && strncmp("message", NAD_ENAME(nad, 0), 7) == 0) || /* or presence */ (NAD_ENAME_L(nad, 0) == 8 && strncmp("presence", NAD_ENAME(nad, 0), 8) == 0) || /* or iq */ (NAD_ENAME_L(nad, 0) == 2 && strncmp("iq", NAD_ENAME(nad, 0), 2) == 0) ) && /* to and from required */ nad_find_attr(nad, 0, -1, "to", NULL) >= 0 && nad_find_attr(nad, 0, -1, "from", NULL) >= 0 )) { log_debug(ZONE, "they sent us a non-jabber looking packet, dropping it"); nad_free(nad); return 0; } _in_packet(in, nad); return 0; case event_CLOSED: mio_close(in->s2s->mio, in->fd); return -1; } return 0; }
/** * process commandline * @return: 0 to indicate that output needs to be written */ int _pbx_process_command(c2s_t c2s, char *cmd) { jid_t jid; int action = 0, len; sess_t sess; unsigned char hashbuf[44] = "PBX"; unsigned char *sesshash; sesshash = hashbuf+3; /* get command */ if(!strncasecmp("START ", cmd, 6)) { cmd += 6; action = 1; } if(!strncasecmp("STOP ", cmd, 5)) { cmd += 5; action = 2; } if(action != 0) { len = _pbx_command_part_len(cmd); if(len > 0) { jid = jid_new(cmd, len); if(jid) { cmd += len; if(*cmd != '\0') cmd++; shahash_r(jid_full(jid), sesshash); sess = xhash_get(c2s->sessions, hashbuf); switch(action) { case 1: log_debug(ZONE, "STARTing session for %s/%s (%s) with commandline: %s", jid_user(jid), jid->resource, hashbuf, cmd); if(sess == NULL) { /* create new session */ sess = (sess_t) calloc(1, sizeof(struct sess_st)); sess->c2s = c2s; sess->last_activity = time(NULL); /* put into sessions hash */ snprintf(sess->skey, sizeof(sess->skey), "%s", hashbuf); xhash_put(c2s->sessions, sess->skey, (void *) sess); /* generate bound resource */ sess->resources = (bres_t) calloc(1, sizeof(struct bres_st)); snprintf(sess->resources->c2s_id, sizeof(sess->resources->c2s_id), "%s", hashbuf); sess->resources->jid = jid; /* open SM session */ log_write(sess->c2s->log, LOG_NOTICE, "[PBX] requesting session: jid=%s", jid_full(jid)); sm_start(sess, sess->resources); /* generate presence packet to get session online */ /* a bit hacky, but we need to emulate _some_ of the client behavior */ sess->result = _pbx_presence_nad(1, cmd); } else { /* just send the presence */ sm_packet(sess, sess->resources, _pbx_presence_nad(1, cmd)); } break; case 2: log_debug(ZONE, "STOPping session for %s/%s with commandline: %s", jid_user(jid), jid->resource, cmd); if(sess != NULL) { /* send unavailable presence */ sm_packet(sess, sess->resources, _pbx_presence_nad(0, cmd)); /* end the session */ sm_end(sess, sess->resources); xhash_zap(c2s->sessions, sess->skey); jqueue_push(c2s->dead_sess, (void *) sess, 0); } break; } /* TODO: respond with "OK", return 0 */ return -1; } } /* TODO: generate "ERR" response, return 0 */ return -1; } if(!strncasecmp("STATUS", cmd, 6)) { log_write(c2s->log, LOG_INFO, "STATUS PBX command not implemented yet"); return -1; } return -1; }
void user_free(user_t user) { log_debug(ZONE, "freeing user %s", jid_user(user->jid)); xhash_zap(user->sm->users, jid_user(user->jid)); pool_free(user->p); }
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; }