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.
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 Mon Aug 29 2022 19:53:39 by
