Simulated product dispenser
Fork of mbed-cloud-workshop-connect-HTS221 by
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 19:12:12 by 1.7.2