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

« Back to documentation index

Show/hide line numbers connector_sm_session.h Source File

connector_sm_session.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 /* This function searches for the next valid request_id and leaves it in connector_ptr->last_request_id */
00013 static connector_status_t sm_get_request_id(connector_data_t * const connector_ptr, connector_sm_data_t * const sm_ptr)
00014 {
00015     connector_status_t result = connector_pending;
00016     unsigned long const request_id = connector_ptr->last_request_id;
00017 
00018     do
00019     {
00020         connector_sm_session_t * session = sm_ptr->session.head;
00021 
00022         connector_ptr->last_request_id++;
00023         connector_ptr->last_request_id &= SM_REQUEST_ID_MASK;
00024 
00025         while (session != NULL)
00026         {
00027             /* already used? */
00028             if (session->request_id == connector_ptr->last_request_id)
00029                 break;
00030 
00031             session = session->next;
00032         }
00033 
00034         if (session == NULL)
00035             break;
00036 
00037     } while (request_id != connector_ptr->last_request_id);
00038 
00039     ASSERT_GOTO(request_id != connector_ptr->last_request_id, error);
00040     result = connector_working;
00041 
00042 error:
00043     return result;
00044 }
00045 
00046 static connector_sm_session_t * get_sm_session(connector_sm_data_t * const sm_ptr, uint32_t const transcation_id, connector_bool_t const client_originated)
00047 {
00048     connector_sm_session_t * session = sm_ptr->session.head;
00049 
00050     while (session != NULL)
00051     {
00052         if ((session->request_id == transcation_id) && (SmIsClientOwned(session->flags) == client_originated))
00053             break;
00054 
00055         session = session->next;
00056     }
00057 
00058     return session;
00059 }
00060 
00061 static connector_sm_session_t * sm_create_session(connector_data_t * const connector_ptr, connector_sm_data_t * const sm_ptr, connector_bool_t const client_originated)
00062 {
00063     connector_sm_session_t * session = NULL;
00064     void * ptr = NULL;
00065     connector_status_t result;
00066     size_t const active_sessions = client_originated ? sm_ptr->session.active_client_sessions : sm_ptr->session.active_cloud_sessions;
00067     static connector_bool_t print_once = connector_true;
00068 
00069     if (active_sessions >= sm_ptr->session.max_sessions)
00070     {
00071         if (print_once)
00072         {
00073             connector_debug_printf("Active %s sessions reached the limit %" PRIsize "\n", client_originated ? "client" : "cloud", active_sessions);
00074             print_once = connector_false;
00075         }
00076 
00077         goto done;
00078     }
00079 
00080     print_once = connector_true;
00081     result = malloc_data_buffer(connector_ptr, sizeof *session, named_buffer_id(sm_session), &ptr);
00082     if (result != connector_working)
00083         goto error;
00084 
00085     session = ptr;
00086     result = get_system_time(connector_ptr, &session->start_time);
00087     ASSERT_GOTO(result == connector_working, error);
00088 
00089     session->flags = 0;
00090     session->error = connector_sm_error_none;
00091     session->in.data = NULL;
00092     session->in.bytes = 0;
00093     session->bytes_processed = 0;
00094     session->user.header = NULL;
00095     session->user.context = NULL;
00096     session->segments.processed = 0;
00097     session->segments.count = 0;
00098 
00099     session->transport = sm_ptr->network.transport;
00100     #if (defined CONNECTOR_TRANSPORT_SMS)
00101     if (session->transport == connector_transport_sms)
00102         SmSetEncoded(session->flags);
00103     #endif
00104 
00105     if (client_originated)
00106     {
00107         result = sm_copy_user_request(sm_ptr, session);
00108         ASSERT_GOTO(result == connector_working, error);
00109         SmSetClientOwned(session->flags);
00110 
00111         session->request_id = sm_ptr->pending.request_id;
00112         sm_ptr->session.active_client_sessions++;
00113     }
00114     else
00115     {
00116         session->sm_state = connector_sm_state_receive_data;
00117         sm_ptr->session.active_cloud_sessions++;
00118     }
00119 
00120     add_list_node(&sm_ptr->session.head, &sm_ptr->session.tail, session);
00121     goto done;
00122 
00123 error:
00124     if (session != NULL)
00125     {
00126         result = free_data_buffer(connector_ptr, named_buffer_id(sm_session), session);
00127         ASSERT(result == connector_working);
00128         session = NULL;
00129     }
00130 
00131 done:
00132     return session;
00133 }
00134 
00135 static connector_status_t sm_delete_session(connector_data_t * const connector_ptr, connector_sm_data_t * const sm_ptr, connector_sm_session_t * const session)
00136 {
00137     connector_status_t result = connector_working;
00138 
00139     ASSERT_GOTO(sm_ptr != NULL, error);
00140     ASSERT_GOTO(session != NULL, error);
00141 
00142     if (SmIsClientOwned(session->flags))
00143     {
00144         ASSERT(sm_ptr->session.active_client_sessions > 0);
00145         sm_ptr->session.active_client_sessions--;
00146     }
00147     else
00148     {
00149         ASSERT(sm_ptr->session.active_cloud_sessions > 0);
00150         sm_ptr->session.active_cloud_sessions--;
00151     }
00152 
00153     if (session->in.data != NULL)
00154     {
00155         result = free_data_buffer(connector_ptr, named_buffer_id(sm_data_block), session->in.data);
00156         session->in.data = NULL;
00157     }
00158 
00159     remove_list_node(&sm_ptr->session.head, &sm_ptr->session.tail, session);
00160     if (sm_ptr->session.current == session)
00161         sm_ptr->session.current = (session->next != NULL) ? session->next : sm_ptr->session.head;
00162 
00163     {
00164         connector_status_t const status = free_data_buffer(connector_ptr, named_buffer_id(sm_session), session);
00165 
00166         if (status != connector_working)
00167             result = connector_abort;
00168     }
00169 
00170     if (sm_ptr->close.stop_condition == connector_wait_sessions_complete)
00171     {
00172         if (sm_ptr->session.head == NULL)
00173             sm_ptr->transport.state = connector_transport_close;
00174     }
00175 
00176 error:
00177     return result;
00178 }
00179 
00180 /* If request_id == NULL cancel ALL sessions. Else cancel the SM session whose Request ID matches the one passed as a parameter. */
00181 #if (CONNECTOR_VERSION >= 0x02010000)
00182 static connector_status_t sm_cancel_session(connector_data_t * const connector_ptr, connector_sm_data_t * const sm_ptr, uint32_t const * const request_id)
00183 {
00184     connector_status_t result = connector_working;
00185     connector_sm_session_t * session = sm_ptr->session.head;
00186     connector_bool_t cancel_all = connector_bool(request_id == NULL);
00187     
00188     while (session != NULL)
00189     {
00190         connector_sm_session_t * next_session = NULL;
00191         uint32_t session_request_id = request_id != NULL ? *request_id : SM_INVALID_REQUEST_ID;
00192 
00193         if (cancel_all || (session_request_id == *request_id))
00194         {
00195             session->error = connector_sm_error_cancel;
00196             result = sm_inform_session_complete(connector_ptr, session);
00197             if (result != connector_working)
00198                 break;
00199             next_session = session->next;
00200             result = sm_delete_session(connector_ptr, sm_ptr, session);
00201             if (result != connector_working)
00202                 break;
00203 
00204             if (!cancel_all)
00205                 break;
00206         }
00207 
00208         session = next_session != NULL ? next_session : session->next;
00209     }
00210 #if (defined CONNECTOR_DATA_POINTS)
00211     dp_cancel_session(connector_ptr, session, request_id);
00212 #endif
00213     return result;
00214 }
00215 #else
00216 static connector_status_t sm_cancel_session(connector_data_t * const connector_ptr, connector_sm_data_t * const sm_ptr, void const * const user_context)
00217 {
00218     connector_status_t result = connector_working;
00219     connector_sm_session_t * session = sm_ptr->session.head;
00220     connector_bool_t cancel_all = connector_bool(user_context == NULL);
00221 
00222     while (session != NULL)
00223     {
00224         connector_status_t status;
00225         connector_sm_session_t * next_session = NULL;
00226 
00227         if (cancel_all || (session->user.context == user_context))
00228         {
00229             if (session->user.context != NULL)
00230             {
00231                 session->error = connector_sm_error_cancel;
00232                 status = sm_inform_session_complete(connector_ptr, session);
00233                 if (status != connector_working)
00234                     result = connector_abort;
00235             }
00236 
00237             next_session = session->next;
00238             status = sm_delete_session(connector_ptr, sm_ptr, session);
00239             if (status != connector_working)
00240             {
00241                 result = connector_abort;
00242                 break;
00243             }
00244             if (!cancel_all)
00245                 break;
00246         }
00247 
00248         session = next_session;
00249     }
00250 
00251     return result;
00252 }
00253 #endif
00254 static connector_status_t sm_process_pending_data(connector_data_t * const connector_ptr, connector_sm_data_t * const sm_ptr)
00255 {
00256     connector_status_t result = connector_idle;
00257 
00258     if (sm_ptr->pending.data == NULL)
00259         goto done;
00260 
00261     switch (sm_ptr->pending.request)
00262     {
00263         case connector_initiate_transport_start:
00264             switch(sm_ptr->transport.state)
00265             {
00266                 case connector_transport_idle:
00267                     sm_ptr->transport.state = connector_transport_open;
00268                     break;
00269 
00270                 case connector_transport_close:
00271                     /* wait for close to complete */
00272                     goto done;
00273 
00274                 case connector_transport_terminate:
00275                     result = connector_device_terminated;
00276                     break;
00277 
00278                 default:
00279                     break;
00280             }
00281             break;
00282 
00283         case connector_initiate_transport_stop:
00284             if ((sm_ptr->close.stop_condition == connector_wait_sessions_complete) && (sm_ptr->session.head != NULL))
00285                 goto done;
00286             else
00287             {
00288                 result = sm_cancel_session(connector_ptr, sm_ptr, NULL);
00289                 sm_ptr->transport.state = connector_transport_close;
00290             }
00291             break;
00292 
00293         case connector_initiate_session_cancel:
00294         {
00295             connector_sm_cancel_request_t const * const request = sm_ptr->pending.data;
00296 #if (CONNECTOR_VERSION >= 0x02010000)
00297             result = sm_cancel_session(connector_ptr, sm_ptr, &request->request_id);
00298 #else
00299             result = sm_cancel_session(connector_ptr, sm_ptr, request->user_context);
00300 #endif
00301             break;
00302         }
00303 #if (CONNECTOR_VERSION >= 0x02010000)
00304         case connector_initiate_session_cancel_all:
00305         {
00306             result = sm_cancel_session(connector_ptr, sm_ptr, NULL);
00307             break;
00308         }
00309 #endif
00310         default:
00311         {
00312             connector_bool_t const client_originated = connector_true;
00313             connector_sm_session_t * const session = sm_create_session(connector_ptr, sm_ptr, client_originated);
00314 
00315             if (session == NULL)
00316             {
00317                 result = connector_pending;
00318                 goto done;
00319             }
00320 
00321             result = connector_working;
00322             break;
00323         }
00324     }
00325 
00326     sm_ptr->pending.data = NULL;
00327 
00328 done:
00329     return result;
00330 }
00331 
00332 
00333