1 //******************************************************************
3 // Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved.
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
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
11 // http://www.apache.org/licenses/LICENSE-2.0
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.
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
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>
36 #include <sys/ioctl.h>
45 #define MOD_NAME ("ocsocket")
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;} }
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)
53 struct sockaddr_in *sa;
56 VERIFY_NON_NULL(ipAddr);
57 memset(ipAddr, 0, sizeof(OCDevAddr));
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);
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)
80 int32_t ret = ERR_UNKNOWN;
81 int32_t sfd = 0xFFFFFFFF;
84 VERIFY_NON_NULL(addr);
85 VERIFY_NON_NULL(ifName);
86 if (ifNameLen > (IFNAMSIZ - 1) ) {
87 return ERR_INVALID_INPUT;
89 if (addrType != AF_INET) {
90 return ERR_INVALID_INPUT;
93 sfd = socket(addrType, SOCK_DGRAM, 0);
95 OC_LOG_V(FATAL, MOD_NAME, "socket API ret val %d", sfd);
99 ifr.ifr_addr.sa_family = addrType;
101 strncpy(ifr.ifr_name, (const char*)ifName, ifNameLen);
103 if (ioctl(sfd, SIOCGIFADDR, &ifr) != 0) {
104 OC_LOG(FATAL, MOD_NAME, "ioctl call failed");
108 strncpy((char *)addr,
109 inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr),
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)
125 struct ifaddrs *myaddrs = NULL, *ifa = NULL;
126 int32_t ret = ERR_UNKNOWN;
128 VERIFY_NON_NULL(addr);
130 if (addrType != AF_INET) {
131 return ERR_INVALID_INPUT;
134 if(getifaddrs(&myaddrs) != 0) {
138 for (ifa = myaddrs; ifa != NULL; ifa = ifa->ifa_next) {
139 if (ifa->ifa_addr == NULL)
141 if (!(ifa->ifa_flags & IFF_UP))
143 if (!(ifa->ifa_flags & IFF_RUNNING))
146 if (ifName && ifa->ifa_name) {
147 if(strncmp((const char*)ifName, ifa->ifa_name, ifNameLen) != 0)
151 switch (ifa->ifa_addr->sa_family)
155 struct sockaddr_in *s4 = (struct sockaddr_in *)ifa->ifa_addr;
156 if(inet_ntop(AF_INET, &(s4->sin_addr), (char *)addr, addrLen))
168 freeifaddrs(myaddrs);
174 /// Creates a BSD socket and binds it specified port for UDP
175 int32_t OCInitUDP(OCDevAddr* ipAddr, int32_t *sockfd)
177 int32_t ret = ERR_UNKNOWN;
178 int32_t sfd = 0xFFFFFFFF;
179 int set_option_on = 1;
181 VERIFY_NON_NULL(ipAddr);
182 VERIFY_NON_NULL(sockfd);
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);
188 OC_LOG_V(FATAL, MOD_NAME, "socket API ret val %d", sfd);
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",
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));
208 if ((ret != ERR_SUCCESS) && (sfd >= 0)) {
212 OC_LOG_V(DEBUG, MOD_NAME, "%s End", __func__ );
218 /// Creates a BSD socket and binds the specified port for UDP multicast.
219 int32_t OCInitUDPMulticast(OCDevAddr* ipmcastaddr, int32_t* sockfd)
221 int32_t ret = ERR_UNKNOWN;
222 int32_t sfd = 0xFFFFFFFF;
224 int set_option_on = 1;
226 VERIFY_NON_NULL(ipmcastaddr);
227 VERIFY_NON_NULL(sockfd);
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);
233 OC_LOG_V(FATAL, MOD_NAME, "socket API ret val %d", sfd);
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));
244 // bind to multicast port
245 struct sockaddr_in sa;
246 struct sockaddr_in *sin;
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;
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));
259 // add membership to receiving socket
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));
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));
279 if (ret == ERR_SUCCESS) {
285 OC_LOG_V(DEBUG, MOD_NAME, "%s End", __func__ );
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,
297 VERIFY_NON_NULL(buf);
298 VERIFY_NON_NULL(ipAddr);
300 OC_LOG_V(DEBUG, MOD_NAME, "%s Begin", __func__ );
301 ret = sendto(sockfd, buf, bufLen, flags,
302 (struct sockaddr*)ipAddr->addr, ipAddr->size);
304 OC_LOG_V(DEBUG, MOD_NAME, "%s End", __func__ );
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,
315 VERIFY_NON_NULL(buf);
316 VERIFY_NON_NULL(ipAddr);
318 struct timeval timeout;
320 timeout.tv_usec = 5000;
323 OC_LOG_V(DEBUG, MOD_NAME, "%s Begin", __func__ );
326 FD_SET(sockfd, &reads);
327 ret = select(sockfd + 1, &reads, NULL, NULL, &timeout);
329 OC_LOG(FATAL, MOD_NAME, "select API failed");
332 if (!FD_ISSET(sockfd, &reads)) {
333 OC_LOG(DEBUG, MOD_NAME, "No data to read");
337 // Read available data.
338 ret = recvfrom(sockfd, buf, bufLen, flags,
339 (struct sockaddr*)ipAddr->addr, (socklen_t*)&(ipAddr->size));
341 OC_LOG(FATAL, MOD_NAME, "OCRecvFrom ERR");
343 OC_LOG_V(DEBUG, MOD_NAME, "%s End", __func__ );
348 /// Close the socket and release all system resources.
349 int32_t OCClose(int32_t sockfd)
351 return (close(sockfd));
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 )
359 struct sockaddr_in *sa;
362 if ( !ipAddr || !a || !b || !c || !d ) {
363 OC_LOG(FATAL, MOD_NAME, "Invalid argument");
364 return ERR_INVALID_INPUT;
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);
378 /// Retrieve the IPv4 address embedded inside OCDev address data structure
379 int32_t OCDevAddrToPort(OCDevAddr *ipAddr, uint16_t *port)
381 struct sockaddr_in *sa;
382 if ( !ipAddr || !port ) {
383 OC_LOG(FATAL, MOD_NAME, "Invalid argument");
384 return ERR_INVALID_INPUT;
387 sa = (struct sockaddr_in*)ipAddr->addr;
388 *port = ntohs(sa->sin_port);