Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2021 Project CHIP Authors
4 : *
5 : * Licensed under the Apache License, Version 2.0 (the "License");
6 : * you may not use this file except in compliance with the License.
7 : * You may obtain a copy of the License at
8 : *
9 : * http://www.apache.org/licenses/LICENSE-2.0
10 : *
11 : * Unless required by applicable law or agreed to in writing, software
12 : * distributed under the License is distributed on an "AS IS" BASIS,
13 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 : * See the License for the specific language governing permissions and
15 : * limitations under the License.
16 : */
17 :
18 : #include "ServiceNaming.h"
19 :
20 : #include <lib/core/CHIPEncoding.h>
21 : #include <lib/support/BytesToHex.h>
22 : #include <lib/support/CodeUtils.h>
23 : #include <lib/support/StringBuilder.h>
24 :
25 : #include <cstdio>
26 : #include <inttypes.h>
27 : #include <string.h>
28 :
29 : namespace chip {
30 : namespace Dnssd {
31 :
32 45 : CHIP_ERROR MakeInstanceName(char * buffer, size_t bufferLen, const PeerId & peerId)
33 : {
34 45 : VerifyOrReturnError(bufferLen > Operational::kInstanceNameMaxLength, CHIP_ERROR_BUFFER_TOO_SMALL);
35 :
36 11 : NodeId nodeId = peerId.GetNodeId();
37 11 : CompressedFabricId fabricId = peerId.GetCompressedFabricId();
38 :
39 11 : uint32_t fabricIdHi = static_cast<uint32_t>(fabricId >> 32);
40 11 : uint32_t fabricIdLo = static_cast<uint32_t>(fabricId);
41 11 : uint32_t nodeIdHi = static_cast<uint32_t>(nodeId >> 32);
42 11 : uint32_t nodeIdLo = static_cast<uint32_t>(nodeId);
43 11 : StringBuilderBase builder(buffer, bufferLen);
44 11 : builder.AddFormat("%08" PRIX32 "%08" PRIX32 "-%08" PRIX32 "%08" PRIX32, fabricIdHi, fabricIdLo, nodeIdHi, nodeIdLo);
45 :
46 11 : VerifyOrReturnError(builder.Fit(), CHIP_ERROR_BUFFER_TOO_SMALL);
47 11 : return CHIP_NO_ERROR;
48 : }
49 :
50 19 : CHIP_ERROR ExtractIdFromInstanceName(const char * name, PeerId * peerId)
51 : {
52 19 : VerifyOrReturnError(name != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
53 17 : VerifyOrReturnError(peerId != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
54 :
55 : // Make sure the string is long enough.
56 : static constexpr size_t fabricIdByteLength = 8;
57 : static constexpr size_t fabricIdStringLength = fabricIdByteLength * 2;
58 : static constexpr size_t nodeIdByteLength = 8;
59 : static constexpr size_t nodeIdStringLength = nodeIdByteLength * 2;
60 : static constexpr size_t totalLength = fabricIdStringLength + nodeIdStringLength + 1; // +1 for '-'
61 :
62 : // Ensure we have at least totalLength chars.
63 16 : size_t len = strnlen(name, totalLength);
64 16 : VerifyOrReturnError(len >= totalLength, CHIP_ERROR_INVALID_ARGUMENT);
65 :
66 : // Check that we have a proper terminator.
67 12 : VerifyOrReturnError(name[totalLength] == '\0' || name[totalLength] == '.', CHIP_ERROR_WRONG_NODE_ID);
68 :
69 : // Check what we have a separator where we expect.
70 10 : VerifyOrReturnError(name[fabricIdStringLength] == '-', CHIP_ERROR_WRONG_NODE_ID);
71 :
72 : static constexpr size_t bufferSize = std::max(fabricIdByteLength, nodeIdByteLength);
73 : uint8_t buf[bufferSize];
74 :
75 5 : VerifyOrReturnError(Encoding::HexToBytes(name, fabricIdStringLength, buf, bufferSize) != 0, CHIP_ERROR_WRONG_NODE_ID);
76 : // Buf now stores the fabric id, as big-endian bytes.
77 : static_assert(fabricIdByteLength == sizeof(uint64_t), "Wrong number of bytes");
78 4 : peerId->SetCompressedFabricId(Encoding::BigEndian::Get64(buf));
79 :
80 4 : VerifyOrReturnError(Encoding::HexToBytes(name + fabricIdStringLength + 1, nodeIdStringLength, buf, bufferSize) != 0,
81 : CHIP_ERROR_WRONG_NODE_ID);
82 : // Buf now stores the node id id, as big-endian bytes.
83 : static_assert(nodeIdByteLength == sizeof(uint64_t), "Wrong number of bytes");
84 4 : peerId->SetNodeId(Encoding::BigEndian::Get64(buf));
85 :
86 4 : return CHIP_NO_ERROR;
87 : }
88 :
89 22 : CHIP_ERROR MakeHostName(char * buffer, size_t bufferLen, const chip::ByteSpan & macOrEui64)
90 : {
91 22 : VerifyOrReturnError(bufferLen >= macOrEui64.size() * 2 + 1, CHIP_ERROR_BUFFER_TOO_SMALL);
92 :
93 22 : int idx = 0;
94 178 : for (size_t i = 0; i < macOrEui64.size(); ++i)
95 : {
96 156 : idx += snprintf(buffer + idx, 3, "%02X", macOrEui64.data()[i]);
97 : }
98 22 : return CHIP_NO_ERROR;
99 : }
100 :
101 92 : CHIP_ERROR MakeServiceSubtype(char * buffer, size_t bufferLen, DiscoveryFilter subtype)
102 : {
103 : int requiredSize;
104 92 : switch (subtype.type)
105 : {
106 20 : case DiscoveryFilterType::kShortDiscriminator:
107 : // 4-bit number
108 20 : if (subtype.code >= 1 << 4)
109 : {
110 2 : return CHIP_ERROR_INVALID_ARGUMENT;
111 : }
112 18 : requiredSize = snprintf(buffer, bufferLen, "_S%u", static_cast<uint16_t>(subtype.code));
113 18 : break;
114 20 : case DiscoveryFilterType::kLongDiscriminator:
115 : // 12-bit number
116 20 : if (subtype.code >= 1 << 12)
117 : {
118 2 : return CHIP_ERROR_INVALID_ARGUMENT;
119 : }
120 18 : requiredSize = snprintf(buffer, bufferLen, "_L%u", static_cast<uint16_t>(subtype.code));
121 18 : break;
122 19 : case DiscoveryFilterType::kVendorId:
123 19 : if (subtype.code >= 1 << 16)
124 : {
125 2 : return CHIP_ERROR_INVALID_ARGUMENT;
126 : }
127 17 : requiredSize = snprintf(buffer, bufferLen, "_V%u", static_cast<uint16_t>(subtype.code));
128 17 : break;
129 5 : case DiscoveryFilterType::kDeviceType:
130 5 : requiredSize = snprintf(buffer, bufferLen, "_T%" PRIu32, static_cast<uint32_t>(subtype.code));
131 5 : break;
132 16 : case DiscoveryFilterType::kCommissioningMode:
133 16 : requiredSize = snprintf(buffer, bufferLen, "_CM");
134 16 : break;
135 0 : case DiscoveryFilterType::kCommissioner:
136 0 : if (subtype.code > 1)
137 : {
138 0 : return CHIP_ERROR_INVALID_ARGUMENT;
139 : }
140 0 : requiredSize = snprintf(buffer, bufferLen, "_D%u", static_cast<uint16_t>(subtype.code));
141 0 : break;
142 10 : case DiscoveryFilterType::kCompressedFabricId:
143 10 : requiredSize = snprintf(buffer, bufferLen, "_I");
144 20 : return Encoding::Uint64ToHex(subtype.code, &buffer[requiredSize], bufferLen - static_cast<size_t>(requiredSize),
145 10 : Encoding::HexFlags::kUppercaseAndNullTerminate);
146 : break;
147 1 : case DiscoveryFilterType::kInstanceName:
148 1 : requiredSize = snprintf(buffer, bufferLen, "%s", subtype.instanceName);
149 1 : break;
150 1 : case DiscoveryFilterType::kNone:
151 1 : requiredSize = 0;
152 1 : buffer[0] = '\0';
153 1 : break;
154 : }
155 76 : return (static_cast<size_t>(requiredSize) <= (bufferLen - 1)) ? CHIP_NO_ERROR : CHIP_ERROR_NO_MEMORY;
156 : }
157 :
158 17 : CHIP_ERROR MakeServiceTypeName(char * buffer, size_t bufferLen, DiscoveryFilter nameDesc, DiscoveryType type)
159 : {
160 : int requiredSize;
161 17 : if (nameDesc.type == DiscoveryFilterType::kNone)
162 : {
163 4 : if (type == DiscoveryType::kCommissionableNode)
164 : {
165 3 : requiredSize = snprintf(buffer, bufferLen, kCommissionableServiceName);
166 : }
167 1 : else if (type == DiscoveryType::kCommissionerNode)
168 : {
169 1 : requiredSize = snprintf(buffer, bufferLen, kCommissionerServiceName);
170 : }
171 0 : else if (type == DiscoveryType::kOperational)
172 : {
173 0 : requiredSize = snprintf(buffer, bufferLen, kOperationalServiceName);
174 : }
175 : else
176 : {
177 0 : return CHIP_ERROR_NOT_IMPLEMENTED;
178 : }
179 : }
180 : else
181 : {
182 13 : ReturnErrorOnFailure(MakeServiceSubtype(buffer, bufferLen, nameDesc));
183 10 : size_t subtypeLen = strlen(buffer);
184 10 : if (type == DiscoveryType::kCommissionableNode)
185 : {
186 9 : requiredSize = snprintf(buffer + subtypeLen, bufferLen - subtypeLen, ".%s.%s", kSubtypeServiceNamePart,
187 : kCommissionableServiceName);
188 : }
189 1 : else if (type == DiscoveryType::kCommissionerNode)
190 : {
191 : requiredSize =
192 0 : snprintf(buffer + subtypeLen, bufferLen - subtypeLen, ".%s.%s", kSubtypeServiceNamePart, kCommissionerServiceName);
193 : }
194 1 : else if (type == DiscoveryType::kOperational)
195 : {
196 : requiredSize =
197 1 : snprintf(buffer + subtypeLen, bufferLen - subtypeLen, ".%s.%s", kSubtypeServiceNamePart, kOperationalServiceName);
198 : }
199 : else
200 : {
201 0 : return CHIP_ERROR_NOT_IMPLEMENTED;
202 : }
203 : }
204 :
205 14 : return (static_cast<size_t>(requiredSize) <= (bufferLen - 1)) ? CHIP_NO_ERROR : CHIP_ERROR_NO_MEMORY;
206 : }
207 :
208 : } // namespace Dnssd
209 : } // namespace chip
|