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 "nstackx_socket.h"
17 #include "nstackx_log.h"
18 #include "nstackx_error.h"
19 #include "nstackx_util.h"
20 #include "nstackx_dev.h"
21 #include "locale.h"
22 #include "securec.h"
23
24 #define NSTACKX_MAX_LISTEN_NUMBER 3
25 #define NSTACKX_TCP_SOCKET_BUFFER_SIZE (1 * 1024 * 1024)
26
27 #define TAG "nStackXSocket"
28
CloseSocket(Socket * socket)29 void CloseSocket(Socket *socket)
30 {
31 if (socket == NULL) {
32 return;
33 }
34 CloseSocketInner(socket->sockfd);
35 socket->sockfd = INVALID_SOCKET;
36 free(socket);
37 socket = NULL;
38 }
39
GetTcpSocketBufSize(SocketDesc fd)40 static void GetTcpSocketBufSize(SocketDesc fd)
41 {
42 int32_t ret;
43 int32_t bufSize;
44 socklen_t optLen = sizeof(bufSize);
45
46 ret = getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &bufSize, &optLen);
47 if (ret < 0) {
48 LOGE(TAG, "getsockopt SO_SNDBUF fail");
49 return;
50 }
51 LOGD(TAG, "SO_SNDBUF = %d", bufSize);
52
53 ret = getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bufSize, &optLen);
54 if (ret < 0) {
55 LOGE(TAG, "getsockopt SO_RCVBUF fail");
56 return;
57 }
58 LOGD(TAG, "SO_RCVBUF = %d", bufSize);
59 }
60
SetTcpSocketBufSize(SocketDesc fd,int32_t bufSize)61 static int32_t SetTcpSocketBufSize(SocketDesc fd, int32_t bufSize)
62 {
63 int32_t ret;
64 socklen_t optLen = sizeof(bufSize);
65
66 if (bufSize < 0) {
67 return NSTACKX_EFAILED;
68 }
69
70 GetTcpSocketBufSize(fd);
71 ret = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &bufSize, optLen);
72 if (ret < 0) {
73 LOGE(TAG, "setsockopt SO_SNDBUF fail");
74 return NSTACKX_EFAILED;
75 }
76 LOGD(TAG, "setsockopt SO_SNDBUF = %d", bufSize);
77
78 ret = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &bufSize, optLen);
79 if (ret < 0) {
80 LOGE(TAG, "setsockopt SO_RCVBUF fail");
81 return NSTACKX_EFAILED;
82 }
83 LOGD(TAG, "setsockopt SO_RCVBUF = %d", bufSize);
84 GetTcpSocketBufSize(fd);
85 return NSTACKX_EOK;
86 }
87
ConnectTcpServerWithTargetDev(Socket * clientSocket,const struct sockaddr_in * sockAddr,const char * localInterface)88 static int32_t ConnectTcpServerWithTargetDev(Socket *clientSocket, const struct sockaddr_in *sockAddr,
89 const char *localInterface)
90 {
91 socklen_t addrLen = sizeof(struct sockaddr_in);
92
93 clientSocket->sockfd = socket(AF_INET, SOCK_STREAM, 0);
94 if (clientSocket->sockfd == INVALID_SOCKET) {
95 LOGE(TAG, "socket create fail, error :%d", GetErrno());
96 return NSTACKX_EFAILED;
97 }
98 if (SetTcpSocketBufSize(clientSocket->sockfd, NSTACKX_TCP_SOCKET_BUFFER_SIZE) != NSTACKX_EOK) {
99 LOGE(TAG, "set socket buf fail");
100 }
101 if (SetSocketNonBlock(clientSocket->sockfd) != NSTACKX_EOK) {
102 LOGE(TAG, "set socket nonblock fail");
103 }
104 if (localInterface == NULL) {
105 BindToDevInTheSameLan(clientSocket->sockfd, sockAddr);
106 } else {
107 LOGI(TAG, "bind to target interface %s", localInterface);
108 if (BindToTargetDev(clientSocket->sockfd, localInterface) != NSTACKX_EOK) {
109 LOGE(TAG, "can't bind to target interface %s", localInterface);
110 } else {
111 LOGI(TAG, "bind to target interface %s successfully", localInterface);
112 }
113 }
114 int32_t ret = connect(clientSocket->sockfd, (struct sockaddr *)sockAddr, addrLen);
115 if (ret != 0) {
116 if (!SocketOpInProgress()) {
117 LOGE(TAG, "connect error, %d", GetErrno());
118 goto FAIL_SOCKET;
119 }
120 }
121 LOGI(TAG, "connect success");
122
123 clientSocket->dstAddr = *sockAddr;
124 return NSTACKX_EOK;
125
126 FAIL_SOCKET:
127 CloseSocketInner(clientSocket->sockfd);
128 clientSocket->sockfd = INVALID_SOCKET;
129 return NSTACKX_EFAILED;
130 }
131
ConnectUdpServerWithTargetDev(Socket * clientSocket,const struct sockaddr_in * sockAddr,const char * localInterface)132 static int32_t ConnectUdpServerWithTargetDev(Socket *clientSocket, const struct sockaddr_in *sockAddr,
133 const char *localInterface)
134 {
135 struct sockaddr_in tmpAddr;
136
137 clientSocket->sockfd = socket(AF_INET, SOCK_DGRAM, 0);
138 if (clientSocket->sockfd == INVALID_SOCKET) {
139 LOGE(TAG, "socket create fail, error :%d", GetErrno());
140 return NSTACKX_EFAILED;
141 }
142 if (SetSocketNonBlock(clientSocket->sockfd) != NSTACKX_EOK) {
143 LOGE(TAG, "set socket nonblock failed");
144 goto FAIL_SOCKET;
145 }
146
147 if (localInterface == NULL) {
148 BindToDevInTheSameLan(clientSocket->sockfd, sockAddr);
149 } else {
150 if (BindToTargetDev(clientSocket->sockfd, localInterface) != NSTACKX_EOK) {
151 LOGE(TAG, "can't bind to target interface %s", localInterface);
152 } else {
153 LOGI(TAG, "bind to target interface %s successfully", localInterface);
154 }
155 }
156 int32_t ret = connect(clientSocket->sockfd, (struct sockaddr *)sockAddr, sizeof(struct sockaddr));
157 if (ret != 0) {
158 LOGE(TAG, "connect to udp server failed %d", GetErrno());
159 goto FAIL_SOCKET;
160 }
161
162 socklen_t srcAddrLen = sizeof(struct sockaddr_in);
163 (void)memset_s(&tmpAddr, sizeof(tmpAddr), 0, sizeof(tmpAddr));
164 ret = getsockname(clientSocket->sockfd, (struct sockaddr *)&tmpAddr, &srcAddrLen);
165 if (ret != 0) {
166 LOGE(TAG, "getsockname failed %d", GetErrno());
167 goto FAIL_SOCKET;
168 }
169 clientSocket->dstAddr = *sockAddr;
170 clientSocket->srcAddr = tmpAddr;
171 return NSTACKX_EOK;
172 FAIL_SOCKET:
173 CloseSocketInner(clientSocket->sockfd);
174 clientSocket->sockfd = INVALID_SOCKET;
175 return NSTACKX_EFAILED;
176 }
177
CreateTcpServer(Socket * serverSocket,const struct sockaddr_in * sockAddr)178 static int32_t CreateTcpServer(Socket *serverSocket, const struct sockaddr_in *sockAddr)
179 {
180 int32_t reuse = 1;
181 struct sockaddr_in localAddr;
182 socklen_t len = sizeof(localAddr);
183
184 serverSocket->sockfd = socket(AF_INET, SOCK_STREAM, 0);
185 if (serverSocket->sockfd == INVALID_SOCKET) {
186 LOGE(TAG, "create socket fail, error :%d", GetErrno());
187 return NSTACKX_EFAILED;
188 }
189 if (SetSocketNonBlock(serverSocket->sockfd) != NSTACKX_EOK) {
190 LOGE(TAG, "set socket nonblock failed");
191 goto FAIL_SOCKET;
192 }
193
194 if (setsockopt(serverSocket->sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) != 0) {
195 LOGE(TAG, "Failed to set server socket! error :%d", GetErrno());
196 goto FAIL_SOCKET;
197 }
198
199 (void)memset_s(&localAddr, sizeof(localAddr), 0, sizeof(localAddr));
200 /* Bind to ANY source ip address and random port number */
201 localAddr.sin_family = AF_INET;
202 localAddr.sin_port = sockAddr->sin_port;
203 if (sockAddr->sin_addr.s_addr != 0) {
204 localAddr.sin_addr.s_addr = sockAddr->sin_addr.s_addr;
205 } else {
206 localAddr.sin_addr.s_addr = INADDR_ANY;
207 }
208
209 if (bind(serverSocket->sockfd, (struct sockaddr *)&localAddr, len) != 0) {
210 LOGE(TAG, "Failed to bind socket error :%d", GetErrno());
211 goto FAIL_SOCKET;
212 }
213
214 if (sockAddr->sin_addr.s_addr != 0 &&
215 BindToDevice(serverSocket->sockfd, sockAddr) != NSTACKX_EOK) {
216 LOGE(TAG, "Failed to bind socket to device");
217 }
218
219 if (getsockname(serverSocket->sockfd, (struct sockaddr *)&(serverSocket->srcAddr), &len) != 0) {
220 LOGE(TAG, "Failed to get socket name! error :%d", GetErrno());
221 goto FAIL_SOCKET;
222 }
223
224 if (listen(serverSocket->sockfd, NSTACKX_MAX_LISTEN_NUMBER) != 0) {
225 LOGE(TAG, "Failed to listen TCP port! error :%d", GetErrno());
226 goto FAIL_SOCKET;
227 }
228
229 /* Note: Here we rely on that an accepted socket will inherit SO_SNDBUF and SO_RCVBUF
230 options from the listening socket. */
231 if (SetTcpSocketBufSize(serverSocket->sockfd, NSTACKX_TCP_SOCKET_BUFFER_SIZE) != NSTACKX_EOK) {
232 LOGE(TAG, "Failed to set socket buff size:%u", NSTACKX_TCP_SOCKET_BUFFER_SIZE);
233 }
234
235 return NSTACKX_EOK;
236 FAIL_SOCKET:
237 CloseSocketInner(serverSocket->sockfd);
238 serverSocket->sockfd = INVALID_SOCKET;
239 return NSTACKX_EFAILED;
240 }
241
CreateUdpServer(Socket * serverSocket,const struct sockaddr_in * sockAddr)242 static int32_t CreateUdpServer(Socket *serverSocket, const struct sockaddr_in *sockAddr)
243 {
244 if (sockAddr == NULL) {
245 LOGE(TAG, "sockAddr is null");
246 return NSTACKX_EFAILED;
247 }
248 struct sockaddr_in localAddr;
249 socklen_t len = sizeof(localAddr);
250 serverSocket->sockfd = socket(AF_INET, SOCK_DGRAM, 0);
251 if (serverSocket->sockfd == INVALID_SOCKET) {
252 LOGE(TAG, "create socket fail, error :%d", GetErrno());
253 return NSTACKX_EFAILED;
254 }
255
256 if (SetSocketNonBlock(serverSocket->sockfd) != NSTACKX_EOK) {
257 LOGE(TAG, "set socket nonblock failed");
258 goto FAIL_SOCKET;
259 }
260
261 (void)memset_s(&localAddr, sizeof(localAddr), 0, sizeof(localAddr));
262 /* Bind to ANY source ip address and random port number */
263 localAddr.sin_family = AF_INET;
264 localAddr.sin_port = sockAddr->sin_port;
265 if (sockAddr->sin_addr.s_addr != 0) {
266 localAddr.sin_addr.s_addr = sockAddr->sin_addr.s_addr;
267 } else {
268 localAddr.sin_addr.s_addr = INADDR_ANY;
269 }
270 if (bind(serverSocket->sockfd, (struct sockaddr *)&localAddr, len) != 0) {
271 LOGE(TAG, "Failed to bind socket, error :%d", GetErrno());
272 goto FAIL_SOCKET;
273 }
274
275 if (sockAddr->sin_addr.s_addr != 0 &&
276 BindToDevice(serverSocket->sockfd, sockAddr) != NSTACKX_EOK) {
277 LOGE(TAG, "Failed to bind socket to device");
278 }
279
280 if (getsockname(serverSocket->sockfd, (struct sockaddr *)(&serverSocket->srcAddr), &len) != 0) {
281 LOGE(TAG, "Failed to get socket name! error :%d", GetErrno());
282 goto FAIL_SOCKET;
283 }
284
285 return NSTACKX_EOK;
286 FAIL_SOCKET:
287 CloseSocketInner(serverSocket->sockfd);
288 serverSocket->sockfd = INVALID_SOCKET;
289 return NSTACKX_EFAILED;
290 }
291
ClientSocketWithTargetDev(SocketProtocol protocol,const struct sockaddr_in * sockAddr,const char * localInterface)292 Socket *ClientSocketWithTargetDev(SocketProtocol protocol, const struct sockaddr_in *sockAddr,
293 const char *localInterface)
294 {
295 int32_t ret;
296 if (sockAddr == NULL) {
297 return NULL;
298 }
299 Socket *socket = calloc(1, sizeof(Socket));
300 if (socket == NULL) {
301 LOGE(TAG, "malloc Socket fail\n");
302 return NULL;
303 }
304
305 switch (protocol) {
306 case NSTACKX_PROTOCOL_TCP:
307 socket->protocol = NSTACKX_PROTOCOL_TCP;
308 ret = ConnectTcpServerWithTargetDev(socket, sockAddr, localInterface);
309 break;
310 case NSTACKX_PROTOCOL_UDP:
311 socket->protocol = NSTACKX_PROTOCOL_UDP;
312 ret = ConnectUdpServerWithTargetDev(socket, sockAddr, localInterface);
313 break;
314 case NSTACKX_PROTOCOL_D2D:
315 LOGE(TAG, "d2d not support");
316 ret = NSTACKX_EFAILED;
317 break;
318 default:
319 LOGE(TAG, "protocol not support");
320 ret = NSTACKX_EFAILED;
321 break;
322 }
323
324 if (ret != NSTACKX_EOK) {
325 LOGE(TAG, "Create client socket failed! %d", ret);
326 free(socket);
327 return NULL;
328 }
329 socket->isServer = NSTACKX_FALSE;
330 return socket;
331 }
332
ClientSocket(SocketProtocol protocol,const struct sockaddr_in * sockAddr)333 Socket *ClientSocket(SocketProtocol protocol, const struct sockaddr_in *sockAddr)
334 {
335 return ClientSocketWithTargetDev(protocol, sockAddr, NULL);
336 }
337
ServerSocket(SocketProtocol protocol,const struct sockaddr_in * sockAddr)338 Socket *ServerSocket(SocketProtocol protocol, const struct sockaddr_in *sockAddr)
339 {
340 int32_t ret;
341 if (sockAddr == NULL) {
342 return NULL;
343 }
344 Socket *socket = calloc(1, sizeof(Socket));
345 if (socket == NULL) {
346 LOGE(TAG, "malloc Socket fail\n");
347 return NULL;
348 }
349
350 switch (protocol) {
351 case NSTACKX_PROTOCOL_TCP:
352 socket->protocol = NSTACKX_PROTOCOL_TCP;
353 ret = CreateTcpServer(socket, sockAddr);
354 break;
355 case NSTACKX_PROTOCOL_UDP:
356 socket->protocol = NSTACKX_PROTOCOL_UDP;
357 ret = CreateUdpServer(socket, sockAddr);
358 break;
359 case NSTACKX_PROTOCOL_D2D:
360 socket->protocol = NSTACKX_PROTOCOL_D2D;
361 ret = NSTACKX_EFAILED;
362 LOGE(TAG, "d2d not support");
363 break;
364 default:
365 LOGE(TAG, "protocol not support");
366 ret = NSTACKX_EFAILED;
367 break;
368 }
369
370 if (ret != NSTACKX_EOK) {
371 LOGE(TAG, "Create server socket failed! %d", ret);
372 free(socket);
373 return NULL;
374 }
375 socket->isServer = NSTACKX_TRUE;
376 return socket;
377 }
378
CheckAcceptSocketValid(const Socket * serverSocket)379 static int32_t CheckAcceptSocketValid(const Socket *serverSocket)
380 {
381 if (serverSocket == NULL || serverSocket->isServer == NSTACKX_FALSE ||
382 serverSocket->protocol != NSTACKX_PROTOCOL_TCP) {
383 LOGE(TAG, "invalue Socket for accept");
384 return NSTACKX_EINVAL;
385 }
386 return NSTACKX_EOK;
387 }
388
SetAcceptSocket(SocketDesc acceptFd)389 static int32_t SetAcceptSocket(SocketDesc acceptFd)
390 {
391 struct sockaddr_in localAddr;
392 socklen_t localAddrLen = sizeof(localAddr);
393 (void)memset_s(&localAddr, localAddrLen, 0, localAddrLen);
394 if (getsockname(acceptFd, (struct sockaddr *)&localAddr, &localAddrLen) != 0) {
395 LOGE(TAG, "get socket name fail %d", GetErrno());
396 return NSTACKX_EFAILED;
397 }
398 /* It will always failed on devices without system authority, such as third-party devices. */
399 if (BindToDevice(acceptFd, &localAddr) != NSTACKX_EOK) {
400 LOGW(TAG, "Accept client bind to device fail");
401 }
402
403 if (SetSocketNonBlock(acceptFd) != NSTACKX_EOK) {
404 LOGE(TAG, "set socket nonblock failed");
405 return NSTACKX_EFAILED;
406 }
407 return NSTACKX_EOK;
408 }
409
AcceptSocket(Socket * serverSocket)410 Socket *AcceptSocket(Socket *serverSocket)
411 {
412 struct sockaddr_in clientAddr;
413 socklen_t addrLen = sizeof(clientAddr);
414 (void)memset_s(&clientAddr, addrLen, 0, addrLen);
415
416 if (CheckAcceptSocketValid(serverSocket) != NSTACKX_EOK) {
417 LOGE(TAG, "invalue Socket for accept \n");
418 return NULL;
419 }
420
421 Socket *clientSocket = calloc(1, sizeof(Socket));
422 if (clientSocket == NULL) {
423 LOGE(TAG, "client socket malloc fail\n");
424 return NULL;
425 }
426 clientSocket->protocol = NSTACKX_PROTOCOL_TCP;
427 clientSocket->isServer = NSTACKX_FALSE;
428 clientSocket->sockfd = accept(serverSocket->sockfd, (struct sockaddr *)&clientAddr, &addrLen);
429 if (clientSocket->sockfd == INVALID_SOCKET) {
430 LOGE(TAG, "accept return error: %d", GetErrno());
431 goto L_SOCKET_FAIL;
432 }
433
434 if (SetAcceptSocket(clientSocket->sockfd) != NSTACKX_EOK) {
435 LOGE(TAG, "set accept socket fail");
436 goto L_SOCKET_FAIL;
437 }
438
439 clientSocket->dstAddr = clientAddr;
440
441 return clientSocket;
442 L_SOCKET_FAIL:
443 if (clientSocket->sockfd != INVALID_SOCKET) {
444 CloseSocketInner(clientSocket->sockfd);
445 clientSocket->sockfd = INVALID_SOCKET;
446 }
447 free(clientSocket);
448 return NULL;
449 }
450
CheckSocketError(void)451 int32_t CheckSocketError(void)
452 {
453 int32_t ret;
454 if (SocketOpWouldBlock()) {
455 ret = NSTACKX_EAGAIN;
456 } else {
457 LOGE(TAG, "sendto/recvfrom error: %d", GetErrno());
458 ret = NSTACKX_EFAILED;
459 }
460 return ret;
461 }
462
SocketSendUdp(const Socket * socket,const uint8_t * buffer,size_t length)463 static int32_t SocketSendUdp(const Socket *socket, const uint8_t *buffer, size_t length)
464 {
465 socklen_t dstAddrLen = sizeof(struct sockaddr_in);
466
467 int32_t ret = (int32_t)sendto(socket->sockfd, buffer, length, 0, (struct sockaddr *)&socket->dstAddr, dstAddrLen);
468 if (ret <= 0) {
469 ret = CheckSocketError();
470 }
471 return ret;
472 }
473
SocketSend(const Socket * socket,const uint8_t * buffer,size_t length)474 int32_t SocketSend(const Socket *socket, const uint8_t *buffer, size_t length)
475 {
476 int32_t ret = NSTACKX_EFAILED;
477
478 if (socket == NULL || buffer == NULL) {
479 LOGE(TAG, "invalue socket input");
480 return ret;
481 }
482
483 if (socket->protocol == NSTACKX_PROTOCOL_TCP) {
484 ret = (int32_t)send(socket->sockfd, buffer, length, 0);
485 } else if (socket->protocol == NSTACKX_PROTOCOL_UDP) {
486 ret = SocketSendUdp(socket, buffer, length);
487 } else {
488 LOGE(TAG, "protocol not support %d", socket->protocol);
489 }
490
491 return ret;
492 }
493
SocketRecvTcp(const Socket * socket,uint8_t * buffer,size_t length,struct sockaddr_in * srcAddr,const socklen_t * addrLen)494 static int32_t SocketRecvTcp(const Socket *socket, uint8_t *buffer, size_t length, struct sockaddr_in *srcAddr,
495 const socklen_t *addrLen)
496 {
497 int32_t ret = (int32_t)recv(socket->sockfd, buffer, length, 0);
498 if (srcAddr != NULL && *addrLen >= (socklen_t)sizeof(struct sockaddr_in)) {
499 *srcAddr = socket->dstAddr;
500 }
501 return ret;
502 }
503
SocketRecvUdp(const Socket * socket,uint8_t * buffer,size_t length,struct sockaddr_in * srcAddr,const socklen_t * addrLen)504 static int32_t SocketRecvUdp(const Socket *socket, uint8_t *buffer, size_t length, struct sockaddr_in *srcAddr,
505 const socklen_t *addrLen)
506 {
507 struct sockaddr_in addr;
508 socklen_t len = sizeof(struct sockaddr_in);
509 (void)memset_s(&addr, sizeof(addr), 0, sizeof(addr));
510 int32_t ret = (int32_t)recvfrom(socket->sockfd, buffer, length, 0, (struct sockaddr *)&addr, &len);
511 if (ret < 0) {
512 ret = CheckSocketError();
513 } else if (ret == 0 || addr.sin_port == 0 || addr.sin_family != AF_INET) {
514 ret = NSTACKX_EAGAIN;
515 } else {
516 if (srcAddr != NULL && *addrLen >= (socklen_t)sizeof(struct sockaddr_in)) {
517 *srcAddr = addr;
518 }
519 }
520 return ret;
521 }
522
SocketRecv(Socket * socket,uint8_t * buffer,size_t length,struct sockaddr_in * srcAddr,const socklen_t * addrLen)523 int32_t SocketRecv(Socket *socket, uint8_t *buffer, size_t length, struct sockaddr_in *srcAddr,
524 const socklen_t *addrLen)
525 {
526 int32_t ret = NSTACKX_EFAILED;
527
528 if (socket == NULL) {
529 LOGE(TAG, "invalue socket input");
530 return ret;
531 }
532
533 if (socket->protocol == NSTACKX_PROTOCOL_TCP) {
534 ret = SocketRecvTcp(socket, buffer, length, srcAddr, addrLen);
535 } else if (socket->protocol == NSTACKX_PROTOCOL_UDP) {
536 ret = SocketRecvUdp(socket, buffer, length, srcAddr, addrLen);
537 } else {
538 LOGE(TAG, "protocol not support %d", socket->protocol);
539 }
540
541 return ret;
542 }
543