1 /*
2  * Copyright (C) 2015-2020 Alibaba Group Holding Limited
3  */
4 
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <errno.h>
9 #include "ulog/ulog.h"
10 #include "aos/kernel.h"
11 #include "aos_socket.h"
12 #include <netdb.h>
13 #include "aos_udp.h"
14 #include "aos_system.h"
15 
16 #define TRANSPORT_ADDR_LEN 16
17 
18 #ifndef IP_PKTINFO
19 #define IP_PKTINFO IP_MULTICAST_IF
20 #endif
21 
22 #ifndef IPV6_PKTINFO
23 #define IPV6_PKTINFO IPV6_V6ONL
24 #endif
25 
26 #define NETWORK_ADDR_LEN (16)
27 
28 #define LOG_TAG "HAL_TL"
29 
30 #define platform_info(format, ...) LOGI(LOG_TAG, format, ##__VA_ARGS__)
31 #define platform_err(format, ...) LOGE(LOG_TAG, format, ##__VA_ARGS__)
32 
aos_udp_socket_create()33 int aos_udp_socket_create()
34 {
35     int                     rc = -1;
36     long                    socket_id = -1;
37 
38     socket_id = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
39     if (socket_id < 0) {
40         aos_printf("create socket error");
41         return rc;
42     }
43 
44     return socket_id;
45 }
46 
aos_udp_socket_bind(int p_socket,unsigned short port)47 int aos_udp_socket_bind(int p_socket, unsigned short port)
48 {
49     struct sockaddr_in addr;
50     int opt_val = 1;
51 
52     memset(&addr, 0, sizeof(struct sockaddr_in));
53 
54     if (0 != setsockopt(p_socket, SOL_SOCKET, SO_REUSEADDR, &opt_val, sizeof(opt_val))) {
55         aos_printf("setsockopt(SO_REUSEADDR) falied\n");
56         close(p_socket);
57         return -1;
58     }
59 
60     addr.sin_addr.s_addr = htonl(INADDR_ANY);
61     addr.sin_family = AF_INET;
62     addr.sin_port = htons(port);
63 
64     if (-1 == bind(p_socket, (struct sockaddr *)&addr, sizeof(struct sockaddr_in))) {
65         aos_printf("bind(%d) falied\n", (int)p_socket);
66         close(p_socket);
67         return -1;
68     }
69     aos_printf("success to establish udp, fd = %d", (int)p_socket);
70 
71     return p_socket;
72 }
73 
74 /**
75  * @brief Create a UDP socket.
76  *
77  * @param [in] port: @n Specify the UDP port of UDP socket
78  *
79  * @retval  < 0 : Fail.
80  * @retval >= 0 : Success, the value is handle of this UDP socket.
81  * @see None.
82  */
aos_udp_create(char * host,unsigned short port)83 int aos_udp_create(char *host, unsigned short port)
84 {
85     int                     rc = -1;
86     long                    socket_id = -1;
87     char                    port_ptr[6] = {0};
88     struct addrinfo         hints;
89     char                    addr[NETWORK_ADDR_LEN] = {0};
90     struct addrinfo        *res, *ainfo;
91     struct sockaddr_in     *sa = NULL;
92 
93     if (NULL == host) {
94         return (-1);
95     }
96 
97     sprintf(port_ptr, "%u", port);
98     memset((char *)&hints, 0x00, sizeof(hints));
99     hints.ai_socktype = SOCK_DGRAM;
100     hints.ai_family = AF_INET;
101     hints.ai_protocol = IPPROTO_UDP;
102 
103     rc = getaddrinfo(host, port_ptr, &hints, &res);
104     if (0 != rc) {
105         platform_err("getaddrinfo error: %d", rc);
106         return (-1);
107     }
108 
109     for (ainfo = res; ainfo != NULL; ainfo = ainfo->ai_next) {
110         if (AF_INET == ainfo->ai_family) {
111             sa = (struct sockaddr_in *)ainfo->ai_addr;
112             inet_ntop(AF_INET, &sa->sin_addr, addr, NETWORK_ADDR_LEN);
113 
114             socket_id = socket(ainfo->ai_family, ainfo->ai_socktype, ainfo->ai_protocol);
115             if (socket_id < 0) {
116                 platform_err("create socket error");
117                 continue;
118             }
119             if (0 == connect(socket_id, ainfo->ai_addr, ainfo->ai_addrlen)) {
120                 break;
121             }
122 
123             close(socket_id);
124         }
125     }
126     freeaddrinfo(res);
127 
128     return socket_id;
129 }
130 
aos_udp_create_without_connect(const char * host,unsigned short port)131 int aos_udp_create_without_connect(const char *host, unsigned short port)
132 {
133     int                flag      = 1;
134     int                ret       = -1;
135     int                socket_id = -1;
136     struct sockaddr_in local_addr; /*local addr*/
137 
138     if ((socket_id = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
139         platform_err("socket create failed\r\n");
140         return (intptr_t)-1;
141     }
142 
143     ret = setsockopt(socket_id, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag));
144     if (ret < 0) {
145         close(socket_id);
146         platform_err("setsockopt SO_REUSEADDR failed");
147         return (intptr_t)-1;
148     }
149 
150     flag = 1;
151 #ifdef IP_RECVPKTINFO
152     if ((ret = setsockopt(socket_id, IPPROTO_IP, IP_RECVPKTINFO, &flag,
153                           sizeof(flag))) < 0)
154 #else  /* IP_RECVPKTINFO */
155     if ((ret = setsockopt(socket_id, IPPROTO_IP, IP_PKTINFO, &flag,
156                           sizeof(flag))) < 0)
157 #endif /* IP_RECVPKTINFO */
158         if (ret < 0) {
159             close(socket_id);
160             platform_err("setsockopt IP_PKTINFO failed\r\n");
161             return (intptr_t)-1;
162         }
163 
164 
165     memset(&local_addr, 0x00, sizeof(local_addr));
166     local_addr.sin_family = AF_INET;
167     if (NULL != host) {
168         inet_aton(host, &local_addr.sin_addr);
169     } else {
170         local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
171     }
172     local_addr.sin_port = htons(port);
173     ret = bind(socket_id, (struct sockaddr *)&local_addr, sizeof(local_addr));
174 
175     // faos_printf(stderr,"\r\n[%s LINE #%d]  Create socket port %d fd %d ret
176     // %d\r\n",
177     //                    __FILE__, __LINE__, port, socket_id, ret);
178     return socket_id;
179 }
180 
aos_udp_close_without_connect(int sockfd)181 int aos_udp_close_without_connect(int sockfd)
182 {
183     return close((int)sockfd);
184 }
185 
aos_udp_recvfrom(int sockfd,aos_networkAddr * p_remote,unsigned char * p_data,unsigned int datalen,unsigned int timeout_ms)186 int aos_udp_recvfrom(int sockfd, aos_networkAddr *p_remote,
187                      unsigned char *p_data, unsigned int datalen,
188                      unsigned int timeout_ms)
189 {
190     int             socket_id = -1;
191     struct sockaddr from;
192     int             count = -1, ret = -1;
193     socklen_t       addrlen = 0;
194     struct timeval  tv;
195     fd_set          read_fds;
196 
197     if (NULL == p_remote || NULL == p_data) {
198         return -1;
199     }
200 
201     socket_id = (int)sockfd;
202 
203     FD_ZERO(&read_fds);
204     FD_SET(socket_id, &read_fds);
205 
206     tv.tv_sec  = timeout_ms / 1000;
207     tv.tv_usec = (timeout_ms % 1000) * 1000;
208 
209     ret = select(socket_id + 1, &read_fds, NULL, NULL,
210                  timeout_ms == 0 ? NULL : &tv);
211 
212     /* Zero fds ready means we timed out */
213     if (ret == 0) {
214         return 0; /* receive timeout */
215     }
216 
217     if (ret < 0) {
218         if (errno == EINTR) {
219             return -3; /* want read */
220         }
221 
222         return -4; /* receive failed */
223     }
224 
225     addrlen = sizeof(struct sockaddr);
226     count   = recvfrom(socket_id, p_data, (size_t)datalen, 0, &from, &addrlen);
227     if (-1 == count) {
228         return -1;
229     }
230     if (from.sa_family == AF_INET) {
231         struct sockaddr_in *sin = (struct sockaddr_in *)&from;
232         inet_ntop(AF_INET, &sin->sin_addr, (char *)p_remote->addr,
233                   NETWORK_ADDR_LEN);
234         p_remote->port = ntohs(sin->sin_port);
235     }
236     return count;
237 }
238 
aos_udp_sendto(int sockfd,const aos_networkAddr * p_remote,const unsigned char * p_data,unsigned int datalen,unsigned int timeout_ms)239 int aos_udp_sendto(int sockfd, const aos_networkAddr *p_remote,
240                    const unsigned char *p_data, unsigned int datalen,
241                    unsigned int timeout_ms)
242 {
243     int                rc        = -1;
244     int                socket_id = -1;
245     struct sockaddr_in remote_addr;
246 
247     if (NULL == p_remote || NULL == p_data) {
248         return -1;
249     }
250 
251     socket_id              = (int)sockfd;
252     remote_addr.sin_family = AF_INET;
253     if (1 !=
254         (rc = inet_pton(remote_addr.sin_family, (const char *)p_remote->addr,
255                         &remote_addr.sin_addr.s_addr))) {
256         return -1;
257     }
258     remote_addr.sin_port = htons(p_remote->port);
259     rc                   = sendto(socket_id, p_data, (size_t)datalen, 0,
260                 (const struct sockaddr *)&remote_addr, sizeof(remote_addr));
261     if (-1 == rc) {
262         return -1;
263     }
264 
265     return (rc) > 0 ? rc : -1;
266 }
267 
aos_udp_joinmulticast(int sockfd,char * p_group)268 int aos_udp_joinmulticast(int sockfd, char *p_group)
269 {
270     int err       = -1;
271     int socket_id = -1;
272 
273     if (NULL == p_group) {
274         return -1;
275     }
276 
277     /*set loopback*/
278     int loop  = 1;
279     socket_id = (int)sockfd;
280     err =
281       setsockopt(socket_id, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop));
282     if (err < 0) {
283         aos_printf("setsockopt():IP_MULTICAST_LOOP failed\r\n");
284         return err;
285     }
286 
287     struct ip_mreq mreq;
288     mreq.imr_multiaddr.s_addr = inet_addr(p_group);
289     mreq.imr_interface.s_addr = htonl(INADDR_ANY); /*default networt interface*/
290 
291     /*join to the mutilcast group*/
292     err =
293       setsockopt(socket_id, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
294     if (err < 0) {
295         aos_printf("setsockopt():IP_ADD_MEMBERSHIP failed\r\n");
296         return err;
297     }
298 
299     return 0;
300 }
301 
aos_udp_write(int p_socket,const unsigned char * p_data,unsigned int datalen)302 int aos_udp_write(int p_socket, const unsigned char *p_data,
303                   unsigned int datalen)
304 {
305     int  rc        = -1;
306     long socket_id = -1;
307 
308     socket_id = (long)p_socket;
309     rc        = send(socket_id, (char *)p_data, (int)datalen, 0);
310     if (-1 == rc) {
311         return -1;
312     }
313 
314     return rc;
315 }
316 
317 
aos_udp_read_timeout(int p_socket,unsigned char * p_data,unsigned int datalen,unsigned int timeout)318 int aos_udp_read_timeout(int p_socket, unsigned char *p_data,
319                         unsigned int datalen, unsigned int timeout)
320 {
321     int            ret;
322     struct timeval tv;
323     fd_set         read_fds;
324     long           socket_id = -1;
325 
326     if (0 == p_socket || NULL == p_data) {
327         return -1;
328     }
329     socket_id = (long)p_socket;
330 
331     if (socket_id < 0) {
332         return -1;
333     }
334 
335     FD_ZERO(&read_fds);
336     FD_SET(socket_id, &read_fds);
337 
338     tv.tv_sec  = timeout / 1000;
339     tv.tv_usec = (timeout % 1000) * 1000;
340 
341     ret =
342       select(socket_id + 1, &read_fds, NULL, NULL, timeout == 0 ? NULL : &tv);
343 
344     /* Zero fds ready means we timed out */
345     if (ret == 0) {
346         return -2; /* receive timeout */
347     }
348 
349     if (ret < 0) {
350         if (errno == EINTR) {
351             return -3; /* want read */
352         }
353 
354         return -4; /* receive failed */
355     }
356 
357     /* This call will not block */
358     return  read((long)p_socket, p_data, datalen);
359 
360 }
361