RANDOM_DIR = $(ROOT_DIR)/ocrandom
STACK_DIR = $(ROOT_DIR)/stack
OCMALLOC_DIR = $(ROOT_DIR)/ocmalloc
-INC_DIRS = -I$(OCSOCK_DIR)/include/ -I$(LOGGER_DIR)/include -I$(RANDOM_DIR)/include -I$(OCMALLOC_DIR)/include -I$(OC_LOG_DIR)/include
+INC_DIRS = -I$(OCSOCK_DIR)/include/ -I$(LOGGER_DIR)/include -I$(RANDOM_DIR)/include \
+ -I$(OCMALLOC_DIR)/include -I$(OC_LOG_DIR)/include
# Note for Arduino: The CC flag is set to the C++ compiler since Arduino build
# includes Time.h header file which has C++ style definitions.
CC_FLAGS.release := -Os -Wall -ffunction-sections -fdata-sections -fno-exceptions
SOURCES+= pdu.c net.c debug.c encode.c uri.c coap_list.c hashkey.c \
- str.c option.c async.c subscribe.c block.c logger.c ocrandom.c ocmalloc.c oc_logger.c oc_console_logger.c
-VPATH += $(OCSOCK_DIR)/src:$(LOGGER_DIR)/src:$(RANDOM_DIR)/src:$(OCMALLOC_DIR)/src:$(OC_LOG_DIR)/c
+ str.c option.c async.c subscribe.c block.c logger.c ocrandom.c ocmalloc.c \
+ oc_logger.c oc_console_logger.c
+VPATH += $(OCSOCK_DIR)/src:$(LOGGER_DIR)/src:$(RANDOM_DIR)/src:$(OCMALLOC_DIR)/src\
+ :$(OC_LOG_DIR)/c
+
+ifeq ($(PLATFORM),linux)
+ifneq ($(wildcard $(ROOT_DIR)/tinydtls/libtinydtls.a),)
+ $(info "Building libcoap with DTLS support")
+ SOURCES += netdtls.c
+ VPATH += sec
+ TINYDTLS_DIR = $(ROOT_DIR)/tinydtls
+ NETDTLS_DIR = sec
+ INC_DIRS += -I$(TINYDTLS_DIR) -I$(NETDTLS_DIR) -I.
+ CC_FLAGS.debug += -DWITH_DTLS
+ CC_FLAGS.release += -DWITH_DTLS
+endif
+endif
OBJECTS:= $(patsubst %.c, %.o, $(SOURCES))
#include <ocsocket.h>
#include <logger.h>
+#if defined(WITH_DTLS)
+#include "netdtls.h"
+#endif /* WITH_DTLS */
#define MOD_NAME ("net.c")
coap_free( c);
return NULL;
}
- else {
- return c;
+
+#if defined(WITH_DTLS)
+ if (coap_dtls_init(c) != 0) {
+ coap_free( c);
+ return NULL;
}
+#else
+ /* set dtls socket file descriptor to uninitialize value */
+ c->sockfd_dtls = -1;
+#endif /* WITH_DTLS */
+ return c;
#endif /* WITH_POSIX || WITH_ARDUINO */
#ifdef WITH_CONTIKI
if (context->sockfd_wellknown != -1) {
OCClose( context->sockfd_wellknown );
}
+#if defined(WITH_DTLS)
+ coap_dtls_deinit( context );
+#endif /* WITH_DTLS */
coap_free( context );
#endif
#ifdef WITH_LWIP
response = coap_pdu_init(COAP_MESSAGE_ACK, 0, request->hdr->id,
sizeof(coap_pdu_t));
if (response) {
- result = coap_send(context, dst, response, flag);
+ result = coap_send(context, dst, response, flag, NULL);
coap_delete_pdu(response);
}
}
response = coap_new_error_response(request, code, opts);
if (response) {
- result = coap_send(context, dst, response, flag);
+ result = coap_send(context, dst, response, flag, NULL);
coap_delete_pdu(response);
}
if (request) {
response = coap_pdu_init(type, 0, request->hdr->id, sizeof(coap_pdu_t));
if (response) {
- result = coap_send(context, dst, response, flag);
+ result = coap_send(context, dst, response, flag, NULL);
coap_delete_pdu(response);
}
}
}
coap_tid_t coap_send(coap_context_t *context,
- const coap_address_t *dst, coap_pdu_t *pdu, coap_send_flags_t flag)
+ const coap_address_t *dst, coap_pdu_t *pdu, coap_send_flags_t flag,
+ uint8_t *cache_flag)
{
coap_queue_t *node = NULL;
coap_tick_t now;
return tid;
sending:
+ OC_LOG_V(DEBUG, MOD_NAME, PCF("sending 0x%x"), flag);
+#if defined(WITH_DTLS)
+ // A secure packet is first encrypted by DTLS library and then send
+ // over the network.
+ if (flag & SEND_SECURE_PORT) {
+ bytesWritten = coap_dtls_encrypt(context, (OCDevAddr*)dst,
+ pdu, &node, tid, cache_flag);
+ } else {
+ bytesWritten = coap_send_impl(context, dst, pdu);
+ }
+#else
bytesWritten = coap_send_impl(context, dst, pdu);
- if(bytesWritten > 0)
- {
+#endif /* WITH_DTLS */
+ if(bytesWritten > 0) {
return tid;
}
debug("coap_send_impl: error sending pdu\n");
debug("** retransmission #%d of transaction %d\n", node->retransmit_cnt,
ntohs(node->pdu->hdr->id));
flag = (coap_send_flags_t)(SEND_RETX | (node->secure ? SEND_SECURE_PORT : 0));
- tid = coap_send(context, (coap_address_t *)&(node->remote),node->pdu, flag);
+ tid = coap_send(context, (coap_address_t *)&(node->remote),node->pdu, flag, NULL);
return (tid == COAP_INVALID_TID)? COAP_INVALID_TID : node->id;
}
#if defined(WITH_LWIP) || defined(WITH_CONTIKI)
char *buf;
#endif
+ char *pbuf = buf;
coap_hdr_t *pdu;
int bytes_read = -1;
unsigned char delayRes = 0;
#ifdef WITH_CONTIKI
- buf = uip_appdata;
+ pbuf = uip_appdata;
#endif /* WITH_CONTIKI */
#ifdef WITH_LWIP
LWIP_ASSERT("No package pending", ctx->pending_package != NULL);
LWIP_ASSERT("Can only deal with contiguous PBUFs to read the initial details", ctx->pending_package->tot_len == ctx->pending_package->len);
- buf = ctx->pending_package->payload;
+ pbuf = ctx->pending_package->payload;
#endif /* WITH_LWIP */
- pdu = (coap_hdr_t *) buf;
-
coap_address_init(&src);
#if defined(WITH_POSIX) || defined(WITH_ARDUINO)
-
- bytes_read = OCRecvFrom( sockfd, (uint8_t*)buf, sizeof(buf), 0,
+ bytes_read = OCRecvFrom( sockfd, (uint8_t*)pbuf, sizeof(buf), 0,
(OCDevAddr*)&src);
// Set the delayed response flag for responding to multicast requests
if (sockfd == ctx->sockfd_wellknown && bytes_read > 0) {
delayRes = 1;
}
+#if defined(WITH_DTLS)
+ // Perform the DTLS decryption if packet is coming on secure port
+ if (sockfd == ctx->sockfd_dtls && bytes_read > 0) {
+ if (coap_dtls_decrypt(ctx, (OCDevAddr*)&src, (uint8_t*)pbuf, bytes_read,
+ (uint8_t**)&pbuf, &bytes_read) < 0) {
+ bytes_read = -1;
+ }
+ }
+#endif /* WITH_DTLS */
+ pdu = (coap_hdr_t *) pbuf;
#endif /* WITH_POSIX || WITH_ARDUINO */
#ifdef WITH_CONTIKI
if(uip_newdata()) {
#endif /* WITH_LWIP */
if (bytes_read < 0) {
- warn("coap_read: recvfrom");
+ warn("coap_read: recvfrom\n");
goto error_early;
}
memcpy(&node->local, &dst, sizeof(coap_address_t));
memcpy(&node->remote, &src, sizeof(coap_address_t));
- if (!coap_pdu_parse((unsigned char *) buf, bytes_read, node->pdu)) {
+ if (!coap_pdu_parse((unsigned char *) pbuf, bytes_read, node->pdu)) {
warn("discard malformed PDU");
goto error;
}
//set the delayed response flag
node->delayedResponse = delayRes;
+ //set the secure flag on the received packet
+#if defined(WITH_DTLS)
+ node->secure = (sockfd == ctx->sockfd_dtls) ? 1 : 0;
+#else
+ node->secure = 0;
+#endif /* WITH_DTLS */
+
/* and add new node to receive queue */
coap_transaction_id(&node->remote, node->pdu, &node->id);
coap_insert_node(&ctx->recvqueue, node);
else {
coap_send_flags_t flag = SEND_NOW;
flag = (coap_send_flags_t)(flag | rcvd->secure ? SEND_SECURE_PORT : 0);
- if (coap_send(context, &rcvd->remote, response, flag)
+ if (coap_send(context, &rcvd->remote, response, flag, NULL)
== COAP_INVALID_TID) {
warn("coap_dispatch: error sending reponse\n");
}
SEND_NOW_CON = (1 << 1), /*Flag used when sending confirmable coap pdu*/
SEND_DELAYED = (1 << 2), /*Flag used to delay the transmission of coap pdu*/
SEND_RETX = (1 << 3), /*Flag used to retransmit a confirmable pdu*/
- SEND_SECURE_PORT = (1 << 4) /*Flag used to indicate that PDU needs to be transmitted on secure port */
+ SEND_SECURE_PORT = (1 << 4) /*Flag used to indicate that PDU needs to
+ be transmitted on secure port */
} coap_send_flags_t;
struct coap_queue_t;
struct coap_async_state_t;
#endif
+struct coap_dtls_context_t;
+
/** Message handler for requests that is used as call-back in coap_context_t */
typedef void (*coap_request_handler_t)(struct coap_context_t *,
const coap_queue_t * rcvd);
#if defined(WITH_POSIX) || defined(WITH_ARDUINO)
int sockfd; /**< send/receive socket */
int sockfd_wellknown; /**< well-known discovery socket */
+ int sockfd_dtls; /**< secure communication happens on this socket */
+ /** dtls interface */
+ struct coap_dtls_context_t *coap_dtls_ctx;
#endif /* WITH_POSIX || WITH_ARDUINO */
#ifdef WITH_CONTIKI
struct uip_udp_conn *conn; /**< uIP connection object */
* Sends a CoAP message to given destination. The memory
* that is allocated by pdu will be released by coap_send().
*
- * @param context The CoAP context to use.
- * @param dst The address to send to.
- * @param pdu The CoAP PDU to send.
- * @param flag The flag indicating how the message will be send
+ * @param context The CoAP context to use.
+ * @param dst The address to send to.
+ * @param pdu The CoAP PDU to send.
+ * @param flag The flag indicating how the message will be send
+ * @param cache_flag When DTLS library determines that a secure session does
+ * not exist with the peer yet, it caches the 'pdu pointer'
+ * so that it can be sent later and 'coap_send' sets this
+ * variable to TRUE to instruct the caller of this method
+ * to not delete the 'pdu'.
* @return The message id of the sent message or @c COAP_INVALID_TID on error.
*/
-
coap_tid_t coap_send(coap_context_t *context, const coap_address_t *dst,
coap_pdu_t *pdu,
- coap_send_flags_t flag);
+ coap_send_flags_t flags,
+ uint8_t *cache_flag);
/**
* Sends an error response with code @p code for request @p request to
--- /dev/null
+//******************************************************************
+//
+// Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+#include "netdtls.h"
+#include "dtls.h"
+#include "alert.h"
+#include "debug.h"
+#include "logger.h"
+#include "mem.h"
+
+#define MOD_NAME ("netdtls.c")
+
+#define get_dtls_ctx(coap_ctx) (coap_ctx->coap_dtls_ctx->dtls_ctx)
+
+
+/**
+ * An internal method to invoke tinyDTLS library 'dtls_write' method.
+ * Return value from this method will indicate if data was successfully sent
+ * to peer OR a new DTLS handshake session was invoked OR some error happened
+ * while processing.
+ *
+ */
+static dtls_ret coap_dtls_encrypt_internal(coap_context_t *ctx, OCDevAddr* dst,
+ uint8_t *pt, uint16_t ptLen) {
+ int ret;
+ if (ptLen == 0)
+ return DTLS_OK;
+
+ ret = dtls_write(get_dtls_ctx(ctx), (session_t*)dst, pt, ptLen);
+ if (ret == 0) {
+ // A new DTLS session was initiated by tinyDTLS library
+ return DTLS_SESSION_INITIATED;
+ }
+
+ if (ret == ptLen) {
+ // tinyDTLS library successfully encrypted the data and
+ // sent it to the peer.
+ return DTLS_OK;
+ }
+
+ return DTLS_FAIL;
+}
+
+/**
+ * An internal method to invoke tinyDTLS library 'dtls_handle_message' method
+ * to decrypt packet received on secure port.
+ * Return value from this method will indicate if a valid application pdu was
+ * decypted OR a DTLS handshake message was received OR some error happened
+ * while processing.
+ *
+ */
+static dtls_ret coap_dtls_decrypt_internal(coap_context_t *ctx, OCDevAddr* src,
+ uint8_t* ct, int ctLen, uint8_t** pt, int* ptLen) {
+ dtls_ret ret = DTLS_FAIL;
+ pt_info_t ptinfo;
+
+ ptinfo.pt =NULL;
+ ptinfo.ptlen = 0;
+ ctx->coap_dtls_ctx->pt_info = &ptinfo;
+
+ if (dtls_handle_message(get_dtls_ctx(ctx), (session_t*)src, ct, ctLen) == 0) {
+ ret = DTLS_HS_MSG;
+ if (ptinfo.pt && ptinfo.ptlen) {
+ *pt = ptinfo.pt;
+ *ptLen = ptinfo.ptlen;
+ ret = DTLS_OK;
+ }
+ }
+ return ret;
+}
+
+
+/**
+ * If tinyDTLS library starts a new DTLS handshake session with a peer, the pdu
+ * which was requested by application to encrypt will need to be cached until
+ * DTLS session is established. This method caches the pdu in cachedqueue.
+ *
+ */
+static int coap_cache_pdu(coap_context_t *ctx,
+ coap_queue_t* existing_node,
+ OCDevAddr *dst,
+ coap_pdu_t *pdu,
+ coap_tid_t tid)
+{
+ coap_queue_t *node;
+ coap_tick_t now;
+
+ if (!ctx)
+ return -1;
+ /* Create a new node for caching the PDU in cachedqueue until
+ * DTLS session is established with peer.
+ */
+ node = coap_new_node();
+ if (!node) {
+ OC_LOG(DEBUG, MOD_NAME, PCF("Unable to allocate memory"));
+ return -1;
+ }
+
+ memcpy(&node->remote, dst, sizeof(coap_address_t));
+ node->pdu = pdu;
+ node->id = tid;
+ node->secure = 1;
+
+ coap_ticks(&now);
+ node->t = now + (COAP_DEFAULT_RESPONSE_TIMEOUT *2) * COAP_TICKS_PER_SECOND;
+
+ if (existing_node) {
+ node->timeout = existing_node->timeout;
+ node->delayedResponse = existing_node->delayedResponse;
+ }
+
+ // Add the node in cachedqueue list
+ // TODO : Do we need to add some limits on how many packets can be cached ?
+ if (ctx->coap_dtls_ctx->cachedqueue) {
+ coap_queue_t *p = ctx->coap_dtls_ctx->cachedqueue;
+ while(p->next != NULL) {
+ p = p->next;
+ }
+ p->next = node;
+ } else {
+ ctx->coap_dtls_ctx->cachedqueue = node;
+ }
+
+ return 0;
+}
+
+/**
+ * Once a DTLS session is established and cached pdu is send, this pdu needs to
+ * be saved in 'sendqueue' if this is a CON pdu for re-transmission purposes.
+ *
+ */
+static void save_cached_con_pdu(coap_context_t *ctx,
+ coap_queue_t *node)
+{
+ coap_tick_t now;
+
+ coap_ticks(&now);
+ if (ctx->sendqueue == NULL)
+ {
+ node->t = node->timeout;
+ ctx->sendqueue_basetime = now;
+ }
+ else
+ {
+ /* make node->t relative to context->sendqueue_basetime */
+ node->t = (now - ctx->sendqueue_basetime) + node->timeout;
+ }
+
+ node->delayedResponse = 0;
+ node->next = NULL;
+ coap_insert_node(&ctx->sendqueue, node);
+}
+
+/**
+ * Once a DTLS session is established, this method is invoked to retrieve any
+ * pdu's available in cachedqueue to be sent to the peer.
+ *
+ */
+static coap_queue_t* get_cached_pdu( coap_context_t *ctx,
+ const coap_address_t *dst)
+{
+ coap_queue_t *node, *prev;
+
+ node = ctx->coap_dtls_ctx->cachedqueue;
+ prev = NULL;
+ while(node) {
+ if (coap_address_equals(dst, &node->remote)) {
+ //disconnect the node from cachedqueue
+ if (node == ctx->coap_dtls_ctx->cachedqueue)
+ ctx->coap_dtls_ctx->cachedqueue = node->next;
+ else if (node->next == NULL)
+ prev->next = NULL;
+ else
+ prev->next = node->next;
+
+ node->next = NULL;
+ return node;
+ }
+ prev = node;
+ node = node->next;
+ }
+ return NULL;
+}
+
+/**
+ * Once a DTLS session is established, this method takes care of sending
+ * pdu's available in cachedqueue to the peer.
+ *
+ */
+static void coap_send_cached_pdu( coap_context_t *ctx,
+ const coap_address_t *dst )
+{
+ coap_queue_t *node;
+
+ if (!ctx)
+ return ;
+
+ for (;node=get_cached_pdu(ctx, dst);) {
+ OC_LOG(DEBUG, MOD_NAME, PCF("Sending cached PDU"));
+ OC_LOG_BUFFER(DEBUG, MOD_NAME, (uint8_t*)node->pdu->hdr, node->pdu->length);
+ // Send this PDU to DTLS library for encryption
+ dtls_ret ret = coap_dtls_encrypt_internal(ctx, (OCDevAddr*)dst,
+ (uint8_t*)node->pdu->hdr, node->pdu->length);
+ if (ret == DTLS_OK) {
+ OC_LOG(DEBUG, MOD_NAME, PCF("coap_send_cached_pdu: successully send cached pdu"));
+ } else {
+ OC_LOG(DEBUG, MOD_NAME, PCF("coap_send_cached_pdu: sending cached pdu failed."));
+ //TODO Notify application that packet send failed.
+ }
+
+ /* Add cache node in sendqueue if it is CON pdu,
+ * as it may be needed for retransmission
+ * else, delete it
+ */
+ if (node->pdu->hdr->type == COAP_MESSAGE_CON) {
+ save_cached_con_pdu(ctx, node);
+ } else {
+ coap_delete_node(node);
+ }
+ }
+}
+
+
+/**
+ * This is the tinyDTLS 'read' callback.
+ * It is invoked by tinyDTLS to provide the decrypted pdu.
+ *
+ */
+static int read_decrypted_payload(dtls_context_t *dtls_ctx,
+ session_t *session,
+ uint8_t *buf,
+ size_t len )
+{
+ if (!dtls_ctx)
+ return -1;
+
+ coap_dtls_context_t* coap_dtls_ctx =
+ ((coap_context_t*)dtls_get_app_data(dtls_ctx))->coap_dtls_ctx;
+
+ if (coap_dtls_ctx && coap_dtls_ctx->pt_info) {
+ coap_dtls_ctx->pt_info->pt = buf;
+ coap_dtls_ctx->pt_info->ptlen = len;
+ return len;
+ }
+
+ return -1;
+}
+
+/**
+ * This is the tinyDTLS 'write' callback.
+ * It is invoked by tinyDTLS to send encrypted data or handshake message to peer.
+ *
+ */
+static int send_secure_data(dtls_context_t *dtls_ctx,
+ session_t *session,
+ uint8_t* buf,
+ size_t buflen)
+{
+ if (!dtls_ctx)
+ return -1;
+
+ return OCSendTo( ((coap_context_t*)dtls_get_app_data(dtls_ctx))->sockfd_dtls,
+ buf, buflen, 0, (OCDevAddr*)session);
+}
+
+
+/**
+ * This is the tinyDTLS 'event' callback.
+ * It is invoked by tinyDTLS to notify any DTLS events or alerts.
+ *
+ */
+static int handle_secure_event(dtls_context_t *dtls_ctx,
+ session_t *session,
+ dtls_alert_level_t level,
+ unsigned short code)
+{
+ if (!dtls_ctx)
+ return -1;
+
+ OC_LOG_V(DEBUG, MOD_NAME, "level %d, code %u", level, code);
+
+ //Notify stack of any errors/connection state changes to upper layer
+ //application
+ if (!level && (code == DTLS_EVENT_CONNECTED))
+ {
+ coap_send_cached_pdu( (coap_context_t*)dtls_get_app_data(dtls_ctx),
+ (coap_address_t*)session);
+ }
+ return 0;
+}
+
+/**
+ * This is the tinyDTLS 'get_psk_info' callback.
+ * It is invoked by tinyDTLS to retrieve identity/credentials.
+ * This is currently a test version using stationary keys.
+ *
+ */
+static int get_psk_credentials(dtls_context_t *ctx,
+ const session_t *session,
+ dtls_credentials_type_t type,
+ const unsigned char *desc, size_t descLen,
+ unsigned char *result, size_t resultLen)
+{
+
+#define RS_IDENTITY ("1111111111111111")
+#define CLIENT_IDENTITY ("2222222222222222")
+#define RS_CLIENT_PSK ("AAAAAAAAAAAAAAAA")
+
+ if (type == DTLS_PSK_HINT)
+ {
+ if (sizeof(RS_IDENTITY) < resultLen)
+ {
+ memcpy(result, RS_IDENTITY, sizeof(RS_IDENTITY));
+ return sizeof(RS_IDENTITY);
+ }
+ }
+ else if (type == DTLS_PSK_IDENTITY)
+ {
+ if (sizeof(CLIENT_IDENTITY) < resultLen)
+ {
+ memcpy(result, CLIENT_IDENTITY, sizeof(CLIENT_IDENTITY));
+ return sizeof(CLIENT_IDENTITY);
+ }
+ }
+ else if (type == DTLS_PSK_KEY && (desc))
+ {
+ if (descLen == sizeof(RS_IDENTITY) &&
+ !memcmp(desc, RS_IDENTITY, descLen))
+ {
+ memcpy(result, RS_CLIENT_PSK, sizeof(RS_CLIENT_PSK));
+ return sizeof(RS_CLIENT_PSK);
+ }
+ if (descLen == sizeof(CLIENT_IDENTITY) &&
+ !memcmp(desc, CLIENT_IDENTITY, descLen))
+ {
+ memcpy(result, RS_CLIENT_PSK, sizeof(RS_CLIENT_PSK));
+ return sizeof(RS_CLIENT_PSK);
+ }
+ }
+
+ return -1;
+}
+
+
+/**
+ * Open secure port and initialize tinyDTLS library.
+ *
+ * @param ctx - handle to global coap_context_t.
+ *
+ * @return A value less than zero on error, greater or
+ * equal otherwise.
+ */
+int coap_dtls_init(coap_context_t *ctx) {
+
+ int ret = -1;
+ coap_dtls_context_t *coap_dtls_ctx = NULL;
+ OCDevAddr dev_addr;
+
+ if (!ctx)
+ goto exit;
+
+ coap_dtls_ctx =
+ (coap_dtls_context_t*)coap_malloc(sizeof(coap_dtls_context_t));
+
+ if (!coap_dtls_ctx)
+ goto exit;
+ memset(coap_dtls_ctx, 0, sizeof(coap_dtls_ctx));
+ ctx->sockfd_dtls = -1;
+
+ //TODO : Initialize secure socket descriptor
+ OCBuildIPv4Address(0, 0, 0, 0, COAP_DTLS_DEFAULT_PORT, &dev_addr);
+ if (OCInitUDP((OCDevAddr *)&dev_addr, (int32_t *)&(ctx->sockfd_dtls)) != ERR_SUCCESS) {
+ OCBuildIPv4Address(0, 0, 0, 0, 5685, &dev_addr);
+ if (OCInitUDP((OCDevAddr *)&dev_addr, (int32_t *)&(ctx->sockfd_dtls)) != ERR_SUCCESS) {
+ goto exit;
+ }
+ }
+
+ // Initialize clock, crypto and other global vars in tinyDTLS library
+ dtls_init();
+
+ coap_dtls_ctx->dtls_ctx = dtls_new_context(ctx);
+ if (!coap_dtls_ctx->dtls_ctx)
+ goto exit;
+
+ coap_dtls_ctx->callbacks.write = send_secure_data;
+ coap_dtls_ctx->callbacks.read = read_decrypted_payload;
+ coap_dtls_ctx->callbacks.event = handle_secure_event;
+ coap_dtls_ctx->callbacks.get_psk_info = get_psk_credentials;
+
+ dtls_set_handler(coap_dtls_ctx->dtls_ctx, &(coap_dtls_ctx->callbacks));
+ ctx->coap_dtls_ctx = coap_dtls_ctx;
+ ret = 0;
+
+exit:
+ if (ret == -1 && coap_dtls_ctx) {
+ coap_dtls_deinit(ctx);
+ }
+ return ret;
+}
+
+
+/**
+ * Closes secure port and de-inits tinyDTLS library.
+ *
+ * @param ctx - handle to global coap_context_t.
+ *
+ */
+void coap_dtls_deinit(coap_context_t *ctx) {
+ if (!ctx)
+ return;
+
+ coap_dtls_context_t *coap_dtls_ctx = ctx->coap_dtls_ctx;
+
+ if (coap_dtls_ctx) {
+ coap_delete_all(coap_dtls_ctx->cachedqueue);
+ if (ctx->sockfd_dtls != -1)
+ OCClose(ctx->sockfd_dtls);
+ dtls_free_context(coap_dtls_ctx->dtls_ctx);
+ coap_free(coap_dtls_ctx);
+ }
+ ctx->coap_dtls_ctx = NULL;
+}
+
+
+/**
+ * Performs DTLS encryption of the CoAP PDU. If a
+ * DTLS session does not exist yet with the @dst,
+ * a DTLS handshake will be started. In case where
+ * a new DTLS handshake is started, pdu info is
+ * cached to be send when session setup is finished.
+ *
+ * @param ctx - handle to global coap_context_t.
+ * @param dst - address of the receiver of the pdu.
+ * @param pdu - pointer to CoAP pdu.
+ * @param node - address of the node holding pdu.
+ * @param tid - tid of the pdu.
+ * @param cached - output variable to indicate if pdu
+ * is cached and inform the caller to
+ * NOT free the memory holding pdu.
+ *
+ * @return A value less than zero on error, greater or
+ * equal otherwise.
+ */
+int coap_dtls_encrypt(coap_context_t *ctx,
+ OCDevAddr *dst,
+ coap_pdu_t *pdu,
+ coap_queue_t **node,
+ coap_tid_t tid,
+ uint8_t *cache_flag) {
+ OC_LOG(DEBUG, MOD_NAME, PCF("coap_dtls_encrypt"));
+
+ if (!dst || !pdu)
+ return -1;
+
+ dtls_ret ret = coap_dtls_encrypt_internal( ctx, dst,
+ (uint8_t*)pdu->hdr, pdu->length);
+
+ if (ret == DTLS_SESSION_INITIATED) {
+ OC_LOG(DEBUG, MOD_NAME, PCF("Initiated new DTLS session"));
+ if (cache_flag && coap_cache_pdu(ctx, *node, dst, pdu, tid) == 0) {
+ /* Delete the node from sendqueue list as it has been
+ * added in cachedqueue list. It will be added
+ * again in sendqueue list when DTLS session is established
+ */
+ if (*node) {
+ coap_queue_t* removed_node = NULL;
+ coap_remove_from_queue(&(ctx->sendqueue),
+ (*node)->id, &removed_node);
+ if (removed_node == *node) {
+ coap_free(*node);
+ *node = NULL;
+ OC_LOG(DEBUG, MOD_NAME, PCF("coap_dtls_encrypt -- Removed correct node"));
+ }
+ }
+ *cache_flag = 1;
+ }
+ return pdu->length;
+ }
+
+ if (ret == DTLS_OK) {
+ OC_LOG(DEBUG, MOD_NAME, PCF("Encrypted App PDU and send to peer"));
+ return pdu->length;
+ }
+ return -1;
+}
+
+
+/**
+ * Performs DTLS decryption of the CoAP PDU received on
+ * secure port. This method performs in-place decryption
+ * of the cipher-text buffer. If a DTLS handshake message
+ * is received or decryption failure happens, this method
+ * returns -1. If a valid CoAP pdu is received, it returns the
+ * length of the decrypted pdu.
+ *
+ * @param ctx - handle to global coap_context_t.
+ * @param src - address of the sender of the pdu.
+ * @param ct - pointer to the cipher text buffer.
+ * @param ctlen - length of the ciphertext buffer.
+ * @param pt - output variable to store the starting address
+ * of decrypted plaintext.
+ * @param ptlen - output variable to store the length of
+ * decrypted plaintext.
+ *
+ * @return A value less than zero on error, greater or
+ * equal otherwise.
+ */
+int coap_dtls_decrypt(coap_context_t *ctx,
+ OCDevAddr* src,
+ uint8_t* ct,
+ int ctlen,
+ uint8_t** pt,
+ int* ptlen) {
+ OC_LOG(DEBUG, MOD_NAME, PCF("coap_dtls_decrypt"));
+
+ if (!src || !ct || !pt || !ptlen)
+ return -1;
+
+ dtls_ret ret = coap_dtls_decrypt_internal(ctx, src, ct, ctlen,
+ pt, ptlen);
+
+ if (ret == DTLS_OK)
+ return *ptlen;
+
+ if (ret == DTLS_HS_MSG)
+ OC_LOG(DEBUG, MOD_NAME, PCF("coap_dtls_decrypt : Handshake msg recvd "));
+ if (ret == DTLS_FAIL)
+ OC_LOG(DEBUG, MOD_NAME, PCF("coap_dtls_decrypt : Decryption failure "));
+
+ return -1;
+}
--- /dev/null
+//******************************************************************
+//
+// Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+#ifndef _NET_DTLS_H
+#define _NET_DTLS_H
+
+#include "net.h"
+#include "address.h"
+#include "pdu.h"
+#include "dtls.h"
+
+#define COAP_DTLS_DEFAULT_PORT 5684
+
+/**
+ * Data structure for holding the tinyDTLS interface
+ * related info.
+ */
+typedef struct coap_dtls_context_t {
+ coap_queue_t *cachedqueue; /**< pdu's are cached until DTLS session is formed */
+ struct dtls_context_t *dtls_ctx; /**< pointer to tinyDTLS context */
+ struct pt_info_t *pt_info; /**< used by callback during
+ decryption to hold address/length */
+ dtls_handler_t callbacks; /**< pointer to callbacks needed by tinyDTLS */
+}coap_dtls_context_t;
+
+/**
+ * Data structure for holding the decrypted data address
+ * and length provided by tinyDTLS callback interface.
+ */
+typedef struct pt_info_t {
+ uint8_t *pt;
+ uint16_t ptlen;
+}pt_info_t;
+
+/**
+ * Declares DTLS errors and return values. Currently used internally only.
+ */
+typedef enum
+{
+ DTLS_OK = 0,
+ DTLS_FAIL,
+ DTLS_SESSION_INITIATED,
+ DTLS_HS_MSG
+} dtls_ret;
+
+/**
+ * Open secure port and initialize tinyDTLS library.
+ *
+ * @param ctx - handle to global coap_context_t.
+ *
+ * @return A value less than zero on error, greater or
+ * equal otherwise.
+ */
+int coap_dtls_init(coap_context_t *ctx);
+
+/**
+ * Closes secure port and de-inits tinyDTLS library.
+ *
+ * @param ctx - handle to global coap_context_t.
+ *
+ */
+void coap_dtls_deinit(coap_context_t *ctx);
+
+/**
+ * Performs DTLS encryption of the CoAP PDU. If a
+ * DTLS session does not exist yet with the @dst,
+ * a DTLS handshake will be started. In case where
+ * a new DTLS handshake is started, pdu info is
+ * cached to be send when session setup is finished.
+ *
+ * @param ctx - handle to global coap_context_t.
+ * @param dst - address of the receiver of the pdu.
+ * @param pdu - pointer to CoAP pdu.
+ * @param node - address of the node holding pdu.
+ * @param tid - tid of the pdu.
+ * @param cache_flag - output variable to indicate if pdu
+ * is cached and inform the caller to
+ * NOT free the memory holding pdu.
+ *
+ * @return A value less than zero on error, greater or
+ * equal otherwise.
+ */
+int coap_dtls_encrypt(coap_context_t *ctx,
+ OCDevAddr* dst,
+ coap_pdu_t *pdu,
+ coap_queue_t **node,
+ coap_tid_t tid,
+ uint8_t *cache_flag);
+
+/**
+ * Performs DTLS decryption of the CoAP PDU received on
+ * secure port. This method performs in-place decryption
+ * of the cipher-text buffer. If a DTLS handshake message
+ * is received or decryption failure happens, this method
+ * returns -1. If a valid application PDU is decrypted, it
+ * returns the length of the decrypted pdu.
+ *
+ * @param ctx - handle to global coap_context_t.
+ * @param src - address of the sender of the pdu.
+ * @param ct - pointer to the cipher text buffer.
+ * @param ctlen - length of the ciphertext buffer.
+ * @param pt - output variable to store the starting address
+ * of decrypted plaintext.
+ * @param ptlen - output variable to store the length of
+ * decrypted plaintext.
+ *
+ * @return A value less than zero on error, greater or
+ * equal otherwise.
+ */
+int coap_dtls_decrypt(coap_context_t *ctx,
+ OCDevAddr* src,
+ uint8_t* ct,
+ int ctlen,
+ uint8_t** pt,
+ int* ptlen);
+
+#endif //_NET_DTLS_H
+
/* There might be an additional 's', indicating the secure version: */
if (len && (secure = tolower(*p) == 's')) {
++p; --len;
+ uri->secure = 1;
}
q = (unsigned char *)"://";
/* p points to beginning of Uri-Host */
q = p;
- if (len && *p == '[') { /* IPv6 address reference */
+ if (len && *p == '[') { /* IPv6 address reference */
++p;
while (len && *q != ']') {
COAP_SET_STR(&uri->host, q - p, p);
++q; --len;
- } else { /* IPv4 address or FQDN */
+ } else { /* IPv4 address or FQDN */
while (len && *q != ':' && *q != '/' && *q != '?') {
*q = tolower(*q);
++q;
--len;
}
- if (p < q) { /* explicit port number given */
+ if (p < q) { /* explicit port number given */
int uri_port = 0;
while (p < q)
- uri_port = uri_port * 10 + (*p++ - '0');
+ uri_port = uri_port * 10 + (*p++ - '0');
uri->port = uri_port;
}
}
- path: /* at this point, p must point to an absolute path */
+ path: /* at this point, p must point to an absolute path */
if (!len)
goto end;
while (length) {
if (*s == '%') {
if (length < 2 || !(isxdigit(s[1]) && isxdigit(s[2])))
- return -1;
+ return -1;
s += 2;
length -= 2;
*/
int
make_decoded_option(const unsigned char *s, size_t length,
- unsigned char *buf, size_t buflen) {
+ unsigned char *buf, size_t buflen) {
int res;
size_t written;
assert(written <= buflen);
- if (!written) /* encoding error */
+ if (!written) /* encoding error */
return -1;
- buf += written; /* advance past option type/length */
+ buf += written; /* advance past option type/length */
buflen -= written;
if (buflen < (size_t)res) {
*/
size_t
coap_split_path_impl(coap_parse_iterator_t *parse_iter,
- segment_handler_t h, void *data) {
+ segment_handler_t h, void *data) {
unsigned char *seg;
size_t length;
int
coap_split_path(const unsigned char *s, size_t length,
- unsigned char *buf, size_t *buflen) {
+ unsigned char *buf, size_t *buflen) {
struct cnt_str tmp = { { *buflen, buf }, 0 };
coap_parse_iterator_t pi;
coap_parse_iterator_init((unsigned char *)s, length,
- '/', (unsigned char *)"?#", 2, &pi);
+ '/', (unsigned char *)"?#", 2, &pi);
coap_split_path_impl(&pi, write_option, &tmp);
*buflen = *buflen - tmp.buf.length;
int
coap_split_query(const unsigned char *s, size_t length,
- unsigned char *buf, size_t *buflen) {
+ unsigned char *buf, size_t *buflen) {
struct cnt_str tmp = { { *buflen, buf }, 0 };
coap_parse_iterator_t pi;
coap_parse_iterator_init((unsigned char *)s, length,
- '&', (unsigned char *)"#", 1, &pi);
+ '&', (unsigned char *)"#", 1, &pi);
coap_split_path_impl(&pi, write_option, &tmp);
return NULL;
result = (coap_uri_t *)coap_malloc( uri->query.length + uri->host.length +
- uri->path.length + sizeof(coap_uri_t) + 1);
+ uri->path.length + sizeof(coap_uri_t) + 1);
if ( !result )
return NULL;
memset(key, 0, sizeof(coap_key_t));
coap_parse_iterator_init((unsigned char *)path, len,
- '/', (unsigned char *)"?#", 2, &pi);
+ '/', (unsigned char *)"?#", 2, &pi);
coap_split_path_impl(&pi, hash_segment, key);
return 1;
coap_parse_iterator_t *
coap_parse_iterator_init(unsigned char *s, size_t n,
- unsigned char separator,
- unsigned char *delim, size_t dlen,
- coap_parse_iterator_t *pi) {
+ unsigned char separator,
+ unsigned char *delim, size_t dlen,
+ coap_parse_iterator_t *pi) {
assert(pi);
assert(separator);
p = pi->pos;
while (pi->segment_length < pi->n && *p != pi->separator &&
- !strnchr(pi->delim, pi->dlen, *p)) {
+ !strnchr(pi->delim, pi->dlen, *p)) {
++p;
++pi->segment_length;
}
* Copyright (C) 2010,2011 Olaf Bergmann <bergmann@tzi.org>
*
* This file is part of the CoAP library libcoap. Please see
- * README for terms of use.
+ * README for terms of use.
*/
#ifndef _COAP_URI_H_
* string with coap_split_uri() and can be used as input for
* option-creation functions. */
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.
- Use coap_split_path() to create Uri-Path options */
- str query; /**< The query part if present */
+ str host; /**< host part of the URI */
+ unsigned short port; /**< The port in host byte order */
+ str path; /**< Beginning of the first path segment.
+ Use coap_split_path() to create Uri-Path options */
+ str query; /**< The query part if present */
+ unsigned char secure; /**< uses coaps URI schema */
} coap_uri_t;
/**
* 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);
* @{
*/
-/**
+/**
* Iterator to for tokenizing a URI path or query. This structure must
* be initialized with coap_parse_iterator_init(). Call
* coap_parse_next() to walk through the tokens.
* @endcode
*/
typedef struct {
- size_t n; /**< number of remaining characters in buffer */
- unsigned char separator; /**< segment separators */
- unsigned char *delim; /**< delimiters where to split the string */
- size_t dlen; /**< length of separator */
- unsigned char *pos; /**< current position in buffer */
- size_t segment_length; /**< length of current segment */
+ size_t n; /**< number of remaining characters in buffer */
+ unsigned char separator; /**< segment separators */
+ unsigned char *delim; /**< delimiters where to split the string */
+ size_t dlen; /**< length of separator */
+ unsigned char *pos; /**< current position in buffer */
+ size_t segment_length; /**< length of current segment */
} coap_parse_iterator_t;
-/**
- * Initializes the given iterator @p pi.
- *
+/**
+ * Initializes the given iterator @p pi.
+ *
* @param s The string to tokenize.
* @param n The length of @p s.
* @param separator The separator character that delimits tokens.
* @param delim A set of characters that delimit @s.
* @param dlen The length of @p delim.
* @param pi The iterator object to initialize.
- *
+ *
* @return The initialized iterator object @p pi.
*/
coap_parse_iterator_t *
-coap_parse_iterator_init(unsigned char *s, size_t n,
- unsigned char separator,
- unsigned char *delim, size_t dlen,
- coap_parse_iterator_t *pi);
+coap_parse_iterator_init(unsigned char *s, size_t n,
+ unsigned char separator,
+ unsigned char *delim, size_t dlen,
+ coap_parse_iterator_t *pi);
-/**
+/**
* Updates the iterator @p pi to point to the next token. This
* function returns a pointer to that token or @c NULL if no more
* tokens exist. The contents of @p pi will be updated. In particular,
* @c pi->segment_length specifies the length of the current token, @c
* pi->pos points to its beginning.
- *
+ *
* @param pi The iterator to update.
- *
+ *
* @return The next token or @c NULL if no more tokens exist.
*/
unsigned char *coap_parse_next(coap_parse_iterator_t *pi);
-/**
+/**
* 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.
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,
- unsigned char *buf, size_t *buflen);
+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,
- unsigned char *buf, size_t *buflen);
+int coap_split_query(const unsigned char *s, size_t length,
+ unsigned char *buf, size_t *buflen);
/** @} */
OCMALLOC_DIR = ocmalloc
EXTLIBS_DIR = ../../extlibs
CJSON_DIR = $(EXTLIBS_DIR)/cjson
+TINYDTLS_DIR = tinydtls
OCCOAP_SRC = $(OCCOAP_DIR)/src
OCTBSTACK_SRC = $(OCTBSTACK_DIR)/src
@cd $(OBJ_DIR) && $(AR) -x $(PLATFORM_SPECIFIC_BACKOUT)$(LCOAP_DIR)/$(PLATFORM)$(ARDUINO_SHIELD_TYPE)/$(BUILD)/libcoap.a
# Repackage all the objects at this location into a single archive. This is OCStack, OCCoap, and LibCoap (LibCoap contains OCRandom, OCLogger, and OCSocket.).
$(AR) -r $(OUT_DIR)/$@ $(OBJ_DIR)/*.o
+
+ ifeq ($(PLATFORM),linux)
+ ifneq ($(wildcard $(TINYDTLS_DIR)/libtinydtls.a),)
+ $(info "Building liboctbstack with DTLS support")
+ mkdir -p $(OBJ_DIR)/$(TINYDTLS_DIR)
+ @cd $(OBJ_DIR)/$(TINYDTLS_DIR) && $(AR) -x ../$(PLATFORM_SPECIFIC_BACKOUT)$(TINYDTLS_DIR)/libtinydtls.a
+ $(AR) -q $(OUT_DIR)/$@ $(OBJ_DIR)/$(TINYDTLS_DIR)/*.o
+ endif
+ endif
.PHONY: clean print_vars
// Internal function to create OCRequest struct at the server from a received coap pdu
OCStackResult FormOCRequest(OCRequest * * requestLoc, OCQualityOfService qos,
unsigned char * uriBuf, OCObserveReq * observeReq,
- OCEntityHandlerRequest * entityHandlerRequest);
+ OCEntityHandlerRequest * entityHandlerRequest,
+ uint8_t secure);
// Internal function to create OCEntityHandlerRequest at the server from a received coap pdu
OCStackResult FormOCEntityHandlerRequest(OCEntityHandlerRequest * entityHandlerRequestLoc,
// fill OCRequest structure
result = FormOCRequest(&request, (recvPdu->hdr->type == COAP_MESSAGE_CON) ?
- OC_HIGH_QOS : OC_LOW_QOS, rcvdUri, rcvdObsReq, &entityHandlerRequest);
+ OC_HIGH_QOS : OC_LOW_QOS, rcvdUri, rcvdObsReq, &entityHandlerRequest,
+ rcvdRequest->secure);
VERIFY_SUCCESS(result, OC_STACK_OK);
OC_LOG_V(INFO, TAG, " Receveid uri: %s", request->resourceUrl);
uri.query.s, options, numOptions), OC_STACK_OK);
//TODO : Investigate the scenario where there will be no uri for OCDoCoAPResource
- //flag = (coap_send_flags_t) (uri.secure ? SEND_SECURE_PORT : 0);
+ flag = (coap_send_flags_t) (uri.secure ? SEND_SECURE_PORT : 0);
OC_LOG_V(DEBUG, TAG, "uri.host.s %s", uri.host.s);
OC_LOG_V(DEBUG, TAG, "uri.path.s %s", uri.path.s);
OC_LOG_V(DEBUG, TAG, "uri.port %d", uri.port);
OC_LOG_V(DEBUG, TAG, "uri.query.s %s", uri.query.s);
+ OC_LOG_V(DEBUG, TAG, "secure uri %d", uri.secure);
}
coapMsgType = OCToCoAPQoS(qos);
coap_show_pdu(sendPdu);
// TODO : resourceProperties will determine if the packet will be send using secure port
- if(SendCoAPPdu(gCoAPCtx, (coap_address_t*) dstAddr, sendPdu , (coap_send_flags_t)0 )
+ if(SendCoAPPdu(gCoAPCtx, (coap_address_t*) dstAddr, sendPdu ,
+ (coap_send_flags_t)((resPtr->resourceProperties & OC_SECURE) ? SEND_SECURE_PORT : 0) )
!= OC_STACK_OK)
{
OC_LOG(DEBUG, TAG, PCF("A problem occurred in sending a pdu"));
OC_LOG(INFO, TAG, PCF("Entering OCProcessCoAP"));
int read = 0;
read = coap_read(gCoAPCtx, gCoAPCtx->sockfd);
- if(read > 0)
- {
+ if(read > 0) {
OC_LOG(INFO, TAG, PCF("This is a Unicast<============"));
}
if (-1 != gCoAPCtx->sockfd_wellknown) {
OC_LOG(INFO, TAG, PCF("This is a Multicast<==========="));
}
}
+ if (-1 != gCoAPCtx->sockfd_dtls) {
+ read = coap_read(gCoAPCtx, gCoAPCtx->sockfd_dtls);
+ if(read > 0)
+ {
+ OC_LOG(INFO, TAG, PCF("This is a Secure packet<==========="));
+ }
+ }
coap_dispatch(gCoAPCtx);
HandleSendQueue(gCoAPCtx);
// Form the OCRequest struct
OCStackResult FormOCRequest(OCRequest * * requestLoc, OCQualityOfService qos,
unsigned char * uriBuf, OCObserveReq * observeReq,
- OCEntityHandlerRequest * entityHandlerRequest)
+ OCEntityHandlerRequest * entityHandlerRequest,
+ uint8_t secure)
{
OCRequest * request = NULL;
// fill in uri
request->resourceUrl = uriBuf;
+ request->secure = secure;
+
// fill in observe
request->observe = observeReq;
{
coap_tid_t tid = COAP_INVALID_TID;
OCStackResult res = OC_STACK_COMM_ERROR;
+ uint8_t cache = 0;
if (!(flag & SEND_DELAYED))
{
flag = (coap_send_flags_t)( flag |
- (pdu->hdr->type == COAP_MESSAGE_CON) ? SEND_NOW_CON : SEND_NOW);
+ ((pdu->hdr->type == COAP_MESSAGE_CON) ? SEND_NOW_CON : SEND_NOW));
}
- tid = coap_send(gCoAPCtx, dst, pdu, flag);
+ tid = coap_send(gCoAPCtx, dst, pdu, flag, &cache);
OC_LOG_V(INFO, TAG, "TID %d", tid);
if(tid != COAP_INVALID_TID)
{
res = OC_STACK_OK;
}
- if ((pdu->hdr->type != COAP_MESSAGE_CON && (!(flag & SEND_DELAYED))) || tid == COAP_INVALID_TID)
+ if (( (pdu->hdr->type != COAP_MESSAGE_CON) && (!(flag & SEND_DELAYED)) && (!cache))
+ || (tid == COAP_INVALID_TID))
{
OC_LOG(INFO, TAG, PCF("Deleting PDU"));
coap_delete_pdu(pdu);
goto exit;
}
- if (ret = setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (char*) &set_option_on,
- sizeof(set_option_on)) < 0) {
+ if ((ret = setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (char*) &set_option_on,
+ sizeof(set_option_on))) < 0) {
OC_LOG_V(FATAL, MOD_NAME, "setsockopt API failed with errno %s",
strerror(errno));
goto exit;
}
- if (ret = bind(sfd, (struct sockaddr*)ipAddr->addr, ipAddr->size) < 0) {
+ if ((ret = bind(sfd, (struct sockaddr*)ipAddr->addr, ipAddr->size)) < 0) {
OC_LOG_V(FATAL, MOD_NAME, "bind API failed with errno %s", strerror(errno));
goto exit;
}
uint32_t sequenceNum;
// this structure will be passed to entity handler
OCEntityHandlerRequest * entityHandlerRequest;
+ // Indicate whether the request arrives on a secure port
+ uint8_t secure;
} OCRequest;
// following structure will be created in occoap and passed up the stack on the client side
* OC_SLOW - When this bit is set, the resource has been marked as 'slow'. 'slow' signifies
* that responses from this resource can expect delays in processing its
* requests from clients.
+ * OC_SECURE - When this bit is set, the resource is a secure resource.
*/
typedef enum {
OC_ACTIVE = (1 << 0),
OC_DISCOVERABLE = (1 << 1),
OC_OBSERVABLE = (1 << 2),
- OC_SLOW = (1 << 3)
+ OC_SLOW = (1 << 3),
+ OC_SECURE = (1 << 4)
} OCResourceProperty;
/**
--- /dev/null
+//******************************************************************
+//
+// Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ocstack.h>
+
+const char *getResult(OCStackResult result) {
+ switch (result) {
+ case OC_STACK_OK:
+ return "OC_STACK_OK";
+ case OC_STACK_RESOURCE_CREATED:
+ return "OC_STACK_RESOURCE_CREATED";
+ case OC_STACK_RESOURCE_DELETED:
+ return "OC_STACK_RESOURCE_DELETED";
+ case OC_STACK_INVALID_URI:
+ return "OC_STACK_INVALID_URI";
+ case OC_STACK_INVALID_QUERY:
+ return "OC_STACK_INVALID_QUERY";
+ case OC_STACK_INVALID_IP:
+ return "OC_STACK_INVALID_IP";
+ case OC_STACK_INVALID_PORT:
+ return "OC_STACK_INVALID_PORT";
+ case OC_STACK_INVALID_CALLBACK:
+ return "OC_STACK_INVALID_CALLBACK";
+ case OC_STACK_INVALID_METHOD:
+ return "OC_STACK_INVALID_METHOD";
+ case OC_STACK_NO_MEMORY:
+ return "OC_STACK_NO_MEMORY";
+ case OC_STACK_COMM_ERROR:
+ return "OC_STACK_COMM_ERROR";
+ case OC_STACK_INVALID_PARAM:
+ return "OC_STACK_INVALID_PARAM";
+ case OC_STACK_NOTIMPL:
+ return "OC_STACK_NOTIMPL";
+ case OC_STACK_NO_RESOURCE:
+ return "OC_STACK_NO_RESOURCE";
+ case OC_STACK_RESOURCE_ERROR:
+ return "OC_STACK_RESOURCE_ERROR";
+ case OC_STACK_SLOW_RESOURCE:
+ return "OC_STACK_SLOW_RESOURCE";
+ case OC_STACK_NO_OBSERVERS:
+ return "OC_STACK_NO_OBSERVERS";
+ #ifdef WITH_PRESENCE
+ case OC_STACK_PRESENCE_DO_NOT_HANDLE:
+ return "OC_STACK_PRESENCE_DO_NOT_HANDLE";
+ case OC_STACK_PRESENCE_STOPPED:
+ return "OC_STACK_PRESENCE_STOPPED";
+ #endif
+ case OC_STACK_ERROR:
+ return "OC_STACK_ERROR";
+ default:
+ return "UNKNOWN";
+ }
+}
--- /dev/null
+# //******************************************************************
+# //
+# // Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved.
+# //
+# //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+# //
+# // Licensed under the Apache License, Version 2.0 (the "License");
+# // you may not use this file except in compliance with the License.
+# // You may obtain a copy of the License at
+# //
+# // http://www.apache.org/licenses/LICENSE-2.0
+# //
+# // Unless required by applicable law or agreed to in writing, software
+# // distributed under the License is distributed on an "AS IS" BASIS,
+# // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# // See the License for the specific language governing permissions and
+# // limitations under the License.
+# //
+# //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+#
+# override with `make BUILD=debug`
+# default to release build
+BUILD := release
+PLATFORM := linux
+CC := g++
+OUT_DIR := $(BUILD)
+OBJ_DIR := $(OUT_DIR)/obj
+
+ifeq ($(ROOT_DIR), )
+ROOT_DIR = ../../../..
+endif
+
+OUT_DIR = .
+
+OCLOGGER_DIR = $(ROOT_DIR)/logger
+OC_LOG_DIR = $(ROOT_DIR)/../oc_logger
+OCRANDOM_DIR = $(ROOT_DIR)/ocrandom
+OCSOCKET_DIR = $(ROOT_DIR)/ocsocket
+LCOAP_DIR = $(ROOT_DIR)/libcoap-4.1.1
+OCCOAP_DIR = $(ROOT_DIR)/occoap
+OCTBSTACK_DIR = $(ROOT_DIR)/stack
+EXTLIBS_DIR = $(ROOT_DIR)/../../extlibs
+CJSON_DIR = $(EXTLIBS_DIR)/cjson
+
+CJSON_SRC = $(CJSON_DIR)
+
+OCLOGGER_INC = $(OCLOGGER_DIR)/include
+OC_LOG_INC = $(OC_LOG_DIR)/include
+OCRANDOM_INC = $(OCRANDOM_DIR)/include
+OCSOCKET_INC = $(OCSOCKET_DIR)/include
+LCOAP_INC = $(LCOAP_DIR)
+OCCOAP_INC = $(OCCOAP_DIR)/include
+OCTBSTACK_INC = $(OCTBSTACK_DIR)/include
+CJSON_INC = $(CJSON_DIR)
+
+INC_DIRS := -I$(OCLOGGER_INC)
+INC_DIRS += -I$(OC_LOG_INC)
+INC_DIRS += -I$(OCRANDOM_INC)
+INC_DIRS += -I$(OCSOCKET_INC)
+INC_DIRS += -I$(LCOAP_INC)
+INC_DIRS += -I$(OCCOAP_INC)
+INC_DIRS += -I$(OCTBSTACK_INC)
+INC_DIRS += -I$(CJSON_INC)
+
+CC_FLAGS.debug := -O0 -g3 -Wall -ffunction-sections -fdata-sections -fno-exceptions \
+ -std=c++0x -pedantic $(INC_DIRS) -L$(ROOT_DIR)/linux/$(BUILD) -DTB_LOG
+CC_FLAGS.release := -Os -Wall -fdata-sections -Wl,--gc-sections -Wl,-s -fno-exceptions \
+ -std=c++0x $(INC_DIRS) -L$(ROOT_DIR)/linux/$(BUILD) -DTB_LOG
+
+LDLIBS += -loctbstack -lpthread
+CPPFLAGS += $(CC_FLAGS.$(BUILD)) $(LDLIBS)
+
+CJSON_SOURCES := $(CJSON_SRC)/cJSON.c
+
+SOURCES := $(CJSON_SOURCES)
+SOURCES += common.cpp ocserverbasicops.cpp occlientbasicops.cpp
+
+OBJECTS:= $(patsubst %.cpp, $(OBJ_DIR)/%.o, $(SOURCES))
+
+PROGRAMS += ocserverbasicops
+PROGRAMS += occlientbasicops
+
+all: c_sdk prep_dirs $(OBJECTS) $(PROGRAMS)
+
+prep_dirs:
+ -mkdir -p $(OUT_DIR)
+ -mkdir -p $(OBJ_DIR)
+
+c_sdk:
+ cd $(ROOT_DIR) && $(MAKE) BUILD=$(BUILD) PLATFORM=$(PLATFORM)
+
+$(OBJ_DIR)/%.o: %.cpp
+ $(CC) -c $(CPPFLAGS) $< -o $@
+
+ocserverbasicops: $(OBJ_DIR)/ocserverbasicops.o $(OBJ_DIR)/common.o
+ $(CC) $^ $(CPPFLAGS) -o $(OUT_DIR)/$(BUILD)/$@
+
+occlientbasicops: $(OBJ_DIR)/occlientbasicops.o $(OBJ_DIR)/common.o
+ $(CC) $^ $(CPPFLAGS) -o $(OUT_DIR)/$(BUILD)/$@
+
+.PHONY: clean
+
+clean: legacy_clean
+ -rm -rf release
+ -rm -rf debug
+ cd $(ROOT_DIR) && $(MAKE) clean
+ cd $(ROOT_DIR) && $(MAKE) deepclean
+
+legacy_clean:
+ rm -f *.o $(PROGRAMS)
--- /dev/null
+//******************************************************************
+//
+// Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <unistd.h>
+#include <iostream>
+#include <sstream>
+#include "ocstack.h"
+#include "logger.h"
+#include "occlientbasicops.h"
+
+#define TAG "occlientbasicops"
+static int UNICAST_DISCOVERY = 0;
+static int TEST_CASE = 0;
+static const char * TEST_APP_UNICAST_DISCOVERY_QUERY = "coap://0.0.0.0:5683/oc/core";
+static std::string putPayload = "{\"state\":\"off\",\"power\":10}";
+static std::string coapServerIP = "255.255.255.255";
+static std::string coapServerPort = "5683";
+static std::string coapServerResource = "/a/led";
+
+int gQuitFlag = 0;
+
+/* SIGINT handler: set gQuitFlag to 1 for graceful termination */
+void handleSigInt(int signum)
+{
+ if (signum == SIGINT)
+ {
+ gQuitFlag = 1;
+ }
+}
+
+static void PrintUsage()
+{
+ OC_LOG(INFO, TAG, "Usage : occlient -u <0|1> -t <1|2|3>");
+ OC_LOG(INFO, TAG, "-u <0|1> : Perform multicast/unicast discovery of resources");
+ OC_LOG(INFO, TAG, "-t 1 : Discover Resources");
+ OC_LOG(INFO, TAG, "-t 2 : Discover Resources and"
+ " Initiate Nonconfirmable Get/Put/Post Requests");
+ OC_LOG(INFO, TAG, "-t 3 : Discover Resources and Initiate Confirmable Get/Put/Post Requests");
+}
+
+OCStackResult InvokeOCDoResource(std::ostringstream &query,
+ OCMethod method, OCQualityOfService qos,
+ OCClientResponseHandler cb, OCHeaderOption * options, uint8_t numOptions)
+{
+ OCStackResult ret;
+ OCCallbackData cbData;
+ OCDoHandle handle;
+
+ cbData.cb = cb;
+ cbData.context = NULL;
+ cbData.cd = NULL;
+
+ ret = OCDoResource(&handle, method, query.str().c_str(), 0,
+ (method == OC_REST_PUT || method == OC_REST_POST) ? putPayload.c_str() : NULL,
+ qos, &cbData, options, numOptions);
+
+ if (ret != OC_STACK_OK)
+ {
+ OC_LOG_V(ERROR, TAG, "OCDoResource returns error %d with method %d", ret, method);
+ }
+
+ return ret;
+}
+
+OCStackApplicationResult putReqCB(void* ctx, OCDoHandle handle, OCClientResponse * clientResponse)
+{
+ OC_LOG(INFO, TAG, "Callback Context for PUT recvd successfully");
+
+ if(clientResponse)
+ {
+ OC_LOG_V(INFO, TAG, "StackResult: %s", getResult(clientResponse->result));
+ OC_LOG_V(INFO, TAG, "JSON = %s =============> Put Response", clientResponse->resJSONPayload);
+ }
+ return OC_STACK_DELETE_TRANSACTION;
+}
+
+OCStackApplicationResult postReqCB(void *ctx, OCDoHandle handle, OCClientResponse *clientResponse)
+{
+ OC_LOG(INFO, TAG, "Callback Context for POST recvd successfully");
+
+ if(clientResponse)
+ {
+ OC_LOG_V(INFO, TAG, "StackResult: %s", getResult(clientResponse->result));
+ OC_LOG_V(INFO, TAG, "JSON = %s =============> Post Response",
+ clientResponse->resJSONPayload);
+ }
+ return OC_STACK_DELETE_TRANSACTION;
+}
+
+OCStackApplicationResult getReqCB(void* ctx, OCDoHandle handle, OCClientResponse * clientResponse)
+{
+ OC_LOG(INFO, TAG, "Callback Context for GET query recvd successfully");
+
+ if(clientResponse)
+ {
+ OC_LOG_V(INFO, TAG, "StackResult: %s", getResult(clientResponse->result));
+ OC_LOG_V(INFO, TAG, "SEQUENCE NUMBER: %d", clientResponse->sequenceNumber);
+ OC_LOG_V(INFO, TAG, "JSON = %s =============> Get Response",
+ clientResponse->resJSONPayload);
+ }
+ if(clientResponse->rcvdVendorSpecificHeaderOptions &&
+ clientResponse->numRcvdVendorSpecificHeaderOptions)
+ {
+ OC_LOG (INFO, TAG, "Received vendor specific options");
+ uint8_t i = 0;
+ OCHeaderOption * rcvdOptions = clientResponse->rcvdVendorSpecificHeaderOptions;
+ for( i = 0; i < clientResponse->numRcvdVendorSpecificHeaderOptions; i++)
+ {
+ if(((OCHeaderOption)rcvdOptions[i]).protocolID == OC_COAP_ID)
+ {
+ OC_LOG_V(INFO, TAG, "Received option with OC_COAP_ID and ID %u with",
+ ((OCHeaderOption)rcvdOptions[i]).optionID );
+ OC_LOG_BUFFER(INFO, TAG, ((OCHeaderOption)rcvdOptions[i]).optionData,
+ ((OCHeaderOption)rcvdOptions[i]).optionLength);
+ }
+ }
+ }
+ return OC_STACK_DELETE_TRANSACTION;
+}
+
+// This is a function called back when a device is discovered
+OCStackApplicationResult discoveryReqCB(void* ctx, OCDoHandle handle,
+ OCClientResponse * clientResponse)
+{
+ uint8_t remoteIpAddr[4];
+ uint16_t remotePortNu;
+
+ OC_LOG(INFO, TAG, "Callback Context for DISCOVER query recvd successfully");
+
+ if (clientResponse)
+ {
+ OC_LOG_V(INFO, TAG, "StackResult: %s", getResult(clientResponse->result));
+
+ OCDevAddrToIPv4Addr((OCDevAddr *) clientResponse->addr, remoteIpAddr,
+ remoteIpAddr + 1, remoteIpAddr + 2, remoteIpAddr + 3);
+ OCDevAddrToPort((OCDevAddr *) clientResponse->addr, &remotePortNu);
+
+ OC_LOG_V(INFO, TAG,
+ "Device =============> Discovered %s @ %d.%d.%d.%d:%d",
+ clientResponse->resJSONPayload, remoteIpAddr[0], remoteIpAddr[1],
+ remoteIpAddr[2], remoteIpAddr[3], remotePortNu);
+
+ parseClientResponse(clientResponse);
+
+ switch(TEST_CASE)
+ {
+ case TEST_NON_CON_OP:
+ InitGetRequest(OC_LOW_QOS);
+ InitPutRequest();
+ //InitPostRequest(OC_LOW_QOS);
+ break;
+ case TEST_CON_OP:
+ InitGetRequest(OC_HIGH_QOS);
+ InitPutRequest();
+ //InitPostRequest(OC_HIGH_QOS);
+ break;
+ }
+ }
+
+ return (UNICAST_DISCOVERY) ? OC_STACK_DELETE_TRANSACTION : OC_STACK_KEEP_TRANSACTION ;
+
+}
+
+int InitPutRequest()
+{
+ OC_LOG_V(INFO, TAG, "\n\nExecuting %s", __func__);
+ std::ostringstream query;
+ query << "coaps://" << coapServerIP << ":" << "5684" << coapServerResource;
+ return (InvokeOCDoResource(query, OC_REST_PUT, OC_LOW_QOS, putReqCB, NULL, 0));
+}
+
+int InitPostRequest(OCQualityOfService qos)
+{
+ OCStackResult result;
+ OC_LOG_V(INFO, TAG, "\n\nExecuting %s", __func__);
+ std::ostringstream query;
+ query << "coaps://" << coapServerIP << ":" << "5684" << coapServerResource;
+
+ // First POST operation (to create an LED instance)
+ result = InvokeOCDoResource(query, OC_REST_POST,
+ ((qos == OC_HIGH_QOS) ? OC_HIGH_QOS: OC_LOW_QOS),
+ postReqCB, NULL, 0);
+ if (OC_STACK_OK != result)
+ {
+ // Error can happen if for example, network connectivity is down
+ OC_LOG(INFO, TAG, "First POST call did not succeed");
+ }
+
+ // Second POST operation (to create an LED instance)
+ result = InvokeOCDoResource(query, OC_REST_POST,
+ ((qos == OC_HIGH_QOS) ? OC_HIGH_QOS: OC_LOW_QOS),
+ postReqCB, NULL, 0);
+ if (OC_STACK_OK != result)
+ {
+ OC_LOG(INFO, TAG, "Second POST call did not succeed");
+ }
+
+ // This POST operation will update the original resourced /a/led
+ return (InvokeOCDoResource(query, OC_REST_POST,
+ ((qos == OC_HIGH_QOS) ? OC_HIGH_QOS: OC_LOW_QOS),
+ postReqCB, NULL, 0));
+}
+
+int InitGetRequest(OCQualityOfService qos)
+{
+ OC_LOG_V(INFO, TAG, "\n\nExecuting %s", __func__);
+ std::ostringstream query;
+ query << "coaps://" << coapServerIP << ":" << "5684" << coapServerResource;
+
+ return (InvokeOCDoResource(query, OC_REST_GET, (qos == OC_HIGH_QOS)?
+ OC_HIGH_QOS:OC_LOW_QOS, getReqCB, NULL, 0));
+}
+
+int InitDiscovery()
+{
+ OCStackResult ret;
+ OCCallbackData cbData;
+ OCDoHandle handle;
+ /* Start a discovery query*/
+ char szQueryUri[64] = { 0 };
+ if (UNICAST_DISCOVERY)
+ {
+ strcpy(szQueryUri, TEST_APP_UNICAST_DISCOVERY_QUERY);
+ }
+ else
+ {
+ strcpy(szQueryUri, OC_WELL_KNOWN_QUERY);
+ }
+ cbData.cb = discoveryReqCB;
+ cbData.context = NULL;
+ cbData.cd = NULL;
+ ret = OCDoResource(&handle, OC_REST_GET, szQueryUri, 0, 0, OC_LOW_QOS, &cbData, NULL, 0);
+ if (ret != OC_STACK_OK)
+ {
+ OC_LOG(ERROR, TAG, "OCStack resource error");
+ }
+ return ret;
+}
+
+int main(int argc, char* argv[])
+{
+ uint8_t addr[20] = {0};
+ uint8_t* paddr = NULL;
+ uint16_t port = USE_RANDOM_PORT;
+ uint8_t ifname[] = "eth0";
+ int opt;
+ struct timespec timeout;
+
+ while ((opt = getopt(argc, argv, "u:t:")) != -1)
+ {
+ switch(opt)
+ {
+ case 'u':
+ UNICAST_DISCOVERY = atoi(optarg);
+ break;
+ case 't':
+ TEST_CASE = atoi(optarg);
+ break;
+ default:
+ PrintUsage();
+ return -1;
+ }
+ }
+
+ if ((UNICAST_DISCOVERY != 0 && UNICAST_DISCOVERY != 1) ||
+ (TEST_CASE < TEST_DISCOVER_REQ || TEST_CASE >= MAX_TESTS) )
+ {
+ PrintUsage();
+ return -1;
+ }
+
+
+ /*Get Ip address on defined interface and initialize coap on it with random port number
+ * this port number will be used as a source port in all coap communications*/
+ if ( OCGetInterfaceAddress(ifname, sizeof(ifname), AF_INET, addr,
+ sizeof(addr)) == ERR_SUCCESS)
+ {
+ OC_LOG_V(INFO, TAG, "Starting occlient on address %s",addr);
+ paddr = addr;
+ }
+
+ /* Initialize OCStack*/
+ if (OCInit((char *) paddr, port, OC_CLIENT) != OC_STACK_OK)
+ {
+ OC_LOG(ERROR, TAG, "OCStack init error");
+ return 0;
+ }
+
+ InitDiscovery();
+
+ timeout.tv_sec = 0;
+ timeout.tv_nsec = 100000000L;
+
+ // Break from loop with Ctrl+C
+ OC_LOG(INFO, TAG, "Entering occlient main loop...");
+ signal(SIGINT, handleSigInt);
+ while (!gQuitFlag)
+ {
+ if (OCProcess() != OC_STACK_OK)
+ {
+ OC_LOG(ERROR, TAG, "OCStack process error");
+ return 0;
+ }
+
+ nanosleep(&timeout, NULL);
+ //sleep(2);
+ }
+ OC_LOG(INFO, TAG, "Exiting occlient main loop...");
+
+ if (OCStop() != OC_STACK_OK)
+ {
+ OC_LOG(ERROR, TAG, "OCStack stop error");
+ }
+
+ return 0;
+}
+
+std::string getIPAddrTBServer(OCClientResponse * clientResponse)
+{
+ if(!clientResponse) return "";
+ if(!clientResponse->addr) return "";
+ uint8_t a, b, c, d = 0;
+ if(0 != OCDevAddrToIPv4Addr(clientResponse->addr, &a, &b, &c, &d) ) return "";
+
+ char ipaddr[16] = {'\0'};
+ // ostringstream not working correctly here, hence snprintf
+ snprintf(ipaddr, sizeof(ipaddr), "%d.%d.%d.%d", a,b,c,d);
+ return std::string (ipaddr);
+}
+
+
+std::string getPortTBServer(OCClientResponse * clientResponse)
+{
+ if(!clientResponse) return "";
+ if(!clientResponse->addr) return "";
+ uint16_t p = 0;
+ if(0 != OCDevAddrToPort(clientResponse->addr, &p) ) return "";
+ std::ostringstream ss;
+ ss << p;
+ return ss.str();
+}
+
+std::string getQueryStrForGetPut(OCClientResponse * clientResponse)
+{
+ return "/a/led";
+}
+
+void parseClientResponse(OCClientResponse * clientResponse)
+{
+ coapServerIP = getIPAddrTBServer(clientResponse);
+ coapServerPort = getPortTBServer(clientResponse);
+ coapServerResource = getQueryStrForGetPut(clientResponse);
+}
--- /dev/null
+//******************************************************************
+//
+// Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+#ifndef OCCLIENT_BASICOPS_H_
+#define OCCLIENT_BASICOPS_H_
+
+#include "ocstack.h"
+
+//-----------------------------------------------------------------------------
+// Typedefs
+//-----------------------------------------------------------------------------
+
+/**
+ * List of methods that can be inititated from the client
+ */
+typedef enum {
+ TEST_DISCOVER_REQ = 1,
+ TEST_NON_CON_OP,
+ TEST_CON_OP,
+ MAX_TESTS
+} CLIENT_TEST;
+
+//-----------------------------------------------------------------------------
+// Function prototype
+//-----------------------------------------------------------------------------
+
+/* call getResult in common.cpp to get the result in string format. */
+const char *getResult(OCStackResult result);
+
+/* Get the IP address of the server */
+std::string getIPAddrTBServer(OCClientResponse * clientResponse);
+
+/* Get the port number the server is listening on */
+std::string getPortTBServer(OCClientResponse * clientResponse);
+
+/* Returns the query string for GET and PUT operations */
+std::string getQueryStrForGetPut(OCClientResponse * clientResponse);
+
+/* Following are initialization functions for GET, PUT
+ * POST & Discovery operations
+ */
+int InitPutRequest();
+int InitGetRequest(OCQualityOfService qos);
+int InitPostRequest(OCQualityOfService qos);
+int InitDiscovery();
+
+/* Function to retrieve ip address, port no. of the server
+ * and query for the operations to be performed.
+ */
+void parseClientResponse(OCClientResponse * clientResponse);
+
+/* This method calls OCDoResource() which in turn makes calls
+ * to the lower layers
+ */
+OCStackResult InvokeOCDoResource(std::ostringstream &query,
+ OCMethod method, OCQualityOfService qos,
+ OCClientResponseHandler cb, OCHeaderOption * options, uint8_t numOptions);
+
+//-----------------------------------------------------------------------------
+// Callback functions
+//-----------------------------------------------------------------------------
+
+/* Following are callback functions for the GET, PUT
+ * POST & Discovery operations
+ */
+
+OCStackApplicationResult putReqCB(void* ctx, OCDoHandle handle, OCClientResponse * clientResponse);
+
+OCStackApplicationResult postReqCB(void *ctx, OCDoHandle handle, OCClientResponse *clientResponse);
+
+OCStackApplicationResult getReqCB(void* ctx, OCDoHandle handle, OCClientResponse * clientResponse);
+
+OCStackApplicationResult discoveryReqCB(void* ctx, OCDoHandle handle,
+ OCClientResponse * clientResponse);
+
+#endif
--- /dev/null
+//******************************************************************
+//
+// Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <pthread.h>
+#include "ocstack.h"
+#include "logger.h"
+#include "cJSON.h"
+#include "ocserverbasicops.h"
+
+int gQuitFlag = 0;
+
+static LEDResource LED;
+// This variable determines instance number of the LED resource.
+// Used by POST method to create a new instance of LED resource.
+static int gCurrLedInstance = 0;
+#define SAMPLE_MAX_NUM_POST_INSTANCE 2
+static LEDResource gLedInstance[SAMPLE_MAX_NUM_POST_INSTANCE];
+
+char *gResourceUri= (char *)"/a/led";
+
+static uint16_t OC_WELL_KNOWN_PORT = 5683;
+
+//This function takes the request as an input and returns the response
+//in JSON format.
+char* constructJsonResponse (OCEntityHandlerRequest *ehRequest)
+{
+ cJSON *json = cJSON_CreateObject();
+ cJSON *format;
+ char *jsonResponse;
+ LEDResource *currLEDResource = &LED;
+
+ if (ehRequest->resource == gLedInstance[0].handle)
+ {
+ currLEDResource = &gLedInstance[0];
+ gResourceUri = (char *) "a/led/0";
+ }
+ else if (ehRequest->resource == gLedInstance[1].handle)
+ {
+ currLEDResource = &gLedInstance[1];
+ gResourceUri = (char *) "a/led/1";
+ }
+
+ if(OC_REST_PUT == ehRequest->method)
+ {
+ cJSON *putJson = cJSON_Parse((char *)ehRequest->reqJSONPayload);
+ currLEDResource->state = ( !strcmp(cJSON_GetObjectItem(putJson,"state")->valuestring ,
+ "on") ? true:false);
+ currLEDResource->power = cJSON_GetObjectItem(putJson,"power")->valuedouble;
+ cJSON_Delete(putJson);
+ }
+
+ cJSON_AddStringToObject(json,"href",gResourceUri);
+ cJSON_AddItemToObject(json, "rep", format=cJSON_CreateObject());
+ cJSON_AddStringToObject(format, "state", (char *) (currLEDResource->state ? "on":"off"));
+ cJSON_AddNumberToObject(format, "power", currLEDResource->power);
+
+ jsonResponse = cJSON_Print(json);
+ cJSON_Delete(json);
+ return jsonResponse;
+}
+
+void ProcessGetRequest (OCEntityHandlerRequest *ehRequest)
+{
+ char *getResp = constructJsonResponse(ehRequest);
+
+ if (ehRequest->resJSONPayloadLen > strlen ((char *)getResp))
+ {
+ strncpy((char *)ehRequest->resJSONPayload, getResp,
+ strlen((char *)getResp));
+ }
+ else
+ {
+ OC_LOG_V (INFO, TAG, "Response buffer: %d bytes is too small",
+ ehRequest->resJSONPayloadLen);
+ }
+
+ free(getResp);
+}
+
+void ProcessPutRequest (OCEntityHandlerRequest *ehRequest)
+{
+ char *putResp = constructJsonResponse(ehRequest);
+
+ if (ehRequest->resJSONPayloadLen > strlen ((char *)putResp))
+ {
+ strncpy((char *)ehRequest->resJSONPayload, putResp,
+ strlen((char *)putResp));
+ }
+ else
+ {
+ OC_LOG_V (INFO, TAG, "Response buffer: %d bytes is too small",
+ ehRequest->resJSONPayloadLen);
+ }
+
+ free(putResp);
+}
+
+void ProcessPostRequest (OCEntityHandlerRequest *ehRequest)
+{
+ char *respPLPost_led = NULL;
+ cJSON *json;
+ cJSON *format;
+
+ /*
+ * The entity handler determines how to process a POST request.
+ * Per the REST paradigm, POST can also be used to update representation of existing
+ * resource or create a new resource.
+ * In the sample below, if the POST is for /a/led then a new instance of the LED
+ * resource is created with default representation (if representation is included in
+ * POST payload it can be used as initial values) as long as the instance is
+ * lesser than max new instance count. Once max instance count is reached, POST on
+ * /a/led updated the representation of /a/led (just like PUT)
+ */
+
+ if (ehRequest->resource == LED.handle)
+ {
+ if (gCurrLedInstance < SAMPLE_MAX_NUM_POST_INSTANCE)
+ {
+ // Create new LED instance
+ char newLedUri[15] = "/a/led/";
+ sprintf (newLedUri + strlen(newLedUri), "%d", gCurrLedInstance);
+
+ json = cJSON_CreateObject();
+
+ cJSON_AddStringToObject(json,"href",gResourceUri);
+ cJSON_AddItemToObject(json, "rep", format=cJSON_CreateObject());
+ cJSON_AddStringToObject(format, "createduri", (char *) newLedUri);
+
+ if (0 == createLEDResource (newLedUri, &gLedInstance[gCurrLedInstance], false, 0))
+ {
+ OC_LOG (INFO, TAG, "Created new LED instance");
+ gLedInstance[gCurrLedInstance].state = 0;
+ gLedInstance[gCurrLedInstance].power = 0;
+ gCurrLedInstance++;
+ respPLPost_led = cJSON_Print(json);
+ }
+
+ cJSON_Delete(json);
+ }
+ else
+ {
+ respPLPost_led = constructJsonResponse(ehRequest);
+ }
+ }
+ else
+ {
+ for (int i = 0; i < SAMPLE_MAX_NUM_POST_INSTANCE; i++)
+ {
+ if (ehRequest->resource == gLedInstance[i].handle)
+ {
+ if (i == 0)
+ {
+ respPLPost_led = constructJsonResponse(ehRequest);
+ break;
+ }
+ else if (i == 1)
+ {
+ respPLPost_led = constructJsonResponse(ehRequest);
+ }
+ }
+ }
+ }
+
+ if (respPLPost_led != NULL && ehRequest->resJSONPayloadLen > strlen ((char *)respPLPost_led))
+ {
+ strncpy((char *)ehRequest->resJSONPayload, respPLPost_led,
+ strlen((char *)respPLPost_led));
+ }
+ else
+ {
+ OC_LOG_V (INFO, TAG, "Response buffer: %d bytes is too small",
+ ehRequest->resJSONPayloadLen);
+ }
+
+ free(respPLPost_led);
+}
+
+OCEntityHandlerResult
+OCEntityHandlerCb (OCEntityHandlerFlag flag,
+ OCEntityHandlerRequest *entityHandlerRequest)
+{
+ OC_LOG_V (INFO, TAG, "Inside entity handler - flags: 0x%x", flag);
+ if (flag & OC_INIT_FLAG)
+ {
+ OC_LOG (INFO, TAG, "Flag includes OC_INIT_FLAG");
+ }
+ if (flag & OC_REQUEST_FLAG)
+ {
+ OC_LOG (INFO, TAG, "Flag includes OC_REQUEST_FLAG");
+ if (entityHandlerRequest)
+ {
+ if (OC_REST_GET == entityHandlerRequest->method)
+ {
+ OC_LOG (INFO, TAG, "Received OC_REST_GET from client");
+ ProcessGetRequest (entityHandlerRequest);
+ }
+ else if (OC_REST_PUT == entityHandlerRequest->method)
+ {
+ OC_LOG (INFO, TAG, "Received OC_REST_PUT from client");
+ ProcessPutRequest (entityHandlerRequest);
+ }
+ else if (OC_REST_POST == entityHandlerRequest->method)
+ {
+ OC_LOG (INFO, TAG, "Received OC_REST_POST from client");
+ ProcessPostRequest (entityHandlerRequest);
+ }
+ else
+ {
+ OC_LOG_V (INFO, TAG, "Received unsupported method %d from client",
+ entityHandlerRequest->method);
+ }
+ }
+ }
+ return OC_EH_OK;
+}
+
+/* SIGINT handler: set gQuitFlag to 1 for graceful termination */
+void handleSigInt(int signum)
+{
+ if (signum == SIGINT)
+ {
+ gQuitFlag = 1;
+ }
+}
+
+int main(int argc, char* argv[])
+{
+ uint8_t addr[20] = {0};
+ uint8_t* paddr = NULL;
+ uint16_t port = OC_WELL_KNOWN_PORT;
+ uint8_t ifname[] = "eth0";
+ int opt;
+ struct timespec timeout;
+
+ OC_LOG(DEBUG, TAG, "OCServer is starting...");
+ /*Get Ip address on defined interface and initialize coap on it with random port number
+ * this port number will be used as a source port in all coap communications*/
+ if ( OCGetInterfaceAddress(ifname, sizeof(ifname), AF_INET, addr,
+ sizeof(addr)) == ERR_SUCCESS)
+ {
+ OC_LOG_V(INFO, TAG, "Starting ocserver on address %s:%d",addr,port);
+ paddr = addr;
+ }
+
+ if (OCInit((char *) paddr, port, OC_SERVER) != OC_STACK_OK)
+ {
+ OC_LOG(ERROR, TAG, "OCStack init error");
+ return 0;
+ }
+
+ /*
+ * Declare and create the example resource: LED
+ */
+ createLEDResource(gResourceUri, &LED, false, 0);
+
+ timeout.tv_sec = 0;
+ timeout.tv_nsec = 100000000L;
+
+ // Break from loop with Ctrl-C
+ OC_LOG(INFO, TAG, "Entering ocserver main loop...");
+ signal(SIGINT, handleSigInt);
+ while (!gQuitFlag)
+ {
+ if (OCProcess() != OC_STACK_OK)
+ {
+ OC_LOG(ERROR, TAG, "OCStack process error");
+ return 0;
+ }
+ nanosleep(&timeout, NULL);
+ //sleep(2);
+ }
+
+ OC_LOG(INFO, TAG, "Exiting ocserver main loop...");
+
+ if (OCStop() != OC_STACK_OK)
+ {
+ OC_LOG(ERROR, TAG, "OCStack process error");
+ }
+
+ return 0;
+}
+
+int createLEDResource (char *uri, LEDResource *ledResource, bool resourceState, int resourcePower)
+{
+ if (!uri)
+ {
+ OC_LOG(ERROR, TAG, "Resource URI cannot be NULL");
+ return -1;
+ }
+
+ ledResource->state = resourceState;
+ ledResource->power= resourcePower;
+ OCStackResult res = OCCreateResource(&(ledResource->handle),
+ "core.led",
+ "oc.mi.def",
+ uri,
+ OCEntityHandlerCb,
+ OC_DISCOVERABLE|OC_OBSERVABLE | OC_SECURE);
+ OC_LOG_V(INFO, TAG, "Created LED resource with result: %s", getResult(res));
+
+ return 0;
+}
--- /dev/null
+//******************************************************************
+//
+// Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+#ifndef OCSERVER_BASICOPS_H_
+#define OCSERVER_BASICOPS_H_
+
+#include "ocstack.h"
+
+//-----------------------------------------------------------------------------
+// Defines
+//-----------------------------------------------------------------------------
+#define TAG "ocserverbasicops"
+
+//-----------------------------------------------------------------------------
+// Typedefs
+//-----------------------------------------------------------------------------
+
+/* Structure to represent a LED resource */
+typedef struct LEDRESOURCE{
+ OCResourceHandle handle;
+ bool state;
+ int power;
+} LEDResource;
+
+//-----------------------------------------------------------------------------
+// Function prototype
+//-----------------------------------------------------------------------------
+
+/* Function that creates a new LED resource by calling the
+ * OCCreateResource() method.
+ */
+int createLEDResource (char *uri, LEDResource *ledResource, bool resourceState, int resourcePower);
+
+/* This method converts the payload to JSON format */
+char* constructJsonResponse (OCEntityHandlerRequest *ehRequest);
+
+/* Following methods process the PUT, GET, POST
+ * requests
+ */
+void ProcessGetRequest (OCEntityHandlerRequest *ehRequest);
+void ProcessPutRequest (OCEntityHandlerRequest *ehRequest);
+void ProcessPostRequest (OCEntityHandlerRequest *ehRequest);
+
+/* call getResult in common.cpp to get the result in string format. */
+const char *getResult(OCStackResult result);
+
+//-----------------------------------------------------------------------------
+// Callback functions
+//-----------------------------------------------------------------------------
+
+/* Entity Handler callback functions */
+
+OCEntityHandlerResult
+OCEntityHandlerCb (OCEntityHandlerFlag flag,
+ OCEntityHandlerRequest *entityHandlerRequest);
+
+#endif
#ifdef WITH_PRESENCE
else if (strcmp((char *)url, GetVirtualResourceUri(OC_PRESENCE)) == 0) {
//Nothing needs to be done, except for pass a OC_PRESENCE query through as OC_STACK_OK.
- OC_LOG(INFO, TAG, "OC_PRESENCE Request!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
+ OC_LOG(INFO, TAG, PCF("OC_PRESENCE Request"));
*filterOn = STACK_RES_DISCOVERY_NOFILTER;
}
#endif
return OC_STACK_NO_RESOURCE;
}
+ // secure resource will entertain only authorized requests
+ if ((resourcePtr->resourceProperties & OC_SECURE) && (request->secure == 0))
+ {
+ OC_LOG(INFO, TAG, PCF("Un-authorized request. Ignore it!"));
+ return OC_STACK_RESOURCE_ERROR;
+ }
+
if (IsCollectionResource (resourcePtr))
{
// Collection resource
// Make sure resourceProperties bitmask has allowed properties specified
if (resourceProperties
- > (OC_ACTIVE | OC_DISCOVERABLE | OC_OBSERVABLE | OC_SLOW)) {
+ > (OC_ACTIVE | OC_DISCOVERABLE | OC_OBSERVABLE | OC_SLOW | OC_SECURE)) {
OC_LOG(ERROR, TAG, PCF("Invalid property"));
return OC_STACK_INVALID_PARAM;
}