1 /* coap_io.h -- Default network I/O functions for libcoap
2  *
3  * Copyright (C) 2012,2014 Olaf Bergmann <bergmann@tzi.org>
4  *
5  * This file is part of the CoAP library libcoap. Please see
6  * README for terms of use.
7  */
8 
9 #include "coap_config.h"
10 
11 #ifdef HAVE_STDIO_H
12 #  include <stdio.h>
13 #endif
14 
15 #ifdef HAVE_SYS_SELECT_H
16 # include <sys/select.h>
17 #endif
18 #ifdef HAVE_SYS_SOCKET_H
19 # include <sys/socket.h>
20 #endif
21 #ifdef HAVE_NETINET_IN_H
22 # include <netinet/in.h>
23 #endif
24 #ifdef HAVE_SYS_UIO_H
25 # include <sys/uio.h>
26 #endif
27 #ifdef HAVE_UNISTD_H
28 # include <unistd.h>
29 #endif
30 #include <errno.h>
31 
32 #ifdef WITH_CONTIKI
33 # include "uip.h"
34 #endif
35 
36 #include "debug.h"
37 #include "mem.h"
38 #include "coap_io.h"
39 
40 #ifdef WITH_POSIX
41 struct coap_packet_t {
42   coap_if_handle_t hnd;	      /**< the interface handle */
43   coap_address_t src;	      /**< the packet's source address */
44   coap_address_t dst;	      /**< the packet's destination address */
45   const coap_endpoint_t *interface;
46 
47   int ifindex;
48   void *session;		/**< opaque session data */
49 
50   size_t length;		/**< length of payload */
51   unsigned char payload[];	/**< payload */
52 };
53 #endif
54 
55 #ifndef CUSTOM_COAP_NETWORK_ENDPOINT
56 
57 #ifdef WITH_CONTIKI
58 static int ep_initialized = 0;
59 
60 static inline struct coap_endpoint_t *
coap_malloc_contiki_endpoint()61 coap_malloc_contiki_endpoint() {
62   static struct coap_endpoint_t ep;
63 
64   if (ep_initialized) {
65     return NULL;
66   } else {
67     ep_initialized = 1;
68     return &ep;
69   }
70 }
71 
72 static inline void
coap_free_contiki_endpoint(struct coap_endpoint_t * ep)73 coap_free_contiki_endpoint(struct coap_endpoint_t *ep) {
74   ep_initialized = 0;
75 }
76 
77 coap_endpoint_t *
coap_new_endpoint(const coap_address_t * addr,int flags)78 coap_new_endpoint(const coap_address_t *addr, int flags) {
79   struct coap_endpoint_t *ep = coap_malloc_contiki_endpoint();
80 
81   if (ep) {
82     memset(ep, 0, sizeof(struct coap_endpoint_t));
83     ep->handle.conn = udp_new(NULL, 0, NULL);
84 
85     if (!ep->handle.conn) {
86       coap_free_endpoint(ep);
87       return NULL;
88     }
89 
90     coap_address_init(&ep->addr);
91     uip_ipaddr_copy(&ep->addr.addr, &addr->addr);
92     ep->addr.port = addr->port;
93     udp_bind((struct uip_udp_conn *)ep->handle.conn, addr->port);
94   }
95   return ep;
96 }
97 
98 void
coap_free_endpoint(coap_endpoint_t * ep)99 coap_free_endpoint(coap_endpoint_t *ep) {
100   if (ep) {
101     if (ep->handle.conn) {
102       uip_udp_remove((struct uip_udp_conn *)ep->handle.conn);
103     }
104     coap_free_contiki_endpoint(ep);
105   }
106 }
107 
108 #else /* WITH_CONTIKI */
109 static inline struct coap_endpoint_t *
coap_malloc_posix_endpoint(void)110 coap_malloc_posix_endpoint(void) {
111   return (struct coap_endpoint_t *)coap_malloc(sizeof(struct coap_endpoint_t));
112 }
113 
114 static inline void
coap_free_posix_endpoint(struct coap_endpoint_t * ep)115 coap_free_posix_endpoint(struct coap_endpoint_t *ep) {
116   coap_free(ep);
117 }
118 
119 coap_endpoint_t *
coap_new_endpoint(const coap_address_t * addr,int flags)120 coap_new_endpoint(const coap_address_t *addr, int flags) {
121   int sockfd = socket(addr->addr.sa.sa_family, SOCK_DGRAM, 0);
122   int on = 1;
123   struct coap_endpoint_t *ep;
124 
125   if (sockfd < 0) {
126     coap_log(LOG_WARNING, "coap_new_endpoint: socket");
127     return NULL;
128   }
129 
130   if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
131     coap_log(LOG_WARNING, "coap_new_endpoint: setsockopt SO_REUSEADDR");
132 
133   on = 1;
134   switch(addr->addr.sa.sa_family) {
135   case AF_INET:
136     if (setsockopt(sockfd, IPPROTO_IP, IP_PKTINFO, &on, sizeof(on)) < 0)
137       coap_log(LOG_ALERT, "coap_new_endpoint: setsockopt IP_PKTINFO\n");
138     break;
139   case AF_INET6:
140 #ifdef IPV6_RECVPKTINFO
141   if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on)) < 0)
142     coap_log(LOG_ALERT, "coap_new_endpoint: setsockopt IPV6_RECVPKTINFO\n");
143 #else /* IPV6_RECVPKTINFO */
144   if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_PKTINFO, &on, sizeof(on)) < 0)
145     coap_log(LOG_ALERT, "coap_new_endpoint: setsockopt IPV6_PKTINFO\n");
146 #endif /* IPV6_RECVPKTINFO */
147   break;
148   default:
149     coap_log(LOG_ALERT, "coap_new_endpoint: unsupported sa_family\n");
150   }
151 
152 #if 0
153   if (bind(sockfd, &addr->addr.sa, addr->size) < 0) {
154     coap_log(LOG_WARNING, "coap_new_endpoint: bind");
155     close (sockfd);
156     return NULL;
157   }
158 #endif
159 
160   ep = coap_malloc_posix_endpoint();
161   if (!ep) {
162     coap_log(LOG_WARNING, "coap_new_endpoint: malloc");
163     close(sockfd);
164     return NULL;
165   }
166 
167   memset(ep, 0, sizeof(struct coap_endpoint_t));
168   ep->handle.fd = sockfd;
169   ep->flags = flags;
170 
171   ep->addr.size = addr->size;
172   if (getsockname(sockfd, &ep->addr.addr.sa, &ep->addr.size) < 0) {
173     coap_log(LOG_WARNING, "coap_new_endpoint: cannot determine local address");
174     close (sockfd);
175     return NULL;
176   }
177 
178 #ifndef NDEBUG
179   if (LOG_DEBUG <= coap_get_log_level()) {
180 #ifndef INET6_ADDRSTRLEN
181 #define INET6_ADDRSTRLEN 40
182 #endif
183     unsigned char addr_str[INET6_ADDRSTRLEN+8];
184 
185     if (coap_print_addr(&ep->addr, addr_str, INET6_ADDRSTRLEN+8)) {
186       debug("created %sendpoint %s\n",
187 	    ep->flags & COAP_ENDPOINT_DTLS ? "DTLS " : "",
188 	    addr_str);
189     }
190   }
191 #endif /* NDEBUG */
192 
193   return (coap_endpoint_t *)ep;
194 }
195 
196 void
coap_free_endpoint(coap_endpoint_t * ep)197 coap_free_endpoint(coap_endpoint_t *ep) {
198   if(ep) {
199     if (ep->handle.fd >= 0)
200       close(ep->handle.fd);
201     coap_free_posix_endpoint((struct coap_endpoint_t *)ep);
202   }
203 }
204 
205 #endif /* WITH_CONTIKI */
206 #endif /* CUSTOM_COAP_NETWORK_ENDPOINT */
207 
208 #ifndef CUSTOM_COAP_NETWORK_SEND
209 
210 #if defined(WITH_POSIX) != defined(HAVE_NETINET_IN_H)
211 /* define struct in6_pktinfo and struct in_pktinfo if not available
212    FIXME: check with configure
213 */
214 struct in6_pktinfo {
215   struct in6_addr ipi6_addr;	/* src/dst IPv6 address */
216   unsigned int ipi6_ifindex;	/* send/recv interface index */
217 };
218 
219 struct in_pktinfo {
220   int ipi_ifindex;
221   struct in_addr ipi_spec_dst;
222   struct in_addr ipi_addr;
223 };
224 #endif
225 
226 #if defined(WITH_POSIX) && !defined(SOL_IP)
227 /* Solaris expects level IPPROTO_IP for ancillary data. */
228 #define SOL_IP IPPROTO_IP
229 #endif
230 
231 #ifdef __GNUC__
232 #define UNUSED_PARAM __attribute__ ((unused))
233 #else /* not a GCC */
234 #define UNUSED_PARAM
235 #endif /* GCC */
236 
237 ssize_t
coap_network_send(struct coap_context_t * context UNUSED_PARAM,const coap_endpoint_t * local_interface,const coap_address_t * dst,unsigned char * data,size_t datalen)238 coap_network_send(struct coap_context_t *context UNUSED_PARAM,
239 		  const coap_endpoint_t *local_interface,
240 		  const coap_address_t *dst,
241 		  unsigned char *data,
242 		  size_t datalen) {
243 
244   struct coap_endpoint_t *ep =
245     (struct coap_endpoint_t *)local_interface;
246 
247 #ifndef WITH_CONTIKI
248   /* a buffer large enough to hold all protocol address types */
249   char buf[CMSG_LEN(sizeof(struct sockaddr_storage))];
250   struct msghdr mhdr;
251   struct iovec iov[1];
252 
253   assert(local_interface);
254 
255   iov[0].iov_base = data;
256   iov[0].iov_len = datalen;
257 
258   memset(&mhdr, 0, sizeof(struct msghdr));
259   mhdr.msg_name = (void *)&dst->addr;
260   mhdr.msg_namelen = dst->size;
261 
262   mhdr.msg_iov = iov;
263   mhdr.msg_iovlen = 1;
264 
265   switch (dst->addr.sa.sa_family) {
266   case AF_INET6: {
267     struct cmsghdr *cmsg;
268     struct in6_pktinfo *pktinfo;
269 
270     mhdr.msg_control = buf;
271     mhdr.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
272 
273     cmsg = CMSG_FIRSTHDR(&mhdr);
274     cmsg->cmsg_level = IPPROTO_IPV6;
275     cmsg->cmsg_type = IPV6_PKTINFO;
276     cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
277 
278     pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsg);
279     memset(pktinfo, 0, sizeof(struct in6_pktinfo));
280 
281     pktinfo->ipi6_ifindex = ep->ifindex;
282     if (coap_is_mcast(&local_interface->addr)) {
283       /* We cannot send with multicast address as source address
284        * and hence let the kernel pick the outgoing interface. */
285       pktinfo->ipi6_ifindex = 0;
286       memset(&pktinfo->ipi6_addr, 0, sizeof(pktinfo->ipi6_addr));
287     } else {
288       pktinfo->ipi6_ifindex = ep->ifindex;
289       memcpy(&pktinfo->ipi6_addr,
290 	     &local_interface->addr.addr.sin6.sin6_addr,
291 	     local_interface->addr.size);
292     }
293     break;
294   }
295   case AF_INET: {
296     struct cmsghdr *cmsg;
297     struct in_pktinfo *pktinfo;
298 
299     mhdr.msg_control = buf;
300     mhdr.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
301 
302     cmsg = CMSG_FIRSTHDR(&mhdr);
303     cmsg->cmsg_level = SOL_IP;
304     cmsg->cmsg_type = IP_PKTINFO;
305     cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
306 
307     pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg);
308     memset(pktinfo, 0, sizeof(struct in_pktinfo));
309 
310     if (coap_is_mcast(&local_interface->addr)) {
311       /* We cannot send with multicast address as source address
312        * and hence let the kernel pick the outgoing interface. */
313       pktinfo->ipi_ifindex = 0;
314       memset(&pktinfo->ipi_spec_dst, 0, sizeof(pktinfo->ipi_spec_dst));
315     } else {
316       pktinfo->ipi_ifindex = ep->ifindex;
317       memcpy(&pktinfo->ipi_spec_dst,
318 	     &local_interface->addr.addr.sin.sin_addr,
319 	     local_interface->addr.size);
320     }
321     break;
322   }
323   default:
324     /* error */
325     coap_log(LOG_WARNING, "protocol not supported\n");
326     return -1;
327   }
328 
329   return sendmsg(ep->handle.fd, &mhdr, 0);
330 #else /* WITH_CONTIKI */
331   /* FIXME: untested */
332   /* FIXME: is there a way to check if send was successful? */
333   uip_udp_packet_sendto((struct uip_udp_conn *)ep->handle.conn, data, datalen,
334 			&dst->addr, dst->port);
335   return datalen;
336 #endif /* WITH_CONTIKI */
337 }
338 
339 #endif /* CUSTOM_COAP_NETWORK_SEND */
340 
341 #ifndef CUSTOM_COAP_NETWORK_READ
342 
343 #define SIN6(A) ((struct sockaddr_in6 *)(A))
344 
345 #ifdef WITH_POSIX
346 static coap_packet_t *
coap_malloc_packet(void)347 coap_malloc_packet(void) {
348   coap_packet_t *packet;
349   const size_t need = sizeof(coap_packet_t) + COAP_MAX_PDU_SIZE;
350 
351   packet = (coap_packet_t *)coap_malloc(need);
352   if (packet) {
353     memset(packet, 0, need);
354   }
355   return packet;
356 }
357 
358 void
coap_free_packet(coap_packet_t * packet)359 coap_free_packet(coap_packet_t *packet) {
360   coap_free(packet);
361 }
362 #endif /* WITH_POSIX */
363 #ifdef WITH_CONTIKI
364 static inline coap_packet_t *
coap_malloc_packet(void)365 coap_malloc_packet(void) {
366   return (coap_packet_t *)coap_malloc_type(COAP_PACKET, 0);
367 }
368 
369 void
coap_free_packet(coap_packet_t * packet)370 coap_free_packet(coap_packet_t *packet) {
371   coap_free_type(COAP_PACKET, packet);
372 }
373 #endif /* WITH_CONTIKI */
374 
375 static inline size_t
coap_get_max_packetlength(const coap_packet_t * packet UNUSED_PARAM)376 coap_get_max_packetlength(const coap_packet_t *packet UNUSED_PARAM) {
377   return COAP_MAX_PDU_SIZE;
378 }
379 
380 void
coap_packet_populate_endpoint(coap_packet_t * packet,coap_endpoint_t * target)381 coap_packet_populate_endpoint(coap_packet_t *packet, coap_endpoint_t *target)
382 {
383   target->handle = packet->interface->handle;
384   memcpy(&target->addr, &packet->dst, sizeof(target->addr));
385   target->ifindex = packet->ifindex;
386   target->flags = 0; /* FIXME */
387 }
388 void
coap_packet_copy_source(coap_packet_t * packet,coap_address_t * target)389 coap_packet_copy_source(coap_packet_t *packet, coap_address_t *target)
390 {
391   memcpy(target, &packet->src, sizeof(coap_address_t));
392 }
393 void
coap_packet_get_memmapped(coap_packet_t * packet,unsigned char ** address,size_t * length)394 coap_packet_get_memmapped(coap_packet_t *packet, unsigned char **address, size_t *length)
395 {
396 	*address = packet->payload;
397 	*length = packet->length;
398 }
399 
400 /**
401  * Checks if a message with destination address @p dst matches the
402  * local interface with address @p local. This function returns @c 1
403  * if @p dst is a valid match, and @c 0 otherwise.
404  */
405 static inline int
is_local_if(const coap_address_t * local,const coap_address_t * dst)406 is_local_if(const coap_address_t *local, const coap_address_t *dst) {
407   return coap_address_isany(local) || coap_address_equals(dst, local) ||
408     coap_is_mcast(dst);
409 }
410 
411 ssize_t
coap_network_read(coap_endpoint_t * ep,coap_packet_t ** packet)412 coap_network_read(coap_endpoint_t *ep, coap_packet_t **packet) {
413   ssize_t len = -1;
414 
415 #ifdef WITH_POSIX
416   char msg_control[CMSG_LEN(sizeof(struct sockaddr_storage))];
417   struct msghdr mhdr;
418   struct iovec iov[1];
419 #endif /* WITH_POSIX */
420 
421   assert(ep);
422   assert(packet);
423 
424   *packet = coap_malloc_packet();
425 
426   if (!*packet) {
427     warn("coap_network_read: insufficient memory, drop packet\n");
428     return -1;
429   }
430 
431   coap_address_init(&(*packet)->dst); /* the local interface address */
432   coap_address_init(&(*packet)->src); /* the remote peer */
433 
434 #ifdef WITH_POSIX
435   iov[0].iov_base = (*packet)->payload;
436   iov[0].iov_len = coap_get_max_packetlength(*packet);
437 
438   memset(&mhdr, 0, sizeof(struct msghdr));
439 
440   mhdr.msg_name = &(*packet)->src.addr.st;
441   mhdr.msg_namelen = sizeof((*packet)->src.addr.st);
442 
443   mhdr.msg_iov = iov;
444   mhdr.msg_iovlen = 1;
445 
446   mhdr.msg_control = msg_control;
447   mhdr.msg_controllen = sizeof(msg_control);
448   assert(sizeof(msg_control) == CMSG_LEN(sizeof(struct sockaddr_storage)));
449 
450   len = recvmsg(ep->handle.fd, &mhdr, 0);
451 
452   if (len < 0) {
453     coap_log(LOG_WARNING, "coap_network_read: %s\n", strerror(errno));
454     goto error;
455   } else {
456     struct cmsghdr *cmsg;
457 
458     coap_log(LOG_DEBUG, "received %d bytes on fd %d\n", (int)len, ep->handle.fd);
459 
460     /* use getsockname() to get the local port */
461     (*packet)->dst.size = sizeof((*packet)->dst.addr);
462     if (getsockname(ep->handle.fd, &(*packet)->dst.addr.sa, &(*packet)->dst.size) < 0) {
463       coap_log(LOG_DEBUG, "cannot determine local port\n");
464       goto error;
465     }
466 
467     (*packet)->length = len;
468 
469     /* Walk through ancillary data records until the local interface
470      * is found where the data was received. */
471     for (cmsg = CMSG_FIRSTHDR(&mhdr); cmsg; cmsg = CMSG_NXTHDR(&mhdr, cmsg)) {
472 
473       /* get the local interface for IPv6 */
474       if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) {
475 	union {
476 	  unsigned char *c;
477 	  struct in6_pktinfo *p;
478 	} u;
479 	u.c = CMSG_DATA(cmsg);
480 	(*packet)->ifindex = (int)(u.p->ipi6_ifindex);
481 
482 	memcpy(&(*packet)->dst.addr.sin6.sin6_addr,
483 	       &u.p->ipi6_addr, sizeof(struct in6_addr));
484 
485 	(*packet)->src.size = mhdr.msg_namelen;
486 	assert((*packet)->src.size == sizeof(struct sockaddr_in6));
487 
488 	(*packet)->src.addr.sin6.sin6_family = SIN6(mhdr.msg_name)->sin6_family;
489 	(*packet)->src.addr.sin6.sin6_addr = SIN6(mhdr.msg_name)->sin6_addr;
490 	(*packet)->src.addr.sin6.sin6_port = SIN6(mhdr.msg_name)->sin6_port;
491 
492 	break;
493       }
494 
495       /* local interface for IPv4 */
496       if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_PKTINFO) {
497 	union {
498 	  unsigned char *c;
499 	  struct in_pktinfo *p;
500 	} u;
501 
502 	u.c = CMSG_DATA(cmsg);
503 	(*packet)->ifindex = u.p->ipi_ifindex;
504 
505 	memcpy(&(*packet)->dst.addr.sin.sin_addr,
506 	       &u.p->ipi_addr, sizeof(struct in_addr));
507 
508 	(*packet)->src.size = mhdr.msg_namelen;
509 	memcpy(&(*packet)->src.addr.st, mhdr.msg_name, (*packet)->src.size);
510 
511 	break;
512       }
513     }
514 
515     if (!is_local_if(&ep->addr, &(*packet)->dst)) {
516       coap_log(LOG_DEBUG, "packet received on wrong interface, dropped\n");
517       goto error;
518     }
519   }
520 #endif /* WITH_POSIX */
521 #ifdef WITH_CONTIKI
522   /* FIXME: untested, make this work */
523 #define UIP_IP_BUF   ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN])
524 #define UIP_UDP_BUF  ((struct uip_udp_hdr *)&uip_buf[UIP_LLIPH_LEN])
525 
526   if(uip_newdata()) {
527     uip_ipaddr_copy(&(*packet)->src.addr, &UIP_IP_BUF->srcipaddr);
528     (*packet)->src.port = UIP_UDP_BUF->srcport;
529     uip_ipaddr_copy(&(*packet)->dst.addr, &UIP_IP_BUF->destipaddr);
530     (*packet)->dst.port = UIP_UDP_BUF->destport;
531 
532     if (!is_local_if(&ep->addr, &(*packet)->dst)) {
533       coap_log(LOG_DEBUG, "packet received on wrong interface, dropped\n");
534       goto error;
535     }
536 
537     len = uip_datalen();
538 
539     if (len > coap_get_max_packetlength(*packet)) {
540       /* FIXME: we might want to send back a response */
541       warn("discarded oversized packet\n");
542       return -1;
543     }
544 
545     ((char *)uip_appdata)[len] = 0;
546 #ifndef NDEBUG
547     if (LOG_DEBUG <= coap_get_log_level()) {
548 #ifndef INET6_ADDRSTRLEN
549 #define INET6_ADDRSTRLEN 40
550 #endif
551       unsigned char addr_str[INET6_ADDRSTRLEN+8];
552 
553       if (coap_print_addr(&(*packet)->src, addr_str, INET6_ADDRSTRLEN+8)) {
554 	debug("received %zd bytes from %s\n", len, addr_str);
555       }
556     }
557 #endif /* NDEBUG */
558 
559     (*packet)->length = len;
560     memcpy(&(*packet)->payload, uip_appdata, len);
561   }
562 
563 #undef UIP_IP_BUF
564 #undef UIP_UDP_BUF
565 #endif /* WITH_CONTIKI */
566 #ifdef WITH_LWIP
567 #error "coap_network_read() not implemented on this platform"
568 #endif
569 
570   (*packet)->interface = ep;
571 
572   return len;
573  error:
574   coap_free_packet(*packet);
575   *packet = NULL;
576   return -1;
577 }
578 
579 #undef SIN6
580 
581 #endif /*  CUSTOM_COAP_NETWORK_READ */
582