Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / third_party / ot-br-posix / repo / src / web / web-service / ot_client.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 "web/web-service/ot_client.hpp"
30
31 #include <openthread/platform/toolchain.h>
32
33 #include <errno.h>
34 #include <inttypes.h>
35 #include <signal.h>
36 #include <stdarg.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <sys/socket.h>
41 #include <sys/un.h>
42 #include <unistd.h>
43
44 #include "common/code_utils.hpp"
45 #include "common/logging.hpp"
46 #include "utils/strcpy_utils.hpp"
47
48 // Temporary solution before posix platform header files are cleaned up.
49 #ifndef OPENTHREAD_POSIX_APP_SOCKET_NAME
50 #define OPENTHREAD_POSIX_APP_SOCKET_NAME "/tmp/openthread.sock"
51 #endif
52
53 namespace otbr {
54 namespace Web {
55
56 OpenThreadClient::OpenThreadClient(void)
57     : mTimeout(kDefaultTimeout)
58     , mSocket(-1)
59 {
60 }
61
62 OpenThreadClient::~OpenThreadClient(void)
63 {
64     Disconnect();
65 }
66
67 void OpenThreadClient::Disconnect(void)
68 {
69     if (mSocket != -1)
70     {
71         close(mSocket);
72         mSocket = -1;
73     }
74 }
75
76 bool OpenThreadClient::Connect(void)
77 {
78     struct sockaddr_un sockname;
79     int                ret;
80
81     mSocket = socket(AF_UNIX, SOCK_STREAM, 0);
82     VerifyOrExit(mSocket != -1, perror("socket"); ret = EXIT_FAILURE);
83
84     memset(&sockname, 0, sizeof(struct sockaddr_un));
85     sockname.sun_family = AF_UNIX;
86     strcpy_safe(sockname.sun_path, sizeof(sockname.sun_path), OPENTHREAD_POSIX_APP_SOCKET_NAME);
87
88     ret = connect(mSocket, reinterpret_cast<const struct sockaddr *>(&sockname), sizeof(struct sockaddr_un));
89
90     if (ret == -1)
91     {
92         otbrLog(OTBR_LOG_ERR, "OpenThread daemon is not running.");
93     }
94
95 exit:
96     return ret == 0;
97 }
98
99 char *OpenThreadClient::Execute(const char *aFormat, ...)
100 {
101     va_list args;
102     int     ret;
103     char *  rval = nullptr;
104     ssize_t count;
105     size_t  rxLength = 0;
106
107     va_start(args, aFormat);
108     ret = vsnprintf(&mBuffer[1], sizeof(mBuffer) - 1, aFormat, args);
109     va_end(args);
110
111     if (ret < 0)
112     {
113         otbrLog(OTBR_LOG_ERR, "Failed to generate command: %s", strerror(errno));
114     }
115
116     mBuffer[0] = '\n';
117     ret++;
118
119     if (ret == sizeof(mBuffer))
120     {
121         otbrLog(OTBR_LOG_ERR, "Command exceeds maximum limit: %d", kBufferSize);
122     }
123
124     mBuffer[ret] = '\n';
125     ret++;
126
127     count = write(mSocket, mBuffer, ret);
128
129     if (count < ret)
130     {
131         mBuffer[ret] = '\0';
132         otbrLog(OTBR_LOG_ERR, "Failed to send command: %s", mBuffer);
133     }
134
135     for (int i = 0; i < mTimeout; ++i)
136     {
137         fd_set  readFdSet;
138         timeval timeout = {0, 1000};
139         char *  done;
140
141         FD_ZERO(&readFdSet);
142         FD_SET(mSocket, &readFdSet);
143
144         ret = select(mSocket + 1, &readFdSet, nullptr, nullptr, &timeout);
145         VerifyOrExit(ret != -1 || errno == EINTR);
146         if (ret <= 0)
147         {
148             continue;
149         }
150
151         count = read(mSocket, &mBuffer[rxLength], sizeof(mBuffer) - rxLength);
152         VerifyOrExit(count > 0);
153         rxLength += count;
154
155         mBuffer[rxLength] = '\0';
156         done              = strstr(mBuffer, "Done\r\n");
157
158         if (done != nullptr)
159         {
160             // remove trailing \r\n
161             if (done - rval > 2)
162             {
163                 done[-2] = '\0';
164             }
165
166             rval = mBuffer;
167             break;
168         }
169     }
170
171 exit:
172     return rval;
173 }
174
175 int OpenThreadClient::Scan(WpanNetworkInfo *aNetworks, int aLength)
176 {
177     char *result;
178     int   rval = 0;
179
180     mTimeout = 5000;
181     result   = Execute("scan");
182     VerifyOrExit(result != nullptr);
183
184     for (result = strtok(result, "\r\n"); result != nullptr && rval < aLength; result = strtok(nullptr, "\r\n"))
185     {
186         static const char kCliPrompt[] = "> ";
187         char *            cliPrompt;
188         int               matched;
189         int               joinable;
190         int               lqi;
191
192         // remove prompt
193         if ((cliPrompt = strstr(result, kCliPrompt)) != nullptr)
194         {
195             if (cliPrompt == result)
196             {
197                 result += sizeof(kCliPrompt) - 1;
198             }
199             else
200             {
201                 memmove(cliPrompt, cliPrompt + sizeof(kCliPrompt) - 1, strlen(cliPrompt) - sizeof(kCliPrompt) - 1);
202             }
203         }
204
205         matched = sscanf(result,
206                          "| %d | %s | %" PRIx64
207                          " | %hx | %02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx | %hu | %hhd | %d |",
208                          &joinable, aNetworks[rval].mNetworkName, &aNetworks[rval].mExtPanId, &aNetworks[rval].mPanId,
209                          &aNetworks[rval].mHardwareAddress[0], &aNetworks[rval].mHardwareAddress[1],
210                          &aNetworks[rval].mHardwareAddress[2], &aNetworks[rval].mHardwareAddress[3],
211                          &aNetworks[rval].mHardwareAddress[4], &aNetworks[rval].mHardwareAddress[5],
212                          &aNetworks[rval].mHardwareAddress[6], &aNetworks[rval].mHardwareAddress[7],
213                          &aNetworks[rval].mChannel, &aNetworks[rval].mRssi, &lqi);
214
215         // 15 is the number of output arguments of the last sscanf()
216         if (matched != 15)
217         {
218             continue;
219         }
220
221         aNetworks[rval].mAllowingJoin = joinable != 0;
222         ++rval;
223     }
224
225     mTimeout = kDefaultTimeout;
226
227 exit:
228     return rval;
229 }
230
231 bool OpenThreadClient::FactoryReset(void)
232 {
233     const char *result;
234     bool        rval = false;
235 #if __APPLE__
236     typedef sig_t sighandler_t;
237 #endif
238     sighandler_t handler;
239
240     // Ignore the expected SIGPIPE signal during daemon reset.
241     handler = signal(SIGPIPE, SIG_IGN);
242     Execute("factoryreset");
243     signal(SIGPIPE, handler);
244     Disconnect();
245     sleep(1);
246     VerifyOrExit(rval = Connect());
247
248     result = Execute("version");
249     VerifyOrExit(result != nullptr);
250
251     rval = strstr(result, "OPENTHREAD") != nullptr;
252
253 exit:
254     return rval;
255 }
256
257 } // namespace Web
258 } // namespace otbr