• 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 "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