param_request.c 12.0 KB
Newer Older
Z
zhong_ning 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/*
 * Copyright (c) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "param_request.h"
S
sun_fan 已提交
17 18 19 20
#include <errno.h>
#include <fcntl.h>
#include <stddef.h>
#include <stdlib.h>
Z
zhong_ning 已提交
21
#include <string.h>
S
sun_fan 已提交
22
#include <sys/socket.h>
Z
zhong_ning 已提交
23 24 25
#include <unistd.h>

#include "param_manager.h"
S
sun_fan 已提交
26
#include "param_message.h"
Z
zhong_ning 已提交
27

S
sun_fan 已提交
28
#define INVALID_SOCKET (-1)
Z
zhong_ning 已提交
29
#define LABEL "Client"
S
sun_fan 已提交
30 31 32 33
static const uint32_t RECV_BUFFER_MAX = 5 * 1024;

static atomic_uint g_requestId = ATOMIC_VAR_INIT(1);
static ClientWorkSpace g_clientSpace = { {}, -1, {} };
Z
zhong_ning 已提交
34

S
sun_fan 已提交
35 36
__attribute__((constructor)) static void ClientInit(void);
__attribute__((destructor)) static void ClientDeinit(void);
Z
zhong_ning 已提交
37

S
sun_fan 已提交
38
static int InitParamClient(void)
Z
zhong_ning 已提交
39
{
S
sun_fan 已提交
40 41 42 43 44 45 46
    if (PARAM_TEST_FLAG(g_clientSpace.paramSpace.flags, WORKSPACE_FLAGS_INIT)) {
        return 0;
    }
    PARAM_LOGI("InitParamClient");
    pthread_mutex_init(&g_clientSpace.mutex, NULL);
    g_clientSpace.clientFd = INVALID_SOCKET;
    return InitParamWorkSpace(&g_clientSpace.paramSpace, 1);
Z
zhong_ning 已提交
47 48
}

S
sun_fan 已提交
49
void ClientInit(void)
Z
zhong_ning 已提交
50
{
S
sun_fan 已提交
51 52
    PARAM_LOGI("ClientInit");
    (void)InitParamClient();
Z
zhong_ning 已提交
53 54
}

S
sun_fan 已提交
55
void ClientDeinit(void)
Z
zhong_ning 已提交
56
{
S
sun_fan 已提交
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
    CloseParamWorkSpace(&g_clientSpace.paramSpace);
}

static ParamSecurityOps *GetClientParamSecurityOps(void)
{
    return &g_clientSpace.paramSpace.paramSecurityOps;
}

static int FillLabelContent(ParamMessage *request, uint32_t *start, uint32_t length)
{
    uint32_t bufferSize = request->msgSize - sizeof(ParamMessage);
    uint32_t offset = *start;
    PARAM_CHECK((offset + sizeof(ParamMsgContent) + length) <= bufferSize,
        return -1, "Invalid msgSize %u offset %u", request->msgSize, offset);
    ParamMsgContent *content = (ParamMsgContent *)(request->data + offset);
    content->type = PARAM_LABEL;
    content->contentSize = 0;
    ParamSecurityOps *ops = GetClientParamSecurityOps();
    if (length != 0 && ops != NULL && ops->securityEncodeLabel != NULL) {
        int ret = ops->securityEncodeLabel(g_clientSpace.paramSpace.securityLabel, content->content, &length);
        PARAM_CHECK(ret == 0, return -1, "Failed to get label length");
        content->contentSize = length;
Z
zhong_ning 已提交
79
    }
S
sun_fan 已提交
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
    offset += sizeof(ParamMsgContent) + PARAM_ALIGN(content->contentSize);
    *start = offset;
    return 0;
}

static int ProcessRecvMsg(const ParamMessage *recvMsg)
{
    PARAM_LOGD("ProcessRecvMsg type: %u msgId: %u name %s", recvMsg->type, recvMsg->id.msgId, recvMsg->key);
    int result = PARAM_CODE_INVALID_PARAM;
    switch (recvMsg->type) {
        case MSG_SET_PARAM:
            result = ((ParamResponseMessage *)recvMsg)->result;
            break;
        case MSG_NOTIFY_PARAM:
            result = 0;
Z
zhong_ning 已提交
95 96 97 98 99 100 101
            break;
        default:
            break;
    }
    return result;
}

S
sun_fan 已提交
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
static int StartRequest(int *fd, ParamMessage *request, int timeout)
{
    int ret = 0;
    struct timeval time;
    time.tv_sec = timeout;
    time.tv_usec = 0;
    do {
        int clientFd = *fd;
        if (clientFd == INVALID_SOCKET) {
            clientFd = socket(AF_UNIX, SOCK_STREAM, 0);
            PARAM_CHECK(clientFd >= 0, return PARAM_CODE_FAIL_CONNECT, "Failed to create socket");
            ret = ConntectServer(clientFd, PIPE_NAME);
            PARAM_CHECK(ret == 0, close(clientFd);
                return PARAM_CODE_FAIL_CONNECT, "Failed to connect server");
            setsockopt(clientFd, SOL_SOCKET, SO_SNDTIMEO, (char *)&time, sizeof(struct timeval));
            setsockopt(clientFd, SOL_SOCKET, SO_RCVTIMEO, (char *)&time, sizeof(struct timeval));
            *fd = clientFd;
        }
        ssize_t recvLen = 0;
        ssize_t sendLen = send(clientFd, (char *)request, request->msgSize, 0);
        if (sendLen > 0) {
            recvLen = recv(clientFd, (char *)request, RECV_BUFFER_MAX, 0);
            if (recvLen > 0) {
                break;
            }
        }
        ret = errno;
        close(clientFd);
        *fd = INVALID_SOCKET;
        if (errno == EAGAIN || recvLen == 0) {
            ret = PARAM_CODE_TIMEOUT;
            break;
        }
        PARAM_LOGE("Send or recv msg fail errno %d %zd %zd", errno, sendLen, recvLen);
    } while (1);

    if (ret == 0) { // check result
        ret = ProcessRecvMsg(request);
    }
    return ret;
}

Z
zhong_ning 已提交
144 145
int SystemSetParameter(const char *name, const char *value)
{
S
sun_fan 已提交
146 147
    InitParamClient();
    PARAM_CHECK(name != NULL && value != NULL, return -1, "Invalid name or value");
Z
zhong_ning 已提交
148
    int ret = CheckParamName(name, 0);
S
sun_fan 已提交
149 150 151 152 153 154 155 156 157 158 159 160 161 162
    PARAM_CHECK(ret == 0, return ret, "Illegal param name %s", name);
    uint32_t msgSize = sizeof(ParamMessage) + sizeof(ParamMsgContent) + PARAM_ALIGN(strlen(value) + 1);
    uint32_t labelLen = 0;
    ParamSecurityOps *ops = GetClientParamSecurityOps();
    if (LABEL_IS_CLIENT_CHECK_PERMITTED(g_clientSpace.paramSpace.securityLabel)) {
        ret = CheckParamPermission(&g_clientSpace.paramSpace, g_clientSpace.paramSpace.securityLabel, name, DAC_WRITE);
        PARAM_CHECK(ret == 0, return ret, "Forbit to set parameter %s", name);
    } else if (!LABEL_IS_ALL_PERMITTED(g_clientSpace.paramSpace.securityLabel)) { // check local can check permissions
        PARAM_CHECK(ops != NULL && ops->securityEncodeLabel != NULL, return -1, "Invalid securityEncodeLabel");
        ret = ops->securityEncodeLabel(g_clientSpace.paramSpace.securityLabel, NULL, &labelLen);
        PARAM_CHECK(ret == 0, return -1, "Failed to get label length");
    }
    msgSize += sizeof(ParamMsgContent) + labelLen;
    msgSize = msgSize < RECV_BUFFER_MAX ? RECV_BUFFER_MAX : msgSize;
Z
zhong_ning 已提交
163

S
sun_fan 已提交
164
    ParamMessage *request = (ParamMessage *)CreateParamMessage(MSG_SET_PARAM, name, msgSize);
Z
zhong_ning 已提交
165
    PARAM_CHECK(request != NULL, return -1, "Failed to malloc for connect");
S
sun_fan 已提交
166 167 168 169 170 171 172 173 174
    uint32_t offset = 0;
    ret = FillParamMsgContent(request, &offset, PARAM_VALUE, value, strlen(value));
    PARAM_CHECK(ret == 0, free(request);
        return -1, "Failed to fill value");
    ret = FillLabelContent(request, &offset, labelLen);
    PARAM_CHECK(ret == 0, free(request);
        return -1, "Failed to fill label");
    request->msgSize = offset + sizeof(ParamMessage);
    request->id.msgId = atomic_fetch_add(&g_requestId, 1);
Z
zhong_ning 已提交
175

S
sun_fan 已提交
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229
    pthread_mutex_lock(&g_clientSpace.mutex);
    ret = StartRequest(&g_clientSpace.clientFd, request, DEFAULT_PARAM_SET_TIMEOUT);
    pthread_mutex_unlock(&g_clientSpace.mutex);
    free(request);
    return ret;
}

int SystemWaitParameter(const char *name, const char *value, int32_t timeout)
{
    InitParamClient();
    PARAM_CHECK(name != NULL, return -1, "Invalid name");
    int ret = CheckParamName(name, 0);
    PARAM_CHECK(ret == 0, return ret, "Illegal param name %s", name);
    ParamHandle handle = 0;
    ret = ReadParamWithCheck(&g_clientSpace.paramSpace, name, DAC_READ, &handle);
    if (ret != PARAM_CODE_NOT_FOUND && ret != 0) {
        PARAM_CHECK(ret == 0, return ret, "Forbid to wait parameter %s", name);
    }
    if (timeout == 0) {
        timeout = DEFAULT_PARAM_WAIT_TIMEOUT;
    }
    uint32_t msgSize = sizeof(ParamMessage) + sizeof(ParamMsgContent) + sizeof(ParamMsgContent) + sizeof(uint32_t);
    msgSize = msgSize < RECV_BUFFER_MAX ? RECV_BUFFER_MAX : msgSize;
    uint32_t offset = 0;
    ParamMessage *request = NULL;
    if (value != NULL) {
        msgSize += PARAM_ALIGN(strlen(value) + 1);
        request = (ParamMessage *)CreateParamMessage(MSG_WAIT_PARAM, name, msgSize);
        PARAM_CHECK(request != NULL, return -1, "Failed to malloc for wait");
        ret = FillParamMsgContent(request, &offset, PARAM_VALUE, value, strlen(value));
    } else {
        msgSize += PARAM_ALIGN(1);
        request = (ParamMessage *)CreateParamMessage(MSG_WAIT_PARAM, name, msgSize);
        PARAM_CHECK(request != NULL, return -1, "Failed to malloc for wait");
        ret = FillParamMsgContent(request, &offset, PARAM_VALUE, "*", 1);
    }
    PARAM_CHECK(ret == 0, free(request);
        return -1, "Failed to fill value");
    ParamMsgContent *content = (ParamMsgContent *)(request->data + offset);
    content->type = PARAM_WAIT_TIMEOUT;
    content->contentSize = sizeof(uint32_t);
    *((uint32_t *)(content->content)) = timeout;
    offset += sizeof(ParamMsgContent) + sizeof(uint32_t);

    request->msgSize = offset + sizeof(ParamMessage);
    request->id.waitId = atomic_fetch_add(&g_requestId, 1);
    int fd = INVALID_SOCKET;
    ret = StartRequest(&fd, request, timeout);
    if (fd != INVALID_SOCKET) {
        close(fd);
    }
    free(request);
    PARAM_LOGI("SystemWaitParameter %s value %s result %d ", name, value, ret);
    return ret;
Z
zhong_ning 已提交
230 231 232 233
}

int SystemGetParameter(const char *name, char *value, unsigned int *len)
{
S
sun_fan 已提交
234
    InitParamClient();
Z
zhong_ning 已提交
235 236
    PARAM_CHECK(name != NULL && len != NULL, return -1, "The name or value is null");
    ParamHandle handle = 0;
S
sun_fan 已提交
237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258
    int ret = ReadParamWithCheck(&g_clientSpace.paramSpace, name, DAC_READ, &handle);
    if (ret != PARAM_CODE_NOT_FOUND && ret != 0) {
        PARAM_CHECK(ret == 0, return ret, "Forbid to get parameter %s", name);
    }
    return ReadParamValue(&g_clientSpace.paramSpace, handle, value, len);
}

int SystemFindParameter(const char *name, ParamHandle *handle)
{
    InitParamClient();
    PARAM_CHECK(name != NULL && handle != NULL, return -1, "The name or handle is null");
    int ret = ReadParamWithCheck(&g_clientSpace.paramSpace, name, DAC_READ, handle);
    if (ret != PARAM_CODE_NOT_FOUND && ret != 0) {
        PARAM_CHECK(ret == 0, return ret, "Forbid to access parameter %s", name);
    }
    return 0;
}

int SystemGetParameterCommitId(ParamHandle handle, uint32_t *commitId)
{
    PARAM_CHECK(handle != 0 || commitId != NULL, return -1, "The handle is null");
    return ReadParamCommitId(&g_clientSpace.paramSpace, handle, commitId);
Z
zhong_ning 已提交
259 260 261 262 263
}

int SystemGetParameterName(ParamHandle handle, char *name, unsigned int len)
{
    PARAM_CHECK(name != NULL && handle != 0, return -1, "The name is null");
S
sun_fan 已提交
264
    return ReadParamName(&g_clientSpace.paramSpace, handle, name, len);
Z
zhong_ning 已提交
265 266 267 268 269
}

int SystemGetParameterValue(ParamHandle handle, char *value, unsigned int *len)
{
    PARAM_CHECK(len != NULL && handle != 0, return -1, "The value is null");
S
sun_fan 已提交
270
    return ReadParamValue(&g_clientSpace.paramSpace, handle, value, len);
Z
zhong_ning 已提交
271 272
}

S
sun_fan 已提交
273
int SystemTraversalParameter(void (*traversalParameter)(ParamHandle handle, void *cookie), void *cookie)
Z
zhong_ning 已提交
274
{
S
sun_fan 已提交
275
    InitParamClient();
Z
zhong_ning 已提交
276
    PARAM_CHECK(traversalParameter != NULL, return -1, "The param is null");
S
sun_fan 已提交
277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303
    ParamHandle handle = 0;
    // check default dac
    int ret = ReadParamWithCheck(&g_clientSpace.paramSpace, "#", DAC_READ, &handle);
    if (ret != PARAM_CODE_NOT_FOUND && ret != 0) {
        PARAM_CHECK(ret == 0, return ret, "Forbid to traversal parameters");
    }
    return TraversalParam(&g_clientSpace.paramSpace, traversalParameter, cookie);
}

void SystemDumpParameters(int verbose)
{
    InitParamClient();
    DumpParameters(&g_clientSpace.paramSpace, verbose);
}

int WatchParamCheck(const char *keyprefix)
{
    InitParamClient();
    PARAM_CHECK(keyprefix != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid keyprefix");
    int ret = CheckParamName(keyprefix, 0);
    PARAM_CHECK(ret == 0, return ret, "Illegal param name %s", keyprefix);
    ParamHandle handle = 0;
    ret = ReadParamWithCheck(&g_clientSpace.paramSpace, keyprefix, DAC_WATCH, &handle);
    if (ret != PARAM_CODE_NOT_FOUND && ret != 0) {
        PARAM_CHECK(ret == 0, return ret, "Forbid to watch parameter %s", keyprefix);
    }
    return 0;
Z
zhong_ning 已提交
304 305
}

S
sun_fan 已提交
306 307
#ifdef STARTUP_INIT_TEST
ParamWorkSpace *GetClientParamWorkSpace(void)
Z
zhong_ning 已提交
308
{
S
sun_fan 已提交
309
    return &g_clientSpace.paramSpace;
Z
zhong_ning 已提交
310
}
S
sun_fan 已提交
311
#endif