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:
Fri May 24 15:25:25 2013 +0000
Revision:
3:b4047e8a0123
Updated from main repo + fixed Mutexes;

Who changed what in which revision?

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