1 /*
2  * Copyright (C) 2021-2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "nstackx_dfinder_hidump.h"
17 #include <inttypes.h>
18 #include "nstackx_dfinder_log.h"
19 #include "nstackx_dfinder_mgt_msg_log.h"
20 #include "nstackx_util.h"
21 #include "nstackx_getopt.h"
22 #include "nstackx_statistics.h"
23 #include "nstackx_common.h"
24 #include "nstackx_device.h"
25 #include "nstackx_event.h"
26 #include "nstackx_error.h"
27 #include "securec.h"
28 #include "nstackx_device_local.h"
29 #include "nstackx_device_remote.h"
30 
31 #ifdef NSTACKX_DFINDER_HIDUMP
32 
33 #define TAG "nStackXDFinder"
34 #define CRLF "\r\n"
35 
36 #define DUMP_BUF_LEN (2048U)
37 #define DUMP_LARGE_BUF_LEN (409600U)
38 #define DFINDER_DUMP_MAX_ARGC (20U)
39 #define DFINDER_DUMP_STRTOL_BASE 10
40 static const char *g_dfinderDumpOpts = "fhlrsm:";
41 
42 typedef struct {
43     char *buf;
44     uint32_t size;
45     int err;
46     sem_t wait;
47 } DumpMsg;
48 
CreateDumpMsg(char * buf,uint32_t size)49 static DumpMsg *CreateDumpMsg(char *buf, uint32_t size)
50 {
51     DumpMsg *msg = (DumpMsg *)malloc(sizeof(DumpMsg));
52     if (msg == NULL) {
53         DFINDER_LOGE(TAG, "malloc dump msg failed");
54         return NULL;
55     }
56 
57     if (SemInit(&(msg->wait), 0, 0)) {
58         DFINDER_LOGE(TAG, "init msg wait failed");
59         free(msg);
60         return NULL;
61     }
62 
63     msg->err = NSTACKX_EOK;
64     msg->buf = buf;
65     msg->size = size;
66     return msg;
67 }
68 
DestroyDumpMsg(DumpMsg * msg)69 static void DestroyDumpMsg(DumpMsg *msg)
70 {
71     SemDestroy(&(msg->wait));
72     free(msg);
73 }
74 
PostDumpMsg(char * buf,uint32_t size,EventHandle handle)75 static int PostDumpMsg(char *buf, uint32_t size, EventHandle handle)
76 {
77     int ret = NSTACKX_EFAILED;
78     DumpMsg *msg = CreateDumpMsg(buf, size);
79     if (msg == NULL) {
80         DFINDER_LOGE(TAG, "create dump msg failed");
81         return ret;
82     }
83 
84     if (PostEvent(GetEventNodeChain(), GetEpollFD(), handle, msg) != NSTACKX_EOK) {
85         DestroyDumpMsg(msg);
86         return ret;
87     }
88 
89     SemWait(&(msg->wait));
90     ret = msg->err;
91     DestroyDumpMsg(msg);
92     return ret;
93 }
94 
95 typedef int (*DumpFunc)(char *buf, uint32_t size);
Dump(void * softObj,uint32_t size,DFinderDumpFunc dump,DumpFunc func)96 static int Dump(void *softObj, uint32_t size, DFinderDumpFunc dump, DumpFunc func)
97 {
98     if (size == 0 || size > DUMP_LARGE_BUF_LEN) {
99         return NSTACKX_EFAILED;
100     }
101 
102     char *buf = (char *)calloc(size, sizeof(char));
103     if (buf == NULL) {
104         DFINDER_LOGE(TAG, "dump malloc failed");
105         return NSTACKX_EFAILED;
106     }
107 
108     if (func(buf, DUMP_BUF_LEN) != NSTACKX_EOK) {
109         DFINDER_LOGE(TAG, "dump func exec failed");
110         free(buf);
111         return NSTACKX_EFAILED;
112     }
113 
114     dump(softObj, buf, strlen(buf) + 1);
115     free(buf);
116     return NSTACKX_EOK;
117 }
118 
DumpStatisticsInfo(char * buf,uint32_t size)119 static int DumpStatisticsInfo(char *buf, uint32_t size)
120 {
121     int ret;
122     uint32_t index = 0;
123     const uint64_t *stat = GetStatistics();
124     DUMP_MSG_ADD_CHECK(ret, buf, index, size, CRLF"DFinder statistics:"CRLF);
125     DUMP_MSG_ADD_CHECK(ret, buf, index, size, "INVALID_OPT_AND_PAYLOAD: %" PRIu64 CRLF,
126         stat[STATS_INVALID_OPT_AND_PAYLOAD]);
127     DUMP_MSG_ADD_CHECK(ret, buf, index, size, "DECODE_FAILED: %" PRIu64 CRLF, stat[STATS_DECODE_FAILED]);
128     DUMP_MSG_ADD_CHECK(ret, buf, index, size, "ENCODE_FAILED: %" PRIu64 CRLF, stat[STATS_ENCODE_FAILED]);
129     DUMP_MSG_ADD_CHECK(ret, buf, index, size, "CREATE_HEADER_FAILED: %" PRIu64 CRLF, stat[STATS_CREATE_HEADER_FAILED]);
130     DUMP_MSG_ADD_CHECK(ret, buf, index, size, "BUILD_PKT_FAILED: %" PRIu64 CRLF, stat[STATS_BUILD_PKT_FAILED]);
131     DUMP_MSG_ADD_CHECK(ret, buf, index, size, "SOCKET_ERROR: %" PRIu64 CRLF, stat[STATS_SOCKET_ERROR]);
132     DUMP_MSG_ADD_CHECK(ret, buf, index, size, "EPOLL_ERROR: %" PRIu64 CRLF, stat[STATS_EPOLL_ERROR]);
133     DUMP_MSG_ADD_CHECK(ret, buf, index, size, "CREATE_SERVER_FAILED: %" PRIu64 CRLF, stat[STATS_CREATE_SERVER_FAILED]);
134     DUMP_MSG_ADD_CHECK(ret, buf, index, size, "CREATE_CLIENT_FAILED: %" PRIu64 CRLF, stat[STATS_CREATE_CLIENT_FAILED]);
135     DUMP_MSG_ADD_CHECK(ret, buf, index, size, "DROP_LOOPBACK_PKT: %" PRIu64 CRLF, stat[STATS_DROP_LOOPBACK_PKT]);
136     DUMP_MSG_ADD_CHECK(ret, buf, index, size, "SEND_MSG_FAILED: %" PRIu64 CRLF, stat[STATS_SEND_MSG_FAILED]);
137     DUMP_MSG_ADD_CHECK(ret, buf, index, size, "SEND_REQUEST_FAILED: %" PRIu64 CRLF, stat[STATS_SEND_REQUEST_FAILED]);
138     DUMP_MSG_ADD_CHECK(ret, buf, index, size, "DROP_MSG_ID: %" PRIu64 CRLF, stat[STATS_DROP_MSG_ID]);
139     DUMP_MSG_ADD_CHECK(ret, buf, index, size, "HANDLE_SERVICE_MSG_FAILED: %" PRIu64 CRLF,
140         stat[STATS_HANDLE_SERVICE_MSG_FAILED]);
141     DUMP_MSG_ADD_CHECK(ret, buf, index, size, "HANDLE_DEVICE_DISCOVER_MSG_FAILED: %" PRIu64 CRLF,
142         stat[STATS_HANDLE_DEVICE_DISCOVER_MSG_FAILED]);
143     DUMP_MSG_ADD_CHECK(ret, buf, index, size, "INVALID_RESPONSE_MSG: %" PRIu64 CRLF, stat[STATS_INVALID_RESPONSE_MSG]);
144     DUMP_MSG_ADD_CHECK(ret, buf, index, size, "POST_SD_REQUEST_FAILED: %" PRIu64 CRLF,
145         stat[STATS_POST_SD_REQUEST_FAILED]);
146     DUMP_MSG_ADD_CHECK(ret, buf, index, size, "ABORT_SD: %" PRIu64 CRLF, stat[STATS_ABORT_SD]);
147     DUMP_MSG_ADD_CHECK(ret, buf, index, size, "START_SD_FAILED: %" PRIu64 CRLF, stat[STATS_START_SD_FAILED]);
148     DUMP_MSG_ADD_CHECK(ret, buf, index, size, "CREATE_SERVICE_MSG_FAILED: %" PRIu64 CRLF,
149         stat[STATS_CREATE_SERVICE_MSG_FAILED]);
150     DUMP_MSG_ADD_CHECK(ret, buf, index, size, "SEND_SD_RESPONSE_FAILED: %" PRIu64 CRLF,
151         stat[STATS_SEND_SD_RESPONSE_FAILED]);
152     DUMP_MSG_ADD_CHECK(ret, buf, index, size, "BACKUP_DEVICE_DB_FAILED: %" PRIu64 CRLF,
153         stat[STATS_BACKUP_DEVICE_DB_FAILED]);
154     DUMP_MSG_ADD_CHECK(ret, buf, index, size, "UPDATE_DEVICE_DB_FAILED: %" PRIu64 CRLF,
155         stat[STATS_UPDATE_DEVICE_DB_FAILED]);
156     DUMP_MSG_ADD_CHECK(ret, buf, index, size, "CREATE_CONTEX_FAILED: %" PRIu64 CRLF, stat[STATS_CREATE_CONTEX_FAILED]);
157     DUMP_MSG_ADD_CHECK(ret, buf, index, size, "CREATE_SESSION_FAILED: %" PRIu64 CRLF,
158         stat[STATS_CREATE_SESSION_FAILED]);
159     DUMP_MSG_ADD_CHECK(ret, buf, index, size, "PREPARE_SD_MSG_FAILED: %" PRIu64 CRLF,
160         stat[STATS_PREPARE_SD_MSG_FAILED]);
161     DUMP_MSG_ADD_CHECK(ret, buf, index, size, "PARSE_SD_MSG_FAILED: %" PRIu64 CRLF, stat[STATS_PARSE_SD_MSG_FAILED]);
162     DUMP_MSG_ADD_CHECK(ret, buf, index, size, "ALLOC_RECORD_FAILED: %" PRIu64 CRLF, stat[STATS_ALLOC_RECORD_FAILED]);
163     DUMP_MSG_ADD_CHECK(ret, buf, index, size, "FREE_RECORD_FAILED: %" PRIu64 CRLF, stat[STATS_FREE_RECORD_FAILED]);
164     DUMP_MSG_ADD_CHECK(ret, buf, index, size, "OVER_DEVICE_LIMIT: %" PRIu64 CRLF, stat[STATS_OVER_DEVICE_LIMIT]);
165     DUMP_MSG_ADD_CHECK(ret, buf, index, size, "COAP_RESOURCE_INIT_FAILED: %" PRIu64 CRLF,
166         stat[STATS_COAP_RESOURCE_INIT_FAILED]);
167     return NSTACKX_EOK;
168 }
169 
DumpStatisticsInner(void * arg)170 static void DumpStatisticsInner(void *arg)
171 {
172     DumpMsg *msg = (DumpMsg *)arg;
173     msg->err = DumpStatisticsInfo(msg->buf, msg->size);
174     SemPost(&(msg->wait));
175 }
176 
DumpStatistics(char * buf,uint32_t size)177 static int DumpStatistics(char *buf, uint32_t size)
178 {
179     return PostDumpMsg(buf, size, DumpStatisticsInner);
180 }
181 
DFinderDumpIface(char * buf,int size,const char * ifname,const struct in_addr * ip,uint8_t state)182 int DFinderDumpIface(char *buf, int size, const char *ifname, const struct in_addr *ip, uint8_t state)
183 {
184     uint32_t index = 0;
185     int ret;
186     DUMP_MSG_ADD_CHECK(ret, buf, index, size, "network name:%s"CRLF, ifname);
187     DUMP_MSG_ADD_CHECK(ret, buf, index, size, "if state:%hhu"CRLF, state);
188 
189     struct sockaddr_in addr;
190     char ipStr[NSTACKX_MAX_IP_STRING_LEN] = {0};
191     (void)memset_s(&addr, sizeof(struct sockaddr_in), 0, sizeof(struct sockaddr_in));
192     addr.sin_family = AF_INET;
193     addr.sin_addr.s_addr = ip->s_addr;
194     ret = IpAddrAnonymousFormat(ipStr, NSTACKX_MAX_IP_STRING_LEN, (struct sockaddr *)&addr, sizeof(addr));
195     if (ret < 0) {
196         return ret;
197     }
198     DUMP_MSG_ADD_CHECK(ret, buf, index, size, "ip: %s"CRLF, ipStr);
199 
200     return index;
201 }
202 
203 #define DFINDER_DEVICE_ID_ANONY_LEN 6
204 #define DFINDER_DEVICE_ID_ANONY_REMOTE_LEN 15
DumpDeviceInfo(const DeviceInfo * info,char * buf,int size,uint8_t remote)205 int DumpDeviceInfo(const DeviceInfo *info, char *buf, int size, uint8_t remote)
206 {
207     int ret;
208     int i;
209     uint32_t index = 0;
210     size_t len;
211     char deviceid[DFINDER_DEVICE_ID_ANONY_REMOTE_LEN + 1] = {0};
212     DUMP_MSG_ADD_CHECK(ret, buf, index, size, "device name:%s"CRLF, info->deviceName);
213 
214     len = strlen(info->deviceId);
215     if (len > 0) {
216         size_t anonyLen = remote == NSTACKX_TRUE ? DFINDER_DEVICE_ID_ANONY_REMOTE_LEN : DFINDER_DEVICE_ID_ANONY_LEN;
217         len = len > anonyLen ? anonyLen : len;
218         ret = memcpy_s(deviceid, anonyLen, info->deviceId, len);
219         if (ret != EOK) {
220             DFINDER_LOGE(TAG, "memcpy_s failed");
221             return NSTACKX_EFAILED;
222         }
223         DUMP_MSG_ADD_CHECK(ret, buf, index, size, "device id:%s******"CRLF, deviceid);
224     }
225 
226     for (i = 0; i < NSTACKX_MAX_CAPABILITY_NUM; i++) {
227         DUMP_MSG_ADD_CHECK(ret, buf, index, size, "cap %d:%u"CRLF, i, info->capabilityBitmap[i]);
228     }
229 
230     DUMP_MSG_ADD_CHECK(ret, buf, index, size, "mode:%hhu"CRLF"businessType:%hhu"CRLF, info->mode, info->businessType);
231     if (remote == NSTACKX_TRUE) {
232         DUMP_MSG_ADD_CHECK(ret, buf, index, size, "discoveryType:%hhu"CRLF, info->discoveryType);
233     }
234     return index;
235 }
236 
DumpLocalDeviceInfoInner(void * arg)237 static void DumpLocalDeviceInfoInner(void *arg)
238 {
239     int ret;
240     DumpMsg *msg = (DumpMsg *)arg;
241     ret = DumpDeviceInfo(GetLocalDeviceInfo(), msg->buf, msg->size, NSTACKX_FALSE);
242     if (ret < 0) {
243         msg->err = ret;
244     } else {
245         ret = LocalIfaceDump(&msg->buf[ret], msg->size - ret);
246         if (ret < 0) {
247             msg->err = ret;
248         } else {
249             msg->err = NSTACKX_EOK;
250         }
251     }
252     SemPost(&(msg->wait));
253 }
254 
DumpLocalDeviceInfo(char * buf,uint32_t size)255 static int DumpLocalDeviceInfo(char *buf, uint32_t size)
256 {
257     return PostDumpMsg(buf, size, DumpLocalDeviceInfoInner);
258 }
259 
260 #ifdef DFINDER_SAVE_DEVICE_LIST
DumpRemoteDeviceInfoInner(void * arg)261 static void DumpRemoteDeviceInfoInner(void *arg)
262 {
263     DumpMsg *msg = (DumpMsg *)arg;
264     int ret = DumpRemoteDevice(msg->buf, msg->size);
265     if (ret < 0) {
266         msg->err = NSTACKX_EFAILED;
267     } else {
268         msg->err = NSTACKX_EOK;
269     }
270     SemPost(&(msg->wait));
271 }
272 
DumpRemoteDeviceInfo(char * buf,uint32_t size)273 static int DumpRemoteDeviceInfo(char *buf, uint32_t size)
274 {
275     return PostDumpMsg(buf, size, DumpRemoteDeviceInfoInner);
276 }
277 #else
DumpRemoteDeviceInfo(char * buf,uint32_t size)278 static int DumpRemoteDeviceInfo(char *buf, uint32_t size)
279 {
280     (void)buf;
281     (void)size;
282     return NSTACKX_EFAILED;
283 }
284 #endif
285 
DumpCapFilterInfoImp(char * buf,uint32_t size)286 static int DumpCapFilterInfoImp(char *buf, uint32_t size)
287 {
288     int i;
289     int ret;
290     uint32_t index = 0;
291     uint32_t bitmapNum;
292     uint32_t *bitmap = GetFilterCapability(&bitmapNum);
293 
294     for (i = 0; i < NSTACKX_MAX_CAPABILITY_NUM; i++) {
295         DUMP_MSG_ADD_CHECK(ret, buf, index, size, "filter cap %d:%u"CRLF, i, bitmap[i]);
296     }
297 
298     DUMP_MSG_ADD_CHECK(ret, buf, index, size, "filter num:%u"CRLF, bitmapNum);
299     return NSTACKX_EOK;
300 }
301 
DumpCapFilterInfoInner(void * arg)302 static void DumpCapFilterInfoInner(void *arg)
303 {
304     DumpMsg *msg = (DumpMsg *)arg;
305     msg->err = DumpCapFilterInfoImp(msg->buf, msg->size);
306     SemPost(&(msg->wait));
307 }
308 
DumpCapFilterInfo(char * buf,uint32_t size)309 static int DumpCapFilterInfo(char *buf, uint32_t size)
310 {
311     return PostDumpMsg(buf, size, DumpCapFilterInfoInner);
312 }
313 
DumpHelp(char * buf,uint32_t size)314 static int DumpHelp(char *buf, uint32_t size)
315 {
316     int ret;
317     uint32_t index = 0;
318     DUMP_MSG_ADD_CHECK(ret, buf, index, size, CRLF"Usage: dfinder <opt>"CRLF);
319     DUMP_MSG_ADD_CHECK(ret, buf, index, size, "       -h         show this help"CRLF);
320     DUMP_MSG_ADD_CHECK(ret, buf, index, size, "       -l         show local device info"CRLF);
321     DUMP_MSG_ADD_CHECK(ret, buf, index, size, "       -r         show remote device info"CRLF);
322     DUMP_MSG_ADD_CHECK(ret, buf, index, size, "       -f         show capability filter info"CRLF);
323     DUMP_MSG_ADD_CHECK(ret, buf, index, size, "       -s         show statistics info"CRLF);
324     DUMP_MSG_ADD_CHECK(ret, buf, index, size, "       -m <0/1>   enable control message log"CRLF);
325     return NSTACKX_EOK;
326 }
327 
EnableMgtMsgLog(const char * optMsg,void * softObj,DFinderDumpFunc dump)328 static int32_t EnableMgtMsgLog(const char *optMsg, void *softObj, DFinderDumpFunc dump)
329 {
330     int32_t enable;
331 
332     if ((optMsg == NULL) || (strlen(optMsg) != 1) ||
333         ((optMsg[0] != '0') && (optMsg[0] != '1'))) {
334         const char *errMsg = "invalid parameter";
335         dump(softObj, errMsg, strlen(errMsg));
336         (void)Dump(softObj, DUMP_BUF_LEN, dump, DumpHelp);
337         return NSTACKX_EFAILED;
338     }
339 
340     enable = (int32_t)strtol(optMsg, NULL, DFINDER_DUMP_STRTOL_BASE);
341 #ifdef DFINDER_MGT_MSG_LOG
342     (void)DFinderSetMgtMsgLog(enable);
343     if (enable == 0) {
344         const char *disableMsg = "disable control message log";
345         dump(softObj, disableMsg, strlen(disableMsg));
346     } else {
347         const char *enableMsg = "enable control message log";
348         dump(softObj, enableMsg, strlen(enableMsg));
349     }
350     return NSTACKX_EOK;
351 #else
352     const char *unsupportMsg = "the command is unsupported";
353     dump(softObj, unsupportMsg, strlen(unsupportMsg));
354     return NSTACKX_EFAILED;
355 #endif
356 }
357 
DFinderDump(const char ** argv,uint32_t argc,void * softObj,DFinderDumpFunc dump)358 int DFinderDump(const char **argv, uint32_t argc, void *softObj, DFinderDumpFunc dump)
359 {
360     int32_t opt;
361     NstackGetOptMsg optMsg;
362     int32_t ret = NstackInitGetOptMsg(&optMsg);
363     if (ret != NSTACKX_EOK) {
364         return ret;
365     }
366 
367     if (argc == 1) {
368         (void)Dump(softObj, DUMP_BUF_LEN, dump, DumpHelp);
369         return NSTACKX_EOK;
370     }
371 
372     ret = NSTACKX_EFAILED;
373     while ((opt = NstackGetOpt(&optMsg, argc, argv, g_dfinderDumpOpts)) != NSTACK_GETOPT_END_OF_STR) {
374         switch (opt) {
375             case 'h':
376                 ret = Dump(softObj, DUMP_BUF_LEN, dump, DumpHelp);
377                 break;
378             case 's':
379                 ret = Dump(softObj, DUMP_BUF_LEN, dump, DumpStatistics);
380                 break;
381             case 'l':
382                 ret = Dump(softObj, DUMP_BUF_LEN, dump, DumpLocalDeviceInfo);
383                 break;
384             case 'r':
385                 ret = Dump(softObj, DUMP_LARGE_BUF_LEN, dump, DumpRemoteDeviceInfo);
386                 break;
387             case 'f':
388                 ret = Dump(softObj, DUMP_BUF_LEN, dump, DumpCapFilterInfo);
389                 break;
390             case 'm':
391                 ret = EnableMgtMsgLog(NstackGetOptArgs(&optMsg), softObj, dump);
392                 break;
393             default:
394                 ret = NSTACKX_EFAILED;
395                 (void)Dump(softObj, DUMP_BUF_LEN, dump, DumpHelp);
396                 DFINDER_LOGE(TAG, "unknown option");
397                 break;
398         }
399 
400         if (ret != NSTACKX_EOK) {
401             break;
402         }
403     }
404 
405     return ret;
406 }
407 
408 #endif /* NSTACKX_DFINDER_HIDUMP */
409