static const char *get_mode(ConfElem *elem);
static bool set_auth(ConfElem *elem, const char *val, PgSocket *console);
static const char *get_auth(ConfElem *elem);
+static bool set_defer_accept(ConfElem *elem, const char *val, PgSocket *console);
static const char *usage_str =
"usage: pgbouncer [-d] [-R] [-q] [-v] [-h|-V] config.ini\n";
/* sbuf config */
int cf_sbuf_len = 2048;
int cf_tcp_socket_buffer = 0;
-#ifdef TCP_DEFER_ACCEPT
-int cf_tcp_defer_accept = 45;
+#if defined(TCP_DEFER_ACCEPT) || defined(SO_ACCEPTFILTER)
+int cf_tcp_defer_accept = 1;
#else
int cf_tcp_defer_accept = 0;
#endif
{"suspend_timeout", true, CF_TIME, &cf_suspend_timeout},
{"pkt_buf", false, CF_INT, &cf_sbuf_len},
-{"tcp_defer_accept", false, CF_INT, &cf_tcp_defer_accept},
+{"tcp_defer_accept", true, {cf_get_int, set_defer_accept}},
{"tcp_socket_buffer", true, CF_INT, &cf_tcp_socket_buffer},
{"tcp_keepalive", true, CF_INT, &cf_tcp_keepalive},
{"tcp_keepcnt", true, CF_INT, &cf_tcp_keepcnt},
return true;
}
+static bool set_defer_accept(ConfElem *elem, const char *val, PgSocket *console)
+{
+ bool ok;
+ int oldval = cf_tcp_defer_accept;
+ ok = cf_set_int(elem, val, console);
+ if (ok && !!oldval != !!cf_tcp_defer_accept)
+ pooler_tune_accept(cf_tcp_defer_accept);
+ return true;
+}
+
static void set_dbs_dead(bool flag)
{
List *item;
return sock;
}
+/*
+ * Notify pooler only when also data is arrived.
+ *
+ * optval specifies how long after connection attempt to wait for data.
+ *
+ * Related to tcp_synack_retries sysctl, default 5 (corresponds 180 secs).
+ *
+ * SO_ACCEPTFILTER needs to be set after listern(), maybe TCP_DEFER_ACCEPT too.
+ */
+static void tune_accept(int sock, bool on)
+{
+ const char *act = on ? "install" : "uninstall";
+ int res = 0;
+#ifdef TCP_DEFER_ACCEPT
+ int val = 45; /* fixme: proper value */
+ res = getsockopt(sock, IPPROTO_TCP, TCP_DEFER_ACCEPT, &val, sizeof(val));
+ log_noise("old TCP_DEFER_ACCEPT on %d = %d", sock, val);
+ val = on ? 1 : 0;
+ log_noise("%s TCP_DEFER_ACCEPT on %d", act, sock);
+ res = setsockopt(sock, IPPROTO_TCP, TCP_DEFER_ACCEPT, &val, sizeof(val));
+#else
+#ifdef SO_ACCEPTFILTER
+ struct accept_filter_arg af, *afp = on ? &af : NULL;
+ socklen_t af_len = on ? sizeof(af) : 0;
+ memset(&af, 0, sizeof(af));
+ strcpy(af.af_name, "dataready");
+ log_noise("%s SO_ACCEPTFILTER on %d", act, sock);
+ res = setsockopt(sock, SOL_SOCKET, SO_ACCEPTFILTER, afp, af_len);
+#endif
+#endif
+ if (res < 0)
+ log_warning("tune_accept: %s TCP_DEFER_ACCEPT/SO_ACCEPTFILTER: %s",
+ act, strerror(errno));
+}
+
+void pooler_tune_accept(bool on)
+{
+ if (fd_net > 0)
+ tune_accept(fd_net, on);
+}
+
static int create_net_socket(const char *listen_addr, int listen_port)
{
int sock;
/* set common options */
tune_socket(sock, false);
-#ifdef TCP_DEFER_ACCEPT
- /*
- * Notify pooler only when also data is arrived.
- *
- * optval specifies how long after connection attempt to wait for data.
- *
- * Related to tcp_synack_retries sysctl, default 5 (corresponds 180 secs).
- */
- if (cf_tcp_defer_accept > 0) {
- val = cf_tcp_defer_accept;
- res = setsockopt(sock, IPPROTO_TCP, TCP_DEFER_ACCEPT, &val, sizeof(val));
- if (res < 0)
- fatal_perror("setsockopt TCP_DEFER_ACCEPT");
- }
-#endif
-
- /* finally, accept connections */
+ /* make it accept connections */
res = listen(sock, 100);
if (res < 0)
fatal_perror("listen");
+ tune_accept(sock, cf_tcp_defer_accept);
+
log_info("listening on %s:%d", cf_listen_addr, cf_listen_port);
return sock;