From 5f9c50b57ea56a34b18c05a5163c32b3d9e0980e Mon Sep 17 00:00:00 2001 From: "hyuna0213.jo" Date: Wed, 19 Aug 2015 15:33:52 +0900 Subject: [PATCH] Add CI Adapter to support CoAP over TCP - add new transport adapter and flag for CoAP over TCP - two interface was added in CA Layer for tcp connection - https://wiki.iotivity.org/proposal_for_cloud_interface_in_iotivity Change-Id: I75849e3f1250d7cc94de67766534ee19c308433d Signed-off-by: hyuna0213.jo Signed-off-by: jihwan.seo Reviewed-on: https://gerrit.iotivity.org/gerrit/2240 Reviewed-by: Jaehong Jo Reviewed-by: Jon A. Cruz Tested-by: Jon A. Cruz --- build_common/SConscript | 4 +- resource/csdk/connectivity/SConscript | 12 +- resource/csdk/connectivity/api/cacommon.h | 34 +- resource/csdk/connectivity/api/cainterface.h | 18 + resource/csdk/connectivity/build/SConscript | 2 +- resource/csdk/connectivity/inc/caciadapter.h | 149 ++++++ resource/csdk/connectivity/inc/caciinterface.h | 141 ++++++ .../csdk/connectivity/samples/linux/sample_main.c | 106 +++- resource/csdk/connectivity/src/SConscript | 5 +- .../csdk/connectivity/src/caconnectivitymanager.c | 54 +- .../csdk/connectivity/src/cainterfacecontroller.c | 20 +- .../csdk/connectivity/src/canetworkconfigurator.c | 23 + .../csdk/connectivity/src/ci_adapter/SConscript | 47 ++ .../csdk/connectivity/src/ci_adapter/caciadapter.c | 468 +++++++++++++++++ .../csdk/connectivity/src/ci_adapter/caciserver.c | 564 +++++++++++++++++++++ .../csdk/connectivity/test/ca_api_unittest.cpp | 4 +- 16 files changed, 1618 insertions(+), 33 deletions(-) create mode 100644 resource/csdk/connectivity/inc/caciadapter.h create mode 100644 resource/csdk/connectivity/inc/caciinterface.h create mode 100644 resource/csdk/connectivity/src/ci_adapter/SConscript create mode 100644 resource/csdk/connectivity/src/ci_adapter/caciadapter.c create mode 100644 resource/csdk/connectivity/src/ci_adapter/caciserver.c diff --git a/build_common/SConscript b/build_common/SConscript index 7f4c650..2bf4e04 100644 --- a/build_common/SConscript +++ b/build_common/SConscript @@ -81,9 +81,9 @@ help_vars.Add(EnumVariable('TARGET_OS', 'Target platform', host, host_target_map help_vars.Add(BoolVariable('WITH_RA', 'Build with Remote Access module', False)) if target_os in targets_disallow_multitransport: - help_vars.Add(ListVariable('TARGET_TRANSPORT', 'Target transport', 'IP', ['BT', 'BLE', 'IP'])) + help_vars.Add(ListVariable('TARGET_TRANSPORT', 'Target transport', 'IP', ['BT', 'BLE', 'IP', 'CI'])) 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', 'CI'])) 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'))) diff --git a/resource/csdk/connectivity/SConscript b/resource/csdk/connectivity/SConscript index e68924f..9e13b75 100644 --- a/resource/csdk/connectivity/SConscript +++ b/resource/csdk/connectivity/SConscript @@ -25,7 +25,7 @@ if 'ALL' in transport: if with_ra == True: env.AppendUnique(CPPDEFINES = ['RA_ADAPTER']) if target_os == 'linux': - env.AppendUnique(CPPDEFINES = ['IP_ADAPTER','NO_EDR_ADAPTER','LE_ADAPTER']) + env.AppendUnique(CPPDEFINES = ['IP_ADAPTER','NO_EDR_ADAPTER','LE_ADAPTER', 'CI_ADAPTER']) elif target_os == 'tizen': env.AppendUnique(CPPDEFINES = ['IP_ADAPTER','EDR_ADAPTER','LE_ADAPTER']) elif target_os in['darwin','ios']: @@ -56,6 +56,16 @@ else: else: env.AppendUnique(CPPDEFINES = ['NO_IP_ADAPTER']) + if 'CI' in transport: + if target_os in['linux']: + env.AppendUnique(CPPDEFINES = ['CI_ADAPTER']) + print "CA Transport is CI" + else: + print "CA Transport CI is not supported " + Exit(1) + else: + env.AppendUnique(CPPDEFINES = ['NO_CI_ADAPTER']) + env.SConscript('./src/SConscript') if build_sample == 'ON': diff --git a/resource/csdk/connectivity/api/cacommon.h b/resource/csdk/connectivity/api/cacommon.h index 02fd501..b7a659a 100644 --- a/resource/csdk/connectivity/api/cacommon.h +++ b/resource/csdk/connectivity/api/cacommon.h @@ -79,6 +79,10 @@ extern "C" #define COAP_MAX_PDU_SIZE 1400 /* maximum size of a CoAP PDU for big platforms*/ #endif +#ifdef CI_ADAPTER +#define COAP_TCP_MAX_PDU_SIZE 64 * 1024 /* maximum size of a CoAP over TCP PDU for Linux platform*/ +#endif + #ifdef WITH_BWT #define CA_DEFAULT_BLOCK_SIZE CA_BLOCK_SIZE_1024_BYTE #endif @@ -142,7 +146,7 @@ typedef enum #endif #ifdef CI_ADAPTER - CA_ADAPTER_CLOUD_INTERFACE = (1 << 4), // CoAP over TCP for Cloud Interface + CA_ADAPTER_CLOUD_INTERFACE = (1 << 5), // CoAP over TCP for Cloud Interface #endif CA_ALL_ADAPTERS = 0xffffffff @@ -160,6 +164,7 @@ typedef enum // Indication that a message was received by multicast. CA_MULTICAST = (1 << 7), #ifdef CI_ADAPTER + // A TCP transport for the CoAP CA_IPV4_TCP = (1 << 8), #endif // Link-Local multicast is the default multicast scope for IPv6. @@ -448,6 +453,17 @@ typedef struct int32_t ifIndex; /**< network interface index */ } CAIfItem_t; +#ifdef CI_ADAPTER +/** + * CI Server Information for IPv4 TCP transport + */ +typedef struct +{ + char addr[MAX_ADDR_STR_SIZE_CA]; /**< CI Server address */ + CASocket_t u4tcp; /**< CI Server port */ +} CACIServerInfo_t; +#endif + typedef struct { CATransportFlags_t clientFlags; /**< flag for client */ @@ -491,6 +507,22 @@ typedef struct CATransportFlags_t previousRequestFlags;/**< address family filtering */ uint16_t previousRequestMessageId; /**< address family filtering */ } ca; + + #ifdef CI_ADAPTER + /** + * Hold global variables for CI Adapter. + */ + struct cisockets + { + void *threadpool; /**< threadpool between Initialize and Start */ + void *svrlist; /**< unicast IPv4 CI server information*/ + int selectTimeout; /**< in seconds */ + int maxfd; /**< highest fd (for select) */ + bool started; /**< the CI adapter has started */ + bool terminate; /**< the CI adapter needs to stop */ + bool ipv4tcpenabled; /**< IPv4 TCP enabled by OCInit flags */ + } ci; + #endif } CAGlobals_t; extern CAGlobals_t caglobals; diff --git a/resource/csdk/connectivity/api/cainterface.h b/resource/csdk/connectivity/api/cainterface.h index 7449b28..7c5a03a 100644 --- a/resource/csdk/connectivity/api/cainterface.h +++ b/resource/csdk/connectivity/api/cainterface.h @@ -238,6 +238,24 @@ CAResult_t CAGetNetworkInformation(CAEndpoint_t **info, uint32_t *size); */ CAResult_t CAHandleRequestResponse(); +#ifdef CI_ADAPTER +/** + * Connect to CI Server. + * @param[in] ciServerInfo CI Server information + * @return ::CA_STATUS_OK or ::CA_STATUS_FAILED or + * ::CA_STATUS_INVALID_PARAM or ::CA_MEMORY_ALLOC_FAILED + */ +CAResult_t CACreateTCPConnection(const CACIServerInfo_t *ciServerInfo); + +/** + * Disconnect to CI Server. + * @param[in] ciServerInfo CI Server information + * @return ::CA_STATUS_OK or ::CA_STATUS_FAILED or + * ::CA_STATUS_INVALID_PARAM or ::CA_MEMORY_ALLOC_FAILED + */ +CAResult_t CADestroyTCPConnection(const CACIServerInfo_t *ciServerInfo); +#endif + #ifdef RA_ADAPTER /** * Set Remote Access information for XMPP Client. diff --git a/resource/csdk/connectivity/build/SConscript b/resource/csdk/connectivity/build/SConscript index 8117205..936c604 100644 --- a/resource/csdk/connectivity/build/SConscript +++ b/resource/csdk/connectivity/build/SConscript @@ -60,7 +60,7 @@ help_vars = Variables() help_vars.Add(BoolVariable('RELEASE', 'Build for release?', True)) # set to 'no', 'false' or 0 for debug help_vars.Add(BoolVariable('LOGGING', 'Enable stack logging', False)) help_vars.Add(EnumVariable('TARGET_OS', 'Target platform', host, host_target_map[host])) -help_vars.Add(ListVariable('TARGET_TRANSPORT', 'Target transport', 'ALL', ['ALL', 'BT', 'BLE', 'IP'])) +help_vars.Add(ListVariable('TARGET_TRANSPORT', 'Target transport', 'ALL', ['ALL', 'BT', 'BLE', 'IP', 'CI'])) 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)) diff --git a/resource/csdk/connectivity/inc/caciadapter.h b/resource/csdk/connectivity/inc/caciadapter.h new file mode 100644 index 0000000..a6257e5 --- /dev/null +++ b/resource/csdk/connectivity/inc/caciadapter.h @@ -0,0 +1,149 @@ +/* **************************************************************** + * + * 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 CI Adapter. + */ +#ifndef CA_CI_ADAPTER_H_ +#define CA_CI_ADAPTER_H_ + +#include "cacommon.h" +#include "caadapterinterface.h" +#include "cathreadpool.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + * API to initialize CI Interface. + * @param[in] registerCallback Callback to register CI 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 CAInitializeCI(CARegisterConnectivityCallback registerCallback, + CANetworkPacketReceivedCallback networkPacketCallback, + CANetworkChangeCallback netCallback, + CAErrorHandleCallback errorCallback, ca_thread_pool_t handle); + +/** + * Start CI Interface adapter. + * @return ::CA_STATUS_OK or Appropriate error code. + */ +CAResult_t CAStartCI(); + +/** + * Start listening server for receiving connect requests. + * Transport Specific Behavior: + * CI 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 CAStartCIListeningServer(); + +/** + * Start discovery servers for receiving advertisements. + * Transport Specific Behavior: + * CI 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 CAStartCIDiscoveryServer(); + +/** + * 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 CASendCIUnicastData(const CAEndpoint_t *endpoint, const void *data, + uint32_t dataLen); + +/** + * Send Multicast data to the endpoint using the CI 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 CASendCIMulticastData(const CAEndpoint_t *endpoint, const void *data, uint32_t dataLen); + +/** + * Get CI 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 CAGetCIInterfaceInformation(CAEndpoint_t **info, uint32_t *size); + +/** + * Read Synchronous API callback. + * @return ::CA_STATUS_OK or Appropriate error code. + */ +CAResult_t CAReadCIData(); + +/** + * Stops Unicast, servers and close the sockets. + * @return ::CA_STATUS_OK or Appropriate error code. + */ +CAResult_t CAStopCI(); + +/** + * Terminate the CI connectivity adapter. + * Configuration information will be deleted from further use. + */ +void CATerminateCI(); + +/** + * Start CI clients and create the sockets. + * @param[in] ciServerInfo CI Server information. + * @return ::CA_STATUS_OK or Appropriate error code. + */ +CAResult_t CACreateCIClient(const CACIServerInfo_t *ciServerInfo); + +/** + * Stop CI clients and close the sockets. + * @param[in] ciServerInfo CI Server information. + * @return ::CA_STATUS_OK or Appropriate error code. + */ +CAResult_t CADestroyCIClient(const CACIServerInfo_t *ciServerInfo); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif // CA_CI_ADAPTER_H_ diff --git a/resource/csdk/connectivity/inc/caciinterface.h b/resource/csdk/connectivity/inc/caciinterface.h new file mode 100644 index 0000000..21343fd --- /dev/null +++ b/resource/csdk/connectivity/inc/caciinterface.h @@ -0,0 +1,141 @@ +/* ***************************************************************** + * + * 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 CI client/server/network monitor modules. + */ + +#ifndef CA_CI_INTERFACE_H_ +#define CA_CI_INTERFACE_H_ + +#include + +#include "cacommon.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 (*CACIPacketReceivedCallback)(const CAEndpoint_t *endpoint, + const void *data, + uint32_t dataLength); + +/** + * Callback to notify error in the CI 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 (*CACIErrorHandleCallback)(const CAEndpoint_t *endpoint, const void *data, + uint32_t dataLength, CAResult_t result); + +/** + * set error callback to notify error in CI adapter. + * + * @param[in] errorHandleCallback Callback function to notify the error + * in the CI adapter. + */ +void CACISetErrorHandler(CACIErrorHandleCallback errorHandleCallback); + +/** + * Start CI 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 CACIStartServer(const ca_thread_pool_t threadPool); + +/** + * Stop CI server. + */ +void CACIStopServer(); + +/** + * Set this callback for receiving data packets from peer devices. + * + * @param[in] callback Callback to be notified on reception of unicast data packets. + */ +void CACISetPacketReceiveCallback(CACIPacketReceivedCallback callback); + +/** + * API to send unicast CI 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 CACISendData(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 *CACIGetInterfaceInformation(int desiredIndex); + +/** + * Connect to CI Server. + * @param[in] ciServerInfo CI Server information. + * @return ::CA_STATUS_OK or Appropriate error code. + */ +CAResult_t CAConnectToCIServer(CACIServerInfo_t *ciServerInfo); + +/** + * Disconnect from CI Server. + * @param[in] ciServerInfo CI Server information. + * @return ::CA_STATUS_OK or Appropriate error code. + */ +CAResult_t CADisconnectFromCIServer(const CACIServerInfo_t *ciServerInfo); + +/** + * Get CI Connection Information from list. + * @param[in] addr CI Server address. + * @param[in] port CI Server port. + * @param[out] index index of array list. + * @return CI Server Information structure. + */ +CACIServerInfo_t *CAGetCIServerInfoFromList(const char *addr, const uint16_t port, + uint32_t *index); + +#ifdef __cplusplus +} +#endif + +#endif /* CA_CI_INTERFACE_H_ */ diff --git a/resource/csdk/connectivity/samples/linux/sample_main.c b/resource/csdk/connectivity/samples/linux/sample_main.c index 0f4fc25..f432aa9 100644 --- a/resource/csdk/connectivity/samples/linux/sample_main.c +++ b/resource/csdk/connectivity/samples/linux/sample_main.c @@ -44,7 +44,9 @@ #define SYSTEM_INVOKE_ERROR 127 #define SYSTEM_ERROR -1 +#ifdef WITH_BWT #define BLOCK_SIZE(arg) (1 << ((arg) + 4)) +#endif /** * @def RS_IDENTITY @@ -87,6 +89,9 @@ void unselect_network(); void handle_request_response(); void get_network_info(); void send_secure_request(); +#ifdef CI_ADAPTER +void create_tcp_connection(); +#endif void request_handler(const CAEndpoint_t *object, const CARequestInfo_t *requestInfo); void response_handler(const CAEndpoint_t *object, const CAResponseInfo_t *responseInfo); @@ -102,8 +107,11 @@ static CAToken_t g_last_request_token = NULL; static const char COAP_PREFIX[] = "coap://"; static const char COAPS_PREFIX[] = "coaps://"; +static const char COAP_TCP_PREFIX[] = "coap+tcp://"; + static const uint16_t COAP_PREFIX_LEN = sizeof(COAP_PREFIX) - 1; static const uint16_t COAPS_PREFIX_LEN = sizeof(COAPS_PREFIX) - 1; +static const uint16_t COAP_TCP_PREFIX_LEN = sizeof(COAP_TCP_PREFIX) - 1; static const char SECURE_INFO_DATA[] = "{\"oc\":[{\"href\":\"%s\",\"prop\":{\"rt\":[\"core.led\"]," @@ -341,6 +349,13 @@ void process() get_network_info(); break; +#ifdef CI_ADAPTER + case 'p': // create tcp connection + case 'P': + create_tcp_connection(); + break; +#endif + default: printf("not supported menu!!\n"); break; @@ -434,6 +449,9 @@ void send_request() printf("Enter the URI like below....\n"); printf("coap://10.11.12.13:4545/resource_uri ( for IP )\n"); printf("coap://10:11:12:13:45:45/resource_uri ( for BT )\n"); +#ifdef CI_ADAPTER + printf("coap+tcp://10:11:12:13:45:45/resource_uri ( for CI )\n"); +#endif } else { @@ -754,6 +772,9 @@ void send_notification() printf("Enter the URI like below....\n"); printf("coap://10.11.12.13:4545/resource_uri ( for IP )\n"); printf("coap://10:11:12:13:45:45/resource_uri ( for BT )\n"); +#ifdef CI_ADAPTER + printf("coap+tcp://10:11:12:13:45:45/resource_uri ( for CI )\n"); +#endif printf("uri : "); char uri[MAX_BUF_LEN] = { 0 }; @@ -848,6 +869,9 @@ void select_network() printf("IP : 0\n"); printf("GATT : 1\n"); printf("RFCOMM : 2\n"); +#ifdef CI_ADAPTER + printf("CI : 5\n"); +#endif printf("select : "); char buf[MAX_BUF_LEN] = { 0 }; @@ -858,7 +882,7 @@ void select_network() int number = buf[0] - '0'; - if (number < 0 || number > 3) + if (number < 0 || number > 5) { printf("Invalid network type\n"); return; @@ -884,6 +908,9 @@ void unselect_network() printf("IP : 0\n"); printf("GATT : 1\n"); printf("RFCOMM : 2\n"); +#ifdef CI_ADAPTER + printf("CI : 5\n"); +#endif printf("select : "); char buf[MAX_BUF_LEN] = { 0 }; @@ -894,7 +921,7 @@ void unselect_network() int number = buf[0] - '0'; - if (number < 0 || number > 3) + if (number < 0 || number > 5) { printf("Invalid network type\n"); return; @@ -928,6 +955,9 @@ char get_menu() printf("\th : handle request response\n"); printf("\tz : run static server\n"); printf("\tw : send secure request\n"); +#ifdef CI_ADAPTER + printf("\tp : create tcp connection\n"); +#endif printf("\tq : quit\n"); printf("=============================================\n"); printf("select : "); @@ -1057,12 +1087,14 @@ void request_handler(const CAEndpoint_t *object, const CARequestInfo_t *requestI } } +#ifdef WITH_BWT // if received message is bulk data, create output file if ((requestInfo->info.payload) && (requestInfo->info.payloadSize > BLOCK_SIZE(CA_DEFAULT_BLOCK_SIZE))) { create_file(requestInfo->info.payload, requestInfo->info.payloadSize); } +#endif printf("Send response with URI\n"); send_response(object, &requestInfo->info); @@ -1111,12 +1143,14 @@ void response_handler(const CAEndpoint_t *object, const CAResponseInfo_t *respon } } +#ifdef WITH_BWT // if received message is bulk data, create output file if ((responseInfo->info.payload) && (responseInfo->info.payloadSize > BLOCK_SIZE(CA_DEFAULT_BLOCK_SIZE))) { create_file(responseInfo->info.payload, responseInfo->info.payloadSize); } +#endif } void error_handler(const CAEndpoint_t *rep, const CAErrorInfo_t* errorInfo) @@ -1404,6 +1438,9 @@ CAResult_t get_network_type() printf("IP : 0\n"); printf("GATT : 1\n"); printf("RFCOMM : 2\n"); +#ifdef CI_ADAPTER + printf("CI : 5\n"); +#endif printf("select : "); if (CA_STATUS_OK != get_input_data(buf, MAX_BUF_LEN)) @@ -1413,25 +1450,21 @@ CAResult_t get_network_type() int number = buf[0] - '0'; - number = (number < 0 || number > 3) ? 0 : 1 << number; + number = (number < 0 || number > 5) ? 0 : 1 << number; - if (number == 1) + switch (number) { - g_selected_nw_type = CA_ADAPTER_IP; - return CA_STATUS_OK; - } - if (number == 2) - { - g_selected_nw_type = CA_ADAPTER_GATT_BTLE; - return CA_STATUS_OK; - } - if (number == 3) - { - g_selected_nw_type = CA_ADAPTER_RFCOMM_BTEDR; - return CA_STATUS_OK; + case CA_ADAPTER_IP: + case CA_ADAPTER_GATT_BTLE: + case CA_ADAPTER_RFCOMM_BTEDR: +#ifdef CI_ADAPTER + case CA_ADAPTER_CLOUD_INTERFACE: +#endif + g_selected_nw_type = number; + return CA_STATUS_OK; + default: + return CA_NOT_SUPPORTED; } - - return CA_NOT_SUPPORTED; } CAResult_t get_input_data(char *buf, int32_t length) @@ -1537,6 +1570,14 @@ void parsing_coap_uri(const char* uri, addressSet_t* address, CATransportFlags_t startIndex = COAP_PREFIX_LEN; *flags = CA_IPV4; } +#ifdef CI_ADAPTER + 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_TCP; + } +#endif // #2. copy uri for parse int32_t len = strlen(uri) - startIndex; @@ -1689,3 +1730,32 @@ bool read_file(const char* name, CAPayload_t* bytes, size_t* length) return true; } + +#ifdef CI_ADAPTER +void create_tcp_connection() +{ + printf("Enter the CI Server information....\n"); + printf("IP: "); + char address[MAX_BUF_LEN] = {'\0'}; + if (CA_STATUS_OK != get_input_data(address, MAX_BUF_LEN)) + { + return; + } + printf("Port: "); + char port[MAX_BUF_LEN] = {'\0'}; + if (CA_STATUS_OK != get_input_data(port, MAX_BUF_LEN)) + { + return; + } + + int portNum = atoi(port); + CACIServerInfo_t serverInfo = { .u4tcp.port = portNum }; + strncpy(serverInfo.addr, address, strlen(address)); + + CAResult_t res = CACreateTCPConnection(&serverInfo); + if (CA_STATUS_OK != res) + { + printf("Failed to create TCP Connection"); + } +} +#endif diff --git a/resource/csdk/connectivity/src/SConscript b/resource/csdk/connectivity/src/SConscript index 78255b6..3ee514e 100644 --- a/resource/csdk/connectivity/src/SConscript +++ b/resource/csdk/connectivity/src/SConscript @@ -96,7 +96,7 @@ ca_common_src = [ env.AppendUnique(CA_SRC = ca_common_src) if 'ALL' in ca_transport: - transports = [ 'ip_adapter', 'bt_edr_adapter', 'bt_le_adapter' ] + transports = [ 'ip_adapter', 'bt_edr_adapter', 'bt_le_adapter', 'ci_adapter'] if with_ra: transports.append ('ra_adapter') env.SConscript(dirs = [ @@ -111,6 +111,9 @@ if 'BT' in ca_transport: if 'BLE' in ca_transport: env.SConscript(os.path.join(ca_path, 'bt_le_adapter/SConscript')) +if 'CI' in ca_transport: + env.SConscript(os.path.join(ca_path, 'ci_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']: diff --git a/resource/csdk/connectivity/src/caconnectivitymanager.c b/resource/csdk/connectivity/src/caconnectivitymanager.c index 7f77d6b..976ce99 100644 --- a/resource/csdk/connectivity/src/caconnectivitymanager.c +++ b/resource/csdk/connectivity/src/caconnectivitymanager.c @@ -34,6 +34,10 @@ #include "caadapternetdtls.h" #endif +#ifdef CI_ADAPTER +#include "caciadapter.h" +#endif + CAGlobals_t caglobals = { 0 }; #define TAG "CA_CONN_MGR" @@ -252,10 +256,20 @@ CAResult_t CASelectNetwork(CATransportAdapter_t interestedNetwork) else if (interestedNetwork & CA_ADAPTER_REMOTE_ACCESS) { res = CAAddNetworkType(CA_ADAPTER_REMOTE_ACCESS); - OIC_LOG_V(ERROR, TAG, "CAAddNetworkType(CA_ADAPTER_REMOTE_ACCESS) function returns error : %d", - res); + OIC_LOG_V(ERROR, TAG, + "CAAddNetworkType(CA_ADAPTER_REMOTE_ACCESS) function returns error : %d", res); } #endif + + #ifdef CI_ADAPTER + else if (interestedNetwork & CA_ADAPTER_CLOUD_INTERFACE) + { + res = CAAddNetworkType(CA_ADAPTER_CLOUD_INTERFACE); + OIC_LOG_V(ERROR, TAG, + "CAAddNetworkType(CA_ADAPTER_CLOUD_INTERFACE) function returns error : %d", res); + } + #endif + else { res = CA_NOT_SUPPORTED; @@ -297,6 +311,16 @@ CAResult_t CAUnSelectNetwork(CATransportAdapter_t nonInterestedNetwork) res); } #endif + + #ifdef CI_ADAPTER + else if (nonInterestedNetwork & CA_ADAPTER_CLOUD_INTERFACE) + { + res = CARemoveNetworkType(CA_ADAPTER_CLOUD_INTERFACE); + OIC_LOG_V(ERROR, TAG, "CARemoveNetworkType(CA_ADAPTER_CLOUD_INTERFACE) function returns error : %d", + res); + } + #endif + else { res = CA_STATUS_FAILED; @@ -317,6 +341,32 @@ CAResult_t CAHandleRequestResponse() return CA_STATUS_OK; } +#ifdef CI_ADAPTER +CAResult_t CACreateTCPConnection(const CACIServerInfo_t *ciServerInfo) +{ + if (!g_isInitialized) + { + OIC_LOG(ERROR, TAG, "not initialized"); + return CA_STATUS_NOT_INITIALIZED; + } + + CAResult_t res = CACreateCIClient(ciServerInfo); + return res; +} + +CAResult_t CADestroyTCPConnection(const CACIServerInfo_t *ciServerInfo) +{ + if (!g_isInitialized) + { + OIC_LOG(ERROR, TAG, "not initialized"); + return CA_STATUS_NOT_INITIALIZED; + } + + CAResult_t res = CADestroyCIClient(ciServerInfo); + return res; +} +#endif + #ifdef __WITH_DTLS__ CAResult_t CASelectCipherSuite(const uint16_t cipher) diff --git a/resource/csdk/connectivity/src/cainterfacecontroller.c b/resource/csdk/connectivity/src/cainterfacecontroller.c index 9b1f8d4..605b85f 100644 --- a/resource/csdk/connectivity/src/cainterfacecontroller.c +++ b/resource/csdk/connectivity/src/cainterfacecontroller.c @@ -39,16 +39,18 @@ #include "caraadapter.h" #endif -#define TAG "CA_INTRFC_CNTRLR" -#ifdef RA_ADAPTER -#include "caraadapter.h" +#ifdef CI_ADAPTER +#include "caciadapter.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 CI_ADAPTER +#define CA_TRANSPORT_TYPE_NUM 6 +#elif RA_ADAPTER #define CA_TRANSPORT_TYPE_NUM 4 #else #define CA_TRANSPORT_TYPE_NUM 3 @@ -78,6 +80,11 @@ static int CAGetAdapterIndex(CATransportAdapter_t cType) return 3; #endif + #ifdef CI_ADAPTER + case CA_ADAPTER_CLOUD_INTERFACE: + return 5; + #endif + default: break; } @@ -193,7 +200,10 @@ void CAInitializeAdapters(ca_thread_pool_t handle) handle); #endif /* RA_ADAPTER */ - +#ifdef CI_ADAPTER + CAInitializeCI(CARegisterCallback, CAReceivedPacketCallback, CANetworkChangedCallback, + CAAdapterErrorHandleCallback, handle); +#endif /* CI_ADAPTER */ } void CASetPacketReceivedCallback(CANetworkPacketReceivedCallback callback) diff --git a/resource/csdk/connectivity/src/canetworkconfigurator.c b/resource/csdk/connectivity/src/canetworkconfigurator.c index d36d378..cb50fcd 100644 --- a/resource/csdk/connectivity/src/canetworkconfigurator.c +++ b/resource/csdk/connectivity/src/canetworkconfigurator.c @@ -36,6 +36,10 @@ static uint32_t NETWORK_GATT = CA_ADAPTER_GATT_BTLE; static uint32_t NETWORK_RA = CA_ADAPTER_REMOTE_ACCESS; #endif +#ifdef CI_ADAPTER +static uint32_t NETWORK_CI = CA_ADAPTER_CLOUD_INTERFACE; +#endif + CAResult_t CAAddNetworkType(CATransportAdapter_t transportType) { OIC_LOG(DEBUG, TAG, "IN"); @@ -107,6 +111,18 @@ CAResult_t CAAddNetworkType(CATransportAdapter_t transportType) break; #endif /* RA_ADAPTER */ +#ifdef CI_ADAPTER + case CA_ADAPTER_CLOUD_INTERFACE: + + OIC_LOG(DEBUG, TAG, "Add network type(CI)"); + if (u_arraylist_contains(g_selectedNetworkList, &NETWORK_CI)) + { + goto exit; + } + res = u_arraylist_add(g_selectedNetworkList, &NETWORK_CI); + break; +#endif /* CI_ADAPTER */ + default: break; } @@ -190,6 +206,13 @@ CAResult_t CARemoveNetworkType(CATransportAdapter_t transportType) break; #endif /* RA_ADAPTER */ +#ifdef CI_ADAPTER + case CA_ADAPTER_CLOUD_INTERFACE: + OIC_LOG(DEBUG, TAG, "Remove network type(RA)"); + u_arraylist_remove(g_selectedNetworkList, index); + break; +#endif /* CI_ADAPTER */ + default: break; } diff --git a/resource/csdk/connectivity/src/ci_adapter/SConscript b/resource/csdk/connectivity/src/ci_adapter/SConscript new file mode 100644 index 0000000..3e55128 --- /dev/null +++ b/resource/csdk/connectivity/src/ci_adapter/SConscript @@ -0,0 +1,47 @@ +####################################################### +# Build CI adapter +####################################################### + +Import('env') +import os.path + +print "Reading IP adapter script" + +target_os = env.get('TARGET_OS') +inc_files = env.get('CPPPATH') +secured = env.get('SECURED') +src_dir = './ci_adapter/' + + +# Source files to build common for all platforms +common_files = None +if target_os == 'linux': + common_files = [ + os.path.join(src_dir, 'caciadapter.c'), + os.path.join(src_dir, 'caciserver.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) diff --git a/resource/csdk/connectivity/src/ci_adapter/caciadapter.c b/resource/csdk/connectivity/src/ci_adapter/caciadapter.c new file mode 100644 index 0000000..3db16c6 --- /dev/null +++ b/resource/csdk/connectivity/src/ci_adapter/caciadapter.c @@ -0,0 +1,468 @@ +/* **************************************************************** + * + * 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 +#include +#include +#include + +#include "caciadapter.h" +#include "caciinterface.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 "CI_ADAP" + +/** + * Holds internal thread CI data information. + */ +typedef struct +{ + CAEndpoint_t *remoteEndpoint; + void *data; + uint32_t dataLen; + bool isMulticast; +} CACIData; + +/** + * 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 CACIPacketReceivedCB(const CAEndpoint_t *endpoint, + const void *data, uint32_t dataLength); + +static CAResult_t CACIInitializeQueueHandles(); + +static void CACIDeinitializeQueueHandles(); + +static void CACISendDataThread(void *threadData); + +static CACIData *CACreateCIData(const CAEndpoint_t *remoteEndpoint, + const void *data, uint32_t dataLength, + bool isMulticast); +void CAFreeCIData(CACIData *ipData); + +static void CADataDestroyer(void *data, uint32_t size); + +CAResult_t CACIInitializeQueueHandles() +{ + 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.ci.threadpool, + CACISendDataThread, 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 CACIDeinitializeQueueHandles() +{ + OIC_LOG(DEBUG, TAG, "IN"); + + CAQueueingThreadDestroy(g_sendQueueHandle); + OICFree(g_sendQueueHandle); + g_sendQueueHandle = NULL; + + OIC_LOG(DEBUG, TAG, "OUT"); +} + +void CACIConnectionStateCB(const char *ipAddress, CANetworkStatus_t status) +{ + (void)ipAddress; + (void)status; + OIC_LOG(DEBUG, TAG, "IN"); +} + +void CACIPacketReceivedCB(const CAEndpoint_t *endpoint, const void *data, + uint32_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 CACIErrorHandler (const CAEndpoint_t *endpoint, const void *data, + uint32_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"); + + void *buf = (void*)OICMalloc(sizeof(char) * dataLength); + if (!buf) + { + OIC_LOG(ERROR, TAG, "Memory Allocation failed!"); + return; + } + memcpy(buf, data, dataLength); + if (g_errorCallback) + { + g_errorCallback(endpoint, buf, dataLength, result); + } + else + { + OICFree(buf); + } + + OIC_LOG(DEBUG, TAG, "OUT"); +} + +static void CAInitializeCIGlobals() +{ + caglobals.ci.selectTimeout = 5000; + caglobals.ci.svrlist = NULL; + + CATransportFlags_t flags = 0; + if (caglobals.client) + { + flags |= caglobals.clientFlags; + } + + caglobals.ci.ipv4tcpenabled = flags & CA_IPV4_TCP; +} + +CAResult_t CAInitializeCI(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; + + CAInitializeCIGlobals(); + caglobals.ci.threadpool = handle; + + CACISetPacketReceiveCallback(CACIPacketReceivedCB); + CACISetErrorHandler(CACIErrorHandler); + + CAConnectivityHandler_t ciHandler; + ciHandler.startAdapter = CAStartCI; + ciHandler.startListenServer = CAStartCIListeningServer; + ciHandler.startDiscoveryServer = CAStartCIDiscoveryServer; + ciHandler.sendData = CASendCIUnicastData; + ciHandler.sendDataToAll = CASendCIMulticastData; + ciHandler.GetnetInfo = CAGetCIInterfaceInformation; + ciHandler.readData = CAReadCIData; + ciHandler.stopAdapter = CAStopCI; + ciHandler.terminate = CATerminateCI; + registerCallback(ciHandler, CA_ADAPTER_CLOUD_INTERFACE); + + OIC_LOG(INFO, TAG, "OUT IntializeCI is Success"); + return CA_STATUS_OK; +} + +CAResult_t CAStartCI() +{ + OIC_LOG(DEBUG, TAG, "IN"); + + if (CA_STATUS_OK != CACIInitializeQueueHandles()) + { + OIC_LOG(ERROR, TAG, "Failed to Initialize Queue Handle"); + CATerminateCI(); + 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 = CACIStartServer((const ca_thread_pool_t)caglobals.ci.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 CAStartCIListeningServer() +{ + OIC_LOG(DEBUG, TAG, "IN"); + + OIC_LOG(DEBUG, TAG, "OUT"); + return CA_STATUS_OK; +} + +CAResult_t CAStartCIDiscoveryServer() +{ + OIC_LOG(DEBUG, TAG, "IN"); + + OIC_LOG(DEBUG, TAG, "OUT"); + return CA_STATUS_OK; +} + +static int32_t CAQueueCIData(bool isMulticast, const CAEndpoint_t *endpoint, + const void *data, uint32_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 CIData to add to queue + CACIData *ciData = CACreateCIData(endpoint, data, dataLength, isMulticast); + if (!ciData) + { + OIC_LOG(ERROR, TAG, "Failed to create ipData!"); + return -1; + } + // Add message to send queue + CAQueueingThreadAddData(g_sendQueueHandle, ciData, sizeof(CACIData)); + + OIC_LOG(DEBUG, TAG, "OUT"); + return dataLength; +} + +int32_t CASendCIUnicastData(const CAEndpoint_t *endpoint, + const void *data, uint32_t dataLength) +{ + OIC_LOG(DEBUG, TAG, "IN"); + return CAQueueCIData(false, endpoint, data, dataLength); +} + +int32_t CASendCIMulticastData(const CAEndpoint_t *endpoint, const void *data, uint32_t dataLength) +{ + OIC_LOG(DEBUG, TAG, "IN"); + return CAQueueCIData(true, endpoint, data, dataLength); +} + +CAResult_t CAReadCIData() +{ + OIC_LOG(DEBUG, TAG, "IN"); + OIC_LOG(DEBUG, TAG, "OUT"); + return CA_STATUS_OK; +} + +CAResult_t CAStopCI() +{ + OIC_LOG(DEBUG, TAG, "IN"); + + if (g_sendQueueHandle && g_sendQueueHandle->threadMutex) + { + CAQueueingThreadStop(g_sendQueueHandle); + } + + CACIDeinitializeQueueHandles(); + + CACIStopServer(); + + OIC_LOG(DEBUG, TAG, "OUT"); + return CA_STATUS_OK; +} + +void CATerminateCI() +{ + OIC_LOG(DEBUG, TAG, "IN"); + + CACISetPacketReceiveCallback(NULL); + + CACIDeinitializeQueueHandles(); + + OIC_LOG(DEBUG, TAG, "OUT"); +} + +void CACISendDataThread(void *threadData) +{ + OIC_LOG(DEBUG, TAG, "IN"); + + CACIData *ciData = (CACIData *) threadData; + if (!ciData) + { + OIC_LOG(DEBUG, TAG, "Invalid CI data!"); + return; + } + + if (ciData->isMulticast) + { + return; + } + else + { + CACISendData(ciData->remoteEndpoint, ciData->data, ciData->dataLen, false); + } + + OIC_LOG(DEBUG, TAG, "OUT"); +} + +CACIData *CACreateCIData(const CAEndpoint_t *remoteEndpoint, const void *data, + uint32_t dataLength, bool isMulticast) +{ + VERIFY_NON_NULL_RET(data, TAG, "CIData is NULL", NULL); + + CACIData *ciData = (CACIData *) OICMalloc(sizeof(CACIData)); + if (!ciData) + { + OIC_LOG(ERROR, TAG, "Memory allocation failed!"); + return NULL; + } + + ciData->remoteEndpoint = CACloneEndpoint(remoteEndpoint); + ciData->data = (void *) OICMalloc(dataLength); + if (!ciData->data) + { + OIC_LOG(ERROR, TAG, "Memory allocation failed!"); + CAFreeCIData(ciData); + return NULL; + } + + memcpy(ciData->data, data, dataLength); + ciData->dataLen = dataLength; + + ciData->isMulticast = isMulticast; + + return ciData; +} + +void CAFreeCIData(CACIData *ciData) +{ + VERIFY_NON_NULL_VOID(ciData, TAG, "ciData is NULL"); + + CAFreeEndpoint(ciData->remoteEndpoint); + OICFree(ciData->data); + OICFree(ciData); +} + +void CADataDestroyer(void *data, uint32_t size) +{ + if (size < sizeof(CACIData)) + { + OIC_LOG_V(ERROR, TAG, "Destroy data too small %p %d", data, size); + } + CACIData *ciData = (CACIData *) data; + + CAFreeCIData(ciData); +} + +CAResult_t CACreateCIClient(const CACIServerInfo_t *ciServerInfo) +{ + VERIFY_NON_NULL(ciServerInfo, TAG, "CI server info is NULL"); + + // #1. create CI server object + CACIServerInfo_t *svritem = (CACIServerInfo_t *) OICMalloc(sizeof (CACIServerInfo_t)); + if (!svritem) + { + OIC_LOG(ERROR, TAG, "Out of memory"); + return CA_MEMORY_ALLOC_FAILED; + } + memcpy(svritem, ciServerInfo, sizeof (CACIServerInfo_t)); + + // #2. create socket and connect to CI server + CAResult_t res = CAConnectToCIServer(svritem); + if (CA_STATUS_OK != res) + { + OIC_LOG(ERROR, TAG, "Failed to start CI Client"); + OICFree(svritem); + return res; + } + + return CA_STATUS_OK; +} + +CAResult_t CADestroyCIClient(const CACIServerInfo_t *ciServerInfo) +{ + VERIFY_NON_NULL(ciServerInfo, TAG, "CI server info is NULL"); + + CAResult_t res = CADisconnectFromCIServer(ciServerInfo); + if (CA_STATUS_OK != res) + { + OIC_LOG(ERROR, TAG, "Failed to stop CI Client"); + return res; + } + + return CA_STATUS_OK; +} diff --git a/resource/csdk/connectivity/src/ci_adapter/caciserver.c b/resource/csdk/connectivity/src/ci_adapter/caciserver.c new file mode 100644 index 0000000..515120e --- /dev/null +++ b/resource/csdk/connectivity/src/ci_adapter/caciserver.c @@ -0,0 +1,564 @@ +/*****************************************************************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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "caciinterface.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 "CI_SERVER" + +/** + * Server port number for local test. + */ +#define SERVER_PORT 8000 + +/** + * Mutex to synchronize device object list. + */ +static ca_mutex g_mutexObjectList = NULL; + +/** + * Maintains the callback to be notified when data received from remote + * Bluetooth device. + */ +static CACIPacketReceivedCallback g_packetReceivedCallback; + +/** + * Error callback to update error in CI. + */ +static CACIErrorHandleCallback g_ciErrorHandler = NULL; + +static CAResult_t CAReceiveMessage(); + +/** + * Destroy Mutex. + */ +static void CACIDestroyMutex() +{ + if (g_mutexObjectList) + { + ca_mutex_free(g_mutexObjectList); + g_mutexObjectList = NULL; + } +} + +/* + * Create Mutex. + */ +static CAResult_t CACICreateMutex() +{ + g_mutexObjectList = ca_mutex_new(); + if (!g_mutexObjectList) + { + OIC_LOG(ERROR, TAG, "Failed to created mutex!"); + + CACIDestroyMutex(); + return CA_STATUS_FAILED; + } + + return CA_STATUS_OK; +} + +static void CACIDisconnectAll() +{ + OIC_LOG(DEBUG, TAG, "IN"); + + ca_mutex_lock(g_mutexObjectList); + uint32_t length = u_arraylist_length(caglobals.ci.svrlist); + + CACIServerInfo_t *svritem = NULL; + for (size_t i = 0; i < length; i++) + { + svritem = (CACIServerInfo_t *) u_arraylist_get(caglobals.ci.svrlist, i); + if (svritem && svritem->u4tcp.fd >= 0) + { + close(svritem->u4tcp.fd); + } + } + u_arraylist_destroy(caglobals.ci.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.ci.terminate) + { + CAReceiveMessage(); + } + + OIC_LOG(DEBUG, TAG, "OUT - CAReceiveHandler"); +} + +static CAResult_t CAReceiveMessage() +{ + uint32_t length = u_arraylist_length(caglobals.ci.svrlist); + + CACIServerInfo_t *svritem = NULL; + for (size_t i = 0; i < length; i++) + { + svritem = (CACIServerInfo_t *) u_arraylist_get(caglobals.ci.svrlist, i); + + if (svritem->u4tcp.fd < 0) + { + continue; + } + + char recvBuffer[COAP_TCP_MAX_PDU_SIZE] = { 0 }; + ssize_t recvLen = recv(svritem->u4tcp.fd, recvBuffer, sizeof (recvBuffer), 0); + if (recvLen <= 0) + { + if(EAGAIN == errno) + { + continue; + } + OIC_LOG_V(ERROR, TAG, "Recvfrom failed %s", strerror(errno)); + close(svritem->u4tcp.fd); + u_arraylist_remove(caglobals.ci.svrlist, i); + } + else + { + CAEndpoint_t ep = { .adapter = CA_ADAPTER_CLOUD_INTERFACE, + .flags = CA_IPV4_TCP, + .port = svritem->u4tcp.port }; + strncpy(ep.addr, svritem->addr, MAX_ADDR_STR_SIZE_CA); + + if (g_packetReceivedCallback) + { + g_packetReceivedCallback(&ep, recvBuffer, recvLen); + } + } + } + return CA_STATUS_OK; +} + +static int CACICreateTCPSocket(int family, CACIServerInfo_t *ciServerInfo) +{ + // 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 + unsigned long nonblock = 1; + if (ioctl(fd, FIONBIO, &nonblock)) + { + OIC_LOG(ERROR, TAG, "set non-blocking socket error!"); + } + + struct sockaddr_in sa = { .sin_family = family }; + inet_pton(family, ciServerInfo->addr, &sa.sin_addr.s_addr); + sa.sin_port = htons(ciServerInfo->u4tcp.port); + + // connect to CI server + socklen_t socklen = sizeof(sa); + if (connect(fd, (struct sockaddr *)&sa, socklen) != 0) + { + OIC_LOG(ERROR, TAG, "first connect, error"); + } + + // update the max file descriptor + if (fd > caglobals.ci.maxfd) + { + caglobals.ci.maxfd = fd; + } + + struct timeval timeout = { .tv_sec = caglobals.ci.selectTimeout / 1000, + .tv_usec = (caglobals.ci.selectTimeout % 1000) * 1000}; + + fd_set writeFd; + FD_ZERO(&writeFd); + FD_SET(caglobals.ci.maxfd, &writeFd); + + int error = 0; + int state = select(caglobals.ci.maxfd + 1, NULL, &writeFd, NULL, &timeout); + switch (state) + { + case -1: + OIC_LOG(ERROR, TAG, "select() error"); + goto exit; + break; + case 0: + OIC_LOG(ERROR, TAG, "time out error"); + goto exit; + break; + default: + if (FD_ISSET(fd, &writeFd)) + { + socklen_t len = sizeof(error); + if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len)) + { + OIC_LOG(ERROR, TAG, "getsockopt error"); + } + } + else + { + OIC_LOG(ERROR, TAG, "select error: sockfd not set"); + } + OIC_LOG(ERROR, TAG, "connect socket success"); + break; + } + + // set blocking socket + nonblock = 0; + if (ioctl(fd, FIONBIO, &nonblock)) + { + OIC_LOG(ERROR, TAG, "set blocking socket error!"); + } + + return fd; + +exit: + if (fd >= 0) + { + close(fd); + } + return -1; +} + +#define CHECKFD(FD) \ + if (FD > caglobals.ci.maxfd) \ + caglobals.ci.maxfd = FD; +#define NEWTCPSOCKET(FAMILY, NAME, SERVER) \ + SERVER->NAME.fd = CACICreateTCPSocket(FAMILY, SERVER); + +static void CACIConvertAddrToString(struct sockaddr_in *addr, char *addr_str) +{ + inet_ntop(AF_INET, &(addr->sin_addr), addr_str, INET_ADDRSTRLEN); +} + +static void CAAcceptHandler(void *data) +{ + (void)data; + OIC_LOG(DEBUG, TAG, "IN - CAAcceptHandler"); + + int reuse = 1; + struct sockaddr_in server; + + server.sin_addr.s_addr = INADDR_ANY; + server.sin_family = AF_INET; + server.sin_port = htons(SERVER_PORT); + + int svrsockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (svrsockfd < 0) + { + OIC_LOG(ERROR, TAG, "Failed to create socket"); + } + + if (setsockopt(svrsockfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0) + { + OIC_LOG(ERROR, TAG, "setsockopt SO_REUSEADDR"); + } + + int serverlen = sizeof(server); + if (bind(svrsockfd, (struct sockaddr *)&server, serverlen) < 0) + { + OIC_LOG(ERROR, TAG, "bind() error"); + } + + if (listen(svrsockfd, 3) != 0) + { + OIC_LOG(ERROR, TAG, "listen() error"); + } + + struct sockaddr clientaddr; + socklen_t clientlen = sizeof(clientaddr); + + while (!caglobals.ci.terminate) + { + int sockfd = accept(svrsockfd, (struct sockaddr *)&clientaddr, &clientlen); + if (sockfd != -1) + { + CACIServerInfo_t *svritem = (CACIServerInfo_t *) OICMalloc(sizeof (CACIServerInfo_t)); + if (!svritem) + { + OIC_LOG(ERROR, TAG, "Out of memory"); + return; + } + svritem->u4tcp.fd = sockfd; + svritem->u4tcp.port = SERVER_PORT; + CACIConvertAddrToString((struct sockaddr_in *)&clientaddr, (char *) &svritem->addr); + + ca_mutex_lock(g_mutexObjectList); + bool res = u_arraylist_add(caglobals.ci.svrlist, svritem); + if (!res) + { + OIC_LOG(ERROR, TAG, "u_arraylist_add failed."); + OICFree(svritem); + ca_mutex_unlock(g_mutexObjectList); + return; + } + ca_mutex_unlock(g_mutexObjectList); + } + } + + OIC_LOG(DEBUG, TAG, "OUT - CAAcceptHandler"); +} + +CAResult_t CACIStartServer(const ca_thread_pool_t threadPool) +{ + if (caglobals.ci.started) + { + return CA_STATUS_OK; + } + + if (!caglobals.ci.ipv4tcpenabled) + { + caglobals.ci.ipv4tcpenabled = true; + } + + CACICreateMutex(); + + ca_mutex_lock(g_mutexObjectList); + if (!caglobals.ci.svrlist) + { + caglobals.ci.svrlist = u_arraylist_create(); + } + ca_mutex_unlock(g_mutexObjectList); + + caglobals.ci.terminate = false; + + CAResult_t 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.ci.started = true; + + return CA_STATUS_OK; +} + +void CACIStopServer() +{ + OIC_LOG(DEBUG, TAG, "IN"); + + caglobals.ci.terminate = true; + + CACIDisconnectAll(); + + CACIDestroyMutex(); + + OIC_LOG(DEBUG, TAG, "OUT"); +} + +void CACISetPacketReceiveCallback(CACIPacketReceivedCallback callback) +{ + OIC_LOG(DEBUG, TAG, "IN"); + + g_packetReceivedCallback = callback; + + OIC_LOG(DEBUG, TAG, "OUT"); +} + +static void sendData(const CAEndpoint_t *endpoint, + const void *data, uint32_t dlen, + const char *cast, const char *fam) +{ + uint32_t index = 0; + CACIServerInfo_t *svritem = CAGetCIServerInfoFromList(endpoint->addr, endpoint->port, + &index); + if (!svritem) + { + OIC_LOG(ERROR, TAG, "Failed to get TCP Server Info"); + return; + } + + if (svritem->u4tcp.fd < 0) + { + return; + } + + struct timeval timeout = { .tv_sec = caglobals.ci.selectTimeout / 1000, + .tv_usec = (caglobals.ci.selectTimeout % 1000) * 1000}; + + if (setsockopt(svritem->u4tcp.fd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)) == -1) + { + OIC_LOG(ERROR, TAG, "Failed to set socket option"); + return; + } + + ssize_t len = send(svritem->u4tcp.fd, data, dlen, 0); + if (-1 == len) + { + OIC_LOG_V(ERROR, TAG, "%s %s sendTo failed: %s", cast, fam, strerror(errno)); + g_ciErrorHandler(endpoint, data, dlen, CA_SEND_FAILED); + } + else + { + OIC_LOG_V(INFO, TAG, "%s %s sendTo is successful: %d bytes", cast, fam, len); + } +} + +void CACISendData(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.ci.ipv4tcpenabled && (endpoint->flags & CA_IPV4_TCP)) + { + sendData(endpoint, data, datalen, "unicast", "ipv4tcp"); + } + } +} + +CAResult_t CAGetCIInterfaceInformation(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; +} + +CAResult_t CAConnectToCIServer(CACIServerInfo_t *ciServerInfo) +{ + VERIFY_NON_NULL(ciServerInfo, TAG, "CI server info is NULL"); + + // create the socket and connect to CI server + if (caglobals.ci.ipv4tcpenabled) + { + NEWTCPSOCKET(AF_INET, u4tcp, ciServerInfo); + if (-1 == ciServerInfo->u4tcp.fd) + { + return CA_STATUS_FAILED; + } + } + + // add TCP connection info to list + ca_mutex_lock(g_mutexObjectList); + if (!caglobals.ci.svrlist) + { + caglobals.ci.svrlist = u_arraylist_create(); + } + + bool res = u_arraylist_add(caglobals.ci.svrlist, ciServerInfo); + if (!res) + { + OIC_LOG(ERROR, TAG, "u_arraylist_add failed."); + ca_mutex_unlock(g_mutexObjectList); + return CA_STATUS_FAILED; + } + ca_mutex_unlock(g_mutexObjectList); + + return CA_STATUS_OK; +} + +CAResult_t CADisconnectFromCIServer(const CACIServerInfo_t *ciServerInfo) +{ + VERIFY_NON_NULL(ciServerInfo, TAG, "CI server info is NULL"); + + // #1. get server info + uint32_t index = 0; + ca_mutex_lock(g_mutexObjectList); + CACIServerInfo_t *svritem = CAGetCIServerInfoFromList(ciServerInfo->addr, + ciServerInfo->u4tcp.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 CI connection info in list + close(svritem->u4tcp.fd); + u_arraylist_remove(caglobals.ci.svrlist, index); + ca_mutex_unlock(g_mutexObjectList); + + return CA_STATUS_OK; +} + +CACIServerInfo_t *CAGetCIServerInfoFromList(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.ci.svrlist); + + CACIServerInfo_t *svritem = NULL; + for (size_t i = 0; i < length; i++) + { + svritem = (CACIServerInfo_t *) u_arraylist_get(caglobals.ci.svrlist, i); + + if (svritem->addr) + { + if (!strncmp(svritem->addr, addr, MAX_ADDR_STR_SIZE_CA) + && (svritem->u4tcp.port == port)) + { + *index = i; + return svritem; + } + } + } + + return NULL; +} + +void CACISetErrorHandler(CACIErrorHandleCallback errorHandleCallback) +{ + g_ciErrorHandler = errorHandleCallback; +} diff --git a/resource/csdk/connectivity/test/ca_api_unittest.cpp b/resource/csdk/connectivity/test/ca_api_unittest.cpp index 543c68f..3db40ed 100644 --- a/resource/csdk/connectivity/test/ca_api_unittest.cpp +++ b/resource/csdk/connectivity/test/ca_api_unittest.cpp @@ -464,14 +464,14 @@ CAResult_t checkSelectNetwork() TEST_F(CATests, SelectNetworkTestBad) { //Select disable network - EXPECT_EQ(CA_NOT_SUPPORTED, CASelectNetwork((CATransportAdapter_t)1000)); + EXPECT_EQ(CA_NOT_SUPPORTED, CASelectNetwork((CATransportAdapter_t)10000)); } // 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)10000)); } // CAHandlerRequestResponse TC -- 2.7.4