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