sandbox / mbed-client-classic

Fork of mbed-client-classic by Christopher Haster

source/m2mconnectionhandlerpimpl.cpp

Committer:
Yogesh Pande
Date:
2016-04-02
Revision:
8:bdd418027540
Parent:
7:774e507fc261
Child:
9:17cb48fbeb85

File content as of revision 8:bdd418027540:

/*
 * 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 "mbed-client-classic/m2mconnectionhandlerpimpl.h"
#include "mbed-client/m2mconnectionobserver.h"
#include "mbed-client/m2mconstants.h"
#include "mbed-client/m2msecurity.h"
#include "mbed-client/m2mconnectionhandler.h"

#include "m2mnetwork.h"
#include "threadwrapper.h"
#include "mbed_error.h"

#include "NetworkInterface.h"
#include "UDPSocket.h"
#include "mbed-trace/mbed_trace.h"

#define TRACE_GROUP "mClt"

M2MConnectionHandlerPimpl::M2MConnectionHandlerPimpl(M2MConnectionHandler* base, M2MConnectionObserver &observer,
                                                     M2MConnectionSecurity* sec,
                                                     M2MInterface::BindingMode mode,
                                                     M2MInterface::NetworkStack stack)
:_base(base),
 _observer(observer),
 _security_impl(sec),
 _use_secure_connection(false),
 _binding_mode(mode),
 _network_stack(stack),
 _socket(0),
 _listening(false),
 _listen_thread(0)
{
    memset(&_address_buffer, 0, sizeof _address_buffer);
    memset(&_address, 0, sizeof _address);
    _address._address = _address_buffer;

    if (_network_stack != M2MInterface::LwIP_IPv4) {
        error("ConnectionHandler: Unsupported network stack, only IPv4 is currently supported");
    }
}

M2MConnectionHandlerPimpl::~M2MConnectionHandlerPimpl()
{
    _listening = false;

    if (_listen_thread) {
        delete _listen_thread;
        _listen_thread = 0;
    }
    if (_socket) {
        delete _socket;
        _socket = 0;
    }

    delete _security_impl;
}

bool M2MConnectionHandlerPimpl::bind_connection(const uint16_t /*listen_port*/)
{
    return true;
}

bool M2MConnectionHandlerPimpl::resolve_server_address(const String& server_address,
                                                       const uint16_t server_port,
                                                       M2MConnectionObserver::ServerType server_type,
                                                       const M2MSecurity* security)
{
    bool success = false;
    NetworkInterface *iface = M2MNetwork::getInterface();
    if (!iface) {
        return false;
    }

    if (_socket) {
        delete _socket;
    }

    _socket = new UDPSocket(iface);
    if (_socket->open(server_address.c_str(), server_port) < 0) {
        return false;
    } else {
        success = true;
    }

    if (security) {
        if (security->resource_value_int(M2MSecurity::SecurityMode) == M2MSecurity::Certificate ||
            security->resource_value_int(M2MSecurity::SecurityMode) == M2MSecurity::Psk) {
            if( _security_impl != NULL ){
                _security_impl->reset();
                _security_impl->init(security);
                tr_debug("M2MConnectionHandlerPimpl::resolve_server_address - connect DTLS");
                success = 0 == _security_impl->connect(_base);
                if( success ) {
                    _use_secure_connection = true;
                }
            }
        }
    }
    if(success) {
        _address._address = (void*)_socket->getIPAddress();
        _address._length = strlen((char*)_address._address);
        _address._port = _socket->getPort();
        _address._stack = _network_stack;

        _observer.address_ready(_address,
                                server_type,
                                _address._port);
    }
    return success;
}

bool M2MConnectionHandlerPimpl::send_data(uint8_t *data,
                                          uint16_t data_len,
                                          sn_nsdl_addr_s *address)
{
    tr_debug("M2MConnectionHandlerPimpl::send_data");
    if (address == NULL || data == NULL) {
        return false;
    }

    bool success = false;
    if(data){
        if( _use_secure_connection ){
            if( _security_impl->send_message(data, data_len) > 0){
                success = true;
                _observer.data_sent();
            }else{
                _observer.socket_error(1);
            }
        } else {
            if(address) {
                ssize_t ret = -1;

                ret = _socket->send(data, data_len);

                if (ret==-1) {
                    //tr_debug("M2MConnectionHandlerPimpl::send_data - Error Code is %d\n",errno);
                    _observer.socket_error(1);
                } else {
                     success = true;
                    _observer.data_sent();
                }
            } else {
                //TODO: Define memory fail error code
                _observer.socket_error(3);
            }
        }
    }
    return success;
}

bool M2MConnectionHandlerPimpl::start_listening_for_data()
{
    _listening = true;
    _listen_thread = rtos::create_thread<
        M2MConnectionHandlerPimpl,
        &M2MConnectionHandlerPimpl::listen_handler>(this);
    return true;
}

void M2MConnectionHandlerPimpl::stop_listening()
{
    _listening = false;
}

void M2MConnectionHandlerPimpl::listen_handler()
{
    tr_debug("M2MConnectionHandlerPimpl::listen_handler");
    memset(_recv_buffer, 0, sizeof(_recv_buffer));
    int rcv_size = -1;

    if (_use_secure_connection) {
        while(_listening){
             rcv_size = _security_impl->read(_recv_buffer, sizeof(_recv_buffer));
            if(rcv_size > 0) {
                _observer.data_available(_recv_buffer, rcv_size, _address);
            }
            else if(rcv_size == 0){
                //We are in initializing phase, so do nothing
            }
            else{
                _listening = false;
                _observer.socket_error(1);
            }
            memset(_recv_buffer, 0, sizeof(_recv_buffer));
        }
    } else {
        while(_listening) {
            int rcv_size = _socket->recv((char*)_recv_buffer, sizeof _recv_buffer, true);
            if (rcv_size == -1) {
               //TODO: Define receive error code
                _observer.socket_error(2);
                _listening = false;
            }

            /* If message received.. */
            if(rcv_size > 0) {
                _observer.data_available(_recv_buffer,rcv_size,_address);
            }
            memset(_recv_buffer, 0, sizeof(_recv_buffer));
        }
    }
}

int M2MConnectionHandlerPimpl::send_to_socket(const unsigned char *buf, size_t len)
{
    tr_debug("M2MConnectionHandlerPimpl::send_to_socket len - %d", len);
    int size = _socket->send(buf,len);
    tr_debug("M2MConnectionHandlerPimpl::send_to_socket size - %d", size);
    return size;
}

int M2MConnectionHandlerPimpl::receive_from_socket(unsigned char *buf, size_t len)
{
    tr_debug("M2MConnectionHandlerPimpl::receive_from_socket - blocking call");
    return _socket->recv(buf, len);
}

void M2MConnectionHandlerPimpl::handle_connection_error(int /*error*/)
{
    tr_debug("M2MConnectionHandlerPimpl::handle_connection_error");
    _observer.socket_error(4);
}