Pārlūkot izejas kodu

components/coap: Add libcoap port for ESP32 platform

liuhan 9 gadi atpakaļ
vecāks
revīzija
d0b10ba2dd

+ 1 - 0
components/coap/Makefile.projbuild

@@ -0,0 +1 @@
+CFLAGS += -DWITH_POSIX

+ 9 - 0
components/coap/component.mk

@@ -0,0 +1,9 @@
+#
+# Component Makefile
+#
+
+COMPONENT_ADD_INCLUDEDIRS := port/include port/include/coap libcoap/include libcoap/include/coap
+
+COMPONENT_OBJS = libcoap/src/address.o libcoap/src/async.o libcoap/src/block.o libcoap/src/coap_time.o libcoap/src/debug.o libcoap/src/encode.o libcoap/src/hashkey.o libcoap/src/mem.o libcoap/src/net.o libcoap/src/option.o libcoap/src/pdu.o libcoap/src/resource.o libcoap/src/str.o libcoap/src/subscribe.o libcoap/src/uri.o port/coap_io_socket.o
+
+COMPONENT_SRCDIRS := libcoap/src libcoap port

+ 468 - 0
components/coap/port/coap_io_socket.c

@@ -0,0 +1,468 @@
+/*
+ * Network function implementation with socket for ESP32 platform.
+ *
+ * Uses libcoap software implementation for failover when concurrent
+ * network operations are in use.
+ *
+ * coap_io.h -- Default network I/O functions for libcoap
+ *
+ * Copyright (C) 2012,2014 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+ *
+ * This file is part of the CoAP library libcoap. Please see
+ * README for terms of use.
+ */
+
+#include "coap_config.h"
+
+#ifdef HAVE_STDIO_H
+#  include <stdio.h>
+#endif
+
+#ifdef HAVE_SYS_SELECT_H
+# include <sys/select.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+# include <sys/socket.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+#ifdef HAVE_SYS_UIO_H
+# include <sys/uio.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#include <errno.h>
+
+#ifdef WITH_CONTIKI
+# include "uip.h"
+#endif
+
+#include "pdu.h"
+#include "debug.h"
+#include "mem.h"
+#include "coap_io.h"
+
+#ifdef WITH_POSIX
+/* define generic PKTINFO for IPv4 */
+#if defined(IP_PKTINFO)
+#  define GEN_IP_PKTINFO IP_PKTINFO
+#elif defined(IP_RECVDSTADDR)
+#  define GEN_IP_PKTINFO IP_RECVDSTADDR
+#else
+#  error "Need IP_PKTINFO or IP_RECVDSTADDR to request ancillary data from OS."
+#endif /* IP_PKTINFO */
+
+/* define generic KTINFO for IPv6 */
+#ifdef IPV6_RECVPKTINFO
+#  define GEN_IPV6_PKTINFO IPV6_RECVPKTINFO
+#elif defined(IPV6_PKTINFO)
+#  define GEN_IPV6_PKTINFO IPV6_PKTINFO
+#else
+#  error "Need IPV6_PKTINFO or IPV6_RECVPKTINFO to request ancillary data from OS."
+#endif /* IPV6_RECVPKTINFO */
+
+struct coap_packet_t {
+  coap_if_handle_t hnd;	      /**< the interface handle */
+  coap_address_t src;	      /**< the packet's source address */
+  coap_address_t dst;	      /**< the packet's destination address */
+  const coap_endpoint_t *interface;
+
+  int ifindex;
+  void *session;		/**< opaque session data */
+
+  size_t length;		/**< length of payload */
+  unsigned char payload[];	/**< payload */
+};
+#endif
+
+#ifdef CUSTOM_COAP_NETWORK_ENDPOINT
+
+#ifdef WITH_CONTIKI
+static int ep_initialized = 0;
+
+static inline struct coap_endpoint_t *
+coap_malloc_contiki_endpoint() {
+  static struct coap_endpoint_t ep;
+
+  if (ep_initialized) {
+    return NULL;
+  } else {
+    ep_initialized = 1;
+    return &ep;
+  }
+}
+
+static inline void
+coap_free_contiki_endpoint(struct coap_endpoint_t *ep) {
+  ep_initialized = 0;
+}
+
+coap_endpoint_t *
+coap_new_endpoint(const coap_address_t *addr, int flags) {
+  struct coap_endpoint_t *ep = coap_malloc_contiki_endpoint();
+
+  if (ep) {
+    memset(ep, 0, sizeof(struct coap_endpoint_t));
+    ep->handle.conn = udp_new(NULL, 0, NULL);
+
+    if (!ep->handle.conn) {
+      coap_free_endpoint(ep);
+      return NULL;
+    }
+
+    coap_address_init(&ep->addr);
+    uip_ipaddr_copy(&ep->addr.addr, &addr->addr);
+    ep->addr.port = addr->port;
+    udp_bind((struct uip_udp_conn *)ep->handle.conn, addr->port);
+  }
+  return ep;
+}
+
+void
+coap_free_endpoint(coap_endpoint_t *ep) {
+  if (ep) {
+    if (ep->handle.conn) {
+      uip_udp_remove((struct uip_udp_conn *)ep->handle.conn);
+    }
+    coap_free_contiki_endpoint(ep);
+  }
+}
+
+#else /* WITH_CONTIKI */
+static inline struct coap_endpoint_t *
+coap_malloc_posix_endpoint(void) {
+  return (struct coap_endpoint_t *)coap_malloc(sizeof(struct coap_endpoint_t));
+}
+
+static inline void
+coap_free_posix_endpoint(struct coap_endpoint_t *ep) {
+  coap_free(ep);
+}
+
+coap_endpoint_t *
+coap_new_endpoint(const coap_address_t *addr, int flags) {
+  int sockfd = socket(addr->addr.sa.sa_family, SOCK_DGRAM, 0);
+  int on = 1;
+  struct coap_endpoint_t *ep;
+
+  if (sockfd < 0) {
+    coap_log(LOG_WARNING, "coap_new_endpoint: socket");
+    return NULL;
+  }
+
+  if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
+    coap_log(LOG_WARNING, "coap_new_endpoint: setsockopt SO_REUSEADDR");
+
+  if (bind(sockfd, &addr->addr.sa, addr->size) < 0) {
+    coap_log(LOG_WARNING, "coap_new_endpoint: bind");
+    close (sockfd);
+    return NULL;
+  }
+
+  ep = coap_malloc_posix_endpoint();
+  if (!ep) {
+    coap_log(LOG_WARNING, "coap_new_endpoint: malloc");
+    close(sockfd);
+    return NULL;
+  }
+
+  memset(ep, 0, sizeof(struct coap_endpoint_t));
+  ep->handle.fd = sockfd;
+  ep->flags = flags;
+
+  ep->addr.size = addr->size;
+  if (getsockname(sockfd, &ep->addr.addr.sa, &ep->addr.size) < 0) {
+    coap_log(LOG_WARNING, "coap_new_endpoint: cannot determine local address");
+    close (sockfd);
+    return NULL;
+  }
+
+#ifndef NDEBUG
+  if (LOG_DEBUG <= coap_get_log_level()) {
+#ifndef INET6_ADDRSTRLEN
+#define INET6_ADDRSTRLEN 40
+#endif
+    unsigned char addr_str[INET6_ADDRSTRLEN+8];
+
+    if (coap_print_addr(&ep->addr, addr_str, INET6_ADDRSTRLEN+8)) {
+      debug("created %sendpoint %s\n",
+	    ep->flags & COAP_ENDPOINT_DTLS ? "DTLS " : "",
+	    addr_str);
+    }
+  }
+#endif /* NDEBUG */
+
+  return (coap_endpoint_t *)ep;
+}
+
+void
+coap_free_endpoint(coap_endpoint_t *ep) {
+  if(ep) {
+    if (ep->handle.fd >= 0)
+      close(ep->handle.fd);
+    coap_free_posix_endpoint((struct coap_endpoint_t *)ep);
+  }
+}
+
+#endif /* WITH_CONTIKI */
+#endif /* CUSTOM_COAP_NETWORK_ENDPOINT */
+
+#ifdef CUSTOM_COAP_NETWORK_SEND
+
+#if defined(WITH_POSIX) != defined(HAVE_NETINET_IN_H)
+/* define struct in6_pktinfo and struct in_pktinfo if not available
+   FIXME: check with configure
+*/
+struct in6_pktinfo {
+  struct in6_addr ipi6_addr;	/* src/dst IPv6 address */
+  unsigned int ipi6_ifindex;	/* send/recv interface index */
+};
+
+struct in_pktinfo {
+  int ipi_ifindex;
+  struct in_addr ipi_spec_dst;
+  struct in_addr ipi_addr;
+};
+#endif
+
+#if defined(WITH_POSIX) && !defined(SOL_IP)
+/* Solaris expects level IPPROTO_IP for ancillary data. */
+#define SOL_IP IPPROTO_IP
+#endif
+
+#ifdef __GNUC__
+#define UNUSED_PARAM __attribute__ ((unused))
+#else /* not a GCC */
+#define UNUSED_PARAM
+#endif /* GCC */
+
+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) {
+
+  struct coap_endpoint_t *ep =
+    (struct coap_endpoint_t *)local_interface;
+
+#ifndef WITH_CONTIKI
+  return sendto(ep->handle.fd, data, datalen, 0, (struct sockaddr*)&dst->addr.sa, sizeof(struct sockaddr));
+#else /* WITH_CONTIKI */
+  /* FIXME: untested */
+  /* FIXME: is there a way to check if send was successful? */
+  uip_udp_packet_sendto((struct uip_udp_conn *)ep->handle.conn, data, datalen,
+			&dst->addr, dst->port);
+  return datalen;
+#endif /* WITH_CONTIKI */
+}
+
+#endif /* CUSTOM_COAP_NETWORK_SEND */
+
+#ifdef CUSTOM_COAP_NETWORK_READ
+
+#define SIN6(A) ((struct sockaddr_in6 *)(A))
+
+#ifdef WITH_POSIX
+static coap_packet_t *
+coap_malloc_packet(void) {
+  coap_packet_t *packet;
+  const size_t need = sizeof(coap_packet_t) + COAP_MAX_PDU_SIZE;
+
+  packet = (coap_packet_t *)coap_malloc(need);
+  if (packet) {
+    memset(packet, 0, need);
+  }
+  return packet;
+}
+
+void
+coap_free_packet(coap_packet_t *packet) {
+  coap_free(packet);
+}
+#endif /* WITH_POSIX */
+#ifdef WITH_CONTIKI
+static inline coap_packet_t *
+coap_malloc_packet(void) {
+  return (coap_packet_t *)coap_malloc_type(COAP_PACKET, 0);
+}
+
+void
+coap_free_packet(coap_packet_t *packet) {
+  coap_free_type(COAP_PACKET, packet);
+}
+#endif /* WITH_CONTIKI */
+
+static inline size_t
+coap_get_max_packetlength(const coap_packet_t *packet UNUSED_PARAM) {
+  return COAP_MAX_PDU_SIZE;
+}
+
+void
+coap_packet_populate_endpoint(coap_packet_t *packet, coap_endpoint_t *target)
+{
+  target->handle = packet->interface->handle;
+  memcpy(&target->addr, &packet->dst, sizeof(target->addr));
+  target->ifindex = packet->ifindex;
+  target->flags = 0; /* FIXME */
+}
+void
+coap_packet_copy_source(coap_packet_t *packet, coap_address_t *target)
+{
+  memcpy(target, &packet->src, sizeof(coap_address_t));
+}
+void
+coap_packet_get_memmapped(coap_packet_t *packet, unsigned char **address, size_t *length)
+{
+	*address = packet->payload;
+	*length = packet->length;
+}
+
+/**
+ * Checks if a message with destination address @p dst matches the
+ * local interface with address @p local. This function returns @c 1
+ * if @p dst is a valid match, and @c 0 otherwise.
+ */
+static inline int
+is_local_if(const coap_address_t *local, const coap_address_t *dst) {
+  return coap_address_isany(local) || coap_address_equals(dst, local) ||
+    coap_is_mcast(dst);
+}
+
+ssize_t
+coap_network_read(coap_endpoint_t *ep, coap_packet_t **packet) {
+  ssize_t len = -1;
+
+#ifdef WITH_POSIX
+  #define SOC_APPDATA_LEN 1460
+  char *soc_appdata = NULL;
+  struct sockaddr_in soc_srcipaddr;
+  socklen_t soc_srcsize = sizeof(struct sockaddr_in);
+#endif /* WITH_POSIX */
+
+  assert(ep);
+  assert(packet);
+
+  *packet = coap_malloc_packet();
+
+  if (!*packet) {
+    warn("coap_network_read: insufficient memory, drop packet\n");
+    return -1;
+  }
+
+  coap_address_init(&(*packet)->dst); /* the local interface address */
+  coap_address_init(&(*packet)->src); /* the remote peer */
+
+#ifdef WITH_POSIX
+  soc_appdata = coap_malloc(SOC_APPDATA_LEN);
+  if (soc_appdata){
+	  len = recvfrom(ep->handle.fd, soc_appdata, SOC_APPDATA_LEN, 0, (struct sockaddr *)&soc_srcipaddr, (socklen_t *)&soc_srcsize);
+
+	  if (len < 0){
+		  coap_log(LOG_WARNING, "coap_network_read: %s\n", strerror(errno));
+		  goto error;
+	  } else {
+		  /* use getsockname() to get the local port */
+	      (*packet)->dst.size = sizeof((*packet)->dst.addr);
+	      if (getsockname(ep->handle.fd, &(*packet)->dst.addr.sa, &(*packet)->dst.size) < 0) {
+	         coap_log(LOG_DEBUG, "cannot determine local port\n");
+	         goto error;
+	      }
+
+	      /* local interface for IPv4 */
+	      (*packet)->src.size = sizeof((*packet)->src.addr);
+	      memcpy(&(*packet)->src.addr.sa, &soc_srcipaddr, (*packet)->src.size);
+
+	      if (len > coap_get_max_packetlength(*packet)) {
+	         /* FIXME: we might want to send back a response */
+	         warn("discarded oversized packet\n");
+	         goto error;
+	      }
+
+	      if (!is_local_if(&ep->addr, &(*packet)->dst)) {
+	      	 coap_log(LOG_DEBUG, "packet received on wrong interface, dropped\n");
+	      	printf("error 3\n");
+	      	 goto error;
+	      }
+
+	      (*packet)->length = len;
+
+	      memcpy(&(*packet)->payload, soc_appdata, len);
+	  }
+
+	  coap_free(soc_appdata);
+	  soc_appdata = NULL;
+  } else {
+	  goto error;
+  }
+#endif /* WITH_POSIX */
+#ifdef WITH_CONTIKI
+  /* FIXME: untested, make this work */
+#define UIP_IP_BUF   ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN])
+#define UIP_UDP_BUF  ((struct uip_udp_hdr *)&uip_buf[UIP_LLIPH_LEN])
+
+  if(uip_newdata()) {
+    uip_ipaddr_copy(&(*packet)->src.addr, &UIP_IP_BUF->srcipaddr);
+    (*packet)->src.port = UIP_UDP_BUF->srcport;
+    uip_ipaddr_copy(&(*packet)->dst.addr, &UIP_IP_BUF->destipaddr);
+    (*packet)->dst.port = UIP_UDP_BUF->destport;
+
+    if (!is_local_if(&ep->addr, &(*packet)->dst)) {
+      coap_log(LOG_DEBUG, "packet received on wrong interface, dropped\n");
+      goto error;
+    }
+
+    len = uip_datalen();
+
+    if (len > coap_get_max_packetlength(*packet)) {
+      /* FIXME: we might want to send back a response */
+      warn("discarded oversized packet\n");
+      return -1;
+    }
+
+    ((char *)uip_appdata)[len] = 0;
+#ifndef NDEBUG
+    if (LOG_DEBUG <= coap_get_log_level()) {
+#ifndef INET6_ADDRSTRLEN
+#define INET6_ADDRSTRLEN 40
+#endif
+      unsigned char addr_str[INET6_ADDRSTRLEN+8];
+
+      if (coap_print_addr(&(*packet)->src, addr_str, INET6_ADDRSTRLEN+8)) {
+	debug("received %zd bytes from %s\n", len, addr_str);
+      }
+    }
+#endif /* NDEBUG */
+
+    (*packet)->length = len;
+    memcpy(&(*packet)->payload, uip_appdata, len);
+  }
+
+#undef UIP_IP_BUF
+#undef UIP_UDP_BUF
+#endif /* WITH_CONTIKI */
+#ifdef WITH_LWIP
+#error "coap_network_read() not implemented on this platform"
+#endif
+
+  (*packet)->interface = ep;
+
+  return len;
+ error:
+#ifdef WITH_POSIX
+ 	if (soc_appdata)
+ 		coap_free(soc_appdata);
+ 	soc_appdata = NULL;
+#endif
+  coap_free_packet(*packet);
+  *packet = NULL;
+  return -1;
+}
+
+#undef SIN6
+
+#endif /*  CUSTOM_COAP_NETWORK_READ */

+ 50 - 0
components/coap/port/include/coap/coap.h

@@ -0,0 +1,50 @@
+/* Modify head file implementation for ESP32 platform.
+ *
+ * Uses libcoap software implementation for failover when concurrent
+ * define operations are in use.
+ *
+ * coap.h -- main header file for CoAP stack of libcoap
+ *
+ * Copyright (C) 2010-2012,2015-2016 Olaf Bergmann <bergmann@tzi.org>
+ *               2015 Carsten Schoenert <c.schoenert@t-online.de>
+ *
+ * Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+ *
+ * This file is part of the CoAP library libcoap. Please see README for terms
+ * of use.
+ */
+
+#ifndef _COAP_H_
+#define _COAP_H_
+
+#include "libcoap.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "address.h"
+#include "async.h"
+#include "bits.h"
+#include "block.h"
+#include "coap_io.h"
+#include "coap_time.h"
+#include "debug.h"
+#include "encode.h"
+#include "mem.h"
+#include "net.h"
+#include "option.h"
+#include "pdu.h"
+#include "prng.h"
+#include "resource.h"
+#include "str.h"
+#include "subscribe.h"
+#include "uri.h"
+#include "uthash.h"
+#include "utlist.h"
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _COAP_H_ */

+ 39 - 0
components/coap/port/include/coap_config.h

@@ -0,0 +1,39 @@
+/*
+ * libcoap configure implementation for ESP32 platform.
+ *
+ * Uses libcoap software implementation for failover when concurrent
+ * configure operations are in use.
+ *
+ * coap.h -- main header file for CoAP stack of libcoap
+ *
+ * Copyright (C) 2010-2012,2015-2016 Olaf Bergmann <bergmann@tzi.org>
+ *               2015 Carsten Schoenert <c.schoenert@t-online.de>
+ *
+ * Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+ *
+ * This file is part of the CoAP library libcoap. Please see README for terms
+ * of use.
+ */
+
+#ifndef _CONFIG_H_
+#define _CONFIG_H_
+
+#ifdef WITH_POSIX
+#include "coap_config_posix.h"
+#endif
+
+#define HAVE_STDIO_H
+#define HAVE_ASSERT_H
+
+#define PACKAGE_STRING PACKAGE_NAME PACKAGE_VERSION
+
+/* it's just provided by libc. i hope we don't get too many of those, as
+ * actually we'd need autotools again to find out what environment we're
+ * building in */
+#define HAVE_STRNLEN 1
+
+#define HAVE_LIMITS_H
+
+#define COAP_RESOURCES_NOHASH
+
+#endif /* _CONFIG_H_ */

+ 41 - 0
components/coap/port/include/coap_config_posix.h

@@ -0,0 +1,41 @@
+/*
+ * libcoap configure implementation for ESP32 platform.
+ *
+ * Uses libcoap software implementation for failover when concurrent
+ * configure operations are in use.
+ *
+ * coap.h -- main header file for CoAP stack of libcoap
+ *
+ * Copyright (C) 2010-2012,2015-2016 Olaf Bergmann <bergmann@tzi.org>
+ *               2015 Carsten Schoenert <c.schoenert@t-online.de>
+ *
+ * Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+ *
+ * This file is part of the CoAP library libcoap. Please see README for terms
+ * of use.
+ */
+
+#ifndef COAP_CONFIG_POSIX_H_
+#define COAP_CONFIG_POSIX_H_
+
+#ifdef WITH_POSIX
+
+#include <sys/socket.h>
+
+#define HAVE_SYS_SOCKET_H
+#define HAVE_MALLOC
+#define HAVE_ARPA_INET_H
+
+#define IP_PKTINFO   IP_MULTICAST_IF
+#define IPV6_PKTINFO IPV6_V6ONLY
+
+#define PACKAGE_NAME "libcoap-posix"
+#define PACKAGE_VERSION "?"
+
+#define CUSTOM_COAP_NETWORK_ENDPOINT
+#define CUSTOM_COAP_NETWORK_SEND
+#define CUSTOM_COAP_NETWORK_READ
+
+#endif
+
+#endif /* COAP_CONFIG_POSIX_H_ */

+ 20 - 0
components/lwip/include/lwip/port/arpa/inet.h

@@ -0,0 +1,20 @@
+// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef INET_H_
+#define INET_H_
+
+#include "lwip/inet.h"
+
+#endif /* INET_H_ */

+ 22 - 0
components/lwip/include/lwip/port/netinet/in.h

@@ -0,0 +1,22 @@
+// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef IN_H_
+#define IN_H_
+
+#include "lwip/inet.h"
+
+#define IN6_IS_ADDR_MULTICAST(a)    IN_MULTICAST(a)
+
+#endif /* IN_H_ */

+ 0 - 3
components/nghttp/Makefile.projbuild

@@ -1,4 +1 @@
-# Anyone compiling mbedTLS code needs the name of the
-# alternative config file
-
 CFLAGS += -DHAVE_CONFIG_H