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