* Copyright (C) 2010--2014 Olaf Bergmann <bergmann@tzi.org>
*
* This file is part of the CoAP library libcoap. Please see
- * README for terms of use.
+ * README for terms of use.
*/
#include "config.h"
#elif HAVE_SYS_UNISTD_H
#include <sys/unistd.h>
#endif
+#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
+#endif
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#include "block.h"
#include "net.h"
-#if defined(WITH_POSIX)
+#if defined(WITH_POSIX) || defined(WITH_ARDUINO)
-time_t clock_offset;
+time_t clock_offset=0;
static inline coap_queue_t *
coap_malloc_node()
{
coap_free(node);
}
-#endif /* WITH_POSIX */
+#endif /* WITH_POSIX || WITH_ARDUINO */
#ifdef WITH_LWIP
#include <lwip/memp.h>
context->pending_address.addr = addr->addr; /* FIXME: this has to become address-type independent, probably there'll be an lwip function for that */
context->pending_port = port;
- char* data;
- coap_read(context, data);
+ coap_read(context);
}
#endif /* WITH_LWIP */
#ifdef COAP_DEFAULT_WKC_HASHKEY
/** Checks if @p Key is equal to the pre-defined hash key for.well-known/core. */
-#define is_wkc(Key) \
+#define is_wkc(Key) \
(memcmp((Key), COAP_DEFAULT_WKC_HASHKEY, sizeof(coap_key_t)) == 0)
#else
/* Implements a singleton to store a hash key for the .wellknown/core
}
#endif
+
+#ifndef WITH_ARDUINO
coap_context_t *
coap_new_context(const coap_address_t *listen_addr)
{
-#ifdef WITH_POSIX
+#if defined(WITH_POSIX)
coap_context_t *c = coap_malloc( sizeof( coap_context_t ) );
int reuse = 1;
#endif /* WITH_POSIX */
coap_register_option(c, COAP_OPTION_BLOCK2);
coap_register_option(c, COAP_OPTION_BLOCK1);
-#ifdef WITH_POSIX
+#if defined(WITH_POSIX) || defined(WITH_ARDUINO)
c->sockfd = socket(listen_addr->addr.sa.sa_family, SOCK_DGRAM, 0);
if ( c->sockfd < 0 )
{
coap_free( c );
return NULL;
-#endif /* WITH_POSIX */
+#endif /* WITH_POSIX || WITH_ARDUINO */
#ifdef WITH_CONTIKI
c->conn = udp_new(NULL, 0, NULL);
udp_bind(c->conn, listen_addr->port);
coap_retransmittimer_restart(context);
#endif
-#if defined(WITH_POSIX) || defined(WITH_LWIP)
+#if defined(WITH_POSIX) || defined(WITH_LWIP) || defined(WITH_ARDUINO)
#ifdef COAP_RESOURCES_NOHASH
LL_FOREACH(context->resources, res)
{
initialized = 0;
#endif /* WITH_CONTIKI */
}
-
+#endif //ifndef WITH_ARDUINO
int coap_option_check_critical(coap_context_t *ctx, coap_pdu_t *pdu, coap_opt_filter_t unknown)
{
coap_opt_iterator_t opt_iter;
int ok = 1;
- coap_option_iterator_init(pdu, &opt_iter, COAP_OPT_ALL);
+ coap_option_iterator_init(pdu, &opt_iter, COAP_OPT_ALL, coap_udp);
while (coap_option_next(&opt_iter))
{
return;
}
#endif
+
+#ifdef WITH_ARDUINO
+ coap_hash((const unsigned char *)peer->addr, peer->size, h);
+#endif /* WITH_ARDUINO */
+
#if defined(WITH_LWIP) || defined(WITH_CONTIKI)
/* FIXME: with lwip, we can do better */
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);
+ coap_hash((const unsigned char *)&pdu->hdr->coap_hdr_udp_t.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)
+ if (request && request->hdr->coap_hdr_udp_t.type == COAP_MESSAGE_CON)
{
- response = coap_pdu_init(COAP_MESSAGE_ACK, 0, request->hdr->id, sizeof(coap_pdu_t));
+ response = coap_pdu_init(COAP_MESSAGE_ACK, 0, request->hdr->coap_hdr_udp_t.id,
+ sizeof(coap_pdu_t), coap_udp);
if (response)
{
result = coap_send(context, dst, response);
return result;
}
-#ifdef WITH_POSIX
+#if defined(WITH_ARDUINO)
+coap_tid_t
+coap_send_impl(coap_context_t *context,
+ const coap_address_t *dst,
+ coap_pdu_t *pdu)
+{
+ return 0;
+}
+#endif
+
+#if defined(WITH_POSIX)
/* releases space allocated by PDU if free_pdu is set */
coap_tid_t
coap_send_impl(coap_context_t *context,
const coap_address_t *dst,
coap_pdu_t *pdu)
{
-
- char* z = inet_ntoa(*(struct in_addr *)&(dst->addr));
-
ssize_t bytes_written;
coap_tid_t id = COAP_INVALID_TID;
return id;
}
-#endif /* WITH_POSIX */
+#endif /* WITH_POSIX || WITH_ARDUINO */
#ifdef WITH_CONTIKI
/* releases space allocated by PDU if free_pdu is set */
coap_tid_t
coap_tid_t coap_send(coap_context_t *context, const coap_address_t *dst, coap_pdu_t *pdu)
{
+#ifndef WITH_ARDUINO
return coap_send_impl(context, dst, pdu);
+#endif
}
coap_tid_t coap_send_error(coap_context_t *context, coap_pdu_t *request, const coap_address_t *dst,
if (request)
{
- response = coap_pdu_init(type, 0, request->hdr->id, sizeof(coap_pdu_t));
+ response = coap_pdu_init(type, 0, request->hdr->coap_hdr_udp_t.id,
+ sizeof(coap_pdu_t), coap_udp);
if (response)
{
result = coap_send(context, dst, response);
node->t = node->timeout << node->retransmit_cnt;
coap_insert_node(&context->sendqueue, node);
#ifdef WITH_LWIP
- if (node == context->sendqueue) /* don't bother with timer stuff if there are earlier retransmits */
+ /* don't bother with timer stuff if there are earlier retransmits */
+ if (node == context->sendqueue)
coap_retransmittimer_restart(context);
#endif
debug(
- "** retransmission #%d of transaction %d\n", node->retransmit_cnt, ntohs(node->pdu->hdr->id));
+ "** retransmission #%d of transaction %d\n", node->retransmit_cnt,
+ ntohs(node->pdu->hdr->coap_hdr_udp_t.id));
node->id = coap_send_impl(context, &node->remote, node->pdu);
return node->id;
/* no more retransmissions, remove node from system */
-#ifndef WITH_CONTIKI
+#if !defined(WITH_CONTIKI) && !defined(WITH_ARDUINO)
debug("** removed transaction %d\n", ntohs(node->id));
#endif
#ifndef WITHOUT_OBSERVE
/* Check if subscriptions exist that should be canceled after
COAP_MAX_NOTIFY_FAILURES */
- if (node->pdu->hdr->code >= 64)
+ if (node->pdu->hdr->coap_hdr_udp_t.code >= 64)
{
str token =
{ 0, NULL };
- token.length = node->pdu->hdr->token_length;
- token.s = node->pdu->hdr->token;
+ token.length = node->pdu->hdr->coap_hdr_udp_t.token_length;
+ token.s = node->pdu->hdr->coap_hdr_udp_t.token;
coap_handle_failed_notify(context, &node->remote, &token);
}
return COAP_INVALID_TID;
}
-/**
+/**
* Checks if @p opt fits into the message that ends with @p maxpos.
* This function returns @c 1 on success, or @c 0 if the option @p opt
* would exceed @p maxpos.
return 0;
}
-int coap_read(coap_context_t *ctx, char* data)
+#ifndef WITH_ARDUINO
+int coap_read(coap_context_t *ctx)
{
-#ifdef WITH_POSIX
+#if defined(WITH_POSIX)
static char buf[COAP_MAX_PDU_SIZE];
#endif
#if defined(WITH_LWIP) || defined(WITH_CONTIKI)
coap_address_init(&src);
-#ifdef WITH_POSIX
+#if defined(WITH_POSIX)
bytes_read = recvfrom(ctx->sockfd, buf, sizeof(buf), 0, &src.addr.sa, &src.size);
-#endif /* WITH_POSIX */
+#endif /* WITH_POSIX || WITH_ARDUINO */
#ifdef WITH_CONTIKI
if(uip_newdata())
{
goto error_early;
}
- if (pdu->version != COAP_DEFAULT_VERSION)
+ if (pdu->coap_hdr_udp_t.version != COAP_DEFAULT_VERSION)
{
debug("coap_read: unknown protocol version\n");
goto error_early;
node->pdu = coap_pdu_from_pbuf(ctx->pending_package);
ctx->pending_package = NULL;
#else
- node->pdu = coap_pdu_init(0, 0, 0, bytes_read);
+ node->pdu = coap_pdu_init(0, 0, 0, bytes_read, coap_udp);
#endif
if (!node->pdu)
goto error;
memcpy(&node->local, &dst, sizeof(coap_address_t));
memcpy(&node->remote, &src, sizeof(coap_address_t));
- if (!coap_pdu_parse((unsigned char *) buf, bytes_read, node->pdu))
+ if (!coap_pdu_parse((unsigned char *) buf, bytes_read, node->pdu, coap_udp))
{
warn("discard malformed PDU");
goto error;
#endif
return -1;
}
+#endif //#ifndef WITH_ARDUINO
int coap_remove_from_queue(coap_queue_t **queue, coap_tid_t id, coap_queue_t **node)
{
void coap_cancel_all_messages(coap_context_t *context, const coap_address_t *dst,
const unsigned char *token, size_t token_length)
{
- /* cancel all messages in sendqueue that are for dst
+ /* cancel all messages in sendqueue that are for dst
* and use the specified 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))
+ && token_match(token, token_length, context->sendqueue->pdu->hdr->coap_hdr_udp_t.token,
+ context->sendqueue->pdu->hdr->coap_hdr_udp_t.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->hdr->coap_hdr_udp_t.id));
coap_delete_node(q);
}
while (q)
{
if (coap_address_equals(dst, &q->remote)
- && token_match(token, token_length, q->pdu->hdr->token, q->pdu->hdr->token_length))
+ && token_match(token, token_length, q->pdu->hdr->coap_hdr_udp_t.token,
+ q->pdu->hdr->coap_hdr_udp_t.token_length))
{
p->next = q->next;
- debug("**** removed transaction %d\n", ntohs(q->pdu->hdr->id));
+ debug("**** removed transaction %d\n", ntohs(q->pdu->hdr->coap_hdr_udp_t.id));
coap_delete_node(q);
q = p->next;
}
{
coap_opt_iterator_t opt_iter;
coap_pdu_t *response;
- size_t size = sizeof(coap_hdr_t) + request->hdr->token_length;
+ size_t size = sizeof(coap_hdr_t) + request->hdr->coap_hdr_udp_t.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;
+ type = request->hdr->coap_hdr_udp_t.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
* options must be included as well. */
coap_option_clrb(opts, COAP_OPTION_CONTENT_TYPE); /* we do not want this */
- coap_option_iterator_init(request, &opt_iter, opts);
+ coap_option_iterator_init(request, &opt_iter, opts, coap_udp);
/* Add size of each unknown critical option. As known critical
options as well as elective options are not copied, the delta
}
/* Now create the response and fill with options and payload data. */
- response = coap_pdu_init(type, code, request->hdr->id, size);
+ response = coap_pdu_init(type, code, request->hdr->coap_hdr_udp_t.id, size, coap_udp);
if (response)
{
/* copy token */
- if (!coap_add_token(response, request->hdr->token_length, request->hdr->token))
+ if (!coap_add_token(response, request->hdr->coap_hdr_udp_t.token_length,
+ request->hdr->coap_hdr_udp_t.token, coap_udp))
{
debug("cannot add token to error response\n");
coap_delete_pdu(response);
}
/* copy all options */
- coap_option_iterator_init(request, &opt_iter, opts);
+ coap_option_iterator_init(request, &opt_iter, opts, coap_udp);
while ((option = coap_option_next(&opt_iter)))
coap_add_option(response, opt_iter.type, COAP_OPT_LENGTH(option),
- COAP_OPT_VALUE(option));
+ COAP_OPT_VALUE(option), coap_udp);
#if COAP_ERROR_PHRASE_LENGTH > 0
/* note that diagnostic messages do not need a Content-Format option. */
size_t offset = 0;
resp = coap_pdu_init(
- request->hdr->type == COAP_MESSAGE_CON ? COAP_MESSAGE_ACK : COAP_MESSAGE_NON,
+ request->hdr->coap_hdr_udp_t.type == COAP_MESSAGE_CON ? COAP_MESSAGE_ACK : COAP_MESSAGE_NON,
COAP_RESPONSE_CODE(205),
- request->hdr->id, COAP_MAX_PDU_SIZE);
+ request->hdr->coap_hdr_udp_t.id, COAP_MAX_PDU_SIZE, coap_udp);
if (!resp)
{
debug("wellknown_response: cannot create PDU\n");
return NULL;
}
- if (!coap_add_token(resp, request->hdr->token_length, request->hdr->token))
+ if (!coap_add_token(resp, request->hdr->coap_hdr_udp_t.token_length,
+ request->hdr->coap_hdr_udp_t.token, coap_udp))
{
debug("wellknown_response: cannot add token\n");
goto error;
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);
+ resp->hdr->coap_hdr_udp_t.code = COAP_RESPONSE_CODE(400);
return resp;
}
else if (block.szx > COAP_MAX_BLOCK_SZX)
need_block2 = 1;
}
- /* Check if there is sufficient space to add Content-Format option
+ /* Check if there is sufficient space to add Content-Format option
* and data. We do this before adding the Content-Format option to
* avoid sending error responses with that option but no actual
* content. */
* 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_encode_var_bytes(buf, COAP_MEDIATYPE_APPLICATION_LINK_FORMAT), buf, coap_udp);
/* 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;
+ resp->hdr->coap_hdr_udp_t.code = COAP_RESPONSE_CODE(503);
+ resp->length = sizeof(coap_hdr_t) + resp->hdr->coap_hdr_udp_t.token_length;
return resp;
}
-#define WANT_WKC(Pdu,Key) \
- (((Pdu)->hdr->code == COAP_REQUEST_GET) && is_wkc(Key))
+#define WANT_WKC(Pdu,Key) \
+ (((Pdu)->hdr->coap_hdr_udp_t.code == COAP_REQUEST_GET) && is_wkc(Key))
void handle_request(coap_context_t *context, coap_queue_t *node, const char* responseData)
{
* 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->hdr->coap_hdr_udp_t.code)
{
case COAP_REQUEST_GET:
}
/* the resource was found, check if there is a registered handler */
- if ((size_t) node->pdu->hdr->code - 1
+ if ((size_t) node->pdu->hdr->coap_hdr_udp_t.code - 1
< sizeof(resource->handler) / sizeof(coap_method_handler_t))
- h = resource->handler[node->pdu->hdr->code - 1];
+ h = resource->handler[node->pdu->hdr->coap_hdr_udp_t.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);
+ node->pdu->hdr->coap_hdr_udp_t.type ==
+ COAP_MESSAGE_CON ? COAP_MESSAGE_ACK : COAP_MESSAGE_NON,
+ 0, node->pdu->hdr->coap_hdr_udp_t.id, COAP_MAX_PDU_SIZE, coap_udp);
/* 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))
+ if (coap_add_token(response, node->pdu->hdr->coap_hdr_udp_t.token_length,
+ node->pdu->hdr->coap_hdr_udp_t.token, coap_udp))
{
str token =
- { node->pdu->hdr->token_length, node->pdu->hdr->token };
+ { node->pdu->hdr->coap_hdr_udp_t.token_length, node->pdu->hdr->coap_hdr_udp_t.token };
- //h(context, resource, &node->remote,
- //node->pdu, &token, response);
+ h(context, resource, &node->remote, node->pdu, &token, response);
unsigned char buf[3];
- response->hdr->code = COAP_RESPONSE_CODE(205);
+ response->hdr->coap_hdr_udp_t.code = COAP_RESPONSE_CODE(205);
coap_add_option(response, COAP_OPTION_CONTENT_TYPE,
- coap_encode_var_bytes(buf, COAP_MEDIATYPE_TEXT_PLAIN), buf);
- coap_add_option(response, COAP_OPTION_MAXAGE, coap_encode_var_bytes(buf, 0x2ffff), buf);
+ coap_encode_var_bytes(buf, COAP_MEDIATYPE_TEXT_PLAIN), buf, coap_udp);
+ coap_add_option(response, COAP_OPTION_MAXAGE, coap_encode_var_bytes(buf, 0x2ffff), buf, coap_udp);
coap_add_data(response, strlen(responseData), (unsigned char *) responseData);
- if (response->hdr->type != COAP_MESSAGE_NON
- || (response->hdr->code >= 64 && !coap_is_mcast(&node->local)))
+ if (response->hdr->coap_hdr_udp_t.type != COAP_MESSAGE_NON
+ || (response->hdr->coap_hdr_udp_t.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->hdr->coap_hdr_udp_t.id);
}
}
str token =
{ 0, NULL };
- /* remove observer for this resource, if any
+ /* 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);
+ COAP_SET_STR(&token, sent->pdu->hdr->coap_hdr_udp_t.token_length,
+ sent->pdu->hdr->coap_hdr_udp_t.token);
#ifndef WITH_CONTIKI
#ifdef COAP_RESOURCES_NOHASH
}
}
#endif /* WITH_CONTIKI */
-#endif /* WITOUT_OBSERVE */
+#endif /* WITOUT_OBSERVE */
}
void coap_dispatch(coap_context_t *context, const char* responseData)
context->recvqueue = context->recvqueue->next;
rcvd->next = NULL;
- if (rcvd->pdu->hdr->version != COAP_DEFAULT_VERSION)
+ if (rcvd->pdu->hdr->coap_hdr_udp_t.version != COAP_DEFAULT_VERSION)
{
- debug("dropped packet with unknown version %u\n", rcvd->pdu->hdr->version);
+ debug("dropped packet with unknown version %u\n", rcvd->pdu->hdr->coap_hdr_udp_t.version);
goto cleanup;
}
- switch (rcvd->pdu->hdr->type)
+ switch (rcvd->pdu->hdr->coap_hdr_udp_t.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->hdr->coap_hdr_udp_t.code == 0)
goto cleanup;
- /* FIXME: if sent code was >= 64 the message might have been a
+ /* 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)
+ if (sent && COAP_RESPONSE_CLASS(sent->pdu->hdr->coap_hdr_udp_t.code) == 2)
{
const str token =
- { sent->pdu->hdr->token_length, sent->pdu->hdr->token };
+ { sent->pdu->hdr->coap_hdr_udp_t.token_length,
+ sent->pdu->hdr->coap_hdr_udp_t.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->hdr->coap_hdr_udp_t.id));
/* find transaction in sendqueue to stop retransmission */
coap_remove_from_queue(&context->sendqueue, rcvd->id, &sent);
if (coap_option_check_critical(context, rcvd->pdu, opt_filter) == 0)
{
- /* FIXME: send response only if we have received a request. Otherwise,
+ /* FIXME: send response only if we have received a request. Otherwise,
* send RST. */
response = coap_new_error_response(rcvd->pdu, COAP_RESPONSE_CODE(402),
opt_filter);
* 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->hdr->coap_hdr_udp_t))
handle_request(context, rcvd, responseData);
- else if (COAP_MESSAGE_IS_RESPONSE(rcvd->pdu->hdr))
+ else if (COAP_MESSAGE_IS_RESPONSE(rcvd->pdu->hdr->coap_hdr_udp_t))
handle_response(context, sent, rcvd);
else
{