This is a fork due to permission issues
Dependencies: mbed Socket lwip-eth lwip-sys lwip
Fork of 6_songs-from-the-cloud by
Diff: mbed-client/mbed-client-classic/source/m2mconnectionhandlerpimpl.cpp
- Revision:
- 0:f7c60d3e7b8a
diff -r 000000000000 -r f7c60d3e7b8a mbed-client/mbed-client-classic/source/m2mconnectionhandlerpimpl.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed-client/mbed-client-classic/source/m2mconnectionhandlerpimpl.cpp Wed May 18 19:06:32 2016 +0000 @@ -0,0 +1,253 @@ +/* + * 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 "Socket/TCPSocketConnection.h" +#include "Socket/UDPSocket.h" +#include "threadwrapper.h" +#include "mbed_error.h" + + +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), + _resolved(true), + _is_handshaking(false), + _listening(false), + _listen_thread(0), + _recv_thread(0), + _send_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"); + } + + if (_binding_mode == M2MInterface::TCP || + _binding_mode == M2MInterface::TCP_QUEUE) { + error("ConnectionHandler: Unsupported binding mode, only UDP based modes are currently supported"); + } + + _running = true; + _recv_thread = rtos::create_thread< + M2MConnectionHandlerPimpl, + &M2MConnectionHandlerPimpl::recv_handler>(this, osPriorityAboveNormal); + _send_thread = rtos::create_thread< + M2MConnectionHandlerPimpl, + &M2MConnectionHandlerPimpl::send_handler>(this); + _listen_thread = rtos::create_thread< + M2MConnectionHandlerPimpl, + &M2MConnectionHandlerPimpl::listen_handler>(this); +} + +M2MConnectionHandlerPimpl::~M2MConnectionHandlerPimpl() +{ + _listening = false; + _running = false; + + if (_listen_thread) { + delete _listen_thread; + _listen_thread = 0; + } + + if (_recv_thread) { + delete _recv_thread; + _recv_thread = 0; + } + + if (_send_thread) { + delete _send_thread; + _send_thread = 0; + } + + delete _security_impl; +} + +bool M2MConnectionHandlerPimpl::bind_connection(const uint16_t listen_port) +{ + return !(_socket.bind(listen_port) < 0); +} + +bool M2MConnectionHandlerPimpl::resolve_server_address(const String& server_address, + const uint16_t server_port, + M2MConnectionObserver::ServerType server_type, + const M2MSecurity* security) +{ + if (_endpoint.set_address(server_address.c_str(), server_port) < 0) { + return false; + } + + inet_aton(_endpoint.get_address(), _address._address); + _address._port = _endpoint.get_port(); + _address._length = 4; + _address._stack = _network_stack; + + 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); + + if (_security_impl->connect(_base) < 0) { + return false; + } + + _use_secure_connection = true; + } + } + } + + _observer.address_ready(_address, + server_type, + _address._port); + + return true; +} + + +void M2MConnectionHandlerPimpl::recv_handler() +{ + while (_running) { + Endpoint recv_endpoint; + int size = _socket.receiveFrom(recv_endpoint, + (char*)_recv_buffer, sizeof _recv_buffer); + + if (size > 0) { + _recv_queue.put(new std::string(_recv_buffer, _recv_buffer+size)); + } else { + rtos::Thread::wait(1000); + } + } +} + +void M2MConnectionHandlerPimpl::send_handler() +{ + while (_running) { + osEvent e = _send_queue.get(); + if (e.status == osEventMessage) { + std::string *packet = (std::string*)e.value.p; + int size = _socket.sendTo(_endpoint, (char*)packet->data(), packet->size()); + delete packet; + } else { + rtos::Thread::wait(1000); + } + } +} + +bool M2MConnectionHandlerPimpl::send_data(uint8_t *data, + uint16_t data_len, + sn_nsdl_addr_s *address) +{ + if (address == NULL || data == NULL) { + return false; + } + + if (_use_secure_connection) { + if (_security_impl->send_message(data, data_len) < 0) { + return false; + } + } else { + if (send_to_socket(data, data_len) < 0) { + return false; + } + } + + _observer.data_sent(); + return true; +} + +bool M2MConnectionHandlerPimpl::start_listening_for_data() +{ + _listening = true; + return true; +} + +void M2MConnectionHandlerPimpl::stop_listening() +{ + _listening = false; +} + +void M2MConnectionHandlerPimpl::listen_handler() +{ + while (_running) { + if (_listening) { + memset(_listen_buffer, 0, sizeof _listen_buffer); + int size; + + if (_use_secure_connection) { + size = _security_impl->read(_listen_buffer, sizeof _listen_buffer); + } else { + size = receive_from_socket(_listen_buffer, sizeof _listen_buffer); + } + + if (size > 0) { + _observer.data_available((uint8_t*)_listen_buffer, size, _address); + } else if (size != 0) { + _listening = false; + _observer.socket_error(2); + } + } else { + rtos::Thread::wait(1000); + } + } +} + + +int M2MConnectionHandlerPimpl::send_to_socket(const unsigned char *buf, size_t len) +{ + if (_send_queue.put(new std::string(buf, buf+len)) != osOK) { + return M2MConnectionHandler::CONNECTION_ERROR_WANTS_WRITE; + } else { + return len; + } +} + +int M2MConnectionHandlerPimpl::receive_from_socket(unsigned char *buf, size_t len) +{ + osEvent e = _recv_queue.get(); + if (e.status == osEventMessage) { + std::string *packet = (std::string*)e.value.p; + int size = packet->size(); + + if (size <= len) { + memcpy(buf, packet->data(), size); + delete packet; + return size; + } + } + + return M2MConnectionHandler::CONNECTION_ERROR_WANTS_READ; +} + +void M2MConnectionHandlerPimpl::handle_connection_error(int /*error*/) +{ + _observer.socket_error(4); +}