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

Committer:
daniele
Date:
Sat Aug 03 13:16:14 2013 +0000
Revision:
2:540f6e142d59
Moved to single package

Who changed what in which revision?

UserRevisionLine numberNew contents of line
daniele 2:540f6e142d59 1 /*********************************************************************
daniele 2:540f6e142d59 2 PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved.
daniele 2:540f6e142d59 3 See LICENSE and COPYING for usage.
daniele 2:540f6e142d59 4
daniele 2:540f6e142d59 5 .
daniele 2:540f6e142d59 6
daniele 2:540f6e142d59 7 Authors: Kristof Roelants
daniele 2:540f6e142d59 8 *********************************************************************/
daniele 2:540f6e142d59 9 #include "pico_config.h"
daniele 2:540f6e142d59 10 #include "pico_stack.h"
daniele 2:540f6e142d59 11 #include "pico_addressing.h"
daniele 2:540f6e142d59 12 #include "pico_socket.h"
daniele 2:540f6e142d59 13 #include "pico_ipv4.h"
daniele 2:540f6e142d59 14 #include "pico_dns_client.h"
daniele 2:540f6e142d59 15 #include "pico_tree.h"
daniele 2:540f6e142d59 16
daniele 2:540f6e142d59 17 #ifdef PICO_SUPPORT_DNS_CLIENT
daniele 2:540f6e142d59 18
daniele 2:540f6e142d59 19 #define dns_dbg(...) do{}while(0)
daniele 2:540f6e142d59 20 //#define dns_dbg dbg
daniele 2:540f6e142d59 21
daniele 2:540f6e142d59 22 /* DNS response length */
daniele 2:540f6e142d59 23 #define PICO_DNS_MAX_RESPONSE_LEN 256
daniele 2:540f6e142d59 24
daniele 2:540f6e142d59 25 /* DNS client retransmission time (msec) + frequency */
daniele 2:540f6e142d59 26 #define PICO_DNS_CLIENT_RETRANS 4000
daniele 2:540f6e142d59 27 #define PICO_DNS_CLIENT_MAX_RETRANS 3
daniele 2:540f6e142d59 28
daniele 2:540f6e142d59 29 /* Default nameservers */
daniele 2:540f6e142d59 30 #define PICO_DNS_NS_GOOGLE "8.8.8.8"
daniele 2:540f6e142d59 31
daniele 2:540f6e142d59 32 /* Nameserver port */
daniele 2:540f6e142d59 33 #define PICO_DNS_NS_PORT 53
daniele 2:540f6e142d59 34
daniele 2:540f6e142d59 35 /* FLAG values */
daniele 2:540f6e142d59 36 #define PICO_DNS_QR_QUERY 0
daniele 2:540f6e142d59 37 #define PICO_DNS_QR_RESPONSE 1
daniele 2:540f6e142d59 38 #define PICO_DNS_OPCODE_QUERY 0
daniele 2:540f6e142d59 39 #define PICO_DNS_OPCODE_IQUERY 1
daniele 2:540f6e142d59 40 #define PICO_DNS_OPCODE_STATUS 2
daniele 2:540f6e142d59 41 #define PICO_DNS_AA_NO_AUTHORITY 0
daniele 2:540f6e142d59 42 #define PICO_DNS_AA_IS_AUTHORITY 1
daniele 2:540f6e142d59 43 #define PICO_DNS_TC_NO_TRUNCATION 0
daniele 2:540f6e142d59 44 #define PICO_DNS_TC_IS_TRUNCATED 1
daniele 2:540f6e142d59 45 #define PICO_DNS_RD_NO_DESIRE 0
daniele 2:540f6e142d59 46 #define PICO_DNS_RD_IS_DESIRED 1
daniele 2:540f6e142d59 47 #define PICO_DNS_RA_NO_SUPPORT 0
daniele 2:540f6e142d59 48 #define PICO_DNS_RA_IS_SUPPORTED 1
daniele 2:540f6e142d59 49 #define PICO_DNS_RCODE_NO_ERROR 0
daniele 2:540f6e142d59 50 #define PICO_DNS_RCODE_EFORMAT 1
daniele 2:540f6e142d59 51 #define PICO_DNS_RCODE_ESERVER 2
daniele 2:540f6e142d59 52 #define PICO_DNS_RCODE_ENAME 3
daniele 2:540f6e142d59 53 #define PICO_DNS_RCODE_ENOIMP 4
daniele 2:540f6e142d59 54 #define PICO_DNS_RCODE_EREFUSED 5
daniele 2:540f6e142d59 55
daniele 2:540f6e142d59 56 /* QTYPE values */
daniele 2:540f6e142d59 57 #define PICO_DNS_TYPE_A 1
daniele 2:540f6e142d59 58 #define PICO_DNS_TYPE_PTR 12
daniele 2:540f6e142d59 59
daniele 2:540f6e142d59 60 /* QCLASS values */
daniele 2:540f6e142d59 61 #define PICO_DNS_CLASS_IN 1
daniele 2:540f6e142d59 62
daniele 2:540f6e142d59 63 /* Compression values */
daniele 2:540f6e142d59 64 #define PICO_DNS_LABEL 0
daniele 2:540f6e142d59 65 #define PICO_DNS_POINTER 3
daniele 2:540f6e142d59 66
daniele 2:540f6e142d59 67 /* TTL values */
daniele 2:540f6e142d59 68 #define PICO_DNS_MAX_TTL 604800 /* one week */
daniele 2:540f6e142d59 69
daniele 2:540f6e142d59 70 /* Header flags */
daniele 2:540f6e142d59 71 #define FLAG_QR(hdr, x) ((hdr)->flags = ((hdr)->flags & ~(0x1 << 15)) | (x << 15))
daniele 2:540f6e142d59 72 #define FLAG_OPCODE(hdr, x) ((hdr)->flags = ((hdr)->flags & ~(0xF << 11)) | (x << 11))
daniele 2:540f6e142d59 73 #define FLAG_AA(hdr, x) ((hdr)->flags = ((hdr)->flags & ~(0x1 << 10)) | (x << 10))
daniele 2:540f6e142d59 74 #define FLAG_TC(hdr, x) ((hdr)->flags = ((hdr)->flags & ~(0x1 << 9)) | (x << 9))
daniele 2:540f6e142d59 75 #define FLAG_RD(hdr, x) ((hdr)->flags = ((hdr)->flags & ~(0x1 << 8)) | (x << 8))
daniele 2:540f6e142d59 76 #define FLAG_RA(hdr, x) ((hdr)->flags = ((hdr)->flags & ~(0x1 << 7)) | (x << 7))
daniele 2:540f6e142d59 77 #define FLAG_Z(hdr, x) ((hdr)->flags = ((hdr)->flags & ~(0x7 << 4)) | (x << 4))
daniele 2:540f6e142d59 78 #define FLAG_RCODE(hdr, x) ((hdr)->flags = ((hdr)->flags & ~(0xF)) | x)
daniele 2:540f6e142d59 79
daniele 2:540f6e142d59 80 #define GET_FLAG_QR(hdr) ((((hdr)->flags) & (1 << 15)) != 0)
daniele 2:540f6e142d59 81 #define GET_FLAG_OPCODE(hdr) ((((hdr)->flags) & (0xF << 11)) >> 11)
daniele 2:540f6e142d59 82 #define GET_FLAG_AA(hdr) ((((hdr)->flags) & (1 << 10)) != 0)
daniele 2:540f6e142d59 83 #define GET_FLAG_TC(hdr) ((((hdr)->flags) & (1 << 9)) != 0)
daniele 2:540f6e142d59 84 #define GET_FLAG_RD(hdr) ((((hdr)->flags) & (1 << 8)) != 0)
daniele 2:540f6e142d59 85 #define GET_FLAG_RA(hdr) ((((hdr)->flags) & (1 << 7)) != 0)
daniele 2:540f6e142d59 86 #define GET_FLAG_Z(hdr) ((((hdr)->flags) & (0x7 << 4)) >> 4)
daniele 2:540f6e142d59 87 #define GET_FLAG_RCODE(hdr) (((hdr)->flags) & (0x0F))
daniele 2:540f6e142d59 88
daniele 2:540f6e142d59 89 /* RFC 1025 section 4. MESSAGES */
daniele 2:540f6e142d59 90 struct __attribute__((packed)) dns_message_hdr
daniele 2:540f6e142d59 91 {
daniele 2:540f6e142d59 92 uint16_t id;
daniele 2:540f6e142d59 93 uint16_t flags;
daniele 2:540f6e142d59 94 uint16_t qdcount;
daniele 2:540f6e142d59 95 uint16_t ancount;
daniele 2:540f6e142d59 96 uint16_t nscount;
daniele 2:540f6e142d59 97 uint16_t arcount;
daniele 2:540f6e142d59 98 };
daniele 2:540f6e142d59 99
daniele 2:540f6e142d59 100 struct __attribute__((packed)) dns_query_suffix
daniele 2:540f6e142d59 101 {
daniele 2:540f6e142d59 102 /* NAME - domain name to which this resource record pertains */
daniele 2:540f6e142d59 103 uint16_t qtype;
daniele 2:540f6e142d59 104 uint16_t qclass;
daniele 2:540f6e142d59 105 };
daniele 2:540f6e142d59 106
daniele 2:540f6e142d59 107 struct __attribute__((packed)) dns_answer_suffix
daniele 2:540f6e142d59 108 {
daniele 2:540f6e142d59 109 /* NAME - domain name to which this resource record pertains */
daniele 2:540f6e142d59 110 uint16_t qtype;
daniele 2:540f6e142d59 111 uint16_t qclass;
daniele 2:540f6e142d59 112 uint32_t ttl;
daniele 2:540f6e142d59 113 uint16_t rdlength;
daniele 2:540f6e142d59 114 /* RDATA - variable length string of octets that describes the resource */
daniele 2:540f6e142d59 115 };
daniele 2:540f6e142d59 116
daniele 2:540f6e142d59 117 struct pico_dns_ns
daniele 2:540f6e142d59 118 {
daniele 2:540f6e142d59 119 struct pico_ip4 ns; /* Nameserver */
daniele 2:540f6e142d59 120 };
daniele 2:540f6e142d59 121
daniele 2:540f6e142d59 122 static int dns_ns_cmp(void *ka, void *kb)
daniele 2:540f6e142d59 123 {
daniele 2:540f6e142d59 124 struct pico_dns_ns *a = ka, *b = kb;
daniele 2:540f6e142d59 125 if (a->ns.addr < b->ns.addr)
daniele 2:540f6e142d59 126 return -1;
daniele 2:540f6e142d59 127 else if (a->ns.addr > b->ns.addr)
daniele 2:540f6e142d59 128 return 1;
daniele 2:540f6e142d59 129 else
daniele 2:540f6e142d59 130 return 0;
daniele 2:540f6e142d59 131 }
daniele 2:540f6e142d59 132
daniele 2:540f6e142d59 133 PICO_TREE_DECLARE(NSTable,dns_ns_cmp);
daniele 2:540f6e142d59 134
daniele 2:540f6e142d59 135 int pico_dns_client_nameserver(struct pico_ip4 *ns, uint8_t flag)
daniele 2:540f6e142d59 136 {
daniele 2:540f6e142d59 137 struct pico_dns_ns test, *key = NULL;
daniele 2:540f6e142d59 138
daniele 2:540f6e142d59 139 if (!ns) {
daniele 2:540f6e142d59 140 pico_err = PICO_ERR_EINVAL;
daniele 2:540f6e142d59 141 return -1;
daniele 2:540f6e142d59 142 }
daniele 2:540f6e142d59 143
daniele 2:540f6e142d59 144 switch (flag)
daniele 2:540f6e142d59 145 {
daniele 2:540f6e142d59 146 case PICO_DNS_NS_ADD:
daniele 2:540f6e142d59 147 key = pico_zalloc(sizeof(struct pico_dns_ns));
daniele 2:540f6e142d59 148 if (!key) {
daniele 2:540f6e142d59 149 pico_err = PICO_ERR_ENOMEM;
daniele 2:540f6e142d59 150 return -1;
daniele 2:540f6e142d59 151 }
daniele 2:540f6e142d59 152 key->ns = *ns;
daniele 2:540f6e142d59 153
daniele 2:540f6e142d59 154 if(pico_tree_insert(&NSTable,key)){
daniele 2:540f6e142d59 155 dns_dbg("DNS WARNING: nameserver %08X already added\n",ns->addr);
daniele 2:540f6e142d59 156 pico_err = PICO_ERR_EINVAL;
daniele 2:540f6e142d59 157 pico_free(key);
daniele 2:540f6e142d59 158 return -1; /* Element key already exists */
daniele 2:540f6e142d59 159 }
daniele 2:540f6e142d59 160 dns_dbg("DNS: nameserver %08X added\n", ns->addr);
daniele 2:540f6e142d59 161 /* If default NS found, remove it */
daniele 2:540f6e142d59 162 pico_string_to_ipv4(PICO_DNS_NS_GOOGLE, &test.ns.addr);
daniele 2:540f6e142d59 163 if (ns->addr != test.ns.addr) {
daniele 2:540f6e142d59 164
daniele 2:540f6e142d59 165 key = pico_tree_findKey(&NSTable,&test);
daniele 2:540f6e142d59 166 if (key) {
daniele 2:540f6e142d59 167 if(pico_tree_delete(&NSTable,key)) {
daniele 2:540f6e142d59 168 dns_dbg("DNS: default nameserver %08X removed\n", test.ns.addr);
daniele 2:540f6e142d59 169 pico_free(key);
daniele 2:540f6e142d59 170 } else {
daniele 2:540f6e142d59 171 pico_err = PICO_ERR_EAGAIN;
daniele 2:540f6e142d59 172 return -1;
daniele 2:540f6e142d59 173 }
daniele 2:540f6e142d59 174 }
daniele 2:540f6e142d59 175 }
daniele 2:540f6e142d59 176 break;
daniele 2:540f6e142d59 177
daniele 2:540f6e142d59 178 case PICO_DNS_NS_DEL:
daniele 2:540f6e142d59 179 test.ns = *ns;
daniele 2:540f6e142d59 180
daniele 2:540f6e142d59 181 key = pico_tree_findKey(&NSTable,&test);
daniele 2:540f6e142d59 182 if (!key) {
daniele 2:540f6e142d59 183 dns_dbg("DNS WARNING: nameserver %08X not found\n", ns->addr);
daniele 2:540f6e142d59 184 pico_err = PICO_ERR_EINVAL;
daniele 2:540f6e142d59 185 return -1;
daniele 2:540f6e142d59 186 }
daniele 2:540f6e142d59 187 /* RB_REMOVE returns pointer to removed element, NULL to indicate error */
daniele 2:540f6e142d59 188
daniele 2:540f6e142d59 189 if(pico_tree_delete(&NSTable,key)) {
daniele 2:540f6e142d59 190 dns_dbg("DNS: nameserver %08X removed\n",key->ns.addr);
daniele 2:540f6e142d59 191 pico_free(key);
daniele 2:540f6e142d59 192 } else {
daniele 2:540f6e142d59 193 pico_err = PICO_ERR_EAGAIN;
daniele 2:540f6e142d59 194 return -1;
daniele 2:540f6e142d59 195 }
daniele 2:540f6e142d59 196 /* If no NS left, add default NS */
daniele 2:540f6e142d59 197 if(pico_tree_first(&NSTable) == NULL){
daniele 2:540f6e142d59 198 dns_dbg("DNS: add default nameserver\n");
daniele 2:540f6e142d59 199 return pico_dns_client_init();
daniele 2:540f6e142d59 200 }
daniele 2:540f6e142d59 201 break;
daniele 2:540f6e142d59 202
daniele 2:540f6e142d59 203 default:
daniele 2:540f6e142d59 204 pico_err = PICO_ERR_EINVAL;
daniele 2:540f6e142d59 205 return -1;
daniele 2:540f6e142d59 206 }
daniele 2:540f6e142d59 207 return 0;
daniele 2:540f6e142d59 208 }
daniele 2:540f6e142d59 209
daniele 2:540f6e142d59 210 int pico_dns_client_init()
daniele 2:540f6e142d59 211 {
daniele 2:540f6e142d59 212 struct pico_ip4 default_ns;
daniele 2:540f6e142d59 213 if (pico_string_to_ipv4(PICO_DNS_NS_GOOGLE, &default_ns.addr) != 0) {
daniele 2:540f6e142d59 214 pico_err = PICO_ERR_EINVAL;
daniele 2:540f6e142d59 215 return -1;
daniele 2:540f6e142d59 216 }
daniele 2:540f6e142d59 217 return pico_dns_client_nameserver(&default_ns, PICO_DNS_NS_ADD);
daniele 2:540f6e142d59 218 }
daniele 2:540f6e142d59 219
daniele 2:540f6e142d59 220 struct pico_dns_key
daniele 2:540f6e142d59 221 {
daniele 2:540f6e142d59 222 char *q_hdr;
daniele 2:540f6e142d59 223 uint16_t len;
daniele 2:540f6e142d59 224 uint16_t id;
daniele 2:540f6e142d59 225 uint16_t qtype;
daniele 2:540f6e142d59 226 uint16_t qclass;
daniele 2:540f6e142d59 227 uint8_t retrans;
daniele 2:540f6e142d59 228 struct pico_dns_ns q_ns;
daniele 2:540f6e142d59 229 struct pico_socket *s;
daniele 2:540f6e142d59 230 void (*callback)(char *, void *);
daniele 2:540f6e142d59 231 void *arg;
daniele 2:540f6e142d59 232 };
daniele 2:540f6e142d59 233
daniele 2:540f6e142d59 234 static int dns_cmp(void *ka, void *kb)
daniele 2:540f6e142d59 235 {
daniele 2:540f6e142d59 236 struct pico_dns_key *a = ka,*b = kb;
daniele 2:540f6e142d59 237 if (a->id < b->id)
daniele 2:540f6e142d59 238 return -1;
daniele 2:540f6e142d59 239 else if (a->id > b->id)
daniele 2:540f6e142d59 240 return 1;
daniele 2:540f6e142d59 241 else
daniele 2:540f6e142d59 242 return 0;
daniele 2:540f6e142d59 243 }
daniele 2:540f6e142d59 244
daniele 2:540f6e142d59 245 PICO_TREE_DECLARE(DNSTable,dns_cmp);
daniele 2:540f6e142d59 246
daniele 2:540f6e142d59 247 static int pico_dns_client_strlen(const char *url)
daniele 2:540f6e142d59 248 {
daniele 2:540f6e142d59 249 uint16_t len = 0;
daniele 2:540f6e142d59 250 int p;
daniele 2:540f6e142d59 251
daniele 2:540f6e142d59 252 if (!url)
daniele 2:540f6e142d59 253 return -1;
daniele 2:540f6e142d59 254
daniele 2:540f6e142d59 255 while ((p = *url++) != 0) {
daniele 2:540f6e142d59 256 len++;
daniele 2:540f6e142d59 257 }
daniele 2:540f6e142d59 258 return len;
daniele 2:540f6e142d59 259 }
daniele 2:540f6e142d59 260
daniele 2:540f6e142d59 261 /* Replace '.' by the label length */
daniele 2:540f6e142d59 262 static int pico_dns_client_label(char *ptr)
daniele 2:540f6e142d59 263 {
daniele 2:540f6e142d59 264 char *l;
daniele 2:540f6e142d59 265 uint8_t lbl_len = 0;
daniele 2:540f6e142d59 266 int p;
daniele 2:540f6e142d59 267
daniele 2:540f6e142d59 268 if (!ptr)
daniele 2:540f6e142d59 269 return -1;
daniele 2:540f6e142d59 270
daniele 2:540f6e142d59 271 l = ptr++;
daniele 2:540f6e142d59 272 while ((p = *ptr++) != 0){
daniele 2:540f6e142d59 273 if (p == '.') {
daniele 2:540f6e142d59 274 *l = lbl_len;
daniele 2:540f6e142d59 275 l = ptr - 1;
daniele 2:540f6e142d59 276 lbl_len = 0;
daniele 2:540f6e142d59 277 } else {
daniele 2:540f6e142d59 278 lbl_len++;
daniele 2:540f6e142d59 279 }
daniele 2:540f6e142d59 280 }
daniele 2:540f6e142d59 281 *l = lbl_len;
daniele 2:540f6e142d59 282 return 0;
daniele 2:540f6e142d59 283 }
daniele 2:540f6e142d59 284
daniele 2:540f6e142d59 285 /* Replace the label length by '.' */
daniele 2:540f6e142d59 286 static int pico_dns_client_reverse_label(char *ptr)
daniele 2:540f6e142d59 287 {
daniele 2:540f6e142d59 288 char *l;
daniele 2:540f6e142d59 289 int p;
daniele 2:540f6e142d59 290
daniele 2:540f6e142d59 291 if(!ptr)
daniele 2:540f6e142d59 292 return -1;
daniele 2:540f6e142d59 293
daniele 2:540f6e142d59 294 l = ptr;
daniele 2:540f6e142d59 295 while ((p = *ptr++) != 0){
daniele 2:540f6e142d59 296 ptr += p;
daniele 2:540f6e142d59 297 *l = '.';
daniele 2:540f6e142d59 298 l = ptr;
daniele 2:540f6e142d59 299 }
daniele 2:540f6e142d59 300 return 0;
daniele 2:540f6e142d59 301 }
daniele 2:540f6e142d59 302
daniele 2:540f6e142d59 303 /* Seek the end of a string */
daniele 2:540f6e142d59 304 static char *pico_dns_client_seek(char *ptr)
daniele 2:540f6e142d59 305 {
daniele 2:540f6e142d59 306 int p;
daniele 2:540f6e142d59 307
daniele 2:540f6e142d59 308 if (!ptr)
daniele 2:540f6e142d59 309 return NULL;
daniele 2:540f6e142d59 310
daniele 2:540f6e142d59 311 while ((p = *ptr++) != 0);
daniele 2:540f6e142d59 312
daniele 2:540f6e142d59 313 return ptr++;
daniele 2:540f6e142d59 314 }
daniele 2:540f6e142d59 315
daniele 2:540f6e142d59 316 static inline void pico_dns_client_construct_hdr(struct dns_message_hdr *hdr, uint16_t id)
daniele 2:540f6e142d59 317 {
daniele 2:540f6e142d59 318 hdr->id = short_be(id);
daniele 2:540f6e142d59 319 FLAG_QR(hdr, PICO_DNS_QR_QUERY);
daniele 2:540f6e142d59 320 FLAG_OPCODE(hdr, PICO_DNS_OPCODE_QUERY);
daniele 2:540f6e142d59 321 FLAG_AA(hdr, PICO_DNS_AA_NO_AUTHORITY);
daniele 2:540f6e142d59 322 FLAG_TC(hdr, PICO_DNS_TC_NO_TRUNCATION);
daniele 2:540f6e142d59 323 FLAG_RD(hdr, PICO_DNS_RD_IS_DESIRED);
daniele 2:540f6e142d59 324 FLAG_RA(hdr, PICO_DNS_RA_NO_SUPPORT);
daniele 2:540f6e142d59 325 FLAG_Z(hdr, 0);
daniele 2:540f6e142d59 326 FLAG_RCODE(hdr, PICO_DNS_RCODE_NO_ERROR);
daniele 2:540f6e142d59 327 hdr->flags = short_be(hdr->flags);
daniele 2:540f6e142d59 328 hdr->qdcount = short_be(1);
daniele 2:540f6e142d59 329 hdr->ancount = short_be(0);
daniele 2:540f6e142d59 330 hdr->nscount = short_be(0);
daniele 2:540f6e142d59 331 hdr->arcount = short_be(0);
daniele 2:540f6e142d59 332 }
daniele 2:540f6e142d59 333
daniele 2:540f6e142d59 334 static inline void pico_dns_client_hdr_ntoh(struct dns_message_hdr *hdr)
daniele 2:540f6e142d59 335 {
daniele 2:540f6e142d59 336 hdr->id = short_be(hdr->id);
daniele 2:540f6e142d59 337 hdr->flags = short_be(hdr->flags);
daniele 2:540f6e142d59 338 hdr->qdcount = short_be(hdr->qdcount);
daniele 2:540f6e142d59 339 hdr->ancount = short_be(hdr->ancount);
daniele 2:540f6e142d59 340 hdr->nscount = short_be(hdr->nscount);
daniele 2:540f6e142d59 341 hdr->arcount = short_be(hdr->arcount);
daniele 2:540f6e142d59 342 }
daniele 2:540f6e142d59 343
daniele 2:540f6e142d59 344
daniele 2:540f6e142d59 345 static int pico_dns_client_mirror(char *ptr)
daniele 2:540f6e142d59 346 {
daniele 2:540f6e142d59 347 unsigned char buf[4] = {0};
daniele 2:540f6e142d59 348 char *m;
daniele 2:540f6e142d59 349 int cnt = 0;
daniele 2:540f6e142d59 350 int p, i;
daniele 2:540f6e142d59 351
daniele 2:540f6e142d59 352 if (!ptr)
daniele 2:540f6e142d59 353 return -1;
daniele 2:540f6e142d59 354
daniele 2:540f6e142d59 355 m = ptr;
daniele 2:540f6e142d59 356 while ((p = *ptr++) != 0)
daniele 2:540f6e142d59 357 {
daniele 2:540f6e142d59 358 if (pico_is_digit(p)) {
daniele 2:540f6e142d59 359 buf[cnt] = (10 * buf[cnt]) + (p - '0');
daniele 2:540f6e142d59 360 } else if (p == '.') {
daniele 2:540f6e142d59 361 cnt++;
daniele 2:540f6e142d59 362 } else {
daniele 2:540f6e142d59 363 return -1;
daniele 2:540f6e142d59 364 }
daniele 2:540f6e142d59 365 }
daniele 2:540f6e142d59 366
daniele 2:540f6e142d59 367 /* Handle short notation */
daniele 2:540f6e142d59 368 if(cnt == 1){
daniele 2:540f6e142d59 369 buf[3] = buf[1];
daniele 2:540f6e142d59 370 buf[1] = 0;
daniele 2:540f6e142d59 371 buf[2] = 0;
daniele 2:540f6e142d59 372 }else if (cnt == 2){
daniele 2:540f6e142d59 373 buf[3] = buf[2];
daniele 2:540f6e142d59 374 buf[2] = 0;
daniele 2:540f6e142d59 375 }else if(cnt != 3){
daniele 2:540f6e142d59 376 /* String could not be parsed, return error */
daniele 2:540f6e142d59 377 return -1;
daniele 2:540f6e142d59 378 }
daniele 2:540f6e142d59 379
daniele 2:540f6e142d59 380 ptr = m;
daniele 2:540f6e142d59 381 for(i = 3; i >= 0; i--)
daniele 2:540f6e142d59 382 {
daniele 2:540f6e142d59 383 if(buf[i] > 99){
daniele 2:540f6e142d59 384 *ptr++ = '0' + (buf[i] / 100);
daniele 2:540f6e142d59 385 *ptr++ = '0' + ((buf[i] % 100) / 10);
daniele 2:540f6e142d59 386 *ptr++ = '0' + ((buf[i] % 100) % 10);
daniele 2:540f6e142d59 387 }else if(buf[i] > 9){
daniele 2:540f6e142d59 388 *ptr++ = '0' + (buf[i] / 10);
daniele 2:540f6e142d59 389 *ptr++ = '0' + (buf[i] % 10);
daniele 2:540f6e142d59 390 }else{
daniele 2:540f6e142d59 391 *ptr++ = '0' + buf[i];
daniele 2:540f6e142d59 392 }
daniele 2:540f6e142d59 393 if(i > 0)
daniele 2:540f6e142d59 394 *ptr++ = '.';
daniele 2:540f6e142d59 395 }
daniele 2:540f6e142d59 396
daniele 2:540f6e142d59 397 return 0;
daniele 2:540f6e142d59 398 }
daniele 2:540f6e142d59 399
daniele 2:540f6e142d59 400 static struct pico_dns_key *pico_dns_client_idcheck(uint16_t id)
daniele 2:540f6e142d59 401 {
daniele 2:540f6e142d59 402 struct pico_dns_key test;
daniele 2:540f6e142d59 403
daniele 2:540f6e142d59 404 test.id = id;
daniele 2:540f6e142d59 405 return pico_tree_findKey(&DNSTable,&test);
daniele 2:540f6e142d59 406 }
daniele 2:540f6e142d59 407
daniele 2:540f6e142d59 408 static void pico_dns_client_callback(uint16_t ev, struct pico_socket *s);
daniele 2:540f6e142d59 409
daniele 2:540f6e142d59 410 static int pico_dns_client_send(struct pico_dns_key *key)
daniele 2:540f6e142d59 411 {
daniele 2:540f6e142d59 412 struct pico_socket *s;
daniele 2:540f6e142d59 413 int w = 0;
daniele 2:540f6e142d59 414
daniele 2:540f6e142d59 415 dns_dbg("DNS: sending query to %08X\n", key->q_ns.ns.addr);
daniele 2:540f6e142d59 416 s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &pico_dns_client_callback);
daniele 2:540f6e142d59 417 if (!s)
daniele 2:540f6e142d59 418 return -1;
daniele 2:540f6e142d59 419 key->s = s;
daniele 2:540f6e142d59 420 if (pico_socket_connect(s, &key->q_ns.ns, short_be(PICO_DNS_NS_PORT)) != 0)
daniele 2:540f6e142d59 421 return -1;
daniele 2:540f6e142d59 422 w = pico_socket_send(s, key->q_hdr, key->len);
daniele 2:540f6e142d59 423 if (w <= 0)
daniele 2:540f6e142d59 424 return -1;
daniele 2:540f6e142d59 425
daniele 2:540f6e142d59 426 return 0;
daniele 2:540f6e142d59 427 }
daniele 2:540f6e142d59 428
daniele 2:540f6e142d59 429 static void pico_dns_client_retransmission(unsigned long now, void *arg)
daniele 2:540f6e142d59 430 {
daniele 2:540f6e142d59 431 struct pico_dns_key *key = (struct pico_dns_key *)arg;
daniele 2:540f6e142d59 432 struct pico_dns_ns *q_ns = NULL;
daniele 2:540f6e142d59 433
daniele 2:540f6e142d59 434 if (!key->retrans) {
daniele 2:540f6e142d59 435 dns_dbg("DNS: no retransmission!\n");
daniele 2:540f6e142d59 436 pico_free(key->q_hdr);
daniele 2:540f6e142d59 437
daniele 2:540f6e142d59 438 if(pico_tree_delete(&DNSTable,key))
daniele 2:540f6e142d59 439 pico_free(key);
daniele 2:540f6e142d59 440 }
daniele 2:540f6e142d59 441 else if (key->retrans <= PICO_DNS_CLIENT_MAX_RETRANS) {
daniele 2:540f6e142d59 442 key->retrans++;
daniele 2:540f6e142d59 443 dns_dbg("DNS: retransmission! (%u attempts)\n", key->retrans);
daniele 2:540f6e142d59 444 // ugly hack
daniele 2:540f6e142d59 445 q_ns = pico_tree_next(pico_tree_findNode(&NSTable,&key->q_ns))->keyValue;
daniele 2:540f6e142d59 446 if (q_ns)
daniele 2:540f6e142d59 447 key->q_ns = *q_ns;
daniele 2:540f6e142d59 448 else
daniele 2:540f6e142d59 449 key->q_ns = *((struct pico_dns_ns *)pico_tree_first(&NSTable));
daniele 2:540f6e142d59 450 pico_dns_client_send(key);
daniele 2:540f6e142d59 451 pico_timer_add(PICO_DNS_CLIENT_RETRANS, pico_dns_client_retransmission, key);
daniele 2:540f6e142d59 452 } else {
daniele 2:540f6e142d59 453 dns_dbg("DNS ERROR: no reply from nameservers! (%u attempts)\n", key->retrans);
daniele 2:540f6e142d59 454 pico_socket_close(key->s);
daniele 2:540f6e142d59 455 pico_err = PICO_ERR_EIO;
daniele 2:540f6e142d59 456 key->callback(NULL, key->arg);
daniele 2:540f6e142d59 457 pico_free(key->q_hdr);
daniele 2:540f6e142d59 458 /* RB_REMOVE returns pointer to removed element, NULL to indicate error */
daniele 2:540f6e142d59 459
daniele 2:540f6e142d59 460 if(pico_tree_delete(&DNSTable,key))
daniele 2:540f6e142d59 461 pico_free(key);
daniele 2:540f6e142d59 462 }
daniele 2:540f6e142d59 463 }
daniele 2:540f6e142d59 464
daniele 2:540f6e142d59 465 static void pico_dns_client_callback(uint16_t ev, struct pico_socket *s)
daniele 2:540f6e142d59 466 {
daniele 2:540f6e142d59 467 char *q_qname, *q_suf, *a_hdr, *a_qname, *a_suf, *a_rdata;
daniele 2:540f6e142d59 468 struct dns_message_hdr *hdr;
daniele 2:540f6e142d59 469 struct dns_query_suffix query_suf;
daniele 2:540f6e142d59 470 struct dns_answer_suffix answer_suf;
daniele 2:540f6e142d59 471 struct pico_dns_key test, *key;
daniele 2:540f6e142d59 472 char *answer;
daniele 2:540f6e142d59 473 char dns_answer[PICO_DNS_MAX_RESPONSE_LEN] = {0};
daniele 2:540f6e142d59 474 uint8_t valid_suffix = 0;
daniele 2:540f6e142d59 475 uint16_t compression = 0;
daniele 2:540f6e142d59 476 int i = 0, r = 0;
daniele 2:540f6e142d59 477
daniele 2:540f6e142d59 478 if (ev & PICO_SOCK_EV_RD) {
daniele 2:540f6e142d59 479 r = pico_socket_read(s, dns_answer, PICO_DNS_MAX_RESPONSE_LEN);
daniele 2:540f6e142d59 480 pico_socket_close(s);
daniele 2:540f6e142d59 481 if (r == PICO_DNS_MAX_RESPONSE_LEN || r < (int)sizeof(struct dns_message_hdr)) {
daniele 2:540f6e142d59 482 dns_dbg("DNS ERROR: received incorrect number(%d) of bytes\n", r);
daniele 2:540f6e142d59 483 return;
daniele 2:540f6e142d59 484 }
daniele 2:540f6e142d59 485
daniele 2:540f6e142d59 486 /* Check header validity */
daniele 2:540f6e142d59 487 a_hdr = dns_answer;
daniele 2:540f6e142d59 488 hdr = (struct dns_message_hdr *) a_hdr;
daniele 2:540f6e142d59 489 pico_dns_client_hdr_ntoh(hdr);
daniele 2:540f6e142d59 490 if (GET_FLAG_QR(hdr) != PICO_DNS_QR_RESPONSE || GET_FLAG_OPCODE(hdr) != PICO_DNS_OPCODE_QUERY
daniele 2:540f6e142d59 491 || GET_FLAG_TC(hdr) == PICO_DNS_TC_IS_TRUNCATED || GET_FLAG_RCODE(hdr) != PICO_DNS_RCODE_NO_ERROR) {
daniele 2:540f6e142d59 492 dns_dbg("DNS ERROR: OPCODE %d | TC %d | RCODE %d\n", GET_FLAG_OPCODE(hdr), GET_FLAG_TC(hdr), GET_FLAG_RCODE(hdr));
daniele 2:540f6e142d59 493 return;
daniele 2:540f6e142d59 494 }
daniele 2:540f6e142d59 495
daniele 2:540f6e142d59 496 if (hdr->ancount < 1 || r < (int)(sizeof(struct dns_message_hdr) + hdr->qdcount * sizeof(struct dns_query_suffix)
daniele 2:540f6e142d59 497 + hdr->ancount * sizeof(struct dns_answer_suffix))) {
daniele 2:540f6e142d59 498 dns_dbg("DNS ERROR: ancount < 1 OR received number(%d) of bytes too low\n", r);
daniele 2:540f6e142d59 499 return;
daniele 2:540f6e142d59 500 }
daniele 2:540f6e142d59 501
daniele 2:540f6e142d59 502 /* Find DNS key */
daniele 2:540f6e142d59 503 test.id = hdr->id;
daniele 2:540f6e142d59 504
daniele 2:540f6e142d59 505 key = pico_tree_findKey(&DNSTable,&test);
daniele 2:540f6e142d59 506 if (!key) {
daniele 2:540f6e142d59 507 dns_dbg("DNS WARNING: key with id %u not found\n", hdr->id);
daniele 2:540f6e142d59 508 return;
daniele 2:540f6e142d59 509 }
daniele 2:540f6e142d59 510 key->retrans = 0;
daniele 2:540f6e142d59 511
daniele 2:540f6e142d59 512 /* Check query suffix validity */
daniele 2:540f6e142d59 513 q_qname = a_hdr + sizeof(struct dns_message_hdr);
daniele 2:540f6e142d59 514 q_suf = pico_dns_client_seek(q_qname);
daniele 2:540f6e142d59 515 query_suf = *(struct dns_query_suffix *) q_suf;
daniele 2:540f6e142d59 516 if (short_be(query_suf.qtype) != key->qtype || short_be(query_suf.qclass) != key->qclass) {
daniele 2:540f6e142d59 517 dns_dbg("DNS ERROR: received qtype (%u) or qclass (%u) incorrect\n", short_be(query_suf.qtype), short_be(query_suf.qclass));
daniele 2:540f6e142d59 518 return;
daniele 2:540f6e142d59 519 }
daniele 2:540f6e142d59 520
daniele 2:540f6e142d59 521 /* Seek answer suffix */
daniele 2:540f6e142d59 522 a_qname = q_suf + sizeof(struct dns_query_suffix);
daniele 2:540f6e142d59 523 a_suf = a_qname;
daniele 2:540f6e142d59 524 while(i++ < hdr->ancount) {
daniele 2:540f6e142d59 525 uint16_t comp_h = short_from(a_suf);
daniele 2:540f6e142d59 526 compression = short_be(comp_h);
daniele 2:540f6e142d59 527 switch (compression >> 14)
daniele 2:540f6e142d59 528 {
daniele 2:540f6e142d59 529 case PICO_DNS_POINTER:
daniele 2:540f6e142d59 530 while (compression >> 14 == PICO_DNS_POINTER) {
daniele 2:540f6e142d59 531 dns_dbg("DNS: pointer\n");
daniele 2:540f6e142d59 532 a_suf += sizeof(uint16_t);
daniele 2:540f6e142d59 533 comp_h = short_from(a_suf);
daniele 2:540f6e142d59 534 compression = short_be(comp_h);
daniele 2:540f6e142d59 535 }
daniele 2:540f6e142d59 536 break;
daniele 2:540f6e142d59 537
daniele 2:540f6e142d59 538 case PICO_DNS_LABEL:
daniele 2:540f6e142d59 539 dns_dbg("DNS: label\n");
daniele 2:540f6e142d59 540 a_suf = pico_dns_client_seek(a_qname);
daniele 2:540f6e142d59 541 break;
daniele 2:540f6e142d59 542
daniele 2:540f6e142d59 543 default:
daniele 2:540f6e142d59 544 dns_dbg("DNS ERROR: incorrect compression (%u) value\n", compression);
daniele 2:540f6e142d59 545 return;
daniele 2:540f6e142d59 546 }
daniele 2:540f6e142d59 547
daniele 2:540f6e142d59 548 /* Check answer suffix validity */
daniele 2:540f6e142d59 549 answer_suf = *(struct dns_answer_suffix *)a_suf;
daniele 2:540f6e142d59 550 if (short_be(answer_suf.qtype) != key->qtype || short_be(answer_suf.qclass) != key->qclass) {
daniele 2:540f6e142d59 551 dns_dbg("DNS WARNING: received qtype (%u) or qclass (%u) incorrect\n", short_be(answer_suf.qtype), short_be(answer_suf.qclass));
daniele 2:540f6e142d59 552 a_suf = a_suf + sizeof(struct dns_answer_suffix) + short_be(answer_suf.rdlength);
daniele 2:540f6e142d59 553 continue;
daniele 2:540f6e142d59 554 }
daniele 2:540f6e142d59 555
daniele 2:540f6e142d59 556 if (short_be(answer_suf.ttl) > PICO_DNS_MAX_TTL) {
daniele 2:540f6e142d59 557 dns_dbg("DNS WARNING: received TTL (%u) > MAX (%u)\n", short_be(answer_suf.ttl), PICO_DNS_MAX_TTL);
daniele 2:540f6e142d59 558 a_suf = a_suf + sizeof(struct dns_answer_suffix) + short_be(answer_suf.rdlength);
daniele 2:540f6e142d59 559 continue;
daniele 2:540f6e142d59 560 }
daniele 2:540f6e142d59 561
daniele 2:540f6e142d59 562 valid_suffix = 1;
daniele 2:540f6e142d59 563 break;
daniele 2:540f6e142d59 564 }
daniele 2:540f6e142d59 565
daniele 2:540f6e142d59 566 if (!valid_suffix) {
daniele 2:540f6e142d59 567 dns_dbg("DNS ERROR: invalid dns answer suffix\n");
daniele 2:540f6e142d59 568 return;
daniele 2:540f6e142d59 569 }
daniele 2:540f6e142d59 570
daniele 2:540f6e142d59 571 a_rdata = a_suf + sizeof(struct dns_answer_suffix);
daniele 2:540f6e142d59 572 if (key->qtype == PICO_DNS_TYPE_A) {
daniele 2:540f6e142d59 573 uint32_t ip_h = long_from(a_rdata);
daniele 2:540f6e142d59 574 dns_dbg("DNS: length %u | ip %08X\n", short_be(answer_suf.rdlength), long_be(ip_h));
daniele 2:540f6e142d59 575 answer = pico_zalloc(16);
daniele 2:540f6e142d59 576 pico_ipv4_to_string(answer, ip_h);
daniele 2:540f6e142d59 577 key->callback(answer, key->arg);
daniele 2:540f6e142d59 578 } else if (key->qtype == PICO_DNS_TYPE_PTR) {
daniele 2:540f6e142d59 579 pico_dns_client_reverse_label((char *) a_rdata);
daniele 2:540f6e142d59 580 dns_dbg("DNS: length %u | name %s\n", short_be(answer_suf.rdlength), (char *)a_rdata + 1);
daniele 2:540f6e142d59 581 answer = pico_zalloc(answer_suf.rdlength - 1);
daniele 2:540f6e142d59 582 memcpy(answer, (char *)a_rdata + 1, short_be(answer_suf.rdlength) - 1);
daniele 2:540f6e142d59 583 key->callback(answer, key->arg);
daniele 2:540f6e142d59 584 } else {
daniele 2:540f6e142d59 585 dns_dbg("DNS ERROR: incorrect qtype (%u)\n", key->qtype);
daniele 2:540f6e142d59 586 return;
daniele 2:540f6e142d59 587 }
daniele 2:540f6e142d59 588 }
daniele 2:540f6e142d59 589
daniele 2:540f6e142d59 590 if (ev == PICO_SOCK_EV_ERR) {
daniele 2:540f6e142d59 591 dns_dbg("DNS: socket error received\n");
daniele 2:540f6e142d59 592 }
daniele 2:540f6e142d59 593 }
daniele 2:540f6e142d59 594
daniele 2:540f6e142d59 595 int pico_dns_client_getaddr(const char *url, void (*callback)(char *, void *), void *arg)
daniele 2:540f6e142d59 596 {
daniele 2:540f6e142d59 597 char *q_hdr, *q_qname, *q_suf;
daniele 2:540f6e142d59 598 struct dns_message_hdr *hdr;
daniele 2:540f6e142d59 599 struct dns_query_suffix query_suf;
daniele 2:540f6e142d59 600 struct pico_dns_key *key;
daniele 2:540f6e142d59 601 uint16_t url_len = 0;
daniele 2:540f6e142d59 602 uint16_t id = 0;
daniele 2:540f6e142d59 603
daniele 2:540f6e142d59 604 if (!url || !callback) {
daniele 2:540f6e142d59 605 dns_dbg("DNS ERROR: NULL parameters\n");
daniele 2:540f6e142d59 606 pico_err = PICO_ERR_EINVAL;
daniele 2:540f6e142d59 607 return -1;
daniele 2:540f6e142d59 608 }
daniele 2:540f6e142d59 609
daniele 2:540f6e142d59 610 url_len = pico_dns_client_strlen(url);
daniele 2:540f6e142d59 611 /* 2 extra bytes for url_len to account for 2 extra label length octets */
daniele 2:540f6e142d59 612 q_hdr = pico_zalloc(sizeof(struct dns_message_hdr) + (1 + url_len + 1) + sizeof(struct dns_query_suffix));
daniele 2:540f6e142d59 613 if (!q_hdr) {
daniele 2:540f6e142d59 614 pico_err = PICO_ERR_ENOMEM;
daniele 2:540f6e142d59 615 return -1;
daniele 2:540f6e142d59 616 }
daniele 2:540f6e142d59 617 q_qname = q_hdr + sizeof(struct dns_message_hdr);
daniele 2:540f6e142d59 618 q_suf = q_qname + (1 + url_len + 1);
daniele 2:540f6e142d59 619
daniele 2:540f6e142d59 620 /* Construct query header */
daniele 2:540f6e142d59 621 hdr = (struct dns_message_hdr *) q_hdr;
daniele 2:540f6e142d59 622 do {
daniele 2:540f6e142d59 623 id = (uint16_t) (pico_rand() & 0xFFFFU);
daniele 2:540f6e142d59 624 dns_dbg("DNS: generated id %u\n", id);
daniele 2:540f6e142d59 625 } while (pico_dns_client_idcheck(id));
daniele 2:540f6e142d59 626 pico_dns_client_construct_hdr(hdr, id);
daniele 2:540f6e142d59 627 /* Add and manipulate domain name */
daniele 2:540f6e142d59 628 memcpy(q_qname + 1, url, url_len + 1);
daniele 2:540f6e142d59 629 pico_dns_client_label(q_qname);
daniele 2:540f6e142d59 630 /* Add type and class of query */
daniele 2:540f6e142d59 631 query_suf.qtype = short_be(PICO_DNS_TYPE_A);
daniele 2:540f6e142d59 632 query_suf.qclass = short_be(PICO_DNS_CLASS_IN);
daniele 2:540f6e142d59 633 memcpy(q_suf, &query_suf, sizeof(struct dns_query_suffix));
daniele 2:540f6e142d59 634 /* Create RB entry */
daniele 2:540f6e142d59 635 key = pico_zalloc(sizeof(struct pico_dns_key));
daniele 2:540f6e142d59 636 if (!key) {
daniele 2:540f6e142d59 637 pico_free(q_hdr);
daniele 2:540f6e142d59 638 pico_err = PICO_ERR_ENOMEM;
daniele 2:540f6e142d59 639 return -1;
daniele 2:540f6e142d59 640 }
daniele 2:540f6e142d59 641 key->q_hdr = q_hdr;
daniele 2:540f6e142d59 642 key->len = sizeof(struct dns_message_hdr) + (1 + url_len + 1) + sizeof(struct dns_query_suffix);
daniele 2:540f6e142d59 643 key->id = id;
daniele 2:540f6e142d59 644 key->qtype = PICO_DNS_TYPE_A;
daniele 2:540f6e142d59 645 key->qclass = PICO_DNS_CLASS_IN;
daniele 2:540f6e142d59 646 key->retrans = 1;
daniele 2:540f6e142d59 647
daniele 2:540f6e142d59 648 key->q_ns = *((struct pico_dns_ns *)pico_tree_first(&NSTable));
daniele 2:540f6e142d59 649 key->s = NULL;
daniele 2:540f6e142d59 650 key->callback = callback;
daniele 2:540f6e142d59 651 key->arg = arg;
daniele 2:540f6e142d59 652 /* Send query */
daniele 2:540f6e142d59 653 if (pico_dns_client_send(key) < 0) {
daniele 2:540f6e142d59 654 pico_free(q_hdr);
daniele 2:540f6e142d59 655 if (key->s)
daniele 2:540f6e142d59 656 pico_socket_close(key->s);
daniele 2:540f6e142d59 657 pico_free(key);
daniele 2:540f6e142d59 658 pico_err = PICO_ERR_EAGAIN;
daniele 2:540f6e142d59 659 return -1;
daniele 2:540f6e142d59 660 }
daniele 2:540f6e142d59 661 /* Insert RB entry */
daniele 2:540f6e142d59 662
daniele 2:540f6e142d59 663 if(pico_tree_insert(&DNSTable,key)) {
daniele 2:540f6e142d59 664 pico_free(q_hdr);
daniele 2:540f6e142d59 665 pico_free(key);
daniele 2:540f6e142d59 666 pico_err = PICO_ERR_EAGAIN;
daniele 2:540f6e142d59 667 return -1; /* Element key already exists */
daniele 2:540f6e142d59 668 }
daniele 2:540f6e142d59 669
daniele 2:540f6e142d59 670 pico_timer_add(PICO_DNS_CLIENT_RETRANS, pico_dns_client_retransmission, key);
daniele 2:540f6e142d59 671 return 0;
daniele 2:540f6e142d59 672 }
daniele 2:540f6e142d59 673
daniele 2:540f6e142d59 674 int pico_dns_client_getname(const char *ip, void (*callback)(char *, void *), void *arg)
daniele 2:540f6e142d59 675 {
daniele 2:540f6e142d59 676 char *q_hdr, *q_qname, *q_suf;
daniele 2:540f6e142d59 677 struct dns_message_hdr *hdr;
daniele 2:540f6e142d59 678 struct dns_query_suffix query_suf;
daniele 2:540f6e142d59 679 struct pico_dns_key *key;
daniele 2:540f6e142d59 680 uint16_t ip_len = 0;
daniele 2:540f6e142d59 681 uint16_t arpa_len = 0;
daniele 2:540f6e142d59 682 uint16_t id = 0;
daniele 2:540f6e142d59 683
daniele 2:540f6e142d59 684 if (!ip || !callback) {
daniele 2:540f6e142d59 685 dns_dbg("DNS ERROR: NULL parameters\n");
daniele 2:540f6e142d59 686 pico_err = PICO_ERR_EINVAL;
daniele 2:540f6e142d59 687 return -1;
daniele 2:540f6e142d59 688 }
daniele 2:540f6e142d59 689
daniele 2:540f6e142d59 690 ip_len = pico_dns_client_strlen(ip);
daniele 2:540f6e142d59 691 arpa_len = pico_dns_client_strlen(".in-addr.arpa");
daniele 2:540f6e142d59 692 /* 2 extra bytes for ip_len and arpa_len to account for 2 extra length octets */
daniele 2:540f6e142d59 693 q_hdr = pico_zalloc(sizeof(struct dns_message_hdr) + (1 + ip_len + arpa_len + 1) + sizeof(struct dns_query_suffix));
daniele 2:540f6e142d59 694 if (!q_hdr) {
daniele 2:540f6e142d59 695 pico_err = PICO_ERR_ENOMEM;
daniele 2:540f6e142d59 696 return -1;
daniele 2:540f6e142d59 697 }
daniele 2:540f6e142d59 698 q_qname = q_hdr + sizeof(struct dns_message_hdr);
daniele 2:540f6e142d59 699 q_suf = q_qname + (1 + ip_len + arpa_len + 1);
daniele 2:540f6e142d59 700
daniele 2:540f6e142d59 701 /* Construct query header */
daniele 2:540f6e142d59 702 hdr = (struct dns_message_hdr *)q_hdr;
daniele 2:540f6e142d59 703 do {
daniele 2:540f6e142d59 704 id = (uint16_t) (pico_rand() & 0xFFFFU);
daniele 2:540f6e142d59 705 dns_dbg("DNS: generated id %u\n", id);
daniele 2:540f6e142d59 706 } while (pico_dns_client_idcheck(id));
daniele 2:540f6e142d59 707 pico_dns_client_construct_hdr(hdr, id);
daniele 2:540f6e142d59 708 /* Add and manipulate domain name */
daniele 2:540f6e142d59 709 memcpy(q_qname + 1, ip, ip_len + 1);
daniele 2:540f6e142d59 710 pico_dns_client_mirror(q_qname + 1);
daniele 2:540f6e142d59 711 memcpy(q_qname + 1 + ip_len, ".in-addr.arpa", arpa_len);
daniele 2:540f6e142d59 712 pico_dns_client_label(q_qname);
daniele 2:540f6e142d59 713 /* Add type and class of query */
daniele 2:540f6e142d59 714 query_suf.qtype = short_be(PICO_DNS_TYPE_PTR);
daniele 2:540f6e142d59 715 query_suf.qclass = short_be(PICO_DNS_CLASS_IN);
daniele 2:540f6e142d59 716 memcpy(q_suf, &query_suf, sizeof(struct dns_query_suffix));
daniele 2:540f6e142d59 717 /* Create RB entry */
daniele 2:540f6e142d59 718 key = pico_zalloc(sizeof(struct pico_dns_key));
daniele 2:540f6e142d59 719 if (!key) {
daniele 2:540f6e142d59 720 pico_free(q_hdr);
daniele 2:540f6e142d59 721 pico_err = PICO_ERR_ENOMEM;
daniele 2:540f6e142d59 722 return -1;
daniele 2:540f6e142d59 723 }
daniele 2:540f6e142d59 724 key->q_hdr = q_hdr;
daniele 2:540f6e142d59 725 key->len = sizeof(struct dns_message_hdr) + (1 + ip_len + arpa_len + 1) + sizeof(struct dns_query_suffix);
daniele 2:540f6e142d59 726 key->id = id;
daniele 2:540f6e142d59 727 key->qtype = PICO_DNS_TYPE_PTR;
daniele 2:540f6e142d59 728 key->qclass = PICO_DNS_CLASS_IN;
daniele 2:540f6e142d59 729 key->retrans = 1;
daniele 2:540f6e142d59 730 key->q_ns = *((struct pico_dns_ns *)pico_tree_first(&NSTable));
daniele 2:540f6e142d59 731 key->s = NULL;
daniele 2:540f6e142d59 732 key->callback = callback;
daniele 2:540f6e142d59 733 key->arg = arg;
daniele 2:540f6e142d59 734 /* Send query */
daniele 2:540f6e142d59 735 if (pico_dns_client_send(key) < 0) {
daniele 2:540f6e142d59 736 pico_free(q_hdr);
daniele 2:540f6e142d59 737 if (key->s)
daniele 2:540f6e142d59 738 pico_socket_close(key->s);
daniele 2:540f6e142d59 739 pico_free(key);
daniele 2:540f6e142d59 740 pico_err = PICO_ERR_EAGAIN;
daniele 2:540f6e142d59 741 return -1;
daniele 2:540f6e142d59 742 }
daniele 2:540f6e142d59 743 /* Insert RB entry */
daniele 2:540f6e142d59 744
daniele 2:540f6e142d59 745 if(pico_tree_insert(&DNSTable,key)) {
daniele 2:540f6e142d59 746 pico_free(q_hdr);
daniele 2:540f6e142d59 747 pico_free(key);
daniele 2:540f6e142d59 748 pico_err = PICO_ERR_EAGAIN;
daniele 2:540f6e142d59 749 return -1; /* Element key already exists */
daniele 2:540f6e142d59 750 }
daniele 2:540f6e142d59 751
daniele 2:540f6e142d59 752 pico_timer_add(PICO_DNS_CLIENT_RETRANS, pico_dns_client_retransmission, key);
daniele 2:540f6e142d59 753 return 0;
daniele 2:540f6e142d59 754 }
daniele 2:540f6e142d59 755
daniele 2:540f6e142d59 756 #ifdef PICO_DNS_CLIENT_MAIN
daniele 2:540f6e142d59 757 int main(int argc, char *argv[])
daniele 2:540f6e142d59 758 {
daniele 2:540f6e142d59 759 dns_dbg(">>>>> DNS GET ADDR\n");
daniele 2:540f6e142d59 760 pico_dns_client_getaddr("www.google.be");
daniele 2:540f6e142d59 761 dns_dbg(">>>>> DNS GET NAME\n");
daniele 2:540f6e142d59 762 pico_dns_client_getname("173.194.67.94");
daniele 2:540f6e142d59 763
daniele 2:540f6e142d59 764 return 0;
daniele 2:540f6e142d59 765 }
daniele 2:540f6e142d59 766 #endif /* PICO_DNS_CLIENT_MAIN */
daniele 2:540f6e142d59 767 #endif /* PICO_SUPPORT_DNS_CLIENT */