mDNSlocal void FoundInstance(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord) { DNSServiceFlags flags = AddRecord ? kDNSServiceFlagsAdd : (DNSServiceFlags)0; domainlabel name; domainname type, domain; char cname[MAX_DOMAIN_LABEL+1]; // Unescaped name: up to 63 bytes plus C-string terminating NULL. char ctype[MAX_ESCAPED_DOMAIN_NAME]; char cdom [MAX_ESCAPED_DOMAIN_NAME]; mDNS_DirectOP_Browse *x = (mDNS_DirectOP_Browse*)question->QuestionContext; (void)m; // Unused if (answer->rrtype != kDNSType_PTR) { LogMsg("FoundInstance: Should not be called with rrtype %d (not a PTR record)", answer->rrtype); return; } if (!DeconstructServiceName(&answer->rdata->u.name, &name, &type, &domain)) { LogMsg("FoundInstance: %##s PTR %##s received from network is not valid DNS-SD service pointer", answer->name->c, answer->rdata->u.name.c); return; } ConvertDomainLabelToCString_unescaped(&name, cname); ConvertDomainNameToCString(&type, ctype); ConvertDomainNameToCString(&domain, cdom); if (x->callback) x->callback((DNSServiceRef)x, flags, 0, 0, cname, ctype, cdom, x->context); }
static void BrowseCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord) // A callback from the core mDNS code that indicates that we've received a // response to our query. Note that this code runs on the main thread // (in fact, there is only one thread!), so we can safely printf the results. { domainlabel name; domainname type; domainname domain; char nameC [MAX_DOMAIN_LABEL+1]; // Unescaped name: up to 63 bytes plus C-string terminating NULL. char typeC [MAX_ESCAPED_DOMAIN_NAME]; char domainC[MAX_ESCAPED_DOMAIN_NAME]; const char *state; (void)m; // Unused (void)question; // Unused assert(answer->rrtype == kDNSType_PTR); DeconstructServiceName(&answer->rdata->u.name, &name, &type, &domain); ConvertDomainLabelToCString_unescaped(&name, nameC); ConvertDomainNameToCString(&type, typeC); ConvertDomainNameToCString(&domain, domainC); // If the TTL has hit 0, the service is no longer available. if (!AddRecord) { state = "Lost "; } else { state = "Found"; } fprintf(stderr, "*** %s name = '%s', type = '%s', domain = '%s'\n", state, nameC, typeC, domainC); }
// This sample ServiceCallback just calls mDNS_RenameAndReregisterService to automatically pick a new // unique name for the service. For a device such as a printer, this may be appropriate. // For a device with a user interface, and a screen, and a keyboard, the appropriate // response may be to prompt the user and ask them to choose a new name for the service. mDNSlocal void ServiceCallback(mDNS *const m, ServiceRecordSet *const sr, mStatus result) { switch (result) { case mStatus_NoError: debugf("Callback: %##s Name Registered", sr->RR_SRV.resrec.name->c); break; case mStatus_NameConflict: debugf("Callback: %##s Name Conflict", sr->RR_SRV.resrec.name->c); break; case mStatus_MemFree: debugf("Callback: %##s Memory Free", sr->RR_SRV.resrec.name->c); break; default: debugf("Callback: %##s Unknown Result %ld", sr->RR_SRV.resrec.name->c, result); break; } if (result == mStatus_NoError) { char buffer[MAX_ESCAPED_DOMAIN_NAME]; ConvertDomainNameToCString(sr->RR_SRV.resrec.name, buffer); printf("Service %s now registered and active\n", buffer); } if (result == mStatus_NameConflict) { char buffer1[MAX_ESCAPED_DOMAIN_NAME], buffer2[MAX_ESCAPED_DOMAIN_NAME]; ConvertDomainNameToCString(sr->RR_SRV.resrec.name, buffer1); mDNS_RenameAndReregisterService(m, sr, mDNSNULL); ConvertDomainNameToCString(sr->RR_SRV.resrec.name, buffer2); printf("Name Conflict! %s renamed as %s\n", buffer1, buffer2); } }
mDNSlocal void NoSuchServiceCallback(mDNS *const m, AuthRecord *const rr, mStatus result) { const domainname *proxyhostname = (const domainname *)rr->RecordContext; switch (result) { case mStatus_NoError: debugf("Callback: %##s Name Registered", rr->resrec.name->c); break; case mStatus_NameConflict: debugf("Callback: %##s Name Conflict", rr->resrec.name->c); break; case mStatus_MemFree: debugf("Callback: %##s Memory Free", rr->resrec.name->c); break; default: debugf("Callback: %##s Unknown Result %ld", rr->resrec.name->c, result); break; } if (result == mStatus_NoError) { char buffer[MAX_ESCAPED_DOMAIN_NAME]; ConvertDomainNameToCString(rr->resrec.name, buffer); printf("Non-existence assertion %s now registered and active\n", buffer); } if (result == mStatus_NameConflict) { domainlabel n; domainname t, d; char buffer1[MAX_ESCAPED_DOMAIN_NAME], buffer2[MAX_ESCAPED_DOMAIN_NAME]; ConvertDomainNameToCString(rr->resrec.name, buffer1); DeconstructServiceName(rr->resrec.name, &n, &t, &d); IncrementLabelSuffix(&n, mDNStrue); mDNS_RegisterNoSuchService(m, rr, &n, &t, &d, proxyhostname, mDNSInterface_Any, NoSuchServiceCallback, mDNSNULL, 0); ConvertDomainNameToCString(rr->resrec.name, buffer2); printf("Name Conflict! %s renamed as %s\n", buffer1, buffer2); } }
static void BrowseCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord) // A callback from the core mDNS code that indicates that we've received a // response to our query. Note that this code runs on the main thread // (in fact, there is only one thread!), so we can safely printf the results. { return; domainlabel name; domainname type; domainname domain; char nameC [MAX_DOMAIN_LABEL+1]; // Unescaped name: up to 63 bytes plus C-string terminating NULL. char typeC [MAX_ESCAPED_DOMAIN_NAME]; char domainC[MAX_ESCAPED_DOMAIN_NAME]; const char *state; (void)m; // Unused (void)question; // Unused assert(answer->rrtype == kDNSType_PTR); DeconstructServiceName(&answer->rdata->u.name, &name, &type, &domain); ConvertDomainLabelToCString_unescaped(&name, nameC); ConvertDomainNameToCString(&type, typeC); ConvertDomainNameToCString(&domain, domainC); callback++; // If the TTL has hit 0, the service is no longer available. if (AddRecord) { fprintf(stderr, "*** Found name = '%s', type = '%s', domain = '%s'\n", nameC, typeC, domainC); //fprintf(stderr, "=== call back count: %d ===\n", callback); if(Service_list == NULL) { Service_list = (struct Queried_Service *)malloc(sizeof(struct Queried_Service)); strcpy(Service_list->service, nameC); strcpy(Service_list->type, typeC); Service_list->sup_device = NULL; Service_cur = Service_list; Service_cur->next = NULL; } else { Service_tmp = (struct Queried_Service *)malloc(sizeof(struct Queried_Service)); strcpy(Service_tmp->service, nameC); strcpy(Service_tmp->type, typeC); Service_tmp->sup_device = NULL; Service_tmp->next = NULL; Service_cur->next = Service_tmp; Service_cur = Service_tmp; } callback = 0; event = 0; } }
// RegisterService() is a simple wrapper function which takes C string // parameters, converts them to domainname parameters, and calls mDNS_RegisterService() mDNSlocal void RegisterService(mDNS *m, ServiceRecordSet *recordset, const char name[], const char type[], const char domain[], const domainname *host, mDNSu16 PortAsNumber, int argc, char **argv) { domainlabel n; domainname t, d; unsigned char txtbuffer[1024], *bptr = txtbuffer; char buffer[MAX_ESCAPED_DOMAIN_NAME]; MakeDomainLabelFromLiteralString(&n, name); MakeDomainNameFromDNSNameString(&t, type); MakeDomainNameFromDNSNameString(&d, domain); while (argc) { int len = strlen(argv[0]); if (len > 255 || bptr + 1 + len >= txtbuffer + sizeof(txtbuffer)) break; printf("STR: %s\n", argv[0]); bptr[0] = len; strcpy((char*)(bptr+1), argv[0]); bptr += 1 + len; argc--; argv++; } mDNS_RegisterService(m, recordset, &n, &t, &d, // Name, type, domain host, mDNSOpaque16fromIntVal(PortAsNumber), txtbuffer, bptr-txtbuffer, // TXT data, length mDNSNULL, 0, // Subtypes mDNSInterface_Any, // Interface ID ServiceCallback, mDNSNULL, 0); // Callback, context, flags ConvertDomainNameToCString(recordset->RR_SRV.resrec.name, buffer); printf("Made Service Records for %s\n", buffer); }
// RegisterService() is a simple wrapper function which takes C string // parameters, converts them to domainname parameters, and calls mDNS_RegisterService() mDNSlocal void RegisterService(mDNS *m, ServiceRecordSet *recordset, UInt16 PortAsNumber, const char txtinfo[], const domainlabel *const n, const char type[], const char domain[]) { domainname t; domainname d; char buffer[MAX_ESCAPED_DOMAIN_NAME]; UInt8 txtbuffer[512]; MakeDomainNameFromDNSNameString(&t, type); MakeDomainNameFromDNSNameString(&d, domain); if (txtinfo) { strncpy((char*)txtbuffer+1, txtinfo, sizeof(txtbuffer)-1); txtbuffer[0] = (UInt8)strlen(txtinfo); } else txtbuffer[0] = 0; mDNS_RegisterService(m, recordset, n, &t, &d, // Name, type, domain mDNSNULL, mDNSOpaque16fromIntVal(PortAsNumber), txtbuffer, (mDNSu16)(1+txtbuffer[0]), // TXT data, length mDNSNULL, 0, // Subtypes (none) mDNSInterface_Any, // Interface ID Callback, mDNSNULL); // Callback and context ConvertDomainNameToCString(recordset->RR_SRV.resrec.name, buffer); printf("Made Service Records for %s\n", buffer); }
mDNSlocal void DNSServiceQueryRecordResponse(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord) { mDNS_DirectOP_QueryRecord *x = (mDNS_DirectOP_QueryRecord*)question->QuestionContext; char fullname[MAX_ESCAPED_DOMAIN_NAME]; (void)m; // Unused ConvertDomainNameToCString(answer->name, fullname); x->callback((DNSServiceRef)x, AddRecord ? kDNSServiceFlagsAdd : (DNSServiceFlags)0, 0, kDNSServiceErr_NoError, fullname, answer->rrtype, answer->rrclass, answer->rdlength, answer->rdata->u.data, answer->rroriginalttl, x->context); }
// PrintServiceInfo prints the service information to standard out // A real application might want to do something else with the information static void PrintServiceInfo(SearcherServices *services) { OTLink *link = OTReverseList(OTLIFOStealList(&services->serviceinfolist)); while (link) { linkedServiceInfo *ls = OTGetLinkObject(link, linkedServiceInfo, link); ServiceInfo *s = &ls->i; if (!services->headerPrinted) { printf("%-55s Type Domain IP Address Port Info\n", "Name"); services->headerPrinted = true; } if (ls->dom) { char c_dom[MAX_ESCAPED_DOMAIN_NAME]; ConvertDomainNameToCString(&s->name, c_dom); if (ls->add) printf("%-55s available for browsing\n", c_dom); else printf("%-55s no longer available for browsing\n", c_dom); } else { domainlabel name; domainname type, domain; char c_name[MAX_DOMAIN_LABEL+1], c_type[MAX_ESCAPED_DOMAIN_NAME], c_dom[MAX_ESCAPED_DOMAIN_NAME], c_ip[20]; DeconstructServiceName(&s->name, &name, &type, &domain); ConvertDomainLabelToCString_unescaped(&name, c_name); ConvertDomainNameToCString(&type, c_type); ConvertDomainNameToCString(&domain, c_dom); sprintf(c_ip, "%d.%d.%d.%d", s->ip.ip.v4.b[0], s->ip.ip.v4.b[1], s->ip.ip.v4.b[2], s->ip.ip.v4.b[3]); printf("%-55s %-16s %-14s ", c_name, c_type, c_dom); if (ls->add) printf("%-15s %5d %#s\n", c_ip, mDNSVal16(s->port), s->TXTinfo); else printf("Removed\n"); } link = link->fNext; OTFreeMem(ls); } }
mDNSlocal void RegCallback(mDNS *const m, ServiceRecordSet *const sr, mStatus result) { mDNS_DirectOP_Register *x = (mDNS_DirectOP_Register*)sr->ServiceContext; domainlabel name; domainname type, dom; char namestr[MAX_DOMAIN_LABEL+1]; // Unescaped name: up to 63 bytes plus C-string terminating NULL. char typestr[MAX_ESCAPED_DOMAIN_NAME]; char domstr [MAX_ESCAPED_DOMAIN_NAME]; if (!DeconstructServiceName(sr->RR_SRV.resrec.name, &name, &type, &dom)) return; if (!ConvertDomainLabelToCString_unescaped(&name, namestr)) return; if (!ConvertDomainNameToCString(&type, typestr)) return; if (!ConvertDomainNameToCString(&dom, domstr)) return; if (result == mStatus_NoError) { if (x->callback) x->callback((DNSServiceRef)x, 0, result, namestr, typestr, domstr, x->context); } else if (result == mStatus_NameConflict) { if (x->autoname) mDNS_RenameAndReregisterService(m, sr, mDNSNULL); else if (x->autorename) { IncrementLabelSuffix(&x->name, mDNStrue); mDNS_RenameAndReregisterService(m, &x->s, &x->name); } else if (x->callback) x->callback((DNSServiceRef)x, 0, result, namestr, typestr, domstr, x->context); } else if (result == mStatus_MemFree) { if (x->autorename) { x->autorename = mDNSfalse; x->name = mDNSStorage.nicelabel; mDNS_RenameAndReregisterService(m, &x->s, &x->name); } else FreeDNSServiceRegistration(x); } }
mDNSlocal void RegisterNoSuchService(mDNS *m, AuthRecord *const rr, domainname *proxyhostname, const char name[], const char type[], const char domain[]) { domainlabel n; domainname t, d; char buffer[MAX_ESCAPED_DOMAIN_NAME]; MakeDomainLabelFromLiteralString(&n, name); MakeDomainNameFromDNSNameString(&t, type); MakeDomainNameFromDNSNameString(&d, domain); mDNS_RegisterNoSuchService(m, rr, &n, &t, &d, proxyhostname, mDNSInterface_Any, NoSuchServiceCallback, proxyhostname, 0); ConvertDomainNameToCString(rr->resrec.name, buffer); printf("Made Non-existence Record for %s\n", buffer); }
mDNSlocal void NameCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord) { (void)m; // Unused (void)question; // Unused (void)AddRecord; // Unused if (!id.NotAnInteger) id = lastid; if (answer->rrtype == kDNSType_PTR || answer->rrtype == kDNSType_CNAME) { ConvertDomainNameToCString(&answer->rdata->u.name, hostname); StopNow = 1; mprintf("%##s %s %##s\n", answer->name->c, DNSTypeName(answer->rrtype), answer->rdata->u.name.c); } }
mDNSlocal void FoundServiceInfo(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord) { mDNS_DirectOP_Resolve *x = (mDNS_DirectOP_Resolve*)question->QuestionContext; (void)m; // Unused if (!AddRecord) { if (answer->rrtype == kDNSType_SRV && x->SRV == answer) x->SRV = mDNSNULL; if (answer->rrtype == kDNSType_TXT && x->TXT == answer) x->TXT = mDNSNULL; } else { if (answer->rrtype == kDNSType_SRV) x->SRV = answer; if (answer->rrtype == kDNSType_TXT) x->TXT = answer; if (x->SRV && x->TXT && x->callback) { char fullname[MAX_ESCAPED_DOMAIN_NAME], targethost[MAX_ESCAPED_DOMAIN_NAME]; ConvertDomainNameToCString(answer->name, fullname); ConvertDomainNameToCString(&x->SRV->rdata->u.srv.target, targethost); x->callback((DNSServiceRef)x, 0, 0, kDNSServiceErr_NoError, fullname, targethost, x->SRV->rdata->u.srv.port.NotAnInteger, x->TXT->rdlength, (char*)x->TXT->rdata->u.txt.c, x->context); } } }
static mDNSBool eval_service_name(const domainname *fqdn, domainlabel *name) { domainname type; domainname domain; mDNSBool ok = DeconstructServiceName(fqdn, name, &type, &domain); if (ok) { char name_str[MAX_DOMAIN_LABEL + 1]; char type_str[MAX_ESCAPED_DOMAIN_NAME]; char domain_str[MAX_ESCAPED_DOMAIN_NAME]; ConvertDomainLabelToCString_unescaped(name, name_str); ConvertDomainNameToCString(&type, type_str); ConvertDomainNameToCString(&domain, domain_str); printf("name = '%s', type = '%s', domain = '%s'", name_str, type_str, domain_str); } else { printf("?"); } return ok; }
// Done once on startup, and then again every time our address changes mDNSlocal OSStatus mDNSResponderTestSetup(mDNS *m) { char buffer[MAX_ESCAPED_DOMAIN_NAME]; mDNSv4Addr ip = m->HostInterfaces->ip.ip.v4; ConvertDomainNameToCString(&m->MulticastHostname, buffer); printf("Name %s\n", buffer); printf("IP %d.%d.%d.%d\n", ip.b[0], ip.b[1], ip.b[2], ip.b[3]); printf("\n"); printf("Registering Service Records\n"); // Create example printer discovery records //static ServiceRecordSet p1, p2; RegisterFakeServiceForTesting(m, &p1, "", "One", "_raop._tcp.", "local."); RegisterFakeServiceForTesting(m, &p2, "", "Two", "_raop._tcp.", "local."); return(kOTNoError); }
// Done once on startup, and then again every time our address changes mDNSlocal OSStatus mDNSResponderTestSetup(mDNS *m) { char buffer[MAX_ESCAPED_DOMAIN_NAME]; mDNSv4Addr ip = m->HostInterfaces->ip.ip.v4; ConvertDomainNameToCString(&m->MulticastHostname, buffer); printf("Name %s\n", buffer); printf("IP %d.%d.%d.%d\n", ip.b[0], ip.b[1], ip.b[2], ip.b[3]); printf("\n"); printf("Registering Service Records\n"); // Create example printer discovery records //static ServiceRecordSet p1, p2; #define SRSET 0 #if SRSET==0 RegisterFakeServiceForTesting(m, &p1, "path=/index.html", "Web Server One", "_http._tcp.", "local."); RegisterFakeServiceForTesting(m, &p2, "path=/path.html", "Web Server Two", "_http._tcp.", "local."); #elif SRSET==1 RegisterFakeServiceForTesting(m, &p1, "rn=lpq1", "Epson Stylus 900N", "_printer._tcp.", "local."); RegisterFakeServiceForTesting(m, &p2, "rn=lpq2", "HP LaserJet", "_printer._tcp.", "local."); #else RegisterFakeServiceForTesting(m, &p1, "rn=lpq3", "My Printer", "_printer._tcp.", "local."); RegisterFakeServiceForTesting(m, &p2, "lrn=pq4", "My Other Printer", "_printer._tcp.", "local."); #endif // If AFP Server is running, register a record for it CreateProxyRegistrationForRealService(m, 548, "", "_afpovertcp._tcp.", &afp); // If Web Server is running, register a record for it CreateProxyRegistrationForRealService(m, 80, "", "_http._tcp.", &http); // And pretend we always have an NJP server running on port 80 too //RegisterService(m, &njp, 80, "NJP/", &m->nicelabel, "_njp._tcp.", "local."); // Advertise that apple.com. is available for browsing mDNS_AdvertiseDomains(m, &browsedomain1, mDNS_DomainTypeBrowse, mDNSInterface_Any, "apple.com."); mDNS_AdvertiseDomains(m, &browsedomain2, mDNS_DomainTypeBrowse, mDNSInterface_Any, "IL 2\\4th Floor.apple.com."); return(kOTNoError); }
static void QueryCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord) { domainlabel name; domainname type; domainname domain; char nameC [MAX_DOMAIN_LABEL+1]; // Unescaped name: up to 63 bytes plus C-string terminating NULL. char typeC [MAX_ESCAPED_DOMAIN_NAME]; char domainC[MAX_ESCAPED_DOMAIN_NAME]; const char *state; (void)m; // Unused (void)question; // Unused assert(answer->rrtype == kDNSType_PTR); DeconstructServiceName(&answer->rdata->u.name, &name, &type, &domain); ConvertDomainLabelToCString_unescaped(&name, nameC); ConvertDomainNameToCString(&type, typeC); ConvertDomainNameToCString(&domain, domainC); callback++; // If the TTL has hit 0, the service is no longer available. if (AddRecord) { fprintf(stderr, "*** Found device = '%s', service = '%s', domain = '%s'\n", nameC, typeC, domainC); //fprintf(stderr, "=== call back count: %d ===\n", callback); if(Device_list == NULL) { Device_list = (struct Device *)malloc(sizeof(struct Device)); QueriedNameParse(Service_tmp->service, nameC, Device_list); printf("1. Get %s, %s\n", Device_list->name, Device_list->MACAddr); Device_list->sup_service = (struct Support_Service *)malloc(sizeof(struct Support_Service)); strcpy(Device_list->sup_service->name, Service_tmp->service); Device_list->sup_service->next = NULL; Device_cur = Device_list; Device_cur->next = NULL; service_count++; } else { Device_found = (struct Device *)malloc(sizeof(struct Device)); QueriedNameParse(Service_tmp->service, nameC, Device_found); printf("2. Get %s, %s\n", Device_found->name, Device_found->MACAddr); Device_cmp = Device_list; while(Device_cmp != NULL) { printf("%s ? %s\n",Device_found->name, Device_cmp->name); if(!strcmp(Device_found->name, Device_cmp->name)) { //the device already exist, add service to list. printf("Device name the same!\n"); Sup_service_cur = Device_cmp->sup_service; while(Sup_service_cur->next!=NULL) Sup_service_cur = Sup_service_cur->next; Sup_service_tmp = (struct Support_Service *)malloc(sizeof(struct Support_Service)); strcpy(Sup_service_tmp->name, Service_tmp->service); Sup_service_tmp->next = NULL; Sup_service_cur->next = Sup_service_tmp; Sup_service_cur = Sup_service_tmp; service_count++; return; } Device_cmp = Device_cmp->next; } printf("New Device name!\n"); Device_found->sup_service = (struct Support_Service *)malloc(sizeof(struct Support_Service)); strcpy(Device_found->sup_service->name, Service_tmp->service); Device_found->sup_service->next = NULL; Device_found->next = NULL; Device_cur->next = Device_found; Device_cur = Device_found; Device_cur->next = NULL; } printf("device= %s\n", Device_cur->name); device_count++; callback = 0; event = 0; } }