1 /*
2  * Copyright (C) 2015-2020 Alibaba Group Holding Limited
3  */
4 
5 #include <stdio.h>
6 #include <string.h>
7 #include <errno.h>
8 #include "aos/kernel.h"
9 #include "aos_tcp.h"
10 #include "aos_socket.h"
11 #include "aos_system.h"
12 
13 #define PLATFORM_LOG_D(format, ...)                                \
14     do {                                                                   \
15         aos_printf("D: %d %s() | " format "\n", __LINE__, __FUNCTION__, \
16                ##__VA_ARGS__);                                             \
17     } while (0);
18 
19 #define PLATFORM_LOG_E(format, ...)                                \
20     do {                                                                   \
21         aos_printf("E: %d %s() | " format "\n", __LINE__, __FUNCTION__, \
22                ##__VA_ARGS__);                                             \
23     } while (0);
24 
25 #ifndef CONFIG_NO_TCPIP
26 
aliot_platform_time_left(uint64_t t_end,uint64_t t_now)27 static uint64_t aliot_platform_time_left(uint64_t t_end, uint64_t t_now)
28 {
29     uint64_t t_left;
30 
31     if (t_end > t_now) {
32         t_left = t_end - t_now;
33     } else {
34         t_left = 0;
35     }
36 
37     return t_left;
38 }
39 
aos_tcp_establish(const char * host,unsigned int port)40 int aos_tcp_establish(const char *host, unsigned int port)
41 {
42     struct addrinfo  hints;
43     struct addrinfo *addrInfoList = NULL;
44     struct addrinfo *cur          = NULL;
45     int              fd           = 0;
46     int              rc           = -1;
47     char             service[6];
48 
49     memset(&hints, 0, sizeof(hints));
50 
51     PLATFORM_LOG_D(
52                 "establish tcp connection with server(host=%s port=%u)", host, port);
53 
54     hints.ai_family   = AF_INET; // only IPv4
55     hints.ai_socktype = SOCK_STREAM;
56     hints.ai_protocol = IPPROTO_TCP;
57     sprintf(service, "%u", port);
58 
59     if ((rc = getaddrinfo(host, service, &hints, &addrInfoList)) != 0) {
60         PLATFORM_LOG_E("getaddrinfo error: %d", rc);
61         return (uintptr_t)-1;
62     }
63     for (cur = addrInfoList; cur != NULL; cur = cur->ai_next) {
64 
65         if (cur->ai_family != AF_INET) {
66             PLATFORM_LOG_E("socket type error");
67             rc = -1;
68             continue;
69         }
70 
71         fd = socket(cur->ai_family, cur->ai_socktype, cur->ai_protocol);
72         if (fd < 0) {
73             PLATFORM_LOG_E("create socket error");
74             rc = -1;
75             continue;
76         }
77 
78         if (connect(fd, cur->ai_addr, cur->ai_addrlen) == 0) {
79             rc = fd;
80             break;
81         }
82 
83         close(fd);
84         PLATFORM_LOG_E("connect error");
85         rc = -1;
86     }
87 
88     if (-1 == rc) {
89         PLATFORM_LOG_D("fail to establish tcp");
90     } else {
91         PLATFORM_LOG_D("success to establish tcp, fd=%d", rc);
92     }
93     freeaddrinfo(addrInfoList);
94 
95     return rc;
96 }
97 
aos_tcp_destroy(unsigned int fd)98 int aos_tcp_destroy(unsigned int fd)
99 {
100     int rc;
101 
102     // Shutdown both send and receive operations.
103     rc = shutdown((int)fd, 2);
104     if (0 != rc) {
105         PLATFORM_LOG_E("shutdown error");
106         return -1;
107     }
108 
109     rc = close((int)fd);
110     if (0 != rc) {
111         PLATFORM_LOG_E("closesocket error");
112         return -1;
113     }
114 
115     return 0;
116 }
117 
118 
aos_tcp_write(unsigned int fd,const char * buf,unsigned int len,unsigned int timeout_ms)119 int aos_tcp_write(unsigned int fd, const char *buf, unsigned int len, unsigned int timeout_ms)
120 {
121     int      ret, err_code;
122     uint32_t len_sent;
123     uint64_t t_end, t_left;
124     fd_set   sets;
125 
126     if (fd >= FD_SETSIZE) {
127         return -1;
128     }
129     t_end    = aos_now_ms() + timeout_ms;
130     len_sent = 0;
131     err_code = 0;
132     ret      = 1; // send one time if timeout_ms is value 0
133 
134     do {
135         t_left = aliot_platform_time_left(t_end, aos_now_ms());
136 
137         if (0 != t_left) {
138             struct timeval timeout;
139 
140             FD_ZERO(&sets);
141             FD_SET(fd, &sets);
142 
143             timeout.tv_sec  = t_left / 1000;
144             timeout.tv_usec = (t_left % 1000) * 1000;
145             ret = select(fd + 1, NULL, &sets, NULL, &timeout);
146             if (ret > 0) {
147                 if (0 == FD_ISSET(fd, &sets)) {
148                     PLATFORM_LOG_D("Should NOT arrive");
149                     // If timeout in next loop, it will not sent any data
150                     ret = 0;
151                     continue;
152                 }
153             } else if (0 == ret) {
154                 // PLATFORM_LOG_D("select-write timeout %lu", fd);
155                 break;
156             } else {
157                 if (EINTR == errno) {
158                     PLATFORM_LOG_D("EINTR be caught");
159                     continue;
160                 }
161 
162                 err_code = -1;
163                 PLATFORM_LOG_E("select-write fail");
164                 break;
165             }
166         }
167 
168         if (ret > 0) {
169             ret = send(fd, buf + len_sent, len - len_sent, 0);
170             if (ret > 0) {
171                 len_sent += ret;
172             } else if (0 == ret) {
173                 PLATFORM_LOG_D("No data be sent");
174             } else {
175                 if (EINTR == errno) {
176                     PLATFORM_LOG_D("EINTR be caught");
177                     continue;
178                 }
179 
180                 err_code = -1;
181                 PLATFORM_LOG_E("send fail");
182                 break;
183             }
184         }
185     } while ((len_sent < len) &&
186              (aliot_platform_time_left(t_end, aos_now_ms()) > 0));
187 
188     return err_code == 0 ? len_sent : err_code;
189 }
190 
aos_tcp_read(unsigned int fd,char * buf,unsigned int len,unsigned int timeout_ms)191 int aos_tcp_read(unsigned int fd, char *buf, unsigned int len, unsigned int timeout_ms)
192 {
193    int res = 0;
194     int32_t recv_bytes = 0;
195     ssize_t recv_res = 0;
196     uint64_t timestart_ms = 0, timenow_ms = 0, timeselect_ms = 0;
197     fd_set recv_sets;
198     struct timeval timestart, timenow, timeselect;
199 
200     FD_ZERO(&recv_sets);
201     FD_SET(fd, &recv_sets);
202 
203     /* Start Time */
204     gettimeofday(&timestart, NULL);
205     timestart_ms = timestart.tv_sec * 1000 + timestart.tv_usec / 1000;
206     timenow_ms = timestart_ms;
207 
208     do {
209         gettimeofday(&timenow, NULL);
210         timenow_ms = timenow.tv_sec * 1000 + timenow.tv_usec / 1000;
211 
212         if (timenow_ms - timestart_ms >= timenow_ms ||
213             timeout_ms - (timenow_ms - timestart_ms) > timeout_ms) {
214             break;
215         }
216 
217         timeselect_ms = timeout_ms - (timenow_ms - timestart_ms);
218         timeselect.tv_sec = timeselect_ms / 1000;
219         timeselect.tv_usec = timeselect_ms % 1000 * 1000;
220 
221         res = select(fd + 1, &recv_sets, NULL, NULL, &timeselect);
222         if (res == 0) {
223             continue;
224         } else if (res < 0) {
225             aos_printf("aos_tcp_read, errno: %d\n", errno);
226             return -1;
227         } else {
228             if (FD_ISSET(fd, &recv_sets)) {
229                 recv_res = recv(fd, buf + recv_bytes, len - recv_bytes, 0);
230                 if (recv_res == 0) {
231                     aos_printf("aos_tcp_read, nwk connection closed\n");
232                     break;
233                 } else if (recv_res < 0) {
234                     aos_printf("aos_tcp_read, errno: %d\n", errno);
235                     if (errno == EINTR) {
236                         continue;
237                     }
238                     return -1;
239                 } else {
240                     recv_bytes += recv_res;
241                     if (recv_bytes == len) {
242                         break;
243                     }
244                 }
245             }
246         }
247     } while (((timenow_ms - timestart_ms) < timeout_ms) && (recv_bytes < len));
248 
249     return recv_bytes;
250 }
251 #else
aos_tcp_establish(_IN_ const char * host,_IN_ uint16_t port)252 uintptr_t aos_tcp_establish(_IN_ const char *host, _IN_ uint16_t port)
253 {
254     return 0;
255 }
aos_tcp_destroy(uintptr_t fd)256 int32_t aos_tcp_destroy(uintptr_t fd)
257 {
258     return 0;
259 }
aos_tcp_write(uintptr_t fd,const char * buf,uint32_t len,uint32_t timeout_ms)260 int32_t aos_tcp_write(uintptr_t fd, const char *buf, uint32_t len,
261                       uint32_t timeout_ms)
262 {
263     return 0;
264 }
aos_tcp_read(uintptr_t fd,char * buf,uint32_t len,uint32_t timeout_ms)265 int32_t aos_tcp_read(uintptr_t fd, char *buf, uint32_t len, uint32_t timeout_ms)
266 {
267     return 0;
268 }
269 #endif
270