From 2b41c1b8b26e144523812b84daf3e7706f9798e7 Mon Sep 17 00:00:00 2001 From: liuhan Date: Sat, 24 Dec 2016 12:58:37 +0800 Subject: [PATCH 1/4] components/coap: Add libcoap library as submodule --- .gitmodules | 3 +++ components/coap/libcoap | 1 + 2 files changed, 4 insertions(+) create mode 160000 components/coap/libcoap diff --git a/.gitmodules b/.gitmodules index c26f92e80..9cba0ec5e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,3 +10,6 @@ [submodule "components/micro-ecc/micro-ecc"] path = components/micro-ecc/micro-ecc url = https://github.com/kmackay/micro-ecc.git +[submodule "components/coap/libcoap"] + path = components/coap/libcoap + url = https://github.com/obgm/libcoap.git diff --git a/components/coap/libcoap b/components/coap/libcoap new file mode 160000 index 000000000..6468887a1 --- /dev/null +++ b/components/coap/libcoap @@ -0,0 +1 @@ +Subproject commit 6468887a12666f88b8704d797fc176cd4f40ee4c From d0b10ba2dd30ee5fbd3343778b8e77859f621aee Mon Sep 17 00:00:00 2001 From: liuhan Date: Sat, 24 Dec 2016 14:43:53 +0800 Subject: [PATCH 2/4] components/coap: Add libcoap port for ESP32 platform --- components/coap/Makefile.projbuild | 1 + components/coap/component.mk | 9 + components/coap/port/coap_io_socket.c | 468 ++++++++++++++++++ components/coap/port/include/coap/coap.h | 50 ++ components/coap/port/include/coap_config.h | 39 ++ .../coap/port/include/coap_config_posix.h | 41 ++ components/lwip/include/lwip/port/arpa/inet.h | 20 + .../lwip/include/lwip/port/netinet/in.h | 22 + components/nghttp/Makefile.projbuild | 3 - 9 files changed, 650 insertions(+), 3 deletions(-) create mode 100644 components/coap/Makefile.projbuild create mode 100644 components/coap/component.mk create mode 100644 components/coap/port/coap_io_socket.c create mode 100644 components/coap/port/include/coap/coap.h create mode 100644 components/coap/port/include/coap_config.h create mode 100644 components/coap/port/include/coap_config_posix.h create mode 100644 components/lwip/include/lwip/port/arpa/inet.h create mode 100644 components/lwip/include/lwip/port/netinet/in.h diff --git a/components/coap/Makefile.projbuild b/components/coap/Makefile.projbuild new file mode 100644 index 000000000..e976ee32f --- /dev/null +++ b/components/coap/Makefile.projbuild @@ -0,0 +1 @@ +CFLAGS += -DWITH_POSIX diff --git a/components/coap/component.mk b/components/coap/component.mk new file mode 100644 index 000000000..b5f6ec43c --- /dev/null +++ b/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 diff --git a/components/coap/port/coap_io_socket.c b/components/coap/port/coap_io_socket.c new file mode 100644 index 000000000..eec8cc131 --- /dev/null +++ b/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 + * + * 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 +#endif + +#ifdef HAVE_SYS_SELECT_H +# include +#endif +#ifdef HAVE_SYS_SOCKET_H +# include +#endif +#ifdef HAVE_NETINET_IN_H +# include +#endif +#ifdef HAVE_SYS_UIO_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif +#include + +#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 */ diff --git a/components/coap/port/include/coap/coap.h b/components/coap/port/include/coap/coap.h new file mode 100644 index 000000000..cbdc9dfc8 --- /dev/null +++ b/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 + * 2015 Carsten Schoenert + * + * 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_ */ diff --git a/components/coap/port/include/coap_config.h b/components/coap/port/include/coap_config.h new file mode 100644 index 000000000..db314f2de --- /dev/null +++ b/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 + * 2015 Carsten Schoenert + * + * 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_ */ diff --git a/components/coap/port/include/coap_config_posix.h b/components/coap/port/include/coap_config_posix.h new file mode 100644 index 000000000..a77e97f07 --- /dev/null +++ b/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 + * 2015 Carsten Schoenert + * + * 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 + +#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_ */ diff --git a/components/lwip/include/lwip/port/arpa/inet.h b/components/lwip/include/lwip/port/arpa/inet.h new file mode 100644 index 000000000..94c6c17ed --- /dev/null +++ b/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_ */ diff --git a/components/lwip/include/lwip/port/netinet/in.h b/components/lwip/include/lwip/port/netinet/in.h new file mode 100644 index 000000000..7eaec6334 --- /dev/null +++ b/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_ */ diff --git a/components/nghttp/Makefile.projbuild b/components/nghttp/Makefile.projbuild index a93010ade..5c6ce7fc9 100644 --- a/components/nghttp/Makefile.projbuild +++ b/components/nghttp/Makefile.projbuild @@ -1,4 +1 @@ -# Anyone compiling mbedTLS code needs the name of the -# alternative config file - CFLAGS += -DHAVE_CONFIG_H From 899f61f4a2496bb261e388a28b7d3d6e232b2832 Mon Sep 17 00:00:00 2001 From: Liu Han Date: Sat, 10 Dec 2016 13:48:38 +0800 Subject: [PATCH 3/4] examples: Add CoAP server demo Test CoAP protocol server --- examples/24_coap_server/Makefile | 9 + .../24_coap_server/main/Kconfig.projbuild | 22 ++ examples/24_coap_server/main/coap_server.c | 190 ++++++++++++++++++ examples/24_coap_server/main/coap_server.h | 38 ++++ examples/24_coap_server/main/component.mk | 5 + 5 files changed, 264 insertions(+) create mode 100644 examples/24_coap_server/Makefile create mode 100644 examples/24_coap_server/main/Kconfig.projbuild create mode 100644 examples/24_coap_server/main/coap_server.c create mode 100644 examples/24_coap_server/main/coap_server.h create mode 100644 examples/24_coap_server/main/component.mk diff --git a/examples/24_coap_server/Makefile b/examples/24_coap_server/Makefile new file mode 100644 index 000000000..f82e5fc27 --- /dev/null +++ b/examples/24_coap_server/Makefile @@ -0,0 +1,9 @@ +# +# This is a project Makefile. It is assumed the directory this Makefile resides in is a +# project subdirectory. +# + +PROJECT_NAME := coap_server + +include $(IDF_PATH)/make/project.mk + diff --git a/examples/24_coap_server/main/Kconfig.projbuild b/examples/24_coap_server/main/Kconfig.projbuild new file mode 100644 index 000000000..4926bfb20 --- /dev/null +++ b/examples/24_coap_server/main/Kconfig.projbuild @@ -0,0 +1,22 @@ +menu "Example Configuration" + +config LOCAL_PORT_NUMBER + int "Local port number" + range 0 65535 + default 5683 + help + Local port number for the example to use. + +config WIFI_SSID + string "WiFi SSID" + default "myssid" + help + SSID (network name) for the example to connect to. + +config WIFI_PASSWORD + string "WiFi Password" + default "mypassword" + help + WiFi password (WPA or WPA2) for the example to use. + +endmenu \ No newline at end of file diff --git a/examples/24_coap_server/main/coap_server.c b/examples/24_coap_server/main/coap_server.c new file mode 100644 index 000000000..4e066689b --- /dev/null +++ b/examples/24_coap_server/main/coap_server.c @@ -0,0 +1,190 @@ +/* CoAP server Example + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ +#include "coap_server.h" + +#include + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/event_groups.h" + +#include "esp_log.h" +#include "esp_wifi.h" +#include "esp_event_loop.h" + +#include "nvs_flash.h" +#include + +#include "coap_config.h" +#include "resource.h" +#include "coap.h" + + +static EventGroupHandle_t wifi_event_group; + +/* The event group allows multiple bits for each event, + but we only care about one event - are we connected + to the AP with an IP? */ +const static int CONNECTED_BIT = BIT0; + +const static char *TAG = "CoAP_demo"; + +static coap_async_state_t *async = NULL; + +static void +send_async_response(coap_context_t *ctx, const coap_endpoint_t *local_if) +{ + coap_pdu_t *response; + unsigned char buf[3]; + const char* response_data = "Hello World!"; + size_t size = sizeof(coap_hdr_t) + 20; + response = coap_pdu_init(async->flags & COAP_MESSAGE_CON, COAP_RESPONSE_CODE(205), 0, size); + response->hdr->id = coap_new_message_id(ctx); + if (async->tokenlen) + coap_add_token(response, async->tokenlen, async->token); + coap_add_option(response, COAP_OPTION_CONTENT_TYPE, coap_encode_var_bytes(buf, COAP_MEDIATYPE_TEXT_PLAIN), buf); + coap_add_data (response, strlen(response_data), (unsigned char *)response_data); + + if (coap_send(ctx, local_if, &async->peer, response) == COAP_INVALID_TID) { + + } + coap_delete_pdu(response); + coap_async_state_t *tmp; + coap_remove_async(ctx, async->id, &tmp); + coap_free_async(async); + async = NULL; +} + +/* + * The resource handler + */ +static void +async_handler(coap_context_t *ctx, struct coap_resource_t *resource, + const coap_endpoint_t *local_interface, coap_address_t *peer, + coap_pdu_t *request, str *token, coap_pdu_t *response) +{ + async = coap_register_async(ctx, peer, request, COAP_ASYNC_SEPARATE | COAP_ASYNC_CONFIRM, (void*)"no data"); +} + +static void coap_demo_thread(void *p) +{ + coap_context_t* ctx = NULL; + coap_address_t serv_addr; + coap_resource_t* resource = NULL; + fd_set readfds; + struct timeval tv; + int flags = 0; + /* Prepare the CoAP server socket */ + coap_address_init(&serv_addr); + serv_addr.addr.sin.sin_family = AF_INET; + serv_addr.addr.sin.sin_addr.s_addr = INADDR_ANY; + serv_addr.addr.sin.sin_port = htons(COAP_DEFAULT_PORT); + ctx = coap_new_context(&serv_addr); + if (ctx) { + flags = fcntl(ctx->sockfd, F_GETFL, 0); + fcntl(ctx->sockfd, F_SETFL, flags|O_NONBLOCK); + + tv.tv_usec = COAP_DEFAULT_TIME_USEC; + tv.tv_sec = COAP_DEFAULT_TIME_SEC; + /* Initialize the resource */ + resource = coap_resource_init((unsigned char *)"Espressif", 9, 0); + if (resource){ + coap_register_handler(resource, COAP_REQUEST_GET, async_handler); + coap_add_resource(ctx, resource); + /*For incoming connections*/ + for (;;) { + FD_ZERO(&readfds); + FD_CLR( ctx->sockfd, &readfds); + FD_SET( ctx->sockfd, &readfds); + + int result = select( FD_SETSIZE, &readfds, 0, 0, &tv ); + if (result > 0){ + if (FD_ISSET( ctx->sockfd, &readfds )) + coap_read(ctx); + } else if (result < 0){ + break; + } else { + printf("select timeout\n"); + } + + if (async) + send_async_response(ctx, ctx->endpoint); + } + } + + coap_free_context(ctx); + } + + vTaskDelete(NULL); +} + +static void coap_server_init(void) +{ + int ret = pdPASS; + xTaskHandle coap_handle = NULL; + + ret = xTaskCreate(coap_demo_thread, + COAP_DEMO_THREAD_NAME, + COAP_DEMO_THREAD_STACK_WORDS, + NULL, + COAP_DEMO_THREAD_PRORIOTY, + &coap_handle); + + if (ret != pdPASS) { + ESP_LOGI(TAG, "create thread %s failed", COAP_DEMO_THREAD_NAME); + } +} + +static esp_err_t wifi_event_handler(void *ctx, system_event_t *event) +{ + switch(event->event_id) { + case SYSTEM_EVENT_STA_START: + esp_wifi_connect(); + break; + case SYSTEM_EVENT_STA_GOT_IP: + xEventGroupSetBits(wifi_event_group, CONNECTED_BIT); + coap_server_init(); + break; + case SYSTEM_EVENT_STA_DISCONNECTED: + /* This is a workaround as ESP32 WiFi libs don't currently + auto-reassociate. */ + esp_wifi_connect(); + xEventGroupClearBits(wifi_event_group, CONNECTED_BIT); + break; + default: + break; + } + return ESP_OK; +} + +static void wifi_conn_init(void) +{ + tcpip_adapter_init(); + wifi_event_group = xEventGroupCreate(); + ESP_ERROR_CHECK( esp_event_loop_init(wifi_event_handler, NULL) ); + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + ESP_ERROR_CHECK( esp_wifi_init(&cfg) ); + ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM) ); + wifi_config_t wifi_config = { + .sta = { + .ssid = EXAMPLE_WIFI_SSID, + .password = EXAMPLE_WIFI_PASS, + }, + }; + ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) ); + ESP_ERROR_CHECK( esp_wifi_set_config(WIFI_IF_STA, &wifi_config) ); + + ESP_ERROR_CHECK( esp_wifi_start() ); +} + +void app_main(void) +{ + nvs_flash_init(); + wifi_conn_init(); +} diff --git a/examples/24_coap_server/main/coap_server.h b/examples/24_coap_server/main/coap_server.h new file mode 100644 index 000000000..e9e8728fc --- /dev/null +++ b/examples/24_coap_server/main/coap_server.h @@ -0,0 +1,38 @@ +/* CoAP server Example + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ + +#ifndef _COAP_SERVER_H_ +#define _COAP_SERVER_H_ + +#include + +/* The examples use simple WiFi configuration that you can set via + 'make menuconfig'. + + If you'd rather not, just change the below entries to strings with + the config you want - ie #define EXAMPLE_WIFI_SSID "mywifissid" +*/ +#define EXAMPLE_WIFI_SSID CONFIG_WIFI_SSID +#define EXAMPLE_WIFI_PASS CONFIG_WIFI_PASSWORD + +#define COAP_DEMO_THREAD_NAME "CoAP_demo" +#define COAP_DEMO_THREAD_STACK_WORDS 10240 +#define COAP_DEMO_THREAD_PRORIOTY 8 + +/* The examples use local port number of 5683 that you can set via 'make menuconfig'. + + If you'd rather not, just change the below entries to strings with + the config you want - ie #define OPENSSL_DEMO_TARGET_TCP_PORT 5683 +*/ +#define COAP_DEFAULT_PORT CONFIG_LOCAL_PORT_NUMBER +#define COAP_DEFAULT_TIME_SEC 5 +#define COAP_DEFAULT_TIME_USEC 0 + +#endif + diff --git a/examples/24_coap_server/main/component.mk b/examples/24_coap_server/main/component.mk new file mode 100644 index 000000000..0b9d7585e --- /dev/null +++ b/examples/24_coap_server/main/component.mk @@ -0,0 +1,5 @@ +# +# "main" pseudo-component makefile. +# +# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) + From 56514d5ab20c5d506f382a7a9c7966bbcd1ba65a Mon Sep 17 00:00:00 2001 From: Liu Han Date: Sat, 10 Dec 2016 14:34:50 +0800 Subject: [PATCH 4/4] examples: Add CoAP client demo Test CoAP protocol client --- examples/23_coap_client/Makefile | 9 + .../23_coap_client/main/Kconfig.projbuild | 34 ++++ examples/23_coap_client/main/coap_client.c | 176 ++++++++++++++++++ examples/23_coap_client/main/coap_client.h | 43 +++++ examples/23_coap_client/main/component.mk | 5 + 5 files changed, 267 insertions(+) create mode 100644 examples/23_coap_client/Makefile create mode 100644 examples/23_coap_client/main/Kconfig.projbuild create mode 100644 examples/23_coap_client/main/coap_client.c create mode 100644 examples/23_coap_client/main/coap_client.h create mode 100644 examples/23_coap_client/main/component.mk diff --git a/examples/23_coap_client/Makefile b/examples/23_coap_client/Makefile new file mode 100644 index 000000000..c9a25d117 --- /dev/null +++ b/examples/23_coap_client/Makefile @@ -0,0 +1,9 @@ +# +# This is a project Makefile. It is assumed the directory this Makefile resides in is a +# project subdirectory. +# + +PROJECT_NAME := coap_client + +include $(IDF_PATH)/make/project.mk + diff --git a/examples/23_coap_client/main/Kconfig.projbuild b/examples/23_coap_client/main/Kconfig.projbuild new file mode 100644 index 000000000..ba3e0d458 --- /dev/null +++ b/examples/23_coap_client/main/Kconfig.projbuild @@ -0,0 +1,34 @@ +menu "Example Configuration" + +config TARGET_DOMAIN + string "Target Domain" + default "californium.eclipse.org" + help + Target domain for the example to connect to. + +config TARGET_DOMAIN_URI + string "Target Uri" + default "coap://californium.eclipse.org" + help + Target uri for the example to use. + +config TARGET_PORT_NUMBER + int "Target port number" + range 0 65535 + default 5683 + help + Target port number for the example to connect to. + +config WIFI_SSID + string "WiFi SSID" + default "myssid" + help + SSID (network name) for the example to connect to. + +config WIFI_PASSWORD + string "WiFi Password" + default "mypassword" + help + WiFi password (WPA or WPA2) for the example to use. + +endmenu \ No newline at end of file diff --git a/examples/23_coap_client/main/coap_client.c b/examples/23_coap_client/main/coap_client.c new file mode 100644 index 000000000..cef24f4c6 --- /dev/null +++ b/examples/23_coap_client/main/coap_client.c @@ -0,0 +1,176 @@ +/* CoAP client Example + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ +#include "coap_client.h" + +#include + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/event_groups.h" + +#include "esp_log.h" +#include "esp_wifi.h" +#include "esp_event_loop.h" + +#include "nvs_flash.h" +#include + +#include "coap_config.h" +#include "resource.h" +#include "coap.h" + + +static EventGroupHandle_t wifi_event_group; + +/* The event group allows multiple bits for each event, + but we only care about one event - are we connected + to the AP with an IP? */ +const static int CONNECTED_BIT = BIT0; + +const static char *TAG = "CoAP_demo"; + +static void message_handler(struct coap_context_t *ctx, const coap_endpoint_t *local_interface, const coap_address_t *remote, + coap_pdu_t *sent, coap_pdu_t *received, + const coap_tid_t id) +{ + unsigned char* data = NULL; + size_t data_len; + if (COAP_RESPONSE_CLASS(received->hdr->code) == 2) { + if (coap_get_data(received, &data_len, &data)) { + printf("Received: %s\n", data); + } + } +} + +static void coap_demo_thread(void *p) +{ + coap_context_t* ctx = NULL; + coap_address_t dst_addr, src_addr; + static coap_uri_t uri; + fd_set readfds; + struct timeval tv; + int flags, result; + coap_pdu_t* request = NULL; + const char* server_uri = COAP_DEFAULT_DEMO_URI; + uint8_t get_method = 1; + + coap_address_init(&src_addr); + src_addr.addr.sin.sin_family = AF_INET; + src_addr.addr.sin.sin_port = htons(0); + src_addr.addr.sin.sin_addr.s_addr = INADDR_ANY; + + ctx = coap_new_context(&src_addr); + if (ctx) { + coap_address_init(&dst_addr); + dst_addr.addr.sin.sin_family = AF_INET; + dst_addr.addr.sin.sin_port = htons(COAP_DEFAULT_PORT); + dst_addr.addr.sin.sin_addr.s_addr = inet_addr(COAP_DEFAULT_DEMO_ADDR); + + coap_split_uri((const uint8_t *)server_uri, strlen(server_uri), &uri); + request = coap_new_pdu(); + if (request){ + request->hdr->type = COAP_MESSAGE_CON; + request->hdr->id = coap_new_message_id(ctx); + request->hdr->code = get_method; + coap_add_option(request, COAP_OPTION_URI_PATH, uri.path.length, uri.path.s); + + coap_register_response_handler(ctx, message_handler); + coap_send_confirmed(ctx, ctx->endpoint, &dst_addr, request); + + flags = fcntl(ctx->sockfd, F_GETFL, 0); + fcntl(ctx->sockfd, F_SETFL, flags|O_NONBLOCK); + + tv.tv_usec = COAP_DEFAULT_TIME_USEC; + tv.tv_sec = COAP_DEFAULT_TIME_SEC; + + for(;;) { + FD_ZERO(&readfds); + FD_CLR( ctx->sockfd, &readfds ); + FD_SET( ctx->sockfd, &readfds ); + result = select( FD_SETSIZE, &readfds, 0, 0, &tv ); + if (result > 0) { + if (FD_ISSET( ctx->sockfd, &readfds )) + coap_read(ctx); + } else if (result < 0) { + break; + } else { + printf("select timeout\n"); + } + } + } + coap_free_context(ctx); + } + + vTaskDelete(NULL); +} + +static void coap_server_init(void) +{ + int ret = pdPASS; + xTaskHandle coap_handle = NULL; + + ret = xTaskCreate(coap_demo_thread, + COAP_DEMO_THREAD_NAME, + COAP_DEMO_THREAD_STACK_WORDS, + NULL, + COAP_DEMO_THREAD_PRORIOTY, + &coap_handle); + + if (ret != pdPASS) { + ESP_LOGI(TAG, "create thread %s failed", COAP_DEMO_THREAD_NAME); + } +} + +static esp_err_t wifi_event_handler(void *ctx, system_event_t *event) +{ + switch(event->event_id) { + case SYSTEM_EVENT_STA_START: + esp_wifi_connect(); + break; + case SYSTEM_EVENT_STA_GOT_IP: + xEventGroupSetBits(wifi_event_group, CONNECTED_BIT); + coap_server_init(); + break; + case SYSTEM_EVENT_STA_DISCONNECTED: + /* This is a workaround as ESP32 WiFi libs don't currently + auto-reassociate. */ + esp_wifi_connect(); + xEventGroupClearBits(wifi_event_group, CONNECTED_BIT); + break; + default: + break; + } + return ESP_OK; +} + +static void wifi_conn_init(void) +{ + tcpip_adapter_init(); + wifi_event_group = xEventGroupCreate(); + ESP_ERROR_CHECK( esp_event_loop_init(wifi_event_handler, NULL) ); + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + ESP_ERROR_CHECK( esp_wifi_init(&cfg) ); + ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM) ); + wifi_config_t wifi_config = { + .sta = { + .ssid = EXAMPLE_WIFI_SSID, + .password = EXAMPLE_WIFI_PASS, + }, + }; + ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) ); + ESP_ERROR_CHECK( esp_wifi_set_config(WIFI_IF_STA, &wifi_config) ); + + ESP_ERROR_CHECK( esp_wifi_start() ); +} + +void app_main(void) +{ + nvs_flash_init(); + wifi_conn_init(); +} diff --git a/examples/23_coap_client/main/coap_client.h b/examples/23_coap_client/main/coap_client.h new file mode 100644 index 000000000..50f4ccd16 --- /dev/null +++ b/examples/23_coap_client/main/coap_client.h @@ -0,0 +1,43 @@ +/* CoAP client Example + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ + +#ifndef _COAP_CLIENT_H_ +#define _COAP_CLIENT_H_ + +#include + +/* The examples use simple WiFi configuration that you can set via + 'make menuconfig'. + + If you'd rather not, just change the below entries to strings with + the config you want - ie #define EXAMPLE_WIFI_SSID "mywifissid" +*/ +#define EXAMPLE_WIFI_SSID CONFIG_WIFI_SSID +#define EXAMPLE_WIFI_PASS CONFIG_WIFI_PASSWORD + +#define COAP_DEMO_THREAD_NAME "CoAP_demo" +#define COAP_DEMO_THREAD_STACK_WORDS 10240 +#define COAP_DEMO_THREAD_PRORIOTY 8 + +#define COAP_DEFAULT_TIME_SEC 5 +#define COAP_DEFAULT_TIME_USEC 0 + +/* The examples use domain of "californium.eclipse.org",uri "coap://californium.eclipse.org" and port number of 5683 that + you can set via 'make menuconfig'. + + If you'd rather not, just change the below entries to strings with + the config you want - ie #define COAP_DEFAULT_DEMO_ADDR "californium.eclipse.org" + , ie #define COAP_DEFAULT_DEMO_URI "coap://californium.eclipse.org" and ie #define COAP_DEFAULT_PORT 5683 +*/ +#define COAP_DEFAULT_PORT CONFIG_TARGET_PORT_NUMBER +#define COAP_DEFAULT_DEMO_ADDR CONFIG_TARGET_DOMAIN +#define COAP_DEFAULT_DEMO_URI CONFIG_TARGET_DOMAIN_URI + +#endif + diff --git a/examples/23_coap_client/main/component.mk b/examples/23_coap_client/main/component.mk new file mode 100644 index 000000000..0b9d7585e --- /dev/null +++ b/examples/23_coap_client/main/component.mk @@ -0,0 +1,5 @@ +# +# "main" pseudo-component makefile. +# +# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) +