ifeq ($(CONFIG_NET_SECURITY_TLS),y)
CFLAGS += -DWITH_MBEDTLS
endif
+CFLAGS += -DWITH_TCP
#CFLAGS += ${shell $(INCDIR) $(INCDIROPT) "$(CC)" $(APPDIR)$(DELIM)include$(DELIM)netutils$(DELIM)libcoap}
ifneq ($(CONFIG_BUILD_KERNEL),y)
coap_pdu_t *pdu = coap_new_pdu();
if (pdu) {
- pdu->hdr->type = COAP_MESSAGE_ACK;
- pdu->hdr->code = 0;
- pdu->hdr->id = node->pdu->hdr->id;
+ pdu->transport_hdr->udp.type = COAP_MESSAGE_ACK;
+ pdu->transport_hdr->udp.code = 0;
+ pdu->transport_hdr->udp.id = node->pdu->transport_hdr->udp.id;
}
return pdu;
coap_pdu_t *pdu = new_ack(ctx, node);
if (pdu) {
- pdu->hdr->code = code;
+ pdu->transport_hdr->udp.code = code;
}
return pdu;
return NULL;
}
- pdu->hdr->type = msgtype;
- pdu->hdr->id = coap_new_message_id(ctx);
- pdu->hdr->code = m;
+ pdu->transport_hdr->udp.type = msgtype;
+ pdu->transport_hdr->udp.id = coap_new_message_id(ctx);
+ pdu->transport_hdr->udp.code = m;
- pdu->hdr->token_length = the_token.length;
+ pdu->transport_hdr->udp.token_length = the_token.length;
if (!coap_add_token(pdu, the_token.length, the_token.s)) {
debug("cannot add token to request\n");
}
}
}
- if (pdu->hdr->type == COAP_MESSAGE_CON) {
+ if (pdu->transport_hdr->udp.type == COAP_MESSAGE_CON) {
tid = coap_send_confirmed(ctx, remote, pdu);
} else {
tid = coap_send(ctx, remote, pdu);
if (tid == COAP_INVALID_TID) {
debug("clear_obs: error sending new request");
coap_delete_pdu(pdu);
- } else if (pdu->hdr->type != COAP_MESSAGE_CON) {
+ } else if (pdu->transport_hdr->udp.type != COAP_MESSAGE_CON) {
coap_delete_pdu(pdu);
}
}
}
#endif
- if (pdu->hdr->type == COAP_MESSAGE_CON) {
+ if (pdu->transport_hdr->udp.type == COAP_MESSAGE_CON) {
tid = coap_send_confirmed(ctx, &dst, pdu);
} else {
tid = coap_send(ctx, &dst, pdu);
}
- if (pdu->hdr->type != COAP_MESSAGE_CON || tid == COAP_INVALID_TID) {
+ if (pdu->transport_hdr->udp.type != COAP_MESSAGE_CON || tid == COAP_INVALID_TID) {
coap_delete_pdu(pdu);
}
ifeq ($(CONFIG_NET_SECURITY_TLS),y)
CFLAGS += -DWITH_MBEDTLS
endif
+CFLAGS += -DWITH_TCP
#CFLAGS += ${shell $(INCDIR) $(INCDIROPT) "$(CC)" $(APPDIR)$(DELIM)include$(DELIM)netutils$(DELIM)libcoap}
ifneq ($(CONFIG_BUILD_KERNEL),y)
{
unsigned char buf[3];
- response->hdr->code = COAP_RESPONSE_CODE(205);
+ response->transport_hdr->udp.code = COAP_RESPONSE_CODE(205);
coap_add_option(response, COAP_OPTION_CONTENT_TYPE, coap_encode_var_bytes(buf, COAP_MEDIATYPE_TEXT_PLAIN), buf);
* when query ?ticks is given. */
/* if my_clock_base was deleted, we pretend to have no such resource */
- response->hdr->code = my_clock_base ? COAP_RESPONSE_CODE(205) : COAP_RESPONSE_CODE(404);
+ response->transport_hdr->udp.code = my_clock_base ? COAP_RESPONSE_CODE(205) : COAP_RESPONSE_CODE(404);
if (request != NULL && coap_check_option(request, COAP_OPTION_OBSERVE, &opt_iter)) {
subscription = coap_add_observer(resource, peer, token);
if (subscription) {
- subscription->non = request->hdr->type == COAP_MESSAGE_NON;
+ subscription->non = request->transport_hdr->udp.type == COAP_MESSAGE_NON;
coap_add_option(response, COAP_OPTION_OBSERVE, 0, NULL);
}
}
*/
/* if my_clock_base was deleted, we pretend to have no such resource */
- response->hdr->code = my_clock_base ? COAP_RESPONSE_CODE(204) : COAP_RESPONSE_CODE(201);
+ response->transport_hdr->udp.code = my_clock_base ? COAP_RESPONSE_CODE(204) : COAP_RESPONSE_CODE(201);
resource->dirty = 1;
{
my_clock_base = 0; /* mark clock as "deleted" */
- /* type = request->hdr->type == COAP_MESSAGE_CON */
+ /* type = request->transport_hdr->udp.type == COAP_MESSAGE_CON */
/* ? COAP_MESSAGE_ACK : COAP_MESSAGE_NON; */
}
size_t size;
if (async) {
- if (async->id != request->hdr->id) {
+ if (async->id != request->transport_hdr->udp.id) {
coap_opt_filter_t f;
coap_option_filter_clear(f);
- response->hdr->code = COAP_RESPONSE_CODE(503);
+ response->transport_hdr->udp.code = COAP_RESPONSE_CODE(503);
}
return;
}
return;
}
- response->hdr->id = coap_new_message_id(ctx);
+ response->transport_hdr->udp.id = coap_new_message_id(ctx);
if (async->tokenlen) {
coap_add_token(response, async->tokenlen, async->token);
coap_add_data(response, 4, (unsigned char *)"done");
if (coap_send(ctx, &async->peer, response) == COAP_INVALID_TID) {
- debug("check_async: cannot send response for message %d\n", response->hdr->id);
+ debug("check_async: cannot send response for message %d\n", response->transport_hdr->udp.id);
}
coap_delete_pdu(response);
coap_remove_async(ctx, async->id, &tmp);
* @param pdu The PDU containing the options.
* @return A pointer to the first option if available, or @c NULL otherwise.
*/
-coap_opt_t *options_start(coap_pdu_t *pdu);
+coap_opt_t *options_start(coap_pdu_t *pdu, coap_transport_t transport);
/**
* Interprets @p opt as pointer to a CoAP option and advances to
} coap_opt_iterator_t;
/**
+ * Initializes the given option iterator @p oi to point to the beginning of the
+ * @p pdu's option list. This function returns @p oi on success, @c NULL
+ * otherwise (i.e. when no options exist). Note that a length check on the
+ * option list must be performed before coap_option_iterator_init() is called.
+ *
+ * @param pdu The PDU the options of which should be walked through.
+ * @param oi An iterator object that will be initilized.
+ * @param filter An optional option type filter.
+ * With @p type != @c COAP_OPT_ALL, coap_option_next()
+ * will return only options matching this bitmask.
+ * Fence-post options @c 14, @c 28, @c 42, ... are always
+ * skipped.
+ *
+ * @return The iterator object @p oi on success, @c NULL otherwise.
+ */
+coap_opt_iterator_t *coap_option_iterator_init(coap_pdu_t *pdu, coap_opt_iterator_t *oi, const coap_opt_filter_t filter);
+
+/**
* Initializes the given option iterator @p oi to point to the
* beginning of the @p pdu's option list. This function returns @p oi
* on success, @c NULL otherwise (i.e. when no options exist).
*
* @return The iterator object @p oi on success, @c NULL otherwise.
*/
-coap_opt_iterator_t *coap_option_iterator_init(coap_pdu_t *pdu, coap_opt_iterator_t *oi, const coap_opt_filter_t filter);
+coap_opt_iterator_t *coap_option_iterator_init2(coap_pdu_t *pdu, coap_opt_iterator_t *oi, const coap_opt_filter_t filter, coap_transport_t transport);
/**
* Updates the iterator @p oi to point to the next option. This
#define COAP_OPTION_PROXY_URI 35 /* C, String, 1-1034 B, (none) */
#define COAP_OPTION_PROXY_SCHEME 39 /* C, String, 1-255 B, (none) */
#define COAP_OPTION_SIZE1 60 /* E, uint, 0-4 B, (none) */
+#define COAP_OPTION_SIZE2 28 /* E, uint, 0-4 B, (none) */
/* option types from draft-ietf-coap-observe-09 */
* use an unallocated type here and hope for the best. */
#define COAP_MEDIATYPE_ANY 0xff /* any media type */
-/* CoAP transaction id */
-/*typedef unsigned short coap_tid_t; */
+/**
+ * coap_tid_t is used to store CoAP transaction id, i.e. a hash value
+ * built from the remote transport address and the message id of a
+ * CoAP PDU. Valid transaction ids are greater or equal zero.
+ */
typedef int coap_tid_t;
+
+/** Indicates an invalid transaction id. */
#define COAP_INVALID_TID -1
+#define COAP_TCP_HEADER_NO_FIELD 2
+#define COAP_TCP_HEADER_8_BIT 3
+#define COAP_TCP_HEADER_16_BIT 4
+#define COAP_TCP_HEADER_32_BIT 6
+
+#define COAP_TCP_LENGTH_FIELD_8_BIT 13
+#define COAP_TCP_LENGTH_FIELD_16_BIT 269
+#define COAP_TCP_LENGTH_FIELD_32_BIT 65805
+
+#define COAP_TCP_LENGTH_LIMIT_8_BIT 13
+#define COAP_TCP_LENGTH_LIMIT_16_BIT 256
+#define COAP_TCP_LENGTH_LIMIT_32_BIT 65536
+
+#define COAP_TCP_LENGTH_FIELD_NUM_8_BIT 13
+#define COAP_TCP_LENGTH_FIELD_NUM_16_BIT 14
+#define COAP_TCP_LENGTH_FIELD_NUM_32_BIT 15
+
+#define COAP_OPTION_FIELD_8_BIT 12
+#define COAP_OPTION_FIELD_16_BIT 256
+#define COAP_OPTION_FIELD_32_BIT 65536
+
+typedef enum {
+ COAP_UDP = 0,
+ COAP_TCP,
+ COAP_TCP_8BIT,
+ COAP_TCP_16BIT,
+ COAP_TCP_32BIT
+} coap_transport_t;
+
#ifdef WORDS_BIGENDIAN
typedef struct {
- unsigned int version: 2; /* protocol version */
- unsigned int type: 2; /* type flag */
- unsigned int token_length: 4; /* length of Token */
- unsigned int code: 8; /* request method (value 1--10) or response code (value 40-255) */
+ unsigned short version:2; /* protocol version */
+ unsigned short type:2; /* type flag */
+ unsigned short token_length:4; /* length of Token */
+ unsigned short code:8; /* request method (value 1--10) or response */
unsigned short id; /* message id */
unsigned char token[]; /* the actual token, if any */
-} coap_hdr_t;
+} coap_hdr_udp_t;
#else
typedef struct {
- unsigned int token_length: 4; /* length of Token */
- unsigned int type: 2; /* type flag */
- unsigned int version: 2; /* protocol version */
- unsigned int code: 8; /* request method (value 1--10) or response code (value 40-255) */
+ unsigned short token_length:4; /* length of Token */
+ unsigned short type:2; /* type flag */
+ unsigned short version:2; /* protocol version */
+ unsigned short code:8; /* request method (value 1--10) or response */
unsigned short id; /* transaction id (network byte order!) */
unsigned char token[]; /* the actual token, if any */
-} coap_hdr_t;
+} coap_hdr_udp_t;
#endif
-#define COAP_MESSAGE_IS_EMPTY(MSG) ((MSG)->code == 0)
+typedef struct {
+ unsigned char header_data[COAP_TCP_HEADER_NO_FIELD];
+ unsigned char token[]; /* the actual token, if any */
+} coap_hdr_tcp_t;
+
+typedef struct {
+ unsigned char header_data[COAP_TCP_HEADER_8_BIT];
+ unsigned char token[]; /* the actual token, if any */
+} coap_hdr_tcp_8bit_t;
+
+typedef struct {
+ unsigned char header_data[COAP_TCP_HEADER_16_BIT];
+ unsigned char token[]; /* the actual token, if any */
+} coap_hdr_tcp_16bit_t;
+
+typedef struct {
+ unsigned char header_data[6];
+ unsigned char token[]; /* the actual token, if any */
+} coap_hdr_tcp_32bit_t;
+
+typedef union {
+ coap_hdr_udp_t udp;
+ coap_hdr_tcp_t tcp;
+ coap_hdr_tcp_8bit_t tcp_8bit;
+ coap_hdr_tcp_16bit_t tcp_16bit;
+ coap_hdr_tcp_32bit_t tcp_32bit;
+} coap_hdr_transport_t;
+
+// Typedef for backwards compatibility.
+typedef coap_hdr_udp_t coap_hdr_t;
+
+#define COAP_MESSAGE_IS_EMPTY(MSG) ((MSG).code == 0)
#define COAP_MESSAGE_IS_REQUEST(MSG) (!COAP_MESSAGE_IS_EMPTY(MSG) \
- && ((MSG)->code < 32))
-#define COAP_MESSAGE_IS_RESPONSE(MSG) ((MSG)->code >= 64 && (MSG)->code <= 191)
+ && ((MSG).code < 32))
+#define COAP_MESSAGE_IS_RESPONSE(MSG) ((MSG).code >= 64 && (MSG).code <= 191)
#define COAP_OPT_LONG 0x0F /* OC == 0b1111 indicates that the option list in a
* CoAP message is limited by 0b11110000 marker */
typedef struct {
size_t max_size;/**< allocated storage for options and data */
- coap_hdr_t *hdr;
- unsigned short max_delta;
- /**< highest option number */
- unsigned short length; /**< PDU length (including header, options, data) */
+ union {
+ coap_hdr_t *hdr; /**< Address of the first byte of the CoAP message. This may or may not equal (coap_hdr_t*)(pdu+1) depending on the memory management implementation. */
+ coap_hdr_transport_t *transport_hdr; /**< Address of the first byte of the CoAP message. This may or may not equal (coap_hdr_t*)(pdu+1) depending on the memory management implementation. */
+ };
+ unsigned short max_delta; /**< highest option number */
+ unsigned int length; /**< PDU length (including header, options, data) */
unsigned char *data; /**< payload */
#ifdef WITH_LWIP
coap_pdu_t *coap_pdu_init(unsigned char type, unsigned char code, unsigned short id, size_t size);
/**
+ * Creates a new CoAP PDU of given @p size (must be large enough to hold the
+ * basic CoAP message header (coap_hdr_t). The function returns a pointer to
+ * the node coap_pdu_t object on success, or @c NULL on error. The storage
+ * allocated for the result must be released with coap_delete_pdu().
+ *
+ * @param type The type of the PDU (one of COAP_MESSAGE_CON,
+ * COAP_MESSAGE_NON, COAP_MESSAGE_ACK, COAP_MESSAGE_RST).
+ * @param code The message code.
+ * @param id The message id to set or COAP_INVALID_TID if unknown.
+ * @param size The number of bytes to allocate for the actual message.
+ * @param transport The transport type.
+ *
+ * @return A pointer to the new PDU object or @c NULL on error.
+ */
+coap_pdu_t *
+coap_pdu_init2(unsigned char type, unsigned char code, unsigned short id, size_t size, coap_transport_t transport);
+
+/**
* Clears any contents from @p pdu and resets @c version field, @c
* length and @c data pointers. @c max_size is set to @p size, any
* other field is set to @c 0. Note that @p pdu must be a valid
void coap_pdu_clear(coap_pdu_t *pdu, size_t size);
/**
- * Creates a new CoAP PDU. The object is created on the heap and must be released
- * using coap_delete_pdu();
+ * Clears any contents from @p pdu and resets @c version field, @c
+ * length and @c data pointers. @c max_size is set to @p size, any
+ * other field is set to @c 0. Note that @p pdu must be a valid
+ * pointer to a coap_pdu_t object created e.g. by coap_pdu_init().
+ */
+void coap_pdu_clear2(coap_pdu_t *pdu, size_t size, coap_transport_t transport, unsigned int length);
+
+/**
+ * Creates a new CoAP PDU.
+ * The object is created on the heap and must be released using
+ * coap_delete_pdu();
*
* @deprecated This function allocates the maximum storage for each
* PDU. Use coap_pdu_init() instead.
*/
coap_pdu_t *coap_new_pdu(void);
+/**
+ * Creates a new CoAP PDU. The object is created on the heap and must be released
+ * using coap_delete_pdu();
+ *
+ * @deprecated This function allocates the maximum storage for each
+ * PDU. Use coap_pdu_init2() instead.
+ */
+coap_pdu_t *coap_new_pdu2(coap_transport_t transport, unsigned int size);
+
void coap_delete_pdu(coap_pdu_t *);
/**
- * Parses @p data into the CoAP PDU structure given in @p result. This
- * function returns @c 0 on error or a number greater than zero on
- * success.
+ * Parses @p data into the CoAP PDU structure given in @p result.
+ * This function returns @c 0 on error or a number greater than zero on success.
*
* @param data The raw data to parse as CoAP PDU
* @param length The actual size of @p data
* @param result The PDU structure to fill. Note that the structure must
* provide space for at least @p length bytes to hold the
* entire CoAP PDU.
+ *
* @return A value greater than zero on success or @c 0 on error.
*/
int coap_pdu_parse(unsigned char *data, size_t length, coap_pdu_t *result);
/**
+ * Parses @p data into the CoAP PDU structure given in @p result.
+ * This function returns @c 0 on error or a number greater than zero on success.
+ *
+ * @param data The raw data to parse as CoAP PDU
+ * @param length The actual size of @p data
+ * @param result The PDU structure to fill. Note that the structure must
+ * provide space for at least @p length bytes to hold the
+ * entire CoAP PDU.
+ * @param transport The transport type.
+ * @return A value greater than zero on success or @c 0 on error.
+ */
+int coap_pdu_parse2(unsigned char *data, size_t length, coap_pdu_t *pdu, coap_transport_t transport);
+
+/**
+ * Get total pdu size including header + option + payload (with marker) from pdu data.
+ *
+ * @param data The raw data to parse as CoAP PDU.
+ * @param size payload size of pdu.
+ * @return Total message length.
+ */
+size_t coap_get_total_message_length(const unsigned char *data, size_t size);
+
+/**
+ * Get transport type of coap header for coap over tcp
+ * through payload size(including payload marker) + option size.
+ *
+ * @param size payload size of pdu.
+ * @return The transport type.
+ */
+coap_transport_t coap_get_tcp_header_type_from_size(unsigned int size);
+
+/**
+ * Get transport type of coap header for coap over tcp
+ * through first nibble(0~E) of init-byte .
+ *
+ * @param legnth length value of init byte.
+* @return The transport type.
+ */
+coap_transport_t coap_get_tcp_header_type_from_initbyte(unsigned int length);
+
+/**
+ * Add length of option/payload into 'Len+ byte...' field of coap header
+ * for coap over tcp.
+ *
+ * @param pdu The pdu pointer.
+ * @param transport The transport type.
+ * @param length length value of init byte.
+ */
+void coap_add_length(const coap_pdu_t *pdu, coap_transport_t transport, unsigned int length);
+
+/**
+ * Get the length of option/payload field of coap header for coap over tcp.
+ *
+ * @param pdu The pdu pointer.
+ * @param transport The transport type.
+ * @return length value of init byte.
+ */
+unsigned int coap_get_length(const coap_pdu_t *pdu, coap_transport_t transport);
+
+/**
+ * Get the length of option/payload field of coap header for coap over tcp.
+ *
+ * @param header The header to parse.
+ * @return transport The transport type.
+ */
+unsigned int coap_get_length_from_header(const unsigned char *header, coap_transport_t transport);
+
+/**
+ * Get length of header including len, TKL, Len+bytes, Code, token bytes for coap over tcp.
+ *
+ * @param data The raw data to parse as CoAP PDU
+ * @return header length + token length
+ */
+unsigned int coap_get_tcp_header_length(unsigned char *data);
+
+/**
+ * Get length of header including len, TKL, Len+bytes, Code
+ * without token bytes for coap over tcp.
+ *
+ * @param transport The transport type.
+ * @return header length.
+ */
+unsigned int coap_get_tcp_header_length_for_transport(coap_transport_t transport);
+
+/**
+ * Get option length.
+ *
+ * @param key delta of option
+ * @param length length of option
+ * @return total option length
+ */
+size_t coap_get_opt_header_length(unsigned short key, size_t length);
+
+/**
+ * Add code in coap header.
+ *
+ * @param pdu The pdu pointer.
+ * @param transport The transport type.
+ * @param code The message code.
+ */
+void coap_add_code(const coap_pdu_t *pdu, coap_transport_t transport, unsigned int code);
+
+/**
+ * Get message code from coap header
+ *
+ * @param pdu The pdu pointer.
+ * @param transport The transport type.
+ * @return The message code.
+ */
+unsigned int coap_get_code(const coap_pdu_t *pdu, coap_transport_t transport);
+
+/**
+ * Adds token of length @p len to @p pdu.
+ * Adding the token destroys any following contents of the pdu. Hence options
+ * and data must be added after coap_add_token() has been called. In @p pdu,
+ * length is set to @p len + @c 4, and max_delta is set to @c 0. This funtion
+ * returns @c 0 on error or a value greater than zero on success.
+ *
+ * @param pdu The PDU where the token is to be added.
+ * @param len The length of the new token.
+ * @param data The token to add.
+ *
+ * @return A value greater than zero on success, or @c 0 on error.
+ */
+int coap_add_token(coap_pdu_t *pdu, size_t len, const unsigned char *data);
+
+/**
* Adds token of length @p len to @p pdu. Adding the token destroys
* any following contents of the pdu. Hence options and data must be
- * added after coap_add_token() has been called. In @p pdu, length is
+ * added after coap_add_token2() has been called. In @p pdu, length is
* set to @p len + @c 4, and max_delta is set to @c 0. This funtion
* returns @c 0 on error or a value greater than zero on success.
*
- * @param pdu The PDU where the token is to be added.
+ * @param pdu The pdu pointer.
* @param len The length of the new token.
* @param data The token to add.
+ * @param transport The transport type.
* @return A value greater than zero on success, or @c 0 on error.
*/
-int coap_add_token(coap_pdu_t *pdu, size_t len, const unsigned char *data);
+int coap_add_token2(coap_pdu_t *pdu, size_t len, const unsigned char *data, coap_transport_t transport);
+
+/**
+ * Get token from coap header
+ *
+ * @param pdu_hdr The header pointer of PDU.
+ * @param token out parameter to get token.
+ * @param token_length out parameter to get token length.
+ */
+void coap_get_token(const coap_hdr_t *pdu_hdr, unsigned char **token, unsigned int *token_length);
+
+/**
+ * Get token from coap header based on transport type
+ *
+ * @param pdu_hdr The header pointer of PDU.
+ * @param transport The transport type.
+ * @param token out parameter to get token.
+ * @param token_length out parameter to get token length.
+ */
+void coap_get_token2(const coap_hdr_transport_t *pdu_hdr, coap_transport_t transport, unsigned char **token, unsigned int *token_length);
+
+/**
+ * Adds option of given type to pdu that is passed as first parameter.
+ * coap_add_option() destroys the PDU's data, so coap_add_data() must be called
+ * after all options have been added. As coap_add_token() destroys the options
+ * following the token, the token must be added before coap_add_option() is
+ * called. This function returns the number of bytes written or @c 0 on error.
+ */
+size_t coap_add_option(coap_pdu_t *pdu, unsigned short type, unsigned int len, const unsigned char *data);
/**
* Adds option of given type to pdu that is passed as first
- * parameter. coap_add_option() destroys the PDU's data, so
+ * parameter. coap_add_option2() destroys the PDU's data, so
* coap_add_data() must be called after all options have been added.
- * As coap_add_token() destroys the options following the token,
- * the token must be added before coap_add_option() is called.
+ * As coap_add_token2() destroys the options following the token,
+ * the token must be added before coap_add_option2() is called.
* This function returns the number of bytes written or @c 0 on error.
*/
-size_t coap_add_option(coap_pdu_t *pdu, unsigned short type, unsigned int len, const unsigned char *data);
+size_t coap_add_option2(coap_pdu_t *pdu, unsigned short type, unsigned int len,
+ const unsigned char *data, coap_transport_t transport);
/**
* Adds option of given type to pdu that is passed as first
ifeq ($(CONFIG_NET_SECURITY_TLS),y)
CFLAGS += -DWITH_MBEDTLS
endif
+CFLAGS += -DWITH_TCP
#CFLAGS += ${shell $(INCDIR) $(INCDIROPT) "$(CC)" $(APPDIR)$(DELIM)include$(DELIM)netutils$(DELIM)libcoap}
ifeq ($(CONFIG_WINDOWS_NATIVE),y)
#include <apps/netutils/libcoap/debug.h>
#include <apps/netutils/libcoap/async.h>
+/* TODO : Considering TCP Case */
coap_async_state_t *coap_register_async(coap_context_t *context, coap_address_t *peer, coap_pdu_t *request, unsigned char flags, void *data)
{
coap_async_state_t *s;
}
/* store information for handling the asynchronous task */
- s = (coap_async_state_t *) coap_malloc(sizeof(coap_async_state_t) + request->hdr->token_length);
+ s = (coap_async_state_t *) coap_malloc(sizeof(coap_async_state_t) +
+ request->transport_hdr->udp.token_length);
if (!s) {
coap_log(LOG_CRIT, "coap_register_async: insufficient memory\n");
return NULL;
}
- memset(s, 0, sizeof(coap_async_state_t) + request->hdr->token_length);
+ memset(s, 0, sizeof(coap_async_state_t) + request->transport_hdr->udp.token_length);
/* set COAP_ASYNC_CONFIRM according to request's type */
s->flags = flags & ~COAP_ASYNC_CONFIRM;
- if (request->hdr->type == COAP_MESSAGE_CON) {
+ if (request->transport_hdr->udp.type == COAP_MESSAGE_CON) {
s->flags |= COAP_ASYNC_CONFIRM;
}
memcpy(&s->peer, peer, sizeof(coap_address_t));
- if (request->hdr->token_length) {
- s->tokenlen = request->hdr->token_length;
- memcpy(s->token, request->hdr->token, request->hdr->token_length);
+ if (request->transport_hdr->udp.token_length) {
+ s->tokenlen = request->transport_hdr->udp.token_length;
+ memcpy(s->token, request->transport_hdr->udp.token, request->transport_hdr->udp.token_length);
}
memcpy(&s->id, &id, sizeof(coap_tid_t));
#ifndef WITH_CONTIKI
void coap_show_pdu(const coap_pdu_t *pdu)
{
- unsigned char buf[COAP_MAX_PDU_SIZE]; /* need some space for output creation */
+#ifndef WITH_TCP
+ unsigned char buf[COAP_MAX_PDU_SIZE]; /* need some space for output creation */
+#else
+ unsigned char buf[COAP_TCP_LENGTH_LIMIT_32_BIT]; /* need some space for output creation */
+#endif
int encode = 0, have_options = 0;
coap_opt_iterator_t opt_iter;
coap_opt_t *option;
-
- fprintf(COAP_DEBUG_FD, "v:%d t:%d tkl:%d c:%d id:%u", pdu->hdr->version, pdu->hdr->type, pdu->hdr->token_length, pdu->hdr->code, ntohs(pdu->hdr->id));
+ /* TODO : Considering TCP Case */
+ fprintf(COAP_DEBUG_FD, "v:%d t:%d tkl:%d c:%d id:%u", pdu->transport_hdr->udp.version,
+ pdu->transport_hdr->udp.type, pdu->transport_hdr->udp.token_length,
+ pdu->transport_hdr->udp.code, ntohs(pdu->transport_hdr->udp.id));
/* show options, if any */
coap_option_iterator_init((coap_pdu_t *) pdu, &opt_iter, COAP_OPT_ALL);
fprintf(COAP_DEBUG_FD, ",");
}
- if (opt_iter.type == COAP_OPTION_URI_PATH || opt_iter.type == COAP_OPTION_PROXY_URI || opt_iter.type == COAP_OPTION_URI_HOST || opt_iter.type == COAP_OPTION_LOCATION_PATH || opt_iter.type == COAP_OPTION_LOCATION_QUERY || opt_iter.type == COAP_OPTION_URI_PATH || opt_iter.type == COAP_OPTION_URI_QUERY) {
+ if (opt_iter.type == COAP_OPTION_URI_PATH || opt_iter.type == COAP_OPTION_PROXY_URI
+ || opt_iter.type == COAP_OPTION_URI_HOST
+ || opt_iter.type == COAP_OPTION_LOCATION_PATH
+ || opt_iter.type == COAP_OPTION_LOCATION_QUERY
+ || opt_iter.type == COAP_OPTION_URI_PATH || opt_iter.type == COAP_OPTION_URI_QUERY) {
encode = 0;
} else {
encode = 1;
{
unsigned char buf[80]; /* need some space for output creation */
- PRINTF("v:%d t:%d oc:%d c:%d id:%u", pdu->hdr->version, pdu->hdr->type, pdu->hdr->optcnt, pdu->hdr->code, uip_ntohs(pdu->hdr->id));
+ PRINTF("v:%d t:%d oc:%d c:%d id:%u",
+ pdu->transport_hdr->udp.version, pdu->transport_hdr->udp.type,
+ pdu->transport_hdr->udp.optcnt, pdu->transport_hdr->udp.code,
+ uip_ntohs(pdu->transport_hdr->udp.id));
/* show options, if any */
if (pdu->hdr->optcnt) {
coap_hash((const unsigned char *)&peer->port, sizeof(peer->port), h);
coap_hash((const unsigned char *)&peer->addr, sizeof(peer->addr), h);
#endif /* WITH_LWIP || WITH_CONTIKI */
-
- coap_hash((const unsigned char *)&pdu->hdr->id, sizeof(unsigned short), h);
+ /* TODO : Considering TCP Case */
+ coap_hash((const unsigned char *)&pdu->transport_hdr->udp.id, sizeof(unsigned short), h);
*id = ((h[0] << 8) | h[1]) ^ ((h[2] << 8) | h[3]);
}
coap_pdu_t *response;
coap_tid_t result = COAP_INVALID_TID;
- if (request && request->hdr->type == COAP_MESSAGE_CON) {
- response = coap_pdu_init(COAP_MESSAGE_ACK, 0, request->hdr->id, sizeof(coap_pdu_t));
+ /* TODO : Considering TCP Case */
+ if (request && request->transport_hdr->udp.type == COAP_MESSAGE_CON) {
+ response = coap_pdu_init(COAP_MESSAGE_ACK, 0, request->transport_hdr->udp.id, sizeof(coap_pdu_t));
if (response) {
result = coap_send(context, dst, response);
coap_delete_pdu(response);
coap_tid_t result = COAP_INVALID_TID;
if (request) {
- response = coap_pdu_init(type, 0, request->hdr->id, sizeof(coap_pdu_t));
+ /* TODO : Considering TCP Case */
+ response = coap_pdu_init(type, 0, request->transport_hdr->udp.id, sizeof(coap_pdu_t));
if (response) {
result = coap_send(context, dst, response);
coap_delete_pdu(response);
etimer_set(&context->retransmit_timer, nextpdu->t);
PROCESS_CONTEXT_END(&coap_retransmit_process);
}
-#endif /* WITH_CONTIKI */
+#endif /* WITH_CONTIKI */
return node->id;
}
}
#endif
- debug("** retransmission #%d of transaction %d\n", node->retransmit_cnt, ntohs(node->pdu->hdr->id));
+ debug("** retransmission #%d of transaction %d\n", node->retransmit_cnt, ntohs(node->pdu->transport_hdr->udp.id));
node->id = coap_send_impl(context, &node->remote, node->pdu);
return node->id;
#ifndef WITHOUT_OBSERVE
/* Check if subscriptions exist that should be canceled after
COAP_MAX_NOTIFY_FAILURES */
- if (node->pdu->hdr->code >= 64) {
+ /* TODO : Considering TCP Case */
+ if (node->pdu->transport_hdr->udp.code >= 64) {
str token = { 0, NULL };
- token.length = node->pdu->hdr->token_length;
- token.s = node->pdu->hdr->token;
+ token.length = node->pdu->transport_hdr->udp.token_length;
+ token.s = node->pdu->transport_hdr->udp.token;
coap_handle_failed_notify(context, &node->remote, &token);
}
coap_queue_t *p, *q;
debug("cancel_all_messages\n");
- while (context->sendqueue && coap_address_equals(dst, &context->sendqueue->remote) && token_match(token, token_length, context->sendqueue->pdu->hdr->token, context->sendqueue->pdu->hdr->token_length)) {
+ /* TODO : Considering TCP Case */
+ while (context->sendqueue && coap_address_equals(dst, &context->sendqueue->remote)
+ && token_match(token, token_length, context->sendqueue->pdu->transport_hdr->udp.token, context->sendqueue->pdu->transport_hdr->udp.token_length)) {
q = context->sendqueue;
context->sendqueue = q->next;
- debug("**** removed transaction %d\n", ntohs(q->pdu->hdr->id));
+ debug("**** removed transaction %d\n", ntohs(q->pdu->transport_hdr->udp.id));
coap_delete_node(q);
}
/* when q is not NULL, it does not match (dst, token), so we can skip it */
while (q) {
- if (coap_address_equals(dst, &q->remote) && token_match(token, token_length, q->pdu->hdr->token, q->pdu->hdr->token_length)) {
+ /* TODO : Considering TCP Case */
+ if (coap_address_equals(dst, &q->remote)
+ && token_match(token, token_length, q->pdu->transport_hdr->udp.token, q->pdu->transport_hdr->udp.token_length)) {
p->next = q->next;
- debug("**** removed transaction %d\n", ntohs(q->pdu->hdr->id));
+ debug("**** removed transaction %d\n", ntohs(q->pdu->transport_hdr->udp.id));
coap_delete_node(q);
q = p->next;
} else {
{
coap_opt_iterator_t opt_iter;
coap_pdu_t *response;
- size_t size = sizeof(coap_hdr_t) + request->hdr->token_length;
+ /* TODO : Considering TCP Case */
+ size_t size = sizeof(coap_hdr_t) + request->transport_hdr->udp.token_length;
int type;
coap_opt_t *option;
unsigned short opt_type = 0; /* used for calculating delta-storage */
assert(request);
/* cannot send ACK if original request was not confirmable */
- type = request->hdr->type == COAP_MESSAGE_CON ? COAP_MESSAGE_ACK : COAP_MESSAGE_NON;
+ /* TODO : Considering TCP Case */
+ type = request->transport_hdr->udp.type == COAP_MESSAGE_CON ? COAP_MESSAGE_ACK : COAP_MESSAGE_NON;
/* Estimate how much space we need for options to copy from
* request. We always need the Token, for 4.02 the unknown critical
}
/* Now create the response and fill with options and payload data. */
- response = coap_pdu_init(type, code, request->hdr->id, size);
+ /* TODO : Considering TCP Case */
+ response = coap_pdu_init(type, code, request->transport_hdr->udp.id, size);
if (response) {
/* copy token */
- if (!coap_add_token(response, request->hdr->token_length, request->hdr->token)) {
+ if (!coap_add_token(response, request->transport_hdr->udp.token_length, request->transport_hdr->udp.token)) {
debug("cannot add token to error response\n");
coap_delete_pdu(response);
return NULL;
unsigned char buf[1];
size_t len = 0;
- if (print_wellknown(context, buf, &len, UINT_MAX, query_filter)
- & COAP_PRINT_STATUS_ERROR) {
+ if (print_wellknown(context, buf, &len, UINT_MAX, query_filter) & COAP_PRINT_STATUS_ERROR) {
warn("cannot determine length of /.well-known/core\n");
return 0;
}
coap_opt_t *query_filter;
size_t offset = 0;
- resp = coap_pdu_init(request->hdr->type == COAP_MESSAGE_CON ? COAP_MESSAGE_ACK : COAP_MESSAGE_NON, COAP_RESPONSE_CODE(205), request->hdr->id, COAP_MAX_PDU_SIZE);
+ /* TODO : Considering TCP Case */
+ resp = coap_pdu_init(request->transport_hdr->udp.type == COAP_MESSAGE_CON ? COAP_MESSAGE_ACK : COAP_MESSAGE_NON,
+ COAP_RESPONSE_CODE(205), request->transport_hdr->udp.id, COAP_MAX_PDU_SIZE);
if (!resp) {
debug("wellknown_response: cannot create PDU\n");
return NULL;
}
-
- if (!coap_add_token(resp, request->hdr->token_length, request->hdr->token)) {
+ /* TODO : Considering TCP Case */
+ if (!coap_add_token(resp, request->transport_hdr->udp.token_length, request->transport_hdr->udp.token)) {
debug("wellknown_response: cannot add token\n");
goto error;
}
/* check whether the request contains the Block2 option */
if (coap_get_block(request, COAP_OPTION_BLOCK2, &block)) {
offset = block.num << (block.szx + 4);
- if (block.szx > 6) { /* invalid, MUST lead to 4.00 Bad Request */
- resp->hdr->code = COAP_RESPONSE_CODE(400);
+ if (block.szx > 6) {
+ /* invalid, MUST lead to 4.00 Bad Request */
+ resp->transport_hdr->udp.code = COAP_RESPONSE_CODE(400);
return resp;
} else if (block.szx > COAP_MAX_BLOCK_SZX) {
block.szx = COAP_MAX_BLOCK_SZX;
/* Add Content-Format. As we have checked for available storage,
* nothing should go wrong here. */
assert(coap_encode_var_bytes(buf, COAP_MEDIATYPE_APPLICATION_LINK_FORMAT) == 1);
- coap_add_option(resp, COAP_OPTION_CONTENT_FORMAT, coap_encode_var_bytes(buf, COAP_MEDIATYPE_APPLICATION_LINK_FORMAT), buf);
+ coap_add_option(resp, COAP_OPTION_CONTENT_FORMAT,
+ coap_encode_var_bytes(buf, COAP_MEDIATYPE_APPLICATION_LINK_FORMAT), buf);
/* check if Block2 option is required even if not requested */
if (!need_block2 && (resp->max_size - (size_t) resp->length < wkc_len)) {
error:
/* set error code 5.03 and remove all options and data from response */
- resp->hdr->code = COAP_RESPONSE_CODE(503);
- resp->length = sizeof(coap_hdr_t) + resp->hdr->token_length;
+ /* TODO : Considering TCP Case */
+ resp->transport_hdr->udp.code = COAP_RESPONSE_CODE(503);
+ resp->length = sizeof(coap_hdr_t) + resp->transport_hdr->udp.token_length;
return resp;
}
-#define WANT_WKC(Pdu,Key) \
- (((Pdu)->hdr->code == COAP_REQUEST_GET) && is_wkc(Key))
+/* TODO : Considering TCP Case */
+#define WANT_WKC(Pdu,Key) \
+ (((Pdu)->transport_hdr->udp.code == COAP_REQUEST_GET) && is_wkc(Key))
void handle_request(coap_context_t *context, coap_queue_t *node)
{
* be the well-known URI. In that case, we generate a default
* response, otherwise, we return 4.04 */
- switch (node->pdu->hdr->code) {
+ switch (node->pdu->transport_hdr->udp.code) {
case COAP_REQUEST_GET:
- if (is_wkc(key)) { /* GET request for .well-known/core */
+ if (is_wkc(key)) {
+ /* GET request for .well-known/core */
info("create default response for %s\n", COAP_DEFAULT_URI_WELLKNOWN);
+
response = wellknown_response(context, node->pdu);
- } else { /* GET request for any another resource, return 4.04 */
+ } else {
+ /* GET request for any another resource, return 4.04 */
debug("GET for unknown resource 0x%02x%02x%02x%02x, return 4.04\n", key[0], key[1], key[2], key[3]);
response = coap_new_error_response(node->pdu, COAP_RESPONSE_CODE(404), opt_filter);
}
/* the resource was found, check if there is a registered handler */
- if ((size_t) node->pdu->hdr->code - 1 < sizeof(resource->handler) / sizeof(coap_method_handler_t)) {
- h = resource->handler[node->pdu->hdr->code - 1];
+ if ((size_t) node->pdu->transport_hdr->udp.code - 1 < sizeof(resource->handler) / sizeof(coap_method_handler_t)) {
+ h = resource->handler[node->pdu->transport_hdr->udp.code - 1];
}
if (h) {
debug("call custom handler for resource 0x%02x%02x%02x%02x\n", key[0], key[1], key[2], key[3]);
- response = coap_pdu_init(node->pdu->hdr->type == COAP_MESSAGE_CON ? COAP_MESSAGE_ACK : COAP_MESSAGE_NON, 0, node->pdu->hdr->id, COAP_MAX_PDU_SIZE);
+ response = coap_pdu_init(node->pdu->transport_hdr->udp.type == COAP_MESSAGE_CON ? COAP_MESSAGE_ACK : COAP_MESSAGE_NON,
+ 0, node->pdu->transport_hdr->udp.id, COAP_MAX_PDU_SIZE);
/* Implementation detail: coap_add_token() immediately returns 0
if response == NULL */
- if (coap_add_token(response, node->pdu->hdr->token_length, node->pdu->hdr->token)) {
- str token = { node->pdu->hdr->token_length, node->pdu->hdr->token };
+ if (coap_add_token(response, node->pdu->transport_hdr->udp.token_length, node->pdu->transport_hdr->udp.token)) {
+ str token = { node->pdu->transport_hdr->udp.token_length, node->pdu->transport_hdr->udp.token };
h(context, resource, &node->remote, node->pdu, &token, response);
- if (response->hdr->type != COAP_MESSAGE_NON || (response->hdr->code >= 64 && !coap_is_mcast(&node->local))) {
+
+ if (response->transport_hdr->udp.type != COAP_MESSAGE_NON
+ || (response->transport_hdr->udp.code >= 64 && !coap_is_mcast(&node->local))) {
+
if (coap_send(context, &node->remote, response) == COAP_INVALID_TID) {
- debug("cannot send response for message %d\n", node->pdu->hdr->id);
+ debug("cannot send response for message %d\n", node->pdu->transport_hdr->udp.id);
}
}
response = coap_new_error_response(node->pdu, COAP_RESPONSE_CODE(405), opt_filter);
}
- if (!response || (coap_send(context, &node->remote, response)
- == COAP_INVALID_TID)) {
+ if (!response || (coap_send(context, &node->remote, response) == COAP_INVALID_TID)) {
debug("cannot send response for transaction %u\n", node->id);
}
coap_delete_pdu(response);
/* remove observer for this resource, if any
* get token from sent and try to find a matching resource. Uh!
*/
-
- COAP_SET_STR(&token, sent->pdu->hdr->token_length, sent->pdu->hdr->token);
+ /* TODO : Considering TCP Case */
+ COAP_SET_STR(&token, sent->pdu->transport_hdr->udp.token_length, sent->pdu->transport_hdr->udp.token);
#ifndef WITH_CONTIKI
#ifdef COAP_RESOURCES_NOHASH
context->recvqueue = context->recvqueue->next;
rcvd->next = NULL;
- if (rcvd->pdu->hdr->version != COAP_DEFAULT_VERSION) {
- debug("dropped packet with unknown version %u\n", rcvd->pdu->hdr->version);
+ if (rcvd->pdu->transport_hdr->udp.version != COAP_DEFAULT_VERSION) {
+ debug("dropped packet with unknown version %u\n", rcvd->pdu->transport_hdr->udp.version);
goto cleanup;
}
- switch (rcvd->pdu->hdr->type) {
+ switch (rcvd->pdu->transport_hdr->udp.type) {
case COAP_MESSAGE_ACK:
/* find transaction in sendqueue to stop retransmission */
coap_remove_from_queue(&context->sendqueue, rcvd->id, &sent);
- if (rcvd->pdu->hdr->code == 0) {
+ if (rcvd->pdu->transport_hdr->udp.code == 0) {
goto cleanup;
}
/* FIXME: if sent code was >= 64 the message might have been a
* notification. Then, we must flag the observer to be alive
* by setting obs->fail_cnt = 0. */
- if (sent && COAP_RESPONSE_CLASS(sent->pdu->hdr->code) == 2) {
- const str token = { sent->pdu->hdr->token_length, sent->pdu->hdr->token };
+ if (sent && COAP_RESPONSE_CLASS(sent->pdu->transport_hdr->udp.code) == 2) {
+ const str token = { sent->pdu->transport_hdr->udp.token_length,
+ sent->pdu->transport_hdr->udp.token
+ };
+
coap_touch_observer(context, &sent->remote, &token);
}
break;
* not only the transaction but also the subscriptions we might
* have. */
- coap_log(LOG_ALERT, "got RST for message %u\n", ntohs(rcvd->pdu->hdr->id));
+ coap_log(LOG_ALERT, "got RST for message %u\n", ntohs(rcvd->pdu->transport_hdr->udp.id));
/* find transaction in sendqueue to stop retransmission */
coap_remove_from_queue(&context->sendqueue, rcvd->id, &sent);
if (!response) {
warn("coap_dispatch: cannot create error reponse\n");
} else {
- if (coap_send(context, &rcvd->remote, response)
- == COAP_INVALID_TID) {
+ if (coap_send(context, &rcvd->remote, response) == COAP_INVALID_TID) {
warn("coap_dispatch: error sending reponse\n");
}
coap_delete_pdu(response);
/* Pass message to upper layer if a specific handler was
* registered for a request that should be handled locally. */
if (handle_locally(context, rcvd)) {
- if (COAP_MESSAGE_IS_REQUEST(rcvd->pdu->hdr)) {
+ if (COAP_MESSAGE_IS_REQUEST(rcvd->pdu->transport_hdr->udp)) {
handle_request(context, rcvd);
- } else if (COAP_MESSAGE_IS_RESPONSE(rcvd->pdu->hdr)) {
+ } else if (COAP_MESSAGE_IS_RESPONSE(rcvd->pdu->transport_hdr->udp)) {
handle_response(context, sent, rcvd);
} else {
debug("dropped message with invalid code\n");
- if (coap_send_message_type(context, &rcvd->remote, rcvd->pdu, COAP_MESSAGE_RST) == COAP_INVALID_TID) {
- debug("failed to send RST message\n");
- }
+ coap_send_message_type(context, &rcvd->remote, rcvd->pdu, COAP_MESSAGE_RST);
}
}
#include <apps/netutils/libcoap/option.h>
#include <apps/netutils/libcoap/debug.h>
-coap_opt_t *options_start(coap_pdu_t *pdu)
+coap_opt_t *options_start(coap_pdu_t *pdu, coap_transport_t transport)
{
-
- if (pdu && pdu->hdr && (pdu->hdr->token + pdu->hdr->token_length < (unsigned char *)pdu->hdr + pdu->length)) {
-
- coap_opt_t *opt = pdu->hdr->token + pdu->hdr->token_length;
- return (*opt == COAP_PAYLOAD_START) ? NULL : opt;
-
+ if (pdu && pdu->hdr) {
+ if (COAP_UDP == transport &&
+ (pdu->transport_hdr->udp.token + pdu->transport_hdr->udp.token_length < (unsigned char *)pdu->hdr + pdu->length)) {
+ coap_opt_t *opt = pdu->transport_hdr->udp.token + pdu->transport_hdr->udp.token_length;
+ return (*opt == COAP_PAYLOAD_START) ? NULL : opt;
+ }
+#ifdef WITH_TCP
+ else if (COAP_TCP == transport &&
+ (pdu->transport_hdr->tcp.token + ((pdu->transport_hdr->tcp.header_data[0]) & 0x0f)
+ < (unsigned char *)pdu->hdr + pdu->length)) {
+ coap_opt_t *opt = pdu->transport_hdr->tcp.token + ((pdu->transport_hdr->tcp.header_data[0]) & 0x0f);
+ return (*opt == COAP_PAYLOAD_START) ? NULL : opt;
+ }
+#endif
+ return NULL;
} else {
return NULL;
}
coap_opt_iterator_t *coap_option_iterator_init(coap_pdu_t *pdu, coap_opt_iterator_t *oi, const coap_opt_filter_t filter)
{
+ return coap_option_iterator_init2(pdu, oi, filter, COAP_UDP);
+}
+
+coap_opt_iterator_t *coap_option_iterator_init2(coap_pdu_t *pdu, coap_opt_iterator_t *oi, const coap_opt_filter_t filter, coap_transport_t transport)
+{
assert(pdu);
assert(pdu->hdr);
assert(oi);
memset(oi, 0, sizeof(coap_opt_iterator_t));
- oi->next_option = (unsigned char *)pdu->hdr + sizeof(coap_hdr_t)
- + pdu->hdr->token_length;
- if ((unsigned char *)pdu->hdr + pdu->length <= oi->next_option) {
- oi->bad = 1;
- return NULL;
+ unsigned int token_length;
+ unsigned int headerSize;
+
+ switch (transport) {
+#ifdef WITH_TCP
+ case COAP_TCP:
+ token_length = (pdu->transport_hdr->tcp.header_data[0]) & 0x0f;
+ headerSize = COAP_TCP_HEADER_NO_FIELD;
+ break;
+ case COAP_TCP_8BIT:
+ token_length = (pdu->transport_hdr->tcp_8bit.header_data[0]) & 0x0f;
+ headerSize = COAP_TCP_HEADER_8_BIT;
+ break;
+ case COAP_TCP_16BIT:
+ token_length = (pdu->transport_hdr->tcp_16bit.header_data[0]) & 0x0f;
+ headerSize = COAP_TCP_HEADER_16_BIT;
+ break;
+ case COAP_TCP_32BIT:
+ token_length = pdu->transport_hdr->tcp_32bit.header_data[0] & 0x0f;
+ headerSize = COAP_TCP_HEADER_32_BIT;
+ break;
+#endif
+ default:
+ token_length = pdu->transport_hdr->udp.token_length;
+ headerSize = sizeof(pdu->transport_hdr->udp);
+ break;
}
- assert((sizeof(coap_hdr_t) + pdu->hdr->token_length) <= pdu->length);
+ oi->next_option = (unsigned char *)pdu->hdr + headerSize + token_length;
+
+ if (COAP_UDP == transport) {
+ if ((unsigned char *)&(pdu->transport_hdr->udp) + pdu->length <= oi->next_option) {
+ oi->bad = 1;
+ return NULL;
+ }
+ }
+#ifdef WITH_TCP
+ else {
+ if ((unsigned char *)&(pdu->transport_hdr->tcp) + pdu->length <= oi->next_option) {
+ oi->bad = 1;
+ return NULL;
+ }
+ }
+#endif
+
+ assert((headerSize + token_length) <= pdu->length);
- oi->length = pdu->length - (sizeof(coap_hdr_t) + pdu->hdr->token_length);
+ oi->length = pdu->length - (headerSize + token_length);
if (filter) {
memcpy(oi->filter, filter, sizeof(coap_opt_filter_t));
assert(opt);
- if (maxlen == 0) { /* need at least one byte */
+ if (maxlen == 0) { /* need at least one byte */
return 0;
}
return 0;
}
- if (val) { /* better be safe here */
+ if (val) { /* better be safe here */
memcpy(opt, val, length);
}
#ifdef WITH_CONTIKI
#include "memb.h"
+#ifndef WITH_TCP
typedef unsigned char _pdu[sizeof(coap_pdu_t) + COAP_MAX_PDU_SIZE];
MEMB(pdu_storage, _pdu, COAP_PDU_MAXCNT);
+#endif
void coap_pdu_resources_init()
{
void coap_pdu_clear(coap_pdu_t *pdu, size_t size)
{
+ coap_pdu_clear2(pdu, size, COAP_UDP, 0);
+}
+
+void coap_pdu_clear2(coap_pdu_t *pdu, size_t size, coap_transport_t 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->transport_hdr->udp.version = COAP_DEFAULT_VERSION;
+ /* data is NULL unless explicitly set by coap_add_data() */
+ pdu->length = sizeof(pdu->transport_hdr->udp);
+ }
+#ifdef WITH_TCP
+ else {
+ /* data is NULL unless explicitly set by coap_add_data() */
+ pdu->length = length;
+ }
+#else
+ (void)length;
+#endif
}
#ifdef WITH_LWIP
coap_pdu_t *coap_pdu_init(unsigned char type, unsigned char code, unsigned short id, size_t size)
{
+ return coap_pdu_init2(type, code, id, size, COAP_UDP);
+}
+
+coap_pdu_t *coap_pdu_init2(unsigned char type, unsigned char code, unsigned short id, size_t size, coap_transport_t transport)
+{
coap_pdu_t *pdu;
#ifdef WITH_LWIP
struct pbuf *p;
#endif
- pdu = NULL; /* to prevent stooped compilng due to warning */
+ unsigned int length = 0;
+ switch (transport) {
+ case COAP_UDP:
+ length = sizeof(pdu->transport_hdr->udp);
+ break;
+#ifdef WITH_TCP
+ 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;
+#endif
+ default:
+ debug("it has wrong type\n");
+ }
+
+#ifndef WITH_TCP
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;
}
+#endif
/* size must be large enough for hdr */
#ifdef WITH_POSIX
- pdu = coap_malloc(sizeof(coap_pdu_t) + size);
+ pdu = (coap_pdu_t *) coap_malloc(sizeof(coap_pdu_t) + size);
#endif
#ifdef WITH_CONTIKI
pdu = (coap_pdu_t *) memb_alloc(&pdu_storage);
}
#endif
if (pdu) {
- coap_pdu_clear(pdu, size);
- pdu->hdr->id = id;
- pdu->hdr->type = type;
- pdu->hdr->code = code;
+ coap_pdu_clear2(pdu, size, transport, length);
+
+ switch (transport) {
+ case COAP_UDP:
+ pdu->transport_hdr->udp.id = id;
+ pdu->transport_hdr->udp.type = type;
+ pdu->transport_hdr->udp.code = code;
+ break;
+#ifdef WITH_TCP
+ case COAP_TCP:
+ pdu->transport_hdr->tcp.header_data[0] = 0;
+ pdu->transport_hdr->tcp.header_data[1] = code;
+ break;
+ case COAP_TCP_8BIT:
+ pdu->transport_hdr->tcp_8bit.header_data[0] = COAP_TCP_LENGTH_FIELD_NUM_8_BIT << 4;
+ pdu->transport_hdr->tcp_8bit.header_data[2] = code;
+ break;
+ case COAP_TCP_16BIT:
+ pdu->transport_hdr->tcp_16bit.header_data[0] = COAP_TCP_LENGTH_FIELD_NUM_16_BIT << 4;
+ pdu->transport_hdr->tcp_16bit.header_data[3] = code;
+ break;
+ case COAP_TCP_32BIT:
+ pdu->transport_hdr->tcp_32bit.header_data[0] = COAP_TCP_LENGTH_FIELD_NUM_32_BIT << 4;
+ pdu->transport_hdr->tcp_32bit.header_data[5] = code;
+ break;
+#endif
+ default:
+ debug("it has wrong type\n");
+ }
+
#ifdef WITH_LWIP
pdu->pbuf = p;
#endif
return pdu;
}
-coap_pdu_t *coap_new_pdu(void)
+coap_pdu_t *coap_new_pdu()
{
coap_pdu_t *pdu;
#ifndef WITH_CONTIKI
pdu = coap_pdu_init(0, 0, ntohs(COAP_INVALID_TID), COAP_MAX_PDU_SIZE);
-#else /* WITH_CONTIKI */
+#else /* WITH_CONTIKI */
pdu = coap_pdu_init(0, 0, uip_ntohs(COAP_INVALID_TID), COAP_MAX_PDU_SIZE);
+#endif /* WITH_CONTIKI */
+
+#ifndef NDEBUG
+ if (!pdu)
+ coap_log(LOG_CRIT, "coap_new_pdu: cannot allocate memory for new PDU\n");
+#endif
+ return pdu;
+}
+
+coap_pdu_t *coap_new_pdu2(coap_transport_t transport, unsigned int size)
+{
+#ifndef WITH_TCP
+ (void)size;
+#endif
+ coap_pdu_t *pdu;
+
+#ifndef WITH_CONTIKI
+ pdu = coap_pdu_init2(0, 0, ntohs(COAP_INVALID_TID),
+#ifndef WITH_TCP
+ COAP_MAX_PDU_SIZE,
+#else
+ size,
+#endif
+ transport);
+#else /* WITH_CONTIKI */
+ pdu = coap_pdu_init2(0, 0, uip_ntohs(COAP_INVALID_TID),
+#ifndef WITH_TCP
+ COAP_MAX_PDU_SIZE,
+#else
+ size,
+#endif
+ transport);
#endif /* WITH_CONTIKI */
#ifndef NDEBUG
#endif
}
+#ifdef WITH_TCP
+size_t coap_get_total_message_length(const unsigned char *data, size_t size)
+{
+ if (!data || !size) {
+ debug("received data length is null\n");
+ return 0;
+ }
+
+ coap_transport_t transport = coap_get_tcp_header_type_from_initbyte(((unsigned char *)data)[0] >> 4);
+ size_t optPaylaodLen = coap_get_length_from_header((unsigned char *)data,
+ transport);
+ size_t headerLen = coap_get_tcp_header_length((unsigned char *)data);
+
+ return headerLen + optPaylaodLen;
+}
+
+coap_transport_t coap_get_tcp_header_type_from_size(unsigned int size)
+{
+ if (size < COAP_TCP_LENGTH_FIELD_8_BIT) {
+ return COAP_TCP;
+ } else if (size < COAP_TCP_LENGTH_FIELD_16_BIT) {
+ return COAP_TCP_8BIT;
+ } else if (size < COAP_TCP_LENGTH_FIELD_32_BIT) {
+ return COAP_TCP_16BIT;
+ } else {
+ return COAP_TCP_32BIT;
+ }
+}
+
+coap_transport_t coap_get_tcp_header_type_from_initbyte(unsigned int length)
+{
+ coap_transport_t 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_t transport, unsigned int length)
+{
+ assert(pdu);
+
+ switch (transport) {
+ case COAP_TCP:
+ pdu->transport_hdr->tcp.header_data[0] = length << 4;
+ break;
+ case COAP_TCP_8BIT:
+ if (length > COAP_TCP_LENGTH_FIELD_8_BIT) {
+ pdu->transport_hdr->tcp_8bit.header_data[1] = length - COAP_TCP_LENGTH_FIELD_8_BIT;
+ }
+ break;
+ case COAP_TCP_16BIT:
+ if (length > COAP_TCP_LENGTH_FIELD_16_BIT) {
+ unsigned int total_length = length - COAP_TCP_LENGTH_FIELD_16_BIT;
+ pdu->transport_hdr->tcp_16bit.header_data[1] = (total_length >> 8) & 0x0000ff;
+ pdu->transport_hdr->tcp_16bit.header_data[2] = total_length & 0x000000ff;
+ }
+ 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->transport_hdr->tcp_32bit.header_data[1] = total_length >> 24;
+ pdu->transport_hdr->tcp_32bit.header_data[2] = (total_length >> 16) & 0x00ff;
+ pdu->transport_hdr->tcp_32bit.header_data[3] = (total_length >> 8) & 0x0000ff;
+ pdu->transport_hdr->tcp_32bit.header_data[4] = total_length & 0x000000ff;
+ }
+ break;
+ default:
+ debug("it has wrong type\n");
+ }
+}
+
+unsigned int coap_get_length_from_header(const unsigned char *header, coap_transport_t transport)
+{
+ assert(header);
+
+ unsigned int length = 0;
+ unsigned int length_field_data = 0;
+ switch (transport) {
+ case COAP_TCP:
+ length = header[0] >> 4;
+ break;
+ case COAP_TCP_8BIT:
+ length = header[1] + COAP_TCP_LENGTH_FIELD_8_BIT;
+ break;
+ case COAP_TCP_16BIT:
+ length_field_data = (header[1] << 8 | header[2]);
+ length = length_field_data + COAP_TCP_LENGTH_FIELD_16_BIT;
+ break;
+ case COAP_TCP_32BIT:
+ length_field_data = header[1] << 24 | header[2] << 16 | header[3] << 8 | header[4];
+ length = length_field_data + COAP_TCP_LENGTH_FIELD_32_BIT;
+ break;
+ default:
+ debug("it has wrong type\n");
+ }
+
+ return length;
+}
+
+unsigned int coap_get_length(const coap_pdu_t *pdu, coap_transport_t transport)
+{
+ assert(pdu);
+
+ unsigned int length = 0;
+ unsigned int length_field_data = 0;
+ switch (transport) {
+ case COAP_TCP:
+ length = pdu->transport_hdr->tcp.header_data[0] >> 4;
+ break;
+ case COAP_TCP_8BIT:
+ length = pdu->transport_hdr->tcp_8bit.header_data[1] + COAP_TCP_LENGTH_FIELD_8_BIT;
+ break;
+ case COAP_TCP_16BIT:
+ length_field_data = pdu->transport_hdr->tcp_16bit.header_data[1] << 8 | pdu->transport_hdr->tcp_16bit.header_data[2];
+ length = length_field_data + COAP_TCP_LENGTH_FIELD_16_BIT;
+ break;
+ case COAP_TCP_32BIT:
+ length_field_data = pdu->transport_hdr->tcp_32bit.header_data[1] << 24 | pdu->transport_hdr->tcp_32bit.header_data[2] << 16 | pdu->transport_hdr->tcp_32bit.header_data[3] << 8 | pdu->transport_hdr->tcp_32bit.header_data[4];
+ length = length_field_data + COAP_TCP_LENGTH_FIELD_32_BIT;
+ break;
+ default:
+ debug("it has wrong type\n");
+ }
+
+ return length;
+}
+
+unsigned int coap_get_tcp_header_length(unsigned char *data)
+{
+ assert(data);
+
+ unsigned int tokenLength = data[0] & 0x0f;
+ coap_transport_t transport = coap_get_tcp_header_type_from_initbyte(data[0] >> 4);
+ unsigned int length = 0;
+
+ length = coap_get_tcp_header_length_for_transport(transport) + tokenLength;
+ return length;
+}
+
+unsigned int coap_get_tcp_header_length_for_transport(coap_transport_t transport)
+{
+ unsigned int length = 0;
+ switch (transport) {
+ case COAP_TCP:
+ length = COAP_TCP_HEADER_NO_FIELD;
+ break;
+ case COAP_TCP_8BIT: /* len(4bit) + TKL(4bit) + Len+bytes(1byte) + Code(1byte) */
+ length = COAP_TCP_HEADER_8_BIT;
+ break;
+ case COAP_TCP_16BIT: /* len(4bit) + TKL(4bit) + Len+bytes(2byte) + Code(1byte) */
+ length = COAP_TCP_HEADER_16_BIT;
+ break;
+ case COAP_TCP_32BIT: /* len(4bit) + TKL(4bit) + Len+bytes(4byte) + Code(1byte) */
+ length = COAP_TCP_HEADER_32_BIT;
+ break;
+ default:
+ debug("it has wrong type\n");
+ }
+
+ return length;
+}
+
+size_t coap_get_opt_header_length(unsigned short key, size_t length)
+{
+ size_t headerLength = 0;
+
+ unsigned short optDeltaLength = 0;
+ if (COAP_OPTION_FIELD_8_BIT >= key) {
+ optDeltaLength = 0;
+ } else if (COAP_OPTION_FIELD_8_BIT < key && COAP_OPTION_FIELD_16_BIT >= key) {
+ optDeltaLength = 1;
+ } else {
+ optDeltaLength = 2;
+ }
+
+ size_t optLength = 0;
+ if (COAP_OPTION_FIELD_8_BIT >= length) {
+ optLength = 0;
+ } else if (COAP_OPTION_FIELD_8_BIT < length && COAP_OPTION_FIELD_16_BIT >= length) {
+ optLength = 1;
+ } else if (COAP_OPTION_FIELD_16_BIT < length && COAP_OPTION_FIELD_32_BIT >= length) {
+ optLength = 2;
+ } else {
+ printf("Error : Reserved for the Payload marker for length");
+ return 0;
+ }
+
+ headerLength = length + optDeltaLength + optLength + 1;
+
+ return headerLength;
+}
+
+#endif
+
+void coap_add_code(const coap_pdu_t *pdu, coap_transport_t transport, unsigned int code)
+{
+ assert(pdu);
+
+ switch (transport) {
+ case COAP_UDP:
+ pdu->transport_hdr->udp.code = COAP_RESPONSE_CODE(code);
+ break;
+#ifdef WITH_TCP
+ case COAP_TCP:
+ pdu->transport_hdr->tcp.header_data[1] = COAP_RESPONSE_CODE(code);
+ break;
+ case COAP_TCP_8BIT:
+ pdu->transport_hdr->tcp_8bit.header_data[2] = COAP_RESPONSE_CODE(code);
+ break;
+ case COAP_TCP_16BIT:
+ pdu->transport_hdr->tcp_16bit.header_data[3] = COAP_RESPONSE_CODE(code);
+ break;
+ case COAP_TCP_32BIT:
+ pdu->transport_hdr->tcp_32bit.header_data[5] = COAP_RESPONSE_CODE(code);
+ break;
+#endif
+ default:
+ debug("it has wrong type\n");
+ }
+}
+
+unsigned int coap_get_code(const coap_pdu_t *pdu, coap_transport_t transport)
+{
+ assert(pdu);
+
+ unsigned int code = 0;
+ switch (transport) {
+ case COAP_UDP:
+ code = pdu->transport_hdr->udp.code;
+ break;
+#ifdef WITH_TCP
+ case COAP_TCP:
+ code = pdu->transport_hdr->tcp.header_data[1];
+ break;
+ case COAP_TCP_8BIT:
+ code = pdu->transport_hdr->tcp_8bit.header_data[2];
+ break;
+ case COAP_TCP_16BIT:
+ code = pdu->transport_hdr->tcp_16bit.header_data[3];
+ break;
+ case COAP_TCP_32BIT:
+ code = pdu->transport_hdr->tcp_32bit.header_data[5];
+ break;
+#endif
+ default:
+ debug("it has wrong type\n");
+ }
+ return code;
+}
+
int coap_add_token(coap_pdu_t *pdu, size_t len, const unsigned char *data)
{
+ return coap_add_token2(pdu, len, data, COAP_UDP);
+}
+
+int coap_add_token2(coap_pdu_t *pdu, size_t len, const unsigned char *data, coap_transport_t 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->transport_hdr->udp.token_length = len;
+ token = pdu->transport_hdr->udp.token;
+ pdu->length = HEADERLENGTH;
+ break;
+#ifdef WITH_TCP
+ case COAP_TCP:
+ pdu->transport_hdr->tcp.header_data[0] = pdu->transport_hdr->tcp.header_data[0] | len;
+ token = pdu->transport_hdr->tcp.token;
+ pdu->length = len + COAP_TCP_HEADER_NO_FIELD;
+ break;
+ case COAP_TCP_8BIT:
+ pdu->transport_hdr->tcp_8bit.header_data[0] = pdu->transport_hdr->tcp_8bit.header_data[0] | len;
+ token = pdu->transport_hdr->tcp_8bit.token;
+ pdu->length = len + COAP_TCP_HEADER_8_BIT;
+ break;
+ case COAP_TCP_16BIT:
+ pdu->transport_hdr->tcp_16bit.header_data[0] = pdu->transport_hdr->tcp_16bit.header_data[0] | len;
+ token = pdu->transport_hdr->tcp_16bit.token;
+ pdu->length = len + COAP_TCP_HEADER_16_BIT;
+ break;
+ case COAP_TCP_32BIT:
+ pdu->transport_hdr->tcp_32bit.header_data[0] = pdu->transport_hdr->tcp_32bit.header_data[0] | len;
+ token = pdu->transport_hdr->tcp_32bit.token;
+ pdu->length = len + COAP_TCP_HEADER_32_BIT;
+ break;
+#endif
+ 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;
}
-/** @FIXME de-duplicate code with coap_add_option_later */
+void coap_get_token(const coap_hdr_t *pdu_hdr, unsigned char **token, unsigned int *token_length)
+{
+ coap_get_token2((const coap_hdr_transport_t *)pdu_hdr, COAP_UDP, token, token_length);
+}
+
+void coap_get_token2(const coap_hdr_transport_t *pdu_hdr, coap_transport_t transport, unsigned char **token, unsigned int *token_length)
+{
+ assert(pdu_hdr);
+ assert(token);
+ assert(token_length);
+
+ switch (transport) {
+ case COAP_UDP:
+ *token_length = pdu_hdr->udp.token_length;
+ *token = (unsigned char *)pdu_hdr->udp.token;
+ break;
+#ifdef WITH_TCP
+ case COAP_TCP:
+ *token_length = (pdu_hdr->tcp.header_data[0]) & 0x0f;
+ *token = (unsigned char *)pdu_hdr->tcp.token;
+ break;
+ case COAP_TCP_8BIT:
+ *token_length = (pdu_hdr->tcp_8bit.header_data[0]) & 0x0f;
+ *token = (unsigned char *)pdu_hdr->tcp_8bit.token;
+ break;
+ case COAP_TCP_16BIT:
+ *token_length = (pdu_hdr->tcp_16bit.header_data[0]) & 0x0f;
+ *token = (unsigned char *)pdu_hdr->tcp_16bit.token;
+ break;
+ case COAP_TCP_32BIT:
+ *token_length = (pdu_hdr->tcp_32bit.header_data[0]) & 0x0f;
+ *token = (unsigned char *)pdu_hdr->tcp_32bit.token;
+ break;
+#endif
+ default:
+ debug("it has wrong type\n");
+ }
+}
+
size_t coap_add_option(coap_pdu_t *pdu, unsigned short type, unsigned int len, const unsigned char *data)
{
+ return coap_add_option2(pdu, type, len, data, COAP_UDP);
+}
+
+/** @FIXME de-duplicate code with coap_add_option_later */
+size_t coap_add_option2(coap_pdu_t *pdu, unsigned short type, unsigned int len, const unsigned char *data, coap_transport_t transport)
+{
size_t optsize;
coap_opt_t *opt;
pdu->data = NULL;
if (type < pdu->max_delta) {
- warn("coap_add_option: options are not in correct order\n");
+ warn("coap_add_option2: options are not in correct order\n");
return 0;
}
- opt = (unsigned char *)pdu->hdr + pdu->length;
+ switch (transport) {
+#ifdef WITH_TCP
+ case COAP_TCP:
+ opt = (unsigned char *)&(pdu->transport_hdr->tcp) + pdu->length;
+ break;
+ case COAP_TCP_8BIT:
+ opt = (unsigned char *)&(pdu->transport_hdr->tcp_8bit) + pdu->length;
+ break;
+ case COAP_TCP_16BIT:
+ opt = (unsigned char *)&(pdu->transport_hdr->tcp_16bit) + pdu->length;
+ break;
+ case COAP_TCP_32BIT:
+ opt = (unsigned char *)&(pdu->transport_hdr->tcp_32bit) + pdu->length;
+ break;
+#endif
+ default:
+ opt = (unsigned char *)&(pdu->transport_hdr->udp) + pdu->length;
+ break;
+ }
/* encode option and check length */
optsize = coap_opt_encode(opt, pdu->max_size - pdu->length, type - pdu->max_delta, data, len);
if (!optsize) {
- warn("coap_add_option: cannot add option\n");
+ warn("coap_add_option2: cannot add option\n");
/* error */
return 0;
} else {
return optsize;
}
-/** @FIXME de-duplicate code with coap_add_option */
+/** @FIXME de-duplicate code with coap_add_option2 */
unsigned char *coap_add_option_later(coap_pdu_t *pdu, unsigned short type, unsigned int len)
{
size_t optsize;
* returns the number of bytes opt has been advanced or @c 0
* on error.
*/
-static size_t next_option_safe(coap_opt_t **optp, size_t *length)
+static size_t next_option_safe(coap_opt_t **optp, size_t *length, coap_option_t *option)
{
- coap_option_t option;
+ //coap_option_t option;
size_t optsize;
assert(optp);
assert(*optp);
assert(length);
-
- optsize = coap_opt_parse(*optp, *length, &option);
+ optsize = coap_opt_parse(*optp, *length, option);
if (optsize) {
assert(optsize <= *length);
int coap_pdu_parse(unsigned char *data, size_t length, coap_pdu_t *pdu)
{
- coap_opt_t *opt;
+ return coap_pdu_parse2(data, length, pdu, COAP_UDP);
+}
+int coap_pdu_parse2(unsigned char *data, size_t length, coap_pdu_t *pdu, coap_transport_t transport)
+{
assert(data);
assert(pdu);
if (pdu->max_size < length) {
debug("insufficient space to store parsed PDU\n");
- return 0;
+ printf("[COAP] insufficient space to store parsed PDU\n");
+ return -1;
+ }
+
+ unsigned int headerSize = 0;
+
+ if (COAP_UDP == transport) {
+ headerSize = sizeof(pdu->transport_hdr->udp);
+ }
+#ifdef WITH_TCP
+ else {
+ headerSize = coap_get_tcp_header_length_for_transport(transport);
}
+#endif
- if (length < sizeof(coap_hdr_t)) {
+ 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];
- pdu->data = NULL;
+ coap_opt_t *opt = NULL;
+ unsigned int tokenLength = 0;
+#ifdef WITH_TCP
+ size_t i;
+
+ switch (transport) {
+ case COAP_UDP:
+ break;
+ case COAP_TCP:
+ for (i = 0; i < headerSize; i++) {
+ pdu->transport_hdr->tcp.header_data[i] = data[i];
+ }
- /* sanity checks */
- if (pdu->hdr->code == 0) {
- if (length != sizeof(coap_hdr_t) || pdu->hdr->token_length) {
- debug("coap_pdu_parse: empty message is not empty\n");
- goto discard;
+ tokenLength = data[0] & 0x0f;
+ opt = (unsigned char *)(&(pdu->transport_hdr->tcp) + 1) + tokenLength;
+ break;
+ case COAP_TCP_8BIT:
+ for (i = 0; i < headerSize; i++) {
+ pdu->transport_hdr->tcp_8bit.header_data[i] = data[i];
}
- }
- if (length < sizeof(coap_hdr_t) + pdu->hdr->token_length || pdu->hdr->token_length > 8) {
- debug("coap_pdu_parse: invalid Token\n");
- goto discard;
- }
+ tokenLength = data[0] & 0x0f;
+ opt = (unsigned char *)(&(pdu->transport_hdr->tcp_8bit))
+ + tokenLength + COAP_TCP_HEADER_8_BIT;
+ break;
+ case COAP_TCP_16BIT:
+ for (i = 0; i < headerSize; i++) {
+ pdu->transport_hdr->tcp_16bit.header_data[i] = data[i];
+ }
- /* 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);
+ tokenLength = data[0] & 0x0f;
+ opt = (unsigned char *)(&(pdu->transport_hdr->tcp_16bit) + 1) + tokenLength;
+ break;
+ case COAP_TCP_32BIT:
+ for (i = 0; i < headerSize; i++) {
+ pdu->transport_hdr->tcp_32bit.header_data[i] = data[i];
+ }
- /* append data (including the Token) to pdu structure */
- memcpy(pdu->hdr + 1, data + sizeof(coap_hdr_t), length - sizeof(coap_hdr_t));
+ tokenLength = data[0] & 0x0f;
+ opt = ((unsigned char *)&(pdu->transport_hdr->tcp_32bit)) + headerSize + tokenLength;
+ break;
+ default:
+ printf("it has wrong type\n");
+ }
+#endif
pdu->length = length;
- /* Finally calculate beginning of data block and thereby check integrity
- * of the PDU structure. */
+ if (COAP_UDP == transport) {
+ pdu->transport_hdr->udp.version = data[0] >> 6;
+ pdu->transport_hdr->udp.type = (data[0] >> 4) & 0x03;
+ pdu->transport_hdr->udp.token_length = data[0] & 0x0f;
+ pdu->transport_hdr->udp.code = data[1];
+ pdu->data = NULL;
+
+ tokenLength = pdu->transport_hdr->udp.token_length;
+
+ /* sanity checks */
+ if (pdu->transport_hdr->udp.code == 0) {
+ if (length != headerSize || tokenLength) {
+ debug("coap_pdu_parse2: empty message is not empty\n");
+ goto discard;
+ }
+ }
- /* skip header + token */
- length -= (pdu->hdr->token_length + sizeof(coap_hdr_t));
- opt = (unsigned char *)(pdu->hdr + 1) + pdu->hdr->token_length;
+ if (length < headerSize + tokenLength || tokenLength > 8) {
+ debug("coap_pdu_parse2: invalid Token\n");
+ goto discard;
+ }
- while (length && *opt != COAP_PAYLOAD_START) {
+ memcpy(&pdu->transport_hdr->udp.id, data + 2, 2);
+
+ /* Finally calculate beginning of data block and thereby check integrity
+ * of the PDU structure. */
+
+ /* append data (including the Token) to pdu structure */
+ memcpy(&(pdu->transport_hdr->udp) + 1, data + headerSize, length - headerSize);
- if (!next_option_safe(&opt, (size_t *)&length)) {
- debug("coap_pdu_parse: drop\n");
+ /* skip header + token */
+ length -= (tokenLength + headerSize);
+ opt = (unsigned char *)(&(pdu->transport_hdr->udp) + 1) + tokenLength;
+ }
+#ifdef WITH_TCP
+ else { // common for tcp header setting
+ pdu->data = NULL;
+
+ if (length < headerSize + tokenLength || tokenLength > 8) {
+ debug("coap_pdu_parse2: invalid Token\n");
+ goto discard;
+ }
+ /* 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 -= (tokenLength + headerSize);
+ }
+#endif
+
+ while (length && *opt != COAP_PAYLOAD_START) {
+ coap_option_t option;
+ memset(&option, 0, sizeof(coap_option_t));
+ if (!next_option_safe(&opt, (size_t *)&length, &option)) {
+ debug("coap_pdu_parse2: drop\n");
goto discard;
}
}
length--;
if (!length) {
- debug("coap_pdu_parse: message ending in payload start marker\n");
+ debug("coap_pdu_parse2: message ending in payload start marker\n");
goto discard;
}
debug("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);
}
return 1;
token.length = obs->token_length;
token.s = obs->token;
-
- response->hdr->id = coap_new_message_id(context);
+ /* TODO : Considering TCP Case */
+ response->transport_hdr->udp.id = coap_new_message_id(context);
if (obs->non && obs->non_cnt < COAP_OBS_MAX_NON) {
- response->hdr->type = COAP_MESSAGE_NON;
+ response->transport_hdr->udp.type = COAP_MESSAGE_NON;
} else {
- response->hdr->type = COAP_MESSAGE_CON;
+ response->transport_hdr->udp.type = COAP_MESSAGE_CON;
}
/* fill with observer-specific data */
h(context, r, &obs->subscriber, NULL, &token, response);
- if (response->hdr->type == COAP_MESSAGE_CON) {
+ if (response->transport_hdr->udp.type == COAP_MESSAGE_CON) {
tid = coap_send_confirmed(context, &obs->subscriber, response);
obs->non_cnt = 0;
} else {
obs->non_cnt++;
}
- if (COAP_INVALID_TID == tid || response->hdr->type != COAP_MESSAGE_CON) {
+ if (COAP_INVALID_TID == tid || response->transport_hdr->udp.type != COAP_MESSAGE_CON) {
coap_delete_pdu(response);
}
if (COAP_INVALID_TID == tid) {
--len;
}
+#ifdef WITH_TCP
+ /* Add to support tcp prefix */
+ q = (unsigned char *)"+tcp";
+ while (len && *q && tolower(*p) == *q) {
+ ++p;
+ ++q;
+ --len;
+ }
+#endif
+
q = (unsigned char *)"://";
while (len && *q && tolower(*p) == *q) {
++p;