blob: 5deb3fe468cc74e844ad8fd935ae3f1a0c3d6c34 [file] [log] [blame]
/*
*
* Copyright (c) 2026 Project CHIP Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <app/server/ThreadRendezvousAnnouncement.h>
#include <inttypes.h>
#include <stdarg.h>
#include <stdio.h>
#include <lib/support/CodeUtils.h>
#include <lib/dnssd/minimal_mdns/ResponseBuilder.h>
#include <lib/dnssd/minimal_mdns/records/Srv.h>
#include <lib/dnssd/minimal_mdns/records/Txt.h>
namespace chip {
namespace app {
CHIP_ERROR TxtStringsBuilder::Fill(const Dnssd::CommissionAdvertisingParameters & params)
{
// VP
auto vendorId = params.GetVendorId();
auto productId = params.GetProductId();
if (vendorId.has_value() && productId.has_value())
{
ReturnErrorOnFailure(FormatAndAdd("VP=%d+%d", *vendorId, *productId));
}
else if (vendorId.has_value())
{
ReturnErrorOnFailure(FormatAndAdd("VP=%d", *vendorId));
}
// D
ReturnErrorOnFailure(FormatAndAdd("D=%d", params.GetLongDiscriminator()));
// CM
ReturnErrorOnFailure(FormatAndAdd("CM=%d", static_cast<int>(params.GetCommissioningMode())));
// DT
auto deviceType = params.GetDeviceType();
if (deviceType.has_value())
{
ReturnErrorOnFailure(FormatAndAdd("DT=%" PRIu32, *deviceType));
}
// DN
auto deviceName = params.GetDeviceName();
if (deviceName.has_value())
{
ReturnErrorOnFailure(FormatAndAdd("DN=%s", *deviceName));
}
// RI
auto rotatingId = params.GetRotatingDeviceId();
if (rotatingId.has_value())
{
ReturnErrorOnFailure(FormatAndAdd("RI=%s", *rotatingId));
}
// PH
auto pairingHint = params.GetPairingHint();
if (pairingHint.has_value())
{
ReturnErrorOnFailure(FormatAndAdd("PH=%d", *pairingHint));
}
// PI
auto pairingInstr = params.GetPairingInstruction();
if (pairingInstr.has_value())
{
ReturnErrorOnFailure(FormatAndAdd("PI=%s", *pairingInstr));
}
return CHIP_NO_ERROR;
}
CHIP_ERROR TxtStringsBuilder::FormatAndAdd(const char * format, ...)
{
VerifyOrReturnError(mCount < MATTER_ARRAY_SIZE(mTxtStrings), CHIP_ERROR_BUFFER_TOO_SMALL);
size_t offset = static_cast<size_t>(mNextStart - &mTxtBuffer[0]);
VerifyOrReturnError(sizeof(mTxtBuffer) > offset, CHIP_ERROR_BUFFER_TOO_SMALL);
va_list args;
va_start(args, format);
int len = vsnprintf(mNextStart, sizeof(mTxtBuffer) - offset, format, args);
va_end(args);
// Make sure not overflowed.
VerifyOrReturnError(len > 0 && offset + static_cast<size_t>(len) < sizeof(mTxtBuffer), CHIP_ERROR_BUFFER_TOO_SMALL);
mTxtStrings[mCount++] = mNextStart;
// skip the null terminator.
mNextStart += len + 1;
return CHIP_NO_ERROR;
}
CHIP_ERROR BuildThreadRendezvousAnnouncement(const Dnssd::CommissionAdvertisingParameters & params,
System::PacketBufferHandle & outBuffer)
{
System::PacketBufferHandle buffer = System::PacketBufferHandle::New(System::PacketBuffer::kMaxSize);
VerifyOrReturnError(!buffer.IsNull(), CHIP_ERROR_NO_MEMORY);
{
mdns::Minimal::ResponseBuilder builder(std::move(buffer));
builder.Header().SetMessageId(0);
builder.Header().SetFlags(builder.Header().GetFlags().SetResponse().SetAuthoritative());
static const char * matterc_udp_local[] = { "_matterc", "_udp", "local" };
mdns::Minimal::FullQName serviceName(matterc_udp_local);
static const char * root[] = { "" };
mdns::Minimal::FullQName targetName(root);
mdns::Minimal::SrvResourceRecord srvRecord(serviceName, targetName, params.GetPort());
builder.AddRecord(mdns::Minimal::ResourceType::kAnswer, srvRecord);
TxtStringsBuilder txtStringsBuilder;
ReturnErrorOnFailure(txtStringsBuilder.Fill(params));
mdns::Minimal::TxtResourceRecord txtRecord(serviceName, txtStringsBuilder.GetEntries(), txtStringsBuilder.GetCount());
builder.AddRecord(mdns::Minimal::ResourceType::kAnswer, txtRecord);
outBuffer = builder.ReleasePacket();
}
return CHIP_NO_ERROR;
}
} // namespace app
} // namespace chip