DNSServiceRegistration *next;
mach_port_t ClientMachPort;
mDNSBool autoname;
+ mDNSBool autorename;
+ domainlabel name;
ServiceRecordSet s;
// Don't add any fields after ServiceRecordSet.
// This is where the implicit extra space goes if we allocate an oversized ServiceRecordSet object
{
DNSServiceRegistration *x = *r;
*r = (*r)->next;
+ x->autorename = mDNSfalse;
mDNS_DeregisterService(&mDNSStorage, &x->s);
// Note that we don't do the "free(x);" here -- wait for the mStatus_MemFree message
return;
// Note: By the time we get the mStatus_NameConflict message, the service is already deregistered
// and the memory is free, so we don't have to wait for an mStatus_MemFree message as well.
if (x->autoname)
- mDNS_RenameAndReregisterService(m, sr);
+ mDNS_RenameAndReregisterService(m, sr, mDNSNULL);
else
{
kern_return_t status;
if (result == mStatus_MemFree)
{
- DNSServiceRegistration **r = &DNSServiceRegistrationList;
- while (*r && *r != x) r = &(*r)->next;
- if (*r)
+ if (x->autorename)
{
- debugf("RegCallback: %##s Still in DNSServiceRegistration list; removing now", sr->RR_SRV.name.c);
- *r = (*r)->next;
+ debugf("RegCallback renaming %#s to %#s", &x->name, &mDNSStorage.nicelabel);
+ x->autorename = mDNSfalse;
+ x->name = mDNSStorage.nicelabel;
+ mDNS_RenameAndReregisterService(m, &x->s, &x->name);
+ }
+ else
+ {
+ DNSServiceRegistration **r = &DNSServiceRegistrationList;
+ while (*r && *r != x) r = &(*r)->next;
+ if (*r)
+ {
+ debugf("RegCallback: %##s Still in DNSServiceRegistration list; removing now", sr->RR_SRV.name.c);
+ *r = (*r)->next;
+ }
+ debugf("RegCallback: Freeing DNSServiceRegistration %##s %d", sr->RR_SRV.name.c, x->ClientMachPort);
+ FreeDNSServiceRegistration(x);
}
- debugf("RegCallback: Freeing DNSServiceRegistration %##s %d", sr->RR_SRV.name.c, x->ClientMachPort);
- FreeDNSServiceRegistration(x);
}
}
DNSCString name, DNSCString regtype, DNSCString domain, int notAnIntPort, DNSCString txtRecord)
{
mStatus err;
- domainlabel n;
domainname t, d;
mDNSIPPort port;
unsigned char txtinfo[1024] = "";
DNSServiceRegistrationList = x;
x->autoname = (*name == 0);
- if (x->autoname) n = mDNSStorage.nicelabel;
- else ConvertCStringToDomainLabel(name, &n);
+ x->autorename = mDNSfalse;
+ if (x->autoname) x->name = mDNSStorage.nicelabel;
+ else ConvertCStringToDomainLabel(name, &x->name);
ConvertCStringToDomainName(regtype, &t);
ConvertCStringToDomainName(*domain ? domain : "local.", &d);
port.NotAnInteger = notAnIntPort;
debugf("Client %d: provide_DNSServiceRegistrationCreate_rpc", client);
debugf("Client %d: Register Service: %#s.%##s%##s %d %.30s",
- client, &n, &t, &d, (int)port.b[0] << 8 | port.b[1], txtRecord);
- CheckForDuplicateRegistrations(x, &n, &t, &d);
- err = mDNS_RegisterService(&mDNSStorage, &x->s, &n, &t, &d, mDNSNULL, port, txtinfo, data_len, RegCallback, x);
+ client, &x->name, &t, &d, (int)port.b[0] << 8 | port.b[1], txtRecord);
+ CheckForDuplicateRegistrations(x, &x->name, &t, &d);
+ err = mDNS_RegisterService(&mDNSStorage, &x->s, &x->name, &t, &d, mDNSNULL, port, txtinfo, data_len, RegCallback, x);
if (err) AbortClient(client);
else EnableDeathNotificationForClient(client);
return(err);
}
+void NetworkChanged(void)
+ {
+ DNSServiceRegistration *r;
+ for (r = DNSServiceRegistrationList; r; r=r->next)
+ if (r->autoname && !SameDomainLabel(r->name.c, mDNSStorage.nicelabel.c))
+ {
+ debugf("NetworkChanged renaming %#s to %#s", &r->name, &mDNSStorage.nicelabel);
+ r->autorename = mDNStrue;
+ mDNS_DeregisterService(&mDNSStorage, &r->s);
+ }
+ }
+
mDNSexport kern_return_t provide_DNSServiceRegistrationAddRecord_rpc(mach_port_t unusedserver, mach_port_t client,
int type, const char *data, mach_msg_type_number_t data_len, uint32_t ttl, natural_t *reference)
{
mDNSlocal kern_return_t start(const char *bundleName, const char *bundleDir)
{
+ extern void (*NotifyClientNetworkChanged)(void); // Temp fix for catching name changes
mStatus err;
CFRunLoopTimerContext myCFRunLoopTimerContext = { 0, &mDNSStorage, NULL, NULL, NULL };
CFMachPortRef d_port = CFMachPortCreate(NULL, ClientDeathCallback, NULL, NULL);
CFRelease(e_rls);
if (debug_mode) printf("Service registered with Mach Port %d\n", m_port);
+ NotifyClientNetworkChanged = NetworkChanged;
+
return(err);
}
return((mDNSu32)(src - name->c + 1));
}
-mDNSlocal mDNSBool SameDomainLabel(const mDNSu8 *a, const mDNSu8 *b)
+mDNSexport mDNSBool SameDomainLabel(const mDNSu8 *a, const mDNSu8 *b)
{
int i;
const int len = *a++;
((RR)->InterfaceAddr.NotAnInteger == 0 || (RR)->InterfaceAddr.NotAnInteger == (I).NotAnInteger))
#define DefaultProbeCountForTypeUnique ((mDNSu8)3)
+#define DefaultProbeCountForRecordType(X) ((X) == kDNSRecordTypeUnique ? DefaultProbeCountForTypeUnique : (mDNSu8)0)
#define DefaultAnnounceCountForTypeShared ((mDNSu8)10)
#define DefaultAnnounceCountForTypeUnique ((mDNSu8)2)
-#define DefaultAnnounceCountForRecordType(X) ((X) == kDNSRecordTypeShared ? DefaultAnnounceCountForTypeShared : \
- (X) == kDNSRecordTypeUnique ? DefaultAnnounceCountForTypeUnique : \
- (X) == kDNSRecordTypeVerified ? DefaultAnnounceCountForTypeUnique : (mDNSu8)0)
+#define DefaultAnnounceCountForRecordType(X) ((X) == kDNSRecordTypeShared ? DefaultAnnounceCountForTypeShared : \
+ (X) == kDNSRecordTypeUnique ? DefaultAnnounceCountForTypeUnique : \
+ (X) == kDNSRecordTypeVerified ? DefaultAnnounceCountForTypeUnique : \
+ (X) == kDNSRecordTypeKnownUnique ? DefaultAnnounceCountForTypeUnique : (mDNSu8)0)
#define DefaultSendIntervalForRecordType(X) ((X) == kDNSRecordTypeShared ? mDNSPlatformOneSecond : \
(X) == kDNSRecordTypeUnique ? mDNSPlatformOneSecond/4 : \
// If we're in the middle of probing this record, we need to start again,
// because changing its rdata may change the outcome of the tie-breaker.
- if (rr->RecordType == kDNSRecordTypeUnique) rr->ProbeCount = DefaultProbeCountForTypeUnique;
+ rr->ProbeCount = DefaultProbeCountForRecordType(rr->RecordType);
+ rr->AnnounceCount = DefaultAnnounceCountForRecordType(rr->RecordType);
+ rr->NextSendTime = mDNSPlatformTimeNow();
+ rr->NextSendInterval = DefaultSendIntervalForRecordType(rr->RecordType);
+ if (rr->RecordType == kDNSRecordTypeUnique && m->SuppressProbes) rr->NextSendTime = m->SuppressProbes;
}
mDNSlocal void UpdateHostNameTargets(const mDNS *const m)
// Field Group 2: Transient state for Authoritative Records
rr->Acknowledged = mDNSfalse;
- rr->ProbeCount = (rr->RecordType == kDNSRecordTypeUnique) ? DefaultProbeCountForTypeUnique : (mDNSu8)0;
+ rr->ProbeCount = DefaultProbeCountForRecordType(rr->RecordType);
rr->AnnounceCount = DefaultAnnounceCountForRecordType(rr->RecordType);
rr->IncludeInProbe = mDNSfalse;
rr->SendPriority = 0;
mDNSu8 RecordType = rr->RecordType;
// If this is a shared record and we've announced it at least once,
// we need to retract that announcement before we delete the record
- if (RecordType == kDNSRecordTypeShared && rr->AnnounceCount < DefaultAnnounceCountForTypeShared)
+ if (RecordType == kDNSRecordTypeShared && rr->AnnounceCount <= DefaultAnnounceCountForTypeShared)
{
debugf("mDNS_Deregister_internal: Sending deregister for %##s (%s)", rr->name.c, DNSTypeName(rr->rrtype));
rr->RecordType = kDNSRecordTypeDeregistering;
// If we have an update queued up which never executed, give the client a chance to free that memory
if (rr->NewRData)
{
- RData *n = rr->NewRData;
+ RData *OldRData = rr->rdata;
+ rr->rdata = rr->NewRData; // Update our rdata
rr->NewRData = mDNSNULL; // Clear the NewRData pointer ...
- if (rr->UpdateCallback) rr->UpdateCallback(m, rr, n); // ...and let the client free this memory, if necessary
+ if (rr->UpdateCallback) rr->UpdateCallback(m, rr, OldRData); // ... and let the client know
}
if (RecordType == kDNSRecordTypeShared && rr->Callback)
if (rr->RecordType == kDNSRecordTypeDeregistering)
{
rr->RecordType = kDNSRecordTypeShared;
- rr->AnnounceCount = DefaultAnnounceCountForTypeShared;
+ rr->AnnounceCount = DefaultAnnounceCountForTypeShared+1;
mDNS_Deregister_internal(m, rr, timenow, mDNS_Dereg_normal);
}
}
int numDereg = 0;
int numAnnounce = 0;
int numAnswer = 0;
+ mDNSs32 minExistingAnnounceInterval = 0;
if (m->CurrentRecord) debugf("BuildResponse ERROR m->CurrentRecord already set");
m->CurrentRecord = m->ResourceRecords;
numDereg++;
responseptr = newptr;
rr->RecordType = kDNSRecordTypeShared;
- rr->AnnounceCount = DefaultAnnounceCountForTypeShared;
+ rr->AnnounceCount = DefaultAnnounceCountForTypeShared+1;
mDNS_Deregister_internal(m, rr, timenow, mDNS_Dereg_normal);
}
}
if (response->h.numAnswers == 0) debugf("BuildResponse announcements failed");
if (newptr || response->h.numAnswers == 0)
{
+ if (minExistingAnnounceInterval > rr->NextSendInterval)
+ minExistingAnnounceInterval = rr->NextSendInterval;
rr->SendPriority = 0;
rr->Requester = zeroIPAddr;
rr->AnnounceCount--;
}
}
+ // 2a. Look for additional announcements that are worth accelerating
+ // They must be (a) at least half-way to their next announcement and
+ // (b) at an interval equal or less than any of the ones we've already put in
+ for (rr = m->ResourceRecords; rr; rr=rr->next)
+ {
+ if (rr->InterfaceAddr.NotAnInteger == InterfaceAddr.NotAnInteger &&
+ rr->AnnounceCount && ResourceRecordIsValidAnswer(rr) &&
+ timenow - (rr->LastSendTime + rr->NextSendInterval/4) >= 0 &&
+ rr->NextSendInterval <= minExistingAnnounceInterval)
+ {
+ newptr = putResourceRecord(response, responseptr, &response->h.numAnswers, rr, m, timenow);
+ if (newptr)
+ {
+ numAnnounce++;
+ responseptr = newptr;
+ }
+ // If we were able to put the record, then update the state variables
+ // If we were unable to put the record because it is too large to fit, even though
+ // there are no other answers in the packet, then pretend we succeeded anyway,
+ // or we'll end up in an infinite loop trying to send a record that will never fit
+ if (response->h.numAnswers == 0) debugf("BuildResponse announcements failed");
+ if (newptr || response->h.numAnswers == 0)
+ {
+ rr->SendPriority = 0;
+ rr->Requester = zeroIPAddr;
+ rr->AnnounceCount--;
+ rr->NextSendTime = timenow + rr->NextSendInterval;
+ rr->NextSendInterval *= 2;
+ }
+ }
+ }
+
// 3. Look for answers we need to send
for (rr = m->ResourceRecords; rr; rr=rr->next)
if (rr->InterfaceAddr.NotAnInteger == InterfaceAddr.NotAnInteger &&
{
// First mark all the records we need to deregister
for (rr = m->ResourceRecords; rr; rr=rr->next)
- if (rr->RecordType == kDNSRecordTypeShared && rr->AnnounceCount < DefaultAnnounceCountForTypeShared)
+ if (rr->RecordType == kDNSRecordTypeShared && rr->AnnounceCount <= DefaultAnnounceCountForTypeShared)
rr->rrremainingttl = 0;
while (HaveResponses(m, timenow)) SendResponses(m, timenow);
}
for (rr = m->ResourceRecords; rr; rr=rr->next)
{
if (rr->RecordType == kDNSRecordTypeVerified) rr->RecordType = kDNSRecordTypeUnique;
- rr->ProbeCount = (rr->RecordType == kDNSRecordTypeUnique) ? DefaultProbeCountForTypeUnique : (mDNSu8)0;
+ rr->ProbeCount = DefaultProbeCountForRecordType(rr->RecordType);
rr->AnnounceCount = DefaultAnnounceCountForRecordType(rr->RecordType);
- rr->NextSendInterval = DefaultSendIntervalForRecordType(rr->RecordType);
rr->NextSendTime = timenow;
+ rr->NextSendInterval = DefaultSendIntervalForRecordType(rr->RecordType);
}
for (q = m->ActiveQuestions; q; q=q->next) // Scan our list of questions
if (!q->DuplicateOf)
else
{
// else, the packet RR has different rdata -- check to see if this is a conflict
- if (PacketRRConflict(m, rr, &pktrr))
+ if (pktrr.rroriginalttl > 0 && PacketRRConflict(m, rr, &pktrr))
{
if (rr->rrtype == kDNSType_SRV)
{
return(mStatus_NoError);
}
-mDNSexport mStatus mDNS_RenameAndReregisterService(mDNS *const m, ServiceRecordSet *const sr)
+mDNSexport mStatus mDNS_RenameAndReregisterService(mDNS *const m, ServiceRecordSet *const sr, const domainlabel *newname)
{
domainlabel name;
domainname type, domain;
mStatus err;
DeconstructServiceName(&sr->RR_SRV.name, &name, &type, &domain);
- IncrementLabelSuffix(&name, mDNStrue);
- debugf("Reregistering as %#s", name.c);
+ if (!newname)
+ {
+ IncrementLabelSuffix(&name, mDNStrue);
+ newname = &name;
+ }
+ debugf("Reregistering as %#s", newname->c);
if (sr->RR_SRV.HostTarget == mDNSfalse && sr->Host.c[0]) host = &sr->Host;
- err = mDNS_RegisterService(m, sr, &name, &type, &domain,
+ err = mDNS_RegisterService(m, sr, newname, &type, &domain,
host, sr->RR_SRV.rdata->u.srv.port, sr->RR_TXT.rdata->u.txt.c, sr->RR_TXT.rdata->RDLength,
sr->Callback, sr->Context);
mDNSexport void mDNS_DeregisterService(mDNS *const m, ServiceRecordSet *sr)
{
const mDNSs32 timenow = mDNS_Lock(m);
+ ExtraResourceRecord *e = sr->Extras;
// We use mDNS_Dereg_repeat because, in the event of a collision, some or all of
// these records could have already been automatically deregistered, and that's okay
mDNS_Deregister_internal(m, &sr->RR_SRV, timenow, mDNS_Dereg_repeat);
mDNS_Deregister_internal(m, &sr->RR_TXT, timenow, mDNS_Dereg_repeat);
- while (sr->Extras)
+ while (e)
{
- ExtraResourceRecord *e = sr->Extras;
- sr->Extras = sr->Extras->next;
mDNS_Deregister_internal(m, &e->r, timenow, mDNS_Dereg_repeat);
+ e=e->next;
}
// Be sure to deregister the PTR last!