Sebastián Pastor / EtheriosCloudConnector
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers connector_tcp_recv.h Source File

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