1 //******************************************************************
3 // Copyright 2014 Intel Corporation All Rights Reserved.
4 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
7 #include <sys/socket.h>
8 #include <sys/select.h>
10 #include <netinet/in.h>
21 #include <sys/ioctl.h>
24 #include <linux/if_link.h>
31 #define MOD_NAME ("ocsocket")
33 /// Macro to verify the validity of input argument
34 #define VERIFY_NON_NULL(arg) { if (!arg) {OC_LOG(FATAL, MOD_NAME, #arg " is NULL"); return ERR_INVALID_INPUT;} }
36 /// Builds a socket interface address using IP address and port number
37 int32_t OCBuildIPv4Address(uint8_t a, uint8_t b, uint8_t c, uint8_t d, uint16_t port, OCDevAddr *ipAddr)
39 struct sockaddr_in *sa;
42 VERIFY_NON_NULL(ipAddr);
43 memset(ipAddr, 0, sizeof(OCDevAddr));
52 ipAddr->size = sizeof(struct sockaddr_in);
53 sa = (struct sockaddr_in*)ipAddr->addr;
54 sa->sin_family = AF_INET;
55 sa->sin_addr.s_addr = htonl(ip);
56 sa->sin_port = htons(port);
62 /// Retrieves the IP address assigned to specified wireless interface
63 int32_t OCGetInterfaceAddress(uint8_t* ifName, uint32_t ifNameLen, uint16_t addrType,
64 uint8_t *addr, uint32_t addrLen)
66 int32_t ret = ERR_UNKNOWN;
67 int32_t sfd = 0xFFFFFFFF;
70 VERIFY_NON_NULL(addr);
71 VERIFY_NON_NULL(ifName);
72 if (ifNameLen > (IFNAMSIZ - 1) ) {
73 return ERR_INVALID_INPUT;
75 if (addrType != AF_INET) {
76 return ERR_INVALID_INPUT;
79 sfd = socket(addrType, SOCK_DGRAM, 0);
81 OC_LOG_V(FATAL, MOD_NAME, "socket API ret val %d", sfd);
85 ifr.ifr_addr.sa_family = addrType;
87 strncpy(ifr.ifr_name, (const char*)ifName, ifNameLen);
89 if (ioctl(sfd, SIOCGIFADDR, &ifr) != 0) {
90 OC_LOG(FATAL, MOD_NAME, "ioctl call failed");
95 inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr),
107 /// Retrieves the IP address assigned to specified wireless interface
108 int32_t OCGetInterfaceAddress(uint8_t* ifName, uint32_t ifNameLen, uint16_t addrType,
109 uint8_t *addr, uint32_t addrLen)
111 struct ifaddrs *myaddrs = NULL, *ifa = NULL;
112 int32_t ret = ERR_UNKNOWN;
114 VERIFY_NON_NULL(addr);
116 if (addrType != AF_INET) {
117 return ERR_INVALID_INPUT;
120 if(getifaddrs(&myaddrs) != 0) {
124 for (ifa = myaddrs; ifa != NULL; ifa = ifa->ifa_next) {
125 if (ifa->ifa_addr == NULL)
127 if (!(ifa->ifa_flags & IFF_UP))
129 if (!(ifa->ifa_flags & IFF_RUNNING))
132 if (ifName && ifa->ifa_name) {
133 if(strncmp((const char*)ifName, ifa->ifa_name, ifNameLen) != 0)
137 switch (ifa->ifa_addr->sa_family)
141 struct sockaddr_in *s4 = (struct sockaddr_in *)ifa->ifa_addr;
142 if(inet_ntop(AF_INET, &(s4->sin_addr), (char *)addr, addrLen))
154 freeifaddrs(myaddrs);
160 /// Creates a BSD socket and binds it specified port for UDP
161 int32_t OCInitUDP(OCDevAddr* ipAddr, int32_t *sockfd)
163 int32_t ret = ERR_UNKNOWN;
164 int32_t sfd = 0xFFFFFFFF;
165 int set_option_on = 1;
167 VERIFY_NON_NULL(ipAddr);
168 VERIFY_NON_NULL(sockfd);
170 OC_LOG_V(DEBUG, MOD_NAME, "%s Begin", __func__ );
171 //Create a datagram socket on which to recv/send.
172 sfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
174 OC_LOG_V(FATAL, MOD_NAME, "socket API ret val %d", sfd);
178 if ((ret = setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (char*) &set_option_on,
179 sizeof(set_option_on))) < 0) {
180 OC_LOG(FATAL, MOD_NAME, "setsockopt API failed");
184 if (bind(sfd, (struct sockaddr*)ipAddr->addr, ipAddr->size) < 0) {
185 OC_LOG_V(FATAL, MOD_NAME, "bind API failed with errno %s", strerror(errno));
192 if ((ret != ERR_SUCCESS) && (sfd >= 0)) {
198 OC_LOG_V(DEBUG, MOD_NAME, "%s End", __func__ );
204 /// Creates a BSD socket and binds the specified port for UDP multicast.
205 int32_t OCInitUDPMulticast(OCDevAddr* ipmcastaddr, int32_t* sockfd)
207 int32_t ret = ERR_UNKNOWN;
208 int32_t sfd = 0xFFFFFFFF;
210 int set_option_on = 1;
212 VERIFY_NON_NULL(ipmcastaddr);
213 VERIFY_NON_NULL(sockfd);
215 OC_LOG_V(DEBUG, MOD_NAME, "%s Begin", __func__ );
216 //Create a datagram socket on which to recv/send.
217 sfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
219 OC_LOG_V(FATAL, MOD_NAME, "socket API ret val %d", sfd);
224 if ((ret = setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (char*) &set_option_on,
225 sizeof(set_option_on))) < 0) {
226 OC_LOG_V(FATAL, MOD_NAME, "setsockopt API for SO_REUSEADDR failed with errno %s", strerror(errno));
230 // bind to multicast port
231 struct sockaddr_in sa;
232 struct sockaddr_in *sin;
234 sin = (struct sockaddr_in *)(ipmcastaddr->addr);
235 memset(&sa, 0, sizeof(sa));
236 sa.sin_family = AF_INET;
237 sa.sin_addr.s_addr = INADDR_ANY;
238 sa.sin_port = sin->sin_port;
240 if ((ret = bind(sfd, (struct sockaddr*)&sa, sizeof(sa))) < 0) {
241 OC_LOG_V(FATAL, MOD_NAME, "bind API failed with errno %s", strerror(errno));
245 // add membership to receiving socket
247 memset(&mreq, 0, sizeof(struct ip_mreq));
248 mreq.imr_interface.s_addr = htonl(INADDR_ANY);
249 mreq.imr_multiaddr.s_addr = sin->sin_addr.s_addr;
250 if ((ret = setsockopt(sfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreq, sizeof(mreq))) < 0) {
251 OC_LOG_V(FATAL, MOD_NAME, "setsockopt API for IP_ADD_MEMBERSHIP failed with errno %s", strerror(errno));
255 //Enable loopback so we can receive our own datagrams.
256 if ((ret = setsockopt(sfd, IPPROTO_IP, IP_MULTICAST_LOOP,
257 (char *)&loopch, sizeof(loopch))) < 0) {
258 OC_LOG_V(FATAL, MOD_NAME, "setsockopt API for IP_MULTICAST_LOOP failed with errno %s", strerror(errno));
265 if (ret == ERR_SUCCESS) {
271 OC_LOG_V(DEBUG, MOD_NAME, "%s End", __func__ );
277 /// Send data to requested end-point using UDP socket
278 int32_t OCSendTo(int32_t sockfd, const uint8_t* buf, uint32_t bufLen, uint32_t flags,
283 VERIFY_NON_NULL(buf);
284 VERIFY_NON_NULL(ipAddr);
286 OC_LOG_V(DEBUG, MOD_NAME, "%s Begin", __func__ );
287 ret = sendto(sockfd, buf, bufLen, flags,
288 (struct sockaddr*)ipAddr->addr, ipAddr->size);
290 OC_LOG_V(DEBUG, MOD_NAME, "%s End", __func__ );
295 /// Retrieve any available data from UDP socket. This is a non-blocking call.
296 int32_t OCRecvFrom(int32_t sockfd, uint8_t* buf, uint32_t bufLen, uint32_t flags,
301 VERIFY_NON_NULL(buf);
302 VERIFY_NON_NULL(ipAddr);
304 struct timeval timeout;
306 timeout.tv_usec = 5000;
309 OC_LOG_V(DEBUG, MOD_NAME, "%s Begin", __func__ );
312 FD_SET(sockfd, &reads);
313 ret = select(sockfd + 1, &reads, NULL, NULL, &timeout);
315 OC_LOG(FATAL, MOD_NAME, "select API failed");
318 if (!FD_ISSET(sockfd, &reads)) {
319 OC_LOG(DEBUG, MOD_NAME, "No data to read");
323 // Read available data.
324 ret = recvfrom(sockfd, buf, bufLen, flags,
325 (struct sockaddr*)ipAddr->addr, (socklen_t*)&(ipAddr->size));
327 OC_LOG(FATAL, MOD_NAME, "OCRecvFrom ERR");
329 OC_LOG_V(DEBUG, MOD_NAME, "%s End", __func__ );
334 /// Close the socket and release all system resources.
335 int32_t OCClose(int32_t sockfd)
337 return (close(sockfd));
341 /// Retrieve the IPv4 address embedded inside OCDev address data structure
342 int32_t OCDevAddrToIPv4Addr(OCDevAddr *ipAddr, uint8_t *a, uint8_t *b,
343 uint8_t *c, uint8_t *d )
345 struct sockaddr_in *sa;
348 if ( !ipAddr || !a || !b || !c || !d ) {
349 OC_LOG(FATAL, MOD_NAME, "Invalid argument");
350 return ERR_INVALID_INPUT;
353 sa = (struct sockaddr_in*)ipAddr->addr;
354 ip = ntohl(sa->sin_addr.s_addr);
355 *d = *((uint8_t*)&ip + 0);
356 *c = *((uint8_t*)&ip + 1);
357 *b = *((uint8_t*)&ip + 2);
358 *a = *((uint8_t*)&ip + 3);
364 /// Retrieve the IPv4 address embedded inside OCDev address data structure
365 int32_t OCDevAddrToPort(OCDevAddr *ipAddr, uint16_t *port)
367 struct sockaddr_in *sa;
368 if ( !ipAddr || !port ) {
369 OC_LOG(FATAL, MOD_NAME, "Invalid argument");
370 return ERR_INVALID_INPUT;
373 sa = (struct sockaddr_in*)ipAddr->addr;
374 *port = ntohs(sa->sin_port);