Ram Gandikota
/
IOTMetronome
FRDM K64F Metronome
mbed-client/source/m2minterfaceimpl.cpp
- Committer:
- ram54288
- Date:
- 2017-05-14
- Revision:
- 0:dbad57390bd1
File content as of revision 0:dbad57390bd1:
/* * Copyright (c) 2015 ARM Limited. All rights reserved. * 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 <assert.h> #include <stdlib.h> #include "include/m2minterfaceimpl.h" #include "include/eventdata.h" #include "mbed-client/m2minterfaceobserver.h" #include "mbed-client/m2mconnectionhandler.h" #include "mbed-client/m2mconnectionsecurity.h" #include "include/m2mnsdlinterface.h" #include "include/nsdlaccesshelper.h" #include "mbed-client/m2msecurity.h" #include "mbed-client/m2mconstants.h" #include "mbed-client/m2mtimer.h" #include "mbed-trace/mbed_trace.h" #include <stdlib.h> #define TRACE_GROUP "mClt" #define RESOLVE_SEC_MODE(mode) ((mode == M2MInterface::TCP || mode == M2MInterface::TCP_QUEUE) ? M2MConnectionSecurity::TLS : M2MConnectionSecurity::DTLS) M2MInterfaceImpl::M2MInterfaceImpl(M2MInterfaceObserver& observer, const String &ep_name, const String &ep_type, const int32_t l_time, const uint16_t listen_port, const String &dmn, M2MInterface::BindingMode mode, M2MInterface::NetworkStack stack, const String &con_addr) : _event_data(NULL), _bootstrap_timer(NULL), _server_port(0), _listen_port(listen_port), _endpoint_type(ep_type), _domain( dmn), _life_time(l_time), _context_address(con_addr), _register_server(NULL), _queue_sleep_timer(*this), _retry_timer(*this), _callback_handler(NULL), _max_states( STATE_MAX_STATES ), _event_ignored(false), _event_generated(false), _reconnecting(false), _retry_timer_expired(false), _bootstrapped(true), // True as default to get it working with connector only configuration _current_state(0), _retry_count(0), _binding_mode(mode), _observer(observer), _security_connection( new M2MConnectionSecurity( RESOLVE_SEC_MODE(mode) )), _connection_handler(*this, _security_connection, mode, stack), _nsdl_interface(*this), _security(NULL) { tr_debug("M2MInterfaceImpl::M2MInterfaceImpl() -IN"); _nsdl_interface.create_endpoint(ep_name, _endpoint_type, _life_time, _domain, (uint8_t)_binding_mode & 0x07, // nsdl binding mode is only 3 least significant bits _context_address); //Here we must use TCP still __connection_handler = &_connection_handler; _connection_handler.bind_connection(_listen_port); #ifndef MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE _bootstrap_timer = new M2MTimer(*this); #endif tr_debug("M2MInterfaceImpl::M2MInterfaceImpl() -OUT"); } M2MInterfaceImpl::~M2MInterfaceImpl() { tr_debug("M2MInterfaceImpl::~M2MInterfaceImpl() - IN"); _connection_handler.stop_listening(); delete _bootstrap_timer; _security_connection = NULL; tr_debug("M2MInterfaceImpl::~M2MInterfaceImpl() - OUT"); } void M2MInterfaceImpl::bootstrap(M2MSecurity *security) { #ifndef MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE tr_debug("M2MInterfaceImpl::bootstrap(M2MSecurity *security) - IN"); if(!security) { _observer.error(M2MInterface::InvalidParameters); return; } // Transition to a new state based upon // the current state of the state machine M2MSecurityData* data = new M2MSecurityData(); data->_object = security; BEGIN_TRANSITION_MAP // - Current State - TRANSITION_MAP_ENTRY (STATE_BOOTSTRAP) // state_idle TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_bootstrap TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state__bootstrap_address_resolved TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_bootstrap_resource_created TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_bootstrap_wait TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_bootstrapped TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_register TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_register_address_resolved TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_registered TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_update_registration TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_unregister TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_unregistered TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_sending_coap_data TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_coap_data_sent TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_coap_data_received TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_processing_coap_data TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_coap_data_processed TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_waiting END_TRANSITION_MAP(data) if(_event_ignored) { _event_ignored = false; _observer.error(M2MInterface::NotAllowed); } tr_debug("M2MInterfaceImpl::bootstrap(M2MSecurity *security) - OUT"); #else _observer.error(M2MInterface::NotAllowed); #endif //MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE } void M2MInterfaceImpl::cancel_bootstrap() { #ifndef MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE //TODO: Do we need this ? #endif //MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE } void M2MInterfaceImpl::register_object(M2MSecurity *security, const M2MObjectList &object_list) { tr_debug("M2MInterfaceImpl::register_object - IN"); if(!security) { _observer.error(M2MInterface::InvalidParameters); return; } // Transition to a new state based upon // the current state of the state machine //TODO: manage register object in a list. _register_server = security; M2MRegisterData *data = new M2MRegisterData(); data->_object = security; data->_object_list = object_list; BEGIN_TRANSITION_MAP // - Current State - TRANSITION_MAP_ENTRY (STATE_REGISTER) // state_idle TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_bootstrap TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state__bootstrap_address_resolved TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_bootstrap_resource_created TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_bootstrap_wait TRANSITION_MAP_ENTRY (STATE_REGISTER) // state_bootstrapped TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_register TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_register_address_resolved TRANSITION_MAP_ENTRY (STATE_REGISTER) // state_registered TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_update_registration TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_unregister TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_unregistered TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_sending_coap_data TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_coap_data_sent TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_coap_data_received TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_processing_coap_data TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_coap_data_processed TRANSITION_MAP_ENTRY (STATE_REGISTER) // state_waiting END_TRANSITION_MAP(data) if(_event_ignored) { _event_ignored = false; _observer.error(M2MInterface::NotAllowed); } tr_debug("M2MInterfaceImpl::register_object - OUT"); } void M2MInterfaceImpl::update_registration(M2MSecurity *security_object, const uint32_t lifetime) { tr_debug("M2MInterfaceImpl::update_registration(M2MSecurity *security_object, const uint32_t lifetime)"); M2MUpdateRegisterData *data = new M2MUpdateRegisterData(); data->_object = security_object; data->_lifetime = lifetime; start_register_update(data); } void M2MInterfaceImpl::update_registration(M2MSecurity *security_object, const M2MObjectList &object_list, const uint32_t lifetime) { tr_debug("M2MInterfaceImpl::update_registration(M2MSecurity *security_object, const M2MObjectList &object_list, const uint32_t lifetime)"); M2MUpdateRegisterData *data = new M2MUpdateRegisterData(); data->_object = security_object; data->_lifetime = lifetime; data->_object_list = object_list; start_register_update(data); } void M2MInterfaceImpl::unregister_object(M2MSecurity* /*security*/) { tr_debug("M2MInterfaceImpl::unregister_object - IN"); tr_debug("M2MInterfaceImpl::unregister_object - current state %d", _current_state); // Transition to a new state based upon // the current state of the state machine BEGIN_TRANSITION_MAP // - Current State - TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_idle TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_bootstrap TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state__bootstrap_address_resolved TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_bootstrap_resource_created TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_bootstrap_wait TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_bootstrapped TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_register TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_register_address_resolved TRANSITION_MAP_ENTRY (STATE_UNREGISTER) // state_registered TRANSITION_MAP_ENTRY (STATE_UNREGISTER) // state_update_registration TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_unregister TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_unregistered TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_sending_coap_data TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_coap_data_sent TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_coap_data_received TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_processing_coap_data TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_coap_data_processed TRANSITION_MAP_ENTRY (STATE_UNREGISTER) // state_waiting END_TRANSITION_MAP(NULL) if(_event_ignored) { _event_ignored = false; _observer.error(M2MInterface::NotAllowed); } tr_debug("M2MInterfaceImpl::unregister_object - OUT"); } void M2MInterfaceImpl::set_queue_sleep_handler(callback_handler handler) { tr_debug("M2MInterfaceImpl::set_queue_sleep_handler()"); _callback_handler = handler; } void M2MInterfaceImpl::set_random_number_callback(random_number_cb callback) { if(_security_connection) { _security_connection->set_random_number_callback(callback); } } void M2MInterfaceImpl::set_entropy_callback(entropy_cb callback) { if(_security_connection) { _security_connection->set_entropy_callback(callback); } } void M2MInterfaceImpl::set_platform_network_handler(void *handler) { tr_debug("M2MInterfaceImpl::set_platform_network_handler()"); _connection_handler.set_platform_network_handler(handler); } void M2MInterfaceImpl::coap_message_ready(uint8_t *data_ptr, uint16_t data_len, sn_nsdl_addr_s *address_ptr) { tr_debug("M2MInterfaceImpl::coap_message_ready"); if (_current_state != STATE_IDLE) { internal_event(STATE_SENDING_COAP_DATA); if(!_connection_handler.send_data(data_ptr,data_len,address_ptr)) { internal_event( STATE_IDLE); tr_error("M2MInterfaceImpl::coap_message_ready() - M2MInterface::NetworkError"); if (!_reconnecting) { _observer.error(M2MInterface::NetworkError); } } } } void M2MInterfaceImpl::client_registered(M2MServer *server_object) { tr_debug("M2MInterfaceImpl::client_registered"); _retry_count = 0; internal_event(STATE_REGISTERED); //Inform client is registered. //TODO: manage register object in a list. _observer.object_registered(_register_server,*server_object); } void M2MInterfaceImpl::registration_updated(const M2MServer &server_object) { tr_debug("M2MInterfaceImpl::registration_updated"); internal_event(STATE_REGISTERED); _observer.registration_updated(_register_server,server_object); } void M2MInterfaceImpl::registration_error(uint8_t error_code, bool retry) { tr_debug("M2MInterfaceImpl::registration_error code [%d]", error_code); // Try to register again if (retry) { socket_error(M2MConnectionHandler::SOCKET_SEND_ERROR); } else { internal_event(STATE_IDLE); _observer.error((M2MInterface::Error)error_code); } } void M2MInterfaceImpl::client_unregistered() { tr_debug("M2MInterfaceImpl::client_unregistered()"); internal_event(STATE_UNREGISTERED); //TODO: manage register object in a list. _observer.object_unregistered(_register_server); } void M2MInterfaceImpl::bootstrap_done(M2MSecurity *security_object) { #ifndef MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE tr_debug("M2MInterfaceImpl::bootstrap_done"); _retry_count = 0; _reconnecting = false; _bootstrapped = true; _bootstrap_timer->stop_timer(); internal_event(STATE_BOOTSTRAPPED); _observer.bootstrap_done(security_object); #endif //MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE } void M2MInterfaceImpl::bootstrap_wait(M2MSecurity *security_object) { #ifndef MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE tr_debug("M2MInterfaceImpl::bootstrap_wait"); _security = security_object; internal_event(STATE_BOOTSTRAP_WAIT); #endif //MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE } void M2MInterfaceImpl::bootstrap_error() { #ifndef MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE tr_debug("M2MInterfaceImpl::bootstrap_error()"); _bootstrapped = false; _bootstrap_timer->stop_timer(); internal_event(STATE_IDLE); _observer.error(M2MInterface::BootstrapFailed); #endif //MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE } void M2MInterfaceImpl::coap_data_processed() { tr_debug("M2MInterfaceImpl::coap_data_processed()"); internal_event(STATE_COAP_DATA_PROCESSED); } void M2MInterfaceImpl::value_updated(M2MBase *base) { tr_debug("M2MInterfaceImpl::value_updated"); if(base) { M2MBase::BaseType type = base->base_type(); _observer.value_updated(base, type); } } void M2MInterfaceImpl::data_available(uint8_t* data, uint16_t data_size, const M2MConnectionObserver::SocketAddress &address) { tr_debug("M2MInterfaceImpl::data_available"); ReceivedData *event = new ReceivedData(); event->_data = data; event->_size = data_size; event->_address = &address; internal_event(STATE_COAP_DATA_RECEIVED, event); } void M2MInterfaceImpl::socket_error(uint8_t error_code, bool retry) { tr_debug("M2MInterfaceImpl::socket_error: (%d), retry (%d), reconnecting (%d)", error_code, retry, _reconnecting); #if MBED_CLIENT_RECONNECTION_LOOP < 1 if (!_retry_timer_expired && _reconnecting) { tr_debug("M2MInterfaceImpl::socket_error - retry timer running - return"); return; } #endif M2MInterface::Error error = M2MInterface::ErrorNone; switch (error_code) { case M2MConnectionHandler::SSL_CONNECTION_ERROR: error = M2MInterface::SecureConnectionFailed; break; case M2MConnectionHandler::DNS_RESOLVING_ERROR: error = M2MInterface::DnsResolvingFailed; break; case M2MConnectionHandler::SOCKET_READ_ERROR: error = M2MInterface::NetworkError; break; case M2MConnectionHandler::SOCKET_SEND_ERROR: error = M2MInterface::NetworkError; break; case M2MConnectionHandler::SSL_HANDSHAKE_ERROR: error = M2MInterface::SecureConnectionFailed; break; case M2MConnectionHandler::SOCKET_ABORT: error = M2MInterface::NetworkError; break; default: break; } // Try to do reconnecting if (retry) { if (_retry_count < MBED_CLIENT_RECONNECTION_COUNT) { _retry_count++; } #if MBED_CLIENT_RECONNECTION_LOOP > 0 else { tr_debug("M2MInterfaceImpl::socket_error - start again"); _retry_count = 1; _observer.error(error); } #else else { tr_debug("M2MInterfaceImpl::socket_error - no more retries"); _connection_handler.stop_listening(); _retry_timer.stop_timer(); retry = false; } #endif if (retry) { internal_event(STATE_IDLE); _reconnecting = true; _connection_handler.stop_listening(); int retry_time = MBED_CLIENT_RECONNECTION_INTERVAL * MBED_CLIENT_RECONNECTION_COUNT * _retry_count * 1000; _retry_timer_expired = false; _retry_timer.start_timer(retry_time, M2MTimerObserver::RetryTimer); tr_debug("M2MInterfaceImpl::socket_error - reconnecting in %d(s), count %d/%d", retry_time / 1000, _retry_count, MBED_CLIENT_RECONNECTION_COUNT); } } // Inform application if (!retry && M2MInterface::ErrorNone != error) { tr_debug("M2MInterfaceImpl::socket_error - send error to application"); _connection_handler.stop_listening(); _retry_timer.stop_timer(); _retry_count = 0; _reconnecting = false; _observer.error(error); internal_event(STATE_IDLE); } } void M2MInterfaceImpl::address_ready(const M2MConnectionObserver::SocketAddress &address, M2MConnectionObserver::ServerType server_type, const uint16_t server_port) { tr_debug("M2MInterfaceImpl::address_ready"); ResolvedAddressData *data = new ResolvedAddressData(); data->_address = &address; data->_port = server_port; if( M2MConnectionObserver::Bootstrap == server_type) { tr_debug("M2MInterfaceImpl::address_ready() Server Type Bootstrap"); internal_event(STATE_BOOTSTRAP_ADDRESS_RESOLVED, data); } else { tr_debug("M2MInterfaceImpl::address_ready() Server Type LWM2M"); internal_event(STATE_REGISTER_ADDRESS_RESOLVED, data); } } void M2MInterfaceImpl::data_sent() { tr_debug("M2MInterfaceImpl::data_sent()"); if(_binding_mode == M2MInterface::UDP_QUEUE || _binding_mode == M2MInterface::TCP_QUEUE || _binding_mode == M2MInterface::SMS_QUEUE || _binding_mode == M2MInterface::UDP_SMS_QUEUE) { if(_callback_handler) { _queue_sleep_timer.stop_timer(); _queue_sleep_timer.start_timer(MBED_CLIENT_RECONNECTION_COUNT*MBED_CLIENT_RECONNECTION_INTERVAL*1000, M2MTimerObserver::QueueSleep); } } if (_current_state == STATE_BOOTSTRAP_WAIT) { // For bootstrap we need to call bootstrap_done callback ONLY after we have // sent the last ACK and ended in STATE_BOOTSTRAP_WAIT M2MSecurity *sec = _security; _security = NULL; bootstrap_done(sec); } else { internal_event(STATE_COAP_DATA_SENT); } } void M2MInterfaceImpl::timer_expired(M2MTimerObserver::Type type) { tr_debug("M2MInterfaceImpl::timer_expired()"); if(M2MTimerObserver::QueueSleep == type) { if(_callback_handler) { _callback_handler(); } } else if (M2MTimerObserver::RetryTimer == type) { _retry_timer_expired = true; if (_bootstrapped) { internal_event(STATE_REGISTER); } else { internal_event(STATE_BOOTSTRAP); } } else if (M2MTimerObserver::BootstrapTimer == type) { bootstrap_error(); } } // state machine sits here. void M2MInterfaceImpl::state_idle(EventData* /*data*/) { tr_debug("M2MInterfaceImpl::state_idle"); _nsdl_interface.stop_timers(); } void M2MInterfaceImpl::state_bootstrap(EventData *data) { #ifndef MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE tr_debug("M2MInterfaceImpl::state_bootstrap"); // Start with bootstrapping preparation _bootstrapped = false; M2MSecurityData *event = static_cast<M2MSecurityData *> (data); if(!_security) { M2MInterface::Error error = M2MInterface::InvalidParameters; if (event) { _security = event->_object; if(_security) { if(M2MSecurity::Bootstrap == _security->server_type()) { tr_debug("M2MInterfaceImpl::state_bootstrap - server_type : M2MSecurity::Bootstrap"); String server_address = _security->resource_value_string(M2MSecurity::M2MServerUri); tr_debug("M2MInterfaceImpl::state_bootstrap - server_address %s", server_address.c_str()); _bootstrap_timer->start_timer(MBED_CLIENT_RECONNECTION_COUNT * MBED_CLIENT_RECONNECTION_INTERVAL * 8 * 1000, M2MTimerObserver::BootstrapTimer); String coap; if(server_address.compare(0,sizeof(COAP)-1,COAP) == 0) { coap = COAP; } else if(server_address.compare(0,sizeof(COAPS)-1,COAPS) == 0) { _security->resource_value_int(M2MSecurity::SecurityMode) != M2MSecurity::NoSecurity ? coap = COAPS: coap = ""; } if(!coap.empty()) { server_address = server_address.substr(coap.size(), server_address.size()-coap.size()); process_address(server_address, _server_ip_address, _server_port); tr_debug("M2MInterfaceImpl::state_bootstrap - IP address %s , Port %d", _server_ip_address.c_str(), _server_port); // If bind and resolving server address succeed then proceed else // return error to the application and go to Idle state. if(!_server_ip_address.empty()) { error = M2MInterface::ErrorNone; _connection_handler.resolve_server_address(_server_ip_address, _server_port, M2MConnectionObserver::Bootstrap, _security); } } } } } if (error != M2MInterface::ErrorNone) { tr_error("M2MInterfaceImpl::state_bootstrap - set error as M2MInterface::InvalidParameters"); internal_event(STATE_IDLE); _observer.error(error); } } else { _listen_port = rand() % 64511 + 1024; _connection_handler.stop_listening(); _connection_handler.bind_connection(_listen_port); _connection_handler.resolve_server_address(_server_ip_address, _server_port, M2MConnectionObserver::Bootstrap, _security); } #endif //MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE } void M2MInterfaceImpl::state_bootstrap_address_resolved( EventData *data) { #ifndef MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE tr_debug("M2MInterfaceImpl::state_bootstrap_address_resolved"); if (data) { ResolvedAddressData *event = static_cast<ResolvedAddressData *> (data); sn_nsdl_addr_s address; M2MInterface::NetworkStack stack = event->_address->_stack; if(M2MInterface::LwIP_IPv4 == stack) { tr_debug("M2MInterfaceImpl::state_bootstrap_address_resolved : IPv4 address"); address.type = SN_NSDL_ADDRESS_TYPE_IPV4; } else if((M2MInterface::LwIP_IPv6 == stack) || (M2MInterface::Nanostack_IPv6 == stack)) { tr_debug("M2MInterfaceImpl::state_bootstrap_address_resolved : IPv6 address"); address.type = SN_NSDL_ADDRESS_TYPE_IPV6; } address.port = event->_port; address.addr_ptr = (uint8_t*)event->_address->_address; address.addr_len = event->_address->_length; _connection_handler.start_listening_for_data(); // Include domain id to be part of endpoint name StringBuffer<M2MBase::MAX_PATH_SIZE> new_ep_name; if(!new_ep_name.ensure_space(_nsdl_interface.endpoint_name().size() + 1)) { tr_error("MM2MInterfaceImpl::state_bootstrap_address_resolved : name too long"); _observer.error(M2MInterface::InvalidParameters); return; } new_ep_name.append(_nsdl_interface.endpoint_name().c_str()); if (!_domain.empty()) { if(!new_ep_name.ensure_space(_nsdl_interface.endpoint_name().size() + 1 + _domain.size() + 1)) { tr_error("MM2MInterfaceImpl::state_bootstrap_address_resolved : name + domain too long"); _observer.error(M2MInterface::InvalidParameters); return; } new_ep_name.append('@'); new_ep_name.append(_domain.c_str()); } if(_nsdl_interface.create_bootstrap_resource(&address, new_ep_name.c_str())) { tr_debug("M2MInterfaceImpl::state_bootstrap_address_resolved : create_bootstrap_resource - success"); internal_event(STATE_BOOTSTRAP_RESOURCE_CREATED); } else{ // If resource creation fails then inform error to application tr_error("M2MInterfaceImpl::state_bootstrap_address_resolved : M2MInterface::InvalidParameters"); internal_event(STATE_IDLE); _observer.error(M2MInterface::InvalidParameters); } } #endif //MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE } void M2MInterfaceImpl::state_bootstrap_resource_created( EventData */*data*/) { #ifndef MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE tr_debug("M2MInterfaceImpl::state_bootstrap_resource_created"); #endif //MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE } void M2MInterfaceImpl::state_bootstrapped( EventData */*data*/) { #ifndef MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE tr_debug("M2MInterfaceImpl::state_bootstrapped"); #endif //MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE } void M2MInterfaceImpl::state_register(EventData *data) { tr_debug("M2MInterfaceImpl::state_register"); M2MRegisterData *event = static_cast<M2MRegisterData *> (data); if (!_security) { M2MInterface::Error error = M2MInterface::InvalidParameters; // Start with registration preparation if(event) { _security = event->_object; if(_security) { if(M2MSecurity::M2MServer == _security->server_type()) { tr_debug("M2MInterfaceImpl::state_register - server_type : M2MSecurity::M2MServer"); if(_nsdl_interface.create_nsdl_list_structure(event->_object_list)) { tr_debug("M2MInterfaceImpl::state_register - create_nsdl_list_structure - success"); // If the nsdl resource structure is created successfully String server_address = _security->resource_value_string(M2MSecurity::M2MServerUri); tr_debug("M2MInterfaceImpl::state_register - server_address %s", server_address.c_str()); String coap; if(server_address.compare(0,sizeof(COAP)-1,COAP) == 0) { coap = COAP; } else if(server_address.compare(0,sizeof(COAPS)-1,COAPS) == 0) { _security->resource_value_int(M2MSecurity::SecurityMode) != M2MSecurity::NoSecurity ? coap = COAPS: coap = ""; } if(!coap.empty()) { server_address = server_address.substr(coap.size(), server_address.size() - coap.size()); process_address(server_address, _server_ip_address, _server_port); tr_debug("M2MInterfaceImpl::state_register - IP address %s , Port %d", _server_ip_address.c_str(), _server_port); if(!_server_ip_address.empty()) { // Connection related errors are coming through callback error = M2MInterface::ErrorNone; _connection_handler.resolve_server_address(_server_ip_address,_server_port, M2MConnectionObserver::LWM2MServer, _security); } } } } } } if (error != M2MInterface::ErrorNone) { tr_error("M2MInterfaceImpl::state_register - set error as M2MInterface::InvalidParameters"); internal_event(STATE_IDLE); _observer.error(error); } } else { _listen_port = rand() % 64511 + 1024; _connection_handler.stop_listening(); if (event) { _nsdl_interface.create_nsdl_list_structure(event->_object_list); } _connection_handler.bind_connection(_listen_port); _connection_handler.resolve_server_address(_server_ip_address,_server_port, M2MConnectionObserver::LWM2MServer, _security); } } void M2MInterfaceImpl::process_address(const String& server_address, String& ip_address, uint16_t& port) { int colonFound = server_address.find_last_of(':'); //10 if(colonFound != -1) { ip_address = server_address.substr(0,colonFound); port = atoi(server_address.substr(colonFound+1, server_address.size()-ip_address.size()).c_str()); colonFound = ip_address.find_last_of(']'); if(ip_address.compare(0,1,"[") == 0) { if(colonFound == -1) { ip_address.clear(); } else { ip_address = ip_address.substr(1,colonFound-1); } } else if(colonFound != -1) { ip_address.clear(); } } } void M2MInterfaceImpl::state_register_address_resolved( EventData *data) { tr_debug("M2MInterfaceImpl::state_register_address_resolved"); if(data) { ResolvedAddressData *event = static_cast<ResolvedAddressData *> (data); sn_nsdl_addr_type_e address_type = SN_NSDL_ADDRESS_TYPE_IPV6; M2MInterface::NetworkStack stack = event->_address->_stack; if(M2MInterface::LwIP_IPv4 == stack) { tr_debug("M2MInterfaceImpl::state_register_address_resolved : IPv4 address"); address_type = SN_NSDL_ADDRESS_TYPE_IPV4; } else if((M2MInterface::LwIP_IPv6 == stack) || (M2MInterface::Nanostack_IPv6 == stack)) { tr_debug("M2MInterfaceImpl::state_register_address_resolved : IPv6 address"); address_type = SN_NSDL_ADDRESS_TYPE_IPV6; } _connection_handler.start_listening_for_data(); if(!_nsdl_interface.send_register_message((uint8_t*)event->_address->_address,event->_address->_length, event->_port, address_type)) { // If resource creation fails then inform error to application tr_error("M2MInterfaceImpl::state_register_address_resolved : M2MInterface::InvalidParameters"); internal_event(STATE_IDLE); _observer.error(M2MInterface::InvalidParameters); } } } void M2MInterfaceImpl::state_registered( EventData */*data*/) { tr_debug("M2MInterfaceImpl::state_registered"); _retry_count = 0; _reconnecting = false; } void M2MInterfaceImpl::state_update_registration(EventData *data) { tr_debug("M2MInterfaceImpl::state_update_registration"); if(data) { M2MUpdateRegisterData *event = static_cast<M2MUpdateRegisterData *> (data); // Create new resources if any if (!event->_object_list.empty()) { _nsdl_interface.create_nsdl_list_structure(event->_object_list); } _nsdl_interface.send_update_registration(event->_lifetime); } } void M2MInterfaceImpl::state_unregister( EventData */*data*/) { tr_debug("M2MInterfaceImpl::state_unregister"); internal_event(STATE_SENDING_COAP_DATA); if(!_nsdl_interface.send_unregister_message()) { tr_error("M2MInterfaceImpl::state_unregister : M2MInterface::NotRegistered"); internal_event(STATE_IDLE); _observer.error(M2MInterface::NotRegistered); } } void M2MInterfaceImpl::state_unregistered( EventData */*data*/) { tr_debug("M2MInterfaceImpl::state_unregistered"); internal_event(STATE_IDLE); } void M2MInterfaceImpl::state_sending_coap_data( EventData */*data*/) { tr_debug("M2MInterfaceImpl::state_sending_coap_data"); internal_event(STATE_WAITING); } void M2MInterfaceImpl::state_coap_data_sent( EventData */*data*/) { tr_debug("M2MInterfaceImpl::state_coap_data_sent"); internal_event(STATE_WAITING); } void M2MInterfaceImpl::state_coap_data_received( EventData *data) { tr_debug("M2MInterfaceImpl::state_coap_data_received"); if(data) { ReceivedData *event = static_cast<ReceivedData*> (data); sn_nsdl_addr_s address; M2MInterface::NetworkStack stack = event->_address->_stack; if(M2MInterface::LwIP_IPv4 == stack) { tr_debug("M2MInterfaceImpl::state_coap_data_received : IPv4 address"); address.type = SN_NSDL_ADDRESS_TYPE_IPV4; address.addr_len = 4; } else if((M2MInterface::LwIP_IPv6 == stack) || (M2MInterface::Nanostack_IPv6 == stack)) { tr_debug("M2MInterfaceImpl::state_coap_data_received : IPv6 address"); address.type = SN_NSDL_ADDRESS_TYPE_IPV6; address.addr_len = 16; } address.port = event->_address->_port; address.addr_ptr = (uint8_t*)event->_address->_address; address.addr_len = event->_address->_length; // Process received data internal_event(STATE_PROCESSING_COAP_DATA); if(!_nsdl_interface.process_received_data(event->_data, event->_size, &address)) { tr_error("M2MInterfaceImpl::state_coap_data_received : M2MInterface::ResponseParseFailed"); _observer.error(M2MInterface::ResponseParseFailed); } } } void M2MInterfaceImpl::state_processing_coap_data( EventData */*data*/) { tr_debug("M2MInterfaceImpl::state_processing_coap_data"); internal_event(STATE_WAITING); } void M2MInterfaceImpl::state_coap_data_processed( EventData */*data*/) { tr_debug("M2MInterfaceImpl::state_coap_data_processed"); internal_event(STATE_WAITING); } void M2MInterfaceImpl::state_waiting( EventData */*data*/) { tr_debug("M2MInterfaceImpl::state_waiting"); } // generates an external event. called once per external event // to start the state machine executing void M2MInterfaceImpl::external_event(uint8_t new_state, EventData* p_data) { tr_debug("M2MInterfaceImpl::external_event : new state %d", new_state); // if we are supposed to ignore this event if (new_state == EVENT_IGNORED) { tr_debug("M2MInterfaceImpl::external_event : new state is EVENT_IGNORED"); // just delete the event data, if any if (p_data) { delete p_data; p_data = NULL; } _event_ignored = true; } else { tr_debug("M2MInterfaceImpl::external_event : handle new state"); // generate the event and execute the state engine internal_event(new_state, p_data); } } // generates an internal event. called from within a state // function to transition to a new state void M2MInterfaceImpl::internal_event(uint8_t new_state, EventData* p_data) { tr_debug("M2MInterfaceImpl::internal_event : new state %d", new_state); _event_data = p_data; _event_generated = true; _current_state = new_state; state_engine(); } // the state engine executes the state machine states void M2MInterfaceImpl::state_engine (void) { tr_debug("M2MInterfaceImpl::state_engine"); EventData* p_data_temp = NULL; // while events are being generated keep executing states while (_event_generated) { p_data_temp = _event_data; // copy of event data pointer _event_data = NULL; // event data used up, reset ptr _event_generated = false; // event used up, reset flag assert(_current_state < _max_states); state_function( _current_state, p_data_temp ); // if event data was used, then delete it if (p_data_temp) { delete p_data_temp; p_data_temp = NULL; } } } void M2MInterfaceImpl::state_function( uint8_t current_state, EventData* data ) { switch( current_state ) { case STATE_IDLE: M2MInterfaceImpl::state_idle(data); break; case STATE_BOOTSTRAP: #ifndef MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE M2MInterfaceImpl::state_bootstrap(data); #endif //MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE break; case STATE_BOOTSTRAP_ADDRESS_RESOLVED: #ifndef MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE M2MInterfaceImpl::state_bootstrap_address_resolved(data); #endif //MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE break; case STATE_BOOTSTRAP_RESOURCE_CREATED: #ifndef MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE M2MInterfaceImpl::state_bootstrap_resource_created(data); #endif //MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE break; case STATE_BOOTSTRAP_WAIT: #ifndef MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE // Do nothing, we're just waiting for data_sent callback #endif //MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE break; case STATE_BOOTSTRAPPED: #ifndef MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE M2MInterfaceImpl::state_bootstrapped(data); #endif //MBED_CLIENT_DISABLE_BOOTSTRAP_FEATURE break; case STATE_REGISTER: M2MInterfaceImpl::state_register(data); break; case STATE_REGISTER_ADDRESS_RESOLVED: M2MInterfaceImpl::state_register_address_resolved(data); break; case STATE_REGISTERED: M2MInterfaceImpl::state_registered(data); break; case STATE_UPDATE_REGISTRATION: M2MInterfaceImpl::state_update_registration(data); break; case STATE_UNREGISTER: M2MInterfaceImpl::state_unregister(data); break; case STATE_UNREGISTERED: M2MInterfaceImpl::state_unregistered(data); break; case STATE_SENDING_COAP_DATA: M2MInterfaceImpl::state_sending_coap_data(data); break; case STATE_COAP_DATA_SENT: M2MInterfaceImpl::state_coap_data_sent(data); break; case STATE_COAP_DATA_RECEIVED: M2MInterfaceImpl::state_coap_data_received(data); break; case STATE_PROCESSING_COAP_DATA: M2MInterfaceImpl::state_processing_coap_data(data); break; case STATE_COAP_DATA_PROCESSED: M2MInterfaceImpl::state_coap_data_processed(data); break; case STATE_WAITING: M2MInterfaceImpl::state_waiting(data); break; } } void M2MInterfaceImpl::start_register_update(M2MUpdateRegisterData *data) { tr_debug("M2MInterfaceImpl::start_register_update - IN"); if(!data || (data->_lifetime != 0 && (data->_lifetime < MINIMUM_REGISTRATION_TIME))) { _observer.error(M2MInterface::InvalidParameters); } BEGIN_TRANSITION_MAP // - Current State - TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_idle TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_bootstrap TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state__bootstrap_address_resolved TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_bootstrap_resource_created TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_bootstrap_wait TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_bootstrapped TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_register TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_register_address_resolved TRANSITION_MAP_ENTRY (STATE_UPDATE_REGISTRATION) // state_registered TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_update_registration TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_unregister TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_unregistered TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_sending_coap_data TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_coap_data_sent TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_coap_data_received TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_processing_coap_data TRANSITION_MAP_ENTRY (EVENT_IGNORED) // state_coap_data_processed TRANSITION_MAP_ENTRY (STATE_UPDATE_REGISTRATION) // state_waiting END_TRANSITION_MAP(data) if(_event_ignored) { _event_ignored = false; if (!_reconnecting) _observer.error(M2MInterface::NotAllowed); } }