1/*
2 * Copyright (c) 2024 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 "appspawn_client.h"
17
18#include <errno.h>
19#include <fcntl.h>
20#include <pthread.h>
21#include <string.h>
22#include <unistd.h>
23
24#include <linux/in.h>
25#include <linux/socket.h>
26#include <linux/tcp.h>
27#include <sys/socket.h>
28#include <sys/time.h>
29#include <sys/types.h>
30#include <sys/un.h>
31
32#include "appspawn_mount_permission.h"
33#include "appspawn_hook.h"
34#include "appspawn_utils.h"
35#include "parameter.h"
36#include "securec.h"
37
38static pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;
39static AppSpawnReqMsgMgr *g_clientInstance[CLIENT_MAX] = {NULL};
40
41static uint32_t GetDefaultTimeout(uint32_t def)
42{
43    uint32_t value = def;
44    char data[32] = {};  // 32 length
45    int ret = GetParameter("persist.appspawn.reqMgr.timeout", "0", data, sizeof(data));
46    if (ret > 0 && strcmp(data, "0") != 0) {
47        errno = 0;
48        value = (uint32_t)atoi(data);
49        return (errno != 0) ? def : value;
50    }
51    return value;
52}
53
54static int InitClientInstance(AppSpawnClientType type)
55{
56    pthread_mutex_lock(&g_mutex);
57    if (g_clientInstance[type] != NULL) {
58        pthread_mutex_unlock(&g_mutex);
59        return 0;
60    }
61    AppSpawnReqMsgMgr *clientInstance = malloc(sizeof(AppSpawnReqMsgMgr) + RECV_BLOCK_LEN);
62    if (clientInstance == NULL) {
63        pthread_mutex_unlock(&g_mutex);
64        return APPSPAWN_SYSTEM_ERROR;
65    }
66    // init
67    clientInstance->type = type;
68    clientInstance->msgNextId = 1;
69    clientInstance->timeout = GetDefaultTimeout(TIMEOUT_DEF);
70    clientInstance->maxRetryCount = MAX_RETRY_SEND_COUNT;
71    clientInstance->socketId = -1;
72    pthread_mutex_init(&clientInstance->mutex, NULL);
73    // init recvBlock
74    OH_ListInit(&clientInstance->recvBlock.node);
75    clientInstance->recvBlock.blockSize = RECV_BLOCK_LEN;
76    clientInstance->recvBlock.currentIndex = 0;
77    g_clientInstance[type] = clientInstance;
78    pthread_mutex_unlock(&g_mutex);
79    return 0;
80}
81
82APPSPAWN_STATIC void CloseClientSocket(int socketId)
83{
84    APPSPAWN_LOGV("Closed socket with fd %{public}d", socketId);
85    if (socketId >= 0) {
86        int flag = 0;
87        setsockopt(socketId, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(int));
88        close(socketId);
89    }
90}
91
92APPSPAWN_STATIC int CreateClientSocket(uint32_t type, uint32_t timeout)
93{
94    const char *socketName;
95
96    switch (type) {
97        case CLIENT_FOR_APPSPAWN:
98            socketName = APPSPAWN_SOCKET_NAME;
99            break;
100        case CLIENT_FOR_CJAPPSPAWN:
101            socketName = CJAPPSPAWN_SOCKET_NAME;
102            break;
103        case CLIENT_FOR_NATIVESPAWN:
104            socketName = NATIVESPAWN_SOCKET_NAME;
105            break;
106        default:
107            socketName = NWEBSPAWN_SOCKET_NAME;
108            break;
109    }
110
111    int socketFd = socket(AF_UNIX, SOCK_STREAM, 0);  // SOCK_SEQPACKET
112    APPSPAWN_CHECK(socketFd >= 0, return -1,
113        "Socket socket fd: %{public}s error: %{public}d", socketName, errno);
114    int ret = 0;
115    do {
116        int flag = 1;
117        ret = setsockopt(socketFd, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(int));
118        flag = 1;
119        ret = setsockopt(socketFd, SOL_SOCKET, SO_PASSCRED, &flag, sizeof(flag));
120        APPSPAWN_CHECK(ret == 0, break, "Set opt SO_PASSCRED name: %{public}s error: %{public}d", socketName, errno);
121
122        struct timeval timeoutVal = {timeout, 0};
123        ret = setsockopt(socketFd, SOL_SOCKET, SO_SNDTIMEO, &timeoutVal, sizeof(timeoutVal));
124        APPSPAWN_CHECK(ret == 0, break, "Set opt SO_SNDTIMEO name: %{public}s error: %{public}d", socketName, errno);
125        ret = setsockopt(socketFd, SOL_SOCKET, SO_RCVTIMEO, &timeoutVal, sizeof(timeoutVal));
126        APPSPAWN_CHECK(ret == 0, break, "Set opt SO_RCVTIMEO name: %{public}s error: %{public}d", socketName, errno);
127
128        ret = APPSPAWN_SYSTEM_ERROR;
129        struct sockaddr_un addr;
130        socklen_t pathSize = sizeof(addr.sun_path);
131        int pathLen = snprintf_s(addr.sun_path, pathSize, (pathSize - 1), "%s%s", APPSPAWN_SOCKET_DIR, socketName);
132        APPSPAWN_CHECK(pathLen > 0, break, "Format path %{public}s error: %{public}d", socketName, errno);
133        addr.sun_family = AF_LOCAL;
134        socklen_t socketAddrLen = (socklen_t)(offsetof(struct sockaddr_un, sun_path) + (socklen_t)pathLen + 1);
135        ret = connect(socketFd, (struct sockaddr *)(&addr), socketAddrLen);
136        APPSPAWN_CHECK(ret == 0, break,
137            "Failed to connect %{public}s error: %{public}d", addr.sun_path, errno);
138        APPSPAWN_LOGI("Create socket success %{public}s socketFd: %{public}d", addr.sun_path, socketFd);
139        return socketFd;
140    } while (0);
141    CloseClientSocket(socketFd);
142    return -1;
143}
144
145APPSPAWN_STATIC int UpdateSocketTimeout(uint32_t timeout, int socketFd)
146{
147    struct timeval timeoutVal = {timeout, 0};
148    int ret = setsockopt(socketFd, SOL_SOCKET, SO_SNDTIMEO, &timeoutVal, sizeof(timeoutVal));
149    APPSPAWN_CHECK(ret == 0, return ret, "Set opt SO_SNDTIMEO error: %{public}d", errno);
150    ret = setsockopt(socketFd, SOL_SOCKET, SO_RCVTIMEO, &timeoutVal, sizeof(timeoutVal));
151    APPSPAWN_CHECK(ret == 0, return ret, "Set opt SO_RCVTIMEO error: %{public}d", errno);
152    return ret;
153}
154
155static int ReadMessage(int socketFd, uint32_t sendMsgId, uint8_t *buf, int len, AppSpawnResult *result)
156{
157    ssize_t rLen = TEMP_FAILURE_RETRY(read(socketFd, buf, len));
158    APPSPAWN_CHECK(rLen >= 0, return APPSPAWN_TIMEOUT,
159        "Read message from fd %{public}d rLen %{public}zd errno: %{public}d", socketFd, rLen, errno);
160    if ((size_t)rLen >= sizeof(AppSpawnResponseMsg)) {
161        AppSpawnResponseMsg *msg = (AppSpawnResponseMsg *)(buf);
162        APPSPAWN_CHECK_ONLY_LOG(sendMsgId == msg->msgHdr.msgId,
163            "Invalid msg recvd %{public}u %{public}u", sendMsgId, msg->msgHdr.msgId);
164        return memcpy_s(result, sizeof(AppSpawnResult), &msg->result, sizeof(msg->result));
165    }
166    return APPSPAWN_TIMEOUT;
167}
168
169static int WriteMessage(int socketFd, const uint8_t *buf, ssize_t len, int *fds, int *fdCount)
170{
171    ssize_t written = 0;
172    ssize_t remain = len;
173    const uint8_t *offset = buf;
174    struct iovec iov = {
175        .iov_base = (void *) offset,
176        .iov_len = len,
177    };
178    struct msghdr msg = {
179        .msg_iov = &iov,
180        .msg_iovlen = 1,
181    };
182    char *ctrlBuffer = NULL;
183    if (fdCount != NULL && fds != NULL && *fdCount > 0) {
184        msg.msg_controllen = CMSG_SPACE(*fdCount * sizeof(int));
185        ctrlBuffer = (char *) malloc(msg.msg_controllen);
186        APPSPAWN_CHECK(ctrlBuffer != NULL, return -1,
187            "WriteMessage fail to alloc memory for msg_control %{public}d %{public}d", msg.msg_controllen, errno);
188        msg.msg_control = ctrlBuffer;
189        struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
190        APPSPAWN_CHECK(cmsg != NULL, free(ctrlBuffer);
191            return -1, "WriteMessage fail to get CMSG_FIRSTHDR %{public}d", errno);
192        cmsg->cmsg_len = CMSG_LEN(*fdCount * sizeof(int));
193        cmsg->cmsg_type = SCM_RIGHTS;
194        cmsg->cmsg_level = SOL_SOCKET;
195        int ret = memcpy_s(CMSG_DATA(cmsg), cmsg->cmsg_len, fds, *fdCount * sizeof(int));
196        APPSPAWN_CHECK(ret == 0, free(ctrlBuffer);
197            return -1, "WriteMessage fail to memcpy_s fd %{public}d", errno);
198        APPSPAWN_LOGV("build fd info count %{public}d", *fdCount);
199    }
200    for (ssize_t wLen = 0; remain > 0; offset += wLen, remain -= wLen, written += wLen) {
201        errno = 0;
202        wLen = sendmsg(socketFd, &msg, MSG_NOSIGNAL);
203        APPSPAWN_LOGV("Write msg errno: %{public}d %{public}zd", errno, wLen);
204        APPSPAWN_CHECK((wLen > 0) || (errno == EINTR), free(ctrlBuffer);
205            return -errno,
206            "Failed to write message to fd %{public}d, wLen %{public}zd errno: %{public}d", socketFd, wLen, errno);
207    }
208    free(ctrlBuffer);
209    return written == len ? 0 : -EFAULT;
210}
211
212static int HandleMsgSend(AppSpawnReqMsgMgr *reqMgr, int socketId, AppSpawnReqMsgNode *reqNode)
213{
214    APPSPAWN_LOGV("HandleMsgSend reqId: %{public}u msgId: %{public}d", reqNode->reqId, reqNode->msg->msgId);
215    ListNode *sendNode = reqNode->msgBlocks.next;
216    uint32_t currentIndex = 0;
217    bool sendFd = true;
218    while (sendNode != NULL && sendNode != &reqNode->msgBlocks) {
219        AppSpawnMsgBlock *sendBlock = (AppSpawnMsgBlock *)ListEntry(sendNode, AppSpawnMsgBlock, node);
220        int ret = WriteMessage(socketId, sendBlock->buffer, sendBlock->currentIndex,
221            sendFd ? reqNode->fds : NULL,
222            sendFd ? &reqNode->fdCount : NULL);
223        currentIndex += sendBlock->currentIndex;
224        APPSPAWN_LOGV("Write msg ret: %{public}d msgId: %{public}u %{public}u %{public}u",
225            ret, reqNode->msg->msgId, reqNode->msg->msgLen, currentIndex);
226        if (ret == 0) {
227            sendFd = false;
228            sendNode = sendNode->next;
229            continue;
230        }
231        APPSPAWN_LOGE("Send msg fail reqId: %{public}u msgId: %{public}d ret: %{public}d",
232            reqNode->reqId, reqNode->msg->msgId, ret);
233        return ret;
234    }
235    return 0;
236}
237
238APPSPAWN_STATIC void TryCreateSocket(AppSpawnReqMsgMgr *reqMgr)
239{
240    uint32_t retryCount = 1;
241    while (retryCount <= reqMgr->maxRetryCount) {
242        if (reqMgr->socketId < 0) {
243            reqMgr->socketId = CreateClientSocket(reqMgr->type, reqMgr->timeout);
244        }
245        if (reqMgr->socketId < 0) {
246            APPSPAWN_LOGV("Failed to create socket, try again");
247            usleep(RETRY_TIME);
248            retryCount++;
249            continue;
250        }
251        break;
252    }
253}
254
255static int ClientSendMsg(AppSpawnReqMsgMgr *reqMgr, AppSpawnReqMsgNode *reqNode, AppSpawnResult *result)
256{
257    uint32_t retryCount = 1;
258    int isColdRun = reqNode->isAsan;
259    while (retryCount <= reqMgr->maxRetryCount) {
260        if (reqMgr->socketId < 0) { // try create socket
261            TryCreateSocket(reqMgr);
262            if (reqMgr->socketId < 0) {
263                usleep(RETRY_TIME);
264                retryCount++;
265                continue;
266            }
267        }
268        if (isColdRun && reqMgr->timeout < ASAN_TIMEOUT) {
269            UpdateSocketTimeout(ASAN_TIMEOUT, reqMgr->socketId);
270        }
271
272        if (reqNode->msg->msgId == 0) {
273            reqNode->msg->msgId = reqMgr->msgNextId++;
274        }
275        int ret = HandleMsgSend(reqMgr, reqMgr->socketId, reqNode);
276        if (ret == 0) {
277            ret = ReadMessage(reqMgr->socketId, reqNode->msg->msgId,
278                reqMgr->recvBlock.buffer, reqMgr->recvBlock.blockSize, result);
279        }
280        if (ret == 0) {
281            if (isColdRun && reqMgr->timeout < ASAN_TIMEOUT) {
282                UpdateSocketTimeout(reqMgr->timeout, reqMgr->socketId);
283            }
284            return 0;
285        }
286        // retry
287        CloseClientSocket(reqMgr->socketId);
288        reqMgr->socketId = -1;
289        reqMgr->msgNextId = 1;
290        reqNode->msg->msgId = 0;
291        usleep(RETRY_TIME);
292        retryCount++;
293    }
294    return APPSPAWN_TIMEOUT;
295}
296
297int AppSpawnClientInit(const char *serviceName, AppSpawnClientHandle *handle)
298{
299    APPSPAWN_CHECK(serviceName != NULL, return APPSPAWN_ARG_INVALID, "Invalid service name");
300    APPSPAWN_CHECK(handle != NULL, return APPSPAWN_ARG_INVALID, "Invalid handle for %{public}s", serviceName);
301    APPSPAWN_LOGV("AppSpawnClientInit serviceName %{public}s", serviceName);
302    AppSpawnClientType type = CLIENT_FOR_APPSPAWN;
303    if (strcmp(serviceName, CJAPPSPAWN_SERVER_NAME) == 0) {
304        type = CLIENT_FOR_CJAPPSPAWN;
305    } else if (strcmp(serviceName, NWEBSPAWN_SERVER_NAME) == 0 || strstr(serviceName, NWEBSPAWN_SOCKET_NAME) != NULL) {
306        type = CLIENT_FOR_NWEBSPAWN;
307    } else if (strcmp(serviceName, NATIVESPAWN_SERVER_NAME) == 0 ||
308        strstr(serviceName, NATIVESPAWN_SOCKET_NAME) != NULL) {
309        type = CLIENT_FOR_NATIVESPAWN;
310    }
311    int ret = InitClientInstance(type);
312    APPSPAWN_CHECK(ret == 0, return APPSPAWN_SYSTEM_ERROR, "Failed to create reqMgr");
313    *handle = (AppSpawnClientHandle)g_clientInstance[type];
314    return 0;
315}
316
317int AppSpawnClientDestroy(AppSpawnClientHandle handle)
318{
319    AppSpawnReqMsgMgr *reqMgr = (AppSpawnReqMsgMgr *)handle;
320    APPSPAWN_CHECK(reqMgr != NULL, return APPSPAWN_SYSTEM_ERROR, "Invalid reqMgr");
321    pthread_mutex_lock(&g_mutex);
322    if (reqMgr->type < sizeof(g_clientInstance) / sizeof(g_clientInstance[0])) {
323        g_clientInstance[reqMgr->type] = NULL;
324    }
325    pthread_mutex_unlock(&g_mutex);
326    pthread_mutex_destroy(&reqMgr->mutex);
327    if (reqMgr->socketId >= 0) {
328        CloseClientSocket(reqMgr->socketId);
329        reqMgr->socketId = -1;
330    }
331    free(reqMgr);
332    return 0;
333}
334
335int AppSpawnClientSendMsg(AppSpawnClientHandle handle, AppSpawnReqMsgHandle reqHandle, AppSpawnResult *result)
336{
337    APPSPAWN_CHECK(result != NULL, AppSpawnReqMsgFree(reqHandle);
338        return APPSPAWN_ARG_INVALID, "Invalid result");
339    result->result = APPSPAWN_ARG_INVALID;
340    result->pid = 0;
341    AppSpawnReqMsgMgr *reqMgr = (AppSpawnReqMsgMgr *)handle;
342    APPSPAWN_CHECK(reqMgr != NULL, AppSpawnReqMsgFree(reqHandle);
343        return APPSPAWN_ARG_INVALID, "Invalid reqMgr");
344    AppSpawnReqMsgNode *reqNode = (AppSpawnReqMsgNode *)reqHandle;
345    APPSPAWN_CHECK(reqNode != NULL && reqNode->msg != NULL, AppSpawnReqMsgFree(reqHandle);
346        return APPSPAWN_ARG_INVALID, "Invalid msgReq");
347
348    APPSPAWN_LOGI("AppSpawnClientSendMsg reqId: %{public}u msgLen: %{public}u %{public}s",
349        reqNode->reqId, reqNode->msg->msgLen, reqNode->msg->processName);
350    pthread_mutex_lock(&reqMgr->mutex);
351    int ret = ClientSendMsg(reqMgr, reqNode, result);
352    if (ret != 0) {
353        result->result = ret;
354    }
355    pthread_mutex_unlock(&reqMgr->mutex);
356    APPSPAWN_LOGI("AppSpawnClientSendMsg reqId: %{public}u end result: 0x%{public}x pid: %{public}d",
357        reqNode->reqId, result->result, result->pid);
358    AppSpawnReqMsgFree(reqHandle);
359    return ret;
360}
361