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

« Back to documentation index

Show/hide line numbers connector_sm_recv.h Source File

connector_sm_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 #if (defined CONNECTOR_TRANSPORT_SMS)
00013 static connector_status_t sm_decode_segment(connector_data_t * const connector_ptr, connector_sm_packet_t * const recv_ptr)
00014 {
00015     size_t const data_size = 1 + ((recv_ptr->total_bytes - recv_ptr->processed_bytes) * 4)/5;
00016     void * data_ptr = NULL;
00017     connector_status_t result = malloc_data_buffer(connector_ptr, data_size, named_buffer_id(sm_data_block), &data_ptr);
00018 
00019     if (result == connector_working)
00020     {
00021         recv_ptr->total_bytes = sm_decode85(data_ptr, data_size, recv_ptr->data + recv_ptr->processed_bytes, recv_ptr->total_bytes - recv_ptr->processed_bytes);
00022         memcpy(recv_ptr->data, data_ptr, recv_ptr->total_bytes);
00023         result = free_data_buffer(connector_ptr, named_buffer_id(sm_data_block), data_ptr);
00024     }
00025 
00026     return result;
00027 }
00028 
00029 static connector_status_t sm_verify_sms_preamble(connector_sm_data_t * const sm_ptr)
00030 {
00031     connector_status_t result = connector_working;
00032 
00033     if (sm_ptr->transport.id_length > 0)
00034     {
00035         uint8_t * const data_ptr = sm_ptr->network.recv_packet.data;
00036         char const prefix = '(';
00037         char const suffix[] = "):";
00038         size_t const suffix_bytes = sizeof suffix - 1;
00039         size_t const prefix_bytes = sizeof prefix;
00040         size_t const suffix_position = prefix_bytes + sm_ptr->transport.id_length;
00041         connector_bool_t const valid_prefix = connector_bool(*data_ptr == prefix);
00042         connector_bool_t const valid_shared_key = connector_bool(memcmp(data_ptr + prefix_bytes, sm_ptr->transport.id, sm_ptr->transport.id_length) == 0);
00043         connector_bool_t const valid_suffix = connector_bool(memcmp(data_ptr + suffix_position, suffix, suffix_bytes) == 0);
00044 
00045         if (valid_prefix && valid_shared_key && valid_suffix)
00046             sm_ptr->network.recv_packet.processed_bytes = suffix_position + suffix_bytes;
00047         else
00048         {
00049             connector_debug_printf("sm_verify_sms_preamble: valid_prefix=%d, valid_shared_key=%d, valid_suffix=%d\n", valid_prefix, valid_shared_key, valid_suffix);
00050             connector_debug_printf("%s\n",(char *)data_ptr);
00051 
00052             result = connector_invalid_response;
00053         }
00054     }
00055 
00056     return result;
00057 }
00058 #endif
00059 
00060 #if (defined CONNECTOR_TRANSPORT_UDP)
00061 static connector_status_t sm_verify_udp_header(connector_sm_data_t * const sm_ptr)
00062 {
00063     connector_status_t result = connector_invalid_response;
00064     connector_sm_packet_t * const recv_ptr = &sm_ptr->network.recv_packet;
00065     uint8_t * data_ptr = recv_ptr->data;
00066     uint8_t const version_and_type = *data_ptr++;
00067     uint8_t const version = version_and_type >> 4;
00068     connector_sm_id_type_t const type = (connector_sm_id_type_t)(version_and_type & 0x0F);
00069 
00070     if (version != SM_UDP_VERSION)
00071     {
00072         connector_debug_printf("sm_verify_udp_header: invalid SM UDP version [%d]\n", version);
00073         result = connector_abort;
00074         goto error;
00075     }
00076 
00077     if (type != sm_ptr->transport.id_type)
00078         goto done;
00079 
00080     if (memcmp(data_ptr, sm_ptr->transport.id, sm_ptr->transport.id_length))
00081         goto done; /* not for us */
00082 
00083     recv_ptr->processed_bytes = sm_ptr->transport.id_length + 1;
00084     result = connector_working;
00085 
00086 done:
00087 error:
00088     return result;
00089 }
00090 #endif
00091 
00092 #if (defined CONNECTOR_SM_MULTIPART)
00093 static connector_status_t sm_multipart_allocate(connector_data_t * const connector_ptr, connector_sm_data_t * const sm_ptr, connector_sm_session_t * const session)
00094 {
00095     connector_status_t status = connector_working;
00096     size_t const max_payload_bytes = sm_get_max_payload_bytes(sm_ptr);
00097     size_t const max_session_bytes = (((max_payload_bytes * session->segments.count) + 3)/4) * 4; /* make sure it is word aligned */
00098     size_t const size_array_bytes = sizeof(*session->segments.size_array) * session->segments.count;
00099 
00100     ASSERT_GOTO(session->in.data == NULL, error);
00101     session->in.bytes = max_session_bytes + size_array_bytes;
00102     status = sm_allocate_user_buffer(connector_ptr, &session->in);
00103     ASSERT_GOTO(status == connector_working, error);
00104     session->segments.size_array = (void *)(session->in.data + max_session_bytes); /* alignment issue is taken care where max_session_bytes is defined */
00105     memset(session->segments.size_array, 0, size_array_bytes);
00106 
00107 error:
00108     return status;
00109 }
00110 #endif
00111 
00112 static connector_status_t sm_more_data_callback(connector_data_t * const connector_ptr, connector_sm_data_t * const sm_ptr)
00113 {
00114     connector_status_t result;
00115     connector_request_id_t request_id;
00116     connector_callback_status_t callback_status;
00117     connector_sm_more_data_t cb_data;
00118 
00119     cb_data.transport = sm_ptr->network.transport;
00120     request_id.sm_request = connector_request_id_sm_more_data;
00121     callback_status = connector_callback(connector_ptr->callback, connector_class_id_short_message, request_id, &cb_data);
00122     result = sm_map_callback_status_to_connector_status(callback_status);
00123 
00124     return result;
00125 }
00126 
00127 typedef struct
00128 {
00129     uint32_t request_id;
00130     size_t bytes;
00131 
00132     connector_bool_t isRequest;
00133     connector_bool_t isResponseNeeded;
00134     connector_bool_t isPackCmd;
00135     connector_bool_t isMultipart;
00136     connector_bool_t isCompressed;
00137     connector_bool_t isError;
00138 
00139     connector_sm_cmd_t command;
00140 
00141     enum
00142     {
00143         sm_single_segment,
00144         sm_multipart_first_segment,
00145         sm_multipart_subsequent_segment
00146     } type;
00147 
00148     struct
00149     {
00150         uint8_t count;
00151         uint8_t number;
00152     } segment;
00153 
00154     uint16_t crc16;
00155     uint8_t cmd_status;
00156 } sm_header_t;
00157 
00158 static connector_status_t sm_process_header(connector_sm_packet_t * const recv_ptr, sm_header_t * const header)
00159 {
00160     connector_status_t result = connector_invalid_payload_packet;
00161     uint8_t * data_ptr = &recv_ptr->data[recv_ptr->processed_bytes];
00162     uint8_t * const segment = data_ptr;
00163 
00164     header->segment.count = 1;
00165     header->segment.number = 0;
00166     header->bytes = 0;
00167     header->command = connector_sm_cmd_opaque_response;
00168     header->isError = connector_false;
00169     header->isCompressed = connector_false;
00170 
00171     {
00172         uint8_t const info_field = message_load_u8(segment, info);
00173         uint8_t const request_id_high_bits_mask = 0x03;
00174 
00175         header->request_id = (info_field & request_id_high_bits_mask) << 8;
00176         header->request_id |= message_load_u8(segment, request);
00177 
00178         header->isMultipart = SmIsMultiPart(info_field);
00179         header->isRequest = SmIsRequest(info_field);
00180         header->isResponseNeeded = SmIsResponseNeeded(info_field);
00181     }
00182 
00183     if (header->isMultipart)
00184     {
00185         #if (defined CONNECTOR_SM_MULTIPART)
00186         {
00187             uint8_t * const segment0 = data_ptr;
00188 
00189             header->segment.number = message_load_u8(segment0, segment);
00190             if (header->segment.number > 0)
00191             {
00192                 uint8_t * const segmentn = data_ptr;
00193 
00194                 header->cmd_status = 0;
00195                 header->type = sm_multipart_subsequent_segment;
00196 
00197                 if (header->isPackCmd)
00198                 {
00199                     header->bytes = record_end(segmentn) - sizeof header->crc16;
00200                 }
00201                 else
00202                 {
00203                     header->crc16 = message_load_be16(segmentn, crc);
00204                     message_store_be16(segmentn, crc, 0);
00205                     header->bytes = record_end(segmentn);
00206                 }
00207             }
00208             else
00209             {
00210                 header->type = sm_multipart_first_segment;
00211                 header->segment.count = message_load_u8(segment0, count);
00212                 header->cmd_status = message_load_u8(segment0, cmd_status);
00213 
00214                 if (header->isPackCmd)
00215                 {
00216                     header->bytes = record_end(segment0) - sizeof header->crc16;
00217                 }
00218                 else
00219                 {
00220                     header->crc16 = message_load_be16(segment0, crc);
00221                     message_store_be16(segment0, crc, 0);
00222                     header->bytes = record_end(segment0);
00223                 }
00224             }
00225         }
00226         #else
00227         {
00228             connector_debug_printf("Received multipart packet, but multipart is disabled\n");
00229             connector_debug_printf("Review CONNECTOR_SM_MULTIPART and CONNECTOR_SM_MAX_RX_SEGMENTS defines\n");
00230             goto error;
00231         }
00232         #endif
00233     }
00234     else
00235     {
00236         header->cmd_status = message_load_u8(segment, cmd_status);
00237         if (header->isPackCmd)
00238         {
00239             header->bytes = record_end(segment) - sizeof header->crc16;
00240         }
00241         else
00242         {
00243             header->crc16 = message_load_be16(segment, crc);
00244             message_store_be16(segment, crc, 0);
00245             header->bytes = record_end(segment);
00246         }
00247     }
00248 
00249     header->isCompressed = SmIsCompressed(header->cmd_status);
00250     #if !(defined CONNECTOR_COMPRESSION)
00251     if (header->isCompressed)
00252     {
00253         connector_debug_printf("sm_process_header: Received compressed packet, but compression is disabled!\n");
00254         goto error;
00255     }
00256     #endif
00257 
00258     if (header->isRequest)
00259     {
00260         header->command = (connector_sm_cmd_t)(header->cmd_status & 0x7F);
00261         if (header->isPackCmd && (header->command == connector_sm_cmd_pack))
00262         {
00263             connector_debug_printf("sm_process_header: Pack command inside a pack command is not allowed!\n");
00264             goto error;
00265         }
00266         header->isError = connector_false;
00267     }
00268     else
00269     {
00270         header->isError = SmIsError(header->cmd_status);
00271         header->command = connector_sm_cmd_opaque_response;
00272     }
00273  
00274     if (!header->isPackCmd)
00275     {
00276         size_t const sm_bytes = recv_ptr->total_bytes - recv_ptr->processed_bytes;
00277         uint16_t calculated_crc = 0;
00278 
00279         calculated_crc = sm_calculate_crc16(calculated_crc, data_ptr, sm_bytes);
00280         if(calculated_crc != header->crc16)
00281         {
00282             connector_debug_printf("sm_process_header: crc error!\n");
00283             goto error;
00284         }
00285 
00286         if (header->isRequest)
00287             header->isPackCmd = connector_bool(header->command == connector_sm_cmd_pack);
00288     }
00289 
00290     recv_ptr->processed_bytes += header->bytes;
00291     result = connector_working;
00292 
00293 error:
00294     return result;
00295 }
00296 
00297 static connector_status_t sm_update_session(connector_data_t * const connector_ptr, connector_sm_data_t * const sm_ptr,
00298                                             sm_header_t * const header, size_t const payload_bytes)
00299 {
00300     connector_status_t result = connector_invalid_payload_packet;
00301     connector_sm_packet_t * const recv_ptr = &sm_ptr->network.recv_packet;
00302     connector_bool_t const client_originated = connector_bool(!header->isRequest);
00303     connector_sm_session_t * session = get_sm_session(sm_ptr, header->request_id, client_originated);
00304 
00305     if (session == NULL)
00306     {
00307         session = sm_create_session(connector_ptr, sm_ptr, connector_false);
00308         if (session == NULL)
00309         {
00310             result = connector_pending;
00311             goto error;
00312         }
00313 
00314         session->request_id = header->request_id;
00315         session->command = client_originated ? connector_sm_cmd_opaque_response : header->command;
00316     }
00317 
00318     if (header->segment.number == 0)
00319     {
00320         if (header->isCompressed) SmSetCompressed(session->flags);
00321 
00322         if (header->isRequest)
00323         {
00324             if (header->isResponseNeeded) SmSetResponseNeeded(session->flags);
00325             /* If the first segment of a multipart SMS that arrived was not segment0, previously stored session->command information is wrong as 
00326              * for multipart messages, type is only included in the 0th segment. Update it here */
00327             session->command = header->command;
00328         }
00329         else if (header->isError)
00330         {
00331             uint16_t const error_value = LoadBE16(&recv_ptr->data[recv_ptr->processed_bytes]);
00332 
00333             switch (error_value)
00334             {
00335                 case connector_sm_error_in_request:
00336                     session->error = connector_sm_error_in_request;
00337                     break;
00338 
00339                 case connector_sm_error_unavailable:
00340                     session->error = connector_sm_error_unavailable;
00341                     break;
00342 
00343                 default:
00344                     session->error = connector_sm_error_unknown;
00345                     break;
00346             }
00347 
00348             SmSetError(session->flags);
00349             recv_ptr->processed_bytes += sizeof error_value;
00350         }
00351 
00352         session->segments.count = header->segment.count;
00353     }
00354 
00355     #if (defined CONNECTOR_SM_MULTIPART)
00356     if (header->isMultipart)
00357     {
00358         SmSetMultiPart(session->flags);
00359         if (session->in.data == NULL)
00360         {
00361             if (header->segment.number > 0)
00362                 session->segments.count = sm_ptr->session.max_segments;
00363 
00364             result = sm_multipart_allocate(connector_ptr, sm_ptr, session);
00365             ASSERT_GOTO(result == connector_working, error);
00366             ASSERT_GOTO(session->in.data != NULL, error);
00367         }
00368 
00369         if (session->segments.size_array[header->segment.number] == 0)
00370         {
00371             size_t const max_payload_bytes = sm_get_max_payload_bytes(sm_ptr);
00372             uint8_t * copy_to = session->in.data + (header->segment.number * max_payload_bytes);
00373 
00374             session->segments.size_array[header->segment.number] = payload_bytes;
00375             memcpy(copy_to, &recv_ptr->data[recv_ptr->processed_bytes], payload_bytes);
00376             session->segments.processed++;
00377         }
00378         else
00379         {
00380             connector_debug_printf("sm_update_session: duplicate segment %d, in id %d\n", header->segment.number, session->request_id);
00381         }
00382     }
00383     else
00384     #endif
00385     {
00386         session->in.bytes = payload_bytes;
00387         if (payload_bytes > 0)
00388         {
00389             result = sm_allocate_user_buffer(connector_ptr, &session->in);
00390             ASSERT_GOTO(result == connector_working, error);
00391             memcpy(session->in.data, &recv_ptr->data[recv_ptr->processed_bytes], payload_bytes);
00392         }
00393         else
00394             session->in.data = NULL;
00395         session->segments.processed++;
00396     }
00397 
00398     if (session->segments.processed >= session->segments.count)
00399     {
00400         session->bytes_processed = 0;
00401         session->segments.processed = 0;
00402         session->sm_state = connector_sm_state_process_payload;
00403 
00404         #if (defined CONNECTOR_COMPRESSION)
00405         if (SmIsCompressed(session->flags))
00406         {
00407             session->compress.out.data = NULL;
00408             session->sm_state = connector_sm_state_decompress;
00409         }
00410         #endif
00411     }
00412 
00413     recv_ptr->processed_bytes += payload_bytes;
00414     result = connector_working;
00415 
00416 error:
00417     return result;
00418 }
00419 
00420 static connector_status_t sm_process_packet(connector_data_t * const connector_ptr, connector_sm_data_t * const sm_ptr)
00421 {
00422     sm_header_t sm_header;
00423     connector_status_t result;
00424     connector_sm_packet_t * const recv_ptr = &sm_ptr->network.recv_packet;
00425     size_t sm_bytes = recv_ptr->total_bytes - recv_ptr->processed_bytes;
00426 
00427     sm_header.isPackCmd = connector_false;
00428     sm_header.crc16 = 0;
00429     do
00430     {
00431         result = sm_process_header(recv_ptr, &sm_header);
00432         if (result != connector_working) goto error;
00433 
00434         if ((sm_header.segment.count > sm_ptr->session.max_segments) || (sm_header.segment.number >= sm_ptr->session.max_segments))
00435         {
00436             connector_debug_printf("sm_process_packet: Exceeded maximum segments [%" PRIsize "/%" PRIsize "]!\n", sm_header.segment.count, sm_ptr->session.max_segments);
00437             connector_debug_printf("Review CONNECTOR_SM_MULTIPART and CONNECTOR_SM_MAX_RX_SEGMENTS defines\n");
00438             goto error;
00439         }
00440 
00441         if (sm_header.command == connector_sm_cmd_pack)
00442         {
00443             enum sm_pack_t
00444             {
00445                 field_define(pack_header, flag, uint8_t),
00446                 field_define(pack_header, length, uint16_t),
00447                 record_end(pack_header)
00448             };
00449             uint8_t * const pack_header = &recv_ptr->data[recv_ptr->processed_bytes];
00450             uint8_t const flag = message_load_u8(pack_header, flag);
00451 
00452             #define SM_MESSAGE_PENDING 0x01
00453             if ((flag & SM_MESSAGE_PENDING) == SM_MESSAGE_PENDING)
00454             {
00455                 result = sm_more_data_callback(connector_ptr, sm_ptr);
00456                 if (result != connector_working) goto error;
00457             }
00458             #undef SM_MESSAGE_PENDING
00459 
00460             sm_bytes = message_load_be16(pack_header, length);
00461             recv_ptr->processed_bytes += record_end(pack_header);
00462             continue;
00463         }
00464 
00465         {
00466             size_t const payload_bytes = sm_bytes - sm_header.bytes;
00467 
00468             ASSERT(sm_bytes >= sm_header.bytes);
00469             result = sm_update_session(connector_ptr, sm_ptr, &sm_header, payload_bytes);
00470         }
00471 
00472         if (!sm_header.isPackCmd) break;
00473 
00474         {
00475             size_t const sm_header_size = 5;
00476             size_t const remaining_bytes = recv_ptr->total_bytes - recv_ptr->processed_bytes;
00477 
00478             if (remaining_bytes < sm_header_size) break;
00479         }
00480 
00481         sm_bytes = LoadBE16(&recv_ptr->data[recv_ptr->processed_bytes]);
00482         recv_ptr->processed_bytes += sizeof(uint16_t);
00483 
00484     } while (recv_ptr->processed_bytes < recv_ptr->total_bytes);
00485 
00486     result = connector_working;
00487 
00488 error:
00489     if (result == connector_invalid_payload_packet)  /* unreliable method, so silently ignore the packet */
00490         result = connector_working;
00491 
00492     recv_ptr->total_bytes = 0;
00493     recv_ptr->processed_bytes = 0;
00494 
00495     return result;
00496 }
00497 
00498 static connector_status_t sm_receive_data(connector_data_t * const connector_ptr, connector_sm_data_t * const sm_ptr)
00499 {
00500     connector_status_t result = connector_pending;
00501     connector_sm_packet_t * const recv_ptr = &sm_ptr->network.recv_packet;
00502     connector_callback_status_t status;
00503     connector_request_id_t request_id;
00504     connector_network_receive_t read_data;
00505 
00506     if (recv_ptr->total_bytes > 0) goto done;
00507 
00508     read_data.handle = sm_ptr->network.handle;
00509     read_data.buffer = recv_ptr->data;
00510     read_data.bytes_available = sm_ptr->transport.mtu;
00511     read_data.bytes_used = 0;
00512 
00513     request_id.network_request = connector_request_id_network_receive;
00514     status = connector_callback(connector_ptr->callback, sm_ptr->network.class_id, request_id, &read_data);
00515     ASSERT(status != connector_callback_unrecognized);
00516     switch (status)
00517     {
00518         case connector_callback_busy:
00519             result = connector_idle;
00520             goto done;
00521 
00522         case connector_callback_continue:
00523             recv_ptr->total_bytes = read_data.bytes_used;
00524             recv_ptr->processed_bytes = 0;
00525 
00526             switch (sm_ptr->network.transport)
00527             {
00528                 #if (defined CONNECTOR_TRANSPORT_SMS)
00529                 case connector_transport_sms:
00530                     result = sm_verify_sms_preamble(sm_ptr);
00531                     switch(result)
00532                     {
00533                         case connector_working:
00534                             break;
00535                         case connector_invalid_response:
00536                             /* not Device Cloud packet? Ignore the packet */
00537                             recv_ptr->total_bytes = 0;
00538                             recv_ptr->processed_bytes = 0;
00539                             result = connector_working;
00540                             goto done;
00541                         default:
00542                             goto done;
00543                     }
00544                                                                 
00545                     result = sm_decode_segment(connector_ptr, recv_ptr);
00546 
00547                     /* Remove sms preamble */
00548                     sm_ptr->network.recv_packet.processed_bytes = 0;
00549 
00550                     break;
00551                 #endif
00552 
00553                 #if (defined CONNECTOR_TRANSPORT_UDP)
00554                 case connector_transport_udp:
00555                     result = sm_verify_udp_header(sm_ptr);
00556                     break;
00557                 #endif
00558 
00559                 default:
00560                     ASSERT_GOTO(connector_false, done);
00561                     break;
00562             }
00563 
00564             if(result != connector_working) goto done; /* not Device Cloud packet? */
00565                 result = sm_process_packet(connector_ptr, sm_ptr);
00566             break;
00567 
00568         case connector_callback_abort:
00569             result = connector_abort;
00570             break;
00571 
00572         default:
00573             connector_debug_printf("sm_receive_data: callback returned error [%d]\n", status);
00574             result = connector_device_error;
00575             break;
00576     }
00577 
00578     sm_verify_result(sm_ptr, &result);
00579 
00580 done:
00581     return result;
00582 }
00583 
00584 #if (defined CONNECTOR_COMPRESSION)
00585 static connector_status_t sm_decompress_data(connector_data_t * const connector_ptr, connector_sm_data_t * const sm_ptr, connector_sm_session_t * const session)
00586 {
00587     connector_status_t status = connector_working;
00588     size_t const max_payload_bytes = sm_get_max_payload_bytes(sm_ptr);
00589     uint8_t zlib_header[] = {0x58, 0xC3};
00590     z_streamp const zlib_ptr = &session->compress.zlib;
00591     int zret;
00592 
00593     if (session->compress.out.data == NULL)
00594     {
00595         session->compress.out.bytes = max_payload_bytes;
00596         status = sm_allocate_user_buffer(connector_ptr, &session->compress.out);
00597         ASSERT_GOTO(status == connector_working, done);
00598 
00599         memset(zlib_ptr, 0, sizeof *zlib_ptr);
00600         zret = inflateInit(zlib_ptr);
00601         ASSERT_GOTO(zret == Z_OK, error);
00602         zlib_ptr->next_out = session->compress.out.data;
00603         zlib_ptr->avail_out = session->compress.out.bytes;
00604         zlib_ptr->next_in = zlib_header;
00605         zlib_ptr->avail_in = sizeof zlib_header;
00606     }
00607 
00608     while (zlib_ptr->avail_out > 0)
00609     {
00610         if (zlib_ptr->avail_in == 0)
00611         {
00612             if (session->segments.processed == session->segments.count)
00613             {
00614                 SmSetLastData(session->flags);
00615                 break;
00616             }
00617             else
00618             {
00619                 size_t const data_index = session->segments.processed * max_payload_bytes;
00620 
00621                 zlib_ptr->next_in = &session->in.data[data_index];
00622                 zlib_ptr->avail_in = SmIsMultiPart(session->flags) ? session->segments.size_array[session->segments.processed] : session->in.bytes;
00623                 session->segments.processed++;
00624             }
00625         }
00626 
00627         zret = inflate(zlib_ptr, Z_NO_FLUSH);
00628         switch(zret)
00629         {
00630             case Z_STREAM_END:
00631             case Z_BUF_ERROR:
00632             case Z_OK:
00633                 break;
00634 
00635             default:
00636                 status = connector_abort;
00637                 connector_debug_printf("ZLIB Return value [%d]\n", zret);
00638                 ASSERT_GOTO(connector_false, error);
00639                 break;
00640         }
00641     }
00642 
00643     {
00644         size_t const payload_bytes = session->compress.out.bytes - zlib_ptr->avail_out;
00645 
00646         status = sm_pass_user_data(connector_ptr, session, session->compress.out.data, payload_bytes);
00647         switch (status)
00648         {
00649             case connector_pending:
00650                 goto done;
00651 
00652             case connector_working:
00653                 if (SmIsNotLastData(session->flags))
00654                 {
00655                     zlib_ptr->next_out = session->compress.out.data;
00656                     zlib_ptr->avail_out = session->compress.out.bytes;
00657                     goto done;
00658                 }
00659                 break;
00660 
00661             default:
00662                 break;
00663         }
00664     }
00665 
00666 error:
00667     zret = inflateEnd(zlib_ptr);
00668     ASSERT(zret == Z_OK);
00669 
00670     if (status != connector_abort)
00671     {
00672         status = free_data_buffer(connector_ptr, named_buffer_id(sm_data_block), session->compress.out.data);
00673         session->compress.out.data = NULL;
00674     }
00675 
00676 done:
00677     return status;
00678 }
00679 #endif
00680 
00681 static connector_status_t sm_handle_error(connector_data_t * const connector_ptr, connector_sm_session_t * const session)
00682 {
00683     connector_status_t result = connector_working;
00684     connector_sm_state_t next_state = connector_sm_state_complete;
00685 
00686     if (SmIsCloudOwned(session->flags) && SmIsRequest(session->flags))
00687         next_state = connector_sm_state_send_data;
00688 
00689     SmSetError(session->flags);
00690     if (session->user.context != NULL) /* let the user know */
00691     {
00692         result = sm_inform_session_complete(connector_ptr, session);
00693         if (result != connector_working) goto error;
00694     }
00695 
00696     result = sm_switch_path(connector_ptr, session, next_state);
00697 
00698 error:
00699     return result;
00700 }
00701 
00702 static connector_status_t sm_handle_complete(connector_data_t * const connector_ptr, connector_sm_data_t * const sm_ptr, connector_sm_session_t * const session)
00703 {
00704     connector_status_t result = connector_working;
00705 
00706     if (session->in.data != NULL)
00707     {
00708         result = free_data_buffer(connector_ptr, named_buffer_id(sm_data_block), session->in.data);
00709         if (result != connector_working) goto error;
00710     }
00711 
00712     if (SmIsReboot(session->flags))
00713         result = sm_process_reboot(connector_ptr);
00714 
00715     switch(result)
00716     {
00717         case connector_abort:
00718             /* Keep connector_abort as the result */
00719             sm_delete_session(connector_ptr, sm_ptr, session);
00720             break;
00721         case connector_pending:
00722             break;
00723         default:
00724             result = sm_delete_session(connector_ptr, sm_ptr, session);
00725     }
00726 
00727 error:
00728     return result;
00729 }
00730 
00731 static connector_status_t sm_process_recv_path(connector_data_t * const connector_ptr, connector_sm_data_t * const sm_ptr, connector_sm_session_t * const session)
00732 {
00733     connector_status_t result = connector_abort;
00734 
00735     ASSERT_GOTO(session != NULL, error);
00736     switch (session->sm_state)
00737     {
00738         case connector_sm_state_receive_data:
00739             if (sm_ptr->timeout_in_seconds != SM_WAIT_FOREVER)
00740             {
00741                 unsigned long current_time = 0;
00742 
00743                 result = get_system_time(connector_ptr, &current_time);
00744                 ASSERT_GOTO(result == connector_working, error);
00745                 if (current_time > (session->start_time + sm_ptr->timeout_in_seconds))
00746                 {
00747                     session->sm_state = connector_sm_state_error;
00748                     session->error = connector_sm_error_timeout;
00749                     connector_debug_printf("Sm session [%u] timeout... start time:%u, current time:%u\n", session->request_id, session->start_time, current_time);
00750                 }
00751             }
00752 
00753             result = connector_idle; /* still receiving data, handled in sm_receive_data() */
00754             break;
00755 
00756         #if (defined CONNECTOR_COMPRESSION)
00757         case connector_sm_state_decompress:
00758             result = sm_decompress_data(connector_ptr, sm_ptr, session);
00759             break;
00760         #endif
00761 
00762         case connector_sm_state_process_payload:
00763             result = sm_process_payload(connector_ptr, sm_ptr, session);
00764             break;
00765 
00766         case connector_sm_state_complete:
00767             result = sm_handle_complete(connector_ptr, sm_ptr, session);
00768             break;
00769 
00770         case connector_sm_state_error:
00771             result = sm_handle_error(connector_ptr, session);
00772             break;
00773 
00774         default:
00775             ASSERT(connector_false);
00776             break;
00777     }
00778 
00779     sm_verify_result(sm_ptr, &result);
00780 
00781 error:
00782     return result;
00783 }
00784