libcoap  4.3.0beta
coap_dtls_gnutls.c
Go to the documentation of this file.
1 /*
2  * coap_dtls_gnutls.c -- GunTLS Datagram Transport Layer Support for libcoap
3  *
4  * Copyright (C) 2017 Dag Bjorklund <dag.bjorklund@comsel.fi>
5  *
6  * This file is part of the CoAP library libcoap. Please see README for terms
7  * of use.
8  */
9 
10 #include "coap_config.h"
11 #include "address.h"
12 #include "coap_debug.h"
13 #include "mem.h"
14 #include "coap_dtls.h"
15 #include "coap_keystore.h"
16 #include "utlist.h"
17 #include <inttypes.h>
18 #include <stdio.h>
19 #include <errno.h>
20 #include <gnutls/gnutls.h>
21 #include <gnutls/x509.h>
22 #include <unistd.h>
23 
24 #ifdef __GNUC__
25 #define UNUSED __attribute__((unused))
26 #else /* __GNUC__ */
27 #define UNUSED
28 #endif /* __GNUC__ */
29 
30 /* this code was inspired by the gnutls code in AwaLWM2M */
31 
32 
33 typedef enum {
38 
39 
40 typedef enum CertificateFormat_ {
45 
46 
47 
48 /* Data item in the DTLS send queue. */
49 struct queue_t {
50  struct queue_t *next;
52  size_t data_length;
53  unsigned char data[];
54 };
55 
58  gnutls_session_t dtls_session;
59  void *credentials;
63  size_t buf_len;
64  struct queue_t *sendqueue;
65  int ifindex;
69 };
70 
71 typedef struct coap_dtls_context_t {
74 
75  // gnutls stuff
76  gnutls_certificate_credentials_t cert_credentials;
78  const char *psk_identity;
80  gnutls_datum_t psk_key;
81  gnutls_priority_t priority_cache;
82 
86 
87 
88 /* Convenience macro to copy IPv6 addresses without garbage. */
89 #define COAP_COPY_ADDRESS(DST,SRC) do { \
90  (DST)->size = (SRC)->size; \
91  if ((SRC)->addr.sa.sa_family == AF_INET6) { \
92  (DST)->addr.sin6.sin6_family = (SRC)->addr.sin6.sin6_family; \
93  (DST)->addr.sin6.sin6_addr = (SRC)->addr.sin6.sin6_addr; \
94  (DST)->addr.sin6.sin6_port = (SRC)->addr.sin6.sin6_port; \
95  } else { \
96  (DST)->addr.st = (SRC)->addr.st; \
97  } \
98  } while (0);
99 
100 
101 #if GNUTLS_VERSION_MAJOR >= 3
102 static int
103 certificate_verify(gnutls_session_t session) {
104  (void)session;
105  return 0;
106 }
107 #endif
108 
109 
110 void
111 dtls_set_psk(struct coap_dtls_context_t *ctx, const char * identity, const uint8_t * key, int key_length) {
112  if (key_length > 0) {
113  ctx->psk_identity = identity;
114  ctx->psk_key.data = (unsigned char *)key;
115  ctx->psk_key.size = key_length;
116  }
117 }
118 
119 
121 int
123  return 1;
124 }
125 
127 void
129  (void)level;
130  return;
131 }
132 
134 int
136  return 0;
137 }
138 
139 static int
141  const unsigned char *data, size_t data_length) {
142  struct queue_t *item;
143 #define ITEM_SIZE (sizeof(struct queue_t) + data_length)
144 
145  /* Only add if we do not already have that item. */
146  LL_SEARCH_SCALAR(session->sendqueue, item, id, id);
147  if (!item) { /* Not found, add new item */
148  if ((item = (struct queue_t *)coap_malloc(ITEM_SIZE)) != NULL) {
149  coap_debug("*** add %p to sendqueue of session %p\n", item, session);
150  item->id = id;
151  item->data_length = data_length;
152  memcpy(item->data, data, data_length);
153  LL_APPEND(session->sendqueue, item);
154  }
155  }
156  return item != NULL;
157 }
158 
166 struct coap_dtls_context_t *
167 coap_dtls_new_context(struct coap_context_t *coap_context) {
168  gnutls_global_init();
169 
170  struct coap_dtls_context_t *context;
171 #define CONTEXT_SIZE (sizeof(struct coap_dtls_context_t))
172 
173  context = (struct coap_dtls_context_t *)coap_malloc(CONTEXT_SIZE);
174  if (context) {
175  memset(context, 0, CONTEXT_SIZE);
176  context->ctx = coap_context;
177  context->cert_credentials = NULL;
178  context->certificate = NULL;
179  context->certificate_length = 0;
180  dtls_set_psk(context, "Client_identity", (uint8_t*)"EodEYFJDcdTYbxcc", 16);
181 
182 #if ((GNUTLS_VERSION_MAJOR > 3) || ((GNUTLS_VERSION_MAJOR == 3) && (GNUTLS_VERSION_MINOR >= 4)))
183  gnutls_priority_init(&context->priority_cache, "NONE:+VERS-ALL:+ECDHE-ECDSA:+ECDHE-PSK:+PSK:+CURVE-ALL:+AES-128-CCM-8:+AES-128-CBC:+MAC-ALL:-SHA1:+COMP-ALL:+SIGN-ALL:+CTYPE-X.509", NULL);
184 #else
185  gnutls_priority_init(&context->priority_cache, "NONE:+VERS-TLS-ALL:+ECDHE-ECDSA:+ECDHE-PSK:+PSK:+CURVE-ALL:+AES-128-CBC:+MAC-ALL:-SHA1:+COMP-ALL:+SIGN-ALL:+CTYPE-X.509", NULL);
186 #endif
187 
188  }
189  return context;
190 }
191 
192 
194 void
196  if (dtls_context->cert_credentials) {
197  //free(cert_credentials);
198  dtls_context->cert_credentials = NULL;
199  }
200  if (dtls_context->certificate) {
201  //free(certificate);
202  dtls_context->certificate = NULL;
203  }
204  if (dtls_context->psk_identity) {
205  //free(psk_identity);
206  dtls_context->psk_identity = NULL;
207  }
208  dtls_context->certificate_length = 0;
209 
210  struct coap_dtls_session_t *session;
211  LL_FOREACH(dtls_context->sessions, session) {
212  coap_dtls_free_session(dtls_context, session);
213  }
214  for (session = dtls_context->sessions; session != NULL; ) {
215  struct coap_dtls_session_t *tmp = session;
216  session = session->next;
217  coap_free(tmp);
218  }
219  if (dtls_context->cert_credentials) {
220  gnutls_certificate_free_credentials(dtls_context->cert_credentials);
221  dtls_context->cert_credentials = NULL;
222 
223  gnutls_priority_deinit(dtls_context->priority_cache);
224  }
225 
226  gnutls_global_deinit();
227  coap_free(dtls_context);
228 }
229 
230 /* callback passed to gnutls_transport_set_pull_function */
231 static ssize_t
232 decrypt_callback(gnutls_transport_ptr_t context, void *receive_buffer, size_t receive_buffer_length) {
233  ssize_t result;
234  struct coap_dtls_session_t * session = (struct coap_dtls_session_t *)context;
235 
237 
238  assert(session->ctx);
239  assert(session->ctx->endpoint);
240 
241  if (session->buf_len == 0) {
243  handle.fd, session->ifindex);
244 
245  coap_packet_t *packet;
246 
247  ssize_t bytes_read = 0;
248  local_interface->flags |= COAP_ENDPOINT_HAS_DATA;
249 
250  bytes_read = coap_network_read(local_interface, &packet);
251 
252  if (bytes_read < 0) {
253  if (errno == EAGAIN) {
254  coap_log(COAP_LOG_DEBUG, "eagain\n");
255  }
256  } else {
257  unsigned char* payload = 0;
258  coap_packet_get_memmapped(packet, &payload, &bytes_read);
259  memcpy(receive_buffer, payload, bytes_read);
260  }
261  return bytes_read;
262  }
263 
264  if (session->buf_len > 0) {
265  if (receive_buffer_length < session->buf_len) {
266  result = receive_buffer_length;
267  } else {
268  result = session->buf_len;
269  }
270  memcpy(receive_buffer, session->buf, result);
271  session->buf_len = session->buf_len - result;
272  session->buf += result;
273  } else {
274  errno = EAGAIN;
275  result = -1;
276  }
277  return result;
278 }
279 
280 
281 /* callback function given to gnutls for sending data over socket */
282 static ssize_t
283 dtls_send_to_peer(gnutls_transport_ptr_t context, const void * send_buffer,
284  size_t send_buffer_length) {
285  int result = 0;
286  struct coap_dtls_session_t *dtls_session = (struct coap_dtls_session_t *)context;
287  if (dtls_session) {
289  assert(dtls_session->ctx);
290  assert(dtls_session->ctx->endpoint);
291 
293  handle.fd, dtls_session->ifindex);
294 
295  assert(local_interface);
297  &dtls_session->network_address, (uint8_t*)send_buffer, send_buffer_length);
298  if (result != (int)send_buffer_length) {
299  coap_log(COAP_LOG_WARNING, "coap_network_send failed\n");
300  result = 0;
301  }
302  } else {
303  result = 0;
304  }
305  return result;
306 }
307 
308 /* callback passed to gnutls_psk_set_client_credentials_function */
309 static int
310 psk_client_callback(gnutls_session_t session, char **username, gnutls_datum_t * key) {
311  (void)session; (void)username; (void)key;
312  assert(0);
313  return 0;
314 }
315 
316 /* callback passed to gnutls_psk_set_server_credentials_function(credentials, psk_callback */
317 static int
318 psk_callback(gnutls_session_t session, const char *username, gnutls_datum_t * key) {
319  struct coap_dtls_session_t* dtls_session = (struct coap_dtls_session_t *)gnutls_transport_get_ptr(session);
320  (void)username;
321  key->data = gnutls_malloc(dtls_session->ctx->dtls_context->psk_key.size);
322  key->size = dtls_session->ctx->dtls_context->psk_key.size;
323  memcpy(key->data, dtls_session->ctx->dtls_context->psk_key.data, key->size);
324  return 0;
325 }
326 
327 #if GNUTLS_VERSION_MAJOR >= 3
328 /* callback set by gnutls_transport_set_pull_timeout_function for gnutls to
329  check if data is available. Should not be needed when select works */
330 static int
331 receive_timeout(gnutls_transport_ptr_t context, unsigned int ms) {
332  fd_set rfds;
333  struct timeval tv;
334  int ret;
335  struct coap_dtls_session_t *session = (struct coap_dtls_session_t*)context;
336 
338  assert(session->ctx);
339  assert(session->ctx->endpoint);
340 
342  handle.fd, session->ifindex);
343 
344  int fd = local_interface->handle.fd;
345 
346  FD_ZERO(&rfds);
347  FD_SET(fd, &rfds);
348 
349  // ms is usually 0 (is data available immediately?). Does not work for me if ms==0
350  if (ms == 0)
351  ms = 100;
352 
353  tv.tv_sec = ms/1000;
354  tv.tv_usec = (ms % 1000) * 1000;
355 
356  ret = select(fd + 1, &rfds, NULL, NULL, &tv);
357  return ret;
358 }
359 #endif
360 
361 
362 struct coap_dtls_session_t *
365  const coap_address_t *remote) {
366  struct coap_dtls_session_t *session;
367  const size_t need = sizeof(struct coap_dtls_session_t);
368  session = coap_malloc_type(COAP_DTLS_SESSION, need);
369  if (session) {
370  memset(session, 0, need);
371  COAP_COPY_ADDRESS(&session->network_address, remote);
372  session->ifindex = local_interface->handle.fd;
373  assert(dtls_context->ctx);
374  session->ctx = dtls_context->ctx;
375 
376  int flags = 0;
377 #if GNUTLS_VERSION_MAJOR >= 3
378  if (dtls_context->client)
379  flags = GNUTLS_CLIENT | GNUTLS_DATAGRAM | GNUTLS_NONBLOCK;
380  else
381  flags = GNUTLS_SERVER | GNUTLS_DATAGRAM | GNUTLS_NONBLOCK;
382 #else
383  if (dtls_context->client)
384  flags = GNUTLS_CLIENT;
385  else
386  flags = GNUTLS_SERVER;
387 #endif
388 
389  assert(gnutls_init(&session->dtls_session, flags) == GNUTLS_E_SUCCESS);
390 
391  gnutls_transport_set_pull_function(session->dtls_session, decrypt_callback);
392  gnutls_transport_set_push_function(session->dtls_session, dtls_send_to_peer);
393 #if GNUTLS_VERSION_MAJOR >= 3
394  gnutls_transport_set_pull_timeout_function(session->dtls_session, receive_timeout);
395 #endif
396  gnutls_transport_set_ptr(session->dtls_session, session); // set user data
397 
398  if (dtls_context->certificate || !dtls_context->psk_identity) {
399  if (dtls_context->cert_credentials) {
400  gnutls_credentials_set(session->dtls_session, GNUTLS_CRD_CERTIFICATE, dtls_context->cert_credentials);
401  } else if (gnutls_certificate_allocate_credentials(&dtls_context->cert_credentials) == GNUTLS_E_SUCCESS) {
402  if (dtls_context->certificate) {
403  gnutls_datum_t certificateData;
404  certificateData.data = dtls_context->certificate;
405  certificateData.size = dtls_context->certificate_length;
406  int format = GNUTLS_X509_FMT_PEM;
407  if (dtls_context->certificateFormat == CERTIFICATE_FORMAT_ASN1)
408  format = GNUTLS_X509_FMT_DER;
409  // if (dtls_context->client)
410  // gnutls_certificate_set_x509_trust_mem(session->Credentials, &certificateData, format);
411  // else
412  gnutls_certificate_set_x509_key_mem(dtls_context->cert_credentials, &certificateData, &certificateData, format);
413  }
414 #if GNUTLS_VERSION_MAJOR >= 3
415  gnutls_certificate_set_verify_function(dtls_context->cert_credentials, certificate_verify);
416  //gnutls_certificate_set_retrieve_function(xcred, cert_callback);
417  //gnutls_session_set_verify_cert(session->dtls_session, NULL, GNUTLS_VERIFY_DISABLE_CA_SIGN);
418 #else
419  gnutls_certificate_set_verify_flags(cert_credentials, GNUTLS_VERIFY_DISABLE_CA_SIGN);
420 #endif
421  gnutls_credentials_set(session->dtls_session, GNUTLS_CRD_CERTIFICATE, dtls_context->cert_credentials);
422  }
423  }
424  if (dtls_context->psk_identity) {
425  if (dtls_context->client) {
426  if (!dtls_context->certificate) {
427  gnutls_psk_client_credentials_t credentials;
428  if (gnutls_psk_allocate_client_credentials(&credentials) == GNUTLS_E_SUCCESS) {
429  if (gnutls_psk_set_client_credentials(credentials, dtls_context->psk_identity, &dtls_context->psk_key, GNUTLS_PSK_KEY_RAW) == GNUTLS_E_SUCCESS) {
430  gnutls_credentials_set(session->dtls_session, GNUTLS_CRD_PSK, credentials);
431  session->credentials = credentials;
433  } else {
434  gnutls_psk_set_client_credentials_function(credentials, psk_client_callback);
435  session->credentials = credentials;
437  }
438  }
439  }
440  } else {
441  gnutls_psk_server_credentials_t credentials;
442  if (gnutls_psk_allocate_server_credentials(&credentials) == GNUTLS_E_SUCCESS) {
443  gnutls_psk_set_server_credentials_function(credentials, psk_callback);
444  gnutls_credentials_set(session->dtls_session, GNUTLS_CRD_PSK, credentials);
445  session->credentials = credentials;
447  }
448  }
449  }
450 
451  gnutls_priority_set(session->dtls_session, dtls_context->priority_cache);
452  if (!dtls_context->client) {
453  gnutls_certificate_server_set_request(session->dtls_session, GNUTLS_CERT_REQUEST); // GNUTLS_CERT_IGNORE Don't require Client Cert
454  }
455 
456 #if GNUTLS_VERSION_MAJOR >= 3
457  gnutls_handshake_set_timeout(session->dtls_session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
458 #endif
459  }
460 
461  LL_PREPEND(dtls_context->sessions, session);
462 
463  return session;
464 }
465 
466 void
468  struct coap_dtls_session_t *session) {
469 
470  (void)dtls_context;
471  if (session->credentials) {
473  gnutls_psk_free_client_credentials(session->credentials);
474  } else if (session->credential_type == CREDENTIAL_TYPE_SERVER_PSK) {
475  gnutls_psk_free_server_credentials(session->credentials);
476  }
477 
478  }
479  gnutls_deinit(session->dtls_session);
480  memset(session,0, sizeof(session->dtls_session));
481 }
482 
483 static struct coap_dtls_session_t *
486  const coap_address_t *dst) {
487  struct coap_dtls_session_t *session = NULL;
488  LL_FOREACH(dtls_context->sessions, session) {
489  if ((session->ifindex == local_interface->handle.fd) &&
490  coap_address_equals(&session->network_address, dst)) {
491  return session;
492  }
493  }
494  return session;
495 }
496 
497 struct coap_dtls_session_t *
500  const coap_address_t *dst) {
501  struct coap_dtls_session_t *session;
502  assert(coap_context);
503  /* reuse existing session if available, otherwise create new session */
504  session = coap_dtls_find_session(coap_context->dtls_context,
505  local_interface, dst);
506  // coap_dtls_get_session is called in a client scenario, marking client=1 in context
507  // this is used later to tell gnutls we are the client
508  coap_context->dtls_context->client = 1;
509  if (!session &&
510  ((session = coap_dtls_new_session(coap_context->dtls_context,
511  local_interface, dst)) == NULL)) {
512  coap_log(COAP_LOG_WARNING, "cannot create session object\n");
513  return NULL;
514  }
515  return session;
516 }
517 
518 /* coap_dlts_send is called by lib-coap in order to send data over dtls */
519 int
520 coap_dtls_send(struct coap_context_t *coap_context,
521  struct coap_dtls_session_t *session,
522  const coap_pdu_t *pdu) {
523  int res = -2;
524 
525  assert(coap_context && coap_context->dtls_context && session);
526 
527  coap_log(COAP_LOG_DEBUG, "call dtls_write\n");
528  assert(session->dtls_session);
529 
530  if (session->session_established) {
531  res = gnutls_write(session->dtls_session, (uint8_t *)pdu->hdr, pdu->length);
532 
533  if (res < 0) {
534  coap_log(COAP_LOG_WARNING, "coap_dtls_send: cannot send PDU\n");
535  } else if (res == 0) {
536 
537  coap_tid_t id;
538  coap_transaction_id((coap_address_t *)&session->dtls_session, pdu, &id);
539 
540  if (!push_data_item(session, id, (uint8_t *)pdu->hdr, pdu->length)) {
541  coap_log(COAP_LOG_DEBUG, "cannot store %u bytes for deferred transmission\n",
542  pdu->length);
543  res = -2;
544  }
545  }
546  } else {
547  int r = gnutls_handshake(session->dtls_session);
548 
549  session->session_established = (r == GNUTLS_E_SUCCESS);
550  if (session->session_established) {
551  res = 0;
552  // recursive call
553  coap_dtls_send(coap_context, session, pdu);
554  } else {
555  coap_log(COAP_LOG_WARNING, "session establish returned %d\n", r);
556  }
557  }
558  return res;
559 }
560 
561 
562 /* coap_dtls_handle message is called from lib-coap */
563 int
566  const coap_address_t *dst,
567  const unsigned char *data,
568  size_t data_len) {
569  struct coap_dtls_session_t *session;
570  int new_session = 0;
571  int ret = -1;
572  session = coap_dtls_find_session(coap_context->dtls_context,
573  local_interface, dst);
574 
575  if (session) {
576  session->buf = (unsigned char*)data;
577  session->buf_len = data_len; // encrypted length
578  if (session->session_established) {
579  int decrypted_len = gnutls_read(session->dtls_session, (uint8_t*)data, data_len);
580 
581  if ((decrypted_len <= 0) && new_session) {
582  coap_dtls_free_session(coap_context->dtls_context, session);
583  } else {
584  ret = coap_handle_message(coap_context, local_interface, dst, (unsigned char*)data, decrypted_len);
585  }
586  } else {
587  session->session_established = (gnutls_handshake(session->dtls_session) == GNUTLS_E_SUCCESS);
588  if (session->session_established) {
589  coap_log(COAP_LOG_DEBUG, "session established\n");
590  }
591  }
592  }
593 
594  if (!session) {
595  // coap_dtls_handle_message is called in a server scenario, marking client=0 in context
596  // this is used later to tell gnutls we are the server
597  coap_context->dtls_context->client = 0;
598  if ((session = coap_dtls_new_session(coap_context->dtls_context,
599  local_interface, dst)) != NULL) {
600  new_session = 1;
601  session->buf = (unsigned char*)data;
602  session->buf_len = data_len;
603  session->session_established = (gnutls_handshake(session->dtls_session) == GNUTLS_E_SUCCESS);
604  if (session->session_established) {
605  // recursive call
606  coap_dtls_handle_message(coap_context, local_interface, dst, data, data_len);
607  } else {
608  coap_log(COAP_LOG_WARNING, "failed to establish session\n");
609  }
610  }
611  }
612 
613  if (!session) {
614  coap_log(COAP_LOG_WARNING, "cannot allocate session, drop packet\n");
615  }
616  return ret;
617 }
int coap_address_equals(const coap_address_t *a, const coap_address_t *b)
Compares given address objects a and b.
Definition: address.c:58
Representation of network addresses.
struct coap_dtls_session_t * coap_dtls_get_session(struct coap_context_t *coap_context, const coap_endpoint_t *local_interface, const coap_address_t *dst)
void coap_dtls_free_context(struct coap_dtls_context_t *dtls_context)
Releases the storage allocated for dtls_context.
int coap_dtls_handle_message(struct coap_context_t *coap_context, const coap_endpoint_t *local_interface, const coap_address_t *dst, const unsigned char *data, size_t data_len)
#define CONTEXT_SIZE
struct coap_dtls_session_t * coap_dtls_new_session(struct coap_dtls_context_t *dtls_context, const coap_endpoint_t *local_interface, const coap_address_t *remote)
static int psk_callback(gnutls_session_t session, const char *username, gnutls_datum_t *key)
struct coap_dtls_context_t coap_dtls_context_t
static int push_data_item(struct coap_dtls_session_t *session, coap_tid_t id, const unsigned char *data, size_t data_length)
static struct coap_dtls_session_t * coap_dtls_find_session(coap_dtls_context_t *dtls_context, const coap_endpoint_t *local_interface, const coap_address_t *dst)
int coap_dtls_send(struct coap_context_t *coap_context, struct coap_dtls_session_t *session, const coap_pdu_t *pdu)
void coap_dtls_free_session(struct coap_dtls_context_t *dtls_context, struct coap_dtls_session_t *session)
static ssize_t dtls_send_to_peer(gnutls_transport_ptr_t context, const void *send_buffer, size_t send_buffer_length)
CertificateFormat_
@ CERTIFICATE_FORMAT_ASN1
@ CERTIFICATE_FORMAT_NONE
@ CERTIFICATE_FORMAT_PEM
static int psk_client_callback(gnutls_session_t session, char **username, gnutls_datum_t *key)
void dtls_set_psk(struct coap_dtls_context_t *ctx, const char *identity, const uint8_t *key, int key_length)
static ssize_t decrypt_callback(gnutls_transport_ptr_t context, void *receive_buffer, size_t receive_buffer_length)
#define ITEM_SIZE
enum CertificateFormat_ CertificateFormat
CredentialType
@ CREDENTIAL_TYPE_NOT_SET
@ CREDENTIAL_TYPE_SERVER_PSK
@ CREDENTIAL_TYPE_CLIENT_PSK
#define COAP_COPY_ADDRESS(DST, SRC)
void coap_packet_get_memmapped(coap_packet_t *packet, unsigned char **address, size_t *length)
Given a packet, set msg and msg_len to an address and length of the packet's data in memory.
Definition: coap_io.c:729
ssize_t coap_network_read(coap_socket_t *sock, coap_packet_t *packet)
Function interface for reading data.
Definition: coap_io.c:736
ssize_t coap_network_send(coap_socket_t *sock, const coap_session_t *session, const uint8_t *data, size_t datalen)
Definition: coap_io.c:555
struct coap_dtls_context_t * coap_dtls_new_context(struct coap_context_t *coap_context)
Creates a new DTLS context for the given coap_context.
int coap_dtls_is_supported(void)
Returns 1 if support for DTLS is enabled, or 0 otherwise.
void coap_dtls_set_log_level(int level)
Sets the log level to the specified value.
int coap_dtls_get_log_level(void)
Returns the current log level.
#define coap_log(level,...)
Logging function.
Definition: coap_debug.h:150
void * coap_malloc_type(coap_memory_tag_t type, size_t size)
Allocates a chunk of size bytes and returns a pointer to the newly allocated memory.
COAP_STATIC_INLINE void * coap_malloc(size_t size)
Wrapper function to coap_malloc_type() for backwards compatibility.
Definition: mem.h:93
COAP_STATIC_INLINE void coap_free(void *object)
Wrapper function to coap_free_type() for backwards compatibility.
Definition: mem.h:100
int coap_tid_t
coap_tid_t is used to store CoAP transaction id, i.e.
Definition: pdu.h:244
multi-purpose address abstraction
Definition: address.h:94
The CoAP stack's global state is stored in a coap_context_t object.
Definition: net.h:141
void * dtls_context
Definition: net.h:195
coap_endpoint_t * endpoint
the endpoints used for listening
Definition: net.h:161
const char * psk_identity
CertificateFormat certificateFormat
gnutls_certificate_credentials_t cert_credentials
struct coap_dtls_session_t * sessions
coap_context_t * ctx
gnutls_priority_t priority_cache
gnutls_datum_t psk_key
coap_context_t * ctx
struct coap_dtls_session_t * next
gnutls_session_t dtls_session
CredentialType credential_type
coap_endpoint_t * local_interface
struct queue_t * sendqueue
coap_address_t network_address
Abstraction of virtual endpoint that can be attached to coap_context_t.
structure for CoAP PDUs token, if any, follows the fixed size header, then options until payload mark...
Definition: pdu.h:287
unsigned char data[]
coap_tid_t id
size_t data_length
struct queue_t * next
unsigned char uint8_t
Definition: uthash.h:79
#define LL_FOREACH(head, el)
Definition: utlist.h:413
#define LL_PREPEND(head, add)
Definition: utlist.h:314
#define LL_SEARCH_SCALAR(head, out, field, val)
Definition: utlist.h:425
#define LL_APPEND(head, add)
Definition: utlist.h:338