Implement sending host port number for secure resources
authorSachin Agrawal <sachin.agrawal@intel.com>
Fri, 14 Nov 2014 01:17:39 +0000 (17:17 -0800)
committerSachin Agrawal <sachin.agrawal@intel.com>
Fri, 14 Nov 2014 01:17:39 +0000 (17:17 -0800)
Secure resources are hosted on a separate IP port. All the
discovery responses are send from unicast unsecure port from
resource server. Currently, when a client receives discovery response
it 'assumes' that the sending port is the port hosting the resource
too. This 'assumption' is NOT valid for secure resources. Therefore,
there is a need to send 'secure port info' for secure resources in
JSON discovery response.

Change-Id: I54fd828a15913ec8be990d040e1190a88be43353
Signed-off-by: Sachin Agrawal <sachin.agrawal@intel.com>
13 files changed:
resource/csdk/occoap/include/occoap.h
resource/csdk/occoap/src/occoap.c
resource/csdk/ocsocket/include/ocsocket.h
resource/csdk/ocsocket/src/ocsocket.c
resource/csdk/ocsocket/src/ocsocket_arduino.cpp
resource/csdk/ocsocket/src/ocsocket_arduino_wifi.cpp
resource/csdk/ocsocket/test/linux/makefile
resource/csdk/ocsocket/test/linux/ocsocket_gtest.cpp
resource/csdk/stack/include/internal/ocresource.h
resource/csdk/stack/samples/linux/secure/occlientbasicops.cpp
resource/csdk/stack/samples/linux/secure/occlientbasicops.h
resource/csdk/stack/samples/linux/secure/ocserverbasicops.cpp
resource/csdk/stack/src/ocresource.c

index 2c82581..512ef74 100644 (file)
@@ -102,4 +102,16 @@ OCStackResult OCSendCoAPNotification (unsigned char * uri, OCDevAddr *dstAddr,
         OCQualityOfService qos, OCCoAPToken * token,
         unsigned char *payload, OCResource *resPtr, uint32_t maxAge);
 
+/**
+ * Retrieve the end-point info where resource is being hosted.
+ * Currently, this method only provides the IP port with which the socket
+ * is bound. This internal method may be extended in future to retrieve
+ * more info (such as IP address, transport technology) about the hosting end-point.
+ *
+ * @param resPtr    - pointer to the resource
+ * @param info      - pointer to 16-bit integer to hold port number
+ * @return 0 - success, else - TBD error
+ */
+OCStackResult OCGetResourceEndPointInfo (OCResource *resPtr, void *info);
+
 #endif /* OCCOAP_H_ */
index 3ac9c94..5c8b26f 100644 (file)
@@ -224,6 +224,13 @@ static void HandleCoAPRequests(struct coap_context_t *ctx,
     }
     #endif
 
+    // do not process further if received an error
+    // ex : when receive a non-secure request to a secure resource
+    if(responseResult == OC_STACK_ERROR)
+    {
+        goto exit;
+    }
+
     OC_LOG_V(INFO, TAG, "Response from ocstack: %s",
             request->entityHandlerRequest->resJSONPayload);
 
@@ -853,3 +860,29 @@ OCStackResult OCProcessCoAP() {
     return OC_STACK_OK;
 }
 
+
+/**
+ * Retrieve the info about the end-point where resource is being hosted.
+ * Currently, this method only provides the IP port with which the socket
+ * is bound.
+ *
+ * @return 0 - success, else - TBD error
+ */
+OCStackResult OCGetResourceEndPointInfo (OCResource *resPtr, void *info) {
+
+    OCStackResult result = OC_STACK_ERROR;
+    int sfd;
+    OC_LOG(INFO, TAG, PCF("Entering OCGetResourceEndPointInfo"));
+    VERIFY_NON_NULL(resPtr);
+    VERIFY_NON_NULL(info);
+
+    sfd = (resPtr->resourceProperties & OC_SECURE) ? gCoAPCtx->sockfd_dtls :
+            gCoAPCtx->sockfd;
+
+    if (OCGetSocketInfo(sfd, (uint16_t*)info) == ERR_SUCCESS)
+        result = OC_STACK_OK;
+exit:
+    return result;
+}
+
+
index 3efd072..ed9b412 100644 (file)
@@ -271,6 +271,23 @@ int32_t OCDevAddrToIPv4Addr(OCDevAddr *ipAddr, uint8_t *a, uint8_t *b,
 //------------------------------------------------------------------------
 int32_t OCDevAddrToPort(OCDevAddr *ipAddr, uint16_t *port);
 
+
+//-- OCGetSocketInfo -----------------------------------------------------
+/** @ingroup ocsocket
+ *
+ * This method is used to retrieve the port number to which the @p sockfd
+ * is bound.
+ *
+ * @param[in]  sockfd
+ *              socket whose port needs to be retrieved
+ * @param[out] port
+ *              port number
+ *
+ * @retval 0 for Success, otherwise some error value
+ */
+//------------------------------------------------------------------------
+int32_t OCGetSocketInfo(int32_t sockfd, uint16_t *port);
+
 #ifdef __cplusplus
 }
 #endif // __cplusplus
index 69367f7..f2911d3 100644 (file)
@@ -389,3 +389,20 @@ int32_t OCDevAddrToPort(OCDevAddr *ipAddr, uint16_t *port)
 
     return ERR_SUCCESS;
 }
+
+/// Retrieve the port to which socket is bound
+int32_t OCGetSocketInfo(int32_t sockfd, uint16_t *port)
+{
+    int32_t ret = ERR_SUCCESS;
+
+    struct sockaddr_in sa;
+    socklen_t salen = sizeof(sa);
+    if (getsockname(sockfd, (struct sockaddr*)&sa, &salen) == 0) {
+        *port = ntohs(sa.sin_port);
+    } else {
+        OC_LOG_V(FATAL, MOD_NAME, "getsockname API failed with errno \
+            %s", strerror(errno));
+        ret = ERR_UNKNOWN;
+    }
+    return ret;
+}
index 56f7e8e..4bc94b5 100644 (file)
@@ -261,3 +261,8 @@ int32_t OCDevAddrToPort(OCDevAddr *ipAddr, uint16_t *port)
     return ERR_SUCCESS;
 }
 
+/// Retrieve the port to which socket is bound
+int32_t OCGetSocketInfo(int32_t sockfd, uint16_t *port)
+{
+    return ERR_NOT_IMPLEMENTED;
+}
index eeb5c01..42a5348 100644 (file)
@@ -298,3 +298,9 @@ int32_t OCDevAddrToPort(OCDevAddr *ipAddr, uint16_t *port)
 
     return ERR_SUCCESS;
 }
+
+/// Retrieve the port to which socket is bound
+int32_t OCGetSocketInfo(int32_t sockfd, uint16_t *port)
+{
+    return ERR_NOT_IMPLEMENTED;
+}
index 6cfd318..adf6abc 100644 (file)
@@ -24,10 +24,11 @@ ROOT_DIR = ../../..
 include $(ROOT_DIR)/local.properties
 
 OCSOCK_DIR = $(ROOT_DIR)/ocsocket
+OC_LOG_DIR    = $(ROOT_DIR)/../oc_logger
 LOGGER_DIR = $(ROOT_DIR)/logger
 BIN_DIR = $(OCSOCK_DIR)/bin/linux/
 OBJ_DIR = $(OCSOCK_DIR)/obj/linux/
-INC_DIRS = -I$(OCSOCK_DIR)/include/ -I$(LOGGER_DIR)/include
+INC_DIRS = -I$(OCSOCK_DIR)/include/ -I$(LOGGER_DIR)/include -I$(OC_LOG_DIR)/include
 
 CXX = g++
 CC = gcc
index 25073db..b6c9872 100644 (file)
@@ -286,3 +286,33 @@ TEST(SendToRecvfromMulticast, Positive) {
     OCClose(ssfd);
 }
 
+TEST(GetSocketInfo, Positive) {
+    OCDevAddr ipaddr;
+    int32_t  sockfd;
+    uint8_t addr[20];
+    uint8_t ifname[] = "eth0";
+    uint16_t port;
+    uint8_t a,b,c,d;
+
+    OCBuildIPv4Address(0,0,0,0, 0, &ipaddr);
+    EXPECT_EQ(ERR_SUCCESS, OCInitUDP(&ipaddr, &sockfd));
+    EXPECT_EQ(ERR_SUCCESS, OCGetSocketInfo(sockfd, &port));
+    OC_LOG_V(DEBUG, MOD_NAME, "Port %d", port);
+    OCClose(sockfd);
+
+    OCBuildIPv4Address(0,0,0,0, 5678, &ipaddr);
+    EXPECT_EQ(ERR_SUCCESS, OCInitUDP(&ipaddr, &sockfd));
+    EXPECT_EQ(ERR_SUCCESS, OCGetSocketInfo(sockfd, &port));
+    OC_LOG_V(DEBUG, MOD_NAME, "Port %d", port);
+    EXPECT_TRUE(port == 5678);
+    OCClose(sockfd);
+
+    OCGetInterfaceAddress( ifname, sizeof(ifname),  AF_INET, addr, sizeof(addr));
+    sscanf((const char*)addr, "%d.%d.%d.%d", (int*)&a, (int*)&b, (int*)&c, (int*)&d);
+    OCBuildIPv4Address(a,b,c,d, TEST_PORT_NUM, &ipaddr);
+    EXPECT_EQ(ERR_SUCCESS, OCInitUDP(&ipaddr, &sockfd));
+    EXPECT_EQ(ERR_SUCCESS, OCGetSocketInfo(sockfd, &port));
+    OC_LOG_V(DEBUG, MOD_NAME, "Port %d", port);
+    EXPECT_TRUE(port == TEST_PORT_NUM);
+    OCClose(sockfd);
+}
index 6e538ba..10f7a91 100644 (file)
@@ -33,6 +33,8 @@
 #define OC_RSRVD_INTERFACE_LL           "oc.mi.ll"
 #define OC_RSRVD_INTERFACE_BATCH        "oc.mi.b"
 #define OC_RSRVD_OBSERVABLE             "obs"
+#define OC_RSRVD_SECURE                 "sec"
+#define OC_RSRVD_HOSTING_PORT           "port"
 
 #define OC_JSON_PREFIX                     "{\"oc\":["
 #define OC_JSON_PREFIX_LEN                 (sizeof(OC_JSON_PREFIX) - 1)
@@ -41,6 +43,7 @@
 #define OC_JSON_SEPARATOR                  ','
 
 #define OC_RESOURCE_OBSERVABLE   1
+#define OC_RESOURCE_SECURE       1
 
 typedef enum {
     STACK_RES_DISCOVERY_NOFILTER = 0,
index 8059bc3..0e69b9a 100644 (file)
 #include "ocstack.h"
 #include "logger.h"
 #include "occlientbasicops.h"
+#include "cJSON.h"
 
 #define TAG "occlientbasicops"
 static int UNICAST_DISCOVERY = 0;
 static int TEST_CASE = 0;
 static const char * TEST_APP_UNICAST_DISCOVERY_QUERY = "coap://0.0.0.0:5683/oc/core";
 static std::string putPayload = "{\"state\":\"off\",\"power\":10}";
-static std::string coapServerIP = "255.255.255.255";
-static std::string coapServerPort = "5683";
-static std::string coapServerResource = "/a/led";
+static std::string coapServerIP;
+static std::string coapServerPort;
+static std::string coapServerResource;
+static int coapSecureResource;
 
 int gQuitFlag = 0;
 
@@ -119,23 +121,6 @@ OCStackApplicationResult getReqCB(void* ctx, OCDoHandle handle, OCClientResponse
         OC_LOG_V(INFO, TAG, "JSON = %s =============> Get Response",
                 clientResponse->resJSONPayload);
     }
-    if(clientResponse->rcvdVendorSpecificHeaderOptions &&
-            clientResponse->numRcvdVendorSpecificHeaderOptions)
-    {
-        OC_LOG (INFO, TAG, "Received vendor specific options");
-        uint8_t i = 0;
-        OCHeaderOption * rcvdOptions = clientResponse->rcvdVendorSpecificHeaderOptions;
-        for( i = 0; i < clientResponse->numRcvdVendorSpecificHeaderOptions; i++)
-        {
-            if(((OCHeaderOption)rcvdOptions[i]).protocolID == OC_COAP_ID)
-            {
-                OC_LOG_V(INFO, TAG, "Received option with OC_COAP_ID and ID %u with",
-                        ((OCHeaderOption)rcvdOptions[i]).optionID );
-                OC_LOG_BUFFER(INFO, TAG, ((OCHeaderOption)rcvdOptions[i]).optionData,
-                        ((OCHeaderOption)rcvdOptions[i]).optionLength);
-            }
-        }
-    }
     return OC_STACK_DELETE_TRANSACTION;
 }
 
@@ -161,20 +146,21 @@ OCStackApplicationResult discoveryReqCB(void* ctx, OCDoHandle handle,
                 clientResponse->resJSONPayload, remoteIpAddr[0], remoteIpAddr[1],
                 remoteIpAddr[2], remoteIpAddr[3], remotePortNu);
 
-        parseClientResponse(clientResponse);
-
-        switch(TEST_CASE)
+        if (parseClientResponse(clientResponse) != -1)
         {
-            case TEST_NON_CON_OP:
-                InitGetRequest(OC_LOW_QOS);
-                InitPutRequest();
-                //InitPostRequest(OC_LOW_QOS);
-                break;
-            case TEST_CON_OP:
-                InitGetRequest(OC_HIGH_QOS);
-                InitPutRequest();
-                //InitPostRequest(OC_HIGH_QOS);
-                break;
+            switch(TEST_CASE)
+            {
+                case TEST_NON_CON_OP:
+                    InitGetRequest(OC_LOW_QOS);
+                    InitPutRequest();
+                    //InitPostRequest(OC_LOW_QOS);
+                    break;
+                case TEST_CON_OP:
+                    InitGetRequest(OC_HIGH_QOS);
+                    InitPutRequest();
+                    //InitPostRequest(OC_HIGH_QOS);
+                    break;
+            }
         }
     }
 
@@ -186,7 +172,8 @@ int InitPutRequest()
 {
     OC_LOG_V(INFO, TAG, "\n\nExecuting %s", __func__);
     std::ostringstream query;
-    query << "coaps://" << coapServerIP << ":" << "5684" << coapServerResource;
+    query << (coapSecureResource ? "coaps://" : "coap://") << coapServerIP
+        << ":" << coapServerPort << coapServerResource;
     return (InvokeOCDoResource(query, OC_REST_PUT, OC_LOW_QOS, putReqCB, NULL, 0));
 }
 
@@ -195,7 +182,8 @@ int InitPostRequest(OCQualityOfService qos)
     OCStackResult result;
     OC_LOG_V(INFO, TAG, "\n\nExecuting %s", __func__);
     std::ostringstream query;
-    query << "coaps://" << coapServerIP << ":" << "5684" << coapServerResource;
+    query << (coapSecureResource ? "coaps://" : "coap://") << coapServerIP
+        << ":" << coapServerPort << coapServerResource;
 
     // First POST operation (to create an LED instance)
     result = InvokeOCDoResource(query, OC_REST_POST,
@@ -226,7 +214,8 @@ int InitGetRequest(OCQualityOfService qos)
 {
     OC_LOG_V(INFO, TAG, "\n\nExecuting %s", __func__);
     std::ostringstream query;
-    query << "coaps://" << coapServerIP << ":" << "5684" << coapServerResource;
+    query << (coapSecureResource ? "coaps://" : "coap://") << coapServerIP
+        << ":" << coapServerPort << coapServerResource;
 
     return (InvokeOCDoResource(query, OC_REST_GET, (qos == OC_HIGH_QOS)?
             OC_HIGH_QOS:OC_LOW_QOS, getReqCB, NULL, 0));
@@ -324,7 +313,6 @@ int main(int argc, char* argv[])
         }
 
         nanosleep(&timeout, NULL);
-        //sleep(2);
     }
     OC_LOG(INFO, TAG, "Exiting occlient main loop...");
 
@@ -361,14 +349,77 @@ std::string getPortTBServer(OCClientResponse * clientResponse)
     return ss.str();
 }
 
-std::string getQueryStrForGetPut(OCClientResponse * clientResponse)
+int parseClientResponse(OCClientResponse * clientResponse)
 {
-    return "/a/led";
-}
+    int port = -1;
+    cJSON * root = NULL;
+    cJSON * oc = NULL;
+
+    // Initialize all global variables
+    coapServerResource.clear();
+    coapServerPort.clear();
+    coapServerIP.clear();
+    coapSecureResource = 0;
+
+    root = cJSON_Parse((char *)(clientResponse->resJSONPayload));
+    if (!root)
+    {
+        return -1;
+    }
+
+    oc = cJSON_GetObjectItem(root,"oc");
+    if (!oc)
+    {
+        return -1;
+    }
+
+    if (oc->type == cJSON_Array)
+    {
+        if (cJSON_GetArraySize(oc) > 0)
+        {
+            cJSON * resource = cJSON_GetArrayItem(oc, 0);
+            if (cJSON_GetObjectItem(resource, "href"))
+            {
+                coapServerResource.assign(cJSON_GetObjectItem(resource, "href")->valuestring);
+            }
+            else
+            {
+                coapServerResource = "";
+            }
+            OC_LOG_V(INFO, TAG, "Uri -- %s", coapServerResource.c_str());
+
+            cJSON * prop = cJSON_GetObjectItem(resource,"prop");
+            if (prop)
+            {
+                // If this is a secure resource, the info about the port at which the
+                // resource is hosted on server is embedded inside discovery JSON response
+                if (cJSON_GetObjectItem(prop, "sec"))
+                {
+                    if ((cJSON_GetObjectItem(prop, "sec")->valueint) == 1)
+                    {
+                        coapSecureResource = 1;
+                    }
+                }
+                OC_LOG_V(INFO, TAG, "Secure -- %s", coapSecureResource == 1 ? "YES" : "NO");
+                if (cJSON_GetObjectItem(prop, "port"))
+                {
+                    port = cJSON_GetObjectItem(prop, "port")->valueint;
+                    OC_LOG_V(INFO, TAG, "Hosting Server Port (embedded inside JSON) -- %u", port);
+
+                    std::ostringstream ss;
+                    ss << port;
+                    coapServerPort = ss.str();
+                }
+            }
+        }
+    }
+    cJSON_Delete(root);
 
-void parseClientResponse(OCClientResponse * clientResponse)
-{
     coapServerIP = getIPAddrTBServer(clientResponse);
-    coapServerPort = getPortTBServer(clientResponse);
-    coapServerResource = getQueryStrForGetPut(clientResponse);
+    if (port == -1)
+    {
+        coapServerPort = getPortTBServer(clientResponse);
+        OC_LOG_V(INFO, TAG, "Hosting Server Port -- %s", coapServerPort.c_str());
+    }
+    return 0;
 }
index e8e9307..104e653 100644 (file)
@@ -64,7 +64,7 @@ int InitDiscovery();
 /* Function to retrieve ip address, port no. of the server
  *  and query for the operations to be performed.
  */
-void parseClientResponse(OCClientResponse * clientResponse);
+int parseClientResponse(OCClientResponse * clientResponse);
 
 /* This method calls OCDoResource() which in turn makes calls
  * to the lower layers
@@ -91,3 +91,4 @@ OCStackApplicationResult discoveryReqCB(void* ctx, OCDoHandle handle,
         OCClientResponse * clientResponse);
 
 #endif
+
index ecb4188..7ed8d14 100644 (file)
@@ -251,7 +251,6 @@ int main(int argc, char* argv[])
     uint8_t* paddr = NULL;
     uint16_t port = OC_WELL_KNOWN_PORT;
     uint8_t ifname[] = "eth0";
-    int opt;
     struct timespec timeout;
 
     OC_LOG(DEBUG, TAG, "OCServer is starting...");
index 78821a7..b47d621 100644 (file)
@@ -25,6 +25,7 @@
 #include "ocresource.h"
 #include "ocobserve.h"
 #include "occollection.h"
+#include "occoap.h"
 #include "logger.h"
 #include "debug.h"
 #include "cJSON.h"
@@ -168,6 +169,16 @@ OCStackResult BuildVirtualResourceResponse(OCResource *resourcePtr, uint8_t filt
                 cJSON_AddItemToObject (propObj, OC_RSRVD_OBSERVABLE,
                                        cJSON_CreateNumber(OC_RESOURCE_OBSERVABLE));
             }
+            // Set secure flag for secure resources
+            if (resourcePtr->resourceProperties & OC_SECURE) {
+                uint16_t port;
+                cJSON_AddNumberToObject (propObj, OC_RSRVD_SECURE, OC_RESOURCE_SECURE);
+                //Set the IP port also as secure resources are hosted on a different port
+                if (OCGetResourceEndPointInfo (resourcePtr, &port) == OC_STACK_OK) {
+                    cJSON_AddNumberToObject (propObj, OC_RSRVD_HOSTING_PORT, port);
+                }
+            }
+
         }
     }
     jsonStr = cJSON_PrintUnformatted (resObj);