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

« Back to documentation index

Show/hide line numbers rci_binary_output.h Source File

rci_binary_output.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 static void rci_set_output_error(rci_t * const rci, unsigned int const id, char const * const hint, rci_output_state_t state)
00013 {
00014     rci_global_error(rci, id, hint);
00015     set_rci_output_state(rci, state);
00016     state_call(rci, rci_parser_state_output);
00017 }
00018 
00019 static connector_bool_t rci_output_data(rci_t * const rci, rci_buffer_t * const output, uint8_t const * const data, size_t const bytes)
00020 {
00021     connector_bool_t const overflow = connector_bool(rci_buffer_remaining(output) < bytes);
00022 
00023     if (overflow)
00024     {
00025         rci->status = rci_status_flush_output;
00026     }
00027     else
00028     {
00029         memcpy(rci_buffer_position(output), data, bytes);
00030         rci_buffer_advance(output, bytes);
00031     }
00032 
00033     return overflow;
00034 }
00035 
00036 static size_t get_bytes_followed(uint32_t value)
00037 {
00038     /* Bytes needed for the value:
00039      * 1 byte is 0 to 0x7F
00040      * 2 bytes is 0 to 0x1FFF
00041      * 3 bytes is 0 to 0xFFFF
00042      * 5 bytes is 0 to 0xFFFFFFFF
00043      *
00044      * Get additional bytes needed according to the value.
00045      */
00046     size_t bytes = 0;
00047     if (value <= UINT32_C(0x7F))
00048     {
00049         bytes = 0;
00050     }
00051     else if (value < UINT32_C(0x2000))
00052     {
00053         bytes = 1;
00054     }
00055     else if (value < UINT32_C(0x10000))
00056     {
00057         bytes = 2;
00058     }
00059     else
00060     {
00061         bytes = 4;
00062     }
00063 
00064     return bytes;
00065 }
00066 
00067 static connector_bool_t rci_output_uint32(rci_t * const rci, uint32_t const value)
00068 {
00069     connector_bool_t overflow;
00070     size_t const bytes_follow = get_bytes_followed(value);
00071 
00072     rci_buffer_t * const output = &rci->buffer.output;
00073     size_t const total_bytes = bytes_follow + 1;
00074 
00075     overflow = connector_bool(rci_buffer_remaining(output) < total_bytes);
00076     if (overflow)
00077     {
00078         rci->status = rci_status_flush_output;
00079     }
00080     else
00081     {
00082         uint8_t * const rci_ber = rci_buffer_position(output);
00083 
00084         /*
00085          *        opcode
00086          *    7 6 5 4 3 2 1 0 bit
00087          *    ---------------
00088          *    0 X X X X X X X   (0 : 0x7F)
00089          *    1 0 0 X X X X X   + 1 byte followed (0: 0x1FFF)
00090          *    1 0 1 - - - 0 0   + 2 bytes followed (0: 0xFFFF)
00091          *    1 0 1 - - - 0 1   + 4 bytes followed (0: 0xFFFFFFFF)
00092          *    1 0 1 - - - 1 0   + 8 bytes followed (0: 0xFFFFFFFFFFFFFFFF)
00093          *    1 1 0 - - - - -   Reserved
00094          *    1 1 1 0 0 0 0 0   NONUM (No Value)
00095          *    1 1 1 0 0 0 0 1   TRM (Terminator)
00096          */
00097         switch (total_bytes)
00098         {
00099             case record_bytes(rci_ber):
00100             {
00101                 /* one byte with range [0, 0x7F] */
00102                 uint8_t const data = (uint8_t)value;
00103                 message_store_u8(rci_ber, value, data);
00104                 break;
00105             }
00106             case record_bytes(rci_ber_u8):
00107             {
00108                 #define MAX_ONE_BYTE_FOLLOW_VALUE   UINT32_C(0x1FFF)
00109 
00110                 /* two bytes with range [0, 0x1FFF] */
00111                 uint8_t * const rci_ber_u8 = rci_ber;
00112                 uint8_t data;
00113                 uint16_t data_value = (uint16_t)value;
00114 
00115                 ASSERT(value <= MAX_ONE_BYTE_FOLLOW_VALUE);
00116 
00117                 data = BINARY_RCI_SIZE_ALTERNATE_FLAG;
00118                 data |= HIGH8(data_value);
00119                 message_store_u8(rci_ber_u8, opcode, data);
00120 
00121                 data =  LOW8(data_value);
00122                 message_store_u8(rci_ber_u8, value, data);
00123 
00124                 #undef MAX_ONE_BYTE_FOLLOW_VALUE
00125                 break;
00126             }
00127             case record_bytes(rci_ber_u16):
00128             {
00129                 /* 3 bytes with range [0, 0xFFFF] */
00130                 uint8_t * const rci_ber_u16 = rci_ber;
00131                 uint8_t const opcode = BINARY_RCI_SET_MULTI_FOLLOW_BYTES(binary_rci_two_follow_byte);
00132                 uint16_t const data = (uint16_t)value;
00133 
00134                 message_store_u8(rci_ber_u16, opcode, opcode);
00135                 message_store_be16(rci_ber_u16, value, data);
00136                 break;
00137             }
00138             case record_bytes(rci_ber_u32):
00139             {
00140                 /* 5 bytes with range [0, 0xFFFFFFFF */
00141                 uint8_t * const rci_ber_u32 = rci_ber;
00142                 uint8_t const opcode = BINARY_RCI_SET_MULTI_FOLLOW_BYTES(binary_rci_four_follow_byte);
00143 
00144                 message_store_u8(rci_ber_u32, opcode, opcode);
00145                 message_store_be32(rci_ber_u32, value, value);
00146 
00147                 break;
00148 
00149             }
00150         }
00151         rci_buffer_advance(output, total_bytes);
00152     }
00153     return overflow;
00154 }
00155 
00156 static connector_bool_t rci_output_string(rci_t * const rci, char const * const string, size_t const length)
00157 {
00158 
00159     rci_buffer_t * const output = &rci->buffer.output;
00160     connector_bool_t overflow = connector_true;
00161 
00162     /* output:  | length | string | */
00163     if (!rcistr_valid(&rci->output.content))
00164     {
00165         /* set up the data and its length */
00166         overflow = rci_output_uint32(rci, length);
00167         if (overflow) goto done;
00168         rci->output.content.data = (uint8_t *)string;
00169         rci->output.content.length = length;
00170     }
00171 
00172     if (rci->output.content.length > 0)
00173     {
00174         size_t const avail_bytes = rci_buffer_remaining(output);
00175         size_t const write_bytes = (rci->output.content.length < avail_bytes) ? rci->output.content.length : avail_bytes;
00176 
00177         overflow = rci_output_data(rci, output, (uint8_t  *)rci->output.content.data, write_bytes);
00178         if (overflow) goto done;
00179 
00180         rci->output.content.data += write_bytes;
00181         rci->output.content.length -= write_bytes;
00182 
00183     }
00184 
00185     if (rci->output.content.length > 0)
00186     {
00187         overflow = connector_true;
00188         rci->status = rci_status_flush_output;
00189     }
00190     else
00191     {
00192         clear_rcistr(&rci->output.content);
00193     }
00194 
00195 done:
00196     return overflow;
00197 }
00198 
00199 #if defined RCI_PARSER_USES_IPV4
00200 static connector_bool_t rci_output_ipv4(rci_t * const rci, char const * const string)
00201 {
00202     rci_buffer_t * const output = &rci->buffer.output;
00203     connector_bool_t overflow = connector_true;
00204     size_t const avail_bytes = rci_buffer_remaining(output);
00205 
00206     if (avail_bytes < sizeof(uint32_t))
00207     {
00208         goto done;
00209     }
00210     else
00211     {
00212         uint32_t ipv4 = 0;
00213         uint8_t * const rci_ber_u32 = rci_buffer_position(output);
00214         int dot_count = 0;
00215         size_t i;
00216         size_t length = strlen(string);
00217         char aux_string[4] = {'\0', '\0', '\0', '\0'}; /* Three chars plus terminator. */
00218 
00219         size_t index = 0;
00220 
00221         for (i = 0; i < length; i++)
00222         {
00223             if (index > sizeof(aux_string) - 1)
00224                 break;
00225 
00226             if (string[i] != '.')
00227             {
00228                 aux_string[index++] = string[i];
00229             }
00230 
00231             if (string[i] == '.' || i == (length -1))
00232             {
00233                 long int val;
00234                 char * endptr;
00235 
00236                 val = strtol(aux_string, &endptr, 10);
00237                 if (endptr == NULL || *endptr != '\0' || val < 0 || val > 255)
00238                 {
00239                     break;
00240                 }
00241 
00242                 ipv4 = (ipv4 << 8) | val;
00243                 dot_count++;
00244                 index = 0;
00245                 memset(aux_string, '\0', sizeof aux_string);
00246             }
00247         }
00248         if (dot_count != 4)
00249         {
00250             connector_request_id_t request_id;
00251             request_id.remote_config_request = connector_request_id_remote_config_group_process;
00252             notify_error_status(rci->service_data->connector_ptr->callback, connector_class_id_remote_config, request_id, connector_invalid_data_range);
00253             rci->status = rci_status_error;
00254             overflow = connector_false;
00255             connector_debug_printf("Invalid IPv4 \"%s\"\n", string);
00256             goto done;
00257         }
00258 
00259         message_store_u8(rci_ber_u32, opcode, sizeof ipv4);
00260         message_store_be32(rci_ber_u32, value, ipv4);
00261 
00262         rci_buffer_advance(output, record_bytes(rci_ber_u32));
00263 
00264         overflow = connector_false;
00265     }
00266 
00267 done:
00268     return overflow;
00269 }
00270 #endif
00271 
00272 static connector_bool_t rci_output_uint8(rci_t * const rci, uint8_t const value)
00273 {
00274     uint8_t const data = value;
00275     rci_buffer_t * const output = &rci->buffer.output;
00276 
00277     return rci_output_data(rci, output, &data, sizeof data);
00278 }
00279 
00280 #if defined RCI_PARSER_USES_FLOAT
00281 static connector_bool_t rci_output_float(rci_t * const rci, float const value)
00282 {
00283     float const float_value = value;
00284     uint32_t float_integer;
00285 
00286     ASSERT(sizeof value == sizeof float_integer);
00287 
00288     memcpy(&float_integer, &float_value, sizeof float_integer);
00289 
00290     return rci_output_uint32(rci, float_integer);
00291 }
00292 #endif
00293 
00294 #define rci_output_no_value(rci)    rci_output_uint8((rci), BINARY_RCI_NO_VALUE)
00295 #define rci_output_terminator(rci)  rci_output_uint8((rci), BINARY_RCI_TERMINATOR)
00296 
00297 static void rci_output_command_id(rci_t * const rci)
00298 {
00299     connector_remote_config_t const * const remote_config = &rci->shared.callback_data;
00300     uint32_t command_id = 0;
00301 
00302     switch (rci->shared.callback_data.group.type)
00303     {
00304         case connector_remote_group_setting:
00305             switch (rci->shared.callback_data.action)
00306             {
00307             case connector_remote_action_set:
00308                 command_id = rci_command_set_setting;
00309                 break;
00310             case connector_remote_action_query:
00311                 command_id = rci_command_query_setting;
00312                 break;
00313             }
00314             break;
00315         case connector_remote_group_state:
00316             switch (rci->shared.callback_data.action)
00317             {
00318             case connector_remote_action_set:
00319                 command_id = rci_command_set_state;
00320                 break;
00321             case connector_remote_action_query:
00322                 command_id = rci_command_query_state;
00323                 break;
00324             }
00325             break;
00326     }
00327 
00328     {
00329         connector_bool_t const overflow = rci_output_uint32(rci, command_id);
00330 
00331         if (!overflow)
00332         {
00333             if (remote_config->error_id != connector_success)
00334                 state_call(rci, rci_parser_state_error);
00335             else
00336                 state_call(rci, rci_parser_state_traverse);
00337         }
00338     }
00339 
00340     return;
00341 }
00342 
00343 static void rci_output_group_id(rci_t * const rci)
00344 {
00345     connector_remote_config_t const * const remote_config = &rci->shared.callback_data;
00346     uint32_t encoding_data;
00347 
00348     if (!have_group_id(rci))
00349     {
00350         state_call(rci, rci_parser_state_error);
00351         goto done;
00352     }
00353 
00354     encoding_data = encode_group_id(get_group_id(rci));
00355 
00356     if (get_group_index(rci) > 1)
00357         encoding_data |= BINARY_RCI_ATTRIBUTE_BIT;
00358 
00359     {
00360         connector_bool_t const overflow = rci_output_uint32(rci, encoding_data);
00361 
00362         if (!overflow)
00363         {
00364             if (remote_config->error_id != connector_success)
00365                 state_call(rci, rci_parser_state_error);
00366             else
00367                 set_rci_output_state(rci, rci_output_state_group_attribute);
00368         }
00369     }
00370 
00371 done:
00372     return;
00373 }
00374 
00375 static connector_bool_t encode_attribute(rci_t * const rci, unsigned int const index)
00376 {
00377     uint32_t encoding_data;
00378     connector_bool_t overflow = connector_false;
00379 
00380     if (index > 1)
00381     {
00382         /* attribute output
00383          * bit |7 | 6 5 | 4 3 2 1 0|
00384          *     |x | 0 1 | - index -|
00385          */
00386         #define BINARY_RCI_ATTRIBUTE_INDEX_MAX 31
00387         #define BINARY_RCI_ATTRIBUTE_TYPE_INDEX  0x20
00388 
00389         ASSERT(index <= BINARY_RCI_ATTRIBUTE_INDEX_MAX);
00390         encoding_data = index | BINARY_RCI_ATTRIBUTE_TYPE_INDEX;
00391 
00392         overflow = rci_output_uint32(rci, encoding_data);
00393     }
00394 
00395     return overflow;
00396 }
00397 
00398 static void rci_output_group_attribute(rci_t * const rci)
00399 {
00400     unsigned int const index = get_group_index(rci);
00401     connector_bool_t overflow = encode_attribute(rci, index);
00402 
00403     if (!overflow)
00404        state_call(rci, rci_parser_state_traverse);
00405 }
00406 
00407 
00408 static void rci_output_field_id(rci_t * const rci)
00409 {
00410     connector_remote_config_t const * const remote_config = &rci->shared.callback_data;
00411 
00412     if (!have_element_id(rci))
00413     {
00414         state_call(rci, rci_parser_state_error);
00415         goto done;
00416     }
00417 
00418     {
00419         /* output field id */
00420         uint32_t id =  encode_element_id(get_element_id(rci));
00421 
00422         if (remote_config->error_id != connector_success) id |= BINARY_RCI_FIELD_TYPE_INDICATOR_BIT;
00423 
00424         {
00425             connector_bool_t const overflow = rci_output_uint32(rci, id);
00426 
00427             if (overflow) goto done;
00428 
00429             if (remote_config->error_id != connector_success)
00430                 state_call(rci, rci_parser_state_error);
00431             else
00432                 set_rci_output_state(rci, rci_output_state_field_value);
00433         }
00434 
00435     }
00436 
00437 done:
00438     return;
00439 }
00440 
00441 
00442 static void rci_output_field_value(rci_t * const rci)
00443 {
00444     connector_group_element_t const * const element = get_current_element(rci);
00445     connector_element_value_type_t const type = element->type;
00446 
00447     connector_bool_t overflow = connector_false;
00448 
00449 
00450     switch (rci->shared.callback_data.action)
00451     {
00452         case connector_remote_action_set:
00453             overflow = rci_output_no_value(rci);
00454             goto done;
00455 
00456         case connector_remote_action_query:
00457             break;
00458     }
00459 
00460     switch (type)
00461     {
00462 #if defined RCI_PARSER_USES_STRINGS
00463 
00464 #if defined RCI_PARSER_USES_STRING
00465     case connector_element_type_string:
00466 #endif
00467 
00468 #if defined RCI_PARSER_USES_MULTILINE_STRING
00469     case connector_element_type_multiline_string:
00470 #endif
00471 
00472 #if defined RCI_PARSER_USES_PASSWORD
00473     case connector_element_type_password:
00474 #endif
00475 
00476 #if defined RCI_PARSER_USES_FQDNV4
00477     case connector_element_type_fqdnv4:
00478 #endif
00479 
00480 #if defined RCI_PARSER_USES_FQDNV6
00481     case connector_element_type_fqdnv6:
00482 #endif
00483 
00484 #if defined RCI_PARSER_USES_DATETIME
00485     case connector_element_type_datetime:
00486 #endif
00487         ASSERT(rci->shared.value.string_value != NULL);
00488         overflow = rci_output_string(rci, rci->shared.value.string_value, strlen(rci->shared.value.string_value));
00489         break;
00490 #endif
00491 
00492 #if defined RCI_PARSER_USES_IPV4
00493     case connector_element_type_ipv4:
00494         ASSERT(rci->shared.value.string_value != NULL);
00495         overflow = rci_output_ipv4(rci, rci->shared.value.string_value);
00496         break;
00497 #endif
00498 
00499 #if defined RCI_PARSER_USES_INT32
00500     case connector_element_type_int32:
00501         overflow = rci_output_uint32(rci, rci->shared.value.signed_integer_value);
00502         break;
00503 #endif
00504 
00505 #if (defined RCI_PARSER_USES_UNSIGNED_INTEGER)
00506 #if defined RCI_PARSER_USES_UINT32
00507     case connector_element_type_uint32:
00508 #endif
00509 
00510 #if defined RCI_PARSER_USES_HEX32
00511     case connector_element_type_hex32:
00512 #endif
00513 
00514 #if defined RCI_PARSER_USES_0X_HEX32
00515     case connector_element_type_0x_hex32:
00516 #endif
00517 
00518         overflow = rci_output_uint32(rci, rci->shared.value.unsigned_integer_value);
00519         break;
00520 #endif
00521 
00522 #if defined RCI_PARSER_USES_FLOAT
00523     case connector_element_type_float:
00524         overflow = rci_output_float(rci, rci->shared.value.float_value);
00525         break;
00526 #endif
00527 
00528 #if defined RCI_PARSER_USES_ENUM
00529     case connector_element_type_enum:
00530         overflow = rci_output_uint32(rci, rci->shared.value.enum_value);
00531         break;
00532 #endif
00533 
00534 #if defined RCI_PARSER_USES_ON_OFF
00535     case connector_element_type_on_off:
00536         overflow = rci_output_uint32(rci, rci->shared.value.on_off_value);
00537         break;
00538 #endif
00539 
00540 #if defined RCI_PARSER_USES_BOOLEAN
00541     case connector_element_type_boolean:
00542         overflow = rci_output_uint32(rci, rci->shared.value.boolean_value);
00543         break;
00544 #endif
00545     }
00546 
00547 done:
00548     if (!overflow)
00549         state_call(rci, rci_parser_state_traverse);
00550 
00551 }
00552 
00553 static void rci_output_field_terminator(rci_t * const rci)
00554 {
00555     connector_remote_config_t const * const remote_config = &rci->shared.callback_data;
00556 
00557     connector_bool_t const overflow = rci_output_terminator(rci);
00558     if (!overflow)
00559     {
00560         invalidate_element_id(rci);
00561 
00562         if (remote_config->error_id != connector_success)
00563             state_call(rci, rci_parser_state_error);
00564         else
00565             state_call(rci, rci_parser_state_traverse);
00566     }
00567     return;
00568 }
00569 
00570 static void rci_output_group_terminator(rci_t * const rci)
00571 {
00572     connector_remote_config_t const * const remote_config = &rci->shared.callback_data;
00573 
00574     if (remote_config->error_id != connector_success)
00575     {
00576         state_call(rci, rci_parser_state_error);
00577     }
00578     else
00579     {
00580         connector_bool_t const overflow = rci_output_terminator(rci);
00581         if (overflow) goto done;
00582 
00583         set_rci_output_state(rci, rci_output_state_response_done);
00584     }
00585 
00586     invalidate_group_id(rci);
00587 
00588 done:
00589     return;
00590 }
00591 
00592 static void rci_generate_output(rci_t * const rci)
00593 {
00594     rci_buffer_t * const output = &rci->buffer.output;
00595 
00596     if ((rci_buffer_remaining(output) != 0))
00597     {
00598         rci_debug_printf("output: %s\n", rci_output_state_t_as_string(rci->output.state));
00599 
00600         switch (rci->output.state)
00601         {
00602             case rci_output_state_command_id:
00603                 rci_output_command_id(rci);
00604                 break;
00605 
00606             case rci_output_state_group_id:
00607                 rci_output_group_id(rci);
00608                 break;
00609 
00610             case rci_output_state_group_attribute:
00611                 rci_output_group_attribute(rci);
00612                 break;
00613 
00614             case rci_output_state_field_id:
00615                 rci_output_field_id(rci);
00616                 break;
00617 
00618             case rci_output_state_field_value:
00619                 rci_output_field_value(rci);
00620                 break;
00621 
00622             case rci_output_state_field_terminator:
00623                 rci_output_field_terminator(rci);
00624                 break;
00625 
00626             case rci_output_state_group_terminator:
00627                 rci_output_group_terminator(rci);
00628                 break;
00629 
00630             case rci_output_state_response_done:
00631 
00632                 if (get_rci_input_state(rci) == rci_input_state_done)
00633                 {
00634                     trigger_rci_callback(rci, connector_request_id_remote_config_session_end);
00635                     set_rci_output_state(rci, rci_output_state_done);
00636                 }
00637                 else
00638                 {
00639                     state_call(rci, rci_parser_state_input);
00640                     set_rci_input_state(rci, rci_input_state_command_id);
00641                 }
00642                 break;
00643 
00644             case rci_output_state_done:
00645             {
00646                 connector_remote_config_t const * const remote_config = &rci->shared.callback_data;
00647                 if (remote_config->error_id != connector_success)
00648                     state_call(rci, rci_parser_state_error);
00649                 else
00650                     rci->status = rci_status_complete;
00651                 break;
00652             }
00653         }
00654     }
00655     else if ((rci_buffer_used(&rci->buffer.output) > 0) && (rci->status == rci_status_busy))
00656     {
00657         /* We are here since we have no space left for more output data and we have output data waiting to be sent.
00658            So set up the state to send out the output data and come back to rci */
00659 
00660         rci->status = rci_status_flush_output;
00661     }
00662 
00663 
00664 #if defined RCI_DEBUG
00665     {
00666         size_t const bytes = rci_buffer_used(&rci->buffer.output);
00667         if (bytes > 0)
00668         {
00669             connector_debug_hexvalue("Response", rci->buffer.output.start, bytes);
00670         }
00671     }
00672 #endif
00673 
00674     return;
00675 }
00676 
00677