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

« Back to documentation index

Show/hide line numbers connector_data_service.h Source File

connector_data_service.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 typedef enum
00014 {
00015     data_service_opcode_put_request,
00016     data_service_opcode_put_response,
00017     data_service_opcode_device_request,
00018     data_service_opcode_device_response
00019 } data_service_opcode_t;
00020 
00021 typedef struct
00022 {
00023     void * callback_context;
00024     connector_request_data_service_send_t const * header;
00025     connector_bool_t dp_request;
00026     connector_request_id_data_service_t request_type;
00027 } data_service_context_t;
00028 
00029 static void set_data_service_error(msg_service_request_t * const service_request, connector_session_error_t const error_code)
00030 {
00031     service_request->error_value = error_code;
00032     service_request->service_type = msg_service_type_error;
00033 }
00034 
00035 
00036 static connector_status_t call_ds_receive_callback(connector_data_t * const connector_ptr,
00037                                                    data_service_context_t * const data_service,
00038                                                    void * const data)
00039 {
00040     connector_status_t result = connector_working;
00041     connector_request_id_t request_id;
00042 
00043     request_id.data_service_request = data_service->request_type;
00044     switch (request_id.data_service_request)
00045     {
00046         case connector_request_id_data_service_receive_reply_length:
00047             request_id.data_service_request = connector_request_id_data_service_receive_reply_data;
00048             /* fall thru for error (not-handle) response data */
00049         case connector_request_id_data_service_receive_target:
00050         case connector_request_id_data_service_receive_data:
00051         case connector_request_id_data_service_receive_status:
00052         case connector_request_id_data_service_receive_reply_data:
00053         {
00054             connector_callback_status_t const status = connector_callback(connector_ptr->callback, connector_class_id_data_service, request_id, data);
00055             switch (status)
00056             {
00057                 case connector_callback_continue:
00058                     break;
00059                 case connector_callback_error:
00060                     data_service->request_type = connector_request_id_data_service_receive_reply_length;
00061                     break;
00062                 case connector_callback_busy:
00063                     result = connector_pending;
00064                     break;
00065                 default:
00066                     result = connector_abort;
00067                     break;
00068 
00069             }
00070             break;
00071         }
00072 
00073         default:
00074             ASSERT(connector_false);
00075             break;
00076     }
00077 
00078     return result;
00079 }
00080 
00081 static connector_status_t process_ds_receive_target(connector_data_t * const connector_ptr,
00082                                                     data_service_context_t * const data_service,
00083                                                     uint8_t const * const data,
00084                                                     size_t * const data_length)
00085 {
00086     /* 1st message so let's parse message-start packet:
00087      *
00088      * Data Service Device request format:
00089      *  -------------------------------------------------------------------------------------------------------
00090      * |   0    |   1    |  2+N   |    +1     |     +1      |    +1       |    +M       |  ...       | +P      |
00091      *  -------------------------------------------------------------------------------------------------------
00092      * | Opcode | Target | Target | Parameter | Parameter 1 | Parameter 1 | Parameter 1 | Additional | Payload |
00093      * |        | length | string |   count   |     ID      | data length |    data     | parameters |         |
00094      *  -------------------------------------------------------------------------------------------------------
00095      *
00096      */
00097     enum {
00098         field_define(ds_device_request, opcode, uint8_t),
00099         field_define(ds_device_request, target_length, uint8_t),
00100         record_end(ds_device_request_header)
00101     };
00102 
00103     enum {
00104         field_define(ds_device_request, parameter_count, uint8_t)
00105     };
00106 
00107     enum {
00108         field_define(ds_device_request, parameter_id, uint8_t),
00109         field_define(ds_device_request, parameter_length, uint8_t),
00110         record_end(ds_device_request_parameter)
00111     };
00112 
00113     connector_status_t result = connector_working;
00114     uint8_t const * ds_device_request = data;
00115 
00116     char * target_string = NULL;
00117     uint8_t const target_length =  message_load_u8(ds_device_request, target_length);
00118 
00119     size_t const min_data_length = (size_t)(target_length +
00120                       record_bytes(ds_device_request_header) +
00121                       field_named_data(ds_device_request, parameter_count, size));
00122 
00123     ASSERT_GOTO((message_load_u8(ds_device_request, opcode) == data_service_opcode_device_request), done);
00124     ASSERT_GOTO(*data_length >= min_data_length, done);
00125 
00126     ds_device_request += record_bytes(ds_device_request_header);
00127 
00128     target_string = (char *)ds_device_request;
00129     ds_device_request += target_length;
00130 
00131     {
00132         /* TODO: Parse and process each parameter in the future.
00133          *      Ignore all parameters now.
00134          */
00135 
00136         uint8_t const parameter_count = message_load_u8(ds_device_request, parameter_count);
00137         uint8_t i;
00138 
00139         ds_device_request += field_named_data(ds_device_request, parameter_count, size);
00140 
00141         for (i=0; i < parameter_count; i++)
00142         {
00143              unsigned int const parameter_length = message_load_u8(ds_device_request, parameter_length);
00144              size_t const min_parameter_length = min_data_length + record_bytes(ds_device_request_parameter) + parameter_length;
00145              ASSERT_GOTO(*data_length >= min_parameter_length, done);
00146 
00147              ds_device_request += record_bytes(ds_device_request_parameter); /* skip id and length */
00148              ds_device_request += parameter_length;
00149 
00150         }
00151     }
00152 
00153     *data_length = (ds_device_request - data);
00154 
00155     /* Add NUL to the target string. Must NULL-terminate it after parsing all parameters.
00156      * The NUL char is on parameter_count field in the request.
00157      */
00158     target_string[target_length] = '\0';
00159 
00160     switch (data_service->request_type)
00161     {
00162         case connector_request_id_data_service_receive_target:
00163         {
00164 
00165             connector_data_service_receive_target_t device_request;
00166 
00167             device_request.transport = connector_transport_tcp;
00168             device_request.user_context = data_service->callback_context;
00169             device_request.target = target_string;
00170             device_request.response_required = connector_true;
00171 
00172             result = call_ds_receive_callback(connector_ptr, data_service, &device_request);
00173             data_service->callback_context = device_request.user_context;
00174             break;
00175         }
00176         default:
00177             /* just skip the header and return */
00178             break;
00179     }
00180 
00181 done:
00182     return result;
00183 }
00184 
00185 static connector_status_t process_ds_receive_data(connector_data_t * const connector_ptr,
00186                                                   data_service_context_t * const data_service,
00187                                                   uint8_t const * const data,
00188                                                   size_t const data_length,
00189                                                   unsigned int const flags)
00190 {
00191     connector_status_t result;
00192 
00193     connector_data_service_receive_data_t device_request;
00194     device_request.transport = connector_transport_tcp;
00195     device_request.user_context = data_service->callback_context;
00196     device_request.buffer = data;
00197     device_request.bytes_used = data_length;
00198     device_request.more_data = MsgIsLastData(flags) ? connector_false : connector_true;
00199 
00200     result = call_ds_receive_callback(connector_ptr, data_service, &device_request);
00201     data_service->callback_context = device_request.user_context;
00202 
00203     return result;
00204 }
00205 static connector_status_t process_data_service_device_request(connector_data_t * const connector_ptr,
00206                                                  msg_service_request_t * const service_request)
00207 {
00208     connector_status_t result = connector_working;
00209     msg_session_t * const session = service_request->session;
00210     data_service_context_t * data_service = session->service_context;
00211     msg_service_data_t * const service_data = service_request->have_data;
00212 
00213     uint8_t const * ds_device_request = service_data->data_ptr;
00214     size_t ds_device_request_length = service_data->length_in_bytes;
00215 
00216     connector_bool_t const isFirstRequest = connector_bool(MsgIsStart(service_data->flags));
00217 
00218     if (isFirstRequest)
00219     {
00220         if (data_service == NULL)
00221         {
00222             /* 1st time here so let's allocate service context memory for device request service */
00223             void * ptr;
00224 
00225             result = malloc_data_buffer(connector_ptr, sizeof *data_service, named_buffer_id(msg_service), &ptr);
00226             if (result != connector_working)
00227             {
00228                 goto done;
00229             }
00230 
00231             data_service = ptr;
00232             session->service_context = data_service;
00233             data_service->callback_context = NULL;
00234             data_service->dp_request = connector_false;
00235             data_service->request_type = connector_request_id_data_service_receive_target;
00236         }
00237     }
00238 
00239     switch (data_service->request_type)
00240     {
00241         case connector_request_id_data_service_receive_target:
00242             ds_device_request_length = service_data->length_in_bytes;
00243 
00244             result = process_ds_receive_target(connector_ptr, data_service, ds_device_request, &ds_device_request_length);
00245 
00246             switch (result)
00247             {
00248             case connector_working:
00249                 if (data_service->request_type == connector_request_id_data_service_receive_target)
00250                     data_service->request_type = connector_request_id_data_service_receive_data;
00251                 /* make it return busy so it comes here to skip parsing the header for the 1st data block */
00252                 result = connector_pending;
00253                 break;
00254             default:
00255                 break;
00256             }
00257             break;
00258 
00259         case connector_request_id_data_service_receive_data:
00260             if (isFirstRequest)
00261             {
00262                 /* skip the header; just get the point to data  */
00263                 result = process_ds_receive_target(connector_ptr, data_service, ds_device_request, &ds_device_request_length);
00264                 if (result != connector_working) goto done;
00265                 ds_device_request += ds_device_request_length;
00266             }
00267             {
00268                 size_t const data_length = (size_t)(ds_device_request - (uint8_t *)service_data->data_ptr);
00269                 ds_device_request_length = service_data->length_in_bytes - data_length;
00270 
00271                 result = process_ds_receive_data(connector_ptr, data_service, ds_device_request, ds_device_request_length, service_data->flags);
00272                 switch (result)
00273                 {
00274                     case connector_working:
00275                         /* data_service->request_type may have been changed inside process_ds_receive_data() */
00276                         switch (data_service->request_type)
00277                         {
00278                             case connector_request_id_data_service_receive_reply_length:
00279                                 break;
00280 
00281                             default:
00282                                 if (MsgIsLastData(service_data->flags))
00283                                     data_service->request_type = connector_request_id_data_service_receive_reply_data;
00284                                 break;
00285                         }
00286                         break;
00287                     default:
00288                         break;
00289                 }
00290                 break;
00291             }
00292         case connector_request_id_data_service_receive_reply_length:
00293             /* We set this when callback returns error.
00294              * We need to respond with an error after receiving all request data.
00295              */
00296             break;
00297 
00298         default:
00299             ASSERT(connector_false);
00300             goto done;
00301     }
00302 
00303 done:
00304     return result;
00305 }
00306 
00307 static connector_status_t process_data_service_device_response(connector_data_t * const connector_ptr,
00308                                                                msg_service_request_t * const service_request)
00309 {
00310     /* Data Service Device response format:
00311      *  ---------------------------------
00312      * |   0    |   1    |     2...      |
00313      *  ---------------------------------
00314      * | Opcode | status | Response Data |
00315      *  ---------------------------------
00316      */
00317     enum {
00318         field_define(ds_device_response, opcode, uint8_t),
00319         field_define(ds_device_response, status, uint8_t),
00320         record_end(ds_device_response_header)
00321     };
00322 
00323     connector_status_t result = connector_working;
00324     msg_service_data_t * const service_data = service_request->need_data;
00325     msg_session_t * const session = service_request->session;
00326     data_service_context_t * const data_service = session->service_context;
00327     connector_bool_t const isFirstResponse = connector_bool(MsgIsStart(service_data->flags));
00328 
00329     /* save some room for response header on 1st response data */
00330     size_t const header_length = isFirstResponse == connector_true ? record_bytes(ds_device_response_header) : 0;
00331     uint8_t * const data_ptr = service_data->data_ptr;
00332 
00333 
00334     connector_data_service_receive_reply_data_t device_request;
00335 
00336     device_request.transport = connector_transport_tcp;
00337     device_request.user_context = data_service->callback_context;
00338     device_request.buffer = data_ptr + header_length;
00339     device_request.bytes_available = service_data->length_in_bytes - header_length;
00340     device_request.bytes_used = 0;
00341     device_request.more_data = connector_false;
00342 
00343     {
00344         connector_request_id_data_service_t const request_type = data_service->request_type;
00345 
00346         switch (request_type)
00347         {
00348             case connector_request_id_data_service_receive_reply_length:
00349             /* We got here because callback returns error for request data.
00350              * Just get the replay data.
00351              */
00352              /* fall thru */
00353             case connector_request_id_data_service_receive_reply_data:
00354             {
00355 
00356                 result = call_ds_receive_callback(connector_ptr, data_service, &device_request);
00357                 data_service->callback_context = device_request.user_context;
00358                 if (request_type != data_service->request_type &&
00359                     data_service->request_type == connector_request_id_data_service_receive_reply_length)
00360                 {
00361                     /* callback returns error on reply data
00362                      * We need to cancel the message in messaging layer.
00363                      */
00364                     device_request.bytes_used = 0;
00365                     device_request.more_data = connector_false;
00366                     set_data_service_error(service_request, connector_session_error_cancel);
00367                 }
00368                 break;
00369             }
00370             default:
00371                 /* should be here */
00372                 ASSERT(connector_false);
00373                 goto done;
00374         }
00375     }
00376     if (isFirstResponse)
00377     {
00378 
00379         enum {
00380             connector_data_service_device_success,
00381             connector_data_service_device_not_handled
00382         };
00383 
00384         /* Add header for 1st response message */
00385         uint8_t * const ds_device_response = service_data->data_ptr;
00386         uint8_t const target_status = (data_service->request_type == connector_request_id_data_service_receive_reply_length) ?
00387                                 connector_data_service_device_not_handled: connector_data_service_device_success;
00388 
00389         message_store_u8(ds_device_response, opcode, data_service_opcode_device_response);
00390         message_store_u8(ds_device_response, status, target_status);
00391     }
00392 
00393     if (!device_request.more_data)
00394     {
00395         data_service->dp_request = connector_true;
00396         MsgSetLastData(service_data->flags);
00397     }
00398     service_data->length_in_bytes = device_request.bytes_used + header_length;
00399 
00400 done:
00401     return result;
00402 }
00403 
00404 
00405 static connector_status_t process_data_service_device_error(connector_data_t * const connector_ptr,
00406                                                        msg_service_request_t * const service_request)
00407 {
00408     connector_status_t result = connector_working;
00409 
00410     msg_session_t * const session = service_request->session;
00411     data_service_context_t * const data_service = session->service_context;
00412     connector_data_service_status_t device_request;
00413 
00414 
00415     device_request.transport = connector_transport_tcp;
00416     device_request.user_context = data_service->callback_context;
00417     data_service->request_type = connector_request_id_data_service_receive_status;
00418 
00419     switch (service_request->error_value)
00420     {
00421         case connector_session_error_none:
00422             device_request.status = connector_data_service_status_complete;
00423             break;
00424 
00425         case connector_session_error_cancel:
00426             device_request.status = connector_data_service_status_cancel;
00427             break;
00428 
00429         case connector_session_error_timeout:
00430             device_request.status = connector_data_service_status_timeout;
00431             break;
00432 
00433         default:
00434             device_request.status = connector_data_service_status_session_error;
00435             device_request.session_error = service_request->error_value;
00436             break;
00437     }
00438 
00439     result = call_ds_receive_callback(connector_ptr, data_service, &device_request);
00440 
00441     data_service->callback_context = device_request.user_context;
00442 
00443     return result;
00444 }
00445 
00446 static connector_status_t data_service_device_request_callback(connector_data_t * const connector_ptr, msg_service_request_t * const service_request)
00447 {
00448     connector_status_t status = connector_working;
00449 
00450     switch (service_request->service_type)
00451     {
00452     case msg_service_type_need_data:
00453         status = process_data_service_device_response(connector_ptr, service_request);
00454         break;
00455 
00456     case msg_service_type_have_data:
00457         status = process_data_service_device_request(connector_ptr, service_request);
00458         break;
00459 
00460     case msg_service_type_error:
00461     {
00462         msg_session_t * const session = service_request->session;
00463         session->error = service_request->error_value;
00464         status = process_data_service_device_error(connector_ptr, service_request);
00465         break;
00466     }
00467 
00468     case msg_service_type_free:
00469         {
00470             msg_session_t * const session = service_request->session;
00471 #if (CONNECTOR_VERSION >= 0x02010000)
00472             if (session->error == connector_session_error_none)
00473             {
00474                 /* If there is no error, call the user to inform that session is done */
00475                 status = process_data_service_device_error(connector_ptr, service_request);
00476                 if (status != connector_working)
00477                     break;
00478             }
00479 #endif
00480             status = free_data_buffer(connector_ptr, named_buffer_id(msg_service), session->service_context);
00481             break;
00482         }
00483 
00484     default:
00485         ASSERT(connector_false);
00486         break;
00487     }
00488 
00489     return status;
00490 }
00491 
00492 static size_t fill_put_request_header(connector_request_data_service_send_t const * const request, uint8_t * const data)
00493 {
00494     uint8_t * ptr = data;
00495 
00496     *ptr++ = data_service_opcode_put_request;
00497 
00498     /* fill path */
00499     if (request->path != NULL)
00500     {
00501         uint8_t const bytes = (uint8_t) strlen(request->path);
00502 
00503         ASSERT(strlen(request->path) <= UCHAR_MAX);
00504         *ptr++ = bytes;
00505         memcpy(ptr, request->path, bytes);
00506         ptr += bytes;
00507     }
00508 
00509     /* fill parameters */
00510     {
00511         connector_bool_t const have_type = connector_bool(request->content_type != NULL);
00512         uint8_t const parameter_requested = 1;
00513         uint8_t params = have_type ? 1 : 0;
00514 
00515         enum
00516         {
00517             parameter_id_content_type,
00518             parameter_id_archive,
00519             parameter_id_append,
00520             parameter_id_transient
00521         };
00522 
00523         if (request->option != connector_data_service_send_option_overwrite) params++;
00524 
00525         *ptr++ = params;
00526 
00527         if (have_type)
00528         {
00529             uint8_t const bytes = (uint8_t) strlen(request->content_type);
00530 
00531             ASSERT(strlen(request->content_type) <= UCHAR_MAX);
00532             *ptr++ = parameter_id_content_type;
00533             *ptr++ = bytes;
00534             memcpy(ptr, request->content_type, bytes);
00535             ptr += bytes;
00536         }
00537 
00538         switch(request->option)
00539         {
00540             case connector_data_service_send_option_archive:
00541                 *ptr++ = parameter_id_archive;
00542                 *ptr++ = parameter_requested;
00543                 break;
00544 
00545             case connector_data_service_send_option_append:
00546                 *ptr++ = parameter_id_append;
00547                 *ptr++ = parameter_requested;
00548                 break;
00549 
00550             case connector_data_service_send_option_transient:
00551                 *ptr++ = parameter_id_transient;
00552                 *ptr++ = parameter_requested;
00553                 break;
00554 
00555             default:
00556                 break;
00557         }
00558     }
00559 
00560     return (size_t)(ptr - data);
00561 }
00562 
00563 static connector_status_t call_put_request_user(connector_data_t * const connector_ptr, msg_service_request_t * const service_request, connector_request_id_data_service_t const request_id, void * const cb_data)
00564 {
00565     connector_status_t status = connector_working;
00566     msg_session_t * const session = service_request->session;
00567     data_service_context_t * const context = (session != NULL) ? session->service_context : NULL;
00568     connector_callback_status_t callback_status = connector_callback_continue;
00569 
00570     if ((context == NULL) || (context->dp_request == connector_false))
00571     {
00572         connector_request_id_t request;
00573 
00574         request.data_service_request = request_id;
00575         callback_status = connector_callback(connector_ptr->callback, connector_class_id_data_service, request, cb_data);
00576     }
00577     #if (defined CONNECTOR_DATA_POINTS)
00578     else
00579     {
00580         callback_status = dp_handle_callback(connector_ptr, request_id, cb_data);
00581     }
00582     #endif
00583 
00584     switch (callback_status)
00585     {
00586         case connector_callback_continue:
00587             status = connector_working;
00588             break;
00589 
00590         case connector_callback_error:
00591             set_data_service_error(service_request, connector_session_error_cancel);
00592             status = connector_working;
00593             break;
00594 
00595         case connector_callback_busy:
00596             status = connector_pending;
00597             break;
00598 
00599         default:
00600             status = connector_abort;
00601             break;
00602     }
00603 
00604     return status;
00605 }
00606 
00607 static connector_status_t process_send_request(connector_data_t * const connector_ptr, msg_service_request_t * const service_request, data_service_context_t * const ds_ptr)
00608 {
00609     connector_status_t status = connector_working;
00610     msg_service_data_t * const service_data = service_request->need_data;
00611     connector_data_service_send_data_t user_data;
00612 
00613     user_data.transport = connector_transport_tcp;
00614     user_data.user_context = ds_ptr->callback_context;
00615     user_data.bytes_used = 0;
00616     user_data.more_data = connector_false;
00617 
00618     if (MsgIsStart(service_data->flags))
00619     {
00620         uint8_t * dptr = service_data->data_ptr;
00621         size_t const bytes = fill_put_request_header(ds_ptr->header, dptr);
00622 
00623         if (bytes >= service_data->length_in_bytes)
00624         {
00625             connector_debug_printf("process_send_request: required bytes [%" PRIsize "] is more than available [%" PRIsize "]\n", bytes, service_data->length_in_bytes);
00626             goto error;
00627         }
00628 
00629         user_data.buffer = dptr + bytes;
00630         user_data.bytes_available = service_data->length_in_bytes - bytes;
00631         service_data->length_in_bytes = bytes;
00632     }
00633     else
00634     {
00635         user_data.buffer = service_data->data_ptr;
00636         user_data.bytes_available = service_data->length_in_bytes;
00637         service_data->length_in_bytes = 0;
00638     }
00639 
00640     status = call_put_request_user(connector_ptr, service_request, connector_request_id_data_service_send_data, &user_data);
00641     if (status == connector_working)
00642     {
00643         service_data->flags = 0;
00644         service_data->length_in_bytes += user_data.bytes_used;
00645         if (user_data.more_data == connector_false)
00646             MsgSetLastData(service_data->flags);
00647     }
00648     goto done;
00649 
00650 error:
00651     set_data_service_error(service_request, connector_session_error_format);
00652 
00653 done:
00654     return status;
00655 }
00656 
00657 static connector_status_t process_send_response(connector_data_t * const connector_ptr, msg_service_request_t * const service_request, data_service_context_t * const ds_ptr)
00658 {
00659     connector_status_t status = connector_working;
00660     connector_data_service_send_response_t user_data;
00661 
00662     /* Data Service put response format:
00663      *  ---------------------------------
00664      * |   0    |   1    |     2...      |
00665      *  ---------------------------------
00666      * | Opcode | status | Response Data |
00667      *  ---------------------------------
00668      */
00669     enum
00670     {
00671         field_define(put_response, opcode, uint8_t),
00672         field_define(put_response, status, uint8_t),
00673         record_end(put_response)
00674     };
00675 
00676     enum
00677     {
00678         ds_data_success,
00679         ds_data_bad_request,
00680         ds_data_service_unavailable,
00681         ds_data_cloud_error
00682     };
00683 
00684     msg_service_data_t * const service_data = service_request->have_data;
00685     uint8_t * const put_response = service_data->data_ptr;
00686     uint8_t const opcode = message_load_u8(put_response, opcode);
00687     uint8_t const result = message_load_u8(put_response, status);
00688 
00689     ASSERT_GOTO(MsgIsStart(service_data->flags), error);
00690     ASSERT_GOTO(opcode == data_service_opcode_put_response, error);
00691 
00692     user_data.transport = connector_transport_tcp;
00693     user_data.user_context = ds_ptr->callback_context;
00694     if (service_data->length_in_bytes > record_end(put_response))
00695     {
00696         int const max_hint_length = (MSG_MAX_RECV_PACKET_SIZE - PACKET_EDP_HEADER_SIZE - record_end(start_packet) - record_end(put_response));
00697         uint8_t * const hint_start = put_response + record_end(put_response);
00698         uint8_t * const hint_end = put_response + service_data->length_in_bytes;
00699         size_t hint_length = (hint_end - hint_start) < max_hint_length ? hint_end - hint_start : max_hint_length;
00700         char * const hint = (char *)hint_start;
00701 
00702         /* Add a null-terminator only if necessary */
00703         if (hint[hint_length - 1] != '\0')
00704             hint[hint_length] = '\0';
00705         user_data.hint = hint;
00706     }
00707     else
00708     {
00709         user_data.hint = NULL;
00710     }
00711 
00712     switch (result)
00713     {
00714     case ds_data_success:
00715         user_data.response = connector_data_service_send_response_success;
00716         break;
00717 
00718     case ds_data_bad_request:
00719         user_data.response = connector_data_service_send_response_bad_request;
00720         break;
00721 
00722     case ds_data_service_unavailable:
00723         user_data.response = connector_data_service_send_response_unavailable;
00724         break;
00725 
00726     case ds_data_cloud_error:
00727         user_data.response = connector_data_service_send_response_cloud_error;
00728         break;
00729 
00730     default:
00731         ASSERT(connector_false);
00732         break;
00733     }
00734 
00735     status = call_put_request_user(connector_ptr, service_request, connector_request_id_data_service_send_response, &user_data);
00736     goto done;
00737 
00738 error:
00739     set_data_service_error(service_request, connector_session_error_format);
00740 
00741 done:
00742     return status;
00743 }
00744 
00745 static connector_status_t process_send_error(connector_data_t * const connector_ptr, msg_service_request_t * const service_request, void * const cb_context)
00746 {
00747     connector_status_t status = connector_working;
00748     connector_data_service_status_t user_data;
00749 
00750     user_data.transport = connector_transport_tcp;
00751     user_data.user_context = cb_context;
00752     user_data.session_error = connector_session_error_none;
00753 
00754     switch (service_request->error_value)
00755     {
00756         case connector_session_error_none:
00757             user_data.status = connector_data_service_status_complete;
00758             break;
00759 
00760         case connector_session_error_cancel:
00761             user_data.status = connector_data_service_status_cancel;
00762             break;
00763 
00764         case connector_session_error_timeout:
00765             user_data.status = connector_data_service_status_timeout;
00766             break;
00767 
00768         default:
00769             user_data.status = connector_data_service_status_session_error;
00770             user_data.session_error = service_request->error_value;
00771             break;
00772     }
00773 
00774     status = call_put_request_user(connector_ptr, service_request, connector_request_id_data_service_send_status, &user_data);
00775 
00776     return status;
00777 }
00778 
00779 static connector_status_t data_service_put_request_callback(connector_data_t * const connector_ptr, msg_service_request_t * const service_request)
00780 {
00781     connector_status_t status;
00782     msg_session_t * const session = service_request->session;
00783     data_service_context_t * const ds_ptr = session->service_context;
00784 
00785     switch (service_request->service_type)
00786     {
00787         case msg_service_type_need_data:
00788             status = process_send_request(connector_ptr, service_request, ds_ptr);
00789             break;
00790 
00791         case msg_service_type_have_data:
00792             status = process_send_response(connector_ptr, service_request, ds_ptr);
00793             break;
00794 
00795         case msg_service_type_error:
00796         {
00797             msg_session_t * const session = service_request->session;
00798             session->error = service_request->error_value;
00799             status = process_send_error(connector_ptr, service_request, ds_ptr->callback_context);
00800             break;
00801         }
00802 
00803         case msg_service_type_free:
00804             {
00805 #if (CONNECTOR_VERSION >= 0x02010000)
00806                 msg_session_t * const session = service_request->session;
00807                 if (session->error == connector_session_error_none)
00808                 {
00809                     /* If there is no error, call the user to inform that session is done */
00810                     status = process_send_error(connector_ptr, service_request, ds_ptr->callback_context);
00811                     if (status != connector_working)
00812                         break;
00813                 }
00814 #endif
00815                 if (ds_ptr != NULL)
00816                     status = free_data_buffer(connector_ptr, named_buffer_id(put_request), ds_ptr);
00817                 else
00818                     status = connector_working;
00819                 break;
00820             }
00821         default:
00822             status = connector_idle;
00823             ASSERT(connector_false);
00824             break;
00825     }
00826 
00827     return status;
00828 }
00829 
00830 static connector_status_t data_service_put_request_init(connector_data_t * const connector_ptr, msg_service_request_t * const service_request)
00831 {
00832     connector_status_t status = connector_working;
00833     connector_session_error_t result = service_request->error_value;
00834     msg_session_t * const session = service_request->session;
00835     connector_request_data_service_send_t * send_ptr = (void *)service_request->have_data;
00836     data_service_context_t * ds_ptr = NULL;
00837 
00838     if (send_ptr != NULL)
00839     {
00840         void * ptr;
00841 
00842         if ((result != connector_session_error_none) || (session == NULL)) goto error;
00843 
00844         status = malloc_data_buffer(connector_ptr, sizeof *ds_ptr, named_buffer_id(put_request), &ptr);
00845         if (status != connector_working)
00846             goto error;
00847 
00848         ds_ptr = ptr;
00849     }
00850     else
00851     {
00852         status = connector_invalid_data;
00853         ASSERT_GOTO(connector_false, done);
00854     }
00855 
00856     ds_ptr->header = send_ptr;
00857     ds_ptr->callback_context = send_ptr->user_context;
00858     ds_ptr->request_type = connector_request_id_data_service_send_data;
00859     ds_ptr->dp_request = connector_false;
00860     session->service_context = ds_ptr;
00861 
00862     #if (defined CONNECTOR_DATA_POINTS)
00863     {
00864         char const data_point_prefix[] = "DataPoint/";
00865 
00866         ds_ptr->dp_request = connector_bool(!strncmp(ds_ptr->header->path, data_point_prefix, strlen(data_point_prefix)));
00867     }
00868     #endif
00869 
00870     goto done;
00871 
00872 error:
00873     set_data_service_error(service_request, result);
00874     process_send_error(connector_ptr, service_request, send_ptr->user_context);
00875 
00876 done:
00877     return status;
00878 }
00879 
00880 static connector_status_t data_service_callback(connector_data_t * const connector_ptr, msg_service_request_t * const service_request)
00881 {
00882     connector_status_t status = connector_idle;
00883     msg_session_t * session;
00884     data_service_context_t * ds_ptr;
00885 
00886     ASSERT_GOTO(connector_ptr != NULL, done);
00887     ASSERT_GOTO(service_request != NULL, done);
00888 
00889     session = service_request->session;
00890 
00891     if (service_request->service_type == msg_service_type_pending_request || session == NULL)
00892     {
00893         status = data_service_put_request_init(connector_ptr, service_request);
00894         goto done;
00895     }
00896 
00897     ds_ptr = session->service_context;
00898 
00899     if (ds_ptr == NULL)
00900     {
00901         status = data_service_device_request_callback(connector_ptr, service_request);
00902         goto done;
00903     }
00904 
00905     switch (ds_ptr->request_type)
00906     {
00907         case connector_request_id_data_service_send_length:
00908         case connector_request_id_data_service_send_data:
00909         case connector_request_id_data_service_send_status:
00910         case connector_request_id_data_service_send_response:
00911             status = data_service_put_request_callback(connector_ptr, service_request);
00912             break;
00913 
00914         case connector_request_id_data_service_receive_target:
00915         case connector_request_id_data_service_receive_data:
00916         case connector_request_id_data_service_receive_status:
00917         case connector_request_id_data_service_receive_reply_length:
00918         case connector_request_id_data_service_receive_reply_data:
00919             status = data_service_device_request_callback(connector_ptr, service_request);
00920             break;
00921 
00922         default:
00923             ASSERT(connector_false);
00924             break;
00925     }
00926 
00927 done:
00928     return status;
00929 }
00930 
00931 static connector_status_t connector_facility_data_service_cleanup(connector_data_t * const connector_ptr)
00932 {
00933     return msg_cleanup_all_sessions(connector_ptr,  msg_service_id_data);
00934 }
00935 
00936 static connector_status_t connector_facility_data_service_delete(connector_data_t * const data_ptr)
00937 {
00938     return msg_delete_facility(data_ptr, msg_service_id_data);
00939 }
00940 
00941 static connector_status_t connector_facility_data_service_init(connector_data_t * const data_ptr, unsigned int const facility_index)
00942 {
00943     return msg_init_facility(data_ptr, facility_index, msg_service_id_data, data_service_callback);
00944 }
00945 
00946 static connector_status_t data_service_initiate(connector_data_t * const connector_ptr,  void const * request)
00947 {
00948     connector_status_t status = connector_invalid_data;
00949 
00950     ASSERT_GOTO(request != NULL, error);
00951 
00952     status = msg_initiate_request(connector_ptr, request) == connector_true ? connector_success : connector_service_busy;
00953 
00954 error:
00955     return status;
00956 }
00957 
00958 
00959