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