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(×tart, 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, ×elect);
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