Toyomasa Watarai
/
Mbed-example-WS-W27
simple-mbed-cloud-client/mbed-cloud-client/source/ConnectorClient.cpp
- Committer:
- MACRUM
- Date:
- 2018-06-30
- Revision:
- 0:119624335925
File content as of revision 0:119624335925:
// ---------------------------------------------------------------------------- // Copyright 2016-2017 ARM Ltd. // // SPDX-License-Identifier: Apache-2.0 // // 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 <string> #include <assert.h> #include <stdio.h> #include "include/ConnectorClient.h" #include "include/CloudClientStorage.h" #include "include/CertificateParser.h" #include "MbedCloudClient.h" #include "mbed-client/m2minterfacefactory.h" #include "mbed-client/m2mdevice.h" #include "mbed-trace/mbed_trace.h" #include "factory_configurator_client.h" #define TRACE_GROUP "mClt" #define INTERNAL_ENDPOINT_PARAM "&iep=" #define DEFAULT_ENDPOINT "endpoint" #define INTERFACE_ERROR "Client interface is not created. Restart" #define CREDENTIAL_ERROR "Failed to read credentials from storage" #define DEVICE_NOT_PROVISIONED "Device not provisioned" #define ERROR_NO_MEMORY "Not enough memory to stroe LWM2M credentials" // XXX: nothing here yet class EventData { }; ConnectorClient::ConnectorClient(ConnectorClientCallback* callback) : _callback(callback), _current_state(State_Bootstrap_Start), _event_generated(false), _state_engine_running(false), _interface(NULL), _security(NULL), _endpoint_info(M2MSecurity::Certificate), _client_objs(NULL), _rebootstrap_timer(*this), _bootstrap_security_instance(1), _lwm2m_security_instance(0) { assert(_callback != NULL); // Create the lwm2m server security object we need always _security = M2MInterfaceFactory::create_security(M2MSecurity::M2MServer); _interface = M2MInterfaceFactory::create_interface(*this, DEFAULT_ENDPOINT, // endpoint name string MBED_CLOUD_CLIENT_ENDPOINT_TYPE, // endpoint type string MBED_CLOUD_CLIENT_LIFETIME, // lifetime MBED_CLOUD_CLIENT_LISTEN_PORT, // listen port _endpoint_info.account_id, // domain string transport_mode(), // binding mode M2MInterface::LwIP_IPv4); // network stack initialize_storage(); } ConnectorClient::~ConnectorClient() { M2MDevice::delete_instance(); M2MSecurity::delete_instance(); delete _interface; } void ConnectorClient::start_bootstrap() { tr_debug("ConnectorClient::start_bootstrap()"); assert(_callback != NULL); // Stop rebootstrap timer if it was running _rebootstrap_timer.stop_timer(); if (create_bootstrap_object()) { _interface->update_endpoint(_endpoint_info.endpoint_name); _interface->update_domain(_endpoint_info.account_id); internal_event(State_Bootstrap_Start); } else { tr_error("ConnectorClient::start_bootstrap() - bootstrap object fail"); } state_engine(); } void ConnectorClient::start_registration(M2MObjectList* client_objs) { tr_debug("ConnectorClient::start_registration()"); assert(_callback != NULL); _client_objs = client_objs; // XXX: actually this call should be external_event() to match the pattern used in other m2m classes create_register_object(); if(_security->get_security_instance_id(M2MSecurity::M2MServer) >= 0) { if(use_bootstrap()) { // Bootstrap registration always uses iep _interface->update_endpoint(_endpoint_info.internal_endpoint_name); } else { // Registration without bootstrap always uses external id _interface->update_endpoint(_endpoint_info.endpoint_name); } _interface->update_domain(_endpoint_info.account_id); internal_event(State_Registration_Start); } else { tr_error("ConnectorClient::state_init(): failed to create objs"); _callback->connector_error(M2MInterface::InvalidParameters, INTERFACE_ERROR); } state_engine(); } M2MInterface * ConnectorClient::m2m_interface() { return _interface; } void ConnectorClient::update_registration() { if(_interface && _security && _security->get_security_instance_id(M2MSecurity::M2MServer) >= 0) { if (_client_objs != NULL) { _interface->update_registration(_security, *_client_objs); } else { _interface->update_registration(_security); } } } // generates an internal event. called from within a state // function to transition to a new state void ConnectorClient::internal_event(StartupSubStateRegistration new_state) { tr_debug("ConnectorClient::internal_event: state: %d -> %d", _current_state, new_state); _event_generated = true; _current_state = new_state; // Avoid recursive chain which eats too much of stack if (!_state_engine_running) { state_engine(); } } // the state engine executes the state machine states void ConnectorClient::state_engine(void) { tr_debug("ConnectorClient::state_engine"); // this simple flagging gets rid of recursive calls to this method _state_engine_running = true; // while events are being generated keep executing states while (_event_generated) { _event_generated = false; // event used up, reset flag state_function(_current_state); } _state_engine_running = false; } void ConnectorClient::state_function(StartupSubStateRegistration current_state) { switch (current_state) { case State_Bootstrap_Start: state_bootstrap_start(); break; case State_Bootstrap_Started: state_bootstrap_started(); break; case State_Bootstrap_Success: state_bootstrap_success(); break; case State_Bootstrap_Failure: state_bootstrap_failure(); break; case State_Registration_Start: state_registration_start(); break; case State_Registration_Started: state_registration_started(); break; case State_Registration_Success: state_registration_success(); break; case State_Registration_Failure: state_registration_failure(); break; case State_Unregistered: state_unregistered(); break; default: break; } } /* * Creates register server object with mbed device server address and other parameters * required for client to connect to mbed device server. */ void ConnectorClient::create_register_object() { tr_debug("ConnectorClient::create_register_object()"); if(_security && _security->get_security_instance_id(M2MSecurity::M2MServer) == -1) { _security->create_object_instance(M2MSecurity::M2MServer); int32_t m2m_id = _security->get_security_instance_id(M2MSecurity::M2MServer); _security->set_resource_value(M2MSecurity::BootstrapServer, M2MSecurity::M2MServer, m2m_id); // Add ResourceID's and values to the security ObjectID/ObjectInstance _security->set_resource_value(M2MSecurity::SecurityMode, _endpoint_info.mode, m2m_id); // Allocate scratch buffer, this will be used to copy parameters from storage to security object const int max_size = 2048; uint8_t *buffer = (uint8_t*)malloc(max_size); size_t real_size = 0; bool success = false; if (buffer != NULL) { success = true; } // Connector CA if (success) { success = false; if (get_config_certificate(g_fcc_lwm2m_server_ca_certificate_name, buffer, max_size, &real_size) == CCS_STATUS_SUCCESS) { tr_info("ConnectorClient::create_register_object - ServerPublicKey %d", (int)real_size); success = true; _security->set_resource_value(M2MSecurity::ServerPublicKey, buffer, (uint32_t)real_size, m2m_id); } else { tr_error("KEY_CONNECTOR_CA cert failed."); } } // Connector device public key if (success) { success = false; if (get_config_certificate(g_fcc_lwm2m_device_certificate_name, buffer, max_size, &real_size) == CCS_STATUS_SUCCESS) { tr_info("ConnectorClient::create_register_object - PublicKey %d", (int)real_size); success = true; _security->set_resource_value(M2MSecurity::PublicKey, buffer, (uint32_t)real_size, m2m_id); } else { tr_error("KEY_CONNECTOR__DEVICE_CERT failed."); } } // Connector device private key if (success) { success = false; if (get_config_private_key(g_fcc_lwm2m_device_private_key_name, buffer, max_size, &real_size) == CCS_STATUS_SUCCESS) { tr_info("ConnectorClient::create_register_object - SecretKey %d", (int)real_size); success = true; _security->set_resource_value(M2MSecurity::Secretkey, buffer, (uint32_t)real_size, m2m_id); } else tr_error("KEY_CONNECTOR_DEVICE_PRIV failed."); } // Connector URL if (success) { success = false; if (get_config_parameter(g_fcc_lwm2m_server_uri_name, buffer, max_size, &real_size) == CCS_STATUS_SUCCESS) { tr_info("ConnectorClient::create_register_object - M2MServerUri %.*s", (int)real_size, buffer); success = true; _security->set_resource_value(M2MSecurity::M2MServerUri, buffer, (uint32_t)real_size, m2m_id); } else tr_error("KEY_CONNECTOR_URL failed."); } // Endpoint if (success) { success = false; if (get_config_parameter(g_fcc_endpoint_parameter_name, buffer, max_size, &real_size) == CCS_STATUS_SUCCESS) { tr_info("ConnectorClient::create_register_object - endpoint name %.*s", (int)real_size, buffer); success = true; _endpoint_info.endpoint_name = String((const char*)buffer, real_size); } else tr_error("KEY_ENDPOINT_NAME failed."); } // Try to get internal endpoint name if (success) { if (get_config_parameter(KEY_INTERNAL_ENDPOINT, buffer, max_size, &real_size) == CCS_STATUS_SUCCESS) { _endpoint_info.internal_endpoint_name = String((const char*)buffer, real_size); tr_info("Using internal endpoint name instead: %s", _endpoint_info.internal_endpoint_name.c_str()); } else { tr_debug("KEY_INTERNAL_ENDPOINT failed."); } } // Account ID, not mandatory if (success) { if (get_config_parameter(KEY_ACCOUNT_ID, buffer, max_size, &real_size) == CCS_STATUS_SUCCESS) { tr_info("ConnectorClient::create_register_object - AccountId %.*s", (int)real_size, buffer); _endpoint_info.account_id = String((const char*)buffer, real_size); } else tr_debug("KEY_ACCOUNT_ID failed."); } free(buffer); if (!success) { tr_error("ConnectorClient::create_register_object - Failed to read credentials"); _callback->connector_error((M2MInterface::Error)MbedCloudClient::ConnectorFailedToReadCredentials,CREDENTIAL_ERROR); // TODO: what to do with the m2mserver security instance } } else { tr_info("ConnectorClient::create_register_object() - Credentials already exists"); } } /* * Creates bootstrap server object with bootstrap server address and other parameters * required for connecting to mbed Cloud bootstrap server. */ bool ConnectorClient::create_bootstrap_object() { tr_debug("ConnectorClient::create_bootstrap_object"); bool success = false; // Check if bootstrap credentials are already stored in KCM if (bootstrap_credentials_stored_in_kcm() && _security) { if (_security->get_security_instance_id(M2MSecurity::Bootstrap) == -1) { _security->create_object_instance(M2MSecurity::Bootstrap); int32_t bs_id = _security->get_security_instance_id(M2MSecurity::Bootstrap); _security->set_resource_value(M2MSecurity::SecurityMode, M2MSecurity::Certificate, bs_id); tr_info("ConnectorClient::create_bootstrap_object - bs_id = %d", bs_id); tr_info("ConnectorClient::create_bootstrap_object - use credentials from storage"); // Allocate scratch buffer, this will be used to copy parameters from storage to security object size_t real_size = 0; const int max_size = 2048; uint8_t *buffer = (uint8_t*)malloc(max_size); if (buffer != NULL) { success = true; } // Read internal endpoint name if it exists, we need to append // it to bootstrap uri if device already bootstrapped uint8_t *iep = NULL; if (success && get_config_parameter_string(KEY_INTERNAL_ENDPOINT, buffer, max_size) == CCS_STATUS_SUCCESS) { iep = (uint8_t*)malloc(strlen((const char*)buffer) + strlen(INTERNAL_ENDPOINT_PARAM) + 1); if (iep != NULL) { strcpy((char*)iep, INTERNAL_ENDPOINT_PARAM); strcat((char*)iep, (const char*)buffer); tr_info("ConnectorClient::create_bootstrap_object - iep: %s", buffer); } //TODO: Should handle error if iep exists but allocation fails? } // Bootstrap URI if (success) { success = false; if (get_config_parameter_string(g_fcc_bootstrap_server_uri_name, buffer, max_size) == CCS_STATUS_SUCCESS) { success = true; real_size = strlen((const char*)buffer); // Append iep if we 1. have it 2. it doesn't already exist in uri 3. it fits if (iep && strstr((const char*)buffer, (const char*)iep) == NULL && (real_size + strlen((const char*)iep) + 1) <= max_size) { strcat((char*)buffer, (const char*)iep); real_size += strlen((const char*)iep) + 1; } tr_info("ConnectorClient::create_bootstrap_object - M2MServerUri %.*s", (int)real_size, buffer); _security->set_resource_value(M2MSecurity::M2MServerUri, buffer, real_size, bs_id); } } free(iep); // Bootstrap server public key (certificate) if (success) { success = false; if (get_config_certificate(g_fcc_bootstrap_server_ca_certificate_name, buffer, max_size, &real_size) == CCS_STATUS_SUCCESS) { success = true; tr_info("ConnectorClient::create_bootstrap_object - ServerPublicKey %d", (int)real_size); _security->set_resource_value(M2MSecurity::ServerPublicKey, buffer, real_size, bs_id); } } // Bootstrap client public key (certificate) if (success) { success = false; if (get_config_certificate(g_fcc_bootstrap_device_certificate_name, buffer, max_size, &real_size) == CCS_STATUS_SUCCESS) { success = true; tr_info("ConnectorClient::create_bootstrap_object - PublicKey %d", (int)real_size); _security->set_resource_value(M2MSecurity::PublicKey, buffer, real_size, bs_id); } } // Bootstrap client private key if (success) { success = false; if (get_config_private_key(g_fcc_bootstrap_device_private_key_name, buffer, max_size, &real_size) == CCS_STATUS_SUCCESS) { success = true; tr_info("ConnectorClient::create_bootstrap_object - Secretkey %d", (int)real_size); _security->set_resource_value(M2MSecurity::Secretkey, buffer, real_size, bs_id); } } // Endpoint if (success) { success = false; if (get_config_parameter(g_fcc_endpoint_parameter_name, buffer, max_size, &real_size) == CCS_STATUS_SUCCESS) { success = true; _endpoint_info.endpoint_name = String((const char*)buffer, real_size); tr_info("ConnectorClient::create_bootstrap_object - Endpoint %s", _endpoint_info.endpoint_name.c_str()); } } // Account ID, not mandatory if (success) { if (get_config_parameter(KEY_ACCOUNT_ID, buffer, max_size, &real_size) == CCS_STATUS_SUCCESS) { _endpoint_info.account_id = String((const char*)buffer, real_size); tr_info("ConnectorClient::create_bootstrap_object - AccountId %s", _endpoint_info.account_id.c_str()); } } free(buffer); if (!success) { tr_error("ConnectorClient::create_bootstrap_object - Failed to read credentials"); _callback->connector_error((M2MInterface::Error)MbedCloudClient::ConnectorFailedToReadCredentials,CREDENTIAL_ERROR); _security->remove_object_instance(bs_id); } } else { success = true; tr_info("ConnectorClient::create_bootstrap_object - bootstrap object already done"); } // Device not provisioned } else { _callback->connector_error((M2MInterface::Error)MbedCloudClient::ConnectorInvalidCredentials, DEVICE_NOT_PROVISIONED); tr_error("ConnectorClient::create_bootstrap_object - device not provisioned!"); } return success; } void ConnectorClient::state_bootstrap_start() { tr_info("ConnectorClient::state_bootstrap_start()"); assert(_interface != NULL); assert(_security != NULL); _interface->bootstrap(_security); internal_event(State_Bootstrap_Started); } void ConnectorClient::state_bootstrap_started() { // this state may be useful only for verifying the callbacks? } void ConnectorClient::state_bootstrap_success() { assert(_callback != NULL); // Parse internal endpoint name from mDS cert _callback->registration_process_result(State_Bootstrap_Success); } void ConnectorClient::state_bootstrap_failure() { assert(_callback != NULL); // maybe some additional canceling and/or leanup is needed here? _callback->registration_process_result(State_Bootstrap_Failure); } void ConnectorClient::state_registration_start() { tr_info("ConnectorClient::state_registration_start()"); assert(_interface != NULL); assert(_security != NULL); _interface->register_object(_security, *_client_objs); internal_event(State_Registration_Started); } void ConnectorClient::state_registration_started() { // this state may be useful only for verifying the callbacks? } void ConnectorClient::state_registration_success() { assert(_callback != NULL); _endpoint_info.internal_endpoint_name = _interface->internal_endpoint_name(); //The endpoint is maximum 32 character long, we put bigger buffer for future extensions size_t real_size = 0; //If this returns success, don't do anything else delete old value and set new one if (size_config_parameter(KEY_INTERNAL_ENDPOINT, &real_size) != CCS_STATUS_SUCCESS) { delete_config_parameter(KEY_INTERNAL_ENDPOINT); set_config_parameter(KEY_INTERNAL_ENDPOINT,(const uint8_t*)_endpoint_info.internal_endpoint_name.c_str(), (size_t)_endpoint_info.internal_endpoint_name.size()); } _callback->registration_process_result(State_Registration_Success); } void ConnectorClient::state_registration_failure() { assert(_callback != NULL); // maybe some additional canceling and/or leanup is needed here? _callback->registration_process_result(State_Registration_Failure); } void ConnectorClient::state_unregistered() { assert(_callback != NULL); _callback->registration_process_result(State_Unregistered); } void ConnectorClient::bootstrap_done(M2MSecurity *security_object) { tr_info("ConnectorClient::bootstrap_done"); ccs_status_e status = CCS_STATUS_ERROR; StartupSubStateRegistration state = State_Bootstrap_Success; if(security_object) { // Update bootstrap credentials (we could skip this if we knew whether they were updated) // This will also update the address in case of first to claim status = set_bootstrap_credentials(security_object); if (status != CCS_STATUS_SUCCESS) { // TODO: what now? tr_error("ConnectorClient::bootstrap_done - couldn't store bootstrap credentials"); } // Clear the first to claim flag if it's active if (is_first_to_claim()) { status = clear_first_to_claim(); if (status != CCS_STATUS_SUCCESS) { // TODO: what now? tr_error("ConnectorClient::bootstrap_done - couldn't clear first to claim flag!"); } } // Bootstrap might delete m2mserver security object instance completely to force bootstrap // with new credentials, in that case delete the stored lwm2m credentials as well and re-bootstrap if (security_object->get_security_instance_id(M2MSecurity::M2MServer) == -1) { tr_info("ConnectorClient::bootstrap_done() - Clearing lwm2m credentials"); // delete the old connector credentials when BS sends re-direction. delete_config_parameter(g_fcc_lwm2m_server_uri_name); delete_config_certificate(g_fcc_lwm2m_server_ca_certificate_name); delete_config_certificate(g_fcc_lwm2m_device_certificate_name); delete_config_private_key(g_fcc_lwm2m_device_private_key_name); // Start re-bootstrap timer tr_info("ConnectorClient::bootstrap_done() - Re-directing bootstrap in 100 milliseconds"); _rebootstrap_timer.start_timer(100, M2MTimerObserver::BootstrapFlowTimer, true); return; } // Bootstrap wrote M2MServer credentials, store them and also update first to claim status if it's configured else { tr_info("ConnectorClient::bootstrap_done() - Storing lwm2m credentials"); status = set_connector_credentials(security_object); } } if (status != CCS_STATUS_SUCCESS) { internal_event(State_Bootstrap_Failure); //Failed to store credentials, bootstrap failed _callback->connector_error(M2MInterface::MemoryFail, ERROR_NO_MEMORY); // Translated to error code ConnectMemoryConnectFail return; } else { tr_error("ConnectorClient::bootstrap_done - set_credentials status %d", status); } internal_event(state); } void ConnectorClient::object_registered(M2MSecurity *security_object, const M2MServer &server_object) { internal_event(State_Registration_Success); } void ConnectorClient::object_unregistered(M2MSecurity *server_object) { internal_event(State_Unregistered); } void ConnectorClient::registration_updated(M2MSecurity *security_object, const M2MServer & server_object) { _callback->registration_process_result(State_Registration_Updated); } void ConnectorClient::error(M2MInterface::Error error) { tr_error("ConnectorClient::error() - error: %d", error); assert(_callback != NULL); if (_current_state >= State_Registration_Start && use_bootstrap() && (error == M2MInterface::SecureConnectionFailed || error == M2MInterface::InvalidParameters)) { tr_info("ConnectorClient::error() - Error during lwm2m registration"); tr_info("ConnectorClient::error() - Clearing lwm2m credentials"); // delete the old connector credentials when DTLS handshake fails or // server rejects the registration. delete_config_parameter(g_fcc_lwm2m_server_uri_name); delete_config_certificate(g_fcc_lwm2m_server_ca_certificate_name); delete_config_certificate(g_fcc_lwm2m_device_certificate_name); delete_config_private_key(g_fcc_lwm2m_device_private_key_name); // Delete the lwm2m security instance int32_t id = _security->get_security_instance_id(M2MSecurity::M2MServer); if (id >= 0) { _security->remove_object_instance(id); } // Delete bootstrap security instance id = _security->get_security_instance_id(M2MSecurity::Bootstrap); if (id >= 0) { _security->remove_object_instance(id); } // Start re-bootstrap timer tr_info("ConnectorClient::error() - Re-bootstrapping in 100 milliseconds"); _rebootstrap_timer.start_timer(100, M2MTimerObserver::BootstrapFlowTimer, true); } else { _callback->connector_error(error, _interface->error_description()); } } void ConnectorClient::value_updated(M2MBase *base, M2MBase::BaseType type) { assert(_callback != NULL); _callback->value_updated(base, type); } bool ConnectorClient::connector_credentials_available() { tr_debug("ConnectorClient::connector_credentials_available"); const int max_size = 2048; uint8_t *buffer = (uint8_t*)malloc(max_size); size_t real_size = 0; get_config_private_key(g_fcc_lwm2m_device_private_key_name, buffer, max_size, &real_size); free(buffer); if (real_size > 0) { return true; } return false; } bool ConnectorClient::use_bootstrap() { tr_debug("ConnectorClient::use_bootstrap"); const int max_size = 32; uint8_t *buffer = (uint8_t*)malloc(max_size); bool ret = false; if (buffer != NULL) { memset(buffer, 0, max_size); size_t real_size = 0; ccs_status_e status = get_config_parameter(g_fcc_use_bootstrap_parameter_name, buffer, max_size, &real_size); if (status == CCS_STATUS_SUCCESS && real_size > 0 && buffer[0] > 0) { ret = true; } free(buffer); } return ret; } bool ConnectorClient::get_key(const char *key, const char *endpoint, char *&key_name) { if(key_name) { free(key_name); key_name = NULL; } key_name = (char*)malloc(strlen(key)+strlen(endpoint)+1); if(key_name) { strcpy(key_name, key); strcat(key_name, endpoint); tr_debug("key %s", key_name); return true; } return false; } ccs_status_e ConnectorClient::set_connector_credentials(M2MSecurity *security) { tr_debug("ConnectorClient::set_connector_credentials"); ccs_status_e status = CCS_STATUS_ERROR; const uint8_t *srv_public_key = NULL; const uint8_t *public_key = NULL; const uint8_t *sec_key = NULL; int32_t m2m_id = security->get_security_instance_id(M2MSecurity::M2MServer); if (m2m_id == -1) { return status; } uint32_t srv_public_key_size = security->resource_value_buffer(M2MSecurity::ServerPublicKey, srv_public_key, m2m_id); uint32_t public_key_size = security->resource_value_buffer(M2MSecurity::PublicKey, public_key, m2m_id); uint32_t sec_key_size = security->resource_value_buffer(M2MSecurity::Secretkey, sec_key, m2m_id); if(srv_public_key && public_key && sec_key) { // Parse common name char common_name[64]; memset(common_name, 0, 64); if (extract_cn_from_certificate(public_key, public_key_size, common_name)){ tr_info("ConnectorClient::set_connector_credentials - CN: %s", common_name); _endpoint_info.internal_endpoint_name = String(common_name); delete_config_parameter(KEY_INTERNAL_ENDPOINT); status = set_config_parameter(KEY_INTERNAL_ENDPOINT,(uint8_t*)common_name, strlen(common_name)); } if(status == CCS_STATUS_SUCCESS) { delete_config_certificate(g_fcc_lwm2m_server_ca_certificate_name); status = set_config_certificate(g_fcc_lwm2m_server_ca_certificate_name, srv_public_key, (size_t)srv_public_key_size); } if(status == CCS_STATUS_SUCCESS) { status = set_config_certificate(g_fcc_lwm2m_device_certificate_name, public_key, (size_t)public_key_size); } if(status == CCS_STATUS_SUCCESS) { status = set_config_private_key(g_fcc_lwm2m_device_private_key_name, sec_key, (size_t)sec_key_size); } if(status == CCS_STATUS_SUCCESS) { delete_config_parameter(KEY_ACCOUNT_ID); // AccountID optional so don't fail if unable to store set_config_parameter(KEY_ACCOUNT_ID, (const uint8_t*)_endpoint_info.account_id.c_str(), (size_t)_endpoint_info.account_id.size()); } if(status == CCS_STATUS_SUCCESS) { status = set_config_parameter(g_fcc_lwm2m_server_uri_name, (const uint8_t*)security->resource_value_string(M2MSecurity::M2MServerUri, m2m_id).c_str(), (size_t)security->resource_value_string(M2MSecurity::M2MServerUri, m2m_id).size()); } M2MDevice *device = M2MInterfaceFactory::create_device(); if (device) { String temp = ""; uint32_t currenttime = (uint32_t)device->resource_value_int(M2MDevice::CurrentTime, 0); uint8_t data[4]; memcpy(data, ¤ttime, 4); delete_config_parameter(g_fcc_current_time_parameter_name); set_config_parameter(g_fcc_current_time_parameter_name, data, 4); temp = device->resource_value_string(M2MDevice::Timezone, 0); delete_config_parameter(g_fcc_device_time_zone_parameter_name); set_config_parameter(g_fcc_device_time_zone_parameter_name, (const uint8_t*)temp.c_str(), temp.size()); temp = device->resource_value_string(M2MDevice::UTCOffset, 0); delete_config_parameter(g_fcc_offset_from_utc_parameter_name); set_config_parameter(g_fcc_offset_from_utc_parameter_name, (const uint8_t*)temp.c_str(), temp.size()); status = CCS_STATUS_SUCCESS; } else { tr_debug("No device object to store!"); } } return status; } ccs_status_e ConnectorClient::set_bootstrap_credentials(M2MSecurity *security) { tr_debug("ConnectorClient::set_bootstrap_credentials"); ccs_status_e status = CCS_STATUS_ERROR; const uint8_t *srv_public_key = NULL; const uint8_t *public_key = NULL; const uint8_t *sec_key = NULL; int32_t bs_id = security->get_security_instance_id(M2MSecurity::Bootstrap); if (bs_id == -1) { return status; } uint32_t srv_public_key_size = security->resource_value_buffer(M2MSecurity::ServerPublicKey, srv_public_key, bs_id); uint32_t public_key_size = security->resource_value_buffer(M2MSecurity::PublicKey, public_key, bs_id); uint32_t sec_key_size = security->resource_value_buffer(M2MSecurity::Secretkey, sec_key, bs_id); if(srv_public_key && public_key && sec_key) { delete_config_certificate(g_fcc_bootstrap_server_ca_certificate_name); status = set_config_certificate(g_fcc_bootstrap_server_ca_certificate_name, srv_public_key, (size_t)srv_public_key_size); if(status == CCS_STATUS_SUCCESS) { delete_config_certificate(g_fcc_bootstrap_device_certificate_name); status = set_config_certificate(g_fcc_bootstrap_device_certificate_name, public_key, (size_t)public_key_size); } if(status == CCS_STATUS_SUCCESS) { delete_config_private_key(g_fcc_bootstrap_device_private_key_name); status = set_config_private_key(g_fcc_bootstrap_device_private_key_name, sec_key, (size_t)sec_key_size); } if(status == CCS_STATUS_SUCCESS) { delete_config_parameter(g_fcc_bootstrap_server_uri_name); status = set_config_parameter(g_fcc_bootstrap_server_uri_name, (const uint8_t*)security->resource_value_string(M2MSecurity::M2MServerUri, bs_id).c_str(), (size_t)security->resource_value_string(M2MSecurity::M2MServerUri, bs_id).size()); } } return status; } ccs_status_e ConnectorClient::store_bootstrap_address(M2MSecurity *security) { tr_debug("ConnectorClient::store_bootstrap_address"); ccs_status_e status = CCS_STATUS_ERROR; const uint8_t *srv_address = NULL; int32_t bs_id = security->get_security_instance_id(M2MSecurity::Bootstrap); if (bs_id == -1) { return status; } uint32_t srv_address_size = security->resource_value_buffer(M2MSecurity::M2MServerUri, srv_address, bs_id); if(srv_address) { delete_config_parameter(g_fcc_bootstrap_server_uri_name); status = set_config_parameter(g_fcc_bootstrap_server_uri_name, srv_address, (size_t)srv_address_size); } return status; } ccs_status_e ConnectorClient::clear_first_to_claim() { tr_debug("ConnectorClient::clear_first_to_claim"); return delete_config_parameter(KEY_FIRST_TO_CLAIM); } const ConnectorClientEndpointInfo *ConnectorClient::endpoint_info() const { return &_endpoint_info; } bool ConnectorClient::bootstrap_credentials_stored_in_kcm() { size_t real_size = 0; ccs_status_e success = size_config_parameter(g_fcc_bootstrap_server_uri_name, &real_size); // Return true if bootstrap uri exists in KCM if ((success == CCS_STATUS_SUCCESS) && real_size > 0) { return true; } else { return false; } } bool ConnectorClient::is_first_to_claim() { size_t real_size = 0; uint8_t data[4] = {0}; uint32_t value = 0; ccs_status_e status = get_config_parameter(KEY_FIRST_TO_CLAIM, data, 4, &real_size); if (status == CCS_STATUS_SUCCESS) { memcpy(&value, data, 4); // Return true if bootstrap uri exists in KCM if (value == 1) { return true; } } return false; } void ConnectorClient::timer_expired(M2MTimerObserver::Type type) { if (type == M2MTimerObserver::BootstrapFlowTimer) { start_bootstrap(); } } M2MInterface::BindingMode ConnectorClient::transport_mode() { #ifdef MBED_CLOUD_CLIENT_TRANSPORT_MODE_UDP return M2MInterface::UDP; #elif defined MBED_CLOUD_CLIENT_TRANSPORT_MODE_TCP return M2MInterface::TCP; #elif defined MBED_CLOUD_CLIENT_TRANSPORT_MODE_UDP_QUEUE return M2MInterface::UDP_QUEUE; #elif defined MBED_CLOUD_CLIENT_TRANSPORT_MODE_TCP_QUEUE return M2MInterface::TCP_QUEUE; #else return M2MInterface::UDP; #endif }