jabberd2
2.2.16
|
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 }