Cloud Interface Feature base on CoAP over TCP in CA Layer
authorjihwan.seo <jihwan.seo@samsung.com>
Tue, 15 Sep 2015 16:16:13 +0000 (01:16 +0900)
committerPatrick Lankswert <patrick.lankswert@intel.com>
Wed, 16 Sep 2015 19:39:18 +0000 (19:39 +0000)
- modified libcoap library to support coap over tcp
- added new transport adapter and flag in CA
- linux platform can be supported
- TLS, IPv6, Keep alive and so on will be support 2nd phase
- https://wiki.iotivity.org/proposal_for_cloud_interface_in_iotivity

Change-Id: Ifcc0f78c1a5ca9d11e41498f712c0039213bd3d0
Signed-off-by: hyuna0213.jo <hyuna0213.jo@samsung.com>
Signed-off-by: jihwan.seo <jihwan.seo@samsung.com>
Reviewed-on: https://gerrit.iotivity.org/gerrit/2298
Tested-by: jenkins-iotivity <jenkins-iotivity@opendaylight.org>
Reviewed-by: Patrick Lankswert <patrick.lankswert@intel.com>
32 files changed:
build_common/SConscript
resource/csdk/connectivity/SConscript
resource/csdk/connectivity/api/cacommon.h
resource/csdk/connectivity/api/cainterface.h
resource/csdk/connectivity/build/SConscript
resource/csdk/connectivity/inc/camessagehandler.h
resource/csdk/connectivity/inc/caprotocolmessage.h
resource/csdk/connectivity/inc/catcpadapter.h [new file with mode: 0644]
resource/csdk/connectivity/inc/catcpinterface.h [new file with mode: 0644]
resource/csdk/connectivity/lib/libcoap-4.1.1/SConscript
resource/csdk/connectivity/lib/libcoap-4.1.1/async.c
resource/csdk/connectivity/lib/libcoap-4.1.1/block.c
resource/csdk/connectivity/lib/libcoap-4.1.1/debug.c
resource/csdk/connectivity/lib/libcoap-4.1.1/net.c
resource/csdk/connectivity/lib/libcoap-4.1.1/option.c
resource/csdk/connectivity/lib/libcoap-4.1.1/option.h
resource/csdk/connectivity/lib/libcoap-4.1.1/pdu.c
resource/csdk/connectivity/lib/libcoap-4.1.1/pdu.h
resource/csdk/connectivity/lib/libcoap-4.1.1/resource.c
resource/csdk/connectivity/lib/libcoap-4.1.1/subscribe.c
resource/csdk/connectivity/samples/linux/sample_main.c
resource/csdk/connectivity/src/SConscript
resource/csdk/connectivity/src/cablockwisetransfer.c
resource/csdk/connectivity/src/caconnectivitymanager.c
resource/csdk/connectivity/src/cainterfacecontroller.c
resource/csdk/connectivity/src/camessagehandler.c
resource/csdk/connectivity/src/canetworkconfigurator.c
resource/csdk/connectivity/src/caprotocolmessage.c
resource/csdk/connectivity/src/tcp_adapter/SConscript [new file with mode: 0644]
resource/csdk/connectivity/src/tcp_adapter/catcpadapter.c [new file with mode: 0644]
resource/csdk/connectivity/src/tcp_adapter/catcpserver.c [new file with mode: 0644]
resource/csdk/connectivity/test/ca_api_unittest.cpp

index 9bda366..9df8f41 100644 (file)
@@ -83,7 +83,7 @@ help_vars.Add(BoolVariable('WITH_RA', 'Build with Remote Access module', False))
 if target_os in targets_disallow_multitransport:
        help_vars.Add(ListVariable('TARGET_TRANSPORT', 'Target transport', 'IP', ['BT', 'BLE', 'IP']))
 else:
-       help_vars.Add(ListVariable('TARGET_TRANSPORT', 'Target transport', 'ALL', ['ALL', 'BT', 'BLE', 'IP']))
+       help_vars.Add(ListVariable('TARGET_TRANSPORT', 'Target transport', 'ALL', ['ALL', 'BT', 'BLE', 'IP', 'TCP']))
 
 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')))
index e68924f..fbcbe66 100644 (file)
@@ -25,7 +25,7 @@ if 'ALL' in transport:
        if with_ra == True:
                        env.AppendUnique(CPPDEFINES = ['RA_ADAPTER'])
        if target_os == 'linux':
-               env.AppendUnique(CPPDEFINES = ['IP_ADAPTER','NO_EDR_ADAPTER','LE_ADAPTER'])
+               env.AppendUnique(CPPDEFINES = ['IP_ADAPTER','NO_EDR_ADAPTER','LE_ADAPTER', 'TCP_ADAPTER'])
        elif target_os == 'tizen':
                env.AppendUnique(CPPDEFINES = ['IP_ADAPTER','EDR_ADAPTER','LE_ADAPTER'])
        elif target_os in['darwin','ios']:
@@ -56,6 +56,16 @@ else:
        else:
                env.AppendUnique(CPPDEFINES = ['NO_IP_ADAPTER'])
 
+       if 'TCP' in transport:
+               if target_os in['linux']:
+                       env.AppendUnique(CPPDEFINES = ['TCP_ADAPTER'])
+                       print "CA Transport is TCP"
+               else:
+                       print "CA Transport TCP is not supported "
+                       Exit(1)
+       else:
+               env.AppendUnique(CPPDEFINES = ['NO_TCP_ADAPTER'])
+
 env.SConscript('./src/SConscript')
 
 if build_sample == 'ON':
index 41431e0..2a6aecc 100644 (file)
@@ -141,6 +141,7 @@ typedef enum
     CA_ADAPTER_REMOTE_ACCESS = (1 << 3),   // Remote Access over XMPP.
 #endif
 
+    CA_ADAPTER_TCP = (1 << 4),   // CoAP over TCP
     CA_ALL_ADAPTERS          = 0xffffffff
 } CATransportAdapter_t;
 
@@ -505,6 +506,23 @@ typedef struct
         CATransportFlags_t previousRequestFlags;/**< address family filtering */
         uint16_t previousRequestMessageId;      /**< address family filtering */
     } ca;
+
+#ifdef TCP_ADAPTER
+    /**
+     * Hold global variables for TCP Adapter.
+     */
+    struct tcpsockets
+    {
+        void *threadpool;       /**< threadpool between Initialize and Start */
+        void *svrlist;          /**< unicast IPv4 TCP server information*/
+        int selectTimeout;      /**< in seconds */
+        int listenBacklog;      /**< backlog counts*/
+        int maxfd;              /**< highest fd (for select) */
+        bool started;           /**< the TCP adapter has started */
+        bool terminate;         /**< the TCP adapter needs to stop */
+        bool ipv4tcpenabled;    /**< IPv4 TCP enabled by OCInit flags */
+    } tcp;
+#endif
 } CAGlobals_t;
 
 extern CAGlobals_t caglobals;
index 9499cf4..7449b28 100644 (file)
@@ -254,10 +254,10 @@ CAResult_t CASetRAInfo(const CARAInfo_t *caraInfo);
 /**
  * Select the cipher suite for dtls handshake.
  *
- * @param[IN] cipher  cipher suite (Note : Make sure endianness)
- *                               0xC018 : TLS_ECDH_anon_WITH_AES_128_CBC_SHA
- *                               0xC0A8 : TLS_PSK_WITH_AES_128_CCM_8
- *                               0xC0AE : TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8
+ * @param[in] cipher  cipher suite (Note : Make sure endianness).
+ *                    0xC018 : TLS_ECDH_anon_WITH_AES_128_CBC_SHA
+ *                    0xC0A8 : TLS_PSK_WITH_AES_128_CCM_8
+ *                    0xC0AE : TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8
  *
  * @retval  ::CA_STATUS_OK    Successful.
  * @retval  ::CA_STATUS_INVALID_PARAM  Invalid input arguments.
@@ -266,7 +266,7 @@ CAResult_t CASetRAInfo(const CARAInfo_t *caraInfo);
 CAResult_t CASelectCipherSuite(const uint16_t cipher);
 
 /**
- * Enable TLS_ECDH_anon_WITH_AES_128_CBC_SHA cipher suite in dtls
+ * Enable TLS_ECDH_anon_WITH_AES_128_CBC_SHA cipher suite in dtls.
  *
  * @param[in] enable  TRUE/FALSE enables/disables anonymous cipher suite.
  *
index 8117205..4a8942d 100644 (file)
@@ -60,7 +60,7 @@ help_vars = Variables()
 help_vars.Add(BoolVariable('RELEASE', 'Build for release?', True)) # set to 'no', 'false' or 0 for debug
 help_vars.Add(BoolVariable('LOGGING', 'Enable stack logging', False))
 help_vars.Add(EnumVariable('TARGET_OS', 'Target platform', host, host_target_map[host]))
-help_vars.Add(ListVariable('TARGET_TRANSPORT', 'Target transport', 'ALL', ['ALL', 'BT', 'BLE', 'IP']))
+help_vars.Add(ListVariable('TARGET_TRANSPORT', 'Target transport', 'ALL', ['ALL', 'BT', 'BLE', 'IP', 'TCP']))
 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))
index 45f9f64..c84836c 100644 (file)
@@ -129,8 +129,9 @@ void CAHandleRequestResponseCallbacks();
 /**
  * To log the PDU data.
  * @param[in] pdu    pdu data.
+ * @param[in] endpoint  endpoint
  */
-void CALogPDUInfo(coap_pdu_t *pdu);
+void CALogPDUInfo(coap_pdu_t *pdu, const CAEndpoint_t *endpoint);
 
 #ifdef WITH_BWT
 /**
index e557f15..06204b8 100644 (file)
@@ -28,7 +28,6 @@
 #include "cacommon.h"
 #include "config.h"
 #include "coap.h"
-#include "debug.h"
 
 #ifdef __cplusplus
 extern "C"
@@ -61,37 +60,43 @@ coap_pdu_t *CAGeneratePDU(uint32_t code, const CAInfo_t *info, const CAEndpoint_
 /**
  * extracts request information from received pdu.
  * @param[in]   pdu                   received pdu.
+ * @param[in]   endpoint              endpoint information.
  * @param[out]  outReqInfo            request info structure made from received pdu.
  * @return  CA_STATUS_OK or ERROR CODES (CAResult_t error codes in cacommon.h).
  */
-CAResult_t CAGetRequestInfoFromPDU(const coap_pdu_t *pdu, CARequestInfo_t *outReqInfo);
+CAResult_t CAGetRequestInfoFromPDU(const coap_pdu_t *pdu, const CAEndpoint_t *endpoint,
+                                   CARequestInfo_t *outReqInfo);
 
 /**
  * extracts response information from received pdu.
  * @param[in]   pdu                   received pdu.
  * @param[out]  outResInfo            response info structure made from received pdu.
+ * @param[in]   endpoint              endpoint information.
  * @return  CA_STATUS_OK or ERROR CODES (CAResult_t error codes in cacommon.h).
  */
-CAResult_t CAGetResponseInfoFromPDU(const coap_pdu_t *pdu, CAResponseInfo_t *outResInfo);
+CAResult_t CAGetResponseInfoFromPDU(const coap_pdu_t *pdu, CAResponseInfo_t *outResInfo,
+                                    const CAEndpoint_t *endpoint);
 
 /**
  * extracts error information from received pdu.
  * @param[in]   pdu                   received pdu.
+ * @param[in]   endpoint              endpoint information.
  * @param[out]  errorInfo             error info structure made from received pdu.
  * @return  CA_STATUS_OK or ERROR CODES (CAResult_t error codes in cacommon.h).
  */
-CAResult_t CAGetErrorInfoFromPDU(const coap_pdu_t *pdu, CAErrorInfo_t *errorInfo);
+CAResult_t CAGetErrorInfoFromPDU(const coap_pdu_t *pdu, const CAEndpoint_t *endpoint,
+                                 CAErrorInfo_t *errorInfo);
 
 /**
  * creates pdu from the request information.
  * @param[in]   code                 request or response code.
- * @param[out]  options              options for the request and response.
  * @param[in]   info                 information to create pdu.
  * @param[in]   endpoint             endpoint information.
+ * @param[out]  options              options for the request and response.
  * @return  generated pdu.
  */
-coap_pdu_t *CAGeneratePDUImpl(code_t code, coap_list_t *options, const CAInfo_t *info,
-                              const CAEndpoint_t *endpoint);
+coap_pdu_t *CAGeneratePDUImpl(code_t code, const CAInfo_t *info,
+                              const CAEndpoint_t *endpoint, coap_list_t *options);
 
 /**
  * parse the URI and creates the options.
@@ -159,33 +164,39 @@ uint32_t CAGetOptionCount(coap_opt_iterator_t opt_iter);
  * @return  option count.
  */
 uint32_t CAGetOptionData(uint16_t key, const uint8_t *data, uint32_t len,
-        uint8_t *option, uint32_t buflen);
+                         uint8_t *option, uint32_t buflen);
 
 /**
  * extracts request information from received pdu.
  * @param[in]    pdu                  received pdu.
+ * @param[in]    endpoint             endpoint information.
  * @param[out]   outCode              code of the received pdu.
  * @param[out]   outInfo              request info structure made from received pdu.
  * @return  CA_STATUS_OK or ERROR CODES (CAResult_t error codes in cacommon.h).
  */
-CAResult_t CAGetInfoFromPDU(const coap_pdu_t *pdu, uint32_t *outCode, CAInfo_t *outInfo);
+CAResult_t CAGetInfoFromPDU(const coap_pdu_t *pdu, const CAEndpoint_t *endpoint,
+                            uint32_t *outCode, CAInfo_t *outInfo);
 
 /**
  * create pdu from received data.
  * @param[in]   data                received data.
  * @param[in]   length              length of the data received.
  * @param[out]  outCode             code received.
+ * @param[in]   endpoint            endpoint information.
  * @return  coap_pdu_t value.
  */
-coap_pdu_t *CAParsePDU(const char *data, uint32_t length, uint32_t *outCode);
+coap_pdu_t *CAParsePDU(const char *data, uint32_t length, uint32_t *outCode,
+                       const CAEndpoint_t *endpoint);
 
 /**
  * get Token from received data(pdu).
  * @param[in]    pdu_hdr             header of received pdu.
  * @param[out]   outInfo             information with token received.
+ * @param[in]    endpoint            endpoint information.
  * @return  CA_STATUS_OK or ERROR CODES (CAResult_t error codes in cacommon.h).
  */
-CAResult_t CAGetTokenFromPDU(const coap_hdr_t *pdu_hdr, CAInfo_t *outInfo);
+CAResult_t CAGetTokenFromPDU(const coap_hdr_t *pdu_hdr, CAInfo_t *outInfo,
+                             const CAEndpoint_t *endpoint);
 
 /**
  * generates the token.
diff --git a/resource/csdk/connectivity/inc/catcpadapter.h b/resource/csdk/connectivity/inc/catcpadapter.h
new file mode 100644 (file)
index 0000000..1938221
--- /dev/null
@@ -0,0 +1,145 @@
+/* ****************************************************************
+ *
+ * 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 TCP Adapter.
+ */
+#ifndef CA_TCP_ADAPTER_H_
+#define CA_TCP_ADAPTER_H_
+
+#include "cacommon.h"
+#include "caadapterinterface.h"
+#include "cathreadpool.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/**
+ * TCP Server Information for IPv4 TCP transport
+ */
+typedef struct
+{
+    char addr[MAX_ADDR_STR_SIZE_CA];    /**< TCP Server address */
+    CASocket_t u4tcp;                   /**< TCP Server port */
+} CATCPServerInfo_t;
+
+/**
+ * API to initialize TCP Interface.
+ * @param[in] registerCallback      Callback to register TCP interfaces to
+ *                                  Connectivity Abstraction Layer.
+ * @param[in] networkPacketCallback Callback to notify request and
+ *                                  response messages from server(s)
+ *                                  started at Connectivity Abstraction Layer.
+ * @param[in] netCallback           Callback to notify the network additions
+ *                                  to Connectivity Abstraction Layer.
+ * @param[in] errorCallback         Callback to notify the network errors to
+ *                                  Connectivity Abstraction Layer.
+ * @param[in] handle                Threadpool Handle.
+ * @return  ::CA_STATUS_OK or Appropriate error code
+ */
+CAResult_t CAInitializeTCP(CARegisterConnectivityCallback registerCallback,
+                           CANetworkPacketReceivedCallback networkPacketCallback,
+                           CANetworkChangeCallback netCallback,
+                           CAErrorHandleCallback errorCallback, ca_thread_pool_t handle);
+
+/**
+ * Start TCP Interface adapter.
+ * @return  ::CA_STATUS_OK or Appropriate error code.
+ */
+CAResult_t CAStartTCP();
+
+/**
+ * Start listening server for receiving connect requests.
+ * Transport Specific Behavior:
+ * TCP Starts Listening Server on a particular interface and prefixed port
+ * number and as per OIC Specification.
+ * @return  ::CA_STATUS_OK or Appropriate error code.
+ */
+CAResult_t CAStartTCPListeningServer();
+
+/**
+ * Start discovery servers for receiving advertisements.
+ * Transport Specific Behavior:
+ * TCP Starts Discovery server on a particular interface and prefixed port
+ * number as per OIC Specification.
+ * @return  ::CA_STATUS_OK or Appropriate error code.
+ */
+CAResult_t CAStartTCPDiscoveryServer();
+
+/**
+ * Sends data to the endpoint using the adapter connectivity.
+ * @param[in]   endpoint       Remote Endpoint information (like ipaddress,
+ *                              port, reference uri and transport type) to
+ *                              which the unicast data has to be sent.
+ * @param[in]   data           Data which is required to be sent.
+ * @param[in]   dataLen        Size of data to be sent.
+ * @note  dataLen must be > 0.
+ * @return  The number of bytes sent on the network, or -1 upon error.
+ */
+int32_t CASendTCPUnicastData(const CAEndpoint_t *endpoint,
+                             const void *data, uint32_t dataLen);
+
+/**
+ * Send Multicast data to the endpoint using the TCP connectivity.
+ * @param[in]   endpoint       Remote Endpoint information (like ipaddress,
+ *                              port)
+ * @param[in]   data           Data which is required to be sent.
+ * @param[in]   dataLen        Size of data to be sent.
+ * @note  dataLen must be > 0.
+ * @return  The number of bytes sent on the network, or -1 upon error.
+ */
+int32_t CASendTCPMulticastData(const CAEndpoint_t *endpoint,
+                               const void *data, uint32_t dataLen);
+
+/**
+ * Get TCP Connectivity network information.
+ * @param[out]   info        Local connectivity information structures.
+ * @note info is allocated in this API and should be freed by the caller.
+ * @param[out]   size        Number of local connectivity structures.
+ * @return  ::CA_STATUS_OK or Appropriate error code.
+ */
+CAResult_t CAGetTCPInterfaceInformation(CAEndpoint_t **info, uint32_t *size);
+
+/**
+ * Read Synchronous API callback.
+ * @return  ::CA_STATUS_OK or Appropriate error code.
+ */
+CAResult_t CAReadTCPData();
+
+/**
+ * Stops Unicast, servers and close the sockets.
+ * @return  ::CA_STATUS_OK or Appropriate error code.
+ */
+CAResult_t CAStopTCP();
+
+/**
+ * Terminate the TCP connectivity adapter.
+ * Configuration information will be deleted from further use.
+ */
+void CATerminateTCP();
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif  // CA_TCP_ADAPTER_H_
diff --git a/resource/csdk/connectivity/inc/catcpinterface.h b/resource/csdk/connectivity/inc/catcpinterface.h
new file mode 100644 (file)
index 0000000..0519263
--- /dev/null
@@ -0,0 +1,142 @@
+/* *****************************************************************
+ *
+ * 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 provides APIs TCP client/server/network monitor modules.
+ */
+
+#ifndef CA_TCP_INTERFACE_H_
+#define CA_TCP_INTERFACE_H_
+
+#include <stdbool.h>
+
+#include "cacommon.h"
+#include "catcpadapter.h"
+#include "cathreadpool.h"
+#include "uarraylist.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/**
+ * Callback to be notified on reception of any data from remote OIC devices.
+ *
+ * @param[in]  endpoint      network endpoint description.
+ * @param[in]  data          Data received from remote OIC device.
+ * @param[in]  dataLength    Length of data in bytes.
+ * @pre  Callback must be registered using CAIPSetPacketReceiveCallback().
+ */
+typedef void (*CATCPPacketReceivedCallback)(const CAEndpoint_t *endpoint,
+                                           const void *data,
+                                           uint32_t dataLength);
+
+/**
+  * Callback to notify error in the TCP adapter.
+  *
+  * @param[in]  endpoint      network endpoint description.
+  * @param[in]  data          Data sent/received.
+  * @param[in]  dataLength    Length of data in bytes.
+  * @param[in]  result        result of request from R.I.
+  * @pre  Callback must be registered using CAIPSetPacketReceiveCallback().
+ */
+typedef void (*CATCPErrorHandleCallback)(const CAEndpoint_t *endpoint, const void *data,
+                                        uint32_t dataLength, CAResult_t result);
+
+/**
+ * set error callback to notify error in TCP adapter.
+ *
+ * @param[in]  errorHandleCallback Callback function to notify the error
+ * in the TCP adapter.
+ */
+void CATCPSetErrorHandler(CATCPErrorHandleCallback errorHandleCallback);
+
+/**
+ * Start TCP server.
+ *
+ * @param   threadPool   Thread pool for managing Unicast server threads.
+ * @return ::CA_STATUS_OK or Appropriate error code.
+ * @retval ::CA_STATUS_OK  Successful.
+ * @retval ::CA_STATUS_INVALID_PARAM Invalid input data.
+ * @retval ::CA_STATUS_FAILED Initialization failed.
+ */
+CAResult_t CATCPStartServer(const ca_thread_pool_t threadPool);
+
+/**
+ * Stop TCP server.
+ */
+void CATCPStopServer();
+
+/**
+ * Set this callback for receiving data packets from peer devices.
+ *
+ * @param[in]  callback    Callback to be notified on reception of unicast data packets.
+ */
+void CATCPSetPacketReceiveCallback(CATCPPacketReceivedCallback callback);
+
+/**
+ * API to send unicast TCP data.
+ *
+ * @param[in]  endpoint          complete network address to send to.
+ * @param[in]  data              Data to be send.
+ * @param[in]  dataLength        Length of data in bytes.
+ * @param[in]  isMulticast       Whether data needs to be sent to multicast ip.
+ */
+void CATCPSendData(CAEndpoint_t *endpoint, const void *data, uint32_t dataLength,
+                   bool isMulticast);
+
+/**
+ * Get a list of CAInterface_t items.
+ *
+ * @return  List of CAInterface_t items.
+ */
+u_arraylist_t *CATCPGetInterfaceInformation(int desiredIndex);
+
+/**
+ * Connect to TCP Server.
+ * @param[in]   TCPServerInfo   TCP Server information.
+ * @return  TCP Server Information structure.
+ */
+CATCPServerInfo_t *CAConnectToTCPServer(const CAEndpoint_t *TCPServerInfo);
+
+/**
+ * Disconnect from TCP Server.
+ * @param[in]   TCPServerInfo   TCP Server information.
+ * @return  ::CA_STATUS_OK or Appropriate error code.
+ */
+CAResult_t CADisconnectFromTCPServer(const CAEndpoint_t *TCPServerInfo);
+
+/**
+ * Get TCP Connection Information from list.
+ * @param[in]   addr    TCP Server address.
+ * @param[in]   port    TCP Server port.
+ * @param[out]  index   index of array list.
+ * @return  TCP Server Information structure.
+ */
+CATCPServerInfo_t *CAGetTCPServerInfoFromList(const char *addr, const uint16_t port,
+                                            uint32_t *index);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CA_TCP_INTERFACE_H_ */
index 8c1059a..2f42239 100644 (file)
@@ -7,6 +7,7 @@ Import('env')
 libcoap_env = env.Clone()
 
 target_os = env.get('TARGET_OS')
+ca_transport = env.get('TARGET_TRANSPORT')
 # As in the source code(C) includes arduino Time library head file(C++)
 # It requires compile the .c with g++
 if target_os == 'arduino':
@@ -35,6 +36,10 @@ if target_os not in ['windows', 'winrt']:
        libcoap_env.AppendUnique(CFLAGS = ['-Wall', '-ffunction-sections',
                        '-fdata-sections', '-fno-exceptions'])
 
+if target_os == 'linux':
+       if (('TCP' in ca_transport) or ('ALL' in ca_transport)):
+               libcoap_env.AppendUnique(CPPDEFINES = ['WITH_TCP'])
+
 if target_os == 'android':
        libcoap_env.AppendUnique(LIBS = ['log'])
 
@@ -69,4 +74,4 @@ libcoap_src = [
 libcoap = libcoap_env.StaticLibrary('libcoap', libcoap_src, OBJPREFIX='libcoap_')
 
 libcoap_env.InstallTarget([libcoap], 'libcoap')
-libcoap_env.UserInstallTargetLib([libcoap], 'libcoap')
+libcoap_env.UserInstallTargetLib([libcoap], 'libcoap')
\ No newline at end of file
index 08cdb86..5bf5d95 100644 (file)
@@ -41,28 +41,28 @@ coap_register_async(coap_context_t *context, coap_address_t *peer, coap_pdu_t *r
 
     /* store information for handling the asynchronous task */
     s = (coap_async_state_t *) coap_malloc(sizeof(coap_async_state_t) +
-            request->hdr->token_length);
+            request->hdr->coap_hdr_udp_t.token_length);
     if (!s)
     {
         coap_log(LOG_CRIT, "coap_register_async: insufficient memory\n");
         return NULL;
     }
 
-    memset(s, 0, sizeof(coap_async_state_t) + request->hdr->token_length);
+    memset(s, 0, sizeof(coap_async_state_t) + request->hdr->coap_hdr_udp_t.token_length);
 
     /* set COAP_ASYNC_CONFIRM according to request's type */
     s->flags = flags & ~COAP_ASYNC_CONFIRM;
-    if (request->hdr->type == COAP_MESSAGE_CON)
+    if (request->hdr->coap_hdr_udp_t.type == COAP_MESSAGE_CON)
         s->flags |= COAP_ASYNC_CONFIRM;
 
     s->appdata = data;
 
     memcpy(&s->peer, peer, sizeof(coap_address_t));
 
-    if (request->hdr->token_length)
+    if (request->hdr->coap_hdr_udp_t.token_length)
     {
-        s->tokenlen = request->hdr->token_length;
-        memcpy(s->token, request->hdr->token, request->hdr->token_length);
+        s->tokenlen = request->hdr->coap_hdr_udp_t.token_length;
+        memcpy(s->token, request->hdr->coap_hdr_udp_t.token, request->hdr->coap_hdr_udp_t.token_length);
     }
 
     memcpy(&s->id, &id, sizeof(coap_tid_t));
index c0373f7..de83a62 100644 (file)
@@ -126,7 +126,8 @@ int coap_write_block_opt(coap_block_t *block, unsigned short type, coap_pdu_t *p
 
     /* to re-encode the block option */
     coap_add_option(pdu, type,
-            coap_encode_var_bytes(buf, ((block->num << 4) | (block->m << 3) | block->szx)), buf);
+            coap_encode_var_bytes(buf, ((block->num << 4) | (block->m << 3) | block->szx)), buf,
+            coap_udp);
 
     return 1;
 }
index df9ae7b..027491d 100644 (file)
@@ -248,16 +248,21 @@ size_t coap_print_addr(const struct coap_address_t *addr, unsigned char *buf, si
 #ifndef WITH_CONTIKI
 void coap_show_pdu(const coap_pdu_t *pdu)
 {
+#ifndef WITH_TCP
     unsigned char buf[COAP_MAX_PDU_SIZE]; /* need some space for output creation */
+#else
+    unsigned char buf[COAP_TCP_LENGTH_LIMIT_32_BIT]; /* need some space for output creation */
+#endif
     int encode = 0, have_options = 0;
     coap_opt_iterator_t opt_iter;
     coap_opt_t *option;
 
-    fprintf(COAP_DEBUG_FD, "v:%d t:%d tkl:%d c:%d id:%u", pdu->hdr->version, pdu->hdr->type,
-            pdu->hdr->token_length, pdu->hdr->code, ntohs(pdu->hdr->id));
+    fprintf(COAP_DEBUG_FD, "v:%d t:%d tkl:%d c:%d id:%u", pdu->hdr->coap_hdr_udp_t.version,
+            pdu->hdr->coap_hdr_udp_t.type, pdu->hdr->coap_hdr_udp_t.token_length,
+            pdu->hdr->coap_hdr_udp_t.code, ntohs(pdu->hdr->coap_hdr_udp_t.id));
 
     /* show options, if any */
-    coap_option_iterator_init((coap_pdu_t *) pdu, &opt_iter, COAP_OPT_ALL);
+    coap_option_iterator_init((coap_pdu_t *) pdu, &opt_iter, COAP_OPT_ALL, coap_udp);
 
     while ((option = coap_option_next(&opt_iter)))
     {
@@ -311,15 +316,16 @@ coap_show_pdu(const coap_pdu_t *pdu)
     unsigned char buf[80]; /* need some space for output creation */
 
     PRINTF("v:%d t:%d oc:%d c:%d id:%u",
-            pdu->hdr->version, pdu->hdr->type,
-            pdu->hdr->optcnt, pdu->hdr->code, uip_ntohs(pdu->hdr->id));
+            pdu->hdr->coap_hdr_udp_t.version, pdu->hdr->coap_hdr_udp_t.type,
+            pdu->hdr->coap_hdr_udp_t.optcnt, pdu->hdr->coap_hdr_udp_t.code,
+            uip_ntohs(pdu->hdr->coap_hdr_udp_t.id));
 
     /* show options, if any */
-    if (pdu->hdr->optcnt)
+    if (pdu->hdr->coap_hdr_udp_t.optcnt)
     {
         coap_opt_iterator_t opt_iter;
         coap_opt_t *option;
-        coap_option_iterator_init((coap_pdu_t *)pdu, &opt_iter, COAP_OPT_ALL);
+        coap_option_iterator_init((coap_pdu_t *)pdu, &opt_iter, COAP_OPT_ALL, coap_udp);
 
         PRINTF(" o:");
         while ((option = coap_option_next(&opt_iter)))
index af5f022..d3ea2ec 100644 (file)
@@ -498,7 +498,7 @@ int coap_option_check_critical(coap_context_t *ctx, coap_pdu_t *pdu, coap_opt_fi
     coap_opt_iterator_t opt_iter;
     int ok = 1;
 
-    coap_option_iterator_init(pdu, &opt_iter, COAP_OPT_ALL);
+    coap_option_iterator_init(pdu, &opt_iter, COAP_OPT_ALL, coap_udp);
 
     while (coap_option_next(&opt_iter))
     {
@@ -562,7 +562,7 @@ void coap_transaction_id(const coap_address_t *peer, const coap_pdu_t *pdu, coap
     coap_hash((const unsigned char *)&peer->addr, sizeof(peer->addr), h);
 #endif /* WITH_LWIP || WITH_CONTIKI */
 
-    coap_hash((const unsigned char *)&pdu->hdr->id, sizeof(unsigned short), h);
+    coap_hash((const unsigned char *)&pdu->hdr->coap_hdr_udp_t.id, sizeof(unsigned short), h);
 
     *id = ((h[0] << 8) | h[1]) ^ ((h[2] << 8) | h[3]);
 }
@@ -572,9 +572,10 @@ coap_tid_t coap_send_ack(coap_context_t *context, const coap_address_t *dst, coa
     coap_pdu_t *response;
     coap_tid_t result = COAP_INVALID_TID;
 
-    if (request && request->hdr->type == COAP_MESSAGE_CON)
+    if (request && request->hdr->coap_hdr_udp_t.type == COAP_MESSAGE_CON)
     {
-        response = coap_pdu_init(COAP_MESSAGE_ACK, 0, request->hdr->id, sizeof(coap_pdu_t));
+        response = coap_pdu_init(COAP_MESSAGE_ACK, 0, request->hdr->coap_hdr_udp_t.id,
+                                 sizeof(coap_pdu_t), coap_udp);
         if (response)
         {
             result = coap_send(context, dst, response);
@@ -735,7 +736,8 @@ coap_tid_t coap_send_message_type(coap_context_t *context, const coap_address_t
 
     if (request)
     {
-        response = coap_pdu_init(type, 0, request->hdr->id, sizeof(coap_pdu_t));
+        response = coap_pdu_init(type, 0, request->hdr->coap_hdr_udp_t.id,
+                                 sizeof(coap_pdu_t), coap_udp);
         if (response)
         {
             result = coap_send(context, dst, response);
@@ -830,12 +832,14 @@ coap_tid_t coap_retransmit(coap_context_t *context, coap_queue_t *node)
         node->t = node->timeout << node->retransmit_cnt;
         coap_insert_node(&context->sendqueue, node);
 #ifdef WITH_LWIP
-        if (node == context->sendqueue) /* don't bother with timer stuff if there are earlier retransmits */
+        /* don't bother with timer stuff if there are earlier retransmits */
+        if (node == context->sendqueue)
         coap_retransmittimer_restart(context);
 #endif
 
         debug(
-                "** retransmission #%d of transaction %d\n", node->retransmit_cnt, ntohs(node->pdu->hdr->id));
+                "** retransmission #%d of transaction %d\n", node->retransmit_cnt,
+                ntohs(node->pdu->hdr->coap_hdr_udp_t.id));
 
         node->id = coap_send_impl(context, &node->remote, node->pdu);
         return node->id;
@@ -850,13 +854,13 @@ coap_tid_t coap_retransmit(coap_context_t *context, coap_queue_t *node)
 #ifndef WITHOUT_OBSERVE
     /* Check if subscriptions exist that should be canceled after
      COAP_MAX_NOTIFY_FAILURES */
-    if (node->pdu->hdr->code >= 64)
+    if (node->pdu->hdr->coap_hdr_udp_t.code >= 64)
     {
         str token =
         { 0, NULL };
 
-        token.length = node->pdu->hdr->token_length;
-        token.s = node->pdu->hdr->token;
+        token.length = node->pdu->hdr->coap_hdr_udp_t.token_length;
+        token.s = node->pdu->hdr->coap_hdr_udp_t.token;
 
         coap_handle_failed_notify(context, &node->remote, &token);
     }
@@ -947,7 +951,7 @@ int coap_read(coap_context_t *ctx)
         goto error_early;
     }
 
-    if (pdu->version != COAP_DEFAULT_VERSION)
+    if (pdu->coap_hdr_udp_t.version != COAP_DEFAULT_VERSION)
     {
         debug("coap_read: unknown protocol version\n");
         goto error_early;
@@ -961,7 +965,7 @@ int coap_read(coap_context_t *ctx)
     node->pdu = coap_pdu_from_pbuf(ctx->pending_package);
     ctx->pending_package = NULL;
 #else
-    node->pdu = coap_pdu_init(0, 0, 0, bytes_read);
+    node->pdu = coap_pdu_init(0, 0, 0, bytes_read, coap_udp);
 #endif
     if (!node->pdu)
         goto error;
@@ -970,7 +974,7 @@ int coap_read(coap_context_t *ctx)
     memcpy(&node->local, &dst, sizeof(coap_address_t));
     memcpy(&node->remote, &src, sizeof(coap_address_t));
 
-    if (!coap_pdu_parse((unsigned char *) buf, bytes_read, node->pdu))
+    if (!coap_pdu_parse((unsigned char *) buf, bytes_read, node->pdu, coap_udp))
     {
         warn("discard malformed PDU");
         goto error;
@@ -1075,12 +1079,12 @@ void coap_cancel_all_messages(coap_context_t *context, const coap_address_t *dst
 
     debug("cancel_all_messages\n");
     while (context->sendqueue && coap_address_equals(dst, &context->sendqueue->remote)
-            && token_match(token, token_length, context->sendqueue->pdu->hdr->token,
-                    context->sendqueue->pdu->hdr->token_length))
+            && token_match(token, token_length, context->sendqueue->pdu->hdr->coap_hdr_udp_t.token,
+                    context->sendqueue->pdu->hdr->coap_hdr_udp_t.token_length))
     {
         q = context->sendqueue;
         context->sendqueue = q->next;
-        debug("**** removed transaction %d\n", ntohs(q->pdu->hdr->id));
+        debug("**** removed transaction %d\n", ntohs(q->pdu->hdr->coap_hdr_udp_t.id));
         coap_delete_node(q);
     }
 
@@ -1094,10 +1098,11 @@ void coap_cancel_all_messages(coap_context_t *context, const coap_address_t *dst
     while (q)
     {
         if (coap_address_equals(dst, &q->remote)
-                && token_match(token, token_length, q->pdu->hdr->token, q->pdu->hdr->token_length))
+                && token_match(token, token_length, q->pdu->hdr->coap_hdr_udp_t.token,
+                               q->pdu->hdr->coap_hdr_udp_t.token_length))
         {
             p->next = q->next;
-            debug("**** removed transaction %d\n", ntohs(q->pdu->hdr->id));
+            debug("**** removed transaction %d\n", ntohs(q->pdu->hdr->coap_hdr_udp_t.id));
             coap_delete_node(q);
             q = p->next;
         }
@@ -1123,7 +1128,7 @@ coap_new_error_response(coap_pdu_t *request, unsigned char code, coap_opt_filter
 {
     coap_opt_iterator_t opt_iter;
     coap_pdu_t *response;
-    size_t size = sizeof(coap_hdr_t) + request->hdr->token_length;
+    size_t size = sizeof(coap_hdr_t) + request->hdr->coap_hdr_udp_t.token_length;
     int type;
     coap_opt_t *option;
     unsigned short opt_type = 0; /* used for calculating delta-storage */
@@ -1139,14 +1144,14 @@ coap_new_error_response(coap_pdu_t *request, unsigned char code, coap_opt_filter
     assert(request);
 
     /* cannot send ACK if original request was not confirmable */
-    type = request->hdr->type == COAP_MESSAGE_CON ? COAP_MESSAGE_ACK : COAP_MESSAGE_NON;
+    type = request->hdr->coap_hdr_udp_t.type == COAP_MESSAGE_CON ? COAP_MESSAGE_ACK : COAP_MESSAGE_NON;
 
     /* Estimate how much space we need for options to copy from
      * request. We always need the Token, for 4.02 the unknown critical
      * options must be included as well. */
     coap_option_clrb(opts, COAP_OPTION_CONTENT_TYPE); /* we do not want this */
 
-    coap_option_iterator_init(request, &opt_iter, opts);
+    coap_option_iterator_init(request, &opt_iter, opts, coap_udp);
 
     /* Add size of each unknown critical option. As known critical
      options as well as elective options are not copied, the delta
@@ -1189,11 +1194,12 @@ coap_new_error_response(coap_pdu_t *request, unsigned char code, coap_opt_filter
     }
 
     /* Now create the response and fill with options and payload data. */
-    response = coap_pdu_init(type, code, request->hdr->id, size);
+    response = coap_pdu_init(type, code, request->hdr->coap_hdr_udp_t.id, size, coap_udp);
     if (response)
     {
         /* copy token */
-        if (!coap_add_token(response, request->hdr->token_length, request->hdr->token))
+        if (!coap_add_token(response, request->hdr->coap_hdr_udp_t.token_length,
+                            request->hdr->coap_hdr_udp_t.token, coap_udp))
         {
             debug("cannot add token to error response\n");
             coap_delete_pdu(response);
@@ -1201,10 +1207,10 @@ coap_new_error_response(coap_pdu_t *request, unsigned char code, coap_opt_filter
         }
 
         /* copy all options */
-        coap_option_iterator_init(request, &opt_iter, opts);
+        coap_option_iterator_init(request, &opt_iter, opts, coap_udp);
         while ((option = coap_option_next(&opt_iter)))
             coap_add_option(response, opt_iter.type, COAP_OPT_LENGTH(option),
-                    COAP_OPT_VALUE(option));
+                    COAP_OPT_VALUE(option), coap_udp);
 
 #if COAP_ERROR_PHRASE_LENGTH > 0
         /* note that diagnostic messages do not need a Content-Format option. */
@@ -1252,16 +1258,17 @@ wellknown_response(coap_context_t *context, coap_pdu_t *request)
     size_t offset = 0;
 
     resp = coap_pdu_init(
-            request->hdr->type == COAP_MESSAGE_CON ? COAP_MESSAGE_ACK : COAP_MESSAGE_NON,
+            request->hdr->coap_hdr_udp_t.type == COAP_MESSAGE_CON ? COAP_MESSAGE_ACK : COAP_MESSAGE_NON,
             COAP_RESPONSE_CODE(205),
-            request->hdr->id, COAP_MAX_PDU_SIZE);
+            request->hdr->coap_hdr_udp_t.id, COAP_MAX_PDU_SIZE, coap_udp);
     if (!resp)
     {
         debug("wellknown_response: cannot create PDU\n");
         return NULL;
     }
 
-    if (!coap_add_token(resp, request->hdr->token_length, request->hdr->token))
+    if (!coap_add_token(resp, request->hdr->coap_hdr_udp_t.token_length,
+                        request->hdr->coap_hdr_udp_t.token, coap_udp))
     {
         debug("wellknown_response: cannot add token\n");
         goto error;
@@ -1276,7 +1283,7 @@ wellknown_response(coap_context_t *context, coap_pdu_t *request)
         offset = block.num << (block.szx + 4);
         if (block.szx > 6)
         { /* invalid, MUST lead to 4.00 Bad Request */
-            resp->hdr->code = COAP_RESPONSE_CODE(400);
+            resp->hdr->coap_hdr_udp_t.code = COAP_RESPONSE_CODE(400);
             return resp;
         }
         else if (block.szx > COAP_MAX_BLOCK_SZX)
@@ -1302,7 +1309,7 @@ wellknown_response(coap_context_t *context, coap_pdu_t *request)
      * nothing should go wrong here. */
     assert(coap_encode_var_bytes(buf, COAP_MEDIATYPE_APPLICATION_LINK_FORMAT) == 1);
     coap_add_option(resp, COAP_OPTION_CONTENT_FORMAT,
-            coap_encode_var_bytes(buf, COAP_MEDIATYPE_APPLICATION_LINK_FORMAT), buf);
+            coap_encode_var_bytes(buf, COAP_MEDIATYPE_APPLICATION_LINK_FORMAT), buf, coap_udp);
 
     /* check if Block2 option is required even if not requested */
     if (!need_block2 && (resp->max_size - (size_t) resp->length < wkc_len))
@@ -1360,13 +1367,13 @@ wellknown_response(coap_context_t *context, coap_pdu_t *request)
 
     error:
     /* set error code 5.03 and remove all options and data from response */
-    resp->hdr->code = COAP_RESPONSE_CODE(503);
-    resp->length = sizeof(coap_hdr_t) + resp->hdr->token_length;
+    resp->hdr->coap_hdr_udp_t.code = COAP_RESPONSE_CODE(503);
+    resp->length = sizeof(coap_hdr_t) + resp->hdr->coap_hdr_udp_t.token_length;
     return resp;
 }
 
 #define WANT_WKC(Pdu,Key)                   \
-  (((Pdu)->hdr->code == COAP_REQUEST_GET) && is_wkc(Key))
+  (((Pdu)->hdr->coap_hdr_udp_t.code == COAP_REQUEST_GET) && is_wkc(Key))
 
 void handle_request(coap_context_t *context, coap_queue_t *node, const char* responseData)
 {
@@ -1389,7 +1396,7 @@ void handle_request(coap_context_t *context, coap_queue_t *node, const char* res
          * be the well-known URI. In that case, we generate a default
          * response, otherwise, we return 4.04 */
 
-        switch (node->pdu->hdr->code)
+        switch (node->pdu->hdr->coap_hdr_udp_t.code)
         {
 
             case COAP_REQUEST_GET:
@@ -1429,41 +1436,43 @@ void handle_request(coap_context_t *context, coap_queue_t *node, const char* res
     }
 
     /* the resource was found, check if there is a registered handler */
-    if ((size_t) node->pdu->hdr->code - 1
+    if ((size_t) node->pdu->hdr->coap_hdr_udp_t.code - 1
             < sizeof(resource->handler) / sizeof(coap_method_handler_t))
-        h = resource->handler[node->pdu->hdr->code - 1];
+        h = resource->handler[node->pdu->hdr->coap_hdr_udp_t.code - 1];
 
     if (h)
     {
         debug(
                 "call custom handler for resource 0x%02x%02x%02x%02x\n", key[0], key[1], key[2], key[3]);
         response = coap_pdu_init(
-                node->pdu->hdr->type == COAP_MESSAGE_CON ? COAP_MESSAGE_ACK : COAP_MESSAGE_NON,
-                0, node->pdu->hdr->id, COAP_MAX_PDU_SIZE);
+                node->pdu->hdr->coap_hdr_udp_t.type ==
+                        COAP_MESSAGE_CON ? COAP_MESSAGE_ACK : COAP_MESSAGE_NON,
+                0, node->pdu->hdr->coap_hdr_udp_t.id, COAP_MAX_PDU_SIZE, coap_udp);
 
         /* Implementation detail: coap_add_token() immediately returns 0
          if response == NULL */
-        if (coap_add_token(response, node->pdu->hdr->token_length, node->pdu->hdr->token))
+        if (coap_add_token(response, node->pdu->hdr->coap_hdr_udp_t.token_length,
+                           node->pdu->hdr->coap_hdr_udp_t.token, coap_udp))
         {
             str token =
-            { node->pdu->hdr->token_length, node->pdu->hdr->token };
+            { node->pdu->hdr->coap_hdr_udp_t.token_length, node->pdu->hdr->coap_hdr_udp_t.token };
 
             h(context, resource, &node->remote, node->pdu, &token, response);
 
             unsigned char buf[3];
-            response->hdr->code = COAP_RESPONSE_CODE(205);
+            response->hdr->coap_hdr_udp_t.code = COAP_RESPONSE_CODE(205);
             coap_add_option(response, COAP_OPTION_CONTENT_TYPE,
-                    coap_encode_var_bytes(buf, COAP_MEDIATYPE_TEXT_PLAIN), buf);
-            coap_add_option(response, COAP_OPTION_MAXAGE, coap_encode_var_bytes(buf, 0x2ffff), buf);
+                    coap_encode_var_bytes(buf, COAP_MEDIATYPE_TEXT_PLAIN), buf, coap_udp);
+            coap_add_option(response, COAP_OPTION_MAXAGE, coap_encode_var_bytes(buf, 0x2ffff), buf, coap_udp);
             coap_add_data(response, strlen(responseData), (unsigned char *) responseData);
 
-            if (response->hdr->type != COAP_MESSAGE_NON
-                    || (response->hdr->code >= 64 && !coap_is_mcast(&node->local)))
+            if (response->hdr->coap_hdr_udp_t.type != COAP_MESSAGE_NON
+                    || (response->hdr->coap_hdr_udp_t.code >= 64 && !coap_is_mcast(&node->local)))
             {
 
                 if (coap_send(context, &node->remote, response) == COAP_INVALID_TID)
                 {
-                    debug("cannot send response for message %d\n", node->pdu->hdr->id);
+                    debug("cannot send response for message %d\n", node->pdu->hdr->coap_hdr_udp_t.id);
                 }
             }
 
@@ -1541,7 +1550,8 @@ handle_locally(coap_context_t *context __attribute__ ((unused)),
          * get token from sent and try to find a matching resource. Uh!
          */
 
-        COAP_SET_STR(&token, sent->pdu->hdr->token_length, sent->pdu->hdr->token);
+        COAP_SET_STR(&token, sent->pdu->hdr->coap_hdr_udp_t.token_length,
+                     sent->pdu->hdr->coap_hdr_udp_t.token);
 
 #ifndef WITH_CONTIKI
 #ifdef COAP_RESOURCES_NOHASH
@@ -1587,28 +1597,30 @@ handle_locally(coap_context_t *context __attribute__ ((unused)),
             context->recvqueue = context->recvqueue->next;
             rcvd->next = NULL;
 
-            if (rcvd->pdu->hdr->version != COAP_DEFAULT_VERSION)
+            if (rcvd->pdu->hdr->coap_hdr_udp_t.version != COAP_DEFAULT_VERSION)
             {
-                debug("dropped packet with unknown version %u\n", rcvd->pdu->hdr->version);
+                debug("dropped packet with unknown version %u\n", rcvd->pdu->hdr->coap_hdr_udp_t.version);
                 goto cleanup;
             }
 
-            switch (rcvd->pdu->hdr->type)
+            switch (rcvd->pdu->hdr->coap_hdr_udp_t.type)
             {
                 case COAP_MESSAGE_ACK:
                     /* find transaction in sendqueue to stop retransmission */
                     coap_remove_from_queue(&context->sendqueue, rcvd->id, &sent);
 
-                    if (rcvd->pdu->hdr->code == 0)
+                    if (rcvd->pdu->hdr->coap_hdr_udp_t.code == 0)
                         goto cleanup;
 
                     /* FIXME: if sent code was >= 64 the message might have been a
                      * notification. Then, we must flag the observer to be alive
                      * by setting obs->fail_cnt = 0. */
-                    if (sent && COAP_RESPONSE_CLASS(sent->pdu->hdr->code) == 2)
+                    if (sent && COAP_RESPONSE_CLASS(sent->pdu->hdr->coap_hdr_udp_t.code) == 2)
                     {
                         const str token =
-                        { sent->pdu->hdr->token_length, sent->pdu->hdr->token };
+                        { sent->pdu->hdr->coap_hdr_udp_t.token_length,
+                          sent->pdu->hdr->coap_hdr_udp_t.token };
+
                         coap_touch_observer(context, &sent->remote, &token);
                     }
                     break;
@@ -1618,7 +1630,8 @@ handle_locally(coap_context_t *context __attribute__ ((unused)),
                      * not only the transaction but also the subscriptions we might
                      * have. */
 
-                    coap_log(LOG_ALERT, "got RST for message %u\n", ntohs(rcvd->pdu->hdr->id));
+                    coap_log(LOG_ALERT, "got RST for message %u\n",
+                             ntohs(rcvd->pdu->hdr->coap_hdr_udp_t.id));
 
                     /* find transaction in sendqueue to stop retransmission */
                     coap_remove_from_queue(&context->sendqueue, rcvd->id, &sent);
@@ -1661,9 +1674,9 @@ handle_locally(coap_context_t *context __attribute__ ((unused)),
              * registered for a request that should be handled locally. */
             if (handle_locally(context, rcvd))
             {
-                if (COAP_MESSAGE_IS_REQUEST(rcvd->pdu->hdr))
+                if (COAP_MESSAGE_IS_REQUEST(rcvd->pdu->hdr->coap_hdr_udp_t))
                     handle_request(context, rcvd, responseData);
-                else if (COAP_MESSAGE_IS_RESPONSE(rcvd->pdu->hdr))
+                else if (COAP_MESSAGE_IS_RESPONSE(rcvd->pdu->hdr->coap_hdr_udp_t))
                     handle_response(context, sent, rcvd);
                 else
                 {
index 9a52fb4..67272d9 100644 (file)
 #include "pdu.h"
 
 coap_opt_t *
-options_start(coap_pdu_t *pdu)
+options_start(coap_pdu_t *pdu, coap_transport_type transport)
 {
-
-    if (pdu && pdu->hdr
-            && (pdu->hdr->token + pdu->hdr->token_length < (unsigned char *) pdu->hdr + pdu->length))
+    if (pdu && pdu->hdr)
     {
-
-        coap_opt_t *opt = pdu->hdr->token + pdu->hdr->token_length;
-        return (*opt == COAP_PAYLOAD_START) ? NULL : opt;
-
+        if (coap_udp == transport && (pdu->hdr->coap_hdr_udp_t.token +
+                pdu->hdr->coap_hdr_udp_t.token_length
+                < (unsigned char *) pdu->hdr + pdu->length))
+        {
+            coap_opt_t *opt = pdu->hdr->coap_hdr_udp_t.token +
+                    pdu->hdr->coap_hdr_udp_t.token_length;
+            return (*opt == COAP_PAYLOAD_START) ? NULL : opt;
+        }
+#ifdef WITH_TCP
+        else if(coap_tcp == transport && (pdu->hdr->coap_hdr_tcp_t.token +
+                pdu->hdr->coap_hdr_tcp_t.token_length
+                < (unsigned char *) pdu->hdr + pdu->length))
+        {
+            coap_opt_t *opt = pdu->hdr->coap_hdr_tcp_t.token +
+                    pdu->hdr->coap_hdr_tcp_t.token_length;
+            return (*opt == COAP_PAYLOAD_START) ? NULL : opt;
+        }
+#endif
+        return NULL;
     }
     else
         return NULL;
@@ -122,7 +135,8 @@ size_t coap_opt_parse(const coap_opt_t *opt, size_t length, coap_option_t *resul
 }
 
 coap_opt_iterator_t *
-coap_option_iterator_init(coap_pdu_t *pdu, coap_opt_iterator_t *oi, const coap_opt_filter_t filter)
+coap_option_iterator_init(coap_pdu_t *pdu, coap_opt_iterator_t *oi,
+                          const coap_opt_filter_t filter, coap_transport_type transport)
 {
     assert(pdu);
     assert(pdu->hdr);
@@ -130,16 +144,59 @@ coap_option_iterator_init(coap_pdu_t *pdu, coap_opt_iterator_t *oi, const coap_o
 
     memset(oi, 0, sizeof(coap_opt_iterator_t));
 
-    oi->next_option = (unsigned char *) pdu->hdr + sizeof(coap_hdr_t) + pdu->hdr->token_length;
-    if ((unsigned char *) pdu->hdr + pdu->length <= oi->next_option)
+    unsigned int token_length;
+    unsigned int headerSize;
+
+    switch(transport)
     {
-        oi->bad = 1;
-        return NULL;
+#ifdef WITH_TCP
+        case coap_tcp:
+            token_length = pdu->hdr->coap_hdr_tcp_t.token_length;
+            headerSize = COAP_TCP_HEADER_NO_FIELD;
+            break;
+        case coap_tcp_8bit:
+            token_length = pdu->hdr->coap_hdr_tcp_t.token_length;
+            headerSize = COAP_TCP_HEADER_8_BIT;
+            break;
+        case coap_tcp_16bit:
+            token_length = pdu->hdr->coap_hdr_tcp_t.token_length;
+            headerSize = COAP_TCP_HEADER_16_BIT;
+            break;
+        case coap_tcp_32bit:
+            token_length = pdu->hdr->coap_hdr_tcp_32bit_t.header_data[0] & 0x0f;
+            headerSize = COAP_TCP_HEADER_32_BIT;
+            break;
+#endif
+        default:
+            token_length = pdu->hdr->coap_hdr_udp_t.token_length;
+            headerSize = sizeof(pdu->hdr->coap_hdr_udp_t);
+            break;
+    }
+
+    oi->next_option = (unsigned char *) pdu->hdr + headerSize + token_length;
+
+    if (coap_udp == transport)
+    {
+        if ((unsigned char *) &(pdu->hdr->coap_hdr_udp_t) + pdu->length <= oi->next_option)
+        {
+            oi->bad = 1;
+            return NULL;
+        }
     }
+#ifdef WITH_TCP
+    else
+    {
+        if ((unsigned char *) &(pdu->hdr->coap_hdr_tcp_t) + pdu->length <= oi->next_option)
+        {
+            oi->bad = 1;
+            return NULL;
+        }
+    }
+#endif
 
-    assert((sizeof(coap_hdr_t) + pdu->hdr->token_length) <= pdu->length);
+    assert((headerSize + token_length) <= pdu->length);
 
-    oi->length = pdu->length - (sizeof(coap_hdr_t) + pdu->hdr->token_length);
+    oi->length = pdu->length - (headerSize + token_length);
 
     if (filter)
     {
@@ -224,7 +281,7 @@ coap_check_option(coap_pdu_t *pdu, unsigned char type, coap_opt_iterator_t *oi)
     coap_option_filter_clear(f);
     coap_option_setb(f, type);
 
-    coap_option_iterator_init(pdu, oi, f);
+    coap_option_iterator_init(pdu, oi, f, coap_udp);
 
     return coap_option_next(oi);
 }
index cfdcfaf..9c33ac8 100644 (file)
@@ -82,7 +82,7 @@ size_t coap_opt_size(const coap_opt_t *opt);
  * @param pdu The PDU containing the options.
  * @return A pointer to the first option if available, or @c NULL otherwise.
  */
-coap_opt_t *options_start(coap_pdu_t *pdu);
+coap_opt_t *options_start(coap_pdu_t *pdu, coap_transport_type transport);
 
 /**
  * Interprets @p opt as pointer to a CoAP option and advances to
@@ -206,7 +206,7 @@ typedef struct
  * @return The iterator object @p oi on success, @c NULL otherwise.
  */
 coap_opt_iterator_t *coap_option_iterator_init(coap_pdu_t *pdu, coap_opt_iterator_t *oi,
-        const coap_opt_filter_t filter);
+        const coap_opt_filter_t filter, coap_transport_type transport);
 
 /**
  * Updates the iterator @p oi to point to the next option. This
@@ -293,9 +293,10 @@ unsigned short coap_opt_delta(const coap_opt_t *opt);
 #define COAP_OPT_DELTA(opt) coap_opt_delta(opt)
 
 /** @deprecated { Use coap_opt_encode() instead. } */
+#ifndef WITH_TCP
 #define COAP_OPT_SETDELTA(opt,val)          \
   coap_opt_encode((opt), COAP_MAX_PDU_SIZE, (val), NULL, 0)
-
+#endif
 /**
  * Returns the length of the given option. @p opt must point to an
  * option jump or the beginning of the option. This function returns
index d246654..857fba5 100644 (file)
 #ifdef WITH_CONTIKI
 #include "memb.h"
 
+#ifndef WITH_TCP
 typedef unsigned char _pdu[sizeof(coap_pdu_t) + COAP_MAX_PDU_SIZE];
 
 MEMB(pdu_storage, _pdu, COAP_PDU_MAXCNT);
+#endif
 
 void
 coap_pdu_resources_init()
@@ -44,17 +46,27 @@ coap_pdu_resources_init()
 #include "mem.h"
 #endif /* WITH_CONTIKI */
 
-void coap_pdu_clear(coap_pdu_t *pdu, size_t size)
+void coap_pdu_clear(coap_pdu_t *pdu, size_t size, coap_transport_type transport, unsigned int length)
 {
     assert(pdu);
 
     memset(pdu, 0, sizeof(coap_pdu_t) + size);
     pdu->max_size = size;
     pdu->hdr = (coap_hdr_t *) ((unsigned char *) pdu + sizeof(coap_pdu_t));
-    pdu->hdr->version = COAP_DEFAULT_VERSION;
 
-    /* data is NULL unless explicitly set by coap_add_data() */
-    pdu->length = sizeof(coap_hdr_t);
+    if (coap_udp == transport)
+    {
+        pdu->hdr->coap_hdr_udp_t.version = COAP_DEFAULT_VERSION;
+        /* data is NULL unless explicitly set by coap_add_data() */
+        pdu->length = sizeof(pdu->hdr->coap_hdr_udp_t);
+    }
+#ifdef WITH_TCP
+    else
+    {
+        /* data is NULL unless explicitly set by coap_add_data() */
+        pdu->length = length;
+    }
+#endif
 }
 
 #ifdef WITH_LWIP
@@ -84,17 +96,44 @@ coap_pdu_from_pbuf(struct pbuf *pbuf)
 #endif
 
 coap_pdu_t *
-coap_pdu_init(unsigned char type, unsigned char code, unsigned short id, size_t size)
+coap_pdu_init(unsigned char type, unsigned char code, unsigned short id,
+              size_t size, coap_transport_type transport)
 {
     coap_pdu_t *pdu;
 #ifdef WITH_LWIP
     struct pbuf *p;
 #endif
 
+    unsigned int length = 0;
+    switch(transport)
+    {
+        case coap_udp:
+            length = sizeof(pdu->hdr->coap_hdr_udp_t);
+            break;
+#ifdef WITH_TCP
+        case coap_tcp:
+            length = COAP_TCP_HEADER_NO_FIELD;
+            break;
+        case coap_tcp_8bit:
+            length = COAP_TCP_HEADER_8_BIT;
+            break;
+        case coap_tcp_16bit:
+            length = COAP_TCP_HEADER_16_BIT;
+            break;
+        case coap_tcp_32bit:
+            length = COAP_TCP_HEADER_32_BIT;
+            break;
+#endif
+        default:
+            debug("it has wrong type\n");
+    }
+
+#ifndef WITH_TCP
     assert(size <= COAP_MAX_PDU_SIZE);
     /* Size must be large enough to fit the header. */
-    if (size < sizeof(coap_hdr_t) || size > COAP_MAX_PDU_SIZE)
+    if (size < length || size > COAP_MAX_PDU_SIZE)
         return NULL;
+#endif
 
     /* size must be large enough for hdr */
 #if defined(WITH_POSIX) || defined(WITH_ARDUINO)
@@ -120,10 +159,38 @@ coap_pdu_init(unsigned char type, unsigned char code, unsigned short id, size_t
 #endif
     if (pdu)
     {
-        coap_pdu_clear(pdu, size);
-        pdu->hdr->id = id;
-        pdu->hdr->type = type;
-        pdu->hdr->code = code;
+        coap_pdu_clear(pdu, size, transport, length);
+
+        switch(transport)
+        {
+            case coap_udp:
+                pdu->hdr->coap_hdr_udp_t.id = id;
+                pdu->hdr->coap_hdr_udp_t.type = type;
+                pdu->hdr->coap_hdr_udp_t.code = code;
+                break;
+#ifdef WITH_TCP
+            case coap_tcp:
+                pdu->hdr->coap_hdr_tcp_t.message_length = 0;
+                pdu->hdr->coap_hdr_tcp_t.code = code;
+                break;
+            case coap_tcp_8bit:
+                pdu->hdr->coap_hdr_tcp_8bit_t.message_length = COAP_TCP_LENGTH_FIELD_NUM_8_BIT;
+                pdu->hdr->coap_hdr_tcp_8bit_t.length_byte = 0;
+                pdu->hdr->coap_hdr_tcp_8bit_t.code = code;
+                break;
+            case coap_tcp_16bit:
+                pdu->hdr->coap_hdr_tcp_16bit_t.header_data[0] = COAP_TCP_LENGTH_FIELD_NUM_16_BIT << 4;
+                pdu->hdr->coap_hdr_tcp_16bit_t.header_data[3] = code;
+                break;
+            case coap_tcp_32bit:
+                pdu->hdr->coap_hdr_tcp_32bit_t.header_data[0] = COAP_TCP_LENGTH_FIELD_NUM_32_BIT << 4;
+                pdu->hdr->coap_hdr_tcp_32bit_t.header_data[5] = code;
+                break;
+#endif
+            default:
+                debug("it has wrong type\n");
+        }
+
 #ifdef WITH_LWIP
         pdu->pbuf = p;
 #endif
@@ -132,14 +199,27 @@ coap_pdu_init(unsigned char type, unsigned char code, unsigned short id, size_t
 }
 
 coap_pdu_t *
-coap_new_pdu()
+coap_new_pdu(coap_transport_type transport, unsigned int size)
 {
     coap_pdu_t *pdu;
 
 #ifndef WITH_CONTIKI
-    pdu = coap_pdu_init(0, 0, ntohs(COAP_INVALID_TID), COAP_MAX_PDU_SIZE);
+    pdu = coap_pdu_init(0, 0,
+                        ntohs(COAP_INVALID_TID),
+#ifndef WITH_TCP
+                        COAP_MAX_PDU_SIZE,
+#else
+                        size,
+#endif
+                        transport);
 #else /* WITH_CONTIKI */
-    pdu = coap_pdu_init(0, 0, uip_ntohs(COAP_INVALID_TID), COAP_MAX_PDU_SIZE);
+    pdu = coap_pdu_init(0, 0, uip_ntohs(COAP_INVALID_TID),
+#ifndef WITH_TCP
+                        COAP_MAX_PDU_SIZE,
+#else
+                        size,
+#endif
+                        transport);
 #endif /* WITH_CONTIKI */
 
 #ifndef NDEBUG
@@ -163,26 +243,338 @@ void coap_delete_pdu(coap_pdu_t *pdu)
 #endif
 }
 
-int coap_add_token(coap_pdu_t *pdu, size_t len, const unsigned char *data)
+#ifdef WITH_TCP
+coap_transport_type coap_get_tcp_header_type_from_size(unsigned int size)
+{
+    if (COAP_TCP_LENGTH_LIMIT_8_BIT < size && COAP_TCP_LENGTH_LIMIT_16_BIT >= size)
+    {
+        return coap_tcp_8bit;
+    }
+    else if (COAP_TCP_LENGTH_LIMIT_16_BIT < size && COAP_TCP_LENGTH_LIMIT_32_BIT >= size)
+    {
+        return coap_tcp_16bit;
+    }
+    else if (COAP_TCP_LENGTH_LIMIT_32_BIT < size)
+    {
+        return coap_tcp_32bit;
+    }
+    else
+    {
+        return coap_tcp;
+    }
+}
+
+coap_transport_type coap_get_tcp_header_type_from_initbyte(unsigned int length)
+{
+    coap_transport_type type;
+    switch(length)
+    {
+        case COAP_TCP_LENGTH_FIELD_NUM_8_BIT:
+            type = coap_tcp_8bit;
+            break;
+        case COAP_TCP_LENGTH_FIELD_NUM_16_BIT:
+            type = coap_tcp_16bit;
+            break;
+        case COAP_TCP_LENGTH_FIELD_NUM_32_BIT:
+            type = coap_tcp_32bit;
+            break;
+        default:
+            type = coap_tcp;
+    }
+    return type;
+}
+
+void coap_add_length(const coap_pdu_t *pdu, coap_transport_type transport, unsigned int length)
+{
+    assert(pdu);
+
+    switch(transport)
+    {
+        case coap_tcp:
+            pdu->hdr->coap_hdr_tcp_t.message_length = length;
+            break;
+        case coap_tcp_8bit:
+            if (length > COAP_TCP_LENGTH_FIELD_8_BIT)
+            {
+                pdu->hdr->coap_hdr_tcp_8bit_t.length_byte =
+                        length - COAP_TCP_LENGTH_FIELD_8_BIT;
+            }
+            break;
+        case coap_tcp_16bit:
+            if (length > COAP_TCP_LENGTH_FIELD_16_BIT)
+            {
+                unsigned int total_length = length - COAP_TCP_LENGTH_FIELD_16_BIT;
+                pdu->hdr->coap_hdr_tcp_16bit_t.header_data[1] = (total_length >> 8) & 0x0000ff;
+                pdu->hdr->coap_hdr_tcp_16bit_t.header_data[2] = total_length & 0x000000ff;
+            }
+            break;
+        case coap_tcp_32bit:
+            if (length > COAP_TCP_LENGTH_FIELD_32_BIT)
+            {
+                unsigned int total_length = length - COAP_TCP_LENGTH_FIELD_32_BIT;
+                pdu->hdr->coap_hdr_tcp_32bit_t.header_data[1] = total_length >> 24;
+                pdu->hdr->coap_hdr_tcp_32bit_t.header_data[2] = (total_length >> 16) & 0x00ff;
+                pdu->hdr->coap_hdr_tcp_32bit_t.header_data[3] = (total_length >> 8) & 0x0000ff;
+                pdu->hdr->coap_hdr_tcp_32bit_t.header_data[4] = total_length & 0x000000ff;
+            }
+            break;
+        default:
+            debug("it has wrong type\n");
+    }
+}
+
+unsigned int coap_get_length_from_header(const unsigned char *header, coap_transport_type transport)
+{
+    assert(header);
+
+    unsigned int length = 0;
+    unsigned int length_field_data = 0;
+    switch(transport)
+    {
+        case coap_tcp_8bit:
+            length = header[1] + COAP_TCP_LENGTH_FIELD_8_BIT;
+            break;
+        case coap_tcp_16bit:
+            length_field_data = (header[1] << 8 | header[2]);
+            length = length_field_data + COAP_TCP_LENGTH_FIELD_16_BIT;
+            break;
+        case coap_tcp_32bit:
+            length_field_data = header[1] << 24 | header[2] << 16 | header[3] << 8 | header[4];
+            length = length_field_data + COAP_TCP_LENGTH_FIELD_32_BIT;
+            break;
+        default:
+            debug("it has wrong type\n");
+    }
+
+    return length;
+}
+
+unsigned int coap_get_length(const coap_pdu_t *pdu, coap_transport_type transport)
+{
+    assert(pdu);
+
+    unsigned int length = 0;
+    unsigned int length_field_data = 0;
+    switch(transport)
+    {
+        case coap_tcp:
+            length = pdu->hdr->coap_hdr_tcp_t.message_length;
+            break;
+        case coap_tcp_8bit:
+            length = pdu->hdr->coap_hdr_tcp_8bit_t.length_byte + COAP_TCP_LENGTH_FIELD_8_BIT;
+            break;
+        case coap_tcp_16bit:
+            length_field_data =
+                    pdu->hdr->coap_hdr_tcp_16bit_t.header_data[1] << 8 |
+                    pdu->hdr->coap_hdr_tcp_16bit_t.header_data[2];
+            length = length_field_data + COAP_TCP_LENGTH_FIELD_16_BIT;
+            break;
+        case coap_tcp_32bit:
+            length_field_data =
+                    pdu->hdr->coap_hdr_tcp_32bit_t.header_data[1] << 24 |
+                    pdu->hdr->coap_hdr_tcp_32bit_t.header_data[2] << 16 |
+                    pdu->hdr->coap_hdr_tcp_32bit_t.header_data[3] << 8 |
+                    pdu->hdr->coap_hdr_tcp_32bit_t.header_data[4];
+            length = length_field_data + COAP_TCP_LENGTH_FIELD_32_BIT;
+            break;
+        default:
+            debug("it has wrong type\n");
+    }
+
+    return length;
+}
+
+unsigned int coap_get_tcp_header_length(unsigned char *data)
+{
+    assert(data);
+
+    unsigned int tokenLength =  data[0] & 0x0f;
+    coap_transport_type transport =
+            coap_get_tcp_header_type_from_initbyte(data[0] >> 4);
+    unsigned int length = 0;
+
+    length = coap_get_tcp_header_length_for_transport(transport) + tokenLength;
+    return length;
+}
+
+unsigned int coap_get_tcp_header_length_for_transport(coap_transport_type transport)
+{
+    unsigned int length = 0;
+    switch(transport)
+    {
+        case coap_tcp:
+            length = COAP_TCP_HEADER_NO_FIELD;
+            break;
+        case coap_tcp_8bit:
+            length = COAP_TCP_HEADER_8_BIT;
+            break;
+        case coap_tcp_16bit:
+            length = COAP_TCP_HEADER_16_BIT;
+            break;
+        case coap_tcp_32bit:
+            length = COAP_TCP_HEADER_32_BIT;
+            break;
+        default:
+            debug("it has wrong type\n");
+    }
+
+    return length;
+}
+
+#endif
+
+void coap_add_code(const coap_pdu_t *pdu, coap_transport_type transport, unsigned int code)
+{
+    assert(pdu);
+
+    switch(transport)
+    {
+        case coap_udp:
+            pdu->hdr->coap_hdr_udp_t.code = COAP_RESPONSE_CODE(code);
+            break;
+#ifdef WITH_TCP
+        case coap_tcp:
+            pdu->hdr->coap_hdr_tcp_t.code = COAP_RESPONSE_CODE(code);
+            break;
+        case coap_tcp_8bit:
+            pdu->hdr->coap_hdr_tcp_8bit_t.code = COAP_RESPONSE_CODE(code);
+            break;
+        case coap_tcp_16bit:
+            pdu->hdr->coap_hdr_tcp_16bit_t.header_data[3] = COAP_RESPONSE_CODE(code);
+            break;
+        case coap_tcp_32bit:
+            pdu->hdr->coap_hdr_tcp_32bit_t.header_data[5] = COAP_RESPONSE_CODE(code);
+            break;
+#endif
+        default:
+            debug("it has wrong type\n");
+    }
+}
+
+unsigned int coap_get_code(const coap_pdu_t *pdu, coap_transport_type transport)
+{
+    assert(pdu);
+
+    unsigned int code = 0;
+    switch(transport)
+    {
+        case coap_udp:
+            code = pdu->hdr->coap_hdr_udp_t.code;
+            break;
+#ifdef WITH_TCP
+        case coap_tcp:
+            code = pdu->hdr->coap_hdr_tcp_t.code;
+            break;
+        case coap_tcp_8bit:
+            code = pdu->hdr->coap_hdr_tcp_8bit_t.code;
+            break;
+        case coap_tcp_16bit:
+            code = pdu->hdr->coap_hdr_tcp_16bit_t.header_data[3];
+            break;
+        case coap_tcp_32bit:
+            code = pdu->hdr->coap_hdr_tcp_32bit_t.header_data[5];
+            break;
+#endif
+        default:
+            debug("it has wrong type\n");
+    }
+    return code;
+}
+
+int coap_add_token(coap_pdu_t *pdu, size_t len, const unsigned char *data,
+                   coap_transport_type transport)
 {
     const size_t HEADERLENGTH = len + 4;
     /* must allow for pdu == NULL as callers may rely on this */
     if (!pdu || len > 8 || pdu->max_size < HEADERLENGTH)
         return 0;
 
-    pdu->hdr->token_length = len;
+    unsigned char* token = NULL;
+    switch(transport)
+    {
+        case coap_udp:
+            pdu->hdr->coap_hdr_udp_t.token_length = len;
+            token = pdu->hdr->coap_hdr_udp_t.token;
+            pdu->length = HEADERLENGTH;
+            break;
+#ifdef WITH_TCP
+        case coap_tcp:
+            pdu->hdr->coap_hdr_tcp_t.token_length = len;
+            token = pdu->hdr->coap_hdr_tcp_t.token;
+            pdu->length = len + COAP_TCP_HEADER_NO_FIELD;
+            break;
+        case coap_tcp_8bit:
+            pdu->hdr->coap_hdr_tcp_8bit_t.token_length = len;
+            token = pdu->hdr->coap_hdr_tcp_8bit_t.token;
+            pdu->length = len + COAP_TCP_HEADER_8_BIT;
+            break;
+        case coap_tcp_16bit:
+            pdu->hdr->coap_hdr_tcp_16bit_t.header_data[0] =
+                    pdu->hdr->coap_hdr_tcp_16bit_t.header_data[0] | len;
+            token = pdu->hdr->coap_hdr_tcp_16bit_t.token;
+            pdu->length = len + COAP_TCP_HEADER_16_BIT;
+            break;
+        case coap_tcp_32bit:
+            pdu->hdr->coap_hdr_tcp_32bit_t.header_data[0] =
+                    pdu->hdr->coap_hdr_tcp_32bit_t.header_data[0] | len;
+            token = pdu->hdr->coap_hdr_tcp_32bit_t.token;
+            pdu->length = len + COAP_TCP_HEADER_32_BIT;
+            break;
+#endif
+        default:
+            debug("it has wrong type\n");
+    }
+
     if (len)
-        memcpy(pdu->hdr->token, data, len);
+    {
+        memcpy(token, data, len);
+    }
+
     pdu->max_delta = 0;
-    pdu->length = HEADERLENGTH;
     pdu->data = NULL;
 
     return 1;
 }
 
+void coap_get_token(const coap_hdr_t *pdu_hdr, coap_transport_type transport,
+                    unsigned char **token, unsigned int *token_length)
+{
+    assert(pdu_hdr);
+    assert(token);
+    assert(token_length);
+
+    switch(transport)
+    {
+        case coap_udp:
+            *token_length = pdu_hdr->coap_hdr_udp_t.token_length;
+            *token = (unsigned char *)pdu_hdr->coap_hdr_udp_t.token;
+            break;
+#ifdef WITH_TCP
+        case coap_tcp:
+            *token_length = pdu_hdr->coap_hdr_tcp_t.token_length;
+            *token = (unsigned char *)pdu_hdr->coap_hdr_tcp_t.token;
+            break;
+        case coap_tcp_8bit:
+            *token_length = pdu_hdr->coap_hdr_tcp_8bit_t.token_length;
+            *token = (unsigned char *)pdu_hdr->coap_hdr_tcp_8bit_t.token;
+            break;
+        case coap_tcp_16bit:
+            *token_length = (pdu_hdr->coap_hdr_tcp_16bit_t.header_data[0]) & 0x0f;
+            *token = (unsigned char *)pdu_hdr->coap_hdr_tcp_16bit_t.token;
+            break;
+        case coap_tcp_32bit:
+            *token_length = (pdu_hdr->coap_hdr_tcp_32bit_t.header_data[0]) & 0x0f;
+            *token = (unsigned char *)pdu_hdr->coap_hdr_tcp_32bit_t.token;
+            break;
+#endif
+        default:
+            debug("it has wrong type\n");
+    }
+}
+
 /** @FIXME de-duplicate code with coap_add_option_later */
 size_t coap_add_option(coap_pdu_t *pdu, unsigned short type, unsigned int len,
-        const unsigned char *data)
+        const unsigned char *data, coap_transport_type transport)
 {
     size_t optsize;
     coap_opt_t *opt;
@@ -196,7 +588,26 @@ size_t coap_add_option(coap_pdu_t *pdu, unsigned short type, unsigned int len,
         return 0;
     }
 
-    opt = (unsigned char *) pdu->hdr + pdu->length;
+    switch(transport)
+    {
+#ifdef WITH_TCP
+        case coap_tcp:
+            opt = (unsigned char *) &(pdu->hdr->coap_hdr_tcp_t) + pdu->length;
+            break;
+        case coap_tcp_8bit:
+            opt = (unsigned char *) &(pdu->hdr->coap_hdr_tcp_8bit_t) + pdu->length;
+            break;
+        case coap_tcp_16bit:
+            opt = (unsigned char *) &(pdu->hdr->coap_hdr_tcp_16bit_t) + pdu->length;
+            break;
+        case coap_tcp_32bit:
+            opt = (unsigned char *) &(pdu->hdr->coap_hdr_tcp_32bit_t) + pdu->length;
+            break;
+#endif
+        default:
+            opt = (unsigned char *) &(pdu->hdr->coap_hdr_udp_t) + pdu->length;
+            break;
+    }
 
     /* encode option and check length */
     optsize = coap_opt_encode(opt, pdu->max_size - pdu->length, type - pdu->max_delta, data, len);
@@ -368,10 +779,9 @@ static size_t next_option_safe(coap_opt_t **optp, size_t *length, coap_option_t*
     return optsize;
 }
 
-int coap_pdu_parse(unsigned char *data, size_t length, coap_pdu_t *pdu)
+int coap_pdu_parse(unsigned char *data, size_t length, coap_pdu_t *pdu,
+                   coap_transport_type transport)
 {
-    coap_opt_t *opt;
-
     assert(data);
     assert(pdu);
 
@@ -379,58 +789,134 @@ int coap_pdu_parse(unsigned char *data, size_t length, coap_pdu_t *pdu)
     {
         debug("insufficient space to store parsed PDU\n");
         printf("[COAP] insufficient space to store parsed PDU\n");
-        return 0;
+        return -1;
     }
 
-    if (length < sizeof(coap_hdr_t))
+    unsigned int headerSize = 0;
+
+    if (coap_udp == transport)
+    {
+        headerSize = sizeof(pdu->hdr->coap_hdr_udp_t);
+    }
+#ifdef WITH_TCP
+    else
+    {
+        headerSize = coap_get_tcp_header_length_for_transport(transport);
+    }
+#endif
+
+    if (length < headerSize)
     {
         debug("discarded invalid PDU\n");
     }
 
-    pdu->hdr->version = data[0] >> 6;
-    pdu->hdr->type = (data[0] >> 4) & 0x03;
-    pdu->hdr->token_length = data[0] & 0x0f;
-    pdu->hdr->code = data[1];
-    /*
-     printf("[COAP] pdu - version : %d\n", pdu->hdr->version);
-     printf("[COAP] pdu - type : %d\n", pdu->hdr->type);
-     printf("[COAP] pdu - token_length : %d\n", pdu->hdr->token_length);
-     printf("[COAP] pdu - code : %d\n", pdu->hdr->code);
-     */
-    pdu->data = NULL;
+    coap_opt_t *opt = NULL;
+    unsigned int tokenLength = 0;
+#ifdef WITH_TCP
+    switch(transport)
+    {
+        case coap_udp:
+            break;
+        case coap_tcp:
+            pdu->hdr->coap_hdr_tcp_t.message_length = data[0] >> 4;
+            pdu->hdr->coap_hdr_tcp_t.token_length = data[0] & 0x0f;
+            pdu->hdr->coap_hdr_tcp_t.code = data[1];
+            tokenLength = pdu->hdr->coap_hdr_tcp_t.token_length;
+            opt = (unsigned char *) (&(pdu->hdr->coap_hdr_tcp_t) + 1) + tokenLength;
+            break;
+        case coap_tcp_8bit:
+            pdu->hdr->coap_hdr_tcp_8bit_t.message_length = data[0] >> 4;
+            pdu->hdr->coap_hdr_tcp_8bit_t.token_length = data[0] & 0x0f;
+            pdu->hdr->coap_hdr_tcp_8bit_t.length_byte = data[1];
+            pdu->hdr->coap_hdr_tcp_8bit_t.code = data[2];
+            tokenLength = pdu->hdr->coap_hdr_tcp_8bit_t.token_length;
+            opt = (unsigned char *) (&(pdu->hdr->coap_hdr_tcp_8bit_t))
+                    + tokenLength + COAP_TCP_HEADER_8_BIT;
+            break;
+        case coap_tcp_16bit:
+            for (size_t i = 0 ; i < headerSize ; i++)
+            {
+                pdu->hdr->coap_hdr_tcp_16bit_t.header_data[i] = data[i];
+            }
+
+            tokenLength = data[0] & 0x0f;
+            opt = (unsigned char *) (&(pdu->hdr->coap_hdr_tcp_16bit_t) + 1) + tokenLength;
+            break;
+        case coap_tcp_32bit:
+            for (size_t i = 0 ; i < headerSize ; i++)
+            {
+                pdu->hdr->coap_hdr_tcp_32bit_t.header_data[i] = data[i];
+            }
+
+            tokenLength = data[0] & 0x0f;
+            opt = ((unsigned char *) &(pdu->hdr->coap_hdr_tcp_32bit_t)) +
+                    headerSize + tokenLength;
+            break;
+        default:
+            printf("it has wrong type\n");
+    }
+#endif
+    pdu->length = length;
 
-    /* sanity checks */
-    if (pdu->hdr->code == 0)
+    if (coap_udp == transport)
     {
-        if (length != sizeof(coap_hdr_t) || pdu->hdr->token_length)
+        pdu->hdr->coap_hdr_udp_t.version = data[0] >> 6;
+        pdu->hdr->coap_hdr_udp_t.type = (data[0] >> 4) & 0x03;
+        pdu->hdr->coap_hdr_udp_t.token_length = data[0] & 0x0f;
+        pdu->hdr->coap_hdr_udp_t.code = data[1];
+        pdu->data = NULL;
+
+        tokenLength = pdu->hdr->coap_hdr_udp_t.token_length;
+
+        /* sanity checks */
+        if (pdu->hdr->coap_hdr_udp_t.code == 0)
+        {
+            if (length != headerSize || tokenLength)
+            {
+                debug("coap_pdu_parse: empty message is not empty\n");
+                goto discard;
+            }
+        }
+
+        if (length < headerSize + tokenLength || tokenLength > 8)
         {
-            debug("coap_pdu_parse: empty message is not empty\n");
+            debug("coap_pdu_parse: invalid Token\n");
             goto discard;
         }
-    }
 
-    if (length < sizeof(coap_hdr_t) + pdu->hdr->token_length || pdu->hdr->token_length > 8)
-    {
-        debug("coap_pdu_parse: invalid Token\n");
-        goto discard;
-    }
+        memcpy(&pdu->hdr->coap_hdr_udp_t.id, data + 2, 2);
 
-    /* Copy message id in network byte order, so we can easily write the
-     * response back to the network. */
-    memcpy(&pdu->hdr->id, data + 2, 2);
+        /* Finally calculate beginning of data block and thereby check integrity
+         * of the PDU structure. */
 
-    //printf("[COAP] pdu - id : %d\n", pdu->hdr->id);
+        /* append data (including the Token) to pdu structure */
+        memcpy(&(pdu->hdr->coap_hdr_udp_t) + 1, data + headerSize, length - headerSize);
 
-    /* append data (including the Token) to pdu structure */
-    memcpy(pdu->hdr + 1, data + sizeof(coap_hdr_t), length - sizeof(coap_hdr_t));
-    pdu->length = length;
+        /* skip header + token */
+        length -= (tokenLength + headerSize);
+        opt = (unsigned char *) (&(pdu->hdr->coap_hdr_udp_t) + 1) + tokenLength;
+    }
+#ifdef WITH_TCP
+    else // common for tcp header setting
+    {
+        pdu->data = NULL;
+
+        if (length < headerSize + tokenLength || tokenLength > 8)
+        {
+            debug("coap_pdu_parse: invalid Token\n");
+            goto discard;
+        }
+        /* Finally calculate beginning of data block and thereby check integrity
+         * of the PDU structure. */
 
-    /* Finally calculate beginning of data block and thereby check integrity
-     * of the PDU structure. */
+        /* append data (including the Token) to pdu structure */
+        memcpy(((unsigned char *) pdu->hdr) + headerSize,
+               data + headerSize, length - headerSize);
 
-    /* skip header + token */
-    length -= (pdu->hdr->token_length + sizeof(coap_hdr_t));
-    opt = (unsigned char *) (pdu->hdr + 1) + pdu->hdr->token_length;
+        /* skip header + token */
+        length -= (tokenLength + headerSize);
+    }
+#endif
 
     while (length && *opt != COAP_PAYLOAD_START)
     {
@@ -457,7 +943,8 @@ int coap_pdu_parse(unsigned char *data, size_t length, coap_pdu_t *pdu)
         }
 
         debug(
-                "set data to %p (pdu ends at %p)\n", (unsigned char *)opt, (unsigned char *)pdu->hdr + pdu->length);
+                "set data to %p (pdu ends at %p)\n", (unsigned char *)opt,
+                (unsigned char *)pdu->hdr + pdu->length);
         pdu->data = (unsigned char *) opt;
         //printf("[COAP] pdu - data : %s\n", pdu->data);
     }
index e10be71..77dd6f6 100644 (file)
@@ -161,32 +161,128 @@ char *coap_response_phrase(unsigned char code);
 typedef int coap_tid_t;
 #define COAP_INVALID_TID -1
 
+#define COAP_TCP_HEADER_NO_FIELD    2
+#define COAP_TCP_HEADER_8_BIT       3
+#define COAP_TCP_HEADER_16_BIT      4
+#define COAP_TCP_HEADER_32_BIT      6
+
+#define COAP_TCP_LENGTH_FIELD_8_BIT      13
+#define COAP_TCP_LENGTH_FIELD_16_BIT     269
+#define COAP_TCP_LENGTH_FIELD_32_BIT     65805
+
+#define COAP_TCP_LENGTH_LIMIT_8_BIT      13
+#define COAP_TCP_LENGTH_LIMIT_16_BIT     256
+#define COAP_TCP_LENGTH_LIMIT_32_BIT     65536
+
+#define COAP_TCP_LENGTH_FIELD_NUM_8_BIT      13
+#define COAP_TCP_LENGTH_FIELD_NUM_16_BIT     14
+#define COAP_TCP_LENGTH_FIELD_NUM_32_BIT     15
+
+typedef enum
+{
+    coap_udp = 0,
+    coap_tcp,
+    coap_tcp_8bit,
+    coap_tcp_16bit,
+    coap_tcp_32bit
+} coap_transport_type;
+
 #ifdef WORDS_BIGENDIAN
-typedef struct
+typedef union
 {
-    unsigned int version:2; /* protocol version */
-    unsigned int type:2; /* type flag */
-    unsigned int token_length:4; /* length of Token */
-    unsigned int code:8; /* request method (value 1--10) or response code (value 40-255) */
-    unsigned short id; /* message id */
-    unsigned char token[]; /* the actual token, if any */
+    typedef struct
+    {
+        unsigned int version:2; /* protocol version */
+        unsigned int type:2; /* type flag */
+        unsigned int token_length:4; /* length of Token */
+        unsigned int code:8; /* request method (value 1--10) or response code (value 40-255) */
+        unsigned short id; /* message id */
+        unsigned char token[]; /* the actual token, if any */
+    } coap_hdr_udp_t;
+
+
+    struct
+    {
+        unsigned int message_length :4; /* length of message */
+        unsigned int token_length :4;   /* length of Token */
+        unsigned int code :8; /* request method (value 1--10) or response code (value 40-255) */
+        unsigned char token[]; /* the actual token, if any */
+    } coap_hdr_tcp_t;
+
+    struct
+    {
+        unsigned int message_length :4; /* length of message */
+        unsigned int token_length :4;   /* length of Token */
+        unsigned int length_byte :8;       /* extend length of message */
+        unsigned int code :8; /* request method (value 1--10) or response code (value 40-255) */
+        unsigned char token[]; /* the actual token, if any */
+    } coap_hdr_tcp_8bit_t;
+
+    struct
+    {
+        unsigned int message_length :4; /* length of message */
+        unsigned int token_length :4;   /* length of Token */
+        unsigned short length_byte :16;       /* extend length of message */
+        unsigned int code :8; /* request method (value 1--10) or response code (value 40-255) */
+        unsigned char token[]; /* the actual token, if any */
+    } coap_hdr_tcp_16bit_t;
+
+    struct
+    {
+        unsigned char header_data[6];
+        unsigned char token[]; /* the actual token, if any */
+    } coap_hdr_tcp_32bit_t;
+
 } coap_hdr_t;
 #else
-typedef struct
+typedef union
 {
-    unsigned int token_length :4; /* length of Token */
-    unsigned int type :2; /* type flag */
-    unsigned int version :2; /* protocol version */
-    unsigned int code :8; /* request method (value 1--10) or response code (value 40-255) */
-    unsigned short id; /* transaction id (network byte order!) */
-    unsigned char token[]; /* the actual token, if any */
+    struct
+    {
+        unsigned int token_length :4; /* length of Token */
+        unsigned int type :2; /* type flag */
+        unsigned int version :2; /* protocol version */
+        unsigned int code :8; /* request method (value 1--10) or response code (value 40-255) */
+        unsigned short id; /* transaction id (network byte order!) */
+        unsigned char token[]; /* the actual token, if any */
+    } coap_hdr_udp_t;
+
+    struct
+    {
+        unsigned int token_length :4;   /* length of Token */
+        unsigned int message_length :4; /* length of message */
+        unsigned int code :8; /* request method (value 1--10) or response code (value 40-255) */
+        unsigned char token[]; /* the actual token, if any */
+    } coap_hdr_tcp_t;
+
+    struct
+    {
+        unsigned int token_length :4;   /* length of Token */
+        unsigned int message_length :4; /* length of message */
+        unsigned int length_byte :8;       /* extend length of message */
+        unsigned int code :8; /* request method (value 1--10) or response code (value 40-255) */
+        unsigned char token[]; /* the actual token, if any */
+    } coap_hdr_tcp_8bit_t;
+
+    struct
+    {
+        unsigned char header_data[COAP_TCP_HEADER_16_BIT];
+        unsigned char token[]; /* the actual token, if any */
+    } coap_hdr_tcp_16bit_t;
+
+    struct
+    {
+        unsigned char header_data[COAP_TCP_HEADER_32_BIT];
+        unsigned char token[]; /* the actual token, if any */
+    } coap_hdr_tcp_32bit_t;
+
 } coap_hdr_t;
 #endif
 
-#define COAP_MESSAGE_IS_EMPTY(MSG)    ((MSG)->code == 0)
+#define COAP_MESSAGE_IS_EMPTY(MSG)    ((MSG).code == 0)
 #define COAP_MESSAGE_IS_REQUEST(MSG)  (!COAP_MESSAGE_IS_EMPTY(MSG)  \
-                       && ((MSG)->code < 32))
-#define COAP_MESSAGE_IS_RESPONSE(MSG) ((MSG)->code >= 64 && (MSG)->code <= 191)
+                       && ((MSG).code < 32))
+#define COAP_MESSAGE_IS_RESPONSE(MSG) ((MSG).code >= 64 && (MSG).code <= 191)
 
 #define COAP_OPT_LONG 0x0F  /* OC == 0b1111 indicates that the option list in a
                  * CoAP message is limited by 0b11110000 marker */
@@ -218,7 +314,7 @@ typedef struct
 
     coap_hdr_t *hdr;
     unsigned short max_delta; /**< highest option number */
-    unsigned short length; /**< PDU length (including header, options, data)  */
+    unsigned int length; /**< PDU length (including header, options, data)  */
     unsigned char *data; /**< payload */
 
 #ifdef WITH_LWIP
@@ -263,11 +359,13 @@ coap_pdu_t * coap_pdu_from_pbuf(struct pbuf *pbuf);
  * @param code The message code.
  * @param id   The message id to set or COAP_INVALID_TID if unknown.
  * @param size The number of bytes to allocate for the actual message.
+ * @param transport The transport type.
  *
  * @return A pointer to the new PDU object or @c NULL on error.
  */
 coap_pdu_t *
-coap_pdu_init(unsigned char type, unsigned char code, unsigned short id, size_t size);
+coap_pdu_init(unsigned char type, unsigned char code, unsigned short id,
+              size_t size, coap_transport_type transport);
 
 /**
  * Clears any contents from @p pdu and resets @c version field, @c
@@ -275,7 +373,8 @@ coap_pdu_init(unsigned char type, unsigned char code, unsigned short id, size_t
  * other field is set to @c 0. Note that @p pdu must be a valid
  * pointer to a coap_pdu_t object created e.g. by coap_pdu_init().
  */
-void coap_pdu_clear(coap_pdu_t *pdu, size_t size);
+void coap_pdu_clear(coap_pdu_t *pdu, size_t size, coap_transport_type transport,
+                    unsigned int length);
 
 /**
  * Creates a new CoAP PDU. The object is created on the heap and must be released
@@ -284,7 +383,7 @@ void coap_pdu_clear(coap_pdu_t *pdu, size_t size);
  * @deprecated This function allocates the maximum storage for each
  * PDU. Use coap_pdu_init() instead.
  */
-coap_pdu_t *coap_new_pdu();
+coap_pdu_t *coap_new_pdu(coap_transport_type transport, unsigned int size);
 
 void coap_delete_pdu(coap_pdu_t *);
 
@@ -298,23 +397,117 @@ void coap_delete_pdu(coap_pdu_t *);
  * @param result The PDU structure to fill. Note that the structure must
  *               provide space for at least @p length bytes to hold the
  *               entire CoAP PDU.
+ * @param transport The transport type.
  * @return A value greater than zero on success or @c 0 on error.
  */
-int coap_pdu_parse(unsigned char *data, size_t length, coap_pdu_t *result);
+int coap_pdu_parse(unsigned char *data, size_t length, coap_pdu_t *pdu,
+                   coap_transport_type transport);
+
+#ifdef WITH_TCP
+/**
+ * Get transport type of coap header for coap over tcp through payload size.
+ *
+ * @param size   payload size of pdu.
+ * @return The transport type.
+ */
+coap_transport_type coap_get_tcp_header_type_from_size(unsigned int size);
+
+/**
+ * Get transport type of coap header for coap over tcp through init-byte.
+ *
+ * @param legnth   length value of init byte.
+* @return The transport type.
+ */
+coap_transport_type coap_get_tcp_header_type_from_initbyte(unsigned int length);
+
+/**
+ * Add length value in field of coap header for coap over tcp.
+ *
+ * @param pdu  The pdu pointer.
+ * @param transport The transport type.
+ * @param length  length value of init byte.
+ */
+void coap_add_length(const coap_pdu_t *pdu, coap_transport_type transport,
+                     unsigned int length);
+
+/**
+ * Get the value of length field of coap header for coap over tcp.
+ *
+ * @param pdu  The pdu pointer.
+ * @param transport The transport type.
+ * @return length value of init byte.
+ */
+unsigned int coap_get_length(const coap_pdu_t *pdu, coap_transport_type transport);
 
 /**
+ * Get pdu length from header of coap over tcp.
+ *
+ * @param header   The header to parse.
+ * @return transport The transport type.
+ */
+unsigned int coap_get_length_from_header(const unsigned char *header, coap_transport_type transport);
+
+/**
+ * Get length of header for coap over tcp.
+ *
+ * @param data   The raw data to parse as CoAP PDU
+ * @return header length + token length
+ */
+unsigned int coap_get_tcp_header_length(unsigned char *data);
+
+/**
+ * Get length of header without token length for coap over tcp.
+ *
+ * @param transport The transport type.
+ * @return header length.
+ */
+unsigned int coap_get_tcp_header_length_for_transport(coap_transport_type transport);
+#endif
+
+/**
+ * Add code in coap header.
+ *
+ * @param pdu  The pdu pointer.
+ * @param transport The transport type.
+ * @param code  The message code.
+ */
+void coap_add_code(const coap_pdu_t *pdu, coap_transport_type transport,
+                   unsigned int code);
+
+/**
+ * Get message code from coap header
+ *
+ * @param pdu  The pdu pointer.
+ * @param transport The transport type.
+ * @return The message code.
+ */
+unsigned int coap_get_code(const coap_pdu_t *pdu, coap_transport_type transport);
+/**
  * Adds token of length @p len to @p pdu. Adding the token destroys
  * any following contents of the pdu. Hence options and data must be
  * added after coap_add_token() has been called. In @p pdu, length is
  * set to @p len + @c 4, and max_delta is set to @c 0.  This funtion
  * returns @c 0 on error or a value greater than zero on success.
  *
- * @param pdu  The PDU where the token is to be added.
+ * @param pdu  The pdu pointer.
  * @param len  The length of the new token.
  * @param data The token to add.
+ * @param transport The transport type.
  * @return A value greater than zero on success, or @c 0 on error.
  */
-int coap_add_token(coap_pdu_t *pdu, size_t len, const unsigned char *data);
+int coap_add_token(coap_pdu_t *pdu, size_t len, const unsigned char *data,
+                   coap_transport_type transport);
+
+/**
+ * Get token from coap header base on transport type
+ *
+ * @param pdu_hdr  The header pointer of PDU.
+ * @param transport The transport type.
+ * @param token  out parameter to get token.
+ * @param token_length  out parameter to get token length.
+ */
+void coap_get_token(const coap_hdr_t *pdu_hdr, coap_transport_type transport,
+                    unsigned char **token, unsigned int *token_length);
 
 /**
  * Adds option of given type to pdu that is passed as first
@@ -325,11 +518,11 @@ int coap_add_token(coap_pdu_t *pdu, size_t len, const unsigned char *data);
  * This function returns the number of bytes written or @c 0 on error.
  */
 size_t coap_add_option(coap_pdu_t *pdu, unsigned short type, unsigned int len,
-        const unsigned char *data);
+        const unsigned char *data, coap_transport_type transport);
 
 /**
  * Adds option of given type to pdu that is passed as first
- * parameter, but does not write a value. It works like coap_add_option with
+ * parameter, but does not write a val13ue. It works like coap_add_option with
  * respect to calling sequence (i.e. after token and before data).
  * This function returns a memory address to which the option data has to be
  * written before the PDU can be sent, or @c NULL on error.
index 8c3a3ec..26c2f1b 100644 (file)
@@ -469,7 +469,7 @@ void coap_hash_request_uri(const coap_pdu_t *request, coap_key_t key)
     coap_option_filter_clear(filter);
     coap_option_setb(filter, COAP_OPTION_URI_PATH);
 
-    coap_option_iterator_init((coap_pdu_t *) request, &opt_iter, filter);
+    coap_option_iterator_init((coap_pdu_t *) request, &opt_iter, filter, coap_udp);
     while ((option = coap_option_next(&opt_iter)))
         coap_hash(COAP_OPT_VALUE(option), COAP_OPT_LENGTH(option), key);
 }
@@ -757,13 +757,14 @@ static void coap_notify_observers(coap_context_t *context, coap_resource_t *r)
                 obs; obs = (coap_subscription_t *) list_item_next((void *) obs))
         {
             if (r->dirty == 0 && obs->dirty == 0)
-                /* running this resource due to partiallydirty, but this observation's notification was already enqueued */
+                /* running this resource due to partiallydirty,
+                 * but this observation's notification was already enqueued */
                 continue;
 
             coap_tid_t tid = COAP_INVALID_TID;
             obs->dirty = 0;
             /* initialize response */
-            response = coap_pdu_init(COAP_MESSAGE_CON, 0, 0, COAP_MAX_PDU_SIZE);
+            response = coap_pdu_init(COAP_MESSAGE_CON, 0, 0, COAP_MAX_PDU_SIZE, coap_udp);
             if (!response)
             {
                 obs->dirty = 1;
@@ -772,7 +773,7 @@ static void coap_notify_observers(coap_context_t *context, coap_resource_t *r)
                 continue;
             }
 
-            if (!coap_add_token(response, obs->token_length, obs->token))
+            if (!coap_add_token(response, obs->token_length, obs->token, coap_udp))
             {
                 obs->dirty = 1;
                 r->partiallydirty = 1;
@@ -784,19 +785,19 @@ static void coap_notify_observers(coap_context_t *context, coap_resource_t *r)
             token.length = obs->token_length;
             token.s = obs->token;
 
-            response->hdr->id = coap_new_message_id(context);
+            response->hdr->coap_hdr_udp_t.id = coap_new_message_id(context);
             if (obs->non && obs->non_cnt < COAP_OBS_MAX_NON)
             {
-                response->hdr->type = COAP_MESSAGE_NON;
+                response->hdr->coap_hdr_udp_t.type = COAP_MESSAGE_NON;
             }
             else
             {
-                response->hdr->type = COAP_MESSAGE_CON;
+                response->hdr->coap_hdr_udp_t.type = COAP_MESSAGE_CON;
             }
             /* fill with observer-specific data */
             h(context, r, &obs->subscriber, NULL, &token, response);
 
-            if (response->hdr->type == COAP_MESSAGE_CON)
+            if (response->hdr->coap_hdr_udp_t.type == COAP_MESSAGE_CON)
             {
                 tid = coap_send_confirmed(context, &obs->subscriber, response);
                 obs->non_cnt = 0;
@@ -807,7 +808,7 @@ static void coap_notify_observers(coap_context_t *context, coap_resource_t *r)
                 obs->non_cnt++;
             }
 
-            if (COAP_INVALID_TID == tid || response->hdr->type != COAP_MESSAGE_CON)
+            if (COAP_INVALID_TID == tid || response->hdr->coap_hdr_udp_t.type != COAP_MESSAGE_CON)
                 coap_delete_pdu(response);
             if (COAP_INVALID_TID == tid)
             {
index e5c3d24..f168d96 100644 (file)
@@ -51,9 +51,9 @@ notify(coap_context_t *context, coap_resource_t *res,
     if ( !context || !res || !sub || !(pdu = coap_new_pdu()) )
     return;
 
-    pdu->hdr->type = COAP_MESSAGE_CON;
-    pdu->hdr->id = rand(); /* use a random transaction id */
-    pdu->hdr->code = code;
+    pdu->hdr->coap_hdr_udp_t.type = COAP_MESSAGE_CON;
+    pdu->hdr->coap_hdr_udp_t.id = rand(); /* use a random transaction id */
+    pdu->hdr->coap_hdr_udp_t.code = code;
 
     /* FIXME: content-type and data (how about block?) */
     if (res->uri->host.length)
index 0f4fc25..2e040c9 100644 (file)
@@ -44,7 +44,9 @@
 #define SYSTEM_INVOKE_ERROR 127
 #define SYSTEM_ERROR -1
 
+#ifdef WITH_BWT
 #define BLOCK_SIZE(arg) (1 << ((arg) + 4))
+#endif
 
 /**
  * @def RS_IDENTITY
@@ -102,8 +104,11 @@ static CAToken_t g_last_request_token = NULL;
 
 static const char COAP_PREFIX[] =  "coap://";
 static const char COAPS_PREFIX[] = "coaps://";
+static const char COAP_TCP_PREFIX[] =  "coap+tcp://";
+
 static const uint16_t COAP_PREFIX_LEN = sizeof(COAP_PREFIX) - 1;
 static const uint16_t COAPS_PREFIX_LEN = sizeof(COAPS_PREFIX) - 1;
+static const uint16_t COAP_TCP_PREFIX_LEN = sizeof(COAP_TCP_PREFIX) - 1;
 
 static const char SECURE_INFO_DATA[] =
                                     "{\"oc\":[{\"href\":\"%s\",\"prop\":{\"rt\":[\"core.led\"],"
@@ -434,6 +439,7 @@ void send_request()
         printf("Enter the URI like below....\n");
         printf("coap://10.11.12.13:4545/resource_uri ( for IP )\n");
         printf("coap://10:11:12:13:45:45/resource_uri ( for BT )\n");
+        printf("coap+tcp://10:11:12:13:45:45/resource_uri ( for TCP )\n");
     }
     else
     {
@@ -754,6 +760,7 @@ void send_notification()
     printf("Enter the URI like below....\n");
     printf("coap://10.11.12.13:4545/resource_uri ( for IP )\n");
     printf("coap://10:11:12:13:45:45/resource_uri ( for BT )\n");
+    printf("coap+tcp://10:11:12:13:45:45/resource_uri ( for TCP )\n");
     printf("uri : ");
 
     char uri[MAX_BUF_LEN] = { 0 };
@@ -848,6 +855,7 @@ void select_network()
     printf("IP     : 0\n");
     printf("GATT   : 1\n");
     printf("RFCOMM : 2\n");
+    printf("TCP    : 4\n");
     printf("select : ");
 
     char buf[MAX_BUF_LEN] = { 0 };
@@ -858,7 +866,7 @@ void select_network()
 
     int number = buf[0] - '0';
 
-    if (number < 0 || number > 3)
+    if (number < 0 || number > 4)
     {
         printf("Invalid network type\n");
         return;
@@ -884,6 +892,7 @@ void unselect_network()
     printf("IP     : 0\n");
     printf("GATT   : 1\n");
     printf("RFCOMM : 2\n");
+    printf("TCP    : 4\n");
     printf("select : ");
 
     char buf[MAX_BUF_LEN] = { 0 };
@@ -894,7 +903,7 @@ void unselect_network()
 
     int number = buf[0] - '0';
 
-    if (number < 0 || number > 3)
+    if (number < 0 || number > 4)
     {
         printf("Invalid network type\n");
         return;
@@ -1057,12 +1066,14 @@ void request_handler(const CAEndpoint_t *object, const CARequestInfo_t *requestI
         }
     }
 
+#ifdef WITH_BWT
     // if received message is bulk data, create output file
     if ((requestInfo->info.payload) &&
             (requestInfo->info.payloadSize > BLOCK_SIZE(CA_DEFAULT_BLOCK_SIZE)))
     {
         create_file(requestInfo->info.payload, requestInfo->info.payloadSize);
     }
+#endif
 
     printf("Send response with URI\n");
     send_response(object, &requestInfo->info);
@@ -1111,12 +1122,14 @@ void response_handler(const CAEndpoint_t *object, const CAResponseInfo_t *respon
         }
     }
 
+#ifdef WITH_BWT
     // if received message is bulk data, create output file
     if ((responseInfo->info.payload) &&
             (responseInfo->info.payloadSize > BLOCK_SIZE(CA_DEFAULT_BLOCK_SIZE)))
     {
         create_file(responseInfo->info.payload, responseInfo->info.payloadSize);
     }
+#endif
 }
 
 void error_handler(const CAEndpoint_t *rep, const CAErrorInfo_t* errorInfo)
@@ -1404,6 +1417,7 @@ CAResult_t get_network_type()
     printf("IP     : 0\n");
     printf("GATT   : 1\n");
     printf("RFCOMM : 2\n");
+    printf("TCP    : 4\n");
     printf("select : ");
 
     if (CA_STATUS_OK != get_input_data(buf, MAX_BUF_LEN))
@@ -1413,25 +1427,19 @@ CAResult_t get_network_type()
 
     int number = buf[0] - '0';
 
-    number = (number < 0 || number > 3) ? 0 : 1 << number;
+    number = (number < 0 || number > 4) ? 0 : 1 << number;
 
-    if (number == 1)
-    {
-        g_selected_nw_type = CA_ADAPTER_IP;
-        return CA_STATUS_OK;
-    }
-    if (number == 2)
+    switch (number)
     {
-        g_selected_nw_type = CA_ADAPTER_GATT_BTLE;
-        return CA_STATUS_OK;
+        case CA_ADAPTER_IP:
+        case CA_ADAPTER_GATT_BTLE:
+        case CA_ADAPTER_RFCOMM_BTEDR:
+        case CA_ADAPTER_TCP:
+            g_selected_nw_type = number;
+            return CA_STATUS_OK;
+        default:
+            return CA_NOT_SUPPORTED;
     }
-    if (number == 3)
-    {
-        g_selected_nw_type = CA_ADAPTER_RFCOMM_BTEDR;
-        return CA_STATUS_OK;
-    }
-
-    return CA_NOT_SUPPORTED;
 }
 
 CAResult_t get_input_data(char *buf, int32_t length)
@@ -1537,6 +1545,12 @@ void parsing_coap_uri(const char* uri, addressSet_t* address, CATransportFlags_t
         startIndex = COAP_PREFIX_LEN;
         *flags = CA_IPV4;
     }
+    else if (strncmp(COAP_TCP_PREFIX, uri, COAP_TCP_PREFIX_LEN) == 0)
+    {
+        printf("uri has '%s' prefix\n", COAP_TCP_PREFIX);
+        startIndex = COAP_TCP_PREFIX_LEN;
+        *flags = CA_IPV4;
+    }
 
     // #2. copy uri for parse
     int32_t len = strlen(uri) - startIndex;
index 60d62de..2165802 100644 (file)
@@ -94,7 +94,9 @@ ca_common_src = [
 env.AppendUnique(CA_SRC = ca_common_src)
 
 if 'ALL' in ca_transport:
-               transports = [ 'ip_adapter', 'bt_edr_adapter', 'bt_le_adapter' ]
+               transports = [ 'ip_adapter', 'bt_edr_adapter', 'bt_le_adapter']
+               if ca_os == 'linux':
+                               transports.append ('tcp_adapter')
                if with_ra:
                                transports.append ('ra_adapter')
                env.SConscript(dirs = [
@@ -109,6 +111,9 @@ if 'BT' in ca_transport:
 if 'BLE' in ca_transport:
        env.SConscript(os.path.join(ca_path, 'bt_le_adapter/SConscript'))
 
+if 'TCP' in ca_transport:
+       env.SConscript(os.path.join(ca_path, 'tcp_adapter/SConscript'))
+
 print "Include path is %s" % env.get('CPPPATH')
 print "Files path is %s" % env.get('CA_SRC')
 if ca_os in ['android', 'tizen']:
index edbcdb1..bcbb025 100644 (file)
@@ -287,7 +287,7 @@ CAResult_t CAReceiveBlockWiseData(coap_pdu_t *pdu, const CAEndpoint_t *endpoint,
     VERIFY_NON_NULL(receivedData, TAG, "receivedData");
 
     // check if received message type is CA_MSG_RESET
-    if (CA_EMPTY == pdu->hdr->code)
+    if (CA_EMPTY == pdu->hdr->coap_hdr_udp_t.code)
     {
         OIC_LOG(DEBUG, TAG, "code is CA_EMPTY..");
 
@@ -345,12 +345,12 @@ CAResult_t CAReceiveBlockWiseData(coap_pdu_t *pdu, const CAEndpoint_t *endpoint,
     // check if there is error code
     if (!isBlock1 && !isBlock2)
     {
-        uint32_t code = CA_RESPONSE_CODE(pdu->hdr->code);
+        uint32_t code = CA_RESPONSE_CODE(pdu->hdr->coap_hdr_udp_t.code);
         if (CA_REQUEST_ENTITY_INCOMPLETE == code)
         {
             CABlockDataID_t* blockDataID = CACreateBlockDatablockId(
-                    (CAToken_t)pdu->hdr->token,
-                     pdu->hdr->token_length,
+                    (CAToken_t)pdu->hdr->coap_hdr_udp_t.token,
+                     pdu->hdr->coap_hdr_udp_t.token_length,
                      endpoint->port);
 
             if(NULL == blockDataID || NULL == blockDataID->id || blockDataID->idLength < 1)
@@ -417,8 +417,8 @@ CAResult_t CAReceiveBlockWiseData(coap_pdu_t *pdu, const CAEndpoint_t *endpoint,
             if (receivedData->responseInfo)
             {
                 CABlockDataID_t* blockDataID = CACreateBlockDatablockId(
-                        (CAToken_t)pdu->hdr->token,
-                        pdu->hdr->token_length,
+                        (CAToken_t)pdu->hdr->coap_hdr_udp_t.token,
+                        pdu->hdr->coap_hdr_udp_t.token_length,
                         endpoint->port);
                 if(NULL == blockDataID || NULL == blockDataID->id || blockDataID->idLength < 1)
                 {
@@ -470,12 +470,12 @@ CAResult_t CAProcessNextStep(const coap_pdu_t *pdu, const CAData_t *receivedData
 
             if (data->requestInfo)
             {
-                data->requestInfo->info.messageId = pdu->hdr->id;
+                data->requestInfo->info.messageId = pdu->hdr->coap_hdr_udp_t.id;
             }
 
             if (data->responseInfo)
             {
-                data->responseInfo->info.messageId = pdu->hdr->id;
+                data->responseInfo->info.messageId = pdu->hdr->coap_hdr_udp_t.id;
             }
 
             res = CAAddSendThreadQueue(data, blockID);
@@ -526,7 +526,7 @@ CAResult_t CAProcessNextStep(const coap_pdu_t *pdu, const CAData_t *receivedData
                 return res;
             }
 
-            if (CA_MSG_NONCONFIRM == pdu->hdr->type)
+            if (CA_MSG_NONCONFIRM == pdu->hdr->coap_hdr_udp_t.type)
             {
                 // remove data from list
                 res = CARemoveBlockDataFromList(blockID);
@@ -539,7 +539,7 @@ CAResult_t CAProcessNextStep(const coap_pdu_t *pdu, const CAData_t *receivedData
             break;
 
         case CA_OPTION1_NO_ACK_BLOCK:
-            if (CA_MSG_CONFIRM == pdu->hdr->type)
+            if (CA_MSG_CONFIRM == pdu->hdr->coap_hdr_udp_t.type)
             {
                 // add data to send thread
                 res = CASendBlockMessage(pdu, CA_MSG_ACKNOWLEDGE, blockWiseStatus,
@@ -553,7 +553,8 @@ CAResult_t CAProcessNextStep(const coap_pdu_t *pdu, const CAData_t *receivedData
             break;
 
         case CA_BLOCK_INCOMPLETE:
-            if (CA_MSG_CONFIRM == pdu->hdr->type || CA_MSG_ACKNOWLEDGE == pdu->hdr->type)
+            if (CA_MSG_CONFIRM == pdu->hdr->coap_hdr_udp_t.type ||
+                    CA_MSG_ACKNOWLEDGE == pdu->hdr->coap_hdr_udp_t.type)
             {
                 // add data to send thread
                 res = CASendErrorMessage(pdu, blockWiseStatus,
@@ -568,7 +569,7 @@ CAResult_t CAProcessNextStep(const coap_pdu_t *pdu, const CAData_t *receivedData
             break;
 
         case CA_BLOCK_TOO_LARGE:
-            if (CA_MSG_ACKNOWLEDGE == pdu->hdr->type)
+            if (CA_MSG_ACKNOWLEDGE == pdu->hdr->coap_hdr_udp_t.type)
             {
                 res = CASendBlockMessage(pdu, CA_MSG_CONFIRM, blockWiseStatus,
                                          blockID);
@@ -578,7 +579,7 @@ CAResult_t CAProcessNextStep(const coap_pdu_t *pdu, const CAData_t *receivedData
                     return res;
                 }
             }
-            else if (CA_MSG_CONFIRM == pdu->hdr->type)
+            else if (CA_MSG_CONFIRM == pdu->hdr->coap_hdr_udp_t.type)
             {
                 res = CASendErrorMessage(pdu, blockWiseStatus,
                                          CA_REQUEST_ENTITY_TOO_LARGE,
@@ -628,7 +629,7 @@ CAResult_t CASendBlockMessage(const coap_pdu_t *pdu, CAMessageType_t msgType,
         if (data->responseInfo)
         {
             OIC_LOG(DEBUG, TAG, "set ACK message");
-            data->responseInfo->info.messageId = pdu->hdr->id;
+            data->responseInfo->info.messageId = pdu->hdr->coap_hdr_udp_t.id;
             data->responseInfo->info.type = CA_MSG_ACKNOWLEDGE;
             if (CA_OPTION1_NO_ACK_LAST_BLOCK == status)
             {
@@ -670,7 +671,7 @@ CAResult_t CASendErrorMessage(const coap_pdu_t *pdu, uint8_t status,
     CAData_t *cloneData = NULL;
     if (data->sentData && data->sentData->responseInfo)
     {
-        data->sentData->responseInfo->info.messageId = pdu->hdr->id;
+        data->sentData->responseInfo->info.messageId = pdu->hdr->coap_hdr_udp_t.id;
         data->sentData->responseInfo->info.type = CA_MSG_ACKNOWLEDGE;
         data->sentData->responseInfo->result = responseResult;
         cloneData = CACloneCAData(data->sentData);
@@ -781,8 +782,8 @@ CAResult_t CASetNextBlockOption1(coap_pdu_t *pdu, const CAEndpoint_t *endpoint,
     OIC_LOG_V(INFO, TAG, "num:%d, M:%d, sze:%d", block.num, block.m, block.szx);
 
     CABlockDataID_t* blockDataID = CACreateBlockDatablockId(
-            (CAToken_t)pdu->hdr->token,
-            pdu->hdr->token_length,
+            (CAToken_t)pdu->hdr->coap_hdr_udp_t.token,
+            pdu->hdr->coap_hdr_udp_t.token_length,
             endpoint->port);
 
     if(NULL == blockDataID || NULL == blockDataID->id || blockDataID->idLength < 1)
@@ -837,9 +838,9 @@ CAResult_t CASetNextBlockOption1(coap_pdu_t *pdu, const CAEndpoint_t *endpoint,
 
     uint8_t blockWiseStatus = CA_BLOCK_UNKNOWN;
     // received type from remote device
-    if (CA_MSG_ACKNOWLEDGE == pdu->hdr->type)
+    if (CA_MSG_ACKNOWLEDGE == pdu->hdr->coap_hdr_udp_t.type)
     {
-        uint32_t code = CA_RESPONSE_CODE(pdu->hdr->code);
+        uint32_t code = CA_RESPONSE_CODE(pdu->hdr->coap_hdr_udp_t.code);
         if (0 == block.m &&
                 (CA_REQUEST_ENTITY_INCOMPLETE != code && CA_REQUEST_ENTITY_TOO_LARGE != code))
         {
@@ -878,7 +879,7 @@ CAResult_t CASetNextBlockOption1(coap_pdu_t *pdu, const CAEndpoint_t *endpoint,
                                                                       &(data->payloadLength));
 
         // check if received payload is exact
-        if (CA_MSG_CONFIRM == pdu->hdr->type)
+        if (CA_MSG_CONFIRM == pdu->hdr->coap_hdr_udp_t.type)
         {
             blockWiseStatus = CACheckBlockErrorType(data, &block, receivedData,
                                                     COAP_OPTION_BLOCK1, dataLen);
@@ -958,8 +959,8 @@ CAResult_t CASetNextBlockOption2(coap_pdu_t *pdu, const CAEndpoint_t *endpoint,
     VERIFY_NON_NULL(receivedData, TAG, "receivedData");
 
     CABlockDataID_t* blockDataID = CACreateBlockDatablockId(
-            (CAToken_t)pdu->hdr->token,
-            pdu->hdr->token_length,
+            (CAToken_t)pdu->hdr->coap_hdr_udp_t.token,
+            pdu->hdr->coap_hdr_udp_t.token_length,
             endpoint->port);
 
     if(NULL == blockDataID || NULL == blockDataID->id || blockDataID->idLength < 1)
@@ -1014,7 +1015,7 @@ CAResult_t CASetNextBlockOption2(coap_pdu_t *pdu, const CAEndpoint_t *endpoint,
     }
 
     uint8_t blockWiseStatus = CA_BLOCK_UNKNOWN;
-    if (0 == block.num && CA_GET == pdu->hdr->code && 0 == block.m)
+    if (0 == block.num && CA_GET == pdu->hdr->coap_hdr_udp_t.code && 0 == block.m)
     {
         OIC_LOG(INFO, TAG, "first block number");
 
@@ -1041,8 +1042,9 @@ CAResult_t CASetNextBlockOption2(coap_pdu_t *pdu, const CAEndpoint_t *endpoint,
     else
     {
         // received type from remote device
-        if (CA_MSG_ACKNOWLEDGE == pdu->hdr->type ||
-                (CA_MSG_NONCONFIRM == pdu->hdr->type && NULL != receivedData->responseInfo))
+        if (CA_MSG_ACKNOWLEDGE == pdu->hdr->coap_hdr_udp_t.type ||
+                (CA_MSG_NONCONFIRM == pdu->hdr->coap_hdr_udp_t.type &&
+                        NULL != receivedData->responseInfo))
         {
             OIC_LOG(DEBUG, TAG, "received ACK or NON");
 
@@ -1052,7 +1054,7 @@ CAResult_t CASetNextBlockOption2(coap_pdu_t *pdu, const CAEndpoint_t *endpoint,
                                                                           &(data->payloadLength));
 
             // check if received payload is exact
-            if (CA_MSG_ACKNOWLEDGE == pdu->hdr->type)
+            if (CA_MSG_ACKNOWLEDGE == pdu->hdr->coap_hdr_udp_t.type)
             {
                 blockWiseStatus = CACheckBlockErrorType(data, &block, receivedData,
                                                         COAP_OPTION_BLOCK2, dataLen);
@@ -1084,7 +1086,7 @@ CAResult_t CASetNextBlockOption2(coap_pdu_t *pdu, const CAEndpoint_t *endpoint,
                 {
                     OIC_LOG(DEBUG, TAG, "M bit is 1");
 
-                    if (CA_MSG_ACKNOWLEDGE == pdu->hdr->type)
+                    if (CA_MSG_ACKNOWLEDGE == pdu->hdr->coap_hdr_udp_t.type)
                     {
                         blockWiseStatus = CA_OPTION2_ACK;
                     }
@@ -1163,7 +1165,7 @@ CAResult_t CAUpdateBlockOptionItems(CABlockData_t *currData, const coap_pdu_t *p
 
     // update block data
     CAResult_t res = CA_STATUS_OK;
-    uint32_t code = CA_RESPONSE_CODE(pdu->hdr->code);
+    uint32_t code = CA_RESPONSE_CODE(pdu->hdr->coap_hdr_udp_t.code);
 
     if (CA_REQUEST_ENTITY_INCOMPLETE == code || CA_REQUEST_ENTITY_TOO_LARGE == code)
     {
@@ -1225,7 +1227,7 @@ CAResult_t CAUpdateBlockOptionItems(CABlockData_t *currData, const coap_pdu_t *p
         if (CA_BLOCK_INCOMPLETE != status && CA_BLOCK_TOO_LARGE != status)
         {
             // negotiate block size
-            res = CANegotiateBlockSize(currData, block, pdu->hdr->type, blockType);
+            res = CANegotiateBlockSize(currData, block, pdu->hdr->coap_hdr_udp_t.type, blockType);
             if (CA_STATUS_OK != res)
             {
                 OIC_LOG(ERROR, TAG, "negotiation has failed");
@@ -1357,7 +1359,7 @@ CAResult_t CAUpdateMessageId(coap_pdu_t *pdu, const CABlockDataID_t *blockID)
     VERIFY_NON_NULL(blockID, TAG, "blockID");
 
     // if CON message is sent, update messageId in block-wise transfer list
-    if (CA_MSG_CONFIRM == pdu->hdr->type)
+    if (CA_MSG_CONFIRM == pdu->hdr->coap_hdr_udp_t.type)
     {
         CAData_t * cadata = CAGetDataSetFromBlockDataList(blockID);
         if (!cadata)
@@ -1368,7 +1370,7 @@ CAResult_t CAUpdateMessageId(coap_pdu_t *pdu, const CABlockDataID_t *blockID)
 
         if (cadata->requestInfo)
         {
-            cadata->requestInfo->info.messageId = pdu->hdr->id;
+            cadata->requestInfo->info.messageId = pdu->hdr->coap_hdr_udp_t.id;
         }
     }
 
@@ -1393,7 +1395,7 @@ CAResult_t CAAddBlockOption(coap_pdu_t **pdu, const CAInfo_t info,
 
     OIC_LOG_V(DEBUG, TAG, "previous payload - %s", (*pdu)->data);
 
-    uint32_t code = CA_RESPONSE_CODE((*pdu)->hdr->code);
+    uint32_t code = CA_RESPONSE_CODE((*pdu)->hdr->coap_hdr_udp_t.code);
     if (CA_REQUEST_ENTITY_INCOMPLETE == code)
     {
         OIC_LOG(INFO, TAG, "don't use option");
@@ -1401,8 +1403,8 @@ CAResult_t CAAddBlockOption(coap_pdu_t **pdu, const CAInfo_t info,
     }
 
     CABlockDataID_t* blockDataID = CACreateBlockDatablockId(
-            (CAToken_t)(*pdu)->hdr->token,
-            (*pdu)->hdr->token_length,
+            (CAToken_t)(*pdu)->hdr->coap_hdr_udp_t.token,
+            (*pdu)->hdr->coap_hdr_udp_t.token_length,
             endpoint->port);
 
     if(NULL == blockDataID || NULL == blockDataID->id || blockDataID->idLength < 1)
@@ -1487,8 +1489,9 @@ CAResult_t CAAddBlockOption2(coap_pdu_t **pdu, const CAInfo_t info, size_t dataL
     CALogBlockInfo(block2);
 
     uint8_t code = 0;
-    if (CA_MSG_ACKNOWLEDGE == (*pdu)->hdr->type ||
-            (CA_MSG_NONCONFIRM == (*pdu)->hdr->type && CA_GET != (*pdu)->hdr->code))
+    if (CA_MSG_ACKNOWLEDGE == (*pdu)->hdr->coap_hdr_udp_t.type ||
+            (CA_MSG_NONCONFIRM == (*pdu)->hdr->coap_hdr_udp_t.type &&
+                    CA_GET != (*pdu)->hdr->coap_hdr_udp_t.code))
     {
         int32_t res = coap_write_block_opt(block2, COAP_OPTION_BLOCK2, *pdu, dataLength);
         switch (res)
@@ -1549,7 +1552,7 @@ CAResult_t CAAddBlockOption2(coap_pdu_t **pdu, const CAInfo_t info, size_t dataL
         }
         else
         {
-            if (CA_MSG_NONCONFIRM == (*pdu)->hdr->type)
+            if (CA_MSG_NONCONFIRM == (*pdu)->hdr->coap_hdr_udp_t.type)
             {
                 OIC_LOG(DEBUG, TAG, "NON, send next block..");
                 // update block data
@@ -1611,7 +1614,7 @@ CAResult_t CAAddBlockOption1(coap_pdu_t **pdu, const CAInfo_t info, size_t dataL
 
     CALogBlockInfo(block1);
 
-    if (CA_MSG_ACKNOWLEDGE == (*pdu)->hdr->type)
+    if (CA_MSG_ACKNOWLEDGE == (*pdu)->hdr->coap_hdr_udp_t.type)
     {
         OIC_LOG(DEBUG, TAG, "option1 and ACK msg..");
         CAResult_t res = CAAddBlockOptionImpl(*pdu, block1, COAP_OPTION_BLOCK1);
@@ -1666,7 +1669,7 @@ CAResult_t CAAddBlockOption1(coap_pdu_t **pdu, const CAInfo_t info, size_t dataL
         }
 
         // check the message type and if message type is NON, next block message will be sent
-        if (CA_MSG_NONCONFIRM == (*pdu)->hdr->type)
+        if (CA_MSG_NONCONFIRM == (*pdu)->hdr->coap_hdr_udp_t.type)
         {
             if (block1->m)
             {
@@ -1713,7 +1716,7 @@ CAResult_t CAAddBlockOptionImpl(coap_pdu_t *pdu, coap_block_t *block, uint8_t bl
     option->length = coap_encode_var_bytes(buf,
                                            ((block->num << BLOCK_NUMBER_IDX)
                                             | (block->m << BLOCK_M_BIT_IDX) | block->szx));
-    if (!coap_add_option(pdu, option->key, option->length, buf))
+    if (!coap_add_option(pdu, option->key, option->length, buf, coap_udp))
     {
         OIC_LOG(ERROR, TAG, "coap_add_option has failed");
         OICFree(option);
@@ -1740,7 +1743,7 @@ CAResult_t CAAddBlockSizeOption(coap_pdu_t *pdu, uint16_t sizeType, size_t dataL
     unsigned char value[BLOCKWISE_OPTION_BUFFER] = { 0 };
     unsigned int optionLength = coap_encode_var_bytes(value, dataLength);
 
-    if (!coap_add_option(pdu, sizeType, optionLength, value))
+    if (!coap_add_option(pdu, sizeType, optionLength, value, coap_udp))
     {
         OIC_LOG(ERROR, TAG, "failed to add size option");
         return CA_STATUS_FAILED;
@@ -1976,14 +1979,14 @@ CAData_t* CACreateNewDataSet(const coap_pdu_t *pdu, const CAEndpoint_t *endpoint
     VERIFY_NON_NULL_RET(pdu->hdr, TAG, "pdu->hdr", NULL);
     VERIFY_NON_NULL_RET(endpoint, TAG, "endpoint", NULL);
 
-    CAInfo_t responseData = { .tokenLength = pdu->hdr->token_length };
+    CAInfo_t responseData = { .tokenLength = pdu->hdr->coap_hdr_udp_t.token_length };
     responseData.token = (CAToken_t) OICMalloc(responseData.tokenLength);
     if (!responseData.token)
     {
         OIC_LOG(ERROR, TAG, "out of memory");
         return NULL;
     }
-    memcpy(responseData.token, pdu->hdr->token, responseData.tokenLength);
+    memcpy(responseData.token, pdu->hdr->coap_hdr_udp_t.token, responseData.tokenLength);
 
     CAResponseInfo_t* responseInfo = (CAResponseInfo_t*) OICCalloc(1, sizeof(CAResponseInfo_t));
     if (!responseInfo)
@@ -2237,7 +2240,7 @@ CAResult_t CAGetTokenFromBlockDataList(const coap_pdu_t *pdu, const CAEndpoint_t
 
         if (NULL != currData->sentData && NULL != currData->sentData->requestInfo)
         {
-            if (pdu->hdr->id == currData->sentData->requestInfo->info.messageId &&
+            if (pdu->hdr->coap_hdr_udp_t.id == currData->sentData->requestInfo->info.messageId &&
                     endpoint->adapter == currData->sentData->remoteEndpoint->adapter)
             {
                 if (NULL != currData->sentData->requestInfo->info.token)
index aa5f64a..f37f38e 100644 (file)
 #include "caadapternetdtls.h"
 #endif
 
+#ifdef TCP_ADAPTER
+#include "catcpadapter.h"
+#endif
+
 CAGlobals_t caglobals = { 0 };
 
 #define TAG "CA_CONN_MGR"
@@ -256,6 +260,16 @@ CAResult_t CASelectNetwork(CATransportAdapter_t interestedNetwork)
                   "CAAddNetworkType(CA_ADAPTER_REMOTE_ACCESS) function returns result : %d", res);
     }
 #endif
+
+#ifdef TCP_ADAPTER
+    else if (interestedNetwork & CA_ADAPTER_TCP)
+    {
+        res = CAAddNetworkType(CA_ADAPTER_TCP);
+        OIC_LOG_V(DEBUG, TAG,
+                  "CAAddNetworkType(CA_ADAPTER_TCP) function returns result : %d", res);
+    }
+#endif
+
     else
     {
         res = CA_NOT_SUPPORTED;
@@ -294,9 +308,20 @@ CAResult_t CAUnSelectNetwork(CATransportAdapter_t nonInterestedNetwork)
     {
         res = CARemoveNetworkType(CA_ADAPTER_REMOTE_ACCESS);
         OIC_LOG_V(DEBUG, TAG, "CARemoveNetworkType(CA_ADAPTER_REMOTE_ACCESS) function returns result : %d",
-                                                res);
+                  res);
     }
 #endif
+
+
+#ifdef TCP_ADAPTER
+    else if (nonInterestedNetwork & CA_ADAPTER_TCP)
+    {
+        res = CARemoveNetworkType(CA_ADAPTER_TCP);
+        OIC_LOG_V(DEBUG, TAG, "CARemoveNetworkType(CA_ADAPTER_TCP) function returns result : %d",
+                  res);
+    }
+#endif
+
     else
     {
         res = CA_STATUS_FAILED;
index 8f3c88c..0e06e6b 100644 (file)
 #include "caraadapter.h"
 #endif
 
-#define TAG "CA_INTRFC_CNTRLR"
-#ifdef RA_ADAPTER
-#include "caraadapter.h"
+#ifdef TCP_ADAPTER
+#include "catcpadapter.h"
 #endif
 
+#define TAG "CA_INTRFC_CNTRLR"
 
 #define CA_MEMORY_ALLOC_CHECK(arg) {if (arg == NULL) \
     {OIC_LOG(ERROR, TAG, "memory error");goto memory_error_exit;} }
 
-#ifdef RA_ADAPTER
+#ifdef TCP_ADAPTER
+#define CA_TRANSPORT_TYPE_NUM   5
+#elif RA_ADAPTER
 #define CA_TRANSPORT_TYPE_NUM   4
 #else
 #define CA_TRANSPORT_TYPE_NUM   3
@@ -78,6 +80,11 @@ static int CAGetAdapterIndex(CATransportAdapter_t cType)
             return 3;
 #endif
 
+#ifdef TCP_ADAPTER
+        case CA_ADAPTER_TCP:
+            return 4;
+#endif
+
         default:
             break;
     }
@@ -193,7 +200,10 @@ void CAInitializeAdapters(ca_thread_pool_t handle)
                    handle);
 #endif /* RA_ADAPTER */
 
-
+#ifdef TCP_ADAPTER
+    CAInitializeTCP(CARegisterCallback, CAReceivedPacketCallback, CANetworkChangedCallback,
+                    CAAdapterErrorHandleCallback, handle);
+#endif /* TCP_ADAPTER */
 }
 
 void CASetPacketReceivedCallback(CANetworkPacketReceivedCallback callback)
index 9817f05..6ca7da6 100644 (file)
@@ -156,7 +156,7 @@ static CAData_t* CAGenerateHandlerData(const CAEndpoint_t *endpoint,
             return NULL;
         }
 
-        result = CAGetResponseInfoFromPDU(data, resInfo);
+        result = CAGetResponseInfoFromPDU(data, resInfo, endpoint);
         if (CA_STATUS_OK != result)
         {
             OIC_LOG(ERROR, TAG, "CAGetResponseInfoFromPDU Failed");
@@ -185,7 +185,7 @@ static CAData_t* CAGenerateHandlerData(const CAEndpoint_t *endpoint,
             return NULL;
         }
 
-        result = CAGetRequestInfoFromPDU(data, reqInfo);
+        result = CAGetRequestInfoFromPDU(data, endpoint, reqInfo);
         if (CA_STATUS_OK != result)
         {
             OIC_LOG(ERROR, TAG, "CAGetRequestInfoFromPDU failed");
@@ -224,7 +224,7 @@ static CAData_t* CAGenerateHandlerData(const CAEndpoint_t *endpoint,
             return NULL;
         }
 
-        CAResult_t result = CAGetErrorInfoFromPDU(data, errorInfo);
+        CAResult_t result = CAGetErrorInfoFromPDU(data, endpoint, errorInfo);
         if (CA_STATUS_OK != result)
         {
             OIC_LOG(ERROR, TAG, "CAGetErrorInfoFromPDU failed");
@@ -278,7 +278,8 @@ static void CATimeoutCallback(const CAEndpoint_t *endpoint, const void *pdu, uin
     resInfo->info.type = CAGetMessageTypeFromPduBinaryData(pdu, size);
     resInfo->info.messageId = CAGetMessageIdFromPduBinaryData(pdu, size);
 
-    CAResult_t res = CAGetTokenFromPDU((const coap_hdr_t *) pdu, &(resInfo->info));
+    CAResult_t res = CAGetTokenFromPDU((const coap_hdr_t *) pdu, &(resInfo->info),
+                                       endpoint);
     if (CA_STATUS_OK != res)
     {
         OIC_LOG(ERROR, TAG, "fail to get Token from retransmission list");
@@ -420,7 +421,6 @@ static CAResult_t CAProcessSendData(const CAData_t *data)
 
     if (SEND_TYPE_UNICAST == type)
     {
-
         OIC_LOG(DEBUG,TAG,"Unicast message");
         if (NULL != data->requestInfo)
         {
@@ -446,7 +446,11 @@ static CAResult_t CAProcessSendData(const CAData_t *data)
         if (NULL != pdu)
         {
 #ifdef WITH_BWT
-            if (CA_ADAPTER_GATT_BTLE != data->remoteEndpoint->adapter)
+            if (CA_ADAPTER_GATT_BTLE != data->remoteEndpoint->adapter
+#ifdef TCP_ADAPTER
+                    && CA_ADAPTER_TCP != data->remoteEndpoint->adapter
+#endif
+                    )
             {
                 // Blockwise transfer
                 if (NULL != info)
@@ -463,7 +467,7 @@ static CAResult_t CAProcessSendData(const CAData_t *data)
                 }
             }
 #endif
-            CALogPDUInfo(pdu);
+            CALogPDUInfo(pdu, data->remoteEndpoint);
 
             res = CASendUnicastData(data->remoteEndpoint, pdu->hdr, pdu->length);
             if (CA_STATUS_OK != res)
@@ -473,15 +477,25 @@ static CAResult_t CAProcessSendData(const CAData_t *data)
                 coap_delete_pdu(pdu);
                 return res;
             }
-            // for retransmission
-            res = CARetransmissionSentData(&g_retransmissionContext, data->remoteEndpoint, pdu->hdr,
-                                           pdu->length);
-            if ((CA_STATUS_OK != res) && (CA_NOT_SUPPORTED != res))
+
+#ifdef TCP_ADAPTER
+            if (CA_ADAPTER_TCP == data->remoteEndpoint->adapter)
             {
-                //when retransmission not supported this will return CA_NOT_SUPPORTED, ignore
-                OIC_LOG_V(INFO, TAG, "retransmission is not enabled due to error, res : %d", res);
-                coap_delete_pdu(pdu);
-                return res;
+                OIC_LOG(INFO, TAG, "retransmission will be not worked");
+            }
+            else
+#endif
+            {
+                // for retransmission
+                res = CARetransmissionSentData(&g_retransmissionContext, data->remoteEndpoint, pdu->hdr,
+                                               pdu->length);
+                if ((CA_STATUS_OK != res) && (CA_NOT_SUPPORTED != res))
+                {
+                    //when retransmission not supported this will return CA_NOT_SUPPORTED, ignore
+                    OIC_LOG_V(INFO, TAG, "retransmission is not enabled due to error, res : %d", res);
+                    coap_delete_pdu(pdu);
+                    return res;
+                }
             }
 
             coap_delete_pdu(pdu);
@@ -505,7 +519,11 @@ static CAResult_t CAProcessSendData(const CAData_t *data)
             if (NULL != pdu)
             {
 #ifdef WITH_BWT
-                if (CA_ADAPTER_GATT_BTLE != data->remoteEndpoint->adapter)
+                if (CA_ADAPTER_GATT_BTLE != data->remoteEndpoint->adapter
+#ifdef TCP_ADAPTER
+                        && CA_ADAPTER_TCP != data->remoteEndpoint->adapter
+#endif
+                        )
                 {
                     // Blockwise transfer
                     CAResult_t res = CAAddBlockOption(&pdu, data->requestInfo->info,
@@ -537,7 +555,11 @@ static CAResult_t CAProcessSendData(const CAData_t *data)
             if (NULL != pdu)
             {
 #ifdef WITH_BWT
-                if (CA_ADAPTER_GATT_BTLE != data->remoteEndpoint->adapter)
+                if (CA_ADAPTER_GATT_BTLE != data->remoteEndpoint->adapter
+#ifdef TCP_ADAPTER
+                        && CA_ADAPTER_TCP != data->remoteEndpoint->adapter
+#endif
+                        )
                 {
                     // Blockwise transfer
                     if (NULL != info)
@@ -568,7 +590,10 @@ static CAResult_t CAProcessSendData(const CAData_t *data)
             return CA_SEND_FAILED;
         }
 
-        CALogPDUInfo(pdu);
+        CALogPDUInfo(pdu, data->remoteEndpoint);
+
+        OIC_LOG(DEBUG, TAG, "pdu to send :");
+        OIC_LOG_BUFFER(DEBUG, TAG,  pdu->hdr, pdu->length);
 
         res = CASendMulticastData(data->remoteEndpoint, pdu->hdr, pdu->length);
         if (CA_STATUS_OK != res)
@@ -648,10 +673,14 @@ static void CAReceivedPacketCallback(const CASecureEndpoint_t *sep,
     VERIFY_NON_NULL_VOID(sep, TAG, "remoteEndpoint");
     VERIFY_NON_NULL_VOID(data, TAG, "data");
 
+    OIC_LOG(DEBUG, TAG, "received pdu data :");
+    OIC_LOG_BUFFER(DEBUG, TAG,  data, dataLen);
+
     uint32_t code = CA_NOT_FOUND;
     CAData_t *cadata = NULL;
 
-    coap_pdu_t *pdu = (coap_pdu_t *) CAParsePDU((const char *) data, dataLen, &code);
+    coap_pdu_t *pdu = (coap_pdu_t *) CAParsePDU((const char *) data, dataLen, &code,
+                                                &(sep->endpoint));
     if (NULL == pdu)
     {
         OIC_LOG(ERROR, TAG, "Parse PDU failed");
@@ -679,28 +708,37 @@ static void CAReceivedPacketCallback(const CASecureEndpoint_t *sep,
             return;
         }
 
-        // for retransmission
-        void *retransmissionPdu = NULL;
-        CARetransmissionReceivedData(&g_retransmissionContext, cadata->remoteEndpoint, pdu->hdr,
-                                     pdu->length, &retransmissionPdu);
-
-        // get token from saved data in retransmission list
-        if (retransmissionPdu && CA_EMPTY == code)
+#ifdef TCP_ADAPTER
+        if (CA_ADAPTER_TCP == sep->endpoint.adapter)
         {
-            if (cadata->responseInfo)
+            OIC_LOG(INFO, TAG, "retransmission is not supported");
+        }
+        else
+#endif
+        {
+            // for retransmission
+            void *retransmissionPdu = NULL;
+            CARetransmissionReceivedData(&g_retransmissionContext, cadata->remoteEndpoint, pdu->hdr,
+                                         pdu->length, &retransmissionPdu);
+
+            // get token from saved data in retransmission list
+            if (retransmissionPdu && CA_EMPTY == code)
             {
-                CAInfo_t *info = &cadata->responseInfo->info;
-                CAResult_t res = CAGetTokenFromPDU((const coap_hdr_t *)retransmissionPdu,
-                                                   info);
-                if (CA_STATUS_OK != res)
+                if (cadata->responseInfo)
                 {
-                    OIC_LOG(ERROR, TAG, "fail to get Token from retransmission list");
-                    OICFree(info->token);
-                    info->tokenLength = 0;
+                    CAInfo_t *info = &cadata->responseInfo->info;
+                    CAResult_t res = CAGetTokenFromPDU((const coap_hdr_t *)retransmissionPdu,
+                                                       info, &(sep->endpoint));
+                    if (CA_STATUS_OK != res)
+                    {
+                        OIC_LOG(ERROR, TAG, "fail to get Token from retransmission list");
+                        OICFree(info->token);
+                        info->tokenLength = 0;
+                    }
                 }
             }
+            OICFree(retransmissionPdu);
         }
-        OICFree(retransmissionPdu);
     }
 
     cadata->type = SEND_TYPE_UNICAST;
@@ -709,7 +747,11 @@ static void CAReceivedPacketCallback(const CASecureEndpoint_t *sep,
     CAProcessReceivedData(cadata);
 #else
 #ifdef WITH_BWT
-    if (CA_ADAPTER_GATT_BTLE != sep->endpoint.adapter)
+    if (CA_ADAPTER_GATT_BTLE != sep->endpoint.adapter
+#ifdef TCP_ADAPTER
+            && CA_ADAPTER_TCP != sep->endpoint.adapter
+#endif
+            )
     {
         CAResult_t res = CAReceiveBlockWiseData(pdu, &(sep->endpoint), cadata, dataLen);
         if (CA_NOT_SUPPORTED == res)
@@ -900,7 +942,11 @@ CAResult_t CADetachRequestMessage(const CAEndpoint_t *object, const CARequestInf
     CADestroyData(data, sizeof(CAData_t));
 #else
 #ifdef WITH_BWT
-    if (CA_ADAPTER_GATT_BTLE != object->adapter)
+    if (CA_ADAPTER_GATT_BTLE != object->adapter
+#ifdef TCP_ADAPTER
+            && CA_ADAPTER_TCP != object->adapter
+#endif
+            )
     {
         // send block data
         CAResult_t res = CASendBlockWiseData(data);
@@ -957,7 +1003,11 @@ CAResult_t CADetachResponseMessage(const CAEndpoint_t *object,
     CADestroyData(data, sizeof(CAData_t));
 #else
 #ifdef WITH_BWT
-    if (CA_ADAPTER_GATT_BTLE != object->adapter)
+    if (CA_ADAPTER_GATT_BTLE != object->adapter
+#ifdef TCP_ADAPTER
+            && CA_ADAPTER_TCP != object->adapter
+#endif
+            )
     {
         // send block data
         CAResult_t res = CASendBlockWiseData(data);
@@ -1165,19 +1215,30 @@ void CATerminateMessageHandler()
     OIC_LOG(DEBUG, TAG, "OUT");
 }
 
-void CALogPDUInfo(coap_pdu_t *pdu)
+void CALogPDUInfo(coap_pdu_t *pdu, const CAEndpoint_t *endpoint)
 {
     VERIFY_NON_NULL_VOID(pdu, TAG, "pdu");
 
     OIC_LOG_V(DEBUG, TAG, "PDU Maker - payload : %s", pdu->data);
 
-    OIC_LOG_V(DEBUG, TAG, "PDU Maker - type : %d", pdu->hdr->type);
+#ifdef TCP_ADAPTER
+    if (CA_ADAPTER_TCP == endpoint->adapter)
+    {
+        OIC_LOG(DEBUG, TAG, "pdu header data :");
+        OIC_LOG_BUFFER(DEBUG, TAG,  pdu->hdr, pdu->length);
+    }
+    else
+#endif
+    {
+        OIC_LOG_V(DEBUG, TAG, "PDU Maker - type : %d", pdu->hdr->coap_hdr_udp_t.type);
 
-    OIC_LOG_V(DEBUG, TAG, "PDU Maker - code : %d", pdu->hdr->code);
+        OIC_LOG_V(DEBUG, TAG, "PDU Maker - code : %d", pdu->hdr->coap_hdr_udp_t.code);
 
-    OIC_LOG(DEBUG, TAG, "PDU Maker - token :");
+        OIC_LOG(DEBUG, TAG, "PDU Maker - token :");
 
-    OIC_LOG_BUFFER(DEBUG, TAG, pdu->hdr->token, pdu->hdr->token_length);
+        OIC_LOG_BUFFER(DEBUG, TAG, pdu->hdr->coap_hdr_udp_t.token,
+                       pdu->hdr->coap_hdr_udp_t.token_length);
+    }
 }
 
 static void CALogPayloadInfo(CAInfo_t *info)
@@ -1228,7 +1289,7 @@ void CAErrorHandler(const CAEndpoint_t *endpoint,
     uint32_t code = CA_NOT_FOUND;
     //Do not free remoteEndpoint and data. Currently they will be freed in data thread
     //Get PDU data
-    coap_pdu_t *pdu = (coap_pdu_t *)CAParsePDU((const char *)data, dataLen, &code);
+    coap_pdu_t *pdu = (coap_pdu_t *)CAParsePDU((const char *)data, dataLen, &code, endpoint);
     if (NULL == pdu)
     {
         OIC_LOG(ERROR, TAG, "Parse PDU failed");
index d36d378..d1d1e5c 100644 (file)
@@ -36,6 +36,10 @@ static uint32_t NETWORK_GATT = CA_ADAPTER_GATT_BTLE;
 static uint32_t NETWORK_RA = CA_ADAPTER_REMOTE_ACCESS;
 #endif
 
+#ifdef TCP_ADAPTER
+static uint32_t NETWORK_TCP = CA_ADAPTER_TCP;
+#endif
+
 CAResult_t CAAddNetworkType(CATransportAdapter_t transportType)
 {
     OIC_LOG(DEBUG, TAG, "IN");
@@ -107,6 +111,18 @@ CAResult_t CAAddNetworkType(CATransportAdapter_t transportType)
            break;
 #endif /* RA_ADAPTER */
 
+#ifdef TCP_ADAPTER
+        case CA_ADAPTER_TCP:
+
+           OIC_LOG(DEBUG, TAG, "Add network type(TCP)");
+           if (u_arraylist_contains(g_selectedNetworkList, &NETWORK_TCP))
+           {
+               goto exit;
+           }
+           res = u_arraylist_add(g_selectedNetworkList, &NETWORK_TCP);
+           break;
+#endif /* TCP_ADAPTER */
+
         default:
             break;
     }
@@ -190,6 +206,13 @@ CAResult_t CARemoveNetworkType(CATransportAdapter_t transportType)
                     break;
 #endif /* RA_ADAPTER */
 
+#ifdef TCP_ADAPTER
+                case CA_ADAPTER_TCP:
+                    OIC_LOG(DEBUG, TAG, "Remove network type(TCP)");
+                    u_arraylist_remove(g_selectedNetworkList, index);
+                    break;
+#endif /* TCP_ADAPTER */
+
                 default:
                     break;
             }
index b42cfaa..04b80a0 100644 (file)
@@ -67,7 +67,8 @@ static const char COAP_URI_HEADER[] = "coap://[::]/";
 
 static unsigned int SEED = 0;
 
-CAResult_t CAGetRequestInfoFromPDU(const coap_pdu_t *pdu, CARequestInfo_t *outReqInfo)
+CAResult_t CAGetRequestInfoFromPDU(const coap_pdu_t *pdu, const CAEndpoint_t *endpoint,
+                                   CARequestInfo_t *outReqInfo)
 {
     OIC_LOG(DEBUG, TAG, "IN");
 
@@ -78,14 +79,15 @@ CAResult_t CAGetRequestInfoFromPDU(const coap_pdu_t *pdu, CARequestInfo_t *outRe
     }
 
     uint32_t code = CA_NOT_FOUND;
-    CAResult_t ret = CAGetInfoFromPDU(pdu, &code, &(outReqInfo->info));
+    CAResult_t ret = CAGetInfoFromPDU(pdu, endpoint, &code, &(outReqInfo->info));
     outReqInfo->method = code;
 
     OIC_LOG(DEBUG, TAG, "OUT");
     return ret;
 }
 
-CAResult_t CAGetResponseInfoFromPDU(const coap_pdu_t *pdu, CAResponseInfo_t *outResInfo)
+CAResult_t CAGetResponseInfoFromPDU(const coap_pdu_t *pdu, CAResponseInfo_t *outResInfo,
+                                    const CAEndpoint_t *endpoint)
 {
     OIC_LOG(DEBUG, TAG, "IN");
 
@@ -96,14 +98,15 @@ CAResult_t CAGetResponseInfoFromPDU(const coap_pdu_t *pdu, CAResponseInfo_t *out
     }
 
     uint32_t code = CA_NOT_FOUND;
-    CAResult_t ret = CAGetInfoFromPDU(pdu, &code, &(outResInfo->info));
+    CAResult_t ret = CAGetInfoFromPDU(pdu, endpoint, &code, &(outResInfo->info));
     outResInfo->result = code;
 
     OIC_LOG(DEBUG, TAG, "OUT");
     return ret;
 }
 
-CAResult_t CAGetErrorInfoFromPDU(const coap_pdu_t *pdu, CAErrorInfo_t *errorInfo)
+CAResult_t CAGetErrorInfoFromPDU(const coap_pdu_t *pdu, const CAEndpoint_t *endpoint,
+                                 CAErrorInfo_t *errorInfo)
 {
     OIC_LOG(DEBUG, TAG, "IN");
 
@@ -114,7 +117,7 @@ CAResult_t CAGetErrorInfoFromPDU(const coap_pdu_t *pdu, CAErrorInfo_t *errorInfo
     }
 
     uint32_t code = 0;
-    CAResult_t ret = CAGetInfoFromPDU(pdu, &code, &errorInfo->info);
+    CAResult_t ret = CAGetInfoFromPDU(pdu, endpoint, &code, &errorInfo->info);
     OIC_LOG(DEBUG, TAG, "OUT");
     return ret;
 }
@@ -133,7 +136,7 @@ coap_pdu_t *CAGeneratePDU(uint32_t code, const CAInfo_t *info, const CAEndpoint_
     if (CA_MSG_RESET == info->type || (CA_EMPTY == code && CA_MSG_ACKNOWLEDGE == info->type))
     {
         OIC_LOG(DEBUG, TAG, "code is empty");
-        if (!(pdu = CAGeneratePDUImpl((code_t) code, NULL, info, endpoint)))
+        if (!(pdu = CAGeneratePDUImpl((code_t) code, info, endpoint, NULL)))
         {
             OIC_LOG(ERROR, TAG, "pdu NULL");
             return NULL;
@@ -191,7 +194,7 @@ coap_pdu_t *CAGeneratePDU(uint32_t code, const CAInfo_t *info, const CAEndpoint_
             return NULL;
         }
 
-        pdu = CAGeneratePDUImpl((code_t) code, optlist, info, endpoint);
+        pdu = CAGeneratePDUImpl((code_t) code, info, endpoint, optlist);
         if (NULL == pdu)
         {
             OIC_LOG(ERROR, TAG, "pdu NULL");
@@ -208,7 +211,8 @@ coap_pdu_t *CAGeneratePDU(uint32_t code, const CAInfo_t *info, const CAEndpoint_
     return pdu;
 }
 
-coap_pdu_t *CAParsePDU(const char *data, uint32_t length, uint32_t *outCode)
+coap_pdu_t *CAParsePDU(const char *data, uint32_t length, uint32_t *outCode,
+                       const CAEndpoint_t *endpoint)
 {
     OIC_LOG(DEBUG, TAG, "IN");
 
@@ -218,53 +222,105 @@ coap_pdu_t *CAParsePDU(const char *data, uint32_t length, uint32_t *outCode)
         return NULL;
     }
 
-    coap_pdu_t *outpdu = coap_new_pdu();
+    coap_transport_type transport;
+#ifdef TCP_ADAPTER
+    if (CA_ADAPTER_TCP == endpoint->adapter)
+    {
+        transport = coap_get_tcp_header_type_from_initbyte(((unsigned char *)data)[0] >> 4);
+    }
+    else
+#endif
+    {
+        transport = coap_udp;
+    }
+
+    coap_pdu_t *outpdu = coap_new_pdu(transport, length);
     if (NULL == outpdu)
     {
         OIC_LOG(ERROR, TAG, "outpdu is null");
         return NULL;
     }
 
-    if (0 >= coap_pdu_parse((unsigned char *) data, length, outpdu))
+    OIC_LOG_V(DEBUG, TAG, "pdu parse-transport type : %d", transport);
+
+    int ret = coap_pdu_parse((unsigned char *) data, length, outpdu, transport);
+    OIC_LOG_V(DEBUG, TAG, "pdu parse ret: %d", ret);
+    if (0 >= ret)
     {
         OIC_LOG(ERROR, TAG, "pdu parse failed");
         coap_delete_pdu(outpdu);
         return NULL;
     }
 
-    if (outpdu->hdr->version != COAP_DEFAULT_VERSION)
+#ifdef TCP_ADAPTER
+    if (CA_ADAPTER_TCP == endpoint->adapter)
     {
-        OIC_LOG_V(ERROR, TAG, "coap version is not available : %d",
-                  outpdu->hdr->version);
-        coap_delete_pdu(outpdu);
-        return NULL;
+        OIC_LOG(INFO, TAG, "there is no version info in coap header");
     }
-
-    if (outpdu->hdr->token_length > CA_MAX_TOKEN_LEN)
+    else
+#endif
     {
-        OIC_LOG_V(ERROR, TAG, "token length has been exceed : %d",
-                  outpdu->hdr->token_length);
-        coap_delete_pdu(outpdu);
-        return NULL;
+        if (outpdu->hdr->coap_hdr_udp_t.version != COAP_DEFAULT_VERSION)
+        {
+            OIC_LOG_V(ERROR, TAG, "coap version is not available : %d",
+                      outpdu->hdr->coap_hdr_udp_t.version);
+            coap_delete_pdu(outpdu);
+            return NULL;
+        }
+        if (outpdu->hdr->coap_hdr_udp_t.token_length > CA_MAX_TOKEN_LEN)
+        {
+            OIC_LOG_V(ERROR, TAG, "token length has been exceed : %d",
+                      outpdu->hdr->coap_hdr_udp_t.token_length);
+            coap_delete_pdu(outpdu);
+            return NULL;
+        }
     }
 
     if (outCode)
     {
-        (*outCode) = (uint32_t) CA_RESPONSE_CODE(outpdu->hdr->code);
+        (*outCode) = (uint32_t) CA_RESPONSE_CODE(coap_get_code(outpdu, transport));
     }
 
     OIC_LOG(DEBUG, TAG, "OUT");
     return outpdu;
 }
 
-coap_pdu_t *CAGeneratePDUImpl(code_t code, coap_list_t *options, const CAInfo_t *info,
-                              const CAEndpoint_t *endpoint)
+coap_pdu_t *CAGeneratePDUImpl(code_t code, const CAInfo_t *info,
+                              const CAEndpoint_t *endpoint, coap_list_t *options)
 {
     OIC_LOG(DEBUG, TAG, "IN");
     VERIFY_NON_NULL_RET(info, TAG, "info", NULL);
     VERIFY_NON_NULL_RET(endpoint, TAG, "endpoint", NULL);
 
-    coap_pdu_t *pdu = coap_new_pdu();
+    coap_transport_type transport;
+    unsigned int length = COAP_MAX_PDU_SIZE;
+#ifdef TCP_ADAPTER
+    unsigned int headerLength = 0;
+    if (CA_ADAPTER_TCP == endpoint->adapter)
+    {
+        if (options)
+        {
+            for (coap_list_t *opt = options; opt; opt = opt->next)
+            {
+                headerLength += COAP_OPTION_LENGTH(*(coap_option *) opt->data) + 1;
+            }
+        }
+
+        if (info->payloadSize > 0)
+        {
+            headerLength = headerLength + info->payloadSize + 1;
+        }
+        transport = coap_get_tcp_header_type_from_size(headerLength);
+        length = headerLength + coap_get_tcp_header_length_for_transport(transport)
+                + info->tokenLength;
+    }
+    else
+#endif
+    {
+        transport = coap_udp;
+    }
+
+    coap_pdu_t *pdu = coap_new_pdu(transport, length);
 
     if (NULL == pdu)
     {
@@ -272,25 +328,38 @@ coap_pdu_t *CAGeneratePDUImpl(code_t code, coap_list_t *options, const CAInfo_t
         return NULL;
     }
 
-    OIC_LOG_V(DEBUG, TAG, "msgID is %d", info->messageId);
-    uint16_t message_id;
-    if (0 == info->messageId)
-    {
-        /* initialize message id */
-        prng((uint8_t * ) &message_id, sizeof(message_id));
+    OIC_LOG_V(DEBUG, TAG, "transport type: %d, payload size: %d",
+              transport, info->payloadSize);
 
-        OIC_LOG_V(DEBUG, TAG, "gen msg id=%d", message_id);
+#ifdef TCP_ADAPTER
+    if (CA_ADAPTER_TCP == endpoint->adapter)
+    {
+        coap_add_length(pdu, transport, headerLength);
     }
     else
+#endif
     {
-        /* use saved message id */
-        message_id = info->messageId;
+        OIC_LOG_V(DEBUG, TAG, "msgID is %d", info->messageId);
+        uint16_t message_id;
+        if (0 == info->messageId)
+        {
+            /* initialize message id */
+            prng((uint8_t * ) &message_id, sizeof(message_id));
+
+            OIC_LOG_V(DEBUG, TAG, "gen msg id=%d", message_id);
+        }
+        else
+        {
+            /* use saved message id */
+            message_id = info->messageId;
+        }
+        pdu->hdr->coap_hdr_udp_t.id = message_id;
+        OIC_LOG_V(DEBUG, TAG, "messageId in pdu is %d, %d", message_id, pdu->hdr->coap_hdr_udp_t.id);
+
+        pdu->hdr->coap_hdr_udp_t.type = info->type;
     }
-    pdu->hdr->id = message_id;
-    OIC_LOG_V(DEBUG, TAG, "messageId in pdu is %d, %d", message_id, pdu->hdr->id);
 
-    pdu->hdr->type = info->type;
-    pdu->hdr->code = COAP_RESPONSE_CODE(code);
+    coap_add_code(pdu, transport, code);
 
     if (info->token && CA_EMPTY != code)
     {
@@ -298,7 +367,7 @@ coap_pdu_t *CAGeneratePDUImpl(code_t code, coap_list_t *options, const CAInfo_t
         OIC_LOG_V(DEBUG, TAG, "token info token length: %d, token :", tokenLength);
         OIC_LOG_BUFFER(DEBUG, TAG, (const uint8_t *)info->token, tokenLength);
 
-        int32_t ret = coap_add_token(pdu, tokenLength, (unsigned char *)info->token);
+        int32_t ret = coap_add_token(pdu, tokenLength, (unsigned char *)info->token, transport);
         if (0 == ret)
         {
             OIC_LOG(ERROR, TAG, "can't add token");
@@ -311,18 +380,26 @@ coap_pdu_t *CAGeneratePDUImpl(code_t code, coap_list_t *options, const CAInfo_t
         {
             OIC_LOG_V(DEBUG, TAG, "[%s] opt will be added.",
                       COAP_OPTION_DATA(*(coap_option *) opt->data));
+
+            OIC_LOG_V(DEBUG, TAG, "[%d] pdu length", pdu->length);
             coap_add_option(pdu, COAP_OPTION_KEY(*(coap_option *) opt->data),
                             COAP_OPTION_LENGTH(*(coap_option *) opt->data),
-                            COAP_OPTION_DATA(*(coap_option *) opt->data));
+                            COAP_OPTION_DATA(*(coap_option *) opt->data), transport);
         }
     }
 
+    OIC_LOG_V(DEBUG, TAG, "[%d] pdu length after option", pdu->length);
+
     bool enabledPayload = false;
 #ifndef WITH_BWT
     enabledPayload = true;
 #endif
 
-    if (enabledPayload || CA_ADAPTER_GATT_BTLE == endpoint->adapter)
+    if (enabledPayload || CA_ADAPTER_GATT_BTLE == endpoint->adapter
+#ifdef TCP_ADAPTER
+            || CA_ADAPTER_TCP == endpoint->adapter
+#endif
+            )
     {
         if (NULL != info->payload && 0 < info->payloadSize)
         {
@@ -660,7 +737,8 @@ uint32_t CAGetOptionCount(coap_opt_iterator_t opt_iter)
     return count;
 }
 
-CAResult_t CAGetInfoFromPDU(const coap_pdu_t *pdu, uint32_t *outCode, CAInfo_t *outInfo)
+CAResult_t CAGetInfoFromPDU(const coap_pdu_t *pdu, const CAEndpoint_t *endpoint,
+                            uint32_t *outCode, CAInfo_t *outInfo)
 {
     OIC_LOG(DEBUG, TAG, "IN");
 
@@ -670,12 +748,24 @@ CAResult_t CAGetInfoFromPDU(const coap_pdu_t *pdu, uint32_t *outCode, CAInfo_t *
         return CA_STATUS_INVALID_PARAM;
     }
 
+    coap_transport_type transport;
+#ifdef TCP_ADAPTER
+    if (CA_ADAPTER_TCP == endpoint->adapter)
+    {
+        transport = coap_get_tcp_header_type_from_initbyte(((unsigned char *)pdu->hdr)[0] >> 4);
+    }
+    else
+#endif
+    {
+        transport = coap_udp;
+    }
+
     coap_opt_iterator_t opt_iter;
-    coap_option_iterator_init((coap_pdu_t *) pdu, &opt_iter, COAP_OPT_ALL);
+    coap_option_iterator_init((coap_pdu_t *) pdu, &opt_iter, COAP_OPT_ALL, transport);
 
     if (outCode)
     {
-        (*outCode) = (uint32_t) CA_RESPONSE_CODE(pdu->hdr->code);
+        (*outCode) = (uint32_t) CA_RESPONSE_CODE(coap_get_code(pdu, transport));
     }
 
     // init HeaderOption list
@@ -684,13 +774,24 @@ CAResult_t CAGetInfoFromPDU(const coap_pdu_t *pdu, uint32_t *outCode, CAInfo_t *
 
     outInfo->numOptions = count;
 
-    // set type
-    outInfo->type = pdu->hdr->type;
+#ifdef TCP_ADAPTER
+    if (CA_ADAPTER_TCP == endpoint->adapter)
+    {
+        // set type
+        outInfo->type = CA_MSG_NONCONFIRM;
+        outInfo->payloadFormat = CA_FORMAT_UNDEFINED;
+    }
+    else
+#endif
+    {
+        // set type
+        outInfo->type = pdu->hdr->coap_hdr_udp_t.type;
 
-    // set message id
-    outInfo->messageId = pdu->hdr->id;
-    outInfo->payloadFormat = CA_FORMAT_UNDEFINED;
-    outInfo->acceptFormat = CA_FORMAT_UNDEFINED;
+        // set message id
+        outInfo->messageId = pdu->hdr->coap_hdr_udp_t.id;
+        outInfo->payloadFormat = CA_FORMAT_UNDEFINED;
+        outInfo->acceptFormat = CA_FORMAT_UNDEFINED;
+    }
 
     if (count > 0)
     {
@@ -843,21 +944,25 @@ CAResult_t CAGetInfoFromPDU(const coap_pdu_t *pdu, uint32_t *outCode, CAInfo_t *
         }
     }
 
+    unsigned char* token = NULL;
+    unsigned int token_length = 0;
+    coap_get_token(pdu->hdr, transport, &token, &token_length);
+
     // set token data
-    if (pdu->hdr->token_length > 0)
+    if (token_length > 0)
     {
-        OIC_LOG_V(DEBUG, TAG, "inside token length : %d", pdu->hdr->token_length);
-        outInfo->token = (char *) OICMalloc(pdu->hdr->token_length);
+        OIC_LOG_V(DEBUG, TAG, "inside token length : %d", token_length);
+        outInfo->token = (char *) OICMalloc(token_length);
         if (NULL == outInfo->token)
         {
             OIC_LOG(ERROR, TAG, "Out of memory");
             OICFree(outInfo->options);
             return CA_MEMORY_ALLOC_FAILED;
         }
-        memcpy(outInfo->token, pdu->hdr->token, pdu->hdr->token_length);
+        memcpy(outInfo->token, token, token_length);
     }
 
-    outInfo->tokenLength = pdu->hdr->token_length;
+    outInfo->tokenLength = token_length;
 
     // set payload data
     size_t dataSize;
@@ -899,7 +1004,8 @@ exit:
     return CA_STATUS_FAILED;
 }
 
-CAResult_t CAGetTokenFromPDU(const coap_hdr_t *pdu_hdr, CAInfo_t *outInfo)
+CAResult_t CAGetTokenFromPDU(const coap_hdr_t *pdu_hdr, CAInfo_t *outInfo,
+                             const CAEndpoint_t *endpoint)
 {
     OIC_LOG(DEBUG, TAG, "IN");
     if (NULL == pdu_hdr)
@@ -914,20 +1020,36 @@ CAResult_t CAGetTokenFromPDU(const coap_hdr_t *pdu_hdr, CAInfo_t *outInfo)
         return CA_STATUS_INVALID_PARAM;
     }
 
+    coap_transport_type transport;
+#ifdef TCP_ADAPTER
+    if (CA_ADAPTER_TCP == endpoint->adapter)
+    {
+        transport = coap_get_tcp_header_type_from_initbyte(((unsigned char *)pdu_hdr)[0] >> 4);
+    }
+    else
+#endif
+    {
+        transport = coap_udp;
+    }
+
+    unsigned char* token = NULL;
+    unsigned int token_length = 0;
+    coap_get_token(pdu_hdr, transport, &token, &token_length);
+
     // set token data
-    if (pdu_hdr->token_length > 0)
+    if (token_length > 0)
     {
-        OIC_LOG_V(DEBUG, TAG, "token len:%d", pdu_hdr->token_length);
-        outInfo->token = (char *) OICMalloc(pdu_hdr->token_length);
+        OIC_LOG_V(DEBUG, TAG, "token len:%d", token_length);
+        outInfo->token = (char *) OICMalloc(token_length);
         if (NULL == outInfo->token)
         {
-            OIC_LOG(ERROR, TAG, "out of memory");
+            OIC_LOG(ERROR, TAG, "Out of memory");
             return CA_MEMORY_ALLOC_FAILED;
         }
-        memcpy(outInfo->token, pdu_hdr->token, pdu_hdr->token_length);
+        memcpy(outInfo->token, token, token_length);
     }
 
-    outInfo->tokenLength = pdu_hdr->token_length;
+    outInfo->tokenLength = token_length;
 
     OIC_LOG(DEBUG, TAG, "OUT");
 
@@ -1078,7 +1200,7 @@ CAMessageType_t CAGetMessageTypeFromPduBinaryData(const void *pdu, uint32_t size
 
     coap_hdr_t *hdr = (coap_hdr_t *) pdu;
 
-    return (CAMessageType_t) hdr->type;
+    return (CAMessageType_t) hdr->coap_hdr_udp_t.type;
 }
 
 uint16_t CAGetMessageIdFromPduBinaryData(const void *pdu, uint32_t size)
@@ -1098,7 +1220,7 @@ uint16_t CAGetMessageIdFromPduBinaryData(const void *pdu, uint32_t size)
 
     coap_hdr_t *hdr = (coap_hdr_t *) pdu;
 
-    return hdr->id;
+    return hdr->coap_hdr_udp_t.id;
 }
 
 CAResponseResult_t CAGetCodeFromPduBinaryData(const void *pdu, uint32_t size)
@@ -1118,7 +1240,7 @@ CAResponseResult_t CAGetCodeFromPduBinaryData(const void *pdu, uint32_t size)
 
     coap_hdr_t *hdr = (coap_hdr_t *) pdu;
 
-    return (CAResponseResult_t) CA_RESPONSE_CODE(hdr->code);
+    return (CAResponseResult_t) CA_RESPONSE_CODE(hdr->coap_hdr_udp_t.code);
 }
 
 CAPayloadFormat_t CAConvertFormat(uint8_t format)
diff --git a/resource/csdk/connectivity/src/tcp_adapter/SConscript b/resource/csdk/connectivity/src/tcp_adapter/SConscript
new file mode 100644 (file)
index 0000000..5e55c1f
--- /dev/null
@@ -0,0 +1,47 @@
+#######################################################
+#      Build TCP adapter
+#######################################################
+
+Import('env')
+import os.path
+
+print "Reading TCP adapter script"
+
+target_os = env.get('TARGET_OS')
+inc_files = env.get('CPPPATH')
+secured = env.get('SECURED')
+src_dir = './tcp_adapter/'
+
+
+# Source files to build common for all platforms
+common_files = None
+if target_os == 'linux':
+    common_files = [
+        os.path.join(src_dir, 'catcpadapter.c'),
+        os.path.join(src_dir, 'catcpserver.c') ]
+
+# Get list of target-specific source file base names, i.e. no parent
+# directories prepended to the path.
+#
+# Target-specific SConscript files are expected to return that list.
+target_files = []
+target_sconscript = os.path.join(target_os, 'SConscript')
+
+# Check for the existence of the platform-specific SConscript file
+# relative to the top-level source directory, not the build (variant)
+# directory, before calling that SConscript file to prevent a missing
+# file warning platforms that don't provide one.
+target_sconscript_abspath = str(File(target_sconscript).srcnode().abspath)
+if os.path.exists(target_sconscript_abspath):
+        target_files = env.SConscript(target_sconscript, exports='src_dir')
+
+# Now prepend the appropriate parent directories
+# (e.g. ./ip_adapter/android) to each of the target source files in
+# the list.
+target_files = [ os.path.join(src_dir, target_os, f) for f in target_files ]
+
+# Source files to build for Linux-like platforms
+
+# The list of BLE adapter source files is a combination of both the
+# common and target-specific source file lists.
+env.AppendUnique(CA_SRC = common_files + target_files)
\ No newline at end of file
diff --git a/resource/csdk/connectivity/src/tcp_adapter/catcpadapter.c b/resource/csdk/connectivity/src/tcp_adapter/catcpadapter.c
new file mode 100644 (file)
index 0000000..56cc8f6
--- /dev/null
@@ -0,0 +1,431 @@
+/* ****************************************************************
+ *
+ * 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 <string.h>
+#include <stdint.h>
+
+#include "catcpadapter.h"
+#include "catcpinterface.h"
+#include "caqueueingthread.h"
+#include "caadapterutils.h"
+#include "camutex.h"
+#include "uarraylist.h"
+#include "caremotehandler.h"
+#include "logger.h"
+#include "oic_malloc.h"
+#include "oic_string.h"
+
+/**
+ * Logging tag for module name.
+ */
+#define TAG "TCP_ADAP"
+
+/**
+ * Holds internal thread TCP data information.
+ */
+typedef struct
+{
+    CAEndpoint_t *remoteEndpoint;
+    void *data;
+    size_t dataLen;
+    bool isMulticast;
+} CATCPData;
+
+#define CA_TCP_TIMEOUT 1000
+
+#define CA_TCP_LISTEN_BACKLOG  3
+
+/**
+ * Queue handle for Send Data.
+ */
+static CAQueueingThread_t *g_sendQueueHandle = NULL;
+
+/**
+ * Network Packet Received Callback to CA.
+ */
+static CANetworkPacketReceivedCallback g_networkPacketCallback = NULL;
+
+/**
+ * Network Changed Callback to CA.
+ */
+static CANetworkChangeCallback g_networkChangeCallback = NULL;
+
+/**
+ * error Callback to CA adapter.
+ */
+static CAErrorHandleCallback g_errorCallback = NULL;
+
+static void CATCPPacketReceivedCB(const CAEndpoint_t *endpoint,
+                                  const void *data, size_t dataLength);
+
+static CAResult_t CATCPInitializeQueueHandles();
+
+static void CATCPDeinitializeQueueHandles();
+
+static void CATCPSendDataThread(void *threadData);
+
+static CATCPData *CACreateTCPData(const CAEndpoint_t *remoteEndpoint,
+                                  const void *data, size_t dataLength,
+                                  bool isMulticast);
+void CAFreeTCPData(CATCPData *ipData);
+
+static void CADataDestroyer(void *data, size_t size);
+
+CAResult_t CATCPInitializeQueueHandles()
+{
+    OIC_LOG(DEBUG, TAG, "IN");
+
+    // Check if the message queue is already initialized
+    if (g_sendQueueHandle)
+    {
+        OIC_LOG(DEBUG, TAG, "send queue handle is already initialized!");
+        return CA_STATUS_OK;
+    }
+
+    // Create send message queue
+    g_sendQueueHandle = OICMalloc(sizeof(CAQueueingThread_t));
+    if (!g_sendQueueHandle)
+    {
+        OIC_LOG(ERROR, TAG, "Memory allocation failed!");
+        return CA_MEMORY_ALLOC_FAILED;
+    }
+
+    if (CA_STATUS_OK != CAQueueingThreadInitialize(g_sendQueueHandle,
+                                (const ca_thread_pool_t)caglobals.tcp.threadpool,
+                                CATCPSendDataThread, CADataDestroyer))
+    {
+        OIC_LOG(ERROR, TAG, "Failed to Initialize send queue thread");
+        OICFree(g_sendQueueHandle);
+        g_sendQueueHandle = NULL;
+        return CA_STATUS_FAILED;
+    }
+
+    OIC_LOG(DEBUG, TAG, "OUT");
+    return CA_STATUS_OK;
+}
+
+void CATCPDeinitializeQueueHandles()
+{
+    OIC_LOG(DEBUG, TAG, "IN");
+
+    CAQueueingThreadDestroy(g_sendQueueHandle);
+    OICFree(g_sendQueueHandle);
+    g_sendQueueHandle = NULL;
+
+    OIC_LOG(DEBUG, TAG, "OUT");
+}
+
+void CATCPConnectionStateCB(const char *ipAddress, CANetworkStatus_t status)
+{
+    (void)ipAddress;
+    (void)status;
+    OIC_LOG(DEBUG, TAG, "IN");
+}
+
+void CATCPPacketReceivedCB(const CAEndpoint_t *endpoint, const void *data,
+                           size_t dataLength)
+{
+    OIC_LOG(DEBUG, TAG, "IN");
+
+    VERIFY_NON_NULL_VOID(endpoint, TAG, "ipAddress is NULL");
+    VERIFY_NON_NULL_VOID(data, TAG, "data is NULL");
+
+    OIC_LOG_V(DEBUG, TAG, "Address: %s, port:%d", endpoint->addr, endpoint->port);
+
+    if (g_networkPacketCallback)
+    {
+        g_networkPacketCallback(endpoint, data, dataLength);
+    }
+    OIC_LOG(DEBUG, TAG, "OUT");
+}
+
+void CATCPErrorHandler(const CAEndpoint_t *endpoint, const void *data,
+                       size_t dataLength, CAResult_t result)
+{
+    OIC_LOG(DEBUG, TAG, "IN");
+
+    VERIFY_NON_NULL_VOID(endpoint, TAG, "endpoint is NULL");
+
+    VERIFY_NON_NULL_VOID(data, TAG, "data is NULL");
+
+    if (g_errorCallback)
+    {
+        g_errorCallback(endpoint, data, dataLength, result);
+    }
+
+    OIC_LOG(DEBUG, TAG, "OUT");
+}
+
+static void CAInitializeTCPGlobals()
+{
+    caglobals.tcp.selectTimeout = CA_TCP_TIMEOUT;
+    caglobals.tcp.listenBacklog = CA_TCP_LISTEN_BACKLOG;
+    caglobals.tcp.svrlist = NULL;
+
+    CATransportFlags_t flags = 0;
+    if (caglobals.client)
+    {
+        flags |= caglobals.clientFlags;
+    }
+    if (caglobals.server)
+    {
+        flags |= caglobals.serverFlags;
+    }
+
+    caglobals.tcp.ipv4tcpenabled = flags & CA_IPV4;
+}
+
+CAResult_t CAInitializeTCP(CARegisterConnectivityCallback registerCallback,
+                           CANetworkPacketReceivedCallback networkPacketCallback,
+                           CANetworkChangeCallback netCallback,
+                           CAErrorHandleCallback errorCallback, ca_thread_pool_t handle)
+{
+    OIC_LOG(DEBUG, TAG, "IN");
+    VERIFY_NON_NULL(registerCallback, TAG, "registerCallback");
+    VERIFY_NON_NULL(networkPacketCallback, TAG, "networkPacketCallback");
+    VERIFY_NON_NULL(netCallback, TAG, "netCallback");
+    VERIFY_NON_NULL(handle, TAG, "thread pool handle");
+
+    g_networkChangeCallback = netCallback;
+    g_networkPacketCallback = networkPacketCallback;
+    g_errorCallback = errorCallback;
+
+    CAInitializeTCPGlobals();
+    caglobals.tcp.threadpool = handle;
+
+    CATCPSetPacketReceiveCallback(CATCPPacketReceivedCB);
+    CATCPSetErrorHandler(CATCPErrorHandler);
+
+    CAConnectivityHandler_t TCPHandler = {
+        .startAdapter = CAStartTCP,
+        .startListenServer = CAStartTCPListeningServer,
+        .startDiscoveryServer = CAStartTCPDiscoveryServer,
+        .sendData = CASendTCPUnicastData,
+        .sendDataToAll = CASendTCPMulticastData,
+        .GetnetInfo = CAGetTCPInterfaceInformation,
+        .readData = CAReadTCPData,
+        .stopAdapter = CAStopTCP,
+        .terminate = CATerminateTCP };
+    registerCallback(TCPHandler, CA_ADAPTER_TCP);
+
+    OIC_LOG(INFO, TAG, "OUT IntializeTCP is Success");
+    return CA_STATUS_OK;
+}
+
+CAResult_t CAStartTCP()
+{
+    OIC_LOG(DEBUG, TAG, "IN");
+
+    if (CA_STATUS_OK != CATCPInitializeQueueHandles())
+    {
+        OIC_LOG(ERROR, TAG, "Failed to Initialize Queue Handle");
+        CATerminateTCP();
+        return CA_STATUS_FAILED;
+    }
+
+    // Start send queue thread
+    if (CA_STATUS_OK != CAQueueingThreadStart(g_sendQueueHandle))
+    {
+        OIC_LOG(ERROR, TAG, "Failed to Start Send Data Thread");
+        return CA_STATUS_FAILED;
+    }
+
+    CAResult_t ret = CATCPStartServer((const ca_thread_pool_t)caglobals.tcp.threadpool);
+    if (CA_STATUS_OK != ret)
+    {
+        OIC_LOG_V(ERROR, TAG, "Failed to start server![%d]", ret);
+        return ret;
+    }
+
+    OIC_LOG(DEBUG, TAG, "OUT");
+    return CA_STATUS_OK;
+}
+
+CAResult_t CAStartTCPListeningServer()
+{
+    OIC_LOG(DEBUG, TAG, "IN");
+
+    OIC_LOG(DEBUG, TAG, "OUT");
+    return CA_STATUS_OK;
+}
+
+CAResult_t CAStartTCPDiscoveryServer()
+{
+    OIC_LOG(DEBUG, TAG, "IN");
+
+    OIC_LOG(DEBUG, TAG, "OUT");
+    return CA_STATUS_OK;
+}
+
+static size_t CAQueueTCPData(bool isMulticast, const CAEndpoint_t *endpoint,
+                             const void *data, size_t dataLength)
+{
+    OIC_LOG(DEBUG, TAG, "IN");
+
+    VERIFY_NON_NULL_RET(endpoint, TAG, "remoteEndpoint", -1);
+    VERIFY_NON_NULL_RET(data, TAG, "data", -1);
+
+    if (0 == dataLength)
+    {
+        OIC_LOG(ERROR, TAG, "Invalid Data Length");
+        return -1;
+    }
+
+    VERIFY_NON_NULL_RET(g_sendQueueHandle, TAG, "sendQueueHandle", -1);
+
+    // Create TCPData to add to queue
+    CATCPData *TCPData = CACreateTCPData(endpoint, data, dataLength, isMulticast);
+    if (!TCPData)
+    {
+        OIC_LOG(ERROR, TAG, "Failed to create ipData!");
+        return -1;
+    }
+    // Add message to send queue
+    CAQueueingThreadAddData(g_sendQueueHandle, TCPData, sizeof(CATCPData));
+
+    OIC_LOG(DEBUG, TAG, "OUT");
+    return dataLength;
+}
+
+int32_t CASendTCPUnicastData(const CAEndpoint_t *endpoint,
+                             const void *data, uint32_t dataLength)
+{
+    OIC_LOG(DEBUG, TAG, "IN");
+    return CAQueueTCPData(false, endpoint, data, dataLength);
+}
+
+int32_t CASendTCPMulticastData(const CAEndpoint_t *endpoint,
+                               const void *data, uint32_t dataLength)
+{
+    OIC_LOG(DEBUG, TAG, "IN");
+    return CAQueueTCPData(true, endpoint, data, dataLength);
+}
+
+CAResult_t CAReadTCPData()
+{
+    OIC_LOG(DEBUG, TAG, "IN");
+    OIC_LOG(DEBUG, TAG, "OUT");
+    return CA_STATUS_OK;
+}
+
+CAResult_t CAStopTCP()
+{
+    OIC_LOG(DEBUG, TAG, "IN");
+
+    if (g_sendQueueHandle && g_sendQueueHandle->threadMutex)
+    {
+        CAQueueingThreadStop(g_sendQueueHandle);
+    }
+
+    CATCPDeinitializeQueueHandles();
+
+    CATCPStopServer();
+
+    OIC_LOG(DEBUG, TAG, "OUT");
+    return CA_STATUS_OK;
+}
+
+void CATerminateTCP()
+{
+    OIC_LOG(DEBUG, TAG, "IN");
+
+    CATCPSetPacketReceiveCallback(NULL);
+
+    CATCPDeinitializeQueueHandles();
+
+    OIC_LOG(DEBUG, TAG, "OUT");
+}
+
+void CATCPSendDataThread(void *threadData)
+{
+    OIC_LOG(DEBUG, TAG, "IN");
+
+    CATCPData *TCPData = (CATCPData *) threadData;
+    if (!TCPData)
+    {
+        OIC_LOG(DEBUG, TAG, "Invalid TCP data!");
+        return;
+    }
+
+    if (TCPData->isMulticast)
+    {
+        //Processing for sending multicast
+        OIC_LOG(DEBUG, TAG, "Send Multicast Data is called, not supported");
+        return;
+    }
+    else
+    {
+        //Processing for sending unicast
+        CATCPSendData(TCPData->remoteEndpoint, TCPData->data, TCPData->dataLen, false);
+    }
+
+    OIC_LOG(DEBUG, TAG, "OUT");
+}
+
+CATCPData *CACreateTCPData(const CAEndpoint_t *remoteEndpoint, const void *data,
+                           size_t dataLength, bool isMulticast)
+{
+    VERIFY_NON_NULL_RET(data, TAG, "TCPData is NULL", NULL);
+
+    CATCPData *TCPData = (CATCPData *) OICMalloc(sizeof(CATCPData));
+    if (!TCPData)
+    {
+        OIC_LOG(ERROR, TAG, "Memory allocation failed!");
+        return NULL;
+    }
+
+    TCPData->remoteEndpoint = CACloneEndpoint(remoteEndpoint);
+    TCPData->data = (void *) OICMalloc(dataLength);
+    if (!TCPData->data)
+    {
+        OIC_LOG(ERROR, TAG, "Memory allocation failed!");
+        CAFreeTCPData(TCPData);
+        return NULL;
+    }
+
+    memcpy(TCPData->data, data, dataLength);
+    TCPData->dataLen = dataLength;
+
+    TCPData->isMulticast = isMulticast;
+
+    return TCPData;
+}
+
+void CAFreeTCPData(CATCPData *TCPData)
+{
+    VERIFY_NON_NULL_VOID(TCPData, TAG, "TCPData is NULL");
+
+    CAFreeEndpoint(TCPData->remoteEndpoint);
+    OICFree(TCPData->data);
+    OICFree(TCPData);
+}
+
+void CADataDestroyer(void *data, size_t size)
+{
+    if (size < sizeof(CATCPData))
+    {
+        OIC_LOG_V(ERROR, TAG, "Destroy data too small %p %d", data, size);
+    }
+    CATCPData *TCPData = (CATCPData *) data;
+
+    CAFreeTCPData(TCPData);
+}
diff --git a/resource/csdk/connectivity/src/tcp_adapter/catcpserver.c b/resource/csdk/connectivity/src/tcp_adapter/catcpserver.c
new file mode 100644 (file)
index 0000000..102893a
--- /dev/null
@@ -0,0 +1,838 @@
+/* ****************************************************************j
+ *
+ * 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 <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/select.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <errno.h>
+#include <sys/poll.h>
+
+#ifndef WITH_ARDUINO
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#endif
+
+#include "catcpinterface.h"
+#include "pdu.h"
+#include "caadapterutils.h"
+#include "camutex.h"
+#include "oic_malloc.h"
+#include "oic_string.h"
+
+/**
+ * Logging tag for module name.
+ */
+#define TAG "TCP_SERVER"
+
+/**
+ * Server port number for local test.
+ */
+#define SERVER_PORT 8000
+
+/**
+ * Maximum CoAP over TCP header length
+ * to know the total data length.
+ */
+#define TCP_MAX_HEADER_LEN  6
+
+/**
+ * Default Thread Counts in TCP adapter
+ */
+#define CA_TCP_DEFAULT_THREAD_COUNTS    2
+
+/**
+ * Accept server file descriptor.
+ */
+static int g_acceptServerFD = -1;
+
+/**
+ * Mutex to synchronize device object list.
+ */
+static ca_mutex g_mutexObjectList = NULL;
+
+/**
+ * Conditional mutex to synchronize.
+ */
+static ca_cond g_condObjectList = NULL;
+
+/**
+ * Maintains the current running thread counts.
+ */
+static uint32_t g_threadCounts = CA_TCP_DEFAULT_THREAD_COUNTS;
+
+/**
+ * Maintains the callback to be notified when data received from remote device.
+ */
+static CATCPPacketReceivedCallback g_packetReceivedCallback;
+
+/**
+ * Error callback to update error in TCP.
+ */
+static CATCPErrorHandleCallback g_TCPErrorHandler = NULL;
+
+static CAResult_t CATCPCreateMutex();
+static void CATCPDestroyMutex();
+static CAResult_t CATCPCreateCond();
+static void CATCPDestroyCond();
+static void CAAcceptHandler(void *data);
+static void CAReceiveHandler(void *data);
+static CAResult_t CAReceiveMessage();
+static int CASetNonblocking(int fd);
+static int CATCPCreateSocket(int family, CATCPServerInfo_t *TCPServerInfo);
+static size_t CAGetTotalLengthFromHeader(const unsigned char *recvBuffer);
+static void CATCPDisconnectAll();
+
+static void CATCPDestroyMutex()
+{
+    if (g_mutexObjectList)
+    {
+        ca_mutex_free(g_mutexObjectList);
+        g_mutexObjectList = NULL;
+    }
+}
+
+static CAResult_t CATCPCreateMutex()
+{
+    if (!g_mutexObjectList)
+    {
+        g_mutexObjectList = ca_mutex_new();
+        if (!g_mutexObjectList)
+        {
+            OIC_LOG(ERROR, TAG, "Failed to created mutex!");
+            return CA_STATUS_FAILED;
+        }
+    }
+
+    return CA_STATUS_OK;
+}
+
+static void CATCPDestroyCond()
+{
+    if (g_condObjectList)
+    {
+        ca_cond_free(g_condObjectList);
+        g_condObjectList = NULL;
+    }
+}
+
+static CAResult_t CATCPCreateCond()
+{
+    if (!g_condObjectList)
+    {
+        g_condObjectList = ca_cond_new();
+        if (!g_condObjectList)
+        {
+            OIC_LOG(ERROR, TAG, "Failed to created cond!");
+            return CA_STATUS_FAILED;
+        }
+    }
+    return CA_STATUS_OK;
+}
+
+static void CATCPDisconnectAll()
+{
+    OIC_LOG(DEBUG, TAG, "IN");
+
+    ca_mutex_lock(g_mutexObjectList);
+    uint32_t length = u_arraylist_length(caglobals.tcp.svrlist);
+
+    CATCPServerInfo_t *svritem = NULL;
+    for (size_t i = 0; i < length; i++)
+    {
+        svritem = (CATCPServerInfo_t *) u_arraylist_get(caglobals.tcp.svrlist, i);
+        if (svritem && svritem->u4tcp.fd >= 0)
+        {
+            shutdown(svritem->u4tcp.fd, SHUT_RDWR);
+            close(svritem->u4tcp.fd);
+        }
+    }
+    u_arraylist_destroy(caglobals.tcp.svrlist);
+
+    ca_mutex_unlock(g_mutexObjectList);
+
+    OIC_LOG(DEBUG, TAG, "OUT");
+}
+
+static void CAReceiveHandler(void *data)
+{
+    (void)data;
+    OIC_LOG(DEBUG, TAG, "IN - CAReceiveHandler");
+
+    while (!caglobals.tcp.terminate)
+    {
+        CAReceiveMessage();
+    }
+
+    ca_mutex_lock(g_mutexObjectList);
+    // notify the thread
+    g_threadCounts--;
+    if (!g_threadCounts)
+    {
+        ca_cond_signal(g_condObjectList);
+    }
+    ca_mutex_unlock(g_mutexObjectList);
+
+    OIC_LOG(DEBUG, TAG, "OUT - CAReceiveHandler");
+}
+
+static size_t CAGetTotalLengthFromHeader(const unsigned char *recvBuffer)
+{
+    OIC_LOG(DEBUG, TAG, "IN - CAGetTotalLengthFromHeader");
+
+    coap_transport_type transport = coap_get_tcp_header_type_from_initbyte(
+            ((unsigned char *)recvBuffer)[0] >> 4);
+    size_t optPaylaodLen = coap_get_length_from_header((unsigned char *)recvBuffer,
+                                                        transport);
+    size_t headerLen = coap_get_tcp_header_length((unsigned char *)recvBuffer);
+
+    OIC_LOG_V(DEBUG, TAG, "option/paylaod length [%d]", optPaylaodLen);
+    OIC_LOG_V(DEBUG, TAG, "header length [%d]", headerLen);
+    OIC_LOG_V(DEBUG, TAG, "total data length [%d]", headerLen + optPaylaodLen);
+
+    OIC_LOG(DEBUG, TAG, "OUT - CAGetTotalLengthFromHeader");
+    return headerLen + optPaylaodLen;
+}
+
+static CAResult_t CAReceiveMessage()
+{
+    uint32_t length = u_arraylist_length(caglobals.tcp.svrlist);
+
+    size_t i = 0;
+    unsigned char *recvBuffer = NULL;
+    CATCPServerInfo_t *svritem = NULL;
+    for (i = 0; i < length; i++)
+    {
+        svritem = (CATCPServerInfo_t *) u_arraylist_get(caglobals.tcp.svrlist, i);
+        if (svritem->u4tcp.fd < 0)
+        {
+            continue;
+        }
+
+        size_t bufSize = TCP_MAX_HEADER_LEN;
+        recvBuffer = (unsigned char *) OICCalloc(1, bufSize);
+        if (!recvBuffer)
+        {
+            OIC_LOG(ERROR, TAG, "out of memory");
+            goto exit;
+        }
+
+        bool isHeaderChecked = false;
+        size_t totalLen = 0;
+        size_t totalReceivedLen = 0;
+        do
+        {
+            ssize_t recvLen = recv(svritem->u4tcp.fd, recvBuffer + totalReceivedLen,
+                                   bufSize - totalReceivedLen, 0);
+            if (recvLen <= 0)
+            {
+                if(EWOULDBLOCK != errno)
+                {
+                    OIC_LOG_V(ERROR, TAG, "Recvfrom failed %s", strerror(errno));
+                    goto exit;
+                }
+                // if received data length is zero, we are breaking loop.
+                // because we use non-blocking socket to receive data from remote device.
+                if (!totalReceivedLen)
+                {
+                    break;
+                }
+                continue;
+            }
+
+            totalReceivedLen += recvLen;
+            if (!isHeaderChecked && totalReceivedLen)
+            {
+                coap_transport_type transport = coap_get_tcp_header_type_from_initbyte(
+                        ((unsigned char *)recvBuffer)[0] >> 4);
+                size_t headerLen = coap_get_tcp_header_length_for_transport(transport);
+                if (totalReceivedLen >= headerLen)
+                {
+                    // get actual data length from coap over tcp header
+                    totalLen = CAGetTotalLengthFromHeader((unsigned char *) recvBuffer);
+                    bufSize = totalLen;
+                    unsigned char *newBuf = OICRealloc(recvBuffer, bufSize);
+                    if (NULL == newBuf)
+                    {
+                        OIC_LOG(ERROR, TAG, "out of memory");
+                        goto exit;
+                    }
+                    recvBuffer = newBuf;
+                    isHeaderChecked = true;
+                }
+            }
+            if (totalLen == totalReceivedLen)
+            {
+                CAEndpoint_t ep = { .adapter = CA_ADAPTER_TCP,
+                                    .port = svritem->u4tcp.port };
+                strncpy(ep.addr, svritem->addr, sizeof(ep.addr));
+
+                if (g_packetReceivedCallback)
+                {
+                    g_packetReceivedCallback(&ep, recvBuffer, totalLen);
+                }
+                OIC_LOG_V(DEBUG, TAG, "received data len:%d", totalLen);
+                break;
+            }
+        } while (!totalLen || totalLen > totalReceivedLen);
+
+        OICFree(recvBuffer);
+    }
+
+    return CA_STATUS_OK;
+
+exit:
+    ca_mutex_lock(g_mutexObjectList);
+    close(svritem->u4tcp.fd);
+    u_arraylist_remove(caglobals.tcp.svrlist, i);
+    ca_mutex_unlock(g_mutexObjectList);
+    OICFree(recvBuffer);
+    return CA_STATUS_FAILED;
+}
+
+// TODO: resolving duplication.
+static int CASetNonblocking(int fd)
+{
+    int fl = fcntl(fd, F_GETFL);
+    if (fl == -1)
+    {
+        OIC_LOG_V(ERROR, TAG, "Failed to get existing flags, Error code: %s",
+                  strerror(errno));
+    }
+    else if ((fl & O_NONBLOCK) != O_NONBLOCK)
+    {
+        fl = fcntl(fd, F_SETFL, fl | O_NONBLOCK);
+        if (fl == -1)
+        {
+            OIC_LOG_V(ERROR, TAG, "Failed to set non-blocking mode, Error code: %s",
+                      strerror(errno));
+        }
+    }
+
+    return fl;
+}
+
+static int CATCPCreateSocket(int family, CATCPServerInfo_t *TCPServerInfo)
+{
+    // create tcp socket
+    int fd = socket(family, SOCK_STREAM, IPPROTO_TCP);
+    if (-1 == fd)
+    {
+        OIC_LOG_V(ERROR, TAG, "create socket failed: %s", strerror(errno));
+        goto exit;
+    }
+
+    // set non-blocking socket
+    if (-1 == CASetNonblocking(fd))
+    {
+        goto exit;
+    }
+
+    struct sockaddr_storage sa = { .ss_family = family };
+    CAConvertNameToAddr(TCPServerInfo->addr, TCPServerInfo->u4tcp.port, &sa);
+    socklen_t socklen = sizeof (struct sockaddr_in);
+
+    // connect to TCP server
+    int ret = connect(fd, (struct sockaddr *)&sa, socklen);
+    if (0 == ret)
+    {
+        OIC_LOG(DEBUG, TAG, "connect socket success");
+    }
+    else if (EINPROGRESS == errno)
+    {
+        int error = 0;
+        socklen_t len = sizeof(error);
+        if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0)
+        {
+            OIC_LOG(ERROR, TAG, "getsockopt() error");
+            goto exit;
+        }
+
+        if (error)
+        {
+            if (ECONNREFUSED == error)
+            {
+                OIC_LOG(ERROR, TAG, "connection refused");
+                goto exit;
+            }
+            OIC_LOG(ERROR, TAG, "failed to connect socket");
+            goto exit;
+        }
+        OIC_LOG(DEBUG, TAG, "connect socket success");
+    }
+    else
+    {
+        OIC_LOG(ERROR, TAG, "failed to connect socket");
+        goto exit;
+    }
+
+    return fd;
+
+exit:
+    if (fd >= 0)
+    {
+        close(fd);
+    }
+    return -1;
+}
+
+static void CAAcceptHandler(void *data)
+{
+    (void)data;
+    OIC_LOG(DEBUG, TAG, "IN - CAAcceptHandler");
+
+    int reuse = 1;
+    struct sockaddr_in server = { .sin_addr.s_addr = INADDR_ANY,
+                                  .sin_family = AF_INET,
+                                  .sin_port = htons(SERVER_PORT) };
+
+    g_acceptServerFD = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    if (g_acceptServerFD < 0)
+    {
+        OIC_LOG(ERROR, TAG, "Failed to create socket");
+        goto exit;
+    }
+
+    if (-1 == setsockopt(g_acceptServerFD, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)))
+    {
+        OIC_LOG(ERROR, TAG, "setsockopt SO_REUSEADDR");
+        goto exit;
+    }
+
+    int serverlen = sizeof(server);
+    if (-1 == bind(g_acceptServerFD, (struct sockaddr *)&server, serverlen))
+    {
+        OIC_LOG(ERROR, TAG, "bind() error");
+        goto exit;
+    }
+
+    if (listen(g_acceptServerFD, caglobals.tcp.listenBacklog) != 0)
+    {
+        OIC_LOG(ERROR, TAG, "listen() error");
+        goto exit;
+    }
+
+    struct pollfd acceptServerFD = { .fd = g_acceptServerFD,
+                                     .events = POLLIN };
+
+    while (!caglobals.tcp.terminate)
+    {
+        int pollState = poll(&acceptServerFD, 1, caglobals.tcp.selectTimeout);
+        if (pollState < 0)
+        {
+            OIC_LOG_V(FATAL, TAG, "polling error %s", strerror(errno));
+            goto exit;
+        }
+        else if (!pollState)
+        {
+            continue;
+        }
+
+        if (acceptServerFD.revents & POLLIN)
+        {
+            struct sockaddr_storage clientaddr;
+            socklen_t clientlen = sizeof (struct sockaddr_in);
+
+            int sockfd = accept(g_acceptServerFD, (struct sockaddr *)&clientaddr, &clientlen);
+            if (sockfd != -1)
+            {
+                CATCPServerInfo_t *svritem = (CATCPServerInfo_t *) OICMalloc(sizeof (*svritem));
+                if (!svritem)
+                {
+                    OIC_LOG(ERROR, TAG, "Out of memory");
+                    close(sockfd);
+                    return;
+                }
+
+                // set non-blocking socket
+                if (-1 == CASetNonblocking(sockfd))
+                {
+                    close(sockfd);
+                    OICFree(svritem);
+                    continue;
+                }
+                svritem->u4tcp.fd = sockfd;
+
+                CAConvertAddrToName((struct sockaddr_storage *)&clientaddr,
+                                    (char *) &svritem->addr, &svritem->u4tcp.port);
+
+                ca_mutex_lock(g_mutexObjectList);
+                bool res = u_arraylist_add(caglobals.tcp.svrlist, svritem);
+                if (!res)
+                {
+                    OIC_LOG(ERROR, TAG, "u_arraylist_add failed.");
+                    close(sockfd);
+                    OICFree(svritem);
+                    ca_mutex_unlock(g_mutexObjectList);
+                    continue;
+                }
+                ca_mutex_unlock(g_mutexObjectList);
+            }
+        }
+    }
+
+    ca_mutex_lock(g_mutexObjectList);
+    // notify the thread
+    g_threadCounts--;
+    if (!g_threadCounts)
+    {
+        ca_cond_signal(g_condObjectList);
+    }
+    ca_mutex_unlock(g_mutexObjectList);
+
+    OIC_LOG(DEBUG, TAG, "OUT - CAAcceptHandler");
+
+exit:
+    if (g_acceptServerFD >= 0)
+    {
+        close(g_acceptServerFD);
+    }
+    ca_mutex_lock(g_mutexObjectList);
+    g_threadCounts--;
+    if (!g_threadCounts)
+    {
+        ca_cond_signal(g_condObjectList);
+    }
+    ca_mutex_unlock(g_mutexObjectList);
+    return;
+}
+
+CAResult_t CATCPStartServer(const ca_thread_pool_t threadPool)
+{
+    if (caglobals.tcp.started)
+    {
+        return CA_STATUS_OK;
+    }
+
+    if (!caglobals.tcp.ipv4tcpenabled)
+    {
+        caglobals.tcp.ipv4tcpenabled = true;    // only needed to run CA tests
+    }
+
+    CAResult_t res = CATCPCreateMutex();
+    if (CA_STATUS_OK != res)
+    {
+        OIC_LOG(ERROR, TAG, "failed to create mutex");
+        return res;
+    }
+
+    res = CATCPCreateCond();
+    if (CA_STATUS_OK != res)
+    {
+        OIC_LOG(ERROR, TAG, "failed to create cond");
+        return res;
+    }
+
+    ca_mutex_lock(g_mutexObjectList);
+    if (!caglobals.tcp.svrlist)
+    {
+        caglobals.tcp.svrlist = u_arraylist_create();
+    }
+    ca_mutex_unlock(g_mutexObjectList);
+
+    caglobals.tcp.terminate = false;
+
+    res = ca_thread_pool_add_task(threadPool, CAAcceptHandler, NULL);
+    if (CA_STATUS_OK != res)
+    {
+        OIC_LOG(ERROR, TAG, "thread_pool_add_task failed");
+        return res;
+    }
+    OIC_LOG(DEBUG, TAG, "CAAcceptHandler thread started successfully.");
+
+    res = ca_thread_pool_add_task(threadPool, CAReceiveHandler, NULL);
+    if (CA_STATUS_OK != res)
+    {
+        OIC_LOG(ERROR, TAG, "thread_pool_add_task failed");
+        return res;
+    }
+    OIC_LOG(DEBUG, TAG, "CAReceiveHandler thread started successfully.");
+
+    caglobals.tcp.started = true;
+
+    return CA_STATUS_OK;
+}
+
+void CATCPStopServer()
+{
+    OIC_LOG(DEBUG, TAG, "IN");
+
+    // mutex lock
+    ca_mutex_lock(g_mutexObjectList);
+
+    // set terminate flag
+    caglobals.tcp.terminate = true;
+
+    ca_cond_wait(g_condObjectList, g_mutexObjectList);
+
+    // mutex unlock
+    ca_mutex_unlock(g_mutexObjectList);
+
+    if (-1 != g_acceptServerFD)
+    {
+        close(g_acceptServerFD);
+        g_acceptServerFD = -1;
+    }
+
+    CATCPDisconnectAll();
+    CATCPDestroyMutex();
+    CATCPDestroyCond();
+
+    OIC_LOG(DEBUG, TAG, "OUT");
+}
+
+void CATCPSetPacketReceiveCallback(CATCPPacketReceivedCallback callback)
+{
+    OIC_LOG(DEBUG, TAG, "IN");
+
+    g_packetReceivedCallback = callback;
+
+    OIC_LOG(DEBUG, TAG, "OUT");
+}
+
+static size_t CACheckPayloadLength(const void *data, size_t dlen)
+{
+    coap_transport_type transport = coap_get_tcp_header_type_from_initbyte(
+            ((unsigned char *)data)[0] >> 4);
+
+    coap_pdu_t *pdu = coap_new_pdu(transport, dlen);
+    if (!pdu)
+    {
+        OIC_LOG(ERROR, TAG, "outpdu is null");
+        return 0;
+    }
+
+    int ret = coap_pdu_parse((unsigned char *) data, dlen, pdu, transport);
+    if (0 >= ret)
+    {
+        OIC_LOG(ERROR, TAG, "pdu parse failed");
+        coap_delete_pdu(pdu);
+        return 0;
+    }
+
+    size_t payloadLen = 0;
+    if (pdu->data)
+    {
+        payloadLen = (unsigned char *) pdu->hdr + pdu->length - pdu->data;
+        OICFree(pdu);
+    }
+
+    return payloadLen;
+}
+
+static void sendData(const CAEndpoint_t *endpoint,
+                     const void *data, size_t dlen)
+{
+    // #1. get TCP Server object from list
+    uint32_t index = 0;
+    CATCPServerInfo_t *svritem = CAGetTCPServerInfoFromList(endpoint->addr, endpoint->port,
+                                                            &index);
+    if (!svritem)
+    {
+        // if there is no connection info, connect to TCP Server
+        svritem = CAConnectToTCPServer(endpoint);
+        if (!svritem)
+        {
+            OIC_LOG(ERROR, TAG, "Failed to create TCP server object");
+            g_TCPErrorHandler(endpoint, data, dlen, CA_SEND_FAILED);
+            return;
+        }
+    }
+
+    // #2. check payload length
+    size_t payloadLen = CACheckPayloadLength(data, dlen);
+    // if payload length is zero, disconnect from TCP server
+    if (!payloadLen)
+    {
+        OIC_LOG(DEBUG, TAG, "payload length is zero, disconnect from remote device");
+        CADisconnectFromTCPServer(endpoint);
+        return;
+    }
+
+    // #3. check connection state
+    if (svritem->u4tcp.fd < 0)
+    {
+        // if file descriptor value is wrong, remove TCP Server info from list
+        OIC_LOG(ERROR, TAG, "Failed to connect to TCP server");
+        CADisconnectFromTCPServer(endpoint);
+        g_TCPErrorHandler(endpoint, data, dlen, CA_SEND_FAILED);
+        return;
+    }
+
+    // #4. send data to TCP Server
+    size_t remainLen = dlen;
+    do
+    {
+        size_t len = send(svritem->u4tcp.fd, data, remainLen, 0);
+        if (-1 == len)
+        {
+            if (EWOULDBLOCK != errno)
+            {
+                OIC_LOG_V(ERROR, TAG, "unicast ipv4tcp sendTo failed: %s", strerror(errno));
+                g_TCPErrorHandler(endpoint, data, dlen, CA_SEND_FAILED);
+                return;
+            }
+            continue;
+        }
+        data += len;
+        remainLen -= len;
+    } while (remainLen > 0);
+
+    OIC_LOG_V(INFO, TAG, "unicast ipv4tcp sendTo is successful: %d bytes", dlen);
+}
+
+void CATCPSendData(CAEndpoint_t *endpoint, const void *data, uint32_t datalen,
+                   bool isMulticast)
+{
+    VERIFY_NON_NULL_VOID(endpoint, TAG, "endpoint is NULL");
+    VERIFY_NON_NULL_VOID(data, TAG, "data is NULL");
+
+    if (!isMulticast)
+    {
+        if (caglobals.tcp.ipv4tcpenabled && (endpoint->adapter & CA_ADAPTER_TCP))
+        {
+            sendData(endpoint, data, datalen);
+        }
+    }
+}
+
+CAResult_t CAGetTCPInterfaceInformation(CAEndpoint_t **info, uint32_t *size)
+{
+    OIC_LOG(DEBUG, TAG, "IN");
+
+    VERIFY_NON_NULL(info, TAG, "info is NULL");
+    VERIFY_NON_NULL(size, TAG, "size is NULL");
+
+    return CA_NOT_SUPPORTED;
+}
+
+CATCPServerInfo_t *CAConnectToTCPServer(const CAEndpoint_t *TCPServerInfo)
+{
+    VERIFY_NON_NULL_RET(TCPServerInfo, TAG, "TCPServerInfo is NULL", NULL);
+
+    // #1. create TCP server object
+    CATCPServerInfo_t *svritem = (CATCPServerInfo_t *) OICMalloc(sizeof (*svritem));
+    if (!svritem)
+    {
+        OIC_LOG(ERROR, TAG, "Out of memory");
+        return NULL;
+    }
+    memcpy(svritem->addr, TCPServerInfo->addr, sizeof(svritem->addr));
+    svritem->u4tcp.port = TCPServerInfo->port;
+
+    // #2. create the socket and connect to TCP server
+    if (caglobals.tcp.ipv4tcpenabled)
+    {
+        svritem->u4tcp.fd = CATCPCreateSocket(AF_INET, svritem);
+        if (-1 == svritem->u4tcp.fd)
+        {
+            OICFree(svritem);
+            return NULL;
+        }
+    }
+
+    // #3. add TCP connection info to list
+    ca_mutex_lock(g_mutexObjectList);
+    if (caglobals.tcp.svrlist)
+    {
+        bool res = u_arraylist_add(caglobals.tcp.svrlist, svritem);
+        if (!res)
+        {
+            OIC_LOG(ERROR, TAG, "u_arraylist_add failed.");
+            close(svritem->u4tcp.fd);
+            OICFree(svritem);
+            ca_mutex_unlock(g_mutexObjectList);
+            return NULL;
+        }
+    }
+    ca_mutex_unlock(g_mutexObjectList);
+
+    return svritem;
+}
+
+CAResult_t CADisconnectFromTCPServer(const CAEndpoint_t *TCPServerInfo)
+{
+    VERIFY_NON_NULL(TCPServerInfo, TAG, "TCP server info is NULL");
+
+    // #1. get server info
+    uint32_t index = 0;
+    ca_mutex_lock(g_mutexObjectList);
+    CATCPServerInfo_t *svritem = CAGetTCPServerInfoFromList(TCPServerInfo->addr,
+                                                            TCPServerInfo->port,
+                                                            &index);
+    if (!svritem)
+    {
+        OIC_LOG(ERROR, TAG, "there is no connection info");
+        ca_mutex_unlock(g_mutexObjectList);
+        return CA_STATUS_FAILED;
+    }
+
+    // #2. close the socket and remove TCP connection info in list
+    if (svritem->u4tcp.fd >= 0)
+    {
+        close(svritem->u4tcp.fd);
+    }
+    u_arraylist_remove(caglobals.tcp.svrlist, index);
+    ca_mutex_unlock(g_mutexObjectList);
+
+    return CA_STATUS_OK;
+}
+
+CATCPServerInfo_t *CAGetTCPServerInfoFromList(const char *addr, const uint16_t port,
+                                              uint32_t *index)
+{
+    VERIFY_NON_NULL_RET(addr, TAG, "addr is NULL", NULL);
+    VERIFY_NON_NULL_RET(index, TAG, "index is NULL", NULL);
+
+    // get connection info from list
+    uint32_t length = u_arraylist_length(caglobals.tcp.svrlist);
+
+    for (size_t i = 0; i < length; i++)
+    {
+        CATCPServerInfo_t *svritem = (CATCPServerInfo_t *) u_arraylist_get(
+                caglobals.tcp.svrlist, i);
+        if (!svritem)
+        {
+            continue;
+        }
+
+        if (!strncmp(svritem->addr, addr, sizeof(svritem->addr))
+                && (svritem->u4tcp.port == port))
+        {
+            *index = i;
+            return svritem;
+        }
+    }
+
+    return NULL;
+}
+
+void CATCPSetErrorHandler(CATCPErrorHandleCallback errorHandleCallback)
+{
+    g_TCPErrorHandler = errorHandleCallback;
+}
index 543c68f..299d39a 100644 (file)
@@ -22,6 +22,7 @@
 #include "cainterface.h"
 #include "cacommon.h"
 
+#define CA_TRANSPORT_ADAPTER_SCOPE  1000
 
 class CATests : public testing::Test {
     protected:
@@ -464,14 +465,16 @@ CAResult_t checkSelectNetwork()
 TEST_F(CATests, SelectNetworkTestBad)
 {
     //Select disable network
-    EXPECT_EQ(CA_NOT_SUPPORTED, CASelectNetwork((CATransportAdapter_t)1000));
+    EXPECT_EQ(CA_NOT_SUPPORTED, CASelectNetwork((CATransportAdapter_t)
+                                                CA_TRANSPORT_ADAPTER_SCOPE));
 }
 
 // check return value when selected network is disable
 TEST_F(CATests, UnSelectNetworkTest)
 {
     //UnSelect disable network
-    EXPECT_EQ(CA_STATUS_FAILED, CAUnSelectNetwork((CATransportAdapter_t)1000));
+    EXPECT_EQ(CA_STATUS_FAILED, CAUnSelectNetwork((CATransportAdapter_t)
+                                                  CA_TRANSPORT_ADAPTER_SCOPE));
 }
 
 // CAHandlerRequestResponse TC