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;
27 static struct event ev_net;
28 static struct event ev_unix;
29 static int suspended = 0;
31 /* on accept() failure sleep 5 seconds */
32 static struct event ev_err;
33 static struct timeval err_timeout = {5, 0};
35 static void cleanup_unix_socket(void)
38 if (!cf_unix_socket_dir || suspended)
40 snprintf(fn, sizeof(fn), "%s/.s.PGSQL.%d",
41 cf_unix_socket_dir, cf_listen_port);
45 void get_pooler_fds(int *p_net, int *p_unix)
51 static int create_unix_socket(const char *socket_dir, int listen_port)
53 struct sockaddr_un un;
58 /* fill sockaddr struct */
59 memset(&un, 0, sizeof(un));
60 un.sun_family = AF_UNIX;
61 snprintf(un.sun_path, sizeof(un.sun_path),
62 "%s/.s.PGSQL.%d", socket_dir, listen_port);
64 /* check for lockfile */
65 snprintf(lockfile, sizeof(lockfile), "%s.lock", un.sun_path);
66 res = lstat(lockfile, &st);
68 fatal("unix port %d is in use", listen_port);
70 /* expect old bouncer gone */
74 sock = socket(PF_UNIX, SOCK_STREAM, 0);
76 fatal_perror("socket");
79 res = bind(sock, (const struct sockaddr *)&un, sizeof(un));
83 /* remove socket on shutdown */
84 atexit(cleanup_unix_socket);
86 /* set common options */
87 tune_socket(sock, true);
89 /* finally, accept connections */
90 res = listen(sock, 100);
92 fatal_perror("listen");
94 res = chmod(un.sun_path, 0777);
96 fatal_perror("chmod");
98 log_info("listening on unix:%s", un.sun_path);
103 static int create_net_socket(const char *listen_addr, int listen_port)
106 struct sockaddr_in sa;
111 sock = socket(AF_INET, SOCK_STREAM, 0);
113 fatal_perror("socket");
116 memset(&sa, 0, sizeof(sa));
117 sa.sin_family = AF_INET;
118 sa.sin_port = htons(cf_listen_port);
119 if (strcmp(listen_addr, "*") == 0) {
120 sa.sin_addr.s_addr = htonl(INADDR_ANY);
122 sa.sin_addr.s_addr = inet_addr(listen_addr);
123 if (sa.sin_addr.s_addr == INADDR_NONE)
124 fatal("cannot parse addr: '%s'", listen_addr);
127 /* relaxed binding */
129 res = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
131 fatal_perror("setsockopt");
133 /* bind to address */
134 res = bind(sock, (struct sockaddr *)&sa, sizeof(sa));
136 fatal_perror("bind");
138 /* set common options */
139 tune_socket(sock, false);
141 #ifdef TCP_DEFER_ACCEPT
143 * Notify pooler only when also data is arrived.
145 * optval specifies how long after connection attempt to wait for data.
147 * Related to tcp_synack_retries sysctl, default 5 (corresponds 180 secs).
149 if (cf_tcp_defer_accept > 0) {
150 val = cf_tcp_defer_accept;
151 res = setsockopt(sock, IPPROTO_TCP, TCP_DEFER_ACCEPT, &val, sizeof(val));
153 fatal_perror("setsockopt TCP_DEFER_ACCEPT");
157 /* finally, accept connections */
158 res = listen(sock, 100);
160 fatal_perror("listen");
162 log_info("listening on %s:%d", cf_listen_addr, cf_listen_port);
167 static void err_wait_func(int sock, short flags, void *arg)
172 /* got new connection, associate it with client struct */
173 static void pool_accept(int sock, short flags, void *is_unix)
178 struct sockaddr_in in;
179 struct sockaddr_un un;
182 socklen_t len = sizeof(addr);
185 fd = accept(sock, &addr.sa, &len);
188 * probably fd limit, pointless to try often
189 * wait a bit, hope that admin resolves somehow
191 log_error("accept() failed: %s", strerror(errno));
193 evtimer_set(&ev_err, err_wait_func, NULL);
194 evtimer_add(&ev_err, &err_timeout);
198 log_noise("new fd from accept=%d", fd);
200 log_debug("P: new unix client");
204 log_noise("getuid(): %d", (int)getuid());
205 if (getpeereid(fd, &uid, &gid) >= 0)
206 log_noise("unix peer uid: %d", (int)uid);
208 log_warning("unix peer uid failed: %s", strerror(errno));
210 client = accept_client(fd, NULL, true);
212 log_debug("P: new tcp client");
213 client = accept_client(fd, &addr.in, false);
217 log_debug("P: no mem for client struct");
222 bool use_pooler_socket(int sock, bool is_unix)
224 tune_socket(sock, is_unix);
233 void suspend_pooler(void)
243 void resume_pooler(void)
248 event_set(&ev_unix, fd_unix, EV_READ | EV_PERSIST, pool_accept, "1");
249 event_add(&ev_unix, NULL);
253 event_set(&ev_net, fd_net, EV_READ | EV_PERSIST, pool_accept, NULL);
254 event_add(&ev_net, NULL);
258 /* listen on socket - should happen after all other initializations */
259 void pooler_setup(void)
261 if (cf_listen_addr && !fd_net)
262 fd_net = create_net_socket(cf_listen_addr, cf_listen_port);
264 if (cf_unix_socket_dir && !fd_unix)
265 fd_unix = create_unix_socket(cf_unix_socket_dir, cf_listen_port);
267 if (!fd_net && !fd_unix)
268 fatal("nowhere to listen on");