// mDNS core calls this routine to initialise the platform-specific data. mDNSexport mStatus mDNSPlatformInit(mDNS *const m) { int err; assert(m != NULL); // Tell mDNS core the names of this machine. // Set up the nice label m->nicelabel.c[0] = 0; GetUserSpecifiedFriendlyComputerName(&m->nicelabel); if (m->nicelabel.c[0] == 0) MakeDomainLabelFromLiteralString(&m->nicelabel, "Macintosh"); // Set up the RFC 1034-compliant label m->hostlabel.c[0] = 0; GetUserSpecifiedRFC1034ComputerName(&m->hostlabel); if (m->hostlabel.c[0] == 0) MakeDomainLabelFromLiteralString(&m->hostlabel, "Macintosh"); mDNS_GenerateFQDN(m); // Tell mDNS core about the network interfaces on this machine. err = SetupInterfaceList(m); // We don't do asynchronous initialization on the Posix platform, so by the time // we get here the setup will already have succeeded or failed. If it succeeded, // we should just call mDNSCoreInitComplete() immediately. if (err == 0) mDNSCoreInitComplete(m, mStatus_NoError); return PosixErrorToStatus(err); }
// 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); }
static mStatus RegisterOneService(const char * richTextHostName, const char * serviceType, const char * serviceDomain, const mDNSu8 text[], mDNSu16 textLen, long portNumber) { mStatus status; PosixService * thisServ; mDNSOpaque16 port; domainlabel name; domainname type; domainname domain; status = mStatus_NoError; thisServ = (PosixService *) malloc(sizeof(*thisServ)); if (thisServ == NULL) { status = mStatus_NoMemoryErr; } if (status == mStatus_NoError) { MakeDomainLabelFromLiteralString(&name, richTextHostName); MakeDomainNameFromDNSNameString(&type, serviceType); MakeDomainNameFromDNSNameString(&domain, serviceDomain); port.b[0] = (portNumber >> 8) & 0x0FF; port.b[1] = (portNumber >> 0) & 0x0FF;; status = mDNS_RegisterService(&mDNSStorage, &thisServ->coreServ, &name, &type, &domain, NULL, port, text, textLen, NULL, 0, mDNSInterface_Any, RegistrationCallback, thisServ); }
// RegisterFakeServiceForTesting() simulates the effect of services being registered on // dynamically-allocated port numbers. No real service exists on that port -- this is just for testing. mDNSlocal void RegisterFakeServiceForTesting(mDNS *m, ServiceRecordSet *recordset, const char txtinfo[], const char name[], const char type[], const char domain[]) { static UInt16 NextPort = 0xF000; domainlabel n; MakeDomainLabelFromLiteralString(&n, name); RegisterService(m, recordset, NextPort++, txtinfo, &n, type, domain); }
static mStatus RegisterOneService(const char * richTextName, const char * serviceType, const char * serviceDomain, const mDNSu8 text[], mDNSu16 textLen, long portNumber) { mStatus status; PosixService * thisServ; domainlabel name; domainname type; domainname domain; status = mStatus_NoError; thisServ = (PosixService *) malloc(sizeof(*thisServ)); if (thisServ == NULL) { status = mStatus_NoMemoryErr; } if (status == mStatus_NoError) { MakeDomainLabelFromLiteralString(&name, richTextName); MakeDomainNameFromDNSNameString(&type, serviceType); MakeDomainNameFromDNSNameString(&domain, serviceDomain); status = mDNS_RegisterService(&mDNSStorage, &thisServ->coreServ, &name, &type, &domain, // Name, type, domain NULL, mDNSOpaque16fromIntVal(portNumber), text, textLen, // TXT data, length NULL, 0, // Subtypes mDNSInterface_Any, // Interface ID RegistrationCallback, thisServ); // Callback and context } if (status == mStatus_NoError) { thisServ->serviceID = gServiceID; gServiceID += 1; thisServ->next = gServiceList; gServiceList = thisServ; if (gMDNSPlatformPosixVerboseLevel > 0) { fprintf(stderr, "%s: Registered service %d, name '%s', type '%s', port %ld\n", gProgramName, thisServ->serviceID, richTextName, serviceType, portNumber); } } else { if (thisServ != NULL) { free(thisServ); } } return status; }
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); }
static ServiceRecordSet * foobar_register(mDNSu16 port) { ServiceRecordSet *srs; mStatus status; domainlabel name; domainname type; domainname domain; srs = calloc(1, sizeof(*srs)); assert(srs != NULL); MakeDomainLabelFromLiteralString(&name, "foobar"); MakeDomainNameFromDNSNameString(&type, "_foobar._tcp"); MakeDomainNameFromDNSNameString(&domain, "local."); status = mDNS_RegisterService(&mDNSStorage, srs, &name, &type, &domain, NULL, mDNSOpaque16fromIntVal(port), NULL, 0, NULL, 0, mDNSInterface_Any, foobar_callback, srs, 0); assert(status == mStatus_NoError); return srs; }
mDNSexport int main(int argc, char **argv) { mStatus status; sigset_t signals; if (argc < 3) goto usage; status = mDNS_Init(&mDNSStorage, &PlatformStorage, mDNS_Init_NoCache, mDNS_Init_ZeroCacheSize, mDNS_Init_DontAdvertiseLocalAddresses, mDNS_Init_NoInitCallback, mDNS_Init_NoInitCallbackContext); if (status) { fprintf(stderr, "Daemon start: mDNS_Init failed %d\n", (int)status); return(status); } mDNSPosixListenForSignalInEventLoop(SIGINT); mDNSPosixListenForSignalInEventLoop(SIGTERM); if (!strcmp(argv[1], "-")) { domainname proxyhostname; AuthRecord proxyrecord; if (argc < 5) goto usage; proxyhostname.c[0] = 0; AppendLiteralLabelString(&proxyhostname, argv[2]); AppendLiteralLabelString(&proxyhostname, "local"); RegisterNoSuchService(&mDNSStorage, &proxyrecord, &proxyhostname, argv[3], argv[4], "local."); } else { ProxyHost proxyhost; ServiceRecordSet proxyservice; proxyhost.ip.NotAnInteger = inet_addr(argv[1]); if (proxyhost.ip.NotAnInteger == INADDR_NONE) // INADDR_NONE is 0xFFFFFFFF { struct hostent *h = gethostbyname(argv[1]); if (h) proxyhost.ip.NotAnInteger = *(long*)h->h_addr; } if (proxyhost.ip.NotAnInteger == INADDR_NONE) // INADDR_NONE is 0xFFFFFFFF { fprintf(stderr, "%s is not valid host address\n", argv[1]); return(-1); } MakeDomainLabelFromLiteralString(&proxyhost.hostlabel, argv[2]); mDNS_RegisterProxyHost(&mDNSStorage, &proxyhost); if (argc >=6) RegisterService(&mDNSStorage, &proxyservice, argv[3], argv[4], "local.", proxyhost.RR_A.resrec.name, atoi(argv[5]), argc-6, &argv[6]); } do { struct timeval timeout = { 0x3FFFFFFF, 0 }; // wait until SIGINT or SIGTERM mDNSBool gotSomething; mDNSPosixRunEventLoopOnce(&mDNSStorage, &timeout, &signals, &gotSomething); } while ( !( sigismember( &signals, SIGINT) || sigismember( &signals, SIGTERM))); mDNS_Close(&mDNSStorage); return(0); usage: fprintf(stderr, "%s ip hostlabel [srvname srvtype port txt [txt ...]]\n", argv[0]); fprintf(stderr, "ip Real IP address (or valid host name) of the host where the service actually resides\n"); fprintf(stderr, "hostlabel First label of the dot-local host name to create for this host, e.g. \"foo\" for \"foo.local.\"\n"); fprintf(stderr, "srvname Descriptive name of service, e.g. \"Stuart's Ink Jet Printer\"\n"); fprintf(stderr, "srvtype IANA service type, e.g. \"_ipp._tcp\" or \"_ssh._tcp\", etc.\n"); fprintf(stderr, "port Port number where the service resides (1-65535)\n"); fprintf(stderr, "txt Additional name/value pairs specified in service definition, e.g. \"pdl=application/postscript\"\n"); fprintf(stderr, "e.g. %s 169.254.12.34 thehost (just create a dot-local host name)\n", argv[0]); fprintf(stderr, "or %s 169.254.12.34 thehost \"My Printer\" _printer._tcp. 515 rp=lpt1 pdl=application/postscript\n", argv[0]); fprintf(stderr, "or %s - thehost \"My Printer\" _printer._tcp. (assertion of non-existence)\n", argv[0]); return(-1); }
DNSServiceErrorType DNSServiceResolve ( DNSServiceRef *sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, const char *name, const char *regtype, const char *domain, DNSServiceResolveReply callback, void *context /* may be NULL */ ) { mStatus err = mStatus_NoError; const char *errormsg = "Unknown"; domainlabel n; domainname t, d, srv; mDNS_DirectOP_Resolve *x; (void)flags; // Unused (void)interfaceIndex; // Unused // Check parameters if (!name[0] || !MakeDomainLabelFromLiteralString(&n, name )) { errormsg = "Bad Instance Name"; goto badparam; } if (!regtype[0] || !MakeDomainNameFromDNSNameString(&t, regtype)) { errormsg = "Bad Service Type"; goto badparam; } if (!domain[0] || !MakeDomainNameFromDNSNameString(&d, domain )) { errormsg = "Bad Domain"; goto badparam; } if (!ConstructServiceName(&srv, &n, &t, &d)) { errormsg = "Bad Name"; goto badparam; } // Allocate memory, and handle failure x = (mDNS_DirectOP_Resolve *)mDNSPlatformMemAllocate(sizeof(*x)); if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; } // Set up object x->disposefn = DNSServiceResolveDispose; x->callback = callback; x->context = context; x->SRV = mDNSNULL; x->TXT = mDNSNULL; x->qSRV.ThisQInterval = -1; // So that DNSServiceResolveDispose() knows whether to cancel this question x->qSRV.InterfaceID = mDNSInterface_Any; x->qSRV.Target = zeroAddr; AssignDomainName(&x->qSRV.qname, &srv); x->qSRV.qtype = kDNSType_SRV; x->qSRV.qclass = kDNSClass_IN; x->qSRV.LongLived = mDNSfalse; x->qSRV.ExpectUnique = mDNStrue; x->qSRV.ForceMCast = mDNSfalse; x->qSRV.QuestionCallback = FoundServiceInfo; x->qSRV.QuestionContext = x; x->qTXT.ThisQInterval = -1; // So that DNSServiceResolveDispose() knows whether to cancel this question x->qTXT.InterfaceID = mDNSInterface_Any; x->qTXT.Target = zeroAddr; AssignDomainName(&x->qTXT.qname, &srv); x->qTXT.qtype = kDNSType_TXT; x->qTXT.qclass = kDNSClass_IN; x->qTXT.LongLived = mDNSfalse; x->qTXT.ExpectUnique = mDNStrue; x->qTXT.ForceMCast = mDNSfalse; x->qTXT.QuestionCallback = FoundServiceInfo; x->qTXT.QuestionContext = x; err = mDNS_StartQuery(&mDNSStorage, &x->qSRV); if (err) { DNSServiceResolveDispose((mDNS_DirectOP*)x); errormsg = "mDNS_StartQuery qSRV"; goto fail; } err = mDNS_StartQuery(&mDNSStorage, &x->qTXT); if (err) { DNSServiceResolveDispose((mDNS_DirectOP*)x); errormsg = "mDNS_StartQuery qTXT"; goto fail; } // Succeeded: Wrap up and return *sdRef = (DNSServiceRef)x; return(mStatus_NoError); badparam: err = mStatus_BadParamErr; fail: LogMsg("DNSServiceResolve(\"%s\", \"%s\", \"%s\") failed: %s (%ld)", name, regtype, domain, errormsg, err); return(err); }
DNSServiceErrorType DNSServiceRegister ( DNSServiceRef *sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, const char *name, /* may be NULL */ const char *regtype, const char *domain, /* may be NULL */ const char *host, /* may be NULL */ uint16_t notAnIntPort, uint16_t txtLen, const void *txtRecord, /* may be NULL */ DNSServiceRegisterReply callback, /* may be NULL */ void *context /* may be NULL */ ) { mStatus err = mStatus_NoError; const char *errormsg = "Unknown"; domainlabel n; domainname t, d, h, srv; mDNSIPPort port; unsigned int size = sizeof(RDataBody); AuthRecord *SubTypes = mDNSNULL; mDNSu32 NumSubTypes = 0; mDNS_DirectOP_Register *x; (void)flags; // Unused (void)interfaceIndex; // Unused // Check parameters if (!name[0]) n = mDNSStorage.nicelabel; else if (!MakeDomainLabelFromLiteralString(&n, name)) { errormsg = "Bad Instance Name"; goto badparam; } if (!regtype || !*regtype || !MakeDomainNameFromDNSNameString(&t, regtype)) { errormsg = "Bad Service Type"; goto badparam; } if (!MakeDomainNameFromDNSNameString(&d, (domain && *domain) ? domain : "local.")) { errormsg = "Bad Domain"; goto badparam; } if (!MakeDomainNameFromDNSNameString(&h, (host && *host ) ? host : "")) { errormsg = "Bad Target Host"; goto badparam; } if (!ConstructServiceName(&srv, &n, &t, &d)) { errormsg = "Bad Name"; goto badparam; } port.NotAnInteger = notAnIntPort; // Allocate memory, and handle failure if (size < txtLen) size = txtLen; x = (mDNS_DirectOP_Register *)mDNSPlatformMemAllocate(sizeof(*x) - sizeof(RDataBody) + size); if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; } // Set up object x->disposefn = DNSServiceRegisterDispose; x->callback = callback; x->context = context; x->autoname = (!name[0]); x->autorename = mDNSfalse; x->name = n; // Do the operation err = mDNS_RegisterService(&mDNSStorage, &x->s, &x->name, &t, &d, // Name, type, domain &h, port, // Host and port txtRecord, txtLen, // TXT data, length SubTypes, NumSubTypes, // Subtypes mDNSInterface_Any, // Interface ID RegCallback, x); // Callback and context if (err) { mDNSPlatformMemFree(x); errormsg = "mDNS_RegisterService"; goto fail; } // Succeeded: Wrap up and return *sdRef = (DNSServiceRef)x; return(mStatus_NoError); badparam: err = mStatus_BadParamErr; fail: LogMsg("DNSServiceBrowse(\"%s\", \"%s\") failed: %s (%ld)", regtype, domain, errormsg, err); return(err); }
// On OS X this gets the text of the field labelled "Computer Name" in the Sharing Prefs Control Panel // Other platforms can either get the information from the appropriate place, // or they can alternatively just require all registering services to provide an explicit name mDNSlocal void GetUserSpecifiedFriendlyComputerName(domainlabel *const namelabel) { MakeDomainLabelFromLiteralString(namelabel, "Fill in Default Service Name Here"); }