2 * PgBouncer - Lightweight connection pooler for PostgreSQL.
4 * Copyright (c) 2007 Marko Kreen, Skype Technologies OÜ
6 * Permission to use, copy, modify, and 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.
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 * Handling of pooler listening sockets
25 static int fd_net = 0;
26 static int fd_unix = 0;
28 static struct event ev_net;
29 static struct event ev_unix;
31 /* if sockets are registered in libevent */
32 static bool reg_net = false;
33 static bool reg_unix = false;
35 /* should listening sockets be active or suspended? */
36 static bool pooler_active = false;
38 /* on accept() failure sleep 5 seconds */
39 static struct event ev_err;
40 static struct timeval err_timeout = {5, 0};
42 /* atexit() cleanup func */
43 static void cleanup_unix_socket(void)
47 /* avoid cleanup if exit() while suspended */
51 snprintf(fn, sizeof(fn), "%s/.s.PGSQL.%d",
52 cf_unix_socket_dir, cf_listen_port);
56 void get_pooler_fds(int *p_net, int *p_unix)
62 static int create_unix_socket(const char *socket_dir, int listen_port)
64 struct sockaddr_un un;
69 /* fill sockaddr struct */
70 memset(&un, 0, sizeof(un));
71 un.sun_family = AF_UNIX;
72 snprintf(un.sun_path, sizeof(un.sun_path),
73 "%s/.s.PGSQL.%d", socket_dir, listen_port);
75 /* check for lockfile */
76 snprintf(lockfile, sizeof(lockfile), "%s.lock", un.sun_path);
77 res = lstat(lockfile, &st);
79 fatal("unix port %d is in use", listen_port);
81 /* expect old bouncer gone */
85 sock = socket(PF_UNIX, SOCK_STREAM, 0);
87 fatal_perror("socket");
90 res = bind(sock, (const struct sockaddr *)&un, sizeof(un));
94 /* remove socket on shutdown */
95 atexit(cleanup_unix_socket);
97 /* set common options */
98 tune_socket(sock, true);
100 /* finally, accept connections */
101 res = listen(sock, 100);
103 fatal_perror("listen");
105 res = chmod(un.sun_path, 0777);
107 fatal_perror("chmod");
109 log_info("listening on unix:%s", un.sun_path);
114 static int create_net_socket(const char *listen_addr, int listen_port)
117 struct sockaddr_in sa;
122 sock = socket(AF_INET, SOCK_STREAM, 0);
124 fatal_perror("socket");
127 memset(&sa, 0, sizeof(sa));
128 sa.sin_family = AF_INET;
129 sa.sin_port = htons(cf_listen_port);
130 if (strcmp(listen_addr, "*") == 0) {
131 sa.sin_addr.s_addr = htonl(INADDR_ANY);
133 sa.sin_addr.s_addr = inet_addr(listen_addr);
134 if (sa.sin_addr.s_addr == INADDR_NONE)
135 fatal("cannot parse addr: '%s'", listen_addr);
138 /* relaxed binding */
140 res = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
142 fatal_perror("setsockopt");
144 /* bind to address */
145 res = bind(sock, (struct sockaddr *)&sa, sizeof(sa));
147 fatal_perror("bind");
149 /* set common options */
150 tune_socket(sock, false);
152 #ifdef TCP_DEFER_ACCEPT
154 * Notify pooler only when also data is arrived.
156 * optval specifies how long after connection attempt to wait for data.
158 * Related to tcp_synack_retries sysctl, default 5 (corresponds 180 secs).
160 if (cf_tcp_defer_accept > 0) {
161 val = cf_tcp_defer_accept;
162 res = setsockopt(sock, IPPROTO_TCP, TCP_DEFER_ACCEPT, &val, sizeof(val));
164 fatal_perror("setsockopt TCP_DEFER_ACCEPT");
168 /* finally, accept connections */
169 res = listen(sock, 100);
171 fatal_perror("listen");
173 log_info("listening on %s:%d", cf_listen_addr, cf_listen_port);
178 static void err_wait_func(int sock, short flags, void *arg)
180 if (cf_pause_mode != P_SUSPEND)
184 /* got new connection, associate it with client struct */
185 static void pool_accept(int sock, short flags, void *is_unix)
190 struct sockaddr_in in;
191 struct sockaddr_un un;
194 socklen_t len = sizeof(addr);
198 fd = safe_accept(sock, &addr.sa, &len);
202 else if (errno == ECONNABORTED)
206 * probably fd limit, pointless to try often
207 * wait a bit, hope that admin resolves somehow
209 log_error("accept() failed: %s", strerror(errno));
210 evtimer_set(&ev_err, err_wait_func, NULL);
211 safe_evtimer_add(&ev_err, &err_timeout);
216 log_noise("new fd from accept=%d", fd);
218 log_debug("P: new unix client");
222 log_noise("getuid(): %d", (int)getuid());
223 if (getpeereid(fd, &uid, &gid) >= 0)
224 log_noise("unix peer uid: %d", (int)uid);
226 log_warning("unix peer uid failed: %s", strerror(errno));
228 client = accept_client(fd, NULL, true);
230 log_debug("P: new tcp client");
231 client = accept_client(fd, &addr.in, false);
235 log_warning("P: no mem for client struct");
240 * there may be several clients waiting,
241 * avoid context switch by looping
246 bool use_pooler_socket(int sock, bool is_unix)
248 tune_socket(sock, is_unix);
257 void suspend_pooler(void)
259 pooler_active = false;
261 if (fd_net && reg_net) {
262 if (event_del(&ev_net) < 0) {
263 log_warning("suspend_pooler, event_del: %s", strerror(errno));
268 if (fd_unix && reg_unix) {
269 if (event_del(&ev_unix) < 0) {
270 log_warning("suspend_pooler, event_del: %s", strerror(errno));
277 void resume_pooler(void)
279 pooler_active = true;
281 if (fd_unix && !reg_unix) {
282 event_set(&ev_unix, fd_unix, EV_READ | EV_PERSIST, pool_accept, "1");
283 if (event_add(&ev_unix, NULL) < 0) {
284 log_warning("event_add failed: %s", strerror(errno));
290 if (fd_net && !reg_net) {
291 event_set(&ev_net, fd_net, EV_READ | EV_PERSIST, pool_accept, NULL);
292 if (event_add(&ev_net, NULL) < 0) {
293 log_warning("event_add failed: %s", strerror(errno));
299 /* listen on socket - should happen after all other initializations */
300 void pooler_setup(void)
302 if (cf_listen_addr && !fd_net)
303 fd_net = create_net_socket(cf_listen_addr, cf_listen_port);
305 if (cf_unix_socket_dir && !fd_unix)
306 fd_unix = create_unix_socket(cf_unix_socket_dir, cf_listen_port);
308 if (!fd_net && !fd_unix)
309 fatal("nowhere to listen on");
314 /* retry previously failed suspend_pooler() / resume_pooler() */
315 void per_loop_pooler_maint(void)
318 if ((fd_unix && !reg_unix) || (fd_net && !reg_net))
321 if ((fd_unix && reg_unix) || (fd_net && reg_net))