?lang_form? ?lang_select? ?lang_submit? ?lang_endform?
{HEADER END}
{BLAME START}

library

?curdirlinks? -

Blame information for rev 32

Line No. Rev Author Line
1 32 kaklik /*********************************************************************
2 *
3 * Zero Configuration (Zeroconf) Multicast DNS and
4 * Service Discovery Module for Microchip TCP/IP Stack
5 *
6 *********************************************************************
7 * FileName: ZeroconfMulticastDNS.h
8 * Dependencies: IP
9 * Processor: PIC24F, PIC24H, dsPIC30F, dsPIC33F, PIC32
10 * Compiler: Microchip C32 v1.05 or higher
11 * Microchip C30 v3.12 or higher
12 * Company: Microchip Technology, Inc.
13 *
14 * Software License Agreement
15 *
16 * Copyright (C) 2009-2010 Microchip Technology Inc. All rights
17 * reserved.
18 *
19 * Microchip licenses to you the right to use, modify, copy, and
20 * distribute:
21 * (i) the Software when embedded on a Microchip microcontroller or
22 * digital signal controller product ("Device") which is
23 * integrated into Licensee's product; or
24 * (ii) ONLY the Software driver source files ENC28J60.c, ENC28J60.h,
25 * ENCX24J600.c and ENCX24J600.h ported to a non-Microchip device
26 * used in conjunction with a Microchip ethernet controller for
27 * the sole purpose of interfacing with the ethernet controller.
28 *
29 * You should refer to the license agreement accompanying this
30 * Software for additional information regarding your rights and
31 * obligations.
32 *
33 * THE SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT
34 * WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT
35 * LIMITATION, ANY WARRANTY OF MERCHANTABILITY, FITNESS FOR A
36 * PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL
37 * MICROCHIP BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR
38 * CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF
39 * PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY OR SERVICES, ANY CLAIMS
40 * BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE
41 * THEREOF), ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION, OR OTHER
42 * SIMILAR COSTS, WHETHER ASSERTED ON THE BASIS OF CONTRACT, TORT
43 * (INCLUDING NEGLIGENCE), BREACH OF WARRANTY, OR OTHERWISE.
44 *
45 *
46 * Author Date Comment
47 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
48 * Pradeep Reddy 31 Mar 2009 Initial creation
49 * Pradeep Reddy 23 Apr 2009 DNS-SD implementation
50 * Pradeep Reddy 27 Apr 2009 Fixes and enhancements
51 * Pradeep Reddy 11 May 2009 Code documentation
52 * Pradeep Reddy 12 May 2009 Cleanup
53 * King Shaw 14 Sep 2009 Added message-compression code
54 * King Shaw 23 Sep 2009 Rewrite message-compression code to
55 * decompress in-place.
56 * King Shaw 10 Oct 2009 Rewrite responder code to pass conformance
57 * tests with small footprint.
58 * Brad Rex 05 Apr 2010 Updated for MRF24WB0M
59 ********************************************************************/
60 #define __Zeroconf_Multicast_DNS_C
61  
62 #include "TCPIP Stack/TCPIP.h"
63 #define TICK DWORD
64  
65 //MDNS_STATIC should be static in production code
66 //For code size tuning, defined to be (blank) - so C30 can give us the size of each function.
67 //#define MDNS_STATIC static
68 #define MDNS_STATIC static
69  
70 #if defined(STACK_USE_ZEROCONF_MDNS_SD)
71 #include "TCPIP Stack/ZeroconfMulticastDNS.h"
72  
73 extern void DisplayIPValue(IP_ADDR IPVal);
74  
75 #define MDNS_PORT 5353
76 #define MAX_HOST_NAME_SIZE 32 //31+'\0' Max Host name size
77 #define MAX_LABEL_SIZE 64 //63+'\0' Maximum size allowed for a label. RFC 1035 (2.3.4) == 63
78 #define MAX_RR_NAME_SIZE 256 //255+'\0' Max Resource Recd Name size. RFC 1035 (2.3.4) == 255
79 #define MAX_SRV_TYPE_SIZE 32 //31+'\0' eg. "_http._tcp.local". Max could be 255, but is an overkill.
80 #define MAX_SRV_NAME_SIZE 64 //63+'\0' eg. "My Web server". Max could be 255, but is an overkill.
81 #define MAX_TXT_DATA_SIZE 128 //127+'\0' eg. "path=/index.htm"
82  
83 #define RESOURCE_RECORD_TTL_VAL 3600 // Time-To-Live for a Resource-Record in seconds.
84  
85 #define MAX_RR_NUM 4 // for A, PTR, SRV, and TXT Max No.of Resource-Records/Service
86  
87 /* Constants from mdns.txt (IETF Draft)*/
88 #define MDNS_PROBE_WAIT 750 // msecs (initial random delay)
89 #define MDNS_PROBE_INTERVAL 250 // msecs (maximum delay till repeated probe)
90 #define MDNS_PROBE_NUM 6 // (number of probe packets)
91 #define MDNS_MAX_PROBE_CONFLICT_NUM 30 // max num of conflicts before we insist and move on to announce ...
92 #define MDNS_ANNOUNCE_NUM 3 // (number of announcement packets)
93 #define MDNS_ANNOUNCE_INTERVAL 250 // msecs (time between announcement packets)
94 #define MDNS_ANNOUNCE_WAIT 250 // msecs (delay before announcing)
95  
96 /* Resource-Record Types from RFC-1035 */
97 typedef enum {
98 QTYPE_A = 1,
99 QTYPE_NS = 2,
100 QTYPE_CNAME = 5,
101 QTYPE_PTR = 12,
102 QTYPE_TXT = 16,
103 QTYPE_SRV = 33,
104 QTYPE_ANY = 255,
105 }MDNS_QTYPE;
106  
107 /* Indexes in Resource-record list */
108 #define QTYPE_A_INDEX 0
109 #define QTYPE_PTR_INDEX 1
110 #define QTYPE_SRV_INDEX 2
111 #define QTYPE_TXT_INDEX 3
112  
113 /* MDNS Message Fomrat, which is common
114 * for Queries and Resource-Records. Taken
115 * from RFC 1035
116 */
117 /* MDNS Message Header Flags */
118 typedef union _MDNS_MSG_HEADER_FLAGS {
119  
120 struct {
121 BYTE rcode:4;
122 BYTE z:3;
123 BYTE ra:1;
124 BYTE rd:1;
125 BYTE tc:1;
126 BYTE aa:1;
127 BYTE opcode:4;
128 BYTE qr:1;
129 }bits;
130 WORD Val;
131 BYTE v[2];
132 } MDNS_MSG_HEADER_FLAGS;
133  
134 /* MDNS Message-Header Format */
135 typedef struct _MDNS_MSG_HEADER
136 {
137 WORD_VAL query_id;
138 MDNS_MSG_HEADER_FLAGS flags;
139 WORD_VAL nQuestions;
140 WORD_VAL nAnswers;
141 WORD_VAL nAuthoritativeRecords;
142 WORD_VAL nAdditionalRecords;
143 } MDNS_MSG_HEADER;
144  
145 /* DNS-Query Format, which is prepended by
146 * DNS-MESSAGE Header defined above */
147 struct question
148 {
149 unsigned char *name;
150 unsigned short int type, class;
151 };
152  
153 /* DNS-Resource Record Format, which is
154 * prepended by DNS-MESSAGE Header
155 * defined above. This definition includes
156 * all resource-record data formats, to have
157 * small-memory foot print */
158  
159 struct _mDNSProcessCtx_sd;// mdnsd_struct
160 struct _mDNSProcessCtx_common;
161  
162 typedef struct _mDNSResourceRecord
163 {
164 BYTE *name;
165 WORD_VAL type;
166 WORD_VAL class;
167 DWORD_VAL ttl;
168 WORD_VAL rdlength;
169  
170 union {
171 IP_ADDR ip; // for A record
172  
173 struct {
174 WORD_VAL priority;
175 WORD_VAL weight;
176 WORD_VAL port;
177 } srv; // for SRV record
178 };
179  
180 // DO NOT merge this into the union.
181 BYTE *rdata; // for PTR, SRV and TXT records.
182  
183 /* House-Keeping Stuff */
184  
185 // pointer to the header Ctx of the process that "owns" this resource record.
186 struct _mDNSProcessCtx_common *pOwnerCtx;
187  
188 BYTE valid; /* indicates whether rr is valid */
189 BOOL bNameAndTypeMatched;
190 BOOL bResponseRequested;
191 BOOL bResponseSuppressed;
192 } mDNSResourceRecord;
193  
194 /* DNS-SD Specific Data-Structures */
195  
196 typedef enum _MDNS_STATE
197 {
198 MDNS_STATE_HOME = 0,
199 MDNS_STATE_INTF_NOT_CONNECTED,
200 MDNS_STATE_IPADDR_NOT_CONFIGURED,
201 MDNS_STATE_NOT_READY,
202 MDNS_STATE_INIT,
203 MDNS_STATE_PROBE,
204 MDNS_STATE_ANNOUNCE,
205 MDNS_STATE_DEFEND,
206 } MDNS_STATE;
207  
208 typedef enum _MDNS_RR_GROUP
209 {
210 MDNS_RR_GROUP_QD,
211 MDNS_RR_GROUP_AN,
212 MDNS_RR_GROUP_NS,
213 MDNS_RR_GROUP_AR
214 } MDNS_RR_GROUP;
215  
216 typedef struct _mDNSResponderCtx
217 {
218 mDNSResourceRecord rr_list[MAX_RR_NUM]; // Our resource records.
219  
220 BOOL bLastMsgIsIncomplete; // Last DNS msg was truncated
221 WORD_VAL query_id; // mDNS Query transaction ID
222 IP_ADDR prev_ipaddr; // To keep track of changes in IP-addr
223 } mDNSResponderCtx;
224  
225 typedef enum _MDNS_CTX_TYPE
226 {
227 MDNS_CTX_TYPE_HOST = 0,
228 MDNS_CTX_TYPE_SD
229 } MDNS_CTX_TYPE;
230  
231 typedef struct _mDNSProcessCtx_common
232 {
233 MDNS_CTX_TYPE type; // Is owner mDNS ("HOST") or mDNS-SD ("SD")?
234 MDNS_STATE state; // PROBE, ANNOUNCE, DEFEND, ...
235  
236 BYTE nProbeCount;
237 BYTE nProbeConflictCount;
238 BYTE nClaimCount;
239 BOOL bProbeConflictSeen;
240 BOOL bLateConflictSeen;
241  
242 BOOL bConflictSeenInLastProbe;
243 BYTE nInstanceId;
244  
245 TICK event_time; // Internal Timer, to keep track of events
246 BYTE time_recorded; // Flag to indicate event_time is loaded
247 TICK random_delay;
248  
249 } mDNSProcessCtx_common;
250  
251 typedef struct _mDNSProcessCtx_host
252 {
253 mDNSProcessCtx_common common;
254  
255 mDNSResponderCtx *pResponderCtx;
256  
257 // other host name related info
258  
259 BYTE szUserChosenHostName[MAX_HOST_NAME_SIZE]; // user chosen host name
260 BYTE szHostName[MAX_HOST_NAME_SIZE]; // mDNS chosen Host-Name
261  
262 } mDNSProcessCtx_host;
263  
264 typedef struct _mDNSProcessCtx_sd
265 {
266 mDNSProcessCtx_common common;
267  
268 mDNSResponderCtx *pResponderCtx;
269  
270 // info specific to SD
271 BYTE srv_name[MAX_SRV_NAME_SIZE];
272 BYTE srv_type[MAX_SRV_TYPE_SIZE];
273 BYTE sd_qualified_name[MAX_RR_NAME_SIZE];
274 BYTE used; /* Spinlock to protect Race-cond. */
275  
276 BYTE sd_auto_rename: 1, /* Flag to show auto-Rename is enabled */
277 sd_service_advertised: 1, /* Flag to show whether service is advertised */
278 service_registered: 1; /* Flag to indicate that user has registered this service */
279  
280 WORD sd_port; /* Port number in Local-sys where Service is being offered */
281 BYTE sd_txt_rec[MAX_TXT_DATA_SIZE];
282 BYTE sd_txt_rec_len;
283  
284 void (*sd_call_back)(char *, MDNSD_ERR_CODE , void *);
285 void *sd_context;
286  
287 } mDNSProcessCtx_sd;
288  
289 static mDNSProcessCtx_host gHostCtx;
290 static mDNSProcessCtx_sd gSDCtx;
291 static mDNSResponderCtx gResponderCtx;
292  
293 /* DNS-SD State-Machine */
294  
295 const BYTE *CONST_STR_local = (BYTE *) "local";
296  
297 /* Multicast-DNS States defintion */
298  
299 /************** Global Declarations ***************/
300 /* Remote Node info, which is Multicast-Node
301 * whose IP-address is 224.0.0.251 & MAC-Address
302 * is 01:00:5E:00:00:FB. Multicast-IP address for
303 * mDNS is specified by mdns.txt (IETF). IP is
304 * translated into Multicast-MAC address according
305 * rules specified in Std.
306 */
307 static NODE_INFO mDNSRemote;
308 UDP_SOCKET mDNS_socket = INVALID_UDP_SOCKET; // Multicast-Socket Opened up for
309 // mDNS Server/Client (Responder/Qurier)
310  
311  
312 /* Global declaration to support Message-Compression
313 * defined in RFC-1035, Section 4.1.4 */
314  
315 /* Forward declarations */
316 MDNS_STATIC void mDNSResponder(void);
317 MDNS_STATIC WORD mDNSDeCompress(WORD wPos, BYTE *pcString, BOOL bFollowPtr, BYTE cElement, BYTE cDepth);
318 static WORD g_mDNS_offset;
319  
320 //#define MDNS_USE_LOCAL_STRLEN y
321 #define MDNS_USE_LOCAL_STRCPY y
322 //#define MDNS_USE_LOCAL_STRCMP y
323 //#define MDNS_USE_LOCAL_ITOA y //local version returns extra info. To be fixed.
324  
325 #ifdef MDNS_USE_LOCAL_STRLEN
326 #define STRLEN_LOCAL(x) strlen_local(x)
327 #else
328 // use string functions provided by the SDK library.
329 #define STRLEN_LOCAL(x) strlen((char *)x)
330 #endif
331  
332 #ifdef MDNS_USE_LOCAL_STRCPY
333 #define STRCPY_LOCAL(x,y) strcpy_local(x,y)
334 #else
335 // use string functions provided by the SDK library.
336 #define STRCPY_LOCAL(x,y) strcpy((char *)x,(char *)y)
337 #endif
338  
339 #ifdef MDNS_USE_LOCAL_STRCMP
340 #define STRCMP_LOCAL(x,y) strcmp_local(x,y)
341 #else
342 // use string functions provided by the SDK library.
343 #define STRCMP_LOCAL(x,y) strcmp((char *)x,(char *)y)
344 #endif
345  
346 #ifdef MDNS_USE_LOCAL_ITOA
347 #define ITOA_LOCAL(x,y) itoa_local(x,y)
348 #else
349 // use itoa functions provided by the SDK library.
350 #define ITOA_LOCAL(x,y) uitoa((WORD)x,y)
351 #endif
352  
353 #ifdef MDNS_USE_LOCAL_STRLEN
354 MDNS_STATIC BYTE strlen_local(BYTE *str);
355 #endif
356  
357 // Redirect all UDPPUT_LOCAL() calls to here.
358 // This seems to make all those 'call + nop' (2 instructions) into 'rcall' (1 instruction)
359  
360 MDNS_STATIC void
361 UDPPUT_LOCAL(BYTE c)
362 {
363 UDPPut(c);
364 }
365  
366 /***************************************************************
367 Function:
368 void DisplayHostName(BYTE *HostName)
369  
370 Summary:
371 Writes an Host-Name to the LCD display and the UART
372 as available
373  
374 Description:
375 This function takes a string and then displays it on LCD's
376 2nd half.
377  
378 Parameters:
379 HostName - the Hos-name to be displayed.
380  
381 Returns:
382 None
383 ***************************************************************/
384 MDNS_STATIC void DisplayHostName(BYTE *HostName)
385 {
386 BYTE SingleChar;
387 BYTE i;
388 BYTE len;
389 #ifdef USE_LCD
390 BYTE LCDPos=0;
391 #endif
392  
393 #if defined(STACK_USE_UART)
394 putrsUART((ROM char*)"\r\nZeroConf: Host = ");
395 putrsUART((ROM char*)HostName);
396 putrsUART((ROM char*)"\r\n");
397 #endif
398  
399 len = STRLEN_LOCAL(HostName);
400  
401 for(i = 0; (i < len) && (i < 16u); i++)
402 {
403 SingleChar = *HostName++;
404 if(SingleChar == '\0')
405 break;
406  
407 #ifdef USE_LCD
408 LCDText[LCDPos++] = SingleChar;
409 #endif
410  
411 }
412  
413 #ifdef USE_LCD
414 if(LCDPos < 32u)
415 LCDText[LCDPos] = 0;
416 LCDUpdate();
417 #endif
418  
419 }
420  
421 /************* Local String Functions ******************/
422  
423 #ifdef MDNS_USE_LOCAL_STRLEN
424 /***************************************************************
425 Function:
426 static BYTE strlen_local(BYTE *string)
427  
428 Summary:
429 Finds the length of a string.
430  
431 Description:
432 This function finds length a string. This is an base
433 implementation for small memory foot-print.
434  
435 Parameters:
436 String - the string for which length to be calculated.
437  
438 Returns:
439 Length of type BYTE.
440 **************************************************************/
441 MDNS_STATIC BYTE strlen_local(BYTE *str)
442 {
443 BYTE len=0;
444  
445 while(*str++)
446 len++;
447  
448 return len;
449 }
450 #endif // MDNS_USE_LOCAL_STRLEN
451  
452 #ifdef MDNS_USE_LOCAL_STRCMP
453 /***************************************************************
454 Function:
455 static BYTE strcmp_local(BYTE *string_1, BYTE *string_2)
456  
457 Summary:
458 Compares two strings
459  
460 Parameters:
461 string_1 & string_2 - Two strings
462  
463 Returns:
464 Zero: If two strings are equal.
465 Non-Zero: If both strings are not equal or on error case
466 **************************************************************/
467 MDNS_STATIC BYTE strcmp_local(BYTE *str_1, BYTE *str_2)
468 {
469 if(str_1 == NULL || str_2 == NULL)
470 {
471 return -1;
472 }
473 while(*str_1 && *str_2){
474 if(*str_1++ != *str_2++)
475 return 1;
476 }
477  
478 if(*str_1 == '\0' && *str_2 == '\0')
479 return 0;
480 else
481 return 1;
482 }
483 #endif // MDNS_USE_LOCAL_STRCMP
484  
485 /***************************************************************
486 Function:
487 static BYTE strcmp_local_ignore_case(BYTE *string_1, BYTE *string_2)
488  
489 Summary:
490 Compares two strings by ignoring the case.
491  
492 Parameters:
493 string_1 & string_2 - Two strings
494  
495 Returns:
496 Zero: If two strings are equal.
497 Non-Zero: If both strings are not equal or on error case
498 **************************************************************/
499 MDNS_STATIC BYTE strcmp_local_ignore_case(BYTE *str_1, BYTE *str_2)
500 {
501 if(str_1 == NULL || str_2 == NULL)
502 {
503 WARN_MDNS_PRINT("strmcmp_local_ignore_case: String is NULL \r\n");
504 return -1;
505 }
506  
507 while(*str_1 && *str_2){
508 if(*str_1 == *str_2 || (*str_1-32) == *str_2 ||
509 *str_1 == (*str_2-32))
510 {
511 str_1++;
512 str_2++;
513 continue;
514 }
515 else
516 return 1;
517  
518 }
519 if(*str_1 == '\0' && *str_2 == '\0')
520 return 0;
521 else
522 return 1;
523  
524 }
525  
526 #ifdef MDNS_USE_LOCAL_STRCPY
527 /********************************************************************
528 Function:
529 static void strcpy_local(BYTE *dst_string, BYTE *src_string)
530  
531 Summary:
532 Copies one string into other string. This is base
533 & optimized implementation without error-handling.
534 Goal is small memory foot print.
535  
536 Parameters:
537 dst_string: Destination String
538 src_string: Source string
539  
540 Returns:
541 None
542 **************************************************************/
543 MDNS_STATIC void strcpy_local(BYTE *dst, BYTE *src)
544 {
545 while((*dst++ = *src++));
546 }
547 #endif // MDNS_USE_LOCAL_STRCPY
548  
549 #ifdef MDNS_USE_LOCAL_ITOA
550 /***************************************************************
551 Function:
552 static void strrev_local(BYTE *string)
553  
554 Summary:
555 Reverses a string
556  
557 Description:
558 This function reverses a string without copying string or
559 requiring additional memory. This is an Optimized
560 implementation for both processing & memory efficiency.
561  
562 Parameters:
563 String - the string to be reversed.
564  
565 Returns:
566 None
567 ***************************************************************/
568 MDNS_STATIC void strrev_local(BYTE *str)
569 {
570 BYTE *first, *last;
571 BYTE ch;
572  
573 first = last = str;
574 while(*last)
575 last++;
576 last--;
577 while(first<=last)
578 {
579 ch = *first;
580 *first = *last;
581 *last = ch;
582 first++;
583 last--;
584 }
585 }
586  
587 /***************************************************************
588 Function:
589 static BYTE itoa_local(BYTE num, BYTE *string)
590  
591 Summary:
592 Converts decimal (num) to String (string).
593  
594 Parameters:
595 num: Decimal number, which needs to be converted to string
596 string: Memory where string needs to be stored.
597 (Output param)
598  
599 Returns:
600 Count of number of characters present in String rep
601 **************************************************************/
602 MDNS_STATIC BYTE itoa_local(BYTE num, BYTE *str)
603 {
604 BYTE *tmp = str;
605 BYTE cnt = 0;
606  
607 while(num>0)
608 {
609 cnt++;
610 *tmp++ = (num%10) + '0';
611 num = num/10;
612 }
613 *tmp = '\0';
614 strrev_local(str);
615 return cnt;
616 }
617 #endif // MDNS_USE_LOCAL_ITOA
618  
619 MDNS_STATIC void
620 mDNSResetCounters(mDNSProcessCtx_common *pHeader, BOOL bResetProbeConflictCount)
621 {
622 if (bResetProbeConflictCount)
623 {
624  
625 pHeader->nProbeConflictCount = 0;
626 }
627  
628 pHeader->nProbeCount = 0;
629 pHeader->nClaimCount = 0;
630 pHeader->bLateConflictSeen = FALSE;
631 pHeader->bProbeConflictSeen = FALSE;
632 }
633  
634 /***************************************************************
635 Function:
636 static void mDNSRename(BYTE *str, BYTE max_len)
637  
638 Summary:
639 Renames a string with a numerical-extension.
640  
641 Description:
642 This function is to rename host-name/Resource-Record Name,
643 when a name-conflict is detected on local-network.
644 For-Ex: "myhost" is chosen name and a conflict is detected
645 this function renames as "myhost-2". Also ensures that string
646 is properly formatted.
647  
648 Precondition:
649 None
650  
651 Parameters:
652 String - the string to be Renamed with Numerical-Extenstion.
653 max_len - Maximum Length allowed for String
654  
655 Returns:
656 None
657 **************************************************************/
658  
659 // strLabel: the user registered name.
660 // E.g., "Web Server", for service name (srv_name), or
661 // "My Host", for host name (taken from MY_DEFAULT_HOST_NAME)
662 // TODO: both names should be run-time configurable,
663 // through registration functions.
664 // nLabelId: instance number, to avoid conflict in the name space.
665 // strBase: the base name for the appropriate name space.
666 // E.g., "_http._tcp.local" for service name, or
667 // "local" for host name.
668 // strTarget: where the newly constructed fully-qualified-name will be stored.
669 // nMaxLen: max length for the newly constructed label, which is the first portion of the
670 // fully-qualified-name
671 //
672 // ("Web Server", 3, "_http._tcp.local", strTarget, 63) =>
673 // stores "Web Server-3._http._tcp.local" to *strTarget.
674 // ("MyHost", 2, "local", strTarget, 63) =>
675 // stores "MyHost-2.local" to *strTarget
676 //
677  
678 MDNS_STATIC void mDNSRename(BYTE *strLabel, BYTE nLabelId, BYTE *strBase, BYTE *strTarget, BYTE nMaxLen)
679 {
680 BYTE n = nLabelId;
681 #define mDNSRename_ID_LEN 6
682 BYTE str_n[mDNSRename_ID_LEN]; //enough for "-255." + '\0'.
683 BYTE i = mDNSRename_ID_LEN - 1 ;
684  
685 str_n[i--] = 0;
686 str_n[i--] = '.';
687  
688 // construct str_n from n
689 while (i != 0)
690 {
691 str_n[i--] = '0'+ n%10;
692 if (n < 10) break;
693 n = n/10;
694 }
695 str_n[i] = '-';
696  
697 STRCPY_LOCAL(strTarget, strLabel);
698 STRCPY_LOCAL(strTarget+STRLEN_LOCAL(strTarget), &(str_n[i]));
699  
700 // nMaxLen not checked, but here is how it should be:
701 #ifdef MDNS_WARN
702 if ( STRLEN_LOCAL(strTarget) > nMaxLen )
703 {
704 MDNS_WARN("mDNSRename: label too long\r\n");
705 }
706 #endif
707  
708 STRCPY_LOCAL(strTarget+STRLEN_LOCAL(strTarget), strBase);
709 }
710  
711 /***************************************************************
712 Function:
713 static void mDNSPutString(BYTE* String)
714  
715 Summary:
716 Writes a string to the Multicast-DNS socket.
717  
718 Description:
719 This function writes a string to the Multicast-DNS socket,
720 ensuring that it is properly formatted.
721  
722 Precondition:
723 UDP socket is obtained and ready for writing.
724  
725 Parameters:
726 String - the string to write to the UDP socket.
727  
728 Returns:
729 None
730 **************************************************************/
731  
732 MDNS_STATIC void mDNSPutString(BYTE* string)
733 {
734 BYTE *right_ptr,*label_ptr;
735 BYTE label[MAX_LABEL_SIZE];
736 BYTE i;
737 BYTE len;
738  
739 right_ptr = string;
740  
741 while(1)
742 {
743 label_ptr = label;
744 len = 0;
745 while(*right_ptr)
746 {
747 i = *right_ptr;
748  
749 if(i == '.' || i == '/' ||
750 i == ',' || i == '>' || i == '\\')
751 {
752 /* Formatted Serv-Instance will have '\.'
753 * instead of just '.' */
754 if(i == '\\')
755 {
756 right_ptr++;
757 }
758  
759 else
760 break;
761 }
762 *label_ptr++ = *right_ptr;
763 len++;
764 right_ptr++;
765 }
766 i = *right_ptr++;
767  
768 // Put the length and data
769 // Also, skip over the '.' in the input string
770 UDPPUT_LOCAL(len);
771 UDPPutArray(label, len);
772 string = right_ptr;
773  
774 if(i == 0x00u || i == '/' || i == ',' || i == '>')
775 break;
776 }
777  
778 // Put the string null terminator character
779 UDPPUT_LOCAL(0x00);
780 }
781  
782 /***************************************************************
783 Function:
784 static BOOL mDNSSendQuery(BYTE* name, BYTE record_type)
785  
786 Summary:
787 Sends out a Multicast-DNS-Query to Multicast-Address
788 through mDNS_socket.
789  
790 Description:
791 This function is used in Probing-phase to check the
792 uniqueness of chosen Host-Name/ Resoruce-Record-Name.
793 Selected Name and Type of Query are put into
794 Multicast UDP socket.
795  
796 Precondition:
797 UDP socket (mDNS_socket) is obtained and ready for writing.
798  
799 Parameters:
800 name - Chosen Host-Name/Resource-Record-Name, checking
801 for uniqueness.
802 type - Type of Query
803  
804 Returns:
805 TRUE - On Success
806 FALSE - On Failure (If UDP-Socket is invalid)
807 **************************************************************/
808 //MDNS_STATIC BOOL mDNSSendQuery(BYTE* name, BYTE record_type, BYTE cFlush, BYTE probe_type)
809  
810 MDNS_STATIC BOOL mDNSProbe(mDNSProcessCtx_common *pCtx)
811 {
812 MDNS_MSG_HEADER mDNS_header;
813  
814 // Abort operation if no UDP sockets are available
815 // If this ever happens, incrementing MAX_UDP_SOCKETS in
816 // StackTsk.h may help (at the expense of more global memory
817 // resources).
818  
819 if(mDNS_socket == INVALID_UDP_SOCKET)
820 {
821 WARN_MDNS_PRINT("mDNSSendQuery: Opening UDP Socket Failed \r\n");
822 return FALSE;
823 }
824  
825 // Make certain the socket can be written to
826 while(!UDPIsPutReady(mDNS_socket));
827  
828 // Put DNS query here
829 gResponderCtx.query_id.Val++;
830  
831 /*
832 UDPPUT_LOCAL(gResponderCtx.query_id.v[1]);// User chosen transaction ID
833 UDPPUT_LOCAL(gResponderCtx.query_id.v[0]);
834  
835 UDPPUT_LOCAL(0x00); // Standard query with recursion
836 UDPPUT_LOCAL(0x00);
837  
838 UDPPUT_LOCAL(0x00); // 1 entry in the question section
839 UDPPUT_LOCAL(0x01);
840  
841 UDPPUT_LOCAL(0x00); // 0 entry in the answer section
842 UDPPUT_LOCAL(0x00);
843  
844 UDPPUT_LOCAL(0x00); // 1 entry in name server section
845 UDPPUT_LOCAL(0x01);
846  
847 UDPPUT_LOCAL(0x00); // 0 entry in additional records section
848 UDPPUT_LOCAL(0x00);
849 */
850  
851 mDNS_header.query_id.Val = swaps(gResponderCtx.query_id.Val); // User chosen transaction ID
852 mDNS_header.flags.Val = 0; // Standard query with recursion
853 mDNS_header.nQuestions.Val = swaps(((WORD)1u)); // 1 entry in the question section
854 mDNS_header.nAnswers.Val = 0; // 0 entry in the answer section
855 mDNS_header.nAuthoritativeRecords.Val = swaps(((WORD)1u)); // 1 entry in name server section
856 mDNS_header.nAdditionalRecords.Val = 0; // 0 entry in additional records section
857  
858 // Put out the mDNS message header
859 UDPPutArray((BYTE *) &mDNS_header, sizeof(MDNS_MSG_HEADER));
860  
861 // Start of the QD section
862  
863 switch (pCtx->type)
864 {
865 case MDNS_CTX_TYPE_HOST:
866  
867 mDNSPutString(gResponderCtx.rr_list[QTYPE_A_INDEX].name);
868 break;
869  
870 case MDNS_CTX_TYPE_SD:
871  
872 mDNSPutString(gResponderCtx.rr_list[QTYPE_SRV_INDEX].name);
873 break;
874 }
875  
876 UDPPUT_LOCAL(0x00); // Type: Always QTYPE_ANY
877 UDPPUT_LOCAL(QTYPE_ANY);
878  
879 UDPPUT_LOCAL(0x80); // Class: Cache-Flush
880 UDPPUT_LOCAL(0x01); // IN (Internet)
881  
882 // Start of the NS section
883  
884 switch (pCtx->type)
885 {
886 case MDNS_CTX_TYPE_HOST:
887 mDNSPutString(gResponderCtx.rr_list[QTYPE_A_INDEX].name);
888 break;
889  
890 case MDNS_CTX_TYPE_SD:
891 mDNSPutString(gResponderCtx.rr_list[QTYPE_SRV_INDEX].name);
892 break;
893 }
894  
895 UDPPUT_LOCAL(0x00); // Type: A or SRV
896  
897 switch (pCtx->type)
898 {
899 case MDNS_CTX_TYPE_HOST:
900 UDPPUT_LOCAL(QTYPE_A);
901 break;
902  
903 case MDNS_CTX_TYPE_SD:
904 UDPPUT_LOCAL(QTYPE_SRV);
905 break;
906 }
907  
908  
909  
910 UDPPUT_LOCAL(0x00); // Class: Cache-Flush bit MUST NOT be set
911 UDPPUT_LOCAL(0x01); // IN (Internet)
912  
913 UDPPUT_LOCAL(0x00); // 0x00000078 Time To Live, 2 minutes
914 UDPPUT_LOCAL(0x00);
915 UDPPUT_LOCAL(0x00);
916 UDPPUT_LOCAL(0x78);
917  
918 switch (pCtx->type)
919 {
920 case MDNS_CTX_TYPE_HOST:
921 {
922 UDPPUT_LOCAL(gResponderCtx.rr_list[QTYPE_A_INDEX].rdlength.v[1]);
923 UDPPUT_LOCAL(gResponderCtx.rr_list[QTYPE_A_INDEX].rdlength.v[0]);
924  
925 UDPPUT_LOCAL(gResponderCtx.rr_list[QTYPE_A_INDEX].ip.v[0]);
926 UDPPUT_LOCAL(gResponderCtx.rr_list[QTYPE_A_INDEX].ip.v[1]);
927 UDPPUT_LOCAL(gResponderCtx.rr_list[QTYPE_A_INDEX].ip.v[2]);
928 UDPPUT_LOCAL(gResponderCtx.rr_list[QTYPE_A_INDEX].ip.v[3]);
929  
930 break;
931 }
932  
933 case MDNS_CTX_TYPE_SD:
934 {
935 UDPPUT_LOCAL(gResponderCtx.rr_list[QTYPE_SRV_INDEX].rdlength.v[1]);
936 UDPPUT_LOCAL(gResponderCtx.rr_list[QTYPE_SRV_INDEX].rdlength.v[0]);
937  
938 UDPPUT_LOCAL(gResponderCtx.rr_list[QTYPE_SRV_INDEX].srv.priority.v[1]);
939 UDPPUT_LOCAL(gResponderCtx.rr_list[QTYPE_SRV_INDEX].srv.priority.v[0]);
940 UDPPUT_LOCAL(gResponderCtx.rr_list[QTYPE_SRV_INDEX].srv.weight.v[1]);
941 UDPPUT_LOCAL(gResponderCtx.rr_list[QTYPE_SRV_INDEX].srv.weight.v[0]);
942 UDPPUT_LOCAL(gResponderCtx.rr_list[QTYPE_SRV_INDEX].srv.port.v[1]);
943 UDPPUT_LOCAL(gResponderCtx.rr_list[QTYPE_SRV_INDEX].srv.port.v[0]);
944  
945 mDNSPutString(gResponderCtx.rr_list[QTYPE_SRV_INDEX].rdata);
946  
947 break;
948 }
949 }
950  
951 UDPFlush();
952  
953 return TRUE;
954 }
955  
956 /***************************************************************
957 Function:
958 static BOOL mDNSSendRR(struct mDNSResourceRecord *record,
959 BYTE record_type, DWORD ttl_val,WORD query_id)
960  
961 Summary:
962 Sends out a Multicast-DNS-Answer (Resource-Record) to
963 Multicast-Address through mDNS_socket (UDP Socket).
964  
965 Description:
966 This function is used in Announce-phase & Defend-Phase.
967  
968 In announce-phase the Host-Name or Resource-Record (Service)
969 will be announced in local-network, so that neighbors can
970 detect new-service or update their caches with new host-name
971 to IP-Address mapping.
972  
973 In Defend-Phase, when mDNSResponder receives a query for
974 Host-name or Resounce-record for which this holds authority.
975  
976 Precondition:
977 UDP socket (mDNS_socket) is obtained and ready for writing.
978  
979 Parameters:
980 record - Resource-Record filled up with required info
981 type - Type of Res-Rec
982 ttl_val - Time-To-Live value for Res-Record
983 query_id - Query-ID for which this mDNS-answer (Res-Rec)
984 corresponds to
985  
986 Returns:
987 TRUE - On Success
988 FALSE - On Failure (If UDP-Socket is invalid)
989 **************************************************************/
990  
991 MDNS_STATIC BOOL
992 mDNSSendRR(mDNSResourceRecord *pRecord,
993 WORD query_id,
994 BYTE cFlush,
995 WORD nAnswersInMsg,
996 BOOL bIsFirstRR,
997 BOOL bIsLastRR)
998 {
999 MDNS_MSG_HEADER mDNS_header;
1000 DWORD_VAL ttl;
1001 BYTE rec_length;
1002 BYTE record_type;
1003  
1004 record_type = pRecord->type.Val;
1005  
1006 DEBUG0_MDNS_MESG(zeroconf_dbg_msg, "tx RR: (%d)\r\n", record_type);
1007 DEBUG0_MDNS_PRINT(zeroconf_dbg_msg);
1008  
1009 if(mDNS_socket == INVALID_UDP_SOCKET)
1010 {
1011 WARN_MDNS_PRINT("mDNSSendRR: Opening UDP Socket Failed \r\n");
1012 return FALSE;
1013 }
1014  
1015 while(!UDPIsPutReady(mDNS_socket));
1016  
1017 if (bIsFirstRR)
1018 {
1019 memset(&mDNS_header, 0, sizeof(MDNS_MSG_HEADER));
1020  
1021 mDNS_header.query_id.Val = swaps(query_id);
1022  
1023 mDNS_header.flags.bits.qr = 1; // this is a Response,
1024 mDNS_header.flags.bits.aa = 1; // and we are authoritative
1025 mDNS_header.flags.Val = swaps(mDNS_header.flags.Val);
1026  
1027 mDNS_header.nAnswers.Val = swaps(nAnswersInMsg);
1028  
1029 // Put out the mDNS message header
1030 UDPPutArray((BYTE *) &mDNS_header, sizeof(MDNS_MSG_HEADER));
1031 }
1032  
1033 ttl.Val = pRecord->ttl.Val;
1034  
1035 //rex#if 0
1036 //rex if ( name != NULL)
1037 //rex {
1038 //rex mDNSPutString(name);
1039 //rex }
1040 //rex else
1041 //rex#endif
1042 //rex {
1043 mDNSPutString(pRecord->name);
1044 //rex }
1045  
1046 UDPPUT_LOCAL(0x00); UDPPUT_LOCAL(record_type); // Resource Record Type
1047  
1048 /* MSB of Upper-byte in Class filed acts as
1049 * Cache-Flush bit to notify all Neighbors to
1050 * flush their caches and fill with this new
1051 * information */
1052 if (UDPSocketInfo[mDNS_socket].remotePort == MDNS_PORT)
1053 {
1054 UDPPUT_LOCAL(cFlush); UDPPUT_LOCAL(0x01); // Class
1055 }
1056 else
1057 {
1058 // Legacy/Unicast DNS response should not set the Cache-Flush bit.
1059 UDPPUT_LOCAL(0x00); UDPPUT_LOCAL(0x01); // Class
1060 }
1061  
1062 UDPPUT_LOCAL(ttl.v[3]); // Time To Live
1063 UDPPUT_LOCAL(ttl.v[2]);
1064 UDPPUT_LOCAL(ttl.v[1]);
1065 UDPPUT_LOCAL(ttl.v[0]);
1066  
1067 switch (record_type)
1068 {
1069 case QTYPE_A:
1070  
1071 UDPPUT_LOCAL(0x00); // 0x0004 Data length
1072 UDPPUT_LOCAL(0x04);
1073 UDPPUT_LOCAL(pRecord->ip.v[0]); // Put out IP address
1074 UDPPUT_LOCAL(pRecord->ip.v[1]); // AppConfig.MyIPAddr.v[1]
1075 UDPPUT_LOCAL(pRecord->ip.v[2]);
1076 UDPPUT_LOCAL(pRecord->ip.v[3]);
1077  
1078 break;
1079  
1080 case QTYPE_PTR:
1081  
1082 /* 2 bytes extra. One for Prefix Length for first-label.
1083 * Other one for NULL terminator */
1084 pRecord->rdlength.Val = STRLEN_LOCAL(pRecord->rdata) + 2 ;
1085  
1086 UDPPUT_LOCAL(pRecord->rdlength.v[1]);
1087 UDPPUT_LOCAL(pRecord->rdlength.v[0]); // Res-Data Length
1088  
1089 mDNSPutString(((mDNSProcessCtx_sd *) (pRecord->pOwnerCtx))->sd_qualified_name);
1090  
1091 break;
1092  
1093 case QTYPE_SRV:
1094  
1095 /* 2 bytes extra. One for Prefix Length for first-label.
1096 * Other one for NULL terminator */
1097  
1098 pRecord->rdlength.Val = STRLEN_LOCAL(pRecord->rdata) + 2;
1099 pRecord->rdlength.Val += 6; // for priority, weight, and port
1100  
1101 UDPPUT_LOCAL(pRecord->rdlength.v[1]);
1102 UDPPUT_LOCAL(pRecord->rdlength.v[0]); // Res-Data Length
1103  
1104 UDPPUT_LOCAL(pRecord->srv.priority.v[1]); // Put Priority
1105 UDPPUT_LOCAL(pRecord->srv.priority.v[0]);
1106 UDPPUT_LOCAL(pRecord->srv.weight.v[1]);
1107 UDPPUT_LOCAL(pRecord->srv.weight.v[0]);
1108 UDPPUT_LOCAL(pRecord->srv.port.v[1]);
1109 UDPPUT_LOCAL(pRecord->srv.port.v[0]);
1110  
1111 mDNSPutString(pRecord->rdata);
1112  
1113 break;
1114  
1115 case QTYPE_TXT:
1116  
1117 rec_length = STRLEN_LOCAL(pRecord->rdata);
1118 pRecord->rdlength.Val = rec_length + 1;
1119  
1120 UDPPUT_LOCAL(pRecord->rdlength.v[1]);
1121 UDPPUT_LOCAL(pRecord->rdlength.v[0]); // Res-Data Length
1122  
1123 UDPPUT_LOCAL(pRecord->rdlength.Val-1); // As of now only single TXT string supported!!
1124  
1125 UDPPutArray(pRecord->rdata,rec_length);
1126  
1127 break;
1128  
1129 default:
1130  
1131 WARN_MDNS_PRINT("RR Type not supported \n");
1132 }
1133  
1134 if (bIsLastRR)
1135 {
1136 UDPFlush();
1137 }
1138  
1139 return TRUE;
1140 }
1141  
1142 /***************************************************************
1143 Function:
1144 void mDNSSDFormatServiceInstance(BYTE *string)
1145  
1146 Summary:
1147 Formats the Service-Instance name according to DNS-SD standard
1148 specification.
1149  
1150 Description:
1151 This function is used to format the Service-Instance name, if
1152 it contains 'dots' and 'backslashes'
1153  
1154 As the service-instance name will be merged with service-type &
1155 to distinguish the 'dots' seperating the service-type words and
1156 'dots' within service-instance name, the 'dots' within service-
1157 instance name will be replaced with '\.' in place of '.' Even the
1158 '\' are replaced with '\\'.
1159  
1160 When the resource-record containing service-instance name is
1161 pushed out, the formatted dots '\.' are sentout as '.' and the
1162 'dots' sperating the service-type & service-instances are replaced
1163 with length bytes, as specified in RFC 1035.
1164  
1165 Precondition:
1166 None
1167  
1168 Parameters:
1169 String - Service-Instance name to be formatted
1170  
1171 Returns:
1172 None
1173 **************************************************************/
1174 void mDNSSDFormatServiceInstance(BYTE *string)
1175 {
1176 BYTE *temp;
1177 BYTE output[MAX_LABEL_SIZE];
1178 BYTE i;
1179 BYTE *right_ptr,*str_token;
1180 BYTE len;
1181  
1182 temp = output;
1183 right_ptr = string;
1184 str_token = string;
1185 while(1)
1186 {
1187 do
1188 {
1189 i = *right_ptr++;
1190 } while((i != 0x00u) && (i != '\\') && (i != '.') );
1191  
1192  
1193 /* Prefix '\' for every occurance of '.' & '\' */
1194 len = (BYTE)(right_ptr-str_token-1);
1195  
1196 memcpy(temp,str_token,len);
1197 temp += len;
1198 str_token += len;
1199 if(i == '.' || i == '\\')
1200 {
1201 *temp = '\\';
1202 temp++;
1203 *temp++ = i;
1204 str_token += 1;
1205  
1206 }
1207 else if(i == 0x00u || i == '/' || i == ',' || i == '>')
1208 break;
1209  
1210 }
1211 *temp++ = '\0';
1212 STRCPY_LOCAL(string,output);
1213 }
1214  
1215 /***************************************************************
1216 Function:
1217 void mDNSSDFillResRecords(mdnsd_struct *sd)
1218  
1219 Summary:
1220 Fills the resource-records with the information received from
1221 sd structure-instance, in which the information is filled from
1222 user input.
1223  
1224 Description:
1225 This function is used to fill the resource-records according to
1226 format specified in RFC 1035.
1227  
1228 In this context Service-Instance + Service-Type is called fully
1229 qualified name. For ex: Dummy HTTP Web-Server._http._tcp.local
1230 where Dummy HTTP Web-Server is Service-instance name
1231 and _http._tcp.local is Service-Type
1232  
1233 Each service-instance that needs to be advertised contains three
1234 resource-reocrds.
1235 1) PTR Resource-Record: This is a shared record, with service-type
1236 as rr-name and fully-qualified name as
1237 rr-data.
1238 2) SRV Resource-Record: This is a unique record, with fully-
1239 qualified name as rr-name and Host-name,
1240 port-num as rr-data.
1241 3) TXT Resource-Record: This is a unique record, with fully-
1242 qualified name as rr-name and additional
1243 information as rr-data like default-page
1244 name (For ex: "/index.htm")
1245  
1246 Precondition:
1247 None
1248  
1249 Parameters:
1250 sd - Service-Discovery structure instance for which Resource-
1251 records to be filled.
1252  
1253 Returns:
1254 None
1255 **************************************************************/
1256 void mDNSSDFillResRecords(mDNSProcessCtx_sd *sd)
1257 {
1258 BYTE *qualified_name;
1259 BYTE srv_name_len,srv_type_len;
1260 mDNSResourceRecord *rr_list = &(gResponderCtx.rr_list[QTYPE_PTR_INDEX]);
1261  
1262 srv_name_len = STRLEN_LOCAL(sd->srv_name);
1263 srv_type_len = STRLEN_LOCAL(sd->srv_type);
1264  
1265 memset(&(gResponderCtx.rr_list[QTYPE_PTR_INDEX]),0,(sizeof(mDNSResourceRecord)));
1266 memset(&(gResponderCtx.rr_list[QTYPE_SRV_INDEX]),0,(sizeof(mDNSResourceRecord)));
1267 memset(&(gResponderCtx.rr_list[QTYPE_TXT_INDEX]),0,(sizeof(mDNSResourceRecord)));
1268  
1269 /* Formatting Service-Instance name.
1270 * And preparing a fully qualified
1271 * Service-instance name. */
1272 STRCPY_LOCAL(sd->sd_qualified_name,sd->srv_name);
1273  
1274 mDNSSDFormatServiceInstance(sd->sd_qualified_name);
1275  
1276 qualified_name = sd->sd_qualified_name + STRLEN_LOCAL(sd->sd_qualified_name);
1277 *qualified_name++ = '.';
1278 STRCPY_LOCAL(qualified_name,sd->srv_type);
1279 DEBUG_MDNS_MESG(zeroconf_dbg_msg,"Fully Qualified Name: %s \r\n",sd->sd_qualified_name);
1280 DEBUG_MDNS_PRINT(zeroconf_dbg_msg);
1281  
1282 /* Fill-up PTR Record */
1283 rr_list->type.Val = QTYPE_PTR;
1284 rr_list->name = (BYTE *) (sd->srv_type);
1285  
1286 /* Res Record Name is
1287 * Service_Instance_name._srv-type._proto.domain */
1288 rr_list->rdata = (BYTE *) (sd->sd_qualified_name);
1289  
1290 qualified_name = rr_list->rdata + srv_name_len;
1291 *qualified_name++ = '.';
1292 STRCPY_LOCAL(qualified_name, sd->srv_type);
1293 qualified_name = rr_list->rdata; /* Save it for later access */
1294 /* 3 bytes extra. One for dot added between
1295 * Serv-Name and Serv-Type. One for length byte.
1296 * added for first-label in fully qualified name
1297 * Other one for NULL terminator */
1298 rr_list->rdlength.Val = srv_name_len+ srv_type_len + 3;
1299 rr_list->ttl.Val = RESOURCE_RECORD_TTL_VAL; /* Seconds. Not sure ! Need to check */
1300 rr_list->pOwnerCtx = (mDNSProcessCtx_common *) sd; /* Save back ptr */
1301 rr_list->valid = 1; /* Mark as valid */
1302  
1303 rr_list = &gResponderCtx.rr_list[QTYPE_SRV_INDEX]; /* Move onto next entry */
1304  
1305 /* Fill-up SRV Record */
1306 rr_list->name = (BYTE *) (sd->sd_qualified_name);
1307 rr_list->type.Val = QTYPE_SRV;
1308 //CLASS???
1309 rr_list->ttl.Val = RESOURCE_RECORD_TTL_VAL;
1310  
1311 //rdlength is calculated/assigned last
1312 rr_list->srv.priority.Val = 0;
1313 rr_list->srv.weight.Val = 0;
1314 rr_list->srv.port.Val = sd->sd_port;
1315  
1316 /* Res Record Name is
1317 * Service_Instance_name._srv-type._proto.domain */
1318 rr_list->rdata = (BYTE *) gHostCtx.szHostName;
1319  
1320 /* 2 bytes extra. One for Prefix Length for first-label.
1321 * Other one for NULL terminator */
1322 // then, add 6-byte extra: for priority, weight, and port
1323  
1324 rr_list->rdlength.Val = STRLEN_LOCAL(rr_list->rdata)+2+6;
1325  
1326 rr_list->pOwnerCtx = (mDNSProcessCtx_common *) sd; /* Save back ptr */
1327 rr_list->valid = 1; /* Mark as valid */
1328  
1329 rr_list = &gResponderCtx.rr_list[QTYPE_TXT_INDEX]; /* Move onto next entry */
1330  
1331 /* Fill-up TXT Record with NULL data*/
1332 rr_list->type.Val = QTYPE_TXT;
1333 rr_list->name = (BYTE *) (sd->sd_qualified_name);
1334  
1335 /* Res Record data is what defined by the user */
1336 rr_list->rdata = (BYTE *) (sd->sd_txt_rec);
1337  
1338 /* Extra byte for Length-Byte of TXT string */
1339 rr_list->rdlength.Val = gSDCtx.sd_txt_rec_len+1;
1340 rr_list->ttl.Val = RESOURCE_RECORD_TTL_VAL;
1341 rr_list->pOwnerCtx = (mDNSProcessCtx_common *) sd; /* Save back ptr */
1342 rr_list->valid = 1; /* Mark as valid */
1343 }
1344  
1345 /***************************************************************
1346 Function:
1347 MDNSD_ERR_CODE mDNSServiceUpdate(
1348 WORD port,
1349 WORD txt_len,
1350 const BYTE *txt_record)
1351  
1352 Summary:
1353 DNS-Service Discovery API for end-user to update the service
1354 -advertisement, which was previously registered with
1355 mDNSServiceRegister
1356  
1357 Description:
1358 This API is used by end-user application to update its service
1359 which was previously registered. With this API end-user app
1360 update the port number on which the service is running. It can
1361 update the additional information of service. For example: the
1362 default page can be updated to new page and corresponding page
1363 name can be input to this API to update all peer machines. The
1364 modified service will be announced with new contents on local
1365 network.
1366  
1367 This is an optional API and hsould be invoked only if it is
1368 necessary.
1369  
1370 Precondition:
1371 mDNSServiceRegister must be invoked before this call.
1372  
1373 Parameters:
1374 port - Port number on which service is running
1375 txt_len - For additional information about service like
1376 default page (eg "index.htm") for HTTP-service.
1377 Length of such additional information
1378 txt_record - String of additional information (eg "index.htm")
1379 for HTTP-service.
1380  
1381 Returns:
1382 MDNSD_ERR_CODE - Returns Error-code to indicate registration is
1383 success or not.
1384 1) MDNSD_SUCCESS - returns on success of call
1385 2) MDNSD_ERR_INVAL - When the input parameters are invalid or
1386 if the API is invoked in invalid state
1387 **************************************************************/
1388 MDNSD_ERR_CODE
1389 mDNSServiceUpdate(WORD port,
1390 const BYTE *txt_record)
1391 {
1392 mDNSProcessCtx_sd *sd = &gSDCtx;
1393  
1394 if( sd->used)
1395 {
1396 sd->service_registered = 0;
1397 sd->sd_port = port;
1398 /* Update Port Value in SRV Resource-record */
1399 gResponderCtx.rr_list[QTYPE_SRV_INDEX].srv.port.Val = port;
1400  
1401 if(txt_record != NULL)
1402 {
1403 STRCPY_LOCAL(sd->sd_txt_rec, (BYTE *) txt_record);
1404 sd->sd_txt_rec_len = STRLEN_LOCAL(sd->sd_txt_rec);
1405  
1406 /* Update Resource-records for this
1407 * Service-instance, in MDNS-SD state-
1408 * -machine */
1409 mDNSSDFillResRecords(sd);
1410 sd->common.state = MDNS_STATE_NOT_READY;
1411 }
1412  
1413 /* Notify MDNS Stack about Service-Registration
1414 * to get a time-slot for its own processing */
1415 sd->service_registered = 1;
1416 return MDNSD_SUCCESS;
1417 }
1418 else
1419 return MDNSD_ERR_INVAL;
1420 }
1421  
1422 /***************************************************************
1423 Function:
1424 MDNSD_ERR_CODE mDNSServiceDeRegister()
1425  
1426 Summary:
1427 DNS-Service Discovery API for end-user to De-register a
1428 service-advertisement, which was previously registered with
1429 mDNSServiceRegister API.
1430  
1431 Description:
1432 This API is used by end-user application to de-register its
1433 service-advertisement on local network. When this gets invoked
1434 by end-user DNS-SD stack sends out Good-Bye packets to update
1435 all peer machines that service will no longer be present. All
1436 peer machines remove the corresponding entry from Browser list.
1437  
1438 This is the last API that needs to be invoked by end-user
1439 application to free-up the DNS-SD stack for some other app.
1440  
1441 Precondition:
1442 mDNSServiceRegister must be invoked before this call.
1443  
1444 Parameters:
1445 None
1446  
1447 Returns:
1448 MDNSD_ERR_CODE - Returns Error-code to indicate registration is
1449 success or not.
1450 1) MDNSD_SUCCESS - returns on success of call
1451 2) MDNSD_ERR_INVAL - When the input parameters are invalid or
1452 if the API is invoked in invalid state
1453 **************************************************************/
1454 MDNSD_ERR_CODE mDNSServiceDeRegister()
1455 {
1456 mDNSProcessCtx_sd *sd = &gSDCtx;
1457  
1458 if(sd->used)
1459 {
1460 if(sd->sd_service_advertised == 1)
1461 {
1462 /* Send GoodBye Packet */
1463 gResponderCtx.rr_list[QTYPE_PTR_INDEX].ttl.Val = 0;
1464 gResponderCtx.rr_list[QTYPE_SRV_INDEX].ttl.Val = 0;
1465 gResponderCtx.rr_list[QTYPE_SRV_INDEX].ttl.Val = 0;
1466  
1467 mDNSSendRR(&gResponderCtx.rr_list[QTYPE_PTR_INDEX], 0, 0x00, 3, TRUE,FALSE);
1468 mDNSSendRR(&gResponderCtx.rr_list[QTYPE_SRV_INDEX], 0, 0x80, 3, FALSE,FALSE);
1469 mDNSSendRR(&gResponderCtx.rr_list[QTYPE_SRV_INDEX], 0, 0x80, 3, FALSE,TRUE);
1470 }
1471 /* Clear gSDCtx struct */
1472 sd->service_registered = 0;
1473 memset(sd,0,sizeof(mDNSProcessCtx_sd));
1474 return MDNSD_SUCCESS;
1475 }
1476 else
1477 return MDNSD_ERR_INVAL; /* Invalid Parameter */
1478 }
1479  
1480 /***************************************************************
1481 Function:
1482 MDNSD_ERR_CODE mDNSServiceRegister( ...)
1483  
1484 Summary:
1485 DNS-Service Discovery API for end-user to register for a
1486 service-advertisement.
1487  
1488 Description:
1489 This API is used by end-user application to announce its
1490 service on local network. All peer machines that are compliant
1491 with Multicast-DNS & DNS-Service Discovery protocol can detect
1492 the announcement and lists out an entry in Service-Browser list.
1493 End-User selects an entry to connect to this service. So
1494 ultimately this is an aid to end-user to discover any services
1495 that he is interested in, on a local network.
1496  
1497 This is the first API that needs to be invoked by end-user
1498 application. Presently only Multicast-DNS & Service-discovery
1499 stack supports only single service-advertisement. Once the
1500 application wants to terminate the service it has to invoke
1501 mDNSServiceDeRegister() API to free-up the DNS-SD stack for
1502 some other application.
1503  
1504 Precondition:
1505 None
1506  
1507 Parameters:
1508 srv_name - Service Name, which is being advertised
1509 srv_type - For a HTTP-Service its "_http._tcp.local"
1510 _http: is application protocol preceeded with
1511 under-score
1512 _tcp: is lower-layer protocol on which service runs
1513 local: is to represent service is on local-network
1514  
1515 For a iTunes Music Sharing "_daap._tcp.local"
1516 For a Priniting Service "_ipp._tcp.local"
1517 Refer to http://www.dns-sd.org/ServiceTypes.html
1518 for more service types
1519  
1520 port - Port number on which service is running
1521 txt_len - For additional information about service like
1522 default page (eg "index.htm") for HTTP-service.
1523 Length of such additional information
1524 txt_record - String of additional information (eg "index.htm")
1525 for HTTP-service.
1526  
1527 auto_rename- A flag to indicate DNS-SD stack, whether to rename
1528 the service automatically or not.
1529 If this is set to '0' Callback parameter will be used
1530 to indicate the conflict error and user has to select
1531 different name and re-register with this API.
1532 If this is set to '1' service-name will be automatically
1533 renamed with numerical suffix.
1534  
1535 callback - Callback function, which is user-application defined.
1536 This callback gets invoked on completion of service-
1537 advertisement. If an service name-conflit error is
1538 detected and auto_rename is set to '0' callback gets
1539 invoked with MDNSD_ERR_CONFLICT as error-code.
1540  
1541 context - Opaque context (pointer to opaque data), which needs
1542 to be used in callback function.
1543  
1544 Returns:
1545 MDNSD_ERR_CODE - Returns Error-code to indicate registration is
1546 success or not.
1547 1) MDNSD_SUCCESS - returns on success of call
1548 2) MDNSD_ERR_BUSY - When already some other service is being
1549 advertised using this DNS-SD stack
1550 **************************************************************/
1551 MDNSD_ERR_CODE
1552 mDNSServiceRegister(const char *srv_name,
1553 const char *srv_type,
1554 WORD port,
1555 const BYTE *txt_record,
1556 BYTE auto_rename,
1557 void (*call_back)(char *name, MDNSD_ERR_CODE err, void *context),
1558 void *context)
1559 {
1560 if(gSDCtx.used)
1561 {
1562 WARN_MDNS_PRINT("mDNSServiceRegister: Some Other Service is registered" \
1563 "Currently only One Serv-Reg is allowed \r\n");
1564 return MDNSD_ERR_BUSY;
1565 }
1566 if ( (srv_name == NULL) || (srv_type == NULL) || (txt_record == NULL) )
1567 {
1568 return MDNSD_ERR_INVAL; // Invalid Parameter
1569 }
1570  
1571 /* Clear the State-Machine */
1572 memset(&gSDCtx,0,sizeof(mDNSProcessCtx_sd));
1573 gSDCtx.used = 1; /* Mark it as used */
1574 gSDCtx.sd_auto_rename = auto_rename;
1575 gSDCtx.sd_port = port;
1576 gSDCtx.sd_service_advertised = 0;
1577 STRCPY_LOCAL(gSDCtx.srv_name, (BYTE *)srv_name);
1578  
1579 STRCPY_LOCAL(gSDCtx.srv_type, (BYTE *)srv_type);
1580 gSDCtx.sd_call_back = call_back;
1581 gSDCtx.sd_context = context;
1582  
1583 STRCPY_LOCAL(gSDCtx.sd_txt_rec, (BYTE *) txt_record);
1584 gSDCtx.sd_txt_rec_len = STRLEN_LOCAL(gSDCtx.sd_txt_rec);
1585  
1586 /* Fill up Resource-records for this
1587 * Service-instance, in MDNS-SD state-
1588 * -machine */
1589 mDNSSDFillResRecords(&gSDCtx);
1590  
1591 gSDCtx.common.type = MDNS_CTX_TYPE_SD;
1592 gSDCtx.common.state = MDNS_STATE_NOT_READY;
1593 gSDCtx.common.nInstanceId = 0;
1594  
1595 /* Notify MDNS Stack about Service-Registration
1596 * to get a time-slot for its own processing */
1597 gSDCtx.service_registered = 1;
1598  
1599 return MDNSD_SUCCESS;
1600 }
1601  
1602 /***************************************************************
1603 Function:
1604 static void mDNSSDStateMachineReset(mdnsd_struct *sd)
1605  
1606 Summary:
1607 Resets DNS-SD state-machine
1608  
1609 Description:
1610 This function is used to reset all state-variables related
1611 to DNS-SD state-machine.
1612  
1613 Precondition:
1614 None
1615  
1616 Parameters:
1617 sd - Service Discovery structure instance
1618  
1619 Returns:
1620 None
1621 **************************************************************/
1622  
1623 /***************************************************************
1624 Function:
1625 void mDNSSDProbe(mdnsd_struct *sd)
1626  
1627 Summary:
1628 Sends out Multicast-DNS SD probe-packet with chosen service-name
1629 The Query-type is of SRV.
1630  
1631 Description:
1632 This function is used to send out mDNS-probe packet for
1633 checking uniqueness of selected service-instance-name. This
1634 function makes use of mDNSSendQuery to send out DNS-Query with
1635 chosen service-name to Multicast-Address. The type of such query
1636 is QTYPE_SRV.
1637  
1638 If any other machine is using same service-name, it responds with
1639 a reply and this host has to select different service-name.
1640  
1641 Precondition:
1642 None
1643  
1644 Parameters:
1645 sd - Service Discovery structure instance
1646  
1647 Returns:
1648 None
1649 **************************************************************/
1650  
1651  
1652 /***************************************************************
1653 Function:
1654 void mDNSSDAnnounce(mdnsd_struct *sd)
1655  
1656 Summary:
1657 Sends out Multicast-DNS SD packet with SRV Resource-Record.
1658  
1659 Description:
1660 This function is used to send out DNS-SD SRV resource-record
1661 Announce packet for announcing the service-name on local network.
1662 This function makes use of mDNSSendRR to send out DNS-Resource-
1663 Record with chosen service-name+service-type as rr-name and the
1664 host-name, port-number as rr-data.
1665  
1666 This announcement updates DNS-caches of neighbor machines on
1667 the local network.
1668  
1669 Precondition:
1670 None
1671  
1672 Parameters:
1673 sd - Service Discovery structure instance
1674  
1675 Returns:
1676 None
1677 **************************************************************/
1678  
1679 void mDNSAnnounce(mDNSResourceRecord *pRR)
1680 {
1681 if( FALSE ==
1682 mDNSSendRR(
1683 pRR,
1684 0,
1685 0x80,
1686 1,
1687 TRUE,
1688 TRUE
1689 )
1690 )
1691 {
1692 WARN_MDNS_PRINT("mDNSAnnounce: Error in sending out Announce pkt \r\n");
1693 }
1694 }
1695  
1696 /***************************************************************
1697 Function:
1698 void mDNSSDTask(mdnsd_struct *sd, struct mDNSResourceRecord *rr,
1699 MDNS_MSG_HEADER *mDNS_header)
1700  
1701 Summary:
1702 Processes the received Resource-Record, which can either be
1703 a query or response.
1704  
1705 Description:
1706 This function is an extension function mDNSResponder. If incoming
1707 query/response's resource-record doesn't match with Host-Name then
1708 the corresponding resource-record will be forwarded to DNS-SD state
1709 machine for further processing. This is invoked from mDNSResponder
1710 if the service is marked as registered.
1711  
1712 This routine compares it with existing resource-records and checks
1713 for any conflict. If it is a query and there's match with the
1714 publihed resource-records then response will be sent back with
1715 that resource-reocrd.
1716  
1717 Precondition:
1718 None
1719  
1720 Parameters:
1721 sd - Service Discovery structure instance
1722 rr - Resource-Record filled with either DNS-query/
1723 response
1724 mDNS_header - Multicast-DNS Message header filled with incoming
1725 query/response information
1726  
1727 Returns:
1728 None
1729 **************************************************************/
1730  
1731  
1732 /***************************************************************
1733 Function:
1734 void mDNSSDProcess(mdnsd_struct *sd)
1735  
1736 Summary:
1737 Main routine for DNS-SD state-machine.
1738  
1739 Description:
1740 This function is main routine of DNS-SD state-machine and invoked
1741 from Multicast-DNS state-machine routine. Based on current state
1742 and the additional flag-bits the coresponding actions will be taken
1743  
1744 Once the user selected service-name is finalized the user-callback
1745 registered with DNS-SD will be invoked to notify that the service
1746 is advertised successfully. Two gracious announcement packets with
1747 service-information will be sent out to update Neighbor caches and
1748 existing service-browsers.
1749  
1750 Precondition:
1751 None
1752  
1753 Parameters:
1754 sd - Service Discovery structure instance
1755  
1756 Returns:
1757 None
1758 **************************************************************/
1759  
1760  
1761 #ifdef DEBUG_MDNS
1762 MDNS_MSG_HEADER *dbg_p_mDNS_header;
1763 mDNSResourceRecord *dbg_p_res_rec;
1764 #endif
1765  
1766 MDNS_STATIC WORD mDNSFetch(WORD wOffset, WORD wLen, BYTE *pcString)
1767 {
1768 WORD rc;
1769  
1770 UDPSetRxBuffer(wOffset);
1771  
1772 rc = UDPGetArray(pcString, wLen);
1773  
1774 return rc;
1775 }
1776  
1777  
1778 /***************************************************************
1779 Function:
1780 static WORD mDNSDeCompress(WORD wPos,
1781 BYTE *pcString,
1782 BOOL bFollowPtr,
1783 BYTE cElement,
1784 BYTE cDepth)
1785  
1786 Summary:
1787 Read a string from a resource record, from the Multicast-DNS socket buffer.
1788  
1789 Description:
1790 This function reads a string to the Multicast-DNS socket,
1791 ensuring that it is properly formatted.
1792  
1793 String may be reconstructed through decompression if necessary.
1794 Decompression pointer traversal is done in place, recursively, in UDP's RxBuffer.
1795  
1796 cDepth represents the recursion depth, for debugging purpose.
1797  
1798 cElement represents the number of elements in the string. For example,
1799 "ezconfig._http._tcp.local" has 4 elements.
1800  
1801 bFollowPtr indicates if DNS compression offset needs to be followed. That is, if
1802 we should reconstruct a compressed string.
1803  
1804 The reconstructed string is placed in pcString, if it is not NULL.
1805  
1806 For DNS message compression format, see RFC 1035, section 4.1.4.
1807  
1808 Precondition:
1809 UDP socket is obtained and ready for writing.
1810 wPos correctly reflect the current position in the UDP RxBuffer.
1811  
1812 Parameters:
1813 String - the string to write to the UDP socket.
1814  
1815 Returns:
1816 Number of bytes in THIS resource record field (in RFC 1035's term, NAME or RDATA).
1817 UDP RxBuffer pointer is repositioned to the place right after THIS resource record field.
1818  
1819 **************************************************************/
1820  
1821 MDNS_STATIC WORD mDNSDeCompress(WORD wPos, BYTE *pcString, BOOL bFollowPtr, BYTE cElement, BYTE cDepth)
1822 {
1823 WORD rr_len = 0; // As is in the packet. Could be in compressed format.
1824 WORD startOffset, endOffset, currOffset;
1825 BYTE i, tmp;
1826 WORD offset_in_ptr;
1827 WORD len;
1828 BYTE substr_len;
1829  
1830 currOffset = startOffset = wPos;
1831  
1832 while (1)
1833 {
1834 rr_len++;
1835 if(!UDPGet(&substr_len))
1836 goto mDNSDeCompress_done;
1837  
1838 if(substr_len == 0u)
1839 {
1840 if (pcString)
1841 {
1842 *pcString++ = '\0';
1843 }
1844 goto mDNSDeCompress_done;
1845 }
1846  
1847 if((substr_len & 0xC0) == 0xC0) // b'11 at MSb indicates compression ptr
1848 {
1849 offset_in_ptr = substr_len & 0x3F; // the rest of 6 bits is part of offset_in_ptr.
1850 offset_in_ptr = offset_in_ptr << 8;
1851  
1852 /* Remove label-ptr byte */
1853 rr_len++;
1854 UDPGet(&i);
1855 offset_in_ptr += i;
1856  
1857 if (bFollowPtr)
1858 {
1859 cDepth++;
1860  
1861 DEBUG_MDNS_MESG(zeroconf_dbg_msg, "follow ptr: h'%X, ", offset_in_ptr);
1862 DEBUG_MDNS_PRINT(zeroconf_dbg_msg);
1863 DEBUG_MDNS_MESG(zeroconf_dbg_msg, "%d\r\n", cDepth);
1864 DEBUG_MDNS_PRINT(zeroconf_dbg_msg);
1865  
1866 UDPSetRxBuffer(offset_in_ptr);
1867 len = mDNSDeCompress(offset_in_ptr, pcString, bFollowPtr, cElement, cDepth);
1868  
1869 // compressed ptr is always the last element
1870 goto mDNSDeCompress_done;
1871 }
1872  
1873 goto mDNSDeCompress_done;
1874 }
1875 else
1876 {
1877 if (pcString)
1878 {
1879 if (cElement > 0)
1880 {
1881 // not the first element in name
1882 *pcString++ = '.';
1883 }
1884  
1885 UDPGetArray(pcString, substr_len);
1886 pcString += substr_len;
1887 }
1888 else
1889 {
1890 i = substr_len;
1891 while (i--)
1892 {
1893 UDPGet(&tmp);
1894 }
1895 }
1896  
1897 cElement++;
1898 rr_len += substr_len;
1899 }
1900 }
1901  
1902 mDNSDeCompress_done:
1903  
1904 endOffset = startOffset + rr_len;
1905 UDPSetRxBuffer(endOffset);
1906  
1907 return rr_len;
1908 }
1909  
1910 /***************************************************************
1911 Function:
1912 void mDNSResponder(void)
1913  
1914 Summary:
1915 Acts as Multicast-DNS respoder & replies when it receives
1916 a query.
1917  
1918 Description:
1919 This function is used as mDNS-Responder. On initialization of
1920 Multicast-DNS stack, this function Opens up mDNS_socket
1921 (UDP-Socket) for Mulitcast-Address (224.0.0.251).
1922  
1923 This function gets polled from mDNSProcess for every iteration.
1924 mDNSResponder constantly monitors the packets being sent to
1925 Multicast-Address, to check whether it is a conflict with
1926 its own host-name/resource-record names. It also verifies
1927 whether incoming query is for its own Host-name/Resource-
1928 Record, in which case it sends back a reply with corresponding
1929 Resource-Record.
1930  
1931 Precondition:
1932 UDP socket (mDNS_socket) is obtained and ready for writing.
1933 A UDP socket must be available before this function is called.
1934 MAX_UDP_SOCKETS may need to be increased if other modules use
1935 UDP sockets.
1936  
1937 Parameters:
1938 None
1939  
1940 Returns:
1941 None
1942 **************************************************************/
1943  
1944 MDNS_STATIC BOOL
1945 mDNSTieBreaker(mDNSResourceRecord *their, mDNSResourceRecord *our)
1946 {
1947 BOOL WeWonTheTieBreaker = TRUE;
1948 BYTE i;
1949  
1950 if (their->type.Val == QTYPE_A)
1951 {
1952 for (i = 0; i<= 3; i++)
1953 {
1954 if (their->ip.v[i] < our->ip.v[i])
1955 {
1956 WeWonTheTieBreaker = TRUE;
1957 break;
1958 }
1959 else if (their->ip.v[i] > our->ip.v[i])
1960 {
1961 WeWonTheTieBreaker = FALSE;
1962 break;
1963 }
1964 }
1965 }
1966 else if (their->type.Val == QTYPE_SRV)
1967 {
1968 if (their->srv.port.Val >= our->srv.port.Val)
1969 {
1970 WeWonTheTieBreaker = FALSE;
1971 }
1972 }
1973  
1974 DEBUG0_MDNS_PRINT( (char *) (WeWonTheTieBreaker ? " tie-breaker won\r\n" : " tie-breaker lost\r\n") );
1975  
1976 return WeWonTheTieBreaker;
1977 }
1978  
1979 MDNS_STATIC BYTE
1980 mDNSProcessIncomingRR(MDNS_RR_GROUP tag,
1981 MDNS_MSG_HEADER *pmDNSMsgHeader,
1982 WORD idxGroup,
1983 WORD idxRR)
1984 {
1985 mDNSResourceRecord res_rec;
1986 BYTE name[MAX_RR_NAME_SIZE];
1987 BYTE i,j;
1988 WORD len;
1989 BYTE tmp;
1990 mDNSProcessCtx_common *pOwnerCtx;
1991 mDNSResourceRecord *pMyRR;
1992 BOOL WeWonTheTieBreaker = FALSE;
1993 BOOL bMsgIsAQuery; // QUERY or RESPNSE ?
1994 BOOL bSenderHasAuthority; // Sender has the authority ?
1995  
1996 bMsgIsAQuery = (pmDNSMsgHeader->flags.bits.qr == 0);
1997 bSenderHasAuthority = (pmDNSMsgHeader->flags.bits.qr == 1);
1998  
1999 res_rec.name = name; // for temporary name storage.
2000  
2001 #ifdef DEBUG_MDNS
2002 dbg_p_mDNS_header = &mDNS_header;
2003 dbg_p_res_rec = &res_rec;
2004 #endif
2005  
2006 DEBUG0_MDNS_MESG(
2007 zeroconf_dbg_msg,
2008 " rec [%d:%d]\t",
2009 idxGroup, idxRR);
2010 DEBUG0_MDNS_PRINT(zeroconf_dbg_msg);
2011  
2012 // NAME
2013 memset(name, 0, MAX_RR_NAME_SIZE);
2014 len = mDNSDeCompress(g_mDNS_offset, name, TRUE, 0, 0);
2015 g_mDNS_offset += len;
2016  
2017 // TYPE & CLASS
2018 UDPGet(&res_rec.type.v[1]);
2019 UDPGet(&res_rec.type.v[0]);
2020 UDPGet(&res_rec.class.v[1]);
2021 UDPGet(&res_rec.class.v[0]);
2022 g_mDNS_offset += 4;
2023  
2024 DEBUG0_MDNS_PRINT("Name: ");
2025 DEBUG0_MDNS_PRINT((char *) name);
2026 DEBUG0_MDNS_MESG(zeroconf_dbg_msg," Type: %d", res_rec.type.Val);
2027 DEBUG0_MDNS_PRINT((char*)zeroconf_dbg_msg);
2028 DEBUG0_MDNS_PRINT("\r\n");
2029  
2030 // Do the first round name check
2031 for (i = 0; i < MAX_RR_NUM; i++)
2032 {
2033 gResponderCtx.rr_list[i].bNameAndTypeMatched = FALSE;
2034  
2035 if (
2036 !strcmp_local_ignore_case((void *)name, gResponderCtx.rr_list[i].name)
2037 &&
2038 ((res_rec.type.Val == QTYPE_ANY) ||
2039 (res_rec.type.Val == gResponderCtx.rr_list[i].type.Val))
2040 )
2041 {
2042 gResponderCtx.rr_list[i].bNameAndTypeMatched = TRUE;
2043 }
2044 else if (
2045 (tag == MDNS_RR_GROUP_QD)
2046 &&
2047 !strcmp_local_ignore_case(name,(BYTE *) "_services._dns-sd._udp.local")
2048 &&
2049 (res_rec.type.Val == QTYPE_PTR)
2050 )
2051 {
2052 gResponderCtx.rr_list[i].bNameAndTypeMatched = TRUE;
2053 }
2054 }
2055  
2056  
2057 // Only AN, NS, AR records have extra fields
2058 if ( tag == MDNS_RR_GROUP_QD )
2059 {
2060 goto ReviewStage;
2061 }
2062  
2063 // Now retrieve those extra fields
2064  
2065 UDPGet(&res_rec.ttl.v[3]); // Time to live
2066 UDPGet(&res_rec.ttl.v[2]);
2067 UDPGet(&res_rec.ttl.v[1]);
2068 UDPGet(&res_rec.ttl.v[0]);
2069 UDPGet(&res_rec.rdlength.v[1]); // Response length
2070 UDPGet(&res_rec.rdlength.v[0]);
2071 g_mDNS_offset += 6;
2072  
2073 // The rest is record type dependent
2074  
2075 switch (res_rec.type.Val)
2076 {
2077 case QTYPE_A:
2078 UDPGet(&res_rec.ip.v[0]); // Read out IP address
2079 UDPGet(&res_rec.ip.v[1]);
2080 UDPGet(&res_rec.ip.v[2]);
2081 UDPGet(&res_rec.ip.v[3]);
2082  
2083 g_mDNS_offset += 4;
2084  
2085 DEBUG_MDNS_MESG(zeroconf_dbg_msg, " [A]: TTL=%ld\r\n", res_rec.ttl.Val);
2086 DEBUG_MDNS_PRINT((char*)zeroconf_dbg_msg);
2087  
2088 break;
2089  
2090 case QTYPE_PTR:
2091  
2092 memset(name, 0 , MAX_RR_NAME_SIZE);
2093 len = mDNSDeCompress(g_mDNS_offset, name, TRUE, 0, 0);
2094 g_mDNS_offset += len;
2095  
2096 DEBUG_MDNS_MESG(zeroconf_dbg_msg, " [PTR]: TTL=%ld RDATA=%s\r\n", res_rec.ttl.Val,name);
2097 DEBUG_MDNS_PRINT((char*)zeroconf_dbg_msg);
2098  
2099 break;
2100  
2101 case QTYPE_SRV:
2102  
2103 UDPGet(&res_rec.srv.priority.v[1]); // Put Priority, weight, port
2104 UDPGet(&res_rec.srv.priority.v[0]);
2105 UDPGet(&res_rec.srv.weight.v[1]);
2106 UDPGet(&res_rec.srv.weight.v[0]);
2107 UDPGet(&res_rec.srv.port.v[1]);
2108 UDPGet(&res_rec.srv.port.v[0]);
2109  
2110 g_mDNS_offset += 6;
2111  
2112 memset(name, 0 , MAX_RR_NAME_SIZE);
2113 len = mDNSDeCompress(g_mDNS_offset, name, TRUE, 0, 0);
2114 g_mDNS_offset += len;
2115  
2116 DEBUG_MDNS_MESG(zeroconf_dbg_msg, " [SRV]: TTL=%ld RDATA=%s\r\n", res_rec.ttl.Val,name);
2117 DEBUG_MDNS_PRINT((char*)zeroconf_dbg_msg);
2118  
2119 break;
2120  
2121 case QTYPE_TXT:
2122  
2123 i = res_rec.rdlength.Val;
2124  
2125 while (i--)
2126 {
2127 UDPGet(&tmp);
2128 }
2129  
2130 g_mDNS_offset += res_rec.rdlength.Val;
2131  
2132 DEBUG_MDNS_MESG(zeroconf_dbg_msg, " [TXT]: (%d bytes)\r\n", res_rec.rdlength.Val);
2133 DEBUG_MDNS_PRINT((char*)zeroconf_dbg_msg);
2134  
2135 break;
2136  
2137 default:
2138  
2139 // Still needs to read it off
2140  
2141 i = res_rec.rdlength.Val;
2142  
2143 while (i--)
2144 {
2145 UDPGet(&tmp);
2146 }
2147  
2148 g_mDNS_offset += res_rec.rdlength.Val;
2149  
2150 DEBUG_MDNS_MESG(zeroconf_dbg_msg, " [*]: (%d bytes)\r\n", res_rec.rdlength.Val);
2151 DEBUG_MDNS_PRINT((char*)zeroconf_dbg_msg);
2152  
2153 break;
2154 }
2155  
2156 // We now have all info about this received RR.
2157  
2158 ReviewStage:
2159  
2160 // Do the second round
2161 for (i = 0; i < MAX_RR_NUM; i++)
2162 {
2163 pMyRR = &(gResponderCtx.rr_list[i]);
2164 pOwnerCtx = gResponderCtx.rr_list[i].pOwnerCtx;
2165  
2166 if ( (!pMyRR->bNameAndTypeMatched) || (pOwnerCtx == NULL) )
2167 {
2168 // do nothing
2169 }
2170 else if (
2171 bMsgIsAQuery &&
2172 (tag == MDNS_RR_GROUP_QD) &&
2173 (pOwnerCtx->state == MDNS_STATE_DEFEND)
2174 )
2175 {
2176 // Simple reply to an incoming DNS query.
2177 // Mark all of our RRs for reply.
2178  
2179 for (j = 0; j < MAX_RR_NUM; j++)
2180 {
2181 gResponderCtx.rr_list[j].bResponseRequested = TRUE;
2182 }
2183 }
2184 else if (
2185 bMsgIsAQuery &&
2186 (tag == MDNS_RR_GROUP_AN) &&
2187 (pOwnerCtx->state == MDNS_STATE_DEFEND)
2188 )
2189 {
2190 // An answer in the incoming DNS query.
2191 // Look for possible duplicate (known) answers suppression.
2192  
2193 if ((((res_rec.type.Val == QTYPE_PTR) && (res_rec.ip.Val == gResponderCtx.rr_list[i].ip.Val))
2194 ||
2195 (!strcmp_local_ignore_case(name, gResponderCtx.rr_list[i].rdata)))
2196 &&
2197 (res_rec.ttl.Val > (gResponderCtx.rr_list[i].ttl.Val/2))
2198 )
2199 {
2200 gResponderCtx.rr_list[i].bResponseSuppressed = TRUE;
2201 DEBUG_MDNS_PRINT(" rr suppressed\r\n");
2202 }
2203 }
2204 else if (
2205 bMsgIsAQuery &&
2206 (tag == MDNS_RR_GROUP_NS) &&
2207 ((pOwnerCtx->state == MDNS_STATE_PROBE) ||
2208 (pOwnerCtx->state == MDNS_STATE_ANNOUNCE))
2209 )
2210 {
2211 // Simultaneous probes by us and sender of this DNS query.
2212 // Mark as a conflict ONLY IF we lose the Tie-Breaker.
2213  
2214 WeWonTheTieBreaker = mDNSTieBreaker(&res_rec,
2215 &(gResponderCtx.rr_list[i]));
2216  
2217 if (!WeWonTheTieBreaker)
2218 {
2219 pOwnerCtx->bProbeConflictSeen = TRUE;
2220 pOwnerCtx->nProbeConflictCount++;
2221 }
2222  
2223 UDPDiscard();
2224  
2225 return 0;
2226 }
2227 else if (
2228 !bMsgIsAQuery &&
2229 bSenderHasAuthority &&
2230 (tag == MDNS_RR_GROUP_AN) &&
2231 ((pOwnerCtx->state == MDNS_STATE_PROBE) ||
2232 (pOwnerCtx->state == MDNS_STATE_ANNOUNCE))
2233 )
2234 {
2235 // An authoritative DNS response to our probe/announcement.
2236 // Mark as a conflict. Effect a re-name, followed by a
2237 // re-probe.
2238  
2239 pOwnerCtx->bProbeConflictSeen = TRUE;
2240 pOwnerCtx->nProbeConflictCount++;
2241  
2242 UDPDiscard();
2243  
2244 return 0;
2245 }
2246 else if (
2247 bMsgIsAQuery &&
2248 (tag == MDNS_RR_GROUP_NS) &&
2249 (pOwnerCtx->state == MDNS_STATE_DEFEND)
2250 )
2251 {
2252 // A probe by the sender conflicts with our established record.
2253 // Need to defend our record. Effect a DNS response.
2254  
2255 INFO_MDNS_PRINT("Defending RR: \r\n");
2256  
2257 pMyRR->bResponseRequested = TRUE;
2258  
2259 UDPDiscard();
2260  
2261 return 0;
2262 }
2263 else if (
2264 !bMsgIsAQuery &&
2265 bSenderHasAuthority &&
2266 (tag == MDNS_RR_GROUP_AN) &&
2267 (pMyRR->type.Val != QTYPE_PTR ) && // No one can claim authority on shared RR
2268 (pOwnerCtx->state == MDNS_STATE_DEFEND)
2269 )
2270 {
2271 // Sender claims that it also has the authority on
2272 // a unique (non-shared) record that we have already established authority.
2273 // Effect a re-probe.
2274  
2275 pOwnerCtx->bLateConflictSeen = TRUE;
2276  
2277 UDPDiscard();
2278  
2279 return 0;
2280 }
2281 }
2282 return 0;
2283 }
2284  
2285 MDNS_STATIC void mDNSResponder(void)
2286 {
2287 MDNS_MSG_HEADER mDNS_header;
2288  
2289 static enum {
2290 MDNS_RESPONDER_INIT = 0,
2291 MDNS_RESPONDER_LISTEN,
2292 } mDNS_responder_state= MDNS_RESPONDER_INIT;
2293  
2294 WORD len;
2295 WORD i,j,count;
2296  
2297 WORD rr_count[4];
2298 MDNS_RR_GROUP rr_group[4];
2299  
2300 BOOL bMsgIsComplete;
2301  
2302 g_mDNS_offset = 0;
2303  
2304 if(mDNS_socket == INVALID_UDP_SOCKET)
2305 {
2306 mDNS_responder_state = MDNS_RESPONDER_INIT;
2307 }
2308 switch(mDNS_responder_state)
2309 {
2310 case MDNS_RESPONDER_INIT:
2311  
2312 /* Open a UDP socket for inbound and outbound transmission
2313 * Since we expect to only receive multicast packets and
2314 * only send multicast packets the remote NodeInfo
2315 * parameter is initialized to Multicast-IP (224.0.0.251)
2316 * corresponding Multicast MAC-Address (01:00:5E:00:00:FB) */
2317  
2318 mDNSRemote.IPAddr.v[0] = 0xE0;
2319 mDNSRemote.IPAddr.v[1] = 0;
2320 mDNSRemote.IPAddr.v[2] = 0;
2321 mDNSRemote.IPAddr.v[3] = 0xFB;
2322  
2323 mDNSRemote.MACAddr.v[0]=0x01;
2324 mDNSRemote.MACAddr.v[1]=0x00;
2325 mDNSRemote.MACAddr.v[2]=0x5E;
2326 mDNSRemote.MACAddr.v[3]=0x00;
2327 mDNSRemote.MACAddr.v[4]=0x00;
2328 mDNSRemote.MACAddr.v[5]=0xFB;
2329  
2330 mDNS_socket = UDPOpen(MDNS_PORT, &mDNSRemote, MDNS_PORT);
2331  
2332 if(mDNS_socket == INVALID_UDP_SOCKET)
2333 {
2334 WARN_MDNS_PRINT("mDNSResponder: Can't open Multicast-DNS UDP-Socket \r\n");
2335 return;
2336 }
2337 else
2338 mDNS_responder_state = MDNS_RESPONDER_LISTEN ;
2339  
2340 /* Called from mDNSInitialize. So return immediately */
2341 break;
2342  
2343 case MDNS_RESPONDER_LISTEN:
2344  
2345 // Do nothing if no data is waiting
2346 if(!UDPIsGetReady(mDNS_socket))
2347 return;
2348  
2349 if ( UDPSocketInfo[mDNS_socket].remotePort != MDNS_PORT )
2350 {
2351 // If the remote port (sender's src port)
2352 // is not MDNS_PORT (5353), then it is a multicast query
2353 // reqeusting a unicast response (even though the packet
2354 // was sent to the multicast group IP:MDNS_PORT ).
2355 // The response needs to be unicast, and sent
2356 // to sender:port, NOT to the multicast group IP:MDSN_PORT
2357 // (i.e., 224.0.0.251:5353).
2358  
2359 // See section 8.5, draft-cheshire-dnsext-multicastdns-08.txt.
2360 }
2361 else
2362 {
2363 /* Reset the Remote-node information in UDP-socket */
2364 memcpy((void*)&UDPSocketInfo[mDNS_socket].remoteNode,
2365 (const void*)&mDNSRemote, sizeof(mDNSRemote));
2366 UDPSocketInfo[mDNS_socket].remotePort = MDNS_PORT;
2367 UDPSocketInfo[mDNS_socket].localPort = MDNS_PORT;
2368 }
2369  
2370 // Retrieve the mDNS header
2371 len = mDNSFetch(0, sizeof(mDNS_header), (BYTE *) &mDNS_header);
2372 mDNS_header.query_id.Val = swaps(mDNS_header.query_id.Val);
2373 mDNS_header.flags.Val = swaps(mDNS_header.flags.Val);
2374 mDNS_header.nQuestions.Val = swaps(mDNS_header.nQuestions.Val);
2375 mDNS_header.nAnswers.Val = swaps(mDNS_header.nAnswers.Val);
2376 mDNS_header.nAuthoritativeRecords.Val = swaps(mDNS_header.nAuthoritativeRecords.Val);
2377 mDNS_header.nAdditionalRecords.Val = swaps(mDNS_header.nAdditionalRecords.Val);
2378  
2379 g_mDNS_offset += len; // MUST BE 12
2380  
2381 if ( (mDNS_header.flags.bits.qr == 0) )
2382 {
2383 DEBUG0_MDNS_PRINT("rx QUERY \r\n");
2384 }
2385 else
2386 {
2387 DEBUG0_MDNS_PRINT("rx RESPONSE \r\n");
2388 }
2389  
2390 bMsgIsComplete = (mDNS_header.flags.bits.tc == 0); // Message is not truncated.
2391  
2392 rr_count[0] = mDNS_header.nQuestions.Val;
2393 rr_group[0] = MDNS_RR_GROUP_QD;
2394  
2395 rr_count[1] = mDNS_header.nAnswers.Val;
2396 rr_group[1] = MDNS_RR_GROUP_AN;
2397  
2398 rr_count[2] = mDNS_header.nAuthoritativeRecords.Val;
2399 rr_group[2] = MDNS_RR_GROUP_NS;
2400  
2401 rr_count[3] = mDNS_header.nAdditionalRecords.Val;
2402 rr_group[3] = MDNS_RR_GROUP_AR;
2403  
2404 for (i = 0; i < MAX_RR_NUM; i++)
2405 {
2406 // Reset flags
2407 gResponderCtx.rr_list[i].bNameAndTypeMatched = FALSE;
2408  
2409 if (gResponderCtx.bLastMsgIsIncomplete)
2410 {
2411 // Do nothing.
2412 // Whether a reply is needed is determined only when all parts
2413 // of the message are received.
2414  
2415 // Ideally, we want to verify that the current message is the
2416 // continuation of the previous message.
2417 // Don't have a cost-effective way to do this yet.
2418 }
2419 else
2420 {
2421 // Start of a new message
2422  
2423 gResponderCtx.rr_list[i].bResponseRequested = FALSE;
2424 gResponderCtx.rr_list[i].bResponseSuppressed = FALSE;
2425 }
2426 }
2427  
2428 for (i=0; i<4; i++) // for all 4 groups: QD, AN, NS, AR
2429 {
2430 for(j=0; j < rr_count[i]; j++) // RR_count = {#QD, #AN, #NS, #AR}
2431 {
2432 mDNSProcessIncomingRR
2433 (
2434 rr_group[i],
2435 &mDNS_header,
2436 i,
2437 j
2438 );
2439  
2440 }
2441 }
2442  
2443 // Record the fact, for the next incoming message.
2444 gResponderCtx.bLastMsgIsIncomplete = (bMsgIsComplete == FALSE);
2445  
2446 // Do not reply any answer if the current message is not the last part of
2447 // the complete message.
2448 // Future parts of the message may request some answers be suppressed.
2449  
2450 if (!bMsgIsComplete)
2451 {
2452 DEBUG0_MDNS_PRINT(" truncated msg.\r\n");
2453 return;
2454 }
2455  
2456 // Count all RRs marked as "reply needed".
2457 count = 0;
2458 for (i = 0; i < MAX_RR_NUM; i++)
2459 {
2460 if ((gResponderCtx.rr_list[i].pOwnerCtx != NULL) &&
2461 (gResponderCtx.rr_list[i].pOwnerCtx->state == MDNS_STATE_DEFEND) &&
2462 (gResponderCtx.rr_list[i].bResponseRequested == TRUE) &&
2463 (gResponderCtx.rr_list[i].bResponseSuppressed == FALSE)
2464 )
2465 {
2466 count++;
2467 }
2468 }
2469  
2470 // Send all RRs marked as "reply needed".
2471 j = 1;
2472 for (i = 0; (count > 0) && (i < MAX_RR_NUM); i++)
2473 {
2474 if ((gResponderCtx.rr_list[i].pOwnerCtx != NULL) &&
2475 (gResponderCtx.rr_list[i].pOwnerCtx->state == MDNS_STATE_DEFEND) &&
2476 (gResponderCtx.rr_list[i].bResponseRequested == TRUE) &&
2477 (gResponderCtx.rr_list[i].bResponseSuppressed == FALSE) )
2478 {
2479 mDNSSendRR(
2480 &gResponderCtx.rr_list[i],
2481 mDNS_header.query_id.Val,
2482 (gResponderCtx.rr_list[i].type.Val == QTYPE_PTR)?
2483 (0x00):(0x80), // flush, except for PTR; for Conformance Test.
2484 count, // MAX_RR_NUM answers;
2485 (j==1)?TRUE:FALSE, // Is this the first RR?
2486 (j==count)?TRUE:FALSE // Is this the last RR?
2487 );
2488 j++;
2489 }
2490 }
2491  
2492 // end of MDNS_RESPONDER_LISTEN
2493 break;
2494  
2495 default:
2496 break;
2497 }
2498  
2499 return;
2500 }
2501  
2502  
2503 /***************************************************************
2504 Function:
2505 static void mDNSStateMachineReset(BOOL bResetProbeCount)
2506  
2507 Summary:
2508 Resets Multicast-DNS state-machine
2509  
2510 Description:
2511 This function is used to reset all global-variables related
2512 to Multicast-DNS state-machine.
2513  
2514 Precondition:
2515 None
2516  
2517 Parameters:
2518 None
2519  
2520 Returns:
2521 None
2522 **************************************************************/
2523  
2524  
2525 /***************************************************************
2526 Function:
2527 static void mDNSProbe(BYTE *name, MDNS_QTYPE q_type)
2528  
2529 Summary:
2530 Sends out Multicast-DNS probe packet with Host-name
2531  
2532 Description:
2533 This function is used to send out mDNS-probe packet for
2534 checking uniqueness of selected host-name. This function makes
2535 use of mDNSSendQuery to send out DNS-Query with chosen host-name
2536 to Multicast-Address.
2537  
2538 If any other machine is using same host-name, it responds with
2539 a reply and this host has to select different name.
2540  
2541 Precondition:
2542 None
2543  
2544 Parameters:
2545 name - Selected Host-Name
2546 Type - Query Type, which is of TYPE_A
2547  
2548 Returns:
2549 None
2550 **************************************************************/
2551  
2552  
2553 /***************************************************************
2554 Function:
2555 static void mDNSAnnounce(BYTE *name, MDNS_QTYPE q_type)
2556  
2557 Summary:
2558 Sends out Multicast-DNS Announce/Claim packet with Host-name
2559  
2560 Description:
2561 This function is used to send out mDNS-Announce packet for
2562 announcing the selected host-name. This function makes
2563 use of mDNSSendRR to send out DNS-Resource-Rec with chosen
2564 host-name to Multicast-Address.
2565  
2566 This announcement updates DNS-caches of neighbor machines on
2567 the local network.
2568  
2569 Precondition:
2570 None
2571  
2572 Parameters:
2573 name - Selected Host-Name
2574 Type - Query Type, which is of TYPE_A
2575  
2576 Returns:
2577 None
2578 **************************************************************/
2579  
2580  
2581 /***************************************************************
2582 Function:
2583 void mDNSInitialize(void)
2584  
2585 Summary:
2586 Initialization routine for Multicast-DNS (mDNS) state-machine.
2587  
2588 Description:
2589 This is initialization function for mDNS and invoked from init
2590 portion of Main-function.
2591  
2592 This initalizes the Multicast-DNS Responder (mDNSResponder) by
2593 opening up Multicast UDP socket on which mDNSResponder keeps on
2594 listening for incoming queries/responses from neighbor machines.
2595  
2596 The host-name chosen is initially seeded from DEFUALT_HOST_NAME
2597 defined in TCPIPConfig.h.
2598  
2599 Precondition:
2600 None
2601  
2602 Parameters:
2603 None
2604  
2605 Returns:
2606 None
2607 **************************************************************/
2608 void mDNSFillHostRecord(void)
2609 {
2610 BYTE i;
2611  
2612 // Fill the type A resource record
2613 gResponderCtx.rr_list[QTYPE_A_INDEX].name = gHostCtx.szHostName;
2614 gResponderCtx.rr_list[QTYPE_A_INDEX].type.Val = QTYPE_A;
2615 // CLASS???
2616 gResponderCtx.rr_list[QTYPE_A_INDEX].ttl.Val = RESOURCE_RECORD_TTL_VAL;
2617  
2618 gResponderCtx.rr_list[QTYPE_A_INDEX].rdlength.Val = 4u; // 4-byte for IP address
2619  
2620 for (i=0; i<=3; i++)
2621 gResponderCtx.rr_list[QTYPE_A_INDEX].ip.v[i] = AppConfig.MyIPAddr.v[i];
2622  
2623 gResponderCtx.rr_list[QTYPE_A_INDEX].valid = 1;
2624 gResponderCtx.rr_list[QTYPE_A_INDEX].pOwnerCtx = (mDNSProcessCtx_common *) &gHostCtx;
2625 }
2626  
2627 MDNSD_ERR_CODE mDNSHostRegister(const char *host_name)
2628 {
2629 if (host_name != NULL)
2630 {
2631 STRCPY_LOCAL(gHostCtx.szUserChosenHostName, (BYTE *) host_name);
2632 }
2633 else
2634 {
2635 #ifdef MY_DEFAULT_HOST_NAME
2636 STRCPY_LOCAL(gHostCtx.szUserChosenHostName, (BYTE *) MY_DEFAULT_HOST_NAME);
2637 #else
2638 STRCPY_LOCAL(gHostCtx.szUserChosenHostName, (BYTE *) "MyHost");
2639 #endif
2640 }
2641  
2642 STRCPY_LOCAL(gHostCtx.szHostName, gHostCtx.szUserChosenHostName);
2643 STRCPY_LOCAL(gHostCtx.szHostName+STRLEN_LOCAL(gHostCtx.szHostName), (BYTE *) ".");
2644 STRCPY_LOCAL(gHostCtx.szHostName+STRLEN_LOCAL(gHostCtx.szHostName), (BYTE *) CONST_STR_local);
2645  
2646 mDNSResetCounters((mDNSProcessCtx_common *) &gHostCtx, TRUE);
2647 gHostCtx.common.type = MDNS_CTX_TYPE_HOST;
2648 gHostCtx.common.state = MDNS_STATE_INIT;
2649 gHostCtx.common.nInstanceId = 0;
2650  
2651 mDNSFillHostRecord();
2652 gResponderCtx.bLastMsgIsIncomplete = FALSE;
2653  
2654 gHostCtx.common.state = MDNS_STATE_INIT;
2655  
2656 return MDNSD_SUCCESS;
2657 }
2658  
2659 void mDNSInitialize(const char *szHostName)
2660 {
2661 gResponderCtx.query_id.Val = 0;
2662 gResponderCtx.prev_ipaddr.Val = AppConfig.MyIPAddr.Val;
2663  
2664 /* Initial Host-Name is seeded from DEFUALT_HOST_NAME
2665 * configured in TCPIPConfig.h. Later on if a name-conflict
2666 * is detected it'll be automatically renamed with a
2667 * numerical-label extenstion */
2668  
2669 if ( szHostName != NULL )
2670 {
2671 mDNSHostRegister(szHostName);
2672 }
2673 else
2674 {
2675 #ifdef MY_DEFAULT_HOST_NAME
2676 mDNSHostRegister((const char *) MY_DEFAULT_HOST_NAME); // TODO: pick it up from names stored in EEPROM
2677 #else
2678 mDNSHostRegister((const char *) "ZCHOST"); // Hardcoded default.
2679 #endif
2680 }
2681  
2682 if(!MACIsLinked())
2683 {
2684 gHostCtx.common.state = MDNS_STATE_INTF_NOT_CONNECTED;
2685 return;
2686 }
2687  
2688 /* Initialize MDNS-Responder by opening up
2689 * Multicast-UDP-Socket */
2690 mDNSResponder();
2691  
2692 gHostCtx.common.state = MDNS_STATE_INIT;
2693  
2694 return;
2695 }
2696  
2697 /***************************************************************
2698 Function:
2699 void mDNSProcess(void)
2700  
2701 Summary:
2702 Main routine for Multicast-DNS (mDNS) state-machine.
2703  
2704 Description:
2705 This function is polled from Main-Routine & Designed to support
2706 co-operative multi-tasking. This has to retrun to Main, if we
2707 have to wait for longer durations.
2708  
2709 This is the main routine of mDNS state-machine. Based on current
2710 state and additional flag-bits the coresponding actions will be
2711 taken.
2712  
2713 Once the chosen host-name is finalized two gracious announcement
2714 packets with host-name will be sent out to update Neighbor DNS-
2715 -caches
2716  
2717 Precondition:
2718 mDNSInitialize should have been called before.
2719  
2720 Parameters:
2721 None
2722  
2723 Returns:
2724 None
2725 **************************************************************/
2726  
2727 void mDNSProcessInternal(mDNSProcessCtx_common *pCtx)
2728 {
2729 BOOL bIsHost = (((void *) pCtx) == ((void *) &gHostCtx));
2730  
2731 switch(pCtx->state)
2732 {
2733 case MDNS_STATE_HOME:
2734  
2735 DEBUG_MDNS_PRINT("MDNS_STATE_HOME: Wrong state \r\n");
2736 break;
2737  
2738 case MDNS_STATE_NOT_READY: // SD starts from here. SD only.
2739  
2740 if(gHostCtx.common.state != MDNS_STATE_DEFEND)
2741 {
2742 /* Multicast DNS is not ready */
2743 return;
2744 }
2745 else
2746 {
2747 /* Multicast DNS is ready now */
2748 pCtx->state = MDNS_STATE_INIT;
2749 pCtx->time_recorded = 0;
2750 }
2751  
2752 INFO_MDNS_PRINT("MDNS_STATE_NOT_READY --> MDNS_STATE_INIT \r\n");
2753 break;
2754  
2755 case MDNS_STATE_INTF_NOT_CONNECTED: // HOST starts from here. HOST only.
2756  
2757 if(!MACIsLinked())
2758 return;
2759  
2760 else
2761 {
2762 /* Interface is connected now */
2763 pCtx->state = MDNS_STATE_IPADDR_NOT_CONFIGURED;
2764 pCtx->time_recorded = 0;
2765 }
2766  
2767 // No break. Fall through
2768  
2769 case MDNS_STATE_IPADDR_NOT_CONFIGURED: // HOST only.
2770 {
2771 // Wait until IP addr is configured ...
2772 if (AppConfig.MyIPAddr.Val == 0)
2773 break;
2774  
2775 pCtx->state = MDNS_STATE_INIT;
2776 pCtx->time_recorded = 0;
2777  
2778 INFO_MDNS_PRINT("MDNS_STATE_IPADDR_NOT_CONFIGURED --> MDNS_STATE_INIT \r\n");
2779  
2780 // No break. Fall through
2781 }
2782  
2783 case MDNS_STATE_INIT:
2784 {
2785 /* DEBUG_MDNS_MESG(zeroconf_dbg_msg,"MDNS_STATE_INIT \r\n");
2786 DEBUG_MDNS_PRINT((char*)zeroconf_dbg_msg); */
2787  
2788 pCtx->bConflictSeenInLastProbe = FALSE;
2789  
2790 switch ( zgzc_wait_for(&(pCtx->random_delay), &(pCtx->event_time), &(pCtx->time_recorded)) )
2791 {
2792 case ZGZC_STARTED_WAITING:
2793  
2794 // Need to choose Random time between 0-MDNS_PROBE_WAIT msec
2795  
2796 pCtx->random_delay = (TICK)((rand()% (MDNS_PROBE_WAIT) * (TICK_SECOND/1000)));
2797 DEBUG_MDNS_MESG(zeroconf_dbg_msg,"MDNS_PROBE_WAIT Random Delay: %ld ticks\r\n",
2798 pCtx->random_delay);
2799 DEBUG_MDNS_PRINT((char*)zeroconf_dbg_msg);
2800  
2801 // Intentional fall-through
2802  
2803 case ZGZC_KEEP_WAITING:
2804  
2805 // Not Completed the delay proposed
2806 return;
2807 }
2808  
2809 // Completed the delay required
2810  
2811 DEBUG_MDNS_MESG(zeroconf_dbg_msg,"MDNS_PROBE_WAIT Random Delay: %ld ticks" \
2812 " Completed \r\n",
2813 pCtx->random_delay);
2814 DEBUG_MDNS_PRINT((char *)zeroconf_dbg_msg);
2815  
2816 // Clear all counters
2817 mDNSResetCounters(pCtx, TRUE);
2818  
2819 pCtx->state = MDNS_STATE_PROBE;
2820 INFO_MDNS_PRINT("MDNS_STATE_INIT --> MDNS_STATE_PROBE \r\n");
2821  
2822 // No break. Fall through
2823 }
2824  
2825 case MDNS_STATE_PROBE:
2826 case MDNS_STATE_ANNOUNCE:
2827 {
2828 //DEBUG_MDNS_PRINT("MDNS_STATE_PROBE \n");
2829 // or
2830 //DEBUG_MDNS_PRINT("MDNS_CLAIM \n");
2831  
2832 if(pCtx->bProbeConflictSeen)
2833 {
2834 pCtx->bConflictSeenInLastProbe = TRUE;
2835  
2836 INFO_MDNS_PRINT("Conflict detected. Will rename\r\n");
2837  
2838 /* Conflict with selected name */
2839 pCtx->state = MDNS_STATE_PROBE;
2840  
2841 // Do not reset nProbeConflictCount if in PROBE state
2842 mDNSResetCounters(
2843 pCtx,
2844 (pCtx->state == MDNS_STATE_PROBE)?FALSE:TRUE
2845 );
2846  
2847 if ( bIsHost )
2848 {
2849 // Rename host name
2850 mDNSRename(
2851 gHostCtx.szUserChosenHostName,
2852 ++gHostCtx.common.nInstanceId,
2853 (BYTE *) CONST_STR_local,
2854 gHostCtx.szHostName,
2855 MAX_HOST_NAME_SIZE);
2856  
2857 INFO_MDNS_MESG(zeroconf_dbg_msg,"New host name : %s \r\n",
2858 gHostCtx.szHostName);
2859 INFO_MDNS_PRINT(zeroconf_dbg_msg);
2860 }
2861 else
2862 {
2863 // Rename service instance name
2864 if(gSDCtx.sd_auto_rename)
2865 {
2866 mDNSRename(
2867 gSDCtx.srv_name,
2868 ++gSDCtx.common.nInstanceId,
2869 gSDCtx.srv_type,
2870 gSDCtx.sd_qualified_name,
2871 MAX_LABEL_SIZE);
2872  
2873 /* Reset Multicast-UDP socket */
2874 UDPClose(mDNS_socket);
2875 mDNS_socket = INVALID_UDP_SOCKET;
2876 mDNSResponder();
2877 }
2878 else
2879 {
2880 gSDCtx.service_registered = 0;
2881  
2882 gSDCtx.used = 0;
2883 if ( gSDCtx.sd_call_back != NULL)
2884 {
2885 gSDCtx.sd_call_back((char *)gSDCtx.srv_name,
2886 MDNSD_ERR_CONFLICT,
2887 gSDCtx.sd_context);
2888 }
2889 }
2890 }
2891 break;
2892 }
2893  
2894 SET_PROBE_ANNOUNCE_TIMER:
2895  
2896 switch ( zgzc_wait_for(&(pCtx->random_delay), &(pCtx->event_time), &(pCtx->time_recorded)) )
2897 {
2898 case ZGZC_STARTED_WAITING:
2899  
2900 if (pCtx->state == MDNS_STATE_PROBE)
2901 {
2902 if (((pCtx->nProbeCount >= MDNS_PROBE_NUM) && !pCtx->bConflictSeenInLastProbe) ||
2903 (pCtx->nProbeConflictCount >= MDNS_MAX_PROBE_CONFLICT_NUM))
2904 {
2905 /* Move onto Announce Step */
2906 pCtx->state = MDNS_STATE_ANNOUNCE;
2907 pCtx->bConflictSeenInLastProbe = FALSE;
2908  
2909 INFO_MDNS_PRINT("MDNS_STATE_PROBE --> MDNS_STATE_ANNOUNCE \r\n");
2910  
2911 //Shall we mDNSResetCounters(pCtx, TRUE)?
2912 return;
2913 }
2914 }
2915 else
2916 {
2917 // We are in MDNS_STATE_ANNOUNCE
2918  
2919 if (pCtx->nClaimCount >= MDNS_ANNOUNCE_NUM)
2920 {
2921 /* Finalize mDNS Host-name, Announced */
2922 pCtx->state = MDNS_STATE_DEFEND;
2923  
2924 if ( bIsHost )
2925 {
2926 // The rest of the MCHP system knows its name through
2927 // AppConfig.NetBIOSName, so update it here.
2928 STRCPY_LOCAL(AppConfig.NetBIOSName, gHostCtx.szHostName);
2929  
2930 INFO_MDNS_MESG(zeroconf_dbg_msg,"\r\n********* Taken Host-Name: %s ********* \r\n",
2931 gHostCtx.szHostName);
2932  
2933 INFO_MDNS_PRINT((char *)zeroconf_dbg_msg);
2934 INFO_MDNS_PRINT("MDNS_STATE_ANNOUNCE --> MDNS_STATE_DEFEND \r\n");
2935  
2936 DisplayHostName(gHostCtx.szHostName);
2937 DisplayIPValue(AppConfig.MyIPAddr);
2938 }
2939 else
2940 {
2941 #if defined(STACK_USE_UART)
2942 putrsUART((ROM char*)"\r\nZeroConf: Service = ");
2943 putrsUART((ROM char*)gSDCtx.sd_qualified_name);
2944 putrsUART((ROM char*)"\r\n");
2945 #endif
2946  
2947 INFO_MDNS_MESG(zeroconf_dbg_msg,"\r\n******** Taken Service-Name: %s ********\r\n",
2948 gSDCtx.sd_qualified_name);
2949  
2950 INFO_MDNS_PRINT((char *)zeroconf_dbg_msg);
2951 INFO_MDNS_PRINT("MDNS_STATE_ANNOUNCE --> MDNS_STATE_DEFEND \r\n");
2952  
2953 mDNSSendRR(&gResponderCtx.rr_list[QTYPE_PTR_INDEX],
2954 0,
2955 0x00,
2956 1,
2957 TRUE,TRUE);
2958  
2959 gSDCtx.sd_service_advertised = 1;
2960 if (gSDCtx.sd_call_back != NULL)
2961 {
2962 gSDCtx.sd_call_back((char *)gSDCtx.srv_name, MDNSD_SUCCESS, gSDCtx.sd_context);
2963 }
2964 }
2965  
2966 mDNSResetCounters(pCtx, TRUE);
2967  
2968 return;
2969 }
2970 }
2971  
2972 if (pCtx->state == MDNS_STATE_PROBE)
2973 {
2974 // Send out Probe packet
2975 mDNSProbe(pCtx);
2976  
2977 pCtx->nProbeCount++;
2978 pCtx->bConflictSeenInLastProbe = FALSE;
2979  
2980 /* Need to set timeout for MDNS_PROBE_INTERVAL msec */
2981 if (pCtx->nProbeConflictCount < 9) // less-than-10 is required to pass Bonjour Conformance test.
2982 {
2983 pCtx->random_delay = (TICK)( MDNS_PROBE_INTERVAL * (TICK_SECOND/1000));
2984 }
2985 else
2986 {
2987 pCtx->random_delay = (TICK) (TICKS_PER_SECOND);
2988 }
2989  
2990 DEBUG_MDNS_MESG(
2991 zeroconf_dbg_msg,"MDNS_PROBE_INTERVAL Delay: %ld ticks (%d)\r\n",
2992 pCtx->random_delay, pCtx->nProbeCount);
2993 DEBUG_MDNS_PRINT((char *)zeroconf_dbg_msg);
2994  
2995 return;
2996 }
2997  
2998 // We are in MDNS_STATE_ANNOUNCE
2999  
3000 /* Announce Name chosen on Local Network */
3001  
3002 mDNSAnnounce(&gResponderCtx.rr_list[(bIsHost?QTYPE_A_INDEX:QTYPE_SRV_INDEX)]);
3003  
3004 pCtx->nClaimCount++;
3005  
3006 // Need to set timeout: ANNOUNCE_WAIT or INTERVAL
3007  
3008 if (pCtx->nClaimCount == 1)
3009 {
3010 /* Setup a delay of MDNS_ANNOUNCE_WAIT before announcing */
3011  
3012 /* Need to wait for time MDNS_ANNOUNCE_WAIT msec */
3013 pCtx->random_delay = (TICK) ( MDNS_ANNOUNCE_WAIT * (TICK_SECOND/1000));
3014 }
3015 else
3016 {
3017 pCtx->random_delay = (TICK)(MDNS_ANNOUNCE_INTERVAL * (TICK_SECOND/1000));
3018 }
3019  
3020 // Intenional fall-through
3021  
3022 case ZGZC_KEEP_WAITING:
3023  
3024 // Not Completed the delay proposed
3025 return;
3026 }
3027  
3028 // Completed the delay required
3029  
3030 DEBUG_MDNS_MESG(zeroconf_dbg_msg,"Probe/Announce delay completed : %ld ticks\r\n",
3031 random_delay);
3032 DEBUG_MDNS_PRINT((char *)zeroconf_dbg_msg);
3033  
3034 /* Set the timer for next announce */
3035 goto SET_PROBE_ANNOUNCE_TIMER;
3036 }
3037  
3038 case MDNS_STATE_DEFEND:
3039 {
3040 //DEBUG_MDNS_PRINT("MDNS_STATE_DEFEND \n");
3041 /* On detection of Conflict Move back to PROBE step */
3042  
3043 if(pCtx->bLateConflictSeen)
3044 {
3045 /* Clear the Flag */
3046 pCtx->bLateConflictSeen = FALSE;
3047 INFO_MDNS_PRINT("CONFLICT DETECTED !!! \r\n");
3048 INFO_MDNS_PRINT("Re-probing the Host-Name because of Conflict \r\n");
3049 pCtx->state = MDNS_STATE_INIT;
3050 pCtx->time_recorded = 0;
3051  
3052 INFO_MDNS_PRINT("MDNS_STATE_DEFEND --> MDNS_STATE_INIT \r\n");
3053 }
3054 else
3055 return;
3056 }
3057  
3058 default:
3059 break;
3060 }
3061 }
3062  
3063 void mDNSProcess(void)
3064 {
3065 if(!MACIsLinked())
3066 {
3067 gHostCtx.common.state = MDNS_STATE_INTF_NOT_CONNECTED;
3068 return;
3069 }
3070 if(AppConfig.MyIPAddr.Val == 0x00)
3071 {
3072 return;
3073 }
3074 else if (AppConfig.MyIPAddr.Val != gResponderCtx.prev_ipaddr.Val) {
3075 // IP address has been changed outside of Zeroconf.
3076 // Such change could be due to static IP assignment, or
3077 // a new dynamic IP lease.
3078 // Need to restart state-machine
3079  
3080 INFO_MDNS_PRINT("IP-Address change is detected \r\n");
3081 gResponderCtx.prev_ipaddr.Val = AppConfig.MyIPAddr.Val;
3082 gHostCtx.common.state = MDNS_STATE_IPADDR_NOT_CONFIGURED;
3083  
3084 // Do not change the nInstanceId.
3085 // Change of IP does not imply prior name conflicts can be avoided.
3086 // Change of host name does.
3087  
3088 mDNSFillHostRecord();
3089 }
3090  
3091 /* Poll mDNSResponder to allow it to check for
3092 * incoming mDNS Quries/Responses */
3093  
3094 mDNSResponder();
3095  
3096 if(gSDCtx.service_registered)
3097 {
3098 // Application has registered some services.
3099 // We now need to start the service probe/announce/defend process.
3100  
3101 if (gHostCtx.common.state != MDNS_STATE_DEFEND)
3102 {
3103 gSDCtx.common.state = MDNS_STATE_NOT_READY;
3104 }
3105 else
3106 {
3107 mDNSProcessInternal((mDNSProcessCtx_common *) &gSDCtx);
3108 }
3109 }
3110  
3111 mDNSProcessInternal((mDNSProcessCtx_common *) &gHostCtx);
3112 }
3113  
3114 /**
3115 * Zeroconf uses 224.0.0.251
3116 * => E0.00.00.FB
3117 * => 1110_0000.0000_0000.0000_0000.1111_1011
3118 * Lower 23 bits are mapped to the multicast MAC address, prepended by 01:00:5E.
3119 * This becomes 0000_0001:0000_0000:0101_1110:0000_0000:0000_0000:1111_1011
3120 * => 01:00:5E:00:00:FB
3121 */
3122 MDNSD_ERR_CODE
3123 mDNSMulticastFilterRegister(void)
3124 {
3125 // Register an RX MAC fitler for the IP multicast group 224.0.0.251,
3126 // which is mapped to 01:00:5E:00:00:FB
3127  
3128 UINT8 mcast_addr[6] = {0x01, 0x00, 0x5E, 0x00, 0x00, 0xFB};
3129  
3130 WF_SetMultiCastFilter(WF_MULTICAST_FILTER_1, mcast_addr);
3131  
3132 return MDNSD_SUCCESS;
3133 }
3134  
3135 //#if defined(DEBUG_MDNS) || defined(INFO_MDNS)
3136 void mDNSDumpInfo(void)
3137 {
3138 BYTE tmp[8];
3139  
3140 putsUART(" Host registered: "); putsUART(gHostCtx.szUserChosenHostName); putsUART("\r\n");
3141 putsUART(" qualified: "); putsUART(gHostCtx.szHostName); putsUART("\r\n");
3142 putsUART("Service registered: "); putsUART(gSDCtx.srv_name); putsUART("\r\n");
3143 putsUART(" qualified: "); putsUART(gSDCtx.sd_qualified_name); putsUART("\r\n");
3144 sprintf((char *) tmp, "%d", gSDCtx.sd_port);
3145 putsUART(" port: "); putsUART(tmp); putsUART("\r\n");
3146 putsUART(" TXT registered: "); putsUART(gSDCtx.sd_txt_rec); putsUART("\r\n");
3147 }
3148  
3149 //#endif
3150  
3151 #endif //#if defined(STACK_USE_ZEROCONF_MDNS_SD)
3152  
3153  
3154  
3155  
3156  
{BLAME END}
{FOOTER START}

Powered by WebSVN v2.8.3