From f8d2b79d17ed0ae3e39796c8a5fc9e9e86ede37e Mon Sep 17 00:00:00 2001 From: franc0is Date: Sun, 6 Sep 2015 18:06:51 -0700 Subject: [PATCH] WIP - Factor out timer code into a timer module --- Makefile.am | 5 +- include/coap/coap_context.h | 10 +- include/coap/coap_timer.h | 187 +++++++++++++++++++++++++++++ platform/lwip/platform_io.c | 7 ++ platform/posix/platform_net.c | 2 + platform/posix/platform_timer.c | 27 +++++ src/coap_context.c | 22 ++-- src/net.c | 202 ++------------------------------ 8 files changed, 250 insertions(+), 212 deletions(-) create mode 100644 include/coap/coap_timer.h create mode 100644 platform/posix/platform_timer.c diff --git a/Makefile.am b/Makefile.am index e5a1cd1a29..7c6fefe293 100644 --- a/Makefile.am +++ b/Makefile.am @@ -65,7 +65,9 @@ libcoap_@LIBCOAP_API_VERSION@_la_SOURCES = \ src/uri.c \ platform/@PLATFORM@/platform_address.c \ platform/@PLATFORM@/platform_io.c \ - platform/@PLATFORM@/platform_time.c + platform/@PLATFORM@/platform_net.c \ + platform/@PLATFORM@/platform_time.c \ + platform/@PLATFORM@/platform_timer.c ## Define the list of public header files and their install location. ## The list defined here will be used within the include/Makefile.am @@ -81,6 +83,7 @@ libcoap_include_HEADERS = \ include/coap/coap_context.h \ include/coap/coap_io.h \ include/coap/coap_time.h \ + include/coap/coap_timer.h \ include/coap/debug.h \ include/coap/encode.h \ include/coap/hashkey.h \ diff --git a/include/coap/coap_context.h b/include/coap/coap_context.h index c8709f1969..4559da0e33 100644 --- a/include/coap/coap_context.h +++ b/include/coap/coap_context.h @@ -15,6 +15,7 @@ #include "pdu.h" #include "coap_time.h" +#include "coap_timer.h" typedef struct coap_queue_t { // TODO create coap_queue.h struct coap_queue_t *next; @@ -60,15 +61,10 @@ typedef struct coap_context_t { #ifdef WITH_CONTIKI struct uip_udp_conn *conn; /**< uIP connection object */ - struct etimer retransmit_timer; /**< fires when the next packet must be sent */ - struct etimer notify_timer; /**< used to check resources periodically */ #endif /* WITH_CONTIKI */ -#ifdef WITH_LWIP - uint8_t timer_configured; /**< Set to 1 when a retransmission is - * scheduled using lwIP timers for this - * context, otherwise 0. */ -#endif /* WITH_LWIP */ + coap_timer_t *retransmit_timer; /**< fires when the next packet must be sent */ + coap_timer_t *notify_timer; /**< used to check resources periodically */ /** * The last message id that was used is stored in this field. The initial diff --git a/include/coap/coap_timer.h b/include/coap/coap_timer.h new file mode 100644 index 0000000000..17dfdcd739 --- /dev/null +++ b/include/coap/coap_timer.h @@ -0,0 +1,187 @@ +#ifndef _COAP_TIMER_H_ +#define _COAP_TIMER_H_ + +#include "coap_time.h" + +struct coap_timer_t; +typedef struct coap_timer_t coap_timer_t; + +void coap_timer_init(void); + +typedef void (*CoapTimerCallback)(void *data); + +coap_timer_t *coap_new_timer(CoapTimerCallback cb, void *data); + +void coap_timer_set(coap_timer_t *timer, coap_tick_t num_ticks); + +void coap_timer_is_set(coap_timer_t *timer); + +void coap_timer_unset(coap_timer_t *timer); + +#endif /* _COAP_TIMER_H_ */ + +#if 0 + +#ifdef WITH_LWIP +#include +#endif + +#ifdef WITH_CONTIKI + +PROCESS(coap_retransmit_process, "message retransmit process"); + +#ifdef WITH_CONTIKI + { /* (re-)initialize retransmission timer */ + process_post(&coap_retransmit_process, PROCESS_EVENT_MSG, context); + } +#endif /* WITH_CONTIKI */ + +#ifdef WITH_LWIP + +#include + +static void coap_retransmittimer_execute(void *arg); +static void coap_retransmittimer_restart(coap_context_t *ctx); + +#endif /* WITH_LWIP */ + + + + +/*---------------------------------------------------------------------------*/ +/* CoAP message retransmission */ +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(coap_retransmit_process, ev, data) +{ + coap_tick_t now; + coap_queue_t *nextpdu; + coap_context_t *context = NULL; + + PROCESS_BEGIN(); + + debug("Started retransmit process\r\n"); + + while(1) { + PROCESS_YIELD(); + + if (ev == PROCESS_EVENT_MSG) { + context = data; + } else if (ev == PROCESS_EVENT_TIMER) { +#ifndef WITHOUT_OBSERVE + if (etimer_expired(&context->notify_timer)) { + coap_check_notify(context); + etimer_reset(context->notify_timer); + } + if (!etimer_expired(&context->retransmit_timer)) { + continue; + } +#endif /* WITHOUT_OBSERVE */ + assert(etimer_expired(&context->retransmit_timer)); + } else { + // Toss out events we're not interested in + continue; + } + + nextpdu = coap_peek_next(context); + + coap_ticks(&now); + while (nextpdu && nextpdu->t <= now) { + coap_retransmit(context, coap_pop_next(context)); + nextpdu = coap_peek_next(context); + } + + /* need to set timer to some value even if no nextpdu is available */ + etimer_set(&context->retransmit_timer, + nextpdu ? nextpdu->t - now : 0xFFFF); + } + + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ + +#endif /* WITH_CONTIKI */ + +#ifdef WITH_LWIP +/* 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; + } +} +#endif + +#endif diff --git a/platform/lwip/platform_io.c b/platform/lwip/platform_io.c index 3b2bca459a..b9da0f6f06 100644 --- a/platform/lwip/platform_io.c +++ b/platform/lwip/platform_io.c @@ -95,6 +95,13 @@ coap_free_endpoint(coap_endpoint_t *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, diff --git a/platform/posix/platform_net.c b/platform/posix/platform_net.c index e390ae9c59..30c67bc68a 100644 --- a/platform/posix/platform_net.c +++ b/platform/posix/platform_net.c @@ -1,5 +1,7 @@ #include "net.h" +#include + void coap_transaction_id(const coap_address_t *peer, const coap_pdu_t *pdu, coap_tid_t *id) { diff --git a/platform/posix/platform_timer.c b/platform/posix/platform_timer.c new file mode 100644 index 0000000000..f33a7cd8cd --- /dev/null +++ b/platform/posix/platform_timer.c @@ -0,0 +1,27 @@ +#include "coap_timer.h" + +struct coap_timer_t { + int time; +}; + +void coap_timer_init(void) { + +} + +coap_timer_t *coap_new_timer(CoapTimerCallback cb, void *data) { + return NULL; +} + +void coap_timer_set(coap_timer_t *timer, coap_tick_t num_ticks) { + return; +} + +void coap_timer_is_set(coap_timer_t *timer) { + return; +} + +void coap_timer_unset(coap_timer_t *timer) { + return; +} + + diff --git a/src/coap_context.c b/src/coap_context.c index fafc312837..bd4d9b8f55 100644 --- a/src/coap_context.c +++ b/src/coap_context.c @@ -22,10 +22,6 @@ #include #endif -#ifdef WITH_LWIP -#include -#endif - #include "debug.h" #include "mem.h" #include "str.h" @@ -35,6 +31,7 @@ #include "encode.h" #include "block.h" #include "net.h" +#include "coap_timer.h" #if defined(WITH_POSIX) @@ -127,22 +124,17 @@ coap_new_context( c->sockfd = c->endpoint->handle.fd; #endif /* WITH_POSIX */ -#if defined(WITH_POSIX) || defined(WITH_CONTIKI) c->network_send = coap_network_send; c->network_read = coap_network_read; -#endif /* WITH_POSIX or WITH_CONTIKI */ -#ifdef WITH_CONTIKI - 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); +# ifndef WITHOUT_OBSERVE + c->notify_timer = coap_new_timer(NULL, c); //FIXME + coap_timer_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); -#endif /* WITH_CONTIKI */ + c->retransmit_timer = coap_new_timer(NULL, c); //FIXME + coap_timer_set(c->retransmit_timer, 0xFFFF); return c; diff --git a/src/net.c b/src/net.c index 99d07fa442..a10ed8f9fc 100644 --- a/src/net.c +++ b/src/net.c @@ -30,10 +30,6 @@ #include #endif -#ifdef WITH_LWIP -#include -#endif - #include "debug.h" #include "mem.h" #include "str.h" @@ -113,15 +109,6 @@ /** creates a Qx.FRAC_BITS from COAP_DEFAULT_ACK_TIMEOUT */ #define ACK_TIMEOUT Q(FRAC_BITS, COAP_DEFAULT_ACK_TIMEOUT) -#ifdef WITH_LWIP - -#include - -static void coap_retransmittimer_execute(void *arg); -static void coap_retransmittimer_restart(coap_context_t *ctx); - -#endif /* WITH_LWIP */ - static inline coap_queue_t * coap_malloc_node(void) { return (coap_queue_t *)coap_malloc_type(COAP_NODE, sizeof(coap_queue_t)); @@ -132,20 +119,6 @@ coap_free_node(coap_queue_t *node) { coap_free_type(COAP_NODE, node); } -#ifdef WITH_CONTIKI -# ifndef DEBUG -# define DEBUG DEBUG_PRINT -# endif /* DEBUG */ - -#include "mem.h" -#include "net/ip/uip-debug.h" - -void coap_resources_init(); - -PROCESS(coap_retransmit_process, "message retransmit process"); - -#endif /* WITH_CONTIKI */ - unsigned int coap_adjust_basetime(coap_context_t *ctx, coap_tick_t now) { unsigned int result = 0; @@ -519,16 +492,10 @@ coap_send_confirmed(coap_context_t *context, coap_insert_node(&context->sendqueue, node); -#ifdef WITH_LWIP - if (node == context->sendqueue) /* don't bother with timer stuff if there are earlier retransmits */ - coap_retransmittimer_restart(context); -#endif - -#ifdef WITH_CONTIKI - { /* (re-)initialize retransmission timer */ - process_post(&coap_retransmit_process, PROCESS_EVENT_MSG, context); + /* Reschedule the retransmit timer if the head node is the new node */ + if (node == context->sendqueue) { + coap_timer_set(context->retransmit_timer, node->t); } -#endif /* WITH_CONTIKI */ return node->id; } @@ -543,24 +510,22 @@ coap_retransmit(coap_context_t *context, coap_queue_t *node) { node->retransmit_cnt++; node->t = node->timeout << node->retransmit_cnt; coap_insert_node(&context->sendqueue, node); -#ifdef WITH_LWIP - if (node == context->sendqueue) /* don't bother with timer stuff if there are earlier retransmits */ - coap_retransmittimer_restart(context); -#endif + + if (node == context->sendqueue) { + coap_timer_set(context->retransmit_timer, node->t); + } debug("** retransmission #%d of transaction %d\n", - node->retransmit_cnt, ntohs(node->pdu->hdr->id)); + node->retransmit_cnt, NTOHS(node->pdu->hdr->id)); node->id = coap_send_impl(context, &node->local_if, - &node->remote, node->pdu); + &node->remote, node->pdu); + return node->id; } /* no more retransmissions, remove node from system */ - -#ifndef WITH_CONTIKI - debug("** removed transaction %d\n", ntohs(node->id)); -#endif + debug("** removed transaction %d\n", NTOHS(node->id)); #ifndef WITHOUT_OBSERVE /* Check if subscriptions exist that should be canceled after @@ -591,16 +556,12 @@ coap_read( coap_context_t *ctx ) { coap_address_init(&src); -#if defined(WITH_POSIX) || defined(WITH_CONTIKI) bytes_read = ctx->network_read(ctx->endpoint, &packet); -#endif /* WITH_POSIX or WITH_CONTIKI */ if ( bytes_read < 0 ) { warn("coap_read: recvfrom"); } else { -#if defined(WITH_POSIX) || defined(WITH_CONTIKI) result = coap_handle_message(ctx, packet); -#endif /* WITH_POSIX or WITH_CONTIKI */ } coap_free_packet(packet); @@ -753,7 +714,7 @@ coap_cancel_all_messages(coap_context_t *context, const coap_address_t *dst, context->sendqueue->pdu->hdr->token_length)) { q = context->sendqueue; context->sendqueue = q->next; - debug("**** removed transaction %d\n", ntohs(q->pdu->hdr->id)); + debug("**** removed transaction %d\n", NTOHS(q->pdu->hdr->id)); coap_delete_node(q); } @@ -769,7 +730,7 @@ coap_cancel_all_messages(coap_context_t *context, const coap_address_t *dst, token_match(token, token_length, q->pdu->hdr->token, q->pdu->hdr->token_length)) { p->next = q->next; - debug("**** removed transaction %d\n", ntohs(q->pdu->hdr->id)); + debug("**** removed transaction %d\n", NTOHS(q->pdu->hdr->id)); coap_delete_node(q); q = p->next; } else { @@ -1393,140 +1354,3 @@ coap_can_exit( coap_context_t *context ) { return !context || (context->sendqueue == NULL); } -#ifdef WITH_CONTIKI - -/*---------------------------------------------------------------------------*/ -/* CoAP message retransmission */ -/*---------------------------------------------------------------------------*/ -PROCESS_THREAD(coap_retransmit_process, ev, data) -{ - coap_tick_t now; - coap_queue_t *nextpdu; - coap_context_t *context = NULL; - - PROCESS_BEGIN(); - - debug("Started retransmit process\r\n"); - - while(1) { - PROCESS_YIELD(); - - if (ev != PROCESS_EVENT_MSG && ev != PROCESS_EVENT_TIMER) { - // Toss out events we're not interested in - continue; - } - - if (ev == PROCESS_EVENT_MSG) { - context = data; -#ifndef WITHOUT_OBSERVE - } else if (etimer_expired(&context->notify_timer)) { - coap_check_notify(context); - etimer_reset(context->notify_timer); -#endif /* WITHOUT_OBSERVE */ - } - - if (ev == PROCESSS_EVENT_TIMER && !etimer_expired(&context->retransmit_timer)) { - continue; - } - - nextpdu = coap_peek_next(context); - - coap_ticks(&now); - while (nextpdu && nextpdu->t <= now) { - coap_retransmit(context, coap_pop_next(context)); - nextpdu = coap_peek_next(context); - } - - /* need to set timer to some value even if no nextpdu is available */ - etimer_set(&context->retransmit_timer, - nextpdu ? nextpdu->t - now : 0xFFFF); - } - - PROCESS_END(); -} -/*---------------------------------------------------------------------------*/ - -#endif /* WITH_CONTIKI */ - -#ifdef WITH_LWIP -/* 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; - } -} -#endif