init_service_socket.c 6.4 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
 * 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"
28
#include "loop_event.h"
29 30 31 32 33 34 35 36 37
#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 已提交
38
    (void)memset_s(addr, sizeof(struct sockaddr_un), 0x0, sizeof(struct sockaddr_un));
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
    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 已提交
62
        if (access(addr.sun_path, F_OK) == 0) {
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 99
            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 已提交
100 101 102
    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);
103
    int ret = setenv(pubName, val, 1);
X
add ut  
xionglei6 已提交
104
    INIT_ERROR_CHECK(ret >= 0, return -1, "setenv fail %d ", errno);
105 106 107 108
    fcntl(fd, F_SETFD, 0);
    return 0;
}

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 144 145 146 147 148 149 150 151
static void ProcessWatchEvent_(const WatcherHandle watcherHandle, int fd, uint32_t *events, const void *context)
{
    *events = 0;
    Service *service = (Service *)context;
    ServiceSocket *tmpSock = service->socketCfg;;
    while (tmpSock != NULL) {
        if (tmpSock->sockFd == fd) {
            tmpSock->watcher = NULL;
            break;
        }
        tmpSock = tmpSock->next;
    }
    if (tmpSock == NULL) { // not found socket
        INIT_LOGE("Service %s not match socket fd %d!", service->name, fd);
        close(fd);
        return;
    }
    INIT_LOGI("Socket information detected, fd:%d service name:%s", fd, service->name);
    SocketDelWatcher(watcherHandle);
    if (ServiceStart(service) != SERVICE_SUCCESS) {
        INIT_LOGE("Service %s start failed!", service->name);
    }
}

int SocketAddWatcher(ServiceWatcher *watcherHandle, Service *service, int fd)
{
    WatcherHandle handle;
    LE_WatchInfo info = {};
    info.fd = fd;
    info.flags = WATCHER_ONCE;
    info.events = Event_Read;
    info.processEvent = ProcessWatchEvent_;
    int ret = LE_StartWatcher(LE_GetDefaultLoop(), &handle, &info, service);
    INIT_LOGI("Start to monitor socket, fd:%d service name:%s", fd, service->name);
    *watcherHandle = (ServiceWatcher)handle;
    return ret;
}

void SocketDelWatcher(ServiceWatcher watcherHandle)
{
    LE_RemoveWatcher(LE_GetDefaultLoop(), (WatcherHandle)watcherHandle);
}

X
xionglei6 已提交
152
int CreateServiceSocket(Service *service)
153
{
X
xionglei6 已提交
154 155 156
    INIT_CHECK(service != NULL && service->socketCfg != NULL, return 0);
    int ret = 0;
    ServiceSocket *tmpSock = service->socketCfg;
157 158
    while (tmpSock != NULL) {
        int fd = CreateSocket(tmpSock);
X
add ut  
xionglei6 已提交
159
        INIT_CHECK_RETURN_VALUE(fd >= 0, -1);
X
xionglei6 已提交
160
        if (IsOnDemandService(service)) {
161 162 163 164 165
            if (IsConnectionBasedSocket(tmpSock)) {
                ret = listen(tmpSock->sockFd, MAX_SOCKET_FD_LEN);
                INIT_CHECK_RETURN_VALUE(ret == 0, -1);
            }
            ret = SocketAddWatcher(&tmpSock->watcher, service, tmpSock->sockFd);
X
xionglei6 已提交
166 167 168
            INIT_CHECK_RETURN_VALUE(ret == 0, -1);
        }
        ret = SetSocketEnv(fd, tmpSock->name);
X
add ut  
xionglei6 已提交
169
        INIT_CHECK_RETURN_VALUE(ret >= 0, -1);
170 171 172 173 174
        tmpSock = tmpSock->next;
    }
    return 0;
}

X
xionglei6 已提交
175
void CloseServiceSocket(Service *service)
176
{
X
xionglei6 已提交
177
    INIT_CHECK(service != NULL && service->socketCfg != NULL, return);
178
    struct sockaddr_un addr;
X
xionglei6 已提交
179 180 181
    ServiceSocket *sockopt = service->socketCfg;
    while (sockopt != NULL) {
        if (sockopt->watcher != NULL) {
182
            SocketDelWatcher(sockopt->watcher);
X
xionglei6 已提交
183
        }
184 185 186 187 188 189 190
        if (sockopt->sockFd >= 0) {
            close(sockopt->sockFd);
            sockopt->sockFd = -1;
        }
        if (GetSocketAddr(&addr, sockopt->name) == 0) {
            unlink(addr.sun_path);
        }
X
xionglei6 已提交
191
        sockopt = sockopt->next;
192 193
    }
    return;
Z
zhong_ning 已提交
194
}