diff --git a/.gitignore b/.gitignore index 1edef7f04f..0350d1714a 100644 --- a/.gitignore +++ b/.gitignore @@ -34,6 +34,7 @@ src/.dirstamp src/.libs/ src/*.o src/*.lo +src/*.lst platform/**/.deps/ platform/**/.dirstamp platform/**/.libs/ diff --git a/Makefile.am b/Makefile.am index 4c456c4fb4..2802174329 100644 --- a/Makefile.am +++ b/Makefile.am @@ -29,8 +29,8 @@ EXTRA_DIST = \ # FIXME Only add for posix AM_CFLAGS = -I @top_builddir@/include/coap/ \ - -I @top_builddir@/platform/@PLATFORM@/ - $(WARNING_CFLAGS) -std=c99 + -I @top_builddir@/platform/@PLATFORM@/ \ + $(WARNING_CFLAGS) -std=c99 # FIXME Only add for posix SUBDIRS = . platform/posix/libev $(DOC_DIR) tests examples @@ -59,7 +59,7 @@ libcoap_@LIBCOAP_API_VERSION@_la_SOURCES = \ src/block.c \ src/coap_io.c \ src/coap_context.c \ - src/debug.c \ + src/coap_debug.c \ src/encode.c \ src/hashkey.c \ src/mem.c \ diff --git a/TODO b/TODO deleted file mode 100644 index 503ea7a03e..0000000000 --- a/TODO +++ /dev/null @@ -1,61 +0,0 @@ -This is a simple file for all kinds of stuff related on devlopment for -libcoap. Please append (and remove) any issue you think its worthy. - -Classification of issues: - Critical -> Break the library in some kind or a missing feature, maybe not - directly but later - Serious -> No regression on the user side, more likly on the libcoap - development - Minor -> Things that are nice to have, but they are not time critical - -================= -* CRITICAL ISSUES -================= --> Remove the #include "coap_config.h" directive from the public header files. --> Remove #ifdef HAVE_ASSERT_H and so on from the public headers. --> Use coap.h as the only header to include from the public view. --> DTLS functionality - -> Adding DTLS functions based on openssl - -> Bill Benett has starting some improvements here, please contact him - first before starting something --> Proxy functionality - -> A coap-server should be able to act as proxy server - -================ -* SERIOUS ISSUES -================ --> Create some development rules like: - --> How to submit patches? What about pull requests? - --> How to implement/change platform related code? --> Adding some documentation for classical users on how to use the libcoap --> Clean up the various inclusion for #ifdef __cplusplus #extern "C" {} --> Adding additional config options (like --with-pdu-size) --> Split of the platform related code into [foo]_platform.c files --> In general, improving the online doxygen documentation like creating some - additional information for doxygen (startpage, development information, - ...) --> In special, improving ... - Adding prams and return explanation in: - include/coap/coap_io.h - include/coap/option.h - include/coap/net.h - include/coap/resource.h - include/coap/str.h - include/coap/subscribe.h - include/coap/uri.h - Adding @brief directive - include/coap/block.h - include/coap/coap_io.h - include/coap/debug.h - include/coap/encode.h - include/coap/net.h - include/coap/str.h - include/coap/subscribe.h - include/coap/uri.h - -============== -* MINOR ISSUES -============== --> Remove the not needed Makefile.in.old files --> Adding a logo for libcoap - diff --git a/client/client.c b/client/client.c new file mode 100644 index 0000000000..67833e744d --- /dev/null +++ b/client/client.c @@ -0,0 +1,599 @@ +#include +#include +#include +#include + +//#include "utils.h" +//#include "clock.h" +//#include "mbuf.h" + +#include "coap/debug.h" +#include "coap/coap_list.h" +#include "coap/net.h" +#include "coap/address.h" +#include "coap/resource.h" +#include "coap/block.h" +#include "coap/pdu.h" +#include "coap/mem.h" +//#include "coap_utils.h" + +#include "client.h" + +extern int resolve_address(const str *addr, coap_address_t *dst); + +static int check_token(coap_request_t *request, coap_pdu_t *received) +{ + return received->hdr->token_length == request->token_length && + memcmp(received->hdr->token, request->token, request->token_length) == 0; +} + +static int order_opts(void *a, void *b) +{ + if (!a || !b) + return a < b ? -1 : 1; + + if (COAP_OPTION_KEY(*(coap_option *)a) < COAP_OPTION_KEY(*(coap_option * )b)) + return -1; + + return COAP_OPTION_KEY(*(coap_option *)a) == COAP_OPTION_KEY(*(coap_option * )b); +} + +coap_list_t * +new_option_node(unsigned short key, unsigned int length, unsigned char *data) +{ + coap_list_t *node; + + node = coap_malloc(sizeof(coap_list_t) + sizeof(coap_option) + length); + + if (node) { + coap_option *option = (coap_option *) (node->data); + COAP_OPTION_KEY(*option) = key; + COAP_OPTION_LENGTH(*option) = length; + memcpy(COAP_OPTION_DATA(*option), data, length); + } else { + critical("new_option_node: malloc\n"); + } + + return node; +} + +static void set_blocksize(coap_request_t *request) +{ + unsigned char buf[4]; /* hack: temporarily take encoded bytes */ + unsigned short opt; + + if (request->method != COAP_REQUEST_DELETE) { + opt = (request->method == COAP_REQUEST_GET ? COAP_OPTION_BLOCK2 : COAP_OPTION_BLOCK1); + coap_insert(&request->optlist, new_option_node(opt, coap_encode_var_bytes(buf, (request->block.num << 4 | request->block.szx)), buf)); + } +} + +int coap_request_set_uri(coap_request_t *request, const char *arg, int is_proxy_uri) +{ + unsigned char portbuf[2]; + unsigned char _buf[128]; + unsigned char *buf = _buf; + size_t buflen; + int res; + + if (is_proxy_uri) { /* create Proxy-Uri from argument */ + size_t len = strlen(arg); + while (len > 270) { + coap_insert(&request->optlist, new_option_node(COAP_OPTION_PROXY_URI, 270, (unsigned char *) arg)); + len -= 270; + arg += 270; + } + coap_insert(&request->optlist, new_option_node(COAP_OPTION_PROXY_URI, len, (unsigned char *) arg)); + + } else { /* split arg into Uri-* options */ + if (coap_split_uri(arg, strlen(arg), &request->uri) < 0) { + return 0; + } + + if (request->uri.port != COAP_DEFAULT_PORT) { + coap_insert(&request->optlist, new_option_node(COAP_OPTION_URI_PORT, coap_encode_var_bytes(portbuf, request->uri.port), portbuf)); + } + + if (request->uri.path.length) { + buflen = sizeof(_buf); + res = coap_split_path(request->uri.path.s, request->uri.path.length, buf, &buflen); + while (res--) { + coap_insert(&request->optlist, new_option_node(COAP_OPTION_URI_PATH, COAP_OPT_LENGTH(buf), COAP_OPT_VALUE(buf))); + buf += COAP_OPT_SIZE(buf); + } + } + + if (request->uri.query.length) { + buflen = sizeof(_buf); + buf = _buf; + res = coap_split_query(request->uri.query.s, request->uri.query.length, buf, &buflen); + while (res--) { + coap_insert(&request->optlist, new_option_node(COAP_OPTION_URI_QUERY, COAP_OPT_LENGTH(buf), COAP_OPT_VALUE(buf))); + buf += COAP_OPT_SIZE(buf); + } + } + } + return 1; +} + +//coap_tid_t clear_obs(coap_client_t *client, const coap_address_t *remote) +//{ +// coap_pdu_t *pdu; +// coap_list_t *option; +// coap_tid_t tid = COAP_INVALID_TID; +// unsigned char buf[2]; +// +// /* create bare PDU w/o any option */ +// pdu = coap_pdu_init(COAP_MESSAGE_CON, COAP_REQUEST_GET, coap_new_message_id(client->coap), COAP_MAX_PDU_SIZE); +// +// if (!pdu) { +// return tid; +// } +// +// if (!coap_add_token(pdu, the_token.length, the_token.s)) { +// error("cannot add token"); +// goto error; +// } +// +// for (option = optlist; option; option = option->next) { +// if (COAP_OPTION_KEY(*(coap_option *)option->data) == COAP_OPTION_URI_HOST) { +// if (!coap_add_option(pdu, COAP_OPTION_KEY(*(coap_option * )option->data), COAP_OPTION_LENGTH(*(coap_option * )option->data), +// COAP_OPTION_DATA(*(coap_option * )option->data))) { +// goto error; +// } +// break; +// } +// } +// +// if (!coap_add_option(pdu, COAP_OPTION_OBSERVE, coap_encode_var_bytes(buf, COAP_OBSERVE_CANCEL), buf)) { +// error("cannot add option Observe: %u", COAP_OBSERVE_CANCEL); +// goto error; +// } +// +// for (option = optlist; option; option = option->next) { +// switch (COAP_OPTION_KEY(*(coap_option * )option->data)) { +// case COAP_OPTION_URI_PORT: +// case COAP_OPTION_URI_PATH: +// case COAP_OPTION_URI_QUERY: +// if (!coap_add_option(pdu, COAP_OPTION_KEY(*(coap_option * )option->data), COAP_OPTION_LENGTH(*(coap_option * )option->data), +// COAP_OPTION_DATA(*(coap_option * )option->data))) { +// goto error; +// } +// break; +// default: +// ; +// } +// } +// +// coap_show_pdu(pdu); +// +// if (pdu->hdr->type == COAP_MESSAGE_CON) +// tid = coap_send_confirmed(client->coap, client->ep, remote, pdu); +// else +// tid = coap_send(client->coap, client->ep, 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) +// coap_delete_pdu(pdu); +// +// return tid; +// error: +// +// coap_delete_pdu(pdu); +// return tid; +//} + +/** + * Create PDU from request. + */ +static coap_pdu_t *create_pdu(coap_request_t *request) +{ + coap_pdu_t *pdu; + + pdu = coap_new_pdu(); + if (!pdu) { + critical("Failed to create request"); + return NULL; + } + + pdu->hdr->type = request->type; + pdu->hdr->id = coap_new_message_id(request->client->coap); + pdu->hdr->code = request->method; + pdu->hdr->token_length = request->token_length; + coap_add_token(pdu, pdu->hdr->token_length, request->token); + + return pdu; +} + +static int send_request(coap_client_t *client, coap_request_t *request, coap_response_t *response, coap_address_t *dst, coap_pdu_t *pdu) +{ + coap_tid_t tid; + + // We add request to the hash map before sending it. This is because it may + // happen that the current thread will be preempted by network thread when an + // acknowledgment is received. Since the response handler lookups the request this + // could lead to bad things. + + coap_request_t *found = NULL; + HASH_FIND(hh, client->requests, request->token, request->token_length, found); + + if (!found) { + HASH_ADD_KEYPTR(hh, client->requests, request->token, request->token_length, request); + request->client = client; + request->response = response; + response->code = 0; + } + + // Send request + if (pdu->hdr->type == COAP_MESSAGE_CON) { + tid = coap_send_confirmed(client->coap, client->ep, dst, pdu); + } else { + tid = coap_send(client->coap, client->ep, dst, pdu); + } + + if (tid == COAP_INVALID_TID) { + coap_delete_pdu(pdu); + HASH_DEL(client->requests, request); + return 0; + } + + if (pdu->hdr->type != COAP_MESSAGE_CON) { + coap_delete_pdu(pdu); + return 0; + } + +#ifndef NDEBUG + char toks[request->token_length*2 + 1]; + memset(toks, 0, sizeof(toks)); +// htos(request->token, request->token_length, toks, sizeof(toks)); + info("Request sent (id:%d tk:%s)", tid, toks); +#endif + + return 1; +} + +static int +request_block(coap_request_t *request) +{ + unsigned char buf[4]; + coap_list_t *option; + + coap_pdu_t *pdu = create_pdu(request); + if (!pdu) { + return 0; + } + + //debug("found the M bit, block size is %u, block nr. %u\n", COAP_OPT_BLOCK_SZX(block_opt), coap_opt_block_num(block_opt)); + + /* add URI components from optlist */ + for (option = request->optlist; option; option = option->next) { + switch (COAP_OPTION_KEY(*(coap_option * )option->data)) { + case COAP_OPTION_URI_HOST: + case COAP_OPTION_URI_PORT: + case COAP_OPTION_URI_PATH: + case COAP_OPTION_URI_QUERY: + coap_add_option(pdu, COAP_OPTION_KEY(*(coap_option * )option->data), COAP_OPTION_LENGTH(*(coap_option * )option->data), + COAP_OPTION_DATA(*(coap_option * )option->data)); + break; + default: + break; /* skip other options */ + } + } + + /* finally add updated block option from response, clear M bit */ + /* blocknr = (blocknr & 0xfffffff7) + 0x10; */ + debug("query block %d\n", request->block.num); + coap_add_option(pdu, request->block_type, coap_encode_var_bytes(buf, (request->block.num << 4) | request->block.szx), buf); + + return send_request(request->client, request, request->response, &request->dst, pdu); +} + +static void handle_205(coap_client_t *client, coap_request_t *request, coap_pdu_t *received) +{ + coap_opt_t *opt; + coap_opt_iterator_t oi; + + coap_option_iterator_init(received, &oi, COAP_OPT_ALL); + + while ((opt = coap_option_next(&oi))) { + switch (oi.type) { + case COAP_OPTION_CONTENT_FORMAT: + request->response->content_type = *(uint8_t *)coap_opt_value(opt); + break; + case COAP_OPTION_OBSERVE: + break; + case COAP_OPTION_BLOCK2: { + request->block.szx = COAP_OPT_BLOCK_SZX(opt); + if (COAP_OPT_BLOCK_MORE(opt)) { + request->block.m = 1; + } + request->block.num = coap_opt_block_num(opt); + + info("Received block (NUM:%d, M:%d)\n", request->block.num, request->block.m); + /* TODO: check if we are looking at the correct block number */ + if (coap_has_data(received) && client->block_write) { + client->block_write(request->response, received, &request->block); + } + break; + } + default: + break; + } + } + + if (request->block.m) { + request->block_type = COAP_OPTION_BLOCK2; + request->block.num += 1; + request_block(request); + } else { + //request->response->data = coap_get_mbuf(received); + request->response->code = received->hdr->code; + // copy received data + if (coap_has_data(received)) { + size_t len; + unsigned char *data; + coap_get_data(received, &len, &data); + request->response->data = coap_malloc(len); + if (request->response->data) { + memcpy(request->response->data, data, len); + request->response->length = len; + } + } + if (request->cb) { + request->cb(request, request->response); + coap_client_delete_request(request); + } + } +} + +static void response_handler( + struct coap_context_t *ctx, + const coap_endpoint_t *ep, + const coap_address_t *remote, + coap_pdu_t *sent, + coap_pdu_t *received, + const coap_tid_t id) +{ + coap_client_t *client = (coap_client_t *)ctx->pdata; + + assert(client); + + char toks[received->hdr->token_length*2 + 1]; + memset(toks, 0, sizeof(toks)); +// htos(received->hdr->token, received->hdr->token_length, toks, sizeof(toks)); + + coap_request_t *request = NULL; + HASH_FIND(hh, client->requests, received->hdr->token, received->hdr->token_length, request); + if (!request) { + warn("Request not found (tk:%s)", toks); + return; + } + + debug("Received response (id:%d, tk:%s code:%d)\n", id, toks, received->hdr->code); + + /* check if this is a response to our original request */ + if (!check_token(request, received)) { + /* drop if this was just some message, or send RST in case of notification */ + if (!sent && (received->hdr->type == COAP_MESSAGE_CON || received->hdr->type == COAP_MESSAGE_NON)) { + coap_send_rst(ctx, ep, remote, received); + } + warn("Token mismatch"); + return; + } + + if (received->hdr->type == COAP_MESSAGE_RST) { + warn("Received RST\n"); + return; + } + + switch (received->hdr->code) { + /* 2.05 Content - send in response to GET request */ + case COAP_RESPONSE_CODE(205): + handle_205(client, request, received); + break; + default: + request->response->code = received->hdr->code; + if (request->cb) { + request->cb(request, request->response); + coap_client_delete_request(request); + } + break; + } +} + +void coap_client_init(coap_client_t *client, coap_context_t *ctx, coap_endpoint_t *ep) +{ + client->coap = ctx; + client->ep = ep; + client->requests = NULL; + + ctx->pdata = client; + + coap_register_option(client->coap, COAP_OPTION_BLOCK2); + coap_register_response_handler(client->coap, response_handler); +} + +void coap_client_deinit(coap_client_t *client) +{ + (void)client; + //TODO: cancel subscriptions +} + +void coap_client_delete_request(coap_request_t *r) +{ + debug("Deleting request [%p]", r); + + if (r->client) { + HASH_DEL(r->client->requests, r); + } + + if (r->optlist != NULL) { + coap_delete_list(r->optlist); + r->optlist = NULL; + } + + if (r->data) { + //mbuf_free((mbuf_t *)r->data); + coap_free(r->data); + r->data = NULL; + } + + if (r->response) { + if (r->response->data) { + coap_free(r->response->data); + //mbuf_free((mbuf_t *)r->response->data); + } + coap_free(r->response); + r->response = NULL; + } + + coap_cancel_all_messages(r->client->coap, &r->dst, r->token, r->token_length); + coap_free(r); +} + + +/** + * Send given request. + */ +int +coap_client_send_request( + coap_client_t *client, + coap_request_t *request, + coap_response_t *response, + coap_address_t *dst) +{ + request->client = client; + request->response = response; + + if (&request->dst != dst) { + memcpy(&request->dst, dst, sizeof(coap_address_t)); + } + + coap_pdu_t *pdu = create_pdu(request); + if (!pdu) { + return 0; + } + + if (request->block_type) { + set_blocksize(request); + } + + // add options if present + if (request->optlist) { + coap_list_t *opt; + /* sort options for delta encoding */ + LL_SORT(request->optlist, order_opts); + + LL_FOREACH(request->optlist, opt) { + coap_option *o = (coap_option *) (opt->data); + coap_add_option(pdu, COAP_OPTION_KEY(*o), COAP_OPTION_LENGTH(*o), COAP_OPTION_DATA(*o)); + } + } + + if (request->data) { + if (request->block_type > 0) { + client->block_read(request, pdu, &request->block); + } else { + coap_add_data(pdu, request->length, request->data); + } + } + + return send_request(request->client, request, request->response, dst, pdu); +} + +coap_request_t *coap_client_new_request(unsigned char method, unsigned char type) +{ + coap_request_t *req = coap_malloc(sizeof(coap_request_t)); + if (!req) { + return NULL; + } + + memset(req, 0, sizeof(coap_request_t)); + + req->method = method; + req->type = type; + req->token_length = AUTO_TOKEN_LENGTH; + prng(req->token, req->token_length); + + return req; +} + +static coap_request_t *make_request( + coap_client_t *client, + const char *uri, + unsigned char method, + unsigned char type, + void *data, + size_t len, + coap_client_cb_t cb) +{ + coap_request_t *req = coap_client_new_request(method, type); + if (!req) + return NULL; + + if (!coap_request_set_uri(req, uri, 0)) { + goto error; + } + + coap_address(req->uri.host.s, req->uri.port, &req->dst); + + coap_response_t *resp = coap_malloc(sizeof(coap_response_t)); + if (!resp) { + goto error; + } + memset(resp, 0, sizeof(coap_response_t)); + + req->data = data; + req->length = len; + req->cb = cb; + + if (coap_client_send_request(client, req, resp, &req->dst)) { + return req; + } + +error: + if (req) { + coap_client_delete_request(req); + } + return NULL; +} + +/** + * + * Request a GET operation on a given resource. + * + * This function uses CON message type for the request. + * + * @param client + * @param uri + * @param cb + * + */ +coap_request_t *coap_client_get(coap_client_t *client, const char *uri, coap_client_cb_t cb) +{ + return make_request(client, uri, COAP_REQUEST_GET, COAP_MESSAGE_CON, NULL, 0, cb); +} + +coap_request_t *coap_client_put(coap_client_t *client, const char *uri, void *data, size_t len, coap_client_cb_t cb) +{ + return make_request(client, uri, COAP_REQUEST_PUT, COAP_MESSAGE_CON, data, len, cb); +} + +coap_request_t *coap_client_post(coap_client_t *client, const char *uri, void *data, size_t len, coap_client_cb_t cb) +{ + return make_request(client, uri, COAP_REQUEST_POST, COAP_MESSAGE_CON, data, len, cb); +} + +/* +response_t *coap_client_subscribe(coap_client_t *client, const char *uri, notification_cb_t cb) +{ + return NULL; +} + +response_t *coap_client_unsubscribe(coap_client_t *client, const char *uri) +{ + return NULL; +} +*/ diff --git a/client/client.h b/client/client.h new file mode 100644 index 0000000000..2b22aa736f --- /dev/null +++ b/client/client.h @@ -0,0 +1,104 @@ +/* + * client.h + * + * Created on: Apr 13, 2015 + * Author: wojtek + */ + +#ifndef uthash_fatal +#define uthash_fatal(msg) return -1; +#endif + +#include "uthash.h" +#include "coap/net.h" +#include "coap/block.h" +#include "coap_list.h" + +#ifndef COAP_CLIENT_CLIENT_H_ +#define COAP_CLIENT_CLIENT_H_ + +typedef enum { + BLOCK = 1, + SUBSCRIBE = 2, + UNSUBSCRIBE = 4, +} request_flags_t; + +#define AUTO_TOKEN_LENGTH 4 +#define MAX_TOKEN_LENGTH 8 + +struct _coap_request_t; +struct _coap_response_t; + +typedef int (*coap_client_cb_t)(struct _coap_request_t *, struct _coap_response_t*); + +typedef struct { + coap_context_t *coap; + coap_endpoint_t *ep; + struct _coap_request_t *requests; + + int (*block_write)(struct _coap_response_t *response, coap_pdu_t *pdu, coap_block_t *block); + int (*block_read)(struct _coap_request_t *request, coap_pdu_t *pdu, coap_block_t *block); + +} coap_client_t; + +// This is a future object. +typedef struct _coap_response_t { + uint8_t code; /* response code */ + uint8_t content_type; /* response content type */ + void *data; /* response payload data */ + size_t length; /* response lenght */ +} coap_response_t; + +typedef struct _coap_request_t { + coap_endpoint_t *ep; + coap_client_t *client; + coap_address_t dst; + coap_list_t *optlist; + coap_uri_t uri; + + uint8_t method; + uint8_t type; + uint8_t token[MAX_TOKEN_LENGTH]; + uint8_t token_length; + + void *data; + size_t length; + + int block_type; + coap_block_t block; + + coap_response_t *response; + coap_client_cb_t cb; + + void *pdata; + + UT_hash_handle hh; +} coap_request_t; + +int coap_request_set_uri(coap_request_t *request, const char *arg, int is_proxy_uri); + +static inline void coap_request_set_token(coap_request_t *request, uint8_t *token, int length) +{ + memcpy(request->token, token, MIN(length, MAX_TOKEN_LENGTH)); +} + +static inline coap_request_t *coap_client_find_request(coap_client_t *client, uint8_t *token, int token_length) +{ + coap_request_t *found = NULL; + HASH_FIND(hh, client->requests, token, token_length, found); + return found; +} + +void coap_client_init(coap_client_t *client, coap_context_t *ctx, coap_endpoint_t *ep); +void coap_client_deinit(coap_client_t *client); + +coap_request_t *coap_client_new_request(unsigned char method, unsigned char type); +void coap_client_delete_request(coap_request_t *r); + +int coap_client_send_request(coap_client_t *client, coap_request_t *request, coap_response_t *response, coap_address_t *dst); + +coap_request_t *coap_client_get(coap_client_t *client, const char *uri, coap_client_cb_t cb); +coap_request_t *coap_client_put(coap_client_t *client, const char *uri, void *data, size_t len, coap_client_cb_t cb); +coap_request_t *coap_client_post(coap_client_t *client, const char *uri, void *data, size_t len, coap_client_cb_t cb); + +#endif /* COAP_CLIENT_CLIENT_H_ */ diff --git a/coap_config.h.lwip b/coap_config.h.lwip index 5f397a0ea6..c42acb01de 100644 --- a/coap_config.h.lwip +++ b/coap_config.h.lwip @@ -17,9 +17,7 @@ * actually we'd need autotools again to find out what environment we're * building in */ #define HAVE_STRNLEN 1 - #define HAVE_LIMITS_H - #define COAP_RESOURCES_NOHASH #endif /* _CONFIG_H_ */ diff --git a/doc/libcoap_style_eclipse.xml b/doc/libcoap_style_eclipse.xml new file mode 100644 index 0000000000..2a20f111a1 --- /dev/null +++ b/doc/libcoap_style_eclipse.xml @@ -0,0 +1,167 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/client.c b/examples/client.c index d355d7a9d0..5cedb36782 100644 --- a/examples/client.c +++ b/examples/client.c @@ -978,9 +978,9 @@ cmdline_method(char *arg) { return i; /* note that we do not prevent illegal methods */ } -static coap_context_t * -get_context(const char *node, const char *port) { - coap_context_t *ctx = NULL; +static coap_endpoint_t * +create_endpoint(const char *node, const char *port) { + coap_endpoint_t *ep = NULL; int s; struct addrinfo hints; struct addrinfo *result, *rp; @@ -1005,24 +1005,25 @@ get_context(const char *node, const char *port) { addr.size = rp->ai_addrlen; memcpy(&addr.addr, rp->ai_addr, rp->ai_addrlen); - ctx = coap_new_context(&addr); - if (ctx) { + ep = coap_new_endpoint(&addr, 0); + if (ep) { /* TODO: output address:port for successful binding */ goto finish; } } } - fprintf(stderr, "no context available for interface '%s'\n", node); + fprintf(stderr, "failed to create endpoint for interface '%s'\n", node); finish: freeaddrinfo(result); - return ctx; + return ep; } int main(int argc, char **argv) { coap_context_t *ctx = NULL; + coap_endpoint_t *ep = NULL; coap_address_t dst; static char addr[INET6_ADDRSTRLEN]; void *addrptr = NULL; @@ -1146,18 +1147,24 @@ main(int argc, char **argv) { addrptr = &dst.addr.sin.sin_addr; /* create context for IPv4 */ - ctx = get_context(node_str[0] == 0 ? "0.0.0.0" : node_str, port_str); + ep = create_endpoint(node_str[0] == 0 ? "0.0.0.0" : node_str, port_str); break; case AF_INET6: addrptr = &dst.addr.sin6.sin6_addr; /* create context for IPv6 */ - ctx = get_context(node_str[0] == 0 ? "::" : node_str, port_str); + ep = create_endpoint(node_str[0] == 0 ? "::" : node_str, port_str); break; default: ; } + if (!ep) { + coap_log(LOG_EMERG, "cannot create endpoint\n"); + return -1; + } + + ctx = coap_new_context(); if (!ctx) { coap_log(LOG_EMERG, "cannot create context\n"); return -1; @@ -1195,9 +1202,9 @@ main(int argc, char **argv) { #endif if (pdu->hdr->type == COAP_MESSAGE_CON) - tid = coap_send_confirmed(ctx, ctx->endpoint, &dst, pdu); + tid = coap_send_confirmed(ctx, ep, &dst, pdu); else - tid = coap_send(ctx, ctx->endpoint, &dst, pdu); + tid = coap_send(ctx, ep, &dst, pdu); if (pdu->hdr->type != COAP_MESSAGE_CON || tid == COAP_INVALID_TID) coap_delete_pdu(pdu); @@ -1207,16 +1214,16 @@ main(int argc, char **argv) { while ( !(ready && coap_can_exit(ctx)) ) { FD_ZERO(&readfds); - FD_SET( ctx->endpoint->handle.fd, &readfds ); + FD_SET(ep->fd, &readfds ); tv.tv_sec = wait_seconds; - result = select(ctx->endpoint->handle.fd + 1, &readfds, 0, 0, &tv); + result = select(ep->fd + 1, &readfds, 0, 0, &tv); if ( result < 0 ) { /* error */ perror("select"); } else if ( result > 0 ) { /* read from socket */ - if ( FD_ISSET( ctx->endpoint->handle.fd, &readfds ) ) { - coap_read( ctx ); /* read received data */ + if ( FD_ISSET(ep->fd, &readfds ) ) { + coap_read( ctx, ep ); /* read received data */ /* coap_dispatch( ctx ); /\* and dispatch PDUs from receivequeue *\/ */ } } else { /* timeout */ @@ -1227,7 +1234,7 @@ main(int argc, char **argv) { } if (obs_wait && obs_wait <= now) { debug("clear observation relationship\n"); - clear_obs(ctx, ctx->endpoint, &dst); /* FIXME: handle error case COAP_TID_INVALID */ + clear_obs(ctx, ep, &dst); /* FIXME: handle error case COAP_TID_INVALID */ /* make sure that the obs timer does not fire again */ obs_wait = 0; @@ -1239,7 +1246,8 @@ main(int argc, char **argv) { close_output(); coap_delete_list(optlist); - coap_free_context( ctx ); + coap_free_context(ctx); + coap_free_endpoint(ep); return 0; } diff --git a/examples/coap-rd.c b/examples/coap-rd.c index 78f440670d..c7eff9feb4 100644 --- a/examples/coap-rd.c +++ b/examples/coap-rd.c @@ -657,7 +657,7 @@ join(coap_context_t *ctx, char *group_name) { } } - result = setsockopt(ctx->endpoint->handle.fd, + result = setsockopt(ctx->endpoint->fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *)&mreq, sizeof(mreq) ); if ( result < 0 ) @@ -720,7 +720,7 @@ main(int argc, char **argv) { while ( !quit ) { FD_ZERO(&readfds); - FD_SET( ctx->endpoint->handle.fd, &readfds ); + FD_SET( ctx->endpoint->fd, &readfds ); coap_ticks(&now); @@ -733,7 +733,7 @@ main(int argc, char **argv) { if (errno != EINTR) perror("select"); } else if ( result > 0 ) { /* read from socket */ - if ( FD_ISSET( ctx->endpoint->handle.fd, &readfds ) ) { + if ( FD_ISSET( ctx->endpoint->fd, &readfds ) ) { coap_read( ctx ); /* read received data */ /* coap_dispatch( ctx ); /\* and dispatch PDUs from receivequeue *\/ */ } diff --git a/examples/coap-server.c b/examples/coap-server.c index 31bfc785a9..1799e64e7f 100644 --- a/examples/coap-server.c +++ b/examples/coap-server.c @@ -430,7 +430,7 @@ join(coap_context_t *ctx, char *group_name){ } } - result = setsockopt(ctx->endpoint->handle.fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, + result = setsockopt(ctx->endpoint->fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *)&mreq, sizeof(mreq)); if (result < 0) perror("join: setsockopt"); @@ -495,7 +495,7 @@ main(int argc, char **argv) { while ( !quit ) { FD_ZERO(&readfds); - FD_SET( ctx->endpoint->handle.fd, &readfds ); + FD_SET( ctx->endpoint->fd, &readfds ); coap_ticks(&now); @@ -508,7 +508,7 @@ main(int argc, char **argv) { if (errno != EINTR) perror("select"); } else if ( result > 0 ) { /* read from socket */ - if ( FD_ISSET( ctx->endpoint->handle.fd, &readfds ) ) { + if ( FD_ISSET( ctx->endpoint->fd, &readfds ) ) { coap_read( ctx ); /* read received data */ /* coap_dispatch( ctx ); /\* and dispatch PDUs from receivequeue *\/ */ } diff --git a/include/coap/address.h b/include/coap/address.h index 2146a837b0..4a598c7c4d 100644 --- a/include/coap/address.h +++ b/include/coap/address.h @@ -58,6 +58,12 @@ int coap_address_isany(const coap_address_t *a); */ int coap_is_mcast(const coap_address_t *a); +/** + * Fill an address structure with given address and port. + * + */ +int coap_address(const char *address, unsigned short port, coap_address_t *result); + /** * Resets the given coap_address_t object @p addr to its default values. In * particular, the member size must be initialized to the available size for @@ -67,4 +73,8 @@ int coap_is_mcast(const coap_address_t *a); */ void coap_address_init(coap_address_t *addr); +/** + * Returns size of a given address object. + */ +int coap_address_size(const coap_address_t *a); #endif /* _COAP_ADDRESS_H_ */ diff --git a/include/coap/bits.h b/include/coap/bits.h index 9eb8f24bdc..a7586a18e2 100644 --- a/include/coap/bits.h +++ b/include/coap/bits.h @@ -15,7 +15,6 @@ #ifndef _BITS_H_ #define _BITS_H_ -#include #include /** diff --git a/include/coap/coap_context.h b/include/coap/coap_context.h index b8689f93a8..1bbaac830c 100644 --- a/include/coap/coap_context.h +++ b/include/coap/coap_context.h @@ -53,7 +53,9 @@ typedef struct coap_context_t { * to sendqueue_basetime. */ coap_tick_t sendqueue_basetime; coap_queue_t *sendqueue; +#if 0 coap_endpoint_t *endpoint; /**< the endpoint used for listening */ +#endif #ifdef WITH_CONTIKI struct uip_udp_conn *conn; /**< uIP connection object */ @@ -76,20 +78,12 @@ typedef struct coap_context_t { unsigned int observe; coap_response_handler_t response_handler; - - ssize_t (*network_send)(struct coap_context_t *context, - const coap_endpoint_t *local_interface, - const coap_address_t *dst, - unsigned char *data, size_t datalen); - - ssize_t (*network_read)(coap_endpoint_t *ep, coap_packet_t **packet); - } coap_context_t; /** * Creates a new coap_context_t object that will hold the CoAP stack status. */ -coap_context_t *coap_new_context(const coap_address_t *listen_addr); +coap_context_t *coap_new_context(void); /** * CoAP stack context must be released with coap_free_context(). This function diff --git a/include/coap/coap_io.h b/include/coap/coap_io.h index 47de3bfdb1..8beafbe69a 100644 --- a/include/coap/coap_io.h +++ b/include/coap/coap_io.h @@ -9,8 +9,6 @@ #ifndef _COAP_IO_H_ #define _COAP_IO_H_ -#include "coap_config.h" - #ifdef HAVE_ASSERT_H #include #else @@ -24,55 +22,24 @@ # include #endif -#include "address.h" - -#define SIN6(A) ((struct sockaddr_in6 *)(A)) - -#ifdef __GNUC__ -#define UNUSED_PARAM __attribute__ ((unused)) -#else /* not a GCC */ -#define UNUSED_PARAM -#endif /* GCC */ - -/** - * Abstract handle that is used to identify a local network interface. - */ -typedef int coap_if_handle_t; - /** Invalid interface handle */ #define COAP_IF_INVALID -1 -struct coap_packet_t; -typedef struct coap_packet_t coap_packet_t; - -struct coap_context_t; - -/** - * Abstraction of virtual endpoint that can be attached to coap_context_t. The - * tuple (handle, addr) must uniquely identify this endpoint. - */ -typedef struct coap_endpoint_t { -#if defined(WITH_POSIX) || defined(WITH_CONTIKI) - union { - int fd; /**< on POSIX systems */ - void *conn; /**< opaque connection (e.g. uip_conn in Contiki) */ - } handle; /**< opaque handle to identify this endpoint */ -#endif /* WITH_POSIX or WITH_CONTIKI */ - -#ifdef WITH_LWIP - struct udp_pcb *pcb; -#endif /* WITH_LWIP */ - - coap_address_t addr; /**< local interface address */ - int ifindex; - int flags; -} coap_endpoint_t; - #define COAP_ENDPOINT_NOSEC 0x00 #define COAP_ENDPOINT_DTLS 0x01 +#include "pdu.h" #include "platform_io.h" +struct coap_context_t; +typedef struct coap_context_t coap_context_t; + +struct coap_packet_t; +typedef struct coap_packet_t coap_packet_t; + +struct coap_endpoint_t; +typedef struct coap_endpoint_t coap_endpoint_t; + coap_endpoint_t *coap_new_endpoint(const coap_address_t *addr, int flags); void coap_free_endpoint(coap_endpoint_t *ep); @@ -84,16 +51,14 @@ void coap_free_endpoint(coap_endpoint_t *ep); * @param context The calling CoAP context. * @param local_interface The local interface to send the data. * @param dst The address of the receiver. - * @param data The data to send. - * @param datalen The actual length of @p data. + * @param pdu The pdu which should be send. * * @return The number of bytes written on success, or a value * less than zero on error. */ -ssize_t coap_network_send(struct coap_context_t *context, +typedef ssize_t (*coap_network_send_t)(coap_context_t *context, const coap_endpoint_t *local_interface, - const coap_address_t *dst, - unsigned char *data, size_t datalen); + const coap_address_t *dst, const coap_pdu_t *pdu); /** * Function interface for reading data. This function returns the number of @@ -108,13 +73,38 @@ ssize_t coap_network_send(struct coap_context_t *context, * @return The number of bytes received on success, or a value less than * zero on error. */ -ssize_t coap_network_read(coap_endpoint_t *ep, coap_packet_t **packet); +typedef ssize_t (*coap_network_read_t)(coap_endpoint_t *ep, coap_packet_t **packet); + +/** + * Abstraction of virtual endpoint that can be attached to coap_context_t. The + * tuple (handle, addr) must uniquely identify this endpoint. + */ +struct coap_endpoint_t { + coap_address_t addr; /**< local interface address */ + int ifindex; + int flags; + coap_network_read_t network_read; + coap_network_send_t network_send; + PLATFORM_ENDPOINT_PROPERTIES +}; + +struct coap_packet_t { + coap_address_t src; /**< the packet's source address */ + coap_address_t dst; /**< the packet's destination address */ + const coap_endpoint_t *interface; + + int ifindex; + void *session; /**< opaque session data */ + + size_t length; /**< length of payload */ + unsigned char payload[]; /**< payload */ +}; #ifndef coap_mcast_interface # define coap_mcast_interface(Local) 0 #endif - +/** Allocates store for a packet */ coap_packet_t *coap_malloc_packet(void); /** diff --git a/include/coap/coap_list.h b/include/coap/coap_list.h new file mode 100644 index 0000000000..293c2309a7 --- /dev/null +++ b/include/coap/coap_list.h @@ -0,0 +1,31 @@ +/* coap_list.h -- CoAP list structures + * + * Copyright (C) 2010,2011,2015 Olaf Bergmann + * + * This file is part of the CoAP library libcoap. Please see + * README for terms of use. + */ + +#ifndef _COAP_LIST_H_ +#define _COAP_LIST_H_ + +#include "utlist.h" + +typedef struct coap_list_t { + struct coap_list_t *next; + char data[]; +} coap_list_t; + +/** + * Adds node to given queue, ordered by specified order function. Returns 1 + * when insert was successful, 0 otherwise. + */ +int coap_insert(coap_list_t **queue, coap_list_t *node); + +/* destroys specified node */ +int coap_delete(coap_list_t *node); + +/* removes all items from given queue and frees the allocated storage */ +void coap_delete_list(coap_list_t *queue); + +#endif /* _COAP_LIST_H_ */ diff --git a/include/coap/debug.h b/include/coap/debug.h index acdf88e780..f8e8d3a324 100644 --- a/include/coap/debug.h +++ b/include/coap/debug.h @@ -1,4 +1,4 @@ -/* debug.h -- debug utilities + /* debug.h -- debug utilities * * Copyright (C) 2010,2011,2014 Olaf Bergmann * @@ -17,6 +17,8 @@ #define COAP_ERR_FD stderr #endif +#include + #ifdef HAVE_SYSLOG_H #include typedef short coap_log_t; @@ -33,6 +35,33 @@ typedef enum { } coap_log_t; #endif +#ifndef min +#define min(a,b) ((a) < (b) ? (a) : (b)) +#endif + +#include +/** Returns a textual description of the message type @p t. */ +static inline const char * +msg_type_string(uint8_t t) { + static const char * const types[] = { "CON", "NON", "ACK", "RST", "???" }; + + return types[min(t, sizeof(types)/sizeof(char *) - 1)]; +} + +/** Returns a textual description of the method or response code. */ +static inline const char * +msg_code_string(uint8_t c) { + static const char * const methods[] = { "0.00", "GET", "POST", "PUT", "DELETE", "PATCH" }; + static char buf[5]; + + if (c < sizeof(methods)/sizeof(char *)) { + return methods[c]; + } else { + snprintf(buf, sizeof(buf), "%u.%02u", c >> 5, c & 0x1f); + return buf; + } +} + /** Returns the current log level. */ coap_log_t coap_get_log_level(void); @@ -50,18 +79,28 @@ const char *coap_package_version(void); * COAP_DEBUG_FD (for @p level >= @c LOG_WARNING). The text is output only when * @p level is below or equal to the log level that set by coap_set_log_level(). */ -void coap_log_impl(coap_log_t level, const char *format, ...); +void coap_log_impl(const char *file, int line, coap_log_t level, const char *format, ...); #ifndef coap_log -#define coap_log(...) coap_log_impl(__VA_ARGS__) +#define coap_log(...) coap_log_impl(__FILE__, __LINE__, __VA_ARGS__) #endif #ifndef NDEBUG /* A set of convenience macros for common log levels. */ +#ifndef info #define info(...) coap_log(LOG_INFO, __VA_ARGS__) +#endif + +#ifndef warn #define warn(...) coap_log(LOG_WARNING, __VA_ARGS__) +#endif + +#ifndef debug #define debug(...) coap_log(LOG_DEBUG, __VA_ARGS__) +#endif + +#define critical(...) coap_log(LOG_CRIT, __VA_ARGS__) #include "pdu.h" void coap_show_pdu(const coap_pdu_t *); diff --git a/include/coap/encode.h b/include/coap/encode.h index 351c8618c3..ac9e02ac6d 100644 --- a/include/coap/encode.h +++ b/include/coap/encode.h @@ -9,11 +9,7 @@ #ifndef _COAP_ENCODE_H_ #define _COAP_ENCODE_H_ -#if (BSD >= 199103) || defined(WITH_CONTIKI) -# include -#else -# include -#endif +#include #define Nn 8 /* duplicate definition of N if built on sky motes */ #define E 4 diff --git a/include/coap/mem.h b/include/coap/mem.h index 291be096ed..fa64c9179f 100644 --- a/include/coap/mem.h +++ b/include/coap/mem.h @@ -13,15 +13,6 @@ #include #endif -#ifndef WITH_LWIP -/** - * Initializes libcoap's memory management. - * This function must be called once before coap_malloc() can be used on - * constrained devices. - */ -void coap_memory_init(void); -#endif /* WITH_LWIP */ - /** * Type specifiers for coap_malloc_type(). Memory objects can be typed to * facilitate arrays of type objects to be used instead of dynamic memory @@ -40,10 +31,16 @@ typedef enum { COAP_RESOURCE, COAP_RESOURCEATTR, COAP_TIMER, - COAP_SUBSCRIPTION + COAP_OPTION, + COAP_SUBSCRIPTION, } coap_memory_tag_t; -#ifndef WITH_LWIP +/** + * Initializes libcoap's memory management. + * This function must be called once before coap_malloc() can be used on + * constrained devices. + */ +void coap_memory_init(void); /** * Allocates a chunk of @p size bytes and returns a pointer to the newly @@ -81,34 +78,4 @@ static inline void coap_free(void *object) { coap_free_type(COAP_STRING, object); } -#endif /* not WITH_LWIP */ - -#ifdef WITH_LWIP - -#include - -/* no initialization needed with lwip (or, more precisely: lwip must be - * completely initialized anyway by the time coap gets active) */ -static inline void coap_memory_init(void) {} - -/* It would be nice to check that size equals the size given at the memp - * declaration, but i currently don't see a standard way to check that without - * sourcing the custom memp pools and becoming dependent of its syntax - */ -#define coap_malloc_type(type, size) memp_malloc(MEMP_ ## type) -#define coap_free_type(type, p) memp_free(MEMP_ ## type, p) - -/* Those are just here to make uri.c happy where string allocation has not been - * made conditional. - */ -static inline void *coap_malloc(size_t size) { - LWIP_ASSERT("coap_malloc must not be used in lwIP", 0); -} - -static inline void coap_free(void *pointer) { - LWIP_ASSERT("coap_free must not be used in lwIP", 0); -} - -#endif /* WITH_LWIP */ - #endif /* _COAP_MEM_H_ */ diff --git a/include/coap/net.h b/include/coap/net.h index 10b8e411fc..6adcdb33bc 100644 --- a/include/coap/net.h +++ b/include/coap/net.h @@ -61,6 +61,8 @@ void coap_delete_all(coap_queue_t *queue); /** Creates a new node suitable for adding to the CoAP sendqueue. */ coap_queue_t *coap_new_node(void); +#define SZX_TO_BYTES(SZX) ((size_t)(1 << ((SZX) + 4))) + struct coap_resource_t; struct coap_context_t; #ifndef WITHOUT_ASYNC @@ -130,6 +132,15 @@ coap_new_message_id(coap_context_t *context) { return HTONS(context->message_id); } +/* + * CoAP stack context must be released with coap_free_context(). This function + * clears all entries from the receive queue and send queue and deletes the + * resources that have been registered with @p context, and frees the attached + * endpoints. + */ +void coap_free_context(coap_context_t *context); + + /** * Sends a confirmed CoAP message to given destination. The memory that is * allocated by pdu will not be released by coap_send_confirmed(). The caller @@ -289,7 +300,7 @@ coap_tid_t coap_retransmit(coap_context_t *context, coap_queue_t *node); * returned and a new node with the parsed PDU is added to the receive queue in * the specified context object. */ -int coap_read(coap_context_t *context); +int coap_read(coap_context_t *context, coap_endpoint_t *ep); /** * Parses and interprets a CoAP message with context @p ctx. This function diff --git a/include/coap/option.h b/include/coap/option.h index 8fc4e9b853..1cf560935a 100644 --- a/include/coap/option.h +++ b/include/coap/option.h @@ -328,11 +328,15 @@ coap_opt_t *coap_check_option(coap_pdu_t *pdu, * * @return The number of bytes used or @c 0 on error. */ + size_t coap_opt_setheader(coap_opt_t *opt, size_t maxlen, unsigned short delta, size_t length); +size_t coap_opt_setheader_to_mbuf(coap_pdu_t *pdu, unsigned short type, + size_t length); + /** * Encodes option with given @p delta into @p opt. This function returns the * number of bytes written to @p opt or @c 0 on error. This happens especially @@ -348,11 +352,9 @@ size_t coap_opt_setheader(coap_opt_t *opt, * @return The number of bytes that have been written to @p opt or @c 0 on * error. The return value will always be less than @p n. */ -size_t coap_opt_encode(coap_opt_t *opt, - size_t n, - unsigned short delta, - const unsigned char *val, - size_t length); + +size_t coap_opt_encode(coap_opt_t *opt, size_t n, unsigned short delta, + const unsigned char *val, size_t length); /** * Decodes the delta value of the next option. This function returns the number @@ -405,6 +407,10 @@ unsigned char *coap_opt_value(coap_opt_t *opt); /** @deprecated { Use coap_opt_value() instead. } */ #define COAP_OPT_VALUE(opt) coap_opt_value((coap_opt_t *)opt) +#if defined(ST_NODE) +size_t coap_opt_encode_to_mbuf(coap_pdu_t *pdu, unsigned short type, const unsigned char *val, size_t length); +#endif + /** @} */ #endif /* _OPTION_H_ */ diff --git a/include/coap/pdu.h b/include/coap/pdu.h index 9b17f89a40..4615865814 100644 --- a/include/coap/pdu.h +++ b/include/coap/pdu.h @@ -15,13 +15,30 @@ #define _PDU_H_ #include "uri.h" +#include -#ifdef WITH_LWIP -#include +/* pre-defined constants that reflect defaults for CoAP */ + +#ifndef COAP_DEFAULT_RESPONSE_TIMEOUT +#define COAP_DEFAULT_RESPONSE_TIMEOUT 3 /* response timeout in seconds */ +#endif + +#ifndef COAP_DEFAULT_MAX_RETRANSMIT +#define COAP_DEFAULT_MAX_RETRANSMIT 3 /* max number of retransmissions */ +#endif + +#ifndef COAP_DEFAULT_PORT +#define COAP_DEFAULT_PORT 5683 /* CoAP default UDP port */ +#endif + +#ifndef COAP_SECURE_PORT +#define COAP_SECURE_PORT 5684 /* CoAP DTLS-secured UDP port */ +#endif + +#ifndef COAP_DEFAULT_MAX_AGE +#define COAP_DEFAULT_MAX_AGE 60 /* default maximum object lifetime in seconds */ #endif -#define COAP_DEFAULT_PORT 5683 /* CoAP default UDP port */ -#define COAP_DEFAULT_MAX_AGE 60 /* default maximum object lifetime in seconds */ #ifndef COAP_MAX_PDU_SIZE #define COAP_MAX_PDU_SIZE 1400 /* maximum size of a CoAP PDU */ #endif /* COAP_MAX_PDU_SIZE */ @@ -94,6 +111,8 @@ */ #define COAP_RESPONSE_CODE(N) (((N)/100 << 5) | (N)%100) +#define COAP_RESPONSE_CODE2(N) (((N) >> 5)*100 + ((N) & 0x1f)) + /* Determines the class of response code C */ #define COAP_RESPONSE_CLASS(C) (((C) >> 5) & 0xFF) @@ -122,17 +141,32 @@ char *coap_response_phrase(unsigned char code); #if 0 /* this does not exist any more */ #define COAP_RESPONSE_100 40 /* 100 Continue */ #endif -#define COAP_RESPONSE_200 COAP_RESPONSE_CODE(200) /* 2.00 OK */ -#define COAP_RESPONSE_201 COAP_RESPONSE_CODE(201) /* 2.01 Created */ -#define COAP_RESPONSE_304 COAP_RESPONSE_CODE(203) /* 2.03 Valid */ -#define COAP_RESPONSE_400 COAP_RESPONSE_CODE(400) /* 4.00 Bad Request */ -#define COAP_RESPONSE_404 COAP_RESPONSE_CODE(404) /* 4.04 Not Found */ -#define COAP_RESPONSE_405 COAP_RESPONSE_CODE(405) /* 4.05 Method Not Allowed */ -#define COAP_RESPONSE_415 COAP_RESPONSE_CODE(415) /* 4.15 Unsupported Media Type */ -#define COAP_RESPONSE_500 COAP_RESPONSE_CODE(500) /* 5.00 Internal Server Error */ -#define COAP_RESPONSE_501 COAP_RESPONSE_CODE(501) /* 5.01 Not Implemented */ -#define COAP_RESPONSE_503 COAP_RESPONSE_CODE(503) /* 5.03 Service Unavailable */ -#define COAP_RESPONSE_504 COAP_RESPONSE_CODE(504) /* 5.04 Gateway Timeout */ +#define COAP_RESPONSE_200 COAP_RESPONSE_CODE(200) /* 2.00 OK */ +#define COAP_RESPONSE_OK COAP_RESPONSE_200 +#define COAP_RESPONSE_201 COAP_RESPONSE_CODE(201) /* 2.01 Created */ +#define COAP_RESPONSE_CREATED COAP_RESPONSE_201 +#define COAP_RESPONSE_203 COAP_RESPONSE_CODE(203) /* 2.03 Valid */ +#define COAP_RESPONSE_VALID COAP_RESPONSE_203 +#define COAP_RESPONSE_204 COAP_RESPONSE_CODE(204) /* 2.04 Valid */ +#define COAP_RESPONSE_CHANGED COAP_RESPONSE_204 +#define COAP_RESPONSE_205 COAP_RESPONSE_CODE(205) /* 2.05 Content */ +#define COAP_RESPONSE_CONTENT COAP_RESPONSE_205 +#define COAP_RESPONSE_400 COAP_RESPONSE_CODE(400) /* 4.00 Bad Request */ +#define COAP_RESPONSE_BAD_REQUEST COAP_RESPONSE_400 +#define COAP_RESPONSE_404 COAP_RESPONSE_CODE(404) /* 4.04 Not Found */ +#define COAP_RESPONSE_NOT_FOUND COAP_RESPONSE_404 +#define COAP_RESPONSE_405 COAP_RESPONSE_CODE(405) /* 4.05 Method Not Allowed */ +#define COAP_RESPONSE_METHOD_NOT_ALLOWED COAP_RESPONSE_405 +#define COAP_RESPONSE_415 COAP_RESPONSE_CODE(415) /* 4.15 Unsupported Media Type */ +#define COAP_RESPONSE_UNSP_MEDIA_TYPE COAP_RESPONSE_415 +#define COAP_RESPONSE_500 COAP_RESPONSE_CODE(500) /* 5.00 Internal Server Error */ +#define COAP_RESPONSE_INT_SRV_ERR COAP_RESPONSE_500 +#define COAP_RESPONSE_501 COAP_RESPONSE_CODE(501) /* 5.01 Not Implemented */ +#define COAP_RESPONSE_NOT_IMPL COAP_RESPONSE_501 +#define COAP_RESPONSE_503 COAP_RESPONSE_CODE(503) /* 5.03 Service Unavailable */ +#define COAP_RESPONSE_SERVICE_UNAVAIL COAP_RESPONSE_503 +#define COAP_RESPONSE_504 COAP_RESPONSE_CODE(504) /* 5.04 Gateway Timeout */ +#define COAP_RESPONSE_GATEWAY_TIMEOUT COAP_RESPONSE_504 #if 0 /* these response codes do not have a valid code any more */ # define COAP_RESPONSE_X_240 240 /* Token Option required by server */ # define COAP_RESPONSE_X_241 241 /* Uri-Authority Option required by server */ @@ -148,6 +182,7 @@ char *coap_response_phrase(unsigned char code); #define COAP_MEDIATYPE_APPLICATION_RDF_XML 43 /* application/rdf+xml */ #define COAP_MEDIATYPE_APPLICATION_EXI 47 /* application/exi */ #define COAP_MEDIATYPE_APPLICATION_JSON 50 /* application/json */ +#define COAP_MEDIATYPE_APPLICATION_MSGPACK 59 /* application/x-msgpack */ #define COAP_MEDIATYPE_APPLICATION_CBOR 60 /* application/cbor */ /* Note that identifiers for registered media types are in the range 0-65535. We @@ -223,7 +258,7 @@ typedef struct { * Header structure for CoAP PDUs */ -typedef struct { +typedef struct coap_pdu_t { size_t max_size; /**< allocated storage for options and data */ coap_hdr_t *hdr; /**< Address of the first byte of the CoAP message. * This may or may not equal (coap_hdr_t*)(pdu+1) @@ -233,15 +268,8 @@ typedef struct { unsigned short length; /**< PDU length (including header, options, data) */ unsigned char *data; /**< payload */ -#ifdef WITH_LWIP - struct pbuf *pbuf; /**< lwIP PBUF. The package data will always reside - * inside the pbuf's payload, but this pointer - * has to be kept because no exact offset can be - * given. This field must not be accessed from - * outside, because the pbuf's reference count - * is checked to be 1 when the pbuf is assigned - * to the pdu, and the pbuf stays exclusive to - * this pdu. */ +#ifdef CUSTOM_PDU_FIELDS + CUSTOM_PDU_FIELDS #endif } coap_pdu_t; @@ -250,24 +278,9 @@ typedef struct { */ #define COAP_OPTION(node) ((coap_option *)(node)->options) -#ifdef WITH_LWIP -/** - * Creates a CoAP PDU from an lwIP @p pbuf, whose reference is passed on to this - * function. - * - * The pbuf is checked for being contiguous, and for having only one reference. - * The reference is stored in the PDU and will be freed when the PDU is freed. - * - * (For now, these are fatal errors; in future, a new pbuf might be allocated, - * the data copied and the passed pbuf freed). - * - * This behaves like coap_pdu_init(0, 0, 0, pbuf->tot_len), and afterwards - * copying the contents of the pbuf to the pdu. - * - * @return A pointer to the new PDU object or @c NULL on error. - */ -coap_pdu_t * coap_pdu_from_pbuf(struct pbuf *pbuf); -#endif +#define COAP_PDU_CODE(pdu) ((pdu)->hdr->code) +#define COAP_PDU_TYPE(pdu) ((pdu)->hdr->type) +#define COAP_PDU_ID(pdu) ((pdu)->hdr->id) /** * Creates a new CoAP PDU of given @p size (must be large enough to hold the @@ -384,4 +397,12 @@ int coap_get_data(coap_pdu_t *pdu, size_t *len, unsigned char **data); +/** + * Return 1 if pdu contains payload, 0 otherwise. + */ +static inline int coap_has_data(coap_pdu_t *pdu) +{ + return (pdu->data != NULL); +} + #endif /* _PDU_H_ */ diff --git a/include/coap/resource.h b/include/coap/resource.h index 2947691fd3..30c3199c67 100644 --- a/include/coap/resource.h +++ b/include/coap/resource.h @@ -66,6 +66,7 @@ typedef struct coap_resource_t { * been notified of the last change */ unsigned int observable:1; /**< can be observed */ unsigned int cacheable:1; /**< can be cached */ + unsigned int dynamic:1; /**< should be freed */ /** * Used to store handlers for the four coap methods @c GET, @c POST, @c PUT, @@ -94,6 +95,10 @@ typedef struct coap_resource_t { str uri; int flags; + /** + * A pointer to user data. + */ + void *pdata; } coap_resource_t; /** @@ -138,6 +143,14 @@ int coap_delete_resource(coap_context_t *context, coap_key_t key); */ void coap_delete_all_resources(coap_context_t *context); +/** + * Deletes all resources from given @p context which uri matches given @p pattern. + * + * @param context The CoAP context with the resources to be deleted. + * @param pattern URI pattern to match + */ +void coap_delete_resource_by_pattern(coap_context_t *context, const char *pattern); + /** * Registers a new attribute with the given @p resource. As the * attributes str fields will point to @p name and @p val the @@ -183,6 +196,23 @@ coap_attr_t *coap_find_attr(coap_resource_t *resource, */ void coap_delete_attr(coap_attr_t *attr); +/** + * Associates user data with the given @p resource. + * + * @param resource The resource to which the data should be associated. + * @param p a pointer to user data + */ +void coap_set_user_data(coap_resource_t *resource, void *p); + +/** + * Returns pointer to user data associated with a given @p + * resource. + * + * @param resource The resource to get the user data. + * @return A pointer to user data or @c NULL if no data was associated. + */ +void *coap_get_user_data(coap_resource_t *resource); + /** * Status word to encode the result of conditional print or copy operations such * as coap_print_link(). The lower 28 bits of coap_print_status_t are used to diff --git a/include/coap/str.h b/include/coap/str.h index 92784ef1f0..05eea62e27 100644 --- a/include/coap/str.h +++ b/include/coap/str.h @@ -11,6 +11,10 @@ #include +#ifndef MIN +#define MIN(x , y) (((x) < (y)) ? (x) : (y)) +#endif + typedef struct { size_t length; /* length of string */ unsigned char *s; /* string data */ @@ -29,4 +33,12 @@ str *coap_new_string(size_t size); */ void coap_delete_string(str *); +/** + * Compare CoAP string with a null terminated string. + */ +static inline int coap_strcmp(const str *s1, const char *s2) +{ + return memcmp(s1->s, s2, MIN(s1->length, strlen(s2) - 1)); +} + #endif /* _COAP_STR_H_ */ diff --git a/include/coap/t_list.h b/include/coap/t_list.h index ebbd70f02a..de2cd98e44 100644 --- a/include/coap/t_list.h +++ b/include/coap/t_list.h @@ -31,7 +31,6 @@ #ifndef _DTLS_LIST_H_ #define _DTLS_LIST_H_ -#ifndef WITH_CONTIKI #include "uthash.h" #include "utlist.h" @@ -138,9 +137,5 @@ list_item_next(void *item) return item == NULL? NULL: ((struct list *)item)->next; } -#else /* WITH_CONTIKI */ -#include "list.h" -#endif /* WITH_CONTIKI */ - #endif /* _DTLS_LIST_H_ */ diff --git a/include/coap/uri.h b/include/coap/uri.h index 438478a673..4824c730a9 100644 --- a/include/coap/uri.h +++ b/include/coap/uri.h @@ -3,7 +3,7 @@ * Copyright (C) 2010,2011 Olaf Bergmann * * This file is part of the CoAP library libcoap. Please see - * README for terms of use. + * README for terms of use. */ #ifndef _COAP_URI_H_ @@ -18,7 +18,7 @@ typedef struct { str host; /**< host part of the URI */ unsigned short port; /**< The port in host byte order */ - str path; /**< Beginning of the first path segment. + str path; /**< Beginning of the first path segment. Use coap_split_path() to create Uri-Path options */ str query; /**< The query part if present */ } coap_uri_t; @@ -40,14 +40,14 @@ coap_uri_t *coap_new_uri(const unsigned char *uri, unsigned int length); * be released with coap_free(). */ coap_uri_t *coap_clone_uri(const coap_uri_t *uri); -/** - * Calculates a hash over the given path and stores the result in +/** + * Calculates a hash over the given path and stores the result in * @p key. This function returns @c 0 on error or @c 1 on success. - * + * * @param path The URI path to generate hash for. * @param len The length of @p path. * @param key The output buffer. - * + * * @return @c 1 if @p key was set, @c 0 otherwise. */ int coap_hash_path(const unsigned char *path, size_t len, coap_key_t key); @@ -60,14 +60,14 @@ int coap_hash_path(const unsigned char *path, size_t len, coap_key_t key); * @{ */ -/** +/** * Parses a given string into URI components. The identified syntactic * components are stored in the result parameter @p uri. Optional URI * components that are not specified will be set to { 0, 0 }, except * for the port which is set to @c COAP_DEFAULT_PORT. This function * returns @p 0 if parsing succeeded, a value less than zero * otherwise. - * + * * @param str_var The string to split up. * @param len The actual length of @p str_var * @param uri The coap_uri_t object to store the result. @@ -79,38 +79,38 @@ int coap_hash_path(const unsigned char *path, size_t len, coap_key_t key); int coap_split_uri(unsigned char *str_var, size_t len, coap_uri_t *uri); -/** +/** * Splits the given URI path into segments. Each segment is preceded * by an option pseudo-header with delta-value 0 and the actual length * of the respective segment after percent-decoding. - * - * @param s The path string to split. + * + * @param s The path string to split. * @param length The actual length of @p s. - * @param buf Result buffer for parsed segments. + * @param buf Result buffer for parsed segments. * @param buflen Maximum length of @p buf. Will be set to the actual number * of bytes written into buf on success. - * + * * @return The number of segments created or @c -1 on error. */ -int coap_split_path(const unsigned char *s, size_t length, +int coap_split_path(const unsigned char *s, size_t length, unsigned char *buf, size_t *buflen); -/** +/** * Splits the given URI query into segments. Each segment is preceded * by an option pseudo-header with delta-value 0 and the actual length * of the respective query term. - * - * @param s The query string to split. + * + * @param s The query string to split. * @param length The actual length of @p s. - * @param buf Result buffer for parsed segments. + * @param buf Result buffer for parsed segments. * @param buflen Maximum length of @p buf. Will be set to the actual number * of bytes written into buf on success. - * + * * @return The number of segments created or @c -1 on error. * * @bug This function does not reserve additional space for delta > 12. */ -int coap_split_query(const unsigned char *s, size_t length, +int coap_split_query(const unsigned char *s, size_t length, unsigned char *buf, size_t *buflen); /** @} */ diff --git a/include/coap/uthash.h b/include/coap/uthash.h index 32b7a81cfb..ed36537468 100644 --- a/include/coap/uthash.h +++ b/include/coap/uthash.h @@ -283,7 +283,7 @@ do { * This is for uthash developer only; it compiles away if HASH_DEBUG isn't defined. */ #ifdef HASH_DEBUG -#define HASH_OOPS(...) do { fprintf(stderr,__VA_ARGS__); exit(-1); } while (0) +#define HASH_OOPS(...) do { fprintf(stderr,__VA_ARGS__); return; } while (0)//exit(-1); } while (0) #define HASH_FSCK(hh,head) \ do { \ struct UT_hash_handle *_thh; \ diff --git a/libcoap-1.pc.in b/libcoap-1.pc.in deleted file mode 100644 index 4a031891f8..0000000000 --- a/libcoap-1.pc.in +++ /dev/null @@ -1,11 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ - -Name: @PACKAGE_NAME@ -Description: C-Implementation of CoAP. -Version: @PACKAGE_VERSION@ -URL: @PACKAGE_URL@ -Libs: -L${libdir} -lcoap -Cflags: -I${includedir}/coap diff --git a/platform/contiki/platform.c b/platform/contiki/platform.c new file mode 100644 index 0000000000..ff94e8f666 --- /dev/null +++ b/platform/contiki/platform.c @@ -0,0 +1,182 @@ +/* + * coap_contiki.c + + * + * Created on: Jun 11, 2015 + * Author: wojtek + */ +# ifndef DEBUG +# define DEBUG DEBUG_PRINT +# endif /* DEBUG */ + +#include "coap_config.h" +#include "net.h" +#include "pdu.h" +#include "coap_io.h" +#include "resource.h" + +#define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN]) +#define UIP_UDP_BUF ((struct uip_udp_hdr *)&uip_buf[UIP_LLIPH_LEN]) + +#define COAP_MAX_STRING_SIZE 12 +#define COAP_MAX_STRINGS 8 +#define COAP_MAX_PACKET_SIZE (sizeof(coap_packet_t) + COAP_MAX_PDU_SIZE) +#define COAP_MAX_PACKETS 2 + +static unsigned char initialized = 0; +static coap_context_t the_coap_context; + +PROCESS(coap_retransmit_process, "message retransmit process"); + +struct coap_string_t +{ + char data[COAP_MAX_STRING_SIZE]; +}; + +typedef union +{ + coap_pdu_t packet; /* try to convince the compiler to word-align this structure */ + char buf[COAP_MAX_PACKET_SIZE]; +} coap_packetbuf_t; + +MEMB(packet_storage, coap_packetbuf_t, COAP_MAX_PACKETS); +MEMB(node_storage, coap_queue_t, COAP_PDU_MAXCNT); +MEMB(pdu_storage, coap_pdu_t, COAP_PDU_MAXCNT); +MEMB(pdu_buf_storage, coap_packetbuf_t, COAP_PDU_MAXCNT); +MEMB(resource_storage, coap_resource_t, COAP_MAX_RESOURCES); +MEMB(attribute_storage, coap_attr_t, COAP_MAX_ATTRIBUTES); +MEMB(subscription_storage, coap_subscription_t, COAP_MAX_SUBSCRIBERS); +MEMB(string_storage, struct coap_string_t, COAP_MAX_STRINGS); + +static struct memb * +get_container(coap_memory_tag_t type) +{ + switch (type) { + case COAP_PACKET: + return &packet_storage; + case COAP_NODE: + return &node_storage; + case COAP_PDU: + return &pdu_storage; + case COAP_PDU_BUF: + return &pdu_buf_storage; + case COAP_RESOURCE: + return &resource_storage; + case COAP_RESOURCEATTR: + return &attribute_storage; + case COAP_SUBSCRIPTION: + return &subscription_storage; + default: + return &string_storage; + } +} + +void +coap_memory_init(void) +{ + memb_init(&string_storage); + memb_init(&packet_storage); + memb_init(&node_storage); + memb_init(&pdu_storage); + memb_init(&pdu_buf_storage); + memb_init(&resource_storage); + memb_init(&attribute_storage); +} + +void * +coap_malloc_type(coap_memory_tag_t type, size_t size) +{ + if (type != COAP_CONTEXT) { + struct memb *container = get_container(type); + + assert(container); + + if (size > container->size) { + debug("coap_malloc_type: Requested memory exceeds maximum object size\n"); + return NULL; + } + + return memb_alloc(container); + } else if (!initialized) { + return &the_coap_context; + } else { + return NULL; + } +} + +void +coap_free_type(coap_memory_tag_t type, void *object) +{ + if (type != COAP_CONTEXT) + memb_free(get_container(type), object); +} + +void +coap_platform_init(void) +{ + coap_resources_init(); + coap_memory_init(); + + process_start(&coap_retransmit_process, (char *) c); + + PROCESS_CONTEXT_BEGIN(&coap_retransmit_process); +#ifndef WITHOUT_OBSERVE + etimer_set(&c->notify_timer, + COAP_RESOURCE_CHECK_TIME * COAP_TICKS_PER_SECOND); +#endif /* WITHOUT_OBSERVE */ + /* the retransmit timer must be initialized to some large value */ + etimer_set(&the_coap_context.retransmit_timer, 0xFFFF); + PROCESS_CONTEXT_END(&coap_retransmit_process); + + c = &the_coap_context; + initialized = 1; +} + +void +coap_platform_deinit(void) +{ + memset(&the_coap_context, 0, sizeof(coap_context_t)); + initialized = 0; +} + +/*---------------------------------------------------------------------------*/ +/* CoAP message retransmission */ +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD( coap_retransmit_process, ev, data) +{ + coap_tick_t now; + coap_queue_t *nextpdu; + + PROCESS_BEGIN(); + + debug("Started retransmit process\r\n"); + + while (1) { + PROCESS_YIELD(); + if (ev == PROCESS_EVENT_TIMER) { + if (etimer_expired(&the_coap_context.retransmit_timer)) { + + nextpdu = coap_peek_next(&the_coap_context); + + coap_ticks(&now); + while (nextpdu && nextpdu->t <= now) { + coap_retransmit(&the_coap_context, coap_pop_next(&the_coap_context)); + nextpdu = coap_peek_next(&the_coap_context); + } + + /* need to set timer to some value even if no nextpdu is available */ + etimer_set(&the_coap_context.retransmit_timer, + nextpdu ? nextpdu->t - now : 0xFFFF); + } +#ifndef WITHOUT_OBSERVE + if (etimer_expired(&the_coap_context.notify_timer)) { + coap_check_notify(&the_coap_context); + etimer_reset(&the_coap_context.notify_timer); + } +#endif /* WITHOUT_OBSERVE */ + } + } + + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ diff --git a/platform/contiki/platform.h b/platform/contiki/platform.h new file mode 100644 index 0000000000..d71ecb4942 --- /dev/null +++ b/platform/contiki/platform.h @@ -0,0 +1,62 @@ +/* + * coap_contiki.h + * + * Created on: Jun 11, 2015 + * Author: wojtek + */ + +#ifndef INCLUDE_COAP_COAP_CONTIKI_H_ +#define INCLUDE_COAP_COAP_CONTIKI_H_ + +#include +#include "clock.h" +#include "mem.h" +#include "net/ip/uip-debug.h" + +typedef clock_time_t coap_tick_t; +typedef clock_time_t coap_time_t; + +/** + * This data type is used to represent the difference between two clock_tick_t + * values. This data type must have the same size in memory as coap_tick_t to + * allow wrapping. + */ +typedef int coap_tick_diff_t; + +#define COAP_TICKS_PER_SECOND CLOCK_SECOND + +static inline void coap_clock_init(void) { + clock_init(); +} + +static inline void coap_ticks(coap_tick_t *t) { + *t = clock_time(); +} + +static inline coap_time_t coap_ticks_to_rt(coap_tick_t t) { + return t / COAP_TICKS_PER_SECOND; +} + +/** + * Fills \p buf with \p len random bytes. This is the default implementation for + * prng(). You might want to change prng() to use a better PRNG on your specific + * platform. + */ +static inline int +coap_prng_impl(unsigned char *buf, size_t len) { + unsigned short v = random_rand(); + while (len > sizeof(v)) { + memcpy(buf, &v, sizeof(v)); + len -= sizeof(v); + buf += sizeof(v); + v = random_rand(); + } + + memcpy(buf, &v, len); + return 1; +} + +#define prng(Buf,Length) coap_prng_impl((Buf), (Length)) +#define prng_init(Value) random_init((unsigned short)(Value)) + +#endif /* INCLUDE_COAP_COAP_CONTIKI_H_ */ diff --git a/platform/contiki/platform_io.c b/platform/contiki/platform_io.c index adb82f3bfa..91a6422e38 100644 --- a/platform/contiki/platform_io.c +++ b/platform/contiki/platform_io.c @@ -1,9 +1,20 @@ #include "coap_io.h" + +#include "coap_config.h" #include "debug.h" #include "mem.h" #include "coap_io.h" +#ifdef HAVE_STDIO_H +#include +#endif + +#include "uip.h" + /* FIXME: untested, make this work */ +#define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN]) +#define UIP_UDP_BUF ((struct uip_udp_hdr *)&uip_buf[UIP_LLIPH_LEN]) + static int ep_initialized = 0; static inline struct coap_endpoint_t * @@ -23,25 +34,28 @@ coap_free_contiki_endpoint(struct coap_endpoint_t *ep) { ep_initialized = 0; } -coap_endpoint_t * -coap_new_endpoint(const coap_address_t *addr, int flags) { - struct coap_endpoint_t *ep = coap_malloc_contiki_endpoint(); +static inline coap_packet_t * +coap_malloc_packet(void) { + return (coap_packet_t *)coap_malloc_type(COAP_PACKET, 0); +} - if (ep) { - memset(ep, 0, sizeof(struct coap_endpoint_t)); - ep->handle.conn = udp_new(NULL, 0, NULL); +void +coap_free_packet(coap_packet_t *packet) { + coap_free_type(COAP_PACKET, packet); +} - if (!ep->handle.conn) { - coap_free_endpoint(ep); - return NULL; - } +static inline size_t +coap_get_max_packetlength(const coap_packet_t *packet UNUSED_PARAM) { + return COAP_MAX_PDU_SIZE; +} - coap_address_init(&ep->addr); - uip_ipaddr_copy(&ep->addr.addr, &addr->addr); - ep->addr.port = addr->port; - udp_bind((struct uip_udp_conn *)ep->handle.conn, addr->port); - } - return ep; +void +coap_packet_populate_endpoint(coap_packet_t *packet, coap_endpoint_t *target) +{ + target->conn = packet->interface->conn; + memcpy(&target->addr, &packet->dst, sizeof(target->addr)); + target->ifindex = packet->ifindex; + target->flags = 0; /* FIXME */ } void @@ -51,28 +65,25 @@ coap_packet_copy_source(coap_packet_t *packet, coap_address_t *target) } void -coap_free_endpoint(coap_endpoint_t *ep) { - if (ep) { - if (ep->handle.conn) { - uip_udp_remove((struct uip_udp_conn *)ep->handle.conn); - } - coap_free_contiki_endpoint(ep); - } +coap_packet_get_memmapped(coap_packet_t *packet, unsigned char **address, size_t *length) +{ + *address = packet->payload; + *length = packet->length; } ssize_t -coap_network_send(struct coap_context_t *context UNUSED_PARAM, +coap_network_send(struct coap_context_t *context, const coap_endpoint_t *local_interface, const coap_address_t *dst, - unsigned char *data, - size_t datalen) { + const coap_pdu_t *pdu) { - struct coap_endpoint_t *ep = + struct coap_endpoint_t *ep = (struct coap_endpoint_t *)local_interface; - /* FIXME: untested */ - /* FIXME: is there a way to check if send was successful? */ - uip_udp_packet_sendto((struct uip_udp_conn *)ep->handle.conn, data, datalen, + unsigned char *data = pdu->hdr; + size_t datalen = pdu->length; + + uip_udp_packet_sendto((struct uip_udp_conn *)ep->conn, data, datalen, &dst->addr, dst->port); return datalen; } @@ -82,10 +93,6 @@ coap_malloc_packet(void) { return (coap_packet_t *)coap_malloc_type(COAP_PACKET, 0); } -/* FIXME: untested, make this work */ -#define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN]) -#define UIP_UDP_BUF ((struct uip_udp_hdr *)&uip_buf[UIP_LLIPH_LEN]) - ssize_t coap_network_read(coap_endpoint_t *ep, coap_packet_t **packet) { ssize_t len = -1; @@ -152,3 +159,35 @@ coap_network_read(coap_endpoint_t *ep, coap_packet_t **packet) { return -1; } +coap_endpoint_t * +coap_new_endpoint(const coap_address_t *addr, int flags) { + struct coap_endpoint_t *ep = coap_malloc_contiki_endpoint(); + + if (ep) { + memset(ep, 0, sizeof(struct coap_endpoint_t)); + ep->conn = udp_new(NULL, 0, NULL); + + if (!ep->conn) { + coap_free_endpoint(ep); + return NULL; + } + + coap_address_init(&ep->addr); + uip_ipaddr_copy(&ep->addr.addr, &addr->addr); + ep->addr.port = addr->port; + ep->network_send = coap_network_send; + ep->network_read = coap_network_read; + udp_bind((struct uip_udp_conn *)ep->conn, addr->port); + } + return ep; +} + +void +coap_free_endpoint(coap_endpoint_t *ep) { + if (ep) { + if (ep->conn) { + uip_udp_remove((struct uip_udp_conn *)ep->conn); + } + coap_free_contiki_endpoint(ep); + } +} diff --git a/platform/contiki/platform_io.h b/platform/contiki/platform_io.h index a9affd727e..b5c4819c23 100644 --- a/platform/contiki/platform_io.h +++ b/platform/contiki/platform_io.h @@ -3,6 +3,42 @@ #include "uip.h" +#define CUSTOM_CONTEXT_FIELDS \ + struct uip_udp_conn *conn; \ + struct etimer retransmit_timer; \ + struct etimer notify_timer; + +/**< uIP connection object */ +/**< fires when the next packet must be sent */ +/**< used to check resources periodically */ + +typedef struct coap_address_t { + uip_ipaddr_t addr; + unsigned short port; +} coap_address_t; + +#define _coap_address_equals_impl(A,B) \ + ((A)->port == (B)->port \ + && uip_ipaddr_cmp(&((A)->addr),&((B)->addr))) + +/** @todo implementation of _coap_address_isany_impl() for Contiki */ +#define _coap_address_isany_impl(A) 0 + +#define _coap_is_mcast_impl(Address) uip_is_addr_mcast(&((Address)->addr)) + +/** + * Abstraction of virtual endpoint that can be attached to coap_context_t. The + * tuple (handle, addr) must uniquely identify this endpoint. + */ +typedef struct coap_endpoint_t { + coap_network_read_t network_read; + coap_network_send_t network_send; + void *conn; /**< opaque connection (e.g. uip_conn in Contiki) */ + coap_address_t addr; /**< local interface address */ + int ifindex; + int flags; +} coap_endpoint_t; + /* * This is only included in coap_io.h instead of .c in order to be available for * sizeof in mem.c. diff --git a/include/coap/lwippools.h b/platform/lwip/lwippools.h similarity index 100% rename from include/coap/lwippools.h rename to platform/lwip/lwippools.h diff --git a/platform/lwip/platform.c b/platform/lwip/platform.c new file mode 100644 index 0000000000..222d0dde7e --- /dev/null +++ b/platform/lwip/platform.c @@ -0,0 +1,185 @@ +/* + * coap_lwip.c + * + * Created on: Jun 11, 2015 + * Author: wojtek + */ + +void coap_platform_init(void) +{ + prng_init(LWIP_RAND()); +} + +void coap_platform_deinit(void) +{ + +} + +/* FIXME: retransmits that are not required any more due to incoming packages + * do *not* get cleared at the moment, the wakeup when the transmission is due + * is silently accepted. this is mainly due to the fact that the required + * checks are similar in two places in the code (when receiving ACK and RST) + * and that they cause more than one patch chunk, as it must be first checked + * whether the sendqueue item to be dropped is the next one pending, and later + * the restart function has to be called. nothing insurmountable, but it can + * also be implemented when things have stabilized, and the performance + * penality is minimal + * + * also, this completely ignores COAP_RESOURCE_CHECK_TIME. + * */ + +static void coap_retransmittimer_execute(void *arg) +{ + coap_context_t *ctx = (coap_context_t*)arg; + coap_tick_t now; + coap_tick_t elapsed; + coap_queue_t *nextinqueue; + + ctx->timer_configured = 0; + + coap_ticks(&now); + + elapsed = now - ctx->sendqueue_basetime; /* that's positive for sure, and unless we haven't been called for a complete wrapping cycle, did not wrap */ + + nextinqueue = coap_peek_next(ctx); + while (nextinqueue != NULL) + { + if (nextinqueue->t > elapsed) { + nextinqueue->t -= elapsed; + break; + } else { + elapsed -= nextinqueue->t; + coap_retransmit(ctx, coap_pop_next(ctx)); + nextinqueue = coap_peek_next(ctx); + } + } + + ctx->sendqueue_basetime = now; + + coap_retransmittimer_restart(ctx); +} + +static void coap_retransmittimer_restart(coap_context_t *ctx) +{ + coap_tick_t now, elapsed, delay; + + if (ctx->timer_configured) + { + printf("clearing\n"); + sys_untimeout(coap_retransmittimer_execute, (void*)ctx); + ctx->timer_configured = 0; + } + if (ctx->sendqueue != NULL) + { + coap_ticks(&now); + elapsed = now - ctx->sendqueue_basetime; + if (ctx->sendqueue->t >= elapsed) { + delay = ctx->sendqueue->t - elapsed; + } else { + /* a strange situation, but not completely impossible. + * + * this happens, for example, right after + * coap_retransmittimer_execute, when a retransmission + * was *just not yet* due, and the clock ticked before + * our coap_ticks was called. + * + * not trying to retransmit anything now, as it might + * cause uncontrollable recursion; let's just try again + * with the next main loop run. + * */ + delay = 0; + } + + printf("scheduling for %d ticks\n", delay); + sys_timeout(delay, coap_retransmittimer_execute, (void*)ctx); + ctx->timer_configured = 1; + } +} + +coap_pdu_t * +coap_pdu_from_pbuf(struct pbuf *pbuf) +{ + if (pbuf == NULL) return NULL; + + LWIP_ASSERT("Can only deal with contiguous PBUFs", pbuf->tot_len == pbuf->len); + LWIP_ASSERT("coap_read needs to receive an exclusive copy of the incoming pbuf", pbuf->ref == 1); + + coap_pdu_t *result = coap_malloc_type(COAP_PDU, sizeof(coap_pdu_t)); + if (!result) { + pbuf_free(pbuf); + return NULL; + } + + memset(result, 0, sizeof(coap_pdu_t)); + + result->max_size = pbuf->tot_len; + result->length = pbuf->tot_len; + result->hdr = pbuf->payload; + result->pbuf = pbuf; + + return result; +} + +void +coap_pdu_clear(coap_pdu_t *pdu, size_t size) { + assert(pdu); + + /* the pdu itself is not wiped as opposed to the other implementations, + * because we have to rely on the pbuf to be set there. */ + pdu->hdr = pdu->pbuf->payload; + pdu->max_size = size; + pdu->hdr->version = COAP_DEFAULT_VERSION; + pdu->hdr->token_length = 0; + + /* data is NULL unless explicitly set by coap_add_data() */ + pdu->length = sizeof(coap_hdr_t); +} + +coap_pdu_t * +coap_pdu_init(unsigned char type, unsigned char code, + unsigned short id, size_t size) { + coap_pdu_t *pdu; + struct pbuf *p; + 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) + return NULL; + + p = pbuf_alloc(PBUF_TRANSPORT, size, PBUF_RAM); + if (p != NULL) { + u8_t header_error = pbuf_header(p, sizeof(coap_pdu_t)); + /* we could catch that case and allocate larger memory in advance, but then + * again, we'd run into greater trouble with incoming packages anyway */ + LWIP_ASSERT("CoAP PDU header does not fit in transport header", header_error == 0); + pdu = p->payload; + } else { + pdu = NULL; + } + if (pdu) { + pdu->pbuf = p; + coap_pdu_clear(pdu, size); + pdu->hdr->id = id; + pdu->hdr->type = type; + pdu->hdr->code = code; + } + return pdu; +} + +coap_pdu_t * +coap_new_pdu(void) { + coap_pdu_t *pdu; + + pdu = coap_pdu_init(0, 0, ntohs(COAP_INVALID_TID), COAP_MAX_PDU_SIZE); + +#ifndef NDEBUG + if (!pdu) + coap_log(LOG_CRIT, "coap_new_pdu: cannot allocate memory for new PDU\n"); +#endif + return pdu; +} + +void +coap_delete_pdu(coap_pdu_t *pdu) { + if (pdu != NULL) /* accepting double free as the other implementation accept that too */ + pbuf_free(pdu->pbuf); +} diff --git a/platform/lwip/platform.h b/platform/lwip/platform.h new file mode 100644 index 0000000000..52187cfeb3 --- /dev/null +++ b/platform/lwip/platform.h @@ -0,0 +1,64 @@ +/* + * coap_lwip.h + * + * Created on: Jun 11, 2015 + * Author: wojtek + */ + +#ifndef INCLUDE_COAP_COAP_LWIP_H_ +#define INCLUDE_COAP_COAP_LWIP_H_ + +#include +#include +#include +#include +#include +#include + +/* lwIP provides ms in sys_now */ +#define COAP_TICKS_PER_SECOND 1000 + +typedef uint32_t coap_tick_t; +typedef uint32_t coap_time_t; +typedef int32_t coap_tick_diff_t; + +static inline void coap_ticks_impl(coap_tick_t *t) { + *t = sys_now(); +} + +static inline void coap_clock_init_impl(void) { +} + +#define coap_clock_init coap_clock_init_impl +#define coap_ticks coap_ticks_impl + +static inline coap_time_t coap_ticks_to_rt(coap_tick_t t) { + return t / COAP_TICKS_PER_SECOND; +} + +static void coap_retransmittimer_execute(void *arg); +static void coap_retransmittimer_restart(coap_context_t *ctx); + +/* no initialization needed with lwip (or, more precisely: lwip must be + * completely initialized anyway by the time coap gets active) */ +static inline void coap_memory_init(void) {} + +/* It would be nice to check that size equals the size given at the memp + * declaration, but i currently don't see a standard way to check that without + * sourcing the custom memp pools and becoming dependent of its syntax + */ +#define coap_malloc_type(type, size) memp_malloc(MEMP_##type) +#define coap_free_type(type, p) memp_free(MEMP_##type, p) + +/* Those are just here to make uri.c happy where string allocation has not been + * made conditional. + */ +static inline void *coap_malloc(size_t size) { + LWIP_ASSERT("coap_malloc must not be used in lwIP", 0); +} + +static inline void coap_free(void *pointer) { + LWIP_ASSERT("coap_free must not be used in lwIP", 0); +} + +#endif /* INCLUDE_COAP_COAP_LWIP_H_ */ diff --git a/platform/lwip/platform_io.c b/platform/lwip/platform_io.c index af2a791731..f492dee49f 100644 --- a/platform/lwip/platform_io.c +++ b/platform/lwip/platform_io.c @@ -1,79 +1,126 @@ #include "coap_io.h" +#include "platform_io.h" #include #include #include "debug.h" #include "mem.h" +#include "coap_config.h" #include "coap_io.h" -/* -void coap_packet_populate_endpoint(coap_packet_t *packet, coap_endpoint_t *target) -{ +void +coap_packet_populate_endpoint(coap_packet_t *packet, coap_endpoint_t *target) { printf("FIXME no endpoint populated\n"); } -*/ -void coap_packet_copy_source(coap_packet_t *packet, coap_address_t *target) -{ +void +coap_packet_copy_source(coap_packet_t *packet, coap_address_t *target) { target->port = packet->srcport; memcpy(&target->addr, ip_current_src_addr(), sizeof(ip_addr_t)); } +void +coap_packet_get_memmapped(coap_packet_t *packet, unsigned char **address, + size_t *length) { + LWIP_ASSERT("Can only deal with contiguous PBUFs to read the initial details", + packet->pbuf->tot_len == packet->pbuf->len); + *address = packet->pbuf->payload; + *length = packet->pbuf->tot_len; +} + +void +coap_free_packet(coap_packet_t *packet) { + if (packet->pbuf) + pbuf_free(packet->pbuf); + coap_free_type(COAP_PACKET, packet); +} + +struct pbuf * +coap_packet_extract_pbuf(coap_packet_t *packet) { + struct pbuf *ret = packet->pbuf; + packet->pbuf = NULL; + return ret; +} + /** Callback from lwIP when a package was received. * - * The current implementation deals this to coap_handle_message immedately, but + * The current implemntation deals this to coap_handle_message immedately, but * other mechanisms (as storing the package in a queue and later fetching it * when coap_read is called) can be envisioned. * * It handles everything coap_read does on other implementations. */ -static void coap_recv(void *arg, struct udp_pcb *upcb, struct pbuf *p, ip_addr_t *addr, u16_t port) -{ - coap_endpoint_t *ep = (coap_endpoint_t*)arg; - - LWIP_ASSERT("Can only deal with contiguous PBUFs to read the initial details", - p->tot_len == p->len); - - coap_packet_t *packet = coap_malloc_type(COAP_PACKET, sizeof(coap_packet_t)); +static void +coap_recv(void *arg, struct udp_pcb *upcb, struct pbuf *p, ip_addr_t *addr, + u16_t port) { + coap_endpoint_t *ep = (coap_endpoint_t*) arg; + coap_packet_t *packet = coap_malloc_type(COAP_PACKET, + sizeof(coap_packet_t)); /* this is fatal because due to the short life of the packet, never should there be more than one coap_packet_t required */ LWIP_ASSERT("Insufficient coap_packet_t resources.", packet != NULL); - - packet->data = p->payload; - packet->data_len = p->tot_len; + packet->pbuf = p; packet->srcport = port; /** FIXME derive the context without changing endopint definition */ coap_handle_message(ep->context, packet); - coap_free_packet(packet); - // Free the pbuf that the data comes from - if (p) { - pbuf_free(p); - } } +static coap_tid_t +coap_network_send(struct coap_context_t *context, const coap_endpoint_t *ep, + const coap_address_t *dst, unsigned char *data, + size_t datalen) { + coap_tid_t id = COAP_INVALID_TID; + uint8_t err; + char *data_backup; + + if (!context || !dst || !pdu) { + return id; + } + + data_backup = pdu->data; + + /* FIXME: we can't check this here with the existing infrastructure, but we + * should actually check that the pdu is not held by anyone but us. the + * respective pbuf is already exclusively owned by the pdu. */ + + pbuf_realloc(pdu->pbuf, pdu->length); + + coap_transaction_id(dst, pdu, &id); + + udp_sendto(ep->pcb, pdu->pbuf, &dst->addr, dst->port); + + return id; +} coap_endpoint_t * coap_new_endpoint(const coap_address_t *addr, int flags) { coap_endpoint_t *result; err_t err; - LWIP_ASSERT("Flags not supported for LWIP endpoints", flags == COAP_ENDPOINT_NOSEC); + LWIP_ASSERT("Flags not supported for LWIP endpoints", + flags == COAP_ENDPOINT_NOSEC); result = coap_malloc_type(COAP_ENDPOINT, sizeof(coap_endpoint_t)); - if (!result) return NULL; + if (!result) + return NULL; result->pcb = udp_new(); - if (result->pcb == NULL) goto error; + if (result->pcb == NULL) + goto error; - udp_recv(result->pcb, coap_recv, (void*)result); + udp_recv(result->pcb, coap_recv, (void*) result); err = udp_bind(result->pcb, &addr->addr, addr->port); if (err) { udp_remove(result->pcb); goto error; } + result->cbs.network_send = coap_network_send; + // FIXME!!!! + result->cbs.network_read = NULL; + return result; error: @@ -86,25 +133,3 @@ coap_free_endpoint(coap_endpoint_t *ep) { udp_remove(ep->pcb); coap_free_type(COAP_ENDPOINT, ep); } - - -ssize_t -coap_network_read(coap_endpoint_t *ep, coap_packet_t **packet) { - // TODO not implemented - return -1; -} - -ssize_t -coap_network_send(struct coap_context_t *context UNUSED_PARAM, - const coap_endpoint_t *local_interface, - const coap_address_t *dst, - unsigned char *data, - size_t datalen) { - struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, datalen, PBUF_REF); - pbuf->payload = data; - udp_sendto(context->endpoint->pcb, pdu->pbuf, - &dst->addr, dst->port); - pbuf_free(p); -} - - diff --git a/platform/lwip/platform_io.h b/platform/lwip/platform_io.h index 98f3e1587e..f01772c31a 100644 --- a/platform/lwip/platform_io.h +++ b/platform/lwip/platform_io.h @@ -1,4 +1,66 @@ +/* + * coap_lwip_io.h + * + * Created on: Jun 11, 2015 + * Author: wojtek + */ + +#ifndef PLATFORM_COAP_LWIP_IO_H_ +#define PLATFORM_COAP_LWIP_IO_H_ + +#include #include +#include + +/**< Set to 1 when a retransmission is + * scheduled using lwIP timers for this + * context, otherwise 0. */ +#define CUSTOM_CONTEXT_FIELDS \ + uint8_t timer_configured; + +typedef struct coap_address_t { + uint16_t port; + ip_addr_t addr; +} coap_address_t; + +/* FIXME oversimplification: just assuming it's an ipv4 address instead of + * looking up the appropraite lwip function */ + +#define _coap_address_equals_impl(A, B) \ + ((A)->addr.addr == (B)->addr.addr \ + && A->port == B->port) + +/** @todo implementation of _coap_address_isany_impl() for Contiki */ +#define _coap_address_isany_impl(A) 0 + +/* FIXME sure there is something in lwip */ +#define _coap_is_mcast_impl(Address) 0 + + +#define CUSTOM_PDU_FIELDS struct pbuf *pbuf; /**< lwIP PBUF. The package data will always reside + * inside the pbuf's payload, but this pointer + * has to be kept because no exact offset can be + * given. This field must not be accessed from + * outside, because the pbuf's reference count + * is checked to be 1 when the pbuf is assigned + * to the pdu, and the pbuf stays exclusive to + * this pdu. */ + +/** + * Abstraction of virtual endpoint that can be attached to coap_context_t. The + * tuple (handle, addr) must uniquely identify this endpoint. + */ +typedef struct coap_endpoint_t { + coap_network_read_t network_read; + coap_network_send_t network_send; + struct udp_pcb *pcb; + /**< @FIXME this was added in a hurry, not sure it confirms to the overall model --chrysn */ + struct coap_context_t *context; + coap_address_t addr; /**< local interface address */ + int ifindex; + int flags; +} coap_endpoint_t; + /* * This is only included in coap_io.h instead of .c in order to be available for @@ -9,8 +71,7 @@ * as the packets have limited lifetime anyway. */ struct coap_packet_t { - unsigned char *data; - size_t data_len; + struct pbuf *pbuf; const coap_endpoint_t *local_interface; uint16_t srcport; }; @@ -21,3 +82,21 @@ struct coap_packet_t { */ struct pbuf *coap_packet_extract_pbuf(coap_packet_t *packet); +/** + * Creates a CoAP PDU from an lwIP @p pbuf, whose reference is passed on to this + * function. + * + * The pbuf is checked for being contiguous, and for having only one reference. + * The reference is stored in the PDU and will be freed when the PDU is freed. + * + * (For now, these are fatal errors; in future, a new pbuf might be allocated, + * the data copied and the passed pbuf freed). + * + * This behaves like coap_pdu_init(0, 0, 0, pbuf->tot_len), and afterwards + * copying the contents of the pbuf to the pdu. + * + * @return A pointer to the new PDU object or @c NULL on error. + */ +coap_pdu_t * coap_pdu_from_pbuf(struct pbuf *pbuf); + +#endif /* PLATFORM_COAP_LWIP_IO_H_ */ diff --git a/platform/posix/libev/libev.la b/platform/posix/libev/libev.la deleted file mode 100644 index a7afa4daae..0000000000 --- a/platform/posix/libev/libev.la +++ /dev/null @@ -1,41 +0,0 @@ -# libev.la - a libtool library file -# Generated by libtool (GNU libtool) 2.4.6 -# -# Please DO NOT delete this file! -# It is necessary for linking the library. - -# The name that we can dlopen(3). -dlname='libev.4.dylib' - -# Names of this library. -library_names='libev.4.dylib libev.dylib' - -# The name of the static archive. -old_library='libev.a' - -# Linker flags that cannot go in dependency_libs. -inherited_linker_flags=' ' - -# Libraries that this one depends upon. -dependency_libs='' - -# Names of additional weak libraries provided by this library -weak_library_names='' - -# Version information for libev. -current=4 -age=0 -revision=0 - -# Is this an already installed library? -installed=no - -# Should we warn about portability when linking against -modules? -shouldnotlink=no - -# Files to dlopen/dlpreopen -dlopen='' -dlpreopen='' - -# Directory that this library needs to be installed in: -libdir='/usr/local/lib' diff --git a/platform/posix/platform.c b/platform/posix/platform.c new file mode 100644 index 0000000000..b96e816d8e --- /dev/null +++ b/platform/posix/platform.c @@ -0,0 +1,45 @@ +/* + * coap_posix.c + * + * Created on: Jun 11, 2015 + * Author: wojtek + */ + +#include +#include +#include + +#ifdef HAVE_ASSERT_H +#include +#else /* HAVE_ASSERT_H */ +#define assert(...) +#endif /* HAVE_ASSERT_H */ + +#ifdef HAVE_MALLOC +#include +#endif + +#ifdef __GNUC__ +#define UNUSED_PARAM __attribute__((unused)) +#else +#define UNUSED_PARAM +#endif /* __GNUC__ */ + +void +coap_platform_init(void) { + prng_init(time(NULL)); +} + +void +coap_memory_init(void) { +} + +void * +coap_malloc_type(coap_memory_tag_t type UNUSED_PARAM, size_t size) { + return malloc(size); +} + +void +coap_free_type(coap_memory_tag_t type UNUSED_PARAM, void *p) { + free(p); +} diff --git a/platform/posix/platform.h b/platform/posix/platform.h new file mode 100644 index 0000000000..17f842c694 --- /dev/null +++ b/platform/posix/platform.h @@ -0,0 +1,57 @@ +/* + * coap_posix.h + * + * Created on: Jun 11, 2015 + * Author: wojtek + */ + +#ifndef INCLUDE_COAP_COAP_POSIX_H_ +#define INCLUDE_COAP_COAP_POSIX_H_ + +#include + +/** + * This data type represents internal timer ticks with COAP_TICKS_PER_SECOND + * resolution. + */ +typedef unsigned long coap_tick_t; + +/** + * CoAP time in seconds since epoch. + */ +typedef time_t coap_time_t; + +/** + * This data type is used to represent the difference between two clock_tick_t + * values. This data type must have the same size in memory as coap_tick_t to + * allow wrapping. + */ +typedef long coap_tick_diff_t; + +/** Use ms resolution on POSIX systems */ +#define COAP_TICKS_PER_SECOND 1000 + +/** + * Sets @p t to the internal time with COAP_TICKS_PER_SECOND resolution. + */ +static inline void coap_ticks(coap_tick_t *t) { + struct timespec spec; + clock_gettime(CLOCK_MONOTONIC, &spec); + *t = (coap_tick_t)spec.tv_sec*1000 + (coap_tick_t)(spec.tv_nsec / 1.0e6); +} + +/** + * Helper function that converts coap ticks to wallclock time. On POSIX, this + * function returns the number of seconds since the epoch. On other systems, it + * may be the calculated number of seconds since last reboot or so. + * + * @param t Internal system ticks. + * + * @return The number of seconds that has passed since a specific reference + * point (seconds since epoch on POSIX). + */ +static inline coap_time_t coap_ticks_to_rt(coap_tick_t t) { + return t / COAP_TICKS_PER_SECOND; +} + +#endif /* INCLUDE_COAP_COAP_POSIX_H_ */ diff --git a/platform/posix/platform_io.c b/platform/posix/platform_io.c index e47b38347d..f9c35e6f95 100644 --- a/platform/posix/platform_io.c +++ b/platform/posix/platform_io.c @@ -1,3 +1,4 @@ +#include "coap_config.h" #include "coap_io.h" #include "debug.h" @@ -8,6 +9,8 @@ #define SOL_IP IPPROTO_IP #endif +#define SIN6(A) ((struct sockaddr_in6 *)(A)) + #if !defined(HAVE_NETINET_IN_H) /* define struct in6_pktinfo and struct in_pktinfo if not available FIXME: check with configure @@ -24,100 +27,10 @@ struct in_pktinfo { }; #endif -static struct coap_endpoint_t * -coap_malloc_posix_endpoint(void) { - return (struct coap_endpoint_t *)coap_malloc(sizeof(struct coap_endpoint_t)); -} - -static void -coap_free_posix_endpoint(struct coap_endpoint_t *ep) { - coap_free(ep); -} - -coap_endpoint_t * -coap_new_endpoint(const coap_address_t *addr, int flags) { - int sockfd = socket(addr->addr.sa.sa_family, SOCK_DGRAM, 0); - int on = 1; - struct coap_endpoint_t *ep; - - if (sockfd < 0) { - coap_log(LOG_WARNING, "coap_new_endpoint: socket"); - return NULL; - } - - if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) - coap_log(LOG_WARNING, "coap_new_endpoint: setsockopt SO_REUSEADDR"); - - on = 1; - switch(addr->addr.sa.sa_family) { - case AF_INET: - if (setsockopt(sockfd, IPPROTO_IP, IP_PKTINFO, &on, sizeof(on)) < 0) - coap_log(LOG_ALERT, "coap_new_endpoint: setsockopt IP_PKTINFO\n"); - break; - case AF_INET6: -#ifdef IPV6_RECVPKTINFO - if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on)) < 0) - coap_log(LOG_ALERT, "coap_new_endpoint: setsockopt IPV6_RECVPKTINFO\n"); -#else /* IPV6_RECVPKTINFO */ - if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_PKTINFO, &on, sizeof(on)) < 0) - coap_log(LOG_ALERT, "coap_new_endpoint: setsockopt IPV6_PKTINFO\n"); -#endif /* IPV6_RECVPKTINFO */ - break; - default: - coap_log(LOG_ALERT, "coap_new_endpoint: unsupported sa_family\n"); - } - - if (bind(sockfd, &addr->addr.sa, addr->size) < 0) { - coap_log(LOG_WARNING, "coap_new_endpoint: bind"); - close (sockfd); - return NULL; - } - - ep = coap_malloc_posix_endpoint(); - if (!ep) { - coap_log(LOG_WARNING, "coap_new_endpoint: malloc"); - close(sockfd); - return NULL; - } - - memset(ep, 0, sizeof(struct coap_endpoint_t)); - ep->handle.fd = sockfd; - ep->flags = flags; - memcpy(&ep->addr, addr, sizeof(coap_address_t)); - -#ifndef NDEBUG - if (LOG_DEBUG <= coap_get_log_level()) { -#ifndef INET6_ADDRSTRLEN -#define INET6_ADDRSTRLEN 40 -#endif - unsigned char addr_str[INET6_ADDRSTRLEN+8]; - - if (coap_print_addr(addr, addr_str, INET6_ADDRSTRLEN+8)) { - debug("created %sendpoint %s\n", - ep->flags & COAP_ENDPOINT_DTLS ? "DTLS " : "", - addr_str); - } - } -#endif /* NDEBUG */ - - return (coap_endpoint_t *)ep; -} - -void -coap_free_endpoint(coap_endpoint_t *ep) { - if(ep) { - if (ep->handle.fd >= 0) - close(ep->handle.fd); - coap_free_posix_endpoint((struct coap_endpoint_t *)ep); - } -} - -ssize_t -coap_network_send(struct coap_context_t *context UNUSED_PARAM, +static ssize_t +coap_network_send(struct coap_context_t *context, const coap_endpoint_t *local_interface, - const coap_address_t *dst, - unsigned char *data, - size_t datalen) { + const coap_address_t *dst, const coap_pdu_t *pdu) { struct coap_endpoint_t *ep = (struct coap_endpoint_t *)local_interface; @@ -126,10 +39,12 @@ coap_network_send(struct coap_context_t *context UNUSED_PARAM, struct msghdr mhdr; struct iovec iov[1]; + (void)context; + assert(local_interface); - iov[0].iov_base = data; - iov[0].iov_len = datalen; + iov[0].iov_base = pdu->hdr; + iov[0].iov_len = pdu->length; memset(&mhdr, 0, sizeof(struct msghdr)); mhdr.msg_name = (void *)&dst->addr; @@ -202,7 +117,7 @@ coap_network_send(struct coap_context_t *context UNUSED_PARAM, return -1; } - return sendmsg(ep->handle.fd, &mhdr, 0); + return sendmsg(ep->fd, &mhdr, 0); } coap_packet_t * @@ -223,7 +138,7 @@ coap_packet_copy_source(coap_packet_t *packet, coap_address_t *target) memcpy(target, &packet->src, sizeof(coap_address_t)); } -ssize_t +static ssize_t coap_network_read(coap_endpoint_t *ep, coap_packet_t **packet) { ssize_t len = -1; char msg_control[CMSG_LEN(sizeof(struct sockaddr_storage))]; @@ -258,7 +173,7 @@ coap_network_read(coap_endpoint_t *ep, coap_packet_t **packet) { mhdr.msg_controllen = sizeof(msg_control); assert(sizeof(msg_control) == CMSG_LEN(sizeof(struct sockaddr_storage))); - len = recvmsg(ep->handle.fd, &mhdr, 0); + len = recvmsg(ep->fd, &mhdr, 0); if (len < 0) { coap_log(LOG_WARNING, "coap_network_read: %s\n", strerror(errno)); @@ -266,11 +181,11 @@ coap_network_read(coap_endpoint_t *ep, coap_packet_t **packet) { } else { struct cmsghdr *cmsg; - coap_log(LOG_DEBUG, "received %d bytes on fd %d\n", (int)len, ep->handle.fd); + coap_log(LOG_DEBUG, "received %d bytes on fd %d\n", (int)len, ep->fd); /* use getsockname() to get the local port */ (*packet)->dst.size = sizeof((*packet)->dst.addr); - if (getsockname(ep->handle.fd, &(*packet)->dst.addr.sa, &(*packet)->dst.size) < 0) { + if (getsockname(ep->fd, &(*packet)->dst.addr.sa, &(*packet)->dst.size) < 0) { coap_log(LOG_DEBUG, "cannot determine local port\n"); goto error; } @@ -338,3 +253,86 @@ coap_network_read(coap_endpoint_t *ep, coap_packet_t **packet) { return -1; } +coap_endpoint_t * +coap_new_endpoint(const coap_address_t *addr, int flags) +{ + int sockfd = socket(addr->addr.sa.sa_family, SOCK_DGRAM, 0); + int on = 1; + struct coap_endpoint_t *ep; + + if (sockfd < 0) { + coap_log(LOG_WARNING, "coap_new_endpoint: socket"); + return NULL; + } + + if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) + coap_log(LOG_WARNING, "coap_new_endpoint: setsockopt SO_REUSEADDR"); + + on = 1; + switch (addr->addr.sa.sa_family) { + case AF_INET: + if (setsockopt(sockfd, IPPROTO_IP, IP_PKTINFO, &on, sizeof(on)) < 0) + coap_log(LOG_ALERT, "coap_new_endpoint: setsockopt IP_PKTINFO\n"); + break; + case AF_INET6: +#ifdef IPV6_RECVPKTINFO + if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on)) < 0) + coap_log(LOG_ALERT, "coap_new_endpoint: setsockopt IPV6_RECVPKTINFO\n"); +#else /* IPV6_RECVPKTINFO */ + if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_PKTINFO, &on, sizeof(on)) < 0) + coap_log(LOG_ALERT, "coap_new_endpoint: setsockopt IPV6_PKTINFO\n"); +#endif /* IPV6_RECVPKTINFO */ + break; + default: + coap_log(LOG_ALERT, "coap_new_endpoint: unsupported sa_family\n"); + } + + if (bind(sockfd, &addr->addr.sa, addr->size) < 0) { + coap_log(LOG_WARNING, "coap_new_endpoint: bind"); + close(sockfd); + return NULL; + } + + ep = coap_malloc_type(COAP_ENDPOINT, sizeof(struct coap_endpoint_t)); + if (!ep) { + coap_log(LOG_WARNING, "coap_new_endpoint: malloc"); + close(sockfd); + return NULL; + } + + memset(ep, 0, sizeof(struct coap_endpoint_t)); + ep->fd = sockfd; + ep->flags = flags; + ep->network_send = coap_network_send; + ep->network_read = coap_network_read; + + memcpy(&ep->addr, addr, sizeof(coap_address_t)); + +#ifndef NDEBUG + if (LOG_DEBUG <= coap_get_log_level()) { +#ifndef INET6_ADDRSTRLEN +#define INET6_ADDRSTRLEN 40 +#endif + unsigned char addr_str[INET6_ADDRSTRLEN + 8]; + + if (coap_print_addr(addr, addr_str, INET6_ADDRSTRLEN + 8)) { + debug("created %sendpoint %s\n", + ep->flags & COAP_ENDPOINT_DTLS ? "DTLS " : "", addr_str); + } + } +#endif /* NDEBUG */ + + return (coap_endpoint_t *) ep; +} + +void +coap_free_endpoint(coap_endpoint_t *ep) +{ + if (ep) { + if (ep->fd >= 0) + close(ep->fd); + coap_free_type(COAP_ENDPOINT, (struct coap_endpoint_t *) ep); + } +} + +#undef SIN6 diff --git a/platform/posix/platform_io.h b/platform/posix/platform_io.h index 00a0a2dda6..fc16b47aed 100644 --- a/platform/posix/platform_io.h +++ b/platform/posix/platform_io.h @@ -23,18 +23,9 @@ #include -struct coap_packet_t { - coap_if_handle_t hnd; /**< the interface handle */ - coap_address_t src; /**< the packet's source address */ - coap_address_t dst; /**< the packet's destination address */ - const coap_endpoint_t *interface; - - int ifindex; - void *session; /**< opaque session data */ - - size_t length; /**< length of payload */ - unsigned char payload[]; /**< payload */ -}; +#include "address.h" +#define PLATFORM_ENDPOINT_PROPERTIES \ + int fd; #endif /* _PLATFORM_IO_H_ */ diff --git a/src/async.c b/src/async.c index 24da89309f..8c3a174865 100644 --- a/src/async.c +++ b/src/async.c @@ -3,10 +3,10 @@ * Copyright (C) 2010,2011 Olaf Bergmann * * This file is part of the CoAP library libcoap. Please see - * README for terms of use. + * README for terms of use. */ -/** +/** * @file async.c * @brief state management for asynchronous messages */ @@ -38,7 +38,7 @@ coap_register_async(coap_context_t *context, coap_address_t *peer, } /* store information for handling the asynchronous task */ - s = (coap_async_state_t *)coap_malloc(sizeof(coap_async_state_t) + + s = (coap_async_state_t *)coap_malloc(sizeof(coap_async_state_t) + request->hdr->token_length); if (!s) { coap_log(LOG_CRIT, "coap_register_async: insufficient memory\n"); @@ -60,7 +60,7 @@ coap_register_async(coap_context_t *context, coap_address_t *peer, s->tokenlen = request->hdr->token_length; memcpy(s->token, request->hdr->token, request->hdr->token_length); } - + memcpy(&s->id, &id, sizeof(coap_tid_t)); coap_touch_async(s); @@ -73,12 +73,12 @@ coap_register_async(coap_context_t *context, coap_address_t *peer, coap_async_state_t * coap_find_async(coap_context_t *context, coap_tid_t id) { coap_async_state_t *tmp; - LL_SEARCH_SCALAR(context->async_state,tmp,id,id); + LL_SEARCH_SCALAR(context->async_state,tmp,id,id); return tmp; } int -coap_remove_async(coap_context_t *context, coap_tid_t id, +coap_remove_async(coap_context_t *context, coap_tid_t id, coap_async_state_t **s) { coap_async_state_t *tmp = coap_find_async(context, id); @@ -89,11 +89,11 @@ coap_remove_async(coap_context_t *context, coap_tid_t id, return tmp != NULL; } -void +void coap_free_async(coap_async_state_t *s) { if (s && (s->flags & COAP_ASYNC_RELEASE_DATA) != 0) coap_free(s->appdata); - coap_free(s); + coap_free(s); } #else diff --git a/src/coap_context.c b/src/coap_context.c index eda8748471..b9bf0cbfca 100644 --- a/src/coap_context.c +++ b/src/coap_context.c @@ -32,11 +32,7 @@ #include "block.h" #include "net.h" #include "coap_timer.h" - -#ifdef WITH_CONTIKI // TODO Should be more abstracted. E.g. CONTEXT_SINGLETON -unsigned char initialized = 0; -coap_context_t the_coap_context; -#endif +#include "coap_io.h" #ifndef WITHOUT_OBSERVE static void notify_timer_cb(void *data) { @@ -64,46 +60,21 @@ static void retransmit_timer_cb(void *data) { } } -coap_context_t * -coap_new_context( - const coap_address_t *listen_addr) { - coap_timer_init(); -#ifndef WITH_CONTIKI - coap_context_t *c = coap_malloc_type(COAP_CONTEXT, sizeof( coap_context_t ) ); -#endif /* not WITH_CONTIKI */ -#ifdef WITH_CONTIKI - coap_context_t *c; - - if (initialized) - return NULL; -#endif /* WITH_CONTIKI */ - - if (!listen_addr) { - coap_log(LOG_EMERG, "no listen address specified\n"); - return NULL; - } +coap_context_t* +coap_new_context(void) { + //FIXME: move this to coap_platform_init()? + coap_timer_init(); coap_clock_init(); - coap_tick_t now; coap_ticks(&now); - prng_init((ptrdiff_t)listen_addr ^ now); + prng_init((ptrdiff_t)now); -#ifndef WITH_CONTIKI + coap_context_t *c = coap_malloc_type(COAP_CONTEXT, sizeof( coap_context_t ) ); if (!c) { -#ifndef NDEBUG coap_log(LOG_EMERG, "coap_init: malloc:\n"); -#endif return NULL; } -#endif /* not WITH_CONTIKI */ -#ifdef WITH_CONTIKI - coap_memory_init(); - - c = &the_coap_context; - initialized = 1; -#endif /* WITH_CONTIKI */ - memset(c, 0, sizeof( coap_context_t ) ); /* initialize message id */ @@ -122,13 +93,12 @@ coap_new_context( coap_register_option(c, COAP_OPTION_BLOCK2); coap_register_option(c, COAP_OPTION_BLOCK1); +#if 0 c->endpoint = coap_new_endpoint(listen_addr, COAP_ENDPOINT_NOSEC); if (c->endpoint == NULL) { goto onerror; } - - c->network_send = coap_network_send; - c->network_read = coap_network_read; +#endif # ifndef WITHOUT_OBSERVE c->notify_timer = coap_new_timer(notify_timer_cb, (void *)c); @@ -158,13 +128,6 @@ coap_free_context(coap_context_t *context) { #endif coap_delete_all_resources(context); - - coap_free_endpoint(context->endpoint); -#ifdef WITH_CONTIKI - memset(&the_coap_context, 0, sizeof(coap_context_t)); - initialized = 0; -#else coap_free_type(COAP_CONTEXT, context); -#endif /* WITH_CONTIKI */ } diff --git a/src/debug.c b/src/coap_debug.c similarity index 91% rename from src/debug.c rename to src/coap_debug.c index 5e1570e2a2..6aa54498b0 100644 --- a/src/debug.c +++ b/src/coap_debug.c @@ -3,10 +3,11 @@ * Copyright (C) 2010--2012,2014--2015 Olaf Bergmann * * This file is part of the CoAP library libcoap. Please see - * README for terms of use. + * README for terms of use. */ #include "coap_config.h" +#include "coap_io.h" #if defined(HAVE_STRNLEN) && defined(__GNUC__) && !defined(_GNU_SOURCE) #define _GNU_SOURCE 1 @@ -29,6 +30,7 @@ #include #endif +#include "coap_time.h" #include "block.h" #include "debug.h" #include "encode.h" @@ -41,7 +43,7 @@ #include "net/ip/uip-debug.h" #endif -static coap_log_t maxlog = LOG_WARNING; /* default maximum log level */ +static coap_log_t maxlog = LOG_DEBUG; /* default maximum log level */ const char *coap_package_name(void) { return PACKAGE_NAME; @@ -51,7 +53,7 @@ const char *coap_package_version(void) { return PACKAGE_STRING; } -coap_log_t +coap_log_t coap_get_log_level(void) { return maxlog; } @@ -63,7 +65,7 @@ coap_set_log_level(coap_log_t level) { /* this array has the same order as the type log_t */ static char *loglevels[] = { - "EMRG", "ALRT", "CRIT", "ERR", "WARN", "NOTE", "INFO", "DEBG" + "EMRG", "ALRT", "CRIT", "ERR", "WARN", "NOTE", "INFO", "DEBG" }; #ifdef HAVE_TIME_H @@ -81,7 +83,7 @@ print_timestamp(char *s, size_t len, coap_tick_t t) { static inline size_t print_timestamp(char *s, size_t len, coap_tick_t t) { #ifdef HAVE_SNPRINTF - return snprintf(s, len, "%u.%03u", + return snprintf(s, len, "%u.%03u", (unsigned int)coap_ticks_to_rt(t), (unsigned int)(t % COAP_TICKS_PER_SECOND)); #else /* HAVE_SNPRINTF */ @@ -95,12 +97,12 @@ print_timestamp(char *s, size_t len, coap_tick_t t) { #ifndef NDEBUG #ifndef HAVE_STRNLEN -/** - * A length-safe strlen() fake. - * +/** + * A length-safe strlen() fake. + * * @param s The string to count characters != 0. * @param maxlen The maximum length of @p s. - * + * * @return The length of @p s. */ static inline size_t @@ -149,10 +151,6 @@ print_readable( const unsigned char *data, unsigned int len, return cnt; } -#ifndef min -#define min(a,b) ((a) < (b) ? (a) : (b)) -#endif - size_t coap_print_addr(const struct coap_address_t *addr, unsigned char *buf, size_t len) { #ifdef HAVE_ARPA_INET_H @@ -161,7 +159,7 @@ coap_print_addr(const struct coap_address_t *addr, unsigned char *buf, size_t le unsigned char *p = buf; switch (addr->addr.sa.sa_family) { - case AF_INET: + case AF_INET: addrptr = &addr->addr.sin.sin_addr; port = ntohs(addr->addr.sin.sin_port); break; @@ -190,7 +188,7 @@ coap_print_addr(const struct coap_address_t *addr, unsigned char *buf, size_t le if (addr->addr.sa.sa_family == AF_INET6) { if (p < buf + len) { *p++ = ']'; - } else + } else return 0; } @@ -254,28 +252,6 @@ coap_print_addr(const struct coap_address_t *addr, unsigned char *buf, size_t le # endif /* HAVE_VPRINTF */ #endif /* WITH_CONTIKI */ -/** Returns a textual description of the message type @p t. */ -static const char * -msg_type_string(uint8_t t) { - static char *types[] = { "CON", "NON", "ACK", "RST", "???" }; - - return types[min(t, sizeof(types)/sizeof(char *) - 1)]; -} - -/** Returns a textual description of the method or response code. */ -static const char * -msg_code_string(uint8_t c) { - static char *methods[] = { "0.00", "GET", "POST", "PUT", "DELETE", "PATCH" }; - static char buf[5]; - - if (c < sizeof(methods)/sizeof(char *)) { - return methods[c]; - } else { - snprintf(buf, sizeof(buf), "%u.%02u", c >> 5, c & 0x1f); - return buf; - } -} - /** Returns a textual description of the option name. */ static const char * msg_option_string(uint16_t option_type) { @@ -449,7 +425,7 @@ coap_show_pdu(const coap_pdu_t *pdu) { } fprintf(COAP_DEBUG_FD, " ]"); - + if (coap_get_data((coap_pdu_t *)pdu, &data_len, &data)) { fprintf(COAP_DEBUG_FD, " :: "); @@ -474,8 +450,8 @@ coap_show_pdu(const coap_pdu_t *pdu) { #endif /* NDEBUG */ -void -coap_log_impl(coap_log_t level, const char *format, ...) { +void +coap_log_impl(const char *file, int line, coap_log_t level, const char *format, ...) { char timebuf[32]; coap_tick_t now; va_list ap; @@ -483,8 +459,9 @@ coap_log_impl(coap_log_t level, const char *format, ...) { if (maxlog < level) return; - - log_fd = level <= LOG_CRIT ? COAP_ERR_FD : COAP_DEBUG_FD; + + //log_fd = level <= LOG_CRIT ? COAP_ERR_FD : COAP_DEBUG_FD; + log_fd = stderr; coap_ticks(&now); if (print_timestamp(timebuf,sizeof(timebuf), now)) diff --git a/src/coap_io.c b/src/coap_io.c index e1d8c0202c..df0b78a20e 100644 --- a/src/coap_io.c +++ b/src/coap_io.c @@ -3,7 +3,7 @@ * Copyright (C) 2012,2014 Olaf Bergmann * * This file is part of the CoAP library libcoap. Please see - * README for terms of use. + * README for terms of use. */ #include "coap_config.h" @@ -15,14 +15,14 @@ #include "platform_io.h" size_t -coap_get_max_packetlength(const coap_packet_t *packet UNUSED_PARAM) { +coap_get_max_packetlength(const coap_packet_t *packet) { return COAP_MAX_PDU_SIZE; } void coap_packet_populate_endpoint(coap_packet_t *packet, coap_endpoint_t *target) { - target->handle = packet->interface->handle; + *target = *packet->interface; memcpy(&target->addr, &packet->dst, sizeof(target->addr)); target->ifindex = packet->ifindex; target->flags = 0; /* FIXME */ diff --git a/src/coap_list.c b/src/coap_list.c new file mode 100644 index 0000000000..6967281250 --- /dev/null +++ b/src/coap_list.c @@ -0,0 +1,51 @@ +/* coap_list.c -- CoAP list structures + * + * Copyright (C) 2010,2011,2015 Olaf Bergmann + * + * This file is part of the CoAP library libcoap. Please see + * README for terms of use. + */ + +/* #include "coap_config.h" */ + +#include +#include + +#include "debug.h" +#include "mem.h" +#include "coap_list.h" + + +int +coap_insert(coap_list_t **head, coap_list_t *node) { + if (!node) { + coap_log(LOG_WARNING, "cannot create option Proxy-Uri\n"); + } else { + /* must append at the list end to avoid re-ordering of + * options during sort */ + LL_APPEND((*head), node); + } + + return node != NULL; +} + +int +coap_delete(coap_list_t *node) { + if (node) { + coap_free(node); + } + return 1; +} + +void +coap_delete_list(coap_list_t *queue) { + coap_list_t *elt, *tmp; + + if (!queue) + return; + + LL_FOREACH_SAFE(queue, elt, tmp) { + coap_delete(elt); + } +} + diff --git a/src/net.c b/src/net.c index d658b3cbee..03827d59ee 100644 --- a/src/net.c +++ b/src/net.c @@ -11,9 +11,9 @@ #include #include #include -//#ifdef HAVE_LIMITS_H FIXME +#ifdef HAVE_LIMITS_H #include -//#endif +#endif #ifdef HAVE_UNISTD_H #include #elif HAVE_SYS_UNISTD_H @@ -109,16 +109,6 @@ /** creates a Qx.FRAC_BITS from COAP_DEFAULT_ACK_TIMEOUT */ #define ACK_TIMEOUT Q(FRAC_BITS, COAP_DEFAULT_ACK_TIMEOUT) -static inline coap_queue_t * -coap_malloc_node(void) { - return (coap_queue_t *)coap_malloc_type(COAP_NODE, sizeof(coap_queue_t)); -} - -static inline void -coap_free_node(coap_queue_t *node) { - coap_free_type(COAP_NODE, node); -} - unsigned int coap_adjust_basetime(coap_context_t *ctx, coap_tick_t now) { unsigned int result = 0; @@ -199,7 +189,7 @@ coap_delete_node(coap_queue_t *node) { return 0; coap_delete_pdu(node->pdu); - coap_free_node(node); + coap_free_type(COAP_NODE, node); return 1; } @@ -216,7 +206,7 @@ coap_delete_all(coap_queue_t *queue) { coap_queue_t * coap_new_node(void) { coap_queue_t *node; - node = coap_malloc_node(); + node = (coap_queue_t *) coap_malloc_type(COAP_NODE, sizeof(coap_queue_t)); if ( ! node ) { #ifndef NDEBUG @@ -255,12 +245,14 @@ coap_pop_next( coap_context_t *context ) { #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) \ - (memcmp((Key), COAP_DEFAULT_WKC_HASHKEY, sizeof(coap_key_t)) == 0) +static int +is_wkc(coap_key_t k) { + return (memcmp(k, COAP_DEFAULT_WKC_HASHKEY, sizeof(coap_key_t)) == 0); +} #else /* Implements a singleton to store a hash key for the .wellknown/core * resources. */ -int +static int is_wkc(coap_key_t k) { static coap_key_t wkc; static unsigned char _initialized = 0; @@ -326,11 +318,10 @@ coap_send_ack(coap_context_t *context, return result; } -static coap_tid_t -coap_send_impl(coap_context_t *context, - const coap_endpoint_t *local_interface, - const coap_address_t *dst, - coap_pdu_t *pdu) { +coap_tid_t +coap_send(coap_context_t *context, const coap_endpoint_t *local_interface, + const coap_address_t *dst, coap_pdu_t *pdu) { + ssize_t bytes_written; coap_tid_t id = COAP_INVALID_TID; @@ -344,8 +335,8 @@ coap_send_impl(coap_context_t *context, return COAP_DROPPED_RESPONSE; } - bytes_written = context->network_send(context, local_interface, dst, - (unsigned char *)pdu->hdr, pdu->length); + bytes_written = local_interface->network_send(context, local_interface, dst, + pdu); if (bytes_written >= 0) { coap_transaction_id(dst, pdu, &id); @@ -357,20 +348,10 @@ coap_send_impl(coap_context_t *context, } coap_tid_t -coap_send(coap_context_t *context, - const coap_endpoint_t *local_interface, - const coap_address_t *dst, - coap_pdu_t *pdu) { - return coap_send_impl(context, local_interface, dst, pdu); -} - -coap_tid_t -coap_send_error(coap_context_t *context, - coap_pdu_t *request, - const coap_endpoint_t *local_interface, - const coap_address_t *dst, - unsigned char code, - coap_opt_filter_t opts) { +coap_send_error(coap_context_t *context, coap_pdu_t *request, + const coap_endpoint_t *local_interface, + const coap_address_t *dst, unsigned char code, + coap_opt_filter_t opts) { coap_pdu_t *response; coap_tid_t result = COAP_INVALID_TID; @@ -457,10 +438,10 @@ coap_send_confirmed(coap_context_t *context, return COAP_INVALID_TID; } - node->id = coap_send_impl(context, local_interface, dst, pdu); + node->id = coap_send(context, local_interface, dst, pdu); if (COAP_INVALID_TID == node->id) { debug("coap_send_confirmed: error sending pdu\n"); - coap_free_node(node); + coap_free_type(COAP_NODE, node); return COAP_INVALID_TID; } @@ -502,7 +483,6 @@ coap_send_confirmed(coap_context_t *context, coap_tid_t coap_retransmit(coap_context_t *context, coap_queue_t *node) { - if (!context || !node) return COAP_INVALID_TID; @@ -519,9 +499,7 @@ coap_retransmit(coap_context_t *context, coap_queue_t *node) { debug("** retransmission #%d of transaction %d\n", node->retransmit_cnt, NTOHS(node->pdu->hdr->id)); - node->id = coap_send_impl(context, &node->local_if, - &node->remote, node->pdu); - + node->id = coap_send(context, &node->local_if, &node->remote, node->pdu); return node->id; } @@ -549,24 +527,20 @@ coap_retransmit(coap_context_t *context, coap_queue_t *node) { void coap_dispatch(coap_context_t *context, coap_queue_t *rcvd); int -coap_read( coap_context_t *ctx ) { +coap_read(coap_context_t *ctx, coap_endpoint_t *ep) { ssize_t bytes_read = -1; coap_packet_t *packet; - coap_address_t src; int result = -1; /* the value to be returned */ - coap_address_init(&src); - - bytes_read = ctx->network_read(ctx->endpoint, &packet); + bytes_read = ep->network_read(ep, &packet); - if ( bytes_read < 0 ) { - warn("coap_read: recvfrom"); + if (bytes_read < 0) { + //warn("coap_read: recvfrom"); } else { result = coap_handle_message(ctx, packet); + coap_free_packet(packet); } - coap_free_packet(packet); - return result; } @@ -604,7 +578,13 @@ coap_handle_message(coap_context_t *ctx, /* from this point, the result code indicates that */ result = RESULT_ERR; +#if defined(WITH_LWIP) + node->pdu = coap_pdu_from_pbuf(coap_packet_extract_pbuf(packet)); +#elif defined(ST_NODE) + node->pdu = coap_pdu_from_mbuf(coap_packet_extract_mbuf(packet)); +#else node->pdu = coap_pdu_init(0, 0, 0, msg_len); +#endif if (!node->pdu) { goto error; } diff --git a/src/option.c b/src/option.c index dd9d0cdbdc..02becaeb6a 100644 --- a/src/option.c +++ b/src/option.c @@ -4,18 +4,22 @@ * Copyright (C) 2010-2013 Olaf Bergmann * * This file is part of the CoAP library libcoap. Please see - * README for terms of use. + * README for terms of use. */ #include "coap_config.h" +#include +#include +#include #if defined(HAVE_ASSERT_H) && !defined(assert) # include #endif -#include -#include +#if defined(ST_NODE) +#include "mbuf.h" +#endif #include "option.h" #include "encode.h" /* for coap_fls() */ @@ -24,14 +28,14 @@ coap_opt_t * options_start(coap_pdu_t *pdu) { - if (pdu && pdu->hdr && - (pdu->hdr->token + pdu->hdr->token_length + 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; - - } else + + } else return NULL; } @@ -77,7 +81,7 @@ coap_opt_parse(const coap_opt_t *opt, size_t length, coap_option_t *result) { ADVANCE_OPT(opt,length,1); result->delta += *opt & 0xff; break; - + default: ; } @@ -97,7 +101,7 @@ coap_opt_parse(const coap_opt_t *opt, size_t length, coap_option_t *result) { ADVANCE_OPT(opt,length,1); result->length += *opt & 0xff; break; - + default: ; } @@ -119,10 +123,10 @@ coap_opt_parse(const coap_opt_t *opt, size_t length, coap_option_t *result) { coap_opt_iterator_t * coap_option_iterator_init(coap_pdu_t *pdu, coap_opt_iterator_t *oi, const coap_opt_filter_t filter) { - assert(pdu); + 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) @@ -147,7 +151,7 @@ static inline int opt_finished(coap_opt_iterator_t *oi) { assert(oi); - if (oi->bad || oi->length == 0 || + if (oi->bad || oi->length == 0 || !oi->next_option || *oi->next_option == COAP_PAYLOAD_START) { oi->bad = 1; } @@ -172,16 +176,16 @@ coap_option_next(coap_opt_iterator_t *oi) { * opt_finished() filters out any bad conditions, we can assume that * oi->option is valid. */ current_opt = oi->next_option; - + /* Advance internal pointer to next option, skipping any option that * is not included in oi->filter. */ optsize = coap_opt_parse(oi->next_option, oi->length, &option); if (optsize) { assert(optsize <= oi->length); - + oi->next_option += optsize; oi->length -= optsize; - + oi->type += option.delta; } else { /* current option is malformed */ oi->bad = 1; @@ -191,7 +195,7 @@ coap_option_next(coap_opt_iterator_t *oi) { /* Exit the while loop when: * - no filtering is done at all * - the filter matches for the current option - * - the filter is too small for the current option number + * - the filter is too small for the current option number */ if (!oi->filtered || (b = coap_option_getb(oi->filter, oi->type)) > 0) @@ -209,7 +213,7 @@ coap_opt_t * coap_check_option(coap_pdu_t *pdu, unsigned short type, coap_opt_iterator_t *oi) { coap_opt_filter_t f; - + coap_option_filter_clear(f); coap_option_setb(f, type); @@ -231,7 +235,7 @@ coap_opt_delta(const coap_opt_t *opt) { /* This case usually should not happen, hence we do not have a * proper way to indicate an error. */ return 0; - case 14: + case 14: /* Handle two-byte value: First, the MSB + 269 is stored as delta value. * After that, the option pointer is advanced to the LSB which is handled * just like case delta == 13. */ @@ -326,7 +330,7 @@ coap_opt_size(const coap_opt_t *opt) { } size_t -coap_opt_setheader(coap_opt_t *opt, size_t maxlen, +coap_opt_setheader(coap_opt_t *opt, size_t maxlen, unsigned short delta, size_t length) { size_t skip = 0; @@ -353,9 +357,9 @@ coap_opt_setheader(coap_opt_t *opt, size_t maxlen, opt[0] = 0xe0; opt[++skip] = ((delta - 269) >> 8) & 0xff; - opt[++skip] = (delta - 269) & 0xff; + opt[++skip] = (delta - 269) & 0xff; } - + if (length < 13) { opt[0] |= length & 0x0f; } else if (length < 270) { @@ -363,7 +367,7 @@ coap_opt_setheader(coap_opt_t *opt, size_t maxlen, debug("insufficient space to encode option length %zu", length); return 0; } - + opt[0] |= 0x0d; opt[++skip] = length - 13; } else { @@ -374,7 +378,7 @@ coap_opt_setheader(coap_opt_t *opt, size_t maxlen, opt[0] |= 0x0e; opt[++skip] = ((length - 269) >> 8) & 0xff; - opt[++skip] = (length - 269) & 0xff; + opt[++skip] = (length - 269) & 0xff; } return skip + 1; @@ -387,12 +391,12 @@ coap_opt_encode(coap_opt_t *opt, size_t maxlen, unsigned short delta, l = coap_opt_setheader(opt, maxlen, delta, length); assert(l <= maxlen); - + if (!l) { debug("coap_opt_encode: cannot set option header\n"); return 0; } - + maxlen -= l; opt += l; diff --git a/src/pdu.c b/src/pdu.c index 959d14e74b..4279806005 100644 --- a/src/pdu.c +++ b/src/pdu.c @@ -3,7 +3,7 @@ * Copyright (C) 2010--2014 Olaf Bergmann * * This file is part of the CoAP library libcoap. Please see - * README for terms of use. + * README for terms of use. */ #include "coap_config.h" @@ -27,24 +27,28 @@ #include "platform_utils.h" +#ifndef CUSTOM_COAP_PDU_HANDLING void coap_pdu_clear(coap_pdu_t *pdu, size_t size) { assert(pdu); pdu->max_delta = 0; + pdu->max_size = size; + pdu->length = sizeof(coap_hdr_t); + /* data is NULL unless explicitly set by coap_add_data() */ pdu->data = NULL; + memset(pdu->hdr, 0, size); pdu->max_size = size; pdu->hdr->version = COAP_DEFAULT_VERSION; - - /* data is NULL unless explicitly set by coap_add_data() */ - pdu->length = sizeof(coap_hdr_t); + pdu->hdr->token_length = 0; } coap_pdu_t * coap_pdu_init(unsigned char type, unsigned char code, unsigned short id, size_t size) { coap_pdu_t *pdu; + 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) @@ -52,19 +56,20 @@ coap_pdu_init(unsigned char type, unsigned char code, /* size must be large enough for hdr */ pdu = coap_malloc_type(COAP_PDU, sizeof(coap_pdu_t)); - if (!pdu) return NULL; + if (!pdu) + return NULL; + pdu->hdr = coap_malloc_type(COAP_PDU_BUF, size); - if (pdu->hdr == NULL) { + if (!pdu->hdr) { coap_free_type(COAP_PDU, pdu); - pdu = NULL; + return NULL; } - if (pdu) { - coap_pdu_clear(pdu, size); - pdu->hdr->id = id; - pdu->hdr->type = type; - pdu->hdr->code = code; - } + coap_pdu_clear(pdu, size); + pdu->hdr->id = id; + pdu->hdr->type = type; + pdu->hdr->code = code; + return pdu; } @@ -91,6 +96,8 @@ coap_delete_pdu(coap_pdu_t *pdu) { } } +#endif /* WITH_CUSTOM_PDU_HANDLING */ + int coap_add_token(coap_pdu_t *pdu, size_t len, const unsigned char *data) { const size_t HEADERLENGTH = len + 4; @@ -99,8 +106,9 @@ coap_add_token(coap_pdu_t *pdu, size_t len, const unsigned char *data) { return 0; pdu->hdr->token_length = len; - if (len) + if (len) { memcpy(pdu->hdr->token, data, len); + } pdu->max_delta = 0; pdu->length = HEADERLENGTH; pdu->data = NULL; @@ -315,6 +323,7 @@ coap_pdu_parse(unsigned char *data, size_t length, coap_pdu_t *pdu) { goto discard; } +#ifndef WITH_LWIP /* 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); @@ -322,9 +331,10 @@ coap_pdu_parse(unsigned char *data, size_t length, coap_pdu_t *pdu) { /* 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; - + /* Finally calculate beginning of data block and thereby check integrity * of the PDU structure. */ +#endif /* skip header + token */ length -= (pdu->hdr->token_length + sizeof(coap_hdr_t)); diff --git a/src/resource.c b/src/resource.c index 45b89676de..6bcc96f7cf 100644 --- a/src/resource.c +++ b/src/resource.c @@ -240,7 +240,12 @@ coap_resource_t * coap_resource_init(const unsigned char *uri, size_t len, int flags) { coap_resource_t *r; +#ifdef WITH_LWIP + r = (coap_resource_t *)memp_malloc(MEMP_COAP_RESOURCE); +#endif +#ifndef WITH_LWIP r = (coap_resource_t *)coap_malloc_type(COAP_RESOURCE, sizeof(coap_resource_t)); +#endif if (r) { memset(r, 0, sizeof(coap_resource_t)); @@ -316,6 +321,16 @@ coap_delete_attr(coap_attr_t *attr) { coap_free_type(COAP_RESOURCEATTR, attr); } +void +coap_set_user_data(coap_resource_t *resource, void *p) { + resource->pdata = p; +} + +void * +coap_get_user_data(coap_resource_t *resource) { + return resource->pdata; +} + void coap_hash_request_uri(const coap_pdu_t *request, coap_key_t key) { coap_opt_iterator_t opt_iter; @@ -335,6 +350,12 @@ coap_hash_request_uri(const coap_pdu_t *request, coap_key_t key) { void coap_add_resource(coap_context_t *context, coap_resource_t *resource) { RESOURCES_ADD(context->resources, resource); +// FIXME don't know what this dynamic stuff is, but it ain't working +// if (!resource->dynamic) { +// resource->uri.length = strlen(resource->uri.s); +// coap_hash_path(resource->uri.s, resource->uri.length, resource->key); +// } +// debug("Added resource 0x%02x%02x%02x%02x\n", resource->key[0], resource->key[1], resource->key[2], resource->key[3]); } static void @@ -345,15 +366,21 @@ coap_free_resource(coap_resource_t *resource) { assert(resource); /* delete registered attributes */ - LL_FOREACH_SAFE(resource->link_attr, attr, tmp) coap_delete_attr(attr); + LL_FOREACH_SAFE(resource->link_attr, attr, tmp) { + coap_delete_attr(attr); + } if (resource->flags & COAP_RESOURCE_FLAGS_RELEASE_URI) coap_free(resource->uri.s); /* free all elements from resource->subscribers */ - LL_FOREACH_SAFE(resource->subscribers, obs, otmp) coap_free_type(COAP_SUBSCRIPTION, obs); + LL_FOREACH_SAFE(resource->subscribers, obs, otmp) { + coap_free_type(COAP_SUBSCRIPTION, obs); + } - coap_free_type(COAP_RESOURCE, resource); + if (resource->dynamic) { + coap_free_type(COAP_RESOURCE, resource); + } } int @@ -396,6 +423,25 @@ coap_delete_all_resources(coap_context_t *context) { context->resources = NULL; } +void +coap_delete_resource_by_pattern(coap_context_t *context, const char *pattern) { + coap_resource_t *res; + coap_resource_t *rtmp; + +#ifdef COAP_RESOURCES_NOHASH + LL_FOREACH_SAFE(context->resources, res, rtmp) { +#else + HASH_ITER(hh, context->resources, res, rtmp) { +#endif + if (strstr((char *)res->uri.s, pattern)) { + /* remove resource from list */ + RESOURCES_DELETE(context->resources, res); + /* and free its allocated memory */ + coap_free_resource(res); + } + } +} + coap_resource_t * coap_get_resource_from_key(coap_context_t *context, coap_key_t key) { coap_resource_t *result; @@ -529,7 +575,6 @@ coap_delete_observer(coap_resource_t *resource, const coap_address_t *observer, if (resource->subscribers && s) { LL_DELETE(resource->subscribers, s); - coap_free_type(COAP_SUBSCRIPTION, s); } diff --git a/src/uri.c b/src/uri.c index ec6c57ee9a..119dae0800 100644 --- a/src/uri.c +++ b/src/uri.c @@ -3,7 +3,7 @@ * Copyright (C) 2010--2012,2015 Olaf Bergmann * * This file is part of the CoAP library libcoap. Please see - * README for terms of use. + * README for terms of use. */ #include "coap_config.h" @@ -22,22 +22,22 @@ #include "option.h" #include "uri.h" -/** +/** * A length-safe version of strchr(). This function returns a pointer * to the first occurrence of @p c in @p s, or @c NULL if not found. - * + * * @param s The string to search for @p c. * @param len The length of @p s. * @param c The character to search. - * - * @return A pointer to the first occurence of @p c, or @c NULL + * + * @return A pointer to the first occurence of @p c, or @c NULL * if not found. */ static inline unsigned char * strnchr(unsigned char *s, size_t len, unsigned char c) { while (len && *s++ != c) --len; - + return len ? s : NULL; } @@ -63,7 +63,7 @@ coap_split_uri(unsigned char *str_var, size_t len, coap_uri_t *uri) { while (len && *q && tolower(*p) == *q) { ++p; ++q; --len; } - + /* If q does not point to the string end marker '\0', the schema * identifier is wrong. */ if (*q) { @@ -90,7 +90,7 @@ coap_split_uri(unsigned char *str_var, size_t len, coap_uri_t *uri) { q = p; if (len && *p == '[') { /* IPv6 address reference */ ++p; - + while (len && *q != ']') { ++q; --len; } @@ -98,13 +98,13 @@ coap_split_uri(unsigned char *str_var, size_t len, coap_uri_t *uri) { if (!len || *q != ']' || p == q) { res = -3; goto error; - } + } COAP_SET_STR(&uri->host, q - p, p); ++q; --len; } else { /* IPv4 address or FQDN */ while (len && *q != ':' && *q != '/' && *q != '?') { - *q = tolower(*q); + //*q = tolower(*q); ++q; --len; } @@ -121,7 +121,7 @@ coap_split_uri(unsigned char *str_var, size_t len, coap_uri_t *uri) { if (len && *q == ':') { p = ++q; --len; - + while (len && isdigit(*q)) { ++q; --len; @@ -129,7 +129,7 @@ coap_split_uri(unsigned char *str_var, size_t len, coap_uri_t *uri) { if (p < q) { /* explicit port number given */ int uri_port = 0; - + while (p < q) uri_port = uri_port * 10 + (*p++ - '0'); @@ -140,14 +140,14 @@ coap_split_uri(unsigned char *str_var, size_t len, coap_uri_t *uri) { } uri->port = uri_port; - } + } } - + path: /* at this point, p must point to an absolute path */ if (!len) goto end; - + if (*q == '/') { p = ++q; --len; @@ -156,7 +156,7 @@ coap_split_uri(unsigned char *str_var, size_t len, coap_uri_t *uri) { ++q; --len; } - + if (p < q) { COAP_SET_STR(&uri->path, q - p, p); p = q; @@ -173,28 +173,28 @@ coap_split_uri(unsigned char *str_var, size_t len, coap_uri_t *uri) { end: return len ? -1 : 0; - + error: return res; } -/** +/** * Calculates decimal value from hexadecimal ASCII character given in * @p c. The caller must ensure that @p c actually represents a valid - * heaxdecimal character, e.g. with isxdigit(3). + * heaxdecimal character, e.g. with isxdigit(3). * * @hideinitializer */ #define hexchar_to_dec(c) ((c) & 0x40 ? ((c) & 0x0F) + 9 : ((c) & 0x0F)) -/** +/** * Decodes percent-encoded characters while copying the string @p seg * of size @p length to @p buf. The caller of this function must * ensure that the percent-encodings are correct (i.e. the character * '%' is always followed by two hex digits. and that @p buf provides * sufficient space to hold the result. This function is supposed to * be called by make_decoded_option() only. - * + * * @param seg The segment to decode and copy. * @param length Length of @p seg. * @param buf The result buffer. @@ -206,12 +206,12 @@ decode_segment(const unsigned char *seg, size_t length, unsigned char *buf) { if (*seg == '%') { *buf = (hexchar_to_dec(seg[1]) << 4) + hexchar_to_dec(seg[2]); - + seg += 2; length -= 2; } else { *buf = *seg; } - + ++buf; ++seg; } } @@ -230,18 +230,18 @@ check_segment(const unsigned char *s, size_t length) { if (*s == '%') { if (length < 2 || !(isxdigit(s[1]) && isxdigit(s[2]))) return -1; - + s += 2; length -= 2; } ++s; ++n; --length; } - + return n; } - -/** + +/** * Writes a coap option from given string @p s to @p buf. @p s should * point to a (percent-encoded) path or query segment of a coap_uri_t * object. The created option will have type @c 0, and the length @@ -249,19 +249,19 @@ check_segment(const unsigned char *s, size_t length) { * On success, this function returns the option's size, or a value * less than zero on error. This function must be called from * coap_split_path_impl() only. - * + * * @param s The string to decode. * @param length The size of the percent-encoded string @p s. * @param buf The buffer to store the new coap option. * @param buflen The maximum size of @p buf. - * + * * @return The option's size, or @c -1 on error. * * @bug This function does not split segments that are bigger than 270 * bytes. */ static int -make_decoded_option(const unsigned char *s, size_t length, +make_decoded_option(const unsigned char *s, size_t length, unsigned char *buf, size_t buflen) { int res; size_t written; @@ -311,15 +311,15 @@ dots(unsigned char *s, size_t len) { return *s == '.' && (len == 1 || (*(s+1) == '.' && len == 2)); } -/** +/** * Splits the given string into segments. You should call one of the * macros coap_split_path() or coap_split_query() instead. - * + * * @param s The URI string to be tokenized. * @param length The length of @p s. * @param h A handler that is called with every token. * @param data Opaque data that is passed to @p h when called. - * + * * @return The number of characters that have been parsed from @p s. */ static size_t @@ -371,7 +371,7 @@ write_option(unsigned char *s, size_t len, void *data) { } int -coap_split_path(const unsigned char *s, size_t length, +coap_split_path(const unsigned char *s, size_t length, unsigned char *buf, size_t *buflen) { struct cnt_str tmp = { { *buflen, buf }, 0 }; @@ -383,7 +383,7 @@ coap_split_path(const unsigned char *s, size_t length, } int -coap_split_query(const unsigned char *s, size_t length, +coap_split_query(const unsigned char *s, size_t length, unsigned char *buf, size_t *buflen) { struct cnt_str tmp = { { *buflen, buf }, 0 }; const unsigned char *p;