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.
connector_tcp_recv.h
00001 /* 00002 * Copyright (c) 2013 Digi International Inc., 00003 * All rights not expressly granted are reserved. 00004 * 00005 * This Source Code Form is subject to the terms of the Mozilla Public 00006 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 00007 * You can obtain one at http://mozilla.org/MPL/2.0/. 00008 * 00009 * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343 00010 * ======================================================================= 00011 */ 00012 00013 static connector_buffer_t * tcp_new_receive_packet(connector_data_t * const connector_ptr) 00014 { 00015 connector_buffer_t * buffer_ptr; 00016 connector_buffer_t * packet = NULL; 00017 00018 /* return an available packet for receiving data */ 00019 buffer_ptr = connector_ptr->edp_data.receive_packet.free_packet_buffer; 00020 if (buffer_ptr != NULL) 00021 { 00022 packet = buffer_ptr; 00023 connector_ptr->edp_data.receive_packet.free_packet_buffer = buffer_ptr->next; 00024 } 00025 00026 00027 return packet; 00028 } 00029 00030 static void tcp_release_receive_packet(connector_data_t * const connector_ptr, connector_buffer_t const * const packet) 00031 { 00032 ASSERT(packet != NULL); 00033 00034 /* release a packet that is from tcp_new_receive_packet() */ 00035 if (packet != NULL) 00036 { 00037 connector_buffer_t * const buffer_ptr = (connector_buffer_t *)packet; 00038 00039 buffer_ptr->next = connector_ptr->edp_data.receive_packet.free_packet_buffer; 00040 connector_ptr->edp_data.receive_packet.free_packet_buffer = buffer_ptr; 00041 } 00042 return; 00043 } 00044 00045 00046 static connector_callback_status_t tcp_receive_buffer(connector_data_t * const connector_ptr, uint8_t * const buffer, size_t * const length) 00047 { 00048 connector_callback_status_t status; 00049 connector_request_id_t request_id; 00050 00051 /* Call callback to receive data from Device Cloud */ 00052 request_id.network_request = connector_request_id_network_receive; 00053 00054 { 00055 connector_network_receive_t read_data; 00056 00057 read_data.handle = connector_ptr->edp_data.network_handle; 00058 read_data.buffer = buffer; 00059 read_data.bytes_available = *length; 00060 read_data.bytes_used = 0; 00061 00062 00063 status = connector_callback(connector_ptr->callback, connector_class_id_network_tcp, request_id, &read_data); 00064 ASSERT(status != connector_callback_unrecognized); 00065 switch (status) 00066 { 00067 case connector_callback_unrecognized: 00068 status = connector_callback_abort; 00069 /* no break */ 00070 case connector_callback_abort: 00071 connector_debug_printf("tcp_receive_buffer: callback returns abort\n"); 00072 goto done; 00073 case connector_callback_busy: 00074 *length = 0; 00075 break; 00076 case connector_callback_continue: 00077 *length = read_data.bytes_used; 00078 break; 00079 case connector_callback_error: 00080 edp_set_close_status(connector_ptr, connector_close_status_device_error); 00081 goto done; 00082 } 00083 00084 if (read_data.bytes_used > 0 || connector_ptr->edp_data.keepalive.last_tx_received_time == 0) 00085 { 00086 /* Retain the "last (tx keepalive) message send" time. */ 00087 if (get_system_time(connector_ptr, &connector_ptr->edp_data.keepalive.last_tx_received_time) != connector_working) 00088 { 00089 status = connector_callback_abort; 00090 } 00091 else 00092 { 00093 if (connector_ptr->edp_data.keepalive.miss_tx_count > 0) 00094 { 00095 if (notify_status(connector_ptr->callback, connector_tcp_keepalive_restored) != connector_working) 00096 status = connector_callback_abort; 00097 connector_ptr->edp_data.keepalive.miss_tx_count = 0; 00098 } 00099 } 00100 goto done; 00101 } 00102 } 00103 00104 00105 /* check Tx keepalive timing */ 00106 if (GET_TX_KEEPALIVE_INTERVAL(connector_ptr) > 0) 00107 { 00108 unsigned long const tx_keepalive_interval = GET_TX_KEEPALIVE_INTERVAL(connector_ptr); 00109 00110 unsigned long const wait_count = connector_ptr->edp_data.keepalive.miss_tx_count + UINT32_C(1); 00111 unsigned long const max_timeout = (tx_keepalive_interval * wait_count); 00112 00113 if (!is_valid_timing_limit(connector_ptr, connector_ptr->edp_data.keepalive.last_tx_received_time, max_timeout)) 00114 { 00115 /* notify callback we have missing a tx keep alive */ 00116 if (notify_status(connector_ptr->callback, connector_tcp_keepalive_missed) != connector_working) 00117 { 00118 status = connector_callback_abort; 00119 goto done; 00120 } 00121 connector_ptr->edp_data.keepalive.miss_tx_count++; 00122 if (connector_ptr->edp_data.keepalive.miss_tx_count == GET_WAIT_COUNT(connector_ptr)) 00123 { 00124 /* consider a lost connection */ 00125 if (notify_error_status(connector_ptr->callback, connector_class_id_network_tcp, request_id, connector_keepalive_error) != connector_working) 00126 { 00127 status = connector_callback_abort; 00128 goto done; 00129 } 00130 00131 connector_debug_printf("connector_receive: keepalive fails\n"); 00132 edp_set_close_status(connector_ptr, connector_close_status_no_keepalive); 00133 status = connector_callback_error; 00134 } 00135 } 00136 00137 } 00138 00139 00140 done: 00141 connector_ptr->edp_data.receive_packet.timeout = MAX_RECEIVE_TIMEOUT_IN_SECONDS; 00142 return status; 00143 } 00144 00145 00146 static connector_callback_status_t tcp_receive_data_status(connector_data_t * const connector_ptr) 00147 { 00148 connector_callback_status_t status = connector_callback_continue; 00149 00150 /* send data if we have more data to send */ 00151 if (connector_ptr->edp_data.receive_packet.bytes_received < connector_ptr->edp_data.receive_packet.total_length) 00152 { 00153 uint8_t * const buf = connector_ptr->edp_data.receive_packet.ptr + connector_ptr->edp_data.receive_packet.bytes_received; 00154 size_t length = connector_ptr->edp_data.receive_packet.total_length - connector_ptr->edp_data.receive_packet.bytes_received; 00155 status = tcp_receive_buffer(connector_ptr, buf, &length); 00156 00157 if (status == connector_callback_continue) 00158 { 00159 connector_ptr->edp_data.receive_packet.bytes_received += length; 00160 } 00161 else if (status != connector_callback_busy) 00162 { 00163 goto done; 00164 } 00165 } 00166 00167 if (connector_ptr->edp_data.receive_packet.bytes_received < connector_ptr->edp_data.receive_packet.total_length) 00168 { 00169 /* still more data */ 00170 status = connector_callback_busy; 00171 } 00172 done: 00173 return status; 00174 } 00175 00176 00177 static connector_status_t tcp_receive_packet(connector_data_t * const connector_ptr, connector_buffer_t ** packet) 00178 { 00179 enum { 00180 receive_packet_init, 00181 receive_packet_type, 00182 receive_packet_length, 00183 receive_packet_data, 00184 receive_packet_complete 00185 }; 00186 00187 connector_status_t result = connector_idle; 00188 00189 *packet = NULL; 00190 00191 ASSERT_GOTO(edp_get_edp_state(connector_ptr) != edp_communication_connect_to_cloud, done); 00192 00193 /* 00194 * Read the MT message type. 00195 * 00196 * For MT version 2, there are numerous message types. Some of these 00197 * messages require special handling, in that they may be legacy EDP 00198 * version response message varieties. These messages are sent by 00199 * device cloud that does not support MTv2. Since the client doesn't support 00200 * both MTv1 and MTv2 concurrently, an MTv2 client must terminate its 00201 * MT connection if it finds the Device Cloud to be incompatible insofar as 00202 * the MT version is concerned. 00203 * 00204 * We only accept messages of the expected types from the Device Cloud. Any 00205 * message other than an expected type is handled as an error, and an 00206 * error is returned to the caller. This must be done since any unknown 00207 * message type cannot be correctly parsed for length and discarded from 00208 * the input stream. 00209 */ 00210 00211 /* we have to read 3 times to get a complete packet. 00212 * 1. read message type 00213 * 2. read message length 00214 * 3. read actual message data 00215 * 00216 * So we use index == receive_packet_init to initialize the packet before starting reading. 00217 * When index == receive_packet_type, set to receive message type. After message type is received, 00218 * we must check valid message type. 00219 * 00220 * When index == receive_packet_length, set to receive message length. 00221 * When index == receive_packet_data, set to receive message data. 00222 * When index == receive_packet_complete, message data is completely received and 00223 * reset index = receive_packet_init and exit. 00224 * 00225 */ 00226 while (connector_ptr->edp_data.receive_packet.index <= receive_packet_complete) 00227 { 00228 connector_callback_status_t status = connector_callback_continue; 00229 00230 if (connector_ptr->edp_data.receive_packet.index != receive_packet_init) 00231 { /* continue for any pending receive */ 00232 status = tcp_receive_data_status(connector_ptr); 00233 00234 switch (status) 00235 { 00236 case connector_callback_continue: 00237 break; 00238 case connector_callback_busy: 00239 result = (connector_ptr->edp_data.receive_packet.index <= receive_packet_length) ? connector_idle : connector_pending; 00240 goto done; 00241 case connector_callback_error: 00242 result = connector_unavailable; 00243 goto done; 00244 case connector_callback_abort: 00245 edp_set_close_status(connector_ptr, connector_close_status_abort); 00246 result = connector_abort; 00247 goto done; 00248 default: 00249 ASSERT(connector_false); 00250 } 00251 } 00252 result = connector_pending; 00253 00254 switch (connector_ptr->edp_data.receive_packet.index) 00255 { 00256 case receive_packet_init: 00257 /* initialize and setup packet for receive */ 00258 connector_ptr->edp_data.receive_packet.packet_type = 0; 00259 connector_ptr->edp_data.receive_packet.packet_length = 0; 00260 connector_ptr->edp_data.receive_packet.bytes_received = 0; 00261 connector_ptr->edp_data.receive_packet.total_length = 0; 00262 connector_ptr->edp_data.receive_packet.index = 0; 00263 00264 if (edp_get_active_state(connector_ptr) == connector_transport_open) 00265 { 00266 /* We are still in edp connection process. 00267 * So we need to setup the packet for any message 00268 * during edp connection process since no facility is 00269 * running. 00270 * Otherwise, we setup the packet in receive_packet_data index 00271 * to receive actual data. Otherwise, we don't have actual 00272 * data received but we need to be able to receive keepalive. 00273 */ 00274 connector_ptr->edp_data.receive_packet.data_packet = tcp_new_receive_packet(connector_ptr); 00275 if (connector_ptr->edp_data.receive_packet.data_packet == NULL) 00276 { 00277 result = connector_idle; 00278 goto done; 00279 } 00280 } 00281 00282 connector_ptr->edp_data.receive_packet.index++; 00283 break; 00284 00285 case receive_packet_type: 00286 /* set to read the message type */ 00287 connector_ptr->edp_data.receive_packet.ptr = (uint8_t *)&connector_ptr->edp_data.receive_packet.packet_type; 00288 connector_ptr->edp_data.receive_packet.bytes_received = 0; 00289 connector_ptr->edp_data.receive_packet.total_length = sizeof connector_ptr->edp_data.receive_packet.packet_type; 00290 connector_ptr->edp_data.receive_packet.index++; 00291 break; 00292 00293 case receive_packet_length: 00294 { 00295 /* Got message type let's get to message length. 00296 * So make sure we support the message type. 00297 * Then, set to read message length. 00298 */ 00299 uint16_t type_val; 00300 00301 type_val = FROM_BE16(connector_ptr->edp_data.receive_packet.packet_type); 00302 connector_ptr->edp_data.receive_packet.packet_type = type_val; 00303 00304 switch (type_val) 00305 { 00306 /* Expected MTv2 message types... */ 00307 case E_MSG_MT2_TYPE_VERSION_OK: 00308 break; 00309 case E_MSG_MT2_TYPE_KA_KEEPALIVE: 00310 break; 00311 case E_MSG_MT2_TYPE_PAYLOAD: 00312 break; 00313 case E_MSG_MT2_TYPE_LEGACY_EDP_VER_RESP: 00314 case E_MSG_MT2_TYPE_VERSION_BAD: 00315 case E_MSG_MT2_TYPE_CLOUD_OVERLOAD: 00316 connector_debug_printf("tcp_receive_packet: unsupported or unexpected error type 0x%x\n", (unsigned) type_val); 00317 edp_set_close_status(connector_ptr, connector_close_status_abort); 00318 result = connector_abort; 00319 goto done; 00320 /* Unexpected/unknown MTv2 message types... */ 00321 case E_MSG_MT2_TYPE_VERSION: 00322 case E_MSG_MT2_TYPE_KA_RX_INTERVAL: 00323 case E_MSG_MT2_TYPE_KA_TX_INTERVAL: 00324 case E_MSG_MT2_TYPE_KA_WAIT: 00325 default: 00326 /* Just tell caller we have unexpected packet message */ 00327 connector_debug_printf("tcp_receive_packet: unsupported or unexpected error type 0x%x\n", (unsigned) type_val); 00328 break; 00329 } 00330 00331 /* set up to read message length */ 00332 connector_ptr->edp_data.receive_packet.ptr = (uint8_t *)&connector_ptr->edp_data.receive_packet.packet_length; 00333 connector_ptr->edp_data.receive_packet.bytes_received = 0; 00334 connector_ptr->edp_data.receive_packet.total_length = sizeof connector_ptr->edp_data.receive_packet.packet_length; 00335 connector_ptr->edp_data.receive_packet.index++; 00336 break; 00337 } 00338 case receive_packet_data: 00339 { 00340 /* got packet length so set to read message data */ 00341 uint16_t packet_length = FROM_BE16(connector_ptr->edp_data.receive_packet.packet_length); 00342 00343 if (connector_ptr->edp_data.receive_packet.packet_type != E_MSG_MT2_TYPE_PAYLOAD) 00344 { 00345 /* 00346 * For all but payload messages, the length field value should be 00347 * zero, as there is no data accompanying the message. The MT 00348 * messages to which this applies here are: 00349 * E_MSG_MT2_TYPE_VERSION_OK 00350 * E_MSG_MT2_TYPE_VERSION_BAD 00351 * E_MSG_MT2_TYPE_CLOUD_OVERLOAD 00352 * E_MSG_MT2_TYPE_KA_KEEPALIVE 00353 */ 00354 if (packet_length != 0) 00355 { 00356 connector_debug_printf("connector_get_receive_packet: Invalid payload\n"); 00357 } 00358 } 00359 00360 00361 if (packet_length == 0) 00362 { 00363 /* set to complete data since no data to be read. */ 00364 connector_ptr->edp_data.receive_packet.index = receive_packet_complete; 00365 connector_ptr->edp_data.receive_packet.packet_length = packet_length; 00366 connector_ptr->edp_data.receive_packet.total_length = packet_length; 00367 } 00368 else 00369 { 00370 /* 00371 * Read the actual message data bytes into the packet buffer. 00372 */ 00373 ASSERT(packet_length <= (sizeof connector_ptr->edp_data.receive_packet.packet_buffer.buffer - PACKET_EDP_HEADER_SIZE)); 00374 00375 if (edp_get_active_state(connector_ptr) != connector_transport_open) 00376 { 00377 /* We already setup data_packet in 00378 * receive_packet_init index. So we setup data_packet when we 00379 * are already established the EDP. 00380 */ 00381 connector_ptr->edp_data.receive_packet.data_packet = tcp_new_receive_packet(connector_ptr); 00382 if (connector_ptr->edp_data.receive_packet.data_packet == NULL) 00383 { 00384 goto done; 00385 } 00386 } 00387 00388 connector_ptr->edp_data.receive_packet.packet_length = packet_length; 00389 connector_ptr->edp_data.receive_packet.total_length = packet_length; 00390 00391 connector_ptr->edp_data.receive_packet.ptr = GET_PACKET_DATA_POINTER(connector_ptr->edp_data.receive_packet.data_packet->buffer, PACKET_EDP_HEADER_SIZE); 00392 connector_ptr->edp_data.receive_packet.bytes_received = 0; 00393 connector_ptr->edp_data.receive_packet.index++; 00394 00395 } 00396 break; 00397 } 00398 case receive_packet_complete: 00399 00400 if (connector_ptr->edp_data.receive_packet.data_packet != NULL && 00401 connector_ptr->edp_data.receive_packet.packet_type != E_MSG_MT2_TYPE_KA_KEEPALIVE) 00402 { 00403 uint8_t * edp_header = connector_ptr->edp_data.receive_packet.data_packet->buffer; 00404 /* got message data. Let's set edp header */ 00405 message_store_be16(edp_header, type, connector_ptr->edp_data.receive_packet.packet_type); 00406 message_store_be16(edp_header, length, connector_ptr->edp_data.receive_packet.packet_length); 00407 *packet = connector_ptr->edp_data.receive_packet.data_packet; 00408 result = connector_working; 00409 } 00410 00411 connector_ptr->edp_data.receive_packet.index = receive_packet_init; 00412 goto done; 00413 } /* switch */ 00414 } 00415 00416 done: 00417 return result; 00418 } 00419 00420 static connector_status_t layer_facility_process(connector_data_t * const connector_ptr); 00421 00422 static connector_status_t edp_tcp_receive_process(connector_data_t * connector_ptr) 00423 { 00424 enum { 00425 facility_receive_message, 00426 facility_process_message 00427 }; 00428 connector_status_t result; 00429 00430 connector_buffer_t * packet_buffer = NULL; 00431 connector_bool_t done_packet = connector_true; 00432 connector_facility_t * fac_ptr; 00433 00434 00435 /* Facility layer is the layer that the Connector has fully established 00436 * communication with Device Cloud. It keeps waiting messages from Device Cloud 00437 * and passes it to the appropriate facility: 00438 * 1. waits message from Device Cloud 00439 * 2. parses message and passes it to the facility 00440 * 3. invokes facility to process message. 00441 */ 00442 result = tcp_receive_packet(connector_ptr, &packet_buffer); 00443 00444 if (result == connector_working) 00445 { 00446 uint8_t * packet ; 00447 uint8_t * edp_header; 00448 uint8_t * edp_protocol; 00449 00450 ASSERT(packet_buffer != NULL); 00451 00452 packet = packet_buffer->buffer; 00453 edp_header = packet; 00454 edp_protocol = packet + PACKET_EDP_HEADER_SIZE; 00455 00456 /* 00457 * received packet format: 00458 * ---------------------------------------------------------- 00459 * | 0 - 1 | 2 - 3 | 4 | 5 | 6 - 7 | 8... | 00460 * ---------------------------------------------------------- 00461 * | Payload | length | coding | discovery | facility | Data | 00462 * | Type | | scheme | payload | | | 00463 * ----------------------------------------------------------- 00464 * | EDP Header | EDP Protocol | 00465 * ----------------------------------------------------------- 00466 */ 00467 00468 if (message_load_be16(edp_header, type) == E_MSG_MT2_TYPE_PAYLOAD) 00469 { 00470 uint16_t total_length = message_load_be16(edp_header, length); 00471 uint8_t const sec_code = message_load_u8(edp_protocol, sec_coding); 00472 uint8_t const payload = message_load_u8(edp_protocol, payload); 00473 00474 /* currently we don't support any other security protocol */ 00475 ASSERT_GOTO(sec_code == SECURITY_PROTO_NONE, error); 00476 ASSERT_GOTO(payload == DISC_OP_PAYLOAD, error); 00477 ASSERT_GOTO(total_length > PACKET_EDP_PROTOCOL_SIZE, error); 00478 00479 connector_debug_printf("edp_tcp_receive_process: receive data facility = 0x%04x\n", message_load_be16(edp_protocol, facility)); 00480 /* adjust the length for facility process */ 00481 { 00482 uint16_t const length = (uint16_t)(total_length - PACKET_EDP_PROTOCOL_SIZE); 00483 message_store_be16(edp_header, length, length); 00484 } 00485 00486 } 00487 00488 if (message_load_be16(edp_header, type) == E_MSG_MT2_TYPE_PAYLOAD) 00489 { 00490 uint16_t facility; 00491 uint8_t * edp_protocol = packet + PACKET_EDP_HEADER_SIZE; 00492 /* search facility 00493 * 00494 * Make sure the facility is not processing previous packet. 00495 */ 00496 facility = message_load_be16(edp_protocol, facility); 00497 for (fac_ptr = connector_ptr->edp_data.facilities.list; fac_ptr != NULL; fac_ptr = fac_ptr->next) 00498 { 00499 if (fac_ptr->facility_num == facility) 00500 { 00501 if (fac_ptr->packet_buffer == NULL) 00502 { 00503 fac_ptr->packet_buffer = packet_buffer; 00504 connector_ptr->edp_data.facilities.current = fac_ptr; 00505 done_packet = connector_false; 00506 } 00507 else 00508 { 00509 /* we only have one receive buffer. 00510 * Since a facility holds on the receive buffer, 00511 * receive should not able to get a free receive buffer 00512 * to receive any data 00513 */ 00514 ASSERT(connector_false); 00515 } 00516 break; 00517 } 00518 } 00519 } 00520 } 00521 else if (result != connector_idle && result != connector_pending) 00522 { 00523 goto done; 00524 } 00525 00526 error: 00527 /* if we are done with packet, release it for another 00528 * receive_packet . 00529 */ 00530 if (done_packet && packet_buffer != NULL) 00531 { 00532 tcp_release_receive_packet(connector_ptr, packet_buffer); 00533 } 00534 00535 /* Let's process facility */ 00536 result = layer_facility_process(connector_ptr); 00537 00538 done: 00539 if (result != connector_idle && result != connector_pending && result != connector_working && result != connector_active) 00540 { 00541 edp_set_active_state(connector_ptr, connector_transport_close); 00542 result = connector_working; 00543 goto done; 00544 } 00545 return result; 00546 } 00547 00548
Generated on Tue Jul 12 2022 19:18:38 by
1.7.2