#include "mem.h"
#endif /* WITH_CONTIKI */
-void coap_pdu_clear(coap_pdu_t *pdu, size_t size)
+void coap_pdu_clear(coap_pdu_t *pdu, size_t size, coap_transport_type transport, unsigned int length)
{
assert(pdu);
memset(pdu, 0, sizeof(coap_pdu_t) + size);
pdu->max_size = size;
pdu->hdr = (coap_hdr_t *) ((unsigned char *) pdu + sizeof(coap_pdu_t));
- pdu->hdr->version = COAP_DEFAULT_VERSION;
- /* data is NULL unless explicitly set by coap_add_data() */
- pdu->length = sizeof(coap_hdr_t);
+ if (coap_udp == transport)
+ {
+ pdu->hdr->coap_hdr_udp_t.version = COAP_DEFAULT_VERSION;
+ /* data is NULL unless explicitly set by coap_add_data() */
+ pdu->length = sizeof(pdu->hdr->coap_hdr_udp_t);
+ }
+ else
+ {
+ /* data is NULL unless explicitly set by coap_add_data() */
+ pdu->length = length;
+ }
}
#ifdef WITH_LWIP
#endif
coap_pdu_t *
-coap_pdu_init(unsigned char type, unsigned char code, unsigned short id, size_t size)
+coap_pdu_init(unsigned char type, unsigned char code, unsigned short id,
+ size_t size, coap_transport_type transport)
{
coap_pdu_t *pdu;
#ifdef WITH_LWIP
struct pbuf *p;
#endif
+ unsigned int length = 0;
+ switch(transport)
+ {
+ case coap_udp:
+ length = sizeof(pdu->hdr->coap_hdr_udp_t);
+ break;
+ case coap_tcp:
+ length = COAP_TCP_HEADER_NO_FIELD;
+ break;
+ case coap_tcp_8bit:
+ length = COAP_TCP_HEADER_8_BIT;
+ break;
+ case coap_tcp_16bit:
+ length = COAP_TCP_HEADER_16_BIT;
+ break;
+ case coap_tcp_32bit:
+ length = COAP_TCP_HEADER_32_BIT;
+ break;
+ default:
+ debug("it has wrong type\n");
+ }
+
assert(size <= COAP_MAX_PDU_SIZE);
/* Size must be large enough to fit the header. */
- if (size < sizeof(coap_hdr_t) || size > COAP_MAX_PDU_SIZE)
+ if (size < length || size > COAP_MAX_PDU_SIZE)
return NULL;
/* size must be large enough for hdr */
#endif
if (pdu)
{
- coap_pdu_clear(pdu, size);
- pdu->hdr->id = id;
- pdu->hdr->type = type;
- pdu->hdr->code = code;
+ coap_pdu_clear(pdu, size, transport, length);
+
+ switch(transport)
+ {
+ case coap_udp:
+ pdu->hdr->coap_hdr_udp_t.id = id;
+ pdu->hdr->coap_hdr_udp_t.type = type;
+ pdu->hdr->coap_hdr_udp_t.code = code;
+ break;
+ case coap_tcp:
+ pdu->hdr->coap_hdr_tcp_t.message_length = 0;
+ pdu->hdr->coap_hdr_tcp_t.code = code;
+ break;
+ case coap_tcp_8bit:
+ pdu->hdr->coap_hdr_tcp_8bit_t.message_length = COAP_TCP_LENGTH_FIELD_NUM_8_BIT;
+ pdu->hdr->coap_hdr_tcp_8bit_t.length_byte = 0;
+ pdu->hdr->coap_hdr_tcp_8bit_t.code = code;
+ break;
+ case coap_tcp_16bit:
+ pdu->hdr->coap_hdr_tcp_16bit_t.message_length = COAP_TCP_LENGTH_FIELD_NUM_16_BIT;
+ pdu->hdr->coap_hdr_tcp_16bit_t.length_byte = 0;
+ pdu->hdr->coap_hdr_tcp_16bit_t.code = code;
+ break;
+ case coap_tcp_32bit:
+ pdu->hdr->coap_hdr_tcp_32bit_t.header_data[0] = COAP_TCP_LENGTH_FIELD_NUM_32_BIT << 4;
+ pdu->hdr->coap_hdr_tcp_32bit_t.header_data[5] = code;
+ break;
+ default:
+ debug("it has wrong type\n");
+ }
+
#ifdef WITH_LWIP
pdu->pbuf = p;
#endif
}
coap_pdu_t *
-coap_new_pdu()
+coap_new_pdu(coap_transport_type transport)
{
coap_pdu_t *pdu;
#ifndef WITH_CONTIKI
- pdu = coap_pdu_init(0, 0, ntohs(COAP_INVALID_TID), COAP_MAX_PDU_SIZE);
+ pdu = coap_pdu_init(0, 0,
+ ntohs(COAP_INVALID_TID),
+ COAP_MAX_PDU_SIZE, transport);
#else /* WITH_CONTIKI */
- pdu = coap_pdu_init(0, 0, uip_ntohs(COAP_INVALID_TID), COAP_MAX_PDU_SIZE);
+ pdu = coap_pdu_init(0, 0, uip_ntohs(COAP_INVALID_TID), COAP_MAX_PDU_SIZE, transport);
#endif /* WITH_CONTIKI */
#ifndef NDEBUG
#endif
}
-int coap_add_token(coap_pdu_t *pdu, size_t len, const unsigned char *data)
+coap_transport_type coap_get_tcp_header_type_from_size(unsigned int size)
+{
+ if (COAP_TCP_LENGTH_LIMIT_8_BIT < size && COAP_TCP_LENGTH_LIMIT_16_BIT >= size)
+ {
+ return coap_tcp_8bit;
+ }
+ else if (COAP_TCP_LENGTH_LIMIT_16_BIT < size && COAP_TCP_LENGTH_LIMIT_32_BIT >= size)
+ {
+ return coap_tcp_16bit;
+ }
+ else if (COAP_TCP_LENGTH_LIMIT_32_BIT < size)
+ {
+ return coap_tcp_32bit;
+ }
+ else
+ {
+ return coap_tcp;
+ }
+}
+
+coap_transport_type coap_get_tcp_header_type_from_initbyte(unsigned int length)
+{
+ coap_transport_type type;
+ switch(length)
+ {
+ case COAP_TCP_LENGTH_FIELD_NUM_8_BIT:
+ type = coap_tcp_8bit;
+ break;
+ case COAP_TCP_LENGTH_FIELD_NUM_16_BIT:
+ type = coap_tcp_16bit;
+ break;
+ case COAP_TCP_LENGTH_FIELD_NUM_32_BIT:
+ type = coap_tcp_32bit;
+ break;
+ default:
+ type = coap_tcp;
+ }
+ return type;
+}
+
+void coap_add_length(const coap_pdu_t *pdu, coap_transport_type transport, unsigned int length)
+{
+ assert(pdu);
+
+ switch(transport)
+ {
+ case coap_tcp_8bit:
+ if (length > COAP_TCP_LENGTH_FIELD_8_BIT)
+ {
+ pdu->hdr->coap_hdr_tcp_8bit_t.length_byte =
+ length - COAP_TCP_LENGTH_FIELD_8_BIT;
+ }
+ break;
+ case coap_tcp_16bit:
+ if (length > COAP_TCP_LENGTH_FIELD_16_BIT)
+ {
+ pdu->hdr->coap_hdr_tcp_16bit_t.length_byte =
+ length - COAP_TCP_LENGTH_FIELD_16_BIT;
+ }
+ break;
+ case coap_tcp_32bit:
+ if (length > COAP_TCP_LENGTH_FIELD_32_BIT)
+ {
+ unsigned int total_length = length - COAP_TCP_LENGTH_FIELD_32_BIT;
+ pdu->hdr->coap_hdr_tcp_32bit_t.header_data[1] = total_length >> 24;
+ pdu->hdr->coap_hdr_tcp_32bit_t.header_data[2] = (total_length >> 16) & 0x00ff;
+ pdu->hdr->coap_hdr_tcp_32bit_t.header_data[3] = (total_length >> 8) & 0x0000ff;
+ pdu->hdr->coap_hdr_tcp_32bit_t.header_data[4] = total_length & 0x000000ff;
+ }
+ break;
+ default:
+ debug("it has wrong type\n");
+ }
+}
+
+unsigned int coap_get_length(const coap_pdu_t *pdu, coap_transport_type transport)
+{
+ assert(pdu);
+
+ unsigned int length = 0;
+ unsigned int length_field_data = 0;
+ switch(transport)
+ {
+ case coap_tcp_8bit:
+ length = pdu->hdr->coap_hdr_tcp_8bit_t.length_byte + COAP_TCP_LENGTH_FIELD_8_BIT;
+ break;
+ case coap_tcp_16bit:
+ length_field_data =
+ ((unsigned char *)(&pdu->hdr->coap_hdr_tcp_16bit_t))[2] << 8 |
+ ((unsigned char *)(&pdu->hdr->coap_hdr_tcp_16bit_t))[1];
+ length = length_field_data + COAP_TCP_LENGTH_FIELD_16_BIT;
+ break;
+ case coap_tcp_32bit:
+ length_field_data =
+ pdu->hdr->coap_hdr_tcp_32bit_t.header_data[1] << 24 |
+ pdu->hdr->coap_hdr_tcp_32bit_t.header_data[2] << 16 |
+ pdu->hdr->coap_hdr_tcp_32bit_t.header_data[3] << 8 |
+ pdu->hdr->coap_hdr_tcp_32bit_t.header_data[4];
+ length = length_field_data + COAP_TCP_LENGTH_FIELD_32_BIT;
+ break;
+ default:
+ debug("it has wrong type\n");
+ }
+
+ return length;
+}
+
+void coap_add_code(const coap_pdu_t *pdu, coap_transport_type transport, unsigned int code)
+{
+ assert(pdu);
+
+ switch(transport)
+ {
+ case coap_udp:
+ pdu->hdr->coap_hdr_udp_t.code = COAP_RESPONSE_CODE(code);
+ break;
+ case coap_tcp:
+ pdu->hdr->coap_hdr_tcp_t.code = COAP_RESPONSE_CODE(code);
+ break;
+ case coap_tcp_8bit:
+ pdu->hdr->coap_hdr_tcp_8bit_t.code = COAP_RESPONSE_CODE(code);
+ break;
+ case coap_tcp_16bit:
+ pdu->hdr->coap_hdr_tcp_16bit_t.code = COAP_RESPONSE_CODE(code);
+ break;
+ case coap_tcp_32bit:
+ pdu->hdr->coap_hdr_tcp_32bit_t.header_data[5] = COAP_RESPONSE_CODE(code);
+ break;
+ default:
+ debug("it has wrong type\n");
+ }
+}
+
+unsigned int coap_get_code(const coap_pdu_t *pdu, coap_transport_type transport)
+{
+ assert(pdu);
+
+ unsigned int code = 0;
+ switch(transport)
+ {
+ case coap_udp:
+ code = pdu->hdr->coap_hdr_udp_t.code;
+ break;
+ case coap_tcp:
+ code = pdu->hdr->coap_hdr_tcp_t.code;
+ break;
+ case coap_tcp_8bit:
+ code = pdu->hdr->coap_hdr_tcp_8bit_t.code;
+ break;
+ case coap_tcp_16bit:
+ code = pdu->hdr->coap_hdr_tcp_16bit_t.code;
+ break;
+ case coap_tcp_32bit:
+ code = pdu->hdr->coap_hdr_tcp_32bit_t.header_data[5];
+ break;
+ default:
+ debug("it has wrong type\n");
+ }
+ return code;
+}
+
+int coap_add_token(coap_pdu_t *pdu, size_t len, const unsigned char *data,
+ coap_transport_type transport)
{
const size_t HEADERLENGTH = len + 4;
/* must allow for pdu == NULL as callers may rely on this */
if (!pdu || len > 8 || pdu->max_size < HEADERLENGTH)
return 0;
- pdu->hdr->token_length = len;
+ unsigned char* token = NULL;
+ switch(transport)
+ {
+ case coap_udp:
+ pdu->hdr->coap_hdr_udp_t.token_length = len;
+ token = pdu->hdr->coap_hdr_udp_t.token;
+ pdu->length = HEADERLENGTH;
+ break;
+ case coap_tcp:
+ pdu->hdr->coap_hdr_tcp_t.token_length = len;
+ token = pdu->hdr->coap_hdr_tcp_t.token;
+ pdu->length = HEADERLENGTH;
+ break;
+ case coap_tcp_8bit:
+ pdu->hdr->coap_hdr_tcp_8bit_t.token_length = len;
+ token = pdu->hdr->coap_hdr_tcp_8bit_t.token;
+ pdu->length = HEADERLENGTH;
+ break;
+ case coap_tcp_16bit:
+ pdu->hdr->coap_hdr_tcp_16bit_t.token_length = len;
+ token = pdu->hdr->coap_hdr_tcp_16bit_t.token;
+ pdu->length = HEADERLENGTH;
+ break;
+ case coap_tcp_32bit:
+ pdu->hdr->coap_hdr_tcp_32bit_t.header_data[0] =
+ pdu->hdr->coap_hdr_tcp_32bit_t.header_data[0] | len;
+ token = pdu->hdr->coap_hdr_tcp_32bit_t.token;
+ pdu->length = len + COAP_TCP_HEADER_32_BIT;
+ break;
+ default:
+ debug("it has wrong type\n");
+ }
+
if (len)
- memcpy(pdu->hdr->token, data, len);
+ {
+ memcpy(token, data, len);
+ }
+
pdu->max_delta = 0;
- pdu->length = HEADERLENGTH;
pdu->data = NULL;
return 1;
}
+void coap_get_token(const coap_hdr_t *pdu_hdr, coap_transport_type transport,
+ unsigned char **token, unsigned int *token_length)
+{
+ assert(pdu);
+ assert(token);
+ assert(token_length);
+
+ switch(transport)
+ {
+ case coap_udp:
+ *token_length = pdu_hdr->coap_hdr_udp_t.token_length;
+ *token = (unsigned char *)pdu_hdr->coap_hdr_udp_t.token;
+ break;
+ case coap_tcp:
+ *token_length = pdu_hdr->coap_hdr_tcp_t.token_length;
+ *token = (unsigned char *)pdu_hdr->coap_hdr_tcp_t.token;
+ break;
+ case coap_tcp_8bit:
+ *token_length = pdu_hdr->coap_hdr_tcp_8bit_t.token_length;
+ *token = (unsigned char *)pdu_hdr->coap_hdr_tcp_8bit_t.token;
+ break;
+ case coap_tcp_16bit:
+ *token_length = pdu_hdr->coap_hdr_tcp_16bit_t.token_length;
+ *token = (unsigned char *)pdu_hdr->coap_hdr_tcp_16bit_t.token;
+ break;
+ case coap_tcp_32bit:
+ *token_length = (pdu_hdr->coap_hdr_tcp_32bit_t.header_data[0]) & 0x0f;
+ *token = (unsigned char *)pdu_hdr->coap_hdr_tcp_32bit_t.token;
+ break;
+ default:
+ debug("it has wrong type\n");
+ }
+}
+
/** @FIXME de-duplicate code with coap_add_option_later */
size_t coap_add_option(coap_pdu_t *pdu, unsigned short type, unsigned int len,
- const unsigned char *data)
+ const unsigned char *data, coap_transport_type transport)
{
size_t optsize;
coap_opt_t *opt;
return 0;
}
- opt = (unsigned char *) pdu->hdr + pdu->length;
+ switch(transport)
+ {
+ case coap_tcp:
+ opt = (unsigned char *) &(pdu->hdr->coap_hdr_tcp_t) + pdu->length;
+ break;
+ case coap_tcp_8bit:
+ opt = (unsigned char *) &(pdu->hdr->coap_hdr_tcp_8bit_t) + pdu->length;
+ break;
+ case coap_tcp_16bit:
+ opt = (unsigned char *) &(pdu->hdr->coap_hdr_tcp_16bit_t) + pdu->length;
+ break;
+ case coap_tcp_32bit:
+ opt = (unsigned char *) &(pdu->hdr->coap_hdr_tcp_32bit_t) + pdu->length;
+ break;
+ default:
+ opt = (unsigned char *) &(pdu->hdr->coap_hdr_udp_t) + pdu->length;
+ break;
+ }
/* encode option and check length */
optsize = coap_opt_encode(opt, pdu->max_size - pdu->length, type - pdu->max_delta, data, len);
return optsize;
}
-int coap_pdu_parse(unsigned char *data, size_t length, coap_pdu_t *pdu)
+int coap_pdu_parse(unsigned char *data, size_t length, coap_pdu_t *pdu,
+ coap_transport_type transport)
{
- coap_opt_t *opt;
-
assert(data);
assert(pdu);
{
debug("insufficient space to store parsed PDU\n");
printf("[COAP] insufficient space to store parsed PDU\n");
- return 0;
+ return -1;
}
- if (length < sizeof(coap_hdr_t))
+ unsigned int headerSize = 0;
+ switch(transport)
+ {
+ case coap_tcp:
+ headerSize = COAP_TCP_HEADER_NO_FIELD;
+ break;
+ case coap_tcp_8bit:
+ headerSize = COAP_TCP_HEADER_8_BIT;
+ break;
+ case coap_tcp_16bit:
+ headerSize = COAP_TCP_HEADER_16_BIT;
+ break;
+ case coap_tcp_32bit:
+ headerSize = COAP_TCP_HEADER_32_BIT;
+ break;
+ default:
+ headerSize = sizeof(pdu->hdr->coap_hdr_udp_t);
+ break;
+ }
+
+ if (length < headerSize)
{
debug("discarded invalid PDU\n");
}
- pdu->hdr->version = data[0] >> 6;
- pdu->hdr->type = (data[0] >> 4) & 0x03;
- pdu->hdr->token_length = data[0] & 0x0f;
- pdu->hdr->code = data[1];
- /*
- printf("[COAP] pdu - version : %d\n", pdu->hdr->version);
- printf("[COAP] pdu - type : %d\n", pdu->hdr->type);
- printf("[COAP] pdu - token_length : %d\n", pdu->hdr->token_length);
- printf("[COAP] pdu - code : %d\n", pdu->hdr->code);
- */
- pdu->data = NULL;
+ coap_opt_t *opt = NULL;
+ unsigned int tokenLength = 0;
+ switch(transport)
+ {
+ case coap_tcp:
+ pdu->hdr->coap_hdr_tcp_t.message_length = data[0] >> 4;
+ pdu->hdr->coap_hdr_tcp_t.token_length = data[0] & 0x0f;
+ pdu->hdr->coap_hdr_tcp_t.code = data[1];
+ tokenLength = pdu->hdr->coap_hdr_tcp_t.token_length;
+ opt = (unsigned char *) (&(pdu->hdr->coap_hdr_tcp_t) + 1) + tokenLength;
+ break;
+ case coap_tcp_8bit:
+ pdu->hdr->coap_hdr_tcp_8bit_t.message_length = data[0] >> 4;
+ pdu->hdr->coap_hdr_tcp_8bit_t.token_length = data[0] & 0x0f;
+ pdu->hdr->coap_hdr_tcp_8bit_t.length_byte = data[1];
+ pdu->hdr->coap_hdr_tcp_8bit_t.code = data[2];
+ tokenLength = pdu->hdr->coap_hdr_tcp_8bit_t.token_length;
+ opt = (unsigned char *) (&(pdu->hdr->coap_hdr_tcp_8bit_t) + 1) + tokenLength;
+ break;
+ case coap_tcp_16bit:
+ pdu->hdr->coap_hdr_tcp_16bit_t.message_length = data[0] >> 4;
+ pdu->hdr->coap_hdr_tcp_16bit_t.token_length = data[0] & 0x0f;
+ pdu->hdr->coap_hdr_tcp_16bit_t.length_byte = (data[2] << 8 | data[1]);
+ pdu->hdr->coap_hdr_tcp_16bit_t.code = data[3];
+ tokenLength = pdu->hdr->coap_hdr_tcp_16bit_t.token_length;
+ opt = (unsigned char *) (&(pdu->hdr->coap_hdr_tcp_16bit_t) + 1) + tokenLength;
+ break;
+ case coap_tcp_32bit:
+ for (size_t i = 0 ; i < headerSize ; i++)
+ {
+ pdu->hdr->coap_hdr_tcp_32bit_t.header_data[i] = data[i];
+ }
+
+ tokenLength = data[0] & 0x0f;
+ opt = ((unsigned char *) &(pdu->hdr->coap_hdr_tcp_32bit_t)) +
+ headerSize + tokenLength;
+ break;
+ default:
+ debug("it has wrong type\n");
+ }
+ pdu->length = length;
- /* sanity checks */
- if (pdu->hdr->code == 0)
+ if (coap_udp == transport)
{
- if (length != sizeof(coap_hdr_t) || pdu->hdr->token_length)
+ pdu->hdr->coap_hdr_udp_t.version = data[0] >> 6;
+ pdu->hdr->coap_hdr_udp_t.type = (data[0] >> 4) & 0x03;
+ pdu->hdr->coap_hdr_udp_t.token_length = data[0] & 0x0f;
+ pdu->hdr->coap_hdr_udp_t.code = data[1];
+ pdu->data = NULL;
+
+ tokenLength = pdu->hdr->coap_hdr_udp_t.token_length;
+
+ /* sanity checks */
+ if (pdu->hdr->coap_hdr_udp_t.code == 0)
{
- debug("coap_pdu_parse: empty message is not empty\n");
+ if (length != headerSize || tokenLength)
+ {
+ debug("coap_pdu_parse: empty message is not empty\n");
+ goto discard;
+ }
+ }
+
+ if (length < headerSize + tokenLength || tokenLength > 8)
+ {
+ debug("coap_pdu_parse: invalid Token\n");
goto discard;
}
- }
- if (length < sizeof(coap_hdr_t) + pdu->hdr->token_length || pdu->hdr->token_length > 8)
- {
- debug("coap_pdu_parse: invalid Token\n");
- goto discard;
- }
+ memcpy(&pdu->hdr->coap_hdr_udp_t.id, data + 2, 2);
- /* Copy message id in network byte order, so we can easily write the
- * response back to the network. */
- memcpy(&pdu->hdr->id, data + 2, 2);
+ /* Finally calculate beginning of data block and thereby check integrity
+ * of the PDU structure. */
- //printf("[COAP] pdu - id : %d\n", pdu->hdr->id);
+ /* append data (including the Token) to pdu structure */
+ memcpy(&(pdu->hdr->coap_hdr_udp_t) + 1, data + headerSize, length - headerSize);
- /* append data (including the Token) to pdu structure */
- memcpy(pdu->hdr + 1, data + sizeof(coap_hdr_t), length - sizeof(coap_hdr_t));
- pdu->length = length;
+ /* skip header + token */
+ length -= (tokenLength + headerSize);
+ opt = (unsigned char *) (&(pdu->hdr->coap_hdr_udp_t) + 1) + tokenLength;
+ }
+ else // common for tcp header setting
+ {
+ pdu->data = NULL;
+
+ if (length < headerSize + tokenLength || tokenLength > 8)
+ {
+ debug("coap_pdu_parse: invalid Token\n");
+ goto discard;
+ }
+ /* Finally calculate beginning of data block and thereby check integrity
+ * of the PDU structure. */
- /* Finally calculate beginning of data block and thereby check integrity
- * of the PDU structure. */
+ /* append data (including the Token) to pdu structure */
+ memcpy(((unsigned char *) pdu->hdr) + headerSize,
+ data + headerSize, length - headerSize);
- /* skip header + token */
- length -= (pdu->hdr->token_length + sizeof(coap_hdr_t));
- opt = (unsigned char *) (pdu->hdr + 1) + pdu->hdr->token_length;
+ /* skip header + token */
+ length -= (tokenLength + headerSize);
+ }
while (length && *opt != COAP_PAYLOAD_START)
{
}
debug(
- "set data to %p (pdu ends at %p)\n", (unsigned char *)opt, (unsigned char *)pdu->hdr + pdu->length);
+ "set data to %p (pdu ends at %p)\n", (unsigned char *)opt,
+ (unsigned char *)pdu->hdr + pdu->length);
pdu->data = (unsigned char *) opt;
//printf("[COAP] pdu - data : %s\n", pdu->data);
}