Skip to content

Commit c8d6f1f

Browse files
Fix error handling in Darwin DNS-SD implementation to clean up properly.
We had several codepaths where we could create a service ref but then do some fallible operations before calling Add() on the context. If those failed, they would call Finalize() on the context, which would delete the context, but _not_ DNSServiceRefDeallocate() the service ref. The fix is to make sure that: 1) All cases where we create a service ref successfully immediately set it on the context. 2) All context deletion goes through MdnsContexts::Delete, so that we make sure to clean up the service ref if there is one.
1 parent 84ee115 commit c8d6f1f

File tree

3 files changed

+47
-29
lines changed

3 files changed

+47
-29
lines changed

src/platform/Darwin/DnssdContexts.cpp

+10-18
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,8 @@ CHIP_ERROR GenericContext::FinalizeInternal(const char * errorStr, CHIP_ERROR er
135135
}
136136
else
137137
{
138-
chip::Platform::Delete(this);
138+
// Ensure that we clean up our service ref, if any, correctly.
139+
MdnsContexts::GetInstance().Delete(this);
139140
}
140141

141142
return err;
@@ -161,33 +162,22 @@ MdnsContexts::~MdnsContexts()
161162
}
162163
}
163164

164-
CHIP_ERROR MdnsContexts::Add(GenericContext * context, DNSServiceRef sdRef)
165+
CHIP_ERROR MdnsContexts::Add(GenericContext * context)
165166
{
166-
VerifyOrReturnError(context != nullptr || sdRef != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
167-
168-
if (context == nullptr)
169-
{
170-
DNSServiceRefDeallocate(sdRef);
171-
return CHIP_ERROR_INVALID_ARGUMENT;
172-
}
173-
174-
if (sdRef == nullptr)
167+
VerifyOrReturnError(context != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
168+
if (!context->serviceRef)
175169
{
176-
chip::Platform::Delete(context);
170+
Delete(context);
177171
return CHIP_ERROR_INVALID_ARGUMENT;
178172
}
179173

180-
auto err = DNSServiceSetDispatchQueue(sdRef, chip::DeviceLayer::PlatformMgrImpl().GetWorkQueue());
174+
auto err = DNSServiceSetDispatchQueue(context->serviceRef, chip::DeviceLayer::PlatformMgrImpl().GetWorkQueue());
181175
if (kDNSServiceErr_NoError != err)
182176
{
183-
// We can't just use our Delete to deallocate the service ref here,
184-
// because our context may not have its serviceRef set yet.
185-
DNSServiceRefDeallocate(sdRef);
186-
chip::Platform::Delete(context);
177+
Delete(context);
187178
return Error::ToChipError(err);
188179
}
189180

190-
context->serviceRef = sdRef;
191181
mContexts.push_back(context);
192182

193183
return CHIP_NO_ERROR;
@@ -242,6 +232,8 @@ CHIP_ERROR MdnsContexts::RemoveAllOfType(ContextType type)
242232
return found ? CHIP_NO_ERROR : CHIP_ERROR_KEY_NOT_FOUND;
243233
}
244234

235+
// TODO: Perhaps this cleanup code should just move into ~GenericContext, and
236+
// the places that call this method should just Platform::Delete() the context?
245237
void MdnsContexts::Delete(GenericContext * context)
246238
{
247239
if (context->serviceRef != nullptr)

src/platform/Darwin/DnssdImpl.cpp

+28-9
Original file line numberDiff line numberDiff line change
@@ -188,12 +188,17 @@ CHIP_ERROR Register(void * context, DnssdPublishCallback callback, uint32_t inte
188188
auto err = sdCtx->mHostNameRegistrar.Init(hostname, addressType, interfaceId);
189189
VerifyOrReturnError(kDNSServiceErr_NoError == err, sdCtx->Finalize(err));
190190

191-
DNSServiceRef sdRef;
192-
err = DNSServiceRegister(&sdRef, registerFlags, interfaceId, name, type, kLocalDot, hostname, htons(port), record.size(),
193-
record.data(), OnRegister, sdCtx);
194-
VerifyOrReturnError(kDNSServiceErr_NoError == err, sdCtx->Finalize(err));
191+
err = DNSServiceRegister(&sdCtx->serviceRef, registerFlags, interfaceId, name, type, kLocalDot, hostname, htons(port),
192+
record.size(), record.data(), OnRegister, sdCtx);
193+
if (err != kDNSServiceErr_NoError)
194+
{
195+
// Just in case DNSServiceCreateConnection put garbage in the outparam
196+
// on failure.
197+
sdCtx->serviceRef = nullptr;
198+
return sdCtx->Finalize(err);
199+
}
195200

196-
return MdnsContexts::GetInstance().Add(sdCtx, sdRef);
201+
return MdnsContexts::GetInstance().Add(sdCtx);
197202
}
198203

199204
static void OnBrowse(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceId, DNSServiceErrorType err, const char * name,
@@ -216,16 +221,23 @@ CHIP_ERROR BrowseOnDomain(BrowseHandler * sdCtx, uint32_t interfaceId, const cha
216221
CHIP_ERROR Browse(BrowseHandler * sdCtx, uint32_t interfaceId, const char * type)
217222
{
218223
auto err = DNSServiceCreateConnection(&sdCtx->serviceRef);
219-
VerifyOrReturnError(kDNSServiceErr_NoError == err, sdCtx->Finalize(err));
224+
if (err != kDNSServiceErr_NoError)
225+
{
226+
// Just in case DNSServiceCreateConnection put garbage in the outparam
227+
// on failure.
228+
sdCtx->serviceRef = nullptr;
229+
return sdCtx->Finalize(err);
230+
}
220231

221232
// We will browse on both the local domain and the SRP domain.
233+
// BrowseOnDomain guarantees it will Finalize() on failure.
222234
ChipLogProgress(Discovery, "Browsing for: %s on local domain", StringOrNullMarker(type));
223235
ReturnErrorOnFailure(BrowseOnDomain(sdCtx, interfaceId, type, kLocalDot));
224236

225237
ChipLogProgress(Discovery, "Browsing for: %s on %s domain", StringOrNullMarker(type), kSRPDot);
226238
ReturnErrorOnFailure(BrowseOnDomain(sdCtx, interfaceId, type, kSRPDot));
227239

228-
return MdnsContexts::GetInstance().Add(sdCtx, sdCtx->serviceRef);
240+
return MdnsContexts::GetInstance().Add(sdCtx);
229241
}
230242

231243
CHIP_ERROR Browse(void * context, DnssdBrowseCallback callback, uint32_t interfaceId, const char * type,
@@ -380,10 +392,17 @@ static CHIP_ERROR Resolve(ResolveContext * sdCtx, uint32_t interfaceId, chip::In
380392
StringOrNullMarker(name), StringOrNullMarker(domain), interfaceId);
381393

382394
auto err = DNSServiceCreateConnection(&sdCtx->serviceRef);
383-
VerifyOrReturnError(kDNSServiceErr_NoError == err, sdCtx->Finalize(err));
395+
if (err != kDNSServiceErr_NoError)
396+
{
397+
// Just in case DNSServiceCreateConnection put garbage in the outparam
398+
// on failure.
399+
sdCtx->serviceRef = nullptr;
400+
return sdCtx->Finalize(err);
401+
}
384402

385403
// If we have a single domain from a browse, we will use that for the Resolve.
386404
// Otherwise we will try to resolve using both the local domain and the SRP domain.
405+
// ResolveWithContext guarantees it will Finalize() on failure.
387406
if (domain != nullptr)
388407
{
389408
ReturnErrorOnFailure(ResolveWithContext(sdCtx, interfaceId, type, name, domain, &sdCtx->resolveContextWithNonSRPType));
@@ -400,7 +419,7 @@ static CHIP_ERROR Resolve(ResolveContext * sdCtx, uint32_t interfaceId, chip::In
400419
sdCtx->shouldStartSRPTimerForResolve = true;
401420
}
402421

403-
auto retval = MdnsContexts::GetInstance().Add(sdCtx, sdCtx->serviceRef);
422+
auto retval = MdnsContexts::GetInstance().Add(sdCtx);
404423
if (retval == CHIP_NO_ERROR)
405424
{
406425
(*(sdCtx->consumerCounter))++;

src/platform/Darwin/DnssdImpl.h

+9-2
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,13 @@ struct GenericContext
4343
{
4444
ContextType type;
4545
void * context;
46-
DNSServiceRef serviceRef;
46+
// When using a GenericContext, if a DNSServiceRef is created successfully
47+
// API consumers must ensure that it gets set as serviceRef on the context
48+
// immediately, before any other operations that might fail can happen.
49+
//
50+
// In all cases, once a context has been created, Finalize() must be called
51+
// on it to clean it up properly.
52+
DNSServiceRef serviceRef = nullptr;
4753

4854
virtual ~GenericContext() {}
4955

@@ -69,7 +75,8 @@ class MdnsContexts
6975
~MdnsContexts();
7076
static MdnsContexts & GetInstance() { return sInstance.get(); }
7177

72-
CHIP_ERROR Add(GenericContext * context, DNSServiceRef sdRef);
78+
// The context being added is expected to have a valid serviceRef.
79+
CHIP_ERROR Add(GenericContext * context);
7380
CHIP_ERROR Remove(GenericContext * context);
7481
CHIP_ERROR RemoveAllOfType(ContextType type);
7582
CHIP_ERROR Has(GenericContext * context);

0 commit comments

Comments
 (0)