blob: 24a998753db2828e70fbf6d8d4144638403daadd [file] [log] [blame]
/*
* Copyright (c) 2016 Intel Corporation
*
* Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* This file is part of the Contiki operating system.
*/
#include <string.h>
#include <stddef.h>
#include "os/mynewt.h"
#include "oic/port/mynewt/config.h"
#include "oic/messaging/coap/transactions.h"
#include "oic/messaging/coap/observe.h"
#include "oic/oc_buffer.h"
#ifdef OC_CLIENT
#include "oic/oc_client_state.h"
#endif /* OC_CLIENT */
#ifdef OC_SECURITY
#include "security/oc_dtls.h"
#endif
#include "port/mynewt/adaptor.h"
static struct os_mempool oc_transaction_memb;
static uint8_t oc_transaction_area[OS_MEMPOOL_BYTES(COAP_MAX_OPEN_TRANSACTIONS,
sizeof(coap_transaction_t))];
static SLIST_HEAD(, coap_transaction) oc_transaction_list;
static void coap_transaction_retrans(struct os_event *ev);
void
coap_transaction_init(void)
{
os_mempool_init(&oc_transaction_memb, COAP_MAX_OPEN_TRANSACTIONS,
sizeof(coap_transaction_t), oc_transaction_area, "coap_tran");
}
coap_transaction_t *
coap_new_transaction(uint16_t mid, oc_endpoint_t *endpoint)
{
coap_transaction_t *t;
struct os_mbuf *m;
t = os_memblock_get(&oc_transaction_memb);
if (t) {
m = oc_allocate_mbuf(endpoint);
if (m) {
t->mid = mid;
t->retrans_counter = 0;
t->m = m;
os_callout_init(&t->retrans_timer, oc_evq_get(),
coap_transaction_retrans, t);
/* list itself makes sure same element is not added twice */
SLIST_INSERT_HEAD(&oc_transaction_list, t, next);
} else {
os_memblock_put(&oc_transaction_memb, t);
t = NULL;
}
}
return t;
}
/*---------------------------------------------------------------------------*/
void
coap_send_transaction(coap_transaction_t *t)
{
bool confirmable = false;
confirmable = (COAP_TYPE_CON == t->type) ? true : false;
OC_LOG(DEBUG, "Sending transaction %u\n", t->mid);
if (confirmable) {
if (t->retrans_counter < COAP_MAX_RETRANSMIT) {
/* not timed out yet */
if (t->retrans_counter == 0) {
t->retrans_tmo =
COAP_RESPONSE_TIMEOUT_TICKS +
(oc_random_rand() %
(oc_clock_time_t)COAP_RESPONSE_TIMEOUT_BACKOFF_MASK);
OC_LOG(DEBUG, "Initial interval " OC_CLK_FMT "\n",
t->retrans_tmo);
} else {
t->retrans_tmo <<= 1; /* double */
OC_LOG(DEBUG, "Doubled " OC_CLK_FMT "\n", t->retrans_tmo);
}
os_callout_reset(&t->retrans_timer, t->retrans_tmo);
coap_send_message(t->m, 1);
t = NULL;
} else {
/* timed out */
OC_LOG(DEBUG, "Timeout\n");
#ifdef OC_SERVER
/* handle observers */
coap_remove_observer_by_client(OC_MBUF_ENDPOINT(t->m));
#endif /* OC_SERVER */
#ifdef OC_SECURITY
if (OC_MBUF_ENDPOINT(t->m)->flags & SECURED) {
oc_sec_dtls_close_init(OC_MBUF_ENDPOINT(t->m));
}
#endif /* OC_SECURITY */
#ifdef OC_CLIENT
oc_ri_remove_client_cb_by_mid(t->mid);
#endif /* OC_CLIENT */
coap_clear_transaction(t);
}
} else {
coap_send_message(t->m, 0);
t->m = NULL;
coap_clear_transaction(t);
}
}
/*---------------------------------------------------------------------------*/
void
coap_clear_transaction(coap_transaction_t *t)
{
struct coap_transaction *tmp;
if (t) {
os_callout_stop(&t->retrans_timer);
os_mbuf_free_chain(t->m);
/*
* Transaction might not be in the list yet.
*/
SLIST_FOREACH(tmp, &oc_transaction_list, next) {
if (t == tmp) {
SLIST_REMOVE(&oc_transaction_list, t, coap_transaction, next);
break;
}
}
os_memblock_put(&oc_transaction_memb, t);
}
}
coap_transaction_t *
coap_get_transaction_by_mid(uint16_t mid)
{
coap_transaction_t *t;
SLIST_FOREACH(t, &oc_transaction_list, next) {
if (t->mid == mid) {
return t;
}
}
return NULL;
}
static void
coap_transaction_retrans(struct os_event *ev)
{
coap_transaction_t *t = ev->ev_arg;
++(t->retrans_counter);
OC_LOG(DEBUG, "Retransmitting %u (%u)\n", t->mid, t->retrans_counter);
coap_send_transaction(t);
}