CDC/ECM driver for mbed, based on USBDevice by mbed-official. Uses PicoTCP to access Ethernet USB device. License: GPLv2

Dependents:   USBEthernet_TEST

Fork of USB_Ethernet by Daniele Lacamera

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 .
00006   
00007 Authors: Kristof Roelants
00008 *********************************************************************/
00009 #include "pico_config.h"
00010 #include "pico_stack.h"
00011 #include "pico_addressing.h"
00012 #include "pico_socket.h"
00013 #include "pico_ipv4.h"
00014 #include "pico_dns_client.h"
00015 #include "pico_tree.h"
00016 
00017 #ifdef PICO_SUPPORT_DNS_CLIENT
00018 
00019 #define dns_dbg(...) do{}while(0)
00020 //#define dns_dbg dbg
00021 
00022 /* DNS response length */
00023 #define PICO_DNS_MAX_RESPONSE_LEN 256
00024 
00025 /* DNS client retransmission time (msec) + frequency */
00026 #define PICO_DNS_CLIENT_RETRANS 4000
00027 #define PICO_DNS_CLIENT_MAX_RETRANS 3
00028 
00029 /* Default nameservers */
00030 #define PICO_DNS_NS_GOOGLE "8.8.8.8"
00031 
00032 /* Nameserver port */
00033 #define PICO_DNS_NS_PORT 53
00034 
00035 /* FLAG values */
00036 #define PICO_DNS_QR_QUERY 0
00037 #define PICO_DNS_QR_RESPONSE 1
00038 #define PICO_DNS_OPCODE_QUERY 0
00039 #define PICO_DNS_OPCODE_IQUERY 1
00040 #define PICO_DNS_OPCODE_STATUS 2
00041 #define PICO_DNS_AA_NO_AUTHORITY 0
00042 #define PICO_DNS_AA_IS_AUTHORITY 1
00043 #define PICO_DNS_TC_NO_TRUNCATION 0
00044 #define PICO_DNS_TC_IS_TRUNCATED 1
00045 #define PICO_DNS_RD_NO_DESIRE 0
00046 #define PICO_DNS_RD_IS_DESIRED 1
00047 #define PICO_DNS_RA_NO_SUPPORT 0
00048 #define PICO_DNS_RA_IS_SUPPORTED 1
00049 #define PICO_DNS_RCODE_NO_ERROR 0
00050 #define PICO_DNS_RCODE_EFORMAT 1
00051 #define PICO_DNS_RCODE_ESERVER 2
00052 #define PICO_DNS_RCODE_ENAME 3
00053 #define PICO_DNS_RCODE_ENOIMP 4
00054 #define PICO_DNS_RCODE_EREFUSED 5
00055 
00056 /* QTYPE values */
00057 #define PICO_DNS_TYPE_A 1
00058 #define PICO_DNS_TYPE_PTR 12
00059 
00060 /* QCLASS values */
00061 #define PICO_DNS_CLASS_IN 1
00062 
00063 /* Compression values */
00064 #define PICO_DNS_LABEL 0
00065 #define PICO_DNS_POINTER 3
00066 
00067 /* TTL values */
00068 #define PICO_DNS_MAX_TTL 604800 /* one week */
00069 
00070 /* Header flags */
00071 #define FLAG_QR(hdr, x) ((hdr)->flags = ((hdr)->flags & ~(0x1 << 15)) | (x << 15)) 
00072 #define FLAG_OPCODE(hdr, x) ((hdr)->flags = ((hdr)->flags & ~(0xF << 11)) | (x << 11)) 
00073 #define FLAG_AA(hdr, x) ((hdr)->flags = ((hdr)->flags & ~(0x1 << 10)) | (x << 10)) 
00074 #define FLAG_TC(hdr, x) ((hdr)->flags = ((hdr)->flags & ~(0x1 << 9)) | (x << 9)) 
00075 #define FLAG_RD(hdr, x) ((hdr)->flags = ((hdr)->flags & ~(0x1 << 8)) | (x << 8)) 
00076 #define FLAG_RA(hdr, x) ((hdr)->flags = ((hdr)->flags & ~(0x1 << 7)) | (x << 7)) 
00077 #define FLAG_Z(hdr, x) ((hdr)->flags = ((hdr)->flags & ~(0x7 << 4)) | (x << 4)) 
00078 #define FLAG_RCODE(hdr, x) ((hdr)->flags = ((hdr)->flags & ~(0xF)) | x) 
00079 
00080 #define GET_FLAG_QR(hdr) ((((hdr)->flags) & (1 << 15)) != 0) 
00081 #define GET_FLAG_OPCODE(hdr) ((((hdr)->flags) & (0xF << 11)) >> 11) 
00082 #define GET_FLAG_AA(hdr) ((((hdr)->flags) & (1 << 10)) != 0) 
00083 #define GET_FLAG_TC(hdr) ((((hdr)->flags) & (1 << 9)) != 0) 
00084 #define GET_FLAG_RD(hdr) ((((hdr)->flags) & (1 << 8)) != 0) 
00085 #define GET_FLAG_RA(hdr) ((((hdr)->flags) & (1 << 7)) != 0) 
00086 #define GET_FLAG_Z(hdr) ((((hdr)->flags) & (0x7 << 4)) >> 4) 
00087 #define GET_FLAG_RCODE(hdr) (((hdr)->flags) & (0x0F)) 
00088 
00089 /* RFC 1025 section 4. MESSAGES */
00090 struct __attribute__((packed)) dns_message_hdr
00091 {
00092   uint16_t id;
00093   uint16_t flags;
00094   uint16_t qdcount;
00095   uint16_t ancount;
00096   uint16_t nscount;
00097   uint16_t arcount;
00098 };
00099 
00100 struct __attribute__((packed)) dns_query_suffix
00101 {
00102   /* NAME - domain name to which this resource record pertains */
00103   uint16_t qtype;
00104   uint16_t qclass;
00105 };
00106 
00107 struct __attribute__((packed)) dns_answer_suffix
00108 {
00109   /* NAME - domain name to which this resource record pertains */
00110   uint16_t qtype;
00111   uint16_t qclass;
00112   uint32_t ttl;
00113   uint16_t rdlength;
00114   /* RDATA - variable length string of octets that describes the resource */
00115 };
00116 
00117 struct pico_dns_ns
00118 {
00119   struct pico_ip4 ns; /* Nameserver */
00120 };
00121 
00122 static int dns_ns_cmp(void *ka, void *kb)
00123 {
00124     struct pico_dns_ns *a = ka, *b = kb;
00125   if (a->ns.addr < b->ns.addr)
00126     return -1; 
00127   else if (a->ns.addr > b->ns.addr)
00128     return 1;
00129   else
00130     return 0;
00131 } 
00132     
00133 PICO_TREE_DECLARE(NSTable,dns_ns_cmp);
00134 
00135 int pico_dns_client_nameserver(struct pico_ip4 *ns, uint8_t flag)
00136 {
00137   struct pico_dns_ns test, *key = NULL;
00138 
00139   if (!ns) {
00140     pico_err = PICO_ERR_EINVAL;
00141     return -1;
00142   }
00143 
00144   switch (flag)
00145   {
00146     case PICO_DNS_NS_ADD:
00147       key = pico_zalloc(sizeof(struct pico_dns_ns));
00148       if (!key) {
00149         pico_err = PICO_ERR_ENOMEM;
00150         return -1;
00151       }
00152       key->ns = *ns;
00153 
00154       if(pico_tree_insert(&NSTable,key)){
00155         dns_dbg("DNS WARNING: nameserver %08X already added\n",ns->addr);
00156         pico_err = PICO_ERR_EINVAL;
00157         pico_free(key);
00158         return -1; /* Element key already exists */
00159       }
00160       dns_dbg("DNS: nameserver %08X added\n", ns->addr);
00161       /* If default NS found, remove it */
00162       pico_string_to_ipv4(PICO_DNS_NS_GOOGLE, &test.ns.addr);
00163       if (ns->addr != test.ns.addr) {
00164 
00165           key = pico_tree_findKey(&NSTable,&test);
00166         if (key) {
00167             if(pico_tree_delete(&NSTable,key)) {
00168             dns_dbg("DNS: default nameserver %08X removed\n", test.ns.addr);
00169             pico_free(key);
00170           } else {
00171             pico_err = PICO_ERR_EAGAIN;
00172             return -1;
00173           }
00174         }
00175       }
00176       break;
00177 
00178     case PICO_DNS_NS_DEL:
00179       test.ns = *ns;
00180 
00181       key = pico_tree_findKey(&NSTable,&test);
00182       if (!key) {
00183         dns_dbg("DNS WARNING: nameserver %08X not found\n", ns->addr);
00184         pico_err = PICO_ERR_EINVAL;
00185         return -1;
00186       }
00187       /* RB_REMOVE returns pointer to removed element, NULL to indicate error */
00188 
00189             if(pico_tree_delete(&NSTable,key)) {
00190         dns_dbg("DNS: nameserver %08X removed\n",key->ns.addr);
00191         pico_free(key);
00192       } else {
00193         pico_err = PICO_ERR_EAGAIN;
00194         return -1;
00195       }
00196       /* If no NS left, add default NS */
00197       if(pico_tree_first(&NSTable) == NULL){
00198         dns_dbg("DNS: add default nameserver\n");
00199         return pico_dns_client_init();
00200       }
00201       break;
00202 
00203     default:
00204       pico_err = PICO_ERR_EINVAL;
00205       return -1;
00206   }
00207   return 0;
00208 }
00209 
00210 int pico_dns_client_init()
00211 {
00212   struct pico_ip4 default_ns;
00213   if (pico_string_to_ipv4(PICO_DNS_NS_GOOGLE, &default_ns.addr) != 0) {
00214     pico_err = PICO_ERR_EINVAL;
00215     return -1;
00216   }
00217   return pico_dns_client_nameserver(&default_ns, PICO_DNS_NS_ADD);
00218 }
00219 
00220 struct pico_dns_key
00221 {
00222   char *q_hdr;
00223   uint16_t len;
00224   uint16_t id;
00225   uint16_t qtype;
00226   uint16_t qclass;
00227   uint8_t retrans;
00228   struct pico_dns_ns q_ns;
00229   struct pico_socket *s;
00230   void (*callback)(char *, void *);
00231   void *arg;
00232 };
00233 
00234 static int dns_cmp(void *ka, void *kb)
00235 {
00236     struct pico_dns_key *a = ka,*b = kb;
00237   if (a->id < b->id)
00238     return -1; 
00239   else if (a->id > b->id)
00240     return 1;
00241   else
00242     return 0;
00243 } 
00244     
00245 PICO_TREE_DECLARE(DNSTable,dns_cmp);
00246 
00247 static int pico_dns_client_strlen(const char *url)
00248 {
00249   uint16_t len = 0;
00250   int p;
00251 
00252   if (!url)
00253     return -1;
00254 
00255   while ((p = *url++) != 0) {
00256     len++;
00257   }
00258   return len;
00259 }
00260 
00261 /* Replace '.' by the label length */
00262 static int pico_dns_client_label(char *ptr)
00263 {
00264   char *l;
00265   uint8_t lbl_len = 0;
00266   int p;
00267 
00268   if (!ptr)
00269     return -1;
00270 
00271   l = ptr++;
00272   while ((p = *ptr++) != 0){
00273     if (p == '.') {
00274       *l = lbl_len;
00275       l = ptr - 1;
00276       lbl_len = 0;
00277     } else {
00278       lbl_len++;
00279     }
00280   }
00281   *l = lbl_len;
00282   return 0;
00283 }
00284 
00285 /* Replace the label length by '.' */
00286 static int pico_dns_client_reverse_label(char *ptr)
00287 {
00288   char *l;
00289   int p;
00290 
00291   if(!ptr)
00292     return -1;
00293 
00294   l = ptr;
00295   while ((p = *ptr++) != 0){
00296     ptr += p;
00297     *l = '.';
00298     l = ptr;
00299   }
00300   return 0;
00301 }
00302 
00303 /* Seek the end of a string */
00304 static char *pico_dns_client_seek(char *ptr)
00305 {
00306   int p;
00307 
00308   if (!ptr)
00309     return NULL;
00310 
00311   while ((p = *ptr++) != 0);
00312 
00313   return ptr++;
00314 }
00315 
00316 static inline void pico_dns_client_construct_hdr(struct dns_message_hdr *hdr, uint16_t id)
00317 {
00318   hdr->id = short_be(id);
00319   FLAG_QR(hdr, PICO_DNS_QR_QUERY); 
00320   FLAG_OPCODE(hdr, PICO_DNS_OPCODE_QUERY); 
00321   FLAG_AA(hdr, PICO_DNS_AA_NO_AUTHORITY); 
00322   FLAG_TC(hdr, PICO_DNS_TC_NO_TRUNCATION); 
00323   FLAG_RD(hdr, PICO_DNS_RD_IS_DESIRED); 
00324   FLAG_RA(hdr, PICO_DNS_RA_NO_SUPPORT); 
00325   FLAG_Z(hdr, 0); 
00326   FLAG_RCODE(hdr, PICO_DNS_RCODE_NO_ERROR); 
00327   hdr->flags = short_be(hdr->flags);
00328   hdr->qdcount = short_be(1);
00329   hdr->ancount = short_be(0);
00330   hdr->nscount = short_be(0);
00331   hdr->arcount = short_be(0);
00332 }
00333 
00334 static inline void pico_dns_client_hdr_ntoh(struct dns_message_hdr *hdr)
00335 {
00336   hdr->id = short_be(hdr->id);
00337   hdr->flags = short_be(hdr->flags);
00338   hdr->qdcount = short_be(hdr->qdcount);
00339   hdr->ancount = short_be(hdr->ancount);
00340   hdr->nscount = short_be(hdr->nscount);
00341   hdr->arcount = short_be(hdr->arcount);
00342 }
00343 
00344 
00345 static int pico_dns_client_mirror(char *ptr)
00346 {
00347   unsigned char buf[4] = {0};
00348   char *m;
00349   int cnt = 0;
00350   int p, i;
00351 
00352   if (!ptr)
00353     return -1;
00354 
00355   m = ptr;
00356   while ((p = *ptr++) != 0)
00357   {
00358     if (pico_is_digit(p)) {
00359       buf[cnt] = (10 * buf[cnt]) + (p - '0');
00360     } else if (p == '.') {
00361         cnt++;
00362     } else {
00363       return -1;
00364     }
00365   }
00366 
00367   /* Handle short notation */
00368   if(cnt == 1){
00369     buf[3] = buf[1];
00370     buf[1] = 0;
00371     buf[2] = 0;
00372   }else if (cnt == 2){
00373     buf[3] = buf[2];
00374     buf[2] = 0;
00375   }else if(cnt != 3){
00376     /* String could not be parsed, return error */
00377     return -1;
00378   }
00379 
00380   ptr = m;
00381   for(i = 3; i >= 0; i--)
00382   {
00383     if(buf[i] > 99){
00384       *ptr++ = '0' + (buf[i] / 100);
00385       *ptr++ = '0' + ((buf[i] % 100) / 10);
00386       *ptr++ = '0' + ((buf[i] % 100) % 10);
00387     }else if(buf[i] > 9){
00388       *ptr++ = '0' + (buf[i] / 10);
00389       *ptr++ = '0' + (buf[i] % 10);
00390     }else{
00391       *ptr++ = '0' + buf[i];
00392     }
00393     if(i > 0)
00394       *ptr++ = '.';
00395   }
00396 
00397   return 0;
00398 }
00399 
00400 static struct pico_dns_key *pico_dns_client_idcheck(uint16_t id)
00401 {
00402   struct pico_dns_key test;
00403 
00404   test.id = id;
00405   return pico_tree_findKey(&DNSTable,&test);
00406 }
00407 
00408 static void pico_dns_client_callback(uint16_t ev, struct pico_socket *s);
00409 
00410 static int pico_dns_client_send(struct pico_dns_key *key)
00411 {
00412   struct pico_socket *s;
00413   int w = 0;
00414 
00415   dns_dbg("DNS: sending query to %08X\n", key->q_ns.ns.addr);
00416   s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &pico_dns_client_callback);
00417   if (!s)
00418     return -1; 
00419   key->s = s;
00420   if (pico_socket_connect(s, &key->q_ns.ns, short_be(PICO_DNS_NS_PORT)) != 0)
00421     return -1;
00422   w = pico_socket_send(s, key->q_hdr, key->len);
00423   if (w <= 0)
00424     return -1;
00425 
00426   return 0;
00427 }
00428 
00429 static void pico_dns_client_retransmission(unsigned long now, void *arg)
00430 {
00431   struct pico_dns_key *key = (struct pico_dns_key *)arg;
00432   struct pico_dns_ns *q_ns = NULL;
00433 
00434   if (!key->retrans) {
00435     dns_dbg("DNS: no retransmission!\n");
00436     pico_free(key->q_hdr);
00437 
00438     if(pico_tree_delete(&DNSTable,key))
00439       pico_free(key);
00440   }
00441   else if (key->retrans <= PICO_DNS_CLIENT_MAX_RETRANS) {
00442     key->retrans++;
00443     dns_dbg("DNS: retransmission! (%u attempts)\n", key->retrans);
00444         // ugly hack
00445     q_ns = pico_tree_next(pico_tree_findNode(&NSTable,&key->q_ns))->keyValue;
00446     if (q_ns)
00447       key->q_ns = *q_ns; 
00448     else
00449         key->q_ns = *((struct pico_dns_ns *)pico_tree_first(&NSTable));
00450     pico_dns_client_send(key);
00451     pico_timer_add(PICO_DNS_CLIENT_RETRANS, pico_dns_client_retransmission, key);
00452   } else {
00453     dns_dbg("DNS ERROR: no reply from nameservers! (%u attempts)\n", key->retrans);
00454     pico_socket_close(key->s);
00455     pico_err = PICO_ERR_EIO;
00456     key->callback(NULL, key->arg);
00457     pico_free(key->q_hdr);
00458     /* RB_REMOVE returns pointer to removed element, NULL to indicate error */
00459 
00460     if(pico_tree_delete(&DNSTable,key))
00461       pico_free(key);
00462   }
00463 }
00464 
00465 static void pico_dns_client_callback(uint16_t ev, struct pico_socket *s)
00466 {
00467   char *q_qname, *q_suf, *a_hdr, *a_qname, *a_suf, *a_rdata;
00468   struct dns_message_hdr *hdr;
00469   struct dns_query_suffix query_suf;
00470   struct dns_answer_suffix answer_suf;
00471   struct pico_dns_key test, *key;
00472   char *answer;
00473   char dns_answer[PICO_DNS_MAX_RESPONSE_LEN] = {0};
00474   uint8_t valid_suffix = 0;
00475   uint16_t compression = 0;
00476   int i = 0, r = 0;
00477 
00478   if (ev & PICO_SOCK_EV_RD) {
00479     r = pico_socket_read(s, dns_answer, PICO_DNS_MAX_RESPONSE_LEN);
00480     pico_socket_close(s);
00481     if (r == PICO_DNS_MAX_RESPONSE_LEN || r < (int)sizeof(struct dns_message_hdr)) {
00482       dns_dbg("DNS ERROR: received incorrect number(%d) of bytes\n", r);
00483       return;
00484     }
00485 
00486     /* Check header validity */
00487     a_hdr = dns_answer;
00488     hdr = (struct dns_message_hdr *) a_hdr;
00489     pico_dns_client_hdr_ntoh(hdr);
00490     if (GET_FLAG_QR(hdr) != PICO_DNS_QR_RESPONSE || GET_FLAG_OPCODE(hdr) != PICO_DNS_OPCODE_QUERY 
00491         || GET_FLAG_TC(hdr) == PICO_DNS_TC_IS_TRUNCATED || GET_FLAG_RCODE(hdr) != PICO_DNS_RCODE_NO_ERROR) {
00492       dns_dbg("DNS ERROR: OPCODE %d | TC %d | RCODE %d\n", GET_FLAG_OPCODE(hdr), GET_FLAG_TC(hdr), GET_FLAG_RCODE(hdr));
00493       return;
00494     }
00495 
00496     if (hdr->ancount < 1 || r < (int)(sizeof(struct dns_message_hdr) + hdr->qdcount * sizeof(struct dns_query_suffix)
00497             + hdr->ancount * sizeof(struct dns_answer_suffix))) {
00498       dns_dbg("DNS ERROR: ancount < 1 OR received number(%d) of bytes too low\n", r);
00499       return;
00500     }
00501 
00502     /* Find DNS key */
00503     test.id = hdr->id;
00504 
00505     key = pico_tree_findKey(&DNSTable,&test);
00506     if (!key) {
00507       dns_dbg("DNS WARNING: key with id %u not found\n", hdr->id);
00508       return;
00509     }
00510     key->retrans = 0;
00511 
00512     /* Check query suffix validity */
00513     q_qname = a_hdr + sizeof(struct dns_message_hdr);
00514     q_suf = pico_dns_client_seek(q_qname);
00515     query_suf = *(struct dns_query_suffix *) q_suf;
00516     if (short_be(query_suf.qtype) != key->qtype || short_be(query_suf.qclass) != key->qclass) {
00517       dns_dbg("DNS ERROR: received qtype (%u) or qclass (%u) incorrect\n", short_be(query_suf.qtype), short_be(query_suf.qclass));
00518       return;
00519     }
00520 
00521     /* Seek answer suffix */
00522     a_qname = q_suf + sizeof(struct dns_query_suffix);
00523     a_suf = a_qname;
00524     while(i++ < hdr->ancount) {
00525       uint16_t comp_h = short_from(a_suf);
00526       compression = short_be(comp_h);
00527       switch (compression >> 14)
00528       {
00529         case PICO_DNS_POINTER:
00530           while (compression >> 14 == PICO_DNS_POINTER) {
00531             dns_dbg("DNS: pointer\n");
00532             a_suf += sizeof(uint16_t);
00533             comp_h = short_from(a_suf);
00534             compression = short_be(comp_h);
00535           }
00536           break;
00537 
00538         case PICO_DNS_LABEL:
00539           dns_dbg("DNS: label\n");
00540           a_suf = pico_dns_client_seek(a_qname);
00541           break;
00542 
00543         default:
00544           dns_dbg("DNS ERROR: incorrect compression (%u) value\n", compression);
00545           return;
00546       }
00547 
00548       /* Check answer suffix validity */
00549       answer_suf = *(struct dns_answer_suffix *)a_suf;
00550       if (short_be(answer_suf.qtype) != key->qtype || short_be(answer_suf.qclass) != key->qclass) {
00551         dns_dbg("DNS WARNING: received qtype (%u) or qclass (%u) incorrect\n", short_be(answer_suf.qtype), short_be(answer_suf.qclass));
00552         a_suf = a_suf + sizeof(struct dns_answer_suffix) + short_be(answer_suf.rdlength);
00553         continue;
00554       }
00555 
00556       if (short_be(answer_suf.ttl) > PICO_DNS_MAX_TTL) {
00557         dns_dbg("DNS WARNING: received TTL (%u) > MAX (%u)\n", short_be(answer_suf.ttl), PICO_DNS_MAX_TTL);
00558         a_suf = a_suf + sizeof(struct dns_answer_suffix) + short_be(answer_suf.rdlength);
00559         continue;
00560       }
00561 
00562       valid_suffix = 1;
00563       break;
00564     }
00565 
00566     if (!valid_suffix) {
00567        dns_dbg("DNS ERROR: invalid dns answer suffix\n");
00568        return;
00569     }
00570 
00571     a_rdata = a_suf + sizeof(struct dns_answer_suffix);
00572     if (key->qtype == PICO_DNS_TYPE_A) {
00573       uint32_t ip_h = long_from(a_rdata);
00574       dns_dbg("DNS: length %u | ip %08X\n", short_be(answer_suf.rdlength), long_be(ip_h));
00575       answer = pico_zalloc(16);
00576       pico_ipv4_to_string(answer, ip_h);
00577       key->callback(answer, key->arg);
00578     } else if (key->qtype == PICO_DNS_TYPE_PTR) {
00579       pico_dns_client_reverse_label((char *) a_rdata);
00580       dns_dbg("DNS: length %u | name %s\n", short_be(answer_suf.rdlength), (char *)a_rdata + 1);
00581       answer = pico_zalloc(answer_suf.rdlength - 1);
00582       memcpy(answer, (char *)a_rdata + 1, short_be(answer_suf.rdlength) - 1);
00583       key->callback(answer, key->arg);
00584     } else {
00585       dns_dbg("DNS ERROR: incorrect qtype (%u)\n", key->qtype);
00586       return;
00587     }
00588   }
00589 
00590   if (ev == PICO_SOCK_EV_ERR) {
00591     dns_dbg("DNS: socket error received\n");
00592   }
00593 }
00594 
00595 int pico_dns_client_getaddr(const char *url, void (*callback)(char *, void *), void *arg)
00596 {
00597   char *q_hdr, *q_qname, *q_suf;
00598   struct dns_message_hdr *hdr;
00599   struct dns_query_suffix query_suf;
00600   struct pico_dns_key *key;
00601   uint16_t url_len = 0;
00602   uint16_t id = 0;
00603 
00604   if (!url || !callback) {
00605     dns_dbg("DNS ERROR: NULL parameters\n");
00606     pico_err = PICO_ERR_EINVAL;
00607     return -1;
00608   }
00609 
00610   url_len = pico_dns_client_strlen(url);
00611   /* 2 extra bytes for url_len to account for 2 extra label length octets */
00612   q_hdr = pico_zalloc(sizeof(struct dns_message_hdr) + (1 + url_len + 1) + sizeof(struct dns_query_suffix));
00613   if (!q_hdr) {
00614     pico_err = PICO_ERR_ENOMEM;
00615     return -1;
00616   }
00617   q_qname = q_hdr + sizeof(struct dns_message_hdr);
00618   q_suf = q_qname + (1 + url_len + 1);
00619 
00620   /* Construct query header */
00621   hdr = (struct dns_message_hdr *) q_hdr;
00622   do {
00623     id = (uint16_t) (pico_rand() & 0xFFFFU);
00624     dns_dbg("DNS: generated id %u\n", id);
00625   } while (pico_dns_client_idcheck(id));
00626   pico_dns_client_construct_hdr(hdr, id);
00627   /* Add and manipulate domain name */
00628   memcpy(q_qname + 1, url, url_len + 1);
00629   pico_dns_client_label(q_qname);
00630   /* Add type and class of query */
00631   query_suf.qtype = short_be(PICO_DNS_TYPE_A);
00632   query_suf.qclass = short_be(PICO_DNS_CLASS_IN);
00633   memcpy(q_suf, &query_suf, sizeof(struct dns_query_suffix));
00634   /* Create RB entry */
00635   key = pico_zalloc(sizeof(struct pico_dns_key));
00636   if (!key) {
00637     pico_free(q_hdr);
00638     pico_err = PICO_ERR_ENOMEM;
00639     return -1;
00640   }
00641   key->q_hdr = q_hdr;
00642   key->len = sizeof(struct dns_message_hdr) + (1 + url_len + 1) + sizeof(struct dns_query_suffix);
00643   key->id = id;
00644   key->qtype = PICO_DNS_TYPE_A;
00645   key->qclass = PICO_DNS_CLASS_IN;
00646   key->retrans = 1;
00647 
00648   key->q_ns = *((struct pico_dns_ns *)pico_tree_first(&NSTable));
00649   key->s = NULL;
00650   key->callback = callback;
00651   key->arg = arg;
00652   /* Send query */
00653   if (pico_dns_client_send(key) < 0) {
00654     pico_free(q_hdr);
00655     if (key->s)
00656       pico_socket_close(key->s);
00657     pico_free(key);
00658     pico_err = PICO_ERR_EAGAIN;
00659     return -1;
00660   }
00661   /* Insert RB entry */
00662 
00663   if(pico_tree_insert(&DNSTable,key)) {
00664     pico_free(q_hdr);
00665     pico_free(key);
00666     pico_err = PICO_ERR_EAGAIN;
00667     return -1; /* Element key already exists */
00668   }
00669 
00670   pico_timer_add(PICO_DNS_CLIENT_RETRANS, pico_dns_client_retransmission, key);
00671   return 0;
00672 }
00673 
00674 int pico_dns_client_getname(const char *ip, void (*callback)(char *, void *), void *arg)
00675 {
00676   char *q_hdr, *q_qname, *q_suf;
00677   struct dns_message_hdr *hdr;
00678   struct dns_query_suffix query_suf;
00679   struct pico_dns_key *key;
00680   uint16_t ip_len = 0;
00681   uint16_t arpa_len = 0;
00682   uint16_t id = 0;
00683 
00684   if (!ip || !callback) {
00685     dns_dbg("DNS ERROR: NULL parameters\n");
00686     pico_err = PICO_ERR_EINVAL;
00687     return -1;
00688   }
00689 
00690   ip_len = pico_dns_client_strlen(ip);
00691   arpa_len = pico_dns_client_strlen(".in-addr.arpa");
00692   /* 2 extra bytes for ip_len and arpa_len to account for 2 extra length octets */
00693   q_hdr = pico_zalloc(sizeof(struct dns_message_hdr) + (1 + ip_len + arpa_len + 1) + sizeof(struct dns_query_suffix));
00694   if (!q_hdr) {
00695     pico_err = PICO_ERR_ENOMEM;
00696     return -1;
00697   }
00698   q_qname = q_hdr + sizeof(struct dns_message_hdr);
00699   q_suf = q_qname + (1 + ip_len + arpa_len + 1);
00700 
00701   /* Construct query header */
00702   hdr = (struct dns_message_hdr *)q_hdr;
00703   do {
00704     id = (uint16_t) (pico_rand() & 0xFFFFU);
00705     dns_dbg("DNS: generated id %u\n", id);
00706   } while (pico_dns_client_idcheck(id));
00707   pico_dns_client_construct_hdr(hdr, id);
00708   /* Add and manipulate domain name */
00709   memcpy(q_qname + 1, ip, ip_len + 1);
00710   pico_dns_client_mirror(q_qname + 1);
00711   memcpy(q_qname + 1 + ip_len, ".in-addr.arpa", arpa_len);
00712   pico_dns_client_label(q_qname);
00713   /* Add type and class of query */
00714   query_suf.qtype = short_be(PICO_DNS_TYPE_PTR);
00715   query_suf.qclass = short_be(PICO_DNS_CLASS_IN);
00716   memcpy(q_suf, &query_suf, sizeof(struct dns_query_suffix));
00717   /* Create RB entry */
00718   key = pico_zalloc(sizeof(struct pico_dns_key));
00719   if (!key) {
00720     pico_free(q_hdr);
00721     pico_err = PICO_ERR_ENOMEM;
00722     return -1;
00723   }
00724   key->q_hdr = q_hdr;
00725   key->len = sizeof(struct dns_message_hdr) + (1 + ip_len + arpa_len + 1) + sizeof(struct dns_query_suffix);
00726   key->id = id;
00727   key->qtype = PICO_DNS_TYPE_PTR;
00728   key->qclass = PICO_DNS_CLASS_IN;
00729   key->retrans = 1;
00730   key->q_ns = *((struct pico_dns_ns *)pico_tree_first(&NSTable));
00731   key->s = NULL;
00732   key->callback = callback;
00733   key->arg = arg;
00734   /* Send query */
00735   if (pico_dns_client_send(key) < 0) {
00736     pico_free(q_hdr);
00737     if (key->s)
00738       pico_socket_close(key->s);
00739     pico_free(key);
00740     pico_err = PICO_ERR_EAGAIN;
00741     return -1;
00742   }
00743   /* Insert RB entry */
00744 
00745   if(pico_tree_insert(&DNSTable,key)) {
00746     pico_free(q_hdr);
00747     pico_free(key);
00748     pico_err = PICO_ERR_EAGAIN;
00749     return -1; /* Element key already exists */
00750   }
00751 
00752   pico_timer_add(PICO_DNS_CLIENT_RETRANS, pico_dns_client_retransmission, key);
00753   return 0;
00754 }
00755 
00756 #ifdef PICO_DNS_CLIENT_MAIN
00757 int main(int argc, char *argv[])
00758 {
00759   dns_dbg(">>>>> DNS GET ADDR\n");
00760   pico_dns_client_getaddr("www.google.be");
00761   dns_dbg(">>>>> DNS GET NAME\n");
00762   pico_dns_client_getname("173.194.67.94");
00763 
00764   return 0;
00765 }
00766 #endif /* PICO_DNS_CLIENT_MAIN */
00767 #endif /* PICO_SUPPORT_DNS_CLIENT */