-/*
+/* -*- Mode: C; tab-width: 4 -*-
+ *
* Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
Change History (most recent first):
$Log: DNSCommon.c,v $
+Revision 1.96.2.1 2006/10/31 02:50:16 cheshire
+<rdar://problem/4683163> mDNSResponder insufficiently defensive against malformed browsing PTR responses
+
+Revision 1.96 2006/03/10 21:51:42 cheshire
+<rdar://problem/4111464> After record update, old record sometimes remains in cache
+Split out SameRDataBody() into a separate routine so it can be called from other code
+
+Revision 1.95 2006/03/08 22:43:11 cheshire
+Use "localdomain" symbol instead of literal string
+
+Revision 1.94 2006/03/02 21:59:55 cheshire
+<rdar://problem/4395331> Spurious warning "GetLargeResourceRecord: m->rec appears to be already in use"
+Improve sanity checks & debugging support in GetLargeResourceRecord()
+
+Revision 1.93 2006/03/02 20:30:47 cheshire
+Improved GetRRDisplayString to also show priority, weight, and port for SRV records
+
+Revision 1.92 2005/09/16 21:06:49 cheshire
+Use mDNS_TimeNow_NoLock macro, instead of writing "mDNSPlatformRawTime() + m->timenow_adjust" all over the place
+
+Revision 1.91 2005/07/10 22:10:37 cheshire
+The getOptRdata routine implicitly assumes the destination ResourceRecord is large enough to
+hold MaximumRDSize bytes, but its parameter was a generic ResourceRecord, which need not be that
+large. Changing the parameter to a LargeCacheRecord makes it clearer what the routine requires.
+
Revision 1.90 2005/03/21 00:33:51 shersche
<rdar://problem/4021486> Fix build warnings on Win32 platform
case kDNSType_TXT: mDNS_snprintf(buffer+length, 79-length, "%#s", rd->txt.c); break;
case kDNSType_AAAA: mDNS_snprintf(buffer+length, 79-length, "%.16a", &rd->ipv6); break;
- case kDNSType_SRV: mDNS_snprintf(buffer+length, 79-length, "%##s", rd->srv.target.c); break;
+ case kDNSType_SRV: mDNS_snprintf(buffer+length, 79-length, "%u %u %u %##s",
+ rd->srv.priority, rd->srv.weight, mDNSVal16(rd->srv.port), rd->srv.target.c); break;
default: mDNS_snprintf(buffer+length, 79-length, "RDLen %d: %s", rr->rdlength, rd->data); break;
}
for (ptr = buffer; *ptr; ptr++) if (*ptr < ' ') *ptr='.';
src = type->c; // Put the service type into the domain name
len = *src;
- if (len < 2 || len >= 0x40 || (len > 15 && !SameDomainName(domain, (domainname*)"\x05" "local")))
+ if (len < 2 || len >= 0x40 || (len > 15 && !SameDomainName(domain, &localdomain)))
{
errormsg="Application protocol name must be underscore plus 1-14 characters. See <http://www.dns-sd.org/ServiceTypes.html>";
goto fail;
return(mDNSNULL);
}
+// A service name has the form: instance.application-protocol.transport-protocol.domain
+// DeconstructServiceName is currently fairly forgiving: It doesn't try to enforce character
+// set or length limits for the protocol names, and the final domain is allowed to be empty.
+// However, if the given FQDN doesn't contain at least three labels,
+// DeconstructServiceName will reject it and return mDNSfalse.
mDNSexport mDNSBool DeconstructServiceName(const domainname *const fqdn,
domainlabel *const name, domainname *const type, domainname *const domain)
{
const mDNSu8 *max = fqdn->c + MAX_DOMAIN_NAME;
mDNSu8 *dst;
- dst = name->c; // Extract the service name from the domain name
+ dst = name->c; // Extract the service name
len = *src;
- if (len >= 0x40) { debugf("DeconstructServiceName: service name too long"); return(mDNSfalse); }
+ if (!len) { debugf("DeconstructServiceName: FQDN empty!"); return(mDNSfalse); }
+ if (len >= 0x40) { debugf("DeconstructServiceName: Instance name too long"); return(mDNSfalse); }
for (i=0; i<=len; i++) *dst++ = *src++;
- dst = type->c; // Extract the service type from the domain name
+ dst = type->c; // Extract the service type
len = *src;
- if (len >= 0x40) { debugf("DeconstructServiceName: service type too long"); return(mDNSfalse); }
+ if (!len) { debugf("DeconstructServiceName: FQDN contains only one label!"); return(mDNSfalse); }
+ if (len >= 0x40) { debugf("DeconstructServiceName: Application protocol name too long"); return(mDNSfalse); }
for (i=0; i<=len; i++) *dst++ = *src++;
len = *src;
- if (len >= 0x40) { debugf("DeconstructServiceName: service type too long"); return(mDNSfalse); }
+ if (!len) { debugf("DeconstructServiceName: FQDN contains only two labels!"); return(mDNSfalse); }
+ if (len >= 0x40) { debugf("DeconstructServiceName: Transport protocol name too long"); return(mDNSfalse); }
for (i=0; i<=len; i++) *dst++ = *src++;
- *dst++ = 0; // Put the null root label on the end of the service type
+ *dst++ = 0; // Put terminator on the end of service type
- dst = domain->c; // Extract the service domain from the domain name
+ dst = domain->c; // Extract the service domain
while (*src)
{
len = *src;
if (len >= 0x40)
- { debugf("DeconstructServiceName: service domain label too long"); return(mDNSfalse); }
+ { debugf("DeconstructServiceName: Label in service domain too long"); return(mDNSfalse); }
if (src + 1 + len + 1 >= max)
- { debugf("DeconstructServiceName: service domain too long"); return(mDNSfalse); }
+ { debugf("DeconstructServiceName: Total service domain too long"); return(mDNSfalse); }
for (i=0; i<=len; i++) *dst++ = *src++;
}
*dst++ = 0; // Put the null root label on the end
return(sum);
}
-mDNSexport mDNSBool SameRData(const ResourceRecord *const r1, const ResourceRecord *const r2)
+// r1 has to be a full ResourceRecord including rrtype and rdlength
+// r2 is just a bare RDataBody, which MUST be the same rrtype and rdlength as r1
+mDNSexport mDNSBool SameRDataBody(const ResourceRecord *const r1, const RDataBody *const r2)
{
- if (r1->rrtype != r2->rrtype) return(mDNSfalse);
- if (r1->rdlength != r2->rdlength) return(mDNSfalse);
- if (r1->rdatahash != r2->rdatahash) return(mDNSfalse);
switch(r1->rrtype)
{
case kDNSType_CNAME:// Same as PTR
- case kDNSType_PTR: return(SameDomainName(&r1->rdata->u.name, &r2->rdata->u.name));
+ case kDNSType_PTR: return(SameDomainName(&r1->rdata->u.name, &r2->name));
- case kDNSType_SRV: return(mDNSBool)( r1->rdata->u.srv.priority == r2->rdata->u.srv.priority &&
- r1->rdata->u.srv.weight == r2->rdata->u.srv.weight &&
- r1->rdata->u.srv.port.NotAnInteger == r2->rdata->u.srv.port.NotAnInteger &&
- SameDomainName(&r1->rdata->u.srv.target, &r2->rdata->u.srv.target) );
+ case kDNSType_SRV: return(mDNSBool)( r1->rdata->u.srv.priority == r2->srv.priority &&
+ r1->rdata->u.srv.weight == r2->srv.weight &&
+ r1->rdata->u.srv.port.NotAnInteger == r2->srv.port.NotAnInteger &&
+ SameDomainName(&r1->rdata->u.srv.target, &r2->srv.target) );
- default: return(mDNSPlatformMemSame(r1->rdata->u.data, r2->rdata->u.data, r1->rdlength));
+ default: return(mDNSPlatformMemSame(r1->rdata->u.data, r2->data, r1->rdlength));
}
}
+mDNSexport mDNSBool SameRData(const ResourceRecord *const r1, const ResourceRecord *const r2)
+ {
+ if (r1->rrtype != r2->rrtype) return(mDNSfalse);
+ if (r1->rdlength != r2->rdlength) return(mDNSfalse);
+ if (r1->rdatahash != r2->rdatahash) return(mDNSfalse);
+ return(SameRDataBody(r1, &r2->rdata->u));
+ }
+
mDNSexport mDNSBool SameResourceRecord(ResourceRecord *r1, ResourceRecord *r2)
{
return (r1->namehash == r2->namehash &&
return val;
}
-mDNSlocal const mDNSu8 *getOptRdata(const mDNSu8 *ptr, const mDNSu8 *limit, ResourceRecord *rr, mDNSu16 pktRDLen)
+mDNSlocal const mDNSu8 *getOptRdata(const mDNSu8 *ptr, const mDNSu8 *const limit, LargeCacheRecord *const cr, mDNSu16 pktRDLen)
{
int nread = 0;
+ ResourceRecord *const rr = &cr->r.resrec;
rdataOpt *opt = (rdataOpt *)rr->rdata->u.data;
while (nread < pktRDLen && (mDNSu8 *)opt < rr->rdata->u.data + MaximumRDSize - sizeof(rdataOpt))
CacheRecord *rr = &largecr->r;
mDNSu16 pktrdlength;
- if (largecr == &m->rec && rr->resrec.RecordType)
- LogMsg("GetLargeResourceRecord: m->rec appears to be already in use");
+ if (largecr == &m->rec && largecr->r.resrec.RecordType)
+ LogMsg("GetLargeResourceRecord: m->rec appears to be already in use for %s", CRDisplayString(m, &largecr->r));
rr->next = mDNSNULL;
- rr->resrec.RecordType = RecordType;
rr->resrec.name = &largecr->namestorage;
rr->NextInKAList = mDNSNULL;
// us to look at. If we decide to copy it into the cache, then we'll update m->NextCacheCheck accordingly.
pktrdlength = (mDNSu16)((mDNSu16)ptr[8] << 8 | ptr[9]);
if (ptr[2] & (kDNSClass_UniqueRRSet >> 8))
- rr->resrec.RecordType |= kDNSRecordTypePacketUniqueMask;
+ RecordType |= kDNSRecordTypePacketUniqueMask;
ptr += 10;
if (ptr + pktrdlength > end) { debugf("GetResourceRecord: RDATA exceeds end of packet"); return(mDNSNULL); }
end = ptr + pktrdlength; // Adjust end to indicate the end of the rdata for this resource record
rr->resrec.rdata->u.soa.min = (mDNSu32) ((mDNSu32)ptr[0x10] << 24 | (mDNSu32)ptr[0x11] << 16 | (mDNSu32)ptr[0x12] << 8 | ptr[0x13]);
break;
- case kDNSType_OPT: getOptRdata(ptr, end, &rr->resrec, pktrdlength); break;
+ case kDNSType_OPT: getOptRdata(ptr, end, largecr, pktrdlength); break;
default: if (pktrdlength > rr->resrec.rdata->MaxRDLength)
{
rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
SetNewRData(&rr->resrec, mDNSNULL, 0);
+ // Success! Now fill in RecordType to show this record contains valid data
+ rr->resrec.RecordType = RecordType;
return(ptr + pktrdlength);
}
if (m->mDNS_busy == 0)
{
if (m->timenow)
- LogMsg("mDNS_Lock: m->timenow already set (%ld/%ld)", m->timenow, mDNSPlatformRawTime() + m->timenow_adjust);
- m->timenow = mDNSPlatformRawTime() + m->timenow_adjust;
+ LogMsg("mDNS_Lock: m->timenow already set (%ld/%ld)", m->timenow, mDNS_TimeNow_NoLock(m));
+ m->timenow = mDNS_TimeNow_NoLock(m);
if (m->timenow == 0) m->timenow = 1;
}
else if (m->timenow == 0)
{
LogMsg("mDNS_Lock: m->mDNS_busy is %ld but m->timenow not set", m->mDNS_busy);
- m->timenow = mDNSPlatformRawTime() + m->timenow_adjust;
+ m->timenow = mDNS_TimeNow_NoLock(m);
if (m->timenow == 0) m->timenow = 1;
}
/* -*- Mode: C; tab-width: 4 -*-
*
- * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2002-2006 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
Change History (most recent first):
$Log: mDNS.c,v $
+Revision 1.535.2.3 2006/11/10 19:36:42 cheshire
+Further refinement: Only harmonize TTL if the value we're adjusting it to is at least 2 seconds
+
+Revision 1.535.2.2 2006/10/31 02:11:26 cheshire
+Compile error: Need to put back AllDNSLinkGroupv4 definition
+
+Revision 1.535.2.1 2006/10/31 01:28:06 cheshire
+<rdar://problem/4456945> After service restarts on different port, for a few seconds DNS-SD may return stale port number
+
+Revision 1.535 2006/03/02 20:41:17 cheshire
+<rdar://problem/4111464> After record update, old record sometimes remains in cache
+Minor code tidying and comments to reduce the risk of similar programming errors in future
+
+Revision 1.534 2006/03/02 03:25:46 cheshire
+<rdar://problem/4111464> After record update, old record sometimes remains in cache
+Code to harmonize RRSet TTLs was inadvertently rescuing expiring records
+
+Revision 1.533 2006/02/26 00:54:41 cheshire
+Fixes to avoid code generation warning/error on FreeBSD 7
+
+Revision 1.532 2005/12/02 20:24:36 cheshire
+<rdar://problem/4363209> Adjust cutoff time for KA list by one second
+
+Revision 1.531 2005/12/02 19:05:42 cheshire
+Tidy up constants
+
+Revision 1.530 2005/11/07 01:49:48 cheshire
+For consistency, use NonZeroTime() function instead of ?: expression
+
+Revision 1.529 2005/10/25 23:42:24 cheshire
+<rdar://problem/4316057> Error in ResolveSimultaneousProbe() when type or class don't match
+Changed switch statement to an "if"
+
+Revision 1.528 2005/10/25 23:34:22 cheshire
+<rdar://problem/4316048> RequireGoodbye state not set/respected sometimes when machine going to sleep
+
+Revision 1.527 2005/10/25 22:43:59 cheshire
+Add clarifying comments
+
Revision 1.526 2005/10/20 00:10:33 cheshire
<rdar://problem/4290265> Add check to avoid crashing NAT gateways that have buggy DNS relay code
<rdar://problem/3739115>: TXT Record updates not available for wide-area services
Revision 1.387 2004/07/26 22:49:30 ksekar
-<rdar://problem/3651409>: Feature #9516: Need support for NATPMP in client
+<rdar://problem/3651409>: Feature #9516: Need support for NAT-PMP in client
Revision 1.386 2004/07/13 21:24:24 rpantos
Fix for <rdar://problem/3701120>.
mDNSlocal const mDNSInterfaceID mDNSInterfaceMark = (mDNSInterfaceID)~0;
-#define UnicastDNSPortAsNumber 53
+#define UnicastDNSPortAsNumber 53
+#define NATPMPPortAsNumber 5351
+#define DNSEXTPortAsNumber 5352 // Port used for end-to-end DNS operations like LLQ, Updates with Leases, etc.
#define MulticastDNSPortAsNumber 5353
+#define LoopbackIPCPortAsNumber 5354
+
mDNSexport const mDNSIPPort UnicastDNSPort = { { UnicastDNSPortAsNumber >> 8, UnicastDNSPortAsNumber & 0xFF } };
+mDNSexport const mDNSIPPort NATPMPPort = { { NATPMPPortAsNumber >> 8, NATPMPPortAsNumber & 0xFF } };
+mDNSexport const mDNSIPPort DNSEXTPort = { { DNSEXTPortAsNumber >> 8, DNSEXTPortAsNumber & 0xFF } };
mDNSexport const mDNSIPPort MulticastDNSPort = { { MulticastDNSPortAsNumber >> 8, MulticastDNSPortAsNumber & 0xFF } };
+mDNSexport const mDNSIPPort LoopbackIPCPort = { { LoopbackIPCPortAsNumber >> 8, LoopbackIPCPortAsNumber & 0xFF } };
+
mDNSexport const mDNSv4Addr AllDNSAdminGroup = { { 239, 255, 255, 251 } };
mDNSexport const mDNSv4Addr AllDNSLinkGroupv4 = { { 224, 0, 0, 251 } };
mDNSexport const mDNSv6Addr AllDNSLinkGroupv6 = { { 0xFF,0x02,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xFB } };
mDNSexport const mDNSAddr AllDNSLinkGroup_v4 = { mDNSAddrType_IPv4, { { { 224, 0, 0, 251 } } } };
mDNSexport const mDNSAddr AllDNSLinkGroup_v6 = { mDNSAddrType_IPv6, { { { 0xFF,0x02,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xFB } } } };
-mDNSexport const mDNSOpaque16 zeroID = { { 0, 0 } };
-mDNSexport const mDNSOpaque16 QueryFlags = { { kDNSFlag0_QR_Query | kDNSFlag0_OP_StdQuery, 0 } };
-mDNSexport const mDNSOpaque16 uQueryFlags = { { kDNSFlag0_QR_Query | kDNSFlag0_OP_StdQuery | kDNSFlag0_RD, 0 } };
-mDNSexport const mDNSOpaque16 ResponseFlags = { { kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery | kDNSFlag0_AA, 0 } };
-mDNSexport const mDNSOpaque16 UpdateReqFlags= { { kDNSFlag0_QR_Query | kDNSFlag0_OP_Update, 0 } };
-mDNSexport const mDNSOpaque16 UpdateRespFlags={ { kDNSFlag0_QR_Response | kDNSFlag0_OP_Update, 0 } };
+mDNSexport const mDNSOpaque16 zeroID = { { 0, 0 } };
+mDNSexport const mDNSOpaque16 QueryFlags = { { kDNSFlag0_QR_Query | kDNSFlag0_OP_StdQuery, 0 } };
+mDNSexport const mDNSOpaque16 uQueryFlags = { { kDNSFlag0_QR_Query | kDNSFlag0_OP_StdQuery | kDNSFlag0_RD, 0 } };
+mDNSexport const mDNSOpaque16 ResponseFlags = { { kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery | kDNSFlag0_AA, 0 } };
+mDNSexport const mDNSOpaque16 UpdateReqFlags = { { kDNSFlag0_QR_Query | kDNSFlag0_OP_Update, 0 } };
+mDNSexport const mDNSOpaque16 UpdateRespFlags = { { kDNSFlag0_QR_Response | kDNSFlag0_OP_Update, 0 } };
// Any records bigger than this are considered 'large' records
#define SmallRecordLimit 1024
numDereg++;
responseptr = newptr;
}
- else if (rr->NewRData) // If we have new data for this record
+ else if (rr->NewRData && !m->SleepState) // If we have new data for this record
{
RData *OldRData = rr->resrec.rdata;
mDNSu16 oldrdlength = rr->resrec.rdlength;
if (!newptr && m->omsg.h.numAnswers) break;
numDereg++;
responseptr = newptr;
+ rr->RequireGoodbye = mDNSfalse;
}
// Now try to see if we can fit the update in the same packet (not fatal if we can't)
SetNewRData(&rr->resrec, rr->NewRData, rr->newrdlength);
rr->resrec.rrclass |= kDNSClass_UniqueRRSet; // Temporarily set the cache flush bit so PutResourceRecord will set it
newptr = PutResourceRecord(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec);
rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet; // Make sure to clear cache flush bit back to normal state
- if (newptr) responseptr = newptr;
+ if (newptr) { responseptr = newptr; rr->RequireGoodbye = mDNStrue; }
SetNewRData(&rr->resrec, OldRData, oldrdlength);
}
else
// Note: MUST call SetNextCacheCheckTime any time we change:
// rr->TimeRcvd
-// rr->DelayDelivery
// rr->resrec.rroriginalttl
// rr->UnansweredQueries
// rr->CRActiveQuestion
+// Also, any time we set rr->DelayDelivery we should call SetNextCacheCheckTime to ensure m->NextCacheCheck is set if necessary
+// Clearing rr->DelayDelivery does not require a call to SetNextCacheCheckTime
mDNSlocal void SetNextCacheCheckTime(mDNS *const m, CacheRecord *const rr)
{
rr->NextRequiredQuery = RRExpireTime(rr);
rr->NextInKAList == mDNSNULL && ka != &rr->NextInKAList && // which is not already in the known answer list
rr->resrec.rdlength <= SmallRecordLimit && // which is small enough to sensibly fit in the packet
ResourceRecordAnswersQuestion(&rr->resrec, q) && // which answers our question
- rr->TimeRcvd + TicksTTL(rr)/2 - m->timenow >= 0) // and it is less than half-way to expiry
+ rr->TimeRcvd + TicksTTL(rr)/2 - m->timenow > // and its half-way-to-expiry time is at least 1 second away
+ mDNSPlatformOneSecond) // (also ensures we never include goodbye records with TTL=1)
{
*ka = rr; // Link this record into our known answer chain
ka = &rr->NextInKAList;
mDNSlocal void CacheRecordDeferredAdd(mDNS *const m, CacheRecord *rr)
{
- rr->DelayDelivery = 0;
+ rr->DelayDelivery = 0; // Note, only need to call SetNextCacheCheckTime() when DelayDelivery is set, not when it's cleared
if (m->CurrentQuestion) LogMsg("CacheRecordDeferredAdd ERROR m->CurrentQuestion already set");
m->CurrentQuestion = m->Questions;
while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
if (threshhold - RRExpireTime(rr) >= 0) // If we have records about to expire within a second
if (delay - RRExpireTime(rr) < 0) // then delay until after they've been deleted
delay = RRExpireTime(rr);
- if (delay - start > 0) return(delay ? delay : 1); // Make sure we return non-zero if we want to delay
+ if (delay - start > 0) return(NonZeroTime(delay));
else return(0);
}
}
}
m->CurrentQuestion = mDNSNULL;
+ SetNextCacheCheckTime(m, rr);
}
// NoCacheAnswer is only called from mDNSCoreReceiveResponse, *never* directly as a result of a client API call.
mDNSlocal void NoCacheAnswer(mDNS *const m, CacheRecord *rr)
{
LogMsg("No cache space: Delivering non-cached result for %##s", m->rec.r.resrec.name->c);
- if (m->CurrentQuestion) LogMsg("CacheRecordAdd ERROR m->CurrentQuestion already set");
+ if (m->CurrentQuestion) LogMsg("NoCacheAnswer ERROR m->CurrentQuestion already set");
m->CurrentQuestion = m->Questions;
while (m->CurrentQuestion)
{
m->CurrentQuestion = q->next;
if (ResourceRecordAnswersQuestion(&rr->resrec, q))
{
- verbosedebugf("CacheRecordRmv %p %##s (%s)", rr, rr->resrec.name->c, DNSTypeName(rr->resrec.rrtype));
+ verbosedebugf("CacheRecordRmv %p %s", rr, CRDisplayString(m, rr));
if (q->CurrentAnswers == 0)
LogMsg("CacheRecordRmv ERROR: How can CurrentAnswers already be zero for %p %##s (%s)?", q, q->qname.c, DNSTypeName(q->qtype));
else
if (*pktptr > *ourptr) return(-1); // Our data is numerically lower; We lost
if (*pktptr < *ourptr) return(+1); // Packet data is numerically lower; We won
- debugf("CompareRData: How did we get here?");
+ LogMsg("CompareRData ERROR: Invalid state");
return(-1);
}
int result = (int)our->resrec.rrclass - (int)m->rec.r.resrec.rrclass;
if (!result) result = (int)our->resrec.rrtype - (int)m->rec.r.resrec.rrtype;
if (!result) result = CompareRData(our, &m->rec.r);
- switch (result)
+ if (result > 0)
+ debugf("ResolveSimultaneousProbe: %##s (%s): We won", our->resrec.name->c, DNSTypeName(our->resrec.rrtype));
+ else if (result < 0)
{
- case 1: debugf("ResolveSimultaneousProbe: %##s (%s): We won", our->resrec.name->c, DNSTypeName(our->resrec.rrtype));
- break;
- case 0: break;
- case -1: debugf("ResolveSimultaneousProbe: %##s (%s): We lost", our->resrec.name->c, DNSTypeName(our->resrec.rrtype));
- mDNS_Deregister_internal(m, our, mDNS_Dereg_conflict);
- goto exit;
+ debugf("ResolveSimultaneousProbe: %##s (%s): We lost", our->resrec.name->c, DNSTypeName(our->resrec.rrtype));
+ mDNS_Deregister_internal(m, our, mDNS_Dereg_conflict);
+ goto exit;
}
}
}
const mDNSInterfaceID InterfaceID)
{
int i;
- const mDNSu8 *ptr = LocateAnswers(response, end); // We ignore questions (if any) in a DNS response packet
- CacheRecord *CacheFlushRecords = (CacheRecord*)1; // "(CacheRecord*)1" is special (non-zero) end-of-list marker
+
+ // We ignore questions (if any) in a DNS response packet
+ const mDNSu8 *ptr = LocateAnswers(response, end);
+
+ // "(CacheRecord*)1" is a special (non-zero) end-of-list marker
+ // We use this non-zero marker so that records in our CacheFlushRecords list will always have NextInCFList
+ // set non-zero, and that tells GetCacheEntity() that they're not, at this moment, eligible for recycling.
+ CacheRecord *CacheFlushRecords = (CacheRecord*)1;
CacheRecord **cfp = &CacheFlushRecords;
// All records in a DNS response packet are treated as equally valid statements of truth. If we want
rr->DelayDelivery = m->timenow + mDNSPlatformOneSecond; // to delay delivery of this 'add' event
else
rr->DelayDelivery = CheckForSoonToExpireRecords(m, rr->resrec.name, rr->resrec.namehash, slot);
- CacheRecordAdd(m, rr);
- // MUST do this AFTER CacheRecordAdd(), because that's what sets CRActiveQuestion for us
- SetNextCacheCheckTime(m, rr);
+ CacheRecordAdd(m, rr); // CacheRecordAdd calls SetNextCacheCheckTime(m, rr); for us
}
}
}
r1->NextInCFList = mDNSNULL;
for (r2 = cg ? cg->members : mDNSNULL; r2; r2=r2->next)
if (SameResourceRecordSignature(&r1->resrec, &r2->resrec))
- {
- // If record is recent, just ensure the whole RRSet has the same TTL (as required by DNS semantics)
- // else, if record is old, mark it to be flushed
- if (m->timenow - r2->TimeRcvd < mDNSPlatformOneSecond)
- r2->resrec.rroriginalttl = r1->resrec.rroriginalttl;
- else
+ if (RRExpireTime(r2) - m->timenow > mDNSPlatformOneSecond)
{
- verbosedebugf("Cache flush %p X %p %##s (%s)", r1, r2, r2->resrec.name->c, DNSTypeName(r2->resrec.rrtype));
- // We set stale records to expire in one second.
- // This gives the owner a chance to rescue it if necessary.
- // This is important in the case of multi-homing and bridged networks:
- // Suppose host X is on Ethernet. X then connects to an AirPort base station, which happens to be
- // bridged onto the same Ethernet. When X announces its AirPort IP address with the cache-flush bit
- // set, the AirPort packet will be bridged onto the Ethernet, and all other hosts on the Ethernet
- // will promptly delete their cached copies of the (still valid) Ethernet IP address record.
- // By delaying the deletion by one second, we give X a change to notice that this bridging has
- // happened, and re-announce its Ethernet IP address to rescue it from deletion from all our caches.
- // We set UnansweredQueries to MaxUnansweredQueries to avoid expensive and unnecessary
- // final expiration queries for this record.
- r2->resrec.rroriginalttl = 1;
- r2->TimeRcvd = m->timenow;
- r2->UnansweredQueries = MaxUnansweredQueries;
+ // If record is recent, just ensure the whole RRSet has the same TTL (as required by DNS semantics)
+ // else, if record is old, mark it to be flushed
+ if (m->timenow - r2->TimeRcvd < mDNSPlatformOneSecond)
+ {
+ if (r2->resrec.rroriginalttl != r1->resrec.rroriginalttl && r1->resrec.rroriginalttl > 1)
+ r2->resrec.rroriginalttl = r1->resrec.rroriginalttl;
+ }
+ else // else, if record is old, mark it to be flushed
+ {
+ verbosedebugf("Cache flush %p X %p %s", r1, r2, CRDisplayString(m, r2));
+ // We set stale records to expire in one second.
+ // This gives the owner a chance to rescue it if necessary.
+ // This is important in the case of multi-homing and bridged networks:
+ // Suppose host X is on Ethernet. X then connects to an AirPort base station, which happens to be
+ // bridged onto the same Ethernet. When X announces its AirPort IP address with the cache-flush bit
+ // set, the AirPort packet will be bridged onto the Ethernet, and all other hosts on the Ethernet
+ // will promptly delete their cached copies of the (still valid) Ethernet IP address record.
+ // By delaying the deletion by one second, we give X a change to notice that this bridging has
+ // happened, and re-announce its Ethernet IP address to rescue it from deletion from all our caches.
+ // We set UnansweredQueries to MaxUnansweredQueries to avoid expensive and unnecessary
+ // final expiration queries for this record.
+ r2->resrec.rroriginalttl = 1;
+ r2->UnansweredQueries = MaxUnansweredQueries;
+ }
+ r2->TimeRcvd = m->timenow;
SetNextCacheCheckTime(m, r2);
}
- }
if (r1->DelayDelivery) // If we were planning to delay delivery of this record, see if we still need to
{
+ // Note, only need to call SetNextCacheCheckTime() when DelayDelivery is set, not when it's cleared
r1->DelayDelivery = CheckForSoonToExpireRecords(m, r1->resrec.name, r1->resrec.namehash, slot);
if (!r1->DelayDelivery) CacheRecordDeferredAdd(m, r1);
}
const mDNSu8 UpdateR = kDNSFlag0_QR_Response | kDNSFlag0_OP_Update;
#ifndef UNICAST_DISABLED
- mDNSIPPort NATPort = mDNSOpaque16fromIntVal(NATMAP_PORT);
-
- if (srcport.NotAnInteger == NATPort.NotAnInteger)
+ if (srcport.NotAnInteger == NATPMPPort.NotAnInteger)
{
mDNS_Lock(m);
uDNS_ReceiveNATMap(m, pkt, (mDNSu16)(end - (mDNSu8 *)pkt));
/* -*- Mode: C; tab-width: 4 -*-
*
- * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2003-2006 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
Change History (most recent first):
$Log: uds_daemon.c,v $
+Revision 1.199.2.1 2007/01/06 03:22:03 cheshire
+<rdar://problem/4912058> Crash at resolve_result_callback + 192
+
+Revision 1.199 2006/06/28 08:53:39 cheshire
+Added (commented out) debugging messages
+
+Revision 1.198 2006/06/27 20:16:07 cheshire
+Fix code layout
+
+Revision 1.197 2006/05/18 01:32:35 cheshire
+<rdar://problem/4472706> iChat: Lost connection with Bonjour
+(mDNSResponder insufficiently defensive against malformed browsing PTR responses)
+
+Revision 1.196 2006/05/05 07:07:13 cheshire
+<rdar://problem/4538206> mDNSResponder fails when UDS reads deliver partial data
+
+Revision 1.195 2006/04/25 20:56:28 mkrochma
+Added comment about previous checkin
+
+Revision 1.194 2006/04/25 18:29:36 mkrochma
+Workaround for warning: unused variable 'status' when building mDNSPosix
+
+Revision 1.193 2006/03/19 17:14:38 cheshire
+<rdar://problem/4483117> Need faster purging of stale records
+read_rr_from_ipc_msg was not setting namehash and rdatahash
+
+Revision 1.192 2006/03/18 20:58:32 cheshire
+Misplaced curly brace
+
+Revision 1.191 2006/03/10 22:19:43 cheshire
+Update debugging message in resolve_result_callback() to indicate whether event is ADD or RMV
+
+Revision 1.190 2006/03/10 21:56:12 cheshire
+<rdar://problem/4111464> After record update, old record sometimes remains in cache
+When service TXT and SRV record both change, clients with active resolve calls get *two* callbacks, one
+when the TXT data changes, and then immediately afterwards a second callback with the new port number
+This change suppresses the first unneccessary (and confusing) callback
+
+Revision 1.189 2006/01/06 00:56:31 cheshire
+<rdar://problem/4400573> Should remove PID file on exit
+
+Revision 1.188 2005/10/11 22:15:03 cheshire
+<rdar://problem/4296042> Add memory corruption safeguards to uds_daemon.c
+Only compile uds_validatelists() when building for Mac OS X
+
+Revision 1.187 2005/10/11 20:30:27 cheshire
+<rdar://problem/4296042> Add memory corruption safeguards to uds_daemon.c
+
+Revision 1.186 2005/09/12 07:11:53 herscher
+<rdar://problem/4248878> Lazily call RegisterSearchDomains to workaround crashes of several routers. This code is conditionally compiled, and currently is only enabled on Windows platforms.
+
+Revision 1.185 2005/07/29 00:55:10 ksekar
+Removed validation check in uds_validatelists which generated false alarms
+
+Revision 1.184 2005/07/04 22:40:26 cheshire
+Additional debugging code to help catch memory corruption
+
Revision 1.183 2005/06/13 22:39:11 cheshire
<rdar://problem/4144870> Missing return statement in handle_enum_request() error handling
#if defined(_WIN32)
#include <process.h>
+#define MDNS_LAZY_REGISTER_SEARCH_DOMAINS
#define dnssd_strerror(X) win32_strerror(X)
#define usleep(X) Sleep(((X)+999)/1000)
-static char * win32_strerror(int inErrorCode);
+static char * win32_strerror(int inErrorCode);
#else
#include <fcntl.h>
#include <errno.h>
#endif // LOCAL_PEERCRED
#endif //__MACOSX__
+#if defined(MDNS_LAZY_REGISTER_SEARCH_DOMAINS)
+extern mStatus dDNS_RegisterSearchDomains( mDNS * const m );
+#endif
+
// Types and Data Structures
// ----------------------------------------------------------------------
// const ResourceRecord *srv;
mDNSBool srv;
mDNSBool txt;
- domainname target;
- mDNSIPPort port;
+ rdataSRV srvdata;
mDNSu16 txtlen;
mDNSu8 txtdata[AbsoluteMaxDNSMessageData];
} resolve_termination_t;
#define MSG_PAD_BYTES 5 // pad message buffer (read from client) with n zero'd bytes to guarantee
// n get_string() calls w/o buffer overrun
// private function prototypes
-static void connect_callback(void *info);
-static int read_msg(request_state *rs);
-static int send_msg(reply_state *rs);
-static void abort_request(request_state *rs);
-static void request_callback(void *info);
-static void handle_resolve_request(request_state *rstate);
-static void question_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord);
-static void question_termination_callback(void *context);
-static void handle_browse_request(request_state *request);
-static void browse_termination_callback(void *context);
-static void browse_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord);
-static void handle_regservice_request(request_state *request);
-static void regservice_termination_callback(void *context);
-static void process_service_registration(ServiceRecordSet *const srs, mDNSBool SuppressError);
-static void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, mStatus result);
-static mStatus handle_add_request(request_state *rstate);
-static mStatus handle_update_request(request_state *rstate);
-static mStatus gen_rr_response(domainname *servicename, mDNSInterfaceID id, request_state *request, reply_state **rep);
-static void append_reply(request_state *req, reply_state *rep);
-static int build_domainname_from_strings(domainname *srv, char *name, char *regtype, char *domain);
-static void enum_termination_callback(void *context);
-static void enum_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord);
-static void handle_query_request(request_state *rstate);
-static reply_state *format_enumeration_reply(request_state *rstate, const char *domain, DNSServiceFlags flags, uint32_t ifi, DNSServiceErrorType err);
-static void handle_enum_request(request_state *rstate);
-static mStatus handle_regrecord_request(request_state *rstate);
-static void regrecord_callback(mDNS *const m, AuthRecord * rr, mStatus result);
-static void connected_registration_termination(void *context);
-static void handle_reconfirm_request(request_state *rstate);
-static AuthRecord *read_rr_from_ipc_msg(char *msgbuf, int ttl, int validate_flags);
-static mStatus handle_removerecord_request(request_state *rstate);
-static void reset_connected_rstate(request_state *rstate);
-static int deliver_error(request_state *rstate, mStatus err);
-static int deliver_async_error(request_state *rs, reply_op_t op, mStatus err);
-static transfer_state send_undelivered_error(request_state *rs);
-static reply_state *create_reply(reply_op_t op, size_t datalen, request_state *request);
-static void update_callback(mDNS *const m, AuthRecord *const rr, RData *oldrd);
-static void my_perror(char *errmsg);
-static void unlink_request(request_state *rs);
-static void resolve_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord);
-static void resolve_termination_callback(void *context);
-static int validate_message(request_state *rstate);
-static mStatus remove_extra(request_state *rstate, service_instance *serv);
-static mStatus remove_record(request_state *rstate);
-static void free_service_instance(service_instance *srv);
-static uint32_t dnssd_htonl(uint32_t l);
-static void handle_setdomain_request(request_state *rstate);
+mDNSlocal void connect_callback(void *info);
+mDNSlocal int read_msg(request_state *rs);
+mDNSlocal int send_msg(reply_state *rs);
+mDNSlocal void abort_request(request_state *rs);
+mDNSlocal void request_callback(void *info);
+mDNSlocal void handle_resolve_request(request_state *rstate);
+mDNSlocal void question_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord);
+mDNSlocal void question_termination_callback(void *context);
+mDNSlocal void handle_browse_request(request_state *request);
+mDNSlocal void browse_termination_callback(void *context);
+mDNSlocal void handle_regservice_request(request_state *request);
+mDNSlocal void regservice_termination_callback(void *context);
+mDNSlocal void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, mStatus result);
+mDNSlocal mStatus handle_add_request(request_state *rstate);
+mDNSlocal mStatus handle_update_request(request_state *rstate);
+mDNSlocal void append_reply(request_state *req, reply_state *rep);
+mDNSlocal int build_domainname_from_strings(domainname *srv, char *name, char *regtype, char *domain);
+mDNSlocal void enum_termination_callback(void *context);
+mDNSlocal void enum_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord);
+mDNSlocal void handle_query_request(request_state *rstate);
+mDNSlocal reply_state *format_enumeration_reply(request_state *rstate, const char *domain, DNSServiceFlags flags, uint32_t ifi, DNSServiceErrorType err);
+mDNSlocal void handle_enum_request(request_state *rstate);
+mDNSlocal mStatus handle_regrecord_request(request_state *rstate);
+mDNSlocal void regrecord_callback(mDNS *const m, AuthRecord * rr, mStatus result);
+mDNSlocal void connected_registration_termination(void *context);
+mDNSlocal void handle_reconfirm_request(request_state *rstate);
+mDNSlocal AuthRecord *read_rr_from_ipc_msg(char *msgbuf, int ttl, int validate_flags);
+mDNSlocal mStatus handle_removerecord_request(request_state *rstate);
+mDNSlocal void reset_connected_rstate(request_state *rstate);
+mDNSlocal int deliver_error(request_state *rstate, mStatus err);
+mDNSlocal int deliver_async_error(request_state *rs, reply_op_t op, mStatus err);
+mDNSlocal transfer_state send_undelivered_error(request_state *rs);
+mDNSlocal reply_state *create_reply(reply_op_t op, size_t datalen, request_state *request);
+mDNSlocal void update_callback(mDNS *const m, AuthRecord *const rr, RData *oldrd);
+mDNSlocal void my_perror(char *errmsg);
+mDNSlocal void unlink_request(request_state *rs);
+mDNSlocal void resolve_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord);
+mDNSlocal void resolve_termination_callback(void *context);
+mDNSlocal int validate_message(request_state *rstate);
+mDNSlocal mStatus remove_extra(request_state *rstate, service_instance *serv);
+mDNSlocal mStatus remove_record(request_state *rstate);
+mDNSlocal void free_service_instance(service_instance *srv);
+mDNSlocal uint32_t dnssd_htonl(uint32_t l);
+mDNSlocal void handle_setdomain_request(request_state *rstate);
// initialization, setup/teardown functions
}
}
-static void FatalError(char *errmsg)
+mDNSlocal void FatalError(char *errmsg)
{
LogMsg("%s: %s", errmsg, dnssd_strerror(dnssd_errno()));
*(long*)0 = 0; // On OS X abort() doesn't generate a crash log, but writing to zero does
debugf("Unable to remove %s", MDNS_UDS_SERVERPATH);
#endif
+ if (PID_FILE[0]) unlink(PID_FILE);
+
return 0;
}
else if (nextevent - now > mDNSPlatformOneSecond) nextevent = now + mDNSPlatformOneSecond; // try again in a second
}
if (result == t_terminated || result == t_error)
- //since we're already doing a list traversal, we unlink the request manunally instead of calling unlink_request()
+ //since we're already doing a list traversal, we unlink the request manually instead of calling unlink_request()
{
tmp = req;
if (prev) prev->next = req->next;
return nextevent;
}
-void udsserver_info(mDNS *const m)
+mDNSexport void udsserver_info(mDNS *const m)
{
mDNSs32 now = mDNS_TimeNow(m);
mDNSu32 CacheUsed = 0, CacheActive = 0;
LogMsgNoIdent("Timenow 0x%08lX (%ld)", (mDNSu32)now, now);
+ LogMsgNoIdent("Slt Q TTL U Type if len rdata");
for (slot = 0; slot < CACHE_HASH_SLOTS; slot++)
for(cg = m->rrcache_hash[slot]; cg; cg=cg->next)
{
mDNSs32 remain = rr->resrec.rroriginalttl - (now - rr->TimeRcvd) / mDNSPlatformOneSecond;
CacheUsed++;
if (rr->CRActiveQuestion) CacheActive++;
- LogMsgNoIdent("%s%6ld %s%-6s%-6s%s",
- rr->CRActiveQuestion ? "*" : " ", remain,
- (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) ? "-" : " ", DNSTypeName(rr->resrec.rrtype),
- ((NetworkInterfaceInfo *)rr->resrec.InterfaceID)->ifname, CRDisplayString(m, rr));
+ LogMsgNoIdent("%3d %s%6ld %s %-6s%-6s%s",
+ slot,
+ rr->CRActiveQuestion ? "*" : " ",
+ remain,
+ (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) ? "-" : " ",
+ DNSTypeName(rr->resrec.rrtype),
+ ((NetworkInterfaceInfo *)rr->resrec.InterfaceID)->ifname,
+ CRDisplayString(m, rr));
usleep(1000); // Limit rate a little so we don't flood syslog too fast
}
}
LogMsgNoIdent("Timenow 0x%08lX (%ld)", (mDNSu32)now, now);
}
-static void rename_service(service_instance *srv)
+#if __MACOSX__ && MACOSX_MDNS_MALLOC_DEBUGGING
+mDNSexport void uds_validatelists(void)
+ {
+ request_state *req;
+ for (req = all_requests; req; req=req->next)
+ if (req->sd < 0 && req->sd != -2)
+ LogMemCorruption("UDS request list: %p is garbage (%X)", req, req->sd);
+ }
+#endif
+
+mDNSlocal void rename_service(service_instance *srv)
{
if (srv->autoname && !SameDomainLabel(srv->name.c, gmDNS->nicelabel.c))
{
}
}
-void udsserver_handle_configchange(void)
+mDNSexport void udsserver_handle_configchange(void)
{
request_state *req;
-
for (req = all_requests; req; req = req->next)
{
if (req->service_registration)
}
}
-static void connect_callback(void *info)
+mDNSlocal void connect_callback(void *info)
{
dnssd_sock_t sd;
dnssd_socklen_t len;
}
// handler
-static void request_callback(void *info)
+mDNSlocal void request_callback(void *info)
{
request_state *rstate = info;
transfer_state result;
return;
}
+ //LogOperation("request_callback: Opened dedicated errfd %d", errfd);
+
#if defined(USE_TCP_LOOPBACK)
{
mDNSOpaque16 port;
strcpy(cliaddr.sun_path, ctrl_path);
}
#endif
+ //LogOperation("request_callback: Connecting to “%s”", cliaddr.sun_path);
if (connect(errfd, (struct sockaddr *)&cliaddr, sizeof(cliaddr)) < 0)
{
+ //LogOperation("request_callback: Couldn't connect to “%s”", cliaddr.sun_path);
my_perror("ERROR: connect");
abort_request(rstate);
unlink_request(rstate);
default: LogMsg("%3d: ERROR: udsserver_recv_request - unsupported request type: %d", rstate->sd, rstate->hdr.op);
}
+ //LogOperation("request_callback: Returning error code %d on socket %d", err, errfd);
err = dnssd_htonl(err);
nwritten = send(errfd, (dnssd_sockbuf_t) &err, sizeof(err), 0);
// On a freshly-created Unix Domain Socket, the kernel should *never* fail to buffer a four-byte write for us.
if (nwritten < (int)sizeof(err))
LogMsg("ERROR: failed to write error response back to caller: %d %d %s",
nwritten, dnssd_errno(), dnssd_strerror(dnssd_errno()));
+ //else LogOperation("request_callback: Returned error code %d on socket %d", err, errfd);
dnssd_close(errfd);
+ //LogOperation("request_callback: Closed errfd %d", errfd);
reset_connected_rstate(rstate); // Reset ready to accept the next request on this pipe
}
else
// massage the name parameters appropriately, but the rest of the operations (making the query call,
// delivering the result to the client, and termination) are identical.
-static void handle_query_request(request_state *rstate)
+mDNSlocal void handle_query_request(request_state *rstate)
{
DNSServiceFlags flags;
uint32_t ifi;
return;
}
-static void handle_resolve_request(request_state *rstate)
+mDNSlocal void handle_resolve_request(request_state *rstate)
{
DNSServiceFlags flags;
uint32_t interfaceIndex;
unlink_request(rstate);
}
-static void resolve_termination_callback(void *context)
+mDNSlocal void resolve_termination_callback(void *context)
{
resolve_termination_t *term = context;
request_state *rs;
rs->termination_context = NULL;
}
-static void resolve_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
-{
+mDNSlocal void resolve_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
+ {
size_t len = 0;
char fullname[MAX_ESCAPED_DOMAIN_NAME], target[MAX_ESCAPED_DOMAIN_NAME];
char *data;
resolve_termination_t *res = rs->termination_context;
(void)m; // Unused
- LogOperation("%3d: DNSServiceResolve(%##s, %s) RESULT %s", rs->sd, question->qname.c, DNSTypeName(question->qtype), RRDisplayString(m, answer));
+ LogOperation("%3d: DNSServiceResolve(%##s, %s) %s %s",
+ rs->sd, question->qname.c, DNSTypeName(question->qtype), AddRecord ? "ADD" : "RMV", RRDisplayString(m, answer));
// This code used to do this trick of just keeping a copy of the pointer to
// the answer record in the cache, but the unicast query code doesn't currently
if (!AddRecord)
{
- // if (answer->rrtype == kDNSType_TXT && res->txt == answer) res->txt = mDNSNULL;
+ // After unicast query code is updated to store its records in the common cache, use this...
// if (answer->rrtype == kDNSType_SRV && res->srv == answer) res->srv = mDNSNULL;
+ // if (answer->rrtype == kDNSType_TXT && res->txt == answer) res->txt = mDNSNULL;
+ // intead of this...
+ if (answer->rrtype == kDNSType_SRV && res->srv && SameRDataBody(answer, (RDataBody *)&res->srvdata))
+ res->srv = mDNSfalse;
+ if (answer->rrtype == kDNSType_TXT && res->txt && answer->rdlength == res->txtlen && SameRDataBody(answer, (RDataBody *)&res->txtdata))
+ res->txt = mDNSfalse;
return;
}
- // if (answer->rrtype == kDNSType_TXT) res->txt = answer;
+ // After unicast query code is updated to store its records in the common cache, use this...
// if (answer->rrtype == kDNSType_SRV) res->srv = answer;
-
+ // if (answer->rrtype == kDNSType_TXT) res->txt = answer;
+ // intead of this...
if (answer->rrtype == kDNSType_SRV)
- {
- AssignDomainName(&res->target, &answer->rdata->u.srv.target);
- res->port = answer->rdata->u.srv.port;
- res->srv = mDNStrue;
- }
+ {
+ // Don't copy structure in its entirety, because the CacheEntity may be an intentionally truncated object
+ // (to economize on space) and reading past the end may run into unmapped memory, causing a crash.
+ //res->srvdata = answer->rdata->u.srv;
+ // The AssignDomainName() macro is smart enough to only copy the valid part of the name, and not
+ // try to copy the full 255 bytes which may not all be there.
+ AssignDomainName(&res->srvdata.target, &answer->rdata->u.srv.target);
+ res->srvdata.port = answer->rdata->u.srv.port;
+ res->srv = mDNStrue;
+ }
if (answer->rrtype == kDNSType_TXT)
{
if (answer->rdlength > AbsoluteMaxDNSMessageData) return;
if (!res->txt || !res->srv) return; // only deliver result to client if we have both answers
ConvertDomainNameToCString(answer->name, fullname);
- ConvertDomainNameToCString(&res->target, target);
+ ConvertDomainNameToCString(&res->srvdata.target, target);
// calculate reply length
len += sizeof(DNSServiceFlags);
// write reply data to message
put_string(fullname, &data);
put_string(target, &data);
- *data++ = res->port.b[0];
- *data++ = res->port.b[1];
+ *data++ = res->srvdata.port.b[0];
+ *data++ = res->srvdata.port.b[1];
put_short(res->txtlen, &data);
put_rdata(res->txtlen, res->txtdata, &data);
}
// what gets called when a resolve is completed and we need to send the data back to the client
-static void question_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
+mDNSlocal void question_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
{
char *data;
char name[MAX_ESCAPED_DOMAIN_NAME];
rep = create_reply(query_reply, len, req);
rep->rhdr->flags = dnssd_htonl(AddRecord ? kDNSServiceFlagsAdd : 0);
- rep->rhdr->ifi = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, answer->InterfaceID));
+ rep->rhdr->ifi = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, answer->InterfaceID));
rep->rhdr->error = dnssd_htonl(kDNSServiceErr_NoError);
data = rep->sdata;
return;
}
-static void question_termination_callback(void *context)
+mDNSlocal void question_termination_callback(void *context)
{
DNSQuestion *q = context;
LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) STOP", ((request_state *)q->QuestionContext)->sd, q->qname.c, DNSTypeName(q->qtype));
// If there's a comma followed by another character,
// FindFirstSubType overwrites the comma with a nul and returns the pointer to the next character.
// Otherwise, it returns a pointer to the final nul at the end of the string
-static char *FindFirstSubType(char *p)
+mDNSlocal char *FindFirstSubType(char *p)
{
while (*p)
{
// FindNextSubType overwrites the comma with a nul and returns the pointer to the next character.
// If it finds an illegal unescaped dot in the subtype name, it returns mDNSNULL
// Otherwise, it returns a pointer to the final nul at the end of the string
-static char *FindNextSubType(char *p)
+mDNSlocal char *FindNextSubType(char *p)
{
while (*p)
{
}
#ifdef _HAVE_SETDOMAIN_SUPPORT_
-static void free_defdomain(mDNS *const m, AuthRecord *const rr, mStatus result)
+mDNSlocal void free_defdomain(mDNS *const m, AuthRecord *const rr, mStatus result)
{
(void)m; // unused
if (result == mStatus_MemFree) free(rr->RecordContext); // context is the enclosing list structure
}
#endif
-static void handle_setdomain_request(request_state *request)
+mDNSlocal void handle_setdomain_request(request_state *request)
{
mStatus err = mStatus_NoError;
char *ptr;
unlink_request(request);
}
-static mStatus add_domain_to_browser(browser_info_t *info, const domainname *d)
+// Generates a response message giving name, type, domain, plus interface index,
+// suitable for a browse result or service registration result.
+// On successful completion rep is set to point to a malloc'd reply_state struct
+mDNSlocal mStatus GenerateNTDResponse(domainname *servicename, mDNSInterfaceID id, request_state *request, reply_state **rep)
+ {
+ domainlabel name;
+ domainname type, dom;
+ *rep = NULL;
+ if (!DeconstructServiceName(servicename, &name, &type, &dom))
+ return kDNSServiceErr_Invalid;
+ else
+ {
+ char namestr[MAX_DOMAIN_LABEL+1];
+ char typestr[MAX_ESCAPED_DOMAIN_NAME];
+ char domstr [MAX_ESCAPED_DOMAIN_NAME];
+ int len;
+ char *data;
+
+ ConvertDomainLabelToCString_unescaped(&name, namestr);
+ ConvertDomainNameToCString(&type, typestr);
+ ConvertDomainNameToCString(&dom, domstr);
+
+ // Calculate reply data length
+ len = sizeof(DNSServiceFlags);
+ len += sizeof(uint32_t); // if index
+ len += sizeof(DNSServiceErrorType);
+ len += (int) (strlen(namestr) + 1);
+ len += (int) (strlen(typestr) + 1);
+ len += (int) (strlen(domstr) + 1);
+
+ // Build reply header
+ *rep = create_reply(query_reply, len, request);
+ (*rep)->rhdr->flags = dnssd_htonl(0);
+ (*rep)->rhdr->ifi = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, id));
+ (*rep)->rhdr->error = dnssd_htonl(kDNSServiceErr_NoError);
+
+ // Build reply body
+ data = (*rep)->sdata;
+ put_string(namestr, &data);
+ put_string(typestr, &data);
+ put_string(domstr, &data);
+
+ return mStatus_NoError;
+ }
+ }
+
+mDNSlocal void FoundInstance(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
+ {
+ request_state *req = question->QuestionContext;
+ reply_state *rep;
+ (void)m; // Unused
+
+ if (answer->rrtype != kDNSType_PTR)
+ { LogMsg("%3d: FoundInstance: Should not be called with rrtype %d (not a PTR record)", req->sd, answer->rrtype); return; }
+
+ if (GenerateNTDResponse(&answer->rdata->u.name, answer->InterfaceID, req, &rep) != mStatus_NoError)
+ {
+ LogMsg("%3d: FoundInstance: %##s PTR %##s received from network is not valid DNS-SD service pointer",
+ req->sd, answer->name->c, answer->rdata->u.name.c);
+ return;
+ }
+
+ LogOperation("%3d: DNSServiceBrowse(%##s, %s) RESULT %s %s",
+ req->sd, question->qname.c, DNSTypeName(question->qtype), AddRecord ? "Add" : "Rmv", RRDisplayString(m, answer));
+
+ if (AddRecord) rep->rhdr->flags |= dnssd_htonl(kDNSServiceFlagsAdd);
+ append_reply(req, rep);
+ }
+
+mDNSlocal mStatus add_domain_to_browser(browser_info_t *info, const domainname *d)
{
browser_t *b, *p;
mStatus err;
-
+
for (p = info->browsers; p; p = p->next)
{
if (SameDomainName(&p->domain, d))
b = mallocL("browser_t", sizeof(*b));
if (!b) return mStatus_NoMemoryErr;
AssignDomainName(&b->domain, d);
- err = mDNS_StartBrowse(gmDNS, &b->q, &info->regtype, d, info->interface_id, info->ForceMCast, browse_result_callback, info->rstate);
+ err = mDNS_StartBrowse(gmDNS, &b->q, &info->regtype, d, info->interface_id, info->ForceMCast, FoundInstance, info->rstate);
if (err)
{
LogMsg("mDNS_StartBrowse returned %d for type %##s domain %##s", err, info->regtype.c, d->c);
return err;
}
-static void handle_browse_request(request_state *request)
+mDNSlocal void handle_browse_request(request_state *request)
{
DNSServiceFlags flags;
uint32_t interfaceIndex;
InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(gmDNS, interfaceIndex);
if (interfaceIndex && !InterfaceID) { err = mStatus_BadParamErr; goto error; }
+#if defined(MDNS_LAZY_REGISTER_SEARCH_DOMAINS)
+ if ( !domain || ( domain[0] == '\0' ) )
+ {
+ dDNS_RegisterSearchDomains( gmDNS );
+ }
+#endif
+
typedn.c[0] = 0;
NumSubTypes = ChopSubTypes(regtype); // Note: Modifies regtype string to remove trailing subtypes
if (NumSubTypes < 0 || NumSubTypes > 1) { err = mStatus_BadParamErr; goto error; }
unlink_request(request);
}
-static void browse_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
- {
- request_state *req = question->QuestionContext;
- reply_state *rep;
- mStatus err;
- (void)m; // Unused
- LogOperation("%3d: DNSServiceBrowse(%##s, %s) RESULT %s %s",
- req->sd, question->qname.c, DNSTypeName(question->qtype), AddRecord ? "Add" : "Rmv", RRDisplayString(m, answer));
-
- err = gen_rr_response(&answer->rdata->u.name, answer->InterfaceID, req, &rep);
- if (err)
- {
- if (deliver_async_error(req, browse_reply, err) < 0)
- {
- abort_request(req);
- unlink_request(req);
- }
- return;
- }
- if (AddRecord) rep->rhdr->flags |= dnssd_htonl(kDNSServiceFlagsAdd); // non-zero TTL indicates add
- append_reply(req, rep);
- return;
- }
-
-static void browse_termination_callback(void *context)
+mDNSlocal void browse_termination_callback(void *context)
{
browser_info_t *info = context;
browser_t *ptr;
return(count);
}
-static mStatus register_service_instance(request_state *request, const domainname *domain)
+mDNSlocal mStatus register_service_instance(request_state *request, const domainname *domain)
{
service_info *info = request->service_registration;
service_instance *ptr, *instance;
}
// service registration
-static void handle_regservice_request(request_state *request)
+mDNSlocal void handle_regservice_request(request_state *request)
{
DNSServiceFlags flags;
uint32_t ifi;
if (!service->txtdata) { my_perror("ERROR: malloc"); result = mStatus_NoMemoryErr; goto finish; }
memcpy(service->txtdata, get_rdata(&ptr, service->txtlen), service->txtlen);
}
- else service->txtdata = NULL;
+ else service->txtdata = NULL;
// Check for sub-types after the service type
service->num_subtypes = ChopSubTypes(service->type_as_string); // Note: Modifies regtype string to remove trailing subtypes
// handles name conflicts, and delivers completed registration information to the client (via
// process_service_registraion())
-static void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, mStatus result)
+mDNSlocal void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, mStatus result)
{
mStatus err;
mDNSBool SuppressError = mDNSfalse;
service_info *info = instance->request->service_registration;
if (info->default_domain && !instance->default_local) SuppressError = mDNStrue;
// don't send errors up to client for wide-area, empty-string registrations
- }
+ }
if (result == mStatus_NoError)
LogOperation("%3d: DNSServiceRegister(%##s, %u) REGISTERED ", instance->sd, srs->RR_SRV.resrec.name->c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port));
if (result == mStatus_NoError)
{
+ request_state *req = instance->request;
if (instance->allowremotequery)
{
ExtraResourceRecord *e;
srs->RR_TXT.AllowRemoteQuery = mDNStrue;
for (e = instance->srs.Extras; e; e = e->next) e->r.AllowRemoteQuery = mDNStrue;
}
- process_service_registration(srs, SuppressError);
+
+ if (!req) LogMsg("ERROR: regservice_callback - null request object");
+ else
+ {
+ reply_state *rep;
+ if (GenerateNTDResponse(srs->RR_SRV.resrec.name, srs->RR_SRV.resrec.InterfaceID, req, &rep) != mStatus_NoError)
+ LogMsg("%3d: regservice_callback: %##s is not valid DNS-SD SRV name", req->sd, srs->RR_SRV.resrec.name->c);
+ else
+ {
+ transfer_state send_result = send_msg(rep);
+ if (send_result == t_error || send_result == t_terminated)
+ { abort_request(req); unlink_request(req); freeL("reply_state", rep); }
+ else if (send_result == t_complete) freeL("regservice_callback", rep);
+ else append_reply(req, rep);
+ }
+ }
if (instance->autoname && CountPeerRegistrations(m, srs) == 0)
RecordUpdatedNiceLabel(m, 0); // Successfully got new name, tell user immediately
return;
freeL("ExtraResourceRecord", extra);
}
-static mStatus add_record_to_service(request_state *rstate, service_instance *instance, uint16_t rrtype, uint16_t rdlen, char *rdata, uint32_t ttl)
+mDNSlocal mStatus add_record_to_service(request_state *rstate, service_instance *instance, uint16_t rrtype, uint16_t rdlen, char *rdata, uint32_t ttl)
{
ServiceRecordSet *srs = &instance->srs;
ExtraResourceRecord *extra;
return result;
}
-static mStatus handle_add_request(request_state *rstate)
+mDNSlocal mStatus handle_add_request(request_state *rstate)
{
uint32_t ttl;
uint16_t rrtype, rdlen;
return(result);
}
-static mStatus update_record(AuthRecord *rr, uint16_t rdlen, char *rdata, uint32_t ttl)
+mDNSlocal mStatus update_record(AuthRecord *rr, uint16_t rdlen, char *rdata, uint32_t ttl)
{
int rdsize;
RData *newrd;
return result;
}
-static mStatus handle_update_request(request_state *rstate)
+mDNSlocal mStatus handle_update_request(request_state *rstate)
{
uint16_t rdlen;
char *ptr, *rdata;
return(result);
}
-static void update_callback(mDNS *const m, AuthRecord *const rr, RData *oldrd)
+mDNSlocal void update_callback(mDNS *const m, AuthRecord *const rr, RData *oldrd)
{
(void)m; // Unused
if (oldrd != &rr->rdatastorage) freeL("update_callback", oldrd);
}
-
-static void process_service_registration(ServiceRecordSet *const srs, mDNSBool SuppressError)
- {
- reply_state *rep;
- transfer_state send_result;
- mStatus err;
- service_instance *instance = srs->ServiceContext;
- request_state *req = instance->request;
-
- if (!req) { LogMsg("ERROR: process_service_registration - null request object"); return; }
- err = gen_rr_response(srs->RR_SRV.resrec.name, srs->RR_SRV.resrec.InterfaceID, req, &rep);
- if (err)
- {
- if (SuppressError && deliver_async_error(req, reg_service_reply, err) < 0)
- {
- abort_request(req);
- unlink_request(req);
- }
- return;
- }
- send_result = send_msg(rep);
- if (send_result == t_error || send_result == t_terminated)
- {
- abort_request(req);
- unlink_request(req);
- freeL("process_service_registration", rep);
- }
- else if (send_result == t_complete) freeL("process_service_registration", rep);
- else append_reply(req, rep);
- }
-static void free_service_instance(service_instance *srv)
+mDNSlocal void free_service_instance(service_instance *srv)
{
request_state *rstate = srv->request;
ExtraResourceRecord *e = srv->srs.Extras, *tmp;
freeL("regservice_callback", srv);
}
-static void regservice_termination_callback(void *context)
+mDNSlocal void regservice_termination_callback(void *context)
{
service_info *info = context;
service_instance *i, *p;
freeL("service_info", info);
}
-static mStatus handle_regrecord_request(request_state *rstate)
+mDNSlocal mStatus handle_regrecord_request(request_state *rstate)
{
AuthRecord *rr;
registered_record_entry *re;
return(result);
}
-static void regrecord_callback(mDNS *const m, AuthRecord * rr, mStatus result)
+mDNSlocal void regrecord_callback(mDNS *const m, AuthRecord * rr, mStatus result)
{
registered_record_entry *re = rr->RecordContext;
request_state *rstate = re ? re->rstate : NULL;
else if (ts == t_morecoming) append_reply(rstate, reply); // client is blocked, link reply into list
}
-static void connected_registration_termination(void *context)
+mDNSlocal void connected_registration_termination(void *context)
{
int shared;
registered_record_entry *fptr, *ptr = ((request_state *)context)->reg_recs;
}
}
-static mStatus handle_removerecord_request(request_state *rstate)
+mDNSlocal mStatus handle_removerecord_request(request_state *rstate)
{
mStatus err = mStatus_BadReferenceErr;
char *ptr;
}
// remove a resource record registered via DNSServiceRegisterRecord()
-static mStatus remove_record(request_state *rstate)
+mDNSlocal mStatus remove_record(request_state *rstate)
{
int shared;
mStatus err = mStatus_UnknownErr;
return err;
}
-static mStatus remove_extra(request_state *rstate, service_instance *serv)
+mDNSlocal mStatus remove_extra(request_state *rstate, service_instance *serv)
{
mStatus err = mStatus_BadReferenceErr;
ExtraResourceRecord *ptr;
}
// domain enumeration
-static void handle_enum_request(request_state *rstate)
+mDNSlocal void handle_enum_request(request_state *rstate)
{
DNSServiceFlags flags;
uint32_t ifi;
term = mallocL("handle_enum_request", sizeof(enum_termination_t));
if (!def || !all || !term) FatalError("ERROR: malloc");
+#if defined(MDNS_LAZY_REGISTER_SEARCH_DOMAINS)
+ dDNS_RegisterSearchDomains( gmDNS );
+#endif
+
// enumeration requires multiple questions, so we must link all the context pointers so that
// necessary context can be reached from the callbacks
def->rstate = rstate;
}
}
-static void enum_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
+mDNSlocal void enum_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
{
char domain[MAX_ESCAPED_DOMAIN_NAME];
domain_enum_t *de = question->QuestionContext;
flags |= kDNSServiceFlagsAdd;
if (de->type == mDNS_DomainTypeRegistrationDefault || de->type == mDNS_DomainTypeBrowseDefault)
flags |= kDNSServiceFlagsDefault;
- }
+ }
ConvertDomainNameToCString(&answer->rdata->u.name, domain);
// note that we do NOT propagate specific interface indexes to the client - for example, a domain we learn from
// a machine's system preferences may be discovered on the LocalOnly interface, but should be browsed on the
return;
}
-static reply_state *format_enumeration_reply(request_state *rstate, const char *domain, DNSServiceFlags flags, uint32_t ifi, DNSServiceErrorType err)
+mDNSlocal reply_state *format_enumeration_reply(request_state *rstate, const char *domain, DNSServiceFlags flags, uint32_t ifi, DNSServiceErrorType err)
{
size_t len;
reply_state *reply;
char *data;
-
-
+
len = sizeof(DNSServiceFlags);
len += sizeof(uint32_t);
len += sizeof(DNSServiceErrorType);
len += strlen(domain) + 1;
-
+
reply = create_reply(enumeration_reply, len, rstate);
reply->rhdr->flags = dnssd_htonl(flags);
reply->rhdr->ifi = dnssd_htonl(ifi);
return reply;
}
-static void enum_termination_callback(void *context)
+mDNSlocal void enum_termination_callback(void *context)
{
enum_termination_t *t = context;
mDNS *coredata = gmDNS;
freeL("enum_termination_callback", t);
}
-static void handle_reconfirm_request(request_state *rstate)
+mDNSlocal void handle_reconfirm_request(request_state *rstate)
{
- AuthRecord *rr;
-
- rr = read_rr_from_ipc_msg(rstate->msgdata, 0, 1);
- if (!rr) return;
- LogOperation("%3d: DNSServiceReconfirmRecord(%##s) %s", rstate->sd, RRDisplayString(gmDNS, &rr->resrec));
- mDNS_ReconfirmByValue(gmDNS, &rr->resrec);
- abort_request(rstate);
- unlink_request(rstate);
- freeL("handle_reconfirm_request", rr);
- }
+ AuthRecord *rr = read_rr_from_ipc_msg(rstate->msgdata, 0, 0);
+ if (rr)
+ {
+ mStatus status = mDNS_ReconfirmByValue(gmDNS, &rr->resrec);
+ LogOperation(
+ (status == mStatus_NoError) ?
+ "%3d: DNSServiceReconfirmRecord(%s) interface %d initiated" :
+ "%3d: DNSServiceReconfirmRecord(%s) interface %d failed: %d",
+ rstate->sd, RRDisplayString(gmDNS, &rr->resrec),
+ mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, rr->resrec.InterfaceID), status);
+ status = 0; // Adding this line eliminates a build failure when building mDNSPosix on Tiger
+ }
+ abort_request(rstate);
+ unlink_request(rstate);
+ freeL("handle_reconfirm_request", rr);
+ }
// setup rstate to accept new reg/dereg requests
-static void reset_connected_rstate(request_state *rstate)
+mDNSlocal void reset_connected_rstate(request_state *rstate)
{
rstate->ts = t_morecoming;
rstate->hdr_bytes = 0;
// returns a resource record (allocated w/ malloc) containing the data found in an IPC message
// data must be in format flags, interfaceIndex, name, rrtype, rrclass, rdlen, rdata, (optional)ttl
// (ttl only extracted/set if ttl argument is non-zero). returns NULL for a bad-parameter error
-static AuthRecord *read_rr_from_ipc_msg(char *msgbuf, int GetTTL, int validate_flags)
+mDNSlocal AuthRecord *read_rr_from_ipc_msg(char *msgbuf, int GetTTL, int validate_flags)
{
char *rdata, name[256];
AuthRecord *rr;
freeL("read_rr_from_ipc_msg", rr);
return NULL;
}
+
if (flags & kDNSServiceFlagsAllowRemoteQuery) rr->AllowRemoteQuery = mDNStrue;
rr->resrec.rrclass = class;
rr->resrec.rdlength = rdlen;
rr->resrec.rdata->MaxRDLength = rdlen;
rdata = get_rdata(&msgbuf, rdlen);
memcpy(rr->resrec.rdata->u.data, rdata, rdlen);
- if (GetTTL)
- {
- rr->resrec.rroriginalttl = get_long(&msgbuf);
- }
+ if (GetTTL) rr->resrec.rroriginalttl = get_long(&msgbuf);
+ rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
+ SetNewRData(&rr->resrec, mDNSNULL, 0); // Sets rr->rdatahash for us
return rr;
}
-// generate a response message for a browse result, service registration result, or any other call with the
-// identical callback signature. on successful completion rep is set to point to a malloc'd reply_state struct,
-// and mStatus_NoError is returned. otherwise the appropriate error is returned.
-
-static mStatus gen_rr_response(domainname *servicename, mDNSInterfaceID id, request_state *request, reply_state **rep)
- {
- char *data;
- int len;
- 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];
-
- *rep = NULL;
-
- if (!DeconstructServiceName(servicename, &name, &type, &dom))
- return kDNSServiceErr_Unknown;
-
- ConvertDomainLabelToCString_unescaped(&name, namestr);
- ConvertDomainNameToCString(&type, typestr);
- ConvertDomainNameToCString(&dom, domstr);
-
- // calculate reply data length
- len = sizeof(DNSServiceFlags);
- len += sizeof(uint32_t); // if index
- len += sizeof(DNSServiceErrorType);
- len += (int) (strlen(namestr) + 1);
- len += (int) (strlen(typestr) + 1);
- len += (int) (strlen(domstr) + 1);
-
- *rep = create_reply(query_reply, len, request);
-
- (*rep)->rhdr->flags = dnssd_htonl(0);
- (*rep)->rhdr->ifi = dnssd_htonl(mDNSPlatformInterfaceIndexfromInterfaceID(gmDNS, id));
- (*rep)->rhdr->error = dnssd_htonl(kDNSServiceErr_NoError);
-
- data = (*rep)->sdata;
-
- put_string(namestr, &data);
- put_string(typestr, &data);
- put_string(domstr, &data);
- return mStatus_NoError;
- }
-
-static int build_domainname_from_strings(domainname *srv, char *name, char *regtype, char *domain)
+mDNSlocal int build_domainname_from_strings(domainname *srv, char *name, char *regtype, char *domain)
{
domainlabel n;
domainname d, t;
}
// append a reply to the list in a request object
-static void append_reply(request_state *req, reply_state *rep)
+mDNSlocal void append_reply(request_state *req, reply_state *rep)
{
reply_state *ptr;
// read_msg may be called any time when the transfer state (rs->ts) is t_morecoming.
// returns the current state of the request (morecoming, error, complete, terminated.)
// if there is no data on the socket, the socket will be closed and t_terminated will be returned
-static int read_msg(request_state *rs)
+mDNSlocal int read_msg(request_state *rs)
{
uint32_t nleft;
int nread;
return t_error;
}
rs->msgdata = rs->msgbuf;
- }
bzero(rs->msgbuf, rs->hdr.datalen + MSG_PAD_BYTES);
+ }
nleft = rs->hdr.datalen - rs->data_bytes;
nread = recv(rs->sd, rs->msgbuf + rs->data_bytes, nleft, 0);
if (nread == 0) { rs->ts = t_terminated; return t_terminated; }
return t_error;
}
-static int send_msg(reply_state *rs)
+mDNSlocal int send_msg(reply_state *rs)
{
ssize_t nwriten;
return rs->ts;
}
-static reply_state *create_reply(reply_op_t op, size_t datalen, request_state *request)
-{
+mDNSlocal reply_state *create_reply(reply_op_t op, size_t datalen, request_state *request)
+ {
reply_state *reply;
int totallen;
-
if ((unsigned)datalen < sizeof(reply_hdr))
{
LogMsg("ERROR: create_reply - data length less than lenght of required fields");
return reply;
}
-static int deliver_error(request_state *rstate, mStatus err)
+mDNSlocal int deliver_error(request_state *rstate, mStatus err)
{
int nwritten = -1;
undelivered_error_t *undeliv;
}
// returns 0 on success, -1 if send is incomplete, or on terminal failure (request is aborted)
-static transfer_state send_undelivered_error(request_state *rs)
+mDNSlocal transfer_state send_undelivered_error(request_state *rs)
{
int nwritten;
// send bogus data along with an error code to the app callback
// returns 0 on success (linking reply into list of not fully delivered),
// -1 on failure (request should be aborted)
-static int deliver_async_error(request_state *rs, reply_op_t op, mStatus err)
+mDNSlocal int deliver_async_error(request_state *rs, reply_op_t op, mStatus err)
{
int len;
reply_state *reply;
return 0;
}
-static void abort_request(request_state *rs)
+mDNSlocal void abort_request(request_state *rs)
{
reply_state *rep, *ptr;
if (rs->msgbuf) freeL("abort_request", rs->msgbuf);
LogOperation("%3d: Removing FD", rs->sd);
udsSupportRemoveFDFromEventLoop(rs->sd); // Note: This also closes file descriptor rs->sd for us
- rs->sd = dnssd_InvalidSocket;
+
+ // Don't use dnssd_InvalidSocket (-1) because that's the sentinel value MACOSX_MDNS_MALLOC_DEBUGGING uses
+ // for detecting when the memory for an object is inadvertently freed while the object is still on some list
+ rs->sd = -2;
// free pending replies
rep = rs->replies;
}
}
-static void unlink_request(request_state *rs)
+mDNSlocal void unlink_request(request_state *rs)
{
request_state *ptr;
}
//hack to search-replace perror's to LogMsg's
-static void my_perror(char *errmsg)
+mDNSlocal void my_perror(char *errmsg)
{
LogMsg("%s: %s", errmsg, dnssd_strerror(dnssd_errno()));
}
// without overrunning it.
// returns 0 on success, -1 on error.
-static int validate_message(request_state *rstate)
+mDNSlocal int validate_message(request_state *rstate)
{
uint32_t min_size;
}
-static uint32_t dnssd_htonl(uint32_t l)
+mDNSlocal uint32_t dnssd_htonl(uint32_t l)
{
uint32_t ret;
char * data;
#if defined(_WIN32)
-static char * win32_strerror(int inErrorCode)
+mDNSlocal char * win32_strerror(int inErrorCode)
{
static char buffer[1024];
DWORD n;