Bläddra i källkod

Merge branch 'feature/update_libcoap_4.2.0' into 'master'

Update component/coap to libcoap version release-4.2.0

See merge request idf/esp-idf!4499
Ivan Grokhotkov 6 år sedan
förälder
incheckning
77e7af4e90

+ 7 - 17
components/coap/CMakeLists.txt

@@ -1,12 +1,14 @@
-set(COMPONENT_ADD_INCLUDEDIRS port/include port/include/coap libcoap/include libcoap/include/coap)
+set(COMPONENT_ADD_INCLUDEDIRS port/include port/include/coap libcoap/include libcoap/include/coap2)
 
 set(COMPONENT_SRCS "libcoap/src/address.c"
                    "libcoap/src/async.c"
                    "libcoap/src/block.c"
+                   "libcoap/src/coap_event.c"
+                   "libcoap/src/coap_hashkey.c"
+                   "libcoap/src/coap_session.c"
                    "libcoap/src/coap_time.c"
-                   "libcoap/src/debug.c"
+                   "libcoap/src/coap_debug.c"
                    "libcoap/src/encode.c"
-                   "libcoap/src/hashkey.c"
                    "libcoap/src/mem.c"
                    "libcoap/src/net.c"
                    "libcoap/src/option.c"
@@ -15,7 +17,8 @@ set(COMPONENT_SRCS "libcoap/src/address.c"
                    "libcoap/src/str.c"
                    "libcoap/src/subscribe.c"
                    "libcoap/src/uri.c"
-                   "port/coap_io_socket.c")
+                   "libcoap/src/coap_notls.c"
+                   "port/coap_io.c")
 
 set(COMPONENT_REQUIRES lwip)
 
@@ -26,16 +29,3 @@ register_component()
 # TODO: find a way to move this to a port header
 target_compile_definitions(${COMPONENT_TARGET} PUBLIC WITH_POSIX)
 
-set_source_files_properties(
-    libcoap/src/debug.c
-    libcoap/src/pdu.c
-    PROPERTIES COMPILE_FLAGS
-    -Wno-write-strings)
-
-if(GCC_NOT_5_2_0)
-    # Temporary suppress "fallthrough" warnings until they are fixed in libcoap repo
-    set_source_files_properties(
-        libcoap/src/option.c
-        PROPERTIES COMPILE_FLAGS
-        -Wno-implicit-fallthrough)
-endif()

+ 2 - 8
components/coap/component.mk

@@ -2,17 +2,11 @@
 # Component Makefile
 #
 
-COMPONENT_ADD_INCLUDEDIRS := port/include port/include/coap libcoap/include libcoap/include/coap
+COMPONENT_ADD_INCLUDEDIRS := port/include port/include/coap libcoap/include libcoap/include/coap2
 
-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_OBJS = libcoap/src/address.o libcoap/src/async.o libcoap/src/block.o libcoap/src/coap_event.o libcoap/src/coap_hashkey.o libcoap/src/coap_session.o libcoap/src/coap_time.o libcoap/src/coap_debug.o libcoap/src/encode.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 libcoap/src/coap_notls.o port/coap_io.o
 
 COMPONENT_SRCDIRS := libcoap/src libcoap port
 
 COMPONENT_SUBMODULES += libcoap
 
-libcoap/src/debug.o: CFLAGS += -Wno-write-strings
-libcoap/src/pdu.o: CFLAGS += -Wno-write-strings
-ifeq ($(GCC_NOT_5_2_0), 1)
-# Temporary suppress "fallthrough" warnings until they are fixed in libcoap repo
-libcoap/src/option.o: CFLAGS += -Wno-implicit-fallthrough
-endif

+ 1 - 1
components/coap/libcoap

@@ -1 +1 @@
-Subproject commit 6468887a12666f88b8704d797fc176cd4f40ee4c
+Subproject commit cfec0d072c5b99ed3e54828ca50ea2f6b91e1f50

+ 1422 - 0
components/coap/port/coap_io.c

@@ -0,0 +1,1422 @@
+/* coap_io.c -- Default network I/O functions for libcoap
+ *
+ * Copyright (C) 2012,2014,2016-2019 Olaf Bergmann <bergmann@tzi.org> and others
+ *
+ * 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>
+# define OPTVAL_T(t)         (t)
+# define OPTVAL_GT(t)        (t)
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+ #include <sys/ioctl.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+#ifdef HAVE_WS2TCPIP_H
+#include <ws2tcpip.h>
+# define OPTVAL_T(t)         (const char*)(t)
+# define OPTVAL_GT(t)        (char*)(t)
+# undef CMSG_DATA
+# define CMSG_DATA WSA_CMSG_DATA
+#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 "libcoap.h"
+#include "coap_debug.h"
+#include "mem.h"
+#include "net.h"
+#include "coap_io.h"
+#include "pdu.h"
+#include "utlist.h"
+#include "resource.h"
+
+#if !defined(WITH_CONTIKI)
+ /* 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 */
+#endif
+
+void coap_free_endpoint(coap_endpoint_t *ep);
+
+#ifdef WITH_CONTIKI
+static int ep_initialized = 0;
+
+struct coap_endpoint_t *
+  coap_malloc_endpoint() {
+  static struct coap_endpoint_t ep;
+
+  if (ep_initialized) {
+    return NULL;
+  } else {
+    ep_initialized = 1;
+    return &ep;
+  }
+}
+
+void
+coap_mfree_endpoint(struct coap_endpoint_t *ep) {
+  ep_initialized = 0;
+  coap_session_mfree(&ep->hello);
+}
+
+int
+coap_socket_bind_udp(coap_socket_t *sock,
+  const coap_address_t *listen_addr,
+  coap_address_t *bound_addr) {
+  sock->conn = udp_new(NULL, 0, NULL);
+
+  if (!sock->conn) {
+    coap_log(LOG_WARNING, "coap_socket_bind_udp");
+    return 0;
+  }
+
+  coap_address_init(bound_addr);
+  uip_ipaddr_copy(&bound_addr->addr, &listen_addr->addr);
+  bound_addr->port = listen_addr->port;
+  udp_bind((struct uip_udp_conn *)sock->conn, bound_addr->port);
+  return 1;
+}
+
+int
+coap_socket_connect_udp(coap_socket_t *sock,
+  const coap_address_t *local_if,
+  const coap_address_t *server,
+  int default_port,
+  coap_address_t *local_addr,
+  coap_address_t *remote_addr) {
+  return 0;
+}
+
+int
+coap_socket_connect_tcp1(coap_socket_t *sock,
+                         const coap_address_t *local_if,
+                         const coap_address_t *server,
+                         int default_port,
+                         coap_address_t *local_addr,
+                         coap_address_t *remote_addr) {
+  return 0;
+}
+
+int
+coap_socket_connect_tcp2(coap_socket_t *sock,
+                         coap_address_t *local_addr,
+                         coap_address_t *remote_addr) {
+  return 0;
+}
+
+int
+coap_socket_bind_tcp(coap_socket_t *sock,
+                     const coap_address_t *listen_addr,
+                     coap_address_t *bound_addr) {
+  return 0;
+}
+
+int
+coap_socket_accept_tcp(coap_socket_t *server,
+                        coap_socket_t *new_client,
+                        coap_address_t *local_addr,
+                        coap_address_t *remote_addr) {
+  return 0;
+}
+
+ssize_t
+coap_socket_write(coap_socket_t *sock, const uint8_t *data, size_t data_len) {
+  return -1;
+}
+
+ssize_t
+coap_socket_read(coap_socket_t *sock, uint8_t *data, size_t data_len) {
+  return -1;
+}
+
+void coap_socket_close(coap_socket_t *sock) {
+  if (sock->conn)
+    uip_udp_remove((struct uip_udp_conn *)sock->conn);
+  sock->flags = COAP_SOCKET_EMPTY;
+}
+
+#else
+
+static const char *coap_socket_format_errno( int error );
+
+struct coap_endpoint_t *
+  coap_malloc_endpoint(void) {
+  return (struct coap_endpoint_t *)coap_malloc_type(COAP_ENDPOINT, sizeof(struct coap_endpoint_t));
+}
+
+void
+coap_mfree_endpoint(struct coap_endpoint_t *ep) {
+  coap_session_mfree(&ep->hello);
+  coap_free_type(COAP_ENDPOINT, ep);
+}
+
+int
+coap_socket_bind_udp(coap_socket_t *sock,
+  const coap_address_t *listen_addr,
+  coap_address_t *bound_addr) {
+  int on = 1, off = 0;
+#ifdef _WIN32
+  u_long u_on = 1;
+#endif
+
+  sock->fd = socket(listen_addr->addr.sa.sa_family, SOCK_DGRAM, 0);
+
+  if (sock->fd == COAP_INVALID_SOCKET) {
+    coap_log(LOG_WARNING,
+             "coap_socket_bind_udp: socket: %s\n", coap_socket_strerror());
+    goto error;
+  }
+
+#ifdef _WIN32
+  if (ioctlsocket(sock->fd, FIONBIO, &u_on) == COAP_SOCKET_ERROR) {
+#else
+  if (ioctl(sock->fd, FIONBIO, &on) == COAP_SOCKET_ERROR) {
+#endif
+    coap_log(LOG_WARNING,
+         "coap_socket_bind_udp: ioctl FIONBIO: %s\n", coap_socket_strerror());
+  }
+
+  if (setsockopt(sock->fd, SOL_SOCKET, SO_REUSEADDR, OPTVAL_T(&on), sizeof(on)) == COAP_SOCKET_ERROR)
+    coap_log(LOG_WARNING,
+             "coap_socket_bind_udp: setsockopt SO_REUSEADDR: %s\n",
+              coap_socket_strerror());
+
+  switch (listen_addr->addr.sa.sa_family) {
+  case AF_INET:
+    if (setsockopt(sock->fd, IPPROTO_IP, GEN_IP_PKTINFO, OPTVAL_T(&on), sizeof(on)) == COAP_SOCKET_ERROR)
+      coap_log(LOG_ALERT,
+               "coap_socket_bind_udp: setsockopt IP_PKTINFO: %s\n",
+                coap_socket_strerror());
+    break;
+  case AF_INET6:
+    /* Configure the socket as dual-stacked */
+    if (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_V6ONLY, OPTVAL_T(&off), sizeof(off)) == COAP_SOCKET_ERROR)
+      coap_log(LOG_ALERT,
+               "coap_socket_bind_udp: setsockopt IPV6_V6ONLY: %s\n",
+                coap_socket_strerror());
+    if (setsockopt(sock->fd, IPPROTO_IPV6, GEN_IPV6_PKTINFO, OPTVAL_T(&on), sizeof(on)) == COAP_SOCKET_ERROR)
+      coap_log(LOG_ALERT,
+               "coap_socket_bind_udp: setsockopt IPV6_PKTINFO: %s\n",
+                coap_socket_strerror());
+    setsockopt(sock->fd, IPPROTO_IP, GEN_IP_PKTINFO, OPTVAL_T(&on), sizeof(on)); /* ignore error, because the likely cause is that IPv4 is disabled at the os level */
+    break;
+  default:
+    coap_log(LOG_ALERT, "coap_socket_bind_udp: unsupported sa_family\n");
+    break;
+  }
+
+  if (bind(sock->fd, &listen_addr->addr.sa, listen_addr->size) == COAP_SOCKET_ERROR) {
+    coap_log(LOG_WARNING, "coap_socket_bind_udp: bind: %s\n",
+             coap_socket_strerror());
+    goto error;
+  }
+
+  bound_addr->size = (socklen_t)sizeof(*bound_addr);
+  if (getsockname(sock->fd, &bound_addr->addr.sa, &bound_addr->size) < 0) {
+    coap_log(LOG_WARNING,
+             "coap_socket_bind_udp: getsockname: %s\n",
+              coap_socket_strerror());
+    goto error;
+  }
+
+  return 1;
+
+error:
+  coap_socket_close(sock);
+  return 0;
+}
+
+int
+coap_socket_connect_tcp1(coap_socket_t *sock,
+                         const coap_address_t *local_if,
+                         const coap_address_t *server,
+                         int default_port,
+                         coap_address_t *local_addr,
+                         coap_address_t *remote_addr) {
+  int on = 1, off = 0;
+#ifdef _WIN32
+  u_long u_on = 1;
+#endif
+  coap_address_t connect_addr;
+  coap_address_copy( &connect_addr, server );
+
+  sock->flags &= ~COAP_SOCKET_CONNECTED;
+  sock->fd = socket(server->addr.sa.sa_family, SOCK_STREAM, 0);
+
+  if (sock->fd == COAP_INVALID_SOCKET) {
+    coap_log(LOG_WARNING,
+             "coap_socket_connect_tcp1: socket: %s\n",
+             coap_socket_strerror());
+    goto error;
+  }
+
+#ifdef _WIN32
+  if (ioctlsocket(sock->fd, FIONBIO, &u_on) == COAP_SOCKET_ERROR) {
+#else
+  if (ioctl(sock->fd, FIONBIO, &on) == COAP_SOCKET_ERROR) {
+#endif
+    coap_log(LOG_WARNING,
+             "coap_socket_connect_tcp1: ioctl FIONBIO: %s\n",
+             coap_socket_strerror());
+  }
+
+  switch (server->addr.sa.sa_family) {
+  case AF_INET:
+    if (connect_addr.addr.sin.sin_port == 0)
+      connect_addr.addr.sin.sin_port = htons(default_port);
+    break;
+  case AF_INET6:
+    if (connect_addr.addr.sin6.sin6_port == 0)
+      connect_addr.addr.sin6.sin6_port = htons(default_port);
+    /* Configure the socket as dual-stacked */
+    if (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_V6ONLY, OPTVAL_T(&off), sizeof(off)) == COAP_SOCKET_ERROR)
+      coap_log(LOG_WARNING,
+               "coap_socket_connect_tcp1: setsockopt IPV6_V6ONLY: %s\n",
+               coap_socket_strerror());
+    break;
+  default:
+    coap_log(LOG_ALERT, "coap_socket_connect_tcp1: unsupported sa_family\n");
+    break;
+  }
+
+  if (local_if && local_if->addr.sa.sa_family) {
+    coap_address_copy(local_addr, local_if);
+    if (setsockopt(sock->fd, SOL_SOCKET, SO_REUSEADDR, OPTVAL_T(&on), sizeof(on)) == COAP_SOCKET_ERROR)
+      coap_log(LOG_WARNING,
+               "coap_socket_connect_tcp1: setsockopt SO_REUSEADDR: %s\n",
+               coap_socket_strerror());
+    if (bind(sock->fd, &local_if->addr.sa, local_if->size) == COAP_SOCKET_ERROR) {
+      coap_log(LOG_WARNING, "coap_socket_connect_tcp1: bind: %s\n",
+               coap_socket_strerror());
+      goto error;
+    }
+  } else {
+    local_addr->addr.sa.sa_family = server->addr.sa.sa_family;
+  }
+
+  if (connect(sock->fd, &connect_addr.addr.sa, connect_addr.size) == COAP_SOCKET_ERROR) {
+#ifdef _WIN32
+    if (WSAGetLastError() == WSAEWOULDBLOCK) {
+#else
+    if (errno == EINPROGRESS) {
+#endif
+      /*
+       * COAP_SOCKET_CONNECTED needs to be set here as there will be reads/writes
+       * by underlying TLS libraries during connect() and we do not want to
+       * assert() in coap_read_session() or coap_write_session() when called by coap_read()
+       */
+      sock->flags |= COAP_SOCKET_WANT_CONNECT | COAP_SOCKET_CONNECTED;
+      return 1;
+    }
+    coap_log(LOG_WARNING, "coap_socket_connect_tcp1: connect: %s\n",
+             coap_socket_strerror());
+    goto error;
+  }
+
+  if (getsockname(sock->fd, &local_addr->addr.sa, &local_addr->size) == COAP_SOCKET_ERROR) {
+    coap_log(LOG_WARNING, "coap_socket_connect_tcp1: getsockname: %s\n",
+             coap_socket_strerror());
+  }
+
+  if (getpeername(sock->fd, &remote_addr->addr.sa, &remote_addr->size) == COAP_SOCKET_ERROR) {
+    coap_log(LOG_WARNING, "coap_socket_connect_tcp1: getpeername: %s\n",
+             coap_socket_strerror());
+  }
+
+  sock->flags |= COAP_SOCKET_CONNECTED;
+  return 1;
+
+error:
+  coap_socket_close(sock);
+  return 0;
+}
+
+int
+coap_socket_connect_tcp2(coap_socket_t *sock,
+                         coap_address_t *local_addr,
+                         coap_address_t *remote_addr) {
+  int error = 0;
+#ifdef _WIN32
+  int optlen = (int)sizeof( error );
+#else
+  socklen_t optlen = (socklen_t)sizeof( error );
+#endif
+
+  sock->flags &= ~(COAP_SOCKET_WANT_CONNECT | COAP_SOCKET_CAN_CONNECT);
+
+  if (getsockopt(sock->fd, SOL_SOCKET, SO_ERROR, OPTVAL_GT(&error),
+    &optlen) == COAP_SOCKET_ERROR) {
+    coap_log(LOG_WARNING, "coap_socket_finish_connect_tcp: getsockopt: %s\n",
+      coap_socket_strerror());
+  }
+
+  if (error) {
+    coap_log(LOG_WARNING,
+             "coap_socket_finish_connect_tcp: connect failed: %s\n",
+             coap_socket_format_errno(error));
+    coap_socket_close(sock);
+    return 0;
+  }
+
+  if (getsockname(sock->fd, &local_addr->addr.sa, &local_addr->size) == COAP_SOCKET_ERROR) {
+    coap_log(LOG_WARNING, "coap_socket_connect_tcp: getsockname: %s\n",
+             coap_socket_strerror());
+  }
+
+  if (getpeername(sock->fd, &remote_addr->addr.sa, &remote_addr->size) == COAP_SOCKET_ERROR) {
+    coap_log(LOG_WARNING, "coap_socket_connect_tcp: getpeername: %s\n",
+             coap_socket_strerror());
+  }
+
+  return 1;
+}
+
+int
+coap_socket_bind_tcp(coap_socket_t *sock,
+                     const coap_address_t *listen_addr,
+                     coap_address_t *bound_addr) {
+  int on = 1, off = 0;
+#ifdef _WIN32
+  u_long u_on = 1;
+#endif
+
+  sock->fd = socket(listen_addr->addr.sa.sa_family, SOCK_STREAM, 0);
+
+  if (sock->fd == COAP_INVALID_SOCKET) {
+    coap_log(LOG_WARNING, "coap_socket_bind_tcp: socket: %s\n",
+             coap_socket_strerror());
+    goto error;
+  }
+
+#ifdef _WIN32
+  if (ioctlsocket(sock->fd, FIONBIO, &u_on) == COAP_SOCKET_ERROR) {
+#else
+  if (ioctl(sock->fd, FIONBIO, &on) == COAP_SOCKET_ERROR) {
+#endif
+    coap_log(LOG_WARNING, "coap_socket_bind_tcp: ioctl FIONBIO: %s\n",
+                           coap_socket_strerror());
+  }
+  if (setsockopt (sock->fd, SOL_SOCKET, SO_KEEPALIVE, OPTVAL_T(&on),
+                  sizeof (on)) == COAP_SOCKET_ERROR)
+    coap_log(LOG_WARNING,
+             "coap_socket_bind_tcp: setsockopt SO_KEEPALIVE: %s\n",
+             coap_socket_strerror());
+
+  if (setsockopt(sock->fd, SOL_SOCKET, SO_REUSEADDR, OPTVAL_T(&on),
+                 sizeof(on)) == COAP_SOCKET_ERROR)
+    coap_log(LOG_WARNING,
+             "coap_socket_bind_tcp: setsockopt SO_REUSEADDR: %s\n",
+             coap_socket_strerror());
+
+  switch (listen_addr->addr.sa.sa_family) {
+  case AF_INET:
+    break;
+  case AF_INET6:
+    /* Configure the socket as dual-stacked */
+    if (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_V6ONLY, OPTVAL_T(&off), sizeof(off)) == COAP_SOCKET_ERROR)
+      coap_log(LOG_ALERT,
+               "coap_socket_bind_tcp: setsockopt IPV6_V6ONLY: %s\n",
+               coap_socket_strerror());
+    break;
+  default:
+    coap_log(LOG_ALERT, "coap_socket_bind_tcp: unsupported sa_family\n");
+  }
+
+  if (bind(sock->fd, &listen_addr->addr.sa, listen_addr->size) == COAP_SOCKET_ERROR) {
+    coap_log(LOG_ALERT, "coap_socket_bind_tcp: bind: %s\n",
+             coap_socket_strerror());
+    goto error;
+  }
+
+  bound_addr->size = (socklen_t)sizeof(*bound_addr);
+  if (getsockname(sock->fd, &bound_addr->addr.sa, &bound_addr->size) < 0) {
+    coap_log(LOG_WARNING, "coap_socket_bind_tcp: getsockname: %s\n",
+             coap_socket_strerror());
+    goto error;
+  }
+
+  if (listen(sock->fd, 5) == COAP_SOCKET_ERROR) {
+    coap_log(LOG_ALERT, "coap_socket_bind_tcp: listen: %s\n",
+             coap_socket_strerror());
+    goto  error;
+  }
+
+  return 1;
+
+error:
+  coap_socket_close(sock);
+  return 0;
+}
+
+int
+coap_socket_accept_tcp(coap_socket_t *server,
+                       coap_socket_t *new_client,
+                       coap_address_t *local_addr,
+                       coap_address_t *remote_addr) {
+#ifdef _WIN32
+  u_long u_on = 1;
+#else
+  int on = 1;
+#endif
+
+  server->flags &= ~COAP_SOCKET_CAN_ACCEPT;
+
+  new_client->fd = accept(server->fd, &remote_addr->addr.sa,
+                          &remote_addr->size);
+  if (new_client->fd == COAP_INVALID_SOCKET) {
+    coap_log(LOG_WARNING, "coap_socket_accept_tcp: accept: %s\n",
+             coap_socket_strerror());
+    return 0;
+  }
+
+  if (getsockname( new_client->fd, &local_addr->addr.sa, &local_addr->size) < 0)
+    coap_log(LOG_WARNING, "coap_socket_accept_tcp: getsockname: %s\n",
+             coap_socket_strerror());
+
+  #ifdef _WIN32
+  if (ioctlsocket(new_client->fd, FIONBIO, &u_on) == COAP_SOCKET_ERROR) {
+#else
+  if (ioctl(new_client->fd, FIONBIO, &on) == COAP_SOCKET_ERROR) {
+#endif
+    coap_log(LOG_WARNING, "coap_socket_accept_tcp: ioctl FIONBIO: %s\n",
+             coap_socket_strerror());
+  }
+
+  return 1;
+}
+
+int
+coap_socket_connect_udp(coap_socket_t *sock,
+  const coap_address_t *local_if,
+  const coap_address_t *server,
+  int default_port,
+  coap_address_t *local_addr,
+  coap_address_t *remote_addr) {
+  int on = 1, off = 0;
+#ifdef _WIN32
+  u_long u_on = 1;
+#endif
+  coap_address_t connect_addr;
+  int is_mcast = coap_is_mcast(server);
+  coap_address_copy(&connect_addr, server);
+
+  sock->flags &= ~(COAP_SOCKET_CONNECTED | COAP_SOCKET_MULTICAST);
+  sock->fd = socket(connect_addr.addr.sa.sa_family, SOCK_DGRAM, 0);
+
+  if (sock->fd == COAP_INVALID_SOCKET) {
+    coap_log(LOG_WARNING, "coap_socket_connect_udp: socket: %s\n",
+             coap_socket_strerror());
+    goto error;
+  }
+
+#ifdef _WIN32
+  if (ioctlsocket(sock->fd, FIONBIO, &u_on) == COAP_SOCKET_ERROR) {
+#else
+  if (ioctl(sock->fd, FIONBIO, &on) == COAP_SOCKET_ERROR) {
+#endif
+    coap_log(LOG_WARNING, "coap_socket_connect_udp: ioctl FIONBIO: %s\n",
+             coap_socket_strerror());
+  }
+
+  switch (connect_addr.addr.sa.sa_family) {
+  case AF_INET:
+    if (connect_addr.addr.sin.sin_port == 0)
+      connect_addr.addr.sin.sin_port = htons(default_port);
+    break;
+  case AF_INET6:
+    if (connect_addr.addr.sin6.sin6_port == 0)
+      connect_addr.addr.sin6.sin6_port = htons(default_port);
+    /* Configure the socket as dual-stacked */
+    if (setsockopt(sock->fd, IPPROTO_IPV6, IPV6_V6ONLY, OPTVAL_T(&off), sizeof(off)) == COAP_SOCKET_ERROR)
+      coap_log(LOG_WARNING,
+               "coap_socket_connect_udp: setsockopt IPV6_V6ONLY: %s\n",
+               coap_socket_strerror());
+    break;
+  default:
+    coap_log(LOG_ALERT, "coap_socket_connect_udp: unsupported sa_family\n");
+    break;
+  }
+
+  if (local_if && local_if->addr.sa.sa_family) {
+    if (setsockopt(sock->fd, SOL_SOCKET, SO_REUSEADDR, OPTVAL_T(&on), sizeof(on)) == COAP_SOCKET_ERROR)
+      coap_log(LOG_WARNING,
+               "coap_socket_connect_udp: setsockopt SO_REUSEADDR: %s\n",
+               coap_socket_strerror());
+    if (bind(sock->fd, &local_if->addr.sa, local_if->size) == COAP_SOCKET_ERROR) {
+      coap_log(LOG_WARNING, "coap_socket_connect_udp: bind: %s\n",
+               coap_socket_strerror());
+      goto error;
+    }
+  }
+
+  /* special treatment for sockets that are used for multicast communication */
+  if (is_mcast) {
+    if (getsockname(sock->fd, &local_addr->addr.sa, &local_addr->size) == COAP_SOCKET_ERROR) {
+      coap_log(LOG_WARNING,
+              "coap_socket_connect_udp: getsockname for multicast socket: %s\n",
+              coap_socket_strerror());
+    }
+    coap_address_copy(remote_addr, &connect_addr);
+    sock->flags |= COAP_SOCKET_MULTICAST;
+    return 1;
+  }
+
+  if (connect(sock->fd, &connect_addr.addr.sa, connect_addr.size) == COAP_SOCKET_ERROR) {
+    coap_log(LOG_WARNING, "coap_socket_connect_udp: connect: %s\n",
+             coap_socket_strerror());
+    goto error;
+  }
+
+  if (getsockname(sock->fd, &local_addr->addr.sa, &local_addr->size) == COAP_SOCKET_ERROR) {
+    coap_log(LOG_WARNING, "coap_socket_connect_udp: getsockname: %s\n",
+             coap_socket_strerror());
+  }
+
+  if (getpeername(sock->fd, &remote_addr->addr.sa, &remote_addr->size) == COAP_SOCKET_ERROR) {
+    coap_log(LOG_WARNING, "coap_socket_connect_udp: getpeername: %s\n",
+             coap_socket_strerror());
+  }
+
+  sock->flags |= COAP_SOCKET_CONNECTED;
+  return 1;
+
+error:
+  coap_socket_close(sock);
+  return 0;
+}
+
+void coap_socket_close(coap_socket_t *sock) {
+  if (sock->fd != COAP_INVALID_SOCKET) {
+    coap_closesocket(sock->fd);
+    sock->fd = COAP_INVALID_SOCKET;
+  }
+  sock->flags = COAP_SOCKET_EMPTY;
+}
+
+ssize_t
+coap_socket_write(coap_socket_t *sock, const uint8_t *data, size_t data_len) {
+  ssize_t r;
+
+  sock->flags &= ~(COAP_SOCKET_WANT_WRITE | COAP_SOCKET_CAN_WRITE);
+#ifdef _WIN32
+  r = send(sock->fd, (const char *)data, (int)data_len, 0);
+#else
+  r = send(sock->fd, data, data_len, 0);
+#endif
+  if (r == COAP_SOCKET_ERROR) {
+#ifdef _WIN32
+    if (WSAGetLastError() == WSAEWOULDBLOCK) {
+#elif EAGAIN != EWOULDBLOCK
+    if (errno==EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
+#else
+    if (errno==EAGAIN || errno == EINTR) {
+#endif
+      sock->flags |= COAP_SOCKET_WANT_WRITE;
+      return 0;
+    }
+    coap_log(LOG_WARNING, "coap_socket_write: send: %s\n",
+             coap_socket_strerror());
+    return -1;
+  }
+  if (r < (ssize_t)data_len)
+    sock->flags |= COAP_SOCKET_WANT_WRITE;
+  return r;
+}
+
+ssize_t
+coap_socket_read(coap_socket_t *sock, uint8_t *data, size_t data_len) {
+  ssize_t r;
+#ifdef _WIN32
+  int error;
+#endif
+
+#ifdef _WIN32
+  r = recv(sock->fd, (char *)data, (int)data_len, 0);
+#else
+  r = recv(sock->fd, data, data_len, 0);
+#endif
+  if (r == 0) {
+    /* graceful shutdown */
+    sock->flags &= ~COAP_SOCKET_CAN_READ;
+    return -1;
+  } else if (r == COAP_SOCKET_ERROR) {
+    sock->flags &= ~COAP_SOCKET_CAN_READ;
+#ifdef _WIN32
+    error = WSAGetLastError();
+    if (error == WSAEWOULDBLOCK) {
+#elif EAGAIN != EWOULDBLOCK
+    if (errno==EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
+#else
+    if (errno==EAGAIN || errno == EINTR) {
+#endif
+      return 0;
+    }
+#ifdef _WIN32
+    if (error != WSAECONNRESET)
+#else
+    if (errno != ECONNRESET)
+#endif
+      coap_log(LOG_WARNING, "coap_socket_read: recv: %s\n",
+               coap_socket_strerror());
+    return -1;
+  }
+  if (r < (ssize_t)data_len)
+    sock->flags &= ~COAP_SOCKET_CAN_READ;
+  return r;
+}
+
+#endif  /* WITH_CONTIKI */
+
+#if (!defined(WITH_CONTIKI)) != ( defined(HAVE_NETINET_IN_H) || defined(HAVE_WS2TCPIP_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_CONTIKI) && !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 */
+
+#if defined(_WIN32)
+#include <mswsock.h>
+static __declspec(thread) LPFN_WSARECVMSG lpWSARecvMsg = NULL;
+/* Map struct WSABUF fields to their posix counterpart */
+#define msghdr _WSAMSG
+#define msg_name name
+#define msg_namelen namelen
+#define msg_iov lpBuffers
+#define msg_iovlen dwBufferCount
+#define msg_control Control.buf
+#define msg_controllen Control.len
+#define iovec _WSABUF
+#define iov_base buf
+#define iov_len len
+#define iov_len_t u_long
+#undef CMSG_DATA
+#define CMSG_DATA WSA_CMSG_DATA
+#define ipi_spec_dst ipi_addr
+#else
+#define iov_len_t size_t
+#endif
+
+ssize_t
+coap_network_send(coap_socket_t *sock, const coap_session_t *session, const uint8_t *data, size_t datalen) {
+  ssize_t bytes_written = 0;
+
+  if (!coap_debug_send_packet()) {
+    bytes_written = (ssize_t)datalen;
+#ifndef WITH_CONTIKI
+  } else if (sock->flags & COAP_SOCKET_CONNECTED) {
+#ifdef _WIN32
+    bytes_written = send(sock->fd, (const char *)data, (int)datalen, 0);
+#else
+    bytes_written = send(sock->fd, data, datalen, 0);
+#endif
+#endif
+  } else {
+#ifndef WITH_CONTIKI
+#ifdef _WIN32
+    DWORD dwNumberOfBytesSent = 0;
+    int r;
+#endif
+#ifndef COAP_BAD_RECVMSG
+    /* a buffer large enough to hold all packet info types, ipv6 is the largest */
+    char buf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
+    struct msghdr mhdr;
+    struct iovec iov[1];
+    const void *addr = &session->remote_addr.addr;
+
+    assert(session);
+
+    memcpy (&iov[0].iov_base, &data, sizeof (iov[0].iov_base));
+    iov[0].iov_len = (iov_len_t)datalen;
+
+    memset(buf, 0, sizeof (buf));
+
+    memset(&mhdr, 0, sizeof(struct msghdr));
+    memcpy (&mhdr.msg_name, &addr, sizeof (mhdr.msg_name));
+    mhdr.msg_namelen = session->remote_addr.size;
+
+    mhdr.msg_iov = iov;
+    mhdr.msg_iovlen = 1;
+
+    if (!coap_address_isany(&session->local_addr) && !coap_is_mcast(&session->local_addr)) switch (session->local_addr.addr.sa.sa_family) {
+    case AF_INET6:
+    {
+      struct cmsghdr *cmsg;
+
+      if (IN6_IS_ADDR_V4MAPPED(&session->local_addr.addr.sin6.sin6_addr)) {
+#if defined(IP_PKTINFO)
+        struct in_pktinfo *pktinfo;
+        mhdr.msg_control = buf;
+        mhdr.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
+
+        cmsg = CMSG_FIRSTHDR(&mhdr);
+        cmsg->cmsg_level = SOL_IP;
+        cmsg->cmsg_type = IP_PKTINFO;
+        cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
+
+        pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg);
+
+        pktinfo->ipi_ifindex = session->ifindex;
+        memcpy(&pktinfo->ipi_spec_dst, session->local_addr.addr.sin6.sin6_addr.s6_addr + 12, sizeof(pktinfo->ipi_spec_dst));
+#elif defined(IP_SENDSRCADDR)
+        mhdr.msg_control = buf;
+        mhdr.msg_controllen = CMSG_SPACE(sizeof(struct in_addr));
+
+        cmsg = CMSG_FIRSTHDR(&mhdr);
+        cmsg->cmsg_level = IPPROTO_IP;
+        cmsg->cmsg_type = IP_SENDSRCADDR;
+        cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
+
+        memcpy(CMSG_DATA(cmsg), session->local_addr.addr.sin6.sin6_addr.s6_addr + 12, sizeof(struct in_addr));
+#endif /* IP_PKTINFO */
+      } else {
+        struct in6_pktinfo *pktinfo;
+        mhdr.msg_control = buf;
+        mhdr.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
+
+        cmsg = CMSG_FIRSTHDR(&mhdr);
+        cmsg->cmsg_level = IPPROTO_IPV6;
+        cmsg->cmsg_type = IPV6_PKTINFO;
+        cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
+
+        pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsg);
+
+        pktinfo->ipi6_ifindex = session->ifindex;
+        memcpy(&pktinfo->ipi6_addr, &session->local_addr.addr.sin6.sin6_addr, sizeof(pktinfo->ipi6_addr));
+      }
+      break;
+    }
+    case AF_INET:
+    {
+#if defined(IP_PKTINFO)
+      struct cmsghdr *cmsg;
+      struct in_pktinfo *pktinfo;
+
+      mhdr.msg_control = buf;
+      mhdr.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
+
+      cmsg = CMSG_FIRSTHDR(&mhdr);
+      cmsg->cmsg_level = SOL_IP;
+      cmsg->cmsg_type = IP_PKTINFO;
+      cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
+
+      pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg);
+
+      pktinfo->ipi_ifindex = session->ifindex;
+      memcpy(&pktinfo->ipi_spec_dst, &session->local_addr.addr.sin.sin_addr, sizeof(pktinfo->ipi_spec_dst));
+#elif defined(IP_SENDSRCADDR)
+      struct cmsghdr *cmsg;
+      mhdr.msg_control = buf;
+      mhdr.msg_controllen = CMSG_SPACE(sizeof(struct in_addr));
+
+      cmsg = CMSG_FIRSTHDR(&mhdr);
+      cmsg->cmsg_level = IPPROTO_IP;
+      cmsg->cmsg_type = IP_SENDSRCADDR;
+      cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
+
+      memcpy(CMSG_DATA(cmsg), &session->local_addr.addr.sin.sin_addr, sizeof(struct in_addr));
+#endif /* IP_PKTINFO */
+      break;
+    }
+    default:
+      /* error */
+      coap_log(LOG_WARNING, "protocol not supported\n");
+      bytes_written = -1;
+    }
+#endif /* ! COAP_BAD_RECVMSG */
+
+#ifdef _WIN32
+    r = WSASendMsg(sock->fd, &mhdr, 0 /*dwFlags*/, &dwNumberOfBytesSent, NULL /*lpOverlapped*/, NULL /*lpCompletionRoutine*/);
+    if (r == 0)
+      bytes_written = (ssize_t)dwNumberOfBytesSent;
+    else
+      bytes_written = -1;
+#else
+#ifndef COAP_BAD_RECVMSG
+    bytes_written = sendmsg(sock->fd, &mhdr, 0);
+#else /* COAP_BAD_RECVMSG */
+    bytes_written = sendto(sock->fd, data, datalen, 0, &session->remote_addr.addr.sa, session->remote_addr.size);
+#endif /* COAP_BAD_RECVMSG */
+#endif
+#else /* WITH_CONTIKI */
+    /* FIXME: untested */
+    /* FIXME: is there a way to check if send was successful? */
+    (void)datalen;
+    (void)data;
+    uip_udp_packet_sendto((struct uip_udp_conn *)sock->conn, data, datalen,
+      &session->remote_addr.addr, session->remote_addr.port);
+    bytes_written = datalen;
+#endif /* WITH_CONTIKI */
+  }
+
+  if (bytes_written < 0)
+    coap_log(LOG_CRIT, "coap_network_send: %s\n", coap_socket_strerror());
+
+  return bytes_written;
+}
+
+#define SIN6(A) ((struct sockaddr_in6 *)(A))
+
+void
+coap_packet_get_memmapped(coap_packet_t *packet, unsigned char **address, size_t *length) {
+  *address = packet->payload;
+  *length = packet->length;
+}
+
+void coap_packet_set_addr(coap_packet_t *packet, const coap_address_t *src, const coap_address_t *dst) {
+  coap_address_copy(&packet->src, src);
+  coap_address_copy(&packet->dst, dst);
+}
+
+ssize_t
+coap_network_read(coap_socket_t *sock, coap_packet_t *packet) {
+  ssize_t len = -1;
+
+  assert(sock);
+  assert(packet);
+
+  if ((sock->flags & COAP_SOCKET_CAN_READ) == 0) {
+    return -1;
+  } else {
+    /* clear has-data flag */
+    sock->flags &= ~COAP_SOCKET_CAN_READ;
+  }
+
+#ifndef WITH_CONTIKI
+  if (sock->flags & COAP_SOCKET_CONNECTED) {
+#ifdef _WIN32
+    len = recv(sock->fd, (char *)packet->payload, COAP_RXBUFFER_SIZE, 0);
+#else
+    len = recv(sock->fd, packet->payload, COAP_RXBUFFER_SIZE, 0);
+#endif
+    if (len < 0) {
+#ifdef _WIN32
+      if (WSAGetLastError() == WSAECONNRESET) {
+#else
+      if (errno == ECONNREFUSED) {
+#endif
+        /* client-side ICMP destination unreachable, ignore it */
+        coap_log(LOG_WARNING, "coap_network_read: unreachable\n");
+        return -2;
+      }
+      coap_log(LOG_WARNING, "coap_network_read: %s\n", coap_socket_strerror());
+      goto error;
+    } else if (len > 0) {
+      packet->length = (size_t)len;
+    }
+  } else {
+#endif /* WITH_CONTIKI */
+#if defined(_WIN32)
+    DWORD dwNumberOfBytesRecvd = 0;
+    int r;
+#endif
+#if !defined(WITH_CONTIKI)
+#ifndef COAP_BAD_RECVMSG
+    /* a buffer large enough to hold all packet info types, ipv6 is the largest */
+    char buf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
+    struct msghdr mhdr;
+    struct iovec iov[1];
+
+    iov[0].iov_base = packet->payload;
+    iov[0].iov_len = (iov_len_t)COAP_RXBUFFER_SIZE;
+
+    memset(&mhdr, 0, sizeof(struct msghdr));
+
+    mhdr.msg_name = (struct sockaddr*)&packet->src.addr;
+    mhdr.msg_namelen = sizeof(packet->src.addr);
+
+    mhdr.msg_iov = iov;
+    mhdr.msg_iovlen = 1;
+
+    mhdr.msg_control = buf;
+    mhdr.msg_controllen = sizeof(buf);
+
+#if defined(_WIN32)
+    if (!lpWSARecvMsg) {
+      GUID wsaid = WSAID_WSARECVMSG;
+      DWORD cbBytesReturned = 0;
+      if (WSAIoctl(sock->fd, SIO_GET_EXTENSION_FUNCTION_POINTER, &wsaid, sizeof(wsaid), &lpWSARecvMsg, sizeof(lpWSARecvMsg), &cbBytesReturned, NULL, NULL) != 0) {
+        coap_log(LOG_WARNING, "coap_network_read: no WSARecvMsg\n");
+        return -1;
+      }
+    }
+    r = lpWSARecvMsg(sock->fd, &mhdr, &dwNumberOfBytesRecvd, NULL /* LPWSAOVERLAPPED */, NULL /* LPWSAOVERLAPPED_COMPLETION_ROUTINE */);
+    if (r == 0)
+      len = (ssize_t)dwNumberOfBytesRecvd;
+#else
+    len = recvmsg(sock->fd, &mhdr, 0);
+#endif
+
+#else /* COAP_BAD_RECVMSG */
+    packet->src.size = packet->src.size;
+    len = recvfrom(sock->fd, packet->payload, COAP_RXBUFFER_SIZE, 0, &packet->src.addr.sa, &packet->src.size);
+#endif /* COAP_BAD_RECVMSG */
+
+    if (len < 0) {
+#ifdef _WIN32
+      if (WSAGetLastError() == WSAECONNRESET) {
+#else
+      if (errno == ECONNREFUSED) {
+#endif
+        /* server-side ICMP destination unreachable, ignore it. The destination address is in msg_name. */
+        return 0;
+      }
+      coap_log(LOG_WARNING, "coap_network_read: %s\n", coap_socket_strerror());
+      goto error;
+    } else {
+#ifndef COAP_BAD_RECVMSG
+      struct cmsghdr *cmsg;
+
+      packet->src.size = mhdr.msg_namelen;
+      packet->length = (size_t)len;
+
+      /* Walk through ancillary data records until the local interface
+       * is found where the data was received. */
+      for (cmsg = CMSG_FIRSTHDR(&mhdr); cmsg; cmsg = CMSG_NXTHDR(&mhdr, cmsg)) {
+
+        /* get the local interface for IPv6 */
+        if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) {
+          union {
+            uint8_t *c;
+            struct in6_pktinfo *p;
+          } u;
+          u.c = CMSG_DATA(cmsg);
+          packet->ifindex = (int)(u.p->ipi6_ifindex);
+          memcpy(&packet->dst.addr.sin6.sin6_addr, &u.p->ipi6_addr, sizeof(struct in6_addr));
+          break;
+        }
+
+        /* local interface for IPv4 */
+#if defined(IP_PKTINFO)
+        if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_PKTINFO) {
+          union {
+            uint8_t *c;
+            struct in_pktinfo *p;
+          } u;
+          u.c = CMSG_DATA(cmsg);
+          packet->ifindex = u.p->ipi_ifindex;
+          if (packet->dst.addr.sa.sa_family == AF_INET6) {
+            memset(packet->dst.addr.sin6.sin6_addr.s6_addr, 0, 10);
+            packet->dst.addr.sin6.sin6_addr.s6_addr[10] = 0xff;
+            packet->dst.addr.sin6.sin6_addr.s6_addr[11] = 0xff;
+            memcpy(packet->dst.addr.sin6.sin6_addr.s6_addr + 12, &u.p->ipi_addr, sizeof(struct in_addr));
+          } else {
+            memcpy(&packet->dst.addr.sin.sin_addr, &u.p->ipi_addr, sizeof(struct in_addr));
+          }
+          break;
+        }
+#elif defined(IP_RECVDSTADDR)
+        if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_RECVDSTADDR) {
+          packet->ifindex = 0;
+          memcpy(&packet->dst.addr.sin.sin_addr, CMSG_DATA(cmsg), sizeof(struct in_addr));
+          break;
+        }
+#endif /* IP_PKTINFO */
+      }
+#else /* COAP_BAD_RECVMSG */
+      packet->length = (size_t)len;
+      packet->ifindex = 0;
+      if (getsockname(sock->fd, &packet->dst.addr.sa, &packet->dst.size) < 0) {
+         coap_log(LOG_DEBUG, "Cannot determine local port\n");
+         goto error;
+      }
+#endif /* COAP_BAD_RECVMSG */
+    }
+#endif /* !defined(WITH_CONTIKI) */
+#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;
+
+      len = uip_datalen();
+
+      if (len > COAP_RXBUFFER_SIZE) {
+        /* FIXME: we might want to send back a response */
+        coap_log(LOG_WARNING, "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)) {
+          coap_log(LOG_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 */
+#ifndef WITH_CONTIKI
+  }
+#endif /* WITH_CONTIKI */
+
+  if (len >= 0)
+    return len;
+#if !defined(WITH_CONTIKI)
+error:
+#endif
+  return -1;
+}
+
+#if !defined(WITH_CONTIKI)
+
+unsigned int
+coap_write(coap_context_t *ctx,
+           coap_socket_t *sockets[],
+           unsigned int max_sockets,
+           unsigned int *num_sockets,
+           coap_tick_t now)
+{
+  coap_queue_t *nextpdu;
+  coap_endpoint_t *ep;
+  coap_session_t *s;
+  coap_tick_t session_timeout;
+  coap_tick_t timeout = 0;
+  coap_session_t *tmp;
+
+  *num_sockets = 0;
+
+  /* Check to see if we need to send off any Observe requests */
+  coap_check_notify(ctx);
+
+  if (ctx->session_timeout > 0)
+    session_timeout = ctx->session_timeout * COAP_TICKS_PER_SECOND;
+  else
+    session_timeout = COAP_DEFAULT_SESSION_TIMEOUT * COAP_TICKS_PER_SECOND;
+
+  LL_FOREACH(ctx->endpoint, ep) {
+    if (ep->sock.flags & (COAP_SOCKET_WANT_READ | COAP_SOCKET_WANT_WRITE | COAP_SOCKET_WANT_ACCEPT)) {
+      if (*num_sockets < max_sockets)
+        sockets[(*num_sockets)++] = &ep->sock;
+    }
+    LL_FOREACH_SAFE(ep->sessions, s, tmp) {
+      if (s->type == COAP_SESSION_TYPE_SERVER && s->ref == 0 &&
+          s->delayqueue == NULL &&
+          (s->last_rx_tx + session_timeout <= now ||
+           s->state == COAP_SESSION_STATE_NONE)) {
+        coap_session_free(s);
+      } else {
+        if (s->type == COAP_SESSION_TYPE_SERVER && s->ref == 0 && s->delayqueue == NULL) {
+          coap_tick_t s_timeout = (s->last_rx_tx + session_timeout) - now;
+          if (timeout == 0 || s_timeout < timeout)
+            timeout = s_timeout;
+        }
+        if (s->sock.flags & (COAP_SOCKET_WANT_READ | COAP_SOCKET_WANT_WRITE)) {
+          if (*num_sockets < max_sockets)
+            sockets[(*num_sockets)++] = &s->sock;
+        }
+      }
+    }
+  }
+  LL_FOREACH_SAFE(ctx->sessions, s, tmp) {
+    if (
+        s->type == COAP_SESSION_TYPE_CLIENT
+     && COAP_PROTO_RELIABLE(s->proto)
+     && s->state == COAP_SESSION_STATE_ESTABLISHED
+     && ctx->ping_timeout > 0
+    ) {
+      coap_tick_t s_timeout;
+      if (s->last_rx_tx + ctx->ping_timeout * COAP_TICKS_PER_SECOND <= now) {
+        if ((s->last_ping > 0 && s->last_pong < s->last_ping)
+          || coap_session_send_ping(s) == COAP_INVALID_TID)
+        {
+          /* Make sure the session object is not deleted in the callback */
+          coap_session_reference(s);
+          coap_session_disconnected(s, COAP_NACK_NOT_DELIVERABLE);
+          coap_session_release(s);
+          continue;
+        }
+        s->last_rx_tx = now;
+        s->last_ping = now;
+      }
+      s_timeout = (s->last_rx_tx + ctx->ping_timeout * COAP_TICKS_PER_SECOND) - now;
+      if (timeout == 0 || s_timeout < timeout)
+        timeout = s_timeout;
+    }
+
+    if (
+        s->type == COAP_SESSION_TYPE_CLIENT
+     && COAP_PROTO_RELIABLE(s->proto)
+     && s->state == COAP_SESSION_STATE_CSM
+     && ctx->csm_timeout > 0
+    ) {
+      coap_tick_t s_timeout;
+      if (s->csm_tx == 0) {
+        s->csm_tx = now;
+      } else if (s->csm_tx + ctx->csm_timeout * COAP_TICKS_PER_SECOND <= now) {
+        /* Make sure the session object is not deleted in the callback */
+        coap_session_reference(s);
+        coap_session_disconnected(s, COAP_NACK_NOT_DELIVERABLE);
+        coap_session_release(s);
+        continue;
+      }
+      s_timeout = (s->csm_tx + ctx->csm_timeout * COAP_TICKS_PER_SECOND) - now;
+      if (timeout == 0 || s_timeout < timeout)
+        timeout = s_timeout;
+    }
+
+    if (s->sock.flags & (COAP_SOCKET_WANT_READ | COAP_SOCKET_WANT_WRITE | COAP_SOCKET_WANT_CONNECT)) {
+      if (*num_sockets < max_sockets)
+        sockets[(*num_sockets)++] = &s->sock;
+    }
+  }
+
+  nextpdu = coap_peek_next(ctx);
+
+  while (nextpdu && now >= ctx->sendqueue_basetime && nextpdu->t <= now - ctx->sendqueue_basetime) {
+    coap_retransmit(ctx, coap_pop_next(ctx));
+    nextpdu = coap_peek_next(ctx);
+  }
+
+  if (nextpdu && (timeout == 0 || nextpdu->t - ( now - ctx->sendqueue_basetime ) < timeout))
+    timeout = nextpdu->t - (now - ctx->sendqueue_basetime);
+
+  if (ctx->dtls_context) {
+    if (coap_dtls_is_context_timeout()) {
+      coap_tick_t tls_timeout = coap_dtls_get_context_timeout(ctx->dtls_context);
+      if (tls_timeout > 0) {
+        if (tls_timeout < now + COAP_TICKS_PER_SECOND / 10)
+          tls_timeout = now + COAP_TICKS_PER_SECOND / 10;
+        coap_log(LOG_DEBUG, "** DTLS global timeout set to %dms\n",
+                 (int)((tls_timeout - now) * 1000 / COAP_TICKS_PER_SECOND));
+        if (timeout == 0 || tls_timeout - now < timeout)
+          timeout = tls_timeout - now;
+      }
+    } else {
+      LL_FOREACH(ctx->endpoint, ep) {
+        if (ep->proto == COAP_PROTO_DTLS) {
+          LL_FOREACH(ep->sessions, s) {
+            if (s->proto == COAP_PROTO_DTLS && s->tls) {
+              coap_tick_t tls_timeout = coap_dtls_get_timeout(s);
+              while (tls_timeout > 0 && tls_timeout <= now) {
+                coap_log(LOG_DEBUG, "** %s: DTLS retransmit timeout\n",
+                         coap_session_str(s));
+                coap_dtls_handle_timeout(s);
+                if (s->tls)
+                  tls_timeout = coap_dtls_get_timeout(s);
+                else {
+                  tls_timeout = 0;
+                  timeout = 1;
+                }
+              }
+              if (tls_timeout > 0 && (timeout == 0 || tls_timeout - now < timeout))
+                timeout = tls_timeout - now;
+            }
+          }
+        }
+      }
+      LL_FOREACH(ctx->sessions, s) {
+        if (s->proto == COAP_PROTO_DTLS && s->tls) {
+          coap_tick_t tls_timeout = coap_dtls_get_timeout(s);
+          while (tls_timeout > 0 && tls_timeout <= now) {
+            coap_log(LOG_DEBUG, "** %s: DTLS retransmit timeout\n", coap_session_str(s));
+            coap_dtls_handle_timeout(s);
+            if (s->tls)
+              tls_timeout = coap_dtls_get_timeout(s);
+            else {
+              tls_timeout = 0;
+              timeout = 1;
+            }
+          }
+          if (tls_timeout > 0 && (timeout == 0 || tls_timeout - now < timeout))
+            timeout = tls_timeout - now;
+        }
+      }
+    }
+  }
+
+  return (unsigned int)((timeout * 1000 + COAP_TICKS_PER_SECOND - 1) / COAP_TICKS_PER_SECOND);
+}
+
+int
+coap_run_once(coap_context_t *ctx, unsigned timeout_ms) {
+  fd_set readfds, writefds, exceptfds;
+  coap_fd_t nfds = 0;
+  struct timeval tv;
+  coap_tick_t before, now;
+  int result;
+  coap_socket_t *sockets[64];
+  unsigned int num_sockets = 0, i, timeout;
+
+  coap_ticks(&before);
+
+  timeout = coap_write(ctx, sockets, (unsigned int)(sizeof(sockets) / sizeof(sockets[0])), &num_sockets, before);
+  if (timeout == 0 || timeout_ms < timeout)
+    timeout = timeout_ms;
+
+  FD_ZERO(&readfds);
+  FD_ZERO(&writefds);
+  FD_ZERO(&exceptfds);
+  for (i = 0; i < num_sockets; i++) {
+    if (sockets[i]->fd + 1 > nfds)
+      nfds = sockets[i]->fd + 1;
+    if (sockets[i]->flags & COAP_SOCKET_WANT_READ)
+      FD_SET(sockets[i]->fd, &readfds);
+    if (sockets[i]->flags & COAP_SOCKET_WANT_WRITE)
+      FD_SET(sockets[i]->fd, &writefds);
+    if (sockets[i]->flags & COAP_SOCKET_WANT_ACCEPT)
+      FD_SET(sockets[i]->fd, &readfds);
+    if (sockets[i]->flags & COAP_SOCKET_WANT_CONNECT) {
+      FD_SET(sockets[i]->fd, &writefds);
+      FD_SET(sockets[i]->fd, &exceptfds);
+    }
+  }
+
+  if ( timeout > 0 ) {
+    tv.tv_usec = (timeout % 1000) * 1000;
+    tv.tv_sec = (long)(timeout / 1000);
+  }
+
+  result = select(nfds, &readfds, &writefds, &exceptfds, timeout > 0 ? &tv : NULL);
+
+  if (result < 0) {   /* error */
+#ifdef _WIN32
+    if (WSAGetLastError() != WSAEINVAL) { /* May happen because of ICMP */
+#else
+    if (errno != EINTR) {
+#endif
+      coap_log(LOG_DEBUG, "%s", coap_socket_strerror());
+      return -1;
+    }
+  }
+
+  if (result > 0) {
+    for (i = 0; i < num_sockets; i++) {
+      if ((sockets[i]->flags & COAP_SOCKET_WANT_READ) && FD_ISSET(sockets[i]->fd, &readfds))
+        sockets[i]->flags |= COAP_SOCKET_CAN_READ;
+      if ((sockets[i]->flags & COAP_SOCKET_WANT_ACCEPT) && FD_ISSET(sockets[i]->fd, &readfds))
+        sockets[i]->flags |= COAP_SOCKET_CAN_ACCEPT;
+      if ((sockets[i]->flags & COAP_SOCKET_WANT_WRITE) && FD_ISSET(sockets[i]->fd, &writefds))
+        sockets[i]->flags |= COAP_SOCKET_CAN_WRITE;
+      if ((sockets[i]->flags & COAP_SOCKET_WANT_CONNECT) && (FD_ISSET(sockets[i]->fd, &writefds) || FD_ISSET(sockets[i]->fd, &exceptfds)))
+        sockets[i]->flags |= COAP_SOCKET_CAN_CONNECT;
+    }
+  }
+
+  coap_ticks(&now);
+  coap_read(ctx, now);
+
+  return (int)(((now - before) * 1000) / COAP_TICKS_PER_SECOND);
+}
+
+#else
+int coap_run_once(coap_context_t *ctx, unsigned int timeout_ms) {
+  return -1;
+}
+
+unsigned int
+coap_write(coap_context_t *ctx,
+           coap_socket_t *sockets[],
+           unsigned int max_sockets,
+           unsigned int *num_sockets,
+           coap_tick_t now)
+{
+  *num_sockets = 0;
+  return 0;
+}
+#endif
+
+#ifdef _WIN32
+static const char *coap_socket_format_errno(int error) {
+  static char szError[256];
+  if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, (DWORD)error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)szError, (DWORD)sizeof(szError), NULL) == 0)
+    strcpy(szError, "Unknown error");
+  return szError;
+}
+
+const char *coap_socket_strerror(void) {
+  return coap_socket_format_errno(WSAGetLastError());
+}
+#else
+#ifndef WITH_CONTIKI
+static const char *coap_socket_format_errno(int error) {
+  return strerror(error);
+}
+#endif /* WITH_CONTIKI */
+
+const char *coap_socket_strerror(void) {
+  return strerror(errno);
+}
+#endif
+
+ssize_t
+coap_socket_send(coap_socket_t *sock, coap_session_t *session,
+  const uint8_t *data, size_t data_len) {
+  return session->context->network_send(sock, session, data, data_len);
+}
+
+#undef SIN6

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

@@ -1,468 +0,0 @@
-/*
- * 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.sa);
-	      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 */

+ 5 - 5
components/coap/port/include/coap/coap.h

@@ -17,19 +17,21 @@
 #ifndef _COAP_H_
 #define _COAP_H_
 
-#include "libcoap.h"
-
 #ifdef __cplusplus
 extern "C" {
 #endif
 
+#include "libcoap.h"
+
 #include "address.h"
 #include "async.h"
 #include "bits.h"
 #include "block.h"
+#include "coap_dtls.h"
+#include "coap_event.h"
 #include "coap_io.h"
 #include "coap_time.h"
-#include "debug.h"
+#include "coap_debug.h"
 #include "encode.h"
 #include "mem.h"
 #include "net.h"
@@ -40,8 +42,6 @@ extern "C" {
 #include "str.h"
 #include "subscribe.h"
 #include "uri.h"
-#include "uthash.h"
-#include "utlist.h"
 
 #ifdef __cplusplus
 }

+ 3 - 5
components/coap/port/include/coap_config_posix.h

@@ -25,6 +25,7 @@
 #define HAVE_SYS_SOCKET_H
 #define HAVE_MALLOC
 #define HAVE_ARPA_INET_H
+#define HAVE_TIME_H
 
 #define IP_PKTINFO   IP_MULTICAST_IF
 #define IPV6_PKTINFO IPV6_V6ONLY
@@ -32,10 +33,7 @@
 #define PACKAGE_NAME "libcoap-posix"
 #define PACKAGE_VERSION "?"
 
-#define CUSTOM_COAP_NETWORK_ENDPOINT
-#define CUSTOM_COAP_NETWORK_SEND
-#define CUSTOM_COAP_NETWORK_READ
-
-#endif
+#define COAP_BAD_RECVMSG
 
+#endif /* WITH_POSIX */
 #endif /* COAP_CONFIG_POSIX_H_ */

+ 21 - 6
examples/protocols/coap_client/README.md

@@ -37,7 +37,8 @@ make -j4 flash monitor
 See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
 
 ## Example Output
-Prerequisite: we startup a CoAP server on coap server example.  
+Prerequisite: we startup a CoAP server on coap server example,
+or use the default of coap://californium.eclipse.org.  
 
 and you could receive data from CoAP server if succeed,  
 such as the following log:
@@ -54,12 +55,26 @@ I (1692) wifi: pm start, type: 1
 
 I (2582) event: sta ip: 192.168.3.89, mask: 255.255.255.0, gw: 192.168.3.1
 I (2582) CoAP_client: Connected to AP
-I (2582) CoAP_client: DNS lookup succeeded. IP=192.168.3.84
-Received: Hello World!
-E (8102) CoAP_client: select timeout
-E (13102) CoAP_client: select timeout
+I (2582) CoAP_client: DNS lookup succeeded. IP=104.196.15.150
+Received:
+************************************************************
+CoAP RFC 7252                              Cf 2.0.0-SNAPSHOT
+************************************************************
+This server is using the Eclipse Californium (Cf) CoAP framework
+published under EPL+EDL: http://www.eclipse.org/californium/
+
+(c) 2014, 2015, 2016 Institute for Pervasive Computing, ETH Zurich and others
+************************************************************
 ...
 ```
 
+## libcoap Documentation
+This can be found at https://libcoap.net/doc/reference/4.2.0/
+
 ## Troubleshooting
-* Please make sure Target Url includes valid `host`, `port`, `path`, and begins with `coap://`  
+* Please make sure Target Url includes valid `host`, optional `port`, optional `path`, and begins
+with `coap://` or `coap+tcp://` for a coap server that supports TCP
+(not all do including coap+tcp://californium.eclipse.org).
+
+* libcoap logging can be increased by changing `#define COAP_LOGGING_LEVEL 0`
+to `#define COAP_LOGGING_LEVEL 9`

+ 184 - 50
examples/protocols/coap_client/main/coap_client_example_main.c

@@ -33,7 +33,9 @@
 #define EXAMPLE_WIFI_PASS CONFIG_WIFI_PASSWORD
 
 #define COAP_DEFAULT_TIME_SEC 5
-#define COAP_DEFAULT_TIME_USEC 0
+
+/* Set this to 9 to get verbose logging from within libcoap */
+#define COAP_LOGGING_LEVEL 0
 
 /* The examples use uri "coap://californium.eclipse.org" that
    you can set via 'make menuconfig'.
@@ -52,17 +54,88 @@ const static int CONNECTED_BIT = BIT0;
 
 const static char *TAG = "CoAP_client";
 
-static void message_handler(struct coap_context_t *ctx, const coap_endpoint_t *local_interface, const coap_address_t *remote,
+static int resp_wait = 1;
+static coap_optlist_t *optlist = NULL;
+static int wait_ms;
+
+static void message_handler(coap_context_t *ctx, coap_session_t *session,
               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);
+    coap_pdu_t *pdu = NULL;
+    coap_opt_t *block_opt;
+    coap_opt_iterator_t opt_iter;
+    unsigned char buf[4];
+    coap_optlist_t *option;
+    coap_tid_t tid;
+
+    if (COAP_RESPONSE_CLASS(received->code) == 2) {
+        /* Need to see if blocked response */
+        block_opt = coap_check_option(received, COAP_OPTION_BLOCK2, &opt_iter);
+        if (block_opt) {
+            uint16_t blktype = opt_iter.type;
+
+            if (coap_opt_block_num(block_opt) == 0) {
+                printf("Received:\n");
+            }
+            if (coap_get_data(received, &data_len, &data)) {
+                printf("%.*s", (int)data_len, data);
+            }
+            if (COAP_OPT_BLOCK_MORE(block_opt)) {
+                /* more bit is set */
+
+                /* create pdu with request for next block */
+                pdu = coap_new_pdu(session);
+                if (!pdu) {
+                     ESP_LOGE(TAG, "coap_new_pdu() failed");
+                     goto clean_up;
+                }
+                pdu->type = COAP_MESSAGE_CON;
+                pdu->tid = coap_new_message_id(session);
+                pdu->code = COAP_REQUEST_GET;
+
+                /* add URI components from optlist */
+                for (option = optlist; option; option = option->next ) {
+                    switch (option->number) {
+                    case COAP_OPTION_URI_HOST :
+                    case COAP_OPTION_URI_PORT :
+                    case COAP_OPTION_URI_PATH :
+                    case COAP_OPTION_URI_QUERY :
+                        coap_add_option(pdu, option->number, option->length,
+                                  option->data);
+                        break;
+                    default:
+                        ;     /* skip other options */
+                    }
+                }
+
+                /* finally add updated block option from response, clear M bit */
+                /* blocknr = (blocknr & 0xfffffff7) + 0x10; */
+                coap_add_option(pdu,
+                                blktype,
+                                coap_encode_var_safe(buf, sizeof(buf),
+                                     ((coap_opt_block_num(block_opt) + 1) << 4) |
+                                      COAP_OPT_BLOCK_SZX(block_opt)), buf);
+
+                tid = coap_send(session, pdu);
+
+                if (tid != COAP_INVALID_TID) {
+                    resp_wait = 1;
+                    wait_ms = COAP_DEFAULT_TIME_SEC * 1000;
+                    return;
+                }
+            }
+            printf("\n");
+        } else {
+            if (coap_get_data(received, &data_len, &data)) {
+                printf("Received: %.*s\n", (int)data_len, data);
+            }
         }
     }
+clean_up:
+    resp_wait = 0;
 }
 
 static void coap_example_task(void *p)
@@ -70,17 +143,22 @@ static void coap_example_task(void *p)
     struct hostent *hp;
     struct ip4_addr *ip4_addr;
 
-    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;
     char* phostname = NULL;
+
+    coap_set_log_level(COAP_LOGGING_LEVEL);
     while (1) {
+#define BUFSIZE 40
+        unsigned char _buf[BUFSIZE];
+        unsigned char *buf;
+        size_t buflen;
+        int res;
+        coap_context_t *ctx = NULL;
+        coap_session_t *session = NULL;
+        coap_pdu_t *request = NULL;
+
         /* Wait for the callback to set the CONNECTED_BIT in the
            event group.
         */
@@ -88,11 +166,18 @@ static void coap_example_task(void *p)
                             false, true, portMAX_DELAY);
         ESP_LOGI(TAG, "Connected to AP");
 
+        optlist = NULL;
         if (coap_split_uri((const uint8_t *)server_uri, strlen(server_uri), &uri) == -1) {
             ESP_LOGE(TAG, "CoAP server uri error");
             break;
         }
 
+        if ((uri.scheme==COAP_URI_SCHEME_COAPS && !coap_dtls_is_supported()) ||
+            (uri.scheme==COAP_URI_SCHEME_COAPS_TCP && !coap_tls_is_supported())) {
+            ESP_LOGE(TAG, "CoAP server uri scheme error");
+            break;
+        }
+
         phostname = (char *)calloc(1, uri.host.length + 1);
 
         if (phostname == NULL) {
@@ -107,6 +192,7 @@ static void coap_example_task(void *p)
         if (hp == NULL) {
             ESP_LOGE(TAG, "DNS lookup failed");
             vTaskDelay(1000 / portTICK_PERIOD_MS);
+            free(phostname);
             continue;
         }
 
@@ -121,46 +207,94 @@ static void coap_example_task(void *p)
         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 = ip4_addr->addr;
-
-            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( ctx->sockfd+1, &readfds, 0, 0, &tv );
-                    if (result > 0) {
-                        if (FD_ISSET( ctx->sockfd, &readfds ))
-                            coap_read(ctx);
-                    } else if (result < 0) {
-                        break;
-                    } else {
-                        ESP_LOGE(TAG, "select timeout");
-                    }
-                }
+        if (uri.path.length) {
+            buflen = BUFSIZE;
+            buf = _buf;
+            res = coap_split_path(uri.path.s, uri.path.length, buf, &buflen);
+
+            while (res--) {
+                coap_insert_optlist(&optlist,
+                    coap_new_optlist(COAP_OPTION_URI_PATH,
+                    coap_opt_length(buf),
+                    coap_opt_value(buf)));
+
+                buf += coap_opt_size(buf);
+            }
+        }
+
+        if (uri.query.length) {
+            buflen = BUFSIZE;
+            buf = _buf;
+            res = coap_split_query(uri.query.s, uri.query.length, buf, &buflen);
+
+            while (res--) {
+                coap_insert_optlist(&optlist,
+                    coap_new_optlist(COAP_OPTION_URI_QUERY,
+                    coap_opt_length(buf),
+                    coap_opt_value(buf)));
+
+                buf += coap_opt_size(buf);
+            }
+        }
+
+        ctx = coap_new_context(NULL);
+        if (!ctx) {
+           ESP_LOGE(TAG, "coap_new_context() failed");
+           goto clean_up;
+        }
+
+        coap_address_init(&dst_addr);
+        dst_addr.addr.sin.sin_family      = AF_INET;
+        dst_addr.addr.sin.sin_port        = htons(uri.port);
+        dst_addr.addr.sin.sin_addr.s_addr = ip4_addr->addr;
+
+        session = coap_new_client_session(ctx, &src_addr, &dst_addr,
+           uri.scheme==COAP_URI_SCHEME_COAP_TCP ? COAP_PROTO_TCP :
+           uri.scheme==COAP_URI_SCHEME_COAPS_TCP ? COAP_PROTO_TLS :
+           uri.scheme==COAP_URI_SCHEME_COAPS ? COAP_PROTO_DTLS : COAP_PROTO_UDP);
+        if (!session) {
+           ESP_LOGE(TAG, "coap_new_client_session() failed");
+           goto clean_up;
+        }
+
+        coap_register_response_handler(ctx, message_handler);
+
+        request = coap_new_pdu(session);
+        if (!request) {
+           ESP_LOGE(TAG, "coap_new_pdu() failed");
+           goto clean_up;
+        }
+        request->type = COAP_MESSAGE_CON;
+        request->tid = coap_new_message_id(session);
+        request->code = COAP_REQUEST_GET;
+        coap_add_optlist_pdu(request, &optlist);
+
+        resp_wait = 1;
+        coap_send(session, request);
+
+        wait_ms = COAP_DEFAULT_TIME_SEC * 1000;
+
+        while (resp_wait) {
+            int result = coap_run_once(ctx, wait_ms > 1000 ? 1000 : wait_ms);
+            if (result >= 0) {
+               if (result >= wait_ms) {
+                  ESP_LOGE(TAG, "select timeout");
+                  break;
+               } else {
+                  wait_ms -= result;
+               } 
             }
-            coap_free_context(ctx);
         }
+clean_up:
+        if (optlist) {
+            coap_delete_optlist(optlist);
+            optlist = NULL;
+        }
+        if (session) coap_session_release(session);
+        if (ctx) coap_free_context(ctx);
+        coap_cleanup();
+        /* Only send the request off once */
+        break;
     }
 
     vTaskDelete(NULL);
@@ -210,5 +344,5 @@ void app_main(void)
 {
     ESP_ERROR_CHECK( nvs_flash_init() );
     wifi_conn_init();
-    xTaskCreate(coap_example_task, "coap", 2048, NULL, 5, NULL);
+    xTaskCreate(coap_example_task, "coap", 1024 * 5, NULL, 5, NULL);
 }

+ 10 - 5
examples/protocols/coap_server/README.md

@@ -51,13 +51,18 @@ I (1692) wifi: pm start, type: 1
 
 I (2622) event: sta ip: 192.168.3.84, mask: 255.255.255.0, gw: 192.168.3.1
 I (2622) CoAP_server: Connected to AP
-E (7622) CoAP_server: select timeout
-E (12622) CoAP_server: select timeout
-E (17622) CoAP_server: select timeout
 ...
 ```
 
-if a CoAP client query `/Espressif` resource, CoAP server would return `"Hello World!"`  
+if a CoAP client query `/Espressif` resource, CoAP server would return `"no data"`  
+until a CoAP client does a PUT with some data.
+
+## libcoap Documentation
+This can be found at https://libcoap.net/doc/reference/4.2.0/
 
 ## Troubleshooting
-* Please make sure CoAP client fetchs data under path: `/Espressif`
+* Please make sure CoAP client fetchs or puts data under path: `/Espressif` or
+fetches `/.well-known/core`
+
+* libcoap logging can be increased by changing `#define COAP_LOGGING_LEVEL 0`
+to `#define COAP_LOGGING_LEVEL 9`

+ 106 - 67
examples/protocols/coap_server/main/coap_server_example_main.c

@@ -31,8 +31,8 @@
 #define EXAMPLE_WIFI_SSID            CONFIG_WIFI_SSID
 #define EXAMPLE_WIFI_PASS            CONFIG_WIFI_PASSWORD
 
-#define COAP_DEFAULT_TIME_SEC 5
-#define COAP_DEFAULT_TIME_USEC 0
+/* Set this to 9 to get verbose logging from within libcoap */
+#define COAP_LOGGING_LEVEL 0
 
 static EventGroupHandle_t wifi_event_group;
 
@@ -42,53 +42,86 @@ static EventGroupHandle_t wifi_event_group;
 const static int CONNECTED_BIT = BIT0;
 
 const static char *TAG = "CoAP_server";
+static char espressif_data[100];
+static int espressif_data_len = 0;
 
-static coap_async_state_t *async = NULL;
+/*
+ * The resource handler
+ */
+static void
+hnd_espressif_get(coap_context_t *ctx, coap_resource_t *resource,
+                  coap_session_t *session,
+                  coap_pdu_t *request, coap_binary_t *token,
+                  coap_string_t *query, coap_pdu_t *response)
+{
+    coap_add_data_blocked_response(resource, session, request, response, token,
+                                   COAP_MEDIATYPE_TEXT_PLAIN, 0,
+                                   (size_t)espressif_data_len,
+                                   (const u_char *)espressif_data);
+}
 
 static void
-send_async_response(coap_context_t *ctx, const coap_endpoint_t *local_if)
+hnd_espressif_put(coap_context_t *ctx,
+                  coap_resource_t *resource,
+                  coap_session_t *session,
+                  coap_pdu_t *request,
+                  coap_binary_t *token,
+                  coap_string_t *query,
+                  coap_pdu_t *response)
 {
-    coap_pdu_t *response;
-    unsigned char buf[3];
-    const char* response_data     = "Hello World!";
-    response = coap_pdu_init(async->flags & COAP_MESSAGE_CON, COAP_RESPONSE_CODE(205), 0, COAP_MAX_PDU_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) {
+    size_t size;
+    unsigned char *data;
+
+    coap_resource_notify_observers(resource, NULL);
+
+    if (strcmp (espressif_data, "no data") == 0) {
+        response->code = COAP_RESPONSE_CODE(201);
+    }
+    else {
+        response->code = COAP_RESPONSE_CODE(204);
+    }
+
+    /* coap_get_data() sets size to 0 on error */
+    (void)coap_get_data(request, &size, &data);
 
+    if (size == 0) {      /* re-init */
+        snprintf(espressif_data, sizeof(espressif_data), "no data");
+        espressif_data_len = strlen(espressif_data);
+    } else {
+        espressif_data_len = size > sizeof (espressif_data) ? sizeof (espressif_data) : size;
+        memcpy (espressif_data, data, espressif_data_len);
     }
-    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)
+hnd_espressif_delete(coap_context_t *ctx,
+                     coap_resource_t *resource,
+                     coap_session_t *session,
+                     coap_pdu_t *request,
+                     coap_binary_t *token,
+                     coap_string_t *query,
+                     coap_pdu_t *response)
 {
-    async = coap_register_async(ctx, peer, request, COAP_ASYNC_SEPARATE | COAP_ASYNC_CONFIRM, (void*)"no data");
+    coap_resource_notify_observers(resource, NULL);
+    snprintf(espressif_data, sizeof(espressif_data), "no data");
+    espressif_data_len = strlen(espressif_data);
+    response->code = COAP_RESPONSE_CODE(202);
 }
 
 static void coap_example_thread(void *p)
 {
-    coap_context_t*  ctx = NULL;
+    coap_context_t *ctx = NULL;
     coap_address_t   serv_addr;
-    coap_resource_t* resource = NULL;
-    fd_set           readfds;
-    struct timeval tv;
-    int flags = 0;
+    coap_resource_t *resource = NULL;
 
+    snprintf(espressif_data, sizeof(espressif_data), "no data");
+    espressif_data_len = strlen(espressif_data);
+    coap_set_log_level(COAP_LOGGING_LEVEL);
     while (1) {
+        coap_endpoint_t *ep_udp = NULL;
+        coap_endpoint_t *ep_tcp = NULL;
+        unsigned wait_ms;
+
         /* Wait for the callback to set the CONNECTED_BIT in the
            event group.
         */
@@ -101,43 +134,49 @@ static void coap_example_thread(void *p)
         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( ctx->sockfd+1, &readfds, 0, 0, &tv );
-                    if (result > 0){
-                        if (FD_ISSET( ctx->sockfd, &readfds ))
-                            coap_read(ctx);
-                    } else if (result < 0){
-                        break;
-                    } else {
-                        ESP_LOGE(TAG, "select timeout");
-                    }
-
-                    if (async) {
-                        send_async_response(ctx, ctx->endpoint);
-                    }
-                }
-            }
 
-            coap_free_context(ctx);
+        ctx = coap_new_context(NULL);
+        if (!ctx) {
+           continue;
+        }
+        ep_udp = coap_new_endpoint(ctx, &serv_addr, COAP_PROTO_UDP);
+        if (!ep_udp) {
+           goto clean_up;
+        }
+        ep_tcp = coap_new_endpoint(ctx, &serv_addr, COAP_PROTO_TCP);
+        if (!ep_tcp) {
+           goto clean_up;
+        }
+        resource = coap_resource_init(coap_make_str_const("Espressif"), 0);
+        if (!resource) {
+           goto clean_up;
+        }
+        coap_register_handler(resource, COAP_REQUEST_GET, hnd_espressif_get);
+        coap_register_handler(resource, COAP_REQUEST_PUT, hnd_espressif_put);
+        coap_register_handler(resource, COAP_REQUEST_DELETE, hnd_espressif_delete);
+        /* We possibly want to Observe the GETs */
+        coap_resource_set_get_observable(resource, 1);
+        coap_add_resource(ctx, resource);
+
+        wait_ms = COAP_RESOURCE_CHECK_TIME * 1000;
+
+        while (1) {
+            int result = coap_run_once(ctx, wait_ms);
+            if (result < 0) {
+                break;
+            } else if (result && (unsigned)result < wait_ms) {
+                /* decrement if there is a result wait time returned */
+                wait_ms -= result;
+            }
+            if (result) {
+                /* result must have been >= wait_ms, so reset wait_ms */
+                wait_ms = COAP_RESOURCE_CHECK_TIME * 1000;
+            }
         }
     }
+clean_up:
+    coap_free_context(ctx);
+    coap_cleanup();
 
     vTaskDelete(NULL);
 }
@@ -187,5 +226,5 @@ void app_main(void)
     ESP_ERROR_CHECK( nvs_flash_init() );
     wifi_conn_init();
 
-    xTaskCreate(coap_example_thread, "coap", 2048, NULL, 5, NULL);
+    xTaskCreate(coap_example_thread, "coap", 1024 * 5, NULL, 5, NULL);
 }