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