1c87c5fbaSopenharmony_ci/*
2c87c5fbaSopenharmony_ci * client-coap.c -- LwIP example
3c87c5fbaSopenharmony_ci *
4c87c5fbaSopenharmony_ci * Copyright (C) 2013-2016 Christian Amsüss <chrysn@fsfe.org>
5c87c5fbaSopenharmony_ci * Copyright (C) 2018-2023 Jon Shallow <supjps-libcoap@jpshallow.com>
6c87c5fbaSopenharmony_ci *
7c87c5fbaSopenharmony_ci * SPDX-License-Identifier: BSD-2-Clause
8c87c5fbaSopenharmony_ci *
9c87c5fbaSopenharmony_ci * This file is part of the CoAP library libcoap. Please see README for terms
10c87c5fbaSopenharmony_ci * of use.
11c87c5fbaSopenharmony_ci */
12c87c5fbaSopenharmony_ci
13c87c5fbaSopenharmony_ci#include "coap_config.h"
14c87c5fbaSopenharmony_ci#include <coap3/coap.h>
15c87c5fbaSopenharmony_ci#include <sys/types.h>
16c87c5fbaSopenharmony_ci#include <sys/socket.h>
17c87c5fbaSopenharmony_ci#include <netdb.h>
18c87c5fbaSopenharmony_ci#include "client-coap.h"
19c87c5fbaSopenharmony_ci
20c87c5fbaSopenharmony_ci#ifndef COAP_URI
21c87c5fbaSopenharmony_ci#define COAP_URI "coap://libcoap.net"
22c87c5fbaSopenharmony_ci#endif /* COAP_URI */
23c87c5fbaSopenharmony_ci
24c87c5fbaSopenharmony_ci#ifndef min
25c87c5fbaSopenharmony_ci#define min(a,b) ((a) < (b) ? (a) : (b))
26c87c5fbaSopenharmony_ci#endif
27c87c5fbaSopenharmony_ci
28c87c5fbaSopenharmony_cistatic coap_context_t *main_coap_context = NULL;
29c87c5fbaSopenharmony_cistatic coap_optlist_t *optlist = NULL;
30c87c5fbaSopenharmony_ci
31c87c5fbaSopenharmony_cistatic int quit = 0;
32c87c5fbaSopenharmony_ci
33c87c5fbaSopenharmony_cistatic coap_response_t
34c87c5fbaSopenharmony_cimessage_handler(coap_session_t *session,
35c87c5fbaSopenharmony_ci                const coap_pdu_t *sent,
36c87c5fbaSopenharmony_ci                const coap_pdu_t *received,
37c87c5fbaSopenharmony_ci                const coap_mid_t id) {
38c87c5fbaSopenharmony_ci  const uint8_t *data;
39c87c5fbaSopenharmony_ci  size_t len;
40c87c5fbaSopenharmony_ci  size_t offset;
41c87c5fbaSopenharmony_ci  size_t total;
42c87c5fbaSopenharmony_ci
43c87c5fbaSopenharmony_ci  (void)session;
44c87c5fbaSopenharmony_ci  (void)sent;
45c87c5fbaSopenharmony_ci  (void)id;
46c87c5fbaSopenharmony_ci  if (coap_get_data_large(received, &len, &data, &offset, &total)) {
47c87c5fbaSopenharmony_ci    printf("%*.*s", (int)len, (int)len, (const char *)data);
48c87c5fbaSopenharmony_ci    if (len + offset == total) {
49c87c5fbaSopenharmony_ci      printf("\n");
50c87c5fbaSopenharmony_ci      quit = 1;
51c87c5fbaSopenharmony_ci    }
52c87c5fbaSopenharmony_ci  }
53c87c5fbaSopenharmony_ci  return COAP_RESPONSE_OK;
54c87c5fbaSopenharmony_ci}
55c87c5fbaSopenharmony_ci
56c87c5fbaSopenharmony_cistatic void
57c87c5fbaSopenharmony_cinack_handler(coap_session_t *session COAP_UNUSED,
58c87c5fbaSopenharmony_ci             const coap_pdu_t *sent COAP_UNUSED,
59c87c5fbaSopenharmony_ci             const coap_nack_reason_t reason,
60c87c5fbaSopenharmony_ci             const coap_mid_t id COAP_UNUSED) {
61c87c5fbaSopenharmony_ci
62c87c5fbaSopenharmony_ci  switch (reason) {
63c87c5fbaSopenharmony_ci  case COAP_NACK_TOO_MANY_RETRIES:
64c87c5fbaSopenharmony_ci  case COAP_NACK_NOT_DELIVERABLE:
65c87c5fbaSopenharmony_ci  case COAP_NACK_RST:
66c87c5fbaSopenharmony_ci  case COAP_NACK_TLS_FAILED:
67c87c5fbaSopenharmony_ci    coap_log_err("cannot send CoAP pdu\n");
68c87c5fbaSopenharmony_ci    quit = 1;
69c87c5fbaSopenharmony_ci    break;
70c87c5fbaSopenharmony_ci  case COAP_NACK_ICMP_ISSUE:
71c87c5fbaSopenharmony_ci  default:
72c87c5fbaSopenharmony_ci    ;
73c87c5fbaSopenharmony_ci  }
74c87c5fbaSopenharmony_ci  return;
75c87c5fbaSopenharmony_ci}
76c87c5fbaSopenharmony_ci
77c87c5fbaSopenharmony_cistatic int
78c87c5fbaSopenharmony_ciresolve_address(const char *host, const char *service, coap_address_t *dst,
79c87c5fbaSopenharmony_ci                int scheme_hint_bits) {
80c87c5fbaSopenharmony_ci
81c87c5fbaSopenharmony_ci  coap_addr_info_t *addr_info;
82c87c5fbaSopenharmony_ci  coap_str_const_t str_host;
83c87c5fbaSopenharmony_ci  uint16_t port = service ? atoi(service) : 0;
84c87c5fbaSopenharmony_ci  int ret = 0;
85c87c5fbaSopenharmony_ci
86c87c5fbaSopenharmony_ci  str_host.s = (const uint8_t *)host;
87c87c5fbaSopenharmony_ci  str_host.length = strlen(host);
88c87c5fbaSopenharmony_ci
89c87c5fbaSopenharmony_ci  addr_info = coap_resolve_address_info(&str_host, port, port, port, port,
90c87c5fbaSopenharmony_ci                                        AF_UNSPEC, scheme_hint_bits,
91c87c5fbaSopenharmony_ci                                        COAP_RESOLVE_TYPE_REMOTE);
92c87c5fbaSopenharmony_ci  if (addr_info) {
93c87c5fbaSopenharmony_ci    ret = 1;
94c87c5fbaSopenharmony_ci    *dst = addr_info->addr;
95c87c5fbaSopenharmony_ci  }
96c87c5fbaSopenharmony_ci
97c87c5fbaSopenharmony_ci  coap_free_address_info(addr_info);
98c87c5fbaSopenharmony_ci  return ret;
99c87c5fbaSopenharmony_ci}
100c87c5fbaSopenharmony_ci
101c87c5fbaSopenharmony_civoid
102c87c5fbaSopenharmony_ciclient_coap_init(coap_lwip_input_wait_handler_t input_wait, void *input_arg,
103c87c5fbaSopenharmony_ci                 int argc, char **argv) {
104c87c5fbaSopenharmony_ci  coap_session_t *session = NULL;
105c87c5fbaSopenharmony_ci  coap_pdu_t *pdu;
106c87c5fbaSopenharmony_ci  coap_address_t dst;
107c87c5fbaSopenharmony_ci  coap_mid_t mid;
108c87c5fbaSopenharmony_ci  int len;
109c87c5fbaSopenharmony_ci  coap_uri_t uri;
110c87c5fbaSopenharmony_ci  char portbuf[8];
111c87c5fbaSopenharmony_ci#define BUFSIZE 100
112c87c5fbaSopenharmony_ci  unsigned char buf[BUFSIZE];
113c87c5fbaSopenharmony_ci  int res;
114c87c5fbaSopenharmony_ci  const char *use_uri = COAP_URI;
115c87c5fbaSopenharmony_ci  int opt;
116c87c5fbaSopenharmony_ci  coap_log_t log_level = COAP_LOG_WARN;
117c87c5fbaSopenharmony_ci  coap_log_t dtls_log_level = COAP_LOG_ERR;
118c87c5fbaSopenharmony_ci  const char *use_psk = "secretPSK";
119c87c5fbaSopenharmony_ci  const char *use_id = "abc";
120c87c5fbaSopenharmony_ci  coap_pdu_type_t pdu_type = COAP_MESSAGE_CON;
121c87c5fbaSopenharmony_ci
122c87c5fbaSopenharmony_ci  /* Initialize libcoap library */
123c87c5fbaSopenharmony_ci  coap_startup();
124c87c5fbaSopenharmony_ci
125c87c5fbaSopenharmony_ci  while ((opt = getopt(argc, argv, ":k:Nu:v:V:")) != -1) {
126c87c5fbaSopenharmony_ci    switch (opt) {
127c87c5fbaSopenharmony_ci    case 'k':
128c87c5fbaSopenharmony_ci      use_psk = optarg;
129c87c5fbaSopenharmony_ci      break;
130c87c5fbaSopenharmony_ci    case 'u':
131c87c5fbaSopenharmony_ci      use_id = optarg;
132c87c5fbaSopenharmony_ci      break;
133c87c5fbaSopenharmony_ci    case 'v':
134c87c5fbaSopenharmony_ci      log_level = atoi(optarg);
135c87c5fbaSopenharmony_ci      break;
136c87c5fbaSopenharmony_ci    case 'N':
137c87c5fbaSopenharmony_ci      pdu_type = COAP_MESSAGE_NON;
138c87c5fbaSopenharmony_ci      break;
139c87c5fbaSopenharmony_ci    case 'V':
140c87c5fbaSopenharmony_ci      dtls_log_level = atoi(optarg);
141c87c5fbaSopenharmony_ci      break;
142c87c5fbaSopenharmony_ci    default:
143c87c5fbaSopenharmony_ci      printf("%s [-k PSK] [-u id] [-v level] [ -V level] [URI]\n", argv[0]);
144c87c5fbaSopenharmony_ci      exit(1);
145c87c5fbaSopenharmony_ci    }
146c87c5fbaSopenharmony_ci  }
147c87c5fbaSopenharmony_ci
148c87c5fbaSopenharmony_ci  if (optind < argc) {
149c87c5fbaSopenharmony_ci    use_uri = argv[optind];
150c87c5fbaSopenharmony_ci  }
151c87c5fbaSopenharmony_ci
152c87c5fbaSopenharmony_ci  coap_set_log_level(log_level);
153c87c5fbaSopenharmony_ci  coap_dtls_set_log_level(dtls_log_level);
154c87c5fbaSopenharmony_ci
155c87c5fbaSopenharmony_ci  /* Parse the URI */
156c87c5fbaSopenharmony_ci  len = coap_split_uri((const unsigned char *)use_uri, strlen(use_uri), &uri);
157c87c5fbaSopenharmony_ci  LWIP_ASSERT("Failed to parse uri", len == 0);
158c87c5fbaSopenharmony_ci  LWIP_ASSERT("Unsupported URI type", uri.scheme == COAP_URI_SCHEME_COAP ||
159c87c5fbaSopenharmony_ci              uri.scheme == COAP_URI_SCHEME_COAPS);
160c87c5fbaSopenharmony_ci  if (uri.scheme == COAP_URI_SCHEME_COAPS) {
161c87c5fbaSopenharmony_ci    LWIP_ASSERT("DTLS not supported", coap_dtls_is_supported());
162c87c5fbaSopenharmony_ci  }
163c87c5fbaSopenharmony_ci
164c87c5fbaSopenharmony_ci  snprintf(portbuf, sizeof(portbuf), "%d", uri.port);
165c87c5fbaSopenharmony_ci  snprintf((char *)buf, sizeof(buf), "%*.*s", (int)uri.host.length,
166c87c5fbaSopenharmony_ci           (int)uri.host.length, (const char *)uri.host.s);
167c87c5fbaSopenharmony_ci  /* resolve destination address where server should be sent */
168c87c5fbaSopenharmony_ci  len = resolve_address((const char *)buf, portbuf, &dst, 1 << uri.scheme);
169c87c5fbaSopenharmony_ci  LWIP_ASSERT("Failed to resolve address", len > 0);
170c87c5fbaSopenharmony_ci
171c87c5fbaSopenharmony_ci  main_coap_context = coap_new_context(NULL);
172c87c5fbaSopenharmony_ci  LWIP_ASSERT("Failed to initialize context", main_coap_context != NULL);
173c87c5fbaSopenharmony_ci
174c87c5fbaSopenharmony_ci  coap_context_set_block_mode(main_coap_context, COAP_BLOCK_USE_LIBCOAP);
175c87c5fbaSopenharmony_ci  coap_lwip_set_input_wait_handler(main_coap_context, input_wait, input_arg);
176c87c5fbaSopenharmony_ci
177c87c5fbaSopenharmony_ci  if (uri.scheme == COAP_URI_SCHEME_COAP) {
178c87c5fbaSopenharmony_ci    session = coap_new_client_session(main_coap_context, NULL, &dst,
179c87c5fbaSopenharmony_ci                                      COAP_PROTO_UDP);
180c87c5fbaSopenharmony_ci  } else {
181c87c5fbaSopenharmony_ci    static coap_dtls_cpsk_t dtls_psk;
182c87c5fbaSopenharmony_ci    static char client_sni[256];
183c87c5fbaSopenharmony_ci
184c87c5fbaSopenharmony_ci    memset(client_sni, 0, sizeof(client_sni));
185c87c5fbaSopenharmony_ci    memset(&dtls_psk, 0, sizeof(dtls_psk));
186c87c5fbaSopenharmony_ci    dtls_psk.version = COAP_DTLS_CPSK_SETUP_VERSION;
187c87c5fbaSopenharmony_ci    if (uri.host.length)
188c87c5fbaSopenharmony_ci      memcpy(client_sni, uri.host.s,
189c87c5fbaSopenharmony_ci             min(uri.host.length, sizeof(client_sni) - 1));
190c87c5fbaSopenharmony_ci    else
191c87c5fbaSopenharmony_ci      memcpy(client_sni, "localhost", 9);
192c87c5fbaSopenharmony_ci    dtls_psk.client_sni = client_sni;
193c87c5fbaSopenharmony_ci    dtls_psk.psk_info.identity.s = (const uint8_t *)use_id;
194c87c5fbaSopenharmony_ci    dtls_psk.psk_info.identity.length = strlen(use_id);
195c87c5fbaSopenharmony_ci    dtls_psk.psk_info.key.s = (const uint8_t *)use_psk;
196c87c5fbaSopenharmony_ci    dtls_psk.psk_info.key.length = strlen(use_psk);
197c87c5fbaSopenharmony_ci
198c87c5fbaSopenharmony_ci    session = coap_new_client_session_psk2(main_coap_context, NULL, &dst,
199c87c5fbaSopenharmony_ci                                           COAP_PROTO_DTLS, &dtls_psk);
200c87c5fbaSopenharmony_ci  }
201c87c5fbaSopenharmony_ci
202c87c5fbaSopenharmony_ci  LWIP_ASSERT("Failed to create session", session != NULL);
203c87c5fbaSopenharmony_ci
204c87c5fbaSopenharmony_ci  coap_register_response_handler(main_coap_context, message_handler);
205c87c5fbaSopenharmony_ci  coap_register_nack_handler(main_coap_context, nack_handler);
206c87c5fbaSopenharmony_ci
207c87c5fbaSopenharmony_ci  /* construct CoAP message */
208c87c5fbaSopenharmony_ci  pdu = coap_pdu_init(pdu_type,
209c87c5fbaSopenharmony_ci                      COAP_REQUEST_CODE_GET,
210c87c5fbaSopenharmony_ci                      coap_new_message_id(session),
211c87c5fbaSopenharmony_ci                      coap_session_max_pdu_size(session));
212c87c5fbaSopenharmony_ci  LWIP_ASSERT("Failed to create PDU", pdu != NULL);
213c87c5fbaSopenharmony_ci
214c87c5fbaSopenharmony_ci  len = coap_uri_into_options(&uri, &dst, &optlist, 1, buf, sizeof(buf));
215c87c5fbaSopenharmony_ci  LWIP_ASSERT("Failed to create options", len == 0);
216c87c5fbaSopenharmony_ci
217c87c5fbaSopenharmony_ci  /* Add option list (which will be sorted) to the PDU */
218c87c5fbaSopenharmony_ci  if (optlist) {
219c87c5fbaSopenharmony_ci    res = coap_add_optlist_pdu(pdu, &optlist);
220c87c5fbaSopenharmony_ci    LWIP_ASSERT("Failed to add options to PDU", res == 1);
221c87c5fbaSopenharmony_ci  }
222c87c5fbaSopenharmony_ci
223c87c5fbaSopenharmony_ci  /* and send the PDU */
224c87c5fbaSopenharmony_ci  mid = coap_send(session, pdu);
225c87c5fbaSopenharmony_ci  LWIP_ASSERT("Failed to send PDU", mid != COAP_INVALID_MID);
226c87c5fbaSopenharmony_ci}
227c87c5fbaSopenharmony_ci
228c87c5fbaSopenharmony_civoid
229c87c5fbaSopenharmony_ciclient_coap_finished(void) {
230c87c5fbaSopenharmony_ci  coap_delete_optlist(optlist);
231c87c5fbaSopenharmony_ci  coap_free_context(main_coap_context);
232c87c5fbaSopenharmony_ci  main_coap_context = NULL;
233c87c5fbaSopenharmony_ci  coap_cleanup();
234c87c5fbaSopenharmony_ci}
235c87c5fbaSopenharmony_ci
236c87c5fbaSopenharmony_ciint
237c87c5fbaSopenharmony_ciclient_coap_poll(void) {
238c87c5fbaSopenharmony_ci  coap_io_process(main_coap_context, 1000);
239c87c5fbaSopenharmony_ci  return quit;
240c87c5fbaSopenharmony_ci}
241