• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 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 #include "init_param.h"
16 
17 #include <errno.h>
18 #include <stdatomic.h>
19 #include <stddef.h>
20 #include <string.h>
21 #include <sys/socket.h>
22 #include <unistd.h>
23 
24 #include "init_log.h"
25 #include "init_utils.h"
26 #include "param_base.h"
27 #include "param_manager.h"
28 #include "param_message.h"
29 #include "param_security.h"
30 
31 #define INVALID_SOCKET (-1)
32 static const uint32_t RECV_BUFFER_MAX = 5 * 1024;
33 static atomic_uint g_requestId = ATOMIC_VAR_INIT(1);
34 static int g_clientFd = INVALID_SOCKET;
35 static pthread_mutex_t g_clientMutex = PTHREAD_MUTEX_INITIALIZER;
36 
ParameterInit(void)37 __attribute__((constructor)) static void ParameterInit(void)
38 {
39     if (getpid() == 1) {
40         return;
41     }
42     EnableInitLog(INIT_ERROR);
43     PARAM_WORKSPACE_OPS ops = {0};
44     ops.updaterMode = 0;
45     ops.logFunc = InitLog;
46 #ifdef PARAM_SUPPORT_SELINUX
47     ops.setfilecon = NULL;
48 #endif
49     InitParamWorkSpace(1, &ops);
50 }
51 
ParameterDeinit(void)52 __attribute__((destructor)) static void ParameterDeinit(void)
53 {
54     if (g_clientFd != INVALID_SOCKET) {
55         close(g_clientFd);
56         g_clientFd = INVALID_SOCKET;
57     }
58     pthread_mutex_destroy(&g_clientMutex);
59 }
60 
ProcessRecvMsg(const ParamMessage * recvMsg)61 static int ProcessRecvMsg(const ParamMessage *recvMsg)
62 {
63     PARAM_LOGV("ProcessRecvMsg type: %u msgId: %u name %s", recvMsg->type, recvMsg->id.msgId, recvMsg->key);
64     int result = PARAM_CODE_INVALID_PARAM;
65     switch (recvMsg->type) {
66         case MSG_SET_PARAM:
67             result = ((ParamResponseMessage *)recvMsg)->result;
68             break;
69         case MSG_NOTIFY_PARAM: {
70             uint32_t offset = 0;
71             ParamMsgContent *valueContent = GetNextContent(recvMsg, &offset);
72             PARAM_CHECK(valueContent != NULL, return PARAM_CODE_TIMEOUT, "Invalid msg");
73             result = 0;
74             break;
75         }
76         default:
77             break;
78     }
79     return result;
80 }
81 
ReadMessage(int fd,char * buffer,uint32_t timeout)82 static int ReadMessage(int fd, char *buffer, uint32_t timeout)
83 {
84     int ret = 0;
85     uint32_t diff = 0;
86     time_t startTime;
87     (void)time(&startTime);
88     do {
89         ssize_t recvLen = recv(fd, (char *)buffer, RECV_BUFFER_MAX, 0);
90         if (recvLen > 0) {
91             break;
92         }
93         time_t finishTime;
94         (void)time(&finishTime);
95         diff = (uint32_t)difftime(finishTime, startTime);
96         if (diff >= timeout) {
97             ret = PARAM_CODE_TIMEOUT;
98             break;
99         }
100         if (errno == EAGAIN || errno == EINTR) {
101             usleep(10*1000); // 10*1000 wait 10ms
102             continue;
103         }
104     } while (1);
105     if (ret != 0) {
106         PARAM_LOGE("ReadMessage errno %d diff %u timeout %d ret %d", errno, diff, timeout, ret);
107     }
108     return ret;
109 }
110 
GetClientSocket(int timeout)111 static int GetClientSocket(int timeout)
112 {
113     struct timeval time;
114     time.tv_sec = timeout;
115     time.tv_usec = 0;
116     int clientFd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
117     PARAM_CHECK(clientFd >= 0, return -1, "Failed to create socket");
118     int ret = ConnectServer(clientFd, CLIENT_PIPE_NAME);
119     if (ret == 0) {
120         setsockopt(clientFd, SOL_SOCKET, SO_SNDTIMEO, (char *)&time, sizeof(struct timeval));
121         setsockopt(clientFd, SOL_SOCKET, SO_RCVTIMEO, (char *)&time, sizeof(struct timeval));
122     } else {
123         close(clientFd);
124         clientFd = INVALID_SOCKET;
125     }
126     return clientFd;
127 }
128 
StartRequest(int clientFd,ParamMessage * request,int timeout)129 static int StartRequest(int clientFd, ParamMessage *request, int timeout)
130 {
131     errno = 0;
132     ssize_t sendLen = send(clientFd, (char *)request, request->msgSize, 0);
133     if (errno == EINVAL || errno == EACCES) {
134         return PARAM_CODE_INVALID_SOCKET;
135     }
136     PARAM_CHECK(sendLen >= 0, return PARAM_CODE_FAIL_CONNECT, "Failed to send message err: %d", errno);
137     PARAM_LOGV("sendMessage sendLen fd %d %zd", clientFd, sendLen);
138     int ret = ReadMessage(clientFd, (char *)request, timeout);
139     if (ret == 0) {
140         ret = ProcessRecvMsg(request);
141     }
142     return ret;
143 }
144 
SystemSetParameter(const char * name,const char * value)145 int SystemSetParameter(const char *name, const char *value)
146 {
147     PARAM_CHECK(name != NULL && value != NULL, return -1, "Invalid name or value");
148     int ret = CheckParamName(name, 0);
149     PARAM_CHECK(ret == 0, return ret, "Illegal param name %s", name);
150     ret = CheckParamValue(NULL, name, value, GetParamValueType(name));
151     PARAM_CHECK(ret == 0, return ret, "Illegal param value %s", value);
152 
153     size_t msgSize = sizeof(ParamMsgContent);
154     msgSize = (msgSize < RECV_BUFFER_MAX) ? RECV_BUFFER_MAX : msgSize;
155 
156     ParamMessage *request = (ParamMessage *)CreateParamMessage(MSG_SET_PARAM, name, msgSize);
157     PARAM_CHECK(request != NULL, return -1, "Failed to malloc for connect");
158     uint32_t offset = 0;
159     ret = FillParamMsgContent(request, &offset, PARAM_VALUE, value, strlen(value));
160     PARAM_CHECK(ret == 0, free(request);
161         return -1, "Failed to fill value");
162     request->msgSize = offset + sizeof(ParamMessage);
163     request->id.msgId = atomic_fetch_add(&g_requestId, 1);
164 
165     PARAM_LOGI("SystemSetParameter name %s msgid:%d ", name, request->id.msgId);
166     pthread_mutex_lock(&g_clientMutex);
167     int retryCount = 0;
168     while (retryCount < 2) { // max retry 2
169         if (g_clientFd == INVALID_SOCKET) {
170             g_clientFd = GetClientSocket(DEFAULT_PARAM_SET_TIMEOUT);
171         }
172         if (g_clientFd < 0) {
173             ret = DAC_RESULT_FORBIDED;
174             break;
175         }
176         ret = StartRequest(g_clientFd, request, DEFAULT_PARAM_SET_TIMEOUT);
177         if (ret == PARAM_CODE_INVALID_SOCKET) {
178             close(g_clientFd);
179             g_clientFd = INVALID_SOCKET;
180             retryCount++;
181             ret = DAC_RESULT_FORBIDED;
182         } else {
183             break;
184         }
185     }
186     PARAM_LOGI("SystemSetParameter name %s msgid:%d  ret: %d ", name, request->id.msgId, ret);
187     pthread_mutex_unlock(&g_clientMutex);
188     free(request);
189     return ret;
190 }
191 
SystemWaitParameter(const char * name,const char * value,int32_t timeout)192 int SystemWaitParameter(const char *name, const char *value, int32_t timeout)
193 {
194     PARAM_CHECK(name != NULL, return -1, "Invalid name");
195     int ret = CheckParamName(name, 0);
196     PARAM_CHECK(ret == 0, return ret, "Illegal param name %s", name);
197     ParamHandle handle = 0;
198     ret = ReadParamWithCheck(name, DAC_READ, &handle);
199     if (ret != PARAM_CODE_NOT_FOUND && ret != 0 && ret != PARAM_CODE_NODE_EXIST) {
200         PARAM_CHECK(ret == 0, return ret, "Forbid to wait parameter %s", name);
201     }
202     if (timeout <= 0) {
203         timeout = DEFAULT_PARAM_WAIT_TIMEOUT;
204     }
205     uint32_t msgSize = sizeof(ParamMessage) + sizeof(ParamMsgContent) + sizeof(ParamMsgContent) + sizeof(uint32_t);
206     msgSize = (msgSize < RECV_BUFFER_MAX) ? RECV_BUFFER_MAX : msgSize;
207     uint32_t offset = 0;
208     ParamMessage *request = NULL;
209     if (value != NULL && strlen(value) > 0) {
210         msgSize += PARAM_ALIGN(strlen(value) + 1);
211         request = (ParamMessage *)CreateParamMessage(MSG_WAIT_PARAM, name, msgSize);
212         PARAM_CHECK(request != NULL, return -1, "Failed to malloc for wait");
213         ret = FillParamMsgContent(request, &offset, PARAM_VALUE, value, strlen(value));
214     } else {
215         msgSize += PARAM_ALIGN(1);
216         request = (ParamMessage *)CreateParamMessage(MSG_WAIT_PARAM, name, msgSize);
217         PARAM_CHECK(request != NULL, return -1, "Failed to malloc for wait");
218         ret = FillParamMsgContent(request, &offset, PARAM_VALUE, "*", 1);
219     }
220     PARAM_CHECK(ret == 0, free(request);
221         return -1, "Failed to fill value");
222     ParamMsgContent *content = (ParamMsgContent *)(request->data + offset);
223     content->type = PARAM_WAIT_TIMEOUT;
224     content->contentSize = sizeof(uint32_t);
225     *((uint32_t *)(content->content)) = timeout;
226     offset += sizeof(ParamMsgContent) + sizeof(uint32_t);
227 
228     request->msgSize = offset + sizeof(ParamMessage);
229     request->id.waitId = atomic_fetch_add(&g_requestId, 1);
230 #ifdef STARTUP_INIT_TEST
231     timeout = 1;
232 #endif
233     int fd = GetClientSocket(timeout);
234     PARAM_CHECK(fd >= 0, return -1, "Failed to connect server for wait %s", name);
235     ret = StartRequest(fd, request, timeout);
236     close(fd);
237     free(request);
238     PARAM_LOGI("SystemWaitParameter %s value %s result %d ", name, value, ret);
239     return ret;
240 }
241 
SystemCheckParamExist(const char * name)242 int SystemCheckParamExist(const char *name)
243 {
244     return SysCheckParamExist(name);
245 }
246 
WatchParamCheck(const char * keyprefix)247 int WatchParamCheck(const char *keyprefix)
248 {
249     PARAM_CHECK(keyprefix != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid keyprefix");
250     int ret = CheckParamName(keyprefix, 0);
251     PARAM_CHECK(ret == 0, return ret, "Illegal param name %s", keyprefix);
252     ParamHandle handle = 0;
253     ret = ReadParamWithCheck(keyprefix, DAC_WATCH, &handle);
254     if (ret != PARAM_CODE_NOT_FOUND && ret != 0 && ret != PARAM_CODE_NODE_EXIST) {
255         PARAM_CHECK(ret == 0, return ret, "Forbid to watch parameter %s", keyprefix);
256     }
257     return 0;
258 }
259