Mayank Gupta / Mbed OS pelion-example-frdm

Dependencies:   FXAS21002 FXOS8700Q

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers m2mconnectionhandlerpimpl.cpp Source File

m2mconnectionhandlerpimpl.cpp

00001 /*
00002  * Copyright (c) 2015 - 2017 ARM Limited. All rights reserved.
00003  * SPDX-License-Identifier: Apache-2.0
00004  * Licensed under the Apache License, Version 2.0 (the License); you may
00005  * not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  * http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an AS IS BASIS, WITHOUT
00012  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 
00017 // fixup the compilation on ARMCC for PRIu32
00018 #define __STDC_FORMAT_MACROS
00019 #include <inttypes.h>
00020 
00021 #include "mbed-client-classic/m2mconnectionhandlerpimpl.h"
00022 #include "mbed-client/m2mconnectionobserver.h"
00023 #include "mbed-client/m2mconstants.h"
00024 #include "mbed-client/m2msecurity.h"
00025 #include "mbed-client/m2mconnectionhandler.h"
00026 
00027 #include "pal.h"
00028 
00029 #include "eventOS_scheduler.h"
00030 
00031 #include "eventOS_event_timer.h"
00032 
00033 #include "mbed-trace/mbed_trace.h"
00034 
00035 #include <stdlib.h> // free() and malloc()
00036 
00037 #define TRACE_GROUP "mClt"
00038 
00039 #ifndef MBED_CONF_MBED_CLIENT_TLS_MAX_RETRY
00040 #define MBED_CONF_MBED_CLIENT_TLS_MAX_RETRY 60
00041 #endif
00042 
00043 #if (PAL_DNS_API_VERSION == 1) && defined(TARGET_LIKE_MBED)
00044 #error "For async PAL DNS only API v2 or greater is supported on Mbed."
00045 #endif
00046 
00047 int8_t M2MConnectionHandlerPimpl::_tasklet_id = -1;
00048 
00049 // This is called from event loop, but as it is static C function, this is just a wrapper
00050 // which calls C++ on the instance.
00051 extern "C" void eventloop_event_handler(arm_event_s *event)
00052 {
00053     tr_debug("M2MConnectionHandlerPimpl::eventloop_event_handler %d", event->event_type);
00054     if (event->event_type != M2MConnectionHandlerPimpl::ESocketIdle) {
00055         if(!event->data_ptr) {
00056             tr_error("M2MConnectionHandlerPimpl::eventloop_event_handler event->data_ptr=NULL !!!!");
00057             assert(event->data_ptr);
00058         }
00059         M2MConnectionHandlerPimpl* instance = (M2MConnectionHandlerPimpl*)event->data_ptr;
00060         instance->event_handler(event);
00061     }
00062 }
00063 
00064 // event handler that forwards the event according to its type and/or connection state
00065 void M2MConnectionHandlerPimpl::event_handler(arm_event_s *event)
00066 {
00067     switch (event->event_type) {
00068 
00069         // Event from socket callback method
00070         case M2MConnectionHandlerPimpl::ESocketCallback:
00071         case M2MConnectionHandlerPimpl::ESocketTimerCallback:
00072 
00073             // this will enable sending more events during this event processing, but that is less evil than missing one
00074             _suppressable_event_in_flight = false;
00075 
00076             if (_socket_state == M2MConnectionHandlerPimpl::ESocketStateHandshaking) {
00077                 receive_handshake_handler();
00078             } else if ((_socket_state == M2MConnectionHandlerPimpl::ESocketStateUnsecureConnection) ||
00079                        (_socket_state == M2MConnectionHandlerPimpl::ESocketStateSecureConnection)) {
00080                 // the connection is established
00081                 receive_handler();
00082             } else {
00083                 socket_connect_handler();
00084             }
00085 
00086             // Receive processing could have changed state, so recheck
00087             if ((_socket_state == M2MConnectionHandlerPimpl::ESocketStateUnsecureConnection) ||
00088                 (_socket_state == M2MConnectionHandlerPimpl::ESocketStateSecureConnection)) {
00089                 // the connection is established
00090                 send_socket_data();
00091             }
00092             break;
00093 
00094         // Data send request from client side
00095         case M2MConnectionHandlerPimpl::ESocketSend:
00096             send_socket_data();
00097             break;
00098 
00099         // DNS resolved successfully
00100         case M2MConnectionHandlerPimpl::ESocketDnsResolved:
00101             handle_dns_result(true);
00102             break;
00103 
00104             // DNS resolving failed
00105         case M2MConnectionHandlerPimpl::ESocketDnsError:
00106             handle_dns_result(false);
00107             break;
00108 
00109         // Establish the connection by connecting the socket
00110         case M2MConnectionHandlerPimpl::ESocketConnect:
00111             socket_connect_handler();
00112             break;
00113 
00114         case M2MConnectionHandlerPimpl::ESocketClose:
00115             close_socket();
00116             break;
00117 
00118         default:
00119             tr_debug("M2MConnectionHandlerPimpl::connection_event_handler: default type: %d", (int)event->event_type);
00120             break;
00121     }
00122 }
00123 
00124 // This callback is used from PAL sockets, it is called with object instance as argument.
00125 // This is received from "some" socket event from "some" socket and the C++ side is responsible
00126 // of forwarding it or ignoring the event completely.
00127 extern "C" void socket_event_handler(void* arg)
00128 {
00129     M2MConnectionHandlerPimpl* instance = (M2MConnectionHandlerPimpl*)arg;
00130 
00131     if (!instance) {
00132         tr_error("Invalid callback argument");
00133         return;
00134     }
00135 
00136     instance->send_socket_event(M2MConnectionHandlerPimpl::ESocketCallback);
00137 }
00138 
00139 void M2MConnectionHandlerPimpl::send_socket_event(SocketEvent event_type)
00140 {
00141     // the socket callback events can safely be suppressed, the receiving end must tolerate that
00142     if (event_type == ESocketCallback) {
00143         // only the socket connected state supports retries somehow
00144         if (_suppressable_event_in_flight == false) {
00145             _suppressable_event_in_flight = true;
00146         } else {
00147             // XXX: DO NOT ADD FOLLOWING LINE TO OFFICIAL GIT, THIS WILL KILL SOME NETWORK STACKS
00148             // IF EVENT IS SENT FROM A INTERRUPT CONTEXT
00149             // tr_debug("** SKIPPING event");
00150             return;
00151         }
00152     }
00153 
00154     if (!send_event(event_type)) {
00155         // TODO: give a proper error based on state instead of this
00156         _observer.socket_error(M2MConnectionHandler::SOCKET_READ_ERROR, true);
00157     }
00158 }
00159 
00160 M2MConnectionHandlerPimpl::M2MConnectionHandlerPimpl(M2MConnectionHandler* base, M2MConnectionObserver &observer,
00161                                                      M2MConnectionSecurity* sec,
00162                                                      M2MInterface::BindingMode mode,
00163                                                      M2MInterface::NetworkStack stack)
00164 :_base(base),
00165  _observer(observer),
00166  _security_impl(sec),
00167  _security(NULL),
00168  _binding_mode(mode),
00169  _socket(0),
00170  _server_type(M2MConnectionObserver::LWM2MServer),
00171  _server_port(0),
00172  _listen_port(0),
00173  _net_iface(0),
00174 #if (PAL_DNS_API_VERSION == 0) || (PAL_DNS_API_VERSION == 1)
00175  _socket_address_len(0),
00176 #elif (PAL_DNS_API_VERSION == 2)
00177   _handler_async_DNS(0),
00178 #endif
00179  _socket_state(ESocketStateDisconnected),
00180  _handshake_retry(0),
00181  _suppressable_event_in_flight(false),
00182  _secure_connection(false)
00183 {
00184 #ifndef PAL_NET_TCP_AND_TLS_SUPPORT
00185     if (is_tcp_connection()) {
00186         tr_error("ConnectionHandler: TCP support not available.");
00187         return;
00188     }
00189 #endif
00190 
00191     if (PAL_SUCCESS != pal_init()) {
00192         tr_error("PAL init failed.");
00193     }
00194 
00195     memset(&_address, 0, sizeof _address);
00196     memset((void*)&_socket_address, 0, sizeof _socket_address);
00197     memset(&_ipV4Addr, 0, sizeof(palIpV4Addr_t));
00198     memset(&_ipV6Addr, 0, sizeof(palIpV6Addr_t));
00199     ns_list_init(&_linked_list_send_data);
00200 
00201     eventOS_scheduler_mutex_wait();
00202     if (M2MConnectionHandlerPimpl::_tasklet_id == -1) {
00203         M2MConnectionHandlerPimpl::_tasklet_id = eventOS_event_handler_create(&eventloop_event_handler, ESocketIdle);
00204     }
00205     eventOS_scheduler_mutex_release();
00206 }
00207 
00208 M2MConnectionHandlerPimpl::~M2MConnectionHandlerPimpl()
00209 {
00210     tr_debug("~M2MConnectionHandlerPimpl()");
00211 #if (PAL_DNS_API_VERSION == 2)
00212     if ( _handler_async_DNS > 0) {
00213         pal_cancelAddressInfoAsync(_handler_async_DNS);
00214     }
00215 #endif
00216 
00217     close_socket();
00218     delete _security_impl;
00219     _security_impl = NULL;
00220     pal_destroy();
00221     tr_debug("~M2MConnectionHandlerPimpl() - OUT");
00222 }
00223 
00224 bool M2MConnectionHandlerPimpl::bind_connection(const uint16_t listen_port)
00225 {
00226     _listen_port = listen_port;
00227     return true;
00228 }
00229 
00230 bool M2MConnectionHandlerPimpl::send_event(SocketEvent event_type)
00231 {
00232     arm_event_s event = {0};
00233 
00234     event.receiver = M2MConnectionHandlerPimpl::_tasklet_id;
00235     event.sender = 0;
00236     event.event_type = event_type;
00237     event.data_ptr = this;
00238     event.event_data = 0;
00239     event.priority = ARM_LIB_HIGH_PRIORITY_EVENT;
00240     return !eventOS_event_send(&event);
00241 }
00242 
00243 
00244 // This callback is used from PAL pal_getAddressInfoAsync,
00245 #if (PAL_DNS_API_VERSION == 2)
00246 extern "C" void address_resolver_cb(const char* url, palSocketAddress_t* address, palStatus_t status, void* callbackArgument)
00247 {
00248     tr_debug("M2MConnectionHandlerPimpl::address_resolver callback");
00249     M2MConnectionHandlerPimpl* instance = (M2MConnectionHandlerPimpl*)callbackArgument;
00250 
00251     if (PAL_SUCCESS != status) {
00252         tr_error("M2MConnectionHandlerPimpl::address_resolver callback failed with %" PRIx32, status);
00253         if (!(instance->send_event(M2MConnectionHandlerPimpl::ESocketDnsError))) {
00254             tr_error("M2MConnectionHandlerPimpl::address_resolver callback, error event alloc fail.");
00255         }
00256     } else {
00257         if (!(instance->send_event(M2MConnectionHandlerPimpl::ESocketDnsResolved))) {
00258             tr_error("M2MConnectionHandlerPimpl::address_resolver callback, resolved event alloc fail.");
00259         }
00260     }
00261 }
00262 #endif
00263 
00264 bool M2MConnectionHandlerPimpl::address_resolver(void)
00265 {
00266     palStatus_t status;
00267     bool ret = false;
00268 
00269 #if (PAL_DNS_API_VERSION == 2)
00270     tr_debug("M2MConnectionHandlerPimpl::address_resolver:asynchronous DNS");
00271     _handler_async_DNS = 0;
00272     status = pal_getAddressInfoAsync(_server_address.c_str(), (palSocketAddress_t*)&_socket_address, &address_resolver_cb, this, &_handler_async_DNS);
00273     if (PAL_SUCCESS != status) {
00274        tr_error("M2MConnectionHandlerPimpl::address_resolver, pal_getAddressInfoAsync fail. %" PRIx32, status);
00275        _observer.socket_error(M2MConnectionHandler::DNS_RESOLVING_ERROR);
00276     }
00277     else {
00278         ret = true;
00279     }
00280 #else // #if (PAL_DNS_API_VERSION == 0)
00281     tr_debug("M2MConnectionHandlerPimpl::address_resolver:synchronous DNS");
00282     status = pal_getAddressInfo(_server_address.c_str(), (palSocketAddress_t*)&_socket_address, &_socket_address_len);
00283     if (PAL_SUCCESS != status) {
00284         tr_error("M2MConnectionHandlerPimpl::getAddressInfo failed with %" PRIx32, status);
00285         if (!send_event(ESocketDnsError)) {
00286             tr_error("M2MConnectionHandlerPimpl::address_resolver, error event alloc fail.");
00287         }
00288     } else {
00289         if (!send_event(ESocketDnsResolved)) {
00290             tr_error("M2MConnectionHandlerPimpl::address_resolver, resolved event alloc fail.");
00291         }
00292         else {
00293             ret = true;
00294         }
00295     }
00296 #endif
00297     return ret;
00298 }
00299 
00300 void M2MConnectionHandlerPimpl::handle_dns_result(bool success)
00301 {
00302 #if (PAL_DNS_API_VERSION == 2)
00303     _handler_async_DNS = 0;
00304 #endif
00305     if (_socket_state != ESocketStateDNSResolving) {
00306         tr_warn("M2MConnectionHandlerPimpl::handle_dns_result() called, not in ESocketStateDNSResolving state!");
00307         return;
00308     }
00309 
00310     if (success) {
00311         _socket_state = EsocketStateInitializeConnection;
00312         socket_connect_handler();
00313 
00314     } else {
00315         _observer.socket_error(M2MConnectionHandler::DNS_RESOLVING_ERROR);
00316     }
00317 }
00318 
00319 bool M2MConnectionHandlerPimpl::resolve_server_address(const String& server_address,
00320                                                        const uint16_t server_port,
00321                                                        M2MConnectionObserver::ServerType server_type,
00322                                                        const M2MSecurity* security)
00323 {
00324 #if (PAL_DNS_API_VERSION == 2)
00325     if ( _handler_async_DNS > 0) {
00326         if (pal_cancelAddressInfoAsync(_handler_async_DNS) != PAL_SUCCESS) {
00327             return false;
00328         }
00329     }
00330 #endif
00331     _socket_state = ESocketStateDNSResolving;
00332     _security = security;
00333 
00334     int32_t security_instance_id = _security->get_security_instance_id(M2MSecurity::M2MServer);
00335     if (server_type == M2MConnectionObserver::Bootstrap) {
00336         security_instance_id = _security->get_security_instance_id(M2MSecurity::Bootstrap);
00337     }
00338 
00339     if (_security &&
00340         security_instance_id >= 0 &&
00341         (_security->resource_value_int(M2MSecurity::SecurityMode, security_instance_id) == M2MSecurity::Certificate ||
00342          _security->resource_value_int(M2MSecurity::SecurityMode, security_instance_id) == M2MSecurity::Psk)) {
00343         _secure_connection = true;
00344     }
00345 
00346     _server_port = server_port;
00347     _server_type = server_type;
00348     _server_address = server_address;
00349 
00350 
00351     return address_resolver();
00352 }
00353 
00354 void M2MConnectionHandlerPimpl::socket_connect_handler()
00355 {
00356     palStatus_t status;
00357     int32_t security_instance_id = _security->get_security_instance_id(M2MSecurity::M2MServer);
00358     if (_server_type == M2MConnectionObserver::Bootstrap) {
00359         security_instance_id = _security->get_security_instance_id(M2MSecurity::Bootstrap);
00360     }
00361 
00362     tr_debug("M2MConnectionHandlerPimpl::socket_connect_handler - _socket_state = %d", _socket_state);
00363 
00364     switch (_socket_state) {
00365         case ESocketStateCloseBeingCalled:
00366         case ESocketStateDNSResolving:
00367         case ESocketStateDisconnected:
00368         case ESocketStateHandshaking:
00369         case ESocketStateUnsecureConnection:
00370         case ESocketStateSecureConnection:
00371             // Ignore these events
00372             break;
00373 
00374         case EsocketStateInitializeConnection:
00375 
00376             // Initialize the socket to stable state
00377             close_socket();
00378 
00379             status = pal_setSockAddrPort((palSocketAddress_t*)&_socket_address, _server_port);
00380 
00381             if (PAL_SUCCESS != status) {
00382                 tr_error("M2MConnectionHandlerPimpl::socket_connect_handler - setSockAddrPort err: %" PRIx32, status);
00383             } else {
00384                 tr_debug("address family: %d", (int)_socket_address.addressType);
00385             }
00386 
00387             if (_socket_address.addressType == PAL_AF_INET) {
00388                 status = pal_getSockAddrIPV4Addr((palSocketAddress_t*)&_socket_address,_ipV4Addr);
00389                 if (PAL_SUCCESS != status) {
00390                     tr_error("M2MConnectionHandlerPimpl::socket_connect_handler - sockAddr4, err: %" PRIx32, status);
00391                     _observer.socket_error(M2MConnectionHandler::DNS_RESOLVING_ERROR);
00392                     return;
00393                 }
00394 
00395                 tr_info("M2MConnectionHandlerPimpl::socket_connect_handler - IPv4 Address %d.%d.%d.%d",
00396                         _ipV4Addr[0], _ipV4Addr[1], _ipV4Addr[2], _ipV4Addr[3]);
00397 
00398                 _address._address = (void*)_ipV4Addr;
00399                 _address._length = PAL_IPV4_ADDRESS_SIZE;
00400                 _address._port = _server_port;
00401             } else if (_socket_address.addressType == PAL_AF_INET6) {
00402                 status = pal_getSockAddrIPV6Addr((palSocketAddress_t*)&_socket_address,_ipV6Addr);
00403                 if (PAL_SUCCESS != status) {
00404                     tr_error("M2MConnectionHandlerPimpl::socket_connect_handler - sockAddr6, err: %" PRIx32, status);
00405                     _observer.socket_error(M2MConnectionHandler::DNS_RESOLVING_ERROR);
00406                     return;
00407                 }
00408 
00409                 tr_info("M2MConnectionHandlerPimpl::socket_connect_handler - IPv6 Address: %s", mbed_trace_ipv6(_ipV6Addr));
00410 
00411                 _address._address = (void*)_ipV6Addr;
00412                 _address._length = PAL_IPV6_ADDRESS_SIZE;
00413                 _address._port = _server_port;
00414             } else {
00415                 tr_error("M2MConnectionHandlerPimpl::socket_connect_handler - socket config error, stack: %d", (int)_socket_address.addressType);
00416                 _observer.socket_error(M2MConnectionHandler::SOCKET_ABORT);
00417                 return;
00418             }
00419 
00420             if (!init_socket()) {
00421                 tr_error("M2MConnectionHandlerPimpl::socket_connect_handler - socket init error");
00422                 // The init_socket() calls the socket_error() -callback directly, so it must not be
00423                 // done here too.
00424                 return;
00425             }
00426 
00427             // This state was used to ignore the spurious events _during_ the call of non-blocking pal_connect().
00428             // Now that we just retry connect when it is not yet succeeded anyway this state might be removed completely.
00429             _socket_state = ESocketStateConnectBeingCalled;
00430 
00431         // fall through is intentional
00432         case ESocketStateConnectBeingCalled:
00433         case ESocketStateConnecting:
00434             if (is_tcp_connection()) {
00435 #ifdef PAL_NET_TCP_AND_TLS_SUPPORT
00436                 tr_info("M2MConnectionHandlerPimpl::socket_connect_handler - Using TCP");
00437 
00438                 status = pal_connect(_socket, (palSocketAddress_t*)&_socket_address, sizeof(_socket_address));
00439 
00440                 if ((status == PAL_ERR_SOCKET_IN_PROGRES ) || (status == PAL_ERR_SOCKET_WOULD_BLOCK )) {
00441                     // In this case the connect is done asynchronously, and the pal_socketMiniSelect()
00442                     // will be used to detect the end of connect.
00443                     tr_debug("M2MConnectionHandlerPimpl::socket_connect_handler - pal_connect(): %" PRIx32 ", async connect started", status);
00444                     // we need to wait for the event
00445                     _socket_state = ESocketStateConnecting;
00446                     break;
00447 
00448                 } else if (status == PAL_SUCCESS || status == PAL_ERR_SOCKET_ALREADY_CONNECTED ) {
00449 
00450                     tr_debug("M2MConnectionHandlerPimpl::socket_connect_handler - pal_connect(): success");
00451                     _socket_state = ESocketStateConnected;
00452 
00453                 } else {
00454                     tr_error("M2MConnectionHandlerPimpl::socket_connect_handler - pal_connect(): failed: %" PRIx32, status);
00455                     close_socket();
00456                     _observer.socket_error(M2MConnectionHandler::SOCKET_ABORT);
00457                     return;
00458                 }
00459 #else
00460                 tr_error("socket_connect_handler() - TCP not configured"
00461 #endif //PAL_NET_TCP_AND_TLS_SUPPORT
00462             } else {
00463                 tr_info("M2MConnectionHandlerPimpl::socket_connect_handler - Using UDP");
00464                 _socket_state = ESocketStateConnected;
00465             }
00466 
00467         // fall through is a normal flow in case the UDP was used or pal_connect() happened to return immediately with PAL_SUCCESS
00468         case ESocketStateConnected:
00469             if (_security && security_instance_id >= 0) {
00470                 if (_secure_connection) {
00471                     if ( _security_impl != NULL ) {
00472                         _security_impl->reset();
00473                         int ret_code = _security_impl->init(_security, security_instance_id);
00474                         if (ret_code == M2MConnectionHandler::ERROR_NONE) {
00475                             // Initiate handshake. Perhaps there could be a separate event type for this?
00476                             _socket_state = ESocketStateHandshaking;
00477                             send_socket_event(ESocketCallback);
00478                         } else {
00479                             tr_error("M2MConnectionHandlerPimpl::socket_connect_handler - init failed");
00480                             close_socket();
00481 
00482                             if (ret_code == M2MConnectionHandler::FAILED_TO_READ_CREDENTIALS) {
00483                                 _observer.socket_error(M2MConnectionHandler::FAILED_TO_READ_CREDENTIALS, false);
00484                             } else {
00485                                 _observer.socket_error(M2MConnectionHandler::SSL_CONNECTION_ERROR, true);
00486                             }
00487 
00488                             return;
00489                         }
00490                     } else {
00491                         tr_error("M2MConnectionHandlerPimpl::socket_connect_handler - sec is null");
00492                         close_socket();
00493                         _observer.socket_error(M2MConnectionHandler::SSL_CONNECTION_ERROR, true);
00494                         return;
00495                     }
00496                 }
00497             }
00498             if (_socket_state != ESocketStateHandshaking) {
00499                 _socket_state = ESocketStateUnsecureConnection;
00500                 _observer.address_ready(_address,
00501                                         _server_type,
00502                                         _address._port);
00503             }
00504             break;
00505 
00506     }
00507 }
00508 
00509 bool M2MConnectionHandlerPimpl::send_data(uint8_t *data,
00510                                           uint16_t data_len,
00511                                           sn_nsdl_addr_s *address)
00512 {
00513     if (address == NULL || data == NULL || !data_len || _socket_state < ESocketStateUnsecureConnection) {
00514         tr_warn("M2MConnectionHandlerPimpl::send_data() - too early");
00515         return false;
00516     }
00517 
00518     send_data_queue_s* out_data = (send_data_queue_s*)malloc(sizeof(send_data_queue_s));
00519     if (!out_data) {
00520         return false;
00521     }
00522 
00523     memset(out_data, 0, sizeof(send_data_queue_s));
00524 
00525     uint8_t offset = 0;
00526 #ifdef PAL_NET_TCP_AND_TLS_SUPPORT
00527     if (is_tcp_connection() && !_secure_connection ) {
00528         offset = 4;
00529     }
00530 #endif
00531 
00532     out_data->data = (uint8_t*)malloc(data_len + offset);
00533     if (!out_data->data) {
00534         free(out_data);
00535         return false;
00536     }
00537 
00538     // TCP non-secure
00539     // We need to "shim" the length in front
00540 #ifdef PAL_NET_TCP_AND_TLS_SUPPORT
00541     if (is_tcp_connection() && !_secure_connection ) {
00542         out_data->data[0] = 0;
00543         out_data->data[1] = 0;
00544         out_data->data[2] = (data_len >> 8 ) & 0xff;
00545         out_data->data[3] = data_len & 0xff;
00546     }
00547 #endif //PAL_NET_TCP_AND_TLS_SUPPORT
00548 
00549     memcpy(out_data->data + offset, data, data_len);
00550     out_data->data_len = data_len + offset;
00551 
00552     claim_mutex();
00553     ns_list_add_to_end(&_linked_list_send_data, out_data);
00554     release_mutex();
00555 
00556     if (!send_event(ESocketSend)) {
00557         // Event push failed, free the buffer
00558         claim_mutex();
00559         ns_list_remove(&_linked_list_send_data, out_data);
00560         release_mutex();
00561         free(out_data->data);
00562         free(out_data);
00563         return false;
00564     }
00565 
00566     return true;
00567 }
00568 
00569 void M2MConnectionHandlerPimpl::send_socket_data()
00570 {
00571     tr_debug("M2MConnectionHandlerPimpl::send_socket_data()");
00572     int bytes_sent = 0;
00573     bool success = true;
00574 
00575     send_data_queue_s* out_data = get_item_from_list();
00576     if (!out_data) {
00577         return;
00578     }
00579 
00580     if (!out_data->data || !out_data->data_len || _socket_state < ESocketStateUnsecureConnection) {
00581         tr_warn("M2MConnectionHandlerPimpl::send_socket_data() - too early");
00582         add_item_to_list(out_data);
00583         return;
00584     }
00585 
00586     // Loop until all the data is sent
00587     for (; out_data->offset < out_data->data_len; out_data->offset += bytes_sent) {
00588         // Secure send
00589         if (_socket_state == ESocketStateSecureConnection) {
00590             // TODO! Change the send_message API to take bytes_sent as a out param like the pal send API's.
00591             while ((bytes_sent = _security_impl->send_message(out_data->data + out_data->offset,
00592                                                             out_data->data_len - out_data->offset)) <= 0) {
00593                 if (bytes_sent == M2MConnectionHandler::CONNECTION_ERROR_WANTS_WRITE) {
00594                     // Return and wait the next event
00595                     add_item_to_list(out_data);
00596                     return;
00597                 }
00598 
00599                 if (bytes_sent != M2MConnectionHandler::CONNECTION_ERROR_WANTS_READ) {
00600                     tr_error("M2MConnectionHandlerPimpl::send_socket_data() - secure, failed %d", bytes_sent);
00601                     success = false;
00602                     break;
00603                 }
00604             }
00605             if (!success) {
00606                 break;
00607             }
00608         }
00609         // Unsecure send
00610         else {
00611             bytes_sent = 0;
00612             palStatus_t ret;
00613             if (is_tcp_connection()) {
00614 #ifdef PAL_NET_TCP_AND_TLS_SUPPORT
00615                 ret = pal_send(_socket,
00616                                out_data->data + out_data->offset,
00617                                out_data->data_len - out_data->offset,
00618                                (size_t*)&bytes_sent);
00619 #endif
00620             } else {
00621                 ret = pal_sendTo(_socket,
00622                                  out_data->data + out_data->offset,
00623                                  out_data->data_len - out_data->offset,
00624                                  (palSocketAddress_t*)&_socket_address,
00625                                  sizeof(_socket_address),
00626                                  (size_t*)&bytes_sent);
00627             }
00628             if (ret == PAL_ERR_SOCKET_WOULD_BLOCK ) {
00629                 // Return and wait next event
00630                 add_item_to_list(out_data);
00631                 return;
00632             }
00633             if (ret < 0) {
00634                 tr_error("M2MConnectionHandlerPimpl::send_socket_data() - unsecure failed %" PRIx32, ret);
00635                 success = false;
00636                 break;
00637             }
00638         }
00639     }
00640 
00641     free(out_data->data);
00642     free(out_data);
00643 
00644     if (!success) {
00645         if (bytes_sent == M2MConnectionHandler::SSL_PEER_CLOSE_NOTIFY) {
00646             _observer.socket_error(M2MConnectionHandler::SSL_PEER_CLOSE_NOTIFY, true);
00647         } else if (bytes_sent == M2MConnectionHandler::MEMORY_ALLOCATION_FAILED) {
00648             tr_error("M2MConnectionHandlerPimpl::send_socket_data() - memory allocation failed!");
00649             _handshake_retry = 0;
00650             _observer.socket_error(M2MConnectionHandler::MEMORY_ALLOCATION_FAILED, false);
00651         } else {
00652             tr_error("M2MConnectionHandlerPimpl::send_socket_data() - SOCKET_SEND_ERROR");
00653             _observer.socket_error(M2MConnectionHandler::SOCKET_SEND_ERROR, true);
00654         }
00655         close_socket();
00656     } else {
00657         _observer.data_sent();
00658     }
00659 }
00660 
00661 bool M2MConnectionHandlerPimpl::start_listening_for_data()
00662 {
00663     return true;
00664 }
00665 
00666 void M2MConnectionHandlerPimpl::stop_listening()
00667 {
00668     // Do not call close_socket() directly here.
00669     // This can be called from multiple locations.
00670     send_socket_event(ESocketClose);
00671 }
00672 
00673 void M2MConnectionHandlerPimpl::handle_connection_error(int error)
00674 {
00675     tr_error("M2MConnectionHandlerPimpl::handle_connection_error - error %d", error);
00676     _observer.socket_error(error);
00677 }
00678 
00679 void M2MConnectionHandlerPimpl::set_platform_network_handler(void *handler)
00680 {
00681     tr_debug("M2MConnectionHandlerPimpl::set_platform_network_handler");
00682 
00683     if (PAL_SUCCESS != pal_registerNetworkInterface(handler, &_net_iface)) {
00684         tr_error("M2MConnectionHandlerPimpl::set_platform_network_handler - Interface registration failed.");
00685     }
00686     tr_debug("M2MConnectionHandlerPimpl::set_platform_network_handler - index = %d", _net_iface);
00687 }
00688 
00689 void M2MConnectionHandlerPimpl::receive_handshake_handler()
00690 {
00691     int return_value;
00692     tr_debug("M2MConnectionHandlerPimpl::receive_handshake_handler()");
00693 
00694     // assert(_socket_state == ESocketStateHandshaking);
00695 
00696     return_value = _security_impl->connect(_base);
00697 
00698     if (return_value == M2MConnectionHandler::ERROR_NONE) {
00699 
00700         _handshake_retry = 0;
00701         _socket_state = ESocketStateSecureConnection;
00702         _observer.address_ready(_address,
00703                                 _server_type,
00704                                 _server_port);
00705 
00706     } else if (return_value == M2MConnectionHandler::SSL_PEER_CLOSE_NOTIFY) {
00707         _handshake_retry = 0;
00708         _observer.socket_error(M2MConnectionHandler::SSL_PEER_CLOSE_NOTIFY, true);
00709         close_socket();
00710 
00711     } else if (return_value == M2MConnectionHandler::MEMORY_ALLOCATION_FAILED) {
00712 
00713         tr_error("M2MConnectionHandlerPimpl::receive_handshake_handler() - memory allocation failed");
00714         _handshake_retry = 0;
00715         _observer.socket_error(M2MConnectionHandler::MEMORY_ALLOCATION_FAILED, false);
00716         close_socket();
00717 
00718     } else if (return_value != M2MConnectionHandler::CONNECTION_ERROR_WANTS_READ) {
00719 
00720         tr_error("M2MConnectionHandlerPimpl::receive_handshake_handler() - SSL_HANDSHAKE_ERROR");
00721         _handshake_retry = 0;
00722         _observer.socket_error(M2MConnectionHandler::SSL_HANDSHAKE_ERROR, true);
00723         close_socket();
00724 
00725     } else {
00726         // Comes here only if error is M2MConnectionHandler::ERROR_GENERIC
00727         if (_handshake_retry++ > MBED_CONF_MBED_CLIENT_TLS_MAX_RETRY) {
00728 
00729             tr_error("M2MConnectionHandlerPimpl::receive_handshake_handler() - Max TLS retry fail");
00730             _handshake_retry = 0;
00731             _observer.socket_error(M2MConnectionHandler::SOCKET_ABORT, true);
00732             close_socket();
00733 
00734         }
00735         eventOS_event_timer_cancel(ESocketTimerCallback, M2MConnectionHandlerPimpl::_tasklet_id);
00736 
00737         // There is required to set event.data_ptr for eventloop_event_handler.
00738         arm_event_s event = {0};
00739         event.receiver = M2MConnectionHandlerPimpl::_tasklet_id;
00740         event.sender = 0;
00741         event.event_id = ESocketTimerCallback;
00742         event.event_type = ESocketTimerCallback;
00743         event.data_ptr = this;
00744         event.event_data = 0;
00745         event.priority = ARM_LIB_HIGH_PRIORITY_EVENT;
00746         eventOS_event_timer_request_in(&event, eventOS_event_timer_ms_to_ticks(1000));
00747     }
00748 }
00749 
00750 bool M2MConnectionHandlerPimpl::is_handshake_ongoing() const
00751 {
00752     return (_socket_state == ESocketStateHandshaking);
00753 }
00754 
00755 void M2MConnectionHandlerPimpl::receive_handler()
00756 {
00757     // assert(_socket_state > ESocketStateHandshaking);
00758 
00759     if (_socket_state == ESocketStateSecureConnection) {
00760 
00761         int rcv_size;
00762         unsigned char recv_buffer[BUFFER_LENGTH];
00763 
00764         // we need to read as much as there is data available as the events may or may not be suppressed
00765         do {
00766             tr_debug("M2MConnectionHandlerPimpl::receive_handler()..");
00767             rcv_size = _security_impl->read(recv_buffer, sizeof(recv_buffer));
00768             tr_debug("M2MConnectionHandlerPimpl::receive_handler() res: %d", rcv_size);
00769             if (rcv_size > 0) {
00770                 _observer.data_available((uint8_t*)recv_buffer,
00771                                          rcv_size, _address);
00772 
00773             } else if (M2MConnectionHandler::SSL_PEER_CLOSE_NOTIFY == rcv_size) {
00774                 tr_error("M2MConnectionHandlerPimpl::receive_handler() - peer close notify!");
00775                 _observer.socket_error(M2MConnectionHandler::SSL_PEER_CLOSE_NOTIFY, true);
00776                 return;
00777 
00778             } else if (M2MConnectionHandler::MEMORY_ALLOCATION_FAILED == rcv_size) {
00779                 tr_error("M2MConnectionHandlerPimpl::receive_handler() - memory allocation failed!");
00780                 _observer.socket_error(M2MConnectionHandler::MEMORY_ALLOCATION_FAILED, false);
00781                 close_socket();
00782                 return;
00783 
00784             } else if (M2MConnectionHandler::ERROR_GENERIC == rcv_size) {
00785                 tr_error("M2MConnectionHandlerPimpl::receive_handler() - secure ERROR_GENERIC");
00786                 _observer.socket_error(M2MConnectionHandler::SOCKET_READ_ERROR, true);
00787                 close_socket();
00788                 return;
00789             }
00790         } while (rcv_size > 0 && _socket_state == ESocketStateSecureConnection);
00791 
00792     } else {
00793         size_t recv;
00794         palStatus_t status;
00795         unsigned char recv_buffer[BUFFER_LENGTH];
00796         do {
00797             if (is_tcp_connection()) {
00798 #ifdef PAL_NET_TCP_AND_TLS_SUPPORT
00799                 status = pal_recv(_socket, recv_buffer, sizeof(recv_buffer), &recv);
00800 #endif //PAL_NET_TCP_AND_TLS_SUPPORT
00801             } else {
00802                 status = pal_receiveFrom(_socket, recv_buffer, sizeof(recv_buffer), NULL, NULL, &recv);
00803             }
00804 
00805             if (status == PAL_ERR_SOCKET_WOULD_BLOCK ) {
00806                 return;
00807             } else if (status != PAL_SUCCESS) {
00808                 tr_error("M2MConnectionHandlerPimpl::receive_handler() - SOCKET_READ_ERROR %" PRIx32, status);
00809                 _observer.socket_error(M2MConnectionHandler::SOCKET_READ_ERROR, true);
00810                 close_socket();
00811                 return;
00812             }
00813 
00814             tr_debug("M2MConnectionHandlerPimpl::receive_handler() - data received, len: %zu", recv);
00815 
00816             if (!is_tcp_connection()) { // Observer for UDP plain mode
00817                 _observer.data_available((uint8_t*)recv_buffer, recv, _address);
00818             } else {
00819 #ifdef PAL_NET_TCP_AND_TLS_SUPPORT
00820                 if ( recv < 4 ) {
00821                     tr_error("M2MConnectionHandlerPimpl::receive_handler() - TCP SOCKET_READ_ERROR");
00822                     _observer.socket_error(M2MConnectionHandler::SOCKET_READ_ERROR, true);
00823                     close_socket();
00824                     return;
00825                 }
00826 
00827                 //We need to "shim" out the length from the front
00828                 uint32_t len = (recv_buffer[0] << 24 & 0xFF000000) + (recv_buffer[1] << 16 & 0xFF0000);
00829                 len += (recv_buffer[2] << 8 & 0xFF00) + (recv_buffer[3] & 0xFF);
00830                 if (len > 0 && len <= recv - 4) {
00831                     // Observer for TCP plain mode
00832                     _observer.data_available(recv_buffer + 4, len, _address);
00833                 }
00834 #endif //PAL_NET_TCP_AND_TLS_SUPPORT
00835             }
00836         } while (recv > 0 && _socket_state == ESocketStateUnsecureConnection);
00837     }
00838 }
00839 
00840 void M2MConnectionHandlerPimpl::claim_mutex()
00841 {
00842     eventOS_scheduler_mutex_wait();
00843 }
00844 
00845 void M2MConnectionHandlerPimpl::release_mutex()
00846 {
00847     eventOS_scheduler_mutex_release();
00848 }
00849 
00850 bool M2MConnectionHandlerPimpl::init_socket()
00851 {
00852     palSocketType_t socket_type = PAL_SOCK_DGRAM;
00853     palStatus_t status;
00854     palSocketAddress_t bind_address;
00855     palIpV4Addr_t interface_address4;
00856     palIpV6Addr_t interface_address6;
00857 
00858     memset(&bind_address, 0, sizeof(palSocketAddress_t));
00859     memset(&interface_address4, 0, sizeof(interface_address4));
00860     memset(&interface_address6, 0, sizeof(interface_address6));
00861 
00862     if (is_tcp_connection()) {
00863 #ifdef PAL_NET_TCP_AND_TLS_SUPPORT
00864         socket_type = PAL_SOCK_STREAM;
00865 #else
00866         // Somebody has built code without TCP support but tries to use it.
00867         // Perhaps a "assert(false)" would be sufficient.
00868         tr_error("M2MConnectionHandlerPimpl::init_socket() - TCP config error");
00869         _observer.socket_error(M2MConnectionHandler::SOCKET_ABORT);
00870         return;
00871 #endif //PAL_NET_TCP_AND_TLS_SUPPORT
00872     }
00873     status = pal_asynchronousSocketWithArgument((palSocketDomain_t)_socket_address.addressType,
00874                                                 socket_type, true, _net_iface, &socket_event_handler,
00875                                                 this, &_socket);
00876 
00877     if (PAL_SUCCESS != status) {
00878         tr_error("M2MConnectionHandlerPimpl::init_socket() - socket create error : %" PRIx32, status);
00879         _observer.socket_error(M2MConnectionHandler::SOCKET_ABORT);
00880         return false;
00881     }
00882 
00883     if (_socket_address.addressType == PAL_AF_INET) {
00884         status = pal_setSockAddrIPV4Addr(&bind_address, interface_address4);
00885     } else if (_socket_address.addressType == PAL_AF_INET6) {
00886         status = pal_setSockAddrIPV6Addr(&bind_address, interface_address6);
00887     } else {
00888         tr_warn("M2MConnectionHandlerPimpl::init_socket() - stack type: %d", (int)_socket_address.addressType);
00889     }
00890     if (PAL_SUCCESS != status) {
00891         tr_error("M2MConnectionHandlerPimpl::init_socket - setSockAddrIPV err: %" PRIx32, status);
00892         return false;
00893     }
00894     status = pal_setSockAddrPort(&bind_address, _listen_port);
00895     if (PAL_SUCCESS != status) {
00896         tr_error("M2MConnectionHandlerPimpl::init_socket - setSockAddrPort err: %" PRIx32, status);
00897         return false;
00898     }
00899     pal_bind(_socket, &bind_address, sizeof(bind_address));
00900 
00901     _security_impl->set_socket(_socket, (palSocketAddress_t*)&_socket_address);
00902 
00903     return true;
00904 }
00905 
00906 bool M2MConnectionHandlerPimpl::is_tcp_connection() const
00907 {
00908     return ( _binding_mode == M2MInterface::TCP ||
00909              _binding_mode == M2MInterface::TCP_QUEUE );
00910 }
00911 
00912 void M2MConnectionHandlerPimpl::close_socket()
00913 {
00914     _suppressable_event_in_flight = false;
00915 
00916     if (_socket) {
00917         // At least on mbed-os the pal_close() will perform callbacks even during it
00918         // is called, which we will ignore when this state is set.
00919         _socket_state = ESocketStateCloseBeingCalled;
00920         pal_close(&_socket);
00921         _socket = 0;
00922     }
00923 
00924     // make sure the socket connection statemachine is reset too.
00925     _socket_state = ESocketStateDisconnected;
00926 
00927     if (_security_impl) {
00928         _security_impl->reset();
00929     }
00930 
00931     claim_mutex();
00932     /*ns_list_foreach_safe(M2MConnectionHandlerPimpl::send_data_queue_s, tmp, &_linked_list_send_data) {
00933         ns_list_remove(&_linked_list_send_data, tmp);
00934         free(tmp->data);
00935         free(tmp);
00936     }*/
00937     // Workaround for IAR compilation issue. ns_list_foreach does not compile with IAR.
00938     // Error[Pe144]: a value of type "void *" cannot be used to initialize an entity of type "M2MConnectionHandlerPimpl::send_data_queue *"
00939     while (!ns_list_is_empty(&_linked_list_send_data)) {
00940         send_data_queue_s* data = (send_data_queue_s*)ns_list_get_first(&_linked_list_send_data);
00941         ns_list_remove(&_linked_list_send_data, data);
00942         free(data->data);
00943         free(data);
00944     }
00945     release_mutex();
00946 }
00947 
00948 M2MConnectionHandlerPimpl::send_data_queue_s* M2MConnectionHandlerPimpl::get_item_from_list()
00949 {
00950     claim_mutex();
00951     send_data_queue_s* out_data = (send_data_queue_s*)ns_list_get_first(&_linked_list_send_data);
00952     if (out_data) {
00953         ns_list_remove(&_linked_list_send_data, out_data);
00954     }
00955     release_mutex();
00956     return out_data;
00957 }
00958 
00959 void M2MConnectionHandlerPimpl::add_item_to_list(M2MConnectionHandlerPimpl::send_data_queue_s *data)
00960 {
00961     claim_mutex();
00962     ns_list_add_to_start(&_linked_list_send_data, data);
00963     release_mutex();
00964 }
00965 
00966 void M2MConnectionHandlerPimpl::force_close()
00967 {
00968     close_socket();
00969 }
00970 
00971 void M2MConnectionHandlerPimpl::unregister_network_handler()
00972 {
00973     pal_unregisterNetworkInterface(_net_iface);
00974 }