Implemented libcoap's tinyDTLS interface
authorSachin Agrawal <sachin.agrawal@intel.com>
Fri, 14 Nov 2014 00:03:57 +0000 (16:03 -0800)
committerErich Keane <erich.keane@intel.com>
Fri, 14 Nov 2014 00:06:21 +0000 (16:06 -0800)
libcoap needs to encrypt/decrypt packets while sending on
secure port. This changeset implements interface for libcoap
to use tinyDTLS for creating DTLS sessions and performing
crypto operations.
This changeset is dependent on having tinyDTLS installed
under oic-resourc/resource/csdk directory.

Change-Id: I728b147991b94b802f125ad8e457c1830a114fba
Signed-off-by: Sachin Agrawal <sachin.agrawal@intel.com>
22 files changed:
resource/csdk/libcoap-4.1.1/makefile
resource/csdk/libcoap-4.1.1/net.c
resource/csdk/libcoap-4.1.1/net.h
resource/csdk/libcoap-4.1.1/sec/netdtls.c [new file with mode: 0644]
resource/csdk/libcoap-4.1.1/sec/netdtls.h [new file with mode: 0644]
resource/csdk/libcoap-4.1.1/uri.c
resource/csdk/libcoap-4.1.1/uri.h
resource/csdk/makefile
resource/csdk/occoap/include/occoaphelper.h
resource/csdk/occoap/src/occoap.c
resource/csdk/occoap/src/occoaphelper.c
resource/csdk/ocsocket/src/ocsocket.c
resource/csdk/stack/include/internal/ocstackinternal.h
resource/csdk/stack/include/ocstack.h
resource/csdk/stack/samples/linux/secure/common.cpp [new file with mode: 0644]
resource/csdk/stack/samples/linux/secure/makefile [new file with mode: 0644]
resource/csdk/stack/samples/linux/secure/occlientbasicops.cpp [new file with mode: 0644]
resource/csdk/stack/samples/linux/secure/occlientbasicops.h [new file with mode: 0644]
resource/csdk/stack/samples/linux/secure/ocserverbasicops.cpp [new file with mode: 0644]
resource/csdk/stack/samples/linux/secure/ocserverbasicops.h [new file with mode: 0644]
resource/csdk/stack/src/ocresource.c
resource/csdk/stack/src/ocstack.c

index 7dba647..9e84a71 100644 (file)
@@ -43,7 +43,8 @@ LOGGER_DIR    = $(ROOT_DIR)/logger
 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.
@@ -98,8 +99,23 @@ CC_FLAGS.debug := -O0 -g3 -Wall -ffunction-sections -fdata-sections -fno-excepti
 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))
 
index d95e1d6..b0bc23c 100644 (file)
@@ -50,6 +50,9 @@
 
 #include <ocsocket.h>
 #include <logger.h>
+#if defined(WITH_DTLS)
+#include "netdtls.h"
+#endif /* WITH_DTLS */
 
 #define MOD_NAME ("net.c")
 
@@ -360,9 +363,17 @@ coap_new_context(const coap_address_t *listen_addr) {
         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
@@ -413,6 +424,9 @@ void coap_free_context(coap_context_t *context) {
     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
@@ -519,7 +533,7 @@ coap_tid_t coap_send_ack(coap_context_t *context, const coap_address_t *dst,
         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);
         }
     }
@@ -633,7 +647,7 @@ coap_tid_t coap_send_error(coap_context_t *context, coap_pdu_t *request,
 
     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);
     }
 
@@ -649,7 +663,7 @@ coap_tid_t coap_send_message_type(coap_context_t *context,
     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);
         }
     }
@@ -657,7 +671,8 @@ coap_tid_t coap_send_message_type(coap_context_t *context,
 }
 
 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;
@@ -751,9 +766,20 @@ coap_tid_t coap_send(coap_context_t *context,
     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");
@@ -781,7 +807,7 @@ coap_tid_t coap_retransmit(coap_context_t *context, coap_queue_t *node) {
         debug("** retransmission #%d of transaction %d\n", node->retransmit_cnt,
             ntohs(node->pdu->hdr->id));
         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;
     }
 
@@ -815,6 +841,7 @@ int coap_read(coap_context_t *ctx, int sockfd) {
 #if defined(WITH_LWIP) || defined(WITH_CONTIKI)
     char *buf;
 #endif
+  char *pbuf = buf;
   coap_hdr_t *pdu;
   int bytes_read = -1;
 
@@ -823,28 +850,35 @@ int coap_read(coap_context_t *ctx, int sockfd) {
   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()) {
@@ -868,7 +902,7 @@ int coap_read(coap_context_t *ctx, int sockfd) {
 #endif /* WITH_LWIP */
 
     if (bytes_read < 0) {
-        warn("coap_read: recvfrom");
+        warn("coap_read: recvfrom\n");
         goto error_early;
     }
 
@@ -899,7 +933,7 @@ int coap_read(coap_context_t *ctx, int sockfd) {
     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;
     }
@@ -907,6 +941,13 @@ int coap_read(coap_context_t *ctx, int sockfd) {
     //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);
@@ -1340,7 +1381,7 @@ handle_locally(coap_context_t *context __attribute__ ((unused)),
                     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");
                         }
index c9d803c..f66a4ff 100644 (file)
@@ -55,7 +55,8 @@ typedef enum {
     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;
@@ -95,6 +96,8 @@ struct coap_context_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);
@@ -131,6 +134,9 @@ typedef struct coap_context_t {
 #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 */
@@ -299,16 +305,21 @@ coap_pdu_t *coap_new_error_response(coap_pdu_t *request,
  * 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
diff --git a/resource/csdk/libcoap-4.1.1/sec/netdtls.c b/resource/csdk/libcoap-4.1.1/sec/netdtls.c
new file mode 100644 (file)
index 0000000..b5e4ee0
--- /dev/null
@@ -0,0 +1,549 @@
+//******************************************************************
+//
+// 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;
+}
diff --git a/resource/csdk/libcoap-4.1.1/sec/netdtls.h b/resource/csdk/libcoap-4.1.1/sec/netdtls.h
new file mode 100644 (file)
index 0000000..97ecdc0
--- /dev/null
@@ -0,0 +1,135 @@
+//******************************************************************
+//
+// 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
+
index 5bd846c..96624c5 100644 (file)
@@ -74,6 +74,7 @@ coap_split_uri(unsigned char *str_var, size_t len, coap_uri_t *uri) {
   /* There might be an additional 's', indicating the secure version: */
   if (len && (secure = tolower(*p) == 's')) {
     ++p; --len;
+    uri->secure = 1;
   }
 
   q = (unsigned char *)"://";
@@ -88,7 +89,7 @@ coap_split_uri(unsigned char *str_var, size_t len, coap_uri_t *uri) {
 
   /* 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 != ']') {
@@ -102,7 +103,7 @@ coap_split_uri(unsigned char *str_var, size_t len, coap_uri_t *uri) {
 
     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;
@@ -127,17 +128,17 @@ coap_split_uri(unsigned char *str_var, size_t len, coap_uri_t *uri) {
       --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;
@@ -223,7 +224,7 @@ check_segment(const unsigned char *s, size_t length) {
   while (length) {
     if (*s == '%') {
       if (length < 2 || !(isxdigit(s[1]) && isxdigit(s[2])))
-       return -1;
+    return -1;
 
       s += 2;
       length -= 2;
@@ -256,7 +257,7 @@ check_segment(const unsigned char *s, size_t length) {
  */
 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;
 
@@ -274,10 +275,10 @@ make_decoded_option(const unsigned char *s, size_t length,
 
   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) {
@@ -309,7 +310,7 @@ typedef void (*segment_handler_t)(unsigned char *, size_t, void *);
  */
 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;
 
@@ -352,12 +353,12 @@ write_option(unsigned char *s, size_t len, void *data) {
 
 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;
@@ -366,12 +367,12 @@ coap_split_path(const unsigned char *s, size_t 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);
 
@@ -408,7 +409,7 @@ coap_clone_uri(const coap_uri_t *uri) {
     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;
@@ -460,7 +461,7 @@ coap_hash_path(const unsigned char *path, size_t len, coap_key_t key) {
   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;
@@ -470,9 +471,9 @@ coap_hash_path(const unsigned char *path, size_t len, coap_key_t key) {
 
 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);
 
@@ -513,7 +514,7 @@ coap_parse_next(coap_parse_iterator_t *pi) {
   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;
   }
index 98fd5d8..31ee386 100644 (file)
@@ -3,7 +3,7 @@
  * 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;
 
 /**
@@ -40,14 +41,14 @@ coap_uri_t *coap_new_uri(const unsigned char *uri, unsigned int length);
  * be released with coap_free(). */
 coap_uri_t *coap_clone_uri(const coap_uri_t *uri);
 
-/** 
- * Calculates a hash over the given path and stores the result in 
+/**
+ * Calculates a hash over the given path and stores the result in
  * @p key. This function returns @c 0 on error or @c 1 on success.
- * 
+ *
  * @param path The URI path to generate hash for.
  * @param len  The length of @p path.
  * @param key  The output buffer.
- * 
+ *
  * @return @c 1 if @p key was set, @c 0 otherwise.
  */
 int coap_hash_path(const unsigned char *path, size_t len, coap_key_t key);
@@ -60,7 +61,7 @@ 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.
@@ -76,53 +77,53 @@ int coap_hash_path(const unsigned char *path, size_t len, coap_key_t key);
  * @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.
@@ -134,39 +135,39 @@ unsigned char *coap_parse_next(coap_parse_iterator_t *pi);
 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);
 
 /** @} */
 
index df468e9..8fed5e0 100644 (file)
@@ -90,6 +90,7 @@ OCTBSTACK_DIR = stack
 OCMALLOC_DIR   = ocmalloc
 EXTLIBS_DIR    = ../../extlibs
 CJSON_DIR      = $(EXTLIBS_DIR)/cjson
+TINYDTLS_DIR   = tinydtls
 
 OCCOAP_SRC     = $(OCCOAP_DIR)/src
 OCTBSTACK_SRC  = $(OCTBSTACK_DIR)/src
@@ -162,6 +163,15 @@ liboctbstack.a: obj_build
        @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
 
index 56a99ca..b0999de 100644 (file)
@@ -71,7 +71,8 @@ CreateNewOptionNode(unsigned short key, unsigned int length,
 // 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,
index 4081675..8c3dab0 100644 (file)
@@ -203,7 +203,8 @@ static void HandleCoAPRequests(struct coap_context_t *ctx,
 
     // 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);
@@ -638,11 +639,12 @@ OCStackResult OCDoCoAPResource(OCMethod method, OCQualityOfService qos, OCCoAPTo
                 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);
@@ -738,7 +740,8 @@ OCStackResult OCSendCoAPNotification (unsigned char * uri, OCDevAddr *dstAddr,
     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"));
@@ -771,8 +774,7 @@ OCStackResult OCProcessCoAP() {
     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) {
@@ -782,6 +784,13 @@ OCStackResult OCProcessCoAP() {
             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);
index 6877d5e..3d4e2bc 100644 (file)
@@ -316,7 +316,8 @@ OCStackResult ParseCoAPPdu(coap_pdu_t * pdu, unsigned char * uriBuf,
 // 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;
 
@@ -333,6 +334,8 @@ OCStackResult FormOCRequest(OCRequest * * requestLoc, OCQualityOfService qos,
     // fill in uri
     request->resourceUrl = uriBuf;
 
+    request->secure = secure;
+
     // fill in observe
     request->observe = observeReq;
 
@@ -562,14 +565,15 @@ SendCoAPPdu(coap_context_t * gCoAPCtx, coap_address_t* dst, coap_pdu_t * pdu,
 {
     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)
     {
@@ -578,7 +582,8 @@ SendCoAPPdu(coap_context_t * gCoAPCtx, coap_address_t* dst, coap_pdu_t * pdu,
         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);
index 5fce889..69367f7 100644 (file)
@@ -189,14 +189,14 @@ int32_t OCInitUDP(OCDevAddr* ipAddr, int32_t *sockfd)
         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;
     }
index 075b109..3fcaa15 100644 (file)
@@ -164,6 +164,8 @@ typedef struct {
     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
index f1a04fd..a40f056 100644 (file)
@@ -114,12 +114,14 @@ typedef enum {
  * 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;
 
 /**
diff --git a/resource/csdk/stack/samples/linux/secure/common.cpp b/resource/csdk/stack/samples/linux/secure/common.cpp
new file mode 100644 (file)
index 0000000..8664f2e
--- /dev/null
@@ -0,0 +1,72 @@
+//******************************************************************
+//
+// 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";
+    }
+}
diff --git a/resource/csdk/stack/samples/linux/secure/makefile b/resource/csdk/stack/samples/linux/secure/makefile
new file mode 100644 (file)
index 0000000..9e5bcc1
--- /dev/null
@@ -0,0 +1,110 @@
+# //******************************************************************
+# //
+# // 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)
diff --git a/resource/csdk/stack/samples/linux/secure/occlientbasicops.cpp b/resource/csdk/stack/samples/linux/secure/occlientbasicops.cpp
new file mode 100644 (file)
index 0000000..8059bc3
--- /dev/null
@@ -0,0 +1,374 @@
+//******************************************************************
+//
+// 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);
+}
diff --git a/resource/csdk/stack/samples/linux/secure/occlientbasicops.h b/resource/csdk/stack/samples/linux/secure/occlientbasicops.h
new file mode 100644 (file)
index 0000000..e8e9307
--- /dev/null
@@ -0,0 +1,93 @@
+//******************************************************************
+//
+// 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
diff --git a/resource/csdk/stack/samples/linux/secure/ocserverbasicops.cpp b/resource/csdk/stack/samples/linux/secure/ocserverbasicops.cpp
new file mode 100644 (file)
index 0000000..ecb4188
--- /dev/null
@@ -0,0 +1,324 @@
+//******************************************************************
+//
+// 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;
+}
diff --git a/resource/csdk/stack/samples/linux/secure/ocserverbasicops.h b/resource/csdk/stack/samples/linux/secure/ocserverbasicops.h
new file mode 100644 (file)
index 0000000..af9f00c
--- /dev/null
@@ -0,0 +1,74 @@
+//******************************************************************
+//
+// 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
index 69355d1..78821a7 100644 (file)
@@ -88,7 +88,7 @@ static OCStackResult ValidateUrlQuery (unsigned char *url, unsigned char *query,
     #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
@@ -304,6 +304,13 @@ OCStackResult DetermineResourceHandling (OCRequest *request,
             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
index d1d9d84..3e96df0 100644 (file)
@@ -751,7 +751,7 @@ OCStackResult OCCreateResource(OCResourceHandle *handle,
 
     // 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;
     }