Ram Gandikota
/
ABCD
A metronome using the FRDM K64F board
mbed-client/mbed-client-classic/source/m2mconnectionhandlerpimpl.cpp
- Committer:
- ram54288
- Date:
- 2017-05-14
- Revision:
- 0:a7a43371b306
File content as of revision 0:a7a43371b306:
/* * 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 "pal.h" #include "pal_rtos.h" #include "pal_errors.h" #include "pal_macros.h" #include "pal_network.h" #include "eventOS_scheduler.h" #include "eventOS_event.h" #include "mbed-trace/mbed_trace.h" #include "mbed.h" #define TRACE_GROUP "mClt" int8_t M2MConnectionHandlerPimpl::_tasklet_id = -1; static M2MConnectionHandlerPimpl *connection_handler = NULL; extern "C" void connection_event_handler(arm_event_s *event) { if(!connection_handler){ return; } switch(event->event_type){ case M2MConnectionHandlerPimpl::ESocketReadytoRead: connection_handler->receive_handler(); break; case M2MConnectionHandlerPimpl::ESocketSend: connection_handler->send_socket_data((uint8_t*)event->data_ptr, event->event_data); free(event->data_ptr); break; case M2MConnectionHandlerPimpl::ESocketDnsHandler: connection_handler->dns_handler(); break; default: break; } } void M2MConnectionHandlerPimpl::send_receive_event(void) { arm_event_s event; event.receiver = M2MConnectionHandlerPimpl::_tasklet_id; event.sender = 0; event.event_type = ESocketReadytoRead; event.data_ptr = NULL; event.priority = ARM_LIB_HIGH_PRIORITY_EVENT; eventOS_event_send(&event); } extern "C" void socket_event_handler(void) { if(!connection_handler) { return; } connection_handler->send_receive_event(); } M2MConnectionHandlerPimpl::M2MConnectionHandlerPimpl(M2MConnectionHandler* base, M2MConnectionObserver &observer, M2MConnectionSecurity* sec, M2MInterface::BindingMode mode, M2MInterface::NetworkStack stack) :_base(base), _observer(observer), _security_impl(sec), _security(NULL), _use_secure_connection(false), _binding_mode(mode), _network_stack(stack), _socket(0), _is_handshaking(false), _listening(true), _server_type(M2MConnectionObserver::LWM2MServer), _server_port(0), _listen_port(0), _running(false), _net_iface(0) { #ifndef PAL_NET_TCP_AND_TLS_SUPPORT if (is_tcp_connection()) { tr_error("ConnectionHandler: TCP support not available."); return; } #endif if(PAL_SUCCESS != pal_init()){ tr_error("PAL init failed."); } memset(&_address, 0, sizeof _address); memset(&_socket_address, 0, sizeof _socket_address); connection_handler = this; eventOS_scheduler_mutex_wait(); if (M2MConnectionHandlerPimpl::_tasklet_id == -1) { M2MConnectionHandlerPimpl::_tasklet_id = eventOS_event_handler_create(&connection_event_handler, ESocketIdle); } eventOS_scheduler_mutex_release(); } M2MConnectionHandlerPimpl::~M2MConnectionHandlerPimpl() { tr_debug("~M2MConnectionHandlerPimpl()"); stop_listening(); close_socket(); delete _security_impl; tr_debug("~M2MConnectionHandlerPimpl() - OUT"); } bool M2MConnectionHandlerPimpl::bind_connection(const uint16_t listen_port) { _listen_port = 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) { arm_event_s event; tr_debug("resolve_server_address()"); _security = security; _server_port = server_port; _server_type = server_type; _server_address = server_address; event.receiver = M2MConnectionHandlerPimpl::_tasklet_id; event.sender = 0; event.event_type = ESocketDnsHandler; event.data_ptr = NULL; event.priority = ARM_LIB_HIGH_PRIORITY_EVENT; return !eventOS_event_send(&event); } void M2MConnectionHandlerPimpl::dns_handler() { palStatus_t status; uint32_t interface_count; status = pal_getNumberOfNetInterfaces(&interface_count); if(PAL_SUCCESS != status ) { _observer.socket_error(M2MConnectionHandler::SOCKET_ABORT); return; } if(interface_count <= 0) { _observer.socket_error(M2MConnectionHandler::SOCKET_ABORT); return; } palSocketLength_t _socket_address_len; if(PAL_SUCCESS != pal_getAddressInfo(_server_address.c_str(), &_socket_address, &_socket_address_len)){ _observer.socket_error(M2MConnectionHandler::SOCKET_ABORT); return; } pal_setSockAddrPort(&_socket_address, _server_port); if(_network_stack == M2MInterface::LwIP_IPv4 || _network_stack == M2MInterface::ATWINC_IPv4){ if(PAL_SUCCESS != pal_getSockAddrIPV4Addr(&_socket_address,_ipV4Addr)){ _observer.socket_error(M2MConnectionHandler::SOCKET_ABORT); return; } tr_debug("IP Address %s",tr_array(_ipV4Addr, 4)); _address._address = (void*)_ipV4Addr; _address._length = PAL_IPV4_ADDRESS_SIZE; _address._port = _server_port; _address._stack = _network_stack; } else if(_network_stack == M2MInterface::LwIP_IPv6 || _network_stack == M2MInterface::Nanostack_IPv6){ if(PAL_SUCCESS != pal_getSockAddrIPV6Addr(&_socket_address,_ipV6Addr)){ _observer.socket_error(M2MConnectionHandler::SOCKET_ABORT); return; } tr_debug("IP Address %s",tr_array(_ipV6Addr,sizeof(_ipV6Addr))); _address._address = (void*)_ipV6Addr; _address._length = PAL_IPV6_ADDRESS_SIZE; _address._port = _server_port; _address._stack = _network_stack; } else { tr_error("socket config error, %d", (int)_network_stack); _observer.socket_error(M2MConnectionHandler::SOCKET_ABORT); return; } close_socket(); if(!init_socket()) { _observer.socket_error(M2MConnectionHandler::SOCKET_ABORT); return; } if(is_tcp_connection()) { #ifdef PAL_NET_TCP_AND_TLS_SUPPORT tr_debug("resolve_server_address - Using TCP"); if (pal_connect(_socket, &_socket_address, sizeof(_socket_address)) != PAL_SUCCESS) { _observer.socket_error(M2MConnectionHandler::SOCKET_ABORT); return; } #endif //PAL_NET_TCP_AND_TLS_SUPPORT } _running = 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(); if (_security_impl->init(_security) == 0) { _is_handshaking = true; tr_debug("resolve_server_address - connect DTLS"); if(_security_impl->start_connecting_non_blocking(_base) < 0 ){ tr_debug("dns_handler - handshake failed"); _is_handshaking = false; _observer.socket_error(M2MConnectionHandler::SSL_CONNECTION_ERROR); close_socket(); return; } } else { tr_error("resolve_server_address - init failed"); _observer.socket_error(M2MConnectionHandler::SSL_CONNECTION_ERROR, false); close_socket(); return; } } else { tr_error("dns_handler - sec is null"); _observer.socket_error(M2MConnectionHandler::SSL_CONNECTION_ERROR, false); close_socket(); return; } } } if(!_is_handshaking) { enable_keepalive(); _observer.address_ready(_address, _server_type, _address._port); } } bool M2MConnectionHandlerPimpl::send_data(uint8_t *data, uint16_t data_len, sn_nsdl_addr_s *address) { arm_event_s event; tr_debug("send_data()"); if (address == NULL || data == NULL || !data_len || !_running) { return false; } event.data_ptr = (uint8_t*)malloc(data_len); if(!event.data_ptr) { return false; } memcpy(event.data_ptr, data, data_len); event.receiver = M2MConnectionHandlerPimpl::_tasklet_id; event.sender = 0; event.event_type = ESocketSend; event.event_data = data_len; event.priority = ARM_LIB_HIGH_PRIORITY_EVENT; if (eventOS_event_send(&event) != 0) { // Event push failed, free the buffer free(event.data_ptr); return false; } return true; } void M2MConnectionHandlerPimpl::send_socket_data(uint8_t *data, uint16_t data_len) { size_t sent_len; bool success = false; palStatus_t ret = PAL_ERR_GENERIC_FAILURE; if(!data || ! data_len || !_running) { return; } tr_debug("send_handler()"); if( _use_secure_connection ){ if( _security_impl->send_message(data, data_len) > 0){ success = true; } } else { if(is_tcp_connection()){ #ifdef PAL_NET_TCP_AND_TLS_SUPPORT //We need to "shim" the length in front uint8_t* d = (uint8_t*)malloc(data_len+4); if(d){ d[0] = 0; d[1] = 0; d[2] = (data_len >> 8 )& 0xff; d[3] = data_len & 0xff; memcpy(d + 4, data, data_len); ret = pal_send(_socket, d, data_len+4, &sent_len); free(d); } #endif //PAL_NET_TCP_AND_TLS_SUPPORT } else { ret = pal_sendTo(_socket, data, data_len, &_socket_address, sizeof(_socket_address), &sent_len); } if (ret == PAL_SUCCESS) { success = true; } } if (!success) { _observer.socket_error(M2MConnectionHandler::SOCKET_SEND_ERROR, true); close_socket(); } else{ _observer.data_sent(); } } bool M2MConnectionHandlerPimpl::start_listening_for_data() { tr_debug("start_listening_for_data()"); _listening = true; return true; } void M2MConnectionHandlerPimpl::stop_listening() { tr_debug("stop_listening()"); _listening = false; if(_security_impl) { _security_impl->reset(); } } int M2MConnectionHandlerPimpl::send_to_socket(const unsigned char *buf, size_t len) { size_t sent_len = 0; palStatus_t status = PAL_ERR_GENERIC_FAILURE; if(!_running) { return (-1); } tr_debug("send_to_socket len - %d", len); if(is_tcp_connection()) { #ifdef PAL_NET_TCP_AND_TLS_SUPPORT status = pal_send(_socket, buf, len, &sent_len); #endif //PAL_NET_TCP_AND_TLS_SUPPORT } else { status = pal_sendTo(_socket, buf, len, &_socket_address, sizeof(_socket_address), &sent_len); } if(status == PAL_SUCCESS){ return sent_len; } return (-1); } int M2MConnectionHandlerPimpl::receive_from_socket(unsigned char *buf, size_t len) { size_t recv_len; palStatus_t status = PAL_ERR_GENERIC_FAILURE; tr_debug("receive_from_socket"); if(!_running) { return (-1); } if(is_tcp_connection()) { #ifdef PAL_NET_TCP_AND_TLS_SUPPORT status = pal_recv(_socket, buf, len, &recv_len); #endif //PAL_NET_TCP_AND_TLS_SUPPORT } else { status = pal_receiveFrom(_socket, buf, len, NULL, NULL, &recv_len); } if(status == PAL_SUCCESS){ return recv_len; } else if(status == PAL_ERR_SOCKET_WOULD_BLOCK || status == (-65536)){ return M2MConnectionHandler::CONNECTION_ERROR_WANTS_READ; } else { tr_info("PAL Socket returned: %d", status); } return (-1); } void M2MConnectionHandlerPimpl::handle_connection_error(int error) { tr_debug("handle_connection_error"); _observer.socket_error(error); } void M2MConnectionHandlerPimpl::set_platform_network_handler(void *handler) { tr_debug("set_platform_network_handler"); if(PAL_SUCCESS != pal_registerNetworkInterface(handler, &_net_iface)) { tr_error("Interface registration failed."); } } void M2MConnectionHandlerPimpl::receive_handshake_handler() { tr_debug("receive_handshake_handler()"); if( _is_handshaking ){ int ret = _security_impl->continue_connecting(); tr_debug("ret %d", ret); if( ret == M2MConnectionHandler::CONNECTION_ERROR_WANTS_READ ){ //We wait for next readable event tr_debug("We wait for next readable event"); return; } else if( ret == 0 ){ _is_handshaking = false; _use_secure_connection = true; enable_keepalive(); _observer.address_ready(_address, _server_type, _server_port); } else if( ret < 0 ){ _is_handshaking = false; _observer.socket_error(M2MConnectionHandler::SSL_CONNECTION_ERROR, true); close_socket(); } } } bool M2MConnectionHandlerPimpl::is_handshake_ongoing() { return _is_handshaking; } void M2MConnectionHandlerPimpl::receive_handler() { tr_debug("receive_handler()"); if(_is_handshaking){ receive_handshake_handler(); return; } if(!_listening || !_running) { return; } if( _use_secure_connection ){ int rcv_size; do{ rcv_size = _security_impl->read(_recv_buffer, sizeof(_recv_buffer)); if(rcv_size > 0){ _observer.data_available((uint8_t*)_recv_buffer, rcv_size, _address); } else if (M2MConnectionHandler::CONNECTION_ERROR_WANTS_READ != rcv_size && rcv_size < 0) { _observer.socket_error(M2MConnectionHandler::SOCKET_READ_ERROR, true); close_socket(); return; } } while(M2MConnectionHandler::CONNECTION_ERROR_WANTS_READ != rcv_size); } else{ size_t recv; palStatus_t status; do{ if(is_tcp_connection()){ #ifdef PAL_NET_TCP_AND_TLS_SUPPORT status = pal_recv(_socket, _recv_buffer, sizeof(_recv_buffer), &recv); #endif //PAL_NET_TCP_AND_TLS_SUPPORT } else{ status = pal_receiveFrom(_socket, _recv_buffer, sizeof(_recv_buffer), NULL, NULL, &recv); } if(status == PAL_ERR_SOCKET_WOULD_BLOCK){ return; } else if (status != PAL_SUCCESS) { _observer.socket_error(M2MConnectionHandler::SOCKET_READ_ERROR, true); close_socket(); return; } tr_debug("data received, len: %zu", recv); if(!is_tcp_connection()){ // Observer for UDP plain mode _observer.data_available((uint8_t*)_recv_buffer, recv, _address); } else { #ifdef PAL_NET_TCP_AND_TLS_SUPPORT if( recv < 4 ){ _observer.socket_error(M2MConnectionHandler::SOCKET_READ_ERROR, true); close_socket(); return; } //We need to "shim" out the length from the front uint32_t len = (_recv_buffer[0] << 24 & 0xFF000000) + (_recv_buffer[1] << 16 & 0xFF0000); len += (_recv_buffer[2] << 8 & 0xFF00) + (_recv_buffer[3] & 0xFF); if(len > 0 && len <= recv - 4) { // Observer for TCP plain mode _observer.data_available(_recv_buffer + 4, len, _address); } #endif //PAL_NET_TCP_AND_TLS_SUPPORT } } while(status != PAL_ERR_SOCKET_WOULD_BLOCK); } } void M2MConnectionHandlerPimpl::claim_mutex() { eventOS_scheduler_mutex_wait(); } void M2MConnectionHandlerPimpl::release_mutex() { eventOS_scheduler_mutex_release(); } static palNetInterfaceInfo_t interface_info; static palIpV4Addr_t interface_address4 = {0,0,0,0}; static palIpV6Addr_t interface_address6 = {0}; bool M2MConnectionHandlerPimpl::init_socket() { tr_debug("init_socket - IN"); _is_handshaking = false; _running = true; palSocketType_t socket_type = PAL_SOCK_DGRAM; palStatus_t status; palSocketDomain_t domain; palSocketAddress_t bind_address; if(is_tcp_connection()) { #ifdef PAL_NET_TCP_AND_TLS_SUPPORT socket_type = PAL_SOCK_STREAM; #else _observer.socket_error(M2MConnectionHandler::SOCKET_ABORT); return; #endif //PAL_NET_TCP_AND_TLS_SUPPORT } if(_network_stack == M2MInterface::LwIP_IPv4){ domain = PAL_AF_INET; } else if(_network_stack == M2MInterface::LwIP_IPv6){ domain = PAL_AF_INET6; } else { domain = PAL_AF_UNSPEC; } uint32_t interface_count; pal_getNumberOfNetInterfaces(&interface_count); tr_debug("Interface count: %d",interface_count); pal_getNetInterfaceInfo(_net_iface, &interface_info); tr_debug("Interface name: %s",interface_info.interfaceName); tr_debug("Interface no: %d", _net_iface); tr_debug("init_socket - port %d", _listen_port); status = pal_asynchronousSocket(domain, socket_type, 1, _net_iface, &socket_event_handler, &_socket); if(PAL_SUCCESS != status) { _observer.socket_error(M2MConnectionHandler::SOCKET_ABORT); return false; } if(_network_stack == M2MInterface::LwIP_IPv4){ pal_setSockAddrIPV4Addr(&bind_address, interface_address4); } else if(_network_stack == M2MInterface::LwIP_IPv6){ pal_setSockAddrIPV6Addr(&bind_address, interface_address6); } pal_setSockAddrPort(&bind_address, _listen_port); pal_bind(_socket, &bind_address, sizeof(bind_address)); tr_debug("init_socket - OUT"); return true; } bool M2MConnectionHandlerPimpl::is_tcp_connection() { return ( _binding_mode == M2MInterface::TCP || _binding_mode == M2MInterface::TCP_QUEUE ); } void M2MConnectionHandlerPimpl::close_socket() { tr_debug("close_socket() - IN"); if(_running) { _running = false; pal_close(&_socket); } tr_debug("close_socket() - OUT"); } void M2MConnectionHandlerPimpl::enable_keepalive() { #if MBED_CLIENT_TCP_KEEPALIVE_TIME #ifdef PAL_NET_TCP_AND_TLS_SUPPORT if(is_tcp_connection()) { int enable = 1; pal_setSocketOptions(_socket, PAL_SO_KEEPALIVE, &enable, sizeof(enable)); } #endif #endif }