#include <stdio.h> // For printf()
#include <stdlib.h> // For exit() etc.
#include <string.h> // For strlen() etc.
#include <unistd.h> // For select()
#include <errno.h> // For errno, EINTR
#include <arpa/inet.h> // For inet_addr()
#include <netinet/in.h> // For INADDR_NONE
#include <netdb.h> // For gethostbyname()
#include "mDNSClientAPI.h" // Defines the interface to the client layer above
#include "mDNSPosix.h" // Defines the specific types needed to run mDNS on this platform
#include "ExampleClientApp.h"
static mDNS mDNSStorage; static mDNS_PlatformSupport PlatformStorage;
typedef struct
{
mDNSv4Addr ip;
domainlabel hostlabel; AuthRecord RR_A; AuthRecord RR_PTR; } ProxyHost;
mDNSlocal void HostNameCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
{
ProxyHost *f = (ProxyHost*)rr->RecordContext;
if (result == mStatus_NoError)
debugf("Host name successfully registered: %##s", &rr->resrec.name);
else
{
debugf("Host name conflict for %##s", &rr->resrec.name);
mDNS_Deregister(m, &f->RR_A);
mDNS_Deregister(m, &f->RR_PTR);
exit(-1);
}
}
mDNSlocal mStatus mDNS_RegisterProxyHost(mDNS *m, ProxyHost *p)
{
char buffer[32];
mDNS_SetupResourceRecord(&p->RR_A, mDNSNULL, mDNSInterface_Any, kDNSType_A, 60, kDNSRecordTypeUnique, HostNameCallback, p);
mDNS_SetupResourceRecord(&p->RR_PTR, mDNSNULL, mDNSInterface_Any, kDNSType_PTR, 60, kDNSRecordTypeKnownUnique, HostNameCallback, p);
p->RR_A.resrec.name.c[0] = 0;
AppendDomainLabel(&p->RR_A.resrec.name, &p->hostlabel);
AppendLiteralLabelString(&p->RR_A.resrec.name, "local");
mDNS_snprintf(buffer, sizeof(buffer), "%d.%d.%d.%d.in-addr.arpa.", p->ip.b[3], p->ip.b[2], p->ip.b[1], p->ip.b[0]);
MakeDomainNameFromDNSNameString(&p->RR_PTR.resrec.name, buffer);
p->RR_A. resrec.rdata->u.ip = p->ip;
p->RR_PTR.resrec.rdata->u.name = p->RR_A.resrec.name;
mDNS_Register(m, &p->RR_A);
mDNS_Register(m, &p->RR_PTR);
debugf("Made Proxy Host Records for %##s", &p->RR_A.resrec.name);
return(mStatus_NoError);
}
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); break;
case mStatus_NameConflict: debugf("Callback: %##s Name Conflict", &sr->RR_SRV.resrec.name); break;
case mStatus_MemFree: debugf("Callback: %##s Memory Free", &sr->RR_SRV.resrec.name); break;
default: debugf("Callback: %##s Unknown Result %d", &sr->RR_SRV.resrec.name, result); break;
}
if (result == mStatus_NoError)
{
char buffer[256];
ConvertDomainNameToCString_unescaped(&sr->RR_SRV.resrec.name, buffer);
printf("Service %s now registered and active\n", buffer);
}
if (result == mStatus_NameConflict)
{
char buffer1[256], buffer2[256];
ConvertDomainNameToCString_unescaped(&sr->RR_SRV.resrec.name, buffer1);
mDNS_RenameAndReregisterService(m, sr, mDNSNULL);
ConvertDomainNameToCString_unescaped(&sr->RR_SRV.resrec.name, buffer2);
printf("Name Conflict! %s renamed as %s\n", buffer1, buffer2);
}
}
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;
mDNSIPPort port;
unsigned char buffer[1024], *bptr = buffer;
MakeDomainLabelFromLiteralString(&n, name);
MakeDomainNameFromDNSNameString(&t, type);
MakeDomainNameFromDNSNameString(&d, domain);
port.b[0] = (mDNSu8)(PortAsNumber >> 8);
port.b[1] = (mDNSu8)(PortAsNumber );
while (argc)
{
int len = strlen(argv[0]);
printf("STR: %s\n", argv[0]);
bptr[0] = len;
strcpy(bptr+1, argv[0]);
bptr += 1 + len;
argc--;
argv++;
}
mDNS_RegisterService(m, recordset,
&n, &t, &d, host, port, buffer, bptr-buffer, mDNSNULL, 0, mDNSInterface_Any, ServiceCallback, mDNSNULL);
ConvertDomainNameToCString_unescaped(&recordset->RR_SRV.resrec.name, buffer);
printf("Made Service Records for %s\n", buffer);
}
mDNSlocal void NoSuchServiceCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
{
domainname *proxyhostname = (domainname *)rr->RecordContext;
switch (result)
{
case mStatus_NoError: debugf("Callback: %##s Name Registered", &rr->resrec.name); break;
case mStatus_NameConflict: debugf("Callback: %##s Name Conflict", &rr->resrec.name); break;
case mStatus_MemFree: debugf("Callback: %##s Memory Free", &rr->resrec.name); break;
default: debugf("Callback: %##s Unknown Result %d", &rr->resrec.name, result); break;
}
if (result == mStatus_NoError)
{
char buffer[256];
ConvertDomainNameToCString_unescaped(&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[256], buffer2[256];
ConvertDomainNameToCString_unescaped(&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);
ConvertDomainNameToCString_unescaped(&rr->resrec.name, buffer2);
printf("Name Conflict! %s renamed as %s\n", buffer1, buffer2);
}
}
mDNSlocal void RegisterNoSuchService(mDNS *m, AuthRecord *const rr, domainname *proxyhostname,
const char name[], const char type[], const char domain[])
{
domainlabel n;
domainname t, d;
unsigned char buffer[256];
MakeDomainLabelFromLiteralString(&n, name);
MakeDomainNameFromDNSNameString(&t, type);
MakeDomainNameFromDNSNameString(&d, domain);
mDNS_RegisterNoSuchService(m, rr, &n, &t, &d, proxyhostname, mDNSInterface_Any, NoSuchServiceCallback, proxyhostname);
ConvertDomainNameToCString_unescaped(&rr->resrec.name, buffer);
printf("Made Non-existence Record for %s\n", buffer);
}
mDNSexport int main(int argc, char **argv)
{
mStatus status;
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 %ld\n", status); return(status); }
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.");
ExampleClientEventLoop(&mDNSStorage);
mDNS_Close(&mDNSStorage);
}
else
{
ProxyHost proxyhost;
ServiceRecordSet proxyservice;
proxyhost.ip.NotAnInteger = inet_addr(argv[1]);
if (proxyhost.ip.NotAnInteger == INADDR_NONE) {
struct hostent *h = gethostbyname(argv[1]);
if (h) proxyhost.ip.NotAnInteger = *(long*)h->h_addr;
}
if (proxyhost.ip.NotAnInteger == INADDR_NONE) {
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]);
ExampleClientEventLoop(&mDNSStorage);
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);
}