Simulated product dispenser

Dependencies:   HTS221

Fork of mbed-cloud-workshop-connect-HTS221 by Jim Carver

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 #ifndef MBED_CONF_MBED_CLIENT_DNS_USE_THREAD
00044 #define MBED_CONF_MBED_CLIENT_DNS_USE_THREAD 0
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 == 2)
00175   _handler_async_DNS(0),
00176 #endif
00177  _socket_state(ESocketStateDisconnected),
00178  _handshake_retry(0),
00179  _suppressable_event_in_flight(false),
00180  _secure_connection(false)
00181 #if (PAL_DNS_API_VERSION < 2)
00182  ,_socket_address_len(0)
00183 #endif
00184 {
00185 #ifndef PAL_NET_TCP_AND_TLS_SUPPORT
00186     if (is_tcp_connection()) {
00187         tr_error("ConnectionHandler: TCP support not available.");
00188         return;
00189     }
00190 #endif
00191 
00192     if (PAL_SUCCESS != pal_init()) {
00193         tr_error("PAL init failed.");
00194     }
00195 
00196     memset(&_address, 0, sizeof _address);
00197     memset((void*)&_socket_address, 0, sizeof _socket_address);
00198     memset(&_ipV4Addr, 0, sizeof(palIpV4Addr_t));
00199     memset(&_ipV6Addr, 0, sizeof(palIpV6Addr_t));
00200     ns_list_init(&_linked_list_send_data);
00201 
00202     eventOS_scheduler_mutex_wait();
00203     if (M2MConnectionHandlerPimpl::_tasklet_id == -1) {
00204         M2MConnectionHandlerPimpl::_tasklet_id = eventOS_event_handler_create(&eventloop_event_handler, ESocketIdle);
00205     }
00206     eventOS_scheduler_mutex_release();
00207 }
00208 
00209 M2MConnectionHandlerPimpl::~M2MConnectionHandlerPimpl()
00210 {
00211     tr_debug("~M2MConnectionHandlerPimpl()");
00212 #if MBED_CONF_MBED_CLIENT_DNS_USE_THREAD
00213 #if (PAL_DNS_API_VERSION == 2)
00214     if ( _handler_async_DNS > 0) {
00215         pal_cancelAddressInfoAsync(_handler_async_DNS);
00216     }
00217 #endif
00218 #endif
00219 
00220     close_socket();
00221     delete _security_impl;
00222     _security_impl = NULL;
00223     pal_destroy();
00224     tr_debug("~M2MConnectionHandlerPimpl() - OUT");
00225 }
00226 
00227 bool M2MConnectionHandlerPimpl::bind_connection(const uint16_t listen_port)
00228 {
00229     _listen_port = listen_port;
00230     return true;
00231 }
00232 
00233 bool M2MConnectionHandlerPimpl::send_event(SocketEvent event_type)
00234 {
00235     arm_event_s event = {0};
00236 
00237     event.receiver = M2MConnectionHandlerPimpl::_tasklet_id;
00238     event.sender = 0;
00239     event.event_type = event_type;
00240     event.data_ptr = this;
00241     event.event_data = 0;
00242     event.priority = ARM_LIB_HIGH_PRIORITY_EVENT;
00243     return !eventOS_event_send(&event);
00244 }
00245 
00246 // This callback is used from PAL pal_getAddressInfoAsync,
00247 #if MBED_CONF_MBED_CLIENT_DNS_USE_THREAD
00248 #if (PAL_DNS_API_VERSION < 2)
00249 extern "C" void address_resolver_cb(const char* url, palSocketAddress_t* address, palSocketLength_t* addressLength, palStatus_t status, void* callbackArgument)
00250 #else
00251 extern "C" void address_resolver_cb(const char* url, palSocketAddress_t* address, palStatus_t status, void* callbackArgument)
00252 #endif
00253 {
00254     tr_debug("M2MConnectionHandlerPimpl::address_resolver callback");
00255     M2MConnectionHandlerPimpl* instance = (M2MConnectionHandlerPimpl*)callbackArgument;
00256 
00257     if (PAL_SUCCESS != status) {
00258         tr_error("M2MConnectionHandlerPimpl::address_resolver callback failed with 0x%X", status);
00259         if (!(instance->send_event(M2MConnectionHandlerPimpl::ESocketDnsError))) {
00260             tr_error("M2MConnectionHandlerPimpl::address_resolver callback, error event alloc fail.");
00261         }
00262     } else {
00263         if (!(instance->send_event(M2MConnectionHandlerPimpl::ESocketDnsResolved))) {
00264             tr_error("M2MConnectionHandlerPimpl::address_resolver callback, resolved event alloc fail.");
00265         }
00266     }
00267 }
00268 #endif
00269 
00270 bool M2MConnectionHandlerPimpl::address_resolver(void)
00271 {
00272     palStatus_t status;
00273     bool ret = false;
00274 
00275 #if MBED_CONF_MBED_CLIENT_DNS_USE_THREAD
00276     tr_debug("M2MConnectionHandlerPimpl::address_resolver:asynchronous DNS");
00277 
00278 #if (PAL_DNS_API_VERSION < 2)
00279     status = pal_getAddressInfoAsync(_server_address.c_str(), (palSocketAddress_t*)&_socket_address, &_socket_address_len, &address_resolver_cb, this);
00280 #else
00281     _handler_async_DNS = 0;
00282     status = pal_getAddressInfoAsync(_server_address.c_str(), (palSocketAddress_t*)&_socket_address, &address_resolver_cb, this, &_handler_async_DNS);
00283 #endif
00284     if (PAL_SUCCESS != status) {
00285        tr_error("M2MConnectionHandlerPimpl::address_resolver, pal_getAddressInfoAsync fail. 0x%X", status);
00286        _observer.socket_error(M2MConnectionHandler::DNS_RESOLVING_ERROR);
00287     }
00288     else {
00289         ret = true;
00290     }
00291 #else
00292     tr_debug("M2MConnectionHandlerPimpl::address_resolver:synchronous DNS");
00293     status = pal_getAddressInfo(_server_address.c_str(), (palSocketAddress_t*)&_socket_address, &_socket_address_len);
00294     if (PAL_SUCCESS != status) {
00295         tr_error("M2MConnectionHandlerPimpl::getAddressInfo failed with 0x%X", status);
00296         if (!send_event(ESocketDnsError)) {
00297             tr_error("M2MConnectionHandlerPimpl::address_resolver, error event alloc fail.");
00298         }
00299     } else {
00300         if (!send_event(ESocketDnsResolved)) {
00301             tr_error("M2MConnectionHandlerPimpl::address_resolver, resolved event alloc fail.");
00302         }
00303         else {
00304             ret = true;
00305         }
00306     }
00307 #endif
00308     return ret;
00309 }
00310 
00311 void M2MConnectionHandlerPimpl::handle_dns_result(bool success)
00312 {
00313 #if MBED_CONF_MBED_CLIENT_DNS_USE_THREAD
00314 #if (PAL_DNS_API_VERSION == 2)
00315     _handler_async_DNS = 0;
00316 #endif
00317 #endif
00318     if (_socket_state != ESocketStateDNSResolving) {
00319         tr_warn("M2MConnectionHandlerPimpl::handle_dns_result() called, not in ESocketStateDNSResolving state!");
00320         return;
00321     }
00322 
00323     if (success) {
00324         _socket_state = EsocketStateInitializeConnection;
00325         socket_connect_handler();
00326 
00327     } else {
00328         _observer.socket_error(M2MConnectionHandler::DNS_RESOLVING_ERROR);
00329     }
00330 }
00331 
00332 bool M2MConnectionHandlerPimpl::resolve_server_address(const String& server_address,
00333                                                        const uint16_t server_port,
00334                                                        M2MConnectionObserver::ServerType server_type,
00335                                                        const M2MSecurity* security)
00336 {
00337 #if MBED_CONF_MBED_CLIENT_DNS_USE_THREAD
00338 #if (PAL_DNS_API_VERSION == 2)
00339     if ( _handler_async_DNS > 0) {
00340         if (pal_cancelAddressInfoAsync(_handler_async_DNS) != PAL_SUCCESS) {
00341             return false;
00342         }
00343     }
00344 #endif
00345 #endif
00346     _socket_state = ESocketStateDNSResolving;
00347     _security = security;
00348 
00349     int32_t security_instance_id = _security->get_security_instance_id(M2MSecurity::M2MServer);
00350     if (server_type == M2MConnectionObserver::Bootstrap) {
00351         security_instance_id = _security->get_security_instance_id(M2MSecurity::Bootstrap);
00352     }
00353 
00354     if (_security &&
00355         security_instance_id >= 0 &&
00356         (_security->resource_value_int(M2MSecurity::SecurityMode, security_instance_id) == M2MSecurity::Certificate ||
00357          _security->resource_value_int(M2MSecurity::SecurityMode, security_instance_id) == M2MSecurity::Psk)) {
00358         _secure_connection = true;
00359     }
00360 
00361     _server_port = server_port;
00362     _server_type = server_type;
00363     _server_address = server_address;
00364 
00365 
00366     return address_resolver();
00367 }
00368 
00369 void M2MConnectionHandlerPimpl::socket_connect_handler()
00370 {
00371     palStatus_t status;
00372     int32_t security_instance_id = _security->get_security_instance_id(M2MSecurity::M2MServer);
00373     if (_server_type == M2MConnectionObserver::Bootstrap) {
00374         security_instance_id = _security->get_security_instance_id(M2MSecurity::Bootstrap);
00375     }
00376 
00377     tr_debug("M2MConnectionHandlerPimpl::socket_connect_handler - _socket_state = %d", _socket_state);
00378 
00379     switch (_socket_state) {
00380         case ESocketStateCloseBeingCalled:
00381         case ESocketStateDNSResolving:
00382         case ESocketStateDisconnected:
00383         case ESocketStateHandshaking:
00384         case ESocketStateUnsecureConnection:
00385         case ESocketStateSecureConnection:
00386             // Ignore these events
00387             break;
00388 
00389         case EsocketStateInitializeConnection:
00390 
00391             // Initialize the socket to stable state
00392             close_socket();
00393 
00394             status = pal_setSockAddrPort((palSocketAddress_t*)&_socket_address, _server_port);
00395 
00396             if (PAL_SUCCESS != status) {
00397                 tr_error("M2MConnectionHandlerPimpl::socket_connect_handler - setSockAddrPort err: %d", (int)status);
00398             } else {
00399                 tr_debug("address family: %d", (int)_socket_address.addressType);
00400             }
00401 
00402             if (_socket_address.addressType == PAL_AF_INET) {
00403                 status = pal_getSockAddrIPV4Addr((palSocketAddress_t*)&_socket_address,_ipV4Addr);
00404                 if (PAL_SUCCESS != status) {
00405                     tr_error("M2MConnectionHandlerPimpl::socket_connect_handler - sockAddr4, err: %d", (int)status);
00406                     _observer.socket_error(M2MConnectionHandler::DNS_RESOLVING_ERROR);
00407                     return;
00408                 }
00409 
00410                 tr_info("M2MConnectionHandlerPimpl::socket_connect_handler - IPv4 Address %d.%d.%d.%d",
00411                         _ipV4Addr[0], _ipV4Addr[1], _ipV4Addr[2], _ipV4Addr[3]);
00412 
00413                 _address._address = (void*)_ipV4Addr;
00414                 _address._length = PAL_IPV4_ADDRESS_SIZE;
00415                 _address._port = _server_port;
00416             } else if (_socket_address.addressType == PAL_AF_INET6 ) {
00417                 status = pal_getSockAddrIPV6Addr((palSocketAddress_t*)&_socket_address,_ipV6Addr);
00418                 if (PAL_SUCCESS != status) {
00419                     tr_error("M2MConnectionHandlerPimpl::socket_connect_handler - sockAddr6, err: %d", (int)status);
00420                     _observer.socket_error(M2MConnectionHandler::DNS_RESOLVING_ERROR);
00421                     return;
00422                 }
00423 
00424                 tr_info("M2MConnectionHandlerPimpl::socket_connect_handler - IPv6 Address: %s", mbed_trace_ipv6(_ipV6Addr));
00425 
00426                 _address._address = (void*)_ipV6Addr;
00427                 _address._length = PAL_IPV6_ADDRESS_SIZE;
00428                 _address._port = _server_port;
00429             } else {
00430                 tr_error("M2MConnectionHandlerPimpl::socket_connect_handler - socket config error, stack: %d", (int)_socket_address.addressType);
00431                 _observer.socket_error(M2MConnectionHandler::SOCKET_ABORT);
00432                 return;
00433             }
00434 
00435             if (!init_socket()) {
00436                 tr_error("M2MConnectionHandlerPimpl::socket_connect_handler - socket init error");
00437                 // The init_socket() calls the socket_error() -callback directly, so it must not be
00438                 // done here too.
00439                 return;
00440             }
00441 
00442             // This state was used to ignore the spurious events _during_ the call of non-blocking pal_connect().
00443             // Now that we just retry connect when it is not yet succeeded anyway this state might be removed completely.
00444             _socket_state = ESocketStateConnectBeingCalled;
00445 
00446         // fall through is intentional
00447         case ESocketStateConnectBeingCalled:
00448         case ESocketStateConnecting:
00449             if (is_tcp_connection()) {
00450 #ifdef PAL_NET_TCP_AND_TLS_SUPPORT
00451                 tr_info("M2MConnectionHandlerPimpl::socket_connect_handler - Using TCP");
00452 
00453                 status = pal_connect(_socket, (palSocketAddress_t*)&_socket_address, sizeof(_socket_address));
00454 
00455                 if ((status == PAL_ERR_SOCKET_IN_PROGRES ) || (status == PAL_ERR_SOCKET_WOULD_BLOCK )) {
00456                     // In this case the connect is done asynchronously, and the pal_socketMiniSelect()
00457                     // will be used to detect the end of connect.
00458                     tr_debug("M2MConnectionHandlerPimpl::socket_connect_handler - pal_connect(): %d, async connect started", (int)status);
00459                     // we need to wait for the event
00460                     _socket_state = ESocketStateConnecting;
00461                     break;
00462 
00463                 } else if (status == PAL_SUCCESS || status == PAL_ERR_SOCKET_ALREADY_CONNECTED ) {
00464 
00465                     tr_debug("M2MConnectionHandlerPimpl::socket_connect_handler - pal_connect(): success");
00466                     _socket_state = ESocketStateConnected;
00467 
00468                 } else {
00469                     tr_error("M2MConnectionHandlerPimpl::socket_connect_handler - pal_connect(): failed: %d", (int)status);
00470                     close_socket();
00471                     _observer.socket_error(M2MConnectionHandler::SOCKET_ABORT);
00472                     return;
00473                 }
00474 #else
00475                 tr_error("socket_connect_handler() - TCP not configured"
00476 #endif //PAL_NET_TCP_AND_TLS_SUPPORT
00477             } else {
00478                 tr_info("M2MConnectionHandlerPimpl::socket_connect_handler - Using UDP");
00479                 _socket_state = ESocketStateConnected;
00480             }
00481 
00482         // fall through is a normal flow in case the UDP was used or pal_connect() happened to return immediately with PAL_SUCCESS
00483         case ESocketStateConnected:
00484             if (_security && security_instance_id >= 0) {
00485                 if (_secure_connection) {
00486                     if ( _security_impl != NULL ) {
00487                         _security_impl->reset();
00488 
00489                         if (_security_impl->init(_security, security_instance_id) == 0) {
00490                             // Initiate handshake. Perhaps there could be a separate event type for this?
00491                             _socket_state = ESocketStateHandshaking;
00492                             send_socket_event(ESocketCallback);
00493                         } else {
00494                             tr_error("M2MConnectionHandlerPimpl::socket_connect_handler - init failed");
00495                             close_socket();
00496                             _observer.socket_error(M2MConnectionHandler::SSL_CONNECTION_ERROR, true);
00497                             return;
00498                         }
00499                     } else {
00500                         tr_error("M2MConnectionHandlerPimpl::socket_connect_handler - sec is null");
00501                         close_socket();
00502                         _observer.socket_error(M2MConnectionHandler::SSL_CONNECTION_ERROR, true);
00503                         return;
00504                     }
00505                 }
00506             }
00507             if (_socket_state != ESocketStateHandshaking) {
00508                 _socket_state = ESocketStateUnsecureConnection;
00509                 _observer.address_ready(_address,
00510                                         _server_type,
00511                                         _address._port);
00512             }
00513             break;
00514 
00515     }
00516 }
00517 
00518 bool M2MConnectionHandlerPimpl::send_data(uint8_t *data,
00519                                           uint16_t data_len,
00520                                           sn_nsdl_addr_s *address)
00521 {
00522     if (address == NULL || data == NULL || !data_len || _socket_state < ESocketStateUnsecureConnection) {
00523         tr_warn("M2MConnectionHandlerPimpl::send_data() - too early");
00524         return false;
00525     }
00526 
00527     send_data_queue_s* out_data = (send_data_queue_s*)malloc(sizeof(send_data_queue_s));
00528     if (!out_data) {
00529         return false;
00530     }
00531 
00532     memset(out_data, 0, sizeof(send_data_queue_s));
00533 
00534     uint8_t offset = 0;
00535 #ifdef PAL_NET_TCP_AND_TLS_SUPPORT
00536     if (is_tcp_connection() && !_secure_connection ) {
00537         offset = 4;
00538     }
00539 #endif
00540 
00541     out_data->data = (uint8_t*)malloc(data_len + offset);
00542     if (!out_data->data) {
00543         free(out_data);
00544         return false;
00545     }
00546 
00547     // TCP non-secure
00548     // We need to "shim" the length in front
00549 #ifdef PAL_NET_TCP_AND_TLS_SUPPORT
00550     if (is_tcp_connection() && !_secure_connection ) {
00551         out_data->data[0] = 0;
00552         out_data->data[1] = 0;
00553         out_data->data[2] = (data_len >> 8 ) & 0xff;
00554         out_data->data[3] = data_len & 0xff;
00555     }
00556 #endif //PAL_NET_TCP_AND_TLS_SUPPORT
00557 
00558     memcpy(out_data->data + offset, data, data_len);
00559     out_data->data_len = data_len + offset;
00560 
00561     claim_mutex();
00562     ns_list_add_to_end(&_linked_list_send_data, out_data);
00563     release_mutex();
00564 
00565     if (!send_event(ESocketSend)) {
00566         // Event push failed, free the buffer
00567         claim_mutex();
00568         ns_list_remove(&_linked_list_send_data, out_data);
00569         release_mutex();
00570         free(out_data->data);
00571         free(out_data);
00572         return false;
00573     }
00574 
00575     return true;
00576 }
00577 
00578 void M2MConnectionHandlerPimpl::send_socket_data()
00579 {
00580     tr_debug("M2MConnectionHandlerPimpl::send_socket_data()");
00581     int bytes_sent = 0;
00582     bool success = true;
00583 
00584     send_data_queue_s* out_data = get_item_from_list();
00585     if (!out_data) {
00586         return;
00587     }
00588 
00589     if (!out_data->data || !out_data->data_len || _socket_state < ESocketStateUnsecureConnection) {
00590         tr_warn("M2MConnectionHandlerPimpl::send_socket_data() - too early");
00591         add_item_to_list(out_data);
00592         return;
00593     }
00594 
00595     // Loop until all the data is sent
00596     for (; out_data->offset < out_data->data_len; out_data->offset += bytes_sent) {
00597         // Secure send
00598         if (_socket_state == ESocketStateSecureConnection) {
00599             // TODO! Change the send_message API to take bytes_sent as a out param like the pal send API's.
00600             while ((bytes_sent = _security_impl->send_message(out_data->data + out_data->offset,
00601                                                             out_data->data_len - out_data->offset)) <= 0) {
00602                 if (bytes_sent == M2MConnectionHandler::CONNECTION_ERROR_WANTS_WRITE) {
00603                     // Return and wait the next event
00604                     add_item_to_list(out_data);
00605                     return;
00606                 }
00607 
00608                 if (bytes_sent != M2MConnectionHandler::CONNECTION_ERROR_WANTS_READ) {
00609                     tr_error("M2MConnectionHandlerPimpl::send_socket_data() - secure, failed %d", bytes_sent);
00610                     success = false;
00611                     break;
00612                 }
00613             }
00614             if (!success) {
00615                 break;
00616             }
00617         }
00618         // Unsecure send
00619         else {
00620             bytes_sent = 0;
00621             palStatus_t ret;
00622             if (is_tcp_connection()) {
00623 #ifdef PAL_NET_TCP_AND_TLS_SUPPORT
00624                 ret = pal_send(_socket,
00625                                out_data->data + out_data->offset,
00626                                out_data->data_len - out_data->offset,
00627                                (size_t*)&bytes_sent);
00628 #endif
00629             } else {
00630                 ret = pal_sendTo(_socket,
00631                                  out_data->data + out_data->offset,
00632                                  out_data->data_len - out_data->offset,
00633                                  (palSocketAddress_t*)&_socket_address,
00634                                  sizeof(_socket_address),
00635                                  (size_t*)&bytes_sent);
00636             }
00637             if (ret == PAL_ERR_SOCKET_WOULD_BLOCK ) {
00638                 // Return and wait next event
00639                 add_item_to_list(out_data);
00640                 return;
00641             }
00642             if (ret < 0) {
00643                 tr_error("M2MConnectionHandlerPimpl::send_socket_data() - unsecure failed %d", (int)ret);
00644                 success = false;
00645                 break;
00646             }
00647         }
00648     }
00649 
00650     free(out_data->data);
00651     free(out_data);
00652 
00653     if (!success) {
00654         if (bytes_sent == M2MConnectionHandler::SSL_PEER_CLOSE_NOTIFY) {
00655             _observer.socket_error(M2MConnectionHandler::SSL_PEER_CLOSED, true);
00656         } else {
00657             tr_error("M2MConnectionHandlerPimpl::send_socket_data() - SOCKET_SEND_ERROR");
00658             _observer.socket_error(M2MConnectionHandler::SOCKET_SEND_ERROR, true);
00659         }
00660         close_socket();
00661     } else {
00662         _observer.data_sent();
00663     }
00664 }
00665 
00666 bool M2MConnectionHandlerPimpl::start_listening_for_data()
00667 {
00668     return true;
00669 }
00670 
00671 void M2MConnectionHandlerPimpl::stop_listening()
00672 {
00673     // Do not call close_socket() directly here.
00674     // This can be called from multiple locations.
00675     send_socket_event(ESocketClose);
00676 }
00677 
00678 void M2MConnectionHandlerPimpl::handle_connection_error(int error)
00679 {
00680     tr_error("M2MConnectionHandlerPimpl::handle_connection_error - error %d", error);
00681     _observer.socket_error(error);
00682 }
00683 
00684 void M2MConnectionHandlerPimpl::set_platform_network_handler(void *handler)
00685 {
00686     tr_debug("M2MConnectionHandlerPimpl::set_platform_network_handler");
00687     if (PAL_SUCCESS != pal_registerNetworkInterface(handler, &_net_iface)) {
00688         tr_error("M2MConnectionHandlerPimpl::set_platform_network_handler - Interface registration failed.");
00689     }
00690 }
00691 
00692 void M2MConnectionHandlerPimpl::receive_handshake_handler()
00693 {
00694     int return_value;
00695     tr_debug("M2MConnectionHandlerPimpl::receive_handshake_handler()");
00696 
00697     // assert(_socket_state == ESocketStateHandshaking);
00698 
00699     return_value = _security_impl->connect(_base);
00700 
00701     if (!return_value) {
00702 
00703         _handshake_retry = 0;
00704         _socket_state = ESocketStateSecureConnection;
00705         _observer.address_ready(_address,
00706                                 _server_type,
00707                                 _server_port);
00708 
00709     } else if (return_value == M2MConnectionHandler::SSL_PEER_CLOSE_NOTIFY) {
00710         _handshake_retry = 0;
00711         _observer.socket_error(M2MConnectionHandler::SSL_PEER_CLOSED, true);
00712         close_socket();
00713 
00714     } else if (return_value != M2MConnectionHandler::CONNECTION_ERROR_WANTS_READ) {
00715 
00716         tr_error("M2MConnectionHandlerPimpl::receive_handshake_handler() - SSL_HANDSHAKE_ERROR");
00717         _handshake_retry = 0;
00718         _observer.socket_error(M2MConnectionHandler::SSL_HANDSHAKE_ERROR, true);
00719         close_socket();
00720 
00721     } else {
00722 
00723         if (_handshake_retry++ > MBED_CONF_MBED_CLIENT_TLS_MAX_RETRY) {
00724 
00725             tr_error("M2MConnectionHandlerPimpl::receive_handshake_handler() - Max TLS retry fail");
00726             _handshake_retry = 0;
00727             _observer.socket_error(M2MConnectionHandler::SOCKET_ABORT, true);
00728             close_socket();
00729 
00730         }
00731         eventOS_event_timer_cancel(ESocketTimerCallback, M2MConnectionHandlerPimpl::_tasklet_id);
00732 
00733         // There is required to set event.data_ptr for eventloop_event_handler.
00734         arm_event_s event = {0};
00735         event.receiver = M2MConnectionHandlerPimpl::_tasklet_id;
00736         event.sender = 0;
00737         event.event_id = ESocketTimerCallback;
00738         event.event_type = ESocketTimerCallback;
00739         event.data_ptr = this;
00740         event.event_data = 0;
00741         event.priority = ARM_LIB_HIGH_PRIORITY_EVENT;
00742         eventOS_event_timer_request_in(&event, eventOS_event_timer_ms_to_ticks(1000));
00743     }
00744 }
00745 
00746 bool M2MConnectionHandlerPimpl::is_handshake_ongoing() const
00747 {
00748     return (_socket_state == ESocketStateHandshaking);
00749 }
00750 
00751 void M2MConnectionHandlerPimpl::receive_handler()
00752 {
00753     // assert(_socket_state > ESocketStateHandshaking);
00754 
00755     if (_socket_state == ESocketStateSecureConnection) {
00756 
00757         int rcv_size;
00758         unsigned char recv_buffer[BUFFER_LENGTH];
00759 
00760         // we need to read as much as there is data available as the events may or may not be suppressed
00761         do {
00762             tr_debug("M2MConnectionHandlerPimpl::receive_handler()..");
00763             rcv_size = _security_impl->read(recv_buffer, sizeof(recv_buffer));
00764             tr_debug("M2MConnectionHandlerPimpl::receive_handler() res: %d", rcv_size);
00765             if (rcv_size > 0) {
00766                 _observer.data_available((uint8_t*)recv_buffer,
00767                                          rcv_size, _address);
00768 
00769             } else if (M2MConnectionHandler::SSL_PEER_CLOSE_NOTIFY == rcv_size) {
00770                 _observer.socket_error(M2MConnectionHandler::SSL_PEER_CLOSED, true);
00771                 return;
00772             } else if (M2MConnectionHandler::CONNECTION_ERROR_WANTS_READ != rcv_size && rcv_size < 0) {
00773                 tr_error("M2MConnectionHandlerPimpl::receive_handler() - secure SOCKET_READ_ERROR");
00774                 _observer.socket_error(M2MConnectionHandler::SOCKET_READ_ERROR, true);
00775                 close_socket();
00776                 return;
00777             }
00778         } while (rcv_size > 0 && _socket_state == ESocketStateSecureConnection);
00779 
00780     } else {
00781         size_t recv;
00782         palStatus_t status;
00783         unsigned char recv_buffer[BUFFER_LENGTH];
00784         do {
00785             if (is_tcp_connection()) {
00786 #ifdef PAL_NET_TCP_AND_TLS_SUPPORT
00787                 status = pal_recv(_socket, recv_buffer, sizeof(recv_buffer), &recv);
00788 #endif //PAL_NET_TCP_AND_TLS_SUPPORT
00789             } else {
00790                 status = pal_receiveFrom(_socket, recv_buffer, sizeof(recv_buffer), NULL, NULL, &recv);
00791             }
00792 
00793             if (status == PAL_ERR_SOCKET_WOULD_BLOCK ) {
00794                 return;
00795             } else if (status != PAL_SUCCESS) {
00796                 tr_error("M2MConnectionHandlerPimpl::receive_handler() - SOCKET_READ_ERROR (%d)", (int)status);
00797                 _observer.socket_error(M2MConnectionHandler::SOCKET_READ_ERROR, true);
00798                 close_socket();
00799                 return;
00800             }
00801 
00802             tr_debug("M2MConnectionHandlerPimpl::receive_handler() - data received, len: %zu", recv);
00803 
00804             if (!is_tcp_connection()) { // Observer for UDP plain mode
00805                 _observer.data_available((uint8_t*)recv_buffer, recv, _address);
00806             } else {
00807 #ifdef PAL_NET_TCP_AND_TLS_SUPPORT
00808                 if ( recv < 4 ) {
00809                     tr_error("M2MConnectionHandlerPimpl::receive_handler() - TCP SOCKET_READ_ERROR");
00810                     _observer.socket_error(M2MConnectionHandler::SOCKET_READ_ERROR, true);
00811                     close_socket();
00812                     return;
00813                 }
00814 
00815                 //We need to "shim" out the length from the front
00816                 uint32_t len = (recv_buffer[0] << 24 & 0xFF000000) + (recv_buffer[1] << 16 & 0xFF0000);
00817                 len += (recv_buffer[2] << 8 & 0xFF00) + (recv_buffer[3] & 0xFF);
00818                 if (len > 0 && len <= recv - 4) {
00819                     // Observer for TCP plain mode
00820                     _observer.data_available(recv_buffer + 4, len, _address);
00821                 }
00822 #endif //PAL_NET_TCP_AND_TLS_SUPPORT
00823             }
00824         } while (recv > 0 && _socket_state == ESocketStateUnsecureConnection);
00825     }
00826 }
00827 
00828 void M2MConnectionHandlerPimpl::claim_mutex()
00829 {
00830     eventOS_scheduler_mutex_wait();
00831 }
00832 
00833 void M2MConnectionHandlerPimpl::release_mutex()
00834 {
00835     eventOS_scheduler_mutex_release();
00836 }
00837 
00838 
00839 bool M2MConnectionHandlerPimpl::init_socket()
00840 {
00841     palSocketType_t  socket_type = PAL_SOCK_DGRAM ;
00842     palStatus_t status;
00843     palSocketAddress_t bind_address;
00844     palIpV4Addr_t interface_address4;
00845     palIpV6Addr_t interface_address6;
00846 
00847     memset(&bind_address, 0, sizeof(palSocketAddress_t));
00848     memset(&interface_address4, 0, sizeof(interface_address4));
00849     memset(&interface_address6, 0, sizeof(interface_address6));
00850 
00851     if (is_tcp_connection()) {
00852 #ifdef PAL_NET_TCP_AND_TLS_SUPPORT
00853         socket_type = PAL_SOCK_STREAM;
00854 #else
00855         // Somebody has built code without TCP support but tries to use it.
00856         // Perhaps a "assert(false)" would be sufficient.
00857         tr_error("M2MConnectionHandlerPimpl::init_socket() - TCP config error");
00858         _observer.socket_error(M2MConnectionHandler::SOCKET_ABORT);
00859         return;
00860 #endif //PAL_NET_TCP_AND_TLS_SUPPORT
00861     }
00862     status = pal_asynchronousSocketWithArgument((palSocketDomain_t )_socket_address.addressType,
00863                                                 socket_type, true, _net_iface, &socket_event_handler,
00864                                                 this, &_socket);
00865 
00866     if (PAL_SUCCESS != status) {
00867         tr_error("M2MConnectionHandlerPimpl::init_socket() - socket create error : %d", (int)status);
00868         _observer.socket_error(M2MConnectionHandler::SOCKET_ABORT);
00869         return false;
00870     }
00871 
00872     if (_socket_address.addressType == PAL_AF_INET) {
00873         status = pal_setSockAddrIPV4Addr(&bind_address, interface_address4);
00874     } else if (_socket_address.addressType == PAL_AF_INET6 ) {
00875         status = pal_setSockAddrIPV6Addr(&bind_address, interface_address6);
00876     } else {
00877         tr_warn("M2MConnectionHandlerPimpl::init_socket() - stack type: %d", (int)_socket_address.addressType);
00878     }
00879     if (PAL_SUCCESS != status) {
00880         tr_error("M2MConnectionHandlerPimpl::init_socket - setSockAddrIPV err: %d", (int)status);
00881         return false;
00882     }
00883     status = pal_setSockAddrPort(&bind_address, _listen_port);
00884     if (PAL_SUCCESS != status) {
00885         tr_error("M2MConnectionHandlerPimpl::init_socket - setSockAddrPort err: %d", (int)status);
00886         return false;
00887     }
00888     pal_bind(_socket, &bind_address, sizeof(bind_address));
00889 
00890     _security_impl->set_socket(_socket, (palSocketAddress_t*)&_socket_address);
00891 
00892     return true;
00893 }
00894 
00895 bool M2MConnectionHandlerPimpl::is_tcp_connection() const
00896 {
00897     return ( _binding_mode == M2MInterface::TCP ||
00898              _binding_mode == M2MInterface::TCP_QUEUE );
00899 }
00900 
00901 void M2MConnectionHandlerPimpl::close_socket()
00902 {
00903     _suppressable_event_in_flight = false;
00904 
00905     if (_socket) {
00906         // At least on mbed-os the pal_close() will perform callbacks even during it
00907         // is called, which we will ignore when this state is set.
00908         _socket_state = ESocketStateCloseBeingCalled;
00909         pal_close(&_socket);
00910         _socket = 0;
00911     }
00912 
00913     // make sure the socket connection statemachine is reset too.
00914     _socket_state = ESocketStateDisconnected;
00915 
00916     if (_security_impl) {
00917         _security_impl->reset();
00918     }
00919 
00920     claim_mutex();
00921     /*ns_list_foreach_safe(M2MConnectionHandlerPimpl::send_data_queue_s, tmp, &_linked_list_send_data) {
00922         ns_list_remove(&_linked_list_send_data, tmp);
00923         free(tmp->data);
00924         free(tmp);
00925     }*/
00926     // Workaround for IAR compilation issue. ns_list_foreach does not compile with IAR.
00927     // Error[Pe144]: a value of type "void *" cannot be used to initialize an entity of type "M2MConnectionHandlerPimpl::send_data_queue *"
00928     while (!ns_list_is_empty(&_linked_list_send_data)) {
00929         send_data_queue_s* data = (send_data_queue_s*)ns_list_get_first(&_linked_list_send_data);
00930         ns_list_remove(&_linked_list_send_data, data);
00931         free(data->data);
00932         free(data);
00933     }
00934     release_mutex();
00935 }
00936 
00937 M2MConnectionHandlerPimpl::send_data_queue_s* M2MConnectionHandlerPimpl::get_item_from_list()
00938 {
00939     claim_mutex();
00940     send_data_queue_s* out_data = (send_data_queue_s*)ns_list_get_first(&_linked_list_send_data);
00941     if (out_data) {
00942         ns_list_remove(&_linked_list_send_data, out_data);
00943     }
00944     release_mutex();
00945     return out_data;
00946 }
00947 
00948 void M2MConnectionHandlerPimpl::add_item_to_list(M2MConnectionHandlerPimpl::send_data_queue_s *data)
00949 {
00950     claim_mutex();
00951     ns_list_add_to_start(&_linked_list_send_data, data);
00952     release_mutex();
00953 }
00954 
00955 void M2MConnectionHandlerPimpl::force_close()
00956 {
00957     close_socket();
00958 }