Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: FXAS21002 FXOS8700Q
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 }
Generated on Tue Jul 12 2022 20:21:00 by
