client_login_timeout: check wait_for_welcome
[pgbouncer.git] / src / main.c
blob8171161bb3d264468b5795613d7df3cd3e9e4e98
1 /*
2 * PgBouncer - Lightweight connection pooler for PostgreSQL.
3 *
4 * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 * Launcer for all the rest.
23 #include "bouncer.h"
25 #include <signal.h>
26 #include <getopt.h>
28 static bool set_mode(ConfElem *elem, const char *val, PgSocket *console);
29 static const char *get_mode(ConfElem *elem);
30 static bool set_auth(ConfElem *elem, const char *val, PgSocket *console);
31 static const char *get_auth(ConfElem *elem);
32 static bool set_defer_accept(ConfElem *elem, const char *val, PgSocket *console);
34 static const char usage_str[] =
35 "Usage: %s [OPTION]... config.ini\n"
36 " -d Run in background (as a daemon)\n"
37 " -R Do a online restart\n"
38 " -q Run quietly\n"
39 " -v Increase verbosity\n"
40 " -u <username> Assume identity of <username>\n"
41 " -V Show version\n"
42 " -h Show this help screen and exit\n";
44 static void usage(int err, char *exe)
46 printf(usage_str, basename(exe));
47 exit(err);
51 * configuration storage
54 int cf_quiet = 0; /* if set, no log is printed to stdout/err */
55 int cf_verbose = 0;
56 int cf_daemon = 0;
57 int cf_pause_mode = P_NONE;
58 int cf_shutdown = 0; /* 1 - wait for queries to finish, 2 - shutdown immediately */
59 int cf_reboot = 0;
60 int cf_syslog = 0;
61 static char *cf_username = "";
62 char *cf_syslog_facility = "daemon";
63 char *cf_config_file = "";
65 char *cf_listen_addr = NULL;
66 int cf_listen_port = 6432;
67 int cf_listen_backlog = 128;
68 #ifndef WIN32
69 char *cf_unix_socket_dir = "/tmp";
70 #else
71 char *cf_unix_socket_dir = "";
72 #endif
74 int cf_pool_mode = POOL_SESSION;
76 /* sbuf config */
77 int cf_sbuf_len = 2048;
78 int cf_sbuf_loopcnt = 5;
79 int cf_tcp_socket_buffer = 0;
80 #if defined(TCP_DEFER_ACCEPT) || defined(SO_ACCEPTFILTER)
81 int cf_tcp_defer_accept = 1;
82 #else
83 int cf_tcp_defer_accept = 0;
84 #endif
85 int cf_tcp_keepalive = 0;
86 int cf_tcp_keepcnt = 0;
87 int cf_tcp_keepidle = 0;
88 int cf_tcp_keepintvl = 0;
90 int cf_auth_type = AUTH_MD5;
91 char *cf_auth_file = "unconfigured_file";
93 int cf_max_client_conn = 100;
94 int cf_default_pool_size = 20;
95 int cf_res_pool_size = 0;
96 usec_t cf_res_pool_timeout = 5;
98 char *cf_server_reset_query = "";
99 char *cf_server_check_query = "select 1";
100 usec_t cf_server_check_delay = 30 * USEC;
101 int cf_server_round_robin = 0;
103 char *cf_ignore_startup_params = "";
105 char *cf_autodb_connstr = NULL; /* here is "" different from NULL */
107 usec_t cf_autodb_idle_timeout = 3600*USEC;
109 usec_t cf_server_lifetime = 60*60*USEC;
110 usec_t cf_server_idle_timeout = 10*60*USEC;
111 usec_t cf_server_connect_timeout = 15*USEC;
112 usec_t cf_server_login_retry = 15*USEC;
113 usec_t cf_query_timeout = 0*USEC;
114 usec_t cf_query_wait_timeout = 0*USEC;
115 usec_t cf_client_idle_timeout = 0*USEC;
116 usec_t cf_client_login_timeout = 60*USEC;
117 usec_t cf_suspend_timeout = 10*USEC;
119 usec_t g_suspend_start = 0;
121 char *cf_logfile = "";
122 char *cf_pidfile = "";
123 char *cf_jobname = "pgbouncer";
125 char *cf_admin_users = "";
126 char *cf_stats_users = "";
127 int cf_stats_period = 60;
129 int cf_log_connections = 1;
130 int cf_log_disconnections = 1;
131 int cf_log_pooler_errors = 1;
134 * config file description
136 ConfElem bouncer_params[] = {
137 {"job_name", false, CF_STR, &cf_jobname},
138 #ifdef WIN32
139 {"service_name", false, CF_STR, &cf_jobname}, /* alias for job_name */
140 #endif
141 {"conffile", true, CF_STR, &cf_config_file},
142 {"logfile", true, CF_STR, &cf_logfile},
143 {"pidfile", false, CF_STR, &cf_pidfile},
144 {"listen_addr", false, CF_STR, &cf_listen_addr},
145 {"listen_port", false, CF_INT, &cf_listen_port},
146 {"listen_backlog", false, CF_INT, &cf_listen_backlog},
147 #ifndef WIN32
148 {"unix_socket_dir", false, CF_STR, &cf_unix_socket_dir},
149 #endif
150 {"auth_type", true, {get_auth, set_auth}},
151 {"auth_file", true, CF_STR, &cf_auth_file},
152 {"pool_mode", true, {get_mode, set_mode}},
153 {"max_client_conn", true, CF_INT, &cf_max_client_conn},
154 {"default_pool_size", true, CF_INT, &cf_default_pool_size},
155 {"reserve_pool_size", true, CF_INT, &cf_res_pool_size},
156 {"reserve_pool_timeout",true, CF_INT, &cf_res_pool_timeout},
157 {"syslog", true, CF_INT, &cf_syslog},
158 {"syslog_facility", true, CF_STR, &cf_syslog_facility},
159 #ifndef WIN32
160 {"user", false, CF_STR, &cf_username},
161 #endif
163 {"autodb_idle_timeout", true, CF_TIME, &cf_autodb_idle_timeout},
165 {"server_reset_query", true, CF_STR, &cf_server_reset_query},
166 {"server_check_query", true, CF_STR, &cf_server_check_query},
167 {"server_check_delay", true, CF_TIME, &cf_server_check_delay},
168 {"query_timeout", true, CF_TIME, &cf_query_timeout},
169 {"query_wait_timeout", true, CF_TIME, &cf_query_wait_timeout},
170 {"client_idle_timeout", true, CF_TIME, &cf_client_idle_timeout},
171 {"client_login_timeout",true, CF_TIME, &cf_client_login_timeout},
172 {"server_lifetime", true, CF_TIME, &cf_server_lifetime},
173 {"server_idle_timeout", true, CF_TIME, &cf_server_idle_timeout},
174 {"server_connect_timeout",true, CF_TIME, &cf_server_connect_timeout},
175 {"server_login_retry", true, CF_TIME, &cf_server_login_retry},
176 {"server_round_robin", true, CF_INT, &cf_server_round_robin},
177 {"suspend_timeout", true, CF_TIME, &cf_suspend_timeout},
178 {"ignore_startup_parameters", true, CF_STR, &cf_ignore_startup_params},
180 {"pkt_buf", false, CF_INT, &cf_sbuf_len},
181 {"sbuf_loopcnt", true, CF_INT, &cf_sbuf_loopcnt},
182 {"tcp_defer_accept", true, {cf_get_int, set_defer_accept}, &cf_tcp_defer_accept},
183 {"tcp_socket_buffer", true, CF_INT, &cf_tcp_socket_buffer},
184 {"tcp_keepalive", true, CF_INT, &cf_tcp_keepalive},
185 {"tcp_keepcnt", true, CF_INT, &cf_tcp_keepcnt},
186 {"tcp_keepidle", true, CF_INT, &cf_tcp_keepidle},
187 {"tcp_keepintvl", true, CF_INT, &cf_tcp_keepintvl},
188 {"verbose", true, CF_INT, &cf_verbose},
189 {"admin_users", true, CF_STR, &cf_admin_users},
190 {"stats_users", true, CF_STR, &cf_stats_users},
191 {"stats_period", true, CF_INT, &cf_stats_period},
192 {"log_connections", true, CF_INT, &cf_log_connections},
193 {"log_disconnections", true, CF_INT, &cf_log_disconnections},
194 {"log_pooler_errors", true, CF_INT, &cf_log_pooler_errors},
195 {NULL},
198 static ConfSection bouncer_config [] = {
199 {"pgbouncer", bouncer_params, NULL},
200 {"databases", NULL, parse_database},
201 {NULL}
204 static const char *get_mode(ConfElem *elem)
206 switch (cf_pool_mode) {
207 case POOL_STMT: return "statement";
208 case POOL_TX: return "transaction";
209 case POOL_SESSION: return "session";
210 default:
211 fatal("borken mode? should not happen");
212 return NULL;
216 static bool set_mode(ConfElem *elem, const char *val, PgSocket *console)
218 if (strcasecmp(val, "session") == 0)
219 cf_pool_mode = POOL_SESSION;
220 else if (strcasecmp(val, "transaction") == 0)
221 cf_pool_mode = POOL_TX;
222 else if (strcasecmp(val, "statement") == 0)
223 cf_pool_mode = POOL_STMT;
224 else {
225 admin_error(console, "bad mode: %s", val);
226 return false;
228 return true;
231 static const char *get_auth(ConfElem *elem)
233 switch (cf_auth_type) {
234 case AUTH_ANY: return "any";
235 case AUTH_TRUST: return "trust";
236 case AUTH_PLAIN: return "plain";
237 case AUTH_CRYPT: return "crypt";
238 case AUTH_MD5: return "md5";
239 default:
240 fatal("borken auth? should not happen");
241 return NULL;
245 static bool set_auth(ConfElem *elem, const char *val, PgSocket *console)
247 if (strcasecmp(val, "any") == 0)
248 cf_auth_type = AUTH_ANY;
249 else if (strcasecmp(val, "trust") == 0)
250 cf_auth_type = AUTH_TRUST;
251 else if (strcasecmp(val, "plain") == 0)
252 cf_auth_type = AUTH_PLAIN;
253 #ifdef HAVE_CRYPT
254 else if (strcasecmp(val, "crypt") == 0)
255 cf_auth_type = AUTH_CRYPT;
256 #endif
257 else if (strcasecmp(val, "md5") == 0)
258 cf_auth_type = AUTH_MD5;
259 else {
260 admin_error(console, "bad auth type: %s", val);
261 return false;
263 return true;
266 static bool set_defer_accept(ConfElem *elem, const char *val, PgSocket *console)
268 bool ok;
269 int oldval = cf_tcp_defer_accept;
270 ok = cf_set_int(elem, val, console);
271 if (ok && !!oldval != !!cf_tcp_defer_accept)
272 pooler_tune_accept(cf_tcp_defer_accept);
273 return true;
276 static void set_dbs_dead(bool flag)
278 List *item;
279 PgDatabase *db;
281 statlist_for_each(item, &database_list) {
282 db = container_of(item, PgDatabase, head);
283 if (db->admin)
284 continue;
285 if (db->db_auto)
286 continue;
287 db->db_dead = flag;
291 /* config loading, tries to be tolerant to errors */
292 void load_config(bool reload)
294 bool ok;
296 set_dbs_dead(true);
298 /* actual loading */
299 ok = iniparser(cf_config_file, bouncer_config, reload);
300 if (ok) {
301 /* load users if needed */
302 if (cf_auth_type >= AUTH_TRUST)
303 load_auth_file(cf_auth_file);
305 /* reset pool_size, kill dbs */
306 config_postprocess();
307 } else {
308 /* if ini file missing, dont kill anybody */
309 set_dbs_dead(false);
312 /* reopen logfile */
313 if (reload)
314 close_logfile();
318 * signal handling.
320 * handle_* functions are not actual signal handlers but called from
321 * event_loop() so they have no restrictions what they can do.
323 static struct event ev_sigterm;
324 static struct event ev_sigint;
326 static void handle_sigterm(int sock, short flags, void *arg)
328 log_info("Got SIGTERM, fast exit");
329 /* pidfile cleanup happens via atexit() */
330 exit(1);
333 static void handle_sigint(int sock, short flags, void *arg)
335 log_info("Got SIGINT, shutting down");
336 if (cf_reboot)
337 fatal("Takeover was in progress, going down immediately");
338 if (cf_pause_mode == P_SUSPEND)
339 fatal("Suspend was in progress, going down immediately");
340 cf_pause_mode = P_PAUSE;
341 cf_shutdown = 1;
344 #ifndef WIN32
346 static struct event ev_sigusr1;
347 static struct event ev_sigusr2;
348 static struct event ev_sighup;
350 static void handle_sigusr1(int sock, short flags, void *arg)
352 if (cf_pause_mode == P_NONE) {
353 log_info("Got SIGUSR1, pausing all activity");
354 cf_pause_mode = P_PAUSE;
355 } else {
356 log_info("Got SIGUSR1, but already paused/suspended");
360 static void handle_sigusr2(int sock, short flags, void *arg)
362 switch (cf_pause_mode) {
363 case P_SUSPEND:
364 log_info("Got SIGUSR2, continuing from SUSPEND");
365 resume_all();
366 cf_pause_mode = P_NONE;
367 break;
368 case P_PAUSE:
369 log_info("Got SIGUSR2, continuing from PAUSE");
370 cf_pause_mode = P_NONE;
371 break;
372 case P_NONE:
373 log_info("Got SIGUSR1, but not paused/suspended");
376 /* avoid surprise later if cf_shutdown stays set */
377 if (cf_shutdown) {
378 log_info("Canceling shutdown");
379 cf_shutdown = 0;
383 static void handle_sighup(int sock, short flags, void *arg)
385 log_info("Got SIGHUP re-reading config");
386 load_config(true);
388 #endif
390 static void signal_setup(void)
392 int err;
394 #ifndef WIN32
395 sigset_t set;
397 /* block SIGPIPE */
398 sigemptyset(&set);
399 sigaddset(&set, SIGPIPE);
400 err = sigprocmask(SIG_BLOCK, &set, NULL);
401 if (err < 0)
402 fatal_perror("sigprocmask");
404 /* install handlers */
406 signal_set(&ev_sigusr1, SIGUSR1, handle_sigusr1, NULL);
407 err = signal_add(&ev_sigusr1, NULL);
408 if (err < 0)
409 fatal_perror("signal_add");
411 signal_set(&ev_sigusr2, SIGUSR2, handle_sigusr2, NULL);
412 err = signal_add(&ev_sigusr2, NULL);
413 if (err < 0)
414 fatal_perror("signal_add");
416 signal_set(&ev_sighup, SIGHUP, handle_sighup, NULL);
417 err = signal_add(&ev_sighup, NULL);
418 if (err < 0)
419 fatal_perror("signal_add");
420 #endif
421 signal_set(&ev_sigterm, SIGTERM, handle_sigterm, NULL);
422 err = signal_add(&ev_sigterm, NULL);
423 if (err < 0)
424 fatal_perror("signal_add");
426 signal_set(&ev_sigint, SIGINT, handle_sigint, NULL);
427 err = signal_add(&ev_sigint, NULL);
428 if (err < 0)
429 fatal_perror("signal_add");
433 * daemon mode
435 static void go_daemon(void)
437 int pid, fd;
439 if (!cf_pidfile[0])
440 fatal("daemon needs pidfile configured");
442 /* dont log to stdout anymore */
443 cf_quiet = 1;
445 /* send stdin, stdout, stderr to /dev/null */
446 fd = open("/dev/null", O_RDWR);
447 if (fd < 0)
448 fatal_perror("/dev/null");
449 dup2(fd, 0);
450 dup2(fd, 1);
451 dup2(fd, 2);
452 if (fd > 2)
453 close(fd);
455 /* fork new process */
456 pid = fork();
457 if (pid < 0)
458 fatal_perror("fork");
459 if (pid > 0)
460 _exit(0);
462 /* create new session */
463 pid = setsid();
464 if (pid < 0)
465 fatal_perror("setsid");
467 /* fork again to avoid being session leader */
468 pid = fork();
469 if (pid < 0)
470 fatal_perror("fork");
471 if (pid > 0)
472 _exit(0);
476 * pidfile management.
479 static void remove_pidfile(void)
481 if (!cf_pidfile[0])
482 return;
483 unlink(cf_pidfile);
486 static void check_pidfile(void)
488 char buf[128 + 1];
489 struct stat st;
490 pid_t pid = 0;
491 int fd, res;
493 if (!cf_pidfile[0])
494 return;
496 /* check if pidfile exists */
497 if (stat(cf_pidfile, &st) < 0) {
498 if (errno != ENOENT)
499 fatal_perror("stat");
500 return;
503 /* read old pid */
504 fd = open(cf_pidfile, O_RDONLY);
505 if (fd < 0)
506 goto locked_pidfile;
507 res = read(fd, buf, sizeof(buf) - 1);
508 close(fd);
509 if (res <= 0)
510 goto locked_pidfile;
512 /* parse pid */
513 buf[res] = 0;
514 pid = atol(buf);
515 if (pid <= 0)
516 goto locked_pidfile;
518 /* check if running */
519 if (kill(pid, 0) >= 0)
520 goto locked_pidfile;
521 if (errno != ESRCH)
522 goto locked_pidfile;
524 /* seems the pidfile is not in use */
525 log_info("Stale pidfile, removing");
526 remove_pidfile();
527 return;
529 locked_pidfile:
530 fatal("pidfile exists, another instance running?");
533 static void write_pidfile(void)
535 char buf[64];
536 pid_t pid;
537 int res, fd;
539 if (!cf_pidfile[0])
540 return;
542 pid = getpid();
543 sprintf(buf, "%u", (unsigned)pid);
545 fd = open(cf_pidfile, O_WRONLY | O_CREAT | O_EXCL, 0644);
546 if (fd < 0)
547 fatal_perror("%s", cf_pidfile);
548 res = safe_write(fd, buf, strlen(buf));
549 if (res < 0)
550 fatal_perror("%s", cf_pidfile);
551 close(fd);
553 /* only remove when we have it actually written */
554 atexit(remove_pidfile);
557 /* just print out max files, in the future may warn if something is off */
558 static void check_limits(void)
560 struct rlimit lim;
561 int total_users = statlist_count(&user_list);
562 int fd_count;
563 int err;
564 List *item;
565 PgDatabase *db;
567 log_noise("event: %d, SBuf: %d, PgSocket: %d, IOBuf: %d",
568 (int)sizeof(struct event), (int)sizeof(SBuf),
569 (int)sizeof(PgSocket), (int)IOBUF_SIZE);
571 /* load limits */
572 err = getrlimit(RLIMIT_NOFILE, &lim);
573 if (err < 0) {
574 log_error("could not get RLIMIT_NOFILE: %s", strerror(errno));
575 return;
578 /* calculate theoretical max, +10 is just in case */
579 fd_count = cf_max_client_conn + 10;
580 statlist_for_each(item, &database_list) {
581 db = container_of(item, PgDatabase, head);
582 if (db->forced_user)
583 fd_count += db->pool_size;
584 else
585 fd_count += db->pool_size * total_users;
588 log_info("File descriptor limit: %d (H:%d), max_client_conn: %d, max fds possible: %d",
589 (int)lim.rlim_cur, (int)lim.rlim_max, cf_max_client_conn, fd_count);
592 static bool check_old_process_unix(void)
594 struct sockaddr_un sa_un;
595 socklen_t len = sizeof(sa_un);
596 int domain = AF_UNIX;
597 int res, fd;
599 if (!*cf_unix_socket_dir)
600 return false;
602 memset(&sa_un, 0, len);
603 sa_un.sun_family = domain;
604 snprintf(sa_un.sun_path, sizeof(sa_un.sun_path),
605 "%s/.s.PGSQL.%d", cf_unix_socket_dir, cf_listen_port);
607 fd = socket(domain, SOCK_STREAM, 0);
608 if (fd < 0)
609 fatal_perror("cannot create socket");
610 res = safe_connect(fd, (struct sockaddr *)&sa_un, len);
611 safe_close(fd);
612 if (res < 0)
613 return false;
614 return true;
617 static void main_loop_once(void)
619 int err;
621 reset_time_cache();
623 err = event_loop(EVLOOP_ONCE);
624 if (err < 0) {
625 if (errno != EINTR)
626 log_warning("event_loop failed: %s", strerror(errno));
628 per_loop_maint();
629 reuse_just_freed_objects();
630 rescue_timers();
631 per_loop_pooler_maint();
634 static void takeover_part1(void)
636 /* use temporary libevent base */
637 void *evtmp = event_init();
639 if (!*cf_unix_socket_dir)
640 fatal("cannot reboot if unix dir not configured");
642 takeover_init();
643 while (cf_reboot)
644 main_loop_once();
645 event_base_free(evtmp);
648 /* boot everything */
649 int main(int argc, char *argv[])
651 int c;
652 bool did_takeover = false;
653 char *arg_username = NULL;
655 /* parse cmdline */
656 while ((c = getopt(argc, argv, "qvhdVRu:")) != EOF) {
657 switch (c) {
658 case 'R':
659 cf_reboot = 1;
660 break;
661 case 'v':
662 cf_verbose++;
663 break;
664 case 'V':
665 printf("%s\n", FULLVER);
666 return 0;
667 case 'd':
668 cf_daemon = 1;
669 break;
670 case 'q':
671 cf_quiet = 1;
672 break;
673 case 'u':
674 arg_username = optarg;
675 break;
676 case 'h':
677 usage(0, argv[0]);
678 default:
679 usage(1, argv[0]);
682 if (optind + 1 != argc) {
683 fprintf(stderr, "Need config file. See pgbouncer -h for usage.\n");
684 exit(1);
686 cf_config_file = argv[optind];
688 init_objects();
689 load_config(false);
690 init_caches();
692 /* prefer cmdline over config for username */
693 if (arg_username)
694 cf_username = arg_username;
696 /* switch user is needed */
697 if (*cf_username)
698 change_user(cf_username);
700 /* disallow running as root */
701 if (getuid() == 0)
702 fatal("PgBouncer should not run as root");
704 /* need to do that after loading config */
705 check_limits();
707 admin_setup();
709 if (cf_reboot) {
710 if (check_old_process_unix()) {
711 takeover_part1();
712 did_takeover = true;
713 } else {
714 log_info("old process not found, try to continue normally");
715 cf_reboot = 0;
716 check_pidfile();
718 } else {
719 if (check_old_process_unix())
720 fatal("unix socket is in use, cannot continue");
721 check_pidfile();
724 if (cf_daemon)
725 go_daemon();
727 /* initialize subsystems, order important */
728 srandom(time(NULL) ^ getpid());
729 if (!event_init())
730 fatal("event_init() failed");
731 signal_setup();
732 janitor_setup();
733 stats_setup();
735 if (did_takeover)
736 takeover_finish();
737 else
738 pooler_setup();
740 write_pidfile();
742 /* main loop */
743 while (cf_shutdown < 2)
744 main_loop_once();
746 return 0;