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

PicoTCP. Copyright (c) 2013 TASS Belgium NV.

Released under the GNU General Public License, version 2.

Different licensing models may exist, at the sole discretion of the Copyright holders.

Official homepage: http://www.picotcp.com

Bug tracker: https://github.com/tass-belgium/picotcp/issues

Development steps:

  • initial integration with mbed RTOS
  • generic mbed Ethernet driver
  • high performance NXP LPC1768 specific Ethernet driver
  • Multi-threading support for mbed RTOS
  • Berkeley sockets and integration with the New Socket API
  • Fork of the apps running on top of the New Socket API
  • Scheduling optimizations
  • Debugging/benchmarking/testing

Demo application (measuring TCP sender performance):

Import programlpc1768-picotcp-demo

A PicoTCP demo app testing the ethernet throughput on the lpc1768 mbed board.

Committer:
daniele
Date:
Thu Jun 06 00:38:54 2013 +0000
Revision:
10:dd7111d4279f
Child:
51:ab4529a384a6
Update from masterbranch;

Who changed what in which revision?

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