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 "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 = ⌖ 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 = ∁ 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 }