jabberd2  2.2.16
sm/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 "sm.h"
00022 #include <stringprep.h>
00023 
00031 static sig_atomic_t sm_shutdown = 0;
00032 static sig_atomic_t sm_logrotate = 0;
00033 static sm_t sm = NULL;
00034 static char* config_file;
00035 
00036 static void _sm_signal(int signum)
00037 {
00038     sm_shutdown = 1;
00039     sm_lost_router = 0;
00040 }
00041 
00042 static void _sm_signal_hup(int signum)
00043 {
00044     config_t conf;
00045 
00046     log_write(sm->log, LOG_NOTICE, "HUP handled. reloading modules...");
00047 
00048     sm_logrotate = 1;
00049 
00050     /* reload dynamic modules */
00051     conf = config_new();
00052     if (conf && config_load(conf, config_file) == 0) {
00053         config_free(sm->config);
00054         sm->config = conf;
00055         /*_sm_config_expand(sm);*/ /* we want to reload modules only */
00056     } else {
00057         log_write(sm->log, LOG_WARNING, "couldn't reload config (%s)", config_file);
00058         if (conf) config_free(conf);
00059     }
00060     mm_free(sm->mm);
00061     sm->mm = mm_new(sm);
00062 }
00063 
00064 static void _sm_signal_usr1(int signum)
00065 {
00066     set_debug_flag(0);
00067 }
00068 
00069 static void _sm_signal_usr2(int signum)
00070 {
00071     set_debug_flag(1);
00072 }
00073 
00075 static void _sm_pidfile(sm_t sm) {
00076     char *pidfile;
00077     FILE *f;
00078     pid_t pid;
00079 
00080     pidfile = config_get_one(sm->config, "pidfile", 0);
00081     if(pidfile == NULL)
00082         return;
00083 
00084     pid = getpid();
00085 
00086     if((f = fopen(pidfile, "w+")) == NULL) {
00087         log_write(sm->log, LOG_ERR, "couldn't open %s for writing: %s", pidfile, strerror(errno));
00088         return;
00089     }
00090 
00091     if(fprintf(f, "%d", pid) < 0) {
00092         log_write(sm->log, LOG_ERR, "couldn't write to %s: %s", pidfile, strerror(errno));
00093         fclose(f);
00094         return;
00095     }
00096 
00097     fclose(f);
00098 
00099     log_write(sm->log, LOG_INFO, "process id is %d, written to %s", pid, pidfile);
00100 }
00101 
00103 static void _sm_config_expand(sm_t sm)
00104 {
00105     char *str;
00106     config_elem_t elem;
00107 
00108     set_debug_log_from_config(sm->config);
00109 
00110     sm->id = config_get_one(sm->config, "id", 0);
00111     if(sm->id == NULL)
00112         sm->id = "sm";
00113 
00114     sm->router_ip = config_get_one(sm->config, "router.ip", 0);
00115     if(sm->router_ip == NULL)
00116         sm->router_ip = "127.0.0.1";
00117 
00118     sm->router_port = j_atoi(config_get_one(sm->config, "router.port", 0), 5347);
00119 
00120     sm->router_user = config_get_one(sm->config, "router.user", 0);
00121     if(sm->router_user == NULL)
00122         sm->router_user = "jabberd";
00123     sm->router_pass = config_get_one(sm->config, "router.pass", 0);
00124     if(sm->router_pass == NULL)
00125         sm->router_pass = "secret";
00126 
00127     sm->router_pemfile = config_get_one(sm->config, "router.pemfile", 0);
00128 
00129     sm->retry_init = j_atoi(config_get_one(sm->config, "router.retry.init", 0), 3);
00130     sm->retry_lost = j_atoi(config_get_one(sm->config, "router.retry.lost", 0), 3);
00131     if((sm->retry_sleep = j_atoi(config_get_one(sm->config, "router.retry.sleep", 0), 2)) < 1)
00132         sm->retry_sleep = 1;
00133 
00134     sm->log_type = log_STDOUT;
00135     if(config_get(sm->config, "log") != NULL) {
00136         if((str = config_get_attr(sm->config, "log", 0, "type")) != NULL) {
00137             if(strcmp(str, "file") == 0)
00138                 sm->log_type = log_FILE;
00139             else if(strcmp(str, "syslog") == 0)
00140                 sm->log_type = log_SYSLOG;
00141         }
00142     }
00143 
00144     if(sm->log_type == log_SYSLOG) {
00145         sm->log_facility = config_get_one(sm->config, "log.facility", 0);
00146         sm->log_ident = config_get_one(sm->config, "log.ident", 0);
00147         if(sm->log_ident == NULL)
00148             sm->log_ident = "jabberd/sm";
00149     } else if(sm->log_type == log_FILE)
00150         sm->log_ident = config_get_one(sm->config, "log.file", 0);
00151         
00152     elem = config_get(sm->config, "storage.limits.queries");
00153     if(elem != NULL)
00154     {
00155         sm->query_rate_total = j_atoi(elem->values[0], 0);
00156         if(sm->query_rate_total != 0)
00157         {
00158             sm->query_rate_seconds = j_atoi(j_attr((const char **) elem->attrs[0], "seconds"), 5);
00159             sm->query_rate_wait = j_atoi(j_attr((const char **) elem->attrs[0], "throttle"), 60);
00160         }
00161     }
00162 }
00163 
00164 static void _sm_hosts_expand(sm_t sm)
00165 {
00166     config_elem_t elem;
00167     char id[1024];
00168     int i;
00169 
00170     elem = config_get(sm->config, "local.id");
00171     if(!elem) {
00172         /* use SM id */
00173         xhash_put(sm->hosts, pstrdup(xhash_pool(sm->hosts), sm->id), sm);
00174         log_write(sm->log, LOG_NOTICE, "id: %s", sm->id);
00175         return;
00176     }
00177 
00178     for(i = 0; i < elem->nvalues; i++) {
00179         /* stringprep ids (domain names) so that they are in canonical form */
00180         strncpy(id, elem->values[i], 1024);
00181         id[1023] = '\0';
00182         if (stringprep_nameprep(id, 1024) != 0) {
00183             log_write(sm->log, LOG_ERR, "cannot stringprep id %s, aborting", id);
00184             exit(1);
00185         }
00186 
00187         /* insert into vHosts xhash */
00188         xhash_put(sm->hosts, pstrdup(xhash_pool(sm->hosts), id), sm);
00189 
00190         log_write(sm->log, LOG_NOTICE, "[%s] configured", id);
00191     }
00192 }
00193 
00194 static int _sm_router_connect(sm_t sm) {
00195     log_write(sm->log, LOG_NOTICE, "attempting connection to router at %s, port=%d", sm->router_ip, sm->router_port);
00196 
00197     sm->fd = mio_connect(sm->mio, sm->router_port, sm->router_ip, NULL, sm_mio_callback, (void *) sm);
00198     if(sm->fd == NULL) {
00199         if(errno == ECONNREFUSED)
00200             sm_lost_router = 1;
00201         log_write(sm->log, LOG_NOTICE, "connection attempt to router failed: %s (%d)", MIO_STRERROR(MIO_ERROR), MIO_ERROR);
00202         return 1;
00203     }
00204 
00205     sm->router = sx_new(sm->sx_env, sm->fd->fd, sm_sx_callback, (void *) sm);
00206     sx_client_init(sm->router, 0, NULL, NULL, NULL, "1.0");
00207 
00208     return 0;
00209 }
00210 
00211 JABBER_MAIN("jabberd2sm", "Jabber 2 Session Manager", "Jabber Open Source Server: Session Manager", "jabberd2router\0")
00212 {
00213     int optchar;
00214     sess_t sess;
00215     char id[1024];
00216 #ifdef POOL_DEBUG
00217     time_t pool_time = 0;
00218 #endif
00219     const char *cli_id = 0;
00220 
00221 #ifdef HAVE_UMASK
00222     umask((mode_t) 0027);
00223 #endif
00224 
00225     srand(time(NULL));
00226 
00227 #ifdef HAVE_WINSOCK2_H
00228 /* get winsock running */
00229     {
00230         WORD wVersionRequested;
00231         WSADATA wsaData;
00232         int err;
00233 
00234         wVersionRequested = MAKEWORD( 2, 2 );
00235 
00236         err = WSAStartup( wVersionRequested, &wsaData );
00237         if ( err != 0 ) {
00238             /* !!! tell user that we couldn't find a usable winsock dll */
00239             return 0;
00240         }
00241     }
00242 #endif
00243 
00244     jabber_signal(SIGINT, _sm_signal);
00245     jabber_signal(SIGTERM, _sm_signal);
00246 #ifdef SIGHUP
00247     jabber_signal(SIGHUP, _sm_signal_hup);
00248 #endif
00249 #ifdef SIGPIPE
00250     jabber_signal(SIGPIPE, SIG_IGN);
00251 #endif
00252     jabber_signal(SIGUSR1, _sm_signal_usr1);
00253     jabber_signal(SIGUSR2, _sm_signal_usr2);
00254 
00255 
00256     sm = (sm_t) calloc(1, sizeof(struct sm_st));
00257 
00258     /* load our config */
00259     sm->config = config_new();
00260 
00261     config_file = CONFIG_DIR "/sm.xml";
00262 
00263     /* cmdline parsing */
00264     while((optchar = getopt(argc, argv, "Dc:hi:?")) >= 0)
00265     {
00266         switch(optchar)
00267         {
00268             case 'c':
00269                 config_file = optarg;
00270                 break;
00271             case 'D':
00272 #ifdef DEBUG
00273                 set_debug_flag(1);
00274 #else
00275                 printf("WARN: Debugging not enabled.  Ignoring -D.\n");
00276 #endif
00277                 break;
00278             case 'i':
00279                 cli_id = optarg;
00280                 break;
00281             case 'h': case '?': default:
00282                 fputs(
00283                     "sm - jabberd session manager (" VERSION ")\n"
00284                     "Usage: sm <options>\n"
00285                     "Options are:\n"
00286                     "   -c <config>     config file to use [default: " CONFIG_DIR "/sm.xml]\n"
00287                     "   -i id           Override <id> config element\n"
00288 #ifdef DEBUG
00289                     "   -D              Show debug output\n"
00290 #endif
00291                     ,
00292                     stdout);
00293                 config_free(sm->config);
00294                 free(sm);
00295                 return 1;
00296         }
00297     }
00298 
00299     if(config_load_with_id(sm->config, config_file, cli_id) != 0)
00300     {
00301         fputs("sm: couldn't load config, aborting\n", stderr);
00302         config_free(sm->config);
00303         free(sm);
00304         return 2;
00305     }
00306 
00307     _sm_config_expand(sm);
00308 
00309     sm->log = log_new(sm->log_type, sm->log_ident, sm->log_facility);
00310     log_write(sm->log, LOG_NOTICE, "starting up");
00311 
00312     /* stringprep id (domain name) so that it's in canonical form */
00313     strncpy(id, sm->id, 1024);
00314     id[sizeof(id)-1] = '\0';
00315     if (stringprep_nameprep(id, 1024) != 0) {
00316         log_write(sm->log, LOG_ERR, "cannot stringprep id %s, aborting", sm->id);
00317         exit(1);
00318     }
00319     sm->id = id;
00320 
00321     _sm_pidfile(sm);
00322 
00323     sm_signature(sm, PACKAGE " sm " VERSION);
00324 
00325     /* start storage */
00326     sm->st = storage_new(sm->config, sm->log);
00327     if (sm->st == NULL) {
00328         log_write(sm->log, LOG_ERR, "failed to initialise one or more storage drivers, aborting");
00329         exit(1);
00330     }
00331 
00332     /* pre-index known namespaces */
00333     sm->xmlns = xhash_new(101);
00334     xhash_put(sm->xmlns, uri_AUTH, (void *) ns_AUTH);
00335     xhash_put(sm->xmlns, uri_REGISTER, (void *) ns_REGISTER);
00336     xhash_put(sm->xmlns, uri_ROSTER, (void *) ns_ROSTER);
00337     xhash_put(sm->xmlns, uri_AGENTS, (void *) ns_AGENTS);
00338     xhash_put(sm->xmlns, uri_DELAY, (void *) ns_DELAY);
00339     xhash_put(sm->xmlns, uri_BROWSE, (void *) ns_BROWSE);
00340     xhash_put(sm->xmlns, uri_EVENT, (void *) ns_EVENT);
00341     xhash_put(sm->xmlns, uri_GATEWAY, (void *) ns_GATEWAY);
00342     xhash_put(sm->xmlns, uri_EXPIRE, (void *) ns_EXPIRE);
00343     xhash_put(sm->xmlns, uri_SEARCH, (void *) ns_SEARCH);
00344     xhash_put(sm->xmlns, uri_DISCO, (void *) ns_DISCO);
00345     xhash_put(sm->xmlns, uri_DISCO_ITEMS, (void *) ns_DISCO_ITEMS);
00346     xhash_put(sm->xmlns, uri_DISCO_INFO, (void *) ns_DISCO_INFO);
00347     sm->xmlns_refcount = xhash_new(101);
00348 
00349     /* supported features */
00350     sm->features = xhash_new(101);
00351 
00352     /* load acls */
00353     sm->acls = aci_load(sm);
00354 
00355     /* the core supports iq, everything else is handled by the modules */
00356     feature_register(sm, "iq");
00357 
00358     /* startup the modules */
00359     sm->mm = mm_new(sm);
00360 
00361     log_write(sm->log, LOG_NOTICE, "version: %s", sm->signature);
00362 
00363     sm->sessions = xhash_new(401);
00364 
00365     sm->users = xhash_new(401);
00366 
00367     sm->query_rates = xhash_new(101);
00368 
00369     sm->sx_env = sx_env_new();
00370 
00371 #ifdef HAVE_SSL
00372     if(sm->router_pemfile != NULL) {
00373         sm->sx_ssl = sx_env_plugin(sm->sx_env, sx_ssl_init, NULL, sm->router_pemfile, NULL, NULL);
00374         if(sm->sx_ssl == NULL) {
00375             log_write(sm->log, LOG_ERR, "failed to load SSL pemfile, SSL disabled");
00376             sm->router_pemfile = NULL;
00377         }
00378     }
00379 #endif
00380 
00381     /* get sasl online */
00382     sm->sx_sasl = sx_env_plugin(sm->sx_env, sx_sasl_init, "xmpp", NULL, NULL);
00383     if(sm->sx_sasl == NULL) {
00384         log_write(sm->log, LOG_ERR, "failed to initialise SASL context, aborting");
00385         exit(1);
00386     }
00387 
00388     sm->mio = mio_new(MIO_MAXFD);
00389 
00390     /* vHosts map */
00391     sm->hosts = xhash_new(1021);
00392     _sm_hosts_expand(sm);
00393 
00394     sm->retry_left = sm->retry_init;
00395     _sm_router_connect(sm);
00396     
00397     while(!sm_shutdown) {
00398         mio_run(sm->mio, 5);
00399 
00400         if(sm_logrotate) {
00401             set_debug_log_from_config(sm->config);
00402 
00403             log_write(sm->log, LOG_NOTICE, "reopening log ...");
00404             log_free(sm->log);
00405             sm->log = log_new(sm->log_type, sm->log_ident, sm->log_facility);
00406             log_write(sm->log, LOG_NOTICE, "log started");
00407 
00408             sm_logrotate = 0;
00409         }
00410 
00411         if(sm_lost_router) {
00412             if(sm->retry_left < 0) {
00413                 log_write(sm->log, LOG_NOTICE, "attempting reconnect");
00414                 sleep(sm->retry_sleep);
00415                 sm_lost_router = 0;
00416                 if (sm->router) sx_free(sm->router);
00417                 _sm_router_connect(sm);
00418             }
00419 
00420             else if(sm->retry_left == 0) {
00421                 sm_shutdown = 1;
00422             }
00423 
00424             else {
00425                 log_write(sm->log, LOG_NOTICE, "attempting reconnect (%d left)", sm->retry_left);
00426                 sm->retry_left--;
00427                 sleep(sm->retry_sleep);
00428                 sm_lost_router = 0;
00429                 if (sm->router) sx_free(sm->router);
00430                 _sm_router_connect(sm);
00431             }
00432         }
00433 
00434 #ifdef POOL_DEBUG
00435         if(time(NULL) > pool_time + 60) {
00436             pool_stat(1);
00437             pool_time = time(NULL);
00438         }
00439 #endif
00440     }
00441 
00442     log_write(sm->log, LOG_NOTICE, "shutting down");
00443 
00444     /* shut down sessions */
00445     if(xhash_iter_first(sm->sessions))
00446         do {
00447             xhash_iter_get(sm->sessions, NULL, NULL, (void *) &sess);
00448             sm_c2s_action(sess, "ended", NULL);
00449             sess_end(sess);
00450         } while (xhash_iter_next(sm->sessions));
00451 
00452     xhash_free(sm->sessions);
00453 
00454     if (sm->fd) mio_close(sm->mio, sm->fd);
00455     mio_free(sm->mio);
00456 
00457     mm_free(sm->mm);
00458     storage_free(sm->st);
00459 
00460     aci_unload(sm->acls);
00461     xhash_free(sm->acls);
00462     xhash_free(sm->features);
00463     xhash_free(sm->xmlns);
00464     xhash_free(sm->xmlns_refcount);
00465     xhash_free(sm->users);
00466     xhash_free(sm->hosts);
00467     xhash_free(sm->query_rates);
00468 
00469     sx_free(sm->router);
00470 
00471     sx_env_free(sm->sx_env);
00472 
00473     log_free(sm->log);
00474 
00475     config_free(sm->config);
00476 
00477     free(sm);
00478 
00479 #ifdef POOL_DEBUG
00480     pool_stat(1);
00481 #endif
00482 
00483 #ifdef HAVE_WINSOCK2_H
00484     WSACleanup();
00485 #endif
00486 
00487     return 0;
00488 }