Merge remote-tracking branch 'origin/routing-manager'
authorJaehong Jo <jaehong.jo@samsung.com>
Thu, 17 Sep 2015 02:26:45 +0000 (11:26 +0900)
committerPatrick Lankswert <patrick.lankswert@intel.com>
Thu, 17 Sep 2015 16:55:43 +0000 (16:55 +0000)
Implementation for Routing Manager.
1) Gateway resource Hosting and exchange of routing tables.
2) Linklist implemenation.
3) Routing table manager to add, remove, get next hop etc.
4) Routing message parser using cbor parser funtions.
5) Dynamic route updates on addition/removal of gateways.
6) Support for Endpoint

Please refer to below links for wiki and jira updates.
https://wiki.iotivity.org/routing_through_heterogeneous_transports
https://jira.iotivity.org/browse/IOT-565

Change-Id: I228b59ef922f55552386fb0b0e1b2bb2343b1adb
Signed-off-by: Abhishek Sharma <ce.abhishek@samsung.com>
Signed-off-by: koushik.girijala <g.koushik@samsung.com>
Signed-off-by: vimala.v <vimala.v@samsung.com>
Signed-off-by: Jaehong Jo <jaehong.jo@samsung.com>
Reviewed-on: https://gerrit.iotivity.org/gerrit/2301
Tested-by: jenkins-iotivity <jenkins-iotivity@opendaylight.org>
Reviewed-by: Ashok Babu Channa <ashok.channa@samsung.com>
Reviewed-by: Patrick Lankswert <patrick.lankswert@intel.com>
62 files changed:
android/android_api/base/jni/JniUtils.h
android/android_api/base/src/main/java/org/iotivity/base/ModeType.java
build_common/SConscript
resource/SConscript
resource/csdk/SConscript
resource/csdk/connectivity/api/cacommon.h
resource/csdk/connectivity/build/SConscript
resource/csdk/connectivity/common/SConscript
resource/csdk/connectivity/common/inc/logger.h
resource/csdk/connectivity/common/inc/ulinklist.h [new file with mode: 0644]
resource/csdk/connectivity/common/src/caremotehandler.c
resource/csdk/connectivity/common/src/logger.c
resource/csdk/connectivity/common/src/ulinklist.c [new file with mode: 0644]
resource/csdk/connectivity/src/SConscript
resource/csdk/connectivity/src/bt_edr_adapter/tizen/caedrnwmonitor.c
resource/csdk/connectivity/src/bt_le_adapter/caleadapter.c
resource/csdk/connectivity/src/camessagehandler.c
resource/csdk/connectivity/src/caprotocolmessage.c
resource/csdk/connectivity/src/caqueueingthread.c
resource/csdk/logger/include/logger.h
resource/csdk/logger/src/logger.c
resource/csdk/ocrandom/src/ocrandom.c
resource/csdk/routing/SConscript [new file with mode: 0644]
resource/csdk/routing/include/routingmanager.h [new file with mode: 0644]
resource/csdk/routing/include/routingmanagerinterface.h [new file with mode: 0644]
resource/csdk/routing/include/routingmessageparser.h [new file with mode: 0644]
resource/csdk/routing/include/routingtablemanager.h [new file with mode: 0644]
resource/csdk/routing/include/routingutility.h [new file with mode: 0644]
resource/csdk/routing/src/routingmanager.c [new file with mode: 0644]
resource/csdk/routing/src/routingmanagerinterface.c [new file with mode: 0644]
resource/csdk/routing/src/routingmessageparser.c [new file with mode: 0644]
resource/csdk/routing/src/routingtablemanager.c [new file with mode: 0644]
resource/csdk/routing/src/routingutility.c [new file with mode: 0644]
resource/csdk/stack/include/internal/ocresourcehandler.h
resource/csdk/stack/include/internal/ocstackinternal.h
resource/csdk/stack/include/ocpayload.h
resource/csdk/stack/include/ocstackconfig.h
resource/csdk/stack/include/octypes.h
resource/csdk/stack/include/payload_logging.h
resource/csdk/stack/samples/linux/SimpleClientServer/SConscript
resource/csdk/stack/samples/linux/SimpleClientServer/occlient.cpp
resource/csdk/stack/samples/linux/SimpleClientServer/ocrouting.cpp [new file with mode: 0644]
resource/csdk/stack/samples/linux/SimpleClientServer/ocserver.cpp
resource/csdk/stack/samples/tizen/SimpleClientServer/SConscript
resource/csdk/stack/samples/tizen/SimpleClientServer/occlient.cpp
resource/csdk/stack/samples/tizen/SimpleClientServer/occlient.h
resource/csdk/stack/samples/tizen/SimpleClientServer/ocrouting.cpp [new file with mode: 0644]
resource/csdk/stack/samples/tizen/SimpleClientServer/ocserver.cpp
resource/csdk/stack/samples/tizen/SimpleClientServer/ocserver.h
resource/csdk/stack/samples/tizen/SimpleClientServer/packaging/com.oic.ri.sample.spec
resource/csdk/stack/samples/tizen/SimpleClientServer/scons/SConscript
resource/csdk/stack/samples/tizen/build/SConscript
resource/csdk/stack/samples/tizen/build/gbsbuild.sh
resource/csdk/stack/samples/tizen/build/packaging/com.oic.ri.spec
resource/csdk/stack/src/ocobserve.c
resource/csdk/stack/src/ocresource.c
resource/csdk/stack/src/ocserverrequest.c
resource/csdk/stack/src/ocstack.c
resource/include/OCApi.h
resource/src/InProcServerWrapper.cpp
resource/src/OCPlatform_impl.cpp
resource/src/SConscript

index 70e8054..c87de9e 100644 (file)
@@ -67,6 +67,8 @@ public:
             return OC::ModeType::Client;
         case 2:
             return OC::ModeType::Both;
+        case 3:
+            return OC::ModeType::Gateway;
         default:
             ThrowOcException(OC_STACK_INVALID_PARAM, "Unexpected mode type");
             return OC::ModeType::Both;
index 70a69a5..96ce9d7 100644 (file)
@@ -25,7 +25,8 @@ package org.iotivity.base;
 public enum ModeType {
     SERVER(0),
     CLIENT(1),
-    CLIENT_SERVER(2),;
+    CLIENT_SERVER(2),
+    GATEWAY(3),;  /**< Client server mode along with Routing capabilities.*/
 
     private int value;
 
index 9df8f41..4f0bf76 100644 (file)
@@ -90,6 +90,7 @@ help_vars.Add(EnumVariable('SECURED', 'Build with DTLS', '0', allowed_values=('0
 help_vars.Add(EnumVariable('TEST', 'Run unit tests', '0', allowed_values=('0', '1')))
 help_vars.Add(BoolVariable('LOGGING', 'Enable stack logging', logging_default))
 help_vars.Add(BoolVariable('UPLOAD', 'Upload binary ? (For Arduino)', require_upload))
+help_vars.Add(EnumVariable('ROUTING', 'Enable routing', 'EP', allowed_values=('GW', 'EP')))
 help_vars.Add(EnumVariable('BUILD_SAMPLE', 'Build with sample', 'ON', allowed_values=('ON', 'OFF')))
 help_vars.AddVariables(('DEVICE_NAME', 'Network display name for device (For Arduino)', device_name, None, None),)
 help_vars.Add(PathVariable('ANDROID_NDK', 'Android NDK path', None, PathVariable.PathAccept))
index 6a189b2..1bea369 100644 (file)
@@ -42,6 +42,10 @@ SConscript('c_common/SConscript')
 # Build connectivity
 SConscript('csdk/connectivity/SConscript')
 
+if env.get('ROUTING') in ['GW', 'EP']:
+       # Build Routing
+       SConscript('csdk/routing/SConscript')
+
 # Build libocsrm
 SConscript('csdk/security/SConscript')
 
index 9070aeb..9f887e9 100644 (file)
@@ -61,6 +61,11 @@ if target_os not in ['arduino', 'windows', 'winrt']:
        liboctbstack_env.AppendUnique(CPPDEFINES  = ['WITH_POSIX'])
        liboctbstack_env.AppendUnique(CFLAGS = ['-std=c99'])
 
+if liboctbstack_env.get('ROUTING') == 'GW':
+       liboctbstack_env.AppendUnique(CPPDEFINES = ['ROUTING_GATEWAY'])
+elif liboctbstack_env.get('ROUTING') == 'EP':
+       liboctbstack_env.AppendUnique(CPPDEFINES = ['ROUTING_EP'])
+
 if target_os not in ['windows', 'winrt']:
        liboctbstack_env.AppendUnique(CFLAGS = ['-Wall'])
 
@@ -98,6 +103,9 @@ if env.get('LOGGING'):
 
 liboctbstack_env.Append(LIBS = ['c_common'])
 
+if liboctbstack_env.get('ROUTING') in ['GW', 'EP']:
+       liboctbstack_env.Prepend(LIBS = ['routingmanager'])
+
 ######################################################################
 # Source files and Targets
 ######################################################################
index 29ac9cc..b85364c 100644 (file)
@@ -54,7 +54,7 @@ extern "C"
 /**
  * Max header options data length
  */
-#define CA_MAX_HEADER_OPTION_DATA_LENGTH 16
+#define CA_MAX_HEADER_OPTION_DATA_LENGTH 20
 
 /**
 * Max token length
@@ -240,6 +240,10 @@ typedef struct
     uint16_t                port;       // for IP
     char                    addr[MAX_ADDR_STR_SIZE_CA]; // address for all
     uint32_t                interface;  // usually zero for default interface
+#if defined (ROUTING_GATEWAY) || defined (ROUTING_EP)
+    char                    routeData[MAX_ADDR_STR_SIZE_CA]; /**< GatewayId:ClientId of
+                                                                    destination. **/
+#endif
 } CAEndpoint_t;
 
 /**
@@ -363,6 +367,10 @@ typedef struct
 {
 
     CAMessageType_t type;       /**< Qos for the request */
+#ifdef ROUTING_GATEWAY
+    bool skipRetransmission;    /**< Will not attempt retransmission even if type is CONFIRM.
+                                     Required for packet forwarding */
+#endif
     uint16_t messageId;         /**< Message id.
                                  * if message id is zero, it will generated by CA inside.
                                  * otherwise, you can use it */
@@ -446,6 +454,8 @@ typedef struct
 {
     CATransportFlags_t flags;
     uint16_t messageId;
+    char token[CA_MAX_TOKEN_LEN];
+    uint8_t tokenLength;
 } CAHistoryItem_t;
 
 typedef struct
index 4a8942d..045faab 100644 (file)
@@ -64,6 +64,7 @@ help_vars.Add(ListVariable('TARGET_TRANSPORT', 'Target transport', 'ALL', ['ALL'
 help_vars.Add(EnumVariable('TARGET_ARCH', 'Target architecture', default_arch, os_arch_map[target_os]))
 help_vars.Add(EnumVariable('SECURED', 'Build with DTLS', '0', allowed_values=('0', '1')))
 help_vars.Add(BoolVariable('UPLOAD', 'Upload binary ? (For Arduino)', require_upload))
+help_vars.Add(EnumVariable('ROUTING', 'Enable routing', 'EP', allowed_values=('GW', 'EP')))
 help_vars.Add(EnumVariable('BUILD_SAMPLE', 'Build with sample', 'ON', allowed_values=('ON', 'OFF')))
 
 help_vars.AddVariables(('DEVICE_NAME', 'Network display name for device', 'OIC-DEVICE', None, None),)
index 2336f2e..d07c625 100644 (file)
@@ -28,6 +28,7 @@ for item in temp:
 ######################################################################
 ca_common_src = [
                ca_common_src_path + 'uarraylist.c',
+               ca_common_src_path + 'ulinklist.c',
                ca_common_src_path + 'uqueue.c',
                ca_common_src_path + 'caremotehandler.c'
        ]
index 18096d3..e48ee7c 100644 (file)
@@ -59,17 +59,25 @@ extern "C"
 #define MAX_LOG_V_BUFFER_SIZE (256)
 
 // Log levels
-#ifndef __TIZEN__
+#ifdef __TIZEN__
+typedef enum {
+    DEBUG = DLOG_DEBUG,
+    INFO = DLOG_INFO,
+    WARNING = DLOG_WARN,
+    ERROR = DLOG_ERROR,
+    FATAL = DLOG_ERROR
+} LogLevel;
+#else
 typedef enum
 {
     DEBUG = 0, INFO, WARNING, ERROR, FATAL
 } LogLevel;
-#else
-#define DEBUG DLOG_DEBUG
-#define INFO DLOG_INFO
-#define WARNING DLOG_WARN
-#define ERROR DLOG_ERROR
-#define FATAL DLOG_ERROR
+#endif
+
+#ifdef __TIZEN__
+#define OC_LOG(level,tag,mes) LOG_(LOG_ID_MAIN, level, tag, mes)
+#define OC_LOG_V(level,tag,fmt,args...) LOG_(LOG_ID_MAIN, level, tag, fmt,##args)
+#define OC_LOG_BUFFER(level, tag, buffer, bufferSize)
 #endif
 
 #ifdef __TIZEN__
diff --git a/resource/csdk/connectivity/common/inc/ulinklist.h b/resource/csdk/connectivity/common/inc/ulinklist.h
new file mode 100644 (file)
index 0000000..7846d24
--- /dev/null
@@ -0,0 +1,136 @@
+/* ****************************************************************
+ *
+ * Copyright 2015 Samsung Electronics 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 U_LINKLIST_H_
+#define U_LINKLIST_H_
+
+/**
+ * @todo Do performance comparision with array list.
+ */
+
+#include <stdint.h>
+#include "cacommon.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+#ifndef OICDEFINE
+#include <stdbool.h>
+
+#endif
+
+/**
+ * link list structure
+ */
+typedef struct linked_list_data u_linklist_data_t;
+
+typedef struct linked_list_data u_linklist_iterator_t;
+
+typedef struct u_linklist
+{
+    u_linklist_data_t *list;
+    int size;
+}u_linklist_t;
+
+struct linked_list_data
+{
+    void *data;
+    u_linklist_data_t *next;
+};
+
+/**
+ * API to create link list and initializes the elements.
+ * @return  u_linklist_t if Success, NULL otherwise.
+ */
+u_linklist_t *u_linklist_create();
+
+/**
+ * Resets and deletes the link list
+ * Linklist elements are deleted, Calling function must take care of freeing
+ * dynamic memory allocated before freeing the linklist.
+ * @param[in,out] list      u_linklist pointer.
+ * @return ::CA_STATUS_OK if Success, ::CA_STATUS_INVALID_PARAM if pointer to list is NULL.
+ */
+CAResult_t u_linklist_free(u_linklist_t **list);
+
+/**
+ * Add data to the head of the link list.
+ * @param[in/out]  list      pointer of link list.
+ * @param[in]      data      pointer of data.
+ * @return ::CA_STATUS_OK if Success, ::CA_MEMORY_ALLOC_FAILED if memory allocation fails.
+ */
+CAResult_t u_linklist_add_head(u_linklist_t *list, void *data);
+
+/**
+ * Add data to the tail of the link list.
+ * @param[in/out]  list      pointer of link list.
+ * @param[in]      data      pointer of data.
+ * @return ::CA_STATUS_OK if Success, ::CA_MEMORY_ALLOC_FAILED if memory allocation fails.
+ */
+CAResult_t u_linklist_add(u_linklist_t *list, void *data);
+
+
+/**
+ * This api deletes node pointed by iterator.
+ * Advances iterator to next node in the list.
+ * @param[in/out]   list         pointer of link list.
+ * @param[in/out]   iter         pointer of iterator pointing to previous node.
+ * @return ::CA_STATUS_OK if Success, ::CA_STATUS_INVALID_PARAM if iterator is NULL.
+ */
+CAResult_t u_linklist_remove(u_linklist_t *list, u_linklist_iterator_t **iter);
+
+
+/**
+ * Returns the length of the link list.
+ * @param[in] list               pointer of link list.
+ * @return length of the link list.
+ */
+uint32_t u_linklist_length(const u_linklist_t *list);
+
+/**
+ * Initializes the iterator, need to be called before calling u_linklist_get_next.
+ * @param[in]       list             pointer of link list.
+ * @param[in,out]   iter             iterator of link list.
+ * @return NONE
+ */
+void u_linklist_init_iterator(const u_linklist_t *list, u_linklist_iterator_t **iter);
+
+/**
+ * Returns the data of the node iterator points to from the link list.
+ * @param[in] iter             iterator of link list.
+ * @return the data of node to which iterator is pointing.
+ */
+void *u_linklist_get_data(const u_linklist_iterator_t *iter);
+
+/**
+ * Returns the data of the next node iterator points to from the link list
+ * Advances iterator to next node in the list.
+ * @param[in,out] iter             iterator of link list.
+ * @return the data of next node.
+ */
+void *u_linklist_get_next(u_linklist_iterator_t **iter);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* U_LINKLIST_H_ */
+
index 91b7199..a39b7d4 100644 (file)
@@ -301,6 +301,10 @@ CAResult_t CACloneInfo(const CAInfo_t *info, CAInfo_t *clone)
         clone->resourceUri = temp;
     }
 
+#ifdef ROUTING_GATEWAY
+    clone->skipRetransmission = info->skipRetransmission;
+#endif
+
     clone->messageId = info->messageId;
     clone->type = info->type;
 
index bcdc905..19b01e2 100644 (file)
@@ -457,4 +457,4 @@ void OICLogv(LogLevel level, const char *tag, const __FlashStringHelper *format,
     va_end(ap);
 }
 
-#endif //ARDUINO
+#endif //ARDUINO
\ No newline at end of file
diff --git a/resource/csdk/connectivity/common/src/ulinklist.c b/resource/csdk/connectivity/common/src/ulinklist.c
new file mode 100644 (file)
index 0000000..7a87de1
--- /dev/null
@@ -0,0 +1,217 @@
+/* ****************************************************************
+ *
+ * Copyright 2015 Samsung Electronics 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 "ulinklist.h"
+#include "logger.h"
+#include "oic_malloc.h"
+#include "caadapterutils.h"
+
+/**
+ * Logging tag for module name.
+ */
+#define TAG "ULINKLIST"
+
+u_linklist_t *u_linklist_create()
+{
+    u_linklist_t *header = (u_linklist_t *)OICMalloc(sizeof(u_linklist_t));
+    if (!header)
+    {
+        OIC_LOG(ERROR, TAG, "Out of memory");
+        return NULL;
+    }
+    header->list=NULL;
+    header->size=0;
+    return header;
+}
+
+CAResult_t u_linklist_add_head(u_linklist_t *linklist, void *data)
+{
+    VERIFY_NON_NULL(linklist, TAG, "list is null");
+    VERIFY_NON_NULL(data, TAG, "data is null");
+
+    u_linklist_data_t *add_node = NULL;
+    add_node = (u_linklist_data_t *) OICMalloc(sizeof(u_linklist_data_t));
+    if (NULL == add_node)
+    {
+        OIC_LOG(DEBUG, TAG, "LinklistAdd FAIL, memory allocation failed");
+        return CA_MEMORY_ALLOC_FAILED;
+    }
+    add_node->data = data;
+    add_node->next = linklist->list;
+    linklist->list = add_node;
+    linklist->size += 1;
+    return CA_STATUS_OK;
+}
+
+CAResult_t u_linklist_add(u_linklist_t *linklist, void *data)
+{
+    VERIFY_NON_NULL(linklist, TAG, "list is null");
+    VERIFY_NON_NULL(data, TAG, "data is null");
+
+    u_linklist_data_t *add_node = NULL;
+    u_linklist_data_t *node = linklist->list;
+    add_node = (u_linklist_data_t *) OICMalloc(sizeof(u_linklist_data_t));
+    if (NULL == add_node)
+    {
+        OIC_LOG(DEBUG, TAG, "LinklistAdd FAIL, memory allocation failed");
+        return CA_MEMORY_ALLOC_FAILED;
+    }
+
+    add_node->data = data;
+    add_node->next = NULL;
+
+    if (NULL == node)
+    {
+        linklist->list = add_node;
+        linklist->size += 1;
+    }
+    else
+    {
+        //else loop through the list and find the last node, insert next to it
+        while (true)
+        {
+            if(node->next == NULL)
+            {
+                node->next = add_node;
+                linklist->size += 1;
+                break;
+            }
+            node = node->next;
+        };
+    }
+
+    return CA_STATUS_OK;
+}
+
+CAResult_t u_linklist_free(u_linklist_t **linklist)
+{
+    VERIFY_NON_NULL(linklist, TAG, "linklist is null");
+    if (!(*linklist))
+    {
+        OIC_LOG(DEBUG, TAG, "List is already Empty");
+        return CA_STATUS_OK;
+    }
+
+    u_linklist_data_t *free_node=NULL;
+    while((*linklist)->size)
+    {
+        free_node = (*linklist)->list;
+        (*linklist)->list = (*linklist)->list->next;
+
+        if(free_node != NULL)
+        {
+            OICFree(free_node);
+            free_node=NULL;
+        }
+
+        (*linklist)->size -= 1;
+    }
+    *linklist=NULL;
+
+    return CA_STATUS_OK;
+}
+
+CAResult_t u_linklist_remove(u_linklist_t *linklist, u_linklist_iterator_t **iter)
+{
+    VERIFY_NON_NULL(linklist, TAG, "list is null");
+    VERIFY_NON_NULL(iter, TAG, "iterator is null");
+
+    if (NULL == *iter)
+    {
+        return CA_STATUS_INVALID_PARAM;
+    }
+
+    // When node to be deleted is head node
+    if (linklist->list == *iter)
+    {
+        // store address of next node
+        linklist->list = linklist->list->next;
+
+        // free memory
+        linklist->size -=1;
+        OICFree(*iter);
+
+        *iter = linklist->list;
+
+        return CA_STATUS_OK;
+    }
+
+
+    // When not first node, follow the normal deletion process find the previous node
+    u_linklist_data_t *prev = linklist->list;
+    while(NULL != prev->next && prev->next != *iter)
+    {
+        prev = prev->next;
+    }
+
+    // Check if node really exists in Linked List
+    if (NULL == prev->next)
+    {
+        OIC_LOG(ERROR, TAG, " Given node is not present in Linked List\n");
+        return CA_STATUS_FAILED;
+    }
+
+    // Remove node from Linked List
+    prev->next = prev->next->next;
+    linklist->size -=1;
+    OICFree(*iter);
+    *iter = prev->next;
+
+    return CA_STATUS_OK;
+}
+
+
+uint32_t u_linklist_length(const u_linklist_t *linklist)
+{
+    VERIFY_NON_NULL(linklist, TAG, "list is null");
+
+    return linklist->size;
+}
+
+void u_linklist_init_iterator(const u_linklist_t *linklist, u_linklist_iterator_t **iter)
+{
+    VERIFY_NON_NULL_VOID(linklist, TAG, "list is null");
+    VERIFY_NON_NULL_VOID(iter, TAG, "iterator is null");
+
+    *iter = linklist->list;
+}
+
+void *u_linklist_get_data(const u_linklist_iterator_t *iter)
+{
+    VERIFY_NON_NULL_RET(iter, TAG, "iterator is null", NULL);
+
+    return iter->data;
+}
+
+void *u_linklist_get_next(u_linklist_iterator_t **iter)
+{
+    VERIFY_NON_NULL_RET(iter, TAG, "iterator is null", NULL);
+    *iter = (*iter)->next;
+
+    if (NULL != *iter)
+    {
+        return (*iter)->data;
+    }
+    else
+    {
+        return NULL;
+    }
+}
index 2165802..d671fb7 100644 (file)
@@ -56,6 +56,12 @@ if env.get('SECURED') == '1':
                                                  'external/inc')])
 
 ca_common_src = None
+
+if env.get('ROUTING') == 'GW':
+       env.AppendUnique(CPPDEFINES = ['ROUTING_GATEWAY'])
+elif env.get('ROUTING') == 'EP':
+       env.AppendUnique(CPPDEFINES = ['ROUTING_EP'])
+
 if ca_os == 'arduino':
        env.AppendUnique(CPPDEFINES = ['SINGLE_THREAD'])
        env.AppendUnique(CPPDEFINES = ['WITH_ARDUINO'])
index d9af8e6..dd3e11d 100644 (file)
@@ -51,9 +51,10 @@ static CAEDRNetworkStatusCallback g_edrNetworkChangeCallback = NULL;
 static void CAEDRAdapterStateChangeCallback(int result, bt_adapter_state_e adapterState,
                                             void *userData);
 
-void GMainLoopThread (void *param)
+void *GMainLoopThread (void *param)
 {
     g_main_loop_run(g_mainloop);
+    return NULL;
 }
 
 CAResult_t CAEDRInitializeNetworkMonitor(const ca_thread_pool_t threadPool)
@@ -125,8 +126,9 @@ CAResult_t CAEDRStopNetworkMonitor()
     }
 
     if (g_mainloop)
-        g_main_loop_unref(g_mainloop);
-
+    {
+        g_main_loop_quit(g_mainloop);
+    }
     OIC_LOG(DEBUG, EDR_ADAPTER_TAG, "OUT");
     return CA_STATUS_OK;
 }
index d4ced58..60cffdb 100644 (file)
@@ -1738,6 +1738,7 @@ static void CATerminateLE()
 static CAResult_t CAStartLEListeningServer()
 {
     OIC_LOG(DEBUG, CALEADAPTER_TAG, "IN");
+#ifndef ROUTING_GATEWAY
     CAResult_t result = CA_STATUS_OK;
 #ifndef SINGLE_THREAD
     result = CAInitLEServerQueues();
@@ -1770,6 +1771,11 @@ static CAResult_t CAStartLEListeningServer()
 
     OIC_LOG(DEBUG, CALEADAPTER_TAG, "OUT");
     return CA_STATUS_OK;
+#else
+    // Routing Gateway only supports BLE client mode.
+    OIC_LOG(ERROR, CALEADAPTER_TAG, "LE server not supported in Routing Gateway");
+    return CA_NOT_SUPPORTED;
+#endif
 }
 
 static CAResult_t CAStartLEDiscoveryServer()
index 6ca7da6..982f1a8 100644 (file)
@@ -83,7 +83,8 @@ static void CAProcessReceivedData(CAData_t *data);
 #endif
 static void CADestroyData(void *data, uint32_t size);
 static void CALogPayloadInfo(CAInfo_t *info);
-static bool CADropSecondMessage(CAHistory_t *history, const CAEndpoint_t *endpoint, uint16_t id);
+static bool CADropSecondMessage(CAHistory_t *history, const CAEndpoint_t *endpoint, uint16_t id,
+                                CAToken_t token, uint8_t tokenLength);
 
 #ifdef WITH_BWT
 void CAAddDataToSendThread(CAData_t *data)
@@ -195,7 +196,8 @@ static CAData_t* CAGenerateHandlerData(const CAEndpoint_t *endpoint,
             return NULL;
         }
 
-        if (CADropSecondMessage(&caglobals.ca.requestHistory, endpoint, reqInfo->info.messageId))
+        if (CADropSecondMessage(&caglobals.ca.requestHistory, endpoint, reqInfo->info.messageId,
+                                reqInfo->info.token, reqInfo->info.tokenLength))
         {
             OIC_LOG(ERROR, TAG, "Second Request with same Token, Drop it");
             CAFreeEndpoint(ep);
@@ -422,11 +424,22 @@ static CAResult_t CAProcessSendData(const CAData_t *data)
     if (SEND_TYPE_UNICAST == type)
     {
         OIC_LOG(DEBUG,TAG,"Unicast message");
+#ifdef ROUTING_GATEWAY
+        /*
+         * When forwarding a packet, do not attempt retransmission as its the responsibility of
+         * packet originator node
+         */
+        bool skipRetransmission = false;
+#endif
+
         if (NULL != data->requestInfo)
         {
             OIC_LOG(DEBUG, TAG, "requestInfo is available..");
 
             info = &data->requestInfo->info;
+#ifdef ROUTING_GATEWAY
+            skipRetransmission = data->requestInfo->info.skipRetransmission;
+#endif
             pdu = CAGeneratePDU(data->requestInfo->method, info, data->remoteEndpoint);
         }
         else if (NULL != data->responseInfo)
@@ -434,6 +447,9 @@ static CAResult_t CAProcessSendData(const CAData_t *data)
             OIC_LOG(DEBUG, TAG, "responseInfo is available..");
 
             info = &data->responseInfo->info;
+#ifdef ROUTING_GATEWAY
+            skipRetransmission = data->responseInfo->info.skipRetransmission;
+#endif
             pdu = CAGeneratePDU(data->responseInfo->result, info, data->remoteEndpoint);
         }
         else
@@ -485,6 +501,9 @@ static CAResult_t CAProcessSendData(const CAData_t *data)
             }
             else
 #endif
+#ifdef ROUTING_GATEWAY
+            if(!skipRetransmission)
+#endif
             {
                 // for retransmission
                 res = CARetransmissionSentData(&g_retransmissionContext, data->remoteEndpoint, pdu->hdr,
@@ -620,10 +639,11 @@ static void CASendThreadProcess(void *threadData)
 #endif
 
 /*
- * If a second message arrives with the same token and the other address
+ * If a second message arrives with the same message ID, token and the other address
  * family, drop it.  Typically, IPv6 beats IPv4, so the IPv4 message is dropped.
  */
-static bool CADropSecondMessage(CAHistory_t *history, const CAEndpoint_t *ep, uint16_t id)
+static bool CADropSecondMessage(CAHistory_t *history, const CAEndpoint_t *ep, uint16_t id,
+                                CAToken_t token, uint8_t tokenLength)
 {
     if (!ep)
     {
@@ -638,13 +658,23 @@ static bool CADropSecondMessage(CAHistory_t *history, const CAEndpoint_t *ep, ui
         return false;
     }
 
+    if (tokenLength > CA_MAX_TOKEN_LEN)
+    {
+        /*
+         * If token length is more than CA_MAX_TOKEN_LEN,
+         * we compare the first CA_MAX_TOKEN_LEN bytes only.
+         */
+        tokenLength = CA_MAX_TOKEN_LEN;
+    }
+
     bool ret = false;
     CATransportFlags_t familyFlags = ep->flags & CA_IPFAMILY_MASK;
 
     for (size_t i = 0; i < sizeof(history->items) / sizeof(history->items[0]); i++)
     {
         CAHistoryItem_t *item = &(history->items[i]);
-        if (id == item->messageId)
+        if (id == item->messageId && tokenLength == item->tokenLength
+            && memcmp(item->token, token, tokenLength) == 0)
         {
             if ((familyFlags ^ item->flags) == CA_IPFAMILY_MASK)
             {
@@ -658,6 +688,12 @@ static bool CADropSecondMessage(CAHistory_t *history, const CAEndpoint_t *ep, ui
 
     history->items[history->nextIndex].flags = familyFlags;
     history->items[history->nextIndex].messageId = id;
+    if (token && tokenLength)
+    {
+        memcpy(history->items[history->nextIndex].token, token, tokenLength);
+        history->items[history->nextIndex].tokenLength = tokenLength;
+    }
+
     if (++history->nextIndex >= HISTORYSIZE)
     {
         history->nextIndex = 0;
index 04b80a0..e3fbe3c 100644 (file)
@@ -563,19 +563,16 @@ CAResult_t CAParseHeadOption(uint32_t code, const CAInfo_t *info, coap_list_t **
         }
         else
         {
-            if ((info->options + i)->optionData && (info->options + i)->optionLength > 0)
+            OIC_LOG_V(DEBUG, TAG, "Head opt ID: %d", id);
+            OIC_LOG_V(DEBUG, TAG, "Head opt data: %s", (info->options + i)->optionData);
+            OIC_LOG_V(DEBUG, TAG, "Head opt length: %d", (info->options + i)->optionLength);
+            int ret = coap_insert(optlist,
+                                  CACreateNewOptionNode(id, (info->options + i)->optionLength,
+                                                        (info->options + i)->optionData),
+                                  CAOrderOpts);
+            if (ret <= 0)
             {
-                OIC_LOG_V(DEBUG, TAG, "Head opt ID: %d", id);
-                OIC_LOG_V(DEBUG, TAG, "Head opt data: %s", (info->options + i)->optionData);
-                OIC_LOG_V(DEBUG, TAG, "Head opt length: %d", (info->options + i)->optionLength);
-                int ret = coap_insert(optlist,
-                                      CACreateNewOptionNode(id, (info->options + i)->optionLength,
-                                                            (info->options + i)->optionData),
-                                      CAOrderOpts);
-                if (ret <= 0)
-                {
-                    return CA_STATUS_INVALID_PARAM;
-                }
+                return CA_STATUS_INVALID_PARAM;
             }
         }
     }
@@ -929,14 +926,12 @@ CAResult_t CAGetInfoFromPDU(const coap_pdu_t *pdu, const CAEndpoint_t *endpoint,
             {
                 if (idx < count)
                 {
-                    uint32_t length = bufLength;
-
-                    if (length <= CA_MAX_HEADER_OPTION_DATA_LENGTH)
+                    if (bufLength <= sizeof(outInfo->options[0].optionData))
                     {
                         outInfo->options[idx].optionID = opt_iter.type;
-                        outInfo->options[idx].optionLength = length;
+                        outInfo->options[idx].optionLength = bufLength;
                         outInfo->options[idx].protocolID = CA_COAP_ID;
-                        memcpy(outInfo->options[idx].optionData, buf, length);
+                        memcpy(outInfo->options[idx].optionData, buf, bufLength);
                         idx++;
                     }
                 }
@@ -1156,12 +1151,6 @@ uint32_t CAGetOptionData(uint16_t key, const uint8_t *data, uint32_t len,
         return 0;
     }
 
-    if (NULL == data || NULL == option)
-    {
-        OIC_LOG(ERROR, TAG, "data/option NULL");
-        return 0;
-    }
-
     if (buflen <= len)
     {
         OIC_LOG(ERROR, TAG, "option buffer too small");
index c410be9..b41a73a 100644 (file)
@@ -60,17 +60,20 @@ static void CAQueueingThreadBaseRoutine(void *threadValue)
             OIC_LOG(DEBUG, TAG, "wake up..");
         }
 
-        // mutex unlock
-        ca_mutex_unlock(thread->threadMutex);
+
 
         // check stop flag
         if (thread->isStop)
         {
+            // mutex unlock
+            ca_mutex_unlock(thread->threadMutex);
             continue;
         }
 
         // get data
         u_queue_message_t *message = u_queue_get_element(thread->dataQueue);
+        // mutex unlock
+        ca_mutex_unlock(thread->threadMutex);
         if (NULL == message)
         {
             continue;
index 81d962d..3c69eae 100644 (file)
@@ -43,11 +43,10 @@ extern "C" {
 // Use the PCF macro to wrap strings stored in FLASH on the Arduino
 // Example:  OC_LOG(INFO, TAG, PCF("Entering function"));
 #ifdef ARDUINO
-
 #ifdef __cplusplus
-    #define PCF(str)  ((PROGMEM const char *)(F(str)))
+#define PCF(str)  ((PROGMEM const char *)(F(str)))
 #else
-    #define PCF(str)  ((PROGMEM const char *)(PSTR(str)))
+#define PCF(str)  ((PROGMEM const char *)(PSTR(str)))
 #endif //__cplusplus
 #else
     #define PCF(str) str
@@ -57,6 +56,15 @@ extern "C" {
 #define MAX_LOG_V_BUFFER_SIZE (256)
 
 // Log levels
+#ifdef __TIZEN__
+typedef enum {
+    DEBUG = DLOG_DEBUG,
+    INFO = DLOG_INFO,
+    WARNING = DLOG_WARN,
+    ERROR = DLOG_ERROR,
+    FATAL = DLOG_ERROR
+} LogLevel;
+#else
 typedef enum {
     DEBUG = 0,
     INFO,
@@ -64,11 +72,6 @@ typedef enum {
     ERROR,
     FATAL
 } LogLevel;
-
-#ifdef __TIZEN__
-
-int OCGetTizenLogLevel(LogLevel level);
-
 #endif
 
 #ifdef __TIZEN__
@@ -162,8 +165,8 @@ int OCGetTizenLogLevel(LogLevel level);
 
 #ifdef TB_LOG
 #ifdef __TIZEN__
-    #define OC_LOG(level,tag,mes) LOG_(LOG_ID_MAIN, OCGetTizenLogLevel(level), tag, mes)
-    #define OC_LOG_V(level,tag,fmt,args...) LOG_(LOG_ID_MAIN, OCGetTizenLogLevel(level), tag, fmt,##args)
+    #define OC_LOG(level,tag,mes) LOG_(LOG_ID_MAIN, level, tag, mes)
+    #define OC_LOG_V(level,tag,fmt,args...) LOG_(LOG_ID_MAIN, level, tag, fmt,##args)
     #define OC_LOG_BUFFER(level, tag, buffer, bufferSize)
 #else // These macros are defined for Linux, Android, and Arduino
     #define OC_LOG_INIT()    OCLogInit()
index da1a420..8e21e33 100644 (file)
@@ -89,32 +89,7 @@ static const uint16_t LINE_BUFFER_SIZE = (16 * 2) + 16 + 1;  // Show 16 bytes, 2
 
 
 #ifndef ARDUINO
-#ifdef __TIZEN__
-
-int OCGetTizenLogLevel(LogLevel level)
-{
-    switch(level)
-    {
-        case DEBUG:
-            return DLOG_DEBUG;
-        case INFO:
-            return DLOG_INFO;
-        case WARNING:
-            return DLOG_WARN;
-        case ERROR:
-            return DLOG_ERROR;
-        case FATAL:
-            /*
-             * Temp fix to resolve DLOG_FATAL runtime crash in tizen binary.
-             * TODO: Revert back to DLOG_FATAL once logging issue is fixed in
-             * Tizen binary.
-             */
-            return DLOG_ERROR;
-    }
-    return DLOG_DEBUG;
-}
-
-#else
+#ifndef __TIZEN__
 void OCLogConfig(oc_log_ctx_t *ctx) {
     logCtx = ctx;
 }
@@ -202,7 +177,6 @@ void OCLog(LogLevel level, const char * tag, const char * logStr) {
     }
     else
     {
-
         int min = 0;
         int sec = 0;
         int ms = 0;
index 0d0f0c1..debbee1 100644 (file)
 //
 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
 
+// Defining _POSIX_C_SOURCE macro with 199309L (or greater) as value
+// causes header files to expose definitions
+// corresponding to the POSIX.1b, Real-time extensions
+// (IEEE Std 1003.1b-1993) specification
+//
+// For this specific file, see use of clock_gettime,
+// Refer to http://pubs.opengroup.org/stage7tc1/functions/clock_gettime.html
+// and to http://man7.org/linux/man-pages/man2/clock_gettime.2.html
+#ifndef _POSIX_C_SOURCE
+#define _POSIX_C_SOURCE 200809L
+#endif
 
 #if defined(__ANDROID__) || defined(__linux__) || defined(__APPLE__)
 #include "fcntl.h"
 #include "unistd.h"
+#include <stdlib.h>
+#include <sys/time.h>
+#include <time.h>
+#if defined(__ANDROID__)
+#include <linux/time.h>
+#endif
 #endif
 #include "ocrandom.h"
 #include <stdio.h>
 #ifdef ARDUINO
 #include "Arduino.h"
 
-uint8_t GetRandomBitRaw() {
+uint8_t GetRandomBitRaw()
+{
     return analogRead((uint8_t)ANALOG_IN) & 0x1;
 }
 
-uint8_t GetRandomBitRaw2() {
+uint8_t GetRandomBitRaw2()
+{
     int a = 0;
-    for(;;) {
+    for (;;)
+    {
         a = GetRandomBitRaw() | (GetRandomBitRaw()<<1);
-        if (a==1){
+        if (a==1)
+        {
             return 0; // 1 to 0 transition: log a zero bit
         }
-        if (a==2){
+        if (a==2)
+        {
             return 1;// 0 to 1 transition: log a one bit
         }
         // For other cases, try again.
     }
 }
 
-uint8_t GetRandomBit() {
+uint8_t GetRandomBit()
+{
     int a = 0;
-    for(;;) {
+    for (;;)
+    {
         a = GetRandomBitRaw2() | (GetRandomBitRaw2()<<1);
-        if (a==1){
+        if (a==1)
+        {
             return 0; // 1 to 0 transition: log a zero bit
         }
-        if (a==2){
+        if (a==2)
+        {
             return 1;// 0 to 1 transition: log a one bit
         }
         // For other cases, try again.
@@ -66,30 +92,55 @@ uint8_t GetRandomBit() {
 }
 #endif
 
-int8_t OCSeedRandom() {
-#if defined(__ANDROID__) || defined(__linux__) || defined(__APPLE__)
+int8_t OCSeedRandom()
+{
+#if defined(__ANDROID__) || defined(__linux__) || defined(__APPLE__) || defined(__TIZEN__)
+    // Get current time to Seed.
+    uint64_t currentTime = 0;
+#ifdef __ANDROID__
+    struct timespec getTs;
+    clock_gettime(CLOCK_MONOTONIC, &getTs);
+    currentTime = (getTs.tv_sec * (uint64_t)1000000000 + getTs.tv_nsec)/1000;
+#elif  _POSIX_TIMERS > 0
+    struct timespec ts;
+    clock_gettime(CLOCK_MONOTONIC, &ts);
+    currentTime = ts.tv_sec * 1000000 + ts.tv_nsec / 1000;
+#else
+    struct timeval tv;
+    gettimeofday(&tv, NULL);
+    currentTime = tv.tv_sec * 1000000 + tv.tv_usec;
+#endif
+
     int32_t fd = open("/dev/urandom", O_RDONLY);
-    if (fd > 0) {
+    if (fd >= 0)
+    {
         uint32_t randomSeed = 0;
         uint32_t totalRead = 0; //how many integers were read
         int32_t currentRead = 0;
-        while (totalRead < sizeof(randomSeed)) {
+        while (totalRead < sizeof(randomSeed))
+        {
             currentRead = read(fd, (uint8_t*) &randomSeed + totalRead,
                     sizeof(randomSeed) - totalRead);
-            if(currentRead > 0){
+            if (currentRead > 0)
+            {
                 totalRead += currentRead;
             }
         }
         close(fd);
-        srand(randomSeed);
-        return 0;
+        srand(randomSeed | currentTime);
     }
-    close(fd);
-    return -1;
+    else
+    {
+        // Do time based seed when problem in accessing "/dev/urandom"
+        srand(currentTime);
+    }
+
+    return 0;
 #elif defined ARDUINO
     uint32_t result =0;
     uint8_t i;
-    for (i=32; i--;){
+    for (i=32; i--;)
+    {
         result += result + GetRandomBit();
     }
     randomSeed(result);
@@ -98,22 +149,27 @@ int8_t OCSeedRandom() {
 
 }
 
-void OCFillRandomMem(uint8_t * location, uint16_t len) {
-    if(!location){
+void OCFillRandomMem(uint8_t * location, uint16_t len)
+{
+    if (!location)
+    {
         return;
     }
-    for (; len--;){
+    for (; len--;)
+    {
         *location++ = OCGetRandomByte();
     }
 }
 
-uint32_t OCGetRandom() {
+uint32_t OCGetRandom()
+{
     uint32_t result = 0;
     OCFillRandomMem((uint8_t*) &result, 4);
     return result;
 }
 
-uint8_t OCGetRandomByte(void) {
+uint8_t OCGetRandomByte(void)
+{
 #if defined(__ANDROID__) || defined(__linux__) || defined(__APPLE__)
     return rand() & 0x00FF;
 #elif defined ARDUINO
@@ -121,17 +177,23 @@ uint8_t OCGetRandomByte(void) {
 #endif
 }
 
-uint32_t OCGetRandomRange(uint32_t firstBound, uint32_t secondBound){
+uint32_t OCGetRandomRange(uint32_t firstBound, uint32_t secondBound)
+{
     uint32_t base;
     uint32_t diff;
     uint32_t result;
-    if(firstBound > secondBound){
+    if (firstBound > secondBound)
+    {
         base = secondBound;
         diff = firstBound - secondBound;
-    }else if(firstBound < secondBound){
+    }
+    else if (firstBound < secondBound)
+    {
         base = firstBound;
         diff = secondBound - firstBound;
-    }else{
+    }
+    else
+    {
         return secondBound;
     }
     result = ((float)OCGetRandom()/((float)(0xFFFFFFFF))*(float)diff) + (float) base;
@@ -141,7 +203,7 @@ uint32_t OCGetRandomRange(uint32_t firstBound, uint32_t secondBound){
 #if defined(__ANDROID__)
 uint8_t parseUuidChar(char c)
 {
-    if(isdigit(c))
+    if (isdigit(c))
     {
         return c - '0';
     }
@@ -158,7 +220,7 @@ uint8_t parseUuidPart(const char *c)
 
 OCRandomUuidResult OCGenerateUuid(uint8_t uuid[UUID_SIZE])
 {
-    if(!uuid)
+    if (!uuid)
     {
         return RAND_UUID_INVALID_PARAM;
     }
@@ -166,7 +228,7 @@ OCRandomUuidResult OCGenerateUuid(uint8_t uuid[UUID_SIZE])
     char uuidString[UUID_STRING_SIZE];
     int8_t ret = OCGenerateUuidString(uuidString);
 
-    if(ret < 0)
+    if (ret < 0)
     {
         return ret;
     }
@@ -206,28 +268,28 @@ OCRandomUuidResult OCGenerateUuid(uint8_t uuid[UUID_SIZE])
 
 OCRandomUuidResult OCGenerateUuidString(char uuidString[UUID_STRING_SIZE])
 {
-    if(!uuidString)
+    if (!uuidString)
     {
         return RAND_UUID_INVALID_PARAM;
     }
 #if defined(__ANDROID__)
     int32_t fd = open("/proc/sys/kernel/random/uuid", O_RDONLY);
-    if(fd > 0)
+    if (fd > 0)
     {
         ssize_t readResult = read(fd, uuidString, UUID_STRING_SIZE - 1);
         close(fd);
-        if(readResult < 0)
+        if (readResult < 0)
         {
             return RAND_UUID_READ_ERROR;
         }
-        else if(readResult < UUID_STRING_SIZE - 1)
+        else if (readResult < UUID_STRING_SIZE - 1)
         {
             uuidString[0] = '\0';
             return RAND_UUID_READ_ERROR;
         }
 
         uuidString[UUID_STRING_SIZE - 1] = '\0';
-        for(char* p = uuidString; *p; ++p)
+        for (char* p = uuidString; *p; ++p)
         {
             *p = tolower(*p);
         }
@@ -242,7 +304,7 @@ OCRandomUuidResult OCGenerateUuidString(char uuidString[UUID_STRING_SIZE])
     uint8_t uuid[UUID_SIZE];
     int8_t ret = OCGenerateUuid(uuid);
 
-    if(ret != 0)
+    if (ret != 0)
     {
         return ret;
     }
diff --git a/resource/csdk/routing/SConscript b/resource/csdk/routing/SConscript
new file mode 100644 (file)
index 0000000..d3d68ba
--- /dev/null
@@ -0,0 +1,61 @@
+Import('env')
+import os
+
+env.AppendUnique(CPPPATH = [os.path.join(Dir('.').abspath, './include')])
+
+if env.get('TARGET_OS') == 'tizen':
+       env.AppendUnique(LIBPATH = [env.get('BUILD_DIR')])
+else:
+       env.AppendUnique(LIBPATH = [os.path.join(env.get('BUILD_DIR'), 'resource/csdk/routing/')])
+
+env.AppendUnique(LIBS = ['routingmanager'])
+
+local_env = env.Clone()
+
+if env.get('ROUTING') == 'GW':
+       local_env.AppendUnique(CPPPATH = [
+                               os.path.join(Dir('.').abspath, './../stack/include'),
+                               os.path.join(Dir('.').abspath, './../stack/include/internal'),
+                               os.path.join(Dir('.').abspath, './../logger'),
+                               os.path.join(Dir('.').abspath, './../../oc_logger/include'),
+                               os.path.join(Dir('.').abspath, './../ocrandom/include'),
+                               os.path.join(Dir('.').abspath, './../connectivity/api'),
+                               os.path.join(Dir('.').abspath, './../connectivity/common/inc'),
+                               os.path.join(Dir('.').abspath, './../security/include'),
+                               os.path.join(Dir('.').abspath, './../connectivity/external/inc')
+                       ])
+elif env.get('ROUTING') == 'EP':
+       local_env.AppendUnique(CPPPATH = [
+                               os.path.join(Dir('.').abspath, './../stack/include'),
+                               os.path.join(Dir('.').abspath, './../stack/include/internal'),
+                               os.path.join(Dir('.').abspath, './../logger'),
+                               os.path.join(Dir('.').abspath, './../../oc_logger/include'),
+                               os.path.join(Dir('.').abspath, './../connectivity/api'),
+                               os.path.join(Dir('.').abspath, './../connectivity/common/inc'),
+                               os.path.join(Dir('.').abspath, './../connectivity/external/inc')
+                       ])
+
+######################################################################
+# Build flags
+######################################################################
+
+######################################################################
+# Source files and Targets
+######################################################################
+
+if env.get('ROUTING') == 'GW':
+       routing_src = [
+               './src/routingutility.c',
+               './src/routingmanager.c',
+               './src/routingtablemanager.c',
+               './src/routingmanagerinterface.c',
+               './src/routingmessageparser.c',
+    ]
+elif env.get('ROUTING') == 'EP':
+       routing_src = [
+               './src/routingutility.c',
+    ]
+
+routinglib = local_env.StaticLibrary('routingmanager', routing_src)
+local_env.InstallTarget(routinglib, 'routingmanager')
+local_env.UserInstallTargetLib(routinglib, 'routingmanager')
diff --git a/resource/csdk/routing/include/routingmanager.h b/resource/csdk/routing/include/routingmanager.h
new file mode 100644 (file)
index 0000000..3cd6156
--- /dev/null
@@ -0,0 +1,124 @@
+/* ****************************************************************
+ *
+ * Copyright 2015 Samsung Electronics 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.
+ *
+ ******************************************************************/
+
+/**
+ * @file
+ * This file contains the APIs for routing manager.
+ */
+#ifndef ROUTING_MANAGER_H_
+#define ROUTING_MANAGER_H_
+
+#include "octypes.h"
+#include "ocserverrequest.h"
+#include "ocresource.h"
+#include "routingutility.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/**
+ * Initialize the Routing Manager.
+ * @return  ::OC_STACK_OK or Appropriate error code.
+ */
+// TODO: Future addition pertaining to security, RM should be given ACL callback from RI.
+OCStackResult RMInitialize();
+
+/**
+ * Terminates the Routing Manager.
+ * @return  ::OC_STACK_OK or Appropriate error code.
+ */
+OCStackResult RMTerminate();
+
+/**
+ * This API will be called from RI layer whenever there is a request for the GATEWAY
+ * Virtual Resource.
+ * @param[in,out]   request    Request Received.
+ * @param[in]       resource   Resource handle used for sending the response.
+ * @return  ::OC_STACK_OK or Appropriate error code.
+ */
+OCStackResult RMHandleGatewayRequest(OCServerRequest *request, const OCResource *resource);
+
+/**
+ * API to handle the Response payload.  The Gateway entries are parsed from
+ * the payload using routingmessageparser apis, addition or removal of
+ * Gateway entries is performed.
+ * @param[in]   devAddr    Address of the Device that sent the payload.
+ * @param[in]   resource   Response payload.
+ * @return  ::OC_STACK_OK or Appropriate error code.
+ */
+OCStackResult RMHandleResponsePayload(const OCDevAddr *devAddr, const OCRepPayload *payload);
+
+/**
+ * Process the routing manager timer to send notification to all the observers.
+ */
+void RMProcess();
+
+/**
+ * API to form the payload with gateway ID.
+ * @param[out]   payload    Payload generated by routing message parser.
+ * @return  ::OC_STACK_OK or Appropriate error code.
+ */
+OCStackResult RMGetGatewayPayload(OCRepPayload **payload);
+
+/**
+ * API to get the gateway UUID of its own.
+ * @return  Gateway UUID.
+ */
+uint32_t RMGetGatewayId();
+
+/**
+ * API to get the multicast sequence number..
+ * @return  Multicast sequence number.
+ */
+uint16_t RMGetMcastSeqNumber();
+
+/**
+ * On reception of request from CA, RI sends to this function.
+ * This checks if the route option is present and adds routing information to
+ * to the route option data.
+ * @param[in,out]   message      Received coap packet.
+ * @param[in]      sender        RemoteEndpoint which sent the packet.
+ * @param[out]     destination   Populated by RM by parsing message, CA then forwards packet to
+ *                               "destination".
+ * @return  ::CA_STATUS_OK or Appropriate error code.
+ */
+OCStackResult RMHandleRequest(CARequestInfo_t *message, const CAEndpoint_t *sender,
+                              bool *selfDestination);
+
+/**
+ * On reception of response from CA, RI sends to this function.
+ * This checks if the route option is present and adds routing information to
+ * to the route option data.
+ * @param[in,out]  message       Received coap packet.
+ * @param[in]      sender        RemoteEndpoint which sent the packet.
+ * @param[out]     destination   Populated by RM by parsing message to know if response is
+ *                               for its own.
+ * @return  ::CA_STATUS_OK or Appropriate error code.
+ */
+OCStackResult RMHandleResponse(CAResponseInfo_t *message, const CAEndpoint_t *sender,
+                               bool *selfDestination);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* ROUTING_MANAGER_H_ */
diff --git a/resource/csdk/routing/include/routingmanagerinterface.h b/resource/csdk/routing/include/routingmanagerinterface.h
new file mode 100644 (file)
index 0000000..f0f3db0
--- /dev/null
@@ -0,0 +1,97 @@
+/* ****************************************************************
+ *
+ * Copyright 2015 Samsung Electronics 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.
+ *
+ ******************************************************************/
+
+/**
+ * @file
+ * This file is an interface of routing manager and resource interospection layer.
+ */
+#ifndef ROUTING_MANAGER_INTERFACE_H_
+#define ROUTING_MANAGER_INTERFACE_H_
+
+#include "routingmanager.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/**
+ * Creates a Gateway resource and initializes the observer List.
+ * @return  ::OC_STACK_OK or Appropriate error code.
+ */
+OCStackResult RMInitGatewayResource();
+
+/**
+ * Send multicast discover request for the Gateway resource.
+ * @return  ::OC_STACK_OK or Appropriate error code.
+ */
+OCStackResult RMDiscoverGatewayResource();
+
+/**
+ * Send observe request for the gateway device hosting the Gateway resource.
+ * @param[in]   devAddr   Device address of the Gateway device hosting
+ *                        the gateway resource.
+ * @param[in]   payload   Payload to be sent with the request.
+ * @return  ::OC_STACK_OK or Appropriate error code.
+ */
+OCStackResult RMSendObserveRequest(const OCDevAddr *devAddr, OCRepPayload *payload);
+
+/**
+ * Send delete request to all the neighbour nodes.
+ * @param[in]   devAddr   Device address of the Gateway device hosting
+ *                        the gateway resource.
+ * @param[in]   payload   Payload to be sent with the request.
+ * @return  ::OC_STACK_OK or Appropriate error code.
+ */
+OCStackResult RMSendDeleteRequest(const OCDevAddr *devAddr, OCRepPayload *payload);
+
+/**
+ * Send a response for GET/OBSERVE request received for Gateway resource.
+ * @param[in]   request     Request Received.
+ * @param[in]   resource    Resource Handle.
+ * @param[in]   payload     Payload containing Gateway Entries.
+ * @return  ::OC_STACK_OK or Appropriate error code.
+ */
+OCStackResult RMSendResponse(const OCServerRequest *request, const OCResource *resource,
+                             const OCRepPayload *payload);
+
+/**
+ * Send notification for list of observers except a particular observer.
+ * @param[in]   obsId     Observer who shouldn't be sent notification.
+ * @param[in]   obsLen    Length of Observer ID list.
+ * @param[in]   payload   Payload containing Gateway Entries.
+ * @return  ::OC_STACK_OK or Appropriate error code.
+ */
+OCStackResult RMSendNotificationForListofObservers(OCObservationId *obsId, uint8_t obsLen,
+                                                   const OCRepPayload *payload);
+
+/**
+ * Adds an observer to the RI stack.
+ * @param[in]   request     Request handle.
+ * @param[out]  obsID       Observer ID generated for the requester.
+ * @return  ::OC_STACK_OK or Appropriate error code.
+ */
+OCStackResult RMAddObserverToStack(const OCServerRequest *request, OCObservationId *obsID);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* ROUTING_MANAGER_INTERFACE_H_ */
diff --git a/resource/csdk/routing/include/routingmessageparser.h b/resource/csdk/routing/include/routingmessageparser.h
new file mode 100644 (file)
index 0000000..58307d5
--- /dev/null
@@ -0,0 +1,108 @@
+/* ****************************************************************
+ *
+ * Copyright 2015 Samsung Electronics 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.
+ *
+ ******************************************************************/
+
+/**
+ * @file
+ * This file contains the APIs for routing message parser.
+ */
+#ifndef ROUTING_MESSAGE_PARSER_H_
+#define ROUTING_MESSAGE_PARSER_H_
+
+#include "ulinklist.h"
+#include "uarraylist.h"
+#include "octypes.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/**
+ * Constructs payload with its Gateway ID. This payload is
+ * shared between the gateways during initial discovery.
+ * @param[in]       gatewayId               Gateway ID.
+ * @param[out]      payload                 Encoded Payload for Gateway ID.
+ * @return  ::OC_STACK_OK or Appropriate error code.
+ */
+OCStackResult RMPConstructGatewayPayload(uint32_t gatewayId, OCRepPayload **payload);
+
+/**
+ * Constructs payload with the Gateway ID and routing table
+ * This payload is shared for any observe response or notification.
+ * @param[in]      gatewayId               Gateway ID.
+ * @param[in]      seqNum                  Sequence Number of Gateway.
+ * @param[in]      routingtable            linklist with Routing Table Entries.
+ * @param[in]      isUpdateSeqNeeded       Response type of payload response/notification.
+ * @param[out]     payload                 Payload with gateway Data.
+ * @return  ::OC_STACK_OK or Appropriate error code.
+ */
+OCStackResult RMPConstructObserveResPayload(uint32_t gatewayId, uint32_t seqNum,
+                                            const u_linklist_t *routingtable, bool isUpdateSeqNeeded,
+                                            OCRepPayload **payload);
+
+/**
+ * Constructs payload with the own GatewayID and the nodes that are removed from the routing table.
+ * @param[in]       gatewayId           Gateway ID.
+ * @param[in]       seqNum              Sequence Number of Gateway.
+ * @param[in]       removedGateways     linklist with Removed gateway entries.
+ * @param[in]       isUpdateSeqNeeded   Response type of payload response/notification.
+ * @param[out]   removedPayload      Encoded Payloads of removed routing table entries.
+ * @return  ::OC_STACK_OK or Appropriate error code.
+ */
+OCStackResult RMPConstructRemovalPayload(uint32_t gatewayId, uint32_t seqNum,
+                                         const u_linklist_t *removedGateways, bool isUpdateSeqNeeded,
+                                         OCRepPayload **removedPayload);
+
+/**
+ * Parse payload for request and get gateway id.
+ * @param[in]   payload              Payload.
+ * @param[in]       payloadSize          Payload Size.
+ * @param[out]      gatewayId            Gateway Id.
+ * @return  ::OC_STACK_OK or Appropriate error code.
+ */
+OCStackResult RMPParseRequestPayload(const uint8_t* payload, size_t payloadSize,
+                                     uint32_t *gatewayId);
+
+/**
+ * Parse payload for response and get required info.
+ * @param[in]       payload              Payload with gateways route table encoded.
+ * @param[in/out]   seqNum               Sequence Number of Gateway.
+ * @param[in/out]   gatewayId            Gateway Id.
+ * @param[in/out]   gatewayTable         Parsed routing table from Payload.
+ * @param[out]      isUpdateSeqNeeded   Response type of payload response/notification.
+ * @return  ::OC_STACK_OK or Appropriate error code.
+ */
+OCStackResult RMPParseResponsePayload(const OCRepPayload *payload, uint32_t *gatewayId,
+                                      uint32_t *seqNum, u_linklist_t **gatewayTable,
+                                      bool *isUpdateSeqNeeded);
+
+/**
+ * Frees payload.
+ * @param[in/out]   payload              Encoded Payload for Gateway ID.
+ * @return  NONE.
+ */
+void RMPFreePayload(OCRepPayload *payload);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* ROUTING_MESSAGE_PARSER_H_ */
+
diff --git a/resource/csdk/routing/include/routingtablemanager.h b/resource/csdk/routing/include/routingtablemanager.h
new file mode 100644 (file)
index 0000000..abe7655
--- /dev/null
@@ -0,0 +1,357 @@
+/* ****************************************************************
+ *
+ * Copyright 2015 Samsung Electronics 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.
+ *
+ ******************************************************************/
+
+/**
+ * @file
+ * This file contains the APIs for routing table manager.
+ */
+#ifndef ROUTING_TABLE_MANAGER_H_
+#define ROUTING_TABLE_MANAGER_H_
+
+#ifndef SINGLE_THREAD
+#include <unistd.h>
+#include <time.h>
+#include <sys/time.h>
+#endif
+
+#if defined(__ANDROID__)
+#include <linux/time.h>
+#endif
+#include "ulinklist.h"
+#include "uarraylist.h"
+#include "octypes.h"
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/**
+ * Maximum hop/destination address length.
+ */
+#define MAX_DEST_ADDR_LEN 40
+
+/**
+ * Maximum number of observers for the gateway resource.
+ */
+#define MAX_NUM_OBSERVERS 10
+
+/**
+ * Maximum time after which gateway should send a notification for its existence.
+ * Every 30s gateway will send its existence notification.
+ */
+#define GATEWAY_ALIVE_TIMEOUT 30
+
+/**
+ * The routing table entries are validated for every 40 seconds for its existence.
+ */
+#define ROUTINGTABLE_REFRESH_TIMEOUT 40
+
+/**
+ * The routing table entries are removed if entries are invalid every 45 seconds.
+ */
+#define ROUTINGTABLE_VALIDATION_TIMEOUT 45
+
+/**
+ * Destination Interface Address entries.
+ */
+typedef struct
+{
+    uint32_t observerId;                    /**< Observer Id. */
+    CAEndpoint_t destIntfAddr;              /**< Destination Interface Address. */
+    uint32_t timeElapsed;                   /**< Time elapsed. */
+    bool isValid;                           /**< Valid check for Gateway. */
+} RTMDestIntfInfo_t;
+
+/**
+ * Endpoint Address entries.
+ */
+typedef struct
+{
+    uint16_t endpointId;                    /**< Endpoint Id. */
+    CAEndpoint_t destIntfAddr;              /**< Destination Interface Address. */
+} RTMEndpointEntry_t;
+
+/**
+ * Gateway Address entries.
+ */
+typedef struct gatewayAddress
+{
+    uint32_t gatewayId;                     /**< Gateway Id. */
+    u_arraylist_t *destIntfAddr;            /**< Destination Interface Addresses. */
+} RTMGatewayId_t;
+
+/**
+ * Routing table entries at Gateway.
+ */
+typedef struct
+{
+    RTMGatewayId_t *destination;            /**< destination Address. */
+    RTMGatewayId_t *nextHop;                /**< Next Hop Information. */
+    uint32_t routeCost;                     /**< routeCost. */
+    uint16_t mcastMessageSeqNum;            /**< sequence number for last mcast packet. */
+    uint32_t seqNum;                        /**< sequence number for notification. */
+} RTMGatewayEntry_t;
+
+/**
+ * Initialize the Routing Table Manager.
+ * @param[in/out] gatewayTable      Gateway Routing Table.
+ * @param[in/out] endpointTable     Endpoint Routing Table.
+ * @return  ::OC_STACK_OK or Appropriate error code.
+ */
+OCStackResult RTMInitialize(u_linklist_t **gatewayTable, u_linklist_t **endpointTable);
+
+/**
+ * Terminates the Routing Table Manager.
+ * @param[in/out] gatewayTable      Gateway Routing Table.
+ * @param[in/out] endpointTable     Endpoint Routing Table.
+ * @return  ::OC_STACK_OK or Appropriate error code.
+ */
+OCStackResult RTMTerminate(u_linklist_t **gatewayTable, u_linklist_t **endpointTable);
+
+/**
+ * Frees the gateway table memory with nodes containing structure RTMGatewayEntry_t.
+ * @param[in/out] gatewayTable      Gateway Routing Table.
+ * @return  ::OC_STACK_OK or Appropriate error code.
+ */
+OCStackResult RTMFreeGatewayRouteTable(u_linklist_t **gatewayTable);
+
+/**
+ * Frees the gateway ID list memory with nodes containing structute RTMGatewayId_t.
+ * @param[in/out] gatewayIdTable      Gateway ID list.
+ * @return  ::OC_STACK_OK or Appropriate error code.
+ */
+OCStackResult RTMFreeGatewayIdList(u_linklist_t **gatewayIdTable);
+
+/**
+ * Frees the endpoint table memory with nodes containing structute RTMEndpointEntry_t.
+ * @param[in/out] endpointTable     Endpoint Routing Table.
+ * @return  ::OC_STACK_OK or Appropriate error code.
+ */
+OCStackResult RTMFreeEndpointRouteTable(u_linklist_t **endpointTable);
+
+/**
+ * Adds the entry to the routing table if the entry for Gateway id is
+ * not preset in Routing table, Updates the Old entry if Entry for
+ * Gateway Id is already present in Routing table i.e routeCost and NextHop
+ * will be updated for efficient hop result.
+ *
+ * @param[in]       gatewayId           Gateway Id.
+ * @param[in]       nextHop             Next Hop address.
+ * @param[in]       routeCost           Shortest Path to Destination - Hopcount.
+ * @param[in]       destInterfaces      Destination Interface Information.
+ * @param[in/out]   gatewayTable        Gateway Routing Table.
+ * @return  ::OC_STACK_OK or Appropriate error code.
+ */
+OCStackResult RTMAddGatewayEntry(uint32_t gatewayId, uint32_t nextHop, uint32_t routeCost,
+                                 const RTMDestIntfInfo_t *destInterfaces, u_linklist_t **gatewayTable);
+
+/**
+ * Adds the endpoint entry to the routing table.
+ * @param[in/out]   endpointId          Endpoint Id.
+ * @param[in]       destAddr            Destination Address.
+ * @param[in/out]   endpointTable       Endpoint Routing Table.
+ * @return  ::OC_STACK_OK or Appropriate error code.
+ */
+OCStackResult RTMAddEndpointEntry(uint16_t *endpointId, const CAEndpoint_t *destAddr,
+                                  u_linklist_t **endpointTable);
+
+/**
+ * Removes the gateway entry from the routing table and also removes
+ * corresponding entries having nexthop as removed gateway.
+ * @param[in]        gatewayId              Gateway id of node need to be removed.
+ * @param[in/out]    removedGatewayNodes    Linklist containing removed gateway nodes
+ *                                          list need to be freed by caller.
+ * @param[in/out]    gatewayTable           Gateway Routing Table.
+ * @return  ::OC_STACK_OK or Appropriate error code.
+ */
+OCStackResult RTMRemoveGatewayEntry(uint32_t gatewayId, u_linklist_t **removedGatewayNodes,
+                                    u_linklist_t **gatewayTable);
+
+/**
+ * Removes the endpoint entry from the routing table.
+ * @param[in]       endpointId        Endpoint id of node need to be removed.
+ * @param[in/out]   endpointTable     Endpoint Routing Table.
+ * @return  ::OC_STACK_OK or Appropriate error code.
+ */
+OCStackResult RTMRemoveEndpointEntry(uint16_t endpointId, u_linklist_t **endpointTable);
+
+/**
+ * Removes the gateway entry from the routing table which has gateway id and nexthop as given.
+ * @param[in]        gatewayId              Gateway Id.
+ * @param[in]        nextHop                Next Hop address.
+ * @param[in]        destInfAdr             Destination Address of Next Hop to update time.
+ * @param[in/out]    existEntry             Entry which has different Next Hop.
+ * @param[in/out]    gatewayTable           Gateway Routing Table.
+ * @return  ::OC_STACK_OK or Appropriate error code.
+ */
+OCStackResult RTMRemoveGatewayDestEntry(uint32_t gatewayId, uint32_t nextHop,
+                                        const RTMDestIntfInfo_t *destInfAdr,
+                                        RTMGatewayEntry_t **existEntry, u_linklist_t **gatewayTable);
+/**
+ * Removes the gateway nodes.
+ * @param[in/out]    gatewayTable           Gateway Routing Table.
+ * @return  ::OC_STACK_OK or Appropriate error code.
+ */
+OCStackResult RTMRemoveGateways(u_linklist_t **gatewayTable);
+
+/**
+ * Removes the endpoint nodes.
+ * @param[in/out]   endpointTable           Endpoint Routing Table.
+ * @return  ::OC_STACK_OK or Appropriate error code.
+ */
+OCStackResult RTMRemoveEndpoints(u_linklist_t **endpointTable);
+
+/**
+ * Gets the neighbour nodes i.e nodes with routecost 1.
+ * @param[in/out]   neighbourNodes        link list containing neighbouring nodes.
+                                          this list will be pointer to GatewayIds
+                                          and must be freed by caller.
+ * @param[in]       gatewayTable           Gateway Routing Table.
+ * @return  NONE.
+ */
+void RTMGetNeighbours(u_linklist_t **neighbourNodes, const u_linklist_t *gatewayTable);
+
+/**
+ * Gets next hop from the routing table.
+ * @param[in]        gatewayId              Gateway Id.
+ * @param[in]        gatewayTable           Gateway Routing Table.
+ * @return  Next Hop address - returns NULL if it is End Device.
+ */
+RTMGatewayId_t *RTMGetNextHop(uint32_t gatewayId, const u_linklist_t *gatewayTable);
+
+/**
+ * Gets endpoint entry
+ * @param[in]       endpointId        Endpoint id of node need to be removed.
+ * @param[in]       endpointTable     Endpoint Routing Table.
+ * @return  Endpoint Destination inteface address.
+ */
+CAEndpoint_t *RTMGetEndpointEntry(uint16_t endpointId, const u_linklist_t *endpointTable);
+
+/**
+ * Updates destination interface address of an entry with provided gateway id
+ * as destination.
+ * @param[in]        gatewayId               Gateway Id of Hop need to be updated.
+ * @param[in]        destInterfaces          Destination Interface Information.
+ * @param[in]        addAdr                  Add/Remove Dest intf addr.
+ * @param[in/out]    gatewayTable            Gateway Routing Table.
+ * @return  ::OC_STACK_OK or Appropriate error code.
+ */
+OCStackResult RTMUpdateDestinationIntfAdr(uint32_t gatewayId, RTMDestIntfInfo_t destInterfaces,
+                                          bool addAdr, u_linklist_t **gatewayTable);
+
+/**
+ * Updates Multicast sequence number for gatewayID
+ * @param[in]       gatewayId           Gateway Id of Hop need to be updated.
+ * @param[in]       seqNum              sequence number for last cast packet from gateway.
+ * @param[in/out]   gatewayTable        Gateway Routing Table.
+ * @return  ::OC_STACK_OK or Appropriate error code.
+ */
+OCStackResult RTMUpdateMcastSeqNumber(uint32_t gatewayId, uint16_t seqNum,
+                                      u_linklist_t **gatewayTable);
+
+/**
+ * Prints the routing table
+ * @param[in]    gatewayTable           Gateway Routing Table.
+ * @param[in]    endpointTable          Endpoint Routing Table.
+ * @return  NONE.
+ */
+void RTMPrintTable(const u_linklist_t *gatewayTable, const u_linklist_t *endpointTable);
+
+/**
+ * Frees the GatewayId
+ * @param[in]        gateway                Gateway Structure pointer.
+ * @param[in/out]    gatewayTable           Gateway Routing Table.
+ * @return  NONE.
+ */
+void RTMFreeGateway(RTMGatewayId_t *gateway, u_linklist_t **gatewayTable);
+
+/**
+ * Gets the list of observer IDs.
+ * @param[in/out]    obsList                List of Observation IDs.
+ * @param[in/out]    obsListLen             Length if Observation ID list.
+ * @param[in]        gatewayTable           Gateway Routing Table.
+ * @return  NONE.
+ */
+void RTMGetObserverList(OCObservationId **obsList, uint8_t *obsListLen,
+                        const u_linklist_t *gatewayTable);
+
+/**
+ * Adds a observer address and obsID to the list.
+ * @param[in]        obsID                  Observation ID.
+ * @param[in]        devAddr                Address of Gateway.
+ * @param[in/out]    gatewayTable           Gateway Routing Table.
+ * @return  NONE.
+ */
+OCStackResult RTMAddObserver(uint32_t obsID, CAEndpoint_t devAddr, u_linklist_t **gatewayTable);
+
+/**
+ * Check if a particular observer address is already registerd and returns
+ * its obsID if present.
+ * @param[in]        devAddr                Address of Gateway.
+ * @param[in/out]    obsID                  Observation ID.
+ * @param[in]        gatewayTable           Gateway Routing Table.
+ * @return  NONE
+ */
+bool RTMIsObserverPresent(CAEndpoint_t devAddr, OCObservationId *obsID,
+                          const u_linklist_t *gatewayTable);
+
+/**
+ * Gets Current Time in Micro Seconds.
+ * @return  Current Time.
+ */
+uint64_t RTMGetCurrentTime();
+
+/**
+ * Update Gateway Address Validity.
+ * @param[in/out] invalidTable      Removed entries Table.
+ * @param[in/out] gatewayTable      Gateway Routing Table.
+ * @return  ::OC_STACK_OK or Appropriate error code.
+ */
+OCStackResult RTMUpdateDestAddrValidity(u_linklist_t **invalidTable, u_linklist_t **gatewayTable);
+
+/**
+ * Removes invalid gateways.
+ * @param[in/out] invalidTable      Removed entries Table.
+ * @param[in/out] gatewayTable      Gateway Routing Table.
+ * @return  ::OC_STACK_OK or Appropriate error code.
+ */
+OCStackResult RTMRemoveInvalidGateways(u_linklist_t **invalidTable, u_linklist_t **gatewayTable);
+
+/**
+ * Update Sequence number of Gateway Entry.
+ * @param[in]       gatewayId           Gateway Id.
+ * @param[in]       seqNum              Sequence Number of Entry.
+ * @param[in]       destInterfaces      Destination Interface Information.
+ * @param[out]   gatewayTable        Gateway Routing Table.
+ * @param[in]       forceUpdate         To Update parameters forcefully.
+ * @return  ::OC_STACK_OK or Appropriate error code.
+ */
+OCStackResult RTMUpdateEntryParameters(uint32_t gatewayId, uint32_t seqNum,
+                                       const RTMDestIntfInfo_t *destAdr, u_linklist_t **gatewayTable,
+                                       bool forceUpdate);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* ROUTING_TABLE_MANAGER_H_ */
+
diff --git a/resource/csdk/routing/include/routingutility.h b/resource/csdk/routing/include/routingutility.h
new file mode 100644 (file)
index 0000000..3e05341
--- /dev/null
@@ -0,0 +1,151 @@
+/* ****************************************************************
+ *
+ * Copyright 2015 Samsung Electronics 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.
+ *
+ ******************************************************************/
+
+/**
+ * @file
+ * This file contains the utility functions used by Routing manager and RI
+ */
+
+#ifndef ROUTING_UTILITY_H_
+#define ROUTING_UTILITY_H_
+
+//TODO Endpoint will also include this file, remove unnecessary includes.
+
+#include "cacommon.h"
+#include "octypes.h"
+#ifdef ROUTING_GATEWAY
+#include "routingmanager.h"
+#endif
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/**
+ * Maximum source or destination address length added to Route Option.
+ */
+#define MAX_ADDR_LEN 40
+
+/**
+ * Gateway ID length.
+ */
+#define GATEWAY_ID_LENGTH sizeof(uint32_t)
+
+/**
+ * Endpoint ID length.
+ */
+#define ENDPOINT_ID_LENGTH sizeof(uint16_t)
+
+/**
+ * Routing option number.
+ */
+// TODO: We need to define proper Option number.
+#define RM_OPTION_MESSAGE_SWITCHING 65524
+
+/**
+ * Macro to verify the validity of input argument with the return.
+ */
+#define RM_NULL_CHECK_WITH_RET(arg, log_tag, log_message) \
+    if (NULL == arg ){ \
+        OC_LOG_V(ERROR, log_tag, "Invalid input:%s", log_message); \
+        return OC_STACK_INVALID_PARAM; \
+    } \
+
+/**
+ * Macro to verify the validity of input argument.
+ */
+#define RM_NULL_CHECK_VOID(arg, log_tag, log_message) \
+    if (NULL == arg ){ \
+        OC_LOG_V(ERROR, log_tag, "Invalid input:%s", log_message); \
+        return; \
+    } \
+
+/**
+ * Macro to verify the return of an API.
+ */
+#define RM_VERIFY_SUCCESS(op, successCode) { if (op != successCode) \
+            {OC_LOG_V(ERROR, TAG, "%s failed!!", #op); goto exit;} }
+
+/**
+ * This structure is used to hold the hopcount, source and destination address.
+ */
+typedef struct
+{
+    uint32_t srcGw;               /**< Source gateway for this packet. */
+    uint32_t destGw;              /**< Destination gateway for this packet. */
+    uint16_t mSeqNum;             /**< HopCount. */
+    uint16_t srcEp;               /**< Source endpoint for this packet. */
+    uint16_t destEp;              /**< Destination endpoint for this packet. */
+} RMRouteOption_t;
+
+/**
+ * Adds the destination address to the Route options.
+ * If Route option is already present, it adds the destination address information to
+ * Route option else creates a new Route option with the destination address info.
+ * @param[in]       endpoint        Destination address.
+ * @param[in,out]   options         Header options present in the Request/response message.
+ * @param[in,out]   numOptions      Number of options present in the message.
+ * @return  ::CA_STATUS_OK or Appropriate error code.
+ */
+OCStackResult RMAddInfo(const char *destination, CAHeaderOption_t **options,
+                        uint8_t *numOptions);
+
+/**
+ * Removes the Route Option from the header options.
+ * @param[in,out]   options     Header options present in request/response message.
+ * @param[in,out]   numOptions  Number of options present in request/response message.
+ * @param[in,out]   endpoint    Remote address updated with the actual source of request/response.
+ * @return  ::CA_STATUS_OK or Appropriate error code.
+ */
+OCStackResult RMUpdateInfo(CAHeaderOption_t **options, uint8_t *numOptions,
+                           CAEndpoint_t *endpoint);
+
+/**
+ * Gets the index of the routing option if present.
+ * @param[in]    options     Header options present in request/response message.
+ * @param[in]    numOptions  Number of options present in request/response message.
+ * @param[out]   index       Index of the route option present in Header options.
+ * @return  NONE.
+ */
+void RMGetRouteOptionIndex(const CAHeaderOption_t *options, uint8_t numOptions,
+                           int8_t *index);
+
+/**
+ * To create a Routing option from the CARouteOption_t structure.
+ * @param[in]    optValue    Routing information.
+ * @param[out]   options     Routing information in the form of Header options.
+ * @return  ::CA_STATUS_OK or Appropriate error code.
+ */
+OCStackResult RMCreateRouteOption(const RMRouteOption_t *optValue, CAHeaderOption_t *options);
+
+/**
+ * To parse the routing option from the Headeroptions.
+ * @param[in]    options    Routing information in the form of Header options.
+ * @param[out]   optValue   Route information after parsing.
+ * @return  ::CA_STATUS_OK or Appropriate error code.
+ */
+OCStackResult RMParseRouteOption(const CAHeaderOption_t *options, RMRouteOption_t *optValue);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* ROUTING_MANAGER_H_ */
diff --git a/resource/csdk/routing/src/routingmanager.c b/resource/csdk/routing/src/routingmanager.c
new file mode 100644 (file)
index 0000000..7eadb23
--- /dev/null
@@ -0,0 +1,1142 @@
+/* ****************************************************************
+ *
+ * Copyright 2015 Samsung Electronics 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 "routingmanager.h"
+#include "routingmanagerinterface.h"
+#include "routingtablemanager.h"
+#include "routingmessageparser.h"
+#include "oic_malloc.h"
+#include "oic_string.h"
+#include "ocrandom.h"
+#include "ulinklist.h"
+#include "uarraylist.h"
+#include "ocstackinternal.h"
+#include "include/logger.h"
+
+/**
+ * Logging tag for module name.
+ */
+#define TAG "RM"
+
+/**
+ * Tag for printing the logs of forwarding the packet.
+ */
+#define RM_TAG "RAP"
+
+
+/**
+ * Unique gateway ID generated before hosting a gateway resource.
+ */
+uint32_t g_GatewayID = 0;
+
+/**
+ * Used for assigning unique ID.to endpoint's connected to this gateway
+ */
+static uint16_t g_EndpointCount = 0;
+
+/**
+ * Routing table which holds hop entries of Gateways with routeCost.
+ */
+static u_linklist_t *g_routingGatewayTable = NULL;
+
+/**
+ * List which holds hop entries with Endpoint information.
+ */
+static u_linklist_t *g_routingEndpointTable = NULL;
+
+/**
+ * Current time in microseconds.
+ */
+static uint64_t g_aliveTime = 0;
+
+/**
+ * Time to refresh the table entries.
+ */
+static uint64_t g_refreshTableTime = 0;
+
+/**
+ * Sequence number for the notification.
+ */
+static uint32_t g_sequenceNumber = 1;
+
+/**
+ * To check if the routing table is validated on 25th seconds.
+ */
+static bool g_isValidated = false;
+
+/**
+ * Multi cast Sequence number.
+ */
+static uint16_t g_mcastsequenceNumber = 1;
+
+/**
+ * To check if RM is initialized.
+ */
+static bool g_isRMInitialized = false;
+
+/**
+ * API to handle the GET request received for a Gateway Resource.
+ * @param[in]   request     Request Received.
+ * @param[in]   resource    Resource handle used for sending the response.
+ * @return  ::OC_STACK_OK or Appropriate error code.
+ */
+OCStackResult RMHandleGETRequest(const OCServerRequest *request, const OCResource *resource);
+
+/**
+ * API to handle the OBSERVE request received for a Gateway Resource.
+ * @param[in,out]   request    Request Received.
+ * @param[in]       resource   Resource handle used for sending the response.
+ * @return  ::OC_STACK_OK or Appropriate error code.
+ */
+OCStackResult RMHandleOBSERVERequest(OCServerRequest *request, const OCResource *resource);
+
+/**
+ * API to handle the OBSERVE request received for a Gateway Resource.
+ * @param[in,out]   request    Request Received.
+ * @param[in]       resource   Resource handle used for sending the response.
+ * @return  ::OC_STACK_OK or Appropriate error code.
+ */
+OCStackResult RMHandleDELETERequest(const OCServerRequest *request, const OCResource *resource);
+
+/**
+ * Adds a observer after generating observer ID whenever observe
+ * request is received.
+ * @param[in,out]   request     Request handle of the Observe request.
+ *                              Sets the value of observeResult as OC_STACK_OK
+ *                              if observer is added successfully.
+ * @param[out]      obsID       Observer ID generated for the observer.
+ * @return  ::OC_STACK_OK or Appropriate error code.
+ */
+OCStackResult RMAddObserver(OCServerRequest *request, OCObservationId *obsID);
+
+/**
+ * Send Notification to all the observers.
+ * @param[in]   payload                 Payload to be sent in notification.
+ * @return  ::OC_STACK_OK or Appropriate error code.
+ */
+OCStackResult RMSendNotificationToAll(const OCRepPayload *payload);
+
+/**
+ * Send Delete request to all the neighbour nodes.
+ * @return  NONE.
+ */
+void RMSendDeleteToNeighbourNodes();
+
+void RMGenerateGatewayID(uint8_t *id, size_t idLen)
+{
+    OC_LOG(DEBUG, TAG, "RMGenerateGatewayID IN");
+    OCFillRandomMem(id, idLen);
+    OC_LOG(DEBUG, TAG, "RMGenerateGatewayID OUT");
+}
+OCStackResult RMInitialize()
+{
+    OC_LOG(DEBUG, TAG, "RMInitialize IN");
+    if (g_isRMInitialized)
+    {
+        OC_LOG(DEBUG, TAG, "RM already initialized");
+        return OC_STACK_OK;
+    }
+
+    // Initialize the GatewayResource[/oic/gateway].
+    OCStackResult result = RMInitGatewayResource();
+    if (OC_STACK_OK != result)
+    {
+        OC_LOG_V(ERROR, TAG, "RMInitGatewayResource failed[%d]", result);
+        return result;
+    }
+
+    // Generates a 4 byte Gateway ID.
+    RMGenerateGatewayID((uint8_t *)&g_GatewayID, sizeof(g_GatewayID));
+
+    OC_LOG_V(INFO, RM_TAG, "Gateway ID: %u", g_GatewayID);
+
+    // Initialize the Routing table manager.
+    result = RTMInitialize(&g_routingGatewayTable, &g_routingEndpointTable);
+    if (OC_STACK_OK != result)
+    {
+        OC_LOG_V(ERROR, TAG, "RTMInitialize failed[%d]", result);
+        return result;
+    }
+
+    g_isRMInitialized = true;
+
+    // Send a DISCOVER request for the gateway resource.
+    result = RMDiscoverGatewayResource();
+    if (OC_STACK_OK != result)
+    {
+        OC_LOG_V(ERROR, TAG, "RMDiscoverGatewayResource failed[%d]", result);
+        RTMTerminate(&g_routingGatewayTable, &g_routingEndpointTable);
+        return result;
+    }
+
+    // Initialize the timer with the current time.
+    g_aliveTime = RTMGetCurrentTime();
+    g_refreshTableTime = g_aliveTime;
+
+    OC_LOG(DEBUG, TAG, "RMInitialize OUT");
+    return result;
+}
+
+OCStackResult RMTerminate()
+{
+    OC_LOG(DEBUG, TAG, "RMTerminate IN");
+    if (!g_isRMInitialized)
+    {
+        OC_LOG(ERROR, TAG, "RM not initialized");
+        return OC_STACK_ERROR;
+    }
+    // Send DELETE request to neighbour nodes
+    RMSendDeleteToNeighbourNodes();
+
+    OCStackResult result = RTMTerminate(&g_routingGatewayTable, &g_routingEndpointTable);
+    if (OC_STACK_OK != result)
+    {
+        OC_LOG_V(ERROR, TAG, "CARegisterRoutingMessageHandler failed[%d]", result);
+        return result;
+    }
+    g_isRMInitialized = false;
+    OC_LOG(DEBUG, TAG, "RMTerminate OUT");
+    return result;
+}
+
+OCStackResult RMHandleGatewayRequest(OCServerRequest *request, const OCResource *resource)
+{
+    OC_LOG(DEBUG, TAG, "RMHandleGatewayRequest IN");
+
+    if (!g_isRMInitialized)
+    {
+        OC_LOG(ERROR, TAG, "RM not initialized");
+        return OC_STACK_ERROR;
+    }
+
+    RM_NULL_CHECK_WITH_RET(request, TAG, "request");
+    RM_NULL_CHECK_WITH_RET(resource, TAG, "resource");
+
+    OC_LOG_V(DEBUG, TAG, "Received request of method: %d", request->method);
+
+    if (OC_REST_GET == request->method)
+    {
+        switch((OCObserveAction)request->observationOption)
+        {
+            case OC_OBSERVE_REGISTER:
+                OC_LOG(DEBUG, TAG, "Received OBSERVE request");
+                RMHandleOBSERVERequest(request, resource);
+                break;
+            case OC_OBSERVE_DEREGISTER:
+                //TODO: Handle this case
+                OC_LOG(DEBUG, TAG, "Received OBSERVE deregister");
+                break;
+            case OC_OBSERVE_NO_OPTION:
+                OC_LOG(DEBUG, TAG, "Received GET request");
+                RMHandleGETRequest(request, resource);
+                break;
+            default:
+                OC_LOG(DEBUG, TAG, "Not Supported by Routing Manager");
+        }
+    }
+    else if (OC_REST_DELETE == request->method)
+    {
+        OC_LOG(DEBUG, TAG, "Received a Delete request");
+        RMHandleDELETERequest(request, resource);
+    }
+    OC_LOG(DEBUG, TAG, "RMHandleGatewayRequest OUT");
+    return OC_STACK_OK;
+}
+
+OCStackResult RMHandleRequestPayload(OCDevAddr devAddr, const uint8_t *reqPayload,
+                                     size_t payloadSize)
+{
+    OC_LOG(DEBUG, TAG, "RMHandleRequestPayload IN");
+    RM_NULL_CHECK_WITH_RET(reqPayload, TAG, "reqPayload");
+
+    uint32_t gatewayId = 0;
+
+    OCStackResult result = RMPParseRequestPayload(reqPayload, payloadSize, &gatewayId);
+    RM_VERIFY_SUCCESS(result, OC_STACK_OK);
+    OC_LOG(INFO, TAG, "RMPParseRequestPayload is success");
+    // Check if the entry is its own.
+    if (gatewayId == g_GatewayID)
+    {
+        OC_LOG(INFO, TAG, "Own Request Received!!");
+        return OC_STACK_CONTINUE;
+    }
+
+    CAEndpoint_t endpoint = {.adapter = CA_DEFAULT_ADAPTER};
+    CopyDevAddrToEndpoint(&devAddr, &endpoint);
+
+    OC_LOG_V(INFO, TAG, "Add the gateway ID: %u", gatewayId);
+    RTMDestIntfInfo_t destInterfaces = {.observerId = 0};
+    destInterfaces.destIntfAddr = endpoint;
+    result = RTMAddGatewayEntry(gatewayId, 0, 1, &destInterfaces, &g_routingGatewayTable);
+
+    if (OC_STACK_OK != result)
+    {
+        OC_LOG(DEBUG, TAG, "Gateway was not added to the routing table");
+        return result;
+    }
+
+    OC_LOG(INFO, TAG, "Gateway was added");
+    // Create a list to add the updated entries and notify the observers
+    u_linklist_t *updatedTableList = u_linklist_create();
+    if(!updatedTableList)
+    {
+        OC_LOG(DEBUG, TAG, "Failure to notify");
+        return OC_STACK_NO_MEMORY;
+    }
+
+    RTMGatewayId_t gwId = {.gatewayId = gatewayId};
+    RTMGatewayEntry_t newNode;
+    newNode.destination = &gwId;
+    newNode.routeCost = 1;
+    u_linklist_add(updatedTableList, (void *)&newNode);
+    RTMPrintTable(g_routingGatewayTable, g_routingEndpointTable);
+
+    OCRepPayload *updatedPayload = NULL;
+
+    g_sequenceNumber++;
+    result = RMPConstructObserveResPayload(g_GatewayID, g_sequenceNumber,
+                                           updatedTableList, false,
+                                           &updatedPayload);
+    RM_VERIFY_SUCCESS(result, OC_STACK_OK);
+
+    result = RMSendNotificationToAll(updatedPayload);
+    RM_VERIFY_SUCCESS(result, OC_STACK_OK);
+    RMPFreePayload(updatedPayload);
+
+exit:
+    u_linklist_free(&updatedTableList);
+    OC_LOG(DEBUG, TAG, "RMHandleRequestPayload OUT");
+    return result;
+}
+
+OCStackResult RMHandleResponsePayload(const OCDevAddr *devAddr, const OCRepPayload *respPayload)
+{
+    OC_LOG(DEBUG, TAG, "RMHandleResponsePayload IN");
+    RM_NULL_CHECK_WITH_RET(respPayload, TAG, "respPayload");
+
+    // Parse the Payload to get the Gateway ID of neighbouring node.
+    uint32_t gatewayId = 0;
+    uint32_t seqNum = 0;
+    u_linklist_t *gatewayTableList = NULL;
+    bool isUpdateSeqNum = false;
+
+    OCStackResult result = RMPParseResponsePayload(respPayload, &gatewayId, &seqNum,
+                                                   &gatewayTableList,  &isUpdateSeqNum);
+    RM_VERIFY_SUCCESS(result, OC_STACK_OK);
+    // Check if the entry is its own.
+    if (gatewayId == g_GatewayID)
+    {
+        OC_LOG(INFO, TAG, "-------------->Own entry, continue!!");
+        return OC_STACK_ERROR;
+    }
+    // Convert OCDevAddr to endpoint address
+    CAEndpoint_t endpoint = {.adapter = CA_DEFAULT_FLAGS};
+    CopyDevAddrToEndpoint(devAddr, &endpoint);
+    RTMDestIntfInfo_t destInterfaces = {.observerId = 0};
+    destInterfaces.destIntfAddr = endpoint;
+    if (0 < seqNum)
+    {
+        OC_LOG_V(DEBUG, TAG, "Sequence Number of Resp payload is %d, Forceupdate: %d",
+                 seqNum, isUpdateSeqNum);
+        result = RTMUpdateEntryParameters(gatewayId, seqNum, &destInterfaces,
+                                          &g_routingGatewayTable, isUpdateSeqNum);
+        if (OC_STACK_COMM_ERROR == result)
+        {
+            OC_LOG(ERROR, TAG, "Few packet drops are found, sequence number is not matching");
+            // Send a observe request to the gateway.
+            RMSendObserveRequest(devAddr, NULL);
+            return result;
+        }
+        else if (OC_STACK_DUPLICATE_REQUEST == result)
+        {
+            OC_LOG(ERROR, TAG, "Same sequence number is received");
+            return result;
+        }
+    }
+
+    // Check if the payload is for Removal
+    bool doRemoveEntry = false;
+
+    if (NULL != gatewayTableList && NULL != gatewayTableList->list)
+    {
+        RTMGatewayEntry_t *headPtr = u_linklist_get_data(gatewayTableList->list);
+        if (headPtr && 0 == headPtr->routeCost)
+        {
+            OC_LOG(INFO, TAG, "Remove entry is called");
+            doRemoveEntry = true;
+        }
+    }
+
+    // Create a list to add the updated entries and notify the observers
+    u_linklist_t *updatedTableList = u_linklist_create();
+    u_linklist_t *alternativeRouteList = u_linklist_create();
+    OCRepPayload *updatedPayload = NULL;
+    if (false == doRemoveEntry)
+    {
+        OC_LOG_V(INFO, TAG, "Add the gateway ID: %u", gatewayId);
+        result = RTMAddGatewayEntry(gatewayId, 0, 1, &destInterfaces, &g_routingGatewayTable);
+        if (OC_STACK_OK == result)
+        {
+            OC_LOG(INFO, TAG, "Node was added");
+            RTMGatewayId_t gwId = {.gatewayId = gatewayId};
+            RTMGatewayEntry_t newNode;
+            newNode.destination = &gwId;
+            newNode.routeCost = 1;
+            u_linklist_add(updatedTableList, (void *)&newNode);
+            RTMPrintTable(g_routingGatewayTable, g_routingEndpointTable);
+
+            if (NULL == gatewayTableList)
+            {
+                OC_LOG(INFO, TAG, "Received a Discover Payload");
+                g_sequenceNumber++;
+                result = RMPConstructObserveResPayload(g_GatewayID, g_sequenceNumber,
+                                                       updatedTableList, false,
+                                                       &updatedPayload);
+                goto sendNotification;
+            }
+        }
+    }
+
+    // Iterate the Table and get each entry
+    u_linklist_iterator_t *iterTable = NULL;
+    u_linklist_init_iterator(gatewayTableList, &iterTable);
+
+    while (NULL != iterTable)
+    {
+        RTMGatewayEntry_t *entry = u_linklist_get_data(iterTable);
+        // Check if the entry is its own.
+        if (!entry || entry->destination->gatewayId == g_GatewayID)
+        {
+            OC_LOG(INFO, TAG, "Ignore entry, continue!!");
+            u_linklist_get_next(&iterTable);
+            continue;
+        }
+
+        OC_LOG_V(INFO, TAG, "Gateway ID: %u", entry->destination->gatewayId);
+        if (true == doRemoveEntry)
+        {
+            // Remove the entry from RTM.
+            RTMGatewayEntry_t *existEntry = NULL;
+            result = RTMRemoveGatewayDestEntry(entry->destination->gatewayId, gatewayId,
+                                               &destInterfaces, &existEntry,
+                                               &g_routingGatewayTable);
+            if (OC_STACK_OK != result && NULL != existEntry)
+            {
+                u_linklist_add(alternativeRouteList, (void *)existEntry);
+            }
+        }
+        else
+        {
+            // Add the entry to RTM.
+            entry->routeCost = entry->routeCost + 1;
+            result = RTMAddGatewayEntry(entry->destination->gatewayId, gatewayId,
+                                        entry->routeCost, NULL, &g_routingGatewayTable);
+        }
+
+        if (OC_STACK_OK == result)
+        {
+            OC_LOG(INFO, TAG, "Gateway was added/removed");
+            u_linklist_add(updatedTableList, (void *)entry);
+            RTMPrintTable(g_routingGatewayTable, g_routingEndpointTable);
+        }
+        u_linklist_get_next(&iterTable);
+    }
+
+    if ( 0 < u_linklist_length(alternativeRouteList))
+    {
+        OC_LOG(DEBUG, TAG, "Alternative routing found");
+        // Send the notification.
+        OCRepPayload *removeTablePayload = NULL;
+        g_sequenceNumber++;
+        result = RMPConstructObserveResPayload(g_GatewayID, g_sequenceNumber,
+                                               alternativeRouteList, false,
+                                               &removeTablePayload);
+        RM_VERIFY_SUCCESS(result, OC_STACK_OK);
+        result = RMSendNotificationToAll(removeTablePayload);
+        RM_VERIFY_SUCCESS(result, OC_STACK_OK);
+        RMPFreePayload(removeTablePayload);
+    }
+
+    if ( 0 >= u_linklist_length(updatedTableList))
+    {
+        OC_LOG_V(DEBUG, TAG, "No updation is needed, Length is %d", u_linklist_length(updatedTableList));
+        goto exit;
+    }
+
+    g_sequenceNumber++;
+    if (true == doRemoveEntry)
+    {
+        result = RMPConstructRemovalPayload(g_GatewayID, g_sequenceNumber, updatedTableList,
+                                            false, &updatedPayload);
+    }
+    else
+    {
+        result = RMPConstructObserveResPayload(g_GatewayID, g_sequenceNumber,
+                                               updatedTableList, false,
+                                               &updatedPayload);
+    }
+    RM_VERIFY_SUCCESS(result, OC_STACK_OK);
+
+sendNotification:
+    result = RMSendNotificationToAll(updatedPayload);
+    RM_VERIFY_SUCCESS(result, OC_STACK_OK);
+    RMPFreePayload(updatedPayload);
+
+exit:
+    u_linklist_free(&updatedTableList);
+    u_linklist_free(&gatewayTableList);
+    u_linklist_free(&alternativeRouteList);
+    OC_LOG(DEBUG, TAG, "RMHandleResponsePayload OUT");
+    return OC_STACK_OK;
+}
+
+OCStackResult RMHandleGETRequest(const OCServerRequest *request, const OCResource *resource)
+{
+    OC_LOG(DEBUG, TAG, "RMHandleGETRequest IN");
+    RM_NULL_CHECK_WITH_RET(request, TAG, "request");
+    RM_NULL_CHECK_WITH_RET(resource, TAG, "resource");
+
+    OCRepPayload *payload = NULL;
+    OCStackResult result = RMPConstructGatewayPayload(g_GatewayID, &payload);
+    if (OC_STACK_OK != result)
+    {
+        OC_LOG_V(DEBUG, TAG, "RMPConstructDiscoverPayload failed[%d]", result);
+        return result;
+    }
+
+    // Send a response for GET request
+    result = RMSendResponse(request, resource, payload);
+    if (OC_STACK_OK != result)
+    {
+        OC_LOG_V(DEBUG, TAG, "Send response failed[%d]", result);
+        return result;
+    }
+
+    RMPFreePayload(payload);
+
+    // Send a observe request
+    result = RMSendObserveRequest(&(request->devAddr), NULL);
+    if (OC_STACK_OK != result)
+    {
+        OC_LOG_V(DEBUG, TAG, "Send response failed[%d]", result);
+    }
+    OC_LOG(DEBUG, TAG, "RMHandleGETRequest OUT");
+    return result;
+}
+
+OCStackResult RMHandleOBSERVERequest(OCServerRequest *request, const OCResource *resource)
+{
+    OC_LOG(DEBUG, TAG, "RMHandleOBSERVERequest IN");
+    RM_NULL_CHECK_WITH_RET(request, TAG, "request");
+    RM_NULL_CHECK_WITH_RET(resource, TAG, "resource");
+
+    // Parse payload and add the gateway entry.
+    if (0 < request->payloadSize)
+    {
+        RMHandleRequestPayload(request->devAddr, request->payload, request->payloadSize);
+    }
+
+    // Generate and add observer.
+    OCObservationId obsID = 0;
+    OCStackResult result = RMAddObserver(request, &obsID);
+    RM_VERIFY_SUCCESS(result, OC_STACK_OK);
+    OC_LOG_V(DEBUG, TAG, "Observer ID is %d", obsID);
+
+
+    // Get the Routing table from RTM
+    OCRepPayload *payload = NULL;
+    RTMPrintTable(g_routingGatewayTable, g_routingEndpointTable);
+    OC_LOG(DEBUG, TAG, "Construct Routing table payload");
+    result = RMPConstructObserveResPayload(g_GatewayID, g_sequenceNumber,
+                                           g_routingGatewayTable, true,
+                                           &payload);
+    RM_VERIFY_SUCCESS(result, OC_STACK_OK);
+
+    result = RMSendResponse(request, resource, payload);
+    RM_VERIFY_SUCCESS(result, OC_STACK_OK);
+    RMPFreePayload(payload);
+exit:
+    OC_LOG(DEBUG, TAG, "RMHandleOBSERVERequest OUT");
+    return result;
+}
+
+OCStackResult RMHandleDELETERequest(const OCServerRequest *request, const OCResource *resource)
+{
+    OC_LOG(DEBUG, TAG, "RMHandleDELETERequest IN");
+    RM_NULL_CHECK_WITH_RET(request, TAG, "request");
+    RM_NULL_CHECK_WITH_RET(resource, TAG, "resource");
+
+    uint32_t gatewayId = 0;
+    OCStackResult result = RMPParseRequestPayload(request->payload, request->payloadSize,
+                                                  &gatewayId);
+    RM_VERIFY_SUCCESS(result, OC_STACK_OK);
+    OC_LOG(INFO, TAG, "RMPParseRequestPayload is success");
+
+    OC_LOG_V(INFO, TAG, "Remove the gateway ID: %u", gatewayId);
+
+    u_linklist_t *removedGatewayNodes = NULL;
+    result = RTMRemoveGatewayEntry(gatewayId, &removedGatewayNodes, &g_routingGatewayTable);
+    RM_VERIFY_SUCCESS(result, OC_STACK_OK);
+
+    if (0 < u_linklist_length(removedGatewayNodes))
+    {
+        OCRepPayload *resPayloads = NULL;
+        g_sequenceNumber++;
+        result = RMPConstructRemovalPayload(g_GatewayID, g_sequenceNumber, removedGatewayNodes,
+                                            false, &resPayloads);
+        RTMFreeGatewayRouteTable(&removedGatewayNodes);
+        RM_VERIFY_SUCCESS(result, OC_STACK_OK);
+        result = RMSendNotificationToAll(resPayloads);
+        RM_VERIFY_SUCCESS(result, OC_STACK_OK);
+        RTMPrintTable(g_routingGatewayTable, g_routingEndpointTable);
+    }
+
+exit:
+    OC_LOG(DEBUG, TAG, "RMHandleDELETERequest OUT");
+    return result;
+}
+
+OCStackResult RMAddObserver(OCServerRequest *request, OCObservationId *obsID)
+{
+    OC_LOG(DEBUG, TAG, "RMAddObserverForGateway OUT");
+    RM_NULL_CHECK_WITH_RET(request, TAG, "request");
+    RM_NULL_CHECK_WITH_RET(obsID, TAG, "obsID");
+
+    // Generate the ObserverID
+    CAEndpoint_t endpoint = {.adapter = 0};
+    CopyDevAddrToEndpoint(&(request->devAddr), &endpoint);
+
+    // Check if observer is already added.
+    if (true == RTMIsObserverPresent(endpoint, obsID, g_routingGatewayTable))
+    {
+        OC_LOG(DEBUG, TAG, "Observer is present");
+        request->observeResult = OC_STACK_OK;
+        return OC_STACK_OK;
+    }
+
+    OCStackResult result = RMAddObserverToStack(request, obsID);
+    request->observeResult = result;
+    if (OC_STACK_OK == result)
+    {
+        OC_LOG(DEBUG, TAG, "Added observer successfully");
+
+        // Add the observer to the list.
+        result = RTMAddObserver(*obsID, endpoint, &g_routingGatewayTable);
+        if (OC_STACK_OK != result)
+        {
+            OC_LOG_V(DEBUG, TAG, "RMAddObserver failed[%d]", result);
+        }
+    }
+    OC_LOG(DEBUG, TAG, "RMAddObserverForGateway OUT");
+    return result;
+}
+
+OCStackResult RMSendNotificationToAll(const OCRepPayload *payload)
+{
+    OC_LOG(DEBUG, TAG, "RMSendNotificationToAll IN");
+    RM_NULL_CHECK_WITH_RET(payload, TAG, "payload");
+
+    OCObservationId *obsList = NULL;
+    uint8_t obsLen = 0;
+    // Get the complete observer list.
+    RTMGetObserverList(&obsList, &obsLen, g_routingGatewayTable);
+    OCStackResult result = OC_STACK_OK;
+    OC_LOG_V(DEBUG, TAG, "Number of observers is %d", obsLen);
+    if (0 < obsLen)
+    {
+        // Send notification to the list of observers.
+        OC_LOG_V(DEBUG, TAG, "Sending notification with Sequence Number: %d", g_sequenceNumber);
+        result = RMSendNotificationForListofObservers(obsList, obsLen, payload);
+        RM_VERIFY_SUCCESS(result, OC_STACK_OK);
+        g_aliveTime = RTMGetCurrentTime();
+    }
+
+exit:
+    OICFree(obsList);
+    OC_LOG(DEBUG, TAG, "RMSendNotificationToAll OUT");
+    return result;
+}
+
+void RMProcess()
+{
+    if (!g_isRMInitialized)
+    {
+        return;
+    }
+
+    OCStackResult result = OC_STACK_OK;
+    uint64_t currentTime = RTMGetCurrentTime();
+    if (GATEWAY_ALIVE_TIMEOUT <= currentTime - g_aliveTime)
+    {
+        g_aliveTime = currentTime;
+        // Construct a payload with only the current sequence number.
+        OCRepPayload *payload = NULL;
+        result = RMPConstructObserveResPayload(g_GatewayID, g_sequenceNumber, NULL,
+                                               false, &payload);
+        RM_VERIFY_SUCCESS(result, OC_STACK_OK);
+
+        OC_LOG(DEBUG, TAG, "Sending the alive notification to all");
+        // Send notification for every 15s to all the neighbours.
+        result = RMSendNotificationToAll(payload);
+        RM_VERIFY_SUCCESS(result, OC_STACK_OK);
+    }
+
+    if (ROUTINGTABLE_VALIDATION_TIMEOUT <= currentTime - g_refreshTableTime)
+    {
+        OC_LOG(DEBUG, TAG, "Validating the routing table");
+        u_linklist_t *removedEntries = NULL;
+        // Remove the invalid gateway entries.
+        RTMRemoveInvalidGateways(&removedEntries, &g_routingGatewayTable);
+        if (0 < u_linklist_length(removedEntries))
+        {
+            OCRepPayload *resPayloads = NULL;
+            g_sequenceNumber++;
+            result = RMPConstructRemovalPayload(g_GatewayID, g_sequenceNumber, removedEntries,
+                                                false, &resPayloads);
+            RTMFreeGatewayRouteTable(&removedEntries);
+            RM_VERIFY_SUCCESS(result, OC_STACK_OK);
+            result = RMSendNotificationToAll(resPayloads);
+            RM_VERIFY_SUCCESS(result, OC_STACK_OK);
+            RTMPrintTable(g_routingGatewayTable, g_routingEndpointTable);
+        }
+        g_refreshTableTime = currentTime;
+        g_isValidated = false;
+        goto exit;
+    }
+
+    if (!g_isValidated && ROUTINGTABLE_REFRESH_TIMEOUT <= (currentTime - g_refreshTableTime))
+    {
+        OC_LOG_V(DEBUG, TAG, "Refreshing the routing table: %u", currentTime);
+        u_linklist_t* invalidInterfaces = NULL;
+        RTMUpdateDestAddrValidity(&invalidInterfaces, &g_routingGatewayTable);
+        if (0 < u_linklist_length(invalidInterfaces))
+        {
+            u_linklist_iterator_t *iterTable = NULL;
+            u_linklist_init_iterator(invalidInterfaces, &iterTable);
+            while (NULL != iterTable)
+            {
+                RTMDestIntfInfo_t *entry = (RTMDestIntfInfo_t *) u_linklist_get_data(iterTable);
+                if(!entry)
+                {
+                    u_linklist_get_next(&iterTable);
+                    continue;
+                }
+                OCDevAddr devAddr = {.adapter = OC_DEFAULT_ADAPTER};
+                CopyEndpointToDevAddr(&(entry->destIntfAddr), &devAddr);
+                RMSendObserveRequest(&devAddr, NULL);
+                u_linklist_get_next(&iterTable);
+            }
+        }
+        g_isValidated = true;
+        RTMPrintTable(g_routingGatewayTable, g_routingEndpointTable);
+        u_linklist_free(&invalidInterfaces);
+    }
+
+exit:
+    return;
+}
+
+OCStackResult RMGetGatewayPayload(OCRepPayload **payload)
+{
+    OC_LOG(DEBUG, TAG, "RMGetGatewayPayload IN");
+    OCStackResult result = RMPConstructGatewayPayload(g_GatewayID, payload);
+    OC_LOG_V(DEBUG, TAG, "RMPConstructDiscoverPayload result is %d", result);
+    OC_LOG(DEBUG, TAG, "RMGetGatewayPayload OUT");
+    return result;
+}
+
+void RMSendDeleteToNeighbourNodes()
+{
+    OC_LOG(DEBUG, TAG, "RMSendDeleteToNeighbourNodes IN");
+    u_linklist_t *neighbourNodes = NULL;
+    RTMGetNeighbours(&neighbourNodes, g_routingGatewayTable);
+
+    if (0 >= u_linklist_length(neighbourNodes))
+    {
+        OC_LOG(DEBUG, TAG, "No neighbour nodes present");
+        return;
+    }
+
+    u_linklist_iterator_t *iterTable = NULL;
+    u_linklist_init_iterator(neighbourNodes, &iterTable);
+    while (NULL != iterTable)
+    {
+
+        OCRepPayload *payload = NULL;
+        // Created payload is freed in the OCDoResource() api.
+        OCStackResult result = RMPConstructGatewayPayload(g_GatewayID, &payload);
+        if (OC_STACK_OK != result)
+        {
+            OC_LOG_V(DEBUG, TAG, "RMPConstructGatewayPayload failed[%d]", result);
+            u_linklist_free(&neighbourNodes);
+            return;
+        }
+
+        RTMGatewayEntry_t *entry = (RTMGatewayEntry_t *) u_linklist_get_data(iterTable);
+        if (entry)
+        {
+            for (uint32_t i = 0; i < u_arraylist_length(entry->destination->destIntfAddr); i++)
+            {
+                RTMDestIntfInfo_t *dest = u_arraylist_get(entry->destination->destIntfAddr, i);
+                OCDevAddr devAddr = {.adapter = OC_DEFAULT_ADAPTER};
+                CopyEndpointToDevAddr(&(dest->destIntfAddr), &devAddr);
+                OC_LOG_V(DEBUG, TAG, "\nDestination interface addresses: %s[%d], OCDevAddr: %s[%d]",
+                         dest->destIntfAddr.addr, dest->destIntfAddr.port, devAddr.addr, devAddr.port);
+                RMSendDeleteRequest(&devAddr, payload);
+            }
+        }
+        u_linklist_get_next(&iterTable);
+    }
+
+    u_linklist_free(&neighbourNodes);
+    OC_LOG(DEBUG, TAG, "RMSendDeleteToNeighbourNodes OUT");
+}
+
+uint32_t RMGetGatewayId()
+{
+    if (!g_isRMInitialized)
+    {
+        OC_LOG(ERROR, TAG, "RM not initialized");
+        return 0;
+    }
+    return g_GatewayID;
+}
+
+uint16_t RMGetMcastSeqNumber()
+{
+    if (!g_isRMInitialized)
+    {
+        OC_LOG(DEBUG, TAG, "RM not initialized");
+        return 0;
+    }
+    return ++g_mcastsequenceNumber;
+}
+
+/*
+ * This function is lifeline of packet forwarding module, hence we are going to do some serious
+ * handling here. Following are the expectations from this function:
+ * 1) If routing option is not available, forward packet to RI only. else:
+ * 2) If source is empty in routing option, packet is from end device, add an end device entry and
+ *    add "GatewayId:ClientId" as source.
+ * 3) If destination is empty in routing option, its multicast packet, increase hopcount and
+ *    multicast on other interfaces. Also remove routing Option and forward to RI. (Before
+ *    forwarding, check last mCastSeqNumber for the source gateway otherwise we might be looping
+ *     the packet.)
+ * 4) If destination is present in routing option, its unicast packet,
+ *    a) If self gatewayId is present in destination and no clientId, remove routing option
+ *       and forward to RI.
+ *    b) If self gatewayId and a clientId is present in destination, forward to end device.
+ * 5) Drop a packet if its hop count reaches NUMBER_OF_GATEWAYS.
+ */
+
+OCStackResult RMHandlePacket(bool isRequest, void *message, const CAEndpoint_t *sender,
+                             bool *selfDestination)
+{
+    RM_NULL_CHECK_WITH_RET(message, RM_TAG, "message");
+    RM_NULL_CHECK_WITH_RET(sender, RM_TAG, "sender");
+    RM_NULL_CHECK_WITH_RET(selfDestination, RM_TAG, "selfDestination");
+
+    bool forward = false;
+    CAEndpoint_t nextHop = {.adapter = CA_DEFAULT_ADAPTER};
+    CAInfo_t *info = NULL;
+    if (isRequest)
+    {
+        CARequestInfo_t *msg = message;
+        info = &(msg->info);
+        RM_NULL_CHECK_WITH_RET(info, RM_TAG, "info");
+    }
+    else
+    {
+        CAResponseInfo_t *msg = message;
+        info = &(msg->info);
+        RM_NULL_CHECK_WITH_RET(info, RM_TAG, "info");
+    }
+
+    // 1.  If routing option is not available, forward packet to RI only.
+    int8_t routeIndex = -1;
+    RMGetRouteOptionIndex(info->options, info->numOptions, &routeIndex);
+    if (-1 >= routeIndex)
+    {
+        OC_LOG(ERROR, RM_TAG, "No route option present. Let RI Handle");
+        // Let RI handle this packet.
+        *selfDestination = true;
+        return OC_STACK_OK;
+    }
+
+    // Get existing values in packet route option.
+    RMRouteOption_t routeOption = {.srcGw = 0};
+    OCStackResult res = RMParseRouteOption(&info->options[routeIndex], &routeOption);
+    if (OC_STACK_OK != res)
+    {
+        OC_LOG_V(ERROR, RM_TAG, "RMParseRouteOption failed");
+        return OC_STACK_ERROR;
+    }
+
+    /*
+     * 2) If source is empty in routing option, packet is from end device, add an end device entry
+     *  and add "GatewayId:ClientId" as source.
+     */
+    if (g_GatewayID == routeOption.srcGw)
+    {
+        OC_LOG_V(ERROR, RM_TAG, "Packet is of its own");
+        if (0 == routeOption.destGw && g_mcastsequenceNumber < routeOption.mSeqNum)
+        {
+            g_mcastsequenceNumber = routeOption.mSeqNum;
+        }
+
+        return OC_STACK_ERROR;
+    }
+    else if (0 == routeOption.srcGw)
+    {
+        OC_LOG(INFO, RM_TAG, "Source missing in option");
+        // Packet from end device as Gateway will add source in option.
+        uint16_t endpointId = g_EndpointCount + 1;
+        OCStackResult res = RTMAddEndpointEntry(&endpointId, sender, &g_routingEndpointTable);
+        if (OC_STACK_OK == res)
+        {
+            g_EndpointCount = endpointId;
+            OC_LOG_V(INFO, RM_TAG, "New endpoint added [%d]:[%s]", g_EndpointCount, sender->addr);
+        }
+        else if (OC_STACK_DUPLICATE_REQUEST == res)
+        {
+            OC_LOG_V(INFO, RM_TAG, "Endpoint exist [%d]", endpointId);
+        }
+        else
+        {
+            OC_LOG(ERROR, RM_TAG, "Add Endpoint failed");
+            return OC_STACK_ERROR;
+        }
+
+        // add source option.
+        routeOption.srcGw = g_GatewayID;
+        routeOption.srcEp = endpointId;
+        OC_LOG_V(INFO, RM_TAG, "Added source: [%u:%u]", g_GatewayID, endpointId);
+    }
+
+    /*
+     * 3) If destination is empty in routing option, its a multicast packet, increase hopcount and
+     *    multicast on other interfaces. Also remove routing Option and forward to RI (taken care by
+     *    caller of this function).
+     */
+    if (0 == routeOption.destGw)
+    {
+        OC_LOG(INFO, RM_TAG, "Destination missing in option");
+        // This is a multicast packet.
+        if (g_GatewayID == routeOption.srcGw)
+        {
+            routeOption.mSeqNum = ++g_mcastsequenceNumber;
+        }
+        else
+        {
+            OCStackResult update = RTMUpdateMcastSeqNumber(routeOption.srcGw, routeOption.mSeqNum,
+                                                           &g_routingGatewayTable);
+            if (OC_STACK_OK != update)
+            {
+                // this shouldnt have been forwarded. ignore.
+                OC_LOG_V(ERROR, RM_TAG, "Multicast Sequence number not proper: %d",
+                         routeOption.mSeqNum);
+                return OC_STACK_ERROR;
+            }
+        }
+
+        // forward
+        *selfDestination = true;
+        forward = true;
+
+        // Send multicast on every adapter except the one from which packet was received
+        // TODO::: support to be added for IP hop.
+        if (sender->adapter != CA_ADAPTER_IP)
+        {
+            nextHop.adapter |= CA_ADAPTER_IP;
+            nextHop.flags |= CA_IPV4 | CA_IPV6;
+        }
+
+        if(sender->adapter != CA_ADAPTER_GATT_BTLE)
+        {
+            nextHop.adapter |= CA_ADAPTER_GATT_BTLE;
+        }
+
+        if(sender->adapter != CA_ADAPTER_RFCOMM_BTEDR)
+        {
+            nextHop.adapter |= CA_ADAPTER_RFCOMM_BTEDR;
+        }
+
+        // Only requests are sent as multicast.
+        if(isRequest)
+        {
+            CARequestInfo_t *msg = message;
+            msg->isMulticast = true;
+        }
+        goto  rewriteandexit;
+    }
+    else if (g_GatewayID == routeOption.destGw)
+    {
+        OC_LOG(INFO, RM_TAG, "GatewayId found in destination");
+        /*
+         * This unicast packet either belongs to us or any of our connected end devices
+         * check if packet belongs to end device.
+         */
+        if (0 != routeOption.destEp)
+        {
+            // forward packet to the client.
+            OC_LOG_V(INFO, RM_TAG, "Forwarding packet to client id [%u]", routeOption.destEp);
+            CAEndpoint_t *clientInfo = RTMGetEndpointEntry(routeOption.destEp,
+                                                           g_routingEndpointTable);
+            if(!clientInfo)
+            {
+                OC_LOG(ERROR, RM_TAG, "Failed to get Client info");
+                return OC_STACK_ERROR;
+            }
+
+            nextHop = *clientInfo;
+            forward = true;
+            *selfDestination = false;
+            goto rewriteandexit;
+        }
+        else
+        {
+            // packet is for us.
+            OC_LOG(INFO, RM_TAG, "Received packet for self");
+            forward = false;
+            *selfDestination = true;
+            goto rewriteandexit;
+        }
+    }
+    else
+    {
+        /*
+         * This unicast packet belongs to other gateway.
+         * we only want to print first 4 bytes of packet as readable GatewayId.
+         */
+        OC_LOG_V(INFO, RM_TAG, "Forwarding packet to Gateway: %u", routeOption.destGw);
+        RTMGatewayId_t *nextHopGw = RTMGetNextHop(routeOption.destGw, g_routingGatewayTable);
+        if(!nextHopGw)
+        {
+            OC_LOG(ERROR, RM_TAG, "Failed to get next hop");
+            return OC_STACK_ERROR;
+        }
+
+        // TODO:: check preferences among multiple interface addresses, for now sending on first one
+        RTMDestIntfInfo_t *address = u_arraylist_get(nextHopGw->destIntfAddr, 0);
+        if (!address)
+        {
+            OC_LOG(ERROR, RM_TAG, "Failed to get address for next hop");
+            return OC_STACK_ERROR;
+        }
+
+        nextHop = address->destIntfAddr;
+        forward = true;
+        *selfDestination = false;
+        goto rewriteandexit;
+    }
+
+rewriteandexit:
+
+    if (forward)
+    {
+        // Don't forward any packet meant for gateway resource.
+        if (info->resourceUri && (0 == strcmp(info->resourceUri, OC_RSRVD_GATEWAY_URI)))
+        {
+            OC_LOG(ERROR, RM_TAG, "Not forwarding gateway resource packet");
+        }
+        else if (sender->flags & CA_SECURE)
+        {
+            OC_LOG(ERROR, RM_TAG, "This is secured request. Not supported by routing manager");
+            return OC_STACK_ERROR;
+        }
+        else
+        {
+            // rewrite any changes in routing option.
+            res = RMCreateRouteOption(&routeOption, &info->options[routeIndex]);
+            if (OC_STACK_OK != res)
+            {
+                OC_LOG_V(ERROR, RM_TAG, "Rewriting RM option failed");
+                return res;
+            }
+            /*
+             * When forwarding a packet, do not attempt retransmission as its the responsibility of
+             * packet originator node.
+             */
+            info->skipRetransmission = true;
+            if(isRequest)
+            {
+                CARequestInfo_t *msg = message;
+                CAResult_t caRes = CASendRequest(&nextHop, msg);
+                if (CA_STATUS_OK != caRes)
+                {
+                    OC_LOG_V(ERROR, RM_TAG, "Failed to forward request to next hop [%d][%s]", caRes,
+                             nextHop.addr);
+                    if(0 == routeOption.destGw)
+                    {
+                        /*
+                         * No point going forward as unicast packet could not be forwarded
+                         * not returning error for multicast as we may still let RI process
+                         * this packet.
+                         */
+                        return OC_STACK_ERROR;
+                    }
+                }
+            }
+            else
+            {
+                CAResponseInfo_t *msg = message;
+                CAResult_t caRes = CASendResponse(&nextHop, msg);
+                if (CA_STATUS_OK != caRes)
+                {
+                    OC_LOG_V(ERROR, RM_TAG, "Failed to forward response to next hop [%d][%s]",
+                             caRes, nextHop.addr);
+                    // Since a response is always unicast, return error here.
+                    return OC_STACK_ERROR;
+                }
+            }
+        }
+    }
+
+    OC_LOG_V(INFO, RM_TAG, "Sender: [%u] Destination: [%u]", routeOption.srcGw, routeOption.destGw);
+    return OC_STACK_OK;
+}
+
+OCStackResult RMHandleRequest(CARequestInfo_t *message, const CAEndpoint_t *sender,
+                              bool *selfDestination)
+{
+    if (!g_isRMInitialized)
+    {
+        OC_LOG(ERROR, TAG, "RM not initialized");
+        *selfDestination = true;
+        return OC_STACK_OK;
+    }
+    OCStackResult res = RMHandlePacket(true, message, sender, selfDestination);
+    return res;
+}
+
+OCStackResult RMHandleResponse(CAResponseInfo_t *message, const CAEndpoint_t *sender,
+                               bool *selfDestination)
+{
+    if (!g_isRMInitialized)
+    {
+        OC_LOG(ERROR, TAG, "RM not initialized");
+        *selfDestination = true;
+        return OC_STACK_OK;
+    }
+    OCStackResult res = RMHandlePacket(false, message, sender, selfDestination);
+    return res;
+}
diff --git a/resource/csdk/routing/src/routingmanagerinterface.c b/resource/csdk/routing/src/routingmanagerinterface.c
new file mode 100644 (file)
index 0000000..59f31f0
--- /dev/null
@@ -0,0 +1,275 @@
+/* ****************************************************************
+ *
+ * Copyright 2015 Samsung Electronics 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 <unistd.h>
+#include "routingmanagerinterface.h"
+#include "routingmessageparser.h"
+#include "routingutility.h"
+#include "ocobserve.h"
+#include "include/logger.h"
+#include "ocrandom.h"
+
+/**
+ * Logging tag for module name.
+ */
+#define TAG "RM_INTERFACE"
+
+/**
+ * Name of resource type.
+ */
+#define GW_RESOURCE_TYPE_NAME "core.gateway"
+
+/**
+ * Name of resource interface.
+ */
+#define GW_RESOURCE_INTF_NAME "oc.mi.def"
+
+/**
+ * URI of the resource.
+ */
+#define GW_RESOURCE_URI "/oic/gateway"
+
+/**
+ * Max Number of times to send data considering wifi packet drops.
+ */
+#define MAX_SEND_DATA 3
+
+/**
+ * Pointer to handle of the newly created gateway resource.
+ */
+static OCResourceHandle g_gateWayHandle = NULL;
+
+/**
+ * Discovery callback registered with RI for a Discover Request.
+ */
+OCStackApplicationResult RMDiscoverGatewayCallback(void* ctx, OCDoHandle handle,
+                                                   OCClientResponse * clientResponse);
+
+/**
+ * Observe callback registered with RI for a observe Request.
+ */
+OCStackApplicationResult RMObserveRequestCallback(void* ctx, OCDoHandle handle,
+                                                  OCClientResponse * clientResponse);
+
+OCConnectivityType RMGetConnectivityType(OCTransportAdapter adapter)
+{
+    switch(adapter)
+    {
+        case OC_ADAPTER_IP:
+            return CT_ADAPTER_IP;
+        case OC_ADAPTER_GATT_BTLE:
+            return CT_ADAPTER_GATT_BTLE;
+        case OC_ADAPTER_RFCOMM_BTEDR:
+            return CT_ADAPTER_RFCOMM_BTEDR;
+        case OC_DEFAULT_ADAPTER:
+            break;
+        default:
+            OC_LOG(DEBUG, TAG, "Default option will be selected");
+    }
+    return CT_DEFAULT;
+}
+
+OCStackResult RMInitGatewayResource()
+{
+    OC_LOG(DEBUG, TAG, "RMInitGatewayResource IN");
+
+    // Create a Gateway resource
+    OCStackResult result = OCCreateResource(&g_gateWayHandle,
+                                            GW_RESOURCE_TYPE_NAME,
+                                            GW_RESOURCE_INTF_NAME,
+                                            GW_RESOURCE_URI,
+                                            NULL,
+                                            NULL,
+                                            OC_OBSERVABLE);
+
+    if (OC_STACK_OK != result)
+    {
+        OC_LOG_V(ERROR, TAG, "Create resource for gateway failed[%d]", result);
+    }
+
+    OC_LOG(DEBUG, TAG, "RMInitGatewayResource OUT");
+    return result;
+}
+
+OCStackResult RMDiscoverGatewayResource()
+{
+    OC_LOG(DEBUG, TAG, "RMDiscoverGatewayResource IN");
+    OCCallbackData discoverData = {.cb = RMDiscoverGatewayCallback};
+    OCStackResult result = OC_STACK_OK;
+
+    result = OCDoResource(NULL, OC_REST_DISCOVER, GW_RESOURCE_URI, 0, 0,
+                          CT_ADAPTER_IP | CT_ADAPTER_RFCOMM_BTEDR,
+                          OC_LOW_QOS, &discoverData, NULL, 0);
+
+    // Temp fix for packet drops in WIFI.
+    for (int sendData = 0; sendData < MAX_SEND_DATA; sendData++)
+    {
+        result = OCDoResource(NULL, OC_REST_DISCOVER, GW_RESOURCE_URI, 0, 0,
+                              CT_ADAPTER_IP, OC_LOW_QOS, &discoverData, NULL, 0);
+        usleep(100000);
+    }
+    OC_LOG(DEBUG, TAG, "RMDiscoverGatewayResource OUT");
+    return result;
+}
+
+OCStackApplicationResult RMDiscoverGatewayCallback(void* ctx, OCDoHandle handle,
+                                                   OCClientResponse * clientResponse)
+{
+    OC_LOG(DEBUG, TAG, "RMDiscoverGatewayCallback IN");
+    (void)ctx;
+    (void)handle;
+    if (NULL == clientResponse)
+    {
+        OC_LOG(DEBUG, TAG, "clientResponse is NULL");
+        return OC_STACK_KEEP_TRANSACTION;
+    }
+
+    OCStackResult result = RMHandleResponsePayload(&(clientResponse->devAddr),
+                                                   (OCRepPayload *)clientResponse->payload);
+    if (OC_STACK_OK != result)
+    {
+        OC_LOG_V(ERROR, TAG, "RMHandleResponsePayload Failed[%d]", result);
+    }
+
+    OCRepPayload *payload = NULL;
+    // Created payload is freed in the OCDoResource() api.
+    result= RMGetGatewayPayload(&payload);
+    if (OC_STACK_OK != result)
+    {
+        OC_LOG_V(ERROR, TAG, "RMGetGatewayPayload Failed[%d]", result);
+    }
+
+    RMSendObserveRequest(&(clientResponse->devAddr), payload);
+
+    OC_LOG(DEBUG, TAG, "RMDiscoverGatewayCallback OUT");
+    return OC_STACK_KEEP_TRANSACTION;
+}
+
+OCStackResult RMSendObserveRequest(const OCDevAddr *devAddr, OCRepPayload *payload)
+{
+    OC_LOG(DEBUG, TAG, "RMSendObserveRequest IN");
+    OC_LOG_V(DEBUG, TAG, "Destination address is %s:%d", devAddr->addr, devAddr->port);
+    OCCallbackData observeData = {.cb = RMObserveRequestCallback};
+    OC_LOG(DEBUG, TAG, "RMSendObserveRequest OUT");
+
+    return OCDoResource(NULL, OC_REST_OBSERVE, GW_RESOURCE_URI, devAddr, (OCPayload *)payload,
+                        RMGetConnectivityType(devAddr->adapter), OC_HIGH_QOS,
+                        &observeData, NULL, 0);
+}
+
+OCStackResult RMSendDeleteRequest(const OCDevAddr *devAddr, OCRepPayload *payload)
+{
+    OC_LOG(DEBUG, TAG, "RMSendDeleteRequest IN");
+    RM_NULL_CHECK_WITH_RET(payload, TAG, "payload");
+    OC_LOG_V(DEBUG, TAG, "Destination address is %s:%d", devAddr->addr, devAddr->port);
+
+    OCCallbackData deleteCb = {.cb = RMDiscoverGatewayCallback};
+    OC_LOG(DEBUG, TAG, "RMSendDeleteRequest OUT");
+    return OCDoResource(NULL, OC_REST_DELETE, GW_RESOURCE_URI, devAddr, (OCPayload *)payload,
+                    RMGetConnectivityType(devAddr->adapter), OC_LOW_QOS,
+                    &deleteCb, NULL, 0);
+}
+
+OCStackResult RMSendResponse(const OCServerRequest *request, const OCResource *resource,
+                             const OCRepPayload *payload)
+{
+    OC_LOG(DEBUG, TAG, "RMSendResponse IN");
+    OCEntityHandlerResponse response = {.ehResult = OC_EH_OK,
+                                        .payload = (OCPayload *)payload,
+                                        .persistentBufferFlag = 0,
+                                        .requestHandle = (OCRequestHandle) request,
+                                        .resourceHandle = (OCResourceHandle) resource
+                                        };
+    OC_LOG(DEBUG, TAG, "RMSendResponse OUT");
+
+    return OCDoResponse(&response);
+}
+
+OCStackResult RMSendNotificationForListofObservers(OCObservationId *obsId, uint8_t obsLen,
+                                                   const OCRepPayload *payload)
+{
+    OC_LOG(DEBUG, TAG, "RMSendNotificationForListofObservers IN");
+    RM_NULL_CHECK_WITH_RET(obsId, TAG, "obsId");
+    RM_NULL_CHECK_WITH_RET(payload, TAG, "payload");
+    OCStackResult result = OCNotifyListOfObservers(g_gateWayHandle, obsId, obsLen,
+                                                   payload, OC_LOW_QOS);
+    OC_LOG_V(DEBUG, TAG, "Result is %d", result);
+    OC_LOG(DEBUG, TAG, "RMSendNotificationForListofObservers OUT");
+    return result;
+}
+
+OCStackApplicationResult RMObserveRequestCallback(void* ctx, OCDoHandle handle,
+                                                  OCClientResponse *clientResponse)
+{
+    OC_LOG(DEBUG, TAG, "RMObserveRequestCallback IN");
+    (void)ctx;
+    (void)handle;
+    if (NULL == clientResponse)
+    {
+        OC_LOG(DEBUG, TAG, "clientResponse is NULL");
+        return OC_STACK_KEEP_TRANSACTION;
+    }
+
+    if (OC_STACK_COMM_ERROR == clientResponse->result)
+    {
+        OC_LOG(DEBUG, TAG, "Received TIMEOUT ERROR");
+        return OC_STACK_KEEP_TRANSACTION;
+    }
+
+    OCStackResult result = RMHandleResponsePayload(&(clientResponse->devAddr),
+                                                   (OCRepPayload *)clientResponse->payload);
+    if (OC_STACK_OK != result)
+    {
+        OC_LOG_V(ERROR, TAG, "RMHandleResponsePayload Failed[%d]", result);
+    }
+
+    OC_LOG(DEBUG, TAG, "RMObserveRequestCallback OUT");
+    return OC_STACK_KEEP_TRANSACTION;
+}
+
+OCStackResult RMAddObserverToStack(const OCServerRequest *request, OCObservationId *obsID)
+{
+    OC_LOG(DEBUG, TAG, "RMAddObserverToStack IN");
+    RM_NULL_CHECK_WITH_RET(request, TAG, "request");
+    RM_NULL_CHECK_WITH_RET(obsID, TAG, "obsID");
+
+    OCStackResult result = OC_STACK_OK;
+    while (0 == *obsID)
+    {
+        result = GenerateObserverId(obsID);
+    }
+    if (OC_STACK_OK != result)
+    {
+        OC_LOG_V(DEBUG, TAG, "GenerateObserverId failed[%d]", result);
+        return result;
+    }
+
+    OC_LOG_V(DEBUG, TAG, "Observer ID is %d", *obsID);
+    // Add the observer
+    result = AddObserver((const char*)(request->resourceUrl),
+                (const char *)(request->query),
+                *obsID, request->requestToken, request->tokenLength,
+                (OCResource *)g_gateWayHandle, request->qos, OC_FORMAT_CBOR,
+                &request->devAddr);
+    OC_LOG(DEBUG, TAG, "RMAddObserverToStack OUT");
+    return result;
+}
\ No newline at end of file
diff --git a/resource/csdk/routing/src/routingmessageparser.c b/resource/csdk/routing/src/routingmessageparser.c
new file mode 100644 (file)
index 0000000..bcaba17
--- /dev/null
@@ -0,0 +1,346 @@
+/* ****************************************************************
+ *
+ * Copyright 2015 Samsung Electronics 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 "routingmessageparser.h"
+#include "routingtablemanager.h"
+#include "routingutility.h"
+#include "ocpayload.h"
+#include "ocpayloadcbor.h"
+#include "oic_malloc.h"
+#include "oic_string.h"
+#include "include/logger.h"
+
+/**
+ * Logging tag for module name.
+ */
+#define TAG "RPM"
+
+/**
+ * Table key to parser Payload Table.
+ */
+static const char TABLE[] = "table";
+
+/**
+ * Length key to get length Payload Array.
+ */
+static const char LENGTH_PROP[] = "len";
+
+/**
+ * Gateway key to parser Payload Table.
+ */
+static const char GATEWAY[] = "gateway";
+
+/**
+ * Route Cost key to parser Payload Table.
+ */
+static const char ROUTE_COST[] = "routecost";
+
+/**
+ * Sequence Number key to parser Payload Table.
+ */
+static const char SEQ_NUM[] = "seqnum";
+
+/**
+ * Response Type key to parser Payload Table.
+ */
+static const char UPDATE_SEQ_NUM[] = "updateseqnum";
+
+OCStackResult RMPConstructGatewayPayload(uint32_t gatewayId, OCRepPayload **payload)
+{
+    OC_LOG(DEBUG, TAG, "RMPConstructGatewayPayload IN");
+    RM_NULL_CHECK_WITH_RET(payload, TAG, "payload");
+
+    *payload = OCRepPayloadCreate();
+    if(!*payload)
+    {
+        OC_LOG(ERROR, TAG, "Failed to allocate Payload");
+        return OC_STACK_ERROR;
+    }
+
+    (*payload)->base.type = PAYLOAD_TYPE_REPRESENTATION;
+    OCRepPayloadSetPropInt(*payload, GATEWAY, gatewayId);
+    OCRepPayloadSetPropInt(*payload, LENGTH_PROP, 0);
+
+    OC_LOG(DEBUG, TAG, "RMPConstructGatewayPayload OUT");
+
+    return OC_STACK_OK;
+}
+
+OCStackResult RMPConstructObserveResPayload(uint32_t gatewayId, uint32_t seqNum,
+                                            const u_linklist_t *routingtable, bool isUpdateSeqNeeded,
+                                            OCRepPayload **payload)
+{
+    OC_LOG(DEBUG, TAG, "RMPConstructObserveResPayload IN");
+    RM_NULL_CHECK_WITH_RET(payload, TAG, "payload");
+
+    *payload =  (OCRepPayload *)OCRepPayloadCreate();
+    if(!*payload)
+    {
+        OC_LOG(ERROR, TAG, "Failed to allocate Payload");
+        return OC_STACK_ERROR;
+    }
+
+    (*payload)->base.type = PAYLOAD_TYPE_REPRESENTATION;
+    OCRepPayloadSetPropInt(*payload, GATEWAY, gatewayId);
+    OCRepPayloadSetPropInt(*payload, SEQ_NUM, seqNum);
+    OCRepPayloadSetPropBool(*payload, UPDATE_SEQ_NUM, isUpdateSeqNeeded);
+    if (NULL == routingtable)
+    {
+        OCRepPayloadSetPropInt(*payload, LENGTH_PROP, 0);
+        OC_LOG(DEBUG, TAG, "Routing Table NULL for ObserveRes Payload");
+        return OC_STACK_OK;
+    }
+
+    u_linklist_iterator_t *iterTable = NULL;
+    u_linklist_init_iterator(routingtable, &iterTable);
+
+    uint32_t len = u_linklist_length(routingtable);
+    const OCRepPayload *arrayPayload[len];
+
+    size_t dimensions[MAX_REP_ARRAY_DEPTH] = {len, 0, 0};
+
+    int i = 0;
+    while (NULL != iterTable)
+    {
+        RTMGatewayEntry_t *entry = u_linklist_get_data(iterTable);
+
+        OCRepPayload *add = OCRepPayloadCreate();
+        if(!add)
+        {
+            OC_LOG(ERROR, TAG, "Failed to allocate Payload");
+            return OC_STACK_ERROR;
+        }
+
+        add->base.type = PAYLOAD_TYPE_REPRESENTATION;
+        OCRepPayloadSetPropInt(add, GATEWAY, entry->destination->gatewayId);
+        OCRepPayloadSetPropInt(add, ROUTE_COST, entry->routeCost);
+        arrayPayload[i] = add;
+
+        i++;
+        u_linklist_get_next(&iterTable);
+    }
+    OCRepPayloadSetPropInt(*payload, LENGTH_PROP, i);
+    if (i > 0)
+    {
+        bool res = OCRepPayloadSetPropObjectArray(*payload, TABLE, arrayPayload, dimensions);
+        if (!res)
+        {
+            OC_LOG(ERROR, TAG, "Failed to Construct Observer response Payload");
+            return OC_STACK_ERROR;
+        }
+    }
+
+    OC_LOG(DEBUG, TAG, "RMPConstructObserveResPayload OUT");
+    return OC_STACK_OK;
+}
+
+OCStackResult RMPConstructRemovalPayload(uint32_t gatewayId, uint32_t seqNum,
+                                         const u_linklist_t *removedGateways, bool isUpdateSeqNeeded,
+                                         OCRepPayload **removedPayload)
+{
+    OC_LOG(DEBUG, TAG, "RMPConstructRemovalPayload IN");
+    RM_NULL_CHECK_WITH_RET(removedGateways, TAG, "removedGateways");
+    RM_NULL_CHECK_WITH_RET(removedPayload, TAG, "removedPayload");
+
+    u_linklist_iterator_t *iterTable = NULL;
+    u_linklist_init_iterator(removedGateways, &iterTable);
+
+    *removedPayload =  OCRepPayloadCreate();
+    if(!*removedPayload)
+    {
+        OC_LOG(ERROR, TAG, "Failed to allocate Payload");
+        return OC_STACK_ERROR;
+    }
+
+    uint32_t len = u_linklist_length(removedGateways);
+    const OCRepPayload *arrayPayload[len];
+
+    size_t dimensions[MAX_REP_ARRAY_DEPTH] = {len, 0, 0};
+
+    (*removedPayload)->base.type = PAYLOAD_TYPE_REPRESENTATION;
+    OCRepPayloadSetPropInt(*removedPayload, GATEWAY, gatewayId);
+    OCRepPayloadSetPropInt(*removedPayload, SEQ_NUM, seqNum);
+    OCRepPayloadSetPropBool(*removedPayload, UPDATE_SEQ_NUM, isUpdateSeqNeeded);
+
+    int i = 0;
+    while (NULL != iterTable)
+    {
+        RTMGatewayEntry_t *entry = (RTMGatewayEntry_t *) u_linklist_get_data(iterTable);
+        if (!entry)
+        {
+            u_linklist_get_next(&iterTable);
+            continue;
+        }
+        OCRepPayload *add = OCRepPayloadCreate();
+        if(!add)
+        {
+            OC_LOG(ERROR, TAG, "Failed to allocate Payload");
+            return OC_STACK_ERROR;
+        }
+
+        add->base.type = PAYLOAD_TYPE_REPRESENTATION;
+        OC_LOG_V(DEBUG, TAG, "Removing the gateway entry: %u", entry->destination->gatewayId);
+        OCRepPayloadSetPropInt(add, GATEWAY, entry->destination->gatewayId);
+        OCRepPayloadSetPropInt(add, ROUTE_COST, 0);
+        arrayPayload[i] = add;
+
+        i++;
+        u_linklist_get_next(&iterTable);
+    }
+    OCRepPayloadSetPropInt(*removedPayload, LENGTH_PROP, i);
+    bool res = OCRepPayloadSetPropObjectArray(*removedPayload, TABLE, arrayPayload, dimensions);
+    if (!res)
+    {
+        OC_LOG(ERROR, TAG, "Failed to Construct Removal Payload");
+        return OC_STACK_ERROR;
+    }
+
+    OC_LOG(DEBUG, TAG, "RMPConstructRemovalPayload OUT");
+    return OC_STACK_OK;
+}
+
+OCStackResult RMPParseRequestPayload(const uint8_t* payload, size_t payloadSize,
+                                     uint32_t *gatewayId)
+{
+    OCPayload *ocPayload = NULL;
+    OCParsePayload(&ocPayload, payload, payloadSize);
+    OCRepPayload *repPayload = (OCRepPayload *)ocPayload;
+    OCStackResult res = RMPParseResponsePayload(repPayload, gatewayId, NULL, NULL, NULL);
+    if (OC_STACK_OK != res)
+    {
+        OC_LOG(DEBUG, TAG, "ParseResponsePayload failed");
+    }
+
+    return res;
+}
+
+OCStackResult RMPParseResponsePayload(const OCRepPayload *payload, uint32_t *gatewayId,
+                                      uint32_t *seqNum, u_linklist_t **gatewayTable,
+                                      bool *isUpdateSeqNeeded)
+{
+    OC_LOG(DEBUG, TAG, "RMPParsePayload IN");
+    RM_NULL_CHECK_WITH_RET(payload, TAG, "payload");
+    RM_NULL_CHECK_WITH_RET(gatewayId, TAG, "gatewayId");
+
+    int64_t tempGateway = 0;
+    OCRepPayloadGetPropInt(payload, GATEWAY, &tempGateway);
+    *gatewayId = tempGateway;
+
+    if (NULL == gatewayId || 0 == *gatewayId)
+    {
+        return OC_STACK_COMM_ERROR;
+    }
+
+    if (NULL != seqNum)
+    {
+        int64_t tempSeq = 0;
+        OCRepPayloadGetPropInt(payload, SEQ_NUM, &tempSeq);
+        *seqNum = tempSeq;
+    }
+
+    int64_t length = 0;
+    OCRepPayloadGetPropInt(payload, LENGTH_PROP, &length);
+
+    if (NULL != isUpdateSeqNeeded)
+    {
+        OCRepPayloadGetPropBool(payload, UPDATE_SEQ_NUM, isUpdateSeqNeeded);
+    }
+
+    int len = length;
+    if (0 == len)
+    {
+        OC_LOG(DEBUG, TAG, "Parsed Gateway Payload");
+        return OC_STACK_OK;
+    }
+
+    if (NULL == gatewayTable)
+    {
+        OC_LOG(DEBUG, TAG, "Parsed Request Payload");
+        return OC_STACK_OK;
+    }
+
+    OCRepPayload **responsePayload[len];
+
+    size_t dimensions[MAX_REP_ARRAY_DEPTH];
+    OCRepPayloadGetPropObjectArray(payload, TABLE, responsePayload, dimensions);
+
+    if (NULL == *responsePayload)
+    {
+        OC_LOG(DEBUG, TAG, "RMPParsePayload OUT");
+        return OC_STACK_OK;
+    }
+
+    *gatewayTable = u_linklist_create();
+    if (NULL == *gatewayTable)
+    {
+        OC_LOG(DEBUG, TAG, "Gateway table create failed");
+        return OC_STACK_ERROR;
+    }
+
+    for (int i = 0; i < len; i++)
+    {
+        RTMGatewayEntry_t *entry = (RTMGatewayEntry_t *)OICCalloc(1, sizeof(RTMGatewayEntry_t));
+
+        if (NULL == entry)
+        {
+            OC_LOG(DEBUG, TAG, "RTMGatewayEntry_t Calloc failed");
+            return OC_STACK_ERROR;
+        }
+        // Filling new Entry
+        entry->destination = (RTMGatewayId_t*)OICCalloc(1, sizeof(RTMGatewayId_t));
+        if (NULL == entry->destination)
+        {
+            OC_LOG(DEBUG, TAG, "Destination Calloc failed");
+            OICFree(entry);
+            return OC_STACK_ERROR;
+        }
+        entry->nextHop = (RTMGatewayId_t*)OICCalloc(1, sizeof(RTMGatewayId_t));
+        if (NULL == entry->nextHop)
+        {
+            OC_LOG(DEBUG, TAG, "nextHop Calloc failed");
+            OICFree(entry);
+            OICFree(entry->destination);
+            return OC_STACK_ERROR;
+        }
+
+        entry->nextHop->gatewayId = *gatewayId;
+
+        int64_t gatewayBuf;
+        int64_t routeCost;
+        OCRepPayloadGetPropInt(*((*responsePayload) + i), GATEWAY, &gatewayBuf);
+        OCRepPayloadGetPropInt(*((*responsePayload) + i), ROUTE_COST, &routeCost);
+
+        entry->destination->gatewayId = gatewayBuf;
+        entry->routeCost = routeCost;
+        u_linklist_add(*gatewayTable, (void *)entry);
+    }
+    OC_LOG(DEBUG, TAG, "RMPParsePayload OUT");
+    return OC_STACK_OK;
+}
+
+void RMPFreePayload(OCRepPayload *payload)
+{
+    OC_LOG(DEBUG, TAG, "RMPFreePayload IN");
+    RM_NULL_CHECK_VOID(payload, TAG, "payload");
+    OCRepPayloadDestroy(payload);
+    OC_LOG(DEBUG, TAG, "RMPFreePayload OUT");
+}
diff --git a/resource/csdk/routing/src/routingtablemanager.c b/resource/csdk/routing/src/routingtablemanager.c
new file mode 100644 (file)
index 0000000..59ce172
--- /dev/null
@@ -0,0 +1,1325 @@
+/* ****************************************************************
+ *
+ * Copyright 2015 Samsung Electronics 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 "routingtablemanager.h"
+#include "routingutility.h"
+#include "oic_malloc.h"
+#include "oic_string.h"
+#include "include/logger.h"
+
+/**
+ * Logging tag for module name.
+ */
+#define TAG "RTM"
+
+/**
+ * Tag for printing the Routing table.
+ */
+#define RM_TAG "RAP"
+
+
+/**
+ * Initial Length of observer list.
+ */
+#define MAX_OBSERVER_LIST_LENGTH 10
+
+static const uint64_t USECS_PER_SEC = 1000000;
+
+OCStackResult RTMInitialize(u_linklist_t **gatewayTable, u_linklist_t **endpointTable)
+{
+    OC_LOG(DEBUG, TAG, "RTMInitialize IN");
+    RM_NULL_CHECK_WITH_RET(gatewayTable, TAG, "gatewayTable");
+    RM_NULL_CHECK_WITH_RET(endpointTable, TAG, "endpointTable");
+    if (NULL == *gatewayTable)
+    {
+        *gatewayTable = u_linklist_create();
+        if (NULL == *gatewayTable)
+        {
+            OC_LOG(ERROR, TAG, "Creating Routing Table failed");
+            RTMTerminate(gatewayTable, endpointTable);
+            return OC_STACK_ERROR;
+        }
+    }
+
+    if (NULL == *endpointTable)
+    {
+        *endpointTable = u_linklist_create();
+        if (NULL == *endpointTable)
+        {
+           OC_LOG(ERROR, TAG, "Creating Routing Table failed");
+            RTMTerminate(gatewayTable, endpointTable);
+           return OC_STACK_ERROR;
+        }
+    }
+    OC_LOG(DEBUG, TAG, "RTMInitialize OUT");
+    return OC_STACK_OK;
+}
+
+/*
+ * Freeing every char pointer and array list of gateway entry here and frees the table.
+ */
+OCStackResult RTMFreeGatewayRouteTable(u_linklist_t **gatewayTable)
+{
+    OC_LOG(DEBUG, TAG, "RTMFreeGatewayRouteTable IN");
+    if (NULL == gatewayTable || NULL == *gatewayTable)
+    {
+        return OC_STACK_OK;
+    }
+
+    u_linklist_iterator_t *iterTable = NULL;
+    u_linklist_init_iterator(*gatewayTable, &iterTable);
+    while (NULL != iterTable)
+    {
+        RTMGatewayEntry_t *hop = u_linklist_get_data(iterTable);
+        if (NULL != hop && NULL != hop->destination)
+        {
+            while (u_arraylist_length(hop->destination->destIntfAddr) > 0)
+            {
+                if (NULL != hop->destination)
+                {
+                    RTMDestIntfInfo_t *data = u_arraylist_remove(hop->destination->destIntfAddr, 0);
+                    OICFree(data);
+                }
+            }
+            u_arraylist_free(&(hop->destination->destIntfAddr));
+            OICFree(hop->destination);
+            // No need to free next hop as it is already freed during it's gateway free
+            OICFree(hop);
+        }
+
+        OCStackResult ret = u_linklist_remove(*gatewayTable, &iterTable);
+        if (OC_STACK_OK != ret)
+        {
+           OC_LOG(ERROR, TAG, "Deleting Entry from Routing Table failed");
+           return OC_STACK_ERROR;
+        }
+    }
+    u_linklist_free(gatewayTable);
+    OC_LOG(DEBUG, TAG, "RTMFreeGatewayRouteTable OUT");
+    return OC_STACK_OK;
+}
+
+/*
+ * Freeing every char pointer of endpoint entry here frees the table.
+ */
+OCStackResult RTMFreeEndpointRouteTable(u_linklist_t **endpointTable)
+{
+    OC_LOG(DEBUG, TAG, "IN");
+    if (NULL == endpointTable || NULL == *endpointTable)
+    {
+        return OC_STACK_OK;
+    }
+
+    u_linklist_iterator_t *iterTable = NULL;
+    u_linklist_init_iterator(*endpointTable, &iterTable);
+    while (NULL != iterTable)
+    {
+        RTMEndpointEntry_t *hop = u_linklist_get_data(iterTable);
+        if (NULL != hop)
+        {
+            OICFree(hop);
+        }
+
+        OCStackResult ret = u_linklist_remove(*endpointTable, &iterTable);
+        if (OC_STACK_OK != ret)
+        {
+            OC_LOG(ERROR, TAG, "Deleting Entry from Routing Table failed");
+            return OC_STACK_ERROR;
+        }
+    }
+    u_linklist_free(endpointTable);
+    OC_LOG(DEBUG, TAG, "OUT");
+    return OC_STACK_OK;
+}
+
+OCStackResult RTMFreeGatewayIdList(u_linklist_t **gatewayIdTable)
+{
+    OC_LOG(DEBUG, TAG, "IN");
+    if (NULL == gatewayIdTable || NULL == *gatewayIdTable)
+    {
+        return OC_STACK_OK;
+    }
+
+    u_linklist_iterator_t *iterTable = NULL;
+    u_linklist_init_iterator(*gatewayIdTable, &iterTable);
+    while (iterTable != NULL)
+    {
+        RTMGatewayId_t *hop = u_linklist_get_data(iterTable);
+        if (NULL != hop)
+        {
+            while (u_arraylist_length(hop->destIntfAddr) > 0)
+            {
+               RTMDestIntfInfo_t *data = u_arraylist_remove(hop->destIntfAddr, 0);
+               OICFree(data);
+            }
+            u_arraylist_free(&(hop->destIntfAddr));
+            OICFree(hop);
+
+            OCStackResult ret = u_linklist_remove(*gatewayIdTable, &iterTable);
+            if (OC_STACK_OK != ret)
+            {
+               OC_LOG(ERROR, TAG, "Deleting Entry from Routing Table failed");
+               return OC_STACK_ERROR;
+            }
+        }
+        else
+        {
+            OCStackResult res = u_linklist_remove(*gatewayIdTable, &iterTable);
+            if (OC_STACK_OK != res)
+            {
+                OC_LOG(ERROR, TAG, "Deleting Entry from Routing Table failed");
+                return OC_STACK_ERROR;
+            }
+        }
+    }
+    OC_LOG(DEBUG, TAG, "OUT");
+    return OC_STACK_OK;
+}
+
+/*
+ * Freeing memory first and then Freeing linked list for gateway and endpoint.
+ */
+OCStackResult RTMTerminate(u_linklist_t **gatewayTable, u_linklist_t **endpointTable)
+{
+    OC_LOG(DEBUG, TAG, "IN");
+
+    OCStackResult ret = RTMFreeGatewayRouteTable(gatewayTable);
+    if (OC_STACK_OK != ret)
+    {
+        OC_LOG(ERROR, TAG, "Deleting Gateway Routing Table failed");
+    }
+    if (NULL != *gatewayTable)
+    {
+        *gatewayTable = NULL;
+    }
+
+    ret = RTMFreeEndpointRouteTable(endpointTable);
+    if (OC_STACK_OK != ret)
+    {
+        OC_LOG(ERROR, TAG, "Deleting Endpoint Routing Table failed");
+    }
+    if (NULL != *endpointTable)
+    {
+        *endpointTable = NULL;
+    }
+    OC_LOG(DEBUG, TAG, "OUT");
+    return OC_STACK_OK;
+}
+
+/*
+ * Checks if destination gateway to be added is already present and update if present or
+ * adds new entry if not present.
+ * Adds Entry to head if route cost is 1.
+ * Adds Entry to Tail if route cost is > 1.
+ * Checks for Gateway id Memory and assigns to next hop address to achieve better memory usage.
+ */
+OCStackResult RTMAddGatewayEntry(uint32_t gatewayId, uint32_t nextHop, uint32_t routeCost,
+                                 const RTMDestIntfInfo_t *destInterfaces, u_linklist_t **gatewayTable)
+{
+    OC_LOG(DEBUG, TAG, "IN");
+    RM_NULL_CHECK_WITH_RET(gatewayTable, TAG, "gatewayTable");
+    if (NULL == *gatewayTable)
+    {
+        *gatewayTable = u_linklist_create();
+    }
+
+    if (1 == routeCost && 0 != nextHop)
+    {
+        OC_LOG(ERROR, TAG, "Adding Gateway Failed as Next Hop should be 0 for route cost 1");
+        return OC_STACK_ERROR;
+    }
+
+    if (0 == routeCost)
+    {
+        OC_LOG(ERROR, TAG, "Adding Gateway Failed as Route cost shouldnot be less than 1");
+        return OC_STACK_ERROR;
+    }
+
+    u_linklist_iterator_t *destNode = NULL;
+    RTMGatewayId_t *gatewayNodeMap = NULL;   // Gateway id ponter can be mapped to NextHop of entry.
+
+    u_linklist_iterator_t *iterTable = NULL;
+    u_linklist_init_iterator(*gatewayTable, &iterTable);
+    // Iterate over gateway list to find if already entry with this gatewayid is present.
+    while (NULL != iterTable)
+    {
+        RTMGatewayEntry_t *entry = u_linklist_get_data(iterTable);
+        if (NULL == entry)
+        {
+            break;
+        }
+
+        // To save node with same gateway id (To update entry instead of add new entry).
+        if (NULL == destNode && NULL != entry->destination &&
+            (gatewayId == entry->destination->gatewayId))
+        {
+            destNode = iterTable;
+        }
+
+        // To find pointer of gateway id for a node provided next hop equals to existing gateway id.
+        if (0 != nextHop && NULL != entry->destination &&
+            nextHop == entry->destination->gatewayId)
+        {
+            gatewayNodeMap = entry->destination;
+        }
+
+        if (NULL != destNode && NULL != gatewayNodeMap)
+        {
+            break;
+        }
+
+        u_linklist_get_next(&iterTable);
+    }
+
+    if (1 < routeCost && NULL == gatewayNodeMap)
+    {
+        OC_LOG(ERROR, TAG, "Adding Gateway Failed as Next Hop is invalid");
+        return OC_STACK_ERROR;
+    }
+
+    //Logic to update entry if it is already destination present or to add new entry.
+    if (NULL != destNode)
+    {
+        RTMGatewayEntry_t *entry = u_linklist_get_data(destNode);
+
+        if (NULL != entry  && 1 == entry->routeCost && 0 == nextHop)
+        {
+            if (NULL == destInterfaces)
+            {
+                OC_LOG(ERROR, TAG, "Not Adding Gateway destInterfaces is NULL");
+                return OC_STACK_ERROR;
+            }
+            OCStackResult update = RTMUpdateDestinationIntfAdr(gatewayId, *destInterfaces, true,
+                                                               gatewayTable);
+            if (OC_STACK_OK != update)
+            {
+                OC_LOG(ERROR, TAG, "RTMUpdateDestinationIntfAdr failed");
+            }
+            return update;
+        }
+        else if (NULL != entry  && entry->routeCost >= routeCost)
+        {
+            if (entry->routeCost == routeCost && NULL != entry->nextHop &&
+                (nextHop == entry->nextHop->gatewayId))
+            {
+                OC_LOG(ERROR, TAG, "Not Adding Gateway As it is Duplicate request");
+                return OC_STACK_DUPLICATE_REQUEST;
+            }
+
+            //Mapped nextHop gateway to another entries having gateway as destination.
+            if (NULL != gatewayNodeMap)
+            {
+                entry->destination->gatewayId = gatewayId;
+                entry->nextHop = gatewayNodeMap;
+                entry->destination->destIntfAddr = NULL;
+                entry->routeCost = routeCost;
+            }
+            else if (0 == nextHop)
+            {
+                entry->routeCost = 1;
+                // Entry can't be updated if Next hop is not same as existing Destinations of Table.
+                OC_LOG(DEBUG, TAG, "Updating the gateway");
+                entry->nextHop = NULL;
+                entry->destination->destIntfAddr = u_arraylist_create();
+                if (NULL == entry->destination->destIntfAddr)
+                {
+                    OC_LOG(ERROR, TAG, "Failed to create array list");
+                    return OC_STACK_ERROR;
+                }
+
+                RTMDestIntfInfo_t *destAdr =
+                    (RTMDestIntfInfo_t *) OICCalloc(1, sizeof(RTMDestIntfInfo_t));
+                if (NULL == destAdr)
+                {
+                    OC_LOG(ERROR, TAG, "Failed to Calloc destAdr");
+                    return OC_STACK_ERROR;
+                }
+
+                *destAdr = *destInterfaces;
+                destAdr->timeElapsed = RTMGetCurrentTime();
+                destAdr->isValid = true;
+                bool result =
+                    u_arraylist_add(entry->destination->destIntfAddr, (void *)destAdr);
+                if (!result)
+                {
+                    OC_LOG(ERROR, TAG, "Adding node to head failed");
+                    OICFree(destAdr);
+                    return OC_STACK_ERROR;
+                }
+            }
+            else
+            {
+                OC_LOG(ERROR, TAG, "Adding Gateway Failed as Next hop is invalid");
+                return OC_STACK_ERROR;
+            }
+
+        }
+        else if (NULL != entry  && entry->routeCost < routeCost)
+        {
+            OC_LOG(ERROR, TAG, "Adding Gateway Failed as Route cost is more than old");
+            return OC_STACK_ERROR;
+        }
+
+        // Logic to add updated node to Head of list as route cost is 1.
+        if (1 == routeCost && NULL != entry)
+        {
+            OCStackResult res = u_linklist_remove(*gatewayTable, &destNode);
+            if (OC_STACK_OK != res)
+            {
+                OC_LOG(ERROR, TAG, "Removing node failed");
+            }
+            else
+            {
+                res = u_linklist_add_head(*gatewayTable, (void *)entry);
+                if (OC_STACK_OK != res)
+                {
+                    OC_LOG(ERROR, TAG, "Adding node to head failed");
+                }
+            }
+        }
+    }
+    else
+    {
+        // Filling new Entry
+        RTMGatewayEntry_t *hopEntry = (RTMGatewayEntry_t *)OICCalloc(1, sizeof(RTMGatewayEntry_t));
+        if (NULL == hopEntry)
+        {
+            OC_LOG(ERROR, TAG, "Calloc failed for hop entry");
+            return OC_STACK_ERROR;
+        }
+
+        hopEntry->destination = (RTMGatewayId_t*)OICCalloc(1, sizeof(RTMGatewayId_t));
+        if (NULL == hopEntry->destination)
+        {
+            OC_LOG(ERROR, TAG, "Calloc failed for hop entry destination");
+            OICFree(hopEntry);
+            return OC_STACK_ERROR;
+        }
+
+        hopEntry->destination->gatewayId = gatewayId;
+        if (NULL != destInterfaces && strlen((*destInterfaces).destIntfAddr.addr) > 0)
+        {
+            hopEntry->destination->destIntfAddr = u_arraylist_create();
+            RTMDestIntfInfo_t *destAdr =
+                (RTMDestIntfInfo_t *) OICCalloc(1, sizeof(RTMDestIntfInfo_t));
+            if (NULL == destAdr)
+            {
+                OC_LOG(ERROR, TAG, "Calloc failed for destAdr");
+                u_arraylist_free(&(hopEntry->destination->destIntfAddr));
+                OICFree(hopEntry->destination);
+                OICFree(hopEntry);
+                return OC_STACK_ERROR;
+            }
+
+            *destAdr = *destInterfaces;
+            destAdr->timeElapsed = RTMGetCurrentTime();
+            destAdr->isValid = true;
+            u_arraylist_add(hopEntry->destination->destIntfAddr, (void *)destAdr);
+        }
+        else
+        {
+            hopEntry->destination->destIntfAddr = NULL;
+        }
+
+        hopEntry->routeCost = routeCost;
+        // Mapped nextHop gateway to another entries having gateway as destination.
+        if (NULL != gatewayNodeMap)
+        {
+            hopEntry->nextHop = gatewayNodeMap;
+        }
+        else if (1 == routeCost)
+        {
+            hopEntry->nextHop = NULL;
+        }
+        else
+        {
+            OC_LOG(ERROR, TAG, "Adding Gateway Failed as Next Hop is invalid");
+            while (u_arraylist_length(hopEntry->destination->destIntfAddr) > 0)
+            {
+                RTMDestIntfInfo_t *data =
+                    u_arraylist_remove(hopEntry->destination->destIntfAddr, 0);
+                OICFree(data);
+            }
+            u_arraylist_free(&(hopEntry->destination->destIntfAddr));
+            OICFree(hopEntry->destination);
+            OICFree(hopEntry);
+
+            return OC_STACK_ERROR;
+        }
+
+        OCStackResult ret = OC_STACK_OK;
+        if (hopEntry->routeCost == 1)
+        {
+            ret = u_linklist_add_head(*gatewayTable, (void *)hopEntry);
+        }
+        else
+        {
+            ret = u_linklist_add(*gatewayTable, (void *)hopEntry);
+        }
+
+        if (OC_STACK_OK != ret)
+        {
+            OC_LOG(ERROR, TAG, "Adding Gateway Entry to Routing Table failed");
+            while (u_arraylist_length(hopEntry->destination->destIntfAddr) > 0)
+            {
+                RTMDestIntfInfo_t *data = u_arraylist_remove(hopEntry->destination->destIntfAddr, 0);
+                OICFree(data);
+            }
+            u_arraylist_free(&(hopEntry->destination->destIntfAddr));
+            OICFree(hopEntry->destination);
+            OICFree(hopEntry);
+            return OC_STACK_ERROR;
+        }
+    }
+    OC_LOG(DEBUG, TAG, "OUT");
+    return OC_STACK_OK;
+}
+
+OCStackResult RTMAddEndpointEntry(uint16_t *endpointId, const CAEndpoint_t *destAddr,
+                                  u_linklist_t **endpointTable)
+{
+    OC_LOG(DEBUG, TAG, "IN");
+    RM_NULL_CHECK_WITH_RET(endpointId, TAG, "endpointId");
+    RM_NULL_CHECK_WITH_RET(destAddr, TAG, "destAddr");
+    RM_NULL_CHECK_WITH_RET(endpointTable, TAG, "endpointTable");
+    if (NULL == *endpointTable)
+    {
+        *endpointTable = u_linklist_create();
+    }
+
+    u_linklist_iterator_t *iterTable = NULL;
+    u_linklist_init_iterator(*endpointTable, &iterTable);
+    // Iterate over gateway list to find if already entry with this gatewayid is present.
+    while (NULL != iterTable)
+    {
+        RTMEndpointEntry_t *entry =
+            (RTMEndpointEntry_t *) u_linklist_get_data(iterTable);
+
+        if (NULL != entry && (0 == memcmp(destAddr->addr, entry->destIntfAddr.addr,
+                              strlen(entry->destIntfAddr.addr)))
+            && destAddr->port == entry->destIntfAddr.port)
+        {
+            *endpointId = entry->endpointId;
+            OC_LOG(ERROR, TAG, "Adding failed as Enpoint Entry Already present in Table");
+            return OC_STACK_DUPLICATE_REQUEST;
+        }
+        u_linklist_get_next(&iterTable);
+    }
+
+    // Filling Entry.
+    RTMEndpointEntry_t *hopEntry = (RTMEndpointEntry_t *)OICCalloc(1, sizeof(RTMEndpointEntry_t));
+
+    if (NULL == hopEntry)
+    {
+       OC_LOG(ERROR, TAG, "Malloc failed for hop entry");
+       return OC_STACK_ERROR;
+    }
+
+    hopEntry->endpointId = *endpointId;
+    hopEntry->destIntfAddr = *destAddr;
+
+    OCStackResult ret = u_linklist_add(*endpointTable, (void *)hopEntry);
+    if (OC_STACK_OK != ret)
+    {
+       OC_LOG(ERROR, TAG, "Adding Enpoint Entry to Routing Table failed");
+       OICFree(hopEntry);
+       return OC_STACK_ERROR;
+    }
+    OC_LOG(DEBUG, TAG, "OUT");
+    return OC_STACK_OK;
+}
+
+OCStackResult RTMAddObserver(uint32_t obsID, CAEndpoint_t devAddr, u_linklist_t **gatewayTable)
+{
+    OC_LOG(DEBUG, TAG, "IN");
+    RM_NULL_CHECK_WITH_RET(gatewayTable, TAG, "gatewayTable");
+    RM_NULL_CHECK_WITH_RET(*gatewayTable, TAG, "*gatewayTable");
+
+    u_linklist_iterator_t *iterTable = NULL;
+    u_linklist_init_iterator(*gatewayTable, &iterTable);
+    while (NULL != iterTable)
+    {
+        RTMGatewayEntry_t *entry = u_linklist_get_data(iterTable);
+
+        for (uint32_t i = 0; i < u_arraylist_length(entry->destination->destIntfAddr); i++)
+        {
+            RTMDestIntfInfo_t *destCheck = u_arraylist_get(entry->destination->destIntfAddr, i);
+            if (NULL != destCheck &&
+                (0 == memcmp(destCheck->destIntfAddr.addr, devAddr.addr, strlen(devAddr.addr)))
+                && devAddr.port == destCheck->destIntfAddr.port)
+            {
+                destCheck->observerId = obsID;
+                OC_LOG(DEBUG, TAG, "OUT");
+                return OC_STACK_OK;
+            }
+        }
+        u_linklist_get_next(&iterTable);
+    }
+    OC_LOG(DEBUG, TAG, "OUT");
+    return OC_STACK_ERROR;
+}
+
+bool RTMIsObserverPresent(CAEndpoint_t devAddr, OCObservationId *obsID,
+                          const u_linklist_t *gatewayTable)
+{
+    OC_LOG(DEBUG, TAG, "IN");
+    if (NULL == obsID)
+    {
+        OC_LOG(ERROR, TAG, "obsID is null");
+        return false;
+    }
+
+    if (NULL == gatewayTable)
+    {
+        OC_LOG(ERROR, TAG, "gatewayTable is null");
+        return false;
+    }
+
+    u_linklist_iterator_t *iterTable = NULL;
+    u_linklist_init_iterator(gatewayTable, &iterTable);
+    while (NULL != iterTable)
+    {
+        RTMGatewayEntry_t *entry = u_linklist_get_data(iterTable);
+        if (NULL == entry && NULL == entry->destination)
+        {
+            OC_LOG(ERROR, TAG, "entry is NULL");
+            return false;
+        }
+        for (uint32_t i = 0; i < u_arraylist_length(entry->destination->destIntfAddr); i++)
+        {
+            RTMDestIntfInfo_t *destCheck =
+                u_arraylist_get(entry->destination->destIntfAddr, i);
+            if (NULL != destCheck && (0 == memcmp(destCheck->destIntfAddr.addr, devAddr.addr,
+                                      strlen(devAddr.addr)))
+                && devAddr.port == destCheck->destIntfAddr.port && 0 != destCheck->observerId)
+            {
+                *obsID = destCheck->observerId;
+                OC_LOG(DEBUG, TAG, "OUT");
+                return true;
+            }
+        }
+        u_linklist_get_next(&iterTable);
+    }
+    OC_LOG(DEBUG, TAG, "OUT");
+    return false;
+}
+
+OCStackResult RTMRemoveGatewayEntry(uint32_t gatewayId, u_linklist_t **removedGatewayNodes,
+                                    u_linklist_t **gatewayTable)
+{
+    OC_LOG(DEBUG, TAG, "IN");
+    RM_NULL_CHECK_WITH_RET(gatewayTable, TAG, "gatewayTable");
+    RM_NULL_CHECK_WITH_RET(*gatewayTable, TAG, "*gatewayTable");
+
+    u_linklist_iterator_t *iterTable = NULL;
+
+    // if link list is not null we can directly add removed nodes to it instead of creating everytime.
+    if (NULL == *removedGatewayNodes)
+    {
+        *removedGatewayNodes = u_linklist_create();
+    }
+    OCStackResult ret = OC_STACK_OK;
+    u_linklist_init_iterator(*gatewayTable, &iterTable);
+    while (NULL != iterTable)
+    {
+        RTMGatewayEntry_t *entry = u_linklist_get_data(iterTable);
+        if (NULL == entry || NULL == entry->destination)
+        {
+            u_linklist_get_next(&iterTable);
+            continue;
+        }
+
+        if (gatewayId == entry->destination->gatewayId || (NULL != entry->nextHop &&
+            (gatewayId == entry->nextHop->gatewayId)))
+        {
+            OC_LOG_V(DEBUG, TAG, "Removing the gateway entry: %u", entry->destination->gatewayId);
+            ret = u_linklist_remove(*gatewayTable, &iterTable);
+            if (OC_STACK_OK != ret)
+            {
+               OC_LOG(ERROR, TAG, "Deleting Entry from Routing Table failed");
+               return OC_STACK_ERROR;
+            }
+            else
+            {
+                u_linklist_add(*removedGatewayNodes, (void *)entry);
+            }
+        }
+        else
+        {
+            u_linklist_get_next(&iterTable);
+        }
+    }
+    OC_LOG(DEBUG, TAG, "RTMRemoveGatewayEntry OUT");
+    return OC_STACK_OK;
+}
+
+OCStackResult RTMRemoveGatewayDestEntry(uint32_t gatewayId, uint32_t nextHop,
+                                        const RTMDestIntfInfo_t *destInfAdr,
+                                        RTMGatewayEntry_t **existEntry, u_linklist_t **gatewayTable)
+{
+    OC_LOG(DEBUG, TAG, "IN");
+    RM_NULL_CHECK_WITH_RET(gatewayTable, TAG, "gatewayTable");
+    RM_NULL_CHECK_WITH_RET(*gatewayTable, TAG, "*gatewayTable");
+    RM_NULL_CHECK_WITH_RET(destInfAdr, TAG, "destInfAdr");
+
+    u_linklist_iterator_t *iterTable = NULL;
+
+    OCStackResult ret = -1;
+    u_linklist_init_iterator(*gatewayTable, &iterTable);
+    while (NULL != iterTable)
+    {
+        RTMGatewayEntry_t *entry = u_linklist_get_data(iterTable);
+        if (NULL == entry)
+        {
+            u_linklist_get_next(&iterTable);
+            continue;
+        }
+
+        // Update the time for NextHop entry.
+        if (NULL != entry->destination && nextHop == entry->destination->gatewayId)
+        {
+            for (uint32_t i = 0; i < u_arraylist_length(entry->destination->destIntfAddr); i++)
+            {
+                RTMDestIntfInfo_t *destCheck = u_arraylist_get(entry->destination->destIntfAddr, i);
+                if (0 == memcmp(destCheck->destIntfAddr.addr, destInfAdr->destIntfAddr.addr,
+                    strlen(destInfAdr->destIntfAddr.addr))
+                    && destInfAdr->destIntfAddr.port == destCheck->destIntfAddr.port)
+                {
+                    destCheck->timeElapsed =  RTMGetCurrentTime();
+                    break;
+                }
+            }
+        }
+
+        // Remove node with given gatewayid and nextHop if not found update exist entry.
+        if (NULL != entry->destination && (gatewayId == entry->destination->gatewayId))
+        {
+            OC_LOG_V(INFO, TAG, "Remove the gateway ID: %u", entry->destination->gatewayId);
+            if (NULL != entry->nextHop && nextHop == entry->nextHop->gatewayId)
+            {
+                ret = u_linklist_remove(*gatewayTable, &iterTable);
+                if (OC_STACK_OK != ret)
+                {
+                   OC_LOG(ERROR, TAG, "Deleting Entry from Routing Table failed");
+                   return OC_STACK_ERROR;
+                }
+                OICFree(entry);
+                return OC_STACK_OK;
+            }
+
+            *existEntry = entry;
+            OC_LOG(DEBUG, TAG, "OUT");
+            return OC_STACK_ERROR;
+        }
+
+        u_linklist_get_next(&iterTable);
+    }
+    OC_LOG(DEBUG, TAG, "OUT");
+    return OC_STACK_ERROR;
+}
+
+OCStackResult RTMRemoveEndpointEntry(uint16_t endpointId, u_linklist_t **endpointTable)
+{
+    OC_LOG(DEBUG, TAG, "IN");
+    RM_NULL_CHECK_WITH_RET(endpointTable, TAG, "endpointTable");
+    RM_NULL_CHECK_WITH_RET(*endpointTable, TAG, "*endpointTable");
+
+    u_linklist_iterator_t *iterTable = NULL;
+    u_linklist_init_iterator(*endpointTable, &iterTable);
+    while (NULL != iterTable)
+    {
+        RTMEndpointEntry_t *entry = u_linklist_get_data(iterTable);
+        if (NULL !=  entry && endpointId == entry->endpointId)
+        {
+            OCStackResult ret = u_linklist_remove(*endpointTable, &iterTable);
+            if (OC_STACK_OK != ret)
+            {
+               OC_LOG(ERROR, TAG, "Deleting Entry from Routing Table failed");
+               return OC_STACK_ERROR;
+            }
+            OICFree(entry);
+        }
+        else
+        {
+            u_linklist_get_next(&iterTable);
+        }
+    }
+    OC_LOG(DEBUG, TAG, "OUT");
+    return OC_STACK_OK;
+}
+
+OCStackResult RTMRemoveGateways(u_linklist_t **gatewayTable)
+{
+    OC_LOG(DEBUG, TAG, "IN");
+
+    if (NULL == gatewayTable || NULL == *gatewayTable)
+    {
+        OC_LOG(DEBUG, TAG, "OUT");
+        return OC_STACK_OK;
+    }
+
+    OCStackResult ret = RTMFreeGatewayRouteTable(gatewayTable);
+    if (OC_STACK_OK != ret)
+    {
+        OC_LOG(ERROR, TAG, "Removing Gateways failed");
+        return ret;
+    }
+    OC_LOG(DEBUG, TAG, "OUT");
+    return OC_STACK_OK;
+}
+
+OCStackResult RTMRemoveEndpoints(u_linklist_t **endpointTable)
+{
+    OC_LOG(DEBUG, TAG, "IN");
+    if (NULL == endpointTable || NULL == *endpointTable)
+    {
+        OC_LOG(DEBUG, TAG, "OUT");
+        return OC_STACK_OK;
+    }
+
+    OCStackResult ret = RTMFreeEndpointRouteTable(endpointTable);
+    if (OC_STACK_OK != ret)
+    {
+        OC_LOG(ERROR, TAG, "Freeing Endpoints failed");
+        return OC_STACK_ERROR;
+    }
+    OC_LOG(DEBUG, TAG, "OUT");
+    return OC_STACK_OK;
+}
+
+void RTMFreeGateway(RTMGatewayId_t *gateway, u_linklist_t **gatewayTable)
+{
+    OC_LOG(DEBUG, TAG, "IN");
+    RM_NULL_CHECK_VOID(gateway, TAG, "gateway");
+    RM_NULL_CHECK_VOID(gatewayTable, TAG, "gatewayTable");
+    RM_NULL_CHECK_VOID(*gatewayTable, TAG, "*gatewayTable");
+    while (0 < u_arraylist_length(gateway->destIntfAddr))
+    {
+        void *data = u_arraylist_remove(gateway->destIntfAddr, 0);
+        OICFree(data);
+    }
+    u_arraylist_free(&(gateway->destIntfAddr));
+    OICFree(gateway);
+    OC_LOG(DEBUG, TAG, "OUT");
+}
+
+void RTMGetNeighbours(u_linklist_t **neighbourNodes, const u_linklist_t *gatewayTable)
+{
+    OC_LOG(DEBUG, TAG, "IN");
+    RM_NULL_CHECK_VOID(neighbourNodes, TAG, "neighbourNodes");
+    RM_NULL_CHECK_VOID(gatewayTable, TAG, "gatewayTable");
+
+    *neighbourNodes = u_linklist_create();
+    u_linklist_iterator_t *iterTable = NULL;
+    u_linklist_init_iterator(gatewayTable, &iterTable);
+    while (NULL != iterTable)
+    {
+        RTMGatewayEntry_t *entry = u_linklist_get_data(iterTable);
+        if (NULL != entry && 1 == entry->routeCost)
+        {
+            u_linklist_add(*neighbourNodes, (void *)entry);
+        }
+        else if (NULL != entry && 1 < entry->routeCost)
+        {
+            OC_LOG(DEBUG, TAG, "OUT");
+            return;
+        }
+
+        u_linklist_get_next(&iterTable);
+    }
+    OC_LOG(DEBUG, TAG, "OUT");
+}
+
+RTMGatewayId_t *RTMGetNextHop(uint32_t gatewayId, const u_linklist_t *gatewayTable)
+{
+    OC_LOG(DEBUG, TAG, "IN");
+    if (0 == gatewayId)
+    {
+        OC_LOG(ERROR, TAG, "gatewayId is invalid");
+        return NULL;
+    }
+
+    if (NULL == gatewayTable)
+    {
+        OC_LOG(ERROR, TAG, "gatewayTable is null");
+        return NULL;
+    }
+
+    u_linklist_iterator_t *iterTable = NULL;
+    u_linklist_init_iterator(gatewayTable, &iterTable);
+    while (NULL != iterTable)
+    {
+        RTMGatewayEntry_t *entry = u_linklist_get_data(iterTable);
+        if (NULL != entry && gatewayId == entry->destination->gatewayId)
+        {
+            if (1 == entry->routeCost)
+            {
+                OC_LOG(DEBUG, TAG, "OUT");
+                return entry->destination;
+            }
+            OC_LOG(DEBUG, TAG, "OUT");
+            return entry->nextHop;
+        }
+        u_linklist_get_next(&iterTable);
+    }
+    OC_LOG(DEBUG, TAG, "OUT");
+    return NULL;
+}
+
+CAEndpoint_t *RTMGetEndpointEntry(uint16_t endpointId, const u_linklist_t *endpointTable)
+{
+    OC_LOG(DEBUG, TAG, "IN");
+    if (NULL == endpointTable)
+    {
+        OC_LOG(ERROR, TAG, "endpointTable is null");
+        return NULL;
+    }
+
+    u_linklist_iterator_t *iterTable = NULL;
+    u_linklist_init_iterator(endpointTable, &iterTable);
+
+    while (NULL != iterTable)
+    {
+        RTMEndpointEntry_t *entry = u_linklist_get_data(iterTable);
+        if (NULL != entry && (endpointId == entry->endpointId))
+        {
+            OC_LOG(DEBUG, TAG, "OUT");
+            return &(entry->destIntfAddr);
+        }
+        u_linklist_get_next(&iterTable);
+    }
+    OC_LOG(DEBUG, TAG, "OUT");
+    return NULL;
+}
+
+void RTMGetObserverList(OCObservationId **obsList, uint8_t *obsListLen,
+                        const u_linklist_t *gatewayTable)
+{
+    OC_LOG(DEBUG, TAG, "IN");
+    RM_NULL_CHECK_VOID(gatewayTable, TAG, "gatewayTable");
+    RM_NULL_CHECK_VOID(obsList, TAG, "obsList");
+
+    *obsList = (OCObservationId *) OICCalloc(MAX_OBSERVER_LIST_LENGTH, sizeof(OCObservationId));
+    u_linklist_iterator_t *iterTable = NULL;
+    u_linklist_init_iterator(gatewayTable, &iterTable);
+    uint8_t len = 0;
+    while (NULL != iterTable)
+    {
+        RTMGatewayEntry_t *entry = u_linklist_get_data(iterTable);
+        for (uint32_t i = 0; i < u_arraylist_length(entry->destination->destIntfAddr); i++)
+        {
+            RTMDestIntfInfo_t *destCheck = u_arraylist_get(entry->destination->destIntfAddr, i);
+            if (NULL == destCheck)
+            {
+                OC_LOG(ERROR, TAG, "destCheck is null");
+                return;
+            }
+            if (0 != destCheck->observerId)
+            {
+                OC_LOG_V(DEBUG, TAG, "Observer ID is %d", destCheck->observerId);
+                *(*obsList + len) = destCheck->observerId;
+                len++;
+            }
+            if (MAX_OBSERVER_LIST_LENGTH < len)
+            {
+                *obsList = (OCObservationId *) OICRealloc((void *)*obsList,
+                           (sizeof(OCObservationId) * (len + 1)));
+            }
+            break;
+        }
+        u_linklist_get_next(&iterTable);
+    }
+
+    *obsListLen = len;
+    OC_LOG(DEBUG, TAG, "OUT");
+}
+
+OCStackResult RTMUpdateDestinationIntfAdr(uint32_t gatewayId, RTMDestIntfInfo_t destInterfaces,
+                                          bool addAdr, u_linklist_t **gatewayTable)
+{
+    OC_LOG(DEBUG, TAG, "IN");
+    RM_NULL_CHECK_WITH_RET(gatewayTable, TAG, "gatewayTable");
+    RM_NULL_CHECK_WITH_RET(*gatewayTable, TAG, "*gatewayTable");
+
+    u_linklist_iterator_t *iterTable = NULL;
+    u_linklist_init_iterator(*gatewayTable, &iterTable);
+    while (NULL != iterTable)
+    {
+        RTMGatewayEntry_t *entry = u_linklist_get_data(iterTable);
+        if (NULL != entry && NULL != entry->destination &&
+            gatewayId == entry->destination->gatewayId)
+        {
+            if (addAdr)
+            {
+                for (uint32_t i = 0; i < u_arraylist_length(entry->destination->destIntfAddr); i++)
+                {
+                    RTMDestIntfInfo_t *destCheck =
+                        u_arraylist_get(entry->destination->destIntfAddr, i);
+                    if (NULL == destCheck)
+                    {
+                        OC_LOG(ERROR, TAG, "Destination adr get failed");
+                        continue;
+                    }
+
+                    if (0 == memcmp(destCheck->destIntfAddr.addr, destInterfaces.destIntfAddr.addr,
+                        strlen(destInterfaces.destIntfAddr.addr))
+                        && destInterfaces.destIntfAddr.port == destCheck->destIntfAddr.port)
+                    {
+                        destCheck->timeElapsed = RTMGetCurrentTime();
+                        destCheck->isValid = true;
+                        OC_LOG(ERROR, TAG, "destInterfaces already present");
+                        return OC_STACK_ERROR;
+                    }
+                }
+
+                RTMDestIntfInfo_t *destAdr =
+                        (RTMDestIntfInfo_t *) OICCalloc(1, sizeof(RTMDestIntfInfo_t));
+                if (NULL == destAdr)
+                {
+                    OC_LOG(ERROR, TAG, "Calloc destAdr failed");
+                    return OC_STACK_ERROR;
+                }
+                *destAdr = destInterfaces;
+                destAdr->timeElapsed = RTMGetCurrentTime();
+                destAdr->isValid = true;
+                bool result =
+                    u_arraylist_add(entry->destination->destIntfAddr, (void *)destAdr);
+                if (!result)
+                {
+                    OC_LOG(ERROR, TAG, "Updating Destinterface address failed");
+                    OICFree(destAdr);
+                    return OC_STACK_ERROR;
+                }
+                OC_LOG(DEBUG, TAG, "OUT");
+                return OC_STACK_DUPLICATE_REQUEST;
+            }
+
+            for (uint32_t i = 0; i < u_arraylist_length(entry->destination->destIntfAddr); i++)
+            {
+                RTMDestIntfInfo_t *removeAdr =
+                    u_arraylist_get(entry->destination->destIntfAddr, i);
+                if (0 == memcmp(removeAdr->destIntfAddr.addr, destInterfaces.destIntfAddr.addr,
+                    strlen(destInterfaces.destIntfAddr.addr))
+                    && destInterfaces.destIntfAddr.port == removeAdr->destIntfAddr.port)
+                {
+                    RTMDestIntfInfo_t *data =
+                        u_arraylist_remove(entry->destination->destIntfAddr, i);
+                    OICFree(data);
+                    break;
+                }
+            }
+        }
+        u_linklist_get_next(&iterTable);
+    }
+    OC_LOG(DEBUG, TAG, "OUT");
+    return OC_STACK_OK;
+}
+
+OCStackResult RTMUpdateMcastSeqNumber(uint32_t gatewayId, uint16_t seqNum,
+                                      u_linklist_t **gatewayTable)
+{
+    OC_LOG(DEBUG, TAG, "IN");
+    RM_NULL_CHECK_WITH_RET(gatewayTable, TAG, "gatewayTable");
+    RM_NULL_CHECK_WITH_RET(*gatewayTable, TAG, "*gatewayTable");
+
+    u_linklist_iterator_t *iterTable = NULL;
+    u_linklist_init_iterator(*gatewayTable, &iterTable);
+    while (NULL != iterTable)
+    {
+        RTMGatewayEntry_t *entry = u_linklist_get_data(iterTable);
+        if (NULL != entry && NULL != entry->destination &&
+            gatewayId == entry->destination->gatewayId)
+        {
+            if (0 == entry->mcastMessageSeqNum || entry->mcastMessageSeqNum < seqNum)
+            {
+                entry->mcastMessageSeqNum = seqNum;
+                return OC_STACK_OK;
+            }
+            else if (entry->mcastMessageSeqNum == seqNum)
+            {
+                return OC_STACK_DUPLICATE_REQUEST;
+            }
+            else
+            {
+                return OC_STACK_COMM_ERROR;
+            }
+        }
+        u_linklist_get_next(&iterTable);
+    }
+    OC_LOG(DEBUG, TAG, "OUT");
+    return OC_STACK_OK;
+}
+
+uint64_t RTMGetCurrentTime()
+{
+    uint64_t currentTime = 0;
+
+#ifdef __ANDROID__
+    struct timespec getTs;
+
+    clock_gettime(CLOCK_MONOTONIC, &getTs);
+
+    currentTime = getTs.tv_sec;
+#elif defined __ARDUINO__
+    currentTime = millis() / 1000;
+#else
+#if _POSIX_TIMERS > 0
+    struct timespec ts;
+    clock_gettime(CLOCK_MONOTONIC, &ts);
+    currentTime = ts.tv_sec;
+#else
+    struct timeval tv;
+    gettimeofday(&tv, NULL);
+    currentTime = tv.tv_sec;
+#endif
+#endif
+    return currentTime;
+}
+
+OCStackResult RTMUpdateDestAddrValidity(u_linklist_t **invalidTable, u_linklist_t **gatewayTable)
+{
+    OC_LOG(DEBUG, TAG, "IN");
+    RM_NULL_CHECK_WITH_RET(invalidTable, TAG, "invalidTable");
+    RM_NULL_CHECK_WITH_RET(gatewayTable, TAG, "gatewayTable");
+    RM_NULL_CHECK_WITH_RET(*gatewayTable, TAG, "*gatewayTable");
+
+    *invalidTable = u_linklist_create();
+    u_linklist_iterator_t *iterTable = NULL;
+    uint64_t presentTime = RTMGetCurrentTime();
+
+    u_linklist_init_iterator(*gatewayTable, &iterTable);
+    while (NULL != iterTable)
+    {
+        RTMGatewayEntry_t *entry = (RTMGatewayEntry_t *) u_linklist_get_data(iterTable);
+        if (NULL == entry)
+        {
+            u_linklist_get_next(&iterTable);
+            continue;
+        }
+        else if (1 == entry->routeCost)
+        {
+            for (uint32_t i = 0; i < u_arraylist_length(entry->destination->destIntfAddr); i++)
+            {
+                RTMDestIntfInfo_t *destCheck = u_arraylist_get(entry->destination->destIntfAddr, i);
+                if (GATEWAY_ALIVE_TIMEOUT < (presentTime - destCheck->timeElapsed))
+                {
+                    destCheck->isValid = false;
+                    u_linklist_add(*invalidTable, (void *)destCheck);
+                }
+            }
+        }
+        else if (1 < entry->routeCost)
+        {
+            break;
+        }
+        u_linklist_get_next(&iterTable);
+    }
+    OC_LOG(DEBUG, TAG, "OUT");
+    return OC_STACK_OK;
+}
+
+OCStackResult RTMRemoveInvalidGateways(u_linklist_t **invalidTable, u_linklist_t **gatewayTable)
+{
+    OC_LOG(DEBUG, TAG, "IN");
+    RM_NULL_CHECK_WITH_RET(invalidTable, TAG, "invalidTable");
+    RM_NULL_CHECK_WITH_RET(gatewayTable, TAG, "gatewayTable");
+    RM_NULL_CHECK_WITH_RET(*gatewayTable, TAG, "*gatewayTable");
+
+    *invalidTable = u_linklist_create();
+
+    u_linklist_iterator_t *iterTable = NULL;
+    u_linklist_init_iterator(*gatewayTable, &iterTable);
+    while (iterTable != NULL)
+    {
+        RTMGatewayEntry_t *entry = u_linklist_get_data(iterTable);
+
+        if (NULL == entry)
+        {
+            u_linklist_get_next(&iterTable);
+            continue;
+        }
+        else if (NULL != entry->destination && (1 == entry->routeCost))
+        {
+            for (uint32_t i = 0; i < u_arraylist_length(entry->destination->destIntfAddr); i++)
+            {
+                RTMDestIntfInfo_t *destCheck = u_arraylist_get(entry->destination->destIntfAddr, i);
+                if (!destCheck->isValid)
+                {
+                    void *data = u_arraylist_remove(entry->destination->destIntfAddr, i);
+                    OICFree(data);
+                    i--;
+                }
+            }
+
+            if (0 == u_arraylist_length(entry->destination->destIntfAddr))
+            {
+                u_arraylist_free(&(entry->destination->destIntfAddr));
+                OCStackResult res =
+                    RTMRemoveGatewayEntry(entry->destination->gatewayId, invalidTable, gatewayTable);
+                if (OC_STACK_OK != res)
+                {
+                    OC_LOG(ERROR, TAG, "Removing Entries failed");
+                    return OC_STACK_ERROR;
+                }
+                u_linklist_get_next(&iterTable);
+            }
+            else
+            {
+                u_linklist_get_next(&iterTable);
+            }
+        }
+        else if (1 < entry->routeCost)
+        {
+            break;
+        }
+        else
+        {
+            u_linklist_get_next(&iterTable);
+        }
+    }
+    OC_LOG(DEBUG, TAG, "OUT");
+    return OC_STACK_OK;
+}
+
+OCStackResult RTMUpdateEntryParameters(uint32_t gatewayId, uint32_t seqNum,
+                                       const RTMDestIntfInfo_t *destAdr, u_linklist_t **gatewayTable,
+                                       bool forceUpdate)
+{
+    OC_LOG(DEBUG, TAG, "IN");
+    RM_NULL_CHECK_WITH_RET(gatewayTable, TAG, "gatewayTable");
+    RM_NULL_CHECK_WITH_RET(*gatewayTable, TAG, "*gatewayTable");
+    RM_NULL_CHECK_WITH_RET(destAdr, TAG, "destAdr");
+
+    u_linklist_iterator_t *iterTable = NULL;
+    u_linklist_init_iterator(*gatewayTable, &iterTable);
+    while (NULL != iterTable)
+    {
+        RTMGatewayEntry_t *entry = u_linklist_get_data(iterTable);
+
+        if (NULL == entry)
+        {
+            u_linklist_get_next(&iterTable);
+            continue;
+        }
+        if (NULL != entry->destination && gatewayId == entry->destination->gatewayId)
+        {
+            for (uint32_t i = 0; i < u_arraylist_length(entry->destination->destIntfAddr); i++)
+            {
+                RTMDestIntfInfo_t *destCheck =
+                    u_arraylist_get(entry->destination->destIntfAddr, i);
+                if (NULL != destCheck &&
+                    (0 == memcmp(destCheck->destIntfAddr.addr, destAdr->destIntfAddr.addr,
+                     strlen(destAdr->destIntfAddr.addr)))
+                     && destAdr->destIntfAddr.port == destCheck->destIntfAddr.port)
+                {
+                    destCheck->timeElapsed = RTMGetCurrentTime();
+                    destCheck->isValid = true;
+                }
+            }
+
+            if (0 != entry->seqNum && seqNum == entry->seqNum)
+            {
+                return OC_STACK_DUPLICATE_REQUEST;
+            }
+            else if (0 != entry->seqNum && seqNum != ((entry->seqNum) + 1) && !forceUpdate)
+            {
+                return OC_STACK_COMM_ERROR;
+            }
+            else
+            {
+                entry->seqNum = seqNum;
+                OC_LOG(DEBUG, TAG, "OUT");
+                return OC_STACK_OK;
+            }
+        }
+        u_linklist_get_next(&iterTable);
+    }
+    OC_LOG(DEBUG, TAG, "OUT");
+    return OC_STACK_OK;
+}
+
+void RTMPrintTable(const u_linklist_t *gatewayTable, const u_linklist_t *endpointTable)
+{
+    RM_NULL_CHECK_VOID(gatewayTable, TAG, "gatewayTable");
+    OC_LOG(DEBUG, RM_TAG, "=================Gateway List table============================\n");
+    u_linklist_iterator_t *iterTable = NULL;
+    u_linklist_init_iterator(gatewayTable, &iterTable);
+    while (NULL != iterTable)
+    {
+        RTMGatewayEntry_t *hop =
+            (RTMGatewayEntry_t *) u_linklist_get_data(iterTable);
+        if (NULL == hop)
+        {
+            OC_LOG(ERROR, RM_TAG, "Printing Table Failed");
+            return;
+        }
+        if (NULL == hop->nextHop || 0 == hop->nextHop->gatewayId)
+        {
+            OC_LOG_V(DEBUG, RM_TAG, "\nDestination : %u\nNextHop : (null)\nHopCount : %d",
+                     hop->destination->gatewayId, hop->routeCost);
+            OC_LOG_V(DEBUG, RM_TAG, "\nSequence Number :%u", hop->seqNum);
+        }
+        else
+        {
+            OC_LOG_V(DEBUG, RM_TAG, "\nDestination : %u\nNextHop : %u\nHopCount : %d",
+                     hop->destination->gatewayId, hop->nextHop->gatewayId, hop->routeCost);
+            OC_LOG_V(DEBUG, RM_TAG, "\nSequence Number :%u", hop->seqNum);
+        }
+        if (1 == hop->routeCost && NULL != hop->destination &&
+            hop->destination->destIntfAddr != NULL)
+        {
+            for (uint32_t i = 0; i < u_arraylist_length(hop->destination->destIntfAddr); i++)
+            {
+                RTMDestIntfInfo_t *dest = u_arraylist_get(hop->destination->destIntfAddr, i);
+                if (NULL != dest)
+                {
+                    OC_LOG_V(DEBUG, RM_TAG, "\nDestination interface addresses: %s Port : %d Obs ID: %d",
+                             dest->destIntfAddr.addr, dest->destIntfAddr.port, dest->observerId);
+                    OC_LOG_V(DEBUG, RM_TAG, "Validity: %d", dest->isValid);
+                }
+            }
+        }
+        OC_LOG(DEBUG, RM_TAG, "********************************************\n");
+        u_linklist_get_next(&iterTable);
+    }
+
+    OC_LOG(DEBUG, RM_TAG, "=================Endpoint List table============================\n");
+    u_linklist_iterator_t *iterEndpointTable = NULL;
+    u_linklist_init_iterator(endpointTable, &iterEndpointTable);
+
+    // Iterate over endpoint list to find if already entry for gatewayid is present.
+    while (NULL != iterEndpointTable)
+    {
+        RTMEndpointEntry_t *hop =
+            (RTMEndpointEntry_t *) u_linklist_get_data(iterEndpointTable);
+        if (NULL == hop)
+        {
+            OC_LOG(ERROR, RM_TAG, "Printing Table Failed");
+            return;
+        }
+        OC_LOG_V(DEBUG, RM_TAG, "EndpointId : %u\naddr : %s Port : %d",
+                  hop->endpointId, hop->destIntfAddr.addr, hop->destIntfAddr.port);
+
+        OC_LOG(DEBUG, RM_TAG, "********************************************\n");
+        u_linklist_get_next(&iterEndpointTable);
+    }
+}
diff --git a/resource/csdk/routing/src/routingutility.c b/resource/csdk/routing/src/routingutility.c
new file mode 100644 (file)
index 0000000..7f342a7
--- /dev/null
@@ -0,0 +1,330 @@
+/* ****************************************************************
+ *
+ * Copyright 2015 Samsung Electronics 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 "routingutility.h"
+#include "routingmanager.h"
+#include "oic_malloc.h"
+#include "include/logger.h"
+
+/**
+ * Logging tag for module name.
+ */
+#define TAG "RM_UTIL"
+
+/**
+ * Tag for printing the logs of forwarding the packet.
+ */
+#define RM_TAG "RAP"
+
+/**
+ * Minimum routing option data length is
+ * length of src address(1byte) + length of destination address(1byte) + hop count(2bytes)
+ */
+#define MIN_ROUTE_OPTION_LEN 4
+
+// destination and source are <GatewayId><ClientId> here, where ClientId is optional.
+OCStackResult RMAddInfo(const char *destination, CAHeaderOption_t **options,
+                        uint8_t *numOptions)
+{
+    OC_LOG(DEBUG, TAG, "IN");
+    RM_NULL_CHECK_WITH_RET(options, TAG, "options");
+    RM_NULL_CHECK_WITH_RET(numOptions, TAG, "numOptions");
+
+    CAHeaderOption_t *optionPtr = NULL;
+    int8_t index = -1;
+
+    RMGetRouteOptionIndex(*options, *numOptions, &index);
+
+    if (-1 < index)
+    {
+        OC_LOG(INFO, TAG, "Route option is present");
+        optionPtr = *options;
+    }
+    else
+    {
+        OC_LOG(INFO, TAG, "Route option is not present");
+        index = *numOptions;
+        optionPtr = OICCalloc((*numOptions + 1), sizeof(CAHeaderOption_t));
+        if (!optionPtr)
+        {
+            OC_LOG(ERROR, TAG, "OICCalloc failed");
+            return OC_STACK_NO_MEMORY;
+        }
+
+        memcpy(optionPtr, *options, sizeof(CAHeaderOption_t) * (*numOptions));
+    }
+
+    OCStackResult res = OC_STACK_OK;
+    RMRouteOption_t routeOption = {.destGw = 0};
+    if (*numOptions != index)
+    {
+        OC_LOG(INFO, TAG, "Route option is already present");
+        res = RMParseRouteOption(&optionPtr[index], &routeOption);
+        if (OC_STACK_OK != res)
+        {
+            OC_LOG(ERROR, TAG, "RMParseRouteOption failed");
+            return OC_STACK_ERROR;
+        }
+    }
+
+    if(destination)
+    {
+        memcpy(&(routeOption.destGw), destination, sizeof(routeOption.destGw));
+        memcpy(&(routeOption.destEp), destination + sizeof(routeOption.destGw),
+               sizeof(routeOption.destEp));
+    }
+
+#ifdef ROUTING_GATEWAY
+    // A gateway is supposed to add its ID as source.
+    uint32_t gatewayId = RMGetGatewayId();
+    if (gatewayId)
+    {
+        memcpy(&(routeOption.srcGw), &gatewayId, sizeof(routeOption.srcGw));
+    }
+
+    if(!routeOption.destGw)
+    {
+        routeOption.mSeqNum = RMGetMcastSeqNumber();
+    }
+#endif
+
+    res = RMCreateRouteOption(&routeOption, optionPtr + index);
+    if (OC_STACK_OK != res)
+    {
+        OC_LOG(ERROR, TAG, "Creation of routing option failed");
+        OICFree(optionPtr);
+        return res;
+    }
+
+    if ((*numOptions) == index )
+    {
+        (*numOptions) = (*numOptions) + 1;
+        OICFree(*options);
+        *options = optionPtr;
+    }
+
+    OC_LOG(DEBUG, TAG, "OUT");
+    return OC_STACK_OK;
+}
+
+OCStackResult RMUpdateInfo(CAHeaderOption_t **options, uint8_t *numOptions,
+                           CAEndpoint_t *endpoint)
+{
+    OC_LOG(DEBUG, TAG, "IN");
+    RM_NULL_CHECK_WITH_RET(options, TAG, "options");
+    RM_NULL_CHECK_WITH_RET(*options, TAG, "invalid option");
+    RM_NULL_CHECK_WITH_RET(numOptions, TAG, "numOptions");
+    RM_NULL_CHECK_WITH_RET(endpoint, TAG, "endpoint");
+
+    if (0 >= *numOptions)
+    {
+        OC_LOG(ERROR, TAG, "Invalid arguement: numOptions");
+        return OC_STACK_ERROR;
+    }
+
+    int8_t routeIndex = -1;
+    RMGetRouteOptionIndex(*options, *numOptions, &routeIndex);
+
+    if (-1 >= routeIndex)
+    {
+        OC_LOG(DEBUG, TAG, "Nothing to remove.");
+        return OC_STACK_OK;
+    }
+
+    // Update Endpoint with source address from RM header option.
+    if (0 != (*options + routeIndex)->optionLength)
+    {
+        uint8_t dLen = 0;
+        uint16_t count = sizeof(dLen);
+        memcpy(&dLen, (*options + routeIndex)->optionData, sizeof(dLen));
+        count += dLen;
+        uint8_t sLen = 0;
+        memcpy(&sLen, (*options + routeIndex)->optionData + count, sizeof(sLen));
+        count += sizeof(sLen);
+        if (0 < sLen)
+        {
+            memcpy(endpoint->routeData, (*options + routeIndex)->optionData + count,
+                   GATEWAY_ID_LENGTH);
+            OC_LOG_V(DEBUG, TAG, "adding srcgid: %u in endpoint [%d]",
+                     *((uint32_t *)endpoint->routeData), sLen);
+
+            count += GATEWAY_ID_LENGTH;
+
+            if (GATEWAY_ID_LENGTH < sLen)
+            {
+                memcpy(endpoint->routeData + GATEWAY_ID_LENGTH,
+                       (*options + routeIndex)->optionData + count, ENDPOINT_ID_LENGTH);
+                OC_LOG_V(DEBUG, TAG, "adding srceid: %u in endpoint",
+                         *((uint16_t *)(endpoint->routeData + GATEWAY_ID_LENGTH)));
+            }
+        }
+    }
+
+    // Remove route option from header.
+    for (uint8_t i = routeIndex; i < (*numOptions)-1; i++)
+    {
+        memcpy((*options) + i, (*options)+i+1, sizeof(**options));
+    }
+    *numOptions = (*numOptions) - 1;
+
+    if (0 == *numOptions)
+    {
+        // Remove route option.
+        OICFree(*options);
+        *options = NULL;
+    }
+    OC_LOG(DEBUG, TAG, "OUT");
+    return OC_STACK_OK;
+}
+
+void RMGetRouteOptionIndex(const CAHeaderOption_t *options, uint8_t numOptions, int8_t *index)
+{
+    OC_LOG(DEBUG, TAG, "IN");
+    RM_NULL_CHECK_VOID(options, TAG, "options");
+    RM_NULL_CHECK_VOID(index, TAG, "index");
+    for (uint32_t i = 0; i < numOptions; i++)
+    {
+        OC_LOG_V(DEBUG, TAG, "Request- optionID: %d", options[i].optionID);
+        if (RM_OPTION_MESSAGE_SWITCHING == options[i].optionID)
+        {
+            OC_LOG_V(INFO, TAG, "Found Option at %d", i);
+            *index = i;
+            break;
+        }
+    }
+    OC_LOG(DEBUG, TAG, "OUT");
+}
+
+OCStackResult RMCreateRouteOption(const RMRouteOption_t *optValue, CAHeaderOption_t *options)
+{
+    OC_LOG(DEBUG, RM_TAG, "IN");
+    RM_NULL_CHECK_WITH_RET(optValue, RM_TAG, "optValue");
+    RM_NULL_CHECK_WITH_RET(options, RM_TAG, "options");
+
+    uint8_t dLen = (optValue->destGw ? GATEWAY_ID_LENGTH:0) +
+                        (optValue->destEp ? ENDPOINT_ID_LENGTH:0);
+    uint8_t sLen = (optValue->srcGw ? GATEWAY_ID_LENGTH:0) +
+                        (optValue->srcEp ? ENDPOINT_ID_LENGTH:0);
+
+    OC_LOG_V(DEBUG, RM_TAG, "createoption dlen %u slen [%u]", dLen, sLen);
+    unsigned int totalLength = MIN_ROUTE_OPTION_LEN + dLen + sLen;
+    void *tempData = OICCalloc(totalLength, sizeof(char));
+    if (NULL == tempData)
+    {
+        OC_LOG(ERROR, RM_TAG, "Calloc failed");
+        return OC_STACK_NO_MEMORY;
+    }
+    memcpy(tempData, &dLen, sizeof(dLen));
+    unsigned int count = sizeof(dLen);
+    if (0 < dLen)
+    {
+        if (optValue->destGw)
+        {
+            memcpy(tempData + count, &(optValue->destGw), GATEWAY_ID_LENGTH);
+            count += GATEWAY_ID_LENGTH;
+        }
+
+        if (optValue->destEp)
+        {
+            memcpy(tempData + count, &(optValue->destEp), ENDPOINT_ID_LENGTH);
+            count += ENDPOINT_ID_LENGTH;
+        }
+    }
+
+    memcpy(tempData + count, &sLen, sizeof(sLen));
+    count += sizeof(sLen);
+    if (0 < sLen)
+    {
+        if (optValue->srcGw)
+        {
+            memcpy(tempData + count, &(optValue->srcGw), GATEWAY_ID_LENGTH);
+            count += GATEWAY_ID_LENGTH;
+        }
+
+        if (optValue->srcEp)
+        {
+            memcpy(tempData + count, &(optValue->srcEp), ENDPOINT_ID_LENGTH);
+            count += ENDPOINT_ID_LENGTH;
+        }
+    }
+
+    memcpy(tempData + count, &optValue->mSeqNum, sizeof(optValue->mSeqNum));
+    memcpy(options->optionData, tempData, totalLength);
+
+    options->optionID = RM_OPTION_MESSAGE_SWITCHING;
+    options->optionLength = totalLength;
+
+    OC_LOG_V(INFO, RM_TAG, "Option Length is %d", options->optionLength);
+
+    OICFree(tempData);
+    OC_LOG(DEBUG, RM_TAG, "OUT");
+    return OC_STACK_OK;
+}
+
+OCStackResult RMParseRouteOption(const CAHeaderOption_t *options, RMRouteOption_t *optValue)
+{
+    OC_LOG(DEBUG, RM_TAG, "IN");
+    RM_NULL_CHECK_WITH_RET(options, RM_TAG, "options");
+    RM_NULL_CHECK_WITH_RET(optValue, RM_TAG, "optValue");
+    if (0 == options->optionLength)
+    {
+        OC_LOG(ERROR, RM_TAG, "Option data is not present");
+        return OC_STACK_ERROR;
+    }
+
+    uint8_t dLen = 0 ;
+    uint16_t count = sizeof(dLen);
+    memcpy(&dLen, options->optionData, sizeof(dLen));
+    if (0 < dLen)
+    {
+        memcpy(&(optValue->destGw), options->optionData + count, GATEWAY_ID_LENGTH);
+        count += GATEWAY_ID_LENGTH;
+
+        if (GATEWAY_ID_LENGTH < dLen)
+        {
+            memcpy(&(optValue->destEp), options->optionData + count, ENDPOINT_ID_LENGTH);
+            count += ENDPOINT_ID_LENGTH;
+        }
+    }
+
+    uint8_t sLen = 0;
+    memcpy(&sLen, options->optionData + count, sizeof(sLen));
+    count += sizeof(sLen);
+    if (0 < sLen)
+    {
+        memcpy(&(optValue->srcGw), options->optionData + count, GATEWAY_ID_LENGTH);
+        count += GATEWAY_ID_LENGTH;
+
+        if (GATEWAY_ID_LENGTH < sLen)
+        {
+            memcpy(&(optValue->srcEp), options->optionData + count, ENDPOINT_ID_LENGTH);
+            count += ENDPOINT_ID_LENGTH;
+        }
+    }
+    memcpy(&optValue->mSeqNum, options->optionData + count, sizeof(optValue->mSeqNum));
+
+    OC_LOG_V(INFO, RM_TAG, "Option hopcount is %d", optValue->mSeqNum);
+    OC_LOG_V(INFO, RM_TAG, "Option Sender Addr is [%u][%u]", optValue->srcGw, optValue->srcEp);
+    OC_LOG_V(INFO, RM_TAG, "Option Dest Addr is [%u][%u]", optValue->destGw, optValue->destEp);
+    OC_LOG(DEBUG, RM_TAG, "OUT");
+    return OC_STACK_OK;
+}
index 5ae5673..606350f 100644 (file)
@@ -63,7 +63,10 @@ typedef enum
 
     /** "/oic/res/d/type" .*/
     OC_RESOURCE_TYPES_URI,
-
+#ifdef ROUTING_GATEWAY
+    /** "/oic/gateway" .*/
+    OC_GATEWAY_URI,
+#endif
     #ifdef WITH_PRESENCE
     /** "/oic/ad" .*/
     OC_PRESENCE,
index a987613..d105105 100644 (file)
@@ -38,7 +38,6 @@
 #include "ocstack.h"
 #include "ocstackconfig.h"
 #include "occlientcb.h"
-#include <logger.h>
 #include <ocrandom.h>
 
 #include "cacommon.h"
index cb950f9..37d56f9 100755 (executable)
@@ -23,7 +23,6 @@
 
 #include <stdbool.h>
 #include <inttypes.h>
-#include "logger.h"
 #include "octypes.h"
 
 #ifdef __cplusplus
index ab0fc29..1bab0fc 100644 (file)
@@ -68,7 +68,7 @@
 /**
  *  Maximum Length of the vendor specific header option
  */
-#define MAX_HEADER_OPTION_DATA_LENGTH (16)
+#define MAX_HEADER_OPTION_DATA_LENGTH (20)
 
 /**
  * Sets the time to live (TTL) for response callback(s).
index 5899dfc..b82d1be 100644 (file)
@@ -64,7 +64,10 @@ extern "C" {
 
 /** Resource Type.*/
 #define OC_RSRVD_RESOURCE_TYPES_URI           "/oic/res/types/d"
-
+#ifdef ROUTING_GATEWAY
+/** Gateway URI.*/
+#define OC_RSRVD_GATEWAY_URI                  "/oic/gateway"
+#endif
 #ifdef WITH_PRESENCE
 
 /** Presence URI through which the OIC devices advertise their presence.*/
@@ -390,7 +393,9 @@ typedef struct
 
     /** usually zero for default interface.*/
     uint32_t                interface;
-
+#if defined (ROUTING_GATEWAY) || defined (ROUTING_EP)
+    char                    routeData[MAX_ADDR_STR_SIZE]; //destination GatewayID:ClientId
+#endif
 } OCDevAddr;
 
 /**
@@ -526,7 +531,8 @@ typedef enum
 {
     OC_CLIENT = 0,
     OC_SERVER,
-    OC_CLIENT_SERVER
+    OC_CLIENT_SERVER,
+    OC_GATEWAY          /**< Client server mode along with routing capabilities.*/
 } OCMode;
 
 /**
index 422100d..691bf08 100644 (file)
 #ifndef PAYLOAD_LOGGING_H_
 #define PAYLOAD_LOGGING_H_
 
+#include "logger.h"
+#ifdef __TIZEN__
+#include <dlog.h>
+#endif
+
 #ifdef __cplusplus
 extern "C"
 {
index 65af835..fe69612 100644 (file)
@@ -53,6 +53,8 @@ samples_env.AppendUnique(CPPDEFINES = ['TB_LOG'])
 # Source files and Targets
 ######################################################################
 ocserver         = samples_env.Program('ocserver', ['ocserver.cpp', 'common.cpp'])
+if samples_env.get('ROUTING') == 'GW':
+       ocrouting        = samples_env.Program('ocrouting', ['ocrouting.cpp', 'common.cpp'])
 occlient         = samples_env.Program('occlient', ['occlient.cpp', 'common.cpp'])
 ocserverslow     = samples_env.Program('ocserverslow', ['ocserverslow.cpp', 'common.cpp'])
 occlientslow     = samples_env.Program('occlientslow', ['occlientslow.cpp', 'common.cpp'])
index 38b9239..d1ea32e 100644 (file)
 #include "ocpayload.h"
 #include "payload_logging.h"
 
+#ifdef ROUTING_GATEWAY
+/**
+ * Maximum number of gateway requests to form the routing table.
+ */
+#define MAX_NUM_GATEWAY_REQUEST 20
+
+/**
+ * Sleep duration after every OCProcess().
+ */
+#define SLEEP_DURATION 100000
+#endif
 // Tracking user input
 static int UnicastDiscovery = 0;
 static int TestCase = 0;
@@ -805,6 +816,21 @@ int main(int argc, char* argv[])
         return 0;
     }
 
+#ifdef ROUTING_GATEWAY
+    /*
+     * Before invoking Discover resource, we process the gateway requests
+     * and form the routing table.
+     */
+    for (int index = 0; index < MAX_NUM_GATEWAY_REQUEST; index++)
+    {
+        if (OC_STACK_OK != OCProcess())
+        {
+            OC_LOG(ERROR, TAG, "OCStack process error");
+            return 0;
+        }
+        usleep(SLEEP_DURATION);
+    }
+#endif
     if (Connectivity == CT_ADAPTER_DEFAULT || Connectivity == CT_IP)
     {
         ConnType = CT_ADAPTER_IP;
@@ -859,8 +885,9 @@ int main(int argc, char* argv[])
             OC_LOG(ERROR, TAG, "OCStack process error");
             return 0;
         }
-
-        sleep(2);
+#ifndef ROUTING_GATEAWAY
+        sleep(1);
+#endif
     }
     OC_LOG(INFO, TAG, "Exiting occlient main loop...");
 
diff --git a/resource/csdk/stack/samples/linux/SimpleClientServer/ocrouting.cpp b/resource/csdk/stack/samples/linux/SimpleClientServer/ocrouting.cpp
new file mode 100644 (file)
index 0000000..282adc2
--- /dev/null
@@ -0,0 +1,79 @@
+/* ****************************************************************
+ *
+ * Copyright 2015 Samsung Electronics 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 <string>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <pthread.h>
+#include <array>
+#include "ocstack.h"
+#include "logger.h"
+#include "ocpayload.h"
+
+#define TAG "ocrouting"
+
+int gQuitFlag = 0;
+
+/* SIGINT handler: set gQuitFlag to 1 for graceful termination */
+void handleSigInt(int signum)
+{
+    if (signum == SIGINT)
+    {
+        gQuitFlag = 1;
+    }
+}
+
+int main()
+{
+    OC_LOG(DEBUG, TAG, "OCRouting sample is starting...");
+
+    if (OCInit(NULL, 0, OC_GATEWAY) != OC_STACK_OK)
+    {
+        OC_LOG(ERROR, TAG, "OCStack init error");
+        return 0;
+    }
+
+    // Break from loop with Ctrl-C
+    OC_LOG(INFO, TAG, "Entering ocrouting main loop...");
+
+    signal(SIGINT, handleSigInt);
+
+    while (!gQuitFlag)
+    {
+        if (OCProcess() != OC_STACK_OK)
+        {
+            OC_LOG(ERROR, TAG, "OCStack process error");
+            return 0;
+        }
+    }
+
+    OC_LOG(INFO, TAG, "Exiting ocrouting main loop...");
+
+    if (OCStop() != OC_STACK_OK)
+    {
+        OC_LOG(ERROR, TAG, "OCStack process error");
+    }
+
+    return 0;
+}
index 66441a0..65d7075 100644 (file)
@@ -1057,8 +1057,9 @@ int main(int argc, char* argv[])
             OC_LOG(ERROR, TAG, "OCStack process error");
             return 0;
         }
-
+#ifndef ROUTING_GATEWAY
         sleep(2);
+#endif
     }
 
     /*
index 0efea50..e20a126 100644 (file)
@@ -56,6 +56,7 @@ help_vars.Add(EnumVariable('TARGET_OS', 'Target platform', host, host_target_map
 help_vars.Add(ListVariable('TARGET_TRANSPORT', 'Target transport', 'ALL', ['ALL', 'IP', 'BT', 'BLE']))
 help_vars.Add(EnumVariable('TARGET_ARCH', 'Target architecture', default_arch, os_arch_map[target_os]))
 help_vars.Add(EnumVariable('SECURED', 'Build with DTLS', '0', allowed_values=('0', '1')))
+help_vars.Add(EnumVariable('ROUTING', 'Enable routing', 'EP', allowed_values=('GW', 'EP')))
 
 ######################################################################
 # Platform(build target) specific options: SDK/NDK & toolchain
@@ -171,6 +172,13 @@ env.AddMethod(__install, 'InstallTarget')
 env.SetDir(env.GetLaunchDir())
 env['ROOT_DIR']=env.GetLaunchDir()
 
+env.AppendUnique(CPPDEFINES = ['TB_LOG'])
+if env.get('ROUTING') == 'GW':
+       env.AppendUnique(CPPDEFINES = ['ROUTING_GATEWAY'])
+elif env.get('ROUTING') == 'EP':
+       env.AppendUnique(CPPDEFINES = ['ROUTING_EP'])
+env.AppendUnique(CPPDEFINES = ['__TIZEN__'])
+
 Export('env')
 
 ######################################################################
index 7a20610..d690cd4 100644 (file)
 #include "logger.h"
 #include "occlient.h"
 #include "ocpayload.h"
+#include "payload_logging.h"
+
 using namespace std;
 
+#ifdef ROUTING_GATEWAY
+/**
+ * Maximum number of gateway requests to form the routing table.
+ */
+#define MAX_NUM_GATEWAY_REQUEST 20
+
+/**
+ * Sleep duration after every OCProcess().
+ */
+#define SLEEP_DURATION 100000
+#endif
+
 // Tracking user input
-static int UNICAST_DISCOVERY = 0;
-static int TEST_CASE = 0;
-static int CONNECTIVITY = 0;
-
-static const char * UNICAST_DEVICE_DISCOVERY_QUERY = "coap://%s/oic/d";
-static const char * MULTICAST_DEVICE_DISCOVERY_QUERY = "/oic/d";
-static const char * UNICAST_PLATFORM_DISCOVERY_QUERY = "coap://%s/oic/p";
-static const char * MULTICAST_PLATFORM_DISCOVERY_QUERY = "/oic/p";
-
-static const char * UNICAST_RESOURCE_DISCOVERY_QUERY = "coap://%s/oic/res";
-static const char * MULTICAST_RESOURCE_DISCOVERY_QUERY = "/oic/res";
-// The following variable determines the interface protocol (IPv4, IPv6, etc)
-//to be used for sending unicast messages. Default set to IPv4.
-static OCConnectivityType OC_CONNTYPE = CT_ADAPTER_IP;
-static std::string coapServerIP = "255.255.255.255";
-static std::string coapServerPort = "5683";
+static int g_unicastDiscovery = 0;
+static int g_testCase = 0;
+static int g_connectivity = 0;
+
+static const char *DEVICE_DISCOVERY_QUERY = "%s/oic/d";
+static const char *PLATFORM_DISCOVERY_QUERY = "%s/oic/p";
+static const char *RESOURCE_DISCOVERY_QUERY = "%s/oic/res";
+
+//The following variable determines the interface protocol (IPv4, IPv6, etc)
+//to be used for sending unicast messages. Default set to IP dual stack.
+static OCConnectivityType g_connType = CT_ADAPTER_IP;
+static OCDevAddr g_serverAddr;
+static char g_discoveryAddr[100];
 static std::string coapServerResource = "/a/light";
-// Size to hold ADDRESS
-static const int MAX_ADDR_SIZE = 24;
-//Use unicastAddr for both InitDiscovery and InitPlatformOrDeviceDiscovery
-char unicastAddr[MAX_ADDR_SIZE];
+
 void StripNewLineChar(char* str);
 
 // The handle for the observe registration
@@ -100,10 +108,9 @@ static void PrintUsage()
     cout << "Hello";
     cout << "\nUsage : occlient -u <0|1> -t <1..17> -c <0|1|2>";
     cout << "\n-u <0|1> : Perform multicast/unicast discovery of resources";
-    cout << "\n-c 0 : Default IPv4 and IPv6 auto-selection";
-    cout << "\n-c 1 : IPv4 Connectivity Type";
-    cout << "\n-c 2 : IPv6 Connectivity Type (IPv6 not currently supported)";
-    cout << "\n-c 3 : EDR Connectivity Type (IPv6 not currently supported)";
+    cout << "\n-c 0 : Default IP selection";
+    cout << "\n-c 1 : IP Connectivity Type";
+    cout << "\n-c 2 : EDR Connectivity Type (IPv6 not currently supported)";
     cout << "\n-t 1  :  Discover Resources";
     cout << "\n-t 2  :  Discover Resources and Initiate Nonconfirmable Get Request";
     cout << "\n-t 3  :  Discover Resources and Initiate Nonconfirmable Get Request with query filter";
@@ -135,6 +142,7 @@ static void PrintUsage()
 }
 
 OCStackResult InvokeOCDoResource(std::ostringstream &query,
+                                 OCDevAddr *remoteAddr,
                                  OCMethod method,
                                  OCQualityOfService qos,
                                  OCClientResponseHandler cb,
@@ -149,9 +157,9 @@ OCStackResult InvokeOCDoResource(std::ostringstream &query,
     cbData.context = (void*)DEFAULT_CONTEXT_VALUE;
     cbData.cd = NULL;
 
-    ret = OCDoResource(&handle, method, query.str().c_str(), 0,
+    ret = OCDoResource(&handle, method, query.str().c_str(), remoteAddr,
                        (method == OC_REST_PUT) ? putPayload() : NULL,
-                       (OC_CONNTYPE), qos, &cbData, options, numOptions);
+                       (g_connType), qos, &cbData, options, numOptions);
 
     if (ret != OC_STACK_OK)
     {
@@ -172,14 +180,15 @@ OCStackResult InvokeOCDoResource(std::ostringstream &query,
     return ret;
 }
 
-OCStackApplicationResult putReqCB(void* ctx, OCDoHandle handle, OCClientResponse * clientResponse)
+OCStackApplicationResult putReqCB(void* ctx, OCDoHandle /*handle*/,
+                                  OCClientResponse * clientResponse)
 {
-    if(ctx == (void*)DEFAULT_CONTEXT_VALUE)
+    if (ctx == (void*)DEFAULT_CONTEXT_VALUE)
     {
         cout << "\nCallback Context for PUT recvd successfully";
     }
 
-    if(clientResponse)
+    if (clientResponse)
     {
         cout << "\nStackResult: " << getResult(clientResponse->result);
         cout << "\nJSON = " << clientResponse->payload;
@@ -191,14 +200,15 @@ OCStackApplicationResult putReqCB(void* ctx, OCDoHandle handle, OCClientResponse
     return OC_STACK_DELETE_TRANSACTION;
 }
 
-OCStackApplicationResult postReqCB(void *ctx, OCDoHandle handle, OCClientResponse *clientResponse)
+OCStackApplicationResult postReqCB(void *ctx, OCDoHandle /*handle*/,
+                                   OCClientResponse *clientResponse)
 {
-    if(ctx == (void*)DEFAULT_CONTEXT_VALUE)
+    if (ctx == (void*)DEFAULT_CONTEXT_VALUE)
     {
         cout << "\nCallback Context for POST recvd successfully";
     }
 
-    if(clientResponse)
+    if (clientResponse)
     {
         cout << "\nStackResult: " << getResult(clientResponse->result);
         cout << "\nJSON = " << clientResponse->payload;
@@ -211,7 +221,8 @@ OCStackApplicationResult postReqCB(void *ctx, OCDoHandle handle, OCClientRespons
 }
 
 OCStackApplicationResult deleteReqCB(void *ctx,
-        OCDoHandle handle, OCClientResponse *clientResponse)
+                                     OCDoHandle /*handle*/,
+                                     OCClientResponse *clientResponse)
 {
     if(ctx == (void*)DEFAULT_CONTEXT_VALUE)
     {
@@ -230,15 +241,16 @@ OCStackApplicationResult deleteReqCB(void *ctx,
     return OC_STACK_DELETE_TRANSACTION;
 }
 
-OCStackApplicationResult getReqCB(void* ctx, OCDoHandle handle, OCClientResponse * clientResponse)
+OCStackApplicationResult getReqCB(void* ctx, OCDoHandle /*handle*/,
+                                  OCClientResponse * clientResponse)
 {
-    if(clientResponse == NULL)
+    if (clientResponse == NULL)
     {
         cout << "\ngetReqCB received NULL clientResponse";
         return   OC_STACK_DELETE_TRANSACTION;
     }
 
-    if(ctx == (void*)DEFAULT_CONTEXT_VALUE)
+    if (ctx == (void*)DEFAULT_CONTEXT_VALUE)
     {
         cout << "\nCallback Context for GET query recvd successfully";
     }
@@ -247,14 +259,14 @@ OCStackApplicationResult getReqCB(void* ctx, OCDoHandle handle, OCClientResponse
     cout << "\nSEQUENCE NUMBER: " << clientResponse->sequenceNumber;
     //OC_LOG_PAYLOAD(INFO, TAG, clientResponse->payload);
 
-    if(clientResponse->numRcvdVendorSpecificHeaderOptions > 0)
+    if (clientResponse->numRcvdVendorSpecificHeaderOptions > 0)
     {
         cout << "\nReceived 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)
+            if (((OCHeaderOption)rcvdOptions[i]).protocolID == OC_COAP_ID)
             {
                 cout << "\nReceived option ID " << ((OCHeaderOption)rcvdOptions[i]).optionID;
             }
@@ -263,14 +275,15 @@ OCStackApplicationResult getReqCB(void* ctx, OCDoHandle handle, OCClientResponse
     return OC_STACK_DELETE_TRANSACTION;
 }
 
-OCStackApplicationResult obsReqCB(void* ctx, OCDoHandle handle, OCClientResponse * clientResponse)
+OCStackApplicationResult obsReqCB(void* ctx, OCDoHandle /*handle*/,
+                                  OCClientResponse * clientResponse)
 {
-    if(ctx == (void*)DEFAULT_CONTEXT_VALUE)
+    if (ctx == (void*)DEFAULT_CONTEXT_VALUE)
     {
         cout << "\nCallback Context for OBS query recvd successfully";
     }
 
-    if(clientResponse)
+    if (clientResponse)
     {
         cout << "\nStackResult: " << getResult(clientResponse->result);
         cout << "\nSEQUENCE NUMBER: " << clientResponse->sequenceNumber;
@@ -279,7 +292,7 @@ OCStackApplicationResult obsReqCB(void* ctx, OCDoHandle handle, OCClientResponse
         gNumObserveNotifies++;
         if (gNumObserveNotifies == 15) //large number to test observing in DELETE case.
         {
-            if(TEST_CASE == TEST_OBS_REQ_NON || TEST_CASE == TEST_OBS_REQ_CON)
+            if (g_testCase == TEST_OBS_REQ_NON || g_testCase == TEST_OBS_REQ_CON)
             {
                 if (OCCancel (gObserveDoHandle, OC_LOW_QOS, NULL, 0) != OC_STACK_OK)
                 {
@@ -287,7 +300,7 @@ OCStackApplicationResult obsReqCB(void* ctx, OCDoHandle handle, OCClientResponse
                 }
                 return OC_STACK_DELETE_TRANSACTION;
             }
-            else if(TEST_CASE == TEST_OBS_REQ_NON_CANCEL_IMM)
+            else if (g_testCase == TEST_OBS_REQ_NON_CANCEL_IMM)
             {
                 if (OCCancel (gObserveDoHandle, OC_HIGH_QOS, NULL, 0) != OC_STACK_OK)
                 {
@@ -295,16 +308,16 @@ OCStackApplicationResult obsReqCB(void* ctx, OCDoHandle handle, OCClientResponse
                 }
             }
         }
-        if(clientResponse->sequenceNumber == OC_OBSERVE_REGISTER)
+        if (clientResponse->sequenceNumber == OC_OBSERVE_REGISTER)
         {
             cout << "\nThis also serves as a registration confirmation";
         }
-        else if(clientResponse->sequenceNumber == OC_OBSERVE_DEREGISTER)
+        else if (clientResponse->sequenceNumber == OC_OBSERVE_DEREGISTER)
         {
             cout << "\nThis also serves as a deregistration confirmation";
             return OC_STACK_DELETE_TRANSACTION;
         }
-        else if(clientResponse->sequenceNumber == OC_OBSERVE_NO_OPTION)
+        else if (clientResponse->sequenceNumber == OC_OBSERVE_NO_OPTION)
         {
             cout << "\nThis also tells you that registration/deregistration failed";
             return OC_STACK_DELETE_TRANSACTION;
@@ -317,7 +330,8 @@ OCStackApplicationResult obsReqCB(void* ctx, OCDoHandle handle, OCClientResponse
     return OC_STACK_KEEP_TRANSACTION;
 }
 #ifdef WITH_PRESENCE
-OCStackApplicationResult presenceCB(void* ctx, OCDoHandle handle, OCClientResponse * clientResponse)
+OCStackApplicationResult presenceCB(void* ctx, OCDoHandle /*handle*/,
+                                    OCClientResponse * clientResponse)
 {
     if (ctx == (void*) DEFAULT_CONTEXT_VALUE)
     {
@@ -349,8 +363,8 @@ OCStackApplicationResult presenceCB(void* ctx, OCDoHandle handle, OCClientRespon
 #endif
 
 // This is a function called back when a device is discovered
-OCStackApplicationResult discoveryReqCB(void* ctx, OCDoHandle handle,
-        OCClientResponse * clientResponse)
+OCStackApplicationResult discoveryReqCB(void* ctx, OCDoHandle /*handle*/,
+                                        OCClientResponse * clientResponse)
 {
     if (ctx == (void*) DEFAULT_CONTEXT_VALUE)
     {
@@ -359,23 +373,29 @@ OCStackApplicationResult discoveryReqCB(void* ctx, OCDoHandle handle,
 
     if (clientResponse)
     {
+        if (NULL == clientResponse->payload)
+        {
+            cout << "\nPayload is NULL, No resources found";
+            return OC_STACK_KEEP_TRANSACTION;
+        }
+
         cout << "\nStackResult: " << getResult(clientResponse->result);
 
         std::string connectionType = getConnectivityType (clientResponse->connType);
         cout << "\nDiscovered on " << connectionType.c_str();
         cout << "\nDevice ======> Discovered ";
         cout << clientResponse->devAddr.addr;
-        //TODO: Bug in RI layer.  Its returning 65600 instead of CT_ADAPTER_IP
-        if (65600 == clientResponse->connType)
+        if (CT_ADAPTER_IP == clientResponse->connType)
         {
             cout << ":" << clientResponse->devAddr.port;
         }
         //OC_LOG_PAYLOAD(INFO, clientResponse->payload);
         cout << "\nConnectivity type: " << clientResponse->connType;
-        OC_CONNTYPE = clientResponse->connType;
+        g_connType = clientResponse->connType;
+        g_serverAddr = clientResponse->devAddr;
         parseClientResponse(clientResponse);
 
-        switch(TEST_CASE)
+        switch(g_testCase)
         {
             case TEST_GET_REQ_NON:
                 InitGetRequest(OC_LOW_QOS, 0, 0);
@@ -440,15 +460,16 @@ OCStackApplicationResult discoveryReqCB(void* ctx, OCDoHandle handle,
     return OC_STACK_KEEP_TRANSACTION;
 }
 
-OCStackApplicationResult PlatformDiscoveryReqCB (void* ctx, OCDoHandle handle,
-        OCClientResponse * clientResponse)
+OCStackApplicationResult PlatformDiscoveryReqCB(void* ctx,
+                                                OCDoHandle /*handle*/,
+                                                OCClientResponse * clientResponse)
 {
     if (ctx == (void*) DEFAULT_CONTEXT_VALUE)
     {
         cout << "\nCallback Context for Platform DISCOVER query recvd successfully";
     }
 
-    if(clientResponse)
+    if (clientResponse)
     {
         //OC_LOG truncates the response as it is too long.
         //OC_LOG_PAYLOAD(INFO, clientResponse->payload);
@@ -458,18 +479,18 @@ OCStackApplicationResult PlatformDiscoveryReqCB (void* ctx, OCDoHandle handle,
         cout << "\nPlatformDiscoveryReqCB received Null clientResponse";
     }
 
-    return (UNICAST_DISCOVERY) ? OC_STACK_DELETE_TRANSACTION : OC_STACK_KEEP_TRANSACTION;
+    return (g_unicastDiscovery) ? OC_STACK_DELETE_TRANSACTION : OC_STACK_KEEP_TRANSACTION;
 }
 
-OCStackApplicationResult DeviceDiscoveryReqCB (void* ctx, OCDoHandle handle,
-        OCClientResponse * clientResponse)
+OCStackApplicationResult DeviceDiscoveryReqCB(void* ctx, OCDoHandle /*handle*/,
+                                              OCClientResponse * clientResponse)
 {
     if (ctx == (void*) DEFAULT_CONTEXT_VALUE)
     {
         cout << "\nCallback Context for Device DISCOVER query recvd successfully";
     }
 
-    if(clientResponse)
+    if (clientResponse)
     {
         //OC_LOG truncates the response as it is too long.
         cout << "\nDiscovery response: ";
@@ -480,7 +501,7 @@ OCStackApplicationResult DeviceDiscoveryReqCB (void* ctx, OCDoHandle handle,
         cout << "\nPlatformDiscoveryReqCB received Null clientResponse";
     }
 
-    return (UNICAST_DISCOVERY) ? OC_STACK_DELETE_TRANSACTION : OC_STACK_KEEP_TRANSACTION;
+    return (g_unicastDiscovery) ? OC_STACK_DELETE_TRANSACTION : OC_STACK_KEEP_TRANSACTION;
 }
 
 #ifdef WITH_PRESENCE
@@ -490,37 +511,37 @@ int InitPresence()
     cout << "\nExecuting " << __func__;
     std::ostringstream query;
     std::ostringstream querySuffix;
-    query << "coap://" << coapServerIP << ":" << coapServerPort << OC_RSRVD_PRESENCE_URI;
-    if(TEST_CASE == TEST_OBS_PRESENCE)
+    query << OC_RSRVD_PRESENCE_URI;
+    if (g_testCase == TEST_OBS_PRESENCE)
     {
-        result = InvokeOCDoResource(query, OC_REST_PRESENCE, OC_LOW_QOS,
-                presenceCB, NULL, 0);
+        result = InvokeOCDoResource(query, &g_serverAddr, OC_REST_PRESENCE,
+                OC_LOW_QOS, presenceCB, NULL, 0);
     }
-    if(TEST_CASE == TEST_OBS_PRESENCE_WITH_FILTER || TEST_CASE == TEST_OBS_PRESENCE_WITH_FILTERS)
+    if (g_testCase == TEST_OBS_PRESENCE_WITH_FILTER || g_testCase == TEST_OBS_PRESENCE_WITH_FILTERS)
     {
         querySuffix.str("");
         querySuffix << query.str() << "?rt=core.led";
-        result = InvokeOCDoResource(querySuffix, OC_REST_PRESENCE, OC_LOW_QOS,
-                presenceCB, NULL, 0);
+        result = InvokeOCDoResource(querySuffix, &g_serverAddr, OC_REST_PRESENCE,
+                OC_LOW_QOS, presenceCB, NULL, 0);
     }
-    if(TEST_CASE == TEST_OBS_PRESENCE_WITH_FILTERS)
+    if (g_testCase == TEST_OBS_PRESENCE_WITH_FILTERS)
     {
-        if(result == OC_STACK_OK)
+        if (result == OC_STACK_OK)
         {
             querySuffix.str("");
             querySuffix << query.str() << "?rt=core.fan";
-            result = InvokeOCDoResource(querySuffix, OC_REST_PRESENCE, OC_LOW_QOS,
+            result = InvokeOCDoResource(querySuffix, &g_serverAddr, OC_REST_PRESENCE, OC_LOW_QOS,
                     presenceCB, NULL, 0);
         }
     }
-    if(TEST_CASE == TEST_OBS_MULTICAST_PRESENCE)
+    if (g_testCase == TEST_OBS_MULTICAST_PRESENCE)
     {
-        if(result == OC_STACK_OK)
+        if (result == OC_STACK_OK)
         {
             std::ostringstream multicastPresenceQuery;
             multicastPresenceQuery.str("");
             multicastPresenceQuery << "coap://" << OC_MULTICAST_PREFIX << OC_RSRVD_PRESENCE_URI;
-            result = InvokeOCDoResource(multicastPresenceQuery, OC_REST_PRESENCE, OC_LOW_QOS,
+            result = InvokeOCDoResource(multicastPresenceQuery, &g_serverAddr, OC_REST_PRESENCE, OC_LOW_QOS,
                     presenceCB, NULL, 0);
         }
     }
@@ -532,18 +553,8 @@ int InitGetRequestToUnavailableResource(OCQualityOfService qos)
 {
     cout << "\nExecuting " << __func__;
     std::ostringstream query;
-
-    //TODO: Bug in RI layer.  Its returning 65600 instead of CT_ADAPTER_IP
-    if (65600 == OC_CONNTYPE)
-    {
-        query << "coap://" << coapServerIP << ":" << coapServerPort << "/SomeUnknownResource";
-    }
-    else
-    {
-        query << "coap://" << coapServerIP << "/SomeUnknownResource";
-    }
-
-    return (InvokeOCDoResource(query, OC_REST_GET, (qos == OC_HIGH_QOS)? OC_HIGH_QOS:OC_LOW_QOS,
+    query << "/SomeUnknownResource";
+    return (InvokeOCDoResource(query, &g_serverAddr, OC_REST_GET, (qos == OC_HIGH_QOS)? OC_HIGH_QOS:OC_LOW_QOS,
             getReqCB, NULL, 0));
 }
 
@@ -551,33 +562,17 @@ int InitObserveRequest(OCQualityOfService qos)
 {
     cout << "\nExecuting " << __func__;
     std::ostringstream query;
-    //TODO: Bug in RI layer.  Its returning 65600 instead of CT_ADAPTER_IP
-    if (65600 == OC_CONNTYPE)
-    {
-        query << "coap://" << coapServerIP << ":" << coapServerPort << coapServerResource;
-    }
-    else
-    {
-        query << "coap://" << coapServerIP << coapServerResource;
-    }
-    return (InvokeOCDoResource(query,
-            OC_REST_OBSERVE, (qos == OC_HIGH_QOS)? OC_HIGH_QOS:OC_LOW_QOS, obsReqCB, NULL, 0));
+    query << coapServerResource;
+    return (InvokeOCDoResource(query, &g_serverAddr, OC_REST_OBSERVE,
+              (qos == OC_HIGH_QOS)? OC_HIGH_QOS:OC_LOW_QOS, obsReqCB, NULL, 0));
 }
 
 int InitPutRequest(OCQualityOfService qos)
 {
     cout << "\nExecuting " << __func__;
     std::ostringstream query;
-    //TODO: Bug in RI layer.  Its returning 65600 instead of CT_ADAPTER_IP
-    if (65600 == OC_CONNTYPE)
-    {
-        query << "coap://" << coapServerIP << ":" << coapServerPort << coapServerResource;
-    }
-    else
-    {
-        query << "coap://" << coapServerIP << coapServerResource;
-    }
-    return (InvokeOCDoResource(query, OC_REST_PUT, (qos == OC_HIGH_QOS)? OC_HIGH_QOS:OC_LOW_QOS,
+    query << coapServerResource;
+    return (InvokeOCDoResource(query, &g_serverAddr, OC_REST_PUT, (qos == OC_HIGH_QOS)? OC_HIGH_QOS:OC_LOW_QOS,
             putReqCB, NULL, 0));
 }
 
@@ -586,19 +581,10 @@ int InitPostRequest(OCQualityOfService qos)
     OCStackResult result;
     cout << "\nExecuting " << __func__;
     std::ostringstream query;
-
-    //TODO: Bug in RI layer.  Its returning 65600 instead of CT_ADAPTER_IP
-    if (65600 == OC_CONNTYPE)
-    {
-        query << "coap://" << coapServerIP << ":" << coapServerPort << coapServerResource;
-    }
-    else
-    {
-        query << "coap://" << coapServerIP << coapServerResource;
-    }
+    query << coapServerResource;
 
     // First POST operation (to create an Light instance)
-    result = InvokeOCDoResource(query, OC_REST_POST,
+    result = InvokeOCDoResource(query, &g_serverAddr, OC_REST_POST,
                                ((qos == OC_HIGH_QOS) ? OC_HIGH_QOS: OC_LOW_QOS),
                                postReqCB, NULL, 0);
     if (OC_STACK_OK != result)
@@ -608,7 +594,7 @@ int InitPostRequest(OCQualityOfService qos)
     }
 
     // Second POST operation (to create an Light instance)
-    result = InvokeOCDoResource(query, OC_REST_POST,
+    result = InvokeOCDoResource(query, &g_serverAddr, OC_REST_POST,
                                ((qos == OC_HIGH_QOS) ? OC_HIGH_QOS: OC_LOW_QOS),
                                postReqCB, NULL, 0);
     if (OC_STACK_OK != result)
@@ -617,7 +603,7 @@ int InitPostRequest(OCQualityOfService qos)
     }
 
     // This POST operation will update the original resourced /a/light
-    return (InvokeOCDoResource(query, OC_REST_POST,
+    return (InvokeOCDoResource(query, &g_serverAddr, OC_REST_POST,
                                ((qos == OC_HIGH_QOS) ? OC_HIGH_QOS: OC_LOW_QOS),
                                postReqCB, NULL, 0));
 }
@@ -626,16 +612,7 @@ void* RequestDeleteDeathResourceTask(void* myqos)
 {
     sleep (30);//long enough to give the server time to finish deleting the resource.
     std::ostringstream query;
-
-    //TODO: Bug in RI layer.  Its returning 65600 instead of CT_ADAPTER_IP
-    if (65600 == OC_CONNTYPE)
-    {
-        query << "coap://" << coapServerIP << ":" << coapServerPort << coapServerResource;
-    }
-    else
-    {
-        query << "coap://" << coapServerIP << coapServerResource;
-    }
+    query << coapServerResource;
 
     cout << "\nExecuting " << __func__;
 
@@ -650,7 +627,7 @@ void* RequestDeleteDeathResourceTask(void* myqos)
         qos = OC_HIGH_QOS;
     }
 
-    OCStackResult result = InvokeOCDoResource(query, OC_REST_DELETE,
+    OCStackResult result = InvokeOCDoResource(query, &g_serverAddr, OC_REST_DELETE,
                                qos,
                                deleteReqCB, NULL, 0);
 
@@ -666,20 +643,12 @@ int InitDeleteRequest(OCQualityOfService qos)
 {
     OCStackResult result;
     std::ostringstream query;
-    //TODO: Bug in RI layer.  Its returning 65600 instead of CT_ADAPTER_IP
-    if (65600 == OC_CONNTYPE)
-    {
-        query << "coap://" << coapServerIP << ":" << coapServerPort << coapServerResource;
-    }
-    else
-    {
-        query << "coap://" << coapServerIP << coapServerResource;
-    }
+    query << coapServerResource;
 
     cout << "\nExecuting " << __func__;
 
     // First DELETE operation
-    result = InvokeOCDoResource(query, OC_REST_DELETE,
+    result = InvokeOCDoResource(query, &g_serverAddr, OC_REST_DELETE,
                                qos,
                                deleteReqCB, NULL, 0);
     if (OC_STACK_OK != result)
@@ -705,16 +674,7 @@ int InitGetRequest(OCQualityOfService qos, uint8_t withVendorSpecificHeaderOptio
 
     cout << "\nExecuting " << __func__;
     std::ostringstream query;
-
-    //TODO: Bug in RI layer.  Its returning 65600 instead of CT_ADAPTER_IP
-    if (65600 == OC_CONNTYPE)
-    {
-        query << "coap://" << coapServerIP << ":" << coapServerPort << coapServerResource;
-    }
-    else
-    {
-        query << "coap://" << coapServerIP << coapServerResource;
-    }
+    query << coapServerResource;
 
     // ocserver is written to only process "power<X" query.
     if (getWithQuery)
@@ -739,12 +699,12 @@ int InitGetRequest(OCQualityOfService qos, uint8_t withVendorSpecificHeaderOptio
     }
     if (withVendorSpecificHeaderOptions)
     {
-        return (InvokeOCDoResource(query, OC_REST_GET,
+        return (InvokeOCDoResource(query, &g_serverAddr, OC_REST_GET,
                 (qos == OC_HIGH_QOS) ? OC_HIGH_QOS : OC_LOW_QOS, getReqCB, options, 2));
     }
     else
     {
-        return (InvokeOCDoResource(query, OC_REST_GET,
+        return (InvokeOCDoResource(query, &g_serverAddr, OC_REST_GET,
                 (qos == OC_HIGH_QOS) ? OC_HIGH_QOS : OC_LOW_QOS, getReqCB, NULL, 0));
     }
 }
@@ -757,32 +717,15 @@ int InitPlatformDiscovery(OCQualityOfService qos)
     OCCallbackData cbData;
     char szQueryUri[64] = { 0 };
 
+    snprintf(szQueryUri, sizeof (szQueryUri) - 1, PLATFORM_DISCOVERY_QUERY, g_discoveryAddr);
+
     cbData.cb = PlatformDiscoveryReqCB;
     cbData.context = (void*)DEFAULT_CONTEXT_VALUE;
     cbData.cd = NULL;
 
-    if(UNICAST_DISCOVERY)
-    {
-        snprintf(szQueryUri, sizeof(szQueryUri), UNICAST_PLATFORM_DISCOVERY_QUERY, unicastAddr);
-    }
-    else
-    {
-        strncpy(szQueryUri, MULTICAST_PLATFORM_DISCOVERY_QUERY, sizeof(szQueryUri) -1 );
-    }
-    szQueryUri[sizeof(szQueryUri) -1] = '\0';
-
-    if(UNICAST_DISCOVERY)
-    {
-        ret = OCDoResource(NULL, OC_REST_GET, szQueryUri, 0, 0, OC_CONNTYPE,
-                (qos == OC_HIGH_QOS) ? OC_HIGH_QOS : OC_LOW_QOS, &cbData, NULL, 0);
-    }
-    else
-    {
-
-        ret = OCDoResource(NULL, OC_REST_DISCOVER, szQueryUri, 0, 0, OC_CONNTYPE,
-                        (qos == OC_HIGH_QOS) ? OC_HIGH_QOS : OC_LOW_QOS, &cbData, NULL, 0);
-    }
-
+    ret = OCDoResource(NULL, OC_REST_DISCOVER, szQueryUri, NULL, 0, CT_DEFAULT,
+                       (qos == OC_HIGH_QOS) ? OC_HIGH_QOS : OC_LOW_QOS,
+                       &cbData, NULL, 0);
     if (ret != OC_STACK_OK)
     {
         cout << "\nOCStack device error";
@@ -797,33 +740,17 @@ int InitDeviceDiscovery(OCQualityOfService qos)
 
     OCStackResult ret;
     OCCallbackData cbData;
-    char szQueryUri[64] = { 0 };
+    char szQueryUri[100] = { 0 };
+
+    snprintf(szQueryUri, sizeof (szQueryUri) - 1, DEVICE_DISCOVERY_QUERY, g_discoveryAddr);
 
     cbData.cb = DeviceDiscoveryReqCB;
     cbData.context = (void*)DEFAULT_CONTEXT_VALUE;
     cbData.cd = NULL;
 
-    if(UNICAST_DISCOVERY)
-    {
-        snprintf(szQueryUri, sizeof(szQueryUri), UNICAST_DEVICE_DISCOVERY_QUERY, unicastAddr);
-    }
-    else
-    {
-        strncpy(szQueryUri, MULTICAST_DEVICE_DISCOVERY_QUERY, sizeof(szQueryUri) -1 );
-    }
-    szQueryUri[sizeof(szQueryUri) -1] = '\0';
-
-    if(UNICAST_DISCOVERY)
-    {
-        ret = OCDoResource(NULL, OC_REST_GET, szQueryUri, 0, 0, OC_CONNTYPE,
-                (qos == OC_HIGH_QOS) ? OC_HIGH_QOS : OC_LOW_QOS, &cbData, NULL, 0);
-    }
-    else
-    {
-        ret = OCDoResource(NULL, OC_REST_DISCOVER, szQueryUri, 0, 0, OC_CONNTYPE,
-                        (qos == OC_HIGH_QOS) ? OC_HIGH_QOS : OC_LOW_QOS, &cbData, NULL, 0);
-    }
-
+    ret = OCDoResource(NULL, OC_REST_DISCOVER, szQueryUri, NULL, 0, CT_DEFAULT,
+                       (qos == OC_HIGH_QOS) ? OC_HIGH_QOS : OC_LOW_QOS,
+                       &cbData, NULL, 0);
     if (ret != OC_STACK_OK)
     {
         cout << "\nOCStack device error";
@@ -836,31 +763,17 @@ int InitDiscovery(OCQualityOfService qos)
 {
     OCStackResult ret;
     OCCallbackData cbData;
-    /* Start a discovery query*/
-    char szQueryUri[64] = { 0 };
+    char szQueryUri[100] = { 0 };
 
-    if (UNICAST_DISCOVERY)
-    {
-        snprintf(szQueryUri, sizeof(szQueryUri), UNICAST_RESOURCE_DISCOVERY_QUERY, unicastAddr);
-    }
-    else
-    {
-        strcpy(szQueryUri, MULTICAST_RESOURCE_DISCOVERY_QUERY);
-    }
+    snprintf(szQueryUri, sizeof (szQueryUri) - 1, RESOURCE_DISCOVERY_QUERY, g_discoveryAddr);
 
     cbData.cb = discoveryReqCB;
     cbData.context = (void*)DEFAULT_CONTEXT_VALUE;
     cbData.cd = NULL;
-    if(UNICAST_DISCOVERY)
-    {
-        ret = OCDoResource(NULL, OC_REST_GET, szQueryUri, 0, 0, OC_CONNTYPE,
-                (qos == OC_HIGH_QOS) ? OC_HIGH_QOS : OC_LOW_QOS, &cbData, NULL, 0);
-    }
-    else
-    {
-        ret = OCDoResource(NULL, OC_REST_DISCOVER, szQueryUri, 0, 0, OC_CONNTYPE,
-                        (qos == OC_HIGH_QOS) ? OC_HIGH_QOS : OC_LOW_QOS, &cbData, NULL, 0);
-    }
+
+    ret = OCDoResource(NULL, OC_REST_DISCOVER, szQueryUri, NULL, 0, CT_DEFAULT,
+                       (qos == OC_HIGH_QOS) ? OC_HIGH_QOS : OC_LOW_QOS,
+                       &cbData, NULL, 0);
     if (ret != OC_STACK_OK)
     {
         cout << "\nOCStack resource error";
@@ -877,13 +790,13 @@ int main(int argc, char* argv[])
         switch(opt)
         {
             case 'u':
-                UNICAST_DISCOVERY = atoi(optarg);
+                g_unicastDiscovery = atoi(optarg);
                 break;
             case 't':
-                TEST_CASE = atoi(optarg);
+                g_testCase = atoi(optarg);
                 break;
             case 'c':
-                CONNECTIVITY = atoi(optarg);
+                g_connectivity = atoi(optarg);
                 break;
             default:
                 PrintUsage();
@@ -891,9 +804,9 @@ int main(int argc, char* argv[])
         }
     }
 
-    if ((UNICAST_DISCOVERY != 0 && UNICAST_DISCOVERY != 1) ||
-            (TEST_CASE < TEST_DISCOVER_REQ || TEST_CASE >= MAX_TESTS) ||
-            (CONNECTIVITY < CT_ADAPTER_DEFAULT || CONNECTIVITY >= MAX_CT))
+    if ((g_unicastDiscovery != 0 && g_unicastDiscovery != 1) ||
+            (g_testCase < TEST_DISCOVER_REQ || g_testCase >= MAX_TESTS) ||
+            (g_connectivity < CT_ADAPTER_DEFAULT || g_connectivity >= MAX_CT))
     {
         PrintUsage();
         return -1;
@@ -901,29 +814,36 @@ int main(int argc, char* argv[])
 
     cout << "\nEntering occlient main loop...\n";
 
-    /* Initialize OCStack*/
-    if (OCInit(NULL, 0, OC_CLIENT) != OC_STACK_OK)
+    if (OCInit1(OC_CLIENT, OC_DEFAULT_FLAGS, OC_DEFAULT_FLAGS) != OC_STACK_OK)
     {
         cout << "\nOCStack init error";
         return 0;
     }
 
-    if(CONNECTIVITY == CT_ADAPTER_DEFAULT || CONNECTIVITY == CT_IPV4)
+#ifdef ROUTING_GATEWAY
+    /*
+     * Before invoking Discover resource, we process the gateway requests
+     * and form the routing table.
+     */
+    for (int index = 0; index < MAX_NUM_GATEWAY_REQUEST; index++)
     {
-        OC_CONNTYPE = CT_ADAPTER_IP;
+        if (OCProcess() != OC_STACK_OK)
+        {
+            OC_LOG(ERROR, TAG, "OCStack process error");
+            return 0;
+        }
+        usleep(SLEEP_DURATION);
     }
-    else if(CONNECTIVITY == CT_IPV6)
+#endif
+
+    if (g_connectivity == CT_ADAPTER_DEFAULT || g_connectivity == CT_IP)
     {
-        //TODO: Remove when IPv6 is available.
-        cout << "\nIPv6 is currently not supported !!!!";
-        PrintUsage();
-        return -1;
+        g_connType = CT_ADAPTER_IP;
     }
-    else if(CONNECTIVITY == CT_EDR)
+    else if(g_connectivity == CT_EDR)
     {
-        OC_CONNTYPE = CT_ADAPTER_RFCOMM_BTEDR;
-
         cout << "\nSelected EDR Adapter\n";
+        g_connType = CT_ADAPTER_RFCOMM_BTEDR;
     }
     else
     {
@@ -931,17 +851,19 @@ int main(int argc, char* argv[])
         PrintUsage();
     }
 
-    if (UNICAST_DISCOVERY)
+    g_discoveryAddr[0] = '\0';
+
+    if (g_unicastDiscovery)
     {
         cout << "\nEnter address of Server hosting resource as given below:";
         cout << "\nIP Adapter: 192.168.0.15:45454(IP:Port)";
         cout << "\nEDR/BLE Adapter: AB:BC:CD:DE:EF:FG(MAC Address)";
         cout << "\nInput:  ";
 
-        if (fgets(unicastAddr, MAX_ADDR_SIZE, stdin))
+        if (fgets(g_discoveryAddr, sizeof (g_discoveryAddr), stdin))
         {
             //Strip newline char from unicastAddr
-            StripNewLineChar(unicastAddr);
+            StripNewLineChar(g_discoveryAddr);
         }
         else
         {
@@ -950,11 +872,11 @@ int main(int argc, char* argv[])
         }
     }
 
-    if(UNICAST_DISCOVERY  == 0  && TEST_CASE == TEST_DISCOVER_DEV_REQ)
+    if (g_unicastDiscovery == 0 && g_testCase == TEST_DISCOVER_DEV_REQ)
     {
         InitDeviceDiscovery(OC_LOW_QOS);
     }
-    else if(UNICAST_DISCOVERY  == 0  && TEST_CASE == TEST_DISCOVER_PLATFORM_REQ)
+    else if (g_unicastDiscovery == 0 && g_testCase == TEST_DISCOVER_PLATFORM_REQ)
     {
         InitPlatformDiscovery(OC_LOW_QOS);
     }
@@ -964,6 +886,7 @@ int main(int argc, char* argv[])
     }
 
     // Break from loop with Ctrl+C
+    OC_LOG(INFO, TAG, "Entering occlient main loop...");
     signal(SIGINT, handleSigInt);
     while (!gQuitFlag)
     {
@@ -973,8 +896,9 @@ int main(int argc, char* argv[])
             cout << "\nOCStack process error\n";
             return 0;
         }
-
-        sleep(2);
+#ifndef ROUTING_GATEWAY
+        sleep(1);
+#endif
     }
 
     cout << "\nExiting occlient main loop...\n";
@@ -987,35 +911,6 @@ int main(int argc, char* argv[])
     return 0;
 }
 
-std::string getIPAddrTBServer(OCClientResponse * clientResponse)
-{
-    if (!clientResponse)
-    {
-        return "";
-    }
-    if (!clientResponse->addr)
-    {
-        return "";
-    }
-
-    return std::string(clientResponse->devAddr.addr);
-}
-
-std::string getPortTBServer(OCClientResponse * clientResponse)
-{
-    if (!clientResponse)
-    {
-        return "";
-    }
-    if (!clientResponse->addr)
-    {
-        return "";
-    }
-    std::ostringstream ss;
-    ss << clientResponse->devAddr.port;
-    return ss.str();
-}
-
 std::string getConnectivityType (OCConnectivityType connType)
 {
     switch (connType & CT_MASK_ADAPTER)
@@ -1040,16 +935,13 @@ std::string getConnectivityType (OCConnectivityType connType)
     }
 }
 
-std::string getQueryStrForGetPut(OCClientResponse * clientResponse)
+std::string getQueryStrForGetPut(OCClientResponse * /*clientResponse*/)
 {
-
     return "/a/light";
 }
 
 void parseClientResponse(OCClientResponse * clientResponse)
 {
-    coapServerIP = getIPAddrTBServer(clientResponse);
-    coapServerPort = getPortTBServer(clientResponse);
     coapServerResource = getQueryStrForGetPut(clientResponse);
 }
 
index 051a21d..e63d947 100644 (file)
@@ -73,8 +73,7 @@ typedef enum {
  */
 typedef enum {
     CT_ADAPTER_DEFAULT = 0,
-    CT_IPV4,
-    CT_IPV6,
+    CT_IP,
     CT_EDR,
     MAX_CT
 } CLIENT_CONNECTIVITY_TYPE;
diff --git a/resource/csdk/stack/samples/tizen/SimpleClientServer/ocrouting.cpp b/resource/csdk/stack/samples/tizen/SimpleClientServer/ocrouting.cpp
new file mode 100644 (file)
index 0000000..7039f93
--- /dev/null
@@ -0,0 +1,82 @@
+/* ****************************************************************
+ *
+ * Copyright 2015 Samsung Electronics 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 <string>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <pthread.h>
+#include <array>
+#include <iostream>
+#include "ocstack.h"
+#include "logger.h"
+#include "ocpayload.h"
+
+using namespace std;
+
+#define TAG "ocrouting"
+
+int gQuitFlag = 0;
+
+/* SIGINT handler: set gQuitFlag to 1 for graceful termination */
+void handleSigInt(int signum)
+{
+    if (signum == SIGINT)
+    {
+        gQuitFlag = 1;
+    }
+}
+
+int main()
+{
+    cout << "\nOCRouting sample is starting...";
+
+    if (OCInit(NULL, 0, OC_GATEWAY) != OC_STACK_OK)
+    {
+        cout << "\nOCStack init error";
+        return 0;
+    }
+
+    // Break from loop with Ctrl-C
+    cout << "\nEntering ocrouting main loop...";
+
+    signal(SIGINT, handleSigInt);
+
+    while (!gQuitFlag)
+    {
+        if (OCProcess() != OC_STACK_OK)
+        {
+            cout << "\nOCStack process error";
+            return 0;
+        }
+    }
+
+    cout << "\nExiting ocrouting main loop...";
+
+    if (OCStop() != OC_STACK_OK)
+    {
+        cout << "\nOCStack process error";
+    }
+
+    return 0;
+}
index d8869de..944adc2 100644 (file)
@@ -632,6 +632,7 @@ OCEntityHandlerCb (OCEntityHandlerFlag flag,
         }
     }
 
+    OCPayloadDestroy(response.payload);
     return ehResult;
 }
 
@@ -1039,8 +1040,9 @@ int main(int argc, char* argv[])
             cout << "\nOCStack process error";
             return 0;
         }
-
-        sleep(2);
+#ifndef ROUTING_GATEWAY
+        sleep(1);
+#endif
     }
 
     /*
index bc482e7..08f2de2 100644 (file)
@@ -63,8 +63,8 @@ const char *getResult(OCStackResult result);
  */
 int createLightResource (char *uri, LightResource *lightResource);
 
-/* This method converts the payload to JSON format */
-char* constructJsonResponse (OCEntityHandlerRequest *ehRequest);
+/* This method constructs a response from the request */
+OCRepPayload* constructResponse (OCEntityHandlerRequest *ehRequest);
 
 /* This method changes the Light power using an independent thread
  * and notifies the observers of new state of the resource.
@@ -79,22 +79,15 @@ OCEntityHandlerResult ValidateQueryParams (OCEntityHandlerRequest *entityHandler
 /* Following methods process the PUT, GET, POST, Delete,
  * & Observe requests */
 OCEntityHandlerResult ProcessGetRequest (OCEntityHandlerRequest *ehRequest,
-                                         char *payload,
-                                         uint16_t maxPayloadSize);
+                                         OCRepPayload **payload);
 OCEntityHandlerResult ProcessPutRequest (OCEntityHandlerRequest *ehRequest,
-                                         char *payload,
-                                         uint16_t maxPayloadSize);
+                                         OCRepPayload **payload);
 OCEntityHandlerResult ProcessPostRequest (OCEntityHandlerRequest *ehRequest,
                                           OCEntityHandlerResponse *response,
-                                          char *payload,
-                                          uint16_t maxPayloadSize);
-OCEntityHandlerResult ProcessDeleteRequest (OCEntityHandlerRequest *ehRequest,
-                                            char *payload,
-                                            uint16_t maxPayloadSize);
-
-OCEntityHandlerResult ProcessNonExistingResourceRequest (OCEntityHandlerRequest *ehRequest,
-                                                         char *payload,
-                                                         uint16_t maxPayloadSize);
+                                         OCRepPayload **payload);
+OCEntityHandlerResult ProcessDeleteRequest (OCEntityHandlerRequest *ehRequest);
+
+OCEntityHandlerResult ProcessNonExistingResourceRequest (OCEntityHandlerRequest *ehRequest);
 
 void ProcessObserveRegister (OCEntityHandlerRequest *ehRequest);
 void ProcessObserveDeregister (OCEntityHandlerRequest *ehRequest);
index 569a132..f719742 100644 (file)
@@ -30,7 +30,7 @@ OIC RIsample application
 %build
 
 scons TARGET_OS=tizen -c
-scons TARGET_OS=tizen TARGET_TRANSPORT=%{TARGET_TRANSPORT} SECURED=%{SECURED} RELEASE=%{RELEASE}
+scons TARGET_OS=tizen TARGET_TRANSPORT=%{TARGET_TRANSPORT} SECURED=%{SECURED} RELEASE=%{RELEASE} ROUTING=%{ROUTING}
 
 %install
 
@@ -42,12 +42,14 @@ mkdir -p %{buildroot}/usr/apps/com.oic.ri.sample/bin/internal
 cp -rf %{ROOTDIR}/com.oic.ri.sample.xml %{buildroot}/%{_datadir}/packages
 cp -rf %{ROOTDIR}/scons/occlient %{buildroot}/usr/apps/com.oic.ri.sample/bin/
 cp -rf %{ROOTDIR}/scons/ocserver %{buildroot}/usr/apps/com.oic.ri.sample/bin/
+cp -rf %{ROOTDIR}/scons/ocrouting %{buildroot}/usr/apps/com.oic.ri.sample/bin/
 
 %files
 %manifest com.oic.ri.sample.manifest
 %defattr(-,root,root,-)
 /usr/apps/com.oic.ri.sample/bin/occlient
 /usr/apps/com.oic.ri.sample/bin/ocserver
+/usr/apps/com.oic.ri.sample/bin/ocrouting
 /%{_datadir}/packages/com.oic.ri.sample.xml
 
 
index 0763dbe..509fec3 100644 (file)
@@ -23,7 +23,7 @@ Import('env')
 target_os = env.get('TARGET_OS')
 transport = env.get('TARGET_TRANSPORT')
 secured = env.get('SECURED')
-
+routing = env.get('ROUTING')
 OIC_LIB = 'oic'
 root_dir = env.get('ROOT_DIR')
 build_dir = env.get('BUILD_DIR')
@@ -32,6 +32,11 @@ sample_dir = build_dir
 env.AppendUnique(CPPFLAGS = ['-std=c++0x', '-fPIC', '-D__TIZEN__','-DWITH_POSIX', '-Wall', '-DSLP_SDK_LOG', '-g','-D_GNU_SOURCE','-DTIZEN_DEBUG_ENABLE', '-DTB_LOG','`pkg-config', '--cflags', '--libs','dlog', 'com.oic.ri', 'capi-network-wifi',
                                'gobject-2.0','glib-2.0`'])
 
+if routing == 'GW':
+       env.AppendUnique(CPPDEFINES = ['ROUTING_GATEWAY'])
+elif routing == 'EP':
+       env.AppendUnique(CPPDEFINES = ['ROUTING_EP'])
+
 env.Append(LIBS=[
   '-lm', '-lpthread', '-lrt', '-ldl', '-lstdc++', '-lgobject-2.0', '-lgio-2.0', '-lglib-2.0', '-lcapi-network-wifi', '-ldlog', '-lcapi-network-bluetooth', '-lconnectivity_abstraction', 'coap', '-loctbstack', 'ocsrm', 'c_common'
 ])
@@ -70,4 +75,5 @@ else:
 #env.Program('ri_sample', [ri_sample_src,])
 
 env.Program('occlient', [sample_dir + 'occlient.cpp', sample_dir + 'common.cpp'])
-env.Program('ocserver', [sample_dir + 'ocserver.cpp', sample_dir + 'common.cpp'])
\ No newline at end of file
+env.Program('ocserver', [sample_dir + 'ocserver.cpp', sample_dir + 'common.cpp'])
+env.Program('ocrouting', [sample_dir + 'ocrouting.cpp', sample_dir + 'common.cpp'])
index 46cb520..1e3722a 100644 (file)
@@ -12,12 +12,28 @@ buildsample = env.get('BUILD_SAMPLE')
 release_mode = env.get('RELEASE')
 secured = env.get('SECURED')
 logging = env.get('LOGGING')
+routing = env.get('ROUTING')
+
+env.PrependUnique(CPPPATH = [
+               '../../../../logger/include',
+               '../../../../stack/include',
+               '../../../../../../extlibs/cjson',
+               '../../../../../oc_logger/include',
+               '../../../../../connectivity/lib/libcoap-4.1.1'
+               ])
+
+env.AppendUnique(CPPDEFINES = ['TB_LOG'])
+if routing == 'GW':
+       env.AppendUnique(CPPDEFINES = ['ROUTING_GATEWAY'])
+elif routing == 'EP':
+       env.AppendUnique(CPPDEFINES = ['ROUTING_EP'])
+env.AppendUnique(CPPDEFINES = ['__TIZEN__'])
 
 print "Given Transport is %s" % transport
 print "Given OS is %s" % target_os
 
 if target_os == 'tizen':
-       command = "sh resource/csdk/stack/samples/tizen/build/gbsbuild.sh %s %s %s %s %s" % (transport, secured, buildsample, release_mode, logging)
+       command = "sh resource/csdk/stack/samples/tizen/build/gbsbuild.sh %s %s %s %s %s %s" % (transport, secured, buildsample, release_mode, logging, routing)
        print "Created Command is %s" % command
        gbs_script = env.Command('gbs_build', None, command)
        AlwaysBuild ('gbs_script')
\ No newline at end of file
index 2b8410f..d1747da 100644 (file)
@@ -23,6 +23,8 @@ export RELEASE=$4
 echo $5
 export LOGGING=$5
 
+echo $6
+export ROUTING=$6
 
 echo $TARGET_TRANSPORT
 echo $BUILD_SAMPLE
@@ -74,7 +76,7 @@ if [ ! -d .git ]; then
 fi
 
 echo "Calling core gbs build command"
-gbscommand="gbs build -A armv7l -B ~/GBS-ROOT-RI --include-all --define 'TARGET_TRANSPORT $1' --define 'SECURED $2' --define 'RELEASE $4' --define 'LOGGING $5' --repository ./"
+gbscommand="gbs build -A armv7l -B ~/GBS-ROOT-RI --include-all --define 'TARGET_TRANSPORT $1' --define 'SECURED $2' --define 'RELEASE $4' --define 'LOGGING $5' --define 'ROUTING $6' --repository ./"
 echo $gbscommand
 if eval $gbscommand; then
    echo "Core build is successful"
@@ -97,7 +99,7 @@ if echo $BUILD_SAMPLE|grep -qi '^ON$'; then
       git commit -m "Initial commit"
    fi
    echo "Calling sample gbs build command"
-   gbscommand="gbs build -A armv7l -B ~/GBS-ROOT-RI --include-all --define 'TARGET_TRANSPORT $1' --define 'SECURED $2' --define 'RELEASE $4' --define 'LOGGING $5' --repository ./"
+   gbscommand="gbs build -A armv7l -B ~/GBS-ROOT-RI --include-all --define 'TARGET_TRANSPORT $1' --define 'SECURED $2' --define 'RELEASE $4' --define 'LOGGING $5' --define 'ROUTING $6' --repository ./"
    echo $gbscommand
    if eval $gbscommand; then
       echo "Sample build is successful"
index 9ec2214..82eee41 100644 (file)
@@ -35,7 +35,7 @@ SLP oicri application
 echo %{ROOTDIR}
 
 scons TARGET_OS=tizen -c
-scons TARGET_OS=tizen TARGET_TRANSPORT=%{TARGET_TRANSPORT} SECURED=%{SECURED} RELEASE=%{RELEASE} LOGGING=%{LOGGING}
+scons TARGET_OS=tizen TARGET_TRANSPORT=%{TARGET_TRANSPORT} SECURED=%{SECURED} RELEASE=%{RELEASE} LOGGING=%{LOGGING} ROUTING=%{ROUTING}
 
 %install
 mkdir -p %{DEST_INC_DIR}
@@ -64,6 +64,7 @@ cp resource/oc_logger/include/targets/oc_ostream_logger.h %{DEST_INC_DIR}
 cp resource/csdk/stack/include/ocpresence.h %{DEST_INC_DIR}
 cp resource/csdk/stack/include/ocpayload.h %{DEST_INC_DIR}
 cp resource/c_common/platform_features.h %{DEST_INC_DIR}
+cp resource/csdk/stack/include/payload_logging.h %{DEST_INC_DIR}
 cp extlibs/cjson/cJSON.h %{DEST_INC_DIR}
 cp -rf %{ROOTDIR}/com.oic.ri.pc %{DEST_LIB_DIR}/pkgconfig/
 
index 3e6f6b0..6749105 100644 (file)
@@ -29,6 +29,7 @@
 #include "oic_string.h"
 #include "ocpayload.h"
 #include "ocserverrequest.h"
+#include "logger.h"
 
 #include "utlist.h"
 #include "pdu.h"
index d085fc1..95265bb 100644 (file)
@@ -38,6 +38,9 @@
 #include "secureresourcemanager.h"
 #include "cacommon.h"
 #include "cainterface.h"
+#ifdef ROUTING_GATEWAY
+#include "routingmanager.h"
+#endif
 
 /// Module Name
 #define TAG "ocresource"
@@ -162,6 +165,12 @@ static OCVirtualResources GetTypeOfVirtualURI(const char *uriInRequest)
     {
         return OC_RESOURCE_TYPES_URI;
     }
+#ifdef ROUTING_GATEWAY
+    else if (0 == strcmp(uriInRequest, OC_RSRVD_GATEWAY_URI))
+    {
+        return OC_GATEWAY_URI;
+    }
+#endif
 #ifdef WITH_PRESENCE
     else if (strcmp(uriInRequest, OC_RSRVD_PRESENCE_URI) == 0)
     {
@@ -491,7 +500,7 @@ static bool includeThisResourceInResponse(OCResource *resource,
         return false;
     }
 
-    if (resource->resourceProperties & OC_EXPLICIT_DISCOVERABLE)
+    if ( resource->resourceProperties & OC_EXPLICIT_DISCOVERABLE)
     {
         /*
          * At least one valid filter should be available to
@@ -505,7 +514,7 @@ static bool includeThisResourceInResponse(OCResource *resource,
             return false;
         }
     }
-    else if (!(resource->resourceProperties & OC_ACTIVE) ||
+    else if ( !(resource->resourceProperties & OC_ACTIVE) ||
          !(resource->resourceProperties & OC_DISCOVERABLE))
     {
         OC_LOG_V(INFO, TAG, "%s not ACTIVE or DISCOVERABLE", resource->uri);
@@ -623,6 +632,15 @@ static OCStackResult HandleVirtualResource (OCServerRequest *request, OCResource
             discoveryResult = OC_STACK_OK;
         }
     }
+#ifdef ROUTING_GATEWAY
+    else if (OC_GATEWAY_URI == virtualUriInRequest)
+    {
+        // Received request for a gateway
+        OC_LOG(INFO, TAG, "Request is for Gateway Virtual Request");
+        discoveryResult = RMHandleGatewayRequest(request, resource);
+
+    }
+#endif
 
     /**
      * Step 2: Send the discovery response
@@ -646,6 +664,10 @@ static OCStackResult HandleVirtualResource (OCServerRequest *request, OCResource
         SendPresenceNotification(resource->rsrcType, OC_PRESENCE_TRIGGER_CHANGE);
     }
     else
+    #endif
+#ifdef ROUTING_GATEWAY
+    // Gateway uses the RMHandleGatewayRequest to respond to the request.
+    if (OC_GATEWAY != virtualUriInRequest)
 #endif
     {
         if(discoveryResult == OC_STACK_OK)
index 5a6c498..a15fcc1 100644 (file)
 #include "oic_string.h"
 #include "ocpayload.h"
 #include "ocpayloadcbor.h"
+#include "logger.h"
+
+#if defined (ROUTING_GATEWAY) || defined (ROUTING_EP)
+#include "routingutility.h"
+#endif
 
 #include "cacommon.h"
 #include "cainterface.h"
@@ -140,7 +145,8 @@ static void FindAndDeleteServerResponse(OCServerResponse * serverResponse)
 }
 
 /**
- * Ensure no accept header option is included when sending responses
+ * Ensure no accept header option is included when sending responses and add routing info to
+ * outgoing response.
  *
  * @param object CA remote endpoint.
  * @param requestInfo CA request info.
@@ -149,6 +155,17 @@ static void FindAndDeleteServerResponse(OCServerResponse * serverResponse)
  */
 static OCStackResult OCSendResponse(const CAEndpoint_t *object, CAResponseInfo_t *responseInfo)
 {
+#if defined (ROUTING_GATEWAY) || defined (ROUTING_EP)
+    // Add route info in RM option.
+    OCStackResult rmResult = RMAddInfo(object->routeData, &(responseInfo->info.options),
+                       &(responseInfo->info.numOptions));
+    if(OC_STACK_OK != rmResult)
+    {
+        OC_LOG(ERROR, TAG, "Add option failed");
+        return rmResult;
+    }
+#endif
+
     // Do not include the accept header option
     responseInfo->info.acceptFormat = CA_FORMAT_UNDEFINED;
     CAResult_t result = CASendResponse(object, responseInfo);
@@ -257,6 +274,8 @@ OCStackResult AddServerRequest (OCServerRequest ** request, uint16_t coapID,
 
     OCServerRequest * serverRequest = NULL;
 
+    OC_LOG_V(INFO, TAG, "addserverrequest entry!! [%s:%u]", devAddr->addr, devAddr->port);
+
     serverRequest = (OCServerRequest *) OICCalloc(1, sizeof(OCServerRequest) +
         (reqTotalSize ? reqTotalSize : 1) - 1);
     VERIFY_NON_NULL(devAddr);
@@ -408,7 +427,7 @@ CAResponseResult_t ConvertEHResultToCAResult (OCEntityHandlerResult result, OCMe
         case OC_EH_OK:
            switch (method)
            {
-               case OC_REST_PUT: 
+               case OC_REST_PUT:
                case OC_REST_POST:
                    // This Response Code is like HTTP 204 "No Content" but only used in
                    // response to POST and PUT requests.
@@ -460,7 +479,6 @@ CAResponseResult_t ConvertEHResultToCAResult (OCEntityHandlerResult result, OCMe
  * @return
  *     OCStackResult
  */
-
 OCStackResult HandleSingleResponse(OCEntityHandlerResponse * ehResponse)
 {
     OCStackResult result = OC_STACK_ERROR;
index b59556a..474da86 100644 (file)
@@ -41,6 +41,7 @@
 #include "ocrandom.h"
 #include "oic_malloc.h"
 #include "oic_string.h"
+#include "logger.h"
 #include "ocserverrequest.h"
 #include "secureresourcemanager.h"
 #include "doxmresource.h"
 #include "ocpayload.h"
 #include "ocpayloadcbor.h"
 
+#if defined (ROUTING_GATEWAY) || defined (ROUTING_EP)
+#include "routingutility.h"
+#ifdef ROUTING_GATEWAY
+#include "routingmanager.h"
+#endif
+#endif
+
 #ifdef WITH_ARDUINO
 #include "Time.h"
 #else
@@ -376,7 +384,8 @@ static OCResourceType *findResourceType(OCResourceType * resourceTypeList,
 static OCStackResult ResetPresenceTTL(ClientCB *cbNode, uint32_t maxAgeSeconds);
 
 /**
- * Ensure the accept header option is set appropriatly before sending the requests.
+ * Ensure the accept header option is set appropriatly before sending the requests and routing
+ * header option is updated with destination.
  *
  * @param object CA remote endpoint.
  * @param requestInfo CA request info.
@@ -416,6 +425,9 @@ void CopyEndpointToDevAddr(const CAEndpoint_t *in, OCDevAddr *out)
     OICStrcpy(out->addr, sizeof(out->addr), in->addr);
     out->port = in->port;
     out->interface = in->interface;
+#if defined (ROUTING_GATEWAY) || defined (ROUTING_EP)
+    memcpy(out->routeData, in->routeData, sizeof(out->routeData));
+#endif
 }
 
 void CopyDevAddrToEndpoint(const OCDevAddr *in, CAEndpoint_t *out)
@@ -426,6 +438,9 @@ void CopyDevAddrToEndpoint(const OCDevAddr *in, CAEndpoint_t *out)
     out->adapter = (CATransportAdapter_t)in->adapter;
     out->flags = OCToCATransportFlags(in->flags);
     OICStrcpy(out->addr, sizeof(out->addr), in->addr);
+#if defined (ROUTING_GATEWAY) || defined (ROUTING_EP)
+    memcpy(out->routeData, in->routeData, sizeof(out->routeData));
+#endif
     out->port = in->port;
     out->interface = in->interface;
 }
@@ -441,6 +456,19 @@ void FixUpClientResponse(OCClientResponse *cr)
 
 static OCStackResult OCSendRequest(const CAEndpoint_t *object, CARequestInfo_t *requestInfo)
 {
+    VERIFY_NON_NULL(object, FATAL, OC_STACK_INVALID_PARAM);
+    VERIFY_NON_NULL(requestInfo, FATAL, OC_STACK_INVALID_PARAM);
+
+#if defined (ROUTING_GATEWAY) || defined (ROUTING_EP)
+    OCStackResult rmResult = RMAddInfo(object->routeData, &(requestInfo->info.options),
+                                     &(requestInfo->info.numOptions));
+    if (OC_STACK_OK != rmResult)
+    {
+        OC_LOG(ERROR, TAG, "Add destination option failed");
+        return rmResult;
+    }
+#endif
+
     // OC stack prefer CBOR encoded payloads.
     requestInfo->info.acceptFormat = CA_FORMAT_APPLICATION_CBOR;
     CAResult_t result = CASendRequest(object, requestInfo);
@@ -610,7 +638,7 @@ CAResponseResult_t OCToCAStackResult(OCStackResult ocCode, OCMethod method)
         case OC_STACK_OK:
            switch (method)
            {
-               case OC_REST_PUT: 
+               case OC_REST_PUT:
                case OC_REST_POST:
                    // This Response Code is like HTTP 204 "No Content" but only used in
                    // response to POST and PUT requests.
@@ -1029,6 +1057,34 @@ void HandleCAResponses(const CAEndpoint_t* endPoint, const CAResponseInfo_t* res
 
     OC_LOG(INFO, TAG, "Enter HandleCAResponses");
 
+#if defined (ROUTING_GATEWAY) || defined (ROUTING_EP)
+#ifdef ROUTING_GATEWAY
+    bool needRIHandling = false;
+    /*
+     * Routing manager is going to update either of endpoint or response or both.
+     * This typecasting is done to avoid unnecessary duplication of Endpoint and responseInfo
+     * RM can update "routeData" option in endPoint so that future RI requests can be sent to proper
+     * destination.
+     */
+    OCStackResult ret = RMHandleResponse((CAResponseInfo_t *)responseInfo, (CAEndpoint_t *)endPoint,
+                                         &needRIHandling);
+    if(ret != OC_STACK_OK || !needRIHandling)
+    {
+        OC_LOG_V(INFO, TAG, "Routing status![%d]. Not forwarding to RI", ret);
+        return;
+    }
+#endif
+
+    /*
+     * Put source in sender endpoint so that the next packet from application can be routed to
+     * proper destination and remove "RM" coap header option before passing request / response to
+     * RI as this option will make no sense to either RI or application.
+     */
+    RMUpdateInfo((CAHeaderOption_t **) &(responseInfo->info.options),
+                 (uint8_t *) &(responseInfo->info.numOptions),
+                 (CAEndpoint_t *) endPoint);
+#endif
+
     if(responseInfo->info.resourceUri &&
         strcmp(responseInfo->info.resourceUri, OC_RSRVD_PRESENCE_URI) == 0)
     {
@@ -1262,7 +1318,8 @@ void HandleCAResponses(const CAEndpoint_t* endPoint, const CAResponseInfo_t* res
 
     if(!cbNode && !observer)
     {
-        if(myStackMode == OC_CLIENT || myStackMode == OC_CLIENT_SERVER)
+        if(myStackMode == OC_CLIENT || myStackMode == OC_CLIENT_SERVER
+           || myStackMode == OC_GATEWAY)
         {
             OC_LOG(INFO, TAG, "This is a client, but no cbNode was found for token");
             if(responseInfo->result == CA_EMPTY)
@@ -1277,7 +1334,8 @@ void HandleCAResponses(const CAEndpoint_t* endPoint, const CAResponseInfo_t* res
             }
         }
 
-        if(myStackMode == OC_SERVER || myStackMode == OC_CLIENT_SERVER)
+        if(myStackMode == OC_SERVER || myStackMode == OC_CLIENT_SERVER
+           || myStackMode == OC_GATEWAY)
         {
             OC_LOG(INFO, TAG, "This is a server, but no observer was found for token");
             if (responseInfo->info.type == CA_MSG_ACKNOWLEDGE)
@@ -1343,16 +1401,28 @@ OCStackResult SendDirectStackResponse(const CAEndpoint_t* endPoint, const uint16
     respInfo.info.resourceUri = OICStrdup (resourceUri);
     respInfo.info.acceptFormat = CA_FORMAT_UNDEFINED;
 
+#if defined (ROUTING_GATEWAY) || defined (ROUTING_EP)
+    // Add the destination to route option from the endpoint->routeData.
+    OCStackResult result = RMAddInfo(endPoint->routeData,
+                                     &(respInfo.info.options),
+                                     &(respInfo.info.numOptions));
+    if(OC_STACK_OK != result)
+    {
+        OC_LOG_V(ERROR, TAG, "Add routing option failed [%d]", result);
+        return result;
+    }
+#endif
+
     CAResult_t caResult = CASendResponse(endPoint, &respInfo);
 
     // resourceUri in the info field is cloned in the CA layer and
     // thus ownership is still here.
     OICFree (respInfo.info.resourceUri);
 
-    if(caResult != CA_STATUS_OK)
+    if(CA_STATUS_OK != caResult)
     {
         OC_LOG(ERROR, TAG, "CASendResponse error");
-        return OC_STACK_ERROR;
+        return CAResultToOCResult(caResult);
     }
     return OC_STACK_OK;
 }
@@ -1373,6 +1443,34 @@ void HandleCARequests(const CAEndpoint_t* endPoint, const CARequestInfo_t* reque
         return;
     }
 
+#if defined (ROUTING_GATEWAY) || defined (ROUTING_EP)
+#ifdef ROUTING_GATEWAY
+    bool needRIHandling = false;
+    /*
+     * Routing manager is going to update either of endpoint or request or both.
+     * This typecasting is done to avoid unnecessary duplication of Endpoint and requestInfo
+     * RM can update "routeData" option in endPoint so that future RI requests can be sent to proper
+     * destination. It can also remove "RM" coap header option before passing request / response to
+     * RI as this option will make no sense to either RI or application.
+     */
+    OCStackResult ret = RMHandleRequest((CARequestInfo_t *)requestInfo, (CAEndpoint_t *)endPoint,
+                                     &needRIHandling);
+    if(OC_STACK_OK != ret || !needRIHandling)
+    {
+        OC_LOG_V(INFO, TAG, "Routing status![%d]. Not forwarding to RI", ret);
+        return;
+    }
+#endif
+
+    /*
+     * Put source in sender endpoint so that the next packet from application can be routed to
+     * proper destination and remove RM header option.
+     */
+    RMUpdateInfo((CAHeaderOption_t **) &(requestInfo->info.options),
+                 (uint8_t *) &(requestInfo->info.numOptions),
+                 (CAEndpoint_t *) endPoint);
+#endif
+
     OCStackResult requestResult = OC_STACK_ERROR;
 
     if(myStackMode == OC_CLIENT)
@@ -1694,6 +1792,14 @@ OCStackResult OCInit1(OCMode mode, OCTransportFlags serverFlags, OCTransportFlag
         return OC_STACK_OK;
     }
 
+#ifndef ROUTING_GATEWAY
+    if (OC_GATEWAY == mode)
+    {
+        OC_LOG(ERROR, TAG, "Routing Manager not supported");
+        return OC_STACK_INVALID_PARAM;
+    }
+#endif
+
 #ifdef RA_ADAPTER
     if(!gRASetInfo)
     {
@@ -1706,18 +1812,19 @@ OCStackResult OCInit1(OCMode mode, OCTransportFlags serverFlags, OCTransportFlag
     OC_LOG(INFO, TAG, "Entering OCInit");
 
     // Validate mode
-    if (!((mode == OC_CLIENT) || (mode == OC_SERVER) || (mode == OC_CLIENT_SERVER)))
+    if (!((mode == OC_CLIENT) || (mode == OC_SERVER) || (mode == OC_CLIENT_SERVER)
+        || (mode == OC_GATEWAY)))
     {
         OC_LOG(ERROR, TAG, "Invalid mode");
         return OC_STACK_ERROR;
     }
     myStackMode = mode;
 
-    if (mode == OC_CLIENT || mode == OC_CLIENT_SERVER)
+    if (mode == OC_CLIENT || mode == OC_CLIENT_SERVER || mode == OC_GATEWAY)
     {
         caglobals.client = true;
     }
-    if (mode == OC_SERVER || mode == OC_CLIENT_SERVER)
+    if (mode == OC_SERVER || mode == OC_CLIENT_SERVER || mode == OC_GATEWAY)
     {
         caglobals.server = true;
     }
@@ -1767,6 +1874,7 @@ OCStackResult OCInit1(OCMode mode, OCTransportFlags serverFlags, OCTransportFlag
             OC_LOG(INFO, TAG, "Server mode: CAStartListeningServer");
             break;
         case OC_CLIENT_SERVER:
+        case OC_GATEWAY:
                        SRMRegisterHandler(HandleCARequests, HandleCAResponses, HandleCAErrorResponse);
             result = CAResultToOCResult(CAStartListeningServer());
             if(result == OC_STACK_OK)
@@ -1797,6 +1905,13 @@ OCStackResult OCInit1(OCMode mode, OCTransportFlags serverFlags, OCTransportFlag
         // TODO after BeachHead delivery: consolidate into single SRMInit()
     }
 
+#ifdef ROUTING_GATEWAY
+    if (OC_GATEWAY == myStackMode)
+    {
+        result = RMInitialize();
+    }
+#endif
+
 exit:
     if(result != OC_STACK_OK)
     {
@@ -1831,6 +1946,13 @@ OCStackResult OCStop()
     presenceResource.presenceTTL = 0;
 #endif // WITH_PRESENCE
 
+#ifdef ROUTING_GATEWAY
+    if (OC_GATEWAY == myStackMode)
+    {
+        RMTerminate();
+    }
+#endif
+
     // Free memory dynamically allocated for resources
     deleteAllResources();
     DeleteDeviceInfo();
@@ -2608,6 +2730,9 @@ OCStackResult OCProcess()
 #endif
     CAHandleRequestResponse();
 
+#ifdef ROUTING_GATEWAY
+    RMProcess();
+#endif
     return OC_STACK_OK;
 }
 
@@ -2701,7 +2826,7 @@ OCStackResult OCSetPlatformInfo(OCPlatformInfo platformInfo)
 {
     OC_LOG(INFO, TAG, "Entering OCSetPlatformInfo");
 
-    if(myStackMode ==  OC_SERVER || myStackMode == OC_CLIENT_SERVER)
+    if(myStackMode ==  OC_SERVER || myStackMode == OC_CLIENT_SERVER || myStackMode == OC_GATEWAY)
     {
         if (validatePlatformInfo(platformInfo))
         {
index 5c5024d..21d56e7 100644 (file)
@@ -97,7 +97,8 @@ namespace OC
     {
         Server,
         Client,
-        Both
+        Both,
+        Gateway  /**< Client server mode along with routing capabilities.*/
     };
 
     /**
index 8a267b0..a25839f 100644 (file)
@@ -257,6 +257,10 @@ namespace OC
         {
             initType = OC_CLIENT_SERVER;
         }
+        else if (cfg.mode == ModeType::Gateway)
+        {
+            initType = OC_GATEWAY;
+        }
         else
         {
             throw InitializeException(OC::InitException::NOT_CONFIGURED_AS_SERVER,
index 09c32df..4abcb5a 100644 (file)
@@ -80,6 +80,7 @@ namespace OC
                 break;
 
             case ModeType::Both:
+            case ModeType::Gateway:
                 m_server = m_WrapperInstance->CreateServerWrapper(m_csdkLock, config);
                 m_client = m_WrapperInstance->CreateClientWrapper(m_csdkLock, config);
                 break;
index 0310f32..df2f209 100644 (file)
@@ -58,6 +58,9 @@ if target_os == 'android':
        oclib_env.AppendUnique(CXXFLAGS = ['-frtti', '-fexceptions'])
        oclib_env.AppendUnique(LIBS = ['boost_thread', 'gnustl_shared', 'log'])
 
+if target_os == 'tizen':
+       oclib_env.AppendUnique(CPPDEFINES = ['__TIZEN__'])
+
 ######################################################################
 # Source files and Targets
 ######################################################################