jabberd2  2.2.16
s2s/main.c
Go to the documentation of this file.
00001 /*
00002  * jabberd - Jabber Open Source Server
00003  * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney,
00004  *                    Ryan Eatmon, Robert Norris
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA
00019  */
00020 
00021 #include "s2s.h"
00022 
00023 #include <stringprep.h>
00024 
00025 static sig_atomic_t s2s_shutdown = 0;
00026 sig_atomic_t s2s_lost_router = 0;
00027 static sig_atomic_t s2s_logrotate = 0;
00028 
00029 static void _s2s_signal(int signum) {
00030     s2s_shutdown = 1;
00031     s2s_lost_router = 0;
00032 }
00033 
00034 static void _s2s_signal_hup(int signum) {
00035     s2s_logrotate = 1;
00036 }
00037 
00038 static void _s2s_signal_usr1(int signum)
00039 {
00040     set_debug_flag(0);
00041 }
00042 
00043 static void _s2s_signal_usr2(int signum)
00044 {
00045     set_debug_flag(1);
00046 }
00047 
00049 static void _s2s_pidfile(s2s_t s2s) {
00050     char *pidfile;
00051     FILE *f;
00052     pid_t pid;
00053 
00054     pidfile = config_get_one(s2s->config, "pidfile", 0);
00055     if(pidfile == NULL)
00056         return;
00057 
00058     pid = getpid();
00059 
00060     if((f = fopen(pidfile, "w+")) == NULL) {
00061         log_write(s2s->log, LOG_ERR, "couldn't open %s for writing: %s", pidfile, strerror(errno));
00062         return;
00063     }
00064 
00065     if(fprintf(f, "%d", pid) < 0) {
00066         log_write(s2s->log, LOG_ERR, "couldn't write to %s: %s", pidfile, strerror(errno));
00067         fclose(f);
00068         return;
00069     }
00070 
00071     fclose(f);
00072 
00073     log_write(s2s->log, LOG_INFO, "process id is %d, written to %s", pid, pidfile);
00074 }
00075 
00077 static void _s2s_config_expand(s2s_t s2s) {
00078     char *str, secret[41];
00079     config_elem_t elem;
00080     int i, r;
00081 
00082     set_debug_log_from_config(s2s->config);
00083 
00084     s2s->id = config_get_one(s2s->config, "id", 0);
00085     if(s2s->id == NULL)
00086         s2s->id = "s2s";
00087 
00088     s2s->router_ip = config_get_one(s2s->config, "router.ip", 0);
00089     if(s2s->router_ip == NULL)
00090         s2s->router_ip = "127.0.0.1";
00091 
00092     s2s->router_port = j_atoi(config_get_one(s2s->config, "router.port", 0), 5347);
00093 
00094     s2s->router_user = config_get_one(s2s->config, "router.user", 0);
00095     if(s2s->router_user == NULL)
00096         s2s->router_user = "jabberd";
00097     s2s->router_pass = config_get_one(s2s->config, "router.pass", 0);
00098     if(s2s->router_pass == NULL)
00099         s2s->router_pass = "secret";
00100 
00101     s2s->router_pemfile = config_get_one(s2s->config, "router.pemfile", 0);
00102 
00103     s2s->retry_init = j_atoi(config_get_one(s2s->config, "router.retry.init", 0), 3);
00104     s2s->retry_lost = j_atoi(config_get_one(s2s->config, "router.retry.lost", 0), 3);
00105     if((s2s->retry_sleep = j_atoi(config_get_one(s2s->config, "router.retry.sleep", 0), 2)) < 1)
00106         s2s->retry_sleep = 1;
00107 
00108     s2s->router_default = config_count(s2s->config, "router.non-default") ? 0 : 1;
00109 
00110     s2s->log_type = log_STDOUT;
00111     if(config_get(s2s->config, "log") != NULL) {
00112         if((str = config_get_attr(s2s->config, "log", 0, "type")) != NULL) {
00113             if(strcmp(str, "file") == 0)
00114                 s2s->log_type = log_FILE;
00115             else if(strcmp(str, "syslog") == 0)
00116                 s2s->log_type = log_SYSLOG;
00117         }
00118     }
00119 
00120     if(s2s->log_type == log_SYSLOG) {
00121         s2s->log_facility = config_get_one(s2s->config, "log.facility", 0);
00122         s2s->log_ident = config_get_one(s2s->config, "log.ident", 0);
00123         if(s2s->log_ident == NULL)
00124             s2s->log_ident = "jabberd/s2s";
00125     } else if(s2s->log_type == log_FILE)
00126         s2s->log_ident = config_get_one(s2s->config, "log.file", 0);
00127 
00128     s2s->packet_stats = config_get_one(s2s->config, "stats.packet", 0);
00129 
00130     if(s2s->local_ip == NULL)
00131         s2s->local_ip = "0.0.0.0";
00132 
00133     /*
00134      * If no origin IP is specified, use local IP as the originating one:
00135      * it makes most sense, at least for SSL'ized connections.
00136      * APPLE: make origin an array of addresses so that both IPv4 and IPv6 can be specified.
00137      */
00138     s2s->local_ip = config_get_one(s2s->config, "local.ip", 0);
00139     if((elem = config_get(s2s->config, "local.origins.ip")) != NULL) {
00140         s2s->origin_ips = elem->values;
00141         s2s->origin_nips = elem->nvalues;
00142     }
00143     if (s2s->origin_nips == 0) {
00144         s2s->origin_ips = (char **)malloc(sizeof(s2s->origin_ips));
00145         s2s->origin_ips[0] = strdup(s2s->local_ip);
00146         s2s->origin_nips = 1;
00147     }
00148 
00149     s2s->local_port = j_atoi(config_get_one(s2s->config, "local.port", 0), 0);
00150 
00151     if(config_get(s2s->config, "local.secret") != NULL)
00152         s2s->local_secret = strdup(config_get_one(s2s->config, "local.secret", 0));
00153     else {
00154         for(i = 0; i < 40; i++) {
00155             r = (int) (36.0 * rand() / RAND_MAX);
00156             secret[i] = (r >= 0 && r <= 9) ? (r + 48) : (r + 87);
00157         }
00158         secret[40] = '\0';
00159 
00160         s2s->local_secret = strdup(secret);
00161     }
00162 
00163     if(s2s->local_secret == NULL)
00164         s2s->local_secret = "secret";
00165 
00166     s2s->local_pemfile = config_get_one(s2s->config, "local.pemfile", 0);
00167     s2s->local_cachain = config_get_one(s2s->config, "local.cachain", 0);
00168     s2s->local_verify_mode = j_atoi(config_get_one(s2s->config, "local.verify-mode", 0), 0);
00169 
00170     s2s->io_max_fds = j_atoi(config_get_one(s2s->config, "io.max_fds", 0), 1024);
00171 
00172     s2s->compression = (config_get(s2s->config, "io.compression") != NULL);
00173 
00174     s2s->stanza_size_limit = j_atoi(config_get_one(s2s->config, "io.limits.stanzasize", 0), 0);
00175     s2s->require_tls = j_atoi(config_get_one(s2s->config, "security.require_tls", 0), 0);
00176     s2s->enable_whitelist = j_atoi(config_get_one(s2s->config, "security.enable_whitelist", 0), 0);
00177     if((elem = config_get(s2s->config, "security.whitelist_domain")) != NULL) {
00178         _s2s_populate_whitelist_domains(s2s, elem->values, elem->nvalues);
00179     }
00180 
00181     s2s->check_interval = j_atoi(config_get_one(s2s->config, "check.interval", 0), 60);
00182     s2s->check_queue = j_atoi(config_get_one(s2s->config, "check.queue", 0), 60);
00183     s2s->check_keepalive = j_atoi(config_get_one(s2s->config, "check.keepalive", 0), 0);
00184     s2s->check_idle = j_atoi(config_get_one(s2s->config, "check.idle", 0), 86400);
00185     s2s->check_dnscache = j_atoi(config_get_one(s2s->config, "check.dnscache", 0), 300);
00186     s2s->retry_limit = j_atoi(config_get_one(s2s->config, "check.retry", 0), 300);
00187 
00188     if((elem = config_get(s2s->config, "lookup.srv")) != NULL) {
00189         s2s->lookup_srv = elem->values;
00190         s2s->lookup_nsrv = elem->nvalues;
00191     }
00192 
00193     s2s->resolve_aaaa = config_count(s2s->config, "lookup.resolve-ipv6") ? 1 : 0;
00194     s2s->dns_cache_enabled = config_count(s2s->config, "lookup.no-cache") ? 0 : 1;
00195     s2s->dns_bad_timeout = j_atoi(config_get_one(s2s->config, "lookup.bad-host-timeout", 0), 3600);
00196     s2s->dns_min_ttl = j_atoi(config_get_one(s2s->config, "lookup.min-ttl", 0), 30);
00197     if (s2s->dns_min_ttl < 5)
00198         s2s->dns_min_ttl = 5;
00199     s2s->dns_max_ttl = j_atoi(config_get_one(s2s->config, "lookup.max-ttl", 0), 86400);
00200     s2s->etc_hosts_ttl = j_atoi(config_get_one(s2s->config, "lookup.etc-hosts-ttl", 0), 86400);
00201     s2s->out_reuse = config_count(s2s->config, "out-conn-reuse") ? 1 : 0;
00202 }
00203 
00204 static void _s2s_hosts_expand(s2s_t s2s)
00205 {
00206     char *realm;
00207     config_elem_t elem;
00208     char id[1024];
00209     int i;
00210 
00211     elem = config_get(s2s->config, "local.id");
00212 
00213     if (elem) for(i = 0; i < elem->nvalues; i++) {
00214         host_t host = (host_t) pmalloco(xhash_pool(s2s->hosts), sizeof(struct host_st));
00215         if(!host) {
00216             log_write(s2s->log, LOG_ERR, "cannot allocate memory for new host, aborting");
00217             exit(1);
00218         }
00219 
00220         realm = j_attr((const char **) elem->attrs[i], "realm");
00221 
00222         /* stringprep ids (domain names) so that they are in canonical form */
00223         strncpy(id, elem->values[i], 1024);
00224         id[1023] = '\0';
00225         if (stringprep_nameprep(id, 1024) != 0) {
00226             log_write(s2s->log, LOG_ERR, "cannot stringprep id %s, aborting", id);
00227             exit(1);
00228         }
00229 
00230         host->realm = (realm != NULL) ? realm : pstrdup(xhash_pool(s2s->hosts), id);
00231 
00232         host->host_pemfile = j_attr((const char **) elem->attrs[i], "pemfile");
00233 
00234         host->host_cachain = j_attr((const char **) elem->attrs[i], "cachain");
00235 
00236         host->host_verify_mode = j_atoi(j_attr((const char **) elem->attrs[i], "verify-mode"), 0);
00237 
00238 #ifdef HAVE_SSL
00239         if(host->host_pemfile != NULL) {
00240             if(s2s->sx_ssl == NULL) {
00241                 s2s->sx_ssl = sx_env_plugin(s2s->sx_env, sx_ssl_init, host->realm, host->host_pemfile, host->host_cachain, host->host_verify_mode);
00242                 if(s2s->sx_ssl == NULL) {
00243                     log_write(s2s->log, LOG_ERR, "failed to load %s SSL pemfile", host->realm);
00244                     host->host_pemfile = NULL;
00245                 }
00246             } else {
00247                 if(sx_ssl_server_addcert(s2s->sx_ssl, host->realm, host->host_pemfile, host->host_cachain, host->host_verify_mode) != 0) {
00248                     log_write(s2s->log, LOG_ERR, "failed to load %s SSL pemfile", host->realm);
00249                     host->host_pemfile = NULL;
00250                 }
00251             }
00252         }
00253 #endif
00254 
00255         /* insert into vHosts xhash */
00256         xhash_put(s2s->hosts, pstrdup(xhash_pool(s2s->hosts), id), host);
00257 
00258         log_write(s2s->log, LOG_NOTICE, "[%s] configured; realm=%s", id, host->realm);
00259     }
00260 }
00261 
00262 static int _s2s_router_connect(s2s_t s2s) {
00263     log_write(s2s->log, LOG_NOTICE, "attempting connection to router at %s, port=%d", s2s->router_ip, s2s->router_port);
00264 
00265     s2s->fd = mio_connect(s2s->mio, s2s->router_port, s2s->router_ip, NULL, s2s_router_mio_callback, (void *) s2s);
00266     if(s2s->fd == NULL) {
00267         if(errno == ECONNREFUSED)
00268             s2s_lost_router = 1;
00269         log_write(s2s->log, LOG_NOTICE, "connection attempt to router failed: %s (%d)", MIO_STRERROR(MIO_ERROR), MIO_ERROR);
00270         return 1;
00271     }
00272 
00273     s2s->router = sx_new(s2s->sx_env, s2s->fd->fd, s2s_router_sx_callback, (void *) s2s);
00274     sx_client_init(s2s->router, 0, NULL, NULL, NULL, "1.0");
00275 
00276     return 0;
00277 }
00278 
00279 int _s2s_check_conn_routes(s2s_t s2s, conn_t conn, const char *direction)
00280 {
00281   char *rkey;
00282   int rkeylen;
00283   conn_state_t state;
00284   time_t now, dialback_time;
00285 
00286   now = time(NULL);
00287 
00288   if(xhash_iter_first(conn->states))
00289      do {
00290            /* retrieve state in a separate operation, as sizeof(int) != sizeof(void *) on 64-bit platforms,
00291               so passing a pointer to state in xhash_iter_get is unsafe */
00292            xhash_iter_get(conn->states, (const char **) &rkey, &rkeylen, NULL);
00293            state = (conn_state_t) xhash_getx(conn->states, rkey, rkeylen);
00294 
00295            if (state == conn_INPROGRESS) {
00296               dialback_time = (time_t) xhash_getx(conn->states_time, rkey, rkeylen);
00297 
00298               if(now > dialback_time + s2s->check_queue) {
00299                  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);
00300 
00301                  xhash_zapx(conn->states, rkey, rkeylen);
00302                  xhash_zapx(conn->states_time, rkey, rkeylen);
00303 
00304                  /* stream error */
00305                  sx_error(conn->s, stream_err_CONNECTION_TIMEOUT, "dialback timed out");
00306 
00307                  /* close connection as per XMPP/RFC3920 */
00308                  sx_close(conn->s);
00309 
00310                  /* indicate that we closed the connection */
00311                  return 0;
00312               }
00313            }
00314      } while(xhash_iter_next(conn->states));
00315 
00316   /* all ok */
00317   return 1;
00318 }
00319 
00320 static void _s2s_time_checks(s2s_t s2s) {
00321     conn_t conn;
00322     time_t now;
00323     char *rkey, *key;
00324     int keylen;
00325     jqueue_t q;
00326     dnscache_t dns;
00327     char *c;
00328     int c_len;
00329     union xhashv xhv;
00330 
00331     now = time(NULL);
00332 
00333     /* queue expiry */
00334     if(s2s->check_queue > 0) {
00335         if(xhash_iter_first(s2s->outq))
00336             do {
00337                 xhv.jq_val = &q;
00338                 xhash_iter_get(s2s->outq, (const char **) &rkey, &keylen, xhv.val);
00339 
00340                 log_debug(ZONE, "running time checks for %.*s", keylen, rkey);
00341                 c = memchr(rkey, '/', keylen);
00342                 c++;
00343                 c_len = keylen - (c - rkey);
00344 
00345                 /* dns lookup timeout check first */
00346                 dns = xhash_getx(s2s->dnscache, c, c_len);
00347                 if(dns != NULL && dns->pending) {
00348                     log_debug(ZONE, "dns lookup pending for %.*s", c_len, c);
00349                     if(now > dns->init_time + s2s->check_queue) {
00350                         log_write(s2s->log, LOG_NOTICE, "dns lookup for %.*s timed out", c_len, c);
00351 
00352                         /* bounce queue */
00353                         out_bounce_route_queue(s2s, rkey, keylen, stanza_err_REMOTE_SERVER_NOT_FOUND);
00354 
00355                         /* expire pending dns entry */
00356                         xhash_zap(s2s->dnscache, dns->name);
00357                         xhash_free(dns->results);
00358                         if (dns->query != NULL) {
00359                             if (dns->query->query != NULL)
00360                                 dns_cancel(NULL, dns->query->query);
00361                             xhash_free(dns->query->hosts);
00362                             xhash_free(dns->query->results);
00363                             free(dns->query->name);
00364                             free(dns->query);
00365                         }
00366                         free(dns);
00367                     }
00368 
00369                     continue;
00370                 }
00371 
00372                 /* get the conn */
00373                 conn = xhash_getx(s2s->out_dest, c, c_len);
00374                 if(conn == NULL) {
00375                     if(jqueue_size(q) > 0) {
00376                        /* no pending conn? perhaps it failed? */
00377                        log_debug(ZONE, "no pending connection for %.*s, bouncing %i packets in queue", c_len, c, jqueue_size(q));
00378 
00379                        /* bounce queue */
00380                        out_bounce_route_queue(s2s, rkey, keylen, stanza_err_REMOTE_SERVER_TIMEOUT);
00381                     }
00382 
00383                     continue;
00384                 }
00385 
00386                 /* connect timeout check */
00387                 if(!conn->online && now > conn->init_time + s2s->check_queue) {
00388                     dnsres_t bad;
00389                     char *ipport;
00390 
00391                     log_write(s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] connection to %s timed out", conn->fd->fd, conn->ip, conn->port, c);
00392 
00393                     if (s2s->dns_bad_timeout > 0) {
00394                         /* mark this host as bad */
00395                         ipport = dns_make_ipport(conn->ip, conn->port);
00396                         bad = xhash_get(s2s->dns_bad, ipport);
00397                         if (bad == NULL) {
00398                             bad = (dnsres_t) calloc(1, sizeof(struct dnsres_st));
00399                             bad->key = ipport;
00400                             xhash_put(s2s->dns_bad, ipport, bad);
00401                         } else {
00402                             free(ipport);
00403                         }
00404                         bad->expiry = time(NULL) + s2s->dns_bad_timeout;
00405                     }
00406 
00407                     /* close connection as per XMPP/RFC3920 */
00408                     /* the close function will retry or bounce the queue */
00409                     sx_close(conn->s);
00410                 }
00411             } while(xhash_iter_next(s2s->outq));
00412     }
00413 
00414     /* expiry of connected routes in conn_INPROGRESS state */
00415     if(s2s->check_queue > 0) {
00416 
00417         /* outgoing connections */
00418         if(s2s->out_reuse) {
00419             if(xhash_iter_first(s2s->out_host))
00420                 do {
00421                     xhv.conn_val = &conn;
00422                     xhash_iter_get(s2s->out_host, (const char **) &key, &keylen, xhv.val);
00423                     log_debug(ZONE, "checking dialback state for outgoing conn %.*s", keylen, key);
00424                     if (_s2s_check_conn_routes(s2s, conn, "outgoing")) {
00425                         log_debug(ZONE, "checking pending verify requests for outgoing conn %.*s", keylen, key);
00426                         if (conn->verify > 0 && now > conn->last_verify + s2s->check_queue) {
00427                             log_write(s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] dialback verify request timed out", conn->fd->fd, conn->ip, conn->port);
00428                             sx_error(conn->s, stream_err_CONNECTION_TIMEOUT, "dialback verify request timed out");
00429                             sx_close(conn->s);
00430                         }
00431                     }
00432                 } while(xhash_iter_next(s2s->out_host));
00433         } else {
00434             if(xhash_iter_first(s2s->out_dest))
00435                 do {
00436                     xhv.conn_val = &conn;
00437                     xhash_iter_get(s2s->out_dest, (const char **) &key, &keylen, xhv.val);
00438                     log_debug(ZONE, "checking dialback state for outgoing conn %s (%s)", conn->dkey, conn->key);
00439                     if (_s2s_check_conn_routes(s2s, conn, "outgoing")) {
00440                         log_debug(ZONE, "checking pending verify requests for outgoing conn %s (%s)", conn->dkey, conn->key);
00441                         if (conn->verify > 0 && now > conn->last_verify + s2s->check_queue) {
00442                             log_write(s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] dialback verify request timed out", conn->fd->fd, conn->ip, conn->port);
00443                             sx_error(conn->s, stream_err_CONNECTION_TIMEOUT, "dialback verify request timed out");
00444                             sx_close(conn->s);
00445                         }
00446                     }
00447                 } while(xhash_iter_next(s2s->out_dest));
00448         }
00449 
00450         /* incoming open streams */
00451         if(xhash_iter_first(s2s->in))
00452             do {
00453                 xhv.conn_val = &conn;
00454                 xhash_iter_get(s2s->in, (const char **) &key, &keylen, xhv.val);
00455 
00456                 log_debug(ZONE, "checking dialback state for incoming conn %.*s", keylen, key);
00457                 if (_s2s_check_conn_routes(s2s, conn, "incoming"))
00458                     /* if the connection is still valid, check that dialbacks have been initiated */
00459                     if(!xhash_count(conn->states) && now > conn->init_time + s2s->check_queue) {
00460                         log_write(s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] no dialback started", conn->fd->fd, conn->ip, conn->port);
00461                         sx_error(conn->s, stream_err_CONNECTION_TIMEOUT, "no dialback initiated");
00462                         sx_close(conn->s);
00463                     }
00464             } while(xhash_iter_next(s2s->in));
00465 
00466         /* incoming open connections (not yet streams) */
00467         if(xhash_iter_first(s2s->in_accept))
00468             do {
00469                 xhv.conn_val = &conn;
00470                 xhash_iter_get(s2s->in_accept, (const char **) &key, &keylen, xhv.val);
00471 
00472                 log_debug(ZONE, "checking stream connection state for incoming conn %i", conn->fd->fd);
00473                 if(!conn->online && now > conn->init_time + s2s->check_queue) {
00474                     log_write(s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] stream initiation timed out", conn->fd->fd, conn->ip, conn->port);
00475                     sx_close(conn->s);
00476                 }
00477             } while(xhash_iter_next(s2s->in_accept));
00478 
00479     }
00480 
00481     /* keepalives */
00482     if(s2s->out_reuse) {
00483         if(xhash_iter_first(s2s->out_host))
00484             do {
00485                 xhv.conn_val = &conn;
00486                 xhash_iter_get(s2s->out_host, NULL, NULL, xhv.val);
00487 
00488                 if(s2s->check_keepalive > 0 && conn->last_activity > 0 && now > conn->last_activity + s2s->check_keepalive && conn->s->state >= state_STREAM) {
00489                     log_debug(ZONE, "sending keepalive for %d", conn->fd->fd);
00490 
00491                     sx_raw_write(conn->s, " ", 1);
00492                 }
00493             } while(xhash_iter_next(s2s->out_host));
00494     } else {
00495         if(xhash_iter_first(s2s->out_dest))
00496             do {
00497                 xhv.conn_val = &conn;
00498                 xhash_iter_get(s2s->out_dest, NULL, NULL, xhv.val);
00499 
00500                 if(s2s->check_keepalive > 0 && conn->last_activity > 0 && now > conn->last_activity + s2s->check_keepalive && conn->s->state >= state_STREAM) {
00501                     log_debug(ZONE, "sending keepalive for %d", conn->fd->fd);
00502 
00503                     sx_raw_write(conn->s, " ", 1);
00504                 }
00505             } while(xhash_iter_next(s2s->out_dest));
00506     }
00507 
00508     /* idle timeouts - disconnect connections through which no packets have been sent for <idle> seconds */
00509     if(s2s->check_idle > 0) {
00510 
00511         /* outgoing connections */
00512         if(s2s->out_reuse) {
00513             if(xhash_iter_first(s2s->out_host))
00514                 do {
00515                     xhv.conn_val = &conn;
00516                     xhash_iter_get(s2s->out_host, (const char **) &key, &keylen, xhv.val);
00517                     log_debug(ZONE, "checking idle state for %.*s", keylen, key);
00518                     if (conn->last_packet > 0 && now > conn->last_packet + s2s->check_idle && conn->s->state >= state_STREAM) {
00519                         log_write(s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] idle timeout", conn->fd->fd, conn->ip, conn->port);
00520                         sx_close(conn->s);
00521                     }
00522                 } while(xhash_iter_next(s2s->out_host));
00523         } else {
00524             if(xhash_iter_first(s2s->out_dest))
00525                 do {
00526                     xhv.conn_val = &conn;
00527                     xhash_iter_get(s2s->out_dest, (const char **) &key, &keylen, xhv.val);
00528                     log_debug(ZONE, "checking idle state for %s (%s)", conn->dkey, conn->key);
00529                     if (conn->last_packet > 0 && now > conn->last_packet + s2s->check_idle && conn->s->state >= state_STREAM) {
00530                         log_write(s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] idle timeout", conn->fd->fd, conn->ip, conn->port);
00531                         sx_close(conn->s);
00532                     }
00533                 } while(xhash_iter_next(s2s->out_dest));
00534         }
00535 
00536         /* incoming connections */
00537         if(xhash_iter_first(s2s->in))
00538             do {
00539                 xhv.conn_val = &conn;
00540                 xhash_iter_get(s2s->in, (const char **) &key, &keylen, xhv.val);
00541                 log_debug(ZONE, "checking idle state for %.*s", keylen, key);
00542                 if (conn->last_packet > 0 && now > conn->last_packet + s2s->check_idle && conn->s->state >= state_STREAM) {
00543                     log_write(s2s->log, LOG_NOTICE, "[%d] [%s, port=%d] idle timeout", conn->fd->fd, conn->ip, conn->port);
00544                     sx_close(conn->s);
00545                 }
00546             } while(xhash_iter_next(s2s->in));
00547 
00548     }
00549 
00550     return;
00551 }
00552 
00553 static void _s2s_dns_expiry(s2s_t s2s) {
00554     time_t now;
00555     dnscache_t dns = NULL;
00556     dnsres_t res = NULL;
00557     union xhashv xhv;
00558 
00559     now = time(NULL);
00560 
00561     /* dnscache timeouts */
00562     if(xhash_iter_first(s2s->dnscache))
00563         do {
00564             xhv.dns_val = &dns;
00565             xhash_iter_get(s2s->dnscache, NULL, NULL, xhv.val);
00566             if (dns && !dns->pending && now > dns->expiry) {
00567                 log_debug(ZONE, "expiring DNS cache for %s", dns->name);
00568                 xhash_iter_zap(s2s->dnscache);
00569 
00570                 xhash_free(dns->results);
00571                 if (dns->query != NULL) {
00572                     if (dns->query->query != NULL)
00573                         dns_cancel(NULL, dns->query->query);
00574                     xhash_free(dns->query->hosts);
00575                     xhash_free(dns->query->results);
00576                     free(dns->query->name);
00577                     free(dns->query);
00578                 }
00579                 free(dns);
00580             }
00581             else if (dns == NULL) {
00582                 xhash_iter_zap(s2s->dnscache);
00583             }
00584         } while(xhash_iter_next(s2s->dnscache));
00585 
00586     if(xhash_iter_first(s2s->dns_bad))
00587         do {
00588             xhv.dnsres_val = &res;
00589             xhash_iter_get(s2s->dns_bad, NULL, NULL, xhv.val);
00590             if (res && now > res->expiry) {
00591                 log_debug(ZONE, "expiring DNS bad host %s", res->key);
00592                 xhash_iter_zap(s2s->dns_bad);
00593 
00594                 free(res->key);
00595                 free(res);
00596             }
00597             else if (res == NULL) {
00598                 xhash_iter_zap(s2s->dns_bad);
00599             }
00600         } while(xhash_iter_next(s2s->dns_bad));
00601 }
00603 static int _mio_resolver_callback(mio_t m, mio_action_t a, mio_fd_t fd, void *data, void *arg) {
00604 
00605     switch(a) {
00606         case action_READ:
00607             log_debug(ZONE, "read action on fd %d", fd->fd);
00608 
00609             dns_ioevent(0, time(NULL));
00610 
00611         default:
00612             break;
00613     }
00614 
00615     return 0;
00616 }
00617 
00618 /* Populate the whitelist_domains array with the config file values */
00619 int _s2s_populate_whitelist_domains(s2s_t s2s, char **values, int nvalues) {
00620     int i, j;
00621     int elem_len;
00622     s2s->whitelist_domains = (char **)malloc(sizeof(char*) * (nvalues));
00623     memset(s2s->whitelist_domains, 0, (sizeof(char *) * (nvalues)));    
00624     for (i = 0, j = 0; i < nvalues; i++) {
00625         elem_len = strlen(values[i]);
00626         if (elem_len > MAX_DOMAIN_LEN) {
00627             log_debug(ZONE, "whitelist domain element is too large, skipping");
00628             continue;
00629         }
00630         if (elem_len == 0) {
00631             log_debug(ZONE, "whitelist domain element is blank, skipping");
00632             continue;
00633         }
00634         s2s->whitelist_domains[j] = (char *) malloc(sizeof(char) * (elem_len+1));
00635         memset(s2s->whitelist_domains[j], 0, (sizeof(char) * (elem_len+1)));
00636         strncpy(s2s->whitelist_domains[j], values[i], elem_len);
00637         s2s->whitelist_domains[j][elem_len+1] = '\0';
00638         log_debug(ZONE, "s2s whitelist domain read from file: %s\n", s2s->whitelist_domains[j]);
00639         j++;
00640     }
00641 
00642     s2s->n_whitelist_domains = j;
00643     log_debug(ZONE, "n_whitelist_domains = %d", s2s->n_whitelist_domains);
00644     return 0;
00645 }
00646 
00647 
00648 /* Compare a domain with whitelist values.
00649     The whitelist values may be FQDN or domain only (with no prepended hostname).
00650     returns 1 on match, 0 on failure to match
00651 */
00652 int s2s_domain_in_whitelist(s2s_t s2s, char *in_domain) {
00653     int segcount = 0;
00654     int dotcount;
00655     char **segments = NULL;
00656     char **dst = NULL;
00657     char *seg_tmp = NULL;    
00658     int seg_tmp_len;
00659     char matchstr[MAX_DOMAIN_LEN + 1];
00660     int domain_index;
00661     int x, i;
00662     int wl_index;
00663     int wl_len;
00664     int matchstr_len;
00665     char domain[1024];
00666     char *domain_ptr = &domain[0];
00667     int domain_len;
00668 
00669     strncpy(domain, in_domain, sizeof(domain));
00670     domain[sizeof(domain)-1] = '\0';
00671     domain_len = strlen((const char *)&domain);
00672 
00673     if (domain_len <= 0) {
00674         log_write(s2s->log, LOG_NOTICE, "s2s_domain_in_whitelist: in_domain is empty");
00675         return 0;
00676     }
00677 
00678     if (domain_len > MAX_DOMAIN_LEN) {
00679         log_write(s2s->log, LOG_NOTICE, "s2s_domain_in_whitelist: in_domain is longer than %s chars", MAX_DOMAIN_LEN);
00680         return 0;
00681     }
00682 
00683     // first try matching the FQDN with whitelist domains
00684     if (s2s->n_whitelist_domains <= 0)
00685         return 0;
00686 
00687     for (wl_index =0; wl_index < s2s->n_whitelist_domains; wl_index++) {
00688         wl_len = strlen(s2s->whitelist_domains[wl_index]);
00689         if (!strncmp((const char *)&domain, s2s->whitelist_domains[wl_index], (domain_len > wl_len) ? domain_len : wl_len)) {
00690             log_debug(ZONE, "domain \"%s\" matches whitelist entry", &domain);
00691             return 1;
00692         }
00693         else {
00694             //log_debug(ZONE, "domain: %s (len %d) does not match whitelist_domains[%d]: %s (len %d)", &domain, strlen((const char *)&domain), wl_index, s2s->whitelist_domains[wl_index], strlen(s2s->whitelist_domains[wl_index]));
00695         }
00696     }
00697 
00698     // break domain into segments for domain-only comparision
00699     for (dotcount = 0, x = 0; domain[x] != '\0'; x++) {
00700         if (domain[x] == '.')
00701             dotcount++;
00702     }
00703         
00704     segments = (char **)malloc(sizeof(char*) * (dotcount + 1));
00705     if (segments == NULL) {
00706         log_write(s2s->log, LOG_ERR, "s2s_domain_in_whitelist: malloc() error");
00707         return 0;
00708     }
00709     memset((char **)segments, 0, (sizeof(char*) * (dotcount + 1)));
00710 
00711     do {
00712         if (segcount > (dotcount+1)) {
00713             log_write(s2s->log, LOG_ERR, "s2s_domain_in_whitelist: did not malloc enough room for domain segments; should never get here");
00714             if (seg_tmp != NULL) {
00715                 free(seg_tmp);
00716                 seg_tmp = NULL;
00717             }
00718             for (x = 0; x < segcount; x++) {
00719                 free(segments[x]);
00720                 segments[x] = NULL;
00721             }
00722             free(segments);
00723             segments = NULL;
00724             return 0;
00725         }
00726         seg_tmp = strsep(&domain_ptr, ".");
00727         if (seg_tmp == NULL) {
00728             break;
00729         }
00730 
00731         seg_tmp_len = strlen(seg_tmp);
00732         if (seg_tmp_len > MAX_DOMAIN_LEN) {
00733             log_write(s2s->log, LOG_NOTICE, "s2s_domain_in_whitelist: domain contains a segment greater than %s chars", MAX_DOMAIN_LEN);
00734             if (seg_tmp != NULL) {
00735                 free(seg_tmp);
00736                 seg_tmp = NULL;
00737             }
00738             for (x = 0; x < segcount; x++) {
00739                 free(segments[x]);
00740                 segments[x] = NULL;
00741             }   
00742             free(segments);
00743             segments = NULL;
00744             return 0;
00745         }
00746         dst = &segments[segcount];
00747         *dst = (char *)malloc(seg_tmp_len + 1);
00748         if (*dst != NULL) {
00749             strncpy(*dst, seg_tmp, seg_tmp_len + 1);
00750             dst[seg_tmp_len] = '\0';
00751         } else { 
00752             if (seg_tmp != NULL) {
00753                 free(seg_tmp);
00754                 seg_tmp = NULL;
00755             }
00756             for (x = 0; x < segcount; x++) {
00757                 free(segments[x]);
00758                 segments[x] = NULL;
00759             }   
00760             free(segments);
00761             segments = NULL;
00762             log_write(s2s->log, LOG_ERR, "s2s_domain_in_whitelist: malloc() error");
00763             return 0;
00764         }
00765         segcount++;
00766     } while (seg_tmp != NULL);
00767 
00768     if (segcount > 1) {
00769         for (domain_index = segcount-2; domain_index > 0; domain_index--) {
00770             matchstr[0] = '\0';
00771             for (i = domain_index; i < segcount; i++) {
00772                 if (i > domain_index) {
00773                     strncat((char *)&matchstr, ".", sizeof(matchstr));
00774                     matchstr[sizeof(matchstr)-1] = '\0';
00775                 }
00776                 strncat((char *)&matchstr, (char *)segments[i], sizeof(matchstr));
00777                 matchstr[sizeof(matchstr)-1] = '\0';
00778             }
00779             for (wl_index = 0; wl_index < s2s->n_whitelist_domains; wl_index++) {
00780                 wl_len = strlen(s2s->whitelist_domains[wl_index]);
00781                 matchstr_len = strlen((const char *)&matchstr);
00782                 if (!strncmp((const char *)&matchstr, s2s->whitelist_domains[wl_index], (wl_len > matchstr_len ? wl_len : matchstr_len))) {
00783                     log_debug(ZONE, "matchstr \"%s\" matches whitelist entry", &matchstr);
00784                     for (x = 0; x < segcount; x++) {
00785                         free(segments[x]);
00786                         segments[x] = NULL;
00787                     }   
00788                     free(segments);
00789                     segments = NULL;
00790                     return 1;
00791                 } 
00792                 else { 
00793                     //log_debug(ZONE, "matchstr: %s (len %d) does not match whitelist_domains[%d]: %s (len %d)", &matchstr, strlen((const char *)&matchstr), wl_index, s2s->whitelist_domains[wl_index], strlen(s2s->whitelist_domains[wl_index]));
00794                 }
00795             }
00796         }
00797     }
00798     for (x = 0; x < segcount; x++) {
00799         free(segments[x]);
00800         segments[x] = NULL;
00801     }   
00802     free(segments);
00803     segments = NULL;
00804 
00805     return 0;    
00806 }
00807 
00808 JABBER_MAIN("jabberd2s2s", "Jabber 2 S2S", "Jabber Open Source Server: Server to Server", "jabberd2router\0")
00809 {
00810     s2s_t s2s;
00811     char *config_file;
00812     int optchar;
00813     conn_t conn;
00814     jqueue_t q;
00815     dnscache_t dns;
00816     dnsres_t res;
00817     union xhashv xhv;
00818     time_t check_time = 0, now = 0;
00819     const char *cli_id = 0;
00820 
00821 #ifdef HAVE_UMASK
00822     umask((mode_t) 0027);
00823 #endif
00824 
00825     srand(time(NULL));
00826 
00827 #ifdef HAVE_WINSOCK2_H
00828 /* get winsock running */
00829     {
00830         WORD wVersionRequested;
00831         WSADATA wsaData;
00832         int err;
00833 
00834         wVersionRequested = MAKEWORD( 2, 2 );
00835 
00836         err = WSAStartup( wVersionRequested, &wsaData );
00837         if ( err != 0 ) {
00838             /* !!! tell user that we couldn't find a usable winsock dll */
00839             return 0;
00840         }
00841     }
00842 #endif
00843 
00844     jabber_signal(SIGINT, _s2s_signal);
00845     jabber_signal(SIGTERM, _s2s_signal);
00846 #ifdef SIGHUP
00847     jabber_signal(SIGHUP, _s2s_signal_hup);
00848 #endif
00849 #ifdef SIGPIPE
00850     jabber_signal(SIGPIPE, SIG_IGN);
00851 #endif
00852     jabber_signal(SIGUSR1, _s2s_signal_usr1);
00853     jabber_signal(SIGUSR2, _s2s_signal_usr2);
00854 
00855 
00856     s2s = (s2s_t) calloc(1, sizeof(struct s2s_st));
00857 
00858     /* load our config */
00859     s2s->config = config_new();
00860 
00861     config_file = CONFIG_DIR "/s2s.xml";
00862 
00863     /* cmdline parsing */
00864     while((optchar = getopt(argc, argv, "Dc:hi:?")) >= 0)
00865     {
00866         switch(optchar)
00867         {
00868             case 'c':
00869                 config_file = optarg;
00870                 break;
00871             case 'D':
00872 #ifdef DEBUG
00873                 set_debug_flag(1);
00874 #else
00875                 printf("WARN: Debugging not enabled.  Ignoring -D.\n");
00876 #endif
00877                 break;
00878             case 'i':
00879                 cli_id = optarg;
00880                 break;
00881             case 'h': case '?': default:
00882                 fputs(
00883                     "s2s - jabberd server-to-server connector (" VERSION ")\n"
00884                     "Usage: s2s <options>\n"
00885                     "Options are:\n"
00886                     "   -c <config>     config file to use [default: " CONFIG_DIR "/s2s.xml]\n"
00887                     "   -i id           Override <id> config element\n"
00888 #ifdef DEBUG
00889                     "   -D              Show debug output\n"
00890 #endif
00891                     ,
00892                     stdout);
00893                 config_free(s2s->config);
00894                 free(s2s);
00895                 return 1;
00896         }
00897     }
00898 
00899     if(config_load_with_id(s2s->config, config_file, cli_id) != 0) {
00900         fputs("s2s: couldn't load config, aborting\n", stderr);
00901         config_free(s2s->config);
00902         free(s2s);
00903         return 2;
00904     }
00905 
00906     _s2s_config_expand(s2s);
00907 
00908     s2s->log = log_new(s2s->log_type, s2s->log_ident, s2s->log_facility);
00909     log_write(s2s->log, LOG_NOTICE, "starting up (interval=%i, queue=%i, keepalive=%i, idle=%i)", s2s->check_interval, s2s->check_queue, s2s->check_keepalive, s2s->check_idle);
00910 
00911     _s2s_pidfile(s2s);
00912 
00913     s2s->outq = xhash_new(401);
00914     s2s->out_host = xhash_new(401);
00915     s2s->out_dest = xhash_new(401);
00916     s2s->in = xhash_new(401);
00917     s2s->in_accept = xhash_new(401);
00918     s2s->dnscache = xhash_new(401);
00919     s2s->dns_bad = xhash_new(401);
00920 
00921     s2s->dead = jqueue_new();
00922     s2s->dead_conn = jqueue_new();
00923 
00924     s2s->sx_env = sx_env_new();
00925 
00926 #ifdef HAVE_SSL
00927     /* get the ssl context up and running */
00928     if(s2s->local_pemfile != NULL) {
00929         s2s->sx_ssl = sx_env_plugin(s2s->sx_env, sx_ssl_init, NULL, s2s->local_pemfile, s2s->local_cachain, s2s->local_verify_mode);
00930 
00931         if(s2s->sx_ssl == NULL) {
00932             log_write(s2s->log, LOG_ERR, "failed to load local SSL pemfile, SSL will not be available to peers");
00933             s2s->local_pemfile = NULL;
00934         } else
00935             log_debug(ZONE, "loaded pemfile for SSL connections to peers");
00936     }
00937 
00938     /* try and get something online, so at least we can encrypt to the router */
00939     if(s2s->sx_ssl == NULL && s2s->router_pemfile != NULL) {
00940         s2s->sx_ssl = sx_env_plugin(s2s->sx_env, sx_ssl_init, NULL, s2s->router_pemfile, NULL, NULL);
00941         if(s2s->sx_ssl == NULL) {
00942             log_write(s2s->log, LOG_ERR, "failed to load router SSL pemfile, channel to router will not be SSL encrypted");
00943             s2s->router_pemfile = NULL;
00944         }
00945     }
00946 #endif
00947 
00948 #ifdef HAVE_LIBZ
00949     /* get compression up and running */
00950     if(s2s->compression)
00951         sx_env_plugin(s2s->sx_env, sx_compress_init);
00952 #endif
00953 
00954     /* get sasl online */
00955     s2s->sx_sasl = sx_env_plugin(s2s->sx_env, sx_sasl_init, "xmpp", NULL, NULL);
00956     if(s2s->sx_sasl == NULL) {
00957         log_write(s2s->log, LOG_ERR, "failed to initialise SASL context, aborting");
00958         exit(1);
00959     }
00960 
00961     /* hosts mapping */
00962     s2s->hosts = xhash_new(1021);
00963     _s2s_hosts_expand(s2s);
00964 
00965     s2s->sx_db = sx_env_plugin(s2s->sx_env, s2s_db_init);
00966 
00967     s2s->mio = mio_new(s2s->io_max_fds);
00968 
00969     if((s2s->udns_fd = dns_init(NULL, 1)) < 0) {
00970         log_write(s2s->log, LOG_ERR, "unable to initialize dns library, aborting");
00971         exit(1);
00972     }
00973     s2s->udns_mio_fd = mio_register(s2s->mio, s2s->udns_fd, _mio_resolver_callback, (void *) s2s);
00974 
00975     s2s->retry_left = s2s->retry_init;
00976     _s2s_router_connect(s2s);
00977 
00978     while(!s2s_shutdown) {
00979         mio_run(s2s->mio, dns_timeouts(0, 5, time(NULL)));
00980 
00981         now = time(NULL);
00982 
00983         if(s2s_logrotate) {
00984             set_debug_log_from_config(s2s->config);
00985 
00986             log_write(s2s->log, LOG_NOTICE, "reopening log ...");
00987             log_free(s2s->log);
00988             s2s->log = log_new(s2s->log_type, s2s->log_ident, s2s->log_facility);
00989             log_write(s2s->log, LOG_NOTICE, "log started");
00990 
00991             s2s_logrotate = 0;
00992         }
00993 
00994         if(s2s_lost_router) {
00995             if(s2s->retry_left < 0) {
00996                 log_write(s2s->log, LOG_NOTICE, "attempting reconnect");
00997                 sleep(s2s->retry_sleep);
00998                 s2s_lost_router = 0;
00999                 if (s2s->router) sx_free(s2s->router);
01000                 _s2s_router_connect(s2s);
01001             }
01002 
01003             else if(s2s->retry_left == 0) {
01004                 s2s_shutdown = 1;
01005             }
01006 
01007             else {
01008                 log_write(s2s->log, LOG_NOTICE, "attempting reconnect (%d left)", s2s->retry_left);
01009                 s2s->retry_left--;
01010                 sleep(s2s->retry_sleep);
01011                 s2s_lost_router = 0;
01012                 if (s2s->router) sx_free(s2s->router);
01013                 _s2s_router_connect(s2s);
01014             }
01015         }
01016 
01017         /* this has to be read unconditionally - we could receive replies to queries we cancelled */
01018           mio_read(s2s->mio, s2s->udns_mio_fd);
01019 
01020         /* cleanup dead sx_ts */
01021         while(jqueue_size(s2s->dead) > 0)
01022             sx_free((sx_t) jqueue_pull(s2s->dead));
01023 
01024         /* cleanup dead conn_ts */
01025         while(jqueue_size(s2s->dead_conn) > 0) {
01026             conn = (conn_t) jqueue_pull(s2s->dead_conn);
01027             xhash_free(conn->states);
01028             xhash_free(conn->states_time);
01029             xhash_free(conn->routes);
01030 
01031             free(conn->key);
01032             free(conn->dkey);
01033             free(conn);
01034         }
01035 
01036         /* time checks */
01037         if(s2s->check_interval > 0 && now >= s2s->next_check) {
01038             log_debug(ZONE, "running time checks");
01039 
01040             _s2s_time_checks(s2s);
01041 
01042             s2s->next_check = now + s2s->check_interval;
01043             log_debug(ZONE, "next time check at %d", s2s->next_check);
01044         }
01045 
01046         /* dnscache expiry */
01047         if(s2s->check_dnscache > 0 && now >= s2s->next_expiry) {
01048             log_debug(ZONE, "running dns expiry");
01049 
01050             _s2s_dns_expiry(s2s);
01051 
01052             s2s->next_expiry = now + s2s->check_dnscache;
01053             log_debug(ZONE, "next dns expiry at %d", s2s->next_expiry);
01054         }
01055 
01056         if(now > check_time + 60) {
01057 #ifdef POOL_DEBUG
01058             pool_stat(1);
01059 #endif
01060             if(s2s->packet_stats != NULL) {
01061                 int fd = open(s2s->packet_stats, O_TRUNC | O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP);
01062                 if(fd) {
01063                     char buf[100];
01064                     int len = snprintf(buf, 100, "%lld\n", s2s->packet_count);
01065                     write(fd, buf, len);
01066                     close(fd);
01067                 } else {
01068                     log_write(s2s->log, LOG_ERR, "failed to write packet statistics to: %s", s2s->packet_stats);
01069                     s2s_shutdown = 1;
01070                 }
01071             }
01072 
01073             check_time = now;
01074         }
01075     }
01076 
01077     log_write(s2s->log, LOG_NOTICE, "shutting down");
01078 
01079     /* close active streams gracefully  */
01080     xhv.conn_val = &conn;
01081     if(s2s->out_reuse) {
01082         if(xhash_iter_first(s2s->out_host))
01083             do {
01084                 xhash_iter_get(s2s->out_host, NULL, NULL, xhv.val);
01085                 if(conn) {
01086                     sx_error(conn->s, stream_err_SYSTEM_SHUTDOWN, "s2s shutdown");
01087                     out_bounce_conn_queues(conn, stanza_err_SERVICE_UNAVAILABLE);
01088                     sx_close(conn->s);
01089                 }
01090             } while(xhash_iter_next(s2s->out_host));
01091     } else {
01092         if(xhash_iter_first(s2s->out_dest))
01093             do {
01094                 xhash_iter_get(s2s->out_dest, NULL, NULL, xhv.val);
01095                 if(conn) {
01096                     sx_error(conn->s, stream_err_SYSTEM_SHUTDOWN, "s2s shutdown");
01097                     out_bounce_conn_queues(conn, stanza_err_SERVICE_UNAVAILABLE);
01098                     sx_close(conn->s);
01099                 }
01100             } while(xhash_iter_next(s2s->out_dest));
01101     }
01102 
01103     if(xhash_iter_first(s2s->in))
01104         do {
01105             xhash_iter_get(s2s->in, NULL, NULL, xhv.val);
01106             if(conn) {
01107                 sx_error(conn->s, stream_err_SYSTEM_SHUTDOWN, "s2s shutdown");
01108                 out_bounce_conn_queues(conn, stanza_err_SERVICE_UNAVAILABLE);
01109                 sx_close(conn->s);
01110             }
01111         } while(xhash_iter_next(s2s->in));
01112 
01113     if(xhash_iter_first(s2s->in_accept))
01114         do {
01115             xhash_iter_get(s2s->in_accept, NULL, NULL, xhv.val);
01116             if(conn) {
01117                 out_bounce_conn_queues(conn, stanza_err_SERVICE_UNAVAILABLE);
01118                 sx_close(conn->s);
01119             }
01120         } while(xhash_iter_next(s2s->in_accept));
01121 
01122 
01123     /* remove dead streams */
01124     while(jqueue_size(s2s->dead) > 0)
01125         sx_free((sx_t) jqueue_pull(s2s->dead));
01126 
01127     /* cleanup dead conn_ts */
01128     while(jqueue_size(s2s->dead_conn) > 0) {
01129         conn = (conn_t) jqueue_pull(s2s->dead_conn);
01130         xhash_free(conn->states);
01131         xhash_free(conn->states_time);
01132         xhash_free(conn->routes);
01133 
01134         if(conn->key != NULL) free(conn->key);
01135         if(conn->dkey != NULL) free(conn->dkey);
01136         free(conn);
01137     }
01138 
01139     /* free outgoing queues  */
01140     xhv.jq_val = &q;
01141     if(xhash_iter_first(s2s->outq))
01142         do {
01143              xhash_iter_get(s2s->outq, NULL, NULL, xhv.val);
01144              while (jqueue_size(q) > 0)
01145                  out_pkt_free((pkt_t) jqueue_pull(q));
01146              free(q->key);
01147              jqueue_free(q);
01148         } while(xhash_iter_next(s2s->outq));
01149 
01150     /* walk & free resolve queues */
01151     xhv.dns_val = &dns;
01152     if(xhash_iter_first(s2s->dnscache))
01153         do {
01154              xhash_iter_get(s2s->dnscache, NULL, NULL, xhv.val);
01155              xhash_free(dns->results);
01156              if (dns->query != NULL) {
01157                  if (dns->query->query != NULL)
01158                      dns_cancel(NULL, dns->query->query);
01159                  xhash_free(dns->query->hosts);
01160                  xhash_free(dns->query->results);
01161                  free(dns->query->name);
01162                  free(dns->query);
01163              }
01164              free(dns);
01165         } while(xhash_iter_next(s2s->dnscache));
01166 
01167     xhv.dnsres_val = &res;
01168     if(xhash_iter_first(s2s->dns_bad))
01169         do {
01170              xhash_iter_get(s2s->dns_bad, NULL, NULL, xhv.val);
01171              free(res->key);
01172              free(res);
01173         } while(xhash_iter_next(s2s->dns_bad));
01174 
01175     if (dns_active(NULL) > 0)
01176         log_debug(ZONE, "there are still active dns queries (%d)", dns_active(NULL));
01177     dns_close(NULL);
01178 
01179     /* close mio */
01180     mio_close(s2s->mio, s2s->udns_mio_fd);
01181     if(s2s->fd != NULL)
01182         mio_close(s2s->mio, s2s->fd);
01183     if(s2s->server_fd != NULL)
01184         mio_close(s2s->mio, s2s->server_fd);
01185 
01186     /* free hashes */
01187     xhash_free(s2s->outq);
01188     xhash_free(s2s->out_host);
01189     xhash_free(s2s->out_dest);
01190     xhash_free(s2s->in);
01191     xhash_free(s2s->in_accept);
01192     xhash_free(s2s->dnscache);
01193     xhash_free(s2s->dns_bad);
01194     xhash_free(s2s->hosts);
01195 
01196     jqueue_free(s2s->dead);
01197     jqueue_free(s2s->dead_conn);
01198 
01199     sx_free(s2s->router);
01200 
01201     sx_env_free(s2s->sx_env);
01202 
01203     mio_free(s2s->mio);
01204 
01205     log_free(s2s->log);
01206 
01207     config_free(s2s->config);
01208 
01209     free(s2s->local_secret);
01210     free(s2s);
01211 
01212 #ifdef POOL_DEBUG
01213     pool_stat(1);
01214 #endif
01215 
01216     return 0;
01217 }