diff --git a/ChangeLog b/ChangeLog index 832aebcb..e3620571 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2014-03-09 Olaf Bergmann + + * net.c (coap_cancel): Removed 7.31 again and implemented new + method for cancelling observe relationships. + 2014-02-25 Olaf Bergmann * net.c (coap_cancel): Handling of 7.31 responses to cancel diff --git a/configure.in b/configure.in index edf763d5..987e4bb4 100644 --- a/configure.in +++ b/configure.in @@ -7,7 +7,7 @@ # README for terms of use. AC_PREREQ([2.65]) -AC_INIT([libcoap], [4.1.1]) +AC_INIT([libcoap], [4.1.2]) AC_CONFIG_SRCDIR([coap.h]) # First check for Contiki build to quit configure before any other test diff --git a/examples/client.c b/examples/client.c index bd75deba..bd6f9b5a 100644 --- a/examples/client.c +++ b/examples/client.c @@ -165,13 +165,14 @@ coap_new_request(coap_context_t *ctx, method_t m, coap_list_t *options ) { coap_tid_t clear_obs(coap_context_t *ctx, 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 */ - coap_log(LOG_INFO, "response code 7.31 is %d\n", COAP_RESPONSE_CODE(731)); - pdu = coap_pdu_init(msgtype, COAP_RESPONSE_CODE(731), + pdu = coap_pdu_init(msgtype, COAP_REQUEST_GET, coap_new_message_id(ctx), - sizeof(coap_hdr_t) + the_token.length); + COAP_MAX_PDU_SIZE); if (!pdu) { return tid; @@ -179,9 +180,44 @@ clear_obs(coap_context_t *ctx, const coap_address_t *remote) { if (!coap_add_token(pdu, the_token.length, the_token.s)) { coap_log(LOG_CRIT, "cannot add token"); - coap_delete_pdu(pdu); - return tid; + 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)) { + coap_log(LOG_CRIT, "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) @@ -196,6 +232,10 @@ clear_obs(coap_context_t *ctx, const coap_address_t *remote) { coap_delete_pdu(pdu); return tid; + error: + + coap_delete_pdu(pdu); + return tid; } int diff --git a/examples/server.c b/examples/server.c index 1442f3eb..fd42ef6d 100644 --- a/examples/server.c +++ b/examples/server.c @@ -83,7 +83,6 @@ hnd_get_time(coap_context_t *ctx, struct coap_resource_t *resource, size_t len; time_t now; coap_tick_t t; - coap_subscription_t *subscription; /* FIXME: return time, e.g. in human-readable by default and ticks * when query ?ticks is given. */ @@ -92,19 +91,12 @@ hnd_get_time(coap_context_t *ctx, struct coap_resource_t *resource, response->hdr->code = my_clock_base ? COAP_RESPONSE_CODE(205) : COAP_RESPONSE_CODE(404); - if (request != NULL && - coap_check_option(request, COAP_OPTION_OBSERVE, &opt_iter)) { - subscription = coap_add_observer(resource, peer, token); - if (subscription) { - subscription->non = request->hdr->type == COAP_MESSAGE_NON; - coap_add_option(response, COAP_OPTION_OBSERVE, 0, NULL); - } - } - if (resource->dirty == 1) + if (coap_find_observer(resource, peer, token)) { + /* FIXME: need to check for resource->dirty? */ coap_add_option(response, COAP_OPTION_OBSERVE, coap_encode_var_bytes(buf, ctx->observe), buf); + } - if (my_clock_base) coap_add_option(response, COAP_OPTION_CONTENT_FORMAT, coap_encode_var_bytes(buf, COAP_MEDIATYPE_TEXT_PLAIN), buf); diff --git a/net.c b/net.c index d267b6ed..cd00e35b 100644 --- a/net.c +++ b/net.c @@ -1399,10 +1399,40 @@ handle_request(coap_context_t *context, coap_queue_t *node) { if (coap_add_token(response, node->pdu->hdr->token_length, node->pdu->hdr->token)) { str token = { node->pdu->hdr->token_length, node->pdu->hdr->token }; + coap_opt_iterator_t opt_iter; + coap_opt_t *observe = NULL; + int observe_action = COAP_OBSERVE_CANCEL; + + /* check for Observe option */ + if (resource->observable) { + observe = coap_check_option(node->pdu, COAP_OPTION_OBSERVE, &opt_iter); + if (observe) { + observe_action = + coap_decode_var_bytes(coap_opt_value(observe), + coap_opt_length(observe)); + + if ((observe_action & COAP_OBSERVE_CANCEL) == 0) { + coap_subscription_t *subscription; + + coap_log(LOG_DEBUG, "create new subscription\n"); + subscription = coap_add_observer(resource, &node->remote, &token); + if (subscription) { + subscription->non = node->pdu->hdr->type == COAP_MESSAGE_NON; + coap_touch_observer(context, &node->remote, &token); + } + } + } + } h(context, resource, &node->remote, node->pdu, &token, response); + if (observe && ((COAP_RESPONSE_CLASS(response->hdr->code) > 2) + || ((observe_action & COAP_OBSERVE_CANCEL) != 0))) { + coap_log(LOG_DEBUG, "removed observer"); + coap_delete_observer(resource, &node->remote, &token); + } + /* If original request contained a token, and the registered * application handler made no changes to the response, then * this is an empty ACK with a token, which is a malformed @@ -1446,23 +1476,15 @@ static inline void handle_response(coap_context_t *context, coap_queue_t *sent, coap_queue_t *rcvd) { - /* First acknowledge incoming response if it is a CON message. Note - * that the necessary checks are done in coap_send_ack(). */ - if (rcvd->pdu->hdr->code == COAP_RESPONSE_CODE(731)) { - if (!coap_cancel(context, rcvd)) { - coap_send_rst(context, &rcvd->remote, rcvd->pdu); - } else { - coap_send_ack(context, &rcvd->remote, rcvd->pdu); - } - } else { - /* In a lossy context, the ACK of a separate response may have - * been lost, so we need to stop retransmitting requests with the - * same token. - */ - coap_cancel_all_messages(context, &rcvd->remote, - rcvd->pdu->hdr->token, - rcvd->pdu->hdr->token_length); - } + coap_send_ack(context, &rcvd->remote, rcvd->pdu); + + /* In a lossy context, the ACK of a separate response may have + * been lost, so we need to stop retransmitting requests with the + * same token. + */ + coap_cancel_all_messages(context, &rcvd->remote, + rcvd->pdu->hdr->token, + rcvd->pdu->hdr->token_length); /* Call application-specific reponse handler when available. */ if (context->response_handler) { diff --git a/resource.c b/resource.c index 1d9cf34c..23484ab1 100644 --- a/resource.c +++ b/resource.c @@ -737,6 +737,9 @@ coap_notify_observers(coap_context_t *context, coap_resource_t *r) { /* fill with observer-specific data */ h(context, r, &obs->subscriber, NULL, &token, response); + /* TODO: do not send response and remove observer when + * COAP_RESPONSE_CLASS(response->hdr->code) > 2 + */ if (response->hdr->type == COAP_MESSAGE_CON) { tid = coap_send_confirmed(context, &obs->subscriber, response); obs->non_cnt = 0; diff --git a/subscribe.h b/subscribe.h index 7eda74ff..0d2b7f7c 100644 --- a/subscribe.h +++ b/subscribe.h @@ -19,6 +19,18 @@ * @{ */ +/** + * The value COAP_OBSERVE_ESTABLISH in a GET request indicates + * a new observe relationship for (sender address, token) is requested. + */ +#define COAP_OBSERVE_ESTABLISH 0 + +/** + * The value COAP_OBSERVE_CANCEL in a GET request indicates that the + * observe relationship for (sender address, token) must be cancelled. + */ +#define COAP_OBSERVE_CANCEL 1 + #ifndef COAP_OBS_MAX_NON /** * Number of notifications that may be sent non-confirmable before a