jabberd2  2.2.16
router/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 "router.h"
00022 
00023 static sig_atomic_t router_shutdown = 0;
00024 static sig_atomic_t router_logrotate = 0;
00025 
00026 static void router_signal(int signum)
00027 {
00028     router_shutdown = 1;
00029 }
00030 
00031 static void router_signal_hup(int signum)
00032 {
00033     router_logrotate = 1;
00034 }
00035 
00036 static void router_signal_usr1(int signum)
00037 {
00038     set_debug_flag(0);
00039 }
00040 
00041 static void router_signal_usr2(int signum)
00042 {
00043     set_debug_flag(1);
00044 }
00045 
00047 static void _router_pidfile(router_t r) {
00048     char *pidfile;
00049     FILE *f;
00050     pid_t pid;
00051 
00052     pidfile = config_get_one(r->config, "pidfile", 0);
00053     if(pidfile == NULL)
00054         return;
00055 
00056     pid = getpid();
00057 
00058     if((f = fopen(pidfile, "w+")) == NULL) {
00059         log_write(r->log, LOG_ERR, "couldn't open %s for writing: %s", pidfile, strerror(errno));
00060         return;
00061     }
00062 
00063     if(fprintf(f, "%d", pid) < 0) {
00064         log_write(r->log, LOG_ERR, "couldn't write to %s: %s", pidfile, strerror(errno));
00065         fclose(f);
00066         return;
00067     }
00068 
00069     fclose(f);
00070 
00071     log_write(r->log, LOG_INFO, "process id is %d, written to %s", pid, pidfile);
00072 }
00073 
00075 static void _router_config_expand(router_t r)
00076 {
00077     char *str, *ip, *mask, *name, *target;
00078     config_elem_t elem;
00079     int i, len;
00080     alias_t alias;
00081 
00082     r->id = config_get_one(r->config, "id", 0);
00083     if(r->id == NULL)
00084         r->id = "router";
00085 
00086     set_debug_log_from_config(r->config);
00087 
00088     r->log_type = log_STDOUT;
00089     if(config_get(r->config, "log") != NULL) {
00090         if((str = config_get_attr(r->config, "log", 0, "type")) != NULL) {
00091             if(strcmp(str, "file") == 0)
00092                 r->log_type = log_FILE;
00093             else if(strcmp(str, "syslog") == 0)
00094                 r->log_type = log_SYSLOG;
00095         }
00096     }
00097 
00098     if(r->log_type == log_SYSLOG) {
00099         r->log_facility = config_get_one(r->config, "log.facility", 0);
00100         r->log_ident = config_get_one(r->config, "log.ident", 0);
00101         if(r->log_ident == NULL)
00102             r->log_ident = "jabberd/router";
00103     } else if(r->log_type == log_FILE)
00104         r->log_ident = config_get_one(r->config, "log.file", 0);
00105 
00106     r->local_ip = config_get_one(r->config, "local.ip", 0);
00107     if(r->local_ip == NULL)
00108         r->local_ip = "0.0.0.0";
00109 
00110     r->local_port = j_atoi(config_get_one(r->config, "local.port", 0), 5347);
00111 
00112     r->local_secret = config_get_one(r->config, "local.secret", 0);
00113 
00114     r->local_pemfile = config_get_one(r->config, "local.pemfile", 0);
00115 
00116     r->io_max_fds = j_atoi(config_get_one(r->config, "io.max_fds", 0), 1024);
00117 
00118     elem = config_get(r->config, "io.limits.bytes");
00119     if(elem != NULL)
00120     {
00121         r->byte_rate_total = j_atoi(elem->values[0], 0);
00122         if(r->byte_rate_total != 0)
00123         {
00124             r->byte_rate_seconds = j_atoi(j_attr((const char **) elem->attrs[0], "seconds"), 5);
00125             r->byte_rate_wait = j_atoi(j_attr((const char **) elem->attrs[0], "throttle"), 5);
00126         }
00127     }
00128 
00129     elem = config_get(r->config, "io.limits.connects");
00130     if(elem != NULL)
00131     {
00132         r->conn_rate_total = j_atoi(elem->values[0], 0);
00133         if(r->conn_rate_total != 0)
00134         {
00135             r->conn_rate_seconds = j_atoi(j_attr((const char **) elem->attrs[0], "seconds"), 5);
00136             r->conn_rate_wait = j_atoi(j_attr((const char **) elem->attrs[0], "throttle"), 5);
00137         }
00138     }
00139 
00140     str = config_get_one(r->config, "io.access.order", 0);
00141     if(str == NULL || strcmp(str, "deny,allow") != 0)
00142         r->access = access_new(0);
00143     else
00144         r->access = access_new(1);
00145 
00146     elem = config_get(r->config, "io.access.allow");
00147     if(elem != NULL)
00148     {
00149         for(i = 0; i < elem->nvalues; i++)
00150         {
00151             ip = j_attr((const char **) elem->attrs[i], "ip");
00152             mask = j_attr((const char **) elem->attrs[i], "mask");
00153 
00154             if(ip == NULL)
00155                 continue;
00156 
00157             if(mask == NULL)
00158                 mask = "255.255.255.255";
00159 
00160             access_allow(r->access, ip, mask);
00161         }
00162     }
00163 
00164     elem = config_get(r->config, "io.access.deny");
00165     if(elem != NULL)
00166     {
00167         for(i = 0; i < elem->nvalues; i++)
00168         {
00169             ip = j_attr((const char **) elem->attrs[i], "ip");
00170             mask = j_attr((const char **) elem->attrs[i], "mask");
00171 
00172             if(ip == NULL)
00173                 continue;
00174 
00175             if(mask == NULL)
00176                 mask = "255.255.255.255";
00177 
00178             access_deny(r->access, ip, mask);
00179         }
00180     }
00181 
00182     /* aliases */
00183     elem = config_get(r->config, "aliases.alias");
00184     if(elem != NULL)
00185         for(i = 0; i < elem->nvalues; i++) {
00186             name = j_attr((const char **) elem->attrs[i], "name");
00187             target = j_attr((const char **) elem->attrs[i], "target");
00188 
00189             if(name == NULL || target == NULL)
00190                 continue;
00191 
00192             alias = (alias_t) calloc(1, sizeof(struct alias_st));
00193 
00194             alias->name = name;
00195             alias->target = target;
00196 
00197             alias->next = r->aliases;
00198             r->aliases = alias;
00199         }
00200 
00201     /* message logging to flat file */
00202     r->message_logging_enabled = j_atoi(config_get_one(r->config, "message_logging.enabled", 0), 0);
00203     r->message_logging_file = config_get_one(r->config, "message_logging.file", 0);
00204 
00205     r->check_interval = j_atoi(config_get_one(r->config, "check.interval", 0), 60);
00206     r->check_keepalive = j_atoi(config_get_one(r->config, "check.keepalive", 0), 0);
00207 }
00208 
00209 static int _router_sx_sasl_callback(int cb, void *arg, void ** res, sx_t s, void *cbarg) {
00210     router_t r = (router_t) cbarg;
00211     sx_sasl_creds_t creds;
00212     static char buf[1024];
00213     char *pass;
00214 
00215     switch(cb) {
00216         case sx_sasl_cb_GET_REALM:
00217             strcpy(buf, "jabberd-router");
00218             *res = (void *)buf;
00219             return sx_sasl_ret_OK;
00220             break;
00221 
00222         case sx_sasl_cb_GET_PASS:
00223             creds = (sx_sasl_creds_t) arg;
00224 
00225             log_debug(ZONE, "sx sasl callback: get pass (authnid=%s, realm=%s)", creds->authnid, creds->realm);
00226 
00227             pass = xhash_get(r->users, creds->authnid);
00228             if(pass == NULL)
00229                 return sx_sasl_ret_FAIL;
00230 
00231             *res = (void *)pass;
00232             return sx_sasl_ret_OK;
00233             break;
00234 
00235         case sx_sasl_cb_CHECK_PASS:
00236             creds = (sx_sasl_creds_t) arg;
00237 
00238             log_debug(ZONE, "sx sasl callback: check pass (authnid=%s, realm=%s)", creds->authnid, creds->realm);
00239 
00240             pass = xhash_get(r->users, creds->authnid);
00241             if(pass == NULL || strcmp(creds->pass, pass) != 0)
00242                 return sx_sasl_ret_OK;
00243 
00244             return sx_sasl_ret_FAIL;
00245             break;
00246 
00247         case sx_sasl_cb_CHECK_AUTHZID:
00248         creds = (sx_sasl_creds_t) arg;
00249 
00250         if (strcmp(creds->authnid, creds->authzid) == 0)
00251                 return sx_sasl_ret_OK;
00252         else
00253                 return sx_sasl_ret_FAIL;
00254             break;
00255 
00256         case sx_sasl_cb_CHECK_MECH:
00257 
00258             if (strcasecmp((char *)arg,"DIGEST-MD5")==0)
00259                 return sx_sasl_ret_OK;
00260 
00261             return sx_sasl_ret_FAIL;
00262             break;
00263 
00264         default:
00265             break;
00266     }
00267 
00268     return sx_sasl_ret_FAIL;
00269 }
00270 
00271 static void _router_time_checks(router_t r) {
00272    component_t target;
00273    time_t now;
00274    union xhashv xhv;
00275 
00276    now = time(NULL);
00277 
00278    /* loop the components and distribute an space on idle connections*/
00279    if(xhash_iter_first(r->components))
00280        do {
00281           xhv.comp_val = &target;
00282           xhash_iter_get(r->components, NULL, NULL, xhv.val);
00283 
00284          if(r->check_keepalive > 0 && target->last_activity > 0 && now > target->last_activity + r->check_keepalive && target->s->state >= state_STREAM) {
00285                log_debug(ZONE, "sending keepalive for %d", target->fd->fd);
00286                sx_raw_write(target->s, " ", 1);
00287           }
00288        } while(xhash_iter_next(r->components));
00289    return;
00290 }
00291 
00292 
00293 JABBER_MAIN("jabberd2router", "Jabber 2 Router", "Jabber Open Source Server: Router", NULL)
00294 {
00295     router_t r;
00296     char *config_file;
00297     int optchar;
00298     rate_t rt;
00299     component_t comp;
00300     union xhashv xhv;
00301     int close_wait_max;
00302     const char *cli_id = 0;
00303 
00304 #ifdef POOL_DEBUG
00305     time_t pool_time = 0;
00306 #endif
00307 
00308 #ifdef HAVE_UMASK
00309     umask((mode_t) 0027);
00310 #endif
00311 
00312     srand(time(NULL));
00313 
00314 #ifdef HAVE_WINSOCK2_H
00315 /* get winsock running */
00316     {
00317         WORD wVersionRequested;
00318         WSADATA wsaData;
00319         int err;
00320 
00321         wVersionRequested = MAKEWORD( 2, 2 );
00322 
00323         err = WSAStartup( wVersionRequested, &wsaData );
00324         if ( err != 0 ) {
00325             /* !!! tell user that we couldn't find a usable winsock dll */
00326             return 0;
00327         }
00328     }
00329 #endif
00330 
00331     jabber_signal(SIGINT, router_signal);
00332     jabber_signal(SIGTERM, router_signal);
00333 #ifdef SIGHUP
00334     jabber_signal(SIGHUP, router_signal_hup);
00335 #endif
00336 #ifdef SIGPIPE
00337     jabber_signal(SIGPIPE, SIG_IGN);
00338 #endif
00339     jabber_signal(SIGUSR1, router_signal_usr1);
00340     jabber_signal(SIGUSR2, router_signal_usr2);
00341 
00342     r = (router_t) calloc(1, sizeof(struct router_st));
00343 
00344     /* load our config */
00345     r->config = config_new();
00346 
00347     config_file = CONFIG_DIR "/router.xml";
00348 
00349     /* cmdline parsing */
00350     while((optchar = getopt(argc, argv, "Dc:hi:?")) >= 0)
00351     {
00352         switch(optchar)
00353         {
00354             case 'c':
00355                 config_file = optarg;
00356                 break;
00357             case 'D':
00358 #ifdef DEBUG
00359                 set_debug_flag(1);
00360 #else
00361                 printf("WARN: Debugging not enabled.  Ignoring -D.\n");
00362 #endif
00363                 break;
00364             case 'i':
00365                 cli_id = optarg;
00366                 break;
00367             case 'h': case '?': default:
00368                 fputs(
00369                     "router - jabberd router (" VERSION ")\n"
00370                     "Usage: router <options>\n"
00371                     "Options are:\n"
00372                     "   -c <config>     config file to use [default: " CONFIG_DIR "/router.xml]\n"
00373                     "   -i id           Override <id> config element\n"
00374 #ifdef DEBUG
00375                     "   -D              Show debug output\n"
00376 #endif
00377                     ,
00378                     stdout);
00379                 config_free(r->config);
00380                 free(r);
00381                 return 1;
00382         }
00383     }
00384 
00385     if(config_load_with_id(r->config, config_file, cli_id) != 0)
00386     {
00387         fputs("router: couldn't load config, aborting\n", stderr);
00388         config_free(r->config);
00389         free(r);
00390         return 2;
00391     }
00392 
00393     _router_config_expand(r);
00394 
00395     r->log = log_new(r->log_type, r->log_ident, r->log_facility);
00396     log_write(r->log, LOG_NOTICE, "starting up");
00397 
00398     _router_pidfile(r);
00399 
00400     user_table_load(r);
00401 
00402     r->aci = aci_load(r);
00403 
00404     if(filter_load(r)) exit(1);
00405 
00406     r->conn_rates = xhash_new(101);
00407 
00408     r->components = xhash_new(101);
00409     r->routes = xhash_new(101);
00410 
00411     r->log_sinks = xhash_new(101);
00412 
00413     r->dead = jqueue_new();
00414     r->closefd = jqueue_new();
00415     r->deadroutes = jqueue_new();
00416 
00417     r->sx_env = sx_env_new();
00418 
00419 #ifdef HAVE_SSL
00420     if(r->local_pemfile != NULL) {
00421         r->sx_ssl = sx_env_plugin(r->sx_env, sx_ssl_init, NULL, r->local_pemfile, NULL, NULL);
00422         if(r->sx_ssl == NULL)
00423             log_write(r->log, LOG_ERR, "failed to load SSL pemfile, SSL disabled");
00424     }
00425 #endif
00426 
00427     /* get sasl online */
00428     r->sx_sasl = sx_env_plugin(r->sx_env, sx_sasl_init, "jabberd-router", _router_sx_sasl_callback, (void *) r);
00429     if(r->sx_sasl == NULL) {
00430         log_write(r->log, LOG_ERR, "failed to initialise SASL context, aborting");
00431         exit(1);
00432     }
00433 
00434     r->mio = mio_new(r->io_max_fds);
00435 
00436     r->fd = mio_listen(r->mio, r->local_port, r->local_ip, router_mio_callback, (void *) r);
00437     if(r->fd == NULL) {
00438         log_write(r->log, LOG_ERR, "[%s, port=%d] unable to listen (%s)", r->local_ip, r->local_port, MIO_STRERROR(MIO_ERROR));
00439         exit(1);
00440     }
00441 
00442     log_write(r->log, LOG_NOTICE, "[%s, port=%d] listening for incoming connections", r->local_ip, r->local_port, MIO_STRERROR(MIO_ERROR));
00443 
00444     while(!router_shutdown)
00445     {
00446         mio_run(r->mio, 5);
00447 
00448         if(router_logrotate)
00449         {
00450             set_debug_log_from_config(r->config);
00451 
00452             log_write(r->log, LOG_NOTICE, "reopening log ...");
00453             log_free(r->log);
00454             r->log = log_new(r->log_type, r->log_ident, r->log_facility);
00455             log_write(r->log, LOG_NOTICE, "log started");
00456 
00457             log_write(r->log, LOG_NOTICE, "reloading filter ...");
00458             filter_unload(r);
00459             filter_load(r);
00460 
00461             log_write(r->log, LOG_NOTICE, "reloading users ...");
00462             user_table_unload(r);
00463             user_table_load(r);
00464 
00465             router_logrotate = 0;
00466         }
00467 
00468         /* cleanup dead sx_ts */
00469         while(jqueue_size(r->dead) > 0)
00470             sx_free((sx_t) jqueue_pull(r->dead));
00471 
00472         /* cleanup closed fd */
00473         while(jqueue_size(r->closefd) > 0)
00474             mio_close(r->mio, (mio_fd_t) jqueue_pull(r->closefd));
00475 
00476         /* cleanup dead routes */
00477         while(jqueue_size(r->deadroutes) > 0)
00478             routes_free((routes_t) jqueue_pull(r->deadroutes));
00479 
00480         /* time checks */
00481         if(r->check_interval > 0 && time(NULL) >= r->next_check) {
00482             log_debug(ZONE, "running time checks");
00483 
00484             _router_time_checks(r);
00485 
00486             r->next_check = time(NULL) + r->check_interval;
00487             log_debug(ZONE, "next time check at %d", r->next_check);
00488         }
00489 
00490 #ifdef POOL_DEBUG
00491         if(time(NULL) > pool_time + 60) {
00492             pool_stat(1);
00493             pool_time = time(NULL);
00494         }
00495 #endif
00496     }
00497 
00498     log_write(r->log, LOG_NOTICE, "shutting down");
00499 
00500     /* stop accepting new connections */
00501     if (r->fd) {
00502         // HACK Do not call router_mio_callback(action_CLOSE) for listenning socket, Just close it and forget.
00503         mio_app(r->mio, r->fd, NULL, NULL);
00504         mio_close(r->mio, r->fd);
00505     }
00506 
00507     /*
00508      * !!! issue remote shutdowns to each service, so they can clean up.
00509      *     we'll need to mio_run() until they all disconnect, so that
00510      *     the the last packets (eg sm presence unavailables) can get to
00511      *     their destinations
00512      */
00513 
00514     close_wait_max = 30; /* time limit for component shutdown */
00515 
00516     /* close connections to components */
00517     xhv.comp_val = &comp;
00518     if(xhash_iter_first(r->components))
00519         do {
00520             xhash_iter_get(r->components, NULL, NULL, xhv.val);
00521             log_debug(ZONE, "close component %p", comp);
00522             if (comp) sx_close(comp->s);
00523             mio_run(r->mio, 5000);
00524             if (1 > close_wait_max--) break;
00525             sleep(1);
00526             while(jqueue_size(r->closefd) > 0)
00527                 mio_close(r->mio, (mio_fd_t) jqueue_pull(r->closefd));
00528         } while (xhash_iter_next(r->components));
00529 
00530     xhash_free(r->components);
00531 
00532     /* cleanup dead sx_ts */
00533     while(jqueue_size(r->dead) > 0)
00534        sx_free((sx_t) jqueue_pull(r->dead));
00535     jqueue_free(r->dead);
00536 
00537     while(jqueue_size(r->closefd) > 0)
00538         mio_close(r->mio, (mio_fd_t) jqueue_pull(r->closefd));
00539     jqueue_free(r->closefd);
00540 
00541     /* cleanup dead routes - probably just showed up (route was just closed) */
00542     while(jqueue_size(r->deadroutes) > 0)
00543         routes_free((routes_t) jqueue_pull(r->deadroutes));
00544     jqueue_free(r->deadroutes);
00545 
00546     /* walk r->conn_rates and free */
00547     xhv.rt_val = &rt;
00548     if(xhash_iter_first(r->conn_rates))
00549         do {
00550             xhash_iter_get(r->conn_rates, NULL, NULL, xhv.val);
00551             rate_free(rt);
00552         } while(xhash_iter_next(r->conn_rates));
00553 
00554     xhash_free(r->conn_rates);
00555 
00556     xhash_free(r->log_sinks);
00557 
00558     /* walk r->routes and free */
00559     if (xhash_iter_first(r->routes))
00560         do {
00561             routes_t p;
00562             xhash_iter_get(r->routes, NULL, NULL, (void *) &p);
00563             routes_free(p);
00564         } while(xhash_iter_next(r->routes));
00565     xhash_free(r->routes);
00566 
00567     /* unload users */
00568     user_table_unload(r);
00569 
00570     /* unload acls */
00571     aci_unload(r->aci);
00572 
00573     /* unload filter */
00574     filter_unload(r);
00575 
00576     sx_env_free(r->sx_env);
00577 
00578     mio_free(r->mio);
00579 
00580     access_free(r->access);
00581 
00582     log_free(r->log);
00583 
00584     config_free(r->config);
00585 
00586     free(r);
00587 
00588 #ifdef POOL_DEBUG
00589     pool_stat(1);
00590 #endif
00591 
00592 #ifdef HAVE_WINSOCK2_H
00593     WSACleanup();
00594 #endif
00595 
00596     return 0;
00597 }