1d9f0492fSopenharmony_ci/*
2d9f0492fSopenharmony_ci * Copyright (c) 2021 Huawei Device Co., Ltd.
3d9f0492fSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4d9f0492fSopenharmony_ci * you may not use this file except in compliance with the License.
5d9f0492fSopenharmony_ci * You may obtain a copy of the License at
6d9f0492fSopenharmony_ci *
7d9f0492fSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0
8d9f0492fSopenharmony_ci *
9d9f0492fSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10d9f0492fSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11d9f0492fSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12d9f0492fSopenharmony_ci * See the License for the specific language governing permissions and
13d9f0492fSopenharmony_ci * limitations under the License.
14d9f0492fSopenharmony_ci */
15d9f0492fSopenharmony_ci
16d9f0492fSopenharmony_ci#include "le_socket.h"
17d9f0492fSopenharmony_ci
18d9f0492fSopenharmony_ci#include <arpa/inet.h>
19d9f0492fSopenharmony_ci#include <errno.h>
20d9f0492fSopenharmony_ci#include <fcntl.h>
21d9f0492fSopenharmony_ci#include <netinet/in.h>
22d9f0492fSopenharmony_ci#include <stddef.h>
23d9f0492fSopenharmony_ci#include <string.h>
24d9f0492fSopenharmony_ci#include <sys/socket.h>
25d9f0492fSopenharmony_ci#include <sys/time.h>
26d9f0492fSopenharmony_ci#include <sys/stat.h>
27d9f0492fSopenharmony_ci#include <sys/un.h>
28d9f0492fSopenharmony_ci#include <unistd.h>
29d9f0492fSopenharmony_ci
30d9f0492fSopenharmony_ci#include "le_utils.h"
31d9f0492fSopenharmony_ci
32d9f0492fSopenharmony_cistatic int SetSocketTimeout(int fd)
33d9f0492fSopenharmony_ci{
34d9f0492fSopenharmony_ci    struct timeval timeout;
35d9f0492fSopenharmony_ci    timeout.tv_sec = SOCKET_TIMEOUT;
36d9f0492fSopenharmony_ci    timeout.tv_usec = 0;
37d9f0492fSopenharmony_ci    int ret = setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
38d9f0492fSopenharmony_ci    LE_CHECK(ret == 0, return ret, "Failed to set socket option");
39d9f0492fSopenharmony_ci
40d9f0492fSopenharmony_ci    ret = setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
41d9f0492fSopenharmony_ci    LE_CHECK(ret == 0, return ret, "Failed to set socket option");
42d9f0492fSopenharmony_ci    return ret;
43d9f0492fSopenharmony_ci}
44d9f0492fSopenharmony_ci
45d9f0492fSopenharmony_cistatic int CreatePipeServerSocket_(const char *server, int maxClient, int public)
46d9f0492fSopenharmony_ci{
47d9f0492fSopenharmony_ci    int listenfd = socket(PF_UNIX, SOCK_STREAM, 0);
48d9f0492fSopenharmony_ci    LE_CHECK(listenfd > 0, return listenfd, "Failed to create socket errno %d", errno);
49d9f0492fSopenharmony_ci
50d9f0492fSopenharmony_ci    int ret = SetSocketTimeout(listenfd);
51d9f0492fSopenharmony_ci    LE_CHECK(ret == 0, return ret, "Failed to set socket timeout");
52d9f0492fSopenharmony_ci
53d9f0492fSopenharmony_ci    unlink(server);
54d9f0492fSopenharmony_ci    struct sockaddr_un serverAddr;
55d9f0492fSopenharmony_ci    ret = memset_s(&serverAddr, sizeof(serverAddr), 0, sizeof(serverAddr));
56d9f0492fSopenharmony_ci    LE_CHECK(ret == 0, close(listenfd);
57d9f0492fSopenharmony_ci        return ret, "Failed to memory set. error: %d", errno);
58d9f0492fSopenharmony_ci    serverAddr.sun_family = AF_UNIX;
59d9f0492fSopenharmony_ci    ret = strcpy_s(serverAddr.sun_path, sizeof(serverAddr.sun_path), server);
60d9f0492fSopenharmony_ci    LE_CHECK(ret == 0, close(listenfd);
61d9f0492fSopenharmony_ci        return ret, "Failed to copy.  error: %d", errno);
62d9f0492fSopenharmony_ci    uint32_t size = offsetof(struct sockaddr_un, sun_path) + strlen(server);
63d9f0492fSopenharmony_ci    ret = bind(listenfd, (struct sockaddr *)&serverAddr, size);
64d9f0492fSopenharmony_ci    LE_CHECK(ret >= 0, close(listenfd);
65d9f0492fSopenharmony_ci        return ret, "Failed to bind socket.  error: %d", errno);
66d9f0492fSopenharmony_ci
67d9f0492fSopenharmony_ci    SetNoBlock(listenfd);
68d9f0492fSopenharmony_ci    ret = listen(listenfd, maxClient);
69d9f0492fSopenharmony_ci    LE_CHECK(ret >= 0, close(listenfd);
70d9f0492fSopenharmony_ci        return ret, "Failed to listen socket  error: %d", errno);
71d9f0492fSopenharmony_ci    mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
72d9f0492fSopenharmony_ci    if (public) {
73d9f0492fSopenharmony_ci        mode |= S_IROTH | S_IWOTH;
74d9f0492fSopenharmony_ci    }
75d9f0492fSopenharmony_ci    ret = chmod(server, mode);
76d9f0492fSopenharmony_ci    LE_CHECK(ret == 0, return -1, "Failed to chmod %s, err %d. ", server, errno);
77d9f0492fSopenharmony_ci    LE_LOGV("CreatePipeSocket listen fd: %d server:%s ", listenfd, serverAddr.sun_path);
78d9f0492fSopenharmony_ci    return listenfd;
79d9f0492fSopenharmony_ci}
80d9f0492fSopenharmony_ci
81d9f0492fSopenharmony_cistatic int CreatePipeSocket_(const char *server)
82d9f0492fSopenharmony_ci{
83d9f0492fSopenharmony_ci    int fd = socket(PF_UNIX, SOCK_STREAM, 0);
84d9f0492fSopenharmony_ci    LE_CHECK(fd > 0, return fd, "Failed to create socket");
85d9f0492fSopenharmony_ci    SetNoBlock(fd);
86d9f0492fSopenharmony_ci
87d9f0492fSopenharmony_ci    int on = 1;
88d9f0492fSopenharmony_ci    int ret = setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
89d9f0492fSopenharmony_ci    LE_CHECK(ret == 0, return ret, "Failed to set socket option");
90d9f0492fSopenharmony_ci
91d9f0492fSopenharmony_ci    ret = SetSocketTimeout(fd);
92d9f0492fSopenharmony_ci    LE_CHECK(ret == 0, return ret, "Failed to set socket timeout");
93d9f0492fSopenharmony_ci
94d9f0492fSopenharmony_ci    struct sockaddr_un serverAddr;
95d9f0492fSopenharmony_ci    ret = memset_s(&serverAddr, sizeof(serverAddr), 0, sizeof(serverAddr));
96d9f0492fSopenharmony_ci    LE_CHECK(ret == 0, close(fd);
97d9f0492fSopenharmony_ci        return ret, "Failed to memset_s serverAddr");
98d9f0492fSopenharmony_ci    serverAddr.sun_family = AF_UNIX;
99d9f0492fSopenharmony_ci    ret = strcpy_s(serverAddr.sun_path, sizeof(serverAddr.sun_path), server);
100d9f0492fSopenharmony_ci    LE_CHECK(ret == 0, close(fd);
101d9f0492fSopenharmony_ci        return ret, "Failed to strcpy_s sun_path");
102d9f0492fSopenharmony_ci    uint32_t size = offsetof(struct sockaddr_un, sun_path) + strlen(serverAddr.sun_path);
103d9f0492fSopenharmony_ci    ret = connect(fd, (struct sockaddr *)&serverAddr, size);
104d9f0492fSopenharmony_ci    LE_CHECK(ret >= 0, close(fd);
105d9f0492fSopenharmony_ci        return ret, "Failed to connect socket");
106d9f0492fSopenharmony_ci    LE_LOGV("CreatePipeSocket connect fd: %d server: %s ", fd, serverAddr.sun_path);
107d9f0492fSopenharmony_ci    return fd;
108d9f0492fSopenharmony_ci}
109d9f0492fSopenharmony_ci
110d9f0492fSopenharmony_cistatic LE_STATUS GetSockaddrFromServer_(const char *server, struct sockaddr_in *addr)
111d9f0492fSopenharmony_ci{
112d9f0492fSopenharmony_ci    int ret = memset_s(addr, sizeof(struct sockaddr_in), 0, sizeof(struct sockaddr_in));
113d9f0492fSopenharmony_ci    LE_CHECK(ret == 0, return ret, "Failed to memory set. error: %s", strerror(errno));
114d9f0492fSopenharmony_ci    addr->sin_family = AF_INET;
115d9f0492fSopenharmony_ci    const char *portStr = strstr(server, ":");
116d9f0492fSopenharmony_ci    LE_CHECK(portStr != NULL, return LE_FAILURE, "Failed to get addr %s", server);
117d9f0492fSopenharmony_ci    uint16_t port = atoi(portStr + 1);
118d9f0492fSopenharmony_ci    addr->sin_port = htons(port);
119d9f0492fSopenharmony_ci    ret = inet_pton(AF_INET, server, &addr->sin_addr);
120d9f0492fSopenharmony_ci    LE_CHECK(ret >= 0, return LE_FAILURE, "Failed to inet_pton addr %s", server);
121d9f0492fSopenharmony_ci    LE_LOGV("CreateTcpSocket server: %s port: %d", server, port);
122d9f0492fSopenharmony_ci    return LE_SUCCESS;
123d9f0492fSopenharmony_ci}
124d9f0492fSopenharmony_ci
125d9f0492fSopenharmony_cistatic int CreateTcpServerSocket_(const char *server, int maxClient)
126d9f0492fSopenharmony_ci{
127d9f0492fSopenharmony_ci    int listenfd = socket(AF_INET, SOCK_STREAM, 0);
128d9f0492fSopenharmony_ci    LE_CHECK(listenfd > 0, return listenfd, "Failed to create socket");
129d9f0492fSopenharmony_ci
130d9f0492fSopenharmony_ci    int ret = SetSocketTimeout(listenfd);
131d9f0492fSopenharmony_ci    LE_CHECK(ret == 0, return ret, "Failed to set socket timeout");
132d9f0492fSopenharmony_ci
133d9f0492fSopenharmony_ci    struct sockaddr_in serverAddr;
134d9f0492fSopenharmony_ci    GetSockaddrFromServer_(server, &serverAddr);
135d9f0492fSopenharmony_ci    ret = bind(listenfd, (struct sockaddr *)&serverAddr, sizeof(serverAddr));
136d9f0492fSopenharmony_ci    LE_CHECK(ret >= 0, close(listenfd);
137d9f0492fSopenharmony_ci        return ret, "Failed to bind socket");
138d9f0492fSopenharmony_ci    SetNoBlock(listenfd);
139d9f0492fSopenharmony_ci
140d9f0492fSopenharmony_ci    ret = listen(listenfd, maxClient);
141d9f0492fSopenharmony_ci    LE_CHECK(ret >= 0, close(listenfd);
142d9f0492fSopenharmony_ci        return ret, "Failed to listen socket");
143d9f0492fSopenharmony_ci    return listenfd;
144d9f0492fSopenharmony_ci}
145d9f0492fSopenharmony_ci
146d9f0492fSopenharmony_cistatic int CreateTcpSocket_(const char *server)
147d9f0492fSopenharmony_ci{
148d9f0492fSopenharmony_ci    int fd = socket(AF_INET, SOCK_STREAM, 0);
149d9f0492fSopenharmony_ci    LE_CHECK(fd > 0, return fd, "Failed to create socket");
150d9f0492fSopenharmony_ci    SetNoBlock(fd);
151d9f0492fSopenharmony_ci
152d9f0492fSopenharmony_ci    int on = 1;
153d9f0492fSopenharmony_ci    int ret = setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
154d9f0492fSopenharmony_ci    LE_CHECK(ret == 0, return ret, "Failed to set socket option");
155d9f0492fSopenharmony_ci
156d9f0492fSopenharmony_ci    ret = SetSocketTimeout(fd);
157d9f0492fSopenharmony_ci    LE_CHECK(ret == 0, return ret, "Failed to set socket timeout");
158d9f0492fSopenharmony_ci
159d9f0492fSopenharmony_ci    struct sockaddr_in serverAddr;
160d9f0492fSopenharmony_ci    GetSockaddrFromServer_(server, &serverAddr);
161d9f0492fSopenharmony_ci    ret = connect(fd, (struct sockaddr *)&serverAddr, sizeof(serverAddr));
162d9f0492fSopenharmony_ci    LE_CHECK(ret >= 0, close(fd);
163d9f0492fSopenharmony_ci        return ret, "Failed to connect socket errno:%d", errno);
164d9f0492fSopenharmony_ci    return fd;
165d9f0492fSopenharmony_ci}
166d9f0492fSopenharmony_ci
167d9f0492fSopenharmony_cistatic int AcceptPipeSocket_(int serverFd)
168d9f0492fSopenharmony_ci{
169d9f0492fSopenharmony_ci    struct sockaddr_un clientAddr;
170d9f0492fSopenharmony_ci    socklen_t addrlen = sizeof(clientAddr);
171d9f0492fSopenharmony_ci    bzero(&clientAddr, addrlen);
172d9f0492fSopenharmony_ci    int fd = accept(serverFd, (struct sockaddr *)&clientAddr, &addrlen);
173d9f0492fSopenharmony_ci    LE_CHECK(fd >= 0, return fd, "Failed to accept socket");
174d9f0492fSopenharmony_ci    LE_LOGV("AcceptPipeSocket client fd %d %s ", fd, clientAddr.sun_path);
175d9f0492fSopenharmony_ci    return fd;
176d9f0492fSopenharmony_ci}
177d9f0492fSopenharmony_ci
178d9f0492fSopenharmony_cistatic int AcceptTcpSocket_(int serverFd)
179d9f0492fSopenharmony_ci{
180d9f0492fSopenharmony_ci    struct sockaddr_in clientAddr;
181d9f0492fSopenharmony_ci    socklen_t addrlen = sizeof(clientAddr);
182d9f0492fSopenharmony_ci    bzero(&clientAddr, addrlen);
183d9f0492fSopenharmony_ci    int fd = accept(serverFd, (struct sockaddr *)&clientAddr, &addrlen);
184d9f0492fSopenharmony_ci    LE_CHECK(fd >= 0, return fd, "Failed to accept socket");
185d9f0492fSopenharmony_ci    LE_LOGV("AcceptTcpSocket_ client: %s ", inet_ntoa(clientAddr.sin_addr));
186d9f0492fSopenharmony_ci    return fd;
187d9f0492fSopenharmony_ci}
188d9f0492fSopenharmony_ciINIT_LOCAL_API
189d9f0492fSopenharmony_ciint CreateSocket(int flags, const char *server)
190d9f0492fSopenharmony_ci{
191d9f0492fSopenharmony_ci    int fd = -1;
192d9f0492fSopenharmony_ci    int type = flags & 0x0000ff00;
193d9f0492fSopenharmony_ci    LE_LOGV("CreateSocket flags %x type %x server %s", flags, type, server);
194d9f0492fSopenharmony_ci    if (type == TASK_TCP) {
195d9f0492fSopenharmony_ci        if (LE_TEST_FLAGS(flags, TASK_SERVER)) {
196d9f0492fSopenharmony_ci            fd = CreateTcpServerSocket_(server, LOOP_MAX_CLIENT);
197d9f0492fSopenharmony_ci        } else if (LE_TEST_FLAGS(flags, TASK_CONNECT)) {
198d9f0492fSopenharmony_ci            fd = CreateTcpSocket_(server);
199d9f0492fSopenharmony_ci        }
200d9f0492fSopenharmony_ci    } else if (type == TASK_PIPE) {
201d9f0492fSopenharmony_ci        if (LE_TEST_FLAGS(flags, TASK_SERVER)) {
202d9f0492fSopenharmony_ci            fd = CreatePipeServerSocket_(server, LOOP_MAX_CLIENT,
203d9f0492fSopenharmony_ci                (int)LE_TEST_FLAGS(flags, TASK_PUBLIC));
204d9f0492fSopenharmony_ci        } else if (LE_TEST_FLAGS(flags, TASK_CONNECT)) {
205d9f0492fSopenharmony_ci            fd = CreatePipeSocket_(server);
206d9f0492fSopenharmony_ci        }
207d9f0492fSopenharmony_ci    }
208d9f0492fSopenharmony_ci    if (fd <= 0) {
209d9f0492fSopenharmony_ci        LE_LOGE("Invalid flags 0x%08x for server %s", flags, server);
210d9f0492fSopenharmony_ci        return -1;
211d9f0492fSopenharmony_ci    }
212d9f0492fSopenharmony_ci    return fd;
213d9f0492fSopenharmony_ci}
214d9f0492fSopenharmony_ciINIT_LOCAL_API
215d9f0492fSopenharmony_ciint AcceptSocket(int fd, int flags)
216d9f0492fSopenharmony_ci{
217d9f0492fSopenharmony_ci    int clientFd = -1;
218d9f0492fSopenharmony_ci    int type = flags & 0x0000ff00;
219d9f0492fSopenharmony_ci    if (type == TASK_TCP) {
220d9f0492fSopenharmony_ci        clientFd = AcceptTcpSocket_(fd);
221d9f0492fSopenharmony_ci    } else if (type == TASK_PIPE) {
222d9f0492fSopenharmony_ci        clientFd = AcceptPipeSocket_(fd);
223d9f0492fSopenharmony_ci    } else {
224d9f0492fSopenharmony_ci        LE_LOGE("AcceptSocket invalid flags %#8x ", flags);
225d9f0492fSopenharmony_ci        return -1;
226d9f0492fSopenharmony_ci    }
227d9f0492fSopenharmony_ci    SetNoBlock(clientFd);
228d9f0492fSopenharmony_ci    return clientFd;
229d9f0492fSopenharmony_ci}
230d9f0492fSopenharmony_ci
231d9f0492fSopenharmony_ciINIT_LOCAL_API
232d9f0492fSopenharmony_ciint listenSocket(int fd, int flags, const char *server)
233d9f0492fSopenharmony_ci{
234d9f0492fSopenharmony_ci    unsigned int type = (unsigned int)flags & 0x0000ff00;
235d9f0492fSopenharmony_ci    LE_LOGV("listenSocket flags %x type %x server %s", flags, type, server);
236d9f0492fSopenharmony_ci    SetNoBlock(fd);
237d9f0492fSopenharmony_ci    if (!LE_TEST_FLAGS((unsigned int)flags, TASK_SERVER)) {
238d9f0492fSopenharmony_ci        return 0;
239d9f0492fSopenharmony_ci    }
240d9f0492fSopenharmony_ci    if (type == TASK_TCP) {
241d9f0492fSopenharmony_ci        int ret = listen(fd, LOOP_MAX_CLIENT);
242d9f0492fSopenharmony_ci        LE_CHECK(ret >= 0, close(fd);
243d9f0492fSopenharmony_ci            return ret, "Failed to listen socket");
244d9f0492fSopenharmony_ci    } else if (type == TASK_PIPE) {
245d9f0492fSopenharmony_ci        int ret = listen(fd, LOOP_MAX_CLIENT);
246d9f0492fSopenharmony_ci        LE_CHECK(ret >= 0, close(fd);
247d9f0492fSopenharmony_ci            return ret, "Failed to listen socket error: %d", errno);
248d9f0492fSopenharmony_ci        ret = chmod(server, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
249d9f0492fSopenharmony_ci        LE_CHECK(ret == 0, return -1, "Failed to chmod %s, err %d. ", server, errno);
250d9f0492fSopenharmony_ci    }
251d9f0492fSopenharmony_ci    return 0;
252d9f0492fSopenharmony_ci}
253