blob: f739f6253660422d98e5860021bed86938c49f0d [file] [log] [blame]
adamdunkels1e45c6d2003-09-02 21:47:27 +00001/**
adamdunkels0170b082003-10-01 11:25:37 +00002 * \addtogroup uip
3 * @{
4 */
5
6/**
7 * \defgroup uipdns uIP hostname resolver functions
8 * @{
9 *
10 * The uIP DNS resolver functions are used to lookup a hostname and
11 * map it to a numerical IP address. It maintains a list of resolved
12 * hostnames that can be queried with the resolv_lookup()
13 * function. New hostnames can be resolved using the resolv_query()
14 * function.
adamdunkels1e45c6d2003-09-02 21:47:27 +000015 *
16 * The signal resolv_signal_found is emitted when a hostname has been
17 * resolved. The signal is emitted to all processes listening for the
18 * signal, and it is up to the receiving process to determine if the
19 * correct hostname has been found by calling the resolv_lookup()
20 * function with the hostname.
21 */
22
adamdunkels0170b082003-10-01 11:25:37 +000023/**
24 * \file
25 * DNS host name to IP address resolver.
26 * \author Adam Dunkels <adam@dunkels.com>
27 *
28 * This file implements a DNS host name to IP address resolver.
29 */
30
adamdunkelsca9ddcb2003-03-19 14:13:31 +000031/*
adamdunkels1e45c6d2003-09-02 21:47:27 +000032 * Copyright (c) 2002-2003, Adam Dunkels.
adamdunkelsca9ddcb2003-03-19 14:13:31 +000033 * All rights reserved.
34 *
35 * Redistribution and use in source and binary forms, with or without
36 * modification, are permitted provided that the following conditions
37 * are met:
38 * 1. Redistributions of source code must retain the above copyright
39 * notice, this list of conditions and the following disclaimer.
40 * 2. Redistributions in binary form must reproduce the above copyright
41 * notice, this list of conditions and the following disclaimer in the
42 * documentation and/or other materials provided with the distribution.
adamdunkels1e45c6d2003-09-02 21:47:27 +000043 * 3. The name of the author may not be used to endorse or promote
adamdunkelsca9ddcb2003-03-19 14:13:31 +000044 * products derived from this software without specific prior
45 * written permission.
46 *
47 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
48 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
49 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
51 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
52 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
53 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
54 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
55 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
56 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
57 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
58 *
59 * This file is part of the uIP TCP/IP stack.
60 *
adamdunkels0170b082003-10-01 11:25:37 +000061 * $Id: resolv.c,v 1.9 2003/10/01 11:25:37 adamdunkels Exp $
adamdunkelsca9ddcb2003-03-19 14:13:31 +000062 *
63 */
64
65#include "resolv.h"
66#include "dispatcher.h"
adamdunkelsbb2e93c2003-09-04 19:38:46 +000067#include "uip-signal.h"
adamdunkelsca9ddcb2003-03-19 14:13:31 +000068
69#ifndef NULL
70#define NULL (void *)0
71#endif /* NULL */
72
adamdunkels1e45c6d2003-09-02 21:47:27 +000073/** \internal The maximum number of retries when asking for a name. */
adamdunkelsca9ddcb2003-03-19 14:13:31 +000074#define MAX_RETRIES 8
75
adamdunkels1e45c6d2003-09-02 21:47:27 +000076/** \internal The DNS message header. */
adamdunkelsca9ddcb2003-03-19 14:13:31 +000077struct dns_hdr {
78 u16_t id;
79 u8_t flags1, flags2;
80#define DNS_FLAG1_RESPONSE 0x80
81#define DNS_FLAG1_OPCODE_STATUS 0x10
82#define DNS_FLAG1_OPCODE_INVERSE 0x08
83#define DNS_FLAG1_OPCODE_STANDARD 0x00
84#define DNS_FLAG1_AUTHORATIVE 0x04
85#define DNS_FLAG1_TRUNC 0x02
86#define DNS_FLAG1_RD 0x01
87#define DNS_FLAG2_RA 0x80
88#define DNS_FLAG2_ERR_MASK 0x0f
89#define DNS_FLAG2_ERR_NONE 0x00
90#define DNS_FLAG2_ERR_NAME 0x03
91 u16_t numquestions;
92 u16_t numanswers;
93 u16_t numauthrr;
94 u16_t numextrarr;
95};
96
adamdunkels1e45c6d2003-09-02 21:47:27 +000097/** \internal The DNS answer message structure. */
adamdunkelsca9ddcb2003-03-19 14:13:31 +000098struct dns_answer {
99 /* DNS answer record starts with either a domain name or a pointer
100 to a name already present somewhere in the packet. */
101 u16_t type;
102 u16_t class;
103 u16_t ttl[2];
104 u16_t len;
105 u16_t ipaddr[2];
106};
107
adamdunkels1e45c6d2003-09-02 21:47:27 +0000108struct namemap {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000109#define STATE_UNUSED 0
110#define STATE_NEW 1
111#define STATE_ASKING 2
112#define STATE_DONE 3
113#define STATE_ERROR 4
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000114 u8_t state;
115 u8_t tmr;
116 u8_t retries;
117 u8_t seqno;
118 u8_t err;
adamdunkels1d31c322003-08-24 22:40:32 +0000119 char name[32];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000120 u16_t ipaddr[2];
121};
122
adamdunkelsbb2e93c2003-09-04 19:38:46 +0000123#ifndef UIP_CONF_RESOLV_ENTRIES
adamdunkels99dcf452003-08-15 18:50:36 +0000124#define RESOLV_ENTRIES 4
adamdunkelsbb2e93c2003-09-04 19:38:46 +0000125#else /* UIP_CONF_RESOLV_ENTRIES */
126#define RESOLV_ENTRIES UIP_CONF_RESOLV_ENTRIES
127#endif /* UIP_CONF_RESOLV_ENTRIES */
128
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000129
130static struct namemap names[RESOLV_ENTRIES];
131
132static u8_t seqno;
133
134static struct uip_udp_conn *resolv_conn = NULL;
135
adamdunkels0170b082003-10-01 11:25:37 +0000136ek_signal_t resolv_signal_found;
137
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000138
139/*-----------------------------------------------------------------------------------*/
adamdunkels1e45c6d2003-09-02 21:47:27 +0000140/** \internal
141 * Walk through a compact encoded DNS name and return the end of it.
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000142 *
adamdunkels1e45c6d2003-09-02 21:47:27 +0000143 * \return The end of the name.
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000144 */
adamdunkels1e45c6d2003-09-02 21:47:27 +0000145/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000146static unsigned char *
147parse_name(unsigned char *query)
148{
149 unsigned char n;
150
151 do {
152 n = *query++;
153
154 while(n > 0) {
155 /* printf("%c", *query);*/
156 ++query;
157 --n;
158 };
159 /* printf(".");*/
160 } while(*query != 0);
161 /* printf("\n");*/
162 return query + 1;
163}
164/*-----------------------------------------------------------------------------------*/
adamdunkels1e45c6d2003-09-02 21:47:27 +0000165/** \internal
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000166 * Runs through the list of names to see if there are any that have
adamdunkels1e45c6d2003-09-02 21:47:27 +0000167 * not yet been queried and, if so, sends out a query.
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000168 */
adamdunkels1e45c6d2003-09-02 21:47:27 +0000169/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000170static void
171check_entries(void)
172{
adamdunkels23664022003-08-05 13:51:50 +0000173 register struct dns_hdr *hdr;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000174 char *query, *nptr, *nameptr;
adamdunkels99dcf452003-08-15 18:50:36 +0000175 static u8_t i;
176 static u8_t n;
adamdunkels23664022003-08-05 13:51:50 +0000177 register struct namemap *namemapptr;
178
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000179 for(i = 0; i < RESOLV_ENTRIES; ++i) {
adamdunkels23664022003-08-05 13:51:50 +0000180 namemapptr = &names[i];
181 if(namemapptr->state == STATE_NEW ||
182 namemapptr->state == STATE_ASKING) {
183 if(namemapptr->state == STATE_ASKING) {
184 if(--namemapptr->tmr == 0) {
185 if(++namemapptr->retries == MAX_RETRIES) {
186 namemapptr->state = STATE_ERROR;
187 resolv_found(namemapptr->name, NULL);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000188 continue;
189 }
adamdunkels23664022003-08-05 13:51:50 +0000190 namemapptr->tmr = namemapptr->retries;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000191 } else {
adamdunkels23664022003-08-05 13:51:50 +0000192 /* printf("Timer %d\n", namemapptr->tmr);*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000193 /* Its timer has not run out, so we move on to next
194 entry. */
195 continue;
196 }
197 } else {
adamdunkels23664022003-08-05 13:51:50 +0000198 namemapptr->state = STATE_ASKING;
199 namemapptr->tmr = 1;
200 namemapptr->retries = 0;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000201 }
202 hdr = (struct dns_hdr *)uip_appdata;
adamdunkels99dcf452003-08-15 18:50:36 +0000203 memset(hdr, 0, sizeof(struct dns_hdr));
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000204 hdr->id = htons(i);
205 hdr->flags1 = DNS_FLAG1_RD;
adamdunkels47ec7fa2003-03-28 12:11:17 +0000206 hdr->numquestions = HTONS(1);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000207 query = (char *)uip_appdata + 12;
adamdunkels23664022003-08-05 13:51:50 +0000208 nameptr = namemapptr->name;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000209 --nameptr;
210 /* Convert hostname into suitable query format. */
211 do {
212 ++nameptr;
213 nptr = query;
214 ++query;
215 for(n = 0; *nameptr != '.' && *nameptr != 0; ++nameptr) {
216 *query = *nameptr;
217 ++query;
218 ++n;
219 }
220 *nptr = n;
221 } while(*nameptr != 0);
adamdunkels23664022003-08-05 13:51:50 +0000222 {
223 static unsigned char endquery[] =
224 {0,0,1,0,1};
225 memcpy(query, endquery, 5);
226 }
adamdunkels23664022003-08-05 13:51:50 +0000227 uip_udp_send((unsigned char)(query + 5 - (char *)uip_appdata));
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000228 break;
229 }
230 }
231}
232/*-----------------------------------------------------------------------------------*/
adamdunkels1e45c6d2003-09-02 21:47:27 +0000233/** \internal
234 * Called when new UDP data arrives.
235 */
236/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000237static void
238newdata(void)
239{
240 char *nameptr;
241 struct dns_answer *ans;
242 struct dns_hdr *hdr;
adamdunkels99dcf452003-08-15 18:50:36 +0000243 static u8_t nquestions, nanswers;
244 static u8_t i;
adamdunkels23664022003-08-05 13:51:50 +0000245 register struct namemap *namemapptr;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000246
247 hdr = (struct dns_hdr *)uip_appdata;
248 /* printf("ID %d\n", htons(hdr->id));
249 printf("Query %d\n", hdr->flags1 & DNS_FLAG1_RESPONSE);
250 printf("Error %d\n", hdr->flags2 & DNS_FLAG2_ERR_MASK);
251 printf("Num questions %d, answers %d, authrr %d, extrarr %d\n",
252 htons(hdr->numquestions),
253 htons(hdr->numanswers),
254 htons(hdr->numauthrr),
255 htons(hdr->numextrarr));
256 */
257
258 /* The ID in the DNS header should be our entry into the name
259 table. */
adamdunkels23664022003-08-05 13:51:50 +0000260 i = htons(hdr->id);
261 namemapptr = &names[i];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000262 if(i < RESOLV_ENTRIES &&
adamdunkels23664022003-08-05 13:51:50 +0000263 namemapptr->state == STATE_ASKING) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000264
265 /* This entry is now finished. */
adamdunkels23664022003-08-05 13:51:50 +0000266 namemapptr->state = STATE_DONE;
267 namemapptr->err = hdr->flags2 & DNS_FLAG2_ERR_MASK;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000268
269 /* Check for error. If so, call callback to inform. */
adamdunkels23664022003-08-05 13:51:50 +0000270 if(namemapptr->err != 0) {
271 namemapptr->state = STATE_ERROR;
272 resolv_found(namemapptr->name, NULL);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000273 return;
274 }
275
276 /* We only care about the question(s) and the answers. The authrr
277 and the extrarr are simply discarded. */
278 nquestions = htons(hdr->numquestions);
279 nanswers = htons(hdr->numanswers);
280
281 /* Skip the name in the question. XXX: This should really be
282 checked agains the name in the question, to be sure that they
283 match. */
284 nameptr = parse_name((char *)uip_appdata + 12) + 4;
285
286 while(nanswers > 0) {
287 /* The first byte in the answer resource record determines if it
288 is a compressed record or a normal one. */
289 if(*nameptr & 0xc0) {
290 /* Compressed name. */
291 nameptr +=2;
292 /* printf("Compressed anwser\n");*/
293 } else {
294 /* Not compressed name. */
295 nameptr = parse_name((char *)nameptr);
296 }
297
298 ans = (struct dns_answer *)nameptr;
299 /* printf("Answer: type %x, class %x, ttl %x, length %x\n",
adamdunkels99dcf452003-08-15 18:50:36 +0000300 htons(ans->type), htons(ans->class), (htons(ans->ttl[0])
301 << 16) | htons(ans->ttl[1]), htons(ans->len));*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000302
303 /* Check for IP address type and Internet class. Others are
304 discarded. */
adamdunkels47ec7fa2003-03-28 12:11:17 +0000305 if(ans->type == HTONS(1) &&
306 ans->class == HTONS(1) &&
307 ans->len == HTONS(4)) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000308 /* printf("IP address %d.%d.%d.%d\n",
309 htons(ans->ipaddr[0]) >> 8,
310 htons(ans->ipaddr[0]) & 0xff,
311 htons(ans->ipaddr[1]) >> 8,
312 htons(ans->ipaddr[1]) & 0xff);*/
313 /* XXX: we should really check that this IP address is the one
314 we want. */
adamdunkels23664022003-08-05 13:51:50 +0000315 namemapptr->ipaddr[0] = ans->ipaddr[0];
316 namemapptr->ipaddr[1] = ans->ipaddr[1];
adamdunkels99dcf452003-08-15 18:50:36 +0000317
adamdunkels23664022003-08-05 13:51:50 +0000318 resolv_found(namemapptr->name, namemapptr->ipaddr);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000319 return;
320 } else {
321 nameptr = nameptr + 10 + htons(ans->len);
322 }
323 --nanswers;
324 }
325 }
326
327}
328/*-----------------------------------------------------------------------------------*/
adamdunkels1e45c6d2003-09-02 21:47:27 +0000329/** \internal
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000330 * The main UDP function.
331 */
adamdunkels1e45c6d2003-09-02 21:47:27 +0000332/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000333void
334udp_appcall(void)
335{
adamdunkels47ec7fa2003-03-28 12:11:17 +0000336 if(uip_udp_conn->rport == HTONS(53)) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000337 if(uip_poll()) {
338 check_entries();
339 }
340 if(uip_newdata()) {
341 newdata();
342 }
343 }
344}
345/*-----------------------------------------------------------------------------------*/
adamdunkels1e45c6d2003-09-02 21:47:27 +0000346/**
347 * Queues a name so that a question for the name will be sent out.
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000348 *
adamdunkels1e45c6d2003-09-02 21:47:27 +0000349 * \param name The hostname that is to be queried.
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000350 */
adamdunkels1e45c6d2003-09-02 21:47:27 +0000351/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000352void
353resolv_query(char *name)
354{
adamdunkels99dcf452003-08-15 18:50:36 +0000355 static u8_t i;
356 static u8_t lseq, lseqi;
adamdunkels23664022003-08-05 13:51:50 +0000357 register struct namemap *nameptr;
358
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000359 lseq = lseqi = 0;
360
361 for(i = 0; i < RESOLV_ENTRIES; ++i) {
adamdunkels23664022003-08-05 13:51:50 +0000362 nameptr = &names[i];
363 if(nameptr->state == STATE_UNUSED) {
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000364 break;
365 }
adamdunkels23664022003-08-05 13:51:50 +0000366 if(seqno - nameptr->seqno > lseq) {
367 lseq = seqno - nameptr->seqno;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000368 lseqi = i;
369 }
370 }
371
372 if(i == RESOLV_ENTRIES) {
373 i = lseqi;
adamdunkels23664022003-08-05 13:51:50 +0000374 nameptr = &names[i];
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000375 }
376
377 /* printf("Using entry %d\n", i);*/
378
adamdunkels23664022003-08-05 13:51:50 +0000379 strcpy(nameptr->name, name);
380 nameptr->state = STATE_NEW;
381 nameptr->seqno = seqno;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000382 ++seqno;
383
adamdunkels1e45c6d2003-09-02 21:47:27 +0000384 if(resolv_conn != NULL) {
adamdunkelsbb2e93c2003-09-04 19:38:46 +0000385 dispatcher_emit(uip_signal_poll_udp, resolv_conn, DISPATCHER_BROADCAST);
adamdunkels1e45c6d2003-09-02 21:47:27 +0000386 }
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000387}
388/*-----------------------------------------------------------------------------------*/
adamdunkels1e45c6d2003-09-02 21:47:27 +0000389/**
390 * Look up a hostname in the array of known hostnames.
391 *
392 * \note This function only looks in the internal array of known
393 * hostnames, it does not send out a query for the hostname if none
394 * was found. The function resolv_query() can be used to send a query
395 * for a hostname.
396 *
397 * \return A pointer to a 4-byte representation of the hostname's IP
398 * address, or NULL if the hostname was not found in the array of
399 * hostnames.
400 */
401/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000402u16_t *
403resolv_lookup(char *name)
404{
adamdunkels99dcf452003-08-15 18:50:36 +0000405 static u8_t i;
adamdunkels23664022003-08-05 13:51:50 +0000406 struct namemap *nameptr;
407
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000408 /* Walk through the list to see if the name is in there. If it is
409 not, we return NULL. */
410 for(i = 0; i < RESOLV_ENTRIES; ++i) {
adamdunkels23664022003-08-05 13:51:50 +0000411 nameptr = &names[i];
412 if(nameptr->state == STATE_DONE &&
adamdunkels99dcf452003-08-15 18:50:36 +0000413 strcmp(name, nameptr->name) == 0) {
adamdunkels23664022003-08-05 13:51:50 +0000414 return nameptr->ipaddr;
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000415 }
416 }
417 return NULL;
418}
419/*-----------------------------------------------------------------------------------*/
adamdunkels1e45c6d2003-09-02 21:47:27 +0000420/**
421 * Obtain the currently configured DNS server.
422 *
423 * \return A pointer to a 4-byte representation of the IP address of
424 * the currently configured DNS server or NULL if no DNS server has
425 * been configured.
426 */
427/*-----------------------------------------------------------------------------------*/
adamdunkels66c6af62003-04-16 18:28:16 +0000428u16_t *
429resolv_getserver(void)
430{
431 if(resolv_conn == NULL) {
432 return NULL;
433 }
434 return resolv_conn->ripaddr;
435}
436/*-----------------------------------------------------------------------------------*/
adamdunkels1e45c6d2003-09-02 21:47:27 +0000437/**
438 * Configure a DNS server.
439 *
440 * \param dnsserver A pointer to a 4-byte representation of the IP
441 * address of the DNS server to be configured.
442 */
443/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000444void
445resolv_conf(u16_t *dnsserver)
446{
447 if(resolv_conn != NULL) {
448 uip_udp_remove(resolv_conn);
449 }
450
451 resolv_conn = uip_udp_new(dnsserver, 53);
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000452}
453/*-----------------------------------------------------------------------------------*/
adamdunkels1e45c6d2003-09-02 21:47:27 +0000454/**
455 * Initalize the resolver.
456 */
457/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000458void
459resolv_init(void)
460{
adamdunkels99dcf452003-08-15 18:50:36 +0000461 static u8_t i;
462
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000463 for(i = 0; i < RESOLV_ENTRIES; ++i) {
464 names[i].state = STATE_DONE;
465 }
466
467 resolv_signal_found = dispatcher_sigalloc();
468}
469/*-----------------------------------------------------------------------------------*/
adamdunkels1e45c6d2003-09-02 21:47:27 +0000470/** \internal
471 * Callback function which is called when a hostname is found.
472 *
473 */
474/*-----------------------------------------------------------------------------------*/
adamdunkelsca9ddcb2003-03-19 14:13:31 +0000475void
476resolv_found(char *name, u16_t *ipaddr)
477{
478 dispatcher_emit(resolv_signal_found, name, DISPATCHER_BROADCAST);
479}
adamdunkels66c6af62003-04-16 18:28:16 +0000480/*-----------------------------------------------------------------------------------*/
adamdunkels0170b082003-10-01 11:25:37 +0000481
482/** @} */
483/** @} */