5fce889c37fa360131359ae8266bf95d23864de6
[contrib/iotivity.git] / resource / csdk / ocsocket / src / ocsocket.c
1 //******************************************************************
2 //
3 // Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved.
4 //
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
6 //
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
10 //
11 //      http://www.apache.org/licenses/LICENSE-2.0
12 //
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
18 //
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
20
21 #include <sys/types.h>
22 #include <sys/socket.h>
23 #include <sys/select.h>
24 #include <arpa/inet.h>
25 #include <netinet/in.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <stdlib.h>
29 #include <math.h>
30 #include <unistd.h>
31 #include <fcntl.h>
32 #include <net/if.h>
33 #include <errno.h>
34
35 #ifdef __ANDROID__
36 #include <sys/ioctl.h>
37 #else
38 #include <ifaddrs.h>
39 #endif
40
41 #include <logger.h>
42 #include <ocsocket.h>
43
44 /// Module Name
45 #define MOD_NAME ("ocsocket")
46
47 /// Macro to verify the validity of input argument
48 #define VERIFY_NON_NULL(arg) { if (!arg) {OC_LOG(FATAL, MOD_NAME, #arg " is NULL"); return ERR_INVALID_INPUT;} }
49
50 /// Builds a socket interface address using IP address and port number
51 int32_t OCBuildIPv4Address(uint8_t a, uint8_t b, uint8_t c, uint8_t d, uint16_t port, OCDevAddr *ipAddr)
52 {
53     struct sockaddr_in *sa;
54     uint32_t ip = a;
55
56     VERIFY_NON_NULL(ipAddr);
57     memset(ipAddr, 0, sizeof(OCDevAddr));
58
59     ip <<= 8;
60     ip |= b;
61     ip <<= 8;
62     ip |= c;
63     ip <<= 8;
64     ip |= d;
65
66     ipAddr->size = sizeof(struct sockaddr_in);
67     sa = (struct sockaddr_in*)ipAddr->addr;
68     sa->sin_family = AF_INET;
69     sa->sin_addr.s_addr = htonl(ip);
70     sa->sin_port = htons(port);
71
72     return ERR_SUCCESS;
73 }
74
75 #ifdef __ANDROID__
76 /// Retrieves the IP address assigned to specified wireless interface
77 int32_t OCGetInterfaceAddress(uint8_t* ifName, uint32_t ifNameLen, uint16_t addrType,
78              uint8_t *addr,  uint32_t addrLen)
79 {
80     int32_t ret = ERR_UNKNOWN;
81     int32_t sfd = 0xFFFFFFFF;
82     struct ifreq ifr;
83
84     VERIFY_NON_NULL(addr);
85     VERIFY_NON_NULL(ifName);
86     if (ifNameLen > (IFNAMSIZ - 1) ) {
87         return ERR_INVALID_INPUT;
88     }
89     if (addrType != AF_INET) {
90         return ERR_INVALID_INPUT;
91     }
92
93     sfd = socket(addrType, SOCK_DGRAM, 0);
94     if (sfd < 0) {
95         OC_LOG_V(FATAL, MOD_NAME, "socket API ret val %d", sfd);
96         goto exit;
97     }
98
99     ifr.ifr_addr.sa_family = addrType;
100
101     strncpy(ifr.ifr_name, (const char*)ifName, ifNameLen);
102
103     if (ioctl(sfd, SIOCGIFADDR, &ifr) != 0) {
104         OC_LOG(FATAL, MOD_NAME, "ioctl call failed");
105         goto exit;
106     }
107
108     strncpy((char *)addr,
109             inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr),
110             addrLen);
111     ret = ERR_SUCCESS;
112
113 exit:
114     if (sfd >= 0) {
115         close(sfd);
116     }
117     return ret;
118 }
119
120 #else
121 /// Retrieves the IP address assigned to specified wireless interface
122 int32_t OCGetInterfaceAddress(uint8_t* ifName, uint32_t ifNameLen, uint16_t addrType,
123              uint8_t *addr,  uint32_t addrLen)
124 {
125     struct ifaddrs *myaddrs = NULL, *ifa = NULL;
126     int32_t ret = ERR_UNKNOWN;
127
128     VERIFY_NON_NULL(addr);
129
130     if (addrType != AF_INET) {
131         return ERR_INVALID_INPUT;
132     }
133
134     if(getifaddrs(&myaddrs) != 0) {
135         goto exit;
136     }
137
138     for (ifa = myaddrs; ifa != NULL; ifa = ifa->ifa_next) {
139         if (ifa->ifa_addr == NULL)
140             continue;
141         if (!(ifa->ifa_flags & IFF_UP))
142             continue;
143         if (!(ifa->ifa_flags & IFF_RUNNING))
144             continue;
145
146         if (ifName && ifa->ifa_name) {
147            if(strncmp((const char*)ifName, ifa->ifa_name, ifNameLen) != 0)
148             continue;
149         }
150
151         switch (ifa->ifa_addr->sa_family)
152         {
153             case AF_INET:
154                 {
155                     struct sockaddr_in *s4 = (struct sockaddr_in *)ifa->ifa_addr;
156                     if(inet_ntop(AF_INET, &(s4->sin_addr), (char *)addr, addrLen))
157                         ret = ERR_SUCCESS;
158                     goto exit;
159                 }
160
161             default:
162                 continue;
163         }
164     }
165
166 exit:
167     if (myaddrs) {
168         freeifaddrs(myaddrs);
169     }
170     return ret;
171 }
172 #endif //__ANDROID__
173
174 /// Creates a BSD socket and binds it specified port for UDP
175 int32_t OCInitUDP(OCDevAddr* ipAddr, int32_t *sockfd)
176 {
177     int32_t ret = ERR_UNKNOWN;
178     int32_t sfd = 0xFFFFFFFF;
179     int set_option_on = 1;
180
181     VERIFY_NON_NULL(ipAddr);
182     VERIFY_NON_NULL(sockfd);
183
184     OC_LOG_V(DEBUG, MOD_NAME, "%s Begin", __func__ );
185     //Create a datagram socket on which to recv/send.
186     sfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
187     if (sfd < 0) {
188         OC_LOG_V(FATAL, MOD_NAME, "socket API ret val %d", sfd);
189         goto exit;
190     }
191
192     if (ret = setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (char*) &set_option_on,
193                 sizeof(set_option_on)) < 0) {
194         OC_LOG_V(FATAL, MOD_NAME, "setsockopt API failed with errno %s",
195                 strerror(errno));
196         goto exit;
197     }
198
199     if (ret = bind(sfd, (struct sockaddr*)ipAddr->addr, ipAddr->size) < 0) {
200         OC_LOG_V(FATAL, MOD_NAME, "bind API failed with errno %s", strerror(errno));
201         goto exit;
202     }
203
204     *sockfd = sfd;
205     ret = ERR_SUCCESS;
206
207 exit:
208     if ((ret != ERR_SUCCESS) && (sfd >= 0)) {
209         close(sfd);
210     }
211
212     OC_LOG_V(DEBUG, MOD_NAME, "%s End", __func__ );
213     return ret;
214 }
215
216
217
218 /// Creates a BSD socket and binds the specified port for UDP multicast.
219 int32_t OCInitUDPMulticast(OCDevAddr* ipmcastaddr, int32_t* sockfd)
220 {
221     int32_t ret = ERR_UNKNOWN;
222     int32_t sfd = 0xFFFFFFFF;
223     char loopch=1;
224     int set_option_on = 1;
225
226     VERIFY_NON_NULL(ipmcastaddr);
227     VERIFY_NON_NULL(sockfd);
228
229     OC_LOG_V(DEBUG, MOD_NAME, "%s Begin", __func__ );
230     //Create a datagram socket on which to recv/send.
231     sfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
232     if (sfd < 0) {
233         OC_LOG_V(FATAL, MOD_NAME, "socket API ret val %d", sfd);
234         goto exit;
235
236     }
237
238     if ((ret = setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (char*) &set_option_on,
239                 sizeof(set_option_on))) < 0) {
240         OC_LOG_V(FATAL, MOD_NAME, "setsockopt API for SO_REUSEADDR failed with errno %s", strerror(errno));
241         goto exit;
242     }
243
244     // bind to multicast port
245     struct sockaddr_in sa;
246     struct sockaddr_in *sin;
247
248     sin = (struct sockaddr_in *)(ipmcastaddr->addr);
249     memset(&sa, 0, sizeof(sa));
250     sa.sin_family = AF_INET;
251     sa.sin_addr.s_addr = sin->sin_addr.s_addr;
252     sa.sin_port = sin->sin_port;
253
254     if ((ret = bind(sfd, (struct sockaddr*)&sa, sizeof(sa))) < 0) {
255         OC_LOG_V(FATAL, MOD_NAME, "bind API failed with errno %s", strerror(errno));
256         goto exit;
257     }
258
259     // add membership to receiving socket
260     struct ip_mreq mreq;
261     memset(&mreq, 0, sizeof(struct ip_mreq));
262     mreq.imr_interface.s_addr = htonl(INADDR_ANY);
263     mreq.imr_multiaddr.s_addr = sin->sin_addr.s_addr;
264     if ((ret = setsockopt(sfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreq, sizeof(mreq))) < 0) {
265         OC_LOG_V(FATAL, MOD_NAME, "setsockopt API for IP_ADD_MEMBERSHIP failed with errno %s", strerror(errno));
266         goto exit;
267     }
268
269     //Enable loopback so we can receive our own datagrams.
270     if ((ret = setsockopt(sfd, IPPROTO_IP, IP_MULTICAST_LOOP,
271                 (char *)&loopch, sizeof(loopch))) < 0) {
272         OC_LOG_V(FATAL, MOD_NAME, "setsockopt API for IP_MULTICAST_LOOP failed with errno %s", strerror(errno));
273         goto exit;
274     }
275
276     ret = ERR_SUCCESS;
277
278 exit:
279     if (ret == ERR_SUCCESS) {
280         *sockfd = sfd;
281     } else {
282         close(sfd);
283     }
284
285     OC_LOG_V(DEBUG, MOD_NAME, "%s End", __func__ );
286     return ret;
287 }
288
289
290
291 /// Send data to requested end-point using UDP socket
292 int32_t OCSendTo(int32_t sockfd, const uint8_t* buf, uint32_t bufLen, uint32_t flags,
293             OCDevAddr * ipAddr)
294 {
295     int32_t ret;
296
297     VERIFY_NON_NULL(buf);
298     VERIFY_NON_NULL(ipAddr);
299
300     OC_LOG_V(DEBUG, MOD_NAME, "%s Begin", __func__ );
301     ret = sendto(sockfd, buf, bufLen, flags,
302             (struct sockaddr*)ipAddr->addr, ipAddr->size);
303
304     OC_LOG_V(DEBUG, MOD_NAME, "%s End", __func__ );
305     return ret;
306 }
307
308
309 /// Retrieve any available data from UDP socket. This is a non-blocking call.
310 int32_t OCRecvFrom(int32_t sockfd, uint8_t* buf, uint32_t bufLen, uint32_t flags,
311             OCDevAddr * ipAddr)
312 {
313     int32_t ret = 0;
314
315     VERIFY_NON_NULL(buf);
316     VERIFY_NON_NULL(ipAddr);
317
318     struct timeval timeout;
319     timeout.tv_sec = 0;
320     timeout.tv_usec = 5000;
321     fd_set reads;
322
323     OC_LOG_V(DEBUG, MOD_NAME, "%s Begin", __func__ );
324
325     FD_ZERO(&reads);
326     FD_SET(sockfd, &reads);
327     ret = select(sockfd + 1, &reads, NULL, NULL, &timeout);
328     if( ret < 0) {
329         OC_LOG(FATAL, MOD_NAME, "select API failed");
330         return ret;
331     }
332     if (!FD_ISSET(sockfd, &reads)) {
333         OC_LOG(DEBUG, MOD_NAME, "No data to read");
334         return ERR_SUCCESS;
335     }
336
337     // Read available data.
338     ret = recvfrom(sockfd, buf, bufLen, flags,
339             (struct sockaddr*)ipAddr->addr, (socklen_t*)&(ipAddr->size));
340     if (ret < 1) {
341         OC_LOG(FATAL, MOD_NAME, "OCRecvFrom ERR");
342     }
343     OC_LOG_V(DEBUG, MOD_NAME, "%s End", __func__ );
344     return ret;
345 }
346
347
348 /// Close the socket and release all system resources.
349 int32_t OCClose(int32_t sockfd)
350 {
351     return (close(sockfd));
352 }
353
354
355 /// Retrieve the IPv4 address embedded inside OCDev address data structure
356 int32_t OCDevAddrToIPv4Addr(OCDevAddr *ipAddr, uint8_t *a, uint8_t *b,
357             uint8_t *c, uint8_t *d )
358 {
359     struct sockaddr_in *sa;
360     uint32_t ip;
361
362     if ( !ipAddr || !a || !b || !c || !d ) {
363         OC_LOG(FATAL, MOD_NAME, "Invalid argument");
364         return ERR_INVALID_INPUT;
365     }
366
367     sa = (struct sockaddr_in*)ipAddr->addr;
368     ip = ntohl(sa->sin_addr.s_addr);
369     *d = *((uint8_t*)&ip + 0);
370     *c = *((uint8_t*)&ip + 1);
371     *b = *((uint8_t*)&ip + 2);
372     *a = *((uint8_t*)&ip + 3);
373
374     return ERR_SUCCESS;
375 }
376
377
378 /// Retrieve the IPv4 address embedded inside OCDev address data structure
379 int32_t OCDevAddrToPort(OCDevAddr *ipAddr, uint16_t *port)
380 {
381     struct sockaddr_in *sa;
382     if ( !ipAddr || !port ) {
383         OC_LOG(FATAL, MOD_NAME, "Invalid argument");
384         return ERR_INVALID_INPUT;
385     }
386
387     sa = (struct sockaddr_in*)ipAddr->addr;
388     *port = ntohs(sa->sin_port);
389
390     return ERR_SUCCESS;
391 }