]> granicus.if.org Git - pgbouncer/commitdiff
Support canceling ongoing DNS requests.
authorMarko Kreen <markokr@gmail.com>
Wed, 17 Nov 2010 13:09:49 +0000 (15:09 +0200)
committerMarko Kreen <markokr@gmail.com>
Wed, 17 Nov 2010 13:09:49 +0000 (15:09 +0200)
This should avoid problems when server_disconnect()
is called during DNS processing.

include/bouncer.h
include/dnslookup.h
src/dnslookup.c
src/objects.c

index 0e59b4ca9ada6ef59ddc22f6d87440c0e0c85cfc..5d2727cd78b9927dce0080f046ce69dc58c6bce4 100644 (file)
@@ -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 */
index 38e529ab1f615ee6b455c2dd494d875b00008379..28459ffc8566a723dcd81158581c9c1a21469704 100644 (file)
@@ -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);
 
index 0e9038e5cd97001b32d1a892ab1d40d051d30f7a..245769e8a90d9e756751474d707976d2aafe95ec 100644 (file)
@@ -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);
+}
+
index bd3521fa3f5a47b91023f5570c2e61a896e2b8ad..69b5dd429a7b4f35b9718008b9b2e77837ca3ed6 100644 (file)
@@ -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;
        }