Support Signaling Message for CoAP over TCP 57/24357/14 1.4.0-RC1
authorHarry <h.marappa@samsung.com>
Tue, 6 Mar 2018 17:43:34 +0000 (23:13 +0530)
committerAshok Babu Channa <ashok.channa@samsung.com>
Sat, 17 Mar 2018 09:27:28 +0000 (09:27 +0000)
Implement signalling messages as per COAP over TCP
spec in RFC 8323

Change-Id: I25baf80c4b4380d1f9f9a8f81281f371927f7ed1
Signed-off-by: Sushil Yadav <sushil.ky@samsung.com>
Signed-off-by: Veeraj Khokale <veeraj.sk@samsung.com>
Signed-off-by: Harry <h.marappa@samsung.com>
16 files changed:
resource/csdk/connectivity/api/cacommon.h
resource/csdk/connectivity/common/inc/caremotehandler.h
resource/csdk/connectivity/common/src/caremotehandler.c
resource/csdk/connectivity/inc/camessagehandler.h
resource/csdk/connectivity/inc/caping.h [new file with mode: 0644]
resource/csdk/connectivity/inc/caprotocolmessage.h
resource/csdk/connectivity/inc/catcpadapter.h
resource/csdk/connectivity/inc/catcpinterface.h
resource/csdk/connectivity/src/SConscript
resource/csdk/connectivity/src/caconnectivitymanager.c
resource/csdk/connectivity/src/camessagehandler.c
resource/csdk/connectivity/src/caping.c [new file with mode: 0644]
resource/csdk/connectivity/src/caprotocolmessage.c
resource/csdk/connectivity/src/tcp_adapter/catcpadapter.c
resource/csdk/connectivity/src/tcp_adapter/catcpserver.c
resource/csdk/stack/src/ocstack.c

index dbc6a6c..e2ea6e8 100644 (file)
@@ -139,6 +139,19 @@ extern "C"
 // The Accept Version and Content-Format Version for OCF 1.0.0 (0b0000 1000 0000 0000).
 #define DEFAULT_VERSION_VALUE 2048
 
+/**
+ * Option numbers for Signaling messages are specific to the message code.
+ * They do not share the number space with CoAP options for request/response
+ * messages or with Signaling messages using other codes.
+ */
+#define CA_OPTION_SERVER_NAME_SETTING 1    /**< Capability and Settings messages, code=7.01 */
+#define CA_OPTION_MAX_MESSAGE_SIZE 2       /**< Capability and Settings messages, code=7.01 */
+#define CA_OPTION_BLOCK_WISE_TRANSFER 4    /**< Capability and Settings messages, code=7.01 */
+#define CA_OPTION_CUSTODY 2                /**< Ping and Pong Messages, code=7.02 */
+#define CA_OPTION_BAD_SERVER_NAME 2        /**< Release Messages, code=7.04 */
+#define CA_OPTION_ALTERNATE_ADDRESS 4      /**< Abort Messages, code=7.05 */
+#define CA_OPTION_HOLD_OFF 6               /**< Abort Messages, code=7.05 */
+
 /**
  * Payload information from resource model.
  */
@@ -359,6 +372,7 @@ typedef enum
     CA_DTLS_AUTHENTICATION_FAILURE, /**< Decryption error in DTLS */
     CA_CONTINUE_OPERATION,          /**< Error happens but current operation should continue */
     CA_HANDLE_ERROR_OTHER_MODULE,   /**< Error happens but it should be handled in other module */
+    CA_STATUS_NOT_FOUND,            /**< Not Found*/
     CA_STATUS_FAILED =255           /**< Failure */
     /* Result code - END HERE */
 } CAResult_t;
@@ -393,6 +407,20 @@ typedef enum
     /* Response status code - END HERE */
 } CAResponseResult_t;
 
+/**
+ * Enums for CA Signaling codes.
+ */
+typedef enum
+{
+    /* Signaling code - START HERE */
+    CA_CSM = 701,                           /**< Capability and Settings messages */
+    CA_PING = 702,                          /**< Ping messages */
+    CA_PONG = 703,                          /**< Pong messages */
+    CA_RELEASE = 704,                       /**< Release messages */
+    CA_ABORT = 705,                         /**< Abort messages */
+    /* Signaling code - END HERE */
+} CASignalingCode_t;
+
 /**
  * Data type whether the data is Request Message or Response Message.
  * if there is some failure before send data on network.
@@ -403,7 +431,8 @@ typedef enum
     CA_REQUEST_DATA = 1,
     CA_RESPONSE_DATA,
     CA_ERROR_DATA,
-    CA_RESPONSE_FOR_RES
+    CA_RESPONSE_FOR_RES,
+    CA_SIGNALING_DATA
 } CADataType_t;
 
 /**
@@ -532,6 +561,17 @@ typedef struct
                              helpful to identify the error */
 } CAErrorInfo_t;
 
+/**
+ * Signaling information received.
+ *
+ * This structure is used to hold signaling information.
+ */
+typedef struct
+{
+    CASignalingCode_t code;
+    CAInfo_t info;              /**< Information of the signaling */
+} CASignalingInfo_t;
+
 /**
  * Hold global variables for CA layer. (also used by RI layer)
  */
index e71d3f6..1d64e3a 100644 (file)
@@ -85,6 +85,13 @@ void CADestroyRequestInfoInternal(CARequestInfo_t *request);
  */
 CAResponseInfo_t *CACloneResponseInfo(const CAResponseInfo_t *response);
 
+/**
+ * Creates a new signaling information.
+ * @param[in]   sig           signaling message information that needs to be duplicated.
+ * @return  duplicated signaling info object.
+ */
+CASignalingInfo_t *CACloneSignalingInfo(const CASignalingInfo_t *sig);
+
 /**
  * Destroy the response information.
  * @param[in]   response           response information that needs to be destroyed.
@@ -97,6 +104,12 @@ void CADestroyResponseInfoInternal(CAResponseInfo_t *response);
  */
 void CADestroyErrorInfoInternal(CAErrorInfo_t *errorInfo);
 
+/**
+ * Free the signaling information.
+ * @param[in]   sig         signaling information to be freed.
+ */
+void CADestroySignalingInfoInternal(CASignalingInfo_t *sig);
+
 #ifdef __cplusplus
 } /* extern "C" */
 #endif
index f72b157..721a1d6 100644 (file)
@@ -151,6 +151,49 @@ CAResponseInfo_t *CACloneResponseInfo(const CAResponseInfo_t *rep)
     return clone;
 }
 
+CASignalingInfo_t *CACloneSignalingInfo(const CASignalingInfo_t *sig)
+{
+    if (NULL == sig)
+    {
+        OIC_LOG(ERROR, TAG, "Singnaling pointer is NULL");
+        return NULL;
+    }
+
+    // check the result value of signaling info.
+    // Keep this check in sync with CASignalingCode_t.
+    switch (sig->code)
+    {
+        case CA_CSM:
+        case CA_PING:
+        case CA_PONG:
+        case CA_RELEASE:
+        case CA_ABORT:
+            break;
+        default:
+            OIC_LOG_V(ERROR, TAG, "Signaling code  %u is invalid", sig->code);
+            return NULL;
+    }
+
+    // allocate the signaling info structure.
+    CASignalingInfo_t *clone = (CASignalingInfo_t *) OICCalloc(1, sizeof(CASignalingInfo_t));
+    if (NULL == clone)
+    {
+        OIC_LOG(ERROR, TAG, "CACloneSignalingInfo Out of memory");
+        return NULL;
+    }
+
+    CAResult_t result = CACloneInfo(&sig->info, &clone->info);
+    if (CA_STATUS_OK != result)
+    {
+        OIC_LOG(ERROR, TAG, "CACloneResponseInfo error in CACloneInfo");
+        CADestroySignalingInfoInternal(clone);
+        return NULL;
+    }
+
+    clone->code = sig->code;
+    return clone;
+}
+
 CAEndpoint_t *CACreateEndpointObject(CATransportFlags_t flags,
                                      CATransportAdapter_t adapter,
                                      const char *address,
@@ -238,6 +281,18 @@ void CADestroyErrorInfoInternal(CAErrorInfo_t *errorInfo)
     OICFree(errorInfo);
 }
 
+void CADestroySignalingInfoInternal(CASignalingInfo_t *sig)
+{
+    if (NULL == sig)
+    {
+        OIC_LOG(ERROR, TAG, "parameter is null");
+        return;
+    }
+
+    CADestroyInfoInternal(&sig->info);
+    OICFree(sig);
+}
+
 CAResult_t CACloneInfo(const CAInfo_t *info, CAInfo_t *clone)
 {
     if (!info || !clone)
index c49e8c9..af85a6d 100644 (file)
@@ -45,6 +45,7 @@ typedef struct
     CARequestInfo_t *requestInfo;
     CAResponseInfo_t *responseInfo;
     CAErrorInfo_t *errorInfo;
+    CASignalingInfo_t *signalingInfo;
     CADataType_t dataType;
 } CAData_t;
 
@@ -97,7 +98,7 @@ void CAHandleRequestResponseCallbacks();
  */
 void CASetNetworkMonitorCallback(CANetworkMonitorCallback nwMonitorHandler);
 
-#ifdef WITH_BWT
+#if defined(WITH_BWT) || defined(TCP_ADAPTER)
 /**
  * Add the data to the send queue thread.
  * @param[in] data    send data.
@@ -111,6 +112,60 @@ void CAAddDataToSendThread(CAData_t *data);
 void CAAddDataToReceiveThread(CAData_t *data);
 #endif
 
+#ifdef TCP_ADAPTER
+/**
+ * Add a header option to the given header option array.
+ * @param[in/out] hdrOpt            Pointer to existing options.
+ * @param[in/out] numOptions        Number of existing options.
+ * @param[in]     optionID          COAP option ID.
+ * @param[in]     optionData        Option data value.
+ * @param[in]     optionDataLength  Size of Option data value.
+ * @return  ::CA_STATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CAAddHeaderOption(CAHeaderOption_t **hdrOpt, uint8_t *numOptions,
+                             uint16_t optionID, void* optionData,
+                             size_t optionDataLength);
+
+/**
+ * Get data value of the option with specified option ID from given header option array.
+ * @param[in] hdrOpt                Pointer to existing options.
+ * @param[in] numOptions            Number of existing options.
+ * @param[in] optionID              COAP option ID.
+ * @param[out] optionData           Pointer to option data.
+ * @param[in] optionDataLength      Size of option data value.
+ * @param[out] receivedDataLen      Pointer to the actual length of received data.
+ * @return  ::CA_STATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CAGetHeaderOption(CAHeaderOption_t *hdrOpt, size_t numOptions, uint16_t optionID,
+                             void *optionData, size_t optionDataLength, uint16_t *receivedDataLen);
+
+/**
+ * Generate signaling message from the given information.
+ * @param[in] endpoint      endpoint information where the data has to be sent.
+ * @param[in] code          signaling code has to be sent.
+ * @param[in] headerOpt     Pointer to existing options.
+ * @param[in] numOptions    Number of existing options.
+ * @return  generated signaling message object.
+ */
+CAData_t *CAGenerateSignalingMessage(const CAEndpoint_t *endpoint, CASignalingCode_t code,
+                                     CAHeaderOption_t *headerOpt, uint8_t numOptions);
+
+/**
+ * Generate signaling message from the given information.
+ * @param[in] endpoint      endpoint information where the data has to be sent.
+ * @param[in] code          signaling code has to be sent.
+ * @param[in] headerOpt     Pointer to existing options.
+ * @param[in] numOptions    Number of existing options.
+ * @param[in] token         The token to be used for the message (required for pong messages)
+ * @param[in] tokenLength   The length of the token
+ * @return  generated signaling message object.
+ */
+CAData_t *CAGenerateSignalingMessageUsingToken(const CAEndpoint_t *endpoint, CASignalingCode_t code,
+                                               CAHeaderOption_t *headerOpt, uint8_t numOptions,
+                                               const CAToken_t token, uint8_t tokenLength);
+
+#endif //TCP_ADAPTER
+
 #ifdef __cplusplus
 } /* extern "C" */
 #endif
diff --git a/resource/csdk/connectivity/inc/caping.h b/resource/csdk/connectivity/inc/caping.h
new file mode 100644 (file)
index 0000000..ff861d1
--- /dev/null
@@ -0,0 +1,110 @@
+/******************************************************************
+ *
+ * Copyright 2017 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 functions for COAP ping and pong over reliable
+ * transports i.e TCP and websocket
+ */
+
+#ifndef CA_PING_H_
+#define CA_PING_H_
+
+#include "cacommon.h"
+
+typedef struct PingInfo_t
+{
+    CAEndpoint_t        endpoint;       // remote endpoint that was pinged
+    bool                withCustody;    // true if ping was sent with custody option
+    CAToken_t           token;          // token used in the ping message
+    uint8_t             tokenLength;    // length of the token
+    uint64_t            timeStamp;      // time stamp at which the ping was sent
+    struct PingInfo_t   *next;          // pointer to next ping info
+} PingInfo;
+
+// Default ping timeout value in ms. Note: RFC 8323 does not specify a default timeout
+#define CA_DEFAULT_PING_TIMEOUT     10000
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/**
+ * Initialize the ping service
+ * @return  ::CA_STATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CAInitializePing();
+
+/**
+ * Send a ping message to the given remote endpoint
+ * @param[in] endpoint    endpoint information where the data has to be sent.
+ * @param[in] withCustody true if the message needs to be sent with custody option
+ * @return  ::CA_STATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CASendPingMessage(const CAEndpoint_t *endpoint, bool withCustody);
+
+/**
+ * Send a pong message to the given remote endpoint
+ * @param[in] endpoint    endpoint information where the data has to be sent.
+ * @param[in] withCustody true if the message needs to be sent with custody option
+ * @param[in] token       The token of the corresponding ping message (per RFC 8323
+ *                        section 5.4 the same token as the ping message should be
+ *                        used for the corresponding pong message)
+ * @param[in] tokenLength length of the token
+ * @return  ::CA_STATUS_OK or ERROR CODES (::CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CASendPongMessage(const CAEndpoint_t *endpoint, bool withCustody,
+                             const CAToken_t token, uint8_t tokenLength);
+
+/**
+ * Checks if the timeout for each ping message has expired and
+ * if so disconnects the corresponding connection since a pong response
+ * was not received in time.
+ */
+void CAProcessPing();
+
+/**
+ * Sets the timeout for a ping message
+ * @param[in] timeout   the timeout for the ping message (in ms). If this
+ *                      method is not invoked to set the timeout then the
+ *                      default timeout CA_DEFAULT_PING_TIMEOUT will be used.
+ */
+void CASetPingTimeout(uint64_t timeout);
+
+/**
+ * Callback that is invoked when a pong message is received by CA layer
+ * It clear the state of the corresponding ping message if it exists
+ * @param[in] endpoint    endpoint information where the data has to be sent.
+ * @param[in] token       The token of the pong message
+ * @param[in] tokenLength length of the token
+ */
+void CAPongReceivedCallback(const CAEndpoint_t *endpoint, const CAToken_t token,
+                            uint8_t tokenLength);
+
+/**
+ * Terminate the ping service
+ */
+void CATerminatePing();
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif /* CA_PING_H_ */
\ No newline at end of file
index 6b2e77b..4991b4c 100644 (file)
@@ -87,6 +87,16 @@ CAResult_t CAGetResponseInfoFromPDU(const coap_pdu_t *pdu, CAResponseInfo_t *out
 CAResult_t CAGetErrorInfoFromPDU(const coap_pdu_t *pdu, const CAEndpoint_t *endpoint,
                                  CAErrorInfo_t *errorInfo);
 
+/**
+ * extracts signaling information from received pdu.
+ * @param[in]   pdu                   received pdu.
+ * @param[in]   endpoint              endpoint information.
+ * @param[out]  outSigInfo            signaling info structure made from received pdu.
+ * @return  CA_STATUS_OK or ERROR CODES (CAResult_t error codes in cacommon.h).
+ */
+CAResult_t CAGetSignalingInfoFromPDU(const coap_pdu_t *pdu, const CAEndpoint_t *endpoint,
+                                     CASignalingInfo_t *outSigInfo);
+
 /**
  * creates pdu from the request information.
  * @param[in]   code                 request or response code.
index 753fff0..8b83907 100644 (file)
@@ -54,6 +54,19 @@ typedef enum
     DISCONNECTED
 } CATCPConnectionState_t;
 
+/**
+ * TCP Capability and Settings message(CSM) exchange state.
+ * Capability and Settings message must be sent
+ * as the first message for both server/client.
+ */
+typedef enum
+{
+    NONE = 0,
+    SENT,
+    RECEIVED,
+    SENT_RECEIVED
+} CACSMExchangeState_t;
+
 /**
  * TCP Session Information for IPv4/IPv6 TCP transport
  */
@@ -68,6 +81,7 @@ typedef struct CATCPSessionInfo_t
     size_t tlsLen;                      /**< received tls data length */
     CAProtocol_t protocol;              /**< application-level protocol */
     CATCPConnectionState_t state;       /**< current tcp session state */
+    CACSMExchangeState_t CSMState;      /**< Capability and Setting Message shared status */
     bool isClient;                      /**< Host Mode of Operation. */
     struct CATCPSessionInfo_t *next;    /**< Linked list; for multiple session list. */
 } CATCPSessionInfo_t;
@@ -100,6 +114,15 @@ CAResult_t CAInitializeTCP(CARegisterConnectivityCallback registerCallback,
  */
 CAResult_t CAStartTCP(void);
 
+/**
+ * Disconnect TCP session.
+ * Per RFC 8323 TCP session needs to be disconnected in certain situations
+ * like if CSM message is not the first message for the session.
+ * @param[in]   endpoint       Remote Endpoint information (like ipaddress,
+ *                             port)
+ */
+CAResult_t CATCPDisconnectSession(const CAEndpoint_t *endpoint);
+
 /**
  * Start listening server for receiving connect requests.
  * Transport Specific Behavior:
@@ -190,6 +213,23 @@ void CATerminateTCP(void);
  */
 void CATCPSetKeepAliveCallbacks(CAKeepAliveConnectionCallback ConnHandler);
 
+/**
+ * Get Capability and Settings message(CSM) exchange state.
+ * @param[in]   endpoint        Remote Endpoint information (like ipaddress,
+ *                              port, reference uri and transport type)
+ *                              to check CSM state in session information.
+ * @return  current CSM exchange state of the session.
+ */
+CACSMExchangeState_t CAGetCSMState(const CAEndpoint_t *endpoint);
+
+/**
+* Update Capability and Settings message(CSM) exchange state when sending or receiving CSM.
+* @param[in]   endpoint        Remote Endpoint information (like ipaddress,
+*                              port, reference uri and transport type) to update CSM state.
+* @param[in]   state           CSM exchange state to be updated.
+*/
+void CAUpdateCSMState(const CAEndpoint_t *endpoint, CACSMExchangeState_t state);
+
 #ifdef __cplusplus
 } /* extern "C" */
 #endif
index 54ef47c..5544657 100644 (file)
@@ -174,6 +174,14 @@ CATCPSessionInfo_t *CAGetTCPSessionInfoFromEndpoint(const CAEndpoint_t *endpoint
  */
 size_t CAGetTotalLengthFromHeader(const unsigned char *recvBuffer);
 
+/**
+ * Get code from CoAP over TCP header.
+ *
+ * @param[in]   recvBuffer    received header data.
+ * @return  method/response code
+ */
+uint32_t CAGetCodeFromHeader(const unsigned char *recvBuffer);
+
 /**
  * Get socket file descriptor from remote device information.
  *
index e3af45a..b249cb3 100644 (file)
@@ -94,6 +94,9 @@ src_files.extend([File(src) for src in (
     'caretransmission.c',
 )])
 
+if  with_tcp:
+    src_files.append(File('caping.c'))
+
 if (('IP' in ca_transport) or ('ALL' in ca_transport)):
     src_files.append(File('cablockwisetransfer.c'))
 
index 3f49c30..211ea8d 100644 (file)
@@ -316,9 +316,6 @@ static CAResult_t CASendMessageMultiAdapter(const CAEndpoint_t *object, const vo
 #endif
 #ifdef RA_ADAPTER
             ,CA_ADAPTER_REMOTE_ACCESS
-#endif
-#ifdef TCP_ADAPTER
-            ,CA_ADAPTER_TCP
 #endif
         };
 
index f450756..1eb7f14 100644 (file)
@@ -22,6 +22,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <stdint.h>
+#include <limits.h>
 
 #include "cainterface.h"
 #include "camessagehandler.h"
 #include "cainterfacecontroller.h"
 #include "caretransmission.h"
 #include "oic_string.h"
+#include "caping.h"
 
 #ifdef WITH_BWT
 #include "cablockwisetransfer.h"
 #endif
 
+#ifdef TCP_ADAPTER
+#include "catcpadapter.h"
+#endif
+
 #include "uqueue.h"
 #include "cathreadpool.h" /* for thread pool */
 #include "caqueueingthread.h"
@@ -94,7 +100,7 @@ static bool CADropSecondMessage(CAHistory_t *history, const CAEndpoint_t *endpoi
  */
 static void CALogPDUInfo(const CAData_t *data, const coap_pdu_t *pdu);
 
-#ifdef WITH_BWT
+#if defined(WITH_BWT) || defined(TCP_ADAPTER)
 void CAAddDataToSendThread(CAData_t *data)
 {
     VERIFY_NON_NULL_VOID(data, TAG, "data");
@@ -235,6 +241,50 @@ static CAData_t* CAGenerateHandlerData(const CAEndpoint_t *endpoint,
         OIC_LOG(DEBUG, TAG, "error Info :");
         CALogPayloadInfo(info);
     }
+#ifdef TCP_ADAPTER
+    else if (CA_SIGNALING_DATA == dataType)
+    {
+        CASignalingInfo_t *signalingInfo =
+                (CASignalingInfo_t *)OICCalloc(1, sizeof (CASignalingInfo_t));
+        if (!signalingInfo)
+        {
+            OIC_LOG(ERROR, TAG, "Memory allocation failed!");
+            goto exit;
+        }
+
+        CAResult_t result = CAGetSignalingInfoFromPDU(data, endpoint, signalingInfo);
+        if (CA_STATUS_OK != result)
+        {
+            OIC_LOG(ERROR, TAG, "CAGetSignalingInfoFromPDU failed");
+            CADestroySignalingInfoInternal(signalingInfo);
+            goto exit;
+        }
+
+        cadata->signalingInfo = signalingInfo;
+        info = &signalingInfo->info;
+        if (identity)
+        {
+            info->identity = *identity;
+        }
+        OIC_LOG(DEBUG, TAG, "Signaling Info :");
+        CALogPayloadInfo(info);
+
+        // Get CA_OPTION_MAX_MESSAGE_SIZE from pdu.
+        unsigned char optionData[CA_MAX_HEADER_OPTION_DATA_LENGTH];
+        size_t optionDataSize = sizeof(optionData);
+        uint16_t receivedDataLength = 0;
+
+        // TODO: We need to decide what options needs to be handled and which needs to be ignored.
+        if(CAGetHeaderOption(info->options, info->numOptions, CA_OPTION_MAX_MESSAGE_SIZE,
+                    optionData, optionDataSize, &receivedDataLength) == CA_STATUS_OK && receivedDataLength) {
+            unsigned int maxMsgSize = (unsigned int) coap_decode_var_bytes(optionData, receivedDataLength);
+            OIC_LOG_V(DEBUG, TAG, "received MAX_MESSAGE_SIZE option data: %u", maxMsgSize);
+            if(maxMsgSize > 1152){
+                //TODO: Change the TCP sockets parameters for maxMsgSize > 1152
+            }
+        }
+    }
+#endif
 
     cadata->remoteEndpoint = ep;
     cadata->dataType = dataType;
@@ -345,6 +395,13 @@ static void CADestroyData(void *data, uint32_t size)
         CADestroyErrorInfoInternal(cadata->errorInfo);
     }
 
+#ifdef TCP_ADAPTER
+    if (NULL != cadata->signalingInfo)
+    {
+        CADestroySignalingInfoInternal(cadata->signalingInfo);
+    }
+#endif
+
     OICFree(cadata);
     OIC_LOG(DEBUG, TAG, "CADestroyData OUT");
 }
@@ -484,6 +541,18 @@ static CAResult_t CAProcessSendData(const CAData_t *data)
             pdu = CAGeneratePDU(data->responseInfo->result, info, data->remoteEndpoint,
                                 &options, &transport);
         }
+#ifdef TCP_ADAPTER
+        else if (NULL != data->signalingInfo)
+        {
+            OIC_LOG(DEBUG, TAG, "signalingInfo is available..");
+            info = &data->signalingInfo->info;
+#ifdef ROUTING_GATEWAY
+            skipRetransmission = data->signalingInfo->info.skipRetransmission;
+#endif
+            pdu = CAGeneratePDU(data->signalingInfo->code, info, data->remoteEndpoint,
+                                &options, &transport);
+        }
+#endif
         else
         {
             OIC_LOG(DEBUG, TAG, "request info, response info is empty");
@@ -690,6 +759,19 @@ static void CAReceivedPacketCallback(const CASecureEndpoint_t *sep,
     }
 
     OIC_LOG_V(DEBUG, TAG, "code = %d", code);
+
+#ifdef TCP_ADAPTER
+    if (CA_ADAPTER_TCP == sep->endpoint.adapter && CA_CSM != code)
+    {
+        CACSMExchangeState_t csmState = CAGetCSMState(&sep->endpoint);
+        if (csmState != RECEIVED && csmState != SENT_RECEIVED)
+        {
+            CATCPDisconnectSession(&sep->endpoint);
+            OIC_LOG(ERROR, TAG, "CAReceivedPacketCallback, first message is not a CSM!!");
+        }
+    }
+#endif
+
     if (CA_GET == code || CA_POST == code || CA_PUT == code || CA_DELETE == code)
     {
         cadata = CAGenerateHandlerData(&(sep->endpoint), &(sep->identity), pdu, CA_REQUEST_DATA);
@@ -702,6 +784,51 @@ static void CAReceivedPacketCallback(const CASecureEndpoint_t *sep,
     }
     else
     {
+#ifdef TCP_ADAPTER
+        // This is signaling message.
+        if (CA_ADAPTER_TCP == sep->endpoint.adapter &&
+                (CA_CSM == code || CA_PING == code || CA_PONG == code
+                        || CA_RELEASE == code || CA_ABORT == code))
+        {
+            cadata = CAGenerateHandlerData(&(sep->endpoint), &(sep->identity),
+                                           pdu, CA_SIGNALING_DATA);
+            if (!cadata)
+            {
+                OIC_LOG(ERROR, TAG, "CAReceivedPacketCallback, CAGenerateHandlerData failed!");
+                coap_delete_pdu(pdu);
+                return;
+            }
+
+            // Received signaling message is CSM.
+            if (CA_CSM == code)
+            {
+                OIC_LOG_V(DEBUG, TAG, "CAReceivedPacketCallback, CSM received");
+                // update session info of tcp_adapter.
+                // TODO check if it is a valid CSM, if it is not valid message disconnect the session.
+                CACSMExchangeState_t csmState = CAGetCSMState(&sep->endpoint);
+                if (csmState == NONE)
+                {
+                    CAUpdateCSMState(&sep->endpoint,RECEIVED);
+                }
+                else if (csmState == SENT)
+                {
+                    CAUpdateCSMState(&sep->endpoint,SENT_RECEIVED);
+                }
+            }
+            else if (CA_PING == code)
+            {
+                CASendPongMessage(cadata->remoteEndpoint, false, cadata->signalingInfo->info.token,
+                                  cadata->signalingInfo->info.tokenLength);
+            }
+            else if(CA_PONG == code)
+            {
+                CAPongReceivedCallback(cadata->remoteEndpoint, cadata->signalingInfo->info.token,
+                                       cadata->signalingInfo->info.tokenLength);
+            }
+            return;
+        }
+#endif
+
         cadata = CAGenerateHandlerData(&(sep->endpoint), &(sep->identity), pdu, CA_RESPONSE_DATA);
         if (!cadata)
         {
@@ -855,6 +982,20 @@ static CAData_t* CAPrepareSendData(const CAEndpoint_t *endpoint, const void *sen
         cadata->type = response->isMulticast ? SEND_TYPE_MULTICAST : SEND_TYPE_UNICAST;
         cadata->responseInfo = response;
     }
+#ifdef TCP_ADAPTER
+    else if (CA_SIGNALING_DATA == dataType)
+    {
+        // clone signaling info
+        CASignalingInfo_t *signaling = CACloneSignalingInfo((CASignalingInfo_t *) sendData);
+        if (!signaling)
+        {
+            OIC_LOG(ERROR, TAG, "CACloneSignalingInfo failed");
+            goto exit;
+        }
+        cadata->type = SEND_TYPE_UNICAST;
+        cadata->signalingInfo = signaling;
+    }
+#endif
     else
     {
         OIC_LOG(ERROR, TAG, "CAPrepareSendData unknown data type");
@@ -887,7 +1028,44 @@ CAResult_t CADetachSendMessage(const CAEndpoint_t *endpoint, const void *sendMsg
         return CA_STATUS_FAILED;
     }
 
-    CAData_t *data = CAPrepareSendData(endpoint, sendMsg, dataType);
+    CAData_t *data = NULL;
+#ifdef TCP_ADAPTER
+    if (CA_ADAPTER_TCP == endpoint->adapter)
+    {
+        // #1. Try to find session info from tcp_adapter.
+        CACSMExchangeState_t CSMstate = CAGetCSMState(endpoint);
+        if (CSMstate != SENT && CSMstate != SENT_RECEIVED)
+        {
+            // #2. Generate CSM message
+            OIC_LOG_V(DEBUG, TAG, "Generate CSM message for [%s:%d]",
+                      endpoint->addr, endpoint->port);
+
+            // TODO: We need to decide what options needs to be sent Initially?
+            //       Right now we're sending CA_OPTION_MAX_MESSAGE_SIZE as 1152,
+            //       which is default according to the RFC.
+            uint8_t numOptions = 0;
+            CAHeaderOption_t *csmOpts = NULL;
+            unsigned int maxMsgSize = 1152;
+            unsigned char optionData[CA_MAX_HEADER_OPTION_DATA_LENGTH] = { 0 };
+            size_t optionDataLength = coap_encode_var_bytes(optionData, maxMsgSize);
+            CAAddHeaderOption(&csmOpts, &numOptions, CA_OPTION_MAX_MESSAGE_SIZE,
+                              optionData, optionDataLength);
+
+            data = CAGenerateSignalingMessage(endpoint, CA_CSM, csmOpts, numOptions);
+            if (!data)
+            {
+                OIC_LOG(ERROR, TAG, "GenerateSignalingMessage failed");
+                return CA_MEMORY_ALLOC_FAILED;
+            }
+            OICFree(csmOpts);
+
+            // #3. Add pdu to send queue.
+            CAQueueingThreadAddData(&g_sendThread, data, sizeof(CAData_t));
+        }
+    }
+#endif
+
+    data = CAPrepareSendData(endpoint, sendMsg, dataType);
     if(!data)
     {
         OIC_LOG(ERROR, TAG, "CAPrepareSendData failed");
@@ -1356,3 +1534,112 @@ static void CALogPDUInfo(const CAData_t *data, const coap_pdu_t *pdu)
     OIC_LOG(DEBUG, ANALYZER_TAG, "=================================================");
     OIC_TRACE_END();
 }
+
+#ifdef TCP_ADAPTER
+CAResult_t CAAddHeaderOption(CAHeaderOption_t **hdrOpt, uint8_t *numOptions,
+                             uint16_t optionID, void *optionData, size_t optionDataLength)
+{
+    OIC_LOG_V(DEBUG, TAG, "Entering CAAddHeaderOption with optionID: %d", optionID);
+
+    VERIFY_NON_NULL(hdrOpt, TAG, "hdrOpt");
+    VERIFY_NON_NULL(numOptions, TAG, "numOptions");
+    VERIFY_NON_NULL(optionData, TAG, "optionData");
+
+    CAHeaderOption_t *tmpOpt = OICRealloc(*hdrOpt, (*numOptions + 1) * sizeof(CAHeaderOption_t));
+    if (!tmpOpt)
+    {
+        OIC_LOG(ERROR, TAG, "out of memory");
+        return CA_MEMORY_ALLOC_FAILED;
+    }
+
+    tmpOpt[*numOptions].protocolID = CA_COAP_ID;
+    tmpOpt[*numOptions].optionID = optionID;
+    tmpOpt[*numOptions].optionLength = (uint16_t)optionDataLength;
+
+    if (optionData)
+    {
+        memcpy(tmpOpt[*numOptions].optionData, optionData,
+               sizeof(tmpOpt[*numOptions].optionData));
+    }
+
+    // increase the number of options.
+    *numOptions += 1;
+    *hdrOpt = tmpOpt;
+
+    OIC_LOG(DEBUG, TAG, "Added option successfully");
+    return CA_STATUS_OK;
+}
+
+CAResult_t CAGetHeaderOption(CAHeaderOption_t *hdrOpt, size_t numOptions, uint16_t optionID,
+                             void *optionData, size_t optionDataLength, uint16_t *receivedDataLen)
+{
+    OIC_LOG_V(DEBUG, TAG, "Entering CAGetHeaderOption with optionID: %d", optionID);
+
+    VERIFY_NON_NULL(hdrOpt, TAG, "hdrOpt");
+    VERIFY_NON_NULL(optionData, TAG, "optionData");
+    VERIFY_NON_NULL(receivedDataLen, TAG, "receivedDataLen");
+
+    for (size_t i = 0; i < numOptions; i++)
+    {
+        if (hdrOpt[i].optionID == optionID)
+        {
+            if (optionDataLength >= hdrOpt[i].optionLength)
+            {
+                memcpy(optionData, hdrOpt[i].optionData, hdrOpt[i].optionLength);
+                *receivedDataLen = hdrOpt[i].optionLength;
+                return CA_STATUS_OK;
+            }
+        }
+    }
+
+    return CA_STATUS_NOT_FOUND;
+}
+
+CAData_t *CAGenerateSignalingMessage(const CAEndpoint_t *endpoint, CASignalingCode_t code,
+                                     CAHeaderOption_t *headerOpt, uint8_t numOptions)
+{
+    OIC_LOG(DEBUG, TAG, "GenerateSignalingMessage - IN");
+
+    // create token for signaling message.
+    CAToken_t token = NULL;
+    uint8_t tokenLength = CA_MAX_TOKEN_LEN;
+    if (CA_STATUS_OK != CAGenerateTokenInternal(&token, tokenLength))
+    {
+        OIC_LOG(ERROR, TAG, "CAGenerateTokenInternal failed");
+        return NULL;
+    }
+
+    CAInfo_t signalingData = { .type = CA_MSG_NONCONFIRM,
+                               .token = token,
+                               .tokenLength = tokenLength,
+                               .numOptions = numOptions,
+                               .options = headerOpt };
+
+    CASignalingInfo_t sigMsg = { .code = code,
+                                 .info = signalingData };
+
+    return CAPrepareSendData(endpoint, &sigMsg, CA_SIGNALING_DATA);
+}
+
+CAData_t *CAGenerateSignalingMessageUsingToken(const CAEndpoint_t *endpoint, CASignalingCode_t code,
+                                               CAHeaderOption_t *headerOpt, uint8_t numOptions,
+                                               const CAToken_t pingToken, uint8_t pingTokenLength)
+{
+    OIC_LOG(DEBUG, TAG, "GenerateSignalingMessage - IN");
+
+    // create token for signaling message.
+    CAToken_t token = (char *)OICCalloc(pingTokenLength + 1, sizeof(char));
+    OICStrcpy(token, pingTokenLength, pingToken);
+
+    CAInfo_t signalingData = { .type = CA_MSG_NONCONFIRM,
+                               .token = token,
+                               .tokenLength = pingTokenLength,
+                               .numOptions = numOptions,
+                               .options = headerOpt };
+
+    CASignalingInfo_t sigMsg = { .code = code,
+                                 .info = signalingData };
+
+    return CAPrepareSendData(endpoint, &sigMsg, CA_SIGNALING_DATA);
+}
+#endif //TCP_ADAPTER
diff --git a/resource/csdk/connectivity/src/caping.c b/resource/csdk/connectivity/src/caping.c
new file mode 100644 (file)
index 0000000..92e0d50
--- /dev/null
@@ -0,0 +1,218 @@
+/******************************************************************
+ *
+ * Copyright 2017 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 implementation for the COAP ping and pong messages
+ * over reliable transports like TCP and websockets.
+ */
+
+#include "caping.h"
+#include "camessagehandler.h"
+#include "octhread.h"
+#include "oic_malloc.h"
+#include "experimental/logger.h"
+#include "oic_time.h"
+#include "oic_string.h"
+#include "catcpadapter.h"
+
+#define TAG "OIC_CA_PING"
+
+/**
+ * List to hold the ping information
+ */
+static PingInfo *g_pingInfoList = NULL;
+
+/**
+ * Mutex to synchronize access to the ping information list
+ */
+static oc_mutex g_pingInfoListMutex = NULL;
+
+/**
+ * Timeout for ping messages
+ */
+static uint64_t g_timeout = CA_DEFAULT_PING_TIMEOUT;
+
+CAResult_t CAInitializePing()
+{
+    OIC_LOG(DEBUG, TAG, "CAInitializePing IN");
+
+    g_pingInfoListMutex = oc_mutex_new();
+    if (!g_pingInfoListMutex)
+    {
+        OIC_LOG(ERROR, TAG, "Could not create mutex");
+        return CA_STATUS_FAILED;
+    }
+
+    OIC_LOG(DEBUG, TAG, "CAInitializePing OUT");
+    return CA_STATUS_OK;
+}
+
+CAResult_t CASendPingMessage(const CAEndpoint_t *endpoint, bool withCustody)
+{
+    OIC_LOG(DEBUG, TAG, "CASendPingMessage IN");
+
+    // Check if ping message has already been sent to this endpoint
+    oc_mutex_lock(g_pingInfoListMutex);
+    PingInfo *cur = g_pingInfoList;
+    while (cur)
+    {
+        if (!strcmp(cur->endpoint.addr, endpoint->addr))
+        {
+            OIC_LOG_V(ERROR, TAG, "Ping already sent to [%s]", cur->endpoint.addr);
+            return CA_STATUS_FAILED;
+        }
+    }
+    oc_mutex_unlock(g_pingInfoListMutex);
+
+    cur = (PingInfo*)OICMalloc(sizeof(PingInfo));
+    if (!cur)
+    {
+        OIC_LOG(ERROR, TAG, "Could not allocate memory for ping info");
+        return CA_MEMORY_ALLOC_FAILED;
+    }
+
+    // Generate ping message and add to send thread
+    // TODO: Implement ping message with custody option
+    CAData_t *data = CAGenerateSignalingMessage(endpoint, CA_PING, NULL, 0);
+    if (!data)
+    {
+        OICFree(cur);
+        OIC_LOG(ERROR, TAG, "Could not generate signaling message");
+        return CA_STATUS_FAILED;
+    }
+    CAAddDataToSendThread(data);
+
+    // Setup ping info and add to the beginning of the ping list,
+    // which ensures that the ping messages are reverse sorted
+    // according to the timestamp
+    cur->endpoint = *endpoint;
+    cur->withCustody = withCustody;
+    OICStrcpy(cur->token, data->signalingInfo->info.tokenLength, data->signalingInfo->info.token);
+    cur->timeStamp = OICGetCurrentTime(TIME_IN_MS);
+    oc_mutex_lock(g_pingInfoListMutex);
+    cur->next = g_pingInfoList;
+    g_pingInfoList = cur;
+    oc_mutex_unlock(g_pingInfoListMutex);
+
+    OIC_LOG(DEBUG, TAG, "CASendPingMessage OUT");
+    return CA_STATUS_OK;
+}
+
+CAResult_t CASendPongMessage(const CAEndpoint_t *endpoint, bool withCustody,
+                             const CAToken_t token, uint8_t tokenLength)
+{
+    (void) withCustody;
+    OIC_LOG(DEBUG, TAG, "CASendPongMessage IN");
+
+    // Generate pong message and add to send thread
+    // TODO: Implement pong message with custody option
+    CAData_t *data = CAGenerateSignalingMessageUsingToken(endpoint, CA_PONG, NULL,
+                                                          0, token, tokenLength);
+    if (!data)
+    {
+        OIC_LOG(ERROR, TAG, "Could not generate signaling message");
+        return CA_STATUS_FAILED;
+    }
+    CAAddDataToSendThread(data);
+
+    OIC_LOG(DEBUG, TAG, "CASendPongMessage OUT");
+    return CA_STATUS_OK;
+}
+
+void CASetPingTimeout(uint64_t timeout)
+{
+    OIC_LOG_V(DEBUG, TAG, "CASetPingTimeout called with timeout=%"PRIu64, timeout);
+    g_timeout = timeout;
+}
+
+void CAProcessPing()
+{
+    oc_mutex_lock(g_pingInfoListMutex);
+    PingInfo **cur = &g_pingInfoList;
+    PingInfo *del = NULL;
+    uint64_t curTime = OICGetCurrentTime(TIME_IN_MS);
+
+    // Find the first message whose timeout has expired and
+    // since the list is reverse sorted, all ping messages
+    // after this would have also have expired
+    while (*cur && (*cur)->timeStamp + g_timeout > curTime)
+    {
+        cur = &((*cur)->next);
+    }
+    del = *cur;
+    *cur = NULL;
+    while (del)
+    {
+        // Disconnect the session since timeout has expired
+        PingInfo *tmp = del;
+        del = del->next;
+        CATCPDisconnectSession(&tmp->endpoint);
+        OICFree(tmp);
+    }
+    oc_mutex_unlock(g_pingInfoListMutex);
+}
+
+void CAPongReceivedCallback(const CAEndpoint_t *endpoint, const CAToken_t token, uint8_t tokenLength)
+{
+    OIC_LOG(DEBUG, TAG, "CAPongReceivedCallback IN");
+
+    // Remove corresponding ping message from the ping info list.
+    // Both the pong message's endpoint address and the token
+    // should match with that of the ping message.
+    oc_mutex_lock(g_pingInfoListMutex);
+    PingInfo **cur = &g_pingInfoList;
+    PingInfo *del = NULL;
+    while (*cur)
+    {
+        if (!strcmp((*cur)->endpoint.addr, endpoint->addr) &&
+            !strncmp((*cur)->token, token, tokenLength))
+        {
+            del = *cur;
+            *cur = del->next;
+            OICFree(del);
+            break;
+        }
+        cur = &((*cur)->next);
+    }
+    oc_mutex_unlock(g_pingInfoListMutex);
+
+    OIC_LOG(DEBUG, TAG, "CAPongReceivedCallback OUT");
+}
+
+void CATerminatePing()
+{
+    OIC_LOG(DEBUG, TAG, "CATerminatePing IN");
+
+    // Destroy the ping info list
+    oc_mutex_lock(g_pingInfoListMutex);
+    PingInfo *cur = g_pingInfoList;
+    PingInfo *del = NULL;
+    while (cur)
+    {
+        del = cur;
+        cur = cur->next;
+        OICFree(del);
+    }
+    oc_mutex_unlock(g_pingInfoListMutex);
+
+    oc_mutex_free(g_pingInfoListMutex);
+
+    OIC_LOG(DEBUG, TAG, "CATerminatePing OUT");
+}
\ No newline at end of file
index b362d03..df98894 100644 (file)
@@ -98,6 +98,20 @@ CAResult_t CAGetErrorInfoFromPDU(const coap_pdu_t *pdu, const CAEndpoint_t *endp
     return ret;
 }
 
+CAResult_t CAGetSignalingInfoFromPDU(const coap_pdu_t *pdu, const CAEndpoint_t *endpoint,
+                                     CASignalingInfo_t *outSigInfo)
+{
+    VERIFY_NON_NULL(pdu, TAG, "pdu");
+    VERIFY_NON_NULL(endpoint, TAG, "endpoint");
+    VERIFY_NON_NULL(outSigInfo, TAG, "outSigInfo");
+
+    uint32_t code = CA_NOT_FOUND;
+    CAResult_t ret = CAGetInfoFromPDU(pdu, endpoint, &code, &(outSigInfo->info));
+    outSigInfo->code = code;
+
+    return ret;
+}
+
 coap_pdu_t *CAGeneratePDU(uint32_t code, const CAInfo_t *info, const CAEndpoint_t *endpoint,
                           coap_list_t **optlist, coap_transport_t *transport)
 {
index adc070e..ab8b96d 100644 (file)
@@ -407,6 +407,26 @@ CAResult_t CAStartTCP()
     return CA_STATUS_OK;
 }
 
+CAResult_t CATCPDisconnectSession(const CAEndpoint_t *endpoint)
+{
+    CAResult_t res = CA_STATUS_OK;
+#ifdef __WITH_TLS__
+    res = CAcloseSslConnection(endpoint);
+    if (CA_STATUS_OK != res)
+    {
+        OIC_LOG(ERROR, TAG, "failed to close TLS session");
+    }
+#endif
+
+    res = CASearchAndDeleteTCPSession(endpoint);
+    if (CA_STATUS_OK != res)
+    {
+        OIC_LOG(ERROR, TAG, "failed to close TCP session");
+    }
+
+    return res;
+}
+
 CAResult_t CAStartTCPListeningServer()
 {
     if (!caglobals.server)
@@ -590,11 +610,27 @@ void CATCPSendDataThread(void *threadData)
                     OIC_LOG(ERROR, TAG, "CAAdapterNetDtlsEncrypt failed!");
                     CASearchAndDeleteTCPSession(tcpData->remoteEndpoint);
                     CATCPErrorHandler(tcpData->remoteEndpoint, tcpData->data, tcpData->dataLen,
-                                      CA_SEND_FAILED);
+                            CA_SEND_FAILED);
+                }
+
+                // if capability and settings message sent successfully update csm state.
+                if (CAGetCodeFromHeader(tcpData->data) == CA_CSM)
+                {
+                    OIC_LOG(DEBUG, TAG, "CSM sent successfully.");
+                    CACSMExchangeState_t csmState = CAGetCSMState(tcpData->remoteEndpoint);
+                    if (csmState == NONE)
+                    {
+                        CAUpdateCSMState(tcpData->remoteEndpoint, SENT);
+                    }
+                    else if (csmState == RECEIVED)
+                    {
+                        CAUpdateCSMState(tcpData->remoteEndpoint, SENT_RECEIVED);
+                    }
                 }
+
                 OIC_LOG_V(DEBUG, TAG,
-                          "CAAdapterNetDtlsEncrypt returned with result[%d]", result);
-               return;
+                        "CAAdapterNetDtlsEncrypt returned with result[%d]", result);
+                return;
             }
 #endif
         }
@@ -608,6 +644,20 @@ void CATCPSendDataThread(void *threadData)
             CATCPErrorHandler(tcpData->remoteEndpoint, tcpData->data, tcpData->dataLen,
                               CA_SEND_FAILED);
         }
+         // if capability and settings message sent successfully update csm state.
+         else if (CAGetCodeFromHeader(tcpData->data) == CA_CSM)
+         {
+             OIC_LOG(DEBUG, TAG, "CSM sent successfully.");
+             CACSMExchangeState_t csmState = CAGetCSMState(tcpData->remoteEndpoint);
+             if (csmState == NONE)
+             {
+                 CAUpdateCSMState(tcpData->remoteEndpoint, SENT);
+             }
+             else if (csmState == RECEIVED)
+             {
+                 CAUpdateCSMState(tcpData->remoteEndpoint, SENT_RECEIVED);
+             }
+         }
     }
 }
 
index 0cdfd57..52a58f7 100644 (file)
@@ -160,6 +160,12 @@ do \
         FD_SET(caglobals.tcp.TYPE.fd, FDS); \
     }
 
+#define CA_TCP_RESPONSE_CLASS(C) (((C) >> 5)*100)
+
+#define CA_TCP_RESPONSE_CODE(C) \
+    (CA_TCP_RESPONSE_CLASS(C) \
+            + (C - COAP_RESPONSE_CODE(CA_TCP_RESPONSE_CLASS(C))))
+
 static void CATCPDestroyMutex(void)
 {
     if (g_mutexObjectList)
@@ -1619,7 +1625,52 @@ size_t CAGetTotalLengthFromHeader(const unsigned char *recvBuffer)
     return headerLen + optPaylaodLen;
 }
 
+uint32_t CAGetCodeFromHeader(const unsigned char *recvBuffer)
+{
+    OIC_LOG(DEBUG, TAG, "IN - CAGetCodeFromHeader");
+
+    coap_transport_t transport = coap_get_tcp_header_type_from_initbyte(
+                ((unsigned char *)recvBuffer)[0] >> 4);
+    size_t headerLen = coap_get_tcp_header_length_for_transport(transport);
+    uint32_t code = CA_TCP_RESPONSE_CODE(recvBuffer[headerLen -1]);
+
+    OIC_LOG_V(DEBUG, TAG, "header length [%zu]", headerLen);
+    OIC_LOG_V(DEBUG, TAG, "code [%d]", code);
+
+    OIC_LOG(DEBUG, TAG, "OUT - CAGetCodeFromHeader");
+    return code;
+}
+
 void CATCPSetErrorHandler(CATCPErrorHandleCallback errorHandleCallback)
 {
     g_tcpErrorHandler = errorHandleCallback;
 }
+
+CACSMExchangeState_t CAGetCSMState(const CAEndpoint_t *endpoint)
+{
+    oc_mutex_lock(g_mutexObjectList);
+
+    CACSMExchangeState_t csmState = NONE;
+    CATCPSessionInfo_t *svritem = CAGetTCPSessionInfoFromEndpoint(endpoint);
+    if (svritem)
+    {
+        csmState = svritem->CSMState;
+    }
+
+    oc_mutex_unlock(g_mutexObjectList);
+    return csmState;
+}
+
+void CAUpdateCSMState(const CAEndpoint_t *endpoint, CACSMExchangeState_t state)
+{
+    oc_mutex_lock(g_mutexObjectList);
+
+    CATCPSessionInfo_t *svritem = CAGetTCPSessionInfoFromEndpoint(endpoint);
+    if (svritem)
+    {
+        svritem->CSMState = state;
+    }
+
+    oc_mutex_unlock(g_mutexObjectList);
+    return;
+}
index bb67a1e..e675c91 100644 (file)
@@ -72,6 +72,7 @@
 #include "ocatomic.h"
 #include "platform_features.h"
 #include "oic_platform.h"
+#include "caping.h"
 
 #ifdef UWP_APP
 #include "ocsqlite3helper.h"
@@ -2812,6 +2813,7 @@ OCStackResult OCInitializeInternal(OCMode mode, OCTransportFlags serverFlags,
     if (result == OC_STACK_OK)
     {
         result = InitializeKeepAlive(myStackMode);
+        result = CAInitializePing();
     }
 #endif
 
@@ -2885,6 +2887,7 @@ OCStackResult OCDeInitializeInternal(void)
 
 #ifdef TCP_ADAPTER
     TerminateKeepAlive(myStackMode);
+    CATerminatePing();
 #endif
 
     OCStackResult result = CAResultToOCResult(
@@ -3958,6 +3961,7 @@ OCStackResult OC_CALL OCProcess(void)
 
 #ifdef TCP_ADAPTER
     ProcessKeepAlive();
+    CAProcessPing();
 #endif
     return OC_STACK_OK;
 }