Line data Source code
1 : /**
2 : * Copyright (c) 2025 Huawei Technologies Co., Ltd.
3 : * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4 : * CANN Open Software License Agreement Version 2.0 (the "License").
5 : * Please refer to the License for details. You may not use this file except in compliance with the License.
6 : * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7 : * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8 : * See LICENSE in the root of the software repository for the full text of the License.
9 : */
10 :
11 : #include "trace_server_socket.h"
12 : #include "grp.h"
13 : #include "adiag_utils.h"
14 : #include "adiag_print.h"
15 : #include "trace_system_api.h"
16 : #include "trace_session_mgr.h"
17 : #include "trace_node.h"
18 : #include "trace_msg.h"
19 : #include "trace_types.h"
20 :
21 : #define SIZE_SIXTEEN_MB (16 * 1024 * 1024) // 16MB
22 : #define SOCKET_TIME_INTERVAL 10000 // 10ms
23 : #define SOCKET_MAX_DATA_SIZE 524288U
24 : #ifndef TRACE_SERVER_USER_NAME
25 : #define TRACE_SERVER_USER_NAME "HwHiAiUser"
26 : #endif
27 :
28 : STATIC int32_t g_sockFd = -1;
29 : STATIC char g_socketPath[SOCKET_PATH_MAX_LENGTH] = {0};
30 : STATIC TraceThread g_traceSocketThread = 0;
31 : STATIC bool g_traceSocketThreadState = false;
32 :
33 18 : STATIC int32_t TraceGetSocketPath(int32_t devId, char* socketPath, uint32_t len)
34 : {
35 18 : if (devId == -1) {
36 14 : int32_t ret = sprintf_s(socketPath, len, "%s%s", SOCKET_FILE_DIR, SOCKET_FILE);
37 14 : if (ret == -1) {
38 2 : ADIAG_ERR("snprintf_s socket path failed, strerr=%s, pid=%d.", strerror(AdiagGetErrorCode()), getpid());
39 2 : return TRACE_FAILURE;
40 : }
41 : } else {
42 4 : int32_t ret = sprintf_s(socketPath, len, "%s%s_%d", SOCKET_FILE_DIR, SOCKET_FILE, devId);
43 4 : if (ret == -1) {
44 2 : ADIAG_ERR(
45 : "snprintf_s socket path failed, strerr=%s, pid=%d, vfid=%u.", strerror(AdiagGetErrorCode()), getpid(),
46 : devId);
47 2 : return TRACE_FAILURE;
48 : }
49 : }
50 14 : return TRACE_SUCCESS;
51 : }
52 :
53 14 : STATIC int32_t TraceCreateSocketByFile(char* socketPath, const char* groupName, uint32_t permission)
54 : {
55 : struct sockaddr_un addr;
56 14 : int32_t nSendBuf = SIZE_SIXTEEN_MB;
57 14 : (void)memset_s(&addr, sizeof(addr), 0, sizeof(addr));
58 14 : addr.sun_family = AF_UNIX;
59 :
60 14 : errno_t err = strcpy_s(addr.sun_path, sizeof(addr.sun_path), socketPath);
61 14 : ADIAG_CHK_EXPR_ACTION(
62 : err != EOK, return -1, "strcpy_s failed, result=%d, strerr=%s.", (int32_t)err, strerror(AdiagGetErrorCode()));
63 :
64 : // Unlink the previous socket file first.
65 14 : int32_t ret = unlink(addr.sun_path);
66 14 : if (ret != 0) {
67 12 : ADIAG_WAR("can not unlink file=%s, strerr=%s.", addr.sun_path, strerror(AdiagGetErrorCode()));
68 : }
69 :
70 : // Create socket.
71 14 : int32_t sockFd = TraceSocket(AF_UNIX, SOCK_DGRAM, 0);
72 14 : ADIAG_CHK_EXPR_ACTION(sockFd < 0, return -1, "create socket failed, strerr=%s.", strerror(AdiagGetErrorCode()));
73 :
74 : do {
75 : // Set socket description.
76 14 : ret = setsockopt(sockFd, SOL_SOCKET, SO_RCVBUF, (const char*)&nSendBuf, sizeof(int32_t));
77 14 : if (ret < 0) {
78 1 : ADIAG_ERR("set socket option failed, strerr=%s.", strerror(AdiagGetErrorCode()));
79 1 : break;
80 : }
81 :
82 : // bind socket with a certain address.
83 13 : ret = TraceBind(sockFd, (TraceSockAddr*)&addr, sizeof(addr));
84 13 : if (ret != TRACE_SUCCESS) {
85 1 : ADIAG_ERR("bind socket failed, bind path is: %s, strerr=%s.", addr.sun_path, strerror(AdiagGetErrorCode()));
86 1 : break;
87 : }
88 :
89 : // Get the GID by using group name string
90 12 : struct group* grpInfo = getgrnam(groupName);
91 12 : if (grpInfo == NULL) {
92 0 : ADIAG_ERR("%s does not exist", groupName);
93 0 : break;
94 : }
95 :
96 : // Change the socket files owner and group.
97 12 : ret = lchown(addr.sun_path, getuid(), grpInfo->gr_gid);
98 12 : if (ret != TRACE_SUCCESS) {
99 0 : ADIAG_ERR(
100 : "change the socket file: %s group failed, strerr=%s.", addr.sun_path, strerror(AdiagGetErrorCode()));
101 0 : break;
102 : }
103 :
104 : // Set the socket files permission.
105 12 : ret = TraceChmod(addr.sun_path, permission);
106 12 : if (ret != TRACE_SUCCESS) {
107 1 : ADIAG_ERR("chmod %s failed , strerr=%s.", addr.sun_path, strerror(AdiagGetErrorCode()));
108 1 : break;
109 : }
110 :
111 11 : ADIAG_INF("create socket succeed, socket path: %s, fd %d.", addr.sun_path, sockFd);
112 11 : return sockFd;
113 : } while (true);
114 :
115 3 : TraceCloseSocket(sockFd);
116 3 : return -1;
117 : }
118 :
119 9 : STATIC TraStatus TraceServerMsgParse(UtraceMsg* traceMsg, TraceEventMsg* eventMsg)
120 : {
121 9 : eventMsg->msgType = TRACE_EVENT_MSG;
122 9 : eventMsg->devId = traceMsg->deviceId;
123 9 : eventMsg->pid = (int32_t)traceMsg->hostPid;
124 9 : eventMsg->seqFlag = TRACE_MSG_SEQFLAG_SINGLE;
125 9 : eventMsg->bufLen = traceMsg->dataLength;
126 9 : eventMsg->saveType = traceMsg->saveType;
127 9 : eventMsg->eventType = 0;
128 9 : eventMsg->sequence = 0;
129 9 : errno_t err = memcpy_s(eventMsg->buf, traceMsg->dataLength, traceMsg + 1U, traceMsg->dataLength);
130 9 : if (err != EOK) {
131 0 : ADIAG_ERR(
132 : "memcpy failed, length = %u bytes, err = %d, strerr = %s.", traceMsg->dataLength, (int32_t)err,
133 : strerror(AdiagGetErrorCode()));
134 0 : return TRACE_FAILURE;
135 : }
136 9 : err = strcpy_s(eventMsg->eventName, EVENT_NAME_MAX_LENGTH, traceMsg->objName);
137 9 : if (err != EOK) {
138 0 : ADIAG_ERR("strcpy_s failed, err = %d, strerr = %s.", (int32_t)err, strerror(AdiagGetErrorCode()));
139 0 : return TRACE_FAILURE;
140 : }
141 9 : err = strcpy_s(eventMsg->eventTime, TIMESTAMP_MAX_LENGTH, traceMsg->eventTime);
142 9 : if (err != EOK) {
143 0 : ADIAG_ERR("strcpy_s failed, err = %d, strerr = %s.", (int32_t)err, strerror(AdiagGetErrorCode()));
144 0 : return TRACE_FAILURE;
145 : }
146 9 : return TRACE_SUCCESS;
147 : }
148 :
149 14 : STATIC void TraceServerDataProcess(char* recvBuf, uint32_t len)
150 : {
151 14 : if (len < sizeof(UtraceMsg)) {
152 5 : ADIAG_ERR(
153 : "parse data received from utrace failed, data length(%u bytes) less then min length(%zu bytes).", len,
154 : sizeof(UtraceMsg));
155 5 : return;
156 : }
157 9 : UtraceMsg* traceMsg = (UtraceMsg*)recvBuf;
158 9 : ADIAG_CHK_EXPR_ACTION(
159 : traceMsg->magic != UTRACE_HEAD_MAGIC, return,
160 : "check magic of data from utrace failed, expect magic = %hu, current magic = %hu.", UTRACE_HEAD_MAGIC,
161 : traceMsg->magic);
162 9 : ADIAG_CHK_EXPR_ACTION(
163 : traceMsg->version < UTRACE_HEAD_VERSION, return,
164 : "check version of data from utrace failed, expect version = %hu, current version = %hu.", UTRACE_HEAD_VERSION,
165 : traceMsg->version);
166 9 : ADIAG_CHK_EXPR_ACTION(
167 : (traceMsg->dataLength == 0) || (traceMsg->dataLength > (len - (uint32_t)sizeof(UtraceMsg))), return,
168 : "data length[%u] is out of range[0-%u].", traceMsg->dataLength, (len - (uint32_t)sizeof(UtraceMsg)));
169 9 : ADIAG_CHK_EXPR_ACTION(
170 : (traceMsg->dataLength > (UINT32_MAX - sizeof(TraceEventMsg))), return,
171 : "dataLength overflow: %u + %zu exceeds UINT32_MAX.", traceMsg->dataLength, sizeof(TraceEventMsg));
172 :
173 9 : TraceEventMsg* eventMsg = (TraceEventMsg*)AdiagMalloc(sizeof(TraceEventMsg) + traceMsg->dataLength);
174 9 : if (eventMsg == NULL) {
175 0 : ADIAG_ERR("malloc for event msg failed, strerr = %s.", strerror(AdiagGetErrorCode()));
176 0 : return;
177 : }
178 9 : if (TraceServerMsgParse(traceMsg, eventMsg) != TRACE_SUCCESS) {
179 0 : ADIAG_ERR("parse msg from socket failed, pid = %u.", traceMsg->hostPid);
180 0 : ADIAG_SAFE_FREE(eventMsg);
181 0 : return;
182 : }
183 9 : TraceServerSessionLock();
184 9 : SessionNode* sessionNode = TraceServerGetSessionNode((int32_t)traceMsg->hostPid, (int32_t)traceMsg->deviceId);
185 9 : if (sessionNode == NULL) {
186 5 : ADIAG_WAR("no session node is valid, pid = %u.", traceMsg->hostPid);
187 5 : TraceServerSessionUnlock();
188 5 : ADIAG_SAFE_FREE(eventMsg);
189 5 : return;
190 : }
191 : TraStatus ret =
192 4 : TraceTsPushNode(sessionNode, eventMsg->seqFlag, (void*)eventMsg, eventMsg->bufLen + sizeof(TraceEventMsg));
193 4 : if (ret == TRACE_SUCCESS) {
194 4 : ADIAG_DBG(
195 : "log read by socket successfully, eventMsg: msgType=%u, eventType=%u, seqFlag=%u,"
196 : "devId=%u, pid=%d, eventName=%s, eventTime=%s, saveType=%u, bufLen=%u bytes.",
197 : (uint32_t)eventMsg->msgType, (uint32_t)eventMsg->eventType, (uint32_t)eventMsg->seqFlag, eventMsg->devId,
198 : eventMsg->pid, eventMsg->eventName, eventMsg->eventTime, (uint32_t)eventMsg->saveType, eventMsg->bufLen);
199 : }
200 4 : TraceServerSessionUnlock();
201 4 : if (ret != TRACE_SUCCESS) {
202 0 : if (ret != TRACE_QUEUE_FULL) {
203 0 : ADIAG_ERR("push node failed, ret = %d, pid = %u.", ret, eventMsg->pid);
204 : }
205 0 : ADIAG_SAFE_FREE(eventMsg);
206 0 : return;
207 : }
208 : }
209 :
210 10 : STATIC void* TraceServerSocketRecv(void* arg)
211 : {
212 : (void)arg;
213 10 : ADIAG_RUN_INF("trace server socket thread start, socket path = %s.", g_socketPath);
214 10 : if (TraceSetThreadName("TraceServerSocketRecv") != TRACE_SUCCESS) {
215 2 : ADIAG_WAR("can not set thread name(TraceServerSocketRecv) but continue.");
216 : }
217 :
218 10 : size_t recvBufLen = SOCKET_MAX_DATA_SIZE; // max receive size
219 10 : char* recvBuf = (char*)AdiagMalloc(recvBufLen);
220 10 : if (recvBuf == NULL) {
221 0 : ADIAG_ERR("create receive buffer failed.");
222 0 : return NULL;
223 : }
224 24 : while (g_traceSocketThreadState) {
225 16 : (void)memset_s(recvBuf, recvBufLen, 0, recvBufLen);
226 16 : ssize_t len = read(g_sockFd, recvBuf, recvBufLen);
227 14 : if (len <= 0) {
228 0 : usleep(SOCKET_TIME_INTERVAL);
229 0 : continue;
230 : }
231 14 : TraceServerDataProcess(recvBuf, (uint32_t)len);
232 : }
233 8 : ADIAG_SAFE_FREE(recvBuf);
234 8 : TraceCloseSocket(g_sockFd);
235 8 : g_sockFd = -1;
236 8 : (void)unlink(g_socketPath);
237 8 : ADIAG_RUN_INF("thread TraceServerSocketRecv exit.");
238 8 : return NULL;
239 : }
240 :
241 11 : STATIC TraStatus TraceServerCreateSocketRecvThread(void)
242 : {
243 : TraceUserBlock thread;
244 11 : thread.procFunc = TraceServerSocketRecv;
245 11 : thread.pulArg = NULL;
246 11 : TraceThreadAttr attr = {1, 0, 0, 0, 0, 0, TRACE_THREAD_STACK_SIZE};
247 11 : TraceThread tid = 0;
248 11 : g_traceSocketThreadState = true;
249 11 : if (TraceCreateTaskWithThreadAttr(&tid, &thread, &attr) != TRACE_SUCCESS) {
250 1 : ADIAG_ERR("create trace server socket receive thread failed, strerr=%s.", strerror(AdiagGetErrorCode()));
251 1 : return TRACE_FAILURE;
252 : }
253 10 : g_traceSocketThread = tid;
254 10 : return TRACE_SUCCESS;
255 : }
256 :
257 18 : TraStatus TraceServerCreateSocketRecv(int32_t devId)
258 : {
259 18 : TraStatus ret = TraceGetSocketPath(devId, g_socketPath, SOCKET_PATH_MAX_LENGTH);
260 18 : ADIAG_CHK_EXPR_ACTION(ret != TRACE_SUCCESS, return TRACE_FAILURE, "get trace socket path failed, result=%d.", ret);
261 :
262 14 : ADIAG_INF("socket path is: %s.", g_socketPath);
263 14 : g_sockFd = TraceCreateSocketByFile(g_socketPath, TRACE_SERVER_USER_NAME, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
264 14 : ADIAG_CHK_EXPR_ACTION(
265 : g_sockFd == TRACE_FAILURE, return TRACE_FAILURE, "create socket failed, strerr=%s.",
266 : strerror(AdiagGetErrorCode()));
267 : // start thread
268 11 : ret = TraceServerCreateSocketRecvThread();
269 11 : if (ret != TRACE_SUCCESS) {
270 1 : ADIAG_ERR("create socket receive thread failed.");
271 1 : TraceCloseSocket(g_sockFd);
272 1 : g_sockFd = -1;
273 1 : (void)unlink(g_socketPath);
274 1 : return TRACE_FAILURE;
275 : }
276 10 : return TRACE_SUCCESS;
277 : }
278 :
279 30 : void TraceServerDestroySocketRecv(void) { g_traceSocketThreadState = false; }
|