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