Explorar o código

libcoap support
add libcoap submodule
add examples based on rtthread
update README

MurphyZhao %!s(int64=8) %!d(string=hai) anos
pai
achega
53f4159587

+ 3 - 0
.gitmodules

@@ -0,0 +1,3 @@
+[submodule "libcoap"]
+      path = libcoap
+      url = https://github.com/obgm/libcoap.git

+ 59 - 2
README.md

@@ -1,2 +1,59 @@
-# coap
-CoAP on RT-Thread
+# CoAP: Constrained Application Protocol (RFC 7252)  
+This coap repository is based on `master` branch `@b425b150` commit of [libcoap](https://github.com/obgm/libcoap/tree/b425b150c2fdf0d24810bb6af55db4f6d4fb65b8).   
+For further information related to CoAP, see http://coap.technology.  
+
+## How to Use in rt-thread  
+
+### 1 Get `CoAP` Package  
+CoAP package Path in `menuconfig` :   
+`RT-Thread online packages/IoT/CoAP`.  
+
+### 2 Open MSH Support  
+Config in `menuconfig` :   
+`RT-Thread Components/Command shell/Using mode shell`  
+
+Modify MSH consle buffer in `menuconfig` :   
+Set `RT-Thread Kernel/Kernel Device Object/the buffer size for console log printf` as `512`      
+
+### 3 Compile and Download  
+If there are some `errors` after compiled , please refer to the following [Notes](#Notes) 
+
+### 4 Run Example   
+Use coap_client to request `coap.me/test`  
+
+#### 4.1 coap client example  
+Using `-m` param to select coap client request method , it only realize `get` method.  
+```
+msh />coap_client -m get coap://coap.me/test
+uri.path.s = test; uri.host.s = coap.me/test 
+server_host = coap.me
+DNS lookup succeeded. IP=134.102.218.18
+welcome to the ETSI plugtest! last change: 2018-01-15 13:55:19 UTC
+```
+
+#### 4.2 coap server example  
+
+```
+msh />coap_server 
+```
+Default coap server uri is `coap://yourserveripaddr/rtthread` , use another coap_client to request this server as `coap_client -m get coap://yourserveripaddr/rtthread` , then client will return `Hello rtthread!` message.   
+
+<span id="Notes"></span>
+## Notes  
+### 1 `strings.h` no define problem  
+
+ Modify `libcoap/include/coap/encode.h` at line 13 as `#if (BSD >= 199103) || defined(WITH_CONTIKI) || defined(RTTHREAD_VERSION)`  
+
+### 2 `sys/select.h` or `sys/socket.h` can't found problem    
+
+Config in `menuconfig` :   
+Don't select `RT-Thread Component/Device virtual file system/Enable BSD socket/Toolchain sys/select.h` and `Toolchain sys/socket.h`.  
+
+### 3 `FD_SETSIZE` too small problem  
+Config in `menuconfig` :   
+The `RT-Thread Component/Device virtual file system/The maximal number of opened files` value need to  greater or equal to `RT-Thread Component/Network stack/light weight TCP/IP stack/The number of raw connection` value.  
+
+## Reference    
+1 CoAP Official website: [http://coap.technology/](http://coap.technology/)  
+2 CoAP test server: [coap.me](http://coap.me/)  
+   

+ 43 - 0
SConscript

@@ -0,0 +1,43 @@
+
+import os
+import rtconfig
+from building import *
+
+cwd = GetCurrentDir()
+coap_src_dir = cwd + '/libcoap/src'
+
+src = Split('''
+libcoap/src/address.c
+libcoap/src/async.c
+libcoap/src/block.c
+libcoap/src/coap_time.c
+libcoap/src/debug.c
+libcoap/src/encode.c
+libcoap/src/hashkey.c
+libcoap/src/mem.c
+libcoap/src/net.c
+libcoap/src/option.c
+libcoap/src/pdu.c
+libcoap/src/resource.c
+libcoap/src/str.c
+libcoap/src/subscribe.c
+libcoap/src/uri.c
+coap-rtthread/coap_io_rt.c
+''')
+
+CPPPATH = [cwd + '/libcoap/include']
+CPPPATH += [cwd + '/libcoap/include/coap']
+CPPPATH += [cwd + '/coap-rtthread']
+CPPPATH += [cwd + '/coap-rtthread/include']
+
+CPPDEFINES = ['WITH_POSIX']
+
+LOCAL_CCFLAGS = ''
+
+if rtconfig.CROSS_TOOL == 'keil':
+    LOCAL_CCFLAGS += ' --gnu'
+
+group = DefineGroup('coap', src, depend = ['PKG_USING_COAP', 'RT_USING_LWIP', 'RT_USING_LWIP_IPV6', 'RT_USING_LIBC', 'RT_USING_POSIX', 'RT_USING_DFS', 'RT_USING_DFS_NET'], CPPPATH = CPPPATH, LOCAL_CCFLAGS = LOCAL_CCFLAGS, CPPDEFINES = CPPDEFINES)
+group += SConscript('examples/SConscript')
+
+Return('group')

+ 460 - 0
coap-rtthread/coap_io_rt.c

@@ -0,0 +1,460 @@
+/* coap_io_rt.h -- Default network I/O functions for libcoap
+ *
+ * Copyright (C) 2012,2014 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see
+ * README for terms of use. 
+ */
+
+#include "coap_config.h"
+#include <rtthread.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 "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 SOCK_BUFFER_LEN (1024 + 512)
+  char *sock_buffer = NULL;
+  struct sockaddr_in sock_addr_src;
+  socklen_t socklen_src = 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
+  sock_buffer = coap_malloc(SOCK_BUFFER_LEN);
+  if (sock_buffer){
+	  len = recvfrom(ep->handle.fd, sock_buffer, SOCK_BUFFER_LEN, 0, (struct sockaddr *)&sock_addr_src, (socklen_t *)&socklen_src);
+
+	  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, &sock_addr_src, (*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, sock_buffer, len);
+	  }
+
+	  coap_free(sock_buffer);
+	  sock_buffer = 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 (sock_buffer)
+ 		coap_free(sock_buffer);
+ 	sock_buffer = NULL;
+#endif
+  coap_free_packet(*packet);
+  *packet = NULL;
+  return -1;
+}
+
+#undef SIN6
+
+#endif /*  CUSTOM_COAP_NETWORK_READ */

+ 44 - 0
coap-rtthread/include/coap.h

@@ -0,0 +1,44 @@
+
+/* coap.h
+ *
+ * Copyright (C) 2012,2014 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * 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__ */

+ 49 - 0
coap-rtthread/include/coap_config.h

@@ -0,0 +1,49 @@
+
+/* coap_config.h
+ *
+ * Copyright (C) 2012,2014 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see
+ * README for terms of use. 
+ */
+
+#ifndef __COAP_CONFIG_H__
+#define __COAP_CONFIG_H__
+
+#include <rtthread.h>
+
+// Defined in SConscript's CPPDEFINES
+#ifdef WITH_POSIX
+#include <sys/socket.h>
+
+#define HAVE_MALLOC
+
+#define IP_PKTINFO   IP_MULTICAST_IF
+// #define IPV6_PKTINFO IPV6_V6ONLY
+
+#define PACKAGE_NAME "libcoap"
+#define PACKAGE_VERSION "@b425b150"
+
+#define CUSTOM_COAP_NETWORK_ENDPOINT
+#define CUSTOM_COAP_NETWORK_SEND
+#define CUSTOM_COAP_NETWORK_READ
+
+#endif
+
+#define HAVE_STDIO_H
+#define HAVE_ASSERT_H
+
+#define PACKAGE_STRING PACKAGE_NAME PACKAGE_VERSION
+
+// #define assert(x) LWIP_ASSERT("CoAP assert failed", x)
+
+/* 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_ */

+ 16 - 0
examples/SConscript

@@ -0,0 +1,16 @@
+
+import os
+from building import *
+
+cwd = GetCurrentDir()
+
+src = Split('''
+coap_client.c
+coap_server.c
+''')
+
+CPPPATH = [cwd ]
+
+group = DefineGroup('coap-examples', src, depend = ['PKG_USING_COAP_EXAMPLE', 'PKG_USING_COAP', 'RT_USING_LWIP', 'RT_USING_LWIP_IPV6', 'RT_USING_LIBC', 'RT_USING_POSIX', 'RT_USING_DFS', 'RT_USING_DFS_NET'], CPPPATH = CPPPATH)
+
+Return('group')

+ 323 - 0
examples/coap_client.c

@@ -0,0 +1,323 @@
+/*
+* File      : coap_client.c
+* This file is part of RT-Thread RTOS
+* COPYRIGHT (C) 2009-2018 RT-Thread Develop Team
+*/
+
+#include <rtthread.h>
+#include "finsh.h"
+
+#include <string.h>
+#include <sys/socket.h>
+#include <netdb.h>
+
+#include "coap.h"
+#include "coap_config.h"
+
+#define COAP_DEFAULT_DEMO_URI "coap://coap.me/test"
+
+#define COAP_DEFAULT_TIME_SEC 5
+#define COAP_DEFAULT_TIME_USEC 0
+
+static uint8_t coap_request_mode = 0;
+char coap_uri[64] = {0};
+static coap_uri_t uri;
+
+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;
+    coap_opt_t *block_opt;
+    coap_pdu_t *request = NULL;
+    unsigned char buf[4];
+    coap_opt_iterator_t opt_iter;
+
+    coap_tid_t tid;
+
+    if (COAP_RESPONSE_CLASS(received->hdr->code) == 2)
+    {
+
+        if (coap_get_data(received, &data_len, &data))
+        {
+            rt_kprintf("%.*s", data_len, data);
+        }
+        /* Got some data, check if block option is set. Behavior is undefined if
+     * both, Block1 and Block2 are present. */
+        block_opt = coap_check_option(received, COAP_OPTION_BLOCK2, &opt_iter);
+        if (block_opt)
+        { /* handle Block2 */
+            unsigned short blktype = opt_iter.type;
+            if (COAP_OPT_BLOCK_MORE(block_opt))
+            {
+                request = coap_new_pdu();
+
+                if (request)
+                {
+                    // CoAP message type
+                    request->hdr->type = COAP_MESSAGE_CON;
+                    request->hdr->id = coap_new_message_id(ctx);
+
+                    // CoAP request methods
+                    request->hdr->code = coap_request_mode;
+
+                    coap_add_option(request, COAP_OPTION_URI_PATH, uri.path.length, uri.path.s);
+
+                    coap_add_option(request,
+                                    blktype,
+                                    coap_encode_var_bytes(buf,
+                                                          ((coap_opt_block_num(block_opt) + 1) << 4) |
+                                                              COAP_OPT_BLOCK_SZX(block_opt)),
+                                    buf);
+
+                    tid = coap_send_confirmed(ctx, local_interface, remote, request);
+                    if (tid == COAP_INVALID_TID)
+                    {
+                        rt_kprintf("message_handler: error sending new request\n");
+                        coap_delete_pdu(request);
+                        return;
+                    }
+                }
+            }
+        }
+    }
+}
+
+void coap_client_task(void *arg)
+{
+    struct hostent *hp;
+    struct ip4_addr *ip4_addr;
+
+    coap_tick_t now;
+
+    coap_context_t *ctx = NULL;
+    coap_address_t dst_addr, src_addr;
+
+    fd_set readfds;
+    struct timeval tv;
+    int result;
+    coap_pdu_t *request = NULL;
+
+    const char *server_uri = RT_NULL;
+    char server_host[64] = {0};
+
+    if (strlen(coap_uri) != 0)
+        server_uri = coap_uri;
+    else
+        server_uri = COAP_DEFAULT_DEMO_URI;
+
+    /* CoAP request methods */
+    uint8_t get_method = coap_request_mode; // COAP_REQUEST_GET
+
+    if (coap_split_uri((const uint8_t *)server_uri, strlen(server_uri), &uri) == -1)
+    {
+        rt_kprintf("CoAP server uri error\n");
+        goto _exit;
+    }
+
+    char *str_s = (char *)uri.host.s;
+    char *dlm_s = (char *)"/";
+    char *str_t = RT_NULL, *saveptr = RT_NULL;
+
+    str_t = strtok_r(str_s, dlm_s, &saveptr);
+
+    if (str_t != RT_NULL)
+    {
+        rt_memset(server_host, 0, sizeof(server_host));
+        strncpy((char *)server_host, str_t, sizeof(server_host));
+        rt_kprintf("server_host = %s\n", server_host);
+    }
+    else
+    {
+        strncpy((char *)server_host, (const char *)uri.host.s, sizeof(server_host));
+        rt_kprintf("server_host = %s\n", server_host);
+    }
+
+    while (1)
+    {
+
+        // It may take several iterations for getting DNS success
+        hp = gethostbyname((const char *)server_host); // getaddrinfo
+        if (hp == NULL)
+        {
+            rt_kprintf("DNS lookup failed\n");
+            rt_thread_delay(1000);
+            continue; // Duplicate DNS GET
+        }
+
+        ip4_addr = (struct ip4_addr *)hp->h_addr;
+        rt_kprintf("DNS lookup succeeded. IP=%s\n", inet_ntoa(*ip4_addr));
+
+        // Reset the given coap_address_t object to its default values
+        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;
+
+        // Create a new object for holding coap stack status
+        ctx = coap_new_context(&src_addr);
+        if (ctx)
+        {
+            // Init destination addr
+            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;
+
+            coap_register_option(ctx, COAP_OPTION_BLOCK2);
+
+            // Register a received message handler
+            coap_register_response_handler(ctx, message_handler);
+
+            request = coap_new_pdu();
+            if (request)
+            {
+                // CoAP message type
+                request->hdr->type = COAP_MESSAGE_CON;
+                request->hdr->id = coap_new_message_id(ctx);
+                // CoAP request methods
+                request->hdr->code = get_method;
+
+                if (uri.path.length != 0)
+                {
+                    coap_add_option(request, COAP_OPTION_URI_PATH, uri.path.length, uri.path.s);
+                }
+
+                // Sends a confirmed CoAP message to given destination
+                int coap_ret = coap_send_confirmed(ctx, ctx->endpoint, &dst_addr, request);
+
+                tv.tv_usec = COAP_DEFAULT_TIME_USEC;
+                tv.tv_sec = COAP_DEFAULT_TIME_SEC;
+
+                coap_queue_t *nextpdu;
+
+                for (;;)
+                {
+                    FD_ZERO(&readfds);
+                    FD_SET(ctx->sockfd, &readfds);
+
+                    nextpdu = coap_peek_next(ctx);
+                    coap_ticks(&now);
+
+                    while (nextpdu && nextpdu->t <= now - ctx->sendqueue_basetime)
+                    {
+                        coap_retransmit(ctx, coap_pop_next(ctx));
+
+                        rt_kprintf("\nCoAP retransmit...\n");
+                        nextpdu = coap_peek_next(ctx);
+                    }
+
+                    if (!nextpdu)
+                    {
+                        rt_kprintf("\nTransmit end.\n");
+                        goto _exit;
+                    }
+
+                    result = select(ctx->sockfd + 1, &readfds, RT_NULL, RT_NULL, &tv);
+                    if (result > 0)
+                    {
+                        if (FD_ISSET(ctx->sockfd, &readfds))
+                            coap_read(ctx);
+                    }
+                    else if (result < 0)
+                    {
+                        break;
+                    }
+                    else
+                    {
+                        rt_kprintf("\nselect timeout...\n");
+                    }
+                }
+            }
+        }
+
+        goto _exit;
+    }
+
+_exit:
+    if (ctx != RT_NULL)
+        coap_free_context(ctx);
+    return;
+}
+
+static void usage(const char *program, const char *version)
+{
+    rt_kprintf("\nHelp:\nlibcoap %s -- a small CoAP implementation\n"
+               "usage: %s [-m type...] [Uri text]\n",
+               version, program);
+    rt_kprintf("\t\t type: get; post; put; delete.\n"
+               "Example: %s -m get coap://wsncoap.org\n",
+               program);
+}
+
+static uint8_t cmdline_method(char *arg)
+{
+    static char *methods[] = {0, "get", "post", "put", "delete", 0};
+    unsigned char i;
+
+    for (i = 1; methods[i] && strcasecmp(arg, methods[i]) != 0; ++i)
+        ;
+
+    return i; /* note that we do not prevent illegal methods */
+}
+
+int cmdline_option_parser(int argc, char **argv)
+{
+    int8_t ret = -1;
+
+    if (argc < 4)
+    {
+        rt_kprintf("\n======= CoAP client usage: ========\n");
+        usage(argv[0], PACKAGE_VERSION);
+        return ret;
+    }
+    else if (strstr(argv[3], "coap://") == RT_NULL) // judge uri format
+    {
+        rt_kprintf("Warning: param three is not allowed!\n");
+        usage(argv[0], PACKAGE_VERSION);
+        return ret;
+    }
+    else if (strcmp(argv[1], "-m") != 0)
+    {
+        rt_kprintf("Warning: in param is error, please use '-m' param.\n");
+        usage(argv[0], PACKAGE_VERSION);
+        return ret;
+    }
+
+    coap_request_mode = cmdline_method(argv[2]); //1:GET; 2:POST; 3:PUT; 4:DELETE
+
+    if (strlen(argv[3]) < sizeof(coap_uri))
+        strncpy((char *)coap_uri, (const char *)argv[3], sizeof(coap_uri));
+    else
+    {
+        rt_kprintf("Warning: coap uri is too long. The length of the limit is %d\n", sizeof(coap_uri) - 1);
+        return ret;
+    }
+
+    rt_kprintf("coap uri = %s\n", coap_uri);
+
+    ret = 0;
+    return ret;
+}
+
+static int coap_client(int argc, char **argv)
+{
+    rt_thread_t tid;
+    int8_t ret = 0;
+
+    ret = cmdline_option_parser(argc, argv);
+    if (ret != 0)
+        return ret;
+
+    tid = rt_thread_create("CoAPClient",
+                           coap_client_task, RT_NULL,
+                           4096,
+                           RT_THREAD_PRIORITY_MAX - 2,
+                           10);
+    if (tid != RT_NULL)
+        rt_thread_startup(tid);
+
+    return ret;
+}
+MSH_CMD_EXPORT(coap_client, Using coap_client to get usage);

+ 130 - 0
examples/coap_server.c

@@ -0,0 +1,130 @@
+/*
+* File      : coap_server.c
+* This file is part of RT-Thread RTOS
+* COPYRIGHT (C) 2009-2018 RT-Thread Develop Team
+*/
+
+#include <rtthread.h>
+#include "finsh.h"
+
+#include <string.h>
+#include <netdb.h>
+
+#include "coap.h"
+
+#define COAP_DEFAULT_TIME_SEC 5
+#define COAP_DEFAULT_TIME_USEC 0
+
+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 rtthread!";
+    size_t size = sizeof(coap_hdr_t) + strlen(response_data) + 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)
+    {
+        rt_kprintf("Error: coap send to client return error.\n");
+    }
+    coap_delete_pdu(response);
+    coap_async_state_t *tmp;
+    coap_remove_async(ctx, async->id, &tmp);
+    coap_free_async(async);
+    async = NULL;
+}
+
+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_server_task(void *arg)
+{
+    coap_context_t *ctx = NULL;
+    coap_address_t serv_addr;
+    coap_resource_t *resource = NULL;
+    fd_set readfds;
+    struct timeval tv;
+    int flags = 0;
+
+    for (;;)
+    {
+        /* 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)
+        {
+            tv.tv_usec = COAP_DEFAULT_TIME_USEC;
+            tv.tv_sec = COAP_DEFAULT_TIME_SEC;
+
+            /* Initialize the resource, first param is uri */
+            resource = coap_resource_init((unsigned char *)"rtthread", 8, 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
+                    {
+                        rt_kprintf("select waiting...\n");
+                    }
+
+                    if (async)
+                    {
+                        send_async_response(ctx, ctx->endpoint);
+                    }
+                }
+            }
+
+            coap_free_context(ctx);
+        }
+    }
+}
+
+static int coap_server(void)
+{
+    rt_thread_t tid;
+
+    tid = rt_thread_create("CoAPServer",
+                           coap_server_task, RT_NULL,
+                           4096,
+                           RT_THREAD_PRIORITY_MAX - 2,
+                           10);
+    if (tid != RT_NULL)
+        rt_thread_startup(tid);
+
+    return 0;        
+}
+MSH_CMD_EXPORT(coap_server, Start a coap server No input param);