Free (GPLv2) TCP/IP stack developed by TASS Belgium

Dependents:   lpc1768-picotcp-demo ZeroMQ_PicoTCP_Publisher_demo TCPSocket_HelloWorld_PicoTCP Pico_TCP_UDP_Test ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers pico_dns_client.c Source File

pico_dns_client.c

00001 /*********************************************************************
00002    PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved.
00003    See LICENSE and COPYING for usage.
00004    .
00005    Authors: Kristof Roelants
00006  *********************************************************************/
00007 #include "pico_config.h"
00008 #include "pico_stack.h"
00009 #include "pico_addressing.h"
00010 #include "pico_socket.h"
00011 #include "pico_ipv4.h"
00012 #include "pico_ipv6.h"
00013 #include "pico_dns_client.h"
00014 #include "pico_dns_common.h"
00015 #include "pico_tree.h"
00016 
00017 #ifdef PICO_SUPPORT_DNS_CLIENT
00018 
00019 #ifdef PICO_SUPPORT_IPV4
00020 
00021 #define dns_dbg(...) do {} while(0)
00022 /* #define dns_dbg dbg */
00023 
00024 /* DNS response length */
00025 #define PICO_DNS_MAX_QUERY_LEN 255
00026 #define PICO_DNS_MAX_QUERY_LABEL_LEN 63
00027 
00028 /* DNS client retransmission time (msec) + frequency */
00029 #define PICO_DNS_CLIENT_RETRANS 4000
00030 #define PICO_DNS_CLIENT_MAX_RETRANS 3
00031 
00032 static void pico_dns_client_callback(uint16_t ev, struct pico_socket *s);
00033 static void pico_dns_client_retransmission(pico_time now, void *arg);
00034 static int pico_dns_client_getaddr_init(const char *url, uint16_t proto, void (*callback)(char *, void *), void *arg);
00035 
00036 struct pico_dns_ns
00037 {
00038     struct pico_ip4 ns; /* nameserver */
00039 };
00040 
00041 static int dns_ns_cmp(void *ka, void *kb)
00042 {
00043     struct pico_dns_ns *a = ka, *b = kb;
00044     return pico_ipv4_compare(&a->ns, &b->ns);
00045 }
00046 PICO_TREE_DECLARE(NSTable, dns_ns_cmp);
00047 
00048 struct pico_dns_query
00049 {
00050     char *query;
00051     uint16_t len;
00052     uint16_t id;
00053     uint16_t qtype;
00054     uint16_t qclass;
00055     uint8_t retrans;
00056     struct pico_dns_ns q_ns;
00057     struct pico_socket *s;
00058     void (*callback)(char *, void *);
00059     void *arg;
00060 };
00061 
00062 static int dns_query_cmp(void *ka, void *kb)
00063 {
00064     struct pico_dns_query *a = ka, *b = kb;
00065     if (a->id == b->id)
00066         return 0;
00067 
00068     return (a->id < b->id) ? (-1) : (1);
00069 }
00070 PICO_TREE_DECLARE(DNSTable, dns_query_cmp);
00071 
00072 static int pico_dns_client_del_ns(struct pico_ip4 *ns_addr)
00073 {
00074     struct pico_dns_ns test = {{0}}, *found = NULL;
00075 
00076     test.ns = *ns_addr;
00077     found = pico_tree_findKey(&NSTable, &test);
00078     if (!found)
00079         return -1;
00080 
00081     pico_tree_delete(&NSTable, found);
00082     PICO_FREE(found);
00083 
00084     /* no NS left, add default NS */
00085     if (pico_tree_empty(&NSTable))
00086         pico_dns_client_init();
00087 
00088     return 0;
00089 }
00090 
00091 static struct pico_dns_ns *pico_dns_client_add_ns(struct pico_ip4 *ns_addr)
00092 {
00093     struct pico_dns_ns *dns = NULL, *found = NULL, test = {{0}};
00094 
00095     dns = PICO_ZALLOC(sizeof(struct pico_dns_ns));
00096     if (!dns) {
00097         pico_err = PICO_ERR_ENOMEM;
00098         return NULL;
00099     }
00100 
00101     dns->ns = *ns_addr;
00102 
00103     found = pico_tree_insert(&NSTable, dns);
00104     if (found) { /* nameserver already present */
00105         PICO_FREE(dns);
00106         return found;
00107     }
00108 
00109     /* default NS found, remove it */
00110     pico_string_to_ipv4(PICO_DNS_NS_DEFAULT, (uint32_t *)&test.ns.addr);
00111     found = pico_tree_findKey(&NSTable, &test);
00112     if (found && (found->ns.addr != ns_addr->addr))
00113         pico_dns_client_del_ns(&found->ns);
00114 
00115     return dns;
00116 }
00117 
00118 static struct pico_dns_ns pico_dns_client_next_ns(struct pico_ip4 *ns_addr)
00119 {
00120     struct pico_dns_ns dns = {{0}}, *nxtdns = NULL;
00121     struct pico_tree_node *node = NULL, *nxtnode = NULL;
00122 
00123     dns.ns = *ns_addr;
00124     node = pico_tree_findNode(&NSTable, &dns);
00125     if (!node)
00126         return dns; /* keep using current NS */
00127 
00128     nxtnode = pico_tree_next(node);
00129     nxtdns = nxtnode->keyValue;
00130     if (!nxtdns)
00131         nxtdns = (struct pico_dns_ns *)pico_tree_first(&NSTable);
00132 
00133     return *nxtdns;
00134 }
00135 
00136 static struct pico_dns_query *pico_dns_client_add_query(struct pico_dns_header *hdr, uint16_t len, struct pico_dns_question_suffix *suffix,
00137                                                         void (*callback)(char *, void *), void *arg)
00138 {
00139     struct pico_dns_query *q = NULL, *found = NULL;
00140 
00141     q = PICO_ZALLOC(sizeof(struct pico_dns_query));
00142     if (!q)
00143         return NULL;
00144 
00145     q->query = (char *)hdr;
00146     q->len = len;
00147     q->id = short_be(hdr->id);
00148     q->qtype = short_be(suffix->qtype);
00149     q->qclass = short_be(suffix->qclass);
00150     q->retrans = 1;
00151     q->q_ns = *((struct pico_dns_ns *)pico_tree_first(&NSTable));
00152     q->callback = callback;
00153     q->arg = arg;
00154     q->s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &pico_dns_client_callback);
00155     if (!q->s) {
00156         PICO_FREE(q);
00157         return NULL;
00158     }
00159 
00160     found = pico_tree_insert(&DNSTable, q);
00161     if (found) {
00162         pico_err = PICO_ERR_EAGAIN;
00163         pico_socket_close(q->s);
00164         PICO_FREE(q);
00165         return NULL;
00166     }
00167 
00168     return q;
00169 }
00170 
00171 static int pico_dns_client_del_query(uint16_t id)
00172 {
00173     struct pico_dns_query test = {
00174         0
00175     }, *found = NULL;
00176 
00177     test.id = id;
00178     found = pico_tree_findKey(&DNSTable, &test);
00179     if (!found)
00180         return -1;
00181 
00182     PICO_FREE(found->query);
00183     pico_socket_close(found->s);
00184     pico_tree_delete(&DNSTable, found);
00185     PICO_FREE(found);
00186     return 0;
00187 }
00188 
00189 static struct pico_dns_query *pico_dns_client_find_query(uint16_t id)
00190 {
00191     struct pico_dns_query test = {
00192         0
00193     }, *found = NULL;
00194 
00195     test.id = id;
00196     found = pico_tree_findKey(&DNSTable, &test);
00197     if (found)
00198         return found;
00199     else
00200         return NULL;
00201 }
00202 
00203 /* seek end of string */
00204 static char *pico_dns_client_seek(char *ptr)
00205 {
00206     if (!ptr)
00207         return NULL;
00208 
00209     while (*ptr != 0)
00210         ptr++;
00211     return ptr + 1;
00212 }
00213 
00214 static struct pico_dns_query *pico_dns_client_idcheck(uint16_t id)
00215 {
00216     struct pico_dns_query test = {
00217         0
00218     };
00219 
00220     test.id = id;
00221     return pico_tree_findKey(&DNSTable, &test);
00222 }
00223 
00224 static int pico_dns_client_query_header(struct pico_dns_header *hdr)
00225 {
00226     uint16_t id = 0;
00227     uint8_t retry = 32;
00228 
00229     do {
00230         id = (uint16_t)(pico_rand() & 0xFFFFU);
00231         dns_dbg("DNS: generated id %u\n", id);
00232     } while (retry-- && pico_dns_client_idcheck(id));
00233     if (!retry)
00234         return -1;
00235 
00236     hdr->id = short_be(id);
00237     pico_dns_fill_packet_header(hdr, 1, 0, 0, 0); /* 1 question, 0 answers */
00238 
00239     return 0;
00240 }
00241 
00242 static int pico_dns_client_check_header(struct pico_dns_header *pre)
00243 {
00244     if (pre->qr != PICO_DNS_QR_RESPONSE || pre->opcode != PICO_DNS_OPCODE_QUERY || pre->rcode != PICO_DNS_RCODE_NO_ERROR) {
00245         dns_dbg("DNS ERROR: OPCODE %d | TC %d | RCODE %d\n", pre->opcode, pre->tc, pre->rcode);
00246         return -1;
00247     }
00248 
00249     if (short_be(pre->ancount) < 1) {
00250         dns_dbg("DNS ERROR: ancount < 1\n");
00251         return -1;
00252     }
00253 
00254     return 0;
00255 }
00256 
00257 static int pico_dns_client_check_qsuffix(struct pico_dns_question_suffix *suf, struct pico_dns_query *q)
00258 {
00259     if (!suf)
00260         return -1;
00261 
00262     if (short_be(suf->qtype) != q->qtype || short_be(suf->qclass) != q->qclass) {
00263         dns_dbg("DNS ERROR: received qtype (%u) or qclass (%u) incorrect\n", short_be(suf->qtype), short_be(suf->qclass));
00264         return -1;
00265     }
00266 
00267     return 0;
00268 }
00269 
00270 static int pico_dns_client_check_url(struct pico_dns_header *resp, struct pico_dns_query *q)
00271 {
00272     char *recv_name = (char*)(resp) + sizeof(struct pico_dns_header) + PICO_DNS_LABEL_INITIAL;
00273     char *exp_name = (char *)(q->query) + sizeof(struct pico_dns_header) + PICO_DNS_LABEL_INITIAL;
00274     if (strcasecmp(recv_name,  exp_name) != 0)
00275         return -1;
00276 
00277     return 0;
00278 }
00279 
00280 static int pico_dns_client_check_asuffix(struct pico_dns_record_suffix *suf, struct pico_dns_query *q)
00281 {
00282     if (!suf) {
00283         pico_err = PICO_ERR_EINVAL;
00284         return -1;
00285     }
00286 
00287     if (short_be(suf->rtype) != q->qtype || short_be(suf->rclass) != q->qclass) {
00288         dns_dbg("DNS WARNING: received qtype (%u) or qclass (%u) incorrect\n", short_be(suf->rtype), short_be(suf->rclass));
00289         return -1;
00290     }
00291 
00292     if (long_be(suf->rttl) > PICO_DNS_MAX_TTL) {
00293         dns_dbg("DNS WARNING: received TTL (%u) > MAX (%u)\n", short_be(suf->rttl), PICO_DNS_MAX_TTL);
00294         return -1;
00295     }
00296 
00297     return 0;
00298 }
00299 
00300 static char *pico_dns_client_seek_suffix(char *suf, struct pico_dns_header *pre, struct pico_dns_query *q)
00301 {
00302     struct pico_dns_record_suffix *asuffix = NULL;
00303     uint16_t comp = 0, compression = 0;
00304     uint16_t i = 0;
00305 
00306     if (!suf)
00307         return NULL;
00308 
00309     while (i++ < short_be(pre->ancount)) {
00310         comp = short_from(suf);
00311         compression = short_be(comp);
00312         switch (compression >> 14)
00313         {
00314         case PICO_DNS_POINTER:
00315             while (compression >> 14 == PICO_DNS_POINTER) {
00316                 dns_dbg("DNS: pointer\n");
00317                 suf += sizeof(uint16_t);
00318                 comp = short_from(suf);
00319                 compression = short_be(comp);
00320             }
00321             break;
00322 
00323         case PICO_DNS_LABEL:
00324             dns_dbg("DNS: label\n");
00325             suf = pico_dns_client_seek(suf);
00326             break;
00327 
00328         default:
00329             dns_dbg("DNS ERROR: incorrect compression (%u) value\n", compression);
00330             return NULL;
00331         }
00332 
00333         asuffix = (struct pico_dns_record_suffix *)suf;
00334         if (!asuffix)
00335             break;
00336 
00337         if (pico_dns_client_check_asuffix(asuffix, q) < 0) {
00338             suf += (sizeof(struct pico_dns_record_suffix) + short_be(asuffix->rdlength));
00339             continue;
00340         }
00341 
00342         return suf;
00343     }
00344     return NULL;
00345 }
00346 
00347 static int pico_dns_client_send(struct pico_dns_query *q)
00348 {
00349     uint16_t *paramID = PICO_ZALLOC(sizeof(uint16_t));
00350     if (!paramID) {
00351         pico_err = PICO_ERR_ENOMEM;
00352         return -1;
00353     }
00354 
00355     dns_dbg("DNS: sending query to %08X\n", q->q_ns.ns.addr);
00356     if (!q->s)
00357         goto failure;
00358 
00359     if (pico_socket_connect(q->s, &q->q_ns.ns, short_be(PICO_DNS_NS_PORT)) < 0)
00360         goto failure;
00361 
00362     pico_socket_send(q->s, q->query, q->len);
00363     *paramID = q->id;
00364     pico_timer_add(PICO_DNS_CLIENT_RETRANS, pico_dns_client_retransmission, paramID);
00365 
00366     return 0;
00367 
00368 failure:
00369     PICO_FREE(paramID);
00370     return -1;
00371 }
00372 
00373 static void pico_dns_client_retransmission(pico_time now, void *arg)
00374 {
00375     struct pico_dns_query *q = NULL;
00376     struct pico_dns_query dummy;
00377     IGNORE_PARAMETER(now);
00378 
00379     if(!arg)
00380         return;
00381 
00382     /* search for the dns query and free used space */
00383     dummy.id = *(uint16_t *)arg;
00384     q = (struct pico_dns_query *)pico_tree_findKey(&DNSTable, &dummy);
00385     PICO_FREE(arg);
00386 
00387     /* dns query successful? */
00388     if (!q) {
00389         return;
00390     }
00391 
00392     q->retrans++;
00393     if (q->retrans <= PICO_DNS_CLIENT_MAX_RETRANS) {
00394         q->q_ns = pico_dns_client_next_ns(&q->q_ns.ns);
00395         pico_dns_client_send(q);
00396     } else {
00397         pico_err = PICO_ERR_EIO;
00398         q->callback(NULL, q->arg);
00399         pico_dns_client_del_query(q->id);
00400     }
00401 }
00402 
00403 static int pico_dns_client_user_callback(struct pico_dns_record_suffix *asuffix, struct pico_dns_query *q)
00404 {
00405     uint32_t ip = 0;
00406     char *str = NULL;
00407     char *rdata = (char *) asuffix + sizeof(struct pico_dns_record_suffix);
00408 
00409     switch (q->qtype)
00410     {
00411     case PICO_DNS_TYPE_A:
00412         ip = long_from(rdata);
00413         str = PICO_ZALLOC(PICO_DNS_IPV4_ADDR_LEN);
00414         pico_ipv4_to_string(str, ip);
00415         break;
00416 #ifdef PICO_SUPPORT_IPV6
00417     case PICO_DNS_TYPE_AAAA:
00418     {
00419         struct pico_ip6 ip6;
00420         memcpy(&ip6.addr, rdata, sizeof(struct pico_ip6));
00421         str = PICO_ZALLOC(PICO_DNS_IPV6_ADDR_LEN);
00422         pico_ipv6_to_string(str, ip6.addr);
00423         break;
00424     }
00425 #endif
00426     case PICO_DNS_TYPE_PTR:
00427         /* TODO: check for decompression / rdlength vs. decompressed length */
00428         pico_dns_notation_to_name(rdata, short_be(asuffix->rdlength));
00429         str = PICO_ZALLOC((size_t)(short_be(asuffix->rdlength) -
00430                                    PICO_DNS_LABEL_INITIAL));
00431         if (!str) {
00432             pico_err = PICO_ERR_ENOMEM;
00433             return -1;
00434         }
00435 
00436         memcpy(str, rdata + PICO_DNS_LABEL_INITIAL, short_be(asuffix->rdlength) - PICO_DNS_LABEL_INITIAL);
00437         break;
00438 
00439     default:
00440         dns_dbg("DNS ERROR: incorrect qtype (%u)\n", q->qtype);
00441         break;
00442     }
00443 
00444     if (q->retrans) {
00445         q->callback(str, q->arg);
00446         q->retrans = 0;
00447         pico_dns_client_del_query(q->id);
00448     }
00449 
00450     if (str)
00451         PICO_FREE(str);
00452 
00453     return 0;
00454 }
00455 
00456 static char dns_response[PICO_IP_MRU] = {
00457     0
00458 };
00459 
00460 static void pico_dns_try_fallback_cname(struct pico_dns_query *q, struct pico_dns_header *h, struct pico_dns_question_suffix *qsuffix)
00461 {
00462     uint16_t type = q->qtype;
00463     uint16_t proto = PICO_PROTO_IPV4;
00464     struct pico_dns_record_suffix *asuffix = NULL;
00465     char *p_asuffix = NULL;
00466     char *cname_orig = NULL;
00467     char *cname = NULL;
00468     uint16_t cname_len;
00469 
00470     /* Try to use CNAME only if A or AAAA query is ongoing */
00471     if (type != PICO_DNS_TYPE_A && type != PICO_DNS_TYPE_AAAA)
00472         return;
00473 
00474     if (type == PICO_DNS_TYPE_AAAA)
00475         proto = PICO_PROTO_IPV6;
00476 
00477     q->qtype = PICO_DNS_TYPE_CNAME;
00478     p_asuffix = (char *)qsuffix + sizeof(struct pico_dns_question_suffix);
00479     p_asuffix = pico_dns_client_seek_suffix(p_asuffix, h, q);
00480     if (!p_asuffix) {
00481         return;
00482     }
00483 
00484     /* Found CNAME response. Re-initiating query. */
00485     asuffix = (struct pico_dns_record_suffix *)p_asuffix;
00486     cname = pico_dns_decompress_name((char *)asuffix + sizeof(struct pico_dns_record_suffix), (pico_dns_packet *)h); /* allocates memory! */
00487     cname_orig = cname; /* to free later */
00488 
00489     if (cname == NULL)
00490         return;
00491 
00492     cname_len = (uint16_t)(pico_dns_strlen(cname) + 1);
00493 
00494     pico_dns_notation_to_name(cname, cname_len);
00495     if (cname[0] == '.')
00496         cname++;
00497 
00498     dns_dbg("Restarting query for name '%s'\n", cname);
00499     pico_dns_client_getaddr_init(cname, proto, q->callback, q->arg);
00500     PICO_FREE(cname_orig);
00501     pico_dns_client_del_query(q->id);
00502 }
00503 
00504 static void pico_dns_client_callback(uint16_t ev, struct pico_socket *s)
00505 {
00506     struct pico_dns_header *header = NULL;
00507     char *domain;
00508     struct pico_dns_question_suffix *qsuffix = NULL;
00509     struct pico_dns_record_suffix *asuffix = NULL;
00510     struct pico_dns_query *q = NULL;
00511     char *p_asuffix = NULL;
00512 
00513     if (ev == PICO_SOCK_EV_ERR) {
00514         dns_dbg("DNS: socket error received\n");
00515         return;
00516     }
00517 
00518     if (ev & PICO_SOCK_EV_RD) {
00519         if (pico_socket_read(s, dns_response, PICO_IP_MRU) < 0)
00520             return;
00521     }
00522 
00523     header = (struct pico_dns_header *)dns_response;
00524     domain = (char *)header + sizeof(struct pico_dns_header);
00525     qsuffix = (struct pico_dns_question_suffix *)pico_dns_client_seek(domain);
00526     /* valid asuffix is determined dynamically later on */
00527 
00528     if (pico_dns_client_check_header(header) < 0)
00529         return;
00530 
00531     q = pico_dns_client_find_query(short_be(header->id));
00532     if (!q)
00533         return;
00534 
00535     if (pico_dns_client_check_qsuffix(qsuffix, q) < 0)
00536         return;
00537 
00538     if (pico_dns_client_check_url(header, q) < 0)
00539         return;
00540 
00541     p_asuffix = (char *)qsuffix + sizeof(struct pico_dns_question_suffix);
00542     p_asuffix = pico_dns_client_seek_suffix(p_asuffix, header, q);
00543     if (!p_asuffix) {
00544         pico_dns_try_fallback_cname(q, header, qsuffix);
00545         return;
00546     }
00547 
00548     asuffix = (struct pico_dns_record_suffix *)p_asuffix;
00549     pico_dns_client_user_callback(asuffix, q);
00550 
00551     return;
00552 }
00553 
00554 static int pico_dns_create_message(struct pico_dns_header **header, struct pico_dns_question_suffix **qsuffix, enum pico_dns_arpa arpa, const char *url, uint16_t *urlen, uint16_t *hdrlen)
00555 {
00556     char *domain;
00557     char inaddr_arpa[14];
00558     uint16_t strlen = 0, arpalen = 0;
00559 
00560     if (!url) {
00561         pico_err = PICO_ERR_EINVAL;
00562         return -1;
00563     }
00564 
00565     if(arpa == PICO_DNS_ARPA4) {
00566         strcpy(inaddr_arpa, ".in-addr.arpa");
00567         strlen = pico_dns_strlen(url);
00568     }
00569 
00570 #ifdef PICO_SUPPORT_IPV6
00571     else if (arpa == PICO_DNS_ARPA6) {
00572         strcpy(inaddr_arpa, ".IP6.ARPA");
00573         strlen = STRLEN_PTR_IP6;
00574     }
00575 #endif
00576     else {
00577         strcpy(inaddr_arpa, "");
00578         strlen = pico_dns_strlen(url);
00579     }
00580 
00581     arpalen = pico_dns_strlen(inaddr_arpa);
00582     *urlen = (uint16_t)(PICO_DNS_LABEL_INITIAL + strlen + arpalen + PICO_DNS_LABEL_ROOT);
00583     *hdrlen = (uint16_t)(sizeof(struct pico_dns_header) + *urlen + sizeof(struct pico_dns_question_suffix));
00584     *header = PICO_ZALLOC(*hdrlen);
00585     if (!*header) {
00586         pico_err = PICO_ERR_ENOMEM;
00587         return -1;
00588     }
00589 
00590     *header = (struct pico_dns_header *)*header;
00591     domain = (char *) *header + sizeof(struct pico_dns_header);
00592     *qsuffix = (struct pico_dns_question_suffix *)(domain + *urlen);
00593 
00594     if(arpa == PICO_DNS_ARPA4) {
00595         memcpy(domain + PICO_DNS_LABEL_INITIAL, url, strlen);
00596         pico_dns_mirror_addr(domain + PICO_DNS_LABEL_INITIAL);
00597         memcpy(domain + PICO_DNS_LABEL_INITIAL + strlen, inaddr_arpa, arpalen);
00598     }
00599 
00600 #ifdef PICO_SUPPORT_IPV6
00601     else if (arpa == PICO_DNS_ARPA6) {
00602         pico_dns_ipv6_set_ptr(url, domain + PICO_DNS_LABEL_INITIAL);
00603         memcpy(domain + PICO_DNS_LABEL_INITIAL + STRLEN_PTR_IP6, inaddr_arpa, arpalen);
00604     }
00605 #endif
00606     else {
00607         memcpy(domain + PICO_DNS_LABEL_INITIAL, url, strlen);
00608     }
00609 
00610     /* assemble dns message */
00611     pico_dns_client_query_header(*header);
00612     pico_dns_name_to_dns_notation(domain, strlen);
00613 
00614     return 0;
00615 }
00616 
00617 static int pico_dns_client_addr_label_check_len(const char *url)
00618 {
00619     const char *p, *label;
00620     int count;
00621     label = url;
00622     p = label;
00623 
00624     while(*p != (char) 0) {
00625         count = 0;
00626         while((*p != (char)0)) {
00627             if (*p == '.') {
00628                 label = ++p;
00629                 break;
00630             }
00631 
00632             count++;
00633             p++;
00634             if (count > PICO_DNS_MAX_QUERY_LABEL_LEN)
00635                 return -1;
00636         }
00637     }
00638     return 0;
00639 }
00640 
00641 static int pico_dns_client_getaddr_check(const char *url, void (*callback)(char *, void *))
00642 {
00643     if (!url || !callback) {
00644         pico_err = PICO_ERR_EINVAL;
00645         return -1;
00646     }
00647 
00648     if (strlen(url) > PICO_DNS_MAX_QUERY_LEN) {
00649         pico_err = PICO_ERR_EINVAL;
00650         return -1;
00651     }
00652 
00653     if (pico_dns_client_addr_label_check_len(url) < 0) {
00654         pico_err = PICO_ERR_EINVAL;
00655         return -1;
00656     }
00657 
00658     return 0;
00659 }
00660 
00661 static int pico_dns_client_getaddr_init(const char *url, uint16_t proto, void (*callback)(char *, void *), void *arg)
00662 {
00663     struct pico_dns_header *header = NULL;
00664     struct pico_dns_question_suffix *qsuffix = NULL;
00665     struct pico_dns_query *q = NULL;
00666     uint16_t len = 0, lblen = 0;
00667     (void)proto;
00668 
00669     if (pico_dns_client_getaddr_check(url, callback) < 0)
00670         return -1;
00671 
00672     if(pico_dns_create_message(&header, &qsuffix, PICO_DNS_NO_ARPA, url, &lblen, &len) != 0)
00673         return -1;
00674 
00675 #ifdef PICO_SUPPORT_IPV6
00676     if (proto == PICO_PROTO_IPV6) {
00677         pico_dns_question_fill_suffix(qsuffix, PICO_DNS_TYPE_AAAA, PICO_DNS_CLASS_IN);
00678     } else
00679 #endif
00680     pico_dns_question_fill_suffix(qsuffix, PICO_DNS_TYPE_A, PICO_DNS_CLASS_IN);
00681 
00682     q = pico_dns_client_add_query(header, len, qsuffix, callback, arg);
00683     if (!q) {
00684         PICO_FREE(header);
00685         return -1;
00686     }
00687 
00688     if (pico_dns_client_send(q) < 0) {
00689         pico_dns_client_del_query(q->id); /* frees msg */
00690         return -1;
00691     }
00692 
00693     return 0;
00694 }
00695 
00696 int pico_dns_client_getaddr(const char *url, void (*callback)(char *, void *), void *arg)
00697 {
00698     return pico_dns_client_getaddr_init(url, PICO_PROTO_IPV4, callback, arg);
00699 }
00700 
00701 int pico_dns_client_getaddr6(const char *url, void (*callback)(char *, void *), void *arg)
00702 {
00703     return pico_dns_client_getaddr_init(url, PICO_PROTO_IPV6, callback, arg);
00704 }
00705 
00706 static int pico_dns_getname_univ(const char *ip, void (*callback)(char *, void *), void *arg, enum pico_dns_arpa arpa)
00707 {
00708     struct pico_dns_header *header = NULL;
00709     struct pico_dns_question_suffix *qsuffix = NULL;
00710     struct pico_dns_query *q = NULL;
00711     uint16_t len = 0, lblen = 0;
00712 
00713     if (!ip || !callback) {
00714         pico_err = PICO_ERR_EINVAL;
00715         return -1;
00716     }
00717 
00718     if(pico_dns_create_message(&header, &qsuffix, arpa, ip, &lblen, &len) != 0)
00719         return -1;
00720 
00721     pico_dns_question_fill_suffix(qsuffix, PICO_DNS_TYPE_PTR, PICO_DNS_CLASS_IN);
00722     q = pico_dns_client_add_query(header, len, qsuffix, callback, arg);
00723     if (!q) {
00724         PICO_FREE(header);
00725         return -1;
00726     }
00727 
00728     if (pico_dns_client_send(q) < 0) {
00729         pico_dns_client_del_query(q->id); /* frees header */
00730         return -1;
00731     }
00732 
00733     return 0;
00734 }
00735 
00736 int pico_dns_client_getname(const char *ip, void (*callback)(char *, void *), void *arg)
00737 {
00738     return pico_dns_getname_univ(ip, callback, arg, PICO_DNS_ARPA4);
00739 }
00740 
00741 
00742 int pico_dns_client_getname6(const char *ip, void (*callback)(char *, void *), void *arg)
00743 {
00744     return pico_dns_getname_univ(ip, callback, arg, PICO_DNS_ARPA6);
00745 }
00746 
00747 int pico_dns_client_nameserver(struct pico_ip4 *ns, uint8_t flag)
00748 {
00749     if (!ns) {
00750         pico_err = PICO_ERR_EINVAL;
00751         return -1;
00752     }
00753 
00754     switch (flag)
00755     {
00756     case PICO_DNS_NS_ADD:
00757         if (!pico_dns_client_add_ns(ns))
00758             return -1;
00759 
00760         break;
00761 
00762     case PICO_DNS_NS_DEL:
00763         if (pico_dns_client_del_ns(ns) < 0) {
00764             pico_err = PICO_ERR_EINVAL;
00765             return -1;
00766         }
00767 
00768         break;
00769 
00770     default:
00771         pico_err = PICO_ERR_EINVAL;
00772         return -1;
00773     }
00774     return 0;
00775 }
00776 
00777 int pico_dns_client_init(void)
00778 {
00779     struct pico_ip4 default_ns = {
00780         0
00781     };
00782 
00783     if (pico_string_to_ipv4(PICO_DNS_NS_DEFAULT, (uint32_t *)&default_ns.addr) < 0)
00784         return -1;
00785 
00786     return pico_dns_client_nameserver(&default_ns, PICO_DNS_NS_ADD);
00787 }
00788 
00789 #else
00790 
00791 int pico_dns_client_init(void)
00792 {
00793     dbg("ERROR Trying to initialize DNS module: IPv4 not supported in this build.\n");
00794     return -1;
00795 }
00796 #endif /* PICO_SUPPORT_IPV4 */
00797 
00798 
00799 #endif /* PICO_SUPPORT_DNS_CLIENT */
00800