Simple interface for Mbed Cloud Client

Dependents:  

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ConnectorClient.cpp Source File

ConnectorClient.cpp

00001 // ----------------------------------------------------------------------------
00002 // Copyright 2016-2017 ARM Ltd.
00003 //
00004 // SPDX-License-Identifier: Apache-2.0
00005 //
00006 // Licensed under the Apache License, Version 2.0 (the "License");
00007 // you may not use this file except in compliance with the License.
00008 // You may obtain a copy of the License at
00009 //
00010 //     http://www.apache.org/licenses/LICENSE-2.0
00011 //
00012 // Unless required by applicable law or agreed to in writing, software
00013 // distributed under the License is distributed on an "AS IS" BASIS,
00014 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00015 // See the License for the specific language governing permissions and
00016 // limitations under the License.
00017 // ----------------------------------------------------------------------------
00018 
00019 #include <string>
00020 #include <assert.h>
00021 #include <stdio.h>
00022 #include "include/ConnectorClient.h"
00023 #include "include/CloudClientStorage.h"
00024 #include "include/CertificateParser.h"
00025 #include "MbedCloudClient.h"
00026 #include "mbed-client/m2minterfacefactory.h"
00027 #include "mbed-client/m2mdevice.h"
00028 #include "mbed-trace/mbed_trace.h"
00029 #include "factory_configurator_client.h"
00030 
00031 #define TRACE_GROUP "mClt"
00032 
00033 #define INTERNAL_ENDPOINT_PARAM     "&iep="
00034 #define DEFAULT_ENDPOINT "endpoint"
00035 #define INTERFACE_ERROR             "Client interface is not created. Restart"
00036 #define CREDENTIAL_ERROR            "Failed to read credentials from storage"
00037 #define DEVICE_NOT_PROVISIONED      "Device not provisioned"
00038 #define ERROR_NO_MEMORY             "Not enough memory to stroe LWM2M credentials"
00039 
00040 // XXX: nothing here yet
00041 class EventData {
00042 
00043 };
00044 
00045 ConnectorClient::ConnectorClient(ConnectorClientCallback* callback)
00046 : _callback(callback),
00047   _current_state(State_Bootstrap_Start),
00048   _event_generated(false), _state_engine_running(false),
00049   _interface(NULL), _security(NULL),
00050   _endpoint_info(M2MSecurity::Certificate), _client_objs(NULL),
00051   _rebootstrap_timer(*this), _bootstrap_security_instance(1), _lwm2m_security_instance(0)
00052 {
00053     assert(_callback != NULL);
00054 
00055     // Create the lwm2m server security object we need always
00056     _security = M2MInterfaceFactory::create_security(M2MSecurity::M2MServer);
00057     _interface = M2MInterfaceFactory::create_interface(*this,
00058                                                       DEFAULT_ENDPOINT,                     // endpoint name string
00059                                                       MBED_CLOUD_CLIENT_ENDPOINT_TYPE,      // endpoint type string
00060                                                       MBED_CLOUD_CLIENT_LIFETIME,           // lifetime
00061                                                       MBED_CLOUD_CLIENT_LISTEN_PORT,        // listen port
00062                                                       _endpoint_info.account_id,            // domain string
00063                                                       transport_mode(),                     // binding mode
00064                                                       M2MInterface::LwIP_IPv4);             // network stack
00065 
00066     initialize_storage();
00067 }
00068 
00069 
00070 ConnectorClient::~ConnectorClient()
00071 {
00072     M2MDevice::delete_instance();
00073     M2MSecurity::delete_instance();
00074     delete _interface;
00075 }
00076 
00077 void ConnectorClient::start_bootstrap()
00078 {
00079     tr_debug("ConnectorClient::start_bootstrap()");
00080     assert(_callback != NULL);
00081     // Stop rebootstrap timer if it was running
00082     _rebootstrap_timer.stop_timer();
00083     if (create_bootstrap_object()) {
00084         _interface->update_endpoint(_endpoint_info.endpoint_name);
00085         _interface->update_domain(_endpoint_info.account_id);
00086         internal_event(State_Bootstrap_Start);
00087     } else {
00088         tr_error("ConnectorClient::start_bootstrap() - bootstrap object fail");
00089     }
00090     state_engine();
00091 }
00092 
00093 void ConnectorClient::start_registration(M2MObjectList* client_objs)
00094 {
00095     tr_debug("ConnectorClient::start_registration()");
00096     assert(_callback != NULL);
00097     _client_objs = client_objs;
00098 
00099     // XXX: actually this call should be external_event() to match the pattern used in other m2m classes
00100     create_register_object();
00101     if(_security->get_security_instance_id(M2MSecurity::M2MServer) >= 0) {
00102         if(use_bootstrap()) {
00103             // Bootstrap registration always uses iep
00104             _interface->update_endpoint(_endpoint_info.internal_endpoint_name);
00105         } else {
00106             // Registration without bootstrap always uses external id
00107             _interface->update_endpoint(_endpoint_info.endpoint_name);
00108         }
00109         _interface->update_domain(_endpoint_info.account_id);
00110         internal_event(State_Registration_Start);
00111     } else {
00112         tr_error("ConnectorClient::state_init(): failed to create objs");
00113         _callback->connector_error(M2MInterface::InvalidParameters, INTERFACE_ERROR);
00114     }
00115     state_engine();
00116 }
00117 
00118 M2MInterface * ConnectorClient::m2m_interface()
00119 {
00120     return _interface;
00121 }
00122 
00123 void ConnectorClient::update_registration()
00124 {
00125     if(_interface && _security && _security->get_security_instance_id(M2MSecurity::M2MServer) >= 0) {
00126         if (_client_objs != NULL) {
00127             _interface->update_registration(_security, *_client_objs);
00128         }
00129         else {
00130             _interface->update_registration(_security);
00131         }
00132     }
00133 }
00134 
00135 // generates an internal event. called from within a state
00136 // function to transition to a new state
00137 void ConnectorClient::internal_event(StartupSubStateRegistration new_state)
00138 {
00139     tr_debug("ConnectorClient::internal_event: state: %d -> %d", _current_state, new_state);
00140     _event_generated = true;
00141     _current_state = new_state;
00142 
00143     // Avoid recursive chain which eats too much of stack
00144     if (!_state_engine_running) {
00145         state_engine();
00146     }
00147 }
00148 
00149 // the state engine executes the state machine states
00150 void ConnectorClient::state_engine(void)
00151 {
00152     tr_debug("ConnectorClient::state_engine");
00153 
00154     // this simple flagging gets rid of recursive calls to this method
00155     _state_engine_running = true;
00156 
00157     // while events are being generated keep executing states
00158     while (_event_generated) {
00159         _event_generated = false;  // event used up, reset flag
00160 
00161         state_function(_current_state);
00162     }
00163 
00164     _state_engine_running = false;
00165 }
00166 
00167 void ConnectorClient::state_function(StartupSubStateRegistration current_state)
00168 {
00169     switch (current_state) {
00170         case State_Bootstrap_Start:
00171             state_bootstrap_start();
00172             break;
00173         case State_Bootstrap_Started:
00174             state_bootstrap_started();
00175             break;
00176         case State_Bootstrap_Success:
00177             state_bootstrap_success();
00178             break;
00179         case State_Bootstrap_Failure:
00180             state_bootstrap_failure();
00181             break;
00182         case State_Registration_Start:
00183             state_registration_start();
00184             break;
00185         case State_Registration_Started:
00186             state_registration_started();
00187             break;
00188         case State_Registration_Success:
00189             state_registration_success();
00190             break;
00191         case State_Registration_Failure:
00192             state_registration_failure();
00193             break;
00194         case State_Unregistered:
00195             state_unregistered();
00196             break;
00197         default:
00198             break;
00199     }
00200 }
00201 
00202 /*
00203 *  Creates register server object with mbed device server address and other parameters
00204 *  required for client to connect to mbed device server.
00205 */
00206 void ConnectorClient::create_register_object()
00207 {
00208     tr_debug("ConnectorClient::create_register_object()");
00209     if(_security && _security->get_security_instance_id(M2MSecurity::M2MServer) == -1) {
00210         _security->create_object_instance(M2MSecurity::M2MServer);
00211         int32_t m2m_id = _security->get_security_instance_id(M2MSecurity::M2MServer);
00212         _security->set_resource_value(M2MSecurity::BootstrapServer, M2MSecurity::M2MServer, m2m_id);
00213         // Add ResourceID's and values to the security ObjectID/ObjectInstance
00214         _security->set_resource_value(M2MSecurity::SecurityMode, _endpoint_info.mode, m2m_id);
00215 
00216         // Allocate scratch buffer, this will be used to copy parameters from storage to security object
00217         const int max_size = 2048;
00218         uint8_t *buffer = (uint8_t*)malloc(max_size);
00219         size_t real_size = 0;
00220         bool success = false;
00221         if (buffer != NULL) {
00222             success = true;
00223         }
00224 
00225         // Connector CA
00226         if (success) {
00227             success = false;
00228             if (get_config_certificate(g_fcc_lwm2m_server_ca_certificate_name, buffer, max_size, &real_size) == CCS_STATUS_SUCCESS) {
00229                 tr_info("ConnectorClient::create_register_object - ServerPublicKey %d", (int)real_size);
00230                 success = true;
00231                 _security->set_resource_value(M2MSecurity::ServerPublicKey,
00232                                               buffer,
00233                                               (uint32_t)real_size,
00234                                               m2m_id);
00235             }
00236             else {
00237                 tr_error("KEY_CONNECTOR_CA cert failed.");
00238             }
00239         }
00240 
00241         // Connector device public key
00242         if (success) {
00243             success = false;
00244             if (get_config_certificate(g_fcc_lwm2m_device_certificate_name, buffer, max_size, &real_size) == CCS_STATUS_SUCCESS) {
00245                 tr_info("ConnectorClient::create_register_object - PublicKey %d", (int)real_size);
00246                 success = true;
00247                 _security->set_resource_value(M2MSecurity::PublicKey, buffer, (uint32_t)real_size, m2m_id);
00248             }
00249             else {
00250                 tr_error("KEY_CONNECTOR__DEVICE_CERT failed.");
00251             }
00252         }
00253 
00254         // Connector device private key
00255         if (success) {
00256             success = false;
00257             if (get_config_private_key(g_fcc_lwm2m_device_private_key_name, buffer, max_size, &real_size) == CCS_STATUS_SUCCESS) {
00258                 tr_info("ConnectorClient::create_register_object - SecretKey %d", (int)real_size);
00259                 success = true;
00260                 _security->set_resource_value(M2MSecurity::Secretkey, buffer, (uint32_t)real_size, m2m_id);
00261             }
00262             else
00263                 tr_error("KEY_CONNECTOR_DEVICE_PRIV failed.");
00264         }
00265 
00266         // Connector URL
00267         if (success) {
00268             success = false;
00269             if (get_config_parameter(g_fcc_lwm2m_server_uri_name, buffer, max_size, &real_size) == CCS_STATUS_SUCCESS) {
00270                 tr_info("ConnectorClient::create_register_object - M2MServerUri %.*s", (int)real_size, buffer);
00271                 success = true;
00272                 _security->set_resource_value(M2MSecurity::M2MServerUri, buffer, (uint32_t)real_size, m2m_id);
00273             }
00274             else
00275                 tr_error("KEY_CONNECTOR_URL failed.");
00276         }
00277 
00278         // Endpoint
00279         if (success) {
00280             success = false;
00281             if (get_config_parameter(g_fcc_endpoint_parameter_name, buffer, max_size, &real_size) == CCS_STATUS_SUCCESS) {
00282                 tr_info("ConnectorClient::create_register_object - endpoint name %.*s", (int)real_size, buffer);
00283                 success = true;
00284                 _endpoint_info.endpoint_name = String((const char*)buffer, real_size);
00285             }
00286             else
00287                 tr_error("KEY_ENDPOINT_NAME failed.");
00288         }
00289 
00290         // Try to get internal endpoint name
00291         if (success) {
00292             if (get_config_parameter(KEY_INTERNAL_ENDPOINT, buffer, max_size, &real_size) == CCS_STATUS_SUCCESS) {
00293                 _endpoint_info.internal_endpoint_name = String((const char*)buffer, real_size);
00294                 tr_info("Using internal endpoint name instead: %s", _endpoint_info.internal_endpoint_name.c_str());
00295             }
00296             else {
00297                 tr_debug("KEY_INTERNAL_ENDPOINT failed.");
00298             }
00299         }
00300 
00301         // Account ID, not mandatory
00302         if (success) {
00303             if (get_config_parameter(KEY_ACCOUNT_ID, buffer, max_size, &real_size) == CCS_STATUS_SUCCESS) {
00304                 tr_info("ConnectorClient::create_register_object - AccountId %.*s", (int)real_size, buffer);
00305                 _endpoint_info.account_id = String((const char*)buffer, real_size);
00306             }
00307             else
00308                 tr_debug("KEY_ACCOUNT_ID failed.");
00309         }
00310 
00311         free(buffer);
00312         if (!success) {
00313             tr_error("ConnectorClient::create_register_object - Failed to read credentials");
00314             _callback->connector_error((M2MInterface::Error)MbedCloudClient::ConnectorFailedToReadCredentials,CREDENTIAL_ERROR);
00315             // TODO: what to do with the m2mserver security instance
00316         }
00317     } else {
00318         tr_info("ConnectorClient::create_register_object() - Credentials already exists");
00319     }
00320 }
00321 
00322 /*
00323 *  Creates bootstrap server object with bootstrap server address and other parameters
00324 *  required for connecting to mbed Cloud bootstrap server.
00325 */
00326 bool ConnectorClient::create_bootstrap_object()
00327 {
00328     tr_debug("ConnectorClient::create_bootstrap_object");
00329     bool success = false;
00330 
00331     // Check if bootstrap credentials are already stored in KCM
00332     if (bootstrap_credentials_stored_in_kcm() && _security) {
00333         if (_security->get_security_instance_id(M2MSecurity::Bootstrap) == -1) {
00334             _security->create_object_instance(M2MSecurity::Bootstrap);
00335             int32_t bs_id = _security->get_security_instance_id(M2MSecurity::Bootstrap);
00336             _security->set_resource_value(M2MSecurity::SecurityMode, M2MSecurity::Certificate, bs_id);
00337             tr_info("ConnectorClient::create_bootstrap_object - bs_id = %d", bs_id);
00338             tr_info("ConnectorClient::create_bootstrap_object - use credentials from storage");
00339 
00340             // Allocate scratch buffer, this will be used to copy parameters from storage to security object
00341             size_t real_size = 0;
00342             const int max_size = 2048;
00343             uint8_t *buffer = (uint8_t*)malloc(max_size);
00344             if (buffer != NULL) {
00345                 success = true;
00346             }
00347 
00348             // Read internal endpoint name if it exists, we need to append
00349             // it to bootstrap uri if device already bootstrapped
00350             uint8_t *iep = NULL;
00351             if (success && get_config_parameter_string(KEY_INTERNAL_ENDPOINT, buffer, max_size) == CCS_STATUS_SUCCESS) {
00352                 iep = (uint8_t*)malloc(strlen((const char*)buffer) + strlen(INTERNAL_ENDPOINT_PARAM) + 1);
00353                 if (iep != NULL) {
00354                     strcpy((char*)iep, INTERNAL_ENDPOINT_PARAM);
00355                     strcat((char*)iep, (const char*)buffer);
00356                     tr_info("ConnectorClient::create_bootstrap_object - iep: %s", buffer);
00357                 }
00358                 //TODO: Should handle error if iep exists but allocation fails?
00359             }
00360 
00361             // Bootstrap URI
00362             if (success) {
00363                 success = false;
00364                 if (get_config_parameter_string(g_fcc_bootstrap_server_uri_name, buffer, max_size) == CCS_STATUS_SUCCESS) {
00365                     success = true;
00366 
00367                     real_size = strlen((const char*)buffer);
00368                     // Append iep if we 1. have it 2. it doesn't already exist in uri 3. it fits
00369                     if (iep &&
00370                         strstr((const char*)buffer, (const char*)iep) == NULL &&
00371                         (real_size + strlen((const char*)iep) + 1) <= max_size) {
00372                         strcat((char*)buffer, (const char*)iep);
00373                         real_size += strlen((const char*)iep) + 1;
00374                     }
00375 
00376                     tr_info("ConnectorClient::create_bootstrap_object - M2MServerUri %.*s", (int)real_size, buffer);
00377                     _security->set_resource_value(M2MSecurity::M2MServerUri, buffer, real_size, bs_id);
00378                 }
00379             }
00380 
00381             free(iep);
00382 
00383             // Bootstrap server public key (certificate)
00384             if (success) {
00385                 success = false;
00386                 if (get_config_certificate(g_fcc_bootstrap_server_ca_certificate_name, buffer, max_size, &real_size) == CCS_STATUS_SUCCESS) {
00387                     success = true;
00388                     tr_info("ConnectorClient::create_bootstrap_object - ServerPublicKey %d", (int)real_size);
00389                     _security->set_resource_value(M2MSecurity::ServerPublicKey, buffer, real_size, bs_id);
00390                 }
00391             }
00392 
00393             // Bootstrap client public key (certificate)
00394             if (success) {
00395                 success = false;
00396                 if (get_config_certificate(g_fcc_bootstrap_device_certificate_name, buffer, max_size, &real_size) == CCS_STATUS_SUCCESS) {
00397                     success = true;
00398                     tr_info("ConnectorClient::create_bootstrap_object - PublicKey %d", (int)real_size);
00399                     _security->set_resource_value(M2MSecurity::PublicKey, buffer, real_size, bs_id);
00400                 }
00401             }
00402 
00403             // Bootstrap client private key
00404             if (success) {
00405                 success = false;
00406                 if (get_config_private_key(g_fcc_bootstrap_device_private_key_name, buffer, max_size, &real_size) == CCS_STATUS_SUCCESS) {
00407                     success = true;
00408                     tr_info("ConnectorClient::create_bootstrap_object - Secretkey %d", (int)real_size);
00409                     _security->set_resource_value(M2MSecurity::Secretkey, buffer, real_size, bs_id);
00410                 }
00411             }
00412 
00413             // Endpoint
00414             if (success) {
00415                 success = false;
00416                 if (get_config_parameter(g_fcc_endpoint_parameter_name, buffer, max_size, &real_size) == CCS_STATUS_SUCCESS) {
00417                     success = true;
00418                     _endpoint_info.endpoint_name = String((const char*)buffer, real_size);
00419                     tr_info("ConnectorClient::create_bootstrap_object - Endpoint %s", _endpoint_info.endpoint_name.c_str());
00420                 }
00421             }
00422 
00423             // Account ID, not mandatory
00424             if (success) {
00425                 if (get_config_parameter(KEY_ACCOUNT_ID, buffer, max_size, &real_size) == CCS_STATUS_SUCCESS) {
00426                     _endpoint_info.account_id = String((const char*)buffer, real_size);
00427                     tr_info("ConnectorClient::create_bootstrap_object - AccountId %s", _endpoint_info.account_id.c_str());
00428                 }
00429             }
00430             free(buffer);
00431 
00432             if (!success) {
00433                 tr_error("ConnectorClient::create_bootstrap_object - Failed to read credentials");
00434                 _callback->connector_error((M2MInterface::Error)MbedCloudClient::ConnectorFailedToReadCredentials,CREDENTIAL_ERROR);
00435                 _security->remove_object_instance(bs_id);
00436             }
00437         } else {
00438             success = true;
00439             tr_info("ConnectorClient::create_bootstrap_object - bootstrap object already done");
00440         }
00441     // Device not provisioned
00442     } else {
00443         _callback->connector_error((M2MInterface::Error)MbedCloudClient::ConnectorInvalidCredentials, DEVICE_NOT_PROVISIONED);
00444         tr_error("ConnectorClient::create_bootstrap_object - device not provisioned!");
00445     }
00446     return success;
00447 }
00448 
00449 void ConnectorClient::state_bootstrap_start()
00450 {
00451     tr_info("ConnectorClient::state_bootstrap_start()");
00452     assert(_interface != NULL);
00453     assert(_security != NULL);
00454 
00455     _interface->bootstrap(_security);
00456 
00457     internal_event(State_Bootstrap_Started);
00458 }
00459 
00460 void ConnectorClient::state_bootstrap_started()
00461 {
00462     // this state may be useful only for verifying the callbacks?
00463 }
00464 
00465 void ConnectorClient::state_bootstrap_success()
00466 {
00467     assert(_callback != NULL);
00468     // Parse internal endpoint name from mDS cert
00469     _callback->registration_process_result(State_Bootstrap_Success);
00470 }
00471 
00472 void ConnectorClient::state_bootstrap_failure()
00473 {
00474     assert(_callback != NULL);
00475     // maybe some additional canceling and/or leanup is needed here?
00476     _callback->registration_process_result(State_Bootstrap_Failure);
00477 }
00478 
00479 void ConnectorClient::state_registration_start()
00480 {
00481     tr_info("ConnectorClient::state_registration_start()");
00482     assert(_interface != NULL);
00483     assert(_security != NULL);
00484     _interface->register_object(_security, *_client_objs);
00485     internal_event(State_Registration_Started);
00486 }
00487 
00488 void ConnectorClient::state_registration_started()
00489 {
00490     // this state may be useful only for verifying the callbacks?
00491 }
00492 
00493 void ConnectorClient::state_registration_success()
00494 {
00495     assert(_callback != NULL);
00496     _endpoint_info.internal_endpoint_name = _interface->internal_endpoint_name();
00497 
00498     //The endpoint is maximum 32 character long, we put bigger buffer for future extensions
00499     const int max_size = 64;
00500     uint8_t buffer[max_size];
00501 
00502     bool no_param_update = true;
00503 
00504     if(get_config_parameter_string(KEY_INTERNAL_ENDPOINT, buffer, max_size) == CCS_STATUS_SUCCESS) {
00505         if (strcmp((const char*)buffer, _endpoint_info.internal_endpoint_name.c_str()) != 0) {
00506             // Update is required as the stored KCM entry is different than _endpoint_info.internal_endpoint_name.
00507             no_param_update = false;
00508         }
00509     }
00510 
00511     // Update INTERNAL_ENDPOINT setting only if there is no such entry or the value is not matching the
00512     // _endpoint_info.internal_endpoint_name.
00513     if(!no_param_update) {
00514         delete_config_parameter(KEY_INTERNAL_ENDPOINT);
00515         set_config_parameter(KEY_INTERNAL_ENDPOINT, (const uint8_t*)_endpoint_info.internal_endpoint_name.c_str(),
00516                              (size_t)_endpoint_info.internal_endpoint_name.size());
00517     }
00518 
00519     _callback->registration_process_result(State_Registration_Success);
00520 }
00521 
00522 void ConnectorClient::state_registration_failure()
00523 {
00524     assert(_callback != NULL);
00525     // maybe some additional canceling and/or leanup is needed here?
00526     _callback->registration_process_result(State_Registration_Failure);
00527 }
00528 
00529 void ConnectorClient::state_unregistered()
00530 {
00531     assert(_callback != NULL);
00532     _callback->registration_process_result(State_Unregistered);
00533 }
00534 
00535 void ConnectorClient::bootstrap_done(M2MSecurity *security_object)
00536 {
00537     tr_info("ConnectorClient::bootstrap_done");
00538     ccs_status_e status = CCS_STATUS_ERROR;
00539     StartupSubStateRegistration state = State_Bootstrap_Success;
00540     if(security_object) {
00541         // Update bootstrap credentials (we could skip this if we knew whether they were updated)
00542         // This will also update the address in case of first to claim
00543         status = set_bootstrap_credentials(security_object);
00544         if (status != CCS_STATUS_SUCCESS) {
00545             // TODO: what now?
00546             tr_error("ConnectorClient::bootstrap_done - couldn't store bootstrap credentials");
00547         }
00548 
00549         // Clear the first to claim flag if it's active
00550         if (is_first_to_claim()) {
00551             status = clear_first_to_claim();
00552             if (status != CCS_STATUS_SUCCESS) {
00553                 // TODO: what now?
00554                 tr_error("ConnectorClient::bootstrap_done - couldn't clear first to claim flag!");
00555             }
00556         }
00557 
00558         // Bootstrap might delete m2mserver security object instance completely to force bootstrap
00559         // with new credentials, in that case delete the stored lwm2m credentials as well and re-bootstrap
00560         if (security_object->get_security_instance_id(M2MSecurity::M2MServer) == -1) {
00561             tr_info("ConnectorClient::bootstrap_done() - Clearing lwm2m credentials");
00562             // delete the old connector credentials when BS sends re-direction.
00563             delete_config_parameter(g_fcc_lwm2m_server_uri_name);
00564             delete_config_certificate(g_fcc_lwm2m_server_ca_certificate_name);
00565             delete_config_certificate(g_fcc_lwm2m_device_certificate_name);
00566             delete_config_private_key(g_fcc_lwm2m_device_private_key_name);
00567             // Start re-bootstrap timer
00568             tr_info("ConnectorClient::bootstrap_done() - Re-directing bootstrap in 100 milliseconds");
00569             _rebootstrap_timer.start_timer(100, M2MTimerObserver::BootstrapFlowTimer, true);
00570             return;
00571         }
00572         // Bootstrap wrote M2MServer credentials, store them and also update first to claim status if it's configured
00573         else {
00574             tr_info("ConnectorClient::bootstrap_done() - Storing lwm2m credentials");
00575             status = set_connector_credentials(security_object);
00576         }
00577     }
00578     if (status != CCS_STATUS_SUCCESS) {
00579         internal_event(State_Bootstrap_Failure);
00580         //Failed to store credentials, bootstrap failed
00581         _callback->connector_error(M2MInterface::MemoryFail, ERROR_NO_MEMORY); // Translated to error code ConnectMemoryConnectFail
00582         return;
00583     } else {
00584         tr_error("ConnectorClient::bootstrap_done - set_credentials status %d", status);
00585     }
00586     internal_event(state);
00587 }
00588 
00589 void ConnectorClient::object_registered(M2MSecurity *security_object, const M2MServer &server_object)
00590 {
00591     internal_event(State_Registration_Success);
00592 }
00593 
00594 void ConnectorClient::object_unregistered(M2MSecurity *server_object)
00595 {
00596     internal_event(State_Unregistered);
00597 }
00598 
00599 void ConnectorClient::registration_updated(M2MSecurity *security_object, const M2MServer & server_object)
00600 {
00601     _callback->registration_process_result(State_Registration_Updated);
00602 }
00603 
00604 void ConnectorClient::error(M2MInterface::Error error)
00605 {
00606     tr_error("ConnectorClient::error() - error: %d", error);
00607     assert(_callback != NULL);
00608     if (_current_state >= State_Registration_Start &&
00609             use_bootstrap() &&
00610             (error == M2MInterface::SecureConnectionFailed ||
00611             error == M2MInterface::InvalidParameters)) {
00612         tr_info("ConnectorClient::error() - Error during lwm2m registration");
00613         tr_info("ConnectorClient::error() - Clearing lwm2m credentials");
00614         // delete the old connector credentials when DTLS handshake fails or
00615         // server rejects the registration.
00616         delete_config_parameter(g_fcc_lwm2m_server_uri_name);
00617         delete_config_certificate(g_fcc_lwm2m_server_ca_certificate_name);
00618         delete_config_certificate(g_fcc_lwm2m_device_certificate_name);
00619         delete_config_private_key(g_fcc_lwm2m_device_private_key_name);
00620         // Delete the lwm2m security instance
00621         int32_t id = _security->get_security_instance_id(M2MSecurity::M2MServer);
00622         if (id >= 0) {
00623             _security->remove_object_instance(id);
00624         }
00625         // Delete bootstrap security instance
00626         id = _security->get_security_instance_id(M2MSecurity::Bootstrap);
00627         if (id >= 0) {
00628             _security->remove_object_instance(id);
00629         }
00630         // Start re-bootstrap timer
00631         tr_info("ConnectorClient::error() - Re-bootstrapping in 100 milliseconds");
00632         _rebootstrap_timer.start_timer(100, M2MTimerObserver::BootstrapFlowTimer, true);
00633     }
00634     else {
00635         _callback->connector_error(error, _interface->error_description());
00636     }
00637 }
00638 
00639 void ConnectorClient::value_updated(M2MBase *base, M2MBase::BaseType type)
00640 {
00641     assert(_callback != NULL);
00642     _callback->value_updated(base, type);
00643 }
00644 
00645 bool ConnectorClient::connector_credentials_available()
00646 {
00647     tr_debug("ConnectorClient::connector_credentials_available");
00648     const int max_size = 2048;
00649     uint8_t *buffer = (uint8_t*)malloc(max_size);
00650     size_t real_size = 0;
00651     get_config_private_key(g_fcc_lwm2m_device_private_key_name, buffer, max_size, &real_size);
00652     free(buffer);
00653     if (real_size > 0) {
00654         return true;
00655     }
00656     return false;
00657 }
00658 
00659 bool ConnectorClient::use_bootstrap()
00660 {
00661     tr_debug("ConnectorClient::use_bootstrap");
00662     const int max_size = 32;
00663     uint8_t *buffer = (uint8_t*)malloc(max_size);
00664     bool ret = false;
00665     if (buffer != NULL) {
00666         memset(buffer, 0, max_size);
00667         size_t real_size = 0;
00668         ccs_status_e status = get_config_parameter(g_fcc_use_bootstrap_parameter_name, buffer, max_size, &real_size);
00669         if (status == CCS_STATUS_SUCCESS && real_size > 0 && buffer[0] > 0) {
00670             ret = true;
00671         }
00672         free(buffer);
00673     }
00674     return ret;
00675 }
00676 
00677 
00678 bool ConnectorClient::get_key(const char *key, const char *endpoint, char *&key_name)
00679 {
00680     if(key_name) {
00681         free(key_name);
00682         key_name = NULL;
00683     }
00684 
00685     key_name = (char*)malloc(strlen(key)+strlen(endpoint)+1);
00686     if(key_name) {
00687         strcpy(key_name, key);
00688         strcat(key_name, endpoint);
00689         tr_debug("key %s", key_name);
00690         return true;
00691     }
00692     return false;
00693 }
00694 
00695 ccs_status_e ConnectorClient::set_connector_credentials(M2MSecurity *security)
00696 {
00697     tr_debug("ConnectorClient::set_connector_credentials");
00698     ccs_status_e status = CCS_STATUS_ERROR;
00699 
00700     const uint8_t *srv_public_key = NULL;
00701     const uint8_t *public_key = NULL;
00702     const uint8_t *sec_key = NULL;
00703 
00704     int32_t m2m_id = security->get_security_instance_id(M2MSecurity::M2MServer);
00705     if (m2m_id == -1) {
00706         return status;
00707     }
00708 
00709     uint32_t srv_public_key_size = security->resource_value_buffer(M2MSecurity::ServerPublicKey, srv_public_key, m2m_id);
00710     uint32_t public_key_size = security->resource_value_buffer(M2MSecurity::PublicKey, public_key, m2m_id);
00711     uint32_t sec_key_size = security->resource_value_buffer(M2MSecurity::Secretkey, sec_key, m2m_id);
00712 
00713     if(srv_public_key && public_key && sec_key) {
00714         // Parse common name
00715         char common_name[64];
00716         memset(common_name, 0, 64);
00717         if (extract_cn_from_certificate(public_key, public_key_size, common_name)){
00718             tr_info("ConnectorClient::set_connector_credentials - CN: %s", common_name);
00719             _endpoint_info.internal_endpoint_name = String(common_name);
00720             delete_config_parameter(KEY_INTERNAL_ENDPOINT);
00721             status = set_config_parameter(KEY_INTERNAL_ENDPOINT,(uint8_t*)common_name, strlen(common_name));
00722         }
00723 
00724         if(status == CCS_STATUS_SUCCESS) {
00725             delete_config_certificate(g_fcc_lwm2m_server_ca_certificate_name);
00726             status = set_config_certificate(g_fcc_lwm2m_server_ca_certificate_name,
00727                                             srv_public_key,
00728                                             (size_t)srv_public_key_size);
00729         }
00730         if(status == CCS_STATUS_SUCCESS) {
00731             status = set_config_certificate(g_fcc_lwm2m_device_certificate_name,
00732                                             public_key,
00733                                             (size_t)public_key_size);
00734         }
00735         if(status == CCS_STATUS_SUCCESS) {
00736             status = set_config_private_key(g_fcc_lwm2m_device_private_key_name,
00737                                             sec_key,
00738                                             (size_t)sec_key_size);
00739         }
00740 
00741         if(status == CCS_STATUS_SUCCESS) {
00742             delete_config_parameter(KEY_ACCOUNT_ID);
00743             // AccountID optional so don't fail if unable to store
00744             set_config_parameter(KEY_ACCOUNT_ID,
00745                                  (const uint8_t*)_endpoint_info.account_id.c_str(),
00746                                  (size_t)_endpoint_info.account_id.size());
00747         }
00748         if(status == CCS_STATUS_SUCCESS) {
00749             status = set_config_parameter(g_fcc_lwm2m_server_uri_name,
00750                                           (const uint8_t*)security->resource_value_string(M2MSecurity::M2MServerUri, m2m_id).c_str(),
00751                                           (size_t)security->resource_value_string(M2MSecurity::M2MServerUri, m2m_id).size());
00752         }
00753         M2MDevice *device = M2MInterfaceFactory::create_device();
00754         if (device) {
00755             String temp = "";
00756             uint32_t currenttime = (uint32_t)device->resource_value_int(M2MDevice::CurrentTime, 0);
00757             uint8_t data[4];
00758             memcpy(data, &currenttime, 4);
00759             delete_config_parameter(g_fcc_current_time_parameter_name);
00760             set_config_parameter(g_fcc_current_time_parameter_name, data, 4);
00761 
00762             temp = device->resource_value_string(M2MDevice::Timezone, 0);
00763             delete_config_parameter(g_fcc_device_time_zone_parameter_name);
00764             set_config_parameter(g_fcc_device_time_zone_parameter_name, (const uint8_t*)temp.c_str(), temp.size());
00765 
00766             temp = device->resource_value_string(M2MDevice::UTCOffset, 0);
00767             delete_config_parameter(g_fcc_offset_from_utc_parameter_name);
00768             set_config_parameter(g_fcc_offset_from_utc_parameter_name, (const uint8_t*)temp.c_str(), temp.size());
00769 
00770             status = CCS_STATUS_SUCCESS;
00771         }
00772         else {
00773             tr_debug("No device object to store!");
00774         }
00775     }
00776 
00777     return status;
00778 }
00779 
00780 ccs_status_e ConnectorClient::set_bootstrap_credentials(M2MSecurity *security)
00781 {
00782     tr_debug("ConnectorClient::set_bootstrap_credentials");
00783     ccs_status_e status = CCS_STATUS_ERROR;
00784 
00785     const uint8_t *srv_public_key = NULL;
00786     const uint8_t *public_key = NULL;
00787     const uint8_t *sec_key = NULL;
00788 
00789     int32_t bs_id = security->get_security_instance_id(M2MSecurity::Bootstrap);
00790     if (bs_id == -1) {
00791         return status;
00792     }
00793 
00794     uint32_t srv_public_key_size = security->resource_value_buffer(M2MSecurity::ServerPublicKey, srv_public_key, bs_id);
00795     uint32_t public_key_size = security->resource_value_buffer(M2MSecurity::PublicKey, public_key, bs_id);
00796     uint32_t sec_key_size = security->resource_value_buffer(M2MSecurity::Secretkey, sec_key, bs_id);
00797 
00798     if(srv_public_key && public_key && sec_key) {
00799         delete_config_certificate(g_fcc_bootstrap_server_ca_certificate_name);
00800         status = set_config_certificate(g_fcc_bootstrap_server_ca_certificate_name,
00801                                             srv_public_key,
00802                                             (size_t)srv_public_key_size);
00803         if(status == CCS_STATUS_SUCCESS) {
00804             delete_config_certificate(g_fcc_bootstrap_device_certificate_name);
00805             status = set_config_certificate(g_fcc_bootstrap_device_certificate_name,
00806                                             public_key,
00807                                             (size_t)public_key_size);
00808         }
00809         if(status == CCS_STATUS_SUCCESS) {
00810             delete_config_private_key(g_fcc_bootstrap_device_private_key_name);
00811             status = set_config_private_key(g_fcc_bootstrap_device_private_key_name,
00812                                             sec_key,
00813                                             (size_t)sec_key_size);
00814         }
00815         if(status == CCS_STATUS_SUCCESS) {
00816             delete_config_parameter(g_fcc_bootstrap_server_uri_name);
00817             status = set_config_parameter(g_fcc_bootstrap_server_uri_name,
00818                                           (const uint8_t*)security->resource_value_string(M2MSecurity::M2MServerUri, bs_id).c_str(),
00819                                           (size_t)security->resource_value_string(M2MSecurity::M2MServerUri, bs_id).size());
00820         }
00821     }
00822 
00823     return status;
00824 }
00825 
00826 ccs_status_e ConnectorClient::store_bootstrap_address(M2MSecurity *security)
00827 {
00828     tr_debug("ConnectorClient::store_bootstrap_address");
00829     ccs_status_e status = CCS_STATUS_ERROR;
00830 
00831     const uint8_t *srv_address = NULL;
00832     int32_t bs_id = security->get_security_instance_id(M2MSecurity::Bootstrap);
00833     if (bs_id == -1) {
00834         return status;
00835     }
00836 
00837     uint32_t srv_address_size = security->resource_value_buffer(M2MSecurity::M2MServerUri, srv_address, bs_id);
00838 
00839     if(srv_address) {
00840         delete_config_parameter(g_fcc_bootstrap_server_uri_name);
00841         status = set_config_parameter(g_fcc_bootstrap_server_uri_name,
00842                                       srv_address,
00843                                       (size_t)srv_address_size);
00844     }
00845 
00846     return status;
00847 }
00848 
00849 ccs_status_e ConnectorClient::clear_first_to_claim()
00850 {
00851     tr_debug("ConnectorClient::clear_first_to_claim");
00852     return delete_config_parameter(KEY_FIRST_TO_CLAIM);
00853 }
00854 
00855 
00856 const ConnectorClientEndpointInfo *ConnectorClient::endpoint_info() const
00857 {
00858     return &_endpoint_info;
00859 }
00860 
00861 bool ConnectorClient::bootstrap_credentials_stored_in_kcm()
00862 {
00863     size_t real_size = 0;
00864     ccs_status_e success = size_config_parameter(g_fcc_bootstrap_server_uri_name, &real_size);
00865     // Return true if bootstrap uri exists in KCM
00866     if ((success == CCS_STATUS_SUCCESS) && real_size > 0) {
00867         return true;
00868     } else {
00869         return false;
00870     }
00871 }
00872 
00873 bool ConnectorClient::is_first_to_claim()
00874 {
00875     size_t real_size = 0;
00876     uint8_t data[4] = {0};
00877     uint32_t value = 0;
00878     ccs_status_e status = get_config_parameter(KEY_FIRST_TO_CLAIM, data, 4, &real_size);
00879     if (status == CCS_STATUS_SUCCESS) {
00880         memcpy(&value, data, 4);
00881         // Return true if bootstrap uri exists in KCM
00882         if (value == 1) {
00883             return true;
00884         }
00885     }
00886     return false;
00887 }
00888 
00889 void ConnectorClient::timer_expired(M2MTimerObserver::Type type)
00890 {
00891     if (type == M2MTimerObserver::BootstrapFlowTimer) {
00892         start_bootstrap();
00893     }
00894 }
00895 
00896 M2MInterface::BindingMode ConnectorClient::transport_mode()
00897 {
00898 #ifdef MBED_CLOUD_CLIENT_TRANSPORT_MODE_UDP
00899     return M2MInterface::UDP;
00900 #elif defined MBED_CLOUD_CLIENT_TRANSPORT_MODE_TCP
00901     return M2MInterface::TCP;
00902 #elif defined MBED_CLOUD_CLIENT_TRANSPORT_MODE_UDP_QUEUE
00903     return M2MInterface::UDP_QUEUE;
00904 #elif defined MBED_CLOUD_CLIENT_TRANSPORT_MODE_TCP_QUEUE
00905     return M2MInterface::TCP_QUEUE;
00906 #else
00907     return M2MInterface::UDP;
00908 #endif
00909 }