Toyomasa Watarai
/
Mbed-example-WS-W27
Mbed Cloud example program for workshop in W27 2018.
Embed:
(wiki syntax)
Show/hide line numbers
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 16:22:06 by 1.7.2