init_service_socket.c 4.8 KB
Newer Older
1
/*
Z
zhong_ning 已提交
2
 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
 * 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 "init_service_socket.h"

#include <errno.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/uio.h>
#include <sys/un.h>

#include "init_log.h"
#include "init_service.h"
#include "securec.h"

#define HOS_SOCKET_DIR "/dev/unix/socket"
#define HOS_SOCKET_ENV_PREFIX "OHOS_SOCKET_"
#define MAX_SOCKET_ENV_PREFIX_LEN 64
#define MAX_SOCKET_FD_LEN 16

static int GetSocketAddr(struct sockaddr_un *addr, const char *name)
{
X
xionglei6 已提交
37
    (void)memset_s(addr, sizeof(struct sockaddr_un), 0x0, sizeof(struct sockaddr_un));
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
    addr->sun_family = AF_UNIX;
    size_t addrLen = sizeof(addr->sun_path);
    int ret = snprintf_s(addr->sun_path, addrLen, addrLen - 1, HOS_SOCKET_DIR "/%s", name);
    INIT_ERROR_CHECK(ret >= 0, return -1, "Failed to format addr %s", name);
    return 0;
}

static int CreateSocket(ServiceSocket *sockopt)
{
    INIT_ERROR_CHECK(sockopt != NULL, return SERVICE_FAILURE, "Invalid socket opt");
    if (sockopt->sockFd >= 0) {
        close(sockopt->sockFd);
        sockopt->sockFd = -1;
    }
    sockopt->sockFd = socket(PF_UNIX, sockopt->type, 0);
    INIT_ERROR_CHECK(sockopt->sockFd >= 0, return -1, "socket fail %d ", errno);

    struct sockaddr_un addr;
    int ret = GetSocketAddr(&addr, sockopt->name);
    INIT_ERROR_CHECK(ret == 0, return -1, "Failed to format addr %s", sockopt->name);

    do {
        ret = -1;
Z
zhong_ning 已提交
61
        if (access(addr.sun_path, F_OK) == 0) {
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
            INIT_LOGI("%s already exist, remove it", addr.sun_path);
            unlink(addr.sun_path);
        }
        if (sockopt->passcred) {
            int on = 1;
            if (setsockopt(sockopt->sockFd, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on))) {
                break;
            }
        }
        if (bind(sockopt->sockFd, (struct sockaddr *)&addr, sizeof(addr))) {
            INIT_LOGE("Create socket for service %s failed: %d", sockopt->name, errno);
            break;
        }
        if (lchown(addr.sun_path, sockopt->uid, sockopt->gid)) {
            INIT_LOGE("lchown fail %d ", errno);
            break;
        }
        if (fchmodat(AT_FDCWD, addr.sun_path, sockopt->perm, AT_SYMLINK_NOFOLLOW)) {
            INIT_LOGE("fchmodat fail %d ", errno);
            break;
        }
        ret = 0;
    } while (0);
    if (ret != 0) {
        close(sockopt->sockFd);
        unlink(addr.sun_path);
        return -1;
    }
    INIT_LOGI("CreateSocket %s success", sockopt->name);
    return sockopt->sockFd;
}

static int SetSocketEnv(int fd, const char *name)
{
    INIT_ERROR_CHECK(name != NULL, return SERVICE_FAILURE, "Invalid name");
    char pubName[MAX_SOCKET_ENV_PREFIX_LEN] = { 0 };
    char val[MAX_SOCKET_FD_LEN] = { 0 };
X
add ut  
xionglei6 已提交
99 100 101
    INIT_CHECK_RETURN_VALUE(snprintf_s(pubName, sizeof(pubName), sizeof(pubName) - 1, HOS_SOCKET_ENV_PREFIX "%s",
        name) >= 0, -1);
    INIT_CHECK_RETURN_VALUE(snprintf_s(val, sizeof(val), sizeof(val) - 1, "%d", fd) >= 0, -1);
102
    int ret = setenv(pubName, val, 1);
X
add ut  
xionglei6 已提交
103
    INIT_ERROR_CHECK(ret >= 0, return -1, "setenv fail %d ", errno);
104 105 106 107
    fcntl(fd, F_SETFD, 0);
    return 0;
}

X
xionglei6 已提交
108
int CreateServiceSocket(Service *service)
109
{
X
xionglei6 已提交
110 111 112
    INIT_CHECK(service != NULL && service->socketCfg != NULL, return 0);
    int ret = 0;
    ServiceSocket *tmpSock = service->socketCfg;
113 114
    while (tmpSock != NULL) {
        int fd = CreateSocket(tmpSock);
X
add ut  
xionglei6 已提交
115
        INIT_CHECK_RETURN_VALUE(fd >= 0, -1);
X
xionglei6 已提交
116 117 118 119 120
        if (IsOnDemandService(service)) {
            ret = ServiceAddWatcher(&tmpSock->watcher, service, tmpSock->sockFd);
            INIT_CHECK_RETURN_VALUE(ret == 0, -1);
        }
        ret = SetSocketEnv(fd, tmpSock->name);
X
add ut  
xionglei6 已提交
121
        INIT_CHECK_RETURN_VALUE(ret >= 0, -1);
122 123 124 125 126
        tmpSock = tmpSock->next;
    }
    return 0;
}

X
xionglei6 已提交
127
void CloseServiceSocket(Service *service)
128
{
X
xionglei6 已提交
129
    INIT_CHECK(service != NULL && service->socketCfg != NULL, return);
130
    struct sockaddr_un addr;
X
xionglei6 已提交
131 132 133 134 135
    ServiceSocket *sockopt = service->socketCfg;
    while (sockopt != NULL) {
        if (sockopt->watcher != NULL) {
            ServiceDelWatcher(sockopt->watcher);
        }
136 137 138 139 140 141 142
        if (sockopt->sockFd >= 0) {
            close(sockopt->sockFd);
            sockopt->sockFd = -1;
        }
        if (GetSocketAddr(&addr, sockopt->name) == 0) {
            unlink(addr.sun_path);
        }
X
xionglei6 已提交
143
        sockopt = sockopt->next;
144 145
    }
    return;
Z
zhong_ning 已提交
146
}