Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / third_party / ot-br-posix / repo / src / rest / resource.cpp
1 /*
2  *  Copyright (c) 2020, The OpenThread Authors.
3  *  All rights reserved.
4  *
5  *  Redistribution and use in source and binary forms, with or without
6  *  modification, are permitted provided that the following conditions are met:
7  *  1. Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  *  2. Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *  3. Neither the name of the copyright holder nor the
13  *     names of its contributors may be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  *  POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include "rest/resource.hpp"
30
31 #include "string.h"
32
33 #define OT_PSKC_MAX_LENGTH 16
34 #define OT_EXTENDED_PANID_LENGTH 8
35
36 #define OT_REST_RESOURCE_PATH_DIAGNOETIC "/diagnostics"
37 #define OT_REST_RESOURCE_PATH_NODE "/node"
38 #define OT_REST_RESOURCE_PATH_NODE_RLOC "/node/rloc"
39 #define OT_REST_RESOURCE_PATH_NODE_RLOC16 "/node/rloc16"
40 #define OT_REST_RESOURCE_PATH_NODE_EXTADDRESS "/node/ext-address"
41 #define OT_REST_RESOURCE_PATH_NODE_STATE "/node/state"
42 #define OT_REST_RESOURCE_PATH_NODE_NETWORKNAME "/node/network-name"
43 #define OT_REST_RESOURCE_PATH_NODE_LEADERDATA "/node/leader-data"
44 #define OT_REST_RESOURCE_PATH_NODE_NUMOFROUTER "/node/num-of-router"
45 #define OT_REST_RESOURCE_PATH_NODE_EXTPANID "/node/ext-panid"
46 #define OT_REST_RESOURCE_PATH_NETWORK "/networks"
47 #define OT_REST_RESOURCE_PATH_NETWORK_CURRENT "/networks/current"
48 #define OT_REST_RESOURCE_PATH_NETWORK_CURRENT_COMMISSION "/networks/commission"
49 #define OT_REST_RESOURCE_PATH_NETWORK_CURRENT_PREFIX "/networks/current/prefix"
50
51 #define OT_REST_HTTP_STATUS_200 "200 OK"
52 #define OT_REST_HTTP_STATUS_404 "404 Not Found"
53 #define OT_REST_HTTP_STATUS_405 "405 Method Not Allowed"
54 #define OT_REST_HTTP_STATUS_408 "408 Request Timeout"
55 #define OT_REST_HTTP_STATUS_500 "500 Internal Server Error"
56
57 using std::chrono::duration_cast;
58 using std::chrono::microseconds;
59 using std::chrono::steady_clock;
60
61 using std::placeholders::_1;
62 using std::placeholders::_2;
63
64 namespace otbr {
65 namespace rest {
66
67 // MulticastAddr
68 static const char *kMulticastAddrAllRouters = "ff02::2";
69
70 // Default TlvTypes for Diagnostic inforamtion
71 static const uint8_t kAllTlvTypes[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 14, 15, 16, 17, 18, 19};
72
73 // Timeout (in Microseconds) for deleting outdated diagnostics
74 static const uint32_t kDiagResetTimeout = 3000000;
75
76 // Timeout (in Microseconds) for collecting diagnostics
77 static const uint32_t kDiagCollectTimeout = 2000000;
78
79 static std::string GetHttpStatus(HttpStatusCode aErrorCode)
80 {
81     std::string httpStatus;
82
83     switch (aErrorCode)
84     {
85     case HttpStatusCode::kStatusOk:
86         httpStatus = OT_REST_HTTP_STATUS_200;
87         break;
88     case HttpStatusCode::kStatusResourceNotFound:
89         httpStatus = OT_REST_HTTP_STATUS_404;
90         break;
91     case HttpStatusCode::kStatusMethodNotAllowed:
92         httpStatus = OT_REST_HTTP_STATUS_405;
93         break;
94     case HttpStatusCode::kStatusRequestTimeout:
95         httpStatus = OT_REST_HTTP_STATUS_408;
96         break;
97     case HttpStatusCode::kStatusInternalServerError:
98         httpStatus = OT_REST_HTTP_STATUS_500;
99         break;
100     }
101
102     return httpStatus;
103 }
104
105 Resource::Resource(ControllerOpenThread *aNcp)
106     : mNcp(aNcp)
107 {
108     mInstance = mNcp->GetThreadHelper()->GetInstance();
109
110     // Resource Handler
111     mResourceMap.emplace(OT_REST_RESOURCE_PATH_DIAGNOETIC, &Resource::Diagnostic);
112     mResourceMap.emplace(OT_REST_RESOURCE_PATH_NODE, &Resource::NodeInfo);
113     mResourceMap.emplace(OT_REST_RESOURCE_PATH_NODE_STATE, &Resource::State);
114     mResourceMap.emplace(OT_REST_RESOURCE_PATH_NODE_EXTADDRESS, &Resource::ExtendedAddr);
115     mResourceMap.emplace(OT_REST_RESOURCE_PATH_NODE_NETWORKNAME, &Resource::NetworkName);
116     mResourceMap.emplace(OT_REST_RESOURCE_PATH_NODE_RLOC16, &Resource::Rloc16);
117     mResourceMap.emplace(OT_REST_RESOURCE_PATH_NODE_LEADERDATA, &Resource::LeaderData);
118     mResourceMap.emplace(OT_REST_RESOURCE_PATH_NODE_NUMOFROUTER, &Resource::NumOfRoute);
119     mResourceMap.emplace(OT_REST_RESOURCE_PATH_NODE_EXTPANID, &Resource::ExtendedPanId);
120     mResourceMap.emplace(OT_REST_RESOURCE_PATH_NODE_RLOC, &Resource::Rloc);
121
122     // Resource callback handler
123     mResourceCallbackMap.emplace(OT_REST_RESOURCE_PATH_DIAGNOETIC, &Resource::HandleDiagnosticCallback);
124 }
125
126 void Resource::Init(void)
127 {
128 }
129
130 void Resource::Handle(Request &aRequest, Response &aResponse) const
131 {
132     std::string url = aRequest.GetUrl();
133     auto        it  = mResourceMap.find(url);
134
135     if (it != mResourceMap.end())
136     {
137         ResourceHandler resourceHandler = it->second;
138         (this->*resourceHandler)(aRequest, aResponse);
139     }
140     else
141     {
142         ErrorHandler(aResponse, HttpStatusCode::kStatusResourceNotFound);
143     }
144 }
145
146 void Resource::HandleCallback(Request &aRequest, Response &aResponse)
147 {
148     std::string url = aRequest.GetUrl();
149     auto        it  = mResourceCallbackMap.find(url);
150
151     if (it != mResourceCallbackMap.end())
152     {
153         ResourceCallbackHandler resourceHandler = it->second;
154         (this->*resourceHandler)(aRequest, aResponse);
155     }
156 }
157
158 void Resource::HandleDiagnosticCallback(const Request &aRequest, Response &aResponse)
159 {
160     OT_UNUSED_VARIABLE(aRequest);
161     std::vector<std::vector<otNetworkDiagTlv>> diagContentSet;
162     std::string                                body;
163     std::string                                errorCode;
164
165     auto duration = duration_cast<microseconds>(steady_clock::now() - aResponse.GetStartTime()).count();
166     if (duration >= kDiagCollectTimeout)
167     {
168         DeleteOutDatedDiagnostic();
169
170         for (auto it = mDiagSet.begin(); it != mDiagSet.end(); ++it)
171         {
172             diagContentSet.push_back(it->second.mDiagContent);
173         }
174
175         body      = Json::Diag2JsonString(diagContentSet);
176         errorCode = GetHttpStatus(HttpStatusCode::kStatusOk);
177         aResponse.SetResponsCode(errorCode);
178         aResponse.SetBody(body);
179         aResponse.SetComplete();
180     }
181 }
182
183 void Resource::ErrorHandler(Response &aResponse, HttpStatusCode aErrorCode) const
184 {
185     std::string errorMessage = GetHttpStatus(aErrorCode);
186     std::string body         = Json::Error2JsonString(aErrorCode, errorMessage);
187
188     aResponse.SetResponsCode(errorMessage);
189     aResponse.SetBody(body);
190     aResponse.SetComplete();
191 }
192
193 void Resource::GetNodeInfo(Response &aResponse) const
194 {
195     otbrError       error = OTBR_ERROR_NONE;
196     struct NodeInfo node;
197     otRouterInfo    routerInfo;
198     uint8_t         maxRouterId;
199     std::string     body;
200     std::string     errorCode;
201
202     VerifyOrExit(otThreadGetLeaderData(mInstance, &node.mLeaderData) == OT_ERROR_NONE, error = OTBR_ERROR_REST);
203
204     node.mNumOfRouter = 0;
205     maxRouterId       = otThreadGetMaxRouterId(mInstance);
206     for (uint8_t i = 0; i <= maxRouterId; ++i)
207     {
208         if (otThreadGetRouterInfo(mInstance, i, &routerInfo) != OT_ERROR_NONE)
209         {
210             continue;
211         }
212         ++node.mNumOfRouter;
213     }
214
215     node.mRole        = otThreadGetDeviceRole(mInstance);
216     node.mExtAddress  = reinterpret_cast<const uint8_t *>(otLinkGetExtendedAddress(mInstance));
217     node.mNetworkName = otThreadGetNetworkName(mInstance);
218     node.mRloc16      = otThreadGetRloc16(mInstance);
219     node.mExtPanId    = reinterpret_cast<const uint8_t *>(otThreadGetExtendedPanId(mInstance));
220     node.mRlocAddress = *otThreadGetRloc(mInstance);
221
222     body = Json::Node2JsonString(node);
223     aResponse.SetBody(body);
224
225 exit:
226     if (error == OTBR_ERROR_NONE)
227     {
228         errorCode = GetHttpStatus(HttpStatusCode::kStatusOk);
229         aResponse.SetResponsCode(errorCode);
230     }
231     else
232     {
233         ErrorHandler(aResponse, HttpStatusCode::kStatusInternalServerError);
234     }
235 }
236
237 void Resource::NodeInfo(const Request &aRequest, Response &aResponse) const
238 {
239     std::string errorCode;
240     if (aRequest.GetMethod() == HttpMethod::kGet)
241     {
242         GetNodeInfo(aResponse);
243     }
244     else
245     {
246         ErrorHandler(aResponse, HttpStatusCode::kStatusMethodNotAllowed);
247     }
248 }
249
250 void Resource::GetDataExtendedAddr(Response &aResponse) const
251 {
252     const uint8_t *extAddress = reinterpret_cast<const uint8_t *>(otLinkGetExtendedAddress(mInstance));
253     std::string    errorCode;
254     std::string    body = Json::Bytes2HexJsonString(extAddress, OT_EXT_ADDRESS_SIZE);
255
256     aResponse.SetBody(body);
257     errorCode = GetHttpStatus(HttpStatusCode::kStatusOk);
258     aResponse.SetResponsCode(errorCode);
259 }
260
261 void Resource::ExtendedAddr(const Request &aRequest, Response &aResponse) const
262 {
263     std::string errorCode;
264
265     if (aRequest.GetMethod() == HttpMethod::kGet)
266     {
267         GetDataExtendedAddr(aResponse);
268     }
269     else
270     {
271         ErrorHandler(aResponse, HttpStatusCode::kStatusMethodNotAllowed);
272     }
273 }
274
275 void Resource::GetDataState(Response &aResponse) const
276 {
277     std::string state;
278     std::string errorCode;
279     uint8_t     role;
280     // 0 : disabled
281     // 1 : detached
282     // 2 : child
283     // 3 : router
284     // 4 : leader
285
286     role  = otThreadGetDeviceRole(mInstance);
287     state = Json::Number2JsonString(role);
288     aResponse.SetBody(state);
289     errorCode = GetHttpStatus(HttpStatusCode::kStatusOk);
290     aResponse.SetResponsCode(errorCode);
291 }
292
293 void Resource::State(const Request &aRequest, Response &aResponse) const
294 {
295     std::string errorCode;
296
297     if (aRequest.GetMethod() == HttpMethod::kGet)
298     {
299         GetDataState(aResponse);
300     }
301     else
302     {
303         ErrorHandler(aResponse, HttpStatusCode::kStatusMethodNotAllowed);
304     }
305 }
306
307 void Resource::GetDataNetworkName(Response &aResponse) const
308 {
309     std::string networkName;
310     std::string errorCode;
311
312     networkName = otThreadGetNetworkName(mInstance);
313     networkName = Json::String2JsonString(networkName);
314
315     aResponse.SetBody(networkName);
316     errorCode = GetHttpStatus(HttpStatusCode::kStatusOk);
317     aResponse.SetResponsCode(errorCode);
318 }
319
320 void Resource::NetworkName(const Request &aRequest, Response &aResponse) const
321 {
322     std::string errorCode;
323
324     if (aRequest.GetMethod() == HttpMethod::kGet)
325     {
326         GetDataNetworkName(aResponse);
327     }
328     else
329     {
330         ErrorHandler(aResponse, HttpStatusCode::kStatusMethodNotAllowed);
331     }
332 }
333
334 void Resource::GetDataLeaderData(Response &aResponse) const
335 {
336     otbrError    error = OTBR_ERROR_NONE;
337     otLeaderData leaderData;
338     std::string  body;
339     std::string  errorCode;
340
341     VerifyOrExit(otThreadGetLeaderData(mInstance, &leaderData) == OT_ERROR_NONE, error = OTBR_ERROR_REST);
342
343     body = Json::LeaderData2JsonString(leaderData);
344
345     aResponse.SetBody(body);
346
347 exit:
348     if (error == OTBR_ERROR_NONE)
349     {
350         errorCode = GetHttpStatus(HttpStatusCode::kStatusOk);
351         aResponse.SetResponsCode(errorCode);
352     }
353     else
354     {
355         ErrorHandler(aResponse, HttpStatusCode::kStatusInternalServerError);
356     }
357 }
358
359 void Resource::LeaderData(const Request &aRequest, Response &aResponse) const
360 {
361     std::string errorCode;
362     if (aRequest.GetMethod() == HttpMethod::kGet)
363     {
364         GetDataLeaderData(aResponse);
365     }
366     else
367     {
368         ErrorHandler(aResponse, HttpStatusCode::kStatusMethodNotAllowed);
369     }
370 }
371
372 void Resource::GetDataNumOfRoute(Response &aResponse) const
373 {
374     uint8_t      count = 0;
375     uint8_t      maxRouterId;
376     otRouterInfo routerInfo;
377     maxRouterId = otThreadGetMaxRouterId(mInstance);
378     std::string body;
379     std::string errorCode;
380
381     for (uint8_t i = 0; i <= maxRouterId; ++i)
382     {
383         if (otThreadGetRouterInfo(mInstance, i, &routerInfo) != OT_ERROR_NONE)
384         {
385             continue;
386         }
387         ++count;
388     }
389
390     body = Json::Number2JsonString(count);
391
392     aResponse.SetBody(body);
393     errorCode = GetHttpStatus(HttpStatusCode::kStatusOk);
394     aResponse.SetResponsCode(errorCode);
395 }
396
397 void Resource::NumOfRoute(const Request &aRequest, Response &aResponse) const
398 {
399     std::string errorCode;
400
401     if (aRequest.GetMethod() == HttpMethod::kGet)
402     {
403         GetDataNumOfRoute(aResponse);
404     }
405     else
406     {
407         ErrorHandler(aResponse, HttpStatusCode::kStatusMethodNotAllowed);
408     }
409 }
410
411 void Resource::GetDataRloc16(Response &aResponse) const
412 {
413     uint16_t    rloc16 = otThreadGetRloc16(mInstance);
414     std::string body;
415     std::string errorCode;
416
417     body = Json::Number2JsonString(rloc16);
418
419     aResponse.SetBody(body);
420     errorCode = GetHttpStatus(HttpStatusCode::kStatusOk);
421     aResponse.SetResponsCode(errorCode);
422 }
423
424 void Resource::Rloc16(const Request &aRequest, Response &aResponse) const
425 {
426     std::string errorCode;
427
428     if (aRequest.GetMethod() == HttpMethod::kGet)
429     {
430         GetDataRloc16(aResponse);
431     }
432     else
433     {
434         ErrorHandler(aResponse, HttpStatusCode::kStatusMethodNotAllowed);
435     }
436 }
437
438 void Resource::GetDataExtendedPanId(Response &aResponse) const
439 {
440     const uint8_t *extPanId = reinterpret_cast<const uint8_t *>(otThreadGetExtendedPanId(mInstance));
441     std::string    body     = Json::Bytes2HexJsonString(extPanId, OT_EXT_PAN_ID_SIZE);
442     std::string    errorCode;
443
444     aResponse.SetBody(body);
445     errorCode = GetHttpStatus(HttpStatusCode::kStatusOk);
446     aResponse.SetResponsCode(errorCode);
447 }
448
449 void Resource::ExtendedPanId(const Request &aRequest, Response &aResponse) const
450 {
451     std::string errorCode;
452
453     if (aRequest.GetMethod() == HttpMethod::kGet)
454     {
455         GetDataExtendedPanId(aResponse);
456     }
457     else
458     {
459         ErrorHandler(aResponse, HttpStatusCode::kStatusMethodNotAllowed);
460     }
461 }
462
463 void Resource::GetDataRloc(Response &aResponse) const
464 {
465     otIp6Address rlocAddress = *otThreadGetRloc(mInstance);
466     std::string  body;
467     std::string  errorCode;
468
469     body = Json::IpAddr2JsonString(rlocAddress);
470
471     aResponse.SetBody(body);
472     errorCode = GetHttpStatus(HttpStatusCode::kStatusOk);
473     aResponse.SetResponsCode(errorCode);
474 }
475
476 void Resource::Rloc(const Request &aRequest, Response &aResponse) const
477 {
478     std::string errorCode;
479
480     if (aRequest.GetMethod() == HttpMethod::kGet)
481     {
482         GetDataRloc(aResponse);
483     }
484     else
485     {
486         ErrorHandler(aResponse, HttpStatusCode::kStatusMethodNotAllowed);
487     }
488 }
489
490 void Resource::DeleteOutDatedDiagnostic(void)
491 {
492     auto eraseIt = mDiagSet.begin();
493     for (eraseIt = mDiagSet.begin(); eraseIt != mDiagSet.end();)
494     {
495         auto diagInfo = eraseIt->second;
496         auto duration = duration_cast<microseconds>(steady_clock::now() - diagInfo.mStartTime).count();
497
498         if (duration >= kDiagResetTimeout)
499         {
500             eraseIt = mDiagSet.erase(eraseIt);
501         }
502         else
503         {
504             eraseIt++;
505         }
506     }
507 }
508
509 void Resource::UpdateDiag(std::string aKey, std::vector<otNetworkDiagTlv> &aDiag)
510 {
511     DiagInfo value;
512
513     value.mStartTime = steady_clock::now();
514     value.mDiagContent.assign(aDiag.begin(), aDiag.end());
515     mDiagSet[aKey] = value;
516 }
517
518 void Resource::Diagnostic(const Request &aRequest, Response &aResponse) const
519 {
520     otbrError error = OTBR_ERROR_NONE;
521     OT_UNUSED_VARIABLE(aRequest);
522     struct otIp6Address rloc16address = *otThreadGetRloc(mInstance);
523     struct otIp6Address multicastAddress;
524
525     VerifyOrExit(otThreadSendDiagnosticGet(mInstance, &rloc16address, kAllTlvTypes, sizeof(kAllTlvTypes),
526                                            &Resource::DiagnosticResponseHandler,
527                                            const_cast<Resource *>(this)) == OT_ERROR_NONE,
528                  error = OTBR_ERROR_REST);
529     VerifyOrExit(otIp6AddressFromString(kMulticastAddrAllRouters, &multicastAddress) == OT_ERROR_NONE,
530                  error = OTBR_ERROR_REST);
531     VerifyOrExit(otThreadSendDiagnosticGet(mInstance, &multicastAddress, kAllTlvTypes, sizeof(kAllTlvTypes),
532                                            &Resource::DiagnosticResponseHandler,
533                                            const_cast<Resource *>(this)) == OT_ERROR_NONE,
534                  error = OTBR_ERROR_REST);
535
536 exit:
537
538     if (error == OTBR_ERROR_NONE)
539     {
540         aResponse.SetStartTime(steady_clock::now());
541         aResponse.SetCallback();
542     }
543     else
544     {
545         ErrorHandler(aResponse, HttpStatusCode::kStatusInternalServerError);
546     }
547 }
548
549 void Resource::DiagnosticResponseHandler(otError              aError,
550                                          otMessage *          aMessage,
551                                          const otMessageInfo *aMessageInfo,
552                                          void *               aContext)
553 {
554     static_cast<Resource *>(aContext)->DiagnosticResponseHandler(aError, aMessage, aMessageInfo);
555 }
556
557 void Resource::DiagnosticResponseHandler(otError aError, const otMessage *aMessage, const otMessageInfo *aMessageInfo)
558 {
559     std::vector<otNetworkDiagTlv> diagSet;
560     otNetworkDiagTlv              diagTlv;
561     otNetworkDiagIterator         iterator = OT_NETWORK_DIAGNOSTIC_ITERATOR_INIT;
562     otError                       error;
563     char                          rloc[7];
564     std::string                   keyRloc = "0xffee";
565
566     SuccessOrExit(aError);
567
568     OTBR_UNUSED_VARIABLE(aMessageInfo);
569
570     while ((error = otThreadGetNextDiagnosticTlv(aMessage, &iterator, &diagTlv)) == OT_ERROR_NONE)
571     {
572         if (diagTlv.mType == OT_NETWORK_DIAGNOSTIC_TLV_SHORT_ADDRESS)
573         {
574             sprintf(rloc, "0x%04x", diagTlv.mData.mAddr16);
575             keyRloc = Json::CString2JsonString(rloc);
576         }
577         diagSet.push_back(diagTlv);
578     }
579     UpdateDiag(keyRloc, diagSet);
580
581 exit:
582     if (aError != OT_ERROR_NONE)
583     {
584         otbrLog(OTBR_LOG_WARNING, "failed to get diagnostic data: %s", otThreadErrorToString(aError));
585     }
586 }
587
588 } // namespace rest
589 } // namespace otbr