From: Samuel Ortiz Date: Mon, 26 Jul 2010 10:13:41 +0000 (+0200) Subject: dnsproxy flush method implementation X-Git-Tag: 0.56~107 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=27118ae27ead53ab927f08173038c2f2498da9ce;p=platform%2Fupstream%2Fconnman.git dnsproxy flush method implementation --- diff --git a/plugins/dnsproxy.c b/plugins/dnsproxy.c index 2cb2f41..5368ceb 100644 --- a/plugins/dnsproxy.c +++ b/plugins/dnsproxy.c @@ -92,12 +92,16 @@ struct request_data { guint timeout; guint numserv; guint numresp; + gpointer request; + gsize request_len; + gpointer name; gpointer resp; gsize resplen; }; static GSList *server_list = NULL; static GSList *request_list = NULL; +static GSList *request_pending_list = NULL; static guint16 request_id = 0x0000; static GIOChannel *listener_channel = NULL; @@ -297,6 +301,144 @@ static void destroy_server(struct server_data *data) g_free(data); } +static int append_query(unsigned char *buf, unsigned int size, + const char *query, const char *domain) +{ + unsigned char *ptr = buf; + char *offset; + + DBG("query %s domain %s", query, domain); + + offset = (char *) query; + while (offset != NULL) { + char *tmp; + + tmp = strchr(offset, '.'); + if (tmp == NULL) { + if (strlen(offset) == 0) + break; + *ptr = strlen(offset); + memcpy(ptr + 1, offset, strlen(offset)); + ptr += strlen(offset) + 1; + break; + } + + *ptr = tmp - offset; + memcpy(ptr + 1, offset, tmp - offset); + ptr += tmp - offset + 1; + + offset = tmp + 1; + } + + offset = (char *) domain; + while (offset != NULL) { + char *tmp; + + tmp = strchr(offset, '.'); + if (tmp == NULL) { + if (strlen(offset) == 0) + break; + *ptr = strlen(offset); + memcpy(ptr + 1, offset, strlen(offset)); + ptr += strlen(offset) + 1; + break; + } + + *ptr = tmp - offset; + memcpy(ptr + 1, offset, tmp - offset); + ptr += tmp - offset + 1; + + offset = tmp + 1; + } + + *ptr++ = 0x00; + + return ptr - buf; +} + +static gboolean request_timeout(gpointer user_data) +{ + struct request_data *req = user_data; + + DBG("id 0x%04x", req->srcid); + + request_list = g_slist_remove(request_list, req); + + if (req->resplen > 0 && req->resp != NULL) { + int sk, err; + + sk = g_io_channel_unix_get_fd(listener_channel); + + err = sendto(sk, req->resp, req->resplen, 0, + (struct sockaddr *) &req->sin, req->len); + } + + g_free(req->resp); + g_free(req); + + return FALSE; +} + +static gboolean resolv(struct request_data *req, + gpointer request, gpointer name) +{ + int sk, err; + GSList *list; + + request_list = g_slist_append(request_list, req); + + req->numserv = 0; + req->timeout = g_timeout_add_seconds(5, request_timeout, req); + + for (list = server_list; list; list = list->next) { + struct server_data *data = list->data; + + DBG("server %s domain %s enabled %d", + data->server, data->domain, data->enabled); + + if (data->enabled == FALSE) + continue; + + sk = g_io_channel_unix_get_fd(data->channel); + + err = send(sk, request, req->request_len, 0); + + req->numserv++; + + if (data->domain != NULL) { + unsigned char alt[1024]; + struct domain_hdr *hdr = (void *) &alt; + int altlen, domlen; + + domlen = strlen(data->domain) + 1; + if (domlen < 5) + continue; + + alt[0] = req->altid & 0xff; + alt[1] = req->altid >> 8; + + memcpy(alt + 2, request + 2, 10); + hdr->qdcount = htons(1); + + altlen = append_query(alt + 12, sizeof(alt) - 12, + name, data->domain); + if (altlen < 0) + continue; + + altlen += 12; + + memcpy(alt + altlen, request + altlen - domlen, + req->request_len - altlen + domlen); + + err = send(sk, alt, req->request_len + domlen + 1, 0); + + req->numserv++; + } + } + + return TRUE; +} + static int dnsproxy_append(const char *interface, const char *domain, const char *server) { @@ -337,11 +479,30 @@ static int dnsproxy_remove(const char *interface, const char *domain, return 0; } +static void dnsproxy_flush(void) +{ + GSList *list; + + list = request_pending_list; + while (list) { + struct request_data *req = list->data; + + list = list->next; + + request_pending_list = + g_slist_remove(request_pending_list, req); + resolv(req, req->request, req->name); + g_free(req->request); + g_free(req->name); + } +} + static struct connman_resolver dnsproxy_resolver = { .name = "dnsproxy", .priority = CONNMAN_RESOLVER_PRIORITY_HIGH, .append = dnsproxy_append, .remove = dnsproxy_remove, + .flush = dnsproxy_flush, }; static void dnsproxy_offline_mode(connman_bool_t enabled) @@ -496,88 +657,9 @@ static void send_response(int sk, unsigned char *buf, int len, err = sendto(sk, buf, len, 0, to, tolen); } -static int append_query(unsigned char *buf, unsigned int size, - const char *query, const char *domain) -{ - unsigned char *ptr = buf; - char *offset; - - DBG("query %s domain %s", query, domain); - - offset = (char *) query; - while (offset != NULL) { - char *tmp; - - tmp = strchr(offset, '.'); - if (tmp == NULL) { - if (strlen(offset) == 0) - break; - *ptr = strlen(offset); - memcpy(ptr + 1, offset, strlen(offset)); - ptr += strlen(offset) + 1; - break; - } - - *ptr = tmp - offset; - memcpy(ptr + 1, offset, tmp - offset); - ptr += tmp - offset + 1; - - offset = tmp + 1; - } - - offset = (char *) domain; - while (offset != NULL) { - char *tmp; - - tmp = strchr(offset, '.'); - if (tmp == NULL) { - if (strlen(offset) == 0) - break; - *ptr = strlen(offset); - memcpy(ptr + 1, offset, strlen(offset)); - ptr += strlen(offset) + 1; - break; - } - - *ptr = tmp - offset; - memcpy(ptr + 1, offset, tmp - offset); - ptr += tmp - offset + 1; - - offset = tmp + 1; - } - - *ptr++ = 0x00; - - return ptr - buf; -} - -static gboolean request_timeout(gpointer user_data) -{ - struct request_data *req = user_data; - - DBG("id 0x%04x", req->srcid); - - request_list = g_slist_remove(request_list, req); - - if (req->resplen > 0 && req->resp != NULL) { - int sk, err; - - sk = g_io_channel_unix_get_fd(listener_channel); - - err = sendto(sk, req->resp, req->resplen, 0, - (struct sockaddr *) &req->sin, req->len); - } - - g_free(req->resp); - g_free(req); - - return FALSE; -} - static gboolean listener_event(GIOChannel *channel, GIOCondition condition, gpointer user_data) { - GSList *list; unsigned char buf[768]; char query[512]; struct request_data *req; @@ -621,62 +703,12 @@ static gboolean listener_event(GIOChannel *channel, GIOCondition condition, req->srcid = buf[0] | (buf[1] << 8); req->dstid = request_id; req->altid = request_id + 1; + req->request_len = len; buf[0] = req->dstid & 0xff; buf[1] = req->dstid >> 8; - request_list = g_slist_append(request_list, req); - - req->numserv = 0; - req->timeout = g_timeout_add_seconds(5, request_timeout, req); - - for (list = server_list; list; list = list->next) { - struct server_data *data = list->data; - - DBG("server %s domain %s enabled %d", - data->server, data->domain, data->enabled); - - if (data->enabled == FALSE) - continue; - - sk = g_io_channel_unix_get_fd(data->channel); - - err = send(sk, buf, len, 0); - - req->numserv++; - - if (data->domain != NULL) { - unsigned char alt[1024]; - struct domain_hdr *hdr = (void *) &alt; - int altlen, domlen; - - domlen = strlen(data->domain) + 1; - if (domlen < 5) - continue; - - alt[0] = req->altid & 0xff; - alt[1] = req->altid >> 8; - - memcpy(alt + 2, buf + 2, 10); - hdr->qdcount = htons(1); - - altlen = append_query(alt + 12, sizeof(alt) - 12, - query, data->domain); - if (altlen < 0) - continue; - - altlen += 12; - - memcpy(alt + altlen, buf + altlen - domlen, - len - altlen + domlen); - - err = send(sk, alt, len + domlen + 1, 0); - - req->numserv++; - } - } - - return TRUE; + return resolv(req, buf, query); } static int create_listener(void) @@ -743,6 +775,22 @@ static void destroy_listener(void) if (listener_watch > 0) g_source_remove(listener_watch); + for (list = request_pending_list; list; list = list->next) { + struct request_data *req = list->data; + + DBG("Dropping pending request (id 0x%04x -> 0x%04x)", + req->srcid, req->dstid); + + g_free(req->resp); + g_free(req->request); + g_free(req->name); + g_free(req); + list->data = NULL; + } + + g_slist_free(request_pending_list); + request_pending_list = NULL; + for (list = request_list; list; list = list->next) { struct request_data *req = list->data; @@ -750,6 +798,8 @@ static void destroy_listener(void) req->srcid, req->dstid); g_free(req->resp); + g_free(req->request); + g_free(req->name); g_free(req); list->data = NULL; }