coap_server_example_main.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  1. /* CoAP server Example
  2. This example code is in the Public Domain (or CC0 licensed, at your option.)
  3. Unless required by applicable law or agreed to in writing, this
  4. software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
  5. CONDITIONS OF ANY KIND, either express or implied.
  6. */
  7. /*
  8. * WARNING
  9. * libcoap is not multi-thread safe, so only this thread must make any coap_*()
  10. * calls. Any external (to this thread) data transmitted in/out via libcoap
  11. * therefore has to be passed in/out by xQueue*() via this thread.
  12. */
  13. #include <string.h>
  14. #include <sys/socket.h>
  15. #include "freertos/FreeRTOS.h"
  16. #include "freertos/task.h"
  17. #include "freertos/event_groups.h"
  18. #include "esp_log.h"
  19. #include "esp_wifi.h"
  20. #include "esp_event.h"
  21. #include "nvs_flash.h"
  22. #include "protocol_examples_common.h"
  23. #include "coap3/coap.h"
  24. #ifndef CONFIG_COAP_SERVER_SUPPORT
  25. #error COAP_SERVER_SUPPORT needs to be enabled
  26. #endif /* COAP_SERVER_SUPPORT */
  27. /* The examples use simple Pre-Shared-Key configuration that you can set via
  28. 'idf.py menuconfig'.
  29. If you'd rather not, just change the below entries to strings with
  30. the config you want - ie #define EXAMPLE_COAP_PSK_KEY "some-agreed-preshared-key"
  31. Note: PSK will only be used if the URI is prefixed with coaps://
  32. instead of coap:// and the PSK must be one that the server supports
  33. (potentially associated with the IDENTITY)
  34. */
  35. #define EXAMPLE_COAP_PSK_KEY CONFIG_EXAMPLE_COAP_PSK_KEY
  36. /* The examples use CoAP Logging Level that
  37. you can set via 'idf.py menuconfig'.
  38. If you'd rather not, just change the below entry to a value
  39. that is between 0 and 7 with
  40. the config you want - ie #define EXAMPLE_COAP_LOG_DEFAULT_LEVEL 7
  41. */
  42. #define EXAMPLE_COAP_LOG_DEFAULT_LEVEL CONFIG_COAP_LOG_DEFAULT_LEVEL
  43. const static char *TAG = "CoAP_server";
  44. static char espressif_data[100];
  45. static int espressif_data_len = 0;
  46. #ifdef CONFIG_COAP_MBEDTLS_PKI
  47. /* CA cert, taken from coap_ca.pem
  48. Server cert, taken from coap_server.crt
  49. Server key, taken from coap_server.key
  50. The PEM, CRT and KEY file are examples taken from
  51. https://github.com/eclipse/californium/tree/master/demo-certs/src/main/resources
  52. as the Certificate test (by default) for the coap_client is against the
  53. californium server.
  54. To embed it in the app binary, the PEM, CRT and KEY file is named
  55. in the component.mk COMPONENT_EMBED_TXTFILES variable.
  56. */
  57. extern uint8_t ca_pem_start[] asm("_binary_coap_ca_pem_start");
  58. extern uint8_t ca_pem_end[] asm("_binary_coap_ca_pem_end");
  59. extern uint8_t server_crt_start[] asm("_binary_coap_server_crt_start");
  60. extern uint8_t server_crt_end[] asm("_binary_coap_server_crt_end");
  61. extern uint8_t server_key_start[] asm("_binary_coap_server_key_start");
  62. extern uint8_t server_key_end[] asm("_binary_coap_server_key_end");
  63. #endif /* CONFIG_COAP_MBEDTLS_PKI */
  64. #define INITIAL_DATA "Hello World!"
  65. /*
  66. * The resource handler
  67. */
  68. static void
  69. hnd_espressif_get(coap_resource_t *resource,
  70. coap_session_t *session,
  71. const coap_pdu_t *request,
  72. const coap_string_t *query,
  73. coap_pdu_t *response)
  74. {
  75. coap_pdu_set_code(response, COAP_RESPONSE_CODE_CONTENT);
  76. coap_add_data_large_response(resource, session, request, response,
  77. query, COAP_MEDIATYPE_TEXT_PLAIN, 60, 0,
  78. (size_t)espressif_data_len,
  79. (const u_char *)espressif_data,
  80. NULL, NULL);
  81. }
  82. static void
  83. hnd_espressif_put(coap_resource_t *resource,
  84. coap_session_t *session,
  85. const coap_pdu_t *request,
  86. const coap_string_t *query,
  87. coap_pdu_t *response)
  88. {
  89. size_t size;
  90. size_t offset;
  91. size_t total;
  92. const unsigned char *data;
  93. coap_resource_notify_observers(resource, NULL);
  94. if (strcmp (espressif_data, INITIAL_DATA) == 0) {
  95. coap_pdu_set_code(response, COAP_RESPONSE_CODE_CREATED);
  96. } else {
  97. coap_pdu_set_code(response, COAP_RESPONSE_CODE_CHANGED);
  98. }
  99. /* coap_get_data_large() sets size to 0 on error */
  100. (void)coap_get_data_large(request, &size, &data, &offset, &total);
  101. if (size == 0) { /* re-init */
  102. snprintf(espressif_data, sizeof(espressif_data), INITIAL_DATA);
  103. espressif_data_len = strlen(espressif_data);
  104. } else {
  105. espressif_data_len = size > sizeof (espressif_data) ? sizeof (espressif_data) : size;
  106. memcpy (espressif_data, data, espressif_data_len);
  107. }
  108. }
  109. static void
  110. hnd_espressif_delete(coap_resource_t *resource,
  111. coap_session_t *session,
  112. const coap_pdu_t *request,
  113. const coap_string_t *query,
  114. coap_pdu_t *response)
  115. {
  116. coap_resource_notify_observers(resource, NULL);
  117. snprintf(espressif_data, sizeof(espressif_data), INITIAL_DATA);
  118. espressif_data_len = strlen(espressif_data);
  119. coap_pdu_set_code(response, COAP_RESPONSE_CODE_DELETED);
  120. }
  121. #ifdef CONFIG_COAP_MBEDTLS_PKI
  122. static int
  123. verify_cn_callback(const char *cn,
  124. const uint8_t *asn1_public_cert,
  125. size_t asn1_length,
  126. coap_session_t *session,
  127. unsigned depth,
  128. int validated,
  129. void *arg
  130. )
  131. {
  132. coap_log(LOG_INFO, "CN '%s' presented by server (%s)\n",
  133. cn, depth ? "CA" : "Certificate");
  134. return 1;
  135. }
  136. #endif /* CONFIG_COAP_MBEDTLS_PKI */
  137. static void
  138. coap_log_handler (coap_log_t level, const char *message)
  139. {
  140. uint32_t esp_level = ESP_LOG_INFO;
  141. char *cp = strchr(message, '\n');
  142. if (cp)
  143. ESP_LOG_LEVEL(esp_level, TAG, "%.*s", (int)(cp-message), message);
  144. else
  145. ESP_LOG_LEVEL(esp_level, TAG, "%s", message);
  146. }
  147. static void coap_example_server(void *p)
  148. {
  149. coap_context_t *ctx = NULL;
  150. coap_address_t serv_addr;
  151. coap_resource_t *resource = NULL;
  152. snprintf(espressif_data, sizeof(espressif_data), INITIAL_DATA);
  153. espressif_data_len = strlen(espressif_data);
  154. coap_set_log_handler(coap_log_handler);
  155. coap_set_log_level(EXAMPLE_COAP_LOG_DEFAULT_LEVEL);
  156. while (1) {
  157. coap_endpoint_t *ep = NULL;
  158. unsigned wait_ms;
  159. int have_dtls = 0;
  160. /* Prepare the CoAP server socket */
  161. coap_address_init(&serv_addr);
  162. serv_addr.addr.sin6.sin6_family = AF_INET6;
  163. serv_addr.addr.sin6.sin6_port = htons(COAP_DEFAULT_PORT);
  164. ctx = coap_new_context(NULL);
  165. if (!ctx) {
  166. ESP_LOGE(TAG, "coap_new_context() failed");
  167. continue;
  168. }
  169. coap_context_set_block_mode(ctx,
  170. COAP_BLOCK_USE_LIBCOAP|COAP_BLOCK_SINGLE_BODY);
  171. #ifdef CONFIG_COAP_MBEDTLS_PSK
  172. /* Need PSK setup before we set up endpoints */
  173. coap_context_set_psk(ctx, "CoAP",
  174. (const uint8_t *)EXAMPLE_COAP_PSK_KEY,
  175. sizeof(EXAMPLE_COAP_PSK_KEY) - 1);
  176. #endif /* CONFIG_COAP_MBEDTLS_PSK */
  177. #ifdef CONFIG_COAP_MBEDTLS_PKI
  178. /* Need PKI setup before we set up endpoints */
  179. unsigned int ca_pem_bytes = ca_pem_end - ca_pem_start;
  180. unsigned int server_crt_bytes = server_crt_end - server_crt_start;
  181. unsigned int server_key_bytes = server_key_end - server_key_start;
  182. coap_dtls_pki_t dtls_pki;
  183. memset (&dtls_pki, 0, sizeof(dtls_pki));
  184. dtls_pki.version = COAP_DTLS_PKI_SETUP_VERSION;
  185. if (ca_pem_bytes) {
  186. /*
  187. * Add in additional certificate checking.
  188. * This list of enabled can be tuned for the specific
  189. * requirements - see 'man coap_encryption'.
  190. *
  191. * Note: A list of root ca file can be setup separately using
  192. * coap_context_set_pki_root_cas(), but the below is used to
  193. * define what checking actually takes place.
  194. */
  195. dtls_pki.verify_peer_cert = 1;
  196. dtls_pki.check_common_ca = 1;
  197. dtls_pki.allow_self_signed = 1;
  198. dtls_pki.allow_expired_certs = 1;
  199. dtls_pki.cert_chain_validation = 1;
  200. dtls_pki.cert_chain_verify_depth = 2;
  201. dtls_pki.check_cert_revocation = 1;
  202. dtls_pki.allow_no_crl = 1;
  203. dtls_pki.allow_expired_crl = 1;
  204. dtls_pki.allow_bad_md_hash = 1;
  205. dtls_pki.allow_short_rsa_length = 1;
  206. dtls_pki.validate_cn_call_back = verify_cn_callback;
  207. dtls_pki.cn_call_back_arg = NULL;
  208. dtls_pki.validate_sni_call_back = NULL;
  209. dtls_pki.sni_call_back_arg = NULL;
  210. }
  211. dtls_pki.pki_key.key_type = COAP_PKI_KEY_PEM_BUF;
  212. dtls_pki.pki_key.key.pem_buf.public_cert = server_crt_start;
  213. dtls_pki.pki_key.key.pem_buf.public_cert_len = server_crt_bytes;
  214. dtls_pki.pki_key.key.pem_buf.private_key = server_key_start;
  215. dtls_pki.pki_key.key.pem_buf.private_key_len = server_key_bytes;
  216. dtls_pki.pki_key.key.pem_buf.ca_cert = ca_pem_start;
  217. dtls_pki.pki_key.key.pem_buf.ca_cert_len = ca_pem_bytes;
  218. coap_context_set_pki(ctx, &dtls_pki);
  219. #endif /* CONFIG_COAP_MBEDTLS_PKI */
  220. ep = coap_new_endpoint(ctx, &serv_addr, COAP_PROTO_UDP);
  221. if (!ep) {
  222. ESP_LOGE(TAG, "udp: coap_new_endpoint() failed");
  223. goto clean_up;
  224. }
  225. if (coap_tcp_is_supported()) {
  226. ep = coap_new_endpoint(ctx, &serv_addr, COAP_PROTO_TCP);
  227. if (!ep) {
  228. ESP_LOGE(TAG, "tcp: coap_new_endpoint() failed");
  229. goto clean_up;
  230. }
  231. }
  232. #if defined(CONFIG_COAP_MBEDTLS_PSK) || defined(CONFIG_COAP_MBEDTLS_PKI)
  233. if (coap_dtls_is_supported()) {
  234. #ifndef CONFIG_MBEDTLS_TLS_SERVER
  235. /* This is not critical as unencrypted support is still available */
  236. ESP_LOGI(TAG, "MbedTLS DTLS Server Mode not configured");
  237. #else /* CONFIG_MBEDTLS_TLS_SERVER */
  238. serv_addr.addr.sin6.sin6_port = htons(COAPS_DEFAULT_PORT);
  239. ep = coap_new_endpoint(ctx, &serv_addr, COAP_PROTO_DTLS);
  240. if (!ep) {
  241. ESP_LOGE(TAG, "dtls: coap_new_endpoint() failed");
  242. goto clean_up;
  243. }
  244. have_dtls = 1;
  245. #endif /* CONFIG_MBEDTLS_TLS_SERVER */
  246. }
  247. if (coap_tls_is_supported()) {
  248. #ifndef CONFIG_MBEDTLS_TLS_SERVER
  249. /* This is not critical as unencrypted support is still available */
  250. ESP_LOGI(TAG, "MbedTLS TLS Server Mode not configured");
  251. #else /* CONFIG_MBEDTLS_TLS_SERVER */
  252. serv_addr.addr.sin6.sin6_port = htons(COAPS_DEFAULT_PORT);
  253. ep = coap_new_endpoint(ctx, &serv_addr, COAP_PROTO_TLS);
  254. if (!ep) {
  255. ESP_LOGE(TAG, "tls: coap_new_endpoint() failed");
  256. goto clean_up;
  257. }
  258. #endif /* CONFIG_MBEDTLS_TLS_SERVER */
  259. }
  260. if (!have_dtls) {
  261. /* This is not critical as unencrypted support is still available */
  262. ESP_LOGI(TAG, "MbedTLS (D)TLS Server Mode not configured");
  263. }
  264. #endif /* CONFIG_COAP_MBEDTLS_PSK || CONFIG_COAP_MBEDTLS_PKI */
  265. resource = coap_resource_init(coap_make_str_const("Espressif"), 0);
  266. if (!resource) {
  267. ESP_LOGE(TAG, "coap_resource_init() failed");
  268. goto clean_up;
  269. }
  270. coap_register_handler(resource, COAP_REQUEST_GET, hnd_espressif_get);
  271. coap_register_handler(resource, COAP_REQUEST_PUT, hnd_espressif_put);
  272. coap_register_handler(resource, COAP_REQUEST_DELETE, hnd_espressif_delete);
  273. /* We possibly want to Observe the GETs */
  274. coap_resource_set_get_observable(resource, 1);
  275. coap_add_resource(ctx, resource);
  276. #if defined(CONFIG_EXAMPLE_COAP_MCAST_IPV4) || defined(CONFIG_EXAMPLE_COAP_MCAST_IPV6)
  277. esp_netif_t *netif = NULL;
  278. for (int i = 0; i < esp_netif_get_nr_of_ifs(); ++i) {
  279. char buf[8];
  280. netif = esp_netif_next(netif);
  281. esp_netif_get_netif_impl_name(netif, buf);
  282. #if defined(CONFIG_EXAMPLE_COAP_MCAST_IPV4)
  283. coap_join_mcast_group_intf(ctx, CONFIG_EXAMPLE_COAP_MULTICAST_IPV4_ADDR, buf);
  284. #endif /* CONFIG_EXAMPLE_COAP_MCAST_IPV4 */
  285. #if defined(CONFIG_EXAMPLE_COAP_MCAST_IPV6)
  286. /* When adding IPV6 esp-idf requires ifname param to be filled in */
  287. coap_join_mcast_group_intf(ctx, CONFIG_EXAMPLE_COAP_MULTICAST_IPV6_ADDR, buf);
  288. #endif /* CONFIG_EXAMPLE_COAP_MCAST_IPV6 */
  289. }
  290. #endif /* CONFIG_EXAMPLE_COAP_MCAST_IPV4 || CONFIG_EXAMPLE_COAP_MCAST_IPV6 */
  291. wait_ms = COAP_RESOURCE_CHECK_TIME * 1000;
  292. while (1) {
  293. int result = coap_io_process(ctx, wait_ms);
  294. if (result < 0) {
  295. break;
  296. } else if (result && (unsigned)result < wait_ms) {
  297. /* decrement if there is a result wait time returned */
  298. wait_ms -= result;
  299. }
  300. if (result) {
  301. /* result must have been >= wait_ms, so reset wait_ms */
  302. wait_ms = COAP_RESOURCE_CHECK_TIME * 1000;
  303. }
  304. }
  305. }
  306. clean_up:
  307. coap_free_context(ctx);
  308. coap_cleanup();
  309. vTaskDelete(NULL);
  310. }
  311. void app_main(void)
  312. {
  313. ESP_ERROR_CHECK( nvs_flash_init() );
  314. ESP_ERROR_CHECK(esp_netif_init());
  315. ESP_ERROR_CHECK(esp_event_loop_create_default());
  316. /* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
  317. * Read "Establishing Wi-Fi or Ethernet Connection" section in
  318. * examples/protocols/README.md for more information about this function.
  319. */
  320. ESP_ERROR_CHECK(example_connect());
  321. xTaskCreate(coap_example_server, "coap", 8 * 1024, NULL, 5, NULL);
  322. }