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 "softbus_tcp_socket.h"
17 
18 #include <securec.h>
19 #include "conn_log.h"
20 #include "softbus_adapter_errcode.h"
21 #include "softbus_conn_common.h"
22 #include "softbus_errcode.h"
23 #include "softbus_socket.h"
24 
25 #define M_BYTES                     0x100000
26 #define SEND_BUF_SIZE               (4 * M_BYTES) // 4M
27 #define RECV_BUF_SIZE               (6 * M_BYTES) // 6M
28 #define USER_TIMEOUT_MS             (15 * 1000)   // 15s
29 #define SOFTBUS_TCP_USER_TIME USER_TIMEOUT_MS
30 #define SOFTBUS_CONN_TCP_USER_TIME  (35 * 1000)   // 35s
31 
32 #ifndef __LITEOS_M__
SetReusePort(int fd,int on)33 static int SetReusePort(int fd, int on)
34 {
35     int rc = SoftBusSocketSetOpt(fd, SOFTBUS_SOL_SOCKET, SOFTBUS_SO_REUSEPORT, &on, sizeof(on));
36     if (rc != 0) {
37         CONN_LOGE(CONN_COMMON, "set SO_REUSEPORT failed");
38         return -1;
39     }
40     return 0;
41 }
42 #endif
43 
SetReuseAddr(int fd,int on)44 static int SetReuseAddr(int fd, int on)
45 {
46     int rc = SoftBusSocketSetOpt(fd, SOFTBUS_SOL_SOCKET, SOFTBUS_SO_REUSEADDR, &on, sizeof(on));
47     if (rc != 0) {
48         CONN_LOGE(CONN_COMMON, "set SO_REUSEADDR failed");
49         return -1;
50     }
51     return 0;
52 }
53 
SetNoDelay(int fd,int on)54 static int SetNoDelay(int fd, int on)
55 {
56     int rc = SoftBusSocketSetOpt(fd, SOFTBUS_IPPROTO_TCP, SOFTBUS_TCP_NODELAY, &on, sizeof(on));
57     if (rc != 0) {
58         CONN_LOGE(CONN_COMMON, "set TCP_NODELAY failed");
59         return -1;
60     }
61     return 0;
62 }
63 
64 #ifndef TCP_QUICK_START
65 #define TCP_QUICK_START 121
66 #endif
67 
SetQuickStart(int fd,int quick)68 static int SetQuickStart(int fd, int quick)
69 {
70     errno = 0;
71     int rc = setsockopt(fd, SOFTBUS_IPPROTO_TCP, TCP_QUICK_START, &quick, sizeof(quick));
72     if (rc != 0) {
73         CONN_LOGE(CONN_COMMON, "set TCP_QUICK_START failed. rc=%{public}d, errno=%{public}d(%{public}s)",
74             rc, errno, strerror(errno));
75         return -1;
76     }
77     return 0;
78 }
79 
SetSendBufFix(int fd,int val)80 static int SetSendBufFix(int fd, int val)
81 {
82     int rc = setsockopt(fd, SOFTBUS_SOL_SOCKET, SOFTBUS_SO_SNDBUF, &val, sizeof(val));
83     if (rc != 0) {
84         CONN_LOGE(CONN_COMMON, "set SOFTBUS_SO_SNDBUF failed. rc=%{public}d, errno=%{public}d(%{public}s)",
85             rc, errno, strerror(errno));
86         return -1;
87     }
88     return 0;
89 }
90 
SetRcvBufFix(int fd,int val)91 static int SetRcvBufFix(int fd, int val)
92 {
93     int rc = setsockopt(fd, SOFTBUS_SOL_SOCKET, SOFTBUS_SO_RCVBUF, &val, sizeof(val));
94     if (rc != 0) {
95         CONN_LOGE(CONN_COMMON, "set SOFTBUS_SO_RCVBUF failed. rc=%{public}d, errno=%{public}d(%{public}s)",
96             rc, errno, strerror(errno));
97         return -1;
98     }
99     return 0;
100 }
101 
SetSendBuf(int fd)102 static int SetSendBuf(int fd)
103 {
104     static int sendBufSize = 0;
105     if (sendBufSize > 0) {
106         return SetSendBufFix(fd, sendBufSize);
107     }
108     // try set buffer size
109     for (int size = SEND_BUF_SIZE; size > 0; size -= M_BYTES) {
110         int ret = SetSendBufFix(fd, size);
111         if (ret == 0) {
112             sendBufSize = size;
113             return ret;
114         }
115     }
116     return -1;
117 }
118 
SetRecvBuf(int fd)119 static int SetRecvBuf(int fd)
120 {
121     static int recvBufSize = 0;
122     if (recvBufSize > 0) {
123         return SetRcvBufFix(fd, recvBufSize);
124     }
125     // try set buffer size
126     for (int size = RECV_BUF_SIZE; size > 0; size -= M_BYTES) {
127         int ret = SetRcvBufFix(fd, size);
128         if (ret == 0) {
129             recvBufSize = size;
130             return ret;
131         }
132     }
133     return -1;
134 }
135 
SetServerOption(int fd)136 static void SetServerOption(int fd)
137 {
138     (void)SetReuseAddr(fd, 1);
139     (void)SetNoDelay(fd, 1);
140 #ifndef __LITEOS_M__
141     (void)SetReusePort(fd, 1);
142 #endif
143     SetSendBuf(fd);
144     SetRecvBuf(fd);
145     (void)ConnSetTcpUserTimeOut(fd, SOFTBUS_TCP_USER_TIME);
146 }
147 
SetClientOption(int fd)148 static void SetClientOption(int fd)
149 {
150     SetReuseAddr(fd, 1);
151     SetNoDelay(fd, 1);
152 #ifndef __LITEOS_M__
153     SetReusePort(fd, 1);
154     SetQuickStart(fd, 1);
155 #endif
156     SetSendBuf(fd);
157     SetRecvBuf(fd);
158     (void)ConnSetTcpUserTimeOut(fd, SOFTBUS_TCP_USER_TIME);
159 }
160 
BindLocalIP(int32_t domain,int fd,const char * localIP,uint16_t port)161 static int BindLocalIP(int32_t domain, int fd, const char *localIP, uint16_t port)
162 {
163     int rc = SOFTBUS_ADAPTER_OK;
164     if (domain == SOFTBUS_AF_INET6) {
165         SoftBusSockAddrIn6 addrIn6 = {0};
166         rc = Ipv6AddrToAddrIn(&addrIn6, localIP, port);
167         if (rc != SOFTBUS_OK) {
168             CONN_LOGE(CONN_COMMON, "pack ipv6 addr failed");
169             return SOFTBUS_SOCKET_ADDR_ERR;
170         }
171         return SOFTBUS_TEMP_FAILURE_RETRY(
172             SoftBusSocketBind(fd, (SoftBusSockAddr *)&addrIn6, sizeof(SoftBusSockAddrIn6)));
173     }
174     SoftBusSockAddrIn addrIn = {0};
175     rc = Ipv4AddrToAddrIn(&addrIn, localIP, port);
176     if (rc != SOFTBUS_OK) {
177         CONN_LOGE(CONN_COMMON, "pack ipv4 addr failed");
178         return SOFTBUS_SOCKET_ADDR_ERR;
179     }
180     return SOFTBUS_TEMP_FAILURE_RETRY(
181         SoftBusSocketBind(fd, (SoftBusSockAddr *)&addrIn, sizeof(SoftBusSockAddrIn)));
182 }
183 
SetIpTos(int fd,uint32_t tos)184 int32_t SetIpTos(int fd, uint32_t tos)
185 {
186     int rc = SoftBusSocketSetOpt(fd, SOFTBUS_IPPROTO_IP, SOFTBUS_IP_TOS, &tos, sizeof(tos));
187     if (rc != 0) {
188         CONN_LOGE(CONN_COMMON, "set tos failed, fd=%{public}d", fd);
189         return SOFTBUS_TCP_SOCKET_ERR;
190     }
191     return SOFTBUS_OK;
192 }
193 
OpenTcpServerSocket(const LocalListenerInfo * option)194 static int32_t OpenTcpServerSocket(const LocalListenerInfo *option)
195 {
196     if (option == NULL) {
197         CONN_LOGE(CONN_COMMON, "invalid param!");
198         return SOFTBUS_INVALID_PARAM;
199     }
200     if (option->type != CONNECT_TCP && option->type != CONNECT_P2P && option->type != CONNECT_HML) {
201         CONN_LOGE(CONN_COMMON, "bad type! type=%{public}d", option->type);
202         return SOFTBUS_INVALID_PARAM;
203     }
204     if (option->socketOption.port < 0) {
205         CONN_LOGE(CONN_COMMON, "bad port! port=%{public}d", option->socketOption.port);
206         return SOFTBUS_INVALID_PARAM;
207     }
208 
209     int fd;
210     int32_t domain = GetDomainByAddr(option->socketOption.addr);
211     int ret = SoftBusSocketCreate(
212         domain, SOFTBUS_SOCK_STREAM | SOFTBUS_SOCK_CLOEXEC | SOFTBUS_SOCK_NONBLOCK, 0, (int32_t *)&fd);
213     if (ret != SOFTBUS_OK) {
214         CONN_LOGE(CONN_COMMON, "Create socket failed! ret=%{public}d", ret);
215         return SOFTBUS_TCP_SOCKET_ERR;
216     }
217 
218     SetServerOption(fd);
219     // tcp user timeout on the Server
220     if (option->socketOption.moduleId >= AUTH_P2P && option->socketOption.moduleId <= AUTH_ENHANCED_P2P_END) {
221         (void)ConnSetTcpUserTimeOut(fd, SOFTBUS_CONN_TCP_USER_TIME);
222     }
223     ret = BindLocalIP(domain, fd, option->socketOption.addr, (uint16_t)option->socketOption.port);
224     if (ret != SOFTBUS_OK) {
225         CONN_LOGE(CONN_COMMON, "BindLocalIP ret=%{public}d", ret);
226         ConnShutdownSocket(fd);
227         return SOFTBUS_SOCKET_BIND_ERR;
228     }
229 
230     BindToInterface(option->socketOption.addr, domain, fd, (char *)(option->socketOption.ifName), IF_NAME_SIZE);
231     CONN_LOGI(CONN_COMMON, "server listen tcp socket, fd=%{public}d", fd);
232     return fd;
233 }
234 
BindTcpClientAddr(int32_t domain,int fd,const char * inputAddr)235 static int32_t BindTcpClientAddr(int32_t domain, int fd, const char *inputAddr)
236 {
237     if (inputAddr == NULL) {
238         return SOFTBUS_OK;
239     }
240 
241     const char *bindAddr = NULL;
242     if (strcmp(inputAddr, BIND_ADDR_ALL) == 0) {
243         if (domain == SOFTBUS_AF_INET6) {
244             bindAddr = "::";
245         } else {
246             bindAddr = "0.0.0.0";
247         }
248     } else {
249         CONN_LOGD(CONN_COMMON, "using specified bind addr");
250         bindAddr = inputAddr;
251     }
252     return BindLocalIP(domain, fd, bindAddr, 0);
253 }
254 
SocketConnect(int32_t fd,int32_t domain,const ConnectOption * option)255 static int32_t SocketConnect(int32_t fd, int32_t domain, const ConnectOption *option)
256 {
257     int rc = SOFTBUS_ADAPTER_OK;
258     if (domain == SOFTBUS_AF_INET6) {
259         SoftBusSockAddrIn6 addrIn6 = {0};
260         rc = Ipv6AddrToAddrIn(&addrIn6, option->socketOption.addr, (uint16_t)option->socketOption.port);
261         if (rc != SOFTBUS_OK) {
262             CONN_LOGW(CONN_COMMON, "pack ipv6 addr failed");
263             return rc;
264         }
265         return SOFTBUS_TEMP_FAILURE_RETRY(
266             SoftBusSocketConnect(fd, (SoftBusSockAddr *)&addrIn6, sizeof(SoftBusSockAddrIn6)));
267     }
268     SoftBusSockAddrIn addrIn = {0};
269     rc = Ipv4AddrToAddrIn(&addrIn, option->socketOption.addr, (uint16_t)option->socketOption.port);
270     if (rc != SOFTBUS_OK) {
271         CONN_LOGE(CONN_COMMON, "pack ipv4 addr failed");
272         return rc;
273     }
274     return SOFTBUS_TEMP_FAILURE_RETRY(
275         SoftBusSocketConnect(fd, (SoftBusSockAddr *)&addrIn, sizeof(SoftBusSockAddrIn)));
276 }
277 
OpenTcpClientSocket(const ConnectOption * option,const char * myIp,bool isNonBlock)278 static int32_t OpenTcpClientSocket(const ConnectOption *option, const char *myIp, bool isNonBlock)
279 {
280     CONN_CHECK_AND_RETURN_RET_LOGW(option != NULL, SOFTBUS_INVALID_PARAM, CONN_COMMON, "invalid param, null option");
281     CONN_CHECK_AND_RETURN_RET_LOGW(option->type == CONNECT_TCP || option->type == CONNECT_P2P ||
282         option->type == CONNECT_P2P_REUSE || option->type == CONNECT_HML, SOFTBUS_INVALID_PARAM, CONN_COMMON,
283         "invalid param, unsupport type=%{public}d", option->type);
284     CONN_CHECK_AND_RETURN_RET_LOGW(option->socketOption.port > 0, SOFTBUS_INVALID_PARAM, CONN_COMMON,
285         "invalid param, invalid port=%{public}d", option->socketOption.port);
286     CONN_CHECK_AND_RETURN_RET_LOGW(option->socketOption.addr[0] != '\0', SOFTBUS_INVALID_PARAM, CONN_COMMON,
287         "invalid param, invalid addr");
288 
289     char animizedIp[IP_LEN] = { 0 };
290     ConvertAnonymizeIpAddress(animizedIp, IP_LEN, option->socketOption.addr, IP_LEN);
291 
292     int32_t fd = -1;
293     int32_t domain = GetDomainByAddr(option->socketOption.addr);
294     int32_t ret = SoftBusSocketCreate(domain, SOFTBUS_SOCK_STREAM, 0, &fd);
295     if (ret != SOFTBUS_OK) {
296         CONN_LOGE(CONN_COMMON, "create socket failed, serverIp=%{public}s, serverPort=%{public}d, error=%{public}d",
297             animizedIp, option->socketOption.port, ret);
298         return ret;
299     }
300     if (isNonBlock && ConnToggleNonBlockMode(fd, true) != SOFTBUS_OK) {
301         CONN_LOGE(CONN_COMMON, "set nonblock failed, serverIp=%{public}s, serverPort=%{public}d, fd=%{public}d",
302             animizedIp, option->socketOption.port, fd);
303         SoftBusSocketClose(fd);
304         return SOFTBUS_TCPCONNECTION_SOCKET_ERR;
305     }
306     SetClientOption(fd);
307     // tcp user timeout on the Client
308     if (option->socketOption.moduleId >= AUTH_P2P && option->socketOption.moduleId <= AUTH_ENHANCED_P2P_END) {
309         (void)ConnSetTcpUserTimeOut(fd, SOFTBUS_CONN_TCP_USER_TIME);
310     }
311     ret = BindTcpClientAddr(domain, fd, myIp);
312     if (ret != SOFTBUS_OK) {
313         CONN_LOGE(CONN_COMMON, "bind client address failed, serverIp=%{public}s, serverPort=%{public}d, "
314             "error=%{public}d", animizedIp, option->socketOption.port, ret);
315         ConnShutdownSocket(fd);
316         return ret;
317     }
318 
319     BindToInterface(myIp, domain, fd, (char *)(option->socketOption.ifName), IF_NAME_SIZE);
320     ret = SocketConnect(fd, domain, option);
321     if ((ret != SOFTBUS_ADAPTER_OK) && (ret != SOFTBUS_ADAPTER_SOCKET_EINPROGRESS) &&
322         (ret != SOFTBUS_ADAPTER_SOCKET_EAGAIN)) {
323         CONN_LOGE(CONN_COMMON, "client connect failed, serverIp=%{public}s, serverPort=%{public}d, fd=%{public}d, "
324             "ret=%{public}d, errno=%{public}d(%{public}s)", animizedIp, option->socketOption.port, fd, ret,
325             errno, strerror(errno));
326         ConnShutdownSocket(fd);
327         return ret;
328     }
329     CONN_LOGI(CONN_COMMON, "client open tcp socket, serverIp=%{public}s, serverPort=%{public}d, fd=%{public}d",
330         animizedIp, option->socketOption.port, fd);
331     return fd;
332 }
333 
GetTcpSockPort(int32_t fd)334 static int32_t GetTcpSockPort(int32_t fd)
335 {
336     SoftBusSockAddr addr;
337     int rc = SoftBusSocketGetLocalName(fd, &addr);
338     if (rc != 0) {
339         CONN_LOGE(CONN_COMMON, "fd=%{public}d, rc=%{public}d", fd, rc);
340         return rc;
341     }
342     if (addr.saFamily == SOFTBUS_AF_INET6) {
343         return SoftBusNtoHs(((SoftBusSockAddrIn6 *)&addr)->sin6Port);
344     }
345     return SoftBusNtoHs(((SoftBusSockAddrIn *)&addr)->sinPort);
346 }
347 
ConnSetTcpKeepalive(int32_t fd,int32_t seconds,int32_t keepAliveIntvl,int32_t keepAliveCount)348 int32_t ConnSetTcpKeepalive(int32_t fd, int32_t seconds, int32_t keepAliveIntvl, int32_t keepAliveCount)
349 {
350     if (fd <= 0 || seconds <= 0 || keepAliveIntvl <= 0 || keepAliveCount <= 0) {
351         CONN_LOGE(CONN_COMMON, "ConnSetTcpKeepalive invalid param");
352         return SOFTBUS_INVALID_PARAM;
353     }
354 
355     int32_t rc;
356     rc = SoftBusSocketSetOpt(fd, SOFTBUS_IPPROTO_TCP, SOFTBUS_TCP_KEEPIDLE, &seconds, sizeof(seconds));
357     if (rc != SOFTBUS_ADAPTER_OK) {
358         CONN_LOGE(CONN_COMMON, "set TCP_KEEPIDLE failed");
359         return SOFTBUS_ADAPTER_ERR;
360     }
361 
362     rc = SoftBusSocketSetOpt(fd, SOFTBUS_IPPROTO_TCP, SOFTBUS_TCP_KEEPCNT, &keepAliveCount, sizeof(keepAliveCount));
363     if (rc != SOFTBUS_ADAPTER_OK) {
364         CONN_LOGE(CONN_COMMON, "set TCP_KEEPCNT failed");
365         return SOFTBUS_ADAPTER_ERR;
366     }
367 
368     rc = SoftBusSocketSetOpt(fd, SOFTBUS_IPPROTO_TCP, SOFTBUS_TCP_KEEPINTVL, &keepAliveIntvl, sizeof(keepAliveIntvl));
369     if (rc != SOFTBUS_ADAPTER_OK) {
370         CONN_LOGE(CONN_COMMON, "set TCP_KEEPINTVL failed");
371         return SOFTBUS_ADAPTER_ERR;
372     }
373 
374     int32_t enable = 1;
375     rc = SoftBusSocketSetOpt(fd, SOFTBUS_SOL_SOCKET, SOFTBUS_SO_KEEPALIVE, &enable, sizeof(enable));
376     if (rc != SOFTBUS_ADAPTER_OK) {
377         CONN_LOGE(CONN_COMMON, "set SO_KEEPALIVE failed");
378         return SOFTBUS_ADAPTER_ERR;
379     }
380     return SOFTBUS_OK;
381 }
382 
383 #ifdef TCP_USER_TIMEOUT
ConnSetTcpUserTimeOut(int32_t fd,uint32_t millSec)384 int32_t ConnSetTcpUserTimeOut(int32_t fd, uint32_t millSec)
385 {
386     if (fd < 0) {
387         CONN_LOGE(CONN_COMMON, "invalid param");
388         return SOFTBUS_ADAPTER_ERR;
389     }
390     if (SoftBusSocketSetOpt(fd, SOFTBUS_IPPROTO_TCP, SOFTBUS_TCP_USER_TIMEOUT, &millSec, sizeof(millSec)) !=
391         SOFTBUS_ADAPTER_OK) {
392         CONN_LOGE(CONN_COMMON, "set SOFTBUS_TCP_USER_TIMEOUT failed");
393         return SOFTBUS_ADAPTER_ERR;
394     }
395     return SOFTBUS_OK;
396 }
397 #else
ConnSetTcpUserTimeOut(int32_t fd,uint32_t millSec)398 int32_t ConnSetTcpUserTimeOut(int32_t fd, uint32_t millSec)
399 {
400     (void)fd;
401     (void)millSec;
402     return 0;
403 }
404 
405 #endif
406 
AcceptTcpClient(int32_t fd,ConnectOption * clientAddr,int32_t * cfd)407 static int32_t AcceptTcpClient(int32_t fd, ConnectOption *clientAddr, int32_t *cfd)
408 {
409     CONN_CHECK_AND_RETURN_RET_LOGW(clientAddr != NULL, SOFTBUS_INVALID_PARAM, CONN_COMMON,
410         "invalid param, clientAddr is null");
411     SoftBusSockAddr addr;
412     (void)memset_s(&addr, sizeof(addr), 0, sizeof(addr));
413     int32_t ret = SOFTBUS_TEMP_FAILURE_RETRY(SoftBusSocketAccept(fd, &addr, cfd));
414     if (ret != SOFTBUS_OK) {
415         CONN_LOGE(CONN_COMMON, "accept failed, ret=%{public}" PRId32 ", cfd=%{public}d, fd=%{public}d", ret, *cfd, fd);
416         return ret;
417     }
418 
419     clientAddr->type = CONNECT_TCP;
420     clientAddr->socketOption.port = GetTcpSockPort(*cfd);
421     clientAddr->socketOption.protocol = LNN_PROTOCOL_IP;
422     if (addr.saFamily == SOFTBUS_AF_INET6) {
423         ret = Ipv6AddrInToAddr((SoftBusSockAddrIn6 *)&addr,
424             clientAddr->socketOption.addr, sizeof(clientAddr->socketOption.addr));
425         if (ret < 0) {
426             CONN_LOGE(CONN_COMMON, "get ipv6 addr failed");
427             return ret;
428         }
429         return SOFTBUS_OK;
430     }
431     if (SoftBusInetNtoP(SOFTBUS_AF_INET, &((SoftBusSockAddrIn *)&addr)->sinAddr,
432         clientAddr->socketOption.addr, sizeof(clientAddr->socketOption.addr)) == NULL) {
433         CONN_LOGE(CONN_COMMON, "get addr failed");
434         return SOFTBUS_TCPCONNECTION_SOCKET_ERR;
435     }
436     return SOFTBUS_OK;
437 }
438 
GetTcpProtocol(void)439 const SocketInterface *GetTcpProtocol(void)
440 {
441     static SocketInterface tcpSocketIntf = {
442         .name = "TCP",
443         .type = LNN_PROTOCOL_IP,
444         .GetSockPort = GetTcpSockPort,
445         .OpenClientSocket = OpenTcpClientSocket,
446         .OpenServerSocket = OpenTcpServerSocket,
447         .AcceptClient = AcceptTcpClient,
448     };
449     return &tcpSocketIntf;
450 }
451