mDNS
Embed:
(wiki syntax)
Show/hide line numbers
mDNSResponder.cpp
00001 /* 00002 ---------------------------------------------------- 00003 Made by JB RYU, KOR - 2015 00004 00005 origin - C / mdns-sd on CONTIKI-ipv6(uIP) I'd made 00006 00007 now - mdns-sd on MBED-LWIP-ipv4 00008 ---------------------------------------------------- 00009 More progressed things than others : 00010 { 00011 Parsing multi-records (OK), 00012 Check duplicated host and avoid (OK) 00013 } 00014 00015 TODO : (Actully these are not necessary for my prj) 00016 { 00017 register multiple service, 00018 managing records-caches 00019 } 00020 ---------------------------------------------------- 00021 Notes : 00022 srv-instance-name = host-name 00023 SEP-<rand 2hex><IP 2hex> 00024 ---------------------------------------------------- 00025 */ 00026 00027 00028 #include "lwip/opt.h" 00029 #include "mbed.h" 00030 #include "EthernetInterface.h" 00031 #include <cstring> 00032 #if LWIP_DNS /* don't build if not configured for use in lwipopts.h */ 00033 00034 #include "mDNSResponder.h" 00035 #include "dns-sd.h" 00036 00037 #define MDNS_DBG 1 00038 #if (MDNS_DBG > 0) 00039 #define MDBG(x...) printf(x) 00040 #else 00041 #define MDBG(x...) 00042 #endif 00043 00044 mDNSResponder::mDNSResponder(EthernetInterface interface) : IP_str(NULL) 00045 { 00046 mdns_sock.open(&interface); 00047 } 00048 00049 /* initialize static instance */ 00050 char mDNSResponder::query_buf[1500] = 00051 { 00052 0, 00053 }; 00054 00055 MY_SD_DOMAINS mDNSResponder::SD_domains = 00056 { 00057 .numbers = N_CONTIKI_SERVICES, 00058 .elements = 00059 { 00060 { 00061 .inst_len = 5, 00062 .instance = {'s','p','y','o','s'}, 00063 .serv_len = 12, 00064 .service = {'_','s','m','a','r','t','e','n','e','r','g','y',}, 00065 .trl_len = 4, 00066 .trl = {'_','t','c','p'}, 00067 .domain_len = 5, 00068 .domain = {'l','o','c','a','l'}, 00069 .txt = 00070 { 00071 .len_txtvers = 9, 00072 .txtvers = {'t','x','t','v','e','r','s','=','1'}, 00073 .len_dcap = 10, 00074 .dcap = {'d','c','a','p','=','/','d','c','a','p'}, 00075 .len_path = 9, 00076 .path = {'p','a','t','h','=','/','u','p','t'}, 00077 .len_https = 9, 00078 .https = {'h','t','t','p','s','=','4','4','3'}, 00079 .len_level = 9, 00080 .level = {'l','e','v','e','l','=','-','S','0'}, 00081 } 00082 }, 00083 }, 00084 }; 00085 00086 struct dns_hdr mDNSResponder::SD_res_hdr = 00087 { 00088 .id = 0x0000, 00089 .flags1 = DNS_FLAG1_RESPONSE | DNS_FLAG1_AUTHORATIVE, 00090 .flags2 = 0, 00091 .numquestions = 0, 00092 .numanswers = htons(1), 00093 .numauthrr = 0, 00094 .numextrarr = 0, 00095 }; 00096 00097 QR_MAP mDNSResponder::g_queries = {0,}; 00098 00099 /* end of initialize static instance */ 00100 00101 mDNSResponder::~mDNSResponder() 00102 { 00103 close(); 00104 } 00105 00106 void mDNSResponder:: 00107 register_service(char* number) 00108 { 00109 memcpy(&SD_domains.elements[0].instance[4], number, 4); 00110 } 00111 00112 void mDNSResponder:: 00113 query_domain(void) 00114 { 00115 volatile uint8_t i; 00116 struct dns_hdr* hdr; 00117 struct dns_question* question; 00118 uint8_t *query; 00119 00120 MDBG("start probe duplicate domain\n\r"); 00121 00122 hdr = (struct dns_hdr *)query_buf; 00123 00124 memset(hdr, 0, sizeof(struct dns_hdr)); 00125 00126 hdr->id = 0; 00127 hdr->flags1 = DNS_FLAG1_RD; 00128 hdr->numquestions = htons(1); 00129 00130 query = (unsigned char *)query_buf + sizeof(*hdr); 00131 00132 memcpy(query, &SD_domains.elements[0].inst_len, 00133 SD_domains.elements[0].inst_len+1); 00134 query += SD_domains.elements[0].inst_len+1; 00135 00136 memcpy(query, &SD_domains.elements[0].domain_len, 00137 SD_domains.elements[0].domain_len+1); 00138 query += SD_domains.elements[0].domain_len+1; 00139 00140 *query = 0x00; 00141 query++; 00142 00143 question = (struct dns_question*)query; 00144 question->type = htons(DNS_TYPE_ANY); 00145 question->obj = htons(DNS_CLASS_IN); 00146 00147 query += 4; 00148 00149 MDBG("send probe query(%d)\n\r", 00150 (uint16_t)((uint32_t)query - (uint32_t)query_buf)); 00151 00152 mdns_sock.sendto(send_endpt, query_buf, 00153 (query - (uint8_t *) query_buf)); 00154 } 00155 00156 void mDNSResponder::announce(const char* ip) 00157 { 00158 send_endpt.set_ip_address(MCAST); 00159 send_endpt.set_port(MDNS_PORT); 00160 00161 mdns_sock.bind(MDNS_PORT); 00162 if (mdns_sock.join_multicast_group(send_endpt) != 0) 00163 { 00164 printf("Error joining the multicast group\n"); 00165 while(true); 00166 } 00167 00168 IP_str = new char[16]; 00169 strcpy(IP_str, ip); 00170 00171 IPstringToByte(IP_str); 00172 00173 char instance_number[4]; 00174 00175 register_service(instance_number); 00176 00177 query_domain(); 00178 } 00179 00180 void mDNSResponder::close() 00181 { 00182 mdns_sock.close(); 00183 } 00184 00185 void mDNSResponder::IPstringToByte(char* IPstr) 00186 { 00187 char ip1[4] = {0,}; char ip2[4] = {0,}; 00188 char ip3[4] = {0,}; char ip4[4] = {0,}; 00189 char* p; 00190 char* p_dot; 00191 00192 p_dot = strstr(IPstr, "."); 00193 memcpy(ip1, IPstr, p_dot - IPstr); 00194 IP_byte[0] = (uint8_t)atoi((const char*)ip1); 00195 00196 p = p_dot + 1; 00197 p_dot = strstr(p, "."); 00198 memcpy(ip2, p, p_dot - p); 00199 IP_byte[1] = (uint8_t)atoi((const char*)ip2); 00200 00201 p = p_dot + 1; 00202 p_dot = strstr(p, "."); 00203 memcpy(ip3, p, p_dot - p); 00204 IP_byte[2] = (uint8_t)atoi((const char*)ip3); 00205 00206 p = p_dot + 1; 00207 memcpy(ip4, p, 3); 00208 IP_byte[3] = (uint8_t)atoi((const char*)ip4); 00209 } 00210 00211 char* mDNSResponder:: 00212 skip_name(char* query) 00213 { 00214 unsigned char n; 00215 00216 do 00217 { 00218 n = *query; 00219 if(n & 0xc0) 00220 { 00221 ++query; 00222 break; 00223 } 00224 00225 ++query; 00226 00227 while(n > 0) 00228 { 00229 ++query; 00230 --n; 00231 }; 00232 } while(*query != 0); 00233 00234 return query + 1; 00235 } 00236 00237 char* mDNSResponder:: 00238 decode_name(char* query, char* packet) 00239 { 00240 char c = 0xff; 00241 static char dest[MAX_DOMAIN_LEN]; 00242 int len = 0; 00243 00244 memset(dest, 0, MAX_DOMAIN_LEN); 00245 00246 MDBG("\n\r"); 00247 while((len < MAX_DOMAIN_LEN) && (c != 0x00)) 00248 { 00249 c = *query; 00250 00251 while (c == 0xc0) 00252 { 00253 MDBG("%s : read offset\n\r", __FUNCTION__); 00254 query++; 00255 query = (char*)((uint32_t)packet + *query); 00256 c = *query; 00257 } 00258 00259 memset(&dest[len], c, 1); 00260 00261 query++; 00262 len++; 00263 } 00264 00265 MDBG("\n%s : %s\n\r", __FUNCTION__, dest); 00266 return dest; 00267 } 00268 00269 void mDNSResponder:: 00270 send_dns_ans(struct dns_hdr* hdr) 00271 { 00272 int i = 0; 00273 uint8_t* ptr; 00274 uint32_t off_inst = 0; 00275 uint32_t off_serv = 0; 00276 uint32_t off_domain = 0; 00277 PTR_ANS* ptr_ans; 00278 SRV_ANS* srv_ans; 00279 struct dns_answer* A_ans; 00280 TXT_ANS* txt_ans; 00281 int numbers = g_queries.numbers; 00282 00283 uint8_t ans_mask = DNS_TYPE_ANY; //later, for addtional ans 00284 00285 memcpy(hdr, &SD_res_hdr, sizeof(struct dns_hdr)); 00286 hdr->numanswers = htons(numbers); 00287 ptr = (uint8_t*)hdr + sizeof(struct dns_hdr); 00288 00289 while (numbers--) 00290 { 00291 switch (g_queries.reqs[i]) 00292 { 00293 case DNS_TYPE_PTR : 00294 { 00295 ans_mask = ans_mask ^ DNS_TYPE_PTR; 00296 if (off_serv == 0) 00297 { 00298 off_serv = (uint32_t)ptr - (uint32_t)hdr; 00299 00300 memcpy(ptr, &SD_domains.elements[0].serv_len, 00301 SD_domains.elements[0].serv_len + 1); 00302 ptr += SD_domains.elements[0].serv_len + 1; 00303 00304 memcpy(ptr, &SD_domains.elements[0].trl_len, 00305 SD_domains.elements[0].trl_len + 1); 00306 ptr += SD_domains.elements[0].trl_len + 1; 00307 00308 memcpy(ptr, &SD_domains.elements[0].domain_len, 00309 SD_domains.elements[0].domain_len + 1); 00310 ptr += SD_domains.elements[0].domain_len + 1; 00311 *ptr = 0x00; 00312 ptr++; 00313 } 00314 else 00315 { 00316 *ptr = 0xc0; 00317 ptr++; 00318 *ptr = (uint8_t)off_serv; 00319 ptr++; 00320 } 00321 00322 ptr_ans = (PTR_ANS*)ptr; 00323 00324 ptr_ans->type = htons(DNS_TYPE_PTR); 00325 ptr_ans->obj = htons(DNS_CLASS_IN); 00326 ptr_ans->ttl[0] = 0; 00327 ptr_ans->ttl[1] = htons(120); 00328 00329 int instance_len = SD_domains.elements[0].inst_len; 00330 00331 ptr = (uint8_t*)ptr_ans->name; 00332 00333 if (off_inst == 0) 00334 { 00335 off_inst = (uint32_t)ptr - (uint32_t)hdr; 00336 00337 ptr_ans->len = htons(instance_len + 3); 00338 00339 memcpy(ptr_ans->name, 00340 &SD_domains.elements[0].inst_len, 00341 1 + SD_domains.elements[0].inst_len); 00342 00343 ptr += instance_len + 1; 00344 *ptr = 0xc0; 00345 ptr++; 00346 *ptr = (uint8_t)off_serv; 00347 ptr++; 00348 } 00349 else 00350 { 00351 ptr_ans->len = htons(2); 00352 00353 *ptr = 0xc0; 00354 ptr++; 00355 *ptr = (uint8_t)off_inst; 00356 ptr++; 00357 } 00358 break; 00359 } 00360 case DNS_TYPE_SRV : 00361 ans_mask = ans_mask ^ DNS_TYPE_SRV; 00362 if (off_inst == 0) 00363 { 00364 off_inst = (uint32_t)ptr - (uint32_t)hdr; 00365 00366 memcpy(ptr, 00367 &SD_domains.elements[0].inst_len, 00368 1 + SD_domains.elements[0].inst_len); 00369 00370 ptr += 1 + SD_domains.elements[0].inst_len; 00371 00372 if (off_serv == 0) 00373 { 00374 off_serv = (uint32_t)ptr - (uint32_t)hdr; 00375 00376 memcpy(ptr, &SD_domains.elements[0].serv_len, 00377 SD_domains.elements[0].serv_len + 1); 00378 ptr += SD_domains.elements[0].serv_len + 1; 00379 00380 memcpy(ptr, &SD_domains.elements[0].trl_len, 00381 SD_domains.elements[0].trl_len + 1); 00382 ptr += SD_domains.elements[0].trl_len + 1; 00383 00384 memcpy(ptr, &SD_domains.elements[0].domain_len, 00385 SD_domains.elements[0].domain_len + 1); 00386 ptr += SD_domains.elements[0].domain_len + 1; 00387 00388 *ptr = 0x00; 00389 ptr++; 00390 } 00391 else 00392 { 00393 *ptr = 0xc0; 00394 ptr++; 00395 *ptr = (uint8_t)off_serv; 00396 ptr++; 00397 } 00398 } 00399 else 00400 { 00401 *ptr = 0xc0; 00402 ptr++; 00403 *ptr = (uint8_t)off_inst; 00404 ptr++; 00405 } 00406 00407 srv_ans = (SRV_ANS*)(ptr); 00408 srv_ans->type = htons(DNS_TYPE_SRV); 00409 srv_ans->obj = htons(DNS_CLASS_IN | DNS_CASH_FLUSH); 00410 srv_ans->ttl[0] = 0; 00411 srv_ans->ttl[1] = htons(120); 00412 srv_ans->pri = 0; 00413 srv_ans->wei = 0; 00414 srv_ans->port = htons(8080); 00415 ptr = (uint8_t*)srv_ans->name; 00416 00417 if (off_domain == 0) 00418 { 00419 off_domain = (uint32_t)ptr - (uint32_t)hdr; 00420 00421 memcpy(ptr, 00422 &SD_domains.elements[0].inst_len, 00423 1 + SD_domains.elements[0].inst_len); 00424 00425 ptr += 1 + SD_domains.elements[0].inst_len; 00426 00427 memcpy(ptr, 00428 &SD_domains.elements[0].domain_len, 00429 1 + SD_domains.elements[0].domain_len); 00430 00431 ptr+= 1 + SD_domains.elements[0].domain_len; 00432 *ptr = 0x00; 00433 ptr++; 00434 } 00435 else 00436 { 00437 *ptr = 0xc0; 00438 ptr++; 00439 *ptr = (uint8_t)off_domain; 00440 ptr++; 00441 } 00442 srv_ans->len = 00443 htons((uint16_t)((uint32_t)ptr - (uint32_t)&srv_ans->pri)); 00444 00445 break; 00446 case DNS_TYPE_TXT : 00447 ans_mask = ans_mask ^ DNS_TYPE_TXT; 00448 if (off_inst == 0) 00449 { 00450 off_inst = (uint32_t)ptr - (uint32_t)hdr; 00451 00452 memcpy(ptr, 00453 &SD_domains.elements[0].inst_len, 00454 1 + SD_domains.elements[0].inst_len); 00455 00456 ptr += 1 + SD_domains.elements[0].inst_len; 00457 00458 if (off_serv == 0) 00459 { 00460 off_serv = (uint32_t)ptr - (uint32_t)hdr; 00461 00462 memcpy(ptr, &SD_domains.elements[0].serv_len, 00463 SD_domains.elements[0].serv_len + 1); 00464 ptr += SD_domains.elements[0].serv_len + 1; 00465 00466 memcpy(ptr, &SD_domains.elements[0].trl_len, 00467 SD_domains.elements[0].trl_len + 1); 00468 ptr += SD_domains.elements[0].trl_len + 1; 00469 00470 memcpy(ptr, &SD_domains.elements[0].domain_len, 00471 SD_domains.elements[0].domain_len + 1); 00472 ptr += SD_domains.elements[0].domain_len + 1; 00473 00474 *ptr = 0x00; 00475 ptr++; 00476 } 00477 else 00478 { 00479 *ptr = 0xc0; 00480 ptr++; 00481 *ptr = (uint8_t)off_serv; 00482 ptr++; 00483 } 00484 } 00485 else 00486 { 00487 *ptr = 0xc0; 00488 ptr++; 00489 *ptr = (uint8_t)off_inst; 00490 ptr++; 00491 } 00492 00493 txt_ans = (TXT_ANS*)(ptr); 00494 txt_ans->type = htons(DNS_TYPE_TXT); 00495 txt_ans->obj = htons(DNS_CLASS_IN | DNS_CASH_FLUSH); 00496 txt_ans->ttl[0] = 0; 00497 txt_ans->ttl[1] = htons(120); 00498 ptr = (uint8_t*)txt_ans->txt; 00499 00500 memcpy(ptr, 00501 &SD_domains.elements[0].txt.len_txtvers, 00502 1 + SD_domains.elements[0].txt.len_txtvers); 00503 ptr += 1 + SD_domains.elements[0].txt.len_txtvers; 00504 00505 memcpy(ptr, 00506 &SD_domains.elements[0].txt.len_dcap, 00507 1 + SD_domains.elements[0].txt.len_dcap); 00508 ptr += 1 + SD_domains.elements[0].txt.len_dcap; 00509 00510 memcpy(ptr, 00511 &SD_domains.elements[0].txt.len_path, 00512 1 + SD_domains.elements[0].txt.len_path); 00513 ptr += 1 + SD_domains.elements[0].txt.len_path; 00514 00515 memcpy(ptr, 00516 &SD_domains.elements[0].txt.len_https, 00517 1 + SD_domains.elements[0].txt.len_https); 00518 ptr += 1 + SD_domains.elements[0].txt.len_https; 00519 00520 memcpy(ptr, 00521 &SD_domains.elements[0].txt.len_level, 00522 1 + SD_domains.elements[0].txt.len_level); 00523 ptr += 1 + SD_domains.elements[0].txt.len_level; 00524 00525 txt_ans->len = 00526 htons((uint16_t)((uint32_t)ptr - (uint32_t)txt_ans->txt)); 00527 00528 break; 00529 case DNS_TYPE_A : 00530 ans_mask = ans_mask ^ DNS_TYPE_A; 00531 if (off_domain == 0) 00532 { 00533 off_domain = (uint32_t)ptr - (uint32_t)hdr; 00534 00535 memcpy(ptr, 00536 &SD_domains.elements[0].inst_len, 00537 1 + SD_domains.elements[0].inst_len); 00538 00539 ptr += 1 + SD_domains.elements[0].inst_len; 00540 00541 memcpy(ptr, 00542 &SD_domains.elements[0].domain_len, 00543 1 + SD_domains.elements[0].domain_len); 00544 00545 ptr += 1 + SD_domains.elements[0].domain_len; 00546 *ptr = 0x00; 00547 ptr++; 00548 } 00549 else 00550 { 00551 *ptr = 0xc0; 00552 ptr++; 00553 *ptr = (uint8_t)off_domain; 00554 ptr++; 00555 } 00556 00557 A_ans = (struct dns_answer*)(ptr); 00558 00559 A_ans->type = htons(DNS_TYPE_A); 00560 A_ans->obj = htons(DNS_CLASS_IN | DNS_CASH_FLUSH); 00561 A_ans->ttl[0] = 0; 00562 A_ans->ttl[1] = htons(120); 00563 A_ans->len = htons(4); 00564 memcpy((uint8_t*)A_ans->ipaddr, 00565 IP_byte, 4); 00566 00567 ptr = (uint8_t*)&A_ans->ipaddr + 4; 00568 break; 00569 00570 default : 00571 break; 00572 } 00573 i++; 00574 } 00575 00576 int send_len = ptr - (uint8_t*)hdr; 00577 00578 mdns_sock.sendto(send_endpt, (char*)hdr, send_len); 00579 } 00580 00581 void mDNSResponder:: 00582 MDNS_process() 00583 { 00584 char rcv_buf[ 1500 ]; 00585 uint8_t nquestions, nanswers; 00586 struct dns_hdr* hdr; 00587 char *queryptr; 00588 uint8_t is_request; 00589 00590 MDBG("MDNS Process\n\r"); 00591 00592 while(mdns_sock.recvfrom(&rcv_endpt, 00593 rcv_buf, sizeof(rcv_buf)) != 0) 00594 { 00595 hdr = (struct dns_hdr *)rcv_buf; 00596 queryptr = (char *)hdr + sizeof(*hdr); 00597 is_request = ((hdr->flags1 & ~1) == 0) && (hdr->flags2 == 0); 00598 nquestions = (uint8_t) ntohs(hdr->numquestions); 00599 nanswers = (uint8_t) ntohs(hdr->numanswers); 00600 00601 MDBG("resolver: flags1=0x%02X flags2=0x%02X nquestions=%d,\ 00602 nanswers=%d, nauthrr=%d, nextrarr=%d\n\r",\ 00603 hdr->flags1, hdr->flags2, (uint8_t) nquestions, (uint8_t) nanswers,\ 00604 (uint8_t) ntohs(hdr->numauthrr),\ 00605 (uint8_t) ntohs(hdr->numextrarr)); 00606 00607 if(hdr->id != 0) 00608 { 00609 return; 00610 } 00611 00612 /** ANSWER HANDLING SECTION ************************************************/ 00613 struct dns_question* question = (struct dns_question *)skip_name(queryptr); 00614 00615 uint16_t type; 00616 00617 if (is_request) 00618 { 00619 char* name; 00620 00621 memset(&g_queries, 0, sizeof(QR_MAP)); 00622 00623 while (nquestions--) 00624 { 00625 type = ntohs(question->type); 00626 name = decode_name(queryptr, (char*)hdr); 00627 00628 if ((type & DNS_TYPE_PTR) == DNS_TYPE_PTR) 00629 { 00630 if (strncmp((const char*)name, 00631 (const char*)&SD_domains.elements[0].serv_len, 00632 SD_domains.elements[0].serv_len + 1) == 0) 00633 { 00634 MDBG("recv PTR request\n\r"); 00635 g_queries.reqs[g_queries.numbers] = DNS_TYPE_PTR; 00636 g_queries.numbers++; 00637 } 00638 } 00639 00640 if ((type & DNS_TYPE_SRV) == DNS_TYPE_SRV) 00641 { 00642 if ((strncmp((const char*)name, 00643 (const char*)&SD_domains.elements[0].inst_len, 00644 SD_domains.elements[0].inst_len + 1) == 0) && 00645 (strncmp((const char*)(name + SD_domains.elements[0].inst_len+1), 00646 (const char*)&SD_domains.elements[0].serv_len, 00647 SD_domains.elements[0].serv_len+1) == 0)) 00648 { 00649 MDBG("recv SRV request\n"); 00650 g_queries.reqs[g_queries.numbers] = DNS_TYPE_SRV; 00651 g_queries.numbers++; 00652 } 00653 } 00654 00655 if ((type & DNS_TYPE_TXT) == DNS_TYPE_TXT) 00656 { 00657 if ((strncmp((const char*)name, 00658 (const char*)&SD_domains.elements[0].inst_len, 00659 SD_domains.elements[0].inst_len + 1) == 0) && 00660 (strncmp((const char*)(name + SD_domains.elements[0].inst_len+1), 00661 (const char*)&SD_domains.elements[0].serv_len, 00662 SD_domains.elements[0].serv_len+1) == 0)) 00663 { 00664 MDBG("recv TXT request\n"); 00665 g_queries.reqs[g_queries.numbers] = DNS_TYPE_TXT; 00666 g_queries.numbers++; 00667 } 00668 } 00669 00670 if ((type & DNS_TYPE_A) == DNS_TYPE_A) 00671 { 00672 if ((strncmp((const char*)name, 00673 (const char*)&SD_domains.elements[0].inst_len, 00674 SD_domains.elements[0].inst_len + 1) == 0) && 00675 (strncmp((const char*)(name + SD_domains.elements[0].inst_len + 1), 00676 (const char*)&SD_domains.elements[0].domain_len, 00677 SD_domains.elements[0].domain_len + 1) == 0)) 00678 { 00679 MDBG("recv AAAA request\n"); 00680 g_queries.reqs[g_queries.numbers] = DNS_TYPE_A; 00681 g_queries.numbers++; 00682 } 00683 } 00684 00685 queryptr = (char*)question + sizeof(struct dns_question); 00686 question = (struct dns_question *)skip_name(queryptr); 00687 } 00688 00689 if (g_queries.numbers) 00690 send_dns_ans(hdr); 00691 } 00692 else 00693 { 00694 if (strncmp((const char*)queryptr, 00695 (const char*)&SD_domains.elements[0].inst_len, 00696 SD_domains.elements[0].inst_len + 1) == 0) 00697 { 00698 type = ntohs(question->type); 00699 if (type == DNS_TYPE_A || type == DNS_TYPE_A) 00700 { 00701 char instance_number[4]; 00702 register_service(instance_number); 00703 query_domain(); 00704 } 00705 } 00706 } 00707 00708 } 00709 } 00710 #endif
Generated on Sat Jul 23 2022 00:40:12 by 1.7.2