libcoap 4.3.5-develop-19cef11
coap_pdu_transmit(3)
coap_pdu_transmit

SYNOPSIS

#include <coap3/coap.h>

coap_mid_t coap_send(coap_session_t *session, coap_pdu_t *pdu);

int coap_send_recv(coap_session_t *session, coap_pdu_t *request_pdu, coap_pdu_t **response_pdu, uint32_t timeout_ms);

void coap_send_recv_terminate(void);

void coap_delete_pdu(coap_pdu_t *pdu);

For specific (D)TLS library support, link with -lcoap-3-notls, -lcoap-3-gnutls, -lcoap-3-openssl, -lcoap-3-mbedtls, -lcoap-3-wolfssl or -lcoap-3-tinydtls. Otherwise, link with -lcoap-3 to get the default (D)TLS library support.

DESCRIPTION

The CoAP PDU should be set up as described in coap_pdu_setup(3). This man page describes how the PDU can be transmitted.

FUNCTIONS

Function: coap_send()

The coap_send() function is used to initiate the transmission of the pdu associated with the session. The caller must not access or delete pdu after calling coap_send() - even if there is a return error.

NOTE: For request handlers, returning from the request handler will cause the response PDU to be transmitted as appropriate and so coap_send() must not be called for the response PDU from within the request handler.

Function: coap_send_recv()

The coap_send_recv() function is used to initiate the transmission of the request_pdu associated with the session and wait for a response. If there is a response, response_pdu will get updated with the received response. The request may cause a block transfer and the response is only returned after all the blocks have been transferred.

timeout_ms is set to the positive number of milliseconds to wait for the response. If this is a blocked transfer, the timeout is used for between each individual (re-)request and response. For CON type transmissions, this does not need to be much bigger than (MAX_TRANSMIT_WAIT - MAX_TRANSMIT_SPAN) (default is 48 seconds).

It is then the responsibility of the caller to analyze response_pdu and following analysis to release both the request_pdu and response_pdu by calling coap_delete_pdu() for both the request_pdu and response_pdu.

NOTE: If coap_send_recv() is being used, coap_send_recv_terminate() must be used to terminate the call from, say, a signal(2) handler, otherwise coap_send_recv() may not return if there is a lot of traffic for session.

Function: coap_send_recv_terminate()

The coap_send_recv_terminate() function is used to terminate any outstanding sessions currently using the coap_send_recv() function. Typically this would be called within a signal or sigaction handler when the application is to close down following the receipt of a signal.

Function: coap_delete_pdu()

The coap_delete_pdu() function is used to delete any created pdu. pdu can be NULL.

NOTE: The coap_send() will always internally call coap_delete_pdu(), even if there is an error, so coap_delete() must not be called after calling coap_send() (or for that matter further code must not reference pdu). However, coap_send_recv() does not delete either of request_pdu or response_pdu, so request_pdu must always be deleted, as well as response_pdu if returned.

RETURN VALUES

coap_send() returns the CoAP message ID on success or COAP_INVALID_MID on failure.

coap_send_recv() returns the following values:

 0 or +ve Time in function in ms after successful transfer (which can be
          bigger than timeout_ms)
       -1 Invalid timeout parameter
       -2 Failed to transmit PDU
       -3 Nack or Event handler invoked, cancelling request
       -4 coap_io_process returned error (fail to re-lock or select())
       -5 Response not received in the given time
       -6 Terminated by user
       -7 Client mode code not enabled

EXAMPLES

Setup PDU and Transmit

#include <coap3/coap.h>

static int
build_send_pdu(coap_context_t *context, coap_session_t *session,
               uint8_t msgtype, uint8_t request_code, const char *path,
               const char *query, unsigned char *data, size_t length,
               int observe) {
  coap_pdu_t *pdu;
  uint8_t buf[8];
  size_t buflen;
  coap_optlist_t *optlist_chain = NULL;

  /* Remove (void) definition if variable is used */
  (void)context;

  /* Create the pdu with the appropriate options */
  pdu = coap_pdu_init(msgtype, request_code, coap_new_message_id(session),
                      coap_session_max_pdu_size(session));
  if (!pdu)
    return 0;

  /*
   * Create unique token for this request for handling unsolicited /
   * delayed responses
   */
  coap_session_new_token(session, &buflen, buf);
  if (!coap_add_token(pdu, buflen, buf)) {
    coap_log_debug("cannot add token to request\n");
    goto error;
  }

  if (path) {
    /* Add in the Uri-Path options */
    if (!coap_path_into_optlist((const uint8_t *)path, strlen(path),
                                COAP_OPTION_URI_PATH, &optlist_chain))
      goto error;
  }

  if (query) {
    /* Add in the Uri-Query options */
    if (!coap_query_into_optlist((const uint8_t *)query, strlen(query),
                                 COAP_OPTION_URI_QUERY, &optlist_chain))
      goto error;
  }

  if (request_code == COAP_REQUEST_GET && observe) {
    /* Indicate that we want to observe this resource */
    if (!coap_insert_optlist(&optlist_chain,
                             coap_new_optlist(COAP_OPTION_OBSERVE,
                                              coap_encode_var_safe(buf, sizeof(buf),
                                                  COAP_OBSERVE_ESTABLISH), buf)
                            ))
      goto error;
  }

  /* ... Other code / options etc. ... */

  /* Add in all the options (after internal sorting) to the pdu */
  if (!coap_add_optlist_pdu(pdu, &optlist_chain))
    goto error;

  if (data && length) {
    /* Add in the specified data */
    if (!coap_add_data(pdu, length, data))
      goto error;
  }

  if (coap_send(session, pdu) == COAP_INVALID_MID)
    goto error;
  return 1;

error:

  if (pdu)
    coap_delete_pdu(pdu);
  return 0;

}

Setup PDU, then Send and Receive

#include <coap3/coap.h>

/*
 * SIGINT/SIGTERM handler: terminate any outstanding coap_send_recv().
 * Handle configure using signal(2) or sigaction(2) */
static void
handle_sigint(int signum COAP_UNUSED) {
  coap_send_recv_terminate();
}

static int
build_send_recv_pdu(coap_context_t *context, coap_session_t *session,
                    uint8_t msgtype, uint8_t request_code, const char *path,
                    const char *query, unsigned char *data, size_t length,
                    int observe) {
  coap_pdu_t *pdu;
  coap_pdu_t *resp_pdu = NULL;
  uint8_t buf[8];
  size_t buflen;
  coap_optlist_t *optlist_chain = NULL;
  int result;
  uint32_t wait_ms = 60*1000;
  int ret = 0;

  /* Remove (void) definition if variable is used */
  (void)context;

  /* Create the pdu with the appropriate options */
  pdu = coap_pdu_init(msgtype, request_code, coap_new_message_id(session),
                      coap_session_max_pdu_size(session));
  if (!pdu)
    return 0;

  /*
   * Create unique token for this request for handling unsolicited /
   * delayed responses
   */
  coap_session_new_token(session, &buflen, buf);
  if (!coap_add_token(pdu, buflen, buf)) {
    coap_log_debug("cannot add token to request\n");
    goto error;
  }

  if (path) {
    /* Add in the Uri-Path options */
    if (!coap_path_into_optlist((const uint8_t *)path, strlen(path),
                                COAP_OPTION_URI_PATH, &optlist_chain))
      goto error;
  }

  if (query) {
    /* Add in the Uri-Query options */
    if (!coap_query_into_optlist((const uint8_t *)query, strlen(query),
                                 COAP_OPTION_URI_QUERY, &optlist_chain))
      goto error;
  }

  if (request_code == COAP_REQUEST_GET && observe) {
    /* Indicate that we want to observe this resource */
    if (!coap_insert_optlist(&optlist_chain,
                             coap_new_optlist(COAP_OPTION_OBSERVE,
                                              coap_encode_var_safe(buf, sizeof(buf),
                                                  COAP_OBSERVE_ESTABLISH), buf)
                            ))
      goto error;
  }

  /* ... Other code / options etc. ... */

  /* Add in all the options (after internal sorting) to the pdu */
  if (!coap_add_optlist_pdu(pdu, &optlist_chain))
    goto error;

  if (data && length) {
    /* Add in the specified data */
    if (!coap_add_data(pdu, length, data))
      goto error;
  }

  result = coap_send_recv(session, pdu, &resp_pdu, wait_ms);
  if (result >= 0) {
    /* ... Process response PDU ... */

    if (result < (int)wait_ms) {
      wait_ms -= result;
    } else {
      wait_ms = 0;
    }
    ret = 1;
  } else {
    switch (result) {
    case -1:
      coap_log_err("coap_send_recv: Invalid timeout value %u\n", wait_ms);
      break;
    case -2:
      coap_log_err("coap_send_recv: Failed to transmit PDU\n");
      break;
    case -3:
      coap_log_err("coap_send_recv: Critical Nack / Event occurred\n");
      break;
    case -4:
      coap_log_err("coap_send_recv: Internal coap_io_process() failed\n");
      break;
    case -5:
      coap_log_err("coap_send_recv: No response received within the timeout\n");
      break;
    case -6:
      coap_log_err("coap_send_recv: Terminated by user\n");
      break;
    case -7:
      coap_log_err("coap_send_recv: Client Mode code not enabled\n");
      break;
    default:
      coap_log_err("coap_send_recv: Invalid return value %d\n", result);
      break;
    }
    ret = 0;
  }

error:

  coap_delete_pdu(pdu);
  coap_delete_pdu(resp_pdu);

  return ret;
}

FURTHER INFORMATION

See

"RFC7252: The Constrained Application Protocol (CoAP)"

for further information.

BUGS

Please raise an issue on GitHub at https://github.com/obgm/libcoap/issues to report any bugs.

Please raise a Pull Request at https://github.com/obgm/libcoap/pulls for any fixes.

AUTHORS

The libcoap project <libcoap-developers@lists.sourceforge.net>

coap_pdu_transmit(3)