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