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:
tass
Date:
Thu Sep 19 12:38:53 2013 +0000
Revision:
63:97f481e33cb2
Parent:
51:ab4529a384a6
Child:
66:71a2ef45a035
Update from the master branch

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