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')))
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']:
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':
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;
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;
/**
* 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.
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.
*
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))
/**
* 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
/**
#include "cacommon.h"
#include "config.h"
#include "coap.h"
-#include "debug.h"
#ifdef __cplusplus
extern "C"
/**
* 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.
* @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.
--- /dev/null
+/* ****************************************************************
+ *
+ * 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_
--- /dev/null
+/* *****************************************************************
+ *
+ * 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_ */
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':
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'])
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
/* 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));
/* 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;
}
#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)))
{
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)))
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))
{
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]);
}
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);
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);
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;
#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);
}
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;
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;
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;
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);
}
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;
}
{
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 */
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
}
/* 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);
}
/* 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. */
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;
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)
* 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))
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)
{
* 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:
}
/* 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);
}
}
* 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
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;
* 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);
* 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
{
#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;
}
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);
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)
{
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);
}
* @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
* @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
#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
#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()
#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
#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)
#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
}
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
#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;
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);
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);
{
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)
{
}
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);
}
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 */
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
* @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
* 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
* @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 *);
* @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
* 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.
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);
}
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;
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;
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;
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)
{
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)
#define SYSTEM_INVOKE_ERROR 127
#define SYSTEM_ERROR -1
+#ifdef WITH_BWT
#define BLOCK_SIZE(arg) (1 << ((arg) + 4))
+#endif
/**
* @def RS_IDENTITY
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\"],"
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
{
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 };
printf("IP : 0\n");
printf("GATT : 1\n");
printf("RFCOMM : 2\n");
+ printf("TCP : 4\n");
printf("select : ");
char buf[MAX_BUF_LEN] = { 0 };
int number = buf[0] - '0';
- if (number < 0 || number > 3)
+ if (number < 0 || number > 4)
{
printf("Invalid network type\n");
return;
printf("IP : 0\n");
printf("GATT : 1\n");
printf("RFCOMM : 2\n");
+ printf("TCP : 4\n");
printf("select : ");
char buf[MAX_BUF_LEN] = { 0 };
int number = buf[0] - '0';
- if (number < 0 || number > 3)
+ if (number < 0 || number > 4)
{
printf("Invalid network type\n");
return;
}
}
+#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);
}
}
+#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)
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))
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)
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;
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 = [
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']:
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..");
// 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)
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)
{
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);
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);
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,
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,
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);
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,
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)
{
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);
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)
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))
{
&(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);
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)
}
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");
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");
&(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);
{
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;
}
// 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)
{
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");
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)
if (cadata->requestInfo)
{
- cadata->requestInfo->info.messageId = pdu->hdr->id;
+ cadata->requestInfo->info.messageId = pdu->hdr->coap_hdr_udp_t.id;
}
}
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");
}
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)
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)
}
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
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);
}
// 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)
{
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);
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;
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)
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)
#include "caadapternetdtls.h"
#endif
+#ifdef TCP_ADAPTER
+#include "catcpadapter.h"
+#endif
+
CAGlobals_t caglobals = { 0 };
#define TAG "CA_CONN_MGR"
"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;
{
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;
#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
return 3;
#endif
+#ifdef TCP_ADAPTER
+ case CA_ADAPTER_TCP:
+ return 4;
+#endif
+
default:
break;
}
handle);
#endif /* RA_ADAPTER */
-
+#ifdef TCP_ADAPTER
+ CAInitializeTCP(CARegisterCallback, CAReceivedPacketCallback, CANetworkChangedCallback,
+ CAAdapterErrorHandleCallback, handle);
+#endif /* TCP_ADAPTER */
}
void CASetPacketReceivedCallback(CANetworkPacketReceivedCallback callback)
return NULL;
}
- result = CAGetResponseInfoFromPDU(data, resInfo);
+ result = CAGetResponseInfoFromPDU(data, resInfo, endpoint);
if (CA_STATUS_OK != result)
{
OIC_LOG(ERROR, TAG, "CAGetResponseInfoFromPDU Failed");
return NULL;
}
- result = CAGetRequestInfoFromPDU(data, reqInfo);
+ result = CAGetRequestInfoFromPDU(data, endpoint, reqInfo);
if (CA_STATUS_OK != result)
{
OIC_LOG(ERROR, TAG, "CAGetRequestInfoFromPDU failed");
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");
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");
if (SEND_TYPE_UNICAST == type)
{
-
OIC_LOG(DEBUG,TAG,"Unicast message");
if (NULL != data->requestInfo)
{
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)
}
}
#endif
- CALogPDUInfo(pdu);
+ CALogPDUInfo(pdu, data->remoteEndpoint);
res = CASendUnicastData(data->remoteEndpoint, pdu->hdr, pdu->length);
if (CA_STATUS_OK != res)
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);
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,
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)
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)
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");
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;
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)
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);
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);
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)
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");
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");
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;
}
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;
}
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");
}
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");
}
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");
}
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;
}
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;
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");
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");
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)
{
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)
{
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");
{
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)
{
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");
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
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)
{
}
}
+ 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;
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)
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");
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)
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)
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)
--- /dev/null
+#######################################################
+# 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
--- /dev/null
+/* ****************************************************************
+ *
+ * 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);
+}
--- /dev/null
+/* ****************************************************************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;
+}
#include "cainterface.h"
#include "cacommon.h"
+#define CA_TRANSPORT_ADAPTER_SCOPE 1000
class CATests : public testing::Test {
protected:
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