/[H8]/trunk/docs/Microchip TCP_IP stack/TCPIP Stack/DNS.c
ViewVC logotype

Contents of /trunk/docs/Microchip TCP_IP stack/TCPIP Stack/DNS.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 15 - (show annotations) (download)
Thu Apr 19 09:01:15 2007 UTC (17 years, 1 month ago) by hedin
File MIME type: text/plain
File size: 16530 byte(s)
added the TCP/IP stack, source code.
1 /*********************************************************************
2 *
3 * Domain Name System (DNS) Client
4 * Module for Microchip TCP/IP Stack
5 * -Provides hostname to IP address translation
6 * -Reference: RFC 1035
7 *
8 *********************************************************************
9 * FileName: DNS.c
10 * Dependencies: UDP, ARP, Tick
11 * Processor: PIC18, PIC24F, PIC24H, dsPIC30F, dsPIC33F
12 * Complier: Microchip C18 v3.02 or higher
13 * Microchip C30 v2.05 or higher
14 * Company: Microchip Technology, Inc.
15 *
16 * Software License Agreement
17 *
18 * Copyright © 2002-2007 Microchip Technology Inc. All rights
19 * reserved.
20 *
21 * Microchip licenses to you the right to use, modify, copy, and
22 * distribute:
23 * (i) the Software when embedded on a Microchip microcontroller or
24 * digital signal controller product (“Device”) which is
25 * integrated into Licensee’s product; or
26 * (ii) ONLY the Software driver source files ENC28J60.c and
27 * ENC28J60.h ported to a non-Microchip device used in
28 * conjunction with a Microchip ethernet controller for the
29 * sole purpose of interfacing with the ethernet controller.
30 *
31 * You should refer to the license agreement accompanying this
32 * Software for additional information regarding your rights and
33 * obligations.
34 *
35 * THE SOFTWARE AND DOCUMENTATION ARE PROVIDED “AS IS” WITHOUT
36 * WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT
37 * LIMITATION, ANY WARRANTY OF MERCHANTABILITY, FITNESS FOR A
38 * PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL
39 * MICROCHIP BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR
40 * CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF
41 * PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY OR SERVICES, ANY CLAIMS
42 * BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE
43 * THEREOF), ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION, OR OTHER
44 * SIMILAR COSTS, WHETHER ASSERTED ON THE BASIS OF CONTRACT, TORT
45 * (INCLUDING NEGLIGENCE), BREACH OF WARRANTY, OR OTHERWISE.
46 *
47 *
48 * Author Date Comment
49 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
50 * Howard Schlunder 7/31/06 Original
51 * Howard Schlunder 10/09/06 Added DNSBeginUsage(), DNSEndUsage()
52 * module ownership semaphore
53 ********************************************************************/
54 #define __DNS_C
55
56 #include "TCPIP Stack/TCPIP.h"
57
58 #if defined(STACK_USE_DNS)
59
60
61 #define DNS_PORT 53u
62 #define DNS_TIMEOUT (TICK_SECOND*2)
63
64
65
66 static UDP_SOCKET MySocket = INVALID_UDP_SOCKET;
67 static BYTE *DNSHostName;
68 static ROM BYTE *DNSHostNameROM;
69 static BYTE RecordType;
70 static union
71 {
72 BYTE Val;
73 struct
74 {
75 unsigned char DNSInUse : 1;
76 unsigned char AddressValid : 1;
77 unsigned char filler : 6;
78 } bits;
79 } Flags = {0x00};
80 static enum
81 {
82 DNS_HOME = 0,
83 DNS_RESOLVE_ARP,
84 DNS_OPEN_SOCKET,
85 DNS_QUERY,
86 DNS_GET_RESULT,
87 DNS_DONE
88 } smDNS = DNS_DONE;
89
90 typedef struct _DNS_HEADER
91 {
92 WORD_VAL TransactionID;
93 WORD_VAL Flags;
94 WORD_VAL Questions;
95 WORD_VAL Answers;
96 WORD_VAL AuthoritativeRecords;
97 WORD_VAL AdditionalRecords;
98 } DNS_HEADER;
99
100 typedef struct _DNS_ANSWER_HEADER
101 {
102 WORD_VAL ResponseName;
103 WORD_VAL ResponseType;
104 WORD_VAL ResponseClass;
105 DWORD_VAL ResponseTTL;
106 WORD_VAL ResponseLen;
107 } DNS_ANSWER_HEADER;
108
109 static void DNSPutString(BYTE *String);
110 static void DNSPutROMString(ROM BYTE *String);
111 static void DNSGetString(BYTE *String);
112
113
114 /*********************************************************************
115 * Function: BOOL DNSBeginUsage(void)
116 *
117 * PreCondition: Stack is initialized()
118 *
119 * Input: None
120 *
121 * Output: TRUE: If no DNS resolution operations are in progress and this application has successfully taken ownership of the DNS module
122 * FALSE: If the DNS module is currently being used by some other module. Call DNSBeginUsage() some time later (after returning to the main() program loop).
123 *
124 * Side Effects: None
125 *
126 * Overview: Call DNSBeginUsage() and make sure it returns TRUE before calling any DNS APIs. Call DNSEndUsage() when this application no longer needs the DNS module so that other applications may make use of it.
127 *
128 * Note: None
129 ********************************************************************/
130 BOOL DNSBeginUsage(void)
131 {
132 if(Flags.bits.DNSInUse)
133 return FALSE;
134
135 Flags.bits.DNSInUse = TRUE;
136 return TRUE;
137 }
138
139
140 /*********************************************************************
141 * Function: BOOL DNSEndUsage(void)
142 *
143 * PreCondition: DNSBeginUsage() returned TRUE on a previous call.
144 *
145 * Input: None
146 *
147 * Output: TRUE: If the address to the host name was
148 * successfully resolved
149 * FALSE: If the DNS failed or address does not
150 * exists. The contents of *Hostname are
151 * unchanged.
152 *
153 * Side Effects: None
154 *
155 * Overview: Call DNSBeginUsage() and make sure it returns
156 * TRUE before calling any DNS APIs. Call
157 * DNSEndUsage() when this application no longer
158 * needs the DNS module so that other applications
159 * may make use of it.
160 *
161 * Note: None
162 ********************************************************************/
163 BOOL DNSEndUsage(void)
164 {
165 if(MySocket != INVALID_UDP_SOCKET)
166 {
167 UDPClose(MySocket);
168 MySocket = INVALID_UDP_SOCKET;
169 }
170 smDNS = DNS_DONE;
171 Flags.bits.DNSInUse = FALSE;
172
173 return Flags.bits.AddressValid;
174 }
175
176
177 /*********************************************************************
178 * Function: void DNSResolve(BYTE *Hostname, BYTE RecordType)
179 *
180 * PreCondition: Stack is initialized()
181 *
182 * Input: *Hostname: Null terminated string specifying the
183 * host address to resolve to an IP
184 * address.
185 * Type: DNS_TYPE_A (1d): Host Address (normal IP address)
186 * DNS_TYPE_MX (15d): Mail eXchange
187 * All other values are reserved
188 *
189 * Output: None
190 *
191 * Side Effects: None
192 *
193 * Overview: Call DNSIsResolved() until the host is resolved.
194 *
195 * Note: A UDP socket must be available before this
196 * function is called. It is freed at the end of
197 * the resolution. MAX_UDP_SOCKETS may need to be
198 * increased if other modules use UDP sockets.
199 *
200 * You must not modify *Hostname until DNSIsResolved()
201 * returns TRUE.
202 ********************************************************************/
203 void DNSResolve(BYTE *Hostname, BYTE Type)
204 {
205 DNSHostName = Hostname;
206 DNSHostNameROM = NULL;
207 smDNS = DNS_HOME;
208 RecordType = Type;
209 Flags.bits.AddressValid = FALSE;
210 }
211
212 void DNSResolveROM(ROM BYTE *Hostname, BYTE Type)
213 {
214 DNSHostName = NULL;
215 DNSHostNameROM = Hostname;
216 smDNS = DNS_HOME;
217 RecordType = Type;
218 Flags.bits.AddressValid = FALSE;
219 }
220
221
222 /*********************************************************************
223 * Function: BOOL DNSIsResolved(IP_ADDR *HostIP)
224 *
225 * PreCondition: DNSResolve() was called.
226 *
227 * Input: HostIP: Pointer to IP_ADDR structure to store the
228 * returned host IP address when DNS
229 * resolution is complete.
230 *
231 * Output: *HostIP, 4 byte IP address
232 *
233 * Side Effects: None
234 *
235 * Overview: Call DNSIsResolved() until the host is resolved.
236 *
237 * Note: You cannot start two DNS resolution proceedures
238 * concurrently.
239 *
240 * You must not modify *Hostname until DNSIsResolved()
241 * returns TRUE.
242 ********************************************************************/
243 BOOL DNSIsResolved(IP_ADDR *HostIP)
244 {
245 static NODE_INFO Remote;
246 static TICK StartTime;
247 static WORD_VAL SentTransactionID __attribute__((persistent));
248 BYTE i;
249 WORD_VAL w;
250 DNS_HEADER DNSHeader;
251 DNS_ANSWER_HEADER DNSAnswerHeader;
252
253 switch(smDNS)
254 {
255 case DNS_HOME:
256 ARPResolve(&AppConfig.PrimaryDNSServer);
257 StartTime = TickGet();
258 smDNS++;
259 break;
260
261 case DNS_RESOLVE_ARP:
262 if(!ARPIsResolved(&AppConfig.PrimaryDNSServer, &Remote.MACAddr))
263 {
264 if(TickGet() - StartTime > DNS_TIMEOUT)
265 {
266 smDNS--;
267 }
268 break;
269 }
270 Remote.IPAddr.Val = AppConfig.PrimaryDNSServer.Val;
271 smDNS++;
272 // No need to break, we can immediately open a socket
273
274 case DNS_OPEN_SOCKET:
275 MySocket = UDPOpen(0, &Remote, DNS_PORT);
276 if(MySocket == INVALID_UDP_SOCKET)
277 break;
278
279 smDNS++;
280 // No need to break, we can immediately start resolution
281
282 case DNS_QUERY:
283 if(!UDPIsPutReady(MySocket))
284 break;
285
286 // Put DNS query here
287 SentTransactionID.Val++;
288 UDPPut(SentTransactionID.v[1]);// User chosen transaction ID
289 UDPPut(SentTransactionID.v[0]);
290 UDPPut(0x01); // Standard query with recursion
291 UDPPut(0x00);
292 UDPPut(0x00); // 0x0001 questions
293 UDPPut(0x01);
294 UDPPut(0x00); // 0x0000 answers
295 UDPPut(0x00);
296 UDPPut(0x00); // 0x0000 name server resource records
297 UDPPut(0x00);
298 UDPPut(0x00); // 0x0000 additional records
299 UDPPut(0x00);
300
301 // Put hostname string to resolve
302 if(DNSHostName)
303 DNSPutString(DNSHostName);
304 else
305 DNSPutROMString(DNSHostNameROM);
306
307 UDPPut(0x00); // Type: DNS_TYPE_A A (host address) or DNS_TYPE_MX for mail exchange
308 UDPPut(RecordType);
309 UDPPut(0x00); // Class: IN (Internet)
310 UDPPut(0x01);
311
312 UDPFlush();
313 StartTime = TickGet();
314 smDNS++;
315 break;
316
317 case DNS_GET_RESULT:
318 if(!UDPIsGetReady(MySocket))
319 {
320 if(TickGet() - StartTime > DNS_TIMEOUT)
321 {
322 smDNS--;
323 }
324 break;
325 }
326
327 // Retrieve the DNS header and de-big-endian it
328 UDPGet(&DNSHeader.TransactionID.v[1]);
329 UDPGet(&DNSHeader.TransactionID.v[0]);
330
331 // Throw this packet away if it isn't in response to our last query
332 if(DNSHeader.TransactionID.Val != SentTransactionID.Val)
333 {
334 UDPDiscard();
335 break;
336 }
337
338 UDPGet(&DNSHeader.Flags.v[1]);
339 UDPGet(&DNSHeader.Flags.v[0]);
340 UDPGet(&DNSHeader.Questions.v[1]);
341 UDPGet(&DNSHeader.Questions.v[0]);
342 UDPGet(&DNSHeader.Answers.v[1]);
343 UDPGet(&DNSHeader.Answers.v[0]);
344 UDPGet(&DNSHeader.AuthoritativeRecords.v[1]);
345 UDPGet(&DNSHeader.AuthoritativeRecords.v[0]);
346 UDPGet(&DNSHeader.AdditionalRecords.v[1]);
347 UDPGet(&DNSHeader.AdditionalRecords.v[0]);
348
349 // Remove all questions
350 while(DNSHeader.Questions.Val--)
351 {
352 DNSGetString(NULL);
353 UDPGet(&w.v[1]); // Question type
354 UDPGet(&w.v[0]);
355 UDPGet(&w.v[1]); // Question class
356 UDPGet(&w.v[0]);
357 }
358
359 // Scan through answers
360 while(DNSHeader.Answers.Val--)
361 {
362 UDPGet(&DNSAnswerHeader.ResponseName.v[1]); // Response name
363 UDPGet(&DNSAnswerHeader.ResponseName.v[0]);
364 UDPGet(&DNSAnswerHeader.ResponseType.v[1]); // Response type
365 UDPGet(&DNSAnswerHeader.ResponseType.v[0]);
366 UDPGet(&DNSAnswerHeader.ResponseClass.v[1]); // Response class
367 UDPGet(&DNSAnswerHeader.ResponseClass.v[0]);
368 UDPGet(&DNSAnswerHeader.ResponseTTL.v[3]); // Time to live
369 UDPGet(&DNSAnswerHeader.ResponseTTL.v[2]);
370 UDPGet(&DNSAnswerHeader.ResponseTTL.v[1]);
371 UDPGet(&DNSAnswerHeader.ResponseTTL.v[0]);
372 UDPGet(&DNSAnswerHeader.ResponseLen.v[1]); // Response length
373 UDPGet(&DNSAnswerHeader.ResponseLen.v[0]);
374
375 // Make sure that this is a 4 byte IP address, response type A or MX, class 1
376 // Check if this is Type A or MX
377 if( DNSAnswerHeader.ResponseType.Val == 0x0001u &&
378 DNSAnswerHeader.ResponseClass.Val == 0x0001u && // Internet class
379 DNSAnswerHeader.ResponseLen.Val == 0x0004u)
380 {
381 Flags.bits.AddressValid = TRUE;
382 UDPGet(&HostIP->v[0]);
383 UDPGet(&HostIP->v[1]);
384 UDPGet(&HostIP->v[2]);
385 UDPGet(&HostIP->v[3]);
386 goto DoneSearchingRecords;
387 }
388 else
389 {
390 while(DNSAnswerHeader.ResponseLen.Val--)
391 {
392 UDPGet(&i);
393 }
394 }
395 }
396
397 // Remove all Authoritative Records
398 while(DNSHeader.AuthoritativeRecords.Val--)
399 {
400 UDPGet(&DNSAnswerHeader.ResponseName.v[1]); // Response name
401 UDPGet(&DNSAnswerHeader.ResponseName.v[0]);
402 UDPGet(&DNSAnswerHeader.ResponseType.v[1]); // Response type
403 UDPGet(&DNSAnswerHeader.ResponseType.v[0]);
404 UDPGet(&DNSAnswerHeader.ResponseClass.v[1]); // Response class
405 UDPGet(&DNSAnswerHeader.ResponseClass.v[0]);
406 UDPGet(&DNSAnswerHeader.ResponseTTL.v[3]); // Time to live
407 UDPGet(&DNSAnswerHeader.ResponseTTL.v[2]);
408 UDPGet(&DNSAnswerHeader.ResponseTTL.v[1]);
409 UDPGet(&DNSAnswerHeader.ResponseTTL.v[0]);
410 UDPGet(&DNSAnswerHeader.ResponseLen.v[1]); // Response length
411 UDPGet(&DNSAnswerHeader.ResponseLen.v[0]);
412
413 // Make sure that this is a 4 byte IP address, response type A or MX, class 1
414 // Check if this is Type A
415 if( DNSAnswerHeader.ResponseType.Val == 0x0001u &&
416 DNSAnswerHeader.ResponseClass.Val == 0x0001u && // Internet class
417 DNSAnswerHeader.ResponseLen.Val == 0x0004u)
418 {
419 Flags.bits.AddressValid = TRUE;
420 UDPGet(&HostIP->v[0]);
421 UDPGet(&HostIP->v[1]);
422 UDPGet(&HostIP->v[2]);
423 UDPGet(&HostIP->v[3]);
424 goto DoneSearchingRecords;
425 }
426 else
427 {
428 while(DNSAnswerHeader.ResponseLen.Val--)
429 {
430 UDPGet(&i);
431 }
432 }
433 }
434
435 // Remove all Additional Records
436 while(DNSHeader.AdditionalRecords.Val--)
437 {
438 UDPGet(&DNSAnswerHeader.ResponseName.v[1]); // Response name
439 UDPGet(&DNSAnswerHeader.ResponseName.v[0]);
440 UDPGet(&DNSAnswerHeader.ResponseType.v[1]); // Response type
441 UDPGet(&DNSAnswerHeader.ResponseType.v[0]);
442 UDPGet(&DNSAnswerHeader.ResponseClass.v[1]); // Response class
443 UDPGet(&DNSAnswerHeader.ResponseClass.v[0]);
444 UDPGet(&DNSAnswerHeader.ResponseTTL.v[3]); // Time to live
445 UDPGet(&DNSAnswerHeader.ResponseTTL.v[2]);
446 UDPGet(&DNSAnswerHeader.ResponseTTL.v[1]);
447 UDPGet(&DNSAnswerHeader.ResponseTTL.v[0]);
448 UDPGet(&DNSAnswerHeader.ResponseLen.v[1]); // Response length
449 UDPGet(&DNSAnswerHeader.ResponseLen.v[0]);
450
451 // Make sure that this is a 4 byte IP address, response type A or MX, class 1
452 // Check if this is Type A
453 if( DNSAnswerHeader.ResponseType.Val == 0x0001u &&
454 DNSAnswerHeader.ResponseClass.Val == 0x0001u && // Internet class
455 DNSAnswerHeader.ResponseLen.Val == 0x0004u)
456 {
457 Flags.bits.AddressValid = TRUE;
458 UDPGet(&HostIP->v[0]);
459 UDPGet(&HostIP->v[1]);
460 UDPGet(&HostIP->v[2]);
461 UDPGet(&HostIP->v[3]);
462 goto DoneSearchingRecords;
463 }
464 else
465 {
466 while(DNSAnswerHeader.ResponseLen.Val--)
467 {
468 UDPGet(&i);
469 }
470 }
471 }
472
473 DoneSearchingRecords:
474
475 UDPDiscard();
476 UDPClose(MySocket);
477 MySocket = INVALID_UDP_SOCKET;
478 smDNS++;
479 // No need to break, we are done and need to return TRUE
480
481 case DNS_DONE:
482 return TRUE;
483 }
484
485 return FALSE;
486 }
487
488 static void DNSPutString(BYTE *String)
489 {
490 BYTE *RightPtr;
491 BYTE i;
492 BYTE Len;
493
494 RightPtr = String;
495
496 while(1)
497 {
498 do
499 {
500 i = *RightPtr++;
501 } while((i != 0x00u) && (i != '.') && (i != '/') && (i != ',') && (i != '>'));
502
503 // Put the length parameter
504 Len = (BYTE)(RightPtr-String-1);
505 UDPPut(Len);
506 while(Len--)
507 {
508 UDPPut(*String++);
509 }
510 if(i == 0x00u || i == '/' || i == ',' || i == '>')
511 break;
512
513 // Skip over the '.' in the input string
514 String++;
515 }
516
517 // Put the string terminator character
518 UDPPut(0x00);
519 }
520
521 static void DNSPutROMString(ROM BYTE *String)
522 {
523 ROM BYTE *RightPtr;
524 BYTE i;
525 BYTE Len;
526
527 RightPtr = String;
528
529 while(1)
530 {
531 do
532 {
533 i = *RightPtr++;
534 } while((i != 0x00u) && (i != '.') && (i != '/') && (i != ',') && (i != '>'));
535
536 // Put the length parameter
537 Len = (BYTE)(RightPtr-String-1);
538 UDPPut(Len);
539 UDPPutROMArray(String, Len);
540 String += Len + 1;
541
542 if(i == 0x00u || i == '/' || i == ',' || i == '>')
543 break;
544 }
545
546 // Put the string terminator character
547 UDPPut(0x00);
548 }
549
550
551 static void DNSGetString(BYTE *String)
552 {
553 BYTE i;
554 BYTE j;
555
556 if(String == NULL)
557 {
558 UDPGet(&i);
559 while(i)
560 {
561 while(i--)
562 {
563 UDPGet(&j);
564 }
565 UDPGet(&i);
566 }
567 }
568 else
569 {
570 UDPGet(&i);
571 while(i)
572 {
573 while(i--)
574 {
575 UDPGet(String);
576 String++;
577 }
578 UDPGet(&i);
579 }
580 }
581 }
582
583
584 #endif //#if defined(STACK_USE_DNS)

  ViewVC Help
Powered by ViewVC 1.1.20