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 #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 }
Generated on Tue Jul 12 2022 16:24:13 by
1.7.2