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