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