Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
source/ConnectorEndpoint.cpp
- Committer:
- ansond
- Date:
- 2016-06-12
- Revision:
- 26:d7b009313e3b
- Parent:
- 23:5852c0884714
File content as of revision 26:d7b009313e3b:
/**
* @file ConnectorEndpoint.cpp
* @brief mbed CoAP Endpoint base class
* @author Doug Anson/Chris Paola
* @version 1.0
* @see
*
* Copyright (c) 2014
*
* 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.
*/
// Lower level Network
#include "mbed-connector-interface/mbedEndpointNetwork.h"
// ConnectorEndpoint
#include "mbed-connector-interface/ConnectorEndpoint.h"
// Utils support
#include "mbed-connector-interface/Utils.h"
// DEBUG
#ifndef NDEBUG
#define DEBUG_OUT(...) { printf(__VA_ARGS__); }
#else
#define DEBUG_OUT(...) /* nothing */
#endif
// our endpoint instance
static Connector::Endpoint *__endpoint = NULL;
// Connector namespace
namespace Connector {
// STATIC: Plumb the network
void Endpoint::plumbNetwork(void *device_manager,bool canActAsRouterNode) {
if (__endpoint == NULL) {
// initialize our endpoint instance
DEBUG_OUT("Endpoint::plumbNetwork: initializing endpoint instance...\r\n");
__endpoint = (Connector::Endpoint *)utils_init_endpoint(canActAsRouterNode);
}
// set the device manager
if (device_manager != NULL) {
// device manager has been supplied
DEBUG_OUT("Endpoint::plumbNetwork: setting a device manager...\r\n");
__endpoint->setDeviceManager(device_manager);
}
else {
// no device manager supplied
DEBUG_OUT("Endpoint::plumbNetwork: no device manager supplied (OK)\r\n");
}
// configure the endpoint now...
DEBUG_OUT("Endpoint::plumbNetwork: configuring endpoint...\r\n");
utils_configure_endpoint((void *)__endpoint);
// plumb network
DEBUG_OUT("Endpoint::plumbNetwork: plumbing network...\r\n");
net_plumb_network((void *)__endpoint);
}
// STATIC: Finalize the endpoint's configuration and begin the endpoint's main even loop (static, not tied into Logger)
void Endpoint::start()
{
// complete setup of our endpoint...
DEBUG_OUT("Endpoint::start: building out endpoint...\r\n");
utils_build_endpoint((void *)__endpoint);
// register the endpoint
DEBUG_OUT("Endpoint::start: completing endpoint build out..\r\n");
net_perform_endpoint_registration(__endpoint);
}
// Constructor
Endpoint::Endpoint(const Logger *logger, const Options *options) : M2MInterfaceObserver()
{
this->m_logger = (Logger *)logger;
this->m_options = (Options *)options;
this->m_device_manager = NULL;
this->m_connected = false;
this->m_registered = false;
}
// Copy Constructor
Endpoint::Endpoint(const Endpoint &ep)
{
this->m_logger = ep.m_logger;
this->m_options = ep.m_options;
this->m_interface = ep.m_interface;
this->m_server_instance = ep.m_server_instance;
this->m_object_list = ep.m_object_list;
this->m_device_object = ep.m_device_object;
this->m_device_manager = ep.m_device_manager;
this->m_connected = ep.m_connected;
this->m_registered = ep.m_registered;
}
// Destructor
Endpoint::~Endpoint() {
if (this->m_interface != NULL)
delete this->m_interface;
if (this->m_server_instance != NULL)
delete this->m_server_instance;
}
// set the device manager
void Endpoint::setDeviceManager(void *device_manager) {
this->m_device_manager = device_manager;
}
// get the device manager
void *Endpoint::getDeviceManager(void) {
return this->m_device_manager;
}
// router node behavior setting
void Endpoint::asRouterNode(bool canActAsRouterNode) {
this->m_canActAsRouterNode = canActAsRouterNode;
}
// set our Options
void Endpoint::setOptions(Options *options) {
this->m_options = options;
}
// get our Options
Options *Endpoint::getOptions() {
return this->m_options;
}
// get our Server
M2MSecurity *Endpoint::getServer() {
return this->m_server_instance;
}
// get our ObjectList
M2MObjectList Endpoint::getObjectList() {
return this->m_object_list;
}
// mbed-client: create our interface
void Endpoint::create_interface() {
// get the CoAP listening port
uint16_t listening_port = (uint16_t)this->m_options->getConnectorPort();
// randomize the port if we are using certificates...
if (this->m_options->getServerCertificateSize() > 0) {
// Randomizing listening port for Certificate mode connectivity
srand(time(NULL));
listening_port = rand() % 65535 + 12345;
}
// Binding Mode - TCP or UDP
M2MInterface::BindingMode network_protocol = M2MInterface::UDP;
if (this->m_options->getCoAPConnectionType() == COAP_TCP) network_protocol = M2MInterface::TCP;
// Network Type IPv4 or IPv6
M2MInterface::NetworkStack ip_address_type = M2MInterface::LwIP_IPv4;
if (this->m_options->getIPAddressType() == IP_ADDRESS_TYPE_IPV6) ip_address_type = M2MInterface::LwIP_IPv6;
// DEBUG
if (network_protocol == M2MInterface::TCP) this->logger()->log("Endpoint: Underlying Protocol: TCP");
if (network_protocol == M2MInterface::UDP) this->logger()->log("Endpoint: Underlying Protocol: UDP");
if (ip_address_type == M2MInterface::LwIP_IPv4) this->logger()->log("Endpoint: IP Address Type: IPv4");
if (ip_address_type == M2MInterface::LwIP_IPv6) this->logger()->log("Endpoint: IP Address Type: IPv6");
// Create the M2M Interface instance
this->m_interface = M2MInterfaceFactory::create_interface(*this,
(char *)this->m_options->getEndpointNodename().c_str(),
(char *)this->m_options->getEndpointType().c_str(),
(int32_t)this->m_options->getLifetime(),
listening_port, // listening port
(char *)this->m_options->getDomain().c_str(),
network_protocol, // CoAP over UDP or TCP...
ip_address_type); // IPv4 addressing or IPv6 addressing
}
// mbed-client: create_server_instance()
M2MSecurity *Endpoint::create_server_instance() {
// Creates register server object with mbed device server address and other parameters
M2MSecurity *server = M2MInterfaceFactory::create_security(M2MSecurity::M2MServer);
if (server != NULL) {
const String url = this->m_options->getConnectorURL();
server->set_resource_value(M2MSecurity::M2MServerUri, url);
server->set_resource_value(M2MSecurity::BootstrapServer, NULL);
server->set_resource_value(M2MSecurity::SecurityMode, M2MSecurity::Certificate);
server->set_resource_value(M2MSecurity::ServerPublicKey,this->m_options->getServerCertificate(),this->m_options->getServerCertificateSize());
server->set_resource_value(M2MSecurity::PublicKey,this->m_options->getClientCertificate(),this->m_options->getClientCertificateSize());
server->set_resource_value(M2MSecurity::Secretkey,this->m_options->getClientKey(),this->m_options->getClientKeySize());
}
return server;
}
// mbed-client: Callback from mbed client stack if any error is encountered
void Endpoint::error(M2MInterface::Error error) {
switch(error){
case M2MInterface::AlreadyExists:
DEBUG_OUT("[ERROR:] M2MInterface::AlreadyExists");
break;
case M2MInterface::BootstrapFailed:
DEBUG_OUT("[ERROR:] M2MInterface::BootstrapFailed");
break;
case M2MInterface::InvalidParameters:
DEBUG_OUT("[ERROR:] M2MInterface::InvalidParameters");
break;
case M2MInterface::NotRegistered:
DEBUG_OUT("[ERROR:] M2MInterface::NotRegistered");
break;
case M2MInterface::Timeout:
DEBUG_OUT("[ERROR:] M2MInterface::Timeout");
break;
case M2MInterface::NetworkError:
DEBUG_OUT("[ERROR:] M2MInterface::NetworkError");
break;
case M2MInterface::ResponseParseFailed:
DEBUG_OUT("[ERROR:] M2MInterface::ResponseParseFailed");
break;
case M2MInterface::UnknownError:
DEBUG_OUT("[ERROR:] M2MInterface::UnknownError");
break;
case M2MInterface::MemoryFail:
DEBUG_OUT("[ERROR:] M2MInterface::MemoryFail");
break;
case M2MInterface::NotAllowed:
DEBUG_OUT("[ERROR:] M2MInterface::NotAllowed");
break;
default:
break;
}
}
// register the endpoint
void Endpoint::register_endpoint(M2MSecurity *server_instance, M2MObjectList resources) {
if (this->m_interface != NULL && server_instance != NULL && resources.size() > 0) {
// register endpoint
this->logger()->log("Registering endpoint...");
this->m_interface->register_object(server_instance, resources);
}
}
// re-register the endpoint
void Endpoint::re_register_endpoint() {
if (this->m_interface != NULL) {
this->m_interface->update_registration(this->m_server_instance, this->m_options->getLifetime());
}
}
// de-register endpoint
void Endpoint::de_register_endpoint(void) {
if (this->m_interface != NULL) {
// de-register endpoint
this->logger()->log("De-registering endpoint...");
this->m_interface->unregister_object(NULL);
}
}
// object registered
void Endpoint::object_registered(M2MSecurity */*security_object */, const M2MServer &/*server_object*/) {
this->logger()->log("Endpoint registered");
this->m_connected = true;
this->m_registered = true;
}
// registration updated
void Endpoint::registration_updated(M2MSecurity */*security_object*/, const M2MServer &/*server_object*/) {
this->logger()->log("Endpoint re-registered.");
this->m_connected = true;
this->m_registered = true;
}
// object unregistered
void Endpoint::object_unregistered(M2MSecurity */*server_object*/) {
// ready to exit
this->logger()->log("Endpoint de-registered... Ready to exit...");
this->m_registered = false;
}
// bootstrap done
void Endpoint::bootstrap_done(M2MSecurity * /*server_object */) {
this->logger()->log("Bootstrapped");
}
// resource value updated
void Endpoint::value_updated(M2MBase *base, M2MBase::BaseType type) {
this->logger()->log("Value Updated");
DynamicResource *target_res = this->lookupDynamicResource(base);
target_res->process(base->operation(),type);
}
// lookup which DynamicResource cooresponds to a given M2MBase instance...
DynamicResource *Endpoint::lookupDynamicResource(M2MBase *base) {
DynamicResource *res = NULL;
bool found = false;
const DynamicResourcesList *dynamic_resources = this->m_options->getDynamicResourceList();
for(int i=0; i<(int)dynamic_resources->size() && found == false; ++i) {
M2MBase *t = dynamic_resources->at(i)->getResource();
if (t == base) {
res = dynamic_resources->at(i);
found = true;
}
}
return res;
}
// build out the endpoint
void Endpoint::build_endpoint()
{
// initialize as an mbed-client
this->create_interface();
// Create our server instance
this->m_server_instance = this->create_server_instance();
// Loop through Static Resources and bind each of them...
this->logger()->log("Endpoint::build(): adding device resources...");
const DeviceResourcesList *device_resources = this->m_options->getDeviceResourceList();
for(int i=0; i<(int)device_resources->size(); ++i) {
this->logger()->log("Endpoint::build(): binding device resource: [%s]...",device_resources->at(i)->getFullName().c_str());
this->m_object_list.push_back(device_resources->at(i)->bind(this));
}
// Loop through Static Resources and bind each of them...
this->logger()->log("Endpoint::build(): adding static resources...");
const StaticResourcesList *static_resources = this->m_options->getStaticResourceList();
for(int i=0; i<(int)static_resources->size(); ++i) {
this->logger()->log("Endpoint::build(): binding static resource: [%s]...",static_resources->at(i)->getFullName().c_str());
this->m_object_list.push_back(static_resources->at(i)->bind(this));
}
// Loop through Dynamic Resources and bind each of them...
this->logger()->log("Endpoint::build(): adding dynamic resources...");
const DynamicResourcesList *dynamic_resources = this->m_options->getDynamicResourceList();
for(int i=0; i<(int)dynamic_resources->size(); ++i) {
this->logger()->log("Endpoint::build(): binding dynamic resource: [%s]...",dynamic_resources->at(i)->getFullName().c_str());
this->m_object_list.push_back(dynamic_resources->at(i)->bind(this));
}
}
// underlying network is connected (SET)
void Endpoint::isConnected(bool connected) {
this->m_connected = connected;
}
// underlying network is connected (GET)
bool Endpoint::isConnected() {
return this->m_connected;
}
// Registered with mDC/mDS
bool Endpoint::isRegistered() {
return this->m_registered;
}
// our logger
Logger *Endpoint::logger()
{
return this->m_logger;
}
} // namespace Connector