• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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 "hilog_base/log_base.h"
17 #include <hilog_base.h>
18 #include <vsnprintf_s_p.h>
19 
20 #include <errno.h>
21 #include <stdatomic.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <sys/socket.h>
25 #include <sys/uio.h>
26 #include <sys/un.h>
27 #include <time.h>
28 #include <unistd.h>
29 
30 #define LOG_LEN 3
31 #define ERROR_FD 2
32 
33 static const int SOCKET_TYPE = SOCK_DGRAM | SOCK_NONBLOCK | SOCK_CLOEXEC;
34 static const struct sockaddr_un SOCKET_ADDR = {AF_UNIX, SOCKET_FILE_DIR INPUT_SOCKET_NAME};
35 static const int INVALID_FD = -1;
36 static const int CAS_FAIL = -1;
37 static const int CAS_INVALID_PARAM = -2;
38 static const int CAS_SUCCESS = 0;
39 static const int INVALID_RESULT = -1;
40 static atomic_int g_socketFd = INVALID_FD;
41 
42 static void CleanSocket(void) __attribute__((destructor));
43 
GenerateSocketFd(void)44 static int GenerateSocketFd(void)
45 {
46     int socketFd = TEMP_FAILURE_RETRY(socket(AF_UNIX, SOCKET_TYPE, 0));
47     if (socketFd == INVALID_FD) {
48         dprintf(ERROR_FD, "HiLogBase: Can't create socket! Errno: %d\n", errno);
49         return INVALID_FD;
50     }
51     long int result =
52         TEMP_FAILURE_RETRY(connect(socketFd, (const struct sockaddr *)(&SOCKET_ADDR), sizeof(SOCKET_ADDR)));
53     if (result == INVALID_RESULT) {
54         dprintf(ERROR_FD, "HiLogBase: Can't connect to server. Errno: %d\n", errno);
55         close(socketFd);
56         return INVALID_FD;
57     }
58     return socketFd;
59 }
60 
CASGlobalSocketFd(int socketFd)61 static int CASGlobalSocketFd(int socketFd)
62 {
63     if (socketFd == INVALID_FD) {
64         return CAS_INVALID_PARAM;
65     }
66     int expected = INVALID_FD;
67     // we should use CAS to avoid multi-thread problem
68     if (!atomic_compare_exchange_strong(&g_socketFd, &expected, socketFd)) {
69         // failure CAS: other threads execute to this branch to close extra fd
70         return CAS_FAIL;
71     }
72     // success CAS: only one thread can execute to this branch
73     return CAS_SUCCESS;
74 }
75 
SendMessage(HilogMsg * header,const char * tag,uint16_t tagLen,const char * fmt,uint16_t fmtLen)76 static int SendMessage(HilogMsg *header, const char *tag, uint16_t tagLen, const char *fmt, uint16_t fmtLen)
77 {
78     bool releaseSocket = false;
79     int socketFd = INVALID_FD;
80     // read fd by using atomic operation
81     socketFd = atomic_load(&g_socketFd);
82     if (socketFd == INVALID_FD) {
83         socketFd = GenerateSocketFd();
84         int result = CASGlobalSocketFd(socketFd);
85         if (result == CAS_INVALID_PARAM) {
86             return INVALID_RESULT;
87         } else if (result == CAS_FAIL) {
88             releaseSocket = true;
89         }
90     }
91 
92     struct timespec ts = {0};
93     (void)clock_gettime(CLOCK_REALTIME, &ts);
94     struct timespec ts_mono = {0};
95     (void)clock_gettime(CLOCK_MONOTONIC, &ts_mono);
96     header->tv_sec = (uint32_t)(ts.tv_sec);
97     header->tv_nsec = (uint32_t)(ts.tv_nsec);
98     header->mono_sec = (uint32_t)(ts_mono.tv_sec);
99     header->len = sizeof(HilogMsg) + tagLen + fmtLen;
100     header->tagLen = tagLen;
101 
102     struct iovec vec[LOG_LEN] = {0};
103     vec[0].iov_base = header;                   // 0 : index of hos log header
104     vec[0].iov_len = sizeof(HilogMsg);          // 0 : index of hos log header
105     vec[1].iov_base = (void *)((char *)(tag));  // 1 : index of log tag
106     vec[1].iov_len = tagLen;                    // 1 : index of log tag
107     vec[2].iov_base = (void *)((char *)(fmt));  // 2 : index of log content
108     vec[2].iov_len = fmtLen;                    // 2 : index of log content
109     int ret = TEMP_FAILURE_RETRY(writev(socketFd, vec, LOG_LEN));
110     if (releaseSocket) {
111         close(socketFd);
112     }
113     return ret;
114 }
115 
CleanSocket(void)116 static void CleanSocket(void)
117 {
118     int socketFd = atomic_load(&g_socketFd);
119     if (socketFd >= 0) {
120         close(socketFd);
121         atomic_store(&g_socketFd, INVALID_FD);
122     }
123 }
124 
HiLogBasePrintArgs(const LogType type,const LogLevel level,const unsigned int domain,const char * tag,const char * fmt,va_list ap)125 int HiLogBasePrintArgs(
126     const LogType type, const LogLevel level, const unsigned int domain, const char *tag, const char *fmt, va_list ap)
127 {
128     char buf[MAX_LOG_LEN] = {0};
129 
130     vsnprintfp_s(buf, MAX_LOG_LEN, MAX_LOG_LEN - 1, true, fmt, ap);
131 
132     size_t tagLen = strnlen(tag, MAX_TAG_LEN - 1);
133     size_t logLen = strnlen(buf, MAX_LOG_LEN - 1);
134     HilogMsg header = {0};
135     header.type = type;
136     header.level = level;
137 #ifndef __RECV_MSG_WITH_UCRED_
138     header.pid = getprocpid();
139 #endif
140     header.tid = (uint32_t)(gettid());
141     header.domain = domain;
142 
143     return SendMessage(&header, tag, tagLen + 1, buf, logLen + 1);
144 }
145 
HiLogBasePrint(LogType type,LogLevel level,unsigned int domain,const char * tag,const char * fmt,...)146 int HiLogBasePrint(LogType type, LogLevel level, unsigned int domain, const char *tag, const char *fmt, ...)
147 {
148     if (!HiLogBaseIsLoggable(domain, tag, level)) {
149         return -1;
150     }
151 
152     int ret;
153     va_list ap;
154     va_start(ap, fmt);
155     ret = HiLogBasePrintArgs(type, level, domain, tag, fmt, ap);
156     va_end(ap);
157     return ret;
158 }
159 
HiLogBaseIsLoggable(unsigned int domain,const char * tag,LogLevel level)160 bool HiLogBaseIsLoggable(unsigned int domain, const char *tag, LogLevel level)
161 {
162     if ((level <= LOG_LEVEL_MIN) || (level >= LOG_LEVEL_MAX) || tag == NULL) {
163         return false;
164     }
165     return true;
166 }