Commit 7907823a authored by Harry's avatar Harry Committed by Ashok Babu Channa

Support Signaling Message for CoAP over TCP

Implement signalling messages as per COAP over TCP
spec in RFC 8323

Change-Id: I25baf80c4b4380d1f9f9a8f81281f371927f7ed1
Signed-off-by: default avatarSushil Yadav <sushil.ky@samsung.com>
Signed-off-by: default avatarVeeraj Khokale <veeraj.sk@samsung.com>
Signed-off-by: default avatarHarry <h.marappa@samsung.com>
parent db6c1199
......@@ -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)
*/
......
......@@ -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
......
......@@ -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)
......
......@@ -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
......
/******************************************************************
*
* 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
......@@ -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.
......
......@@ -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
......
......@@ -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.
*
......
......@@ -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'))
......
......@@ -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
};
......
......@@ -22,6 +22,7 @@
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <limits.h>
#include "cainterface.h"
#include "camessagehandler.h"
......@@ -38,11 +39,16 @@
#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.