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