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

« Back to documentation index

Show/hide line numbers connector_tcp_send.h Source File

connector_tcp_send.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 /* The data security coding schemes (a.k.a. encryption types)... */
00014 #define SECURITY_PROTO_NONE          0x00 /* no encryption, no authentication */
00015 
00016 
00017 /* Discovery layer opcodes */
00018 #define DISC_OP_PAYLOAD       0
00019 #define DISC_OP_DEVICETYPE    4
00020 #define DISC_OP_INITCOMPLETE  5
00021 #define DISC_OP_VENDOR_ID     6
00022 
00023 #define tcp_is_send_active(connector_ptr)   connector_bool(connector_ptr->edp_data.send_packet.total_length > 0)
00024 
00025 static connector_status_t tcp_initiate_send_packet(connector_data_t * const connector_ptr, uint8_t * const edp_header,
00026                                                     size_t const length, uint16_t const type,
00027                                                     send_complete_cb_t send_complete_cb, void * const user_data)
00028 {
00029     connector_status_t status = connector_working;
00030 
00031     /* Setup data to be sent. tcp_send_packet_process() will actually
00032      * send out the data.
00033      */
00034 
00035     ASSERT_GOTO(edp_header != NULL, done);
00036     ASSERT_GOTO(length <= UINT16_MAX, done);
00037 
00038     if (connector_ptr->edp_data.send_packet.total_length > 0)
00039     {
00040         connector_debug_printf("tcp_initiate_send_packet: unable to trigger another send since previous data is still pending\n");
00041         status = connector_pending;
00042         goto done;
00043     }
00044 
00045     /*
00046      * MTv2 (and later)...
00047      * Packet format for MT version:
00048      *    ------------------------
00049      *   | 0 - 1 | 2 - 3  | 4 ... |
00050      *    ------------------------
00051      *   |  type | length |  data |
00052      *    ------------------------
00053      *   |   EDP Header   |
00054      *    ----------------
00055      *
00056      *
00057     */
00058 
00059     /* total bytes to be sent to Device Cloud (packet data length + the edp header length) */
00060     connector_ptr->edp_data.send_packet.total_length = length + PACKET_EDP_HEADER_SIZE;
00061     connector_ptr->edp_data.send_packet.ptr = edp_header;
00062 
00063     message_store_be16(edp_header, type, type);
00064 
00065     {
00066         uint16_t const length16 = (uint16_t) length;
00067 
00068         ASSERT(length <= UINT16_MAX);
00069         message_store_be16(edp_header, length, length16);
00070     }
00071 
00072     /* clear the actual number of bytes to be sent */
00073     connector_ptr->edp_data.send_packet.bytes_sent = 0;
00074     connector_ptr->edp_data.send_packet.complete_cb = send_complete_cb;
00075     connector_ptr->edp_data.send_packet.user_data = user_data;
00076 done:
00077     return status;
00078 }
00079 
00080 static connector_status_t tcp_initiate_send_facility_packet(connector_data_t * const connector_ptr, uint8_t * const edp_header,
00081                                                              size_t const length, uint16_t const facility,
00082                                                              send_complete_cb_t send_complete_cb, void * const user_data)
00083 {
00084     uint8_t * const edp_protocol = edp_header + PACKET_EDP_HEADER_SIZE;
00085 
00086 
00087     /* this function is to set up a facility packet to be sent.
00088      * Setup security coding, discovery payload & facility.
00089      *
00090      * facility packet:
00091      *    -------------------------------------------------------------------------------------
00092      *   | 0 - 1 | 2 - 3  |         4            |        5          |  6 - 7   |     8...     |
00093      *    -------------------------------------------------------------------------------------
00094      *   |  type | length | data security coding | discovery payload | facility | facility data|
00095      *    -------------------------------------------------------------------------------------
00096      *   |   EDP Header   |                   EDP  Protocol                     |
00097      *    ----------------------------------------------------------------------
00098      */
00099     message_store_u8(edp_protocol, sec_coding, SECURITY_PROTO_NONE);
00100     message_store_u8(edp_protocol, payload, DISC_OP_PAYLOAD);
00101     message_store_be16(edp_protocol, facility, facility);
00102 
00103 
00104     return tcp_initiate_send_packet(connector_ptr, edp_header,
00105                                 (length + PACKET_EDP_PROTOCOL_SIZE),
00106                                 E_MSG_MT2_TYPE_PAYLOAD,
00107                                 send_complete_cb,
00108                                 user_data);
00109 }
00110 
00111 static connector_callback_status_t tcp_send_buffer(connector_data_t * const connector_ptr, uint8_t * const buffer, size_t * const length)
00112 {
00113     connector_callback_status_t status;
00114     connector_network_send_t send_data;
00115     connector_request_id_t request_id;
00116 
00117     send_data.buffer = buffer;
00118     send_data.bytes_available = *length;
00119     send_data.bytes_used = 0;
00120     send_data.handle = connector_ptr->edp_data.network_handle;
00121 
00122     request_id.network_request = connector_request_id_network_send;
00123     status = connector_callback(connector_ptr->callback, connector_class_id_network_tcp, request_id, &send_data);
00124     ASSERT(status != connector_callback_unrecognized);
00125     switch (status)
00126     {
00127     case connector_callback_continue:
00128         *length = send_data.bytes_used;
00129         if (*length > 0)
00130         {
00131             /* Retain the "last (RX) message send" time. */
00132             if (get_system_time(connector_ptr, &connector_ptr->edp_data.keepalive.last_rx_sent_time) != connector_working)
00133             {
00134                 status = connector_callback_abort;
00135             }
00136         }
00137         break;
00138     case connector_callback_busy:
00139         *length = 0;
00140         break;
00141     case connector_callback_unrecognized:
00142         status = connector_callback_abort;
00143         /* no break */
00144     case connector_callback_abort:
00145         break;
00146     case connector_callback_error:
00147         edp_set_close_status(connector_ptr, connector_close_status_device_error);
00148         break;
00149     }
00150 
00151     return status;
00152 }
00153 
00154 static connector_status_t tcp_release_packet_buffer(connector_data_t * const connector_ptr, uint8_t const * const packet, connector_status_t const status, void * const user_data)
00155 {
00156     /* this is called when the Connector is done sending or after tcp_get_packet_buffer()
00157      * is called to release connector_ptr->edp_data.send_packet.packet_buffer.buffer.
00158      *
00159      */
00160     UNUSED_PARAMETER(status);
00161     UNUSED_PARAMETER(packet);
00162     UNUSED_PARAMETER(user_data);
00163 
00164     ASSERT(connector_ptr->edp_data.send_packet.packet_buffer.buffer == packet);
00165 
00166     connector_ptr->edp_data.send_packet.packet_buffer.in_use = connector_false;
00167 
00168     return connector_working;
00169 }
00170 #if (defined CONNECTOR_DEBUG)
00171 static unsigned int debug_count = 0;
00172 #endif
00173 
00174 static uint8_t * tcp_get_packet_buffer(connector_data_t * const connector_ptr, uint16_t const facility, uint8_t ** data_ptr, size_t * data_length)
00175 {
00176 #define MIN_EDP_MESSAGE_SIZE    (PACKET_EDP_HEADER_SIZE +CLOUD_URL_LENGTH)
00177     uint8_t * packet = NULL;
00178     uint8_t * ptr = NULL;
00179     size_t length = 0;
00180 
00181     /* Return a pointer to caller to setup data to be sent to Device Cloud.
00182      * Must call tcp_release_packet_buffer() to release the buffer (pass
00183      * tcp_release_packet_buffer as complete_callback to tcp_initiate_send_packet()
00184      * or tcp_initiate_send_facility_packet().
00185      */
00186 
00187 
00188      /* make sure no send is pending */
00189     if ((connector_ptr->edp_data.send_packet.total_length == 0) &&
00190         (!connector_ptr->edp_data.send_packet.packet_buffer.in_use))
00191     {
00192         connector_ptr->edp_data.send_packet.packet_buffer.in_use = connector_true;
00193 
00194         packet = connector_ptr->edp_data.send_packet.packet_buffer.buffer;
00195 
00196         /* set ptr to the data portion */
00197         ptr = GET_PACKET_DATA_POINTER(packet, PACKET_EDP_HEADER_SIZE);
00198 
00199         if (facility != E_MSG_MT2_MSG_NUM)
00200         {
00201             /* set ptr to the data portion of facility packet */
00202             ptr += PACKET_EDP_PROTOCOL_SIZE;
00203         }
00204 
00205         {
00206             size_t const max_packet_size = sizeof connector_ptr->edp_data.send_packet.packet_buffer.buffer;
00207             size_t const header_size = (size_t)(ptr - packet);
00208 
00209             ASSERT(max_packet_size >= MIN_EDP_MESSAGE_SIZE);
00210             ASSERT(ptr > packet);
00211             length = max_packet_size - header_size;
00212         }
00213 #if (defined CONNECTOR_DEBUG)
00214         debug_count = 0;
00215 #endif
00216 
00217     }
00218 #if (defined CONNECTOR_DEBUG)
00219     else
00220     {
00221         if (debug_count == 0)
00222            connector_debug_printf("tcp_get packet buffer: send pending\n");
00223 
00224         debug_count++;
00225     }
00226 #endif
00227     if (data_ptr != NULL)
00228     {
00229         *data_ptr = ptr;
00230     }
00231 
00232     if (data_length != NULL)
00233     {
00234         *data_length = length;
00235     }
00236 
00237     return packet;
00238 }
00239 
00240 static connector_status_t tcp_rx_keepalive_process(connector_data_t * const connector_ptr)
00241 {
00242    connector_status_t status = connector_idle;
00243 
00244     if (edp_get_active_state(connector_ptr) == connector_transport_open)
00245     {
00246         goto done;
00247     }
00248 
00249     /* Sends rx keepalive if keepalive timing is expired.
00250      *
00251      * last_rx_keepalive_time is last time we sent Rx keepalive.
00252      */
00253     if (is_valid_timing_limit(connector_ptr, connector_ptr->edp_data.keepalive.last_rx_sent_time, GET_RX_KEEPALIVE_INTERVAL(connector_ptr)))
00254     {
00255         /* not expired yet. no need to send rx keepalive */
00256         goto done;
00257     }
00258 
00259     connector_debug_printf("tcp_rx_keepalive_process: time to send Rx keepalive\n");
00260 
00261     status = tcp_initiate_send_packet(connector_ptr, connector_ptr->edp_data.keepalive.send_rx_packet, 0, E_MSG_MT2_TYPE_KA_KEEPALIVE, NULL, NULL);
00262 
00263 done:
00264     return status;
00265 }
00266 
00267 static connector_status_t tcp_send_complete_callback(connector_data_t * const connector_ptr, connector_status_t status)
00268 {
00269     connector_status_t result = connector_working;
00270     send_complete_cb_t callback = connector_ptr->edp_data.send_packet.complete_cb;
00271 
00272     if (callback != NULL)
00273     {
00274         connector_ptr->edp_data.send_packet.complete_cb = NULL;
00275         result = callback(connector_ptr, connector_ptr->edp_data.send_packet.ptr, status, connector_ptr->edp_data.send_packet.user_data);
00276         ASSERT(result != connector_pending);
00277     }
00278 
00279     return result;
00280 }
00281 
00282 static connector_status_t edp_tcp_send_process(connector_data_t * const connector_ptr)
00283 {
00284     connector_status_t result = connector_idle;
00285 
00286     /* if nothing needs to be sent, check whether we need to send rx keepalive */
00287     if (connector_ptr->edp_data.send_packet.total_length == 0)
00288     {
00289 
00290         result = tcp_rx_keepalive_process(connector_ptr);
00291     }
00292 
00293     if (connector_ptr->edp_data.send_packet.total_length > 0)
00294     {
00295         /* We have something to be sent */
00296 
00297         uint8_t * const buf = connector_ptr->edp_data.send_packet.ptr + connector_ptr->edp_data.send_packet.bytes_sent;
00298         size_t length = connector_ptr->edp_data.send_packet.total_length;
00299 
00300         connector_callback_status_t const status = tcp_send_buffer(connector_ptr, buf, &length);
00301 
00302         switch (status)
00303         {
00304             case connector_callback_continue:
00305                 connector_ptr->edp_data.send_packet.total_length -= length;
00306                 connector_ptr->edp_data.send_packet.bytes_sent += length;
00307 
00308                 if (connector_ptr->edp_data.send_packet.total_length == 0)
00309                 {   /* sent completed so let's call the complete callback */
00310                     result = tcp_send_complete_callback(connector_ptr, connector_success);
00311                 }
00312                 else if (connector_ptr->edp_data.send_packet.total_length > 0)
00313                 {
00314                     result = connector_pending;
00315                 }
00316                 break;
00317 
00318             case connector_callback_busy:
00319                 result = connector_pending;
00320                 goto done;
00321 
00322             case connector_callback_error:
00323                 edp_set_close_status(connector_ptr, connector_close_status_device_error);
00324                 edp_set_active_state(connector_ptr, connector_transport_close);
00325                 break;
00326             case connector_callback_abort:
00327                 edp_set_close_status(connector_ptr, connector_close_status_abort);
00328                 edp_set_active_state(connector_ptr, connector_transport_close);
00329                 break;
00330             default:
00331                 ASSERT(connector_false);
00332                 break;
00333         }
00334     }
00335 
00336 done:
00337     return result;
00338 
00339 }
00340 
00341 
00342