jabberd2  2.2.17
main.c
Go to the documentation of this file.
1 /*
2  * jabberd - Jabber Open Source Server
3  * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney,
4  * Ryan Eatmon, Robert Norris
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA
19  */
20 
21 #include "router.h"
22 
23 static sig_atomic_t router_shutdown = 0;
24 static sig_atomic_t router_logrotate = 0;
25 
26 static void router_signal(int signum)
27 {
28  router_shutdown = 1;
29 }
30 
31 static void router_signal_hup(int signum)
32 {
33  router_logrotate = 1;
34 }
35 
36 static void router_signal_usr1(int signum)
37 {
38  set_debug_flag(0);
39 }
40 
41 static void router_signal_usr2(int signum)
42 {
43  set_debug_flag(1);
44 }
45 
47 static void _router_pidfile(router_t r) {
48  char *pidfile;
49  FILE *f;
50  pid_t pid;
51 
52  pidfile = config_get_one(r->config, "pidfile", 0);
53  if(pidfile == NULL)
54  return;
55 
56  pid = getpid();
57 
58  if((f = fopen(pidfile, "w+")) == NULL) {
59  log_write(r->log, LOG_ERR, "couldn't open %s for writing: %s", pidfile, strerror(errno));
60  return;
61  }
62 
63  if(fprintf(f, "%d", pid) < 0) {
64  log_write(r->log, LOG_ERR, "couldn't write to %s: %s", pidfile, strerror(errno));
65  fclose(f);
66  return;
67  }
68 
69  fclose(f);
70 
71  log_write(r->log, LOG_INFO, "process id is %d, written to %s", pid, pidfile);
72 }
73 
76 {
77  char *str, *ip, *mask, *name, *target;
78  config_elem_t elem;
79  int i, len;
80  alias_t alias;
81 
82  r->id = config_get_one(r->config, "id", 0);
83  if(r->id == NULL)
84  r->id = "router";
85 
87 
88  r->log_type = log_STDOUT;
89  if(config_get(r->config, "log") != NULL) {
90  if((str = config_get_attr(r->config, "log", 0, "type")) != NULL) {
91  if(strcmp(str, "file") == 0)
92  r->log_type = log_FILE;
93  else if(strcmp(str, "syslog") == 0)
94  r->log_type = log_SYSLOG;
95  }
96  }
97 
98  if(r->log_type == log_SYSLOG) {
99  r->log_facility = config_get_one(r->config, "log.facility", 0);
100  r->log_ident = config_get_one(r->config, "log.ident", 0);
101  if(r->log_ident == NULL)
102  r->log_ident = "jabberd/router";
103  } else if(r->log_type == log_FILE)
104  r->log_ident = config_get_one(r->config, "log.file", 0);
105 
106  r->local_ip = config_get_one(r->config, "local.ip", 0);
107  if(r->local_ip == NULL)
108  r->local_ip = "0.0.0.0";
109 
110  r->local_port = j_atoi(config_get_one(r->config, "local.port", 0), 5347);
111 
112  r->local_secret = config_get_one(r->config, "local.secret", 0);
113 
114  r->local_pemfile = config_get_one(r->config, "local.pemfile", 0);
115 
116  r->io_max_fds = j_atoi(config_get_one(r->config, "io.max_fds", 0), 1024);
117 
118  elem = config_get(r->config, "io.limits.bytes");
119  if(elem != NULL)
120  {
121  r->byte_rate_total = j_atoi(elem->values[0], 0);
122  if(r->byte_rate_total != 0)
123  {
124  r->byte_rate_seconds = j_atoi(j_attr((const char **) elem->attrs[0], "seconds"), 5);
125  r->byte_rate_wait = j_atoi(j_attr((const char **) elem->attrs[0], "throttle"), 5);
126  }
127  }
128 
129  elem = config_get(r->config, "io.limits.connects");
130  if(elem != NULL)
131  {
132  r->conn_rate_total = j_atoi(elem->values[0], 0);
133  if(r->conn_rate_total != 0)
134  {
135  r->conn_rate_seconds = j_atoi(j_attr((const char **) elem->attrs[0], "seconds"), 5);
136  r->conn_rate_wait = j_atoi(j_attr((const char **) elem->attrs[0], "throttle"), 5);
137  }
138  }
139 
140  str = config_get_one(r->config, "io.access.order", 0);
141  if(str == NULL || strcmp(str, "deny,allow") != 0)
142  r->access = access_new(0);
143  else
144  r->access = access_new(1);
145 
146  elem = config_get(r->config, "io.access.allow");
147  if(elem != NULL)
148  {
149  for(i = 0; i < elem->nvalues; i++)
150  {
151  ip = j_attr((const char **) elem->attrs[i], "ip");
152  mask = j_attr((const char **) elem->attrs[i], "mask");
153 
154  if(ip == NULL)
155  continue;
156 
157  if(mask == NULL)
158  mask = "255.255.255.255";
159 
160  access_allow(r->access, ip, mask);
161  }
162  }
163 
164  elem = config_get(r->config, "io.access.deny");
165  if(elem != NULL)
166  {
167  for(i = 0; i < elem->nvalues; i++)
168  {
169  ip = j_attr((const char **) elem->attrs[i], "ip");
170  mask = j_attr((const char **) elem->attrs[i], "mask");
171 
172  if(ip == NULL)
173  continue;
174 
175  if(mask == NULL)
176  mask = "255.255.255.255";
177 
178  access_deny(r->access, ip, mask);
179  }
180  }
181 
182  /* aliases */
183  elem = config_get(r->config, "aliases.alias");
184  if(elem != NULL)
185  for(i = 0; i < elem->nvalues; i++) {
186  name = j_attr((const char **) elem->attrs[i], "name");
187  target = j_attr((const char **) elem->attrs[i], "target");
188 
189  if(name == NULL || target == NULL)
190  continue;
191 
192  alias = (alias_t) calloc(1, sizeof(struct alias_st));
193 
194  alias->name = name;
195  alias->target = target;
196 
197  alias->next = r->aliases;
198  r->aliases = alias;
199  }
200 
201  /* message logging to flat file */
202  r->message_logging_enabled = j_atoi(config_get_one(r->config, "message_logging.enabled", 0), 0);
203  r->message_logging_file = config_get_one(r->config, "message_logging.file", 0);
204 
205  r->check_interval = j_atoi(config_get_one(r->config, "check.interval", 0), 60);
206  r->check_keepalive = j_atoi(config_get_one(r->config, "check.keepalive", 0), 0);
207 }
208 
209 static int _router_sx_sasl_callback(int cb, void *arg, void ** res, sx_t s, void *cbarg) {
210  router_t r = (router_t) cbarg;
211  sx_sasl_creds_t creds;
212  static char buf[1024];
213  char *pass;
214 
215  switch(cb) {
217  strcpy(buf, "jabberd-router");
218  *res = (void *)buf;
219  return sx_sasl_ret_OK;
220  break;
221 
222  case sx_sasl_cb_GET_PASS:
223  creds = (sx_sasl_creds_t) arg;
224 
225  log_debug(ZONE, "sx sasl callback: get pass (authnid=%s, realm=%s)", creds->authnid, creds->realm);
226 
227  pass = xhash_get(r->users, creds->authnid);
228  if(pass == NULL)
229  return sx_sasl_ret_FAIL;
230 
231  *res = (void *)pass;
232  return sx_sasl_ret_OK;
233  break;
234 
236  creds = (sx_sasl_creds_t) arg;
237 
238  log_debug(ZONE, "sx sasl callback: check pass (authnid=%s, realm=%s)", creds->authnid, creds->realm);
239 
240  pass = xhash_get(r->users, creds->authnid);
241  if(pass == NULL || strcmp(creds->pass, pass) != 0)
242  return sx_sasl_ret_OK;
243 
244  return sx_sasl_ret_FAIL;
245  break;
246 
248  creds = (sx_sasl_creds_t) arg;
249 
250  if (strcmp(creds->authnid, creds->authzid) == 0)
251  return sx_sasl_ret_OK;
252  else
253  return sx_sasl_ret_FAIL;
254  break;
255 
257 
258  if (strcasecmp((char *)arg,"DIGEST-MD5")==0)
259  return sx_sasl_ret_OK;
260 
261  return sx_sasl_ret_FAIL;
262  break;
263 
264  default:
265  break;
266  }
267 
268  return sx_sasl_ret_FAIL;
269 }
270 
272  component_t target;
273  time_t now;
274  union xhashv xhv;
275 
276  now = time(NULL);
277 
278  /* loop the components and distribute an space on idle connections*/
280  do {
281  xhv.comp_val = &target;
282  xhash_iter_get(r->components, NULL, NULL, xhv.val);
283 
284  if(r->check_keepalive > 0 && target->last_activity > 0 && now > target->last_activity + r->check_keepalive && target->s->state >= state_STREAM) {
285  log_debug(ZONE, "sending keepalive for %d", target->fd->fd);
286  sx_raw_write(target->s, " ", 1);
287  }
288  } while(xhash_iter_next(r->components));
289  return;
290 }
291 
292 
293 JABBER_MAIN("jabberd2router", "Jabber 2 Router", "Jabber Open Source Server: Router", NULL)
294 {
295  router_t r;
296  char *config_file;
297  int optchar;
298  rate_t rt;
299  component_t comp;
300  union xhashv xhv;
301  int close_wait_max;
302  const char *cli_id = 0;
303 
304 #ifdef POOL_DEBUG
305  time_t pool_time = 0;
306 #endif
307 
308 #ifdef HAVE_UMASK
309  umask((mode_t) 0027);
310 #endif
311 
312  srand(time(NULL));
313 
314 #ifdef HAVE_WINSOCK2_H
315 /* get winsock running */
316  {
317  WORD wVersionRequested;
318  WSADATA wsaData;
319  int err;
320 
321  wVersionRequested = MAKEWORD( 2, 2 );
322 
323  err = WSAStartup( wVersionRequested, &wsaData );
324  if ( err != 0 ) {
325  /* !!! tell user that we couldn't find a usable winsock dll */
326  return 0;
327  }
328  }
329 #endif
330 
331  jabber_signal(SIGINT, router_signal);
332  jabber_signal(SIGTERM, router_signal);
333 #ifdef SIGHUP
335 #endif
336 #ifdef SIGPIPE
337  jabber_signal(SIGPIPE, SIG_IGN);
338 #endif
341 
342  r = (router_t) calloc(1, sizeof(struct router_st));
343 
344  /* load our config */
345  r->config = config_new();
346 
347  config_file = CONFIG_DIR "/router.xml";
348 
349  /* cmdline parsing */
350  while((optchar = getopt(argc, argv, "Dc:hi:?")) >= 0)
351  {
352  switch(optchar)
353  {
354  case 'c':
355  config_file = optarg;
356  break;
357  case 'D':
358 #ifdef DEBUG
359  set_debug_flag(1);
360 #else
361  printf("WARN: Debugging not enabled. Ignoring -D.\n");
362 #endif
363  break;
364  case 'i':
365  cli_id = optarg;
366  break;
367  case 'h': case '?': default:
368  fputs(
369  "router - jabberd router (" VERSION ")\n"
370  "Usage: router <options>\n"
371  "Options are:\n"
372  " -c <config> config file to use [default: " CONFIG_DIR "/router.xml]\n"
373  " -i id Override <id> config element\n"
374 #ifdef DEBUG
375  " -D Show debug output\n"
376 #endif
377  ,
378  stdout);
379  config_free(r->config);
380  free(r);
381  return 1;
382  }
383  }
384 
385  if(config_load_with_id(r->config, config_file, cli_id) != 0)
386  {
387  fputs("router: couldn't load config, aborting\n", stderr);
388  config_free(r->config);
389  free(r);
390  return 2;
391  }
392 
394 
395  r->log = log_new(r->log_type, r->log_ident, r->log_facility);
396  log_write(r->log, LOG_NOTICE, "starting up");
397 
398  _router_pidfile(r);
399 
400  user_table_load(r);
401 
402  r->aci = aci_load(r);
403 
404  if(filter_load(r)) exit(1);
405 
406  r->conn_rates = xhash_new(101);
407 
408  r->components = xhash_new(101);
409  r->routes = xhash_new(101);
410 
411  r->log_sinks = xhash_new(101);
412 
413  r->dead = jqueue_new();
414  r->closefd = jqueue_new();
415  r->deadroutes = jqueue_new();
416 
417  r->sx_env = sx_env_new();
418 
419 #ifdef HAVE_SSL
420  if(r->local_pemfile != NULL) {
421  r->sx_ssl = sx_env_plugin(r->sx_env, sx_ssl_init, NULL, r->local_pemfile, NULL, NULL);
422  if(r->sx_ssl == NULL)
423  log_write(r->log, LOG_ERR, "failed to load SSL pemfile, SSL disabled");
424  }
425 #endif
426 
427  /* get sasl online */
428  r->sx_sasl = sx_env_plugin(r->sx_env, sx_sasl_init, "jabberd-router", _router_sx_sasl_callback, (void *) r);
429  if(r->sx_sasl == NULL) {
430  log_write(r->log, LOG_ERR, "failed to initialise SASL context, aborting");
431  exit(1);
432  }
433 
434  r->mio = mio_new(r->io_max_fds);
435 
436  r->fd = mio_listen(r->mio, r->local_port, r->local_ip, router_mio_callback, (void *) r);
437  if(r->fd == NULL) {
438  log_write(r->log, LOG_ERR, "[%s, port=%d] unable to listen (%s)", r->local_ip, r->local_port, MIO_STRERROR(MIO_ERROR));
439  exit(1);
440  }
441 
442  log_write(r->log, LOG_NOTICE, "[%s, port=%d] listening for incoming connections", r->local_ip, r->local_port, MIO_STRERROR(MIO_ERROR));
443 
444  while(!router_shutdown)
445  {
446  mio_run(r->mio, 5);
447 
448  if(router_logrotate)
449  {
451 
452  log_write(r->log, LOG_NOTICE, "reopening log ...");
453  log_free(r->log);
454  r->log = log_new(r->log_type, r->log_ident, r->log_facility);
455  log_write(r->log, LOG_NOTICE, "log started");
456 
457  log_write(r->log, LOG_NOTICE, "reloading filter ...");
458  filter_unload(r);
459  filter_load(r);
460 
461  log_write(r->log, LOG_NOTICE, "reloading users ...");
463  user_table_load(r);
464 
465  router_logrotate = 0;
466  }
467 
468  /* cleanup dead sx_ts */
469  while(jqueue_size(r->dead) > 0)
470  sx_free((sx_t) jqueue_pull(r->dead));
471 
472  /* cleanup closed fd */
473  while(jqueue_size(r->closefd) > 0)
475 
476  /* cleanup dead routes */
477  while(jqueue_size(r->deadroutes) > 0)
479 
480  /* time checks */
481  if(r->check_interval > 0 && time(NULL) >= r->next_check) {
482  log_debug(ZONE, "running time checks");
483 
485 
486  r->next_check = time(NULL) + r->check_interval;
487  log_debug(ZONE, "next time check at %d", r->next_check);
488  }
489 
490 #ifdef POOL_DEBUG
491  if(time(NULL) > pool_time + 60) {
492  pool_stat(1);
493  pool_time = time(NULL);
494  }
495 #endif
496  }
497 
498  log_write(r->log, LOG_NOTICE, "shutting down");
499 
500  /* stop accepting new connections */
501  if (r->fd) {
502  // HACK Do not call router_mio_callback(action_CLOSE) for listenning socket, Just close it and forget.
503  mio_app(r->mio, r->fd, NULL, NULL);
504  mio_close(r->mio, r->fd);
505  }
506 
507  /*
508  * !!! issue remote shutdowns to each service, so they can clean up.
509  * we'll need to mio_run() until they all disconnect, so that
510  * the the last packets (eg sm presence unavailables) can get to
511  * their destinations
512  */
513 
514  close_wait_max = 30; /* time limit for component shutdown */
515 
516  /* close connections to components */
517  xhv.comp_val = &comp;
519  do {
520  xhash_iter_get(r->components, NULL, NULL, xhv.val);
521  log_debug(ZONE, "close component %p", comp);
522  if (comp) sx_close(comp->s);
523  mio_run(r->mio, 5000);
524  if (1 > close_wait_max--) break;
525  sleep(1);
526  while(jqueue_size(r->closefd) > 0)
528  } while (xhash_iter_next(r->components));
529 
531 
532  /* cleanup dead sx_ts */
533  while(jqueue_size(r->dead) > 0)
534  sx_free((sx_t) jqueue_pull(r->dead));
535  jqueue_free(r->dead);
536 
537  while(jqueue_size(r->closefd) > 0)
539  jqueue_free(r->closefd);
540 
541  /* cleanup dead routes - probably just showed up (route was just closed) */
542  while(jqueue_size(r->deadroutes) > 0)
545 
546  /* walk r->conn_rates and free */
547  xhv.rt_val = &rt;
549  do {
550  xhash_iter_get(r->conn_rates, NULL, NULL, xhv.val);
551  rate_free(rt);
552  } while(xhash_iter_next(r->conn_rates));
553 
555 
556  xhash_free(r->log_sinks);
557 
558  /* walk r->routes and free */
559  if (xhash_iter_first(r->routes))
560  do {
561  routes_t p;
562  xhash_iter_get(r->routes, NULL, NULL, (void *) &p);
563  routes_free(p);
564  } while(xhash_iter_next(r->routes));
565  xhash_free(r->routes);
566 
567  /* unload users */
569 
570  /* unload acls */
571  aci_unload(r->aci);
572 
573  /* unload filter */
574  filter_unload(r);
575 
576  sx_env_free(r->sx_env);
577 
578  mio_free(r->mio);
579 
580  access_free(r->access);
581 
582  log_free(r->log);
583 
584  config_free(r->config);
585 
586  free(r);
587 
588 #ifdef POOL_DEBUG
589  pool_stat(1);
590 #endif
591 
592 #ifdef HAVE_WINSOCK2_H
593  WSACleanup();
594 #endif
595 
596  return 0;
597 }