From: Marko Kreen Date: Wed, 17 Nov 2010 13:09:49 +0000 (+0200) Subject: Support canceling ongoing DNS requests. X-Git-Tag: pgbouncer_1_4_rc3~10 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=c86cb165946e41ac534b9ca74b30b2555aca4c2b;p=pgbouncer Support canceling ongoing DNS requests. This should avoid problems when server_disconnect() is called during DNS processing. --- diff --git a/include/bouncer.h b/include/bouncer.h index 0e59b4c..5d2727c 100644 --- a/include/bouncer.h +++ b/include/bouncer.h @@ -290,6 +290,8 @@ struct PgSocket { PgAddr remote_addr; /* ip:port for remote endpoint */ PgAddr local_addr; /* ip:port for local endpoint */ + struct DNSToken *dns_token; /* ongoing request */ + VarCache vars; /* state of interesting server parameters */ SBuf sbuf; /* stream buffer, must be last */ diff --git a/include/dnslookup.h b/include/dnslookup.h index 38e529a..28459ff 100644 --- a/include/dnslookup.h +++ b/include/dnslookup.h @@ -35,6 +35,7 @@ struct DNSContext; +struct DNSToken; typedef void (*adns_callback_f)(void *arg, const struct sockaddr *sa, int salen); @@ -42,5 +43,7 @@ struct DNSContext *adns_create_context(void); void adns_reload(struct DNSContext *ctx); void adns_free_context(struct DNSContext *ctx); -void adns_resolve(struct DNSContext *ctx, const char *name, adns_callback_f cb_func, void *arg); +struct DNSToken *adns_resolve(struct DNSContext *ctx, const char *name, adns_callback_f cb_func, void *arg); + +void adns_cancel(struct DNSContext *ctx, struct DNSToken *tk); diff --git a/src/dnslookup.c b/src/dnslookup.c index 0e9038e..245769e 100644 --- a/src/dnslookup.c +++ b/src/dnslookup.c @@ -42,7 +42,7 @@ #endif -struct UserCallback { +struct DNSToken { struct List node; adns_callback_f cb_func; void *cb_arg; @@ -312,7 +312,7 @@ static void impl_release(struct DNSContext *ctx) static void deliver_info(struct DNSRequest *req) { - struct UserCallback *ucb; + struct DNSToken *ucb; struct List *el; const struct addrinfo *ai = req->current; char sabuf[128]; @@ -322,7 +322,7 @@ loop: el = list_pop(&req->ucb_list); if (!el) return; - ucb = container_of(el, struct UserCallback, node); + ucb = container_of(el, struct DNSToken, node); /* launch callback */ log_noise("dns: deliver_info(%s) addr=%s", req->name, @@ -359,12 +359,12 @@ static void req_reset(struct DNSRequest *req) static void req_free(struct AANode *node, void *arg) { - struct UserCallback *ucb; + struct DNSToken *ucb; struct DNSRequest *req; struct List *el; req = container_of(node, struct DNSRequest, node); while ((el = list_pop(&req->ucb_list)) != NULL) { - ucb = container_of(el, struct UserCallback, node); + ucb = container_of(el, struct DNSToken, node); free(ucb); } req_reset(req); @@ -395,11 +395,11 @@ void adns_free_context(struct DNSContext *ctx) } } -void adns_resolve(struct DNSContext *ctx, const char *name, adns_callback_f cb_func, void *cb_arg) +struct DNSToken *adns_resolve(struct DNSContext *ctx, const char *name, adns_callback_f cb_func, void *cb_arg) { int namelen = strlen(name); struct DNSRequest *req; - struct UserCallback *ucb; + struct DNSToken *ucb; struct AANode *node; /* setup actual lookup */ @@ -441,10 +441,11 @@ void adns_resolve(struct DNSContext *ctx, const char *name, adns_callback_f cb_f } else deliver_info(req); } - return; + return ucb; nomem: log_warning("dns(%s): req failed, no mem", name); cb_func(cb_arg, NULL, 0); + return NULL; } /* struct addrinfo -> deliver_info() */ @@ -468,3 +469,10 @@ static void got_result_gai(int result, struct addrinfo *res, void *arg) deliver_info(req); } +void adns_cancel(struct DNSContext *ctx, struct DNSToken *tk) +{ + list_del(&tk->node); + memset(tk, 0, sizeof(*tk)); + free(tk); +} + diff --git a/src/objects.c b/src/objects.c index bd3521f..69b5dd4 100644 --- a/src/objects.c +++ b/src/objects.c @@ -750,6 +750,11 @@ void disconnect_server(PgSocket *server, bool notify, const char *reason, ...) notify = false; } + if (server->dns_token) { + adns_cancel(adns, server->dns_token); + server->dns_token = NULL; + } + change_server_state(server, SV_JUSTFREE); if (!sbuf_close(&server->sbuf)) log_noise("sbuf_close failed, retry later"); @@ -842,6 +847,8 @@ static void dns_callback(void *arg, const struct sockaddr *sa, int salen) struct PgDatabase *db = server->pool->db; struct sockaddr_in sa_in; + server->dns_token = NULL; + if (!sa) { disconnect_server(server, true, "server dns lookup failed"); return; @@ -889,9 +896,12 @@ static void dns_connect(struct PgSocket *server) sa = (struct sockaddr *)&sa_in; sa_len = sizeof(sa_in); } else { + struct DNSToken *tk; slog_noise(server, "dns socket: %s", db->host); /* launch dns lookup */ - adns_resolve(adns, db->host, dns_callback, server); + tk = adns_resolve(adns, db->host, dns_callback, server); + if (tk) + server->dns_token = tk; return; }