Coverage Report

Created: 2026-02-14 06:27

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/S2OPC/src/ClientServer/services/sopc_services_api.c
Line
Count
Source
1
/*
2
 * Licensed to Systerel under one or more contributor license
3
 * agreements. See the NOTICE file distributed with this work
4
 * for additional information regarding copyright ownership.
5
 * Systerel licenses this file to you under the Apache
6
 * License, Version 2.0 (the "License"); you may not use this
7
 * file except in compliance with the License. You may obtain
8
 * a copy of the License at
9
 *
10
 *   http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing,
13
 * software distributed under the License is distributed on an
14
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
 * KIND, either express or implied.  See the License for the
16
 * specific language governing permissions and limitations
17
 * under the License.
18
 */
19
20
#include <inttypes.h>
21
#include <stdbool.h>
22
#include <stdio.h>
23
24
#include "sopc_array.h"
25
#include "sopc_assert.h"
26
#include "sopc_date_time.h"
27
#include "sopc_enums.h"
28
#include "sopc_helper_string.h"
29
#include "sopc_internal_app_dispatcher.h"
30
#include "sopc_logger.h"
31
#include "sopc_macros.h"
32
#include "sopc_mem_alloc.h"
33
#include "sopc_mutexes.h"
34
#include "sopc_secure_channels_api.h"
35
#include "sopc_services_api.h"
36
#include "sopc_services_api_internal.h"
37
#include "sopc_toolkit_config.h"
38
#include "sopc_toolkit_config_internal.h"
39
#include "sopc_user_app_itf.h"
40
41
#include "io_dispatch_mgr.h"
42
#include "monitored_item_pointer_bs.h"
43
#include "service_mgr_bs.h"
44
#include "toolkit_header_init.h"
45
#include "util_b2c.h"
46
47
static SOPC_Looper* servicesLooper = NULL;
48
static SOPC_EventHandler* secureChannelsEventHandler = NULL;
49
static SOPC_EventHandler* servicesEventHandler = NULL;
50
51
// Structure used to close all connections in a synchronous way
52
// (necessary on toolkit clear)
53
static struct
54
{
55
    SOPC_Mutex mutex;
56
    SOPC_Condition cond;
57
    bool allDisconnectedFlag;
58
    bool requestedFlag;
59
    bool clientOnlyFlag;
60
} closeAllConnectionsSync = {.allDisconnectedFlag = false, .requestedFlag = false, .clientOnlyFlag = false};
61
62
SOPC_EventHandler* SOPC_Services_GetEventHandler(void)
63
0
{
64
0
    return servicesEventHandler;
65
0
}
66
67
static void SOPC_Internal_AllClientSecureChannelsDisconnected(bool clientOnly)
68
0
{
69
0
    SOPC_Mutex_Lock(&closeAllConnectionsSync.mutex);
70
0
    SOPC_ASSERT(closeAllConnectionsSync.clientOnlyFlag == clientOnly);
71
0
    if (closeAllConnectionsSync.requestedFlag)
72
0
    {
73
0
        closeAllConnectionsSync.allDisconnectedFlag = true;
74
0
        SOPC_Condition_SignalAll(&closeAllConnectionsSync.cond);
75
0
    }
76
0
    SOPC_Mutex_Unlock(&closeAllConnectionsSync.mutex);
77
0
}
78
79
static void onSecureChannelEvent(SOPC_EventHandler* handler,
80
                                 int32_t event,
81
                                 uint32_t id,
82
                                 uintptr_t params,
83
                                 uintptr_t auxParam)
84
0
{
85
0
    SOPC_UNUSED_ARG(handler);
86
0
    SOPC_SecureChannels_OutputEvent scEvent = (SOPC_SecureChannels_OutputEvent) event;
87
0
    bool bres = false;
88
0
    uint32_t channel_config_idx = 0;
89
0
    SOPC_ReturnStatus status = SOPC_STATUS_NOK;
90
91
0
    switch (scEvent)
92
0
    {
93
0
    case EP_CONNECTED:
94
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER,
95
0
                               "ServicesMgr: SC_EP_SC_CONNECTED epCfgIdx=%" PRIu32 " scCfgIdx=%" PRIuPTR
96
0
                               " scIdx=%" PRIuPTR,
97
0
                               id, params, auxParam);
98
99
        // id ==  endpoint configuration index
100
        // params = channel configuration index
101
        // auxParam == connection Id
102
0
        SOPC_ASSERT(id <= INT32_MAX);
103
0
        channel_config_idx = (uint32_t) params;
104
0
        SOPC_ASSERT(channel_config_idx <= constants__t_channel_config_idx_i_max);
105
0
        SOPC_ASSERT(auxParam <= constants__t_channel_i_max);
106
107
0
        io_dispatch_mgr__server_channel_connected_event(id, channel_config_idx, (uint32_t) auxParam, &bres);
108
0
        if (bres == false)
109
0
        {
110
0
            SOPC_Logger_TraceError(SOPC_LOG_MODULE_CLIENTSERVER,
111
0
                                   "Services: channel state incoherent or maximum reached epCfgIdx=%" PRIu32
112
0
                                   " scIdx=%" PRIuPTR,
113
0
                                   id, auxParam);
114
115
0
            SOPC_SecureChannels_EnqueueEvent(SC_DISCONNECT, (uint32_t) auxParam,
116
0
                                             (uintptr_t) OpcUa_BadSecureChannelClosed, 0);
117
0
        }
118
119
0
        break;
120
0
    case EP_CLOSED:
121
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER,
122
0
                               "ServicesMgr: SC_EP_CLOSED epCfgIdx=%" PRIu32 " returnStatus=%" PRIuPTR, id, auxParam);
123
        // id == endpoint configuration index
124
        // params = NULL
125
        // auxParam == status
126
        // => B model entry point to add
127
0
        status = SOPC_App_EnqueueComEvent(SE_CLOSED_ENDPOINT, id, (uintptr_t) NULL, auxParam);
128
0
        SOPC_ASSERT(status == SOPC_STATUS_OK);
129
0
        break;
130
0
    case EP_REVERSE_CLOSED:
131
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER,
132
0
                               "ServicesMgr: EP_REVERSE_CLOSED reverseEpCfgIdx=%" PRIu32 " returnStatus=%" PRIuPTR, id,
133
0
                               auxParam);
134
        //  id = reverse endpoint config index,
135
        // auxParams = SOPC_ReturnStatus
136
0
        status = SOPC_App_EnqueueComEvent(SE_REVERSE_ENDPOINT_CLOSED, id, (uintptr_t) NULL, auxParam);
137
0
        SOPC_ASSERT(status == SOPC_STATUS_OK);
138
0
        break;
139
0
    case SC_CONNECTED:
140
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER,
141
0
                               "ServicesMgr: SC_SC_CONNECTED scIdx=%" PRIu32 " scCfgIdx=%" PRIuPTR, id, auxParam);
142
        // id == connection Id
143
        // auxParam == secure channel configuration index
144
        // => B model entry point to add
145
0
        SOPC_ASSERT(id <= constants__t_channel_i_max);
146
0
        SOPC_ASSERT(auxParam <= constants__t_channel_config_idx_i_max);
147
0
        io_dispatch_mgr__client_channel_connected_event((uint32_t) auxParam,
148
0
                                                        constants__c_reverse_endpoint_config_idx_indet, id);
149
0
        break;
150
0
    case SC_REVERSE_CONNECTED:
151
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER,
152
0
                               "ServicesMgr: SC_REVERSE_CONNECTED scIdx=%" PRIu32 " scCfgIdx=%" PRIuPTR, id, auxParam);
153
        // id = secure channel connection index,
154
        // params = (uint32_t) secure channel configuration index,
155
        // auxParams = (uint32) reverse endpoint configuration index
156
        // => B model entry point to add
157
0
        SOPC_ASSERT(id <= constants__t_channel_i_max);
158
0
        SOPC_ASSERT(auxParam <= constants__t_channel_config_idx_i_max);
159
0
        io_dispatch_mgr__client_channel_connected_event((uint32_t) params, (uint32_t) auxParam, id);
160
0
        break;
161
0
    case SC_CONNECTION_TIMEOUT:
162
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER, "ServicesMgr: SC_SC_CONNECTION_TIMEOUT scCfgIdx=%" PRIu32,
163
0
                               id);
164
165
        // id == secure channel configuration index
166
        // => B model entry point to add
167
0
        SOPC_ASSERT(id <= constants_bs__t_channel_config_idx_i_max);
168
0
        io_dispatch_mgr__client_secure_channel_timeout(id);
169
0
        break;
170
0
    case SC_DISCONNECTED:
171
0
        channel_config_idx = (uint32_t) params;
172
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER,
173
0
                               "ServicesMgr: SC_SC_DISCONNECTED scIdx=%" PRIu32 " scCfgIdx=%" PRIu32
174
0
                               " with status=x%08" PRIX32,
175
0
                               id, channel_config_idx, (uint32_t) auxParam);
176
        // id == connection Id
177
        // params == secure channel configuration index (server only)
178
        // auxParam = status
179
0
        io_dispatch_mgr__secure_channel_lost(id);
180
        // Acknowledge the disconnected state is set in service layer to free the connection index
181
0
        SOPC_SecureChannels_EnqueueEvent(SC_DISCONNECTED_ACK, id, params, 0);
182
0
        break;
183
0
    case SC_SERVICE_RCV_MSG:
184
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER,
185
0
                               "ServicesMgr: SC_SC_SERVICE_RCV_MSG scIdx=%" PRIu32 " reqId/0=%" PRIuPTR, id, auxParam);
186
187
        // id ==  connection Id
188
        // params = message content (byte buffer)
189
        // auxParam == requestId (server) / 0 (client)
190
0
        SOPC_ASSERT(NULL != (void*) params);
191
0
        io_dispatch_mgr__receive_msg_buffer(id, (constants__t_byte_buffer_i) params,
192
0
                                            (constants__t_request_context_i) auxParam, &bres);
193
0
        if (!bres)
194
0
        {
195
0
            SOPC_Logger_TraceError(SOPC_LOG_MODULE_CLIENTSERVER,
196
0
                                   "ServicesMgr: SC_SC_SERVICE_RCV_MSG scIdx=%" PRIu32 " reqId/0=%" PRIuPTR
197
0
                                   " received message considered invalid",
198
0
                                   id, auxParam);
199
0
        }
200
        // params is freed by services manager
201
0
        break;
202
0
    case SC_SND_FAILURE:
203
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER,
204
0
                               "ServicesMgr: SC_SND_FAILURE scIdx=%" PRIu32 " reqId/Handle=%" PRIuPTR
205
0
                               " statusCode=%" PRIXPTR,
206
0
                               id, (uintptr_t) params, auxParam);
207
208
0
        constants_statuscodes_bs__t_StatusCode_i statusCode;
209
0
        util_status_code__C_to_B((SOPC_StatusCode) auxParam, &statusCode);
210
0
        io_dispatch_mgr__snd_msg_failure(id, (constants__t_request_context_i) params, statusCode);
211
0
        break;
212
0
    case SC_REQUEST_TIMEOUT:
213
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER,
214
0
                               "ServicesMgr: SC_REQUEST_TIMEOUT scIdx=%" PRIu32 " reqHandle=%" PRIuPTR, id, auxParam);
215
216
        /* id = secure channel connection index,
217
           auxParam = request handle */
218
0
        SOPC_ASSERT(id <= constants__t_channel_i_max);
219
0
        SOPC_ASSERT(auxParam <= SOPC_MAX_PENDING_REQUESTS);
220
0
        io_dispatch_mgr__client_request_timeout(id, (uint32_t) auxParam);
221
0
        break;
222
0
    default:
223
0
        SOPC_ASSERT(false && "Unknown event");
224
0
    }
225
0
}
226
227
static void onServiceEvent(SOPC_EventHandler* handler,
228
                           int32_t scEvent,
229
                           uint32_t id,
230
                           uintptr_t params,
231
                           uintptr_t auxParam)
232
0
{
233
0
    SOPC_Services_Event event = (SOPC_Services_Event) scEvent;
234
0
    SOPC_ReturnStatus status = SOPC_STATUS_OK;
235
0
    SOPC_Endpoint_Config* epConfig = NULL;
236
0
    constants_statuscodes_bs__t_StatusCode_i sCode = constants_statuscodes_bs__e_sc_ok;
237
0
    SOPC_EncodeableType* encType = NULL;
238
0
    bool lbres = false;
239
0
    bool bres = false;
240
0
    void* msg = NULL;
241
0
    size_t length = 0;
242
0
    SOPC_Array* dataOrNodeChangedArray = NULL;
243
0
    SOPC_WriteDataChanged* writeDataChanged = NULL;
244
0
    SOPC_NodeChanged* nodeChanged = NULL;
245
0
    OpcUa_WriteValue* old_value = NULL;
246
0
    OpcUa_WriteValue* new_value = NULL;
247
0
    SOPC_Internal_AsyncSendMsgData* msg_data;
248
0
    const SOPC_NodeId* nodeId2 = NULL;
249
0
    char* nodeIdStr = NULL;
250
0
    char* nodeIdStr2 = NULL;
251
0
    const char* reverseEndpointURL = NULL;
252
0
    SOPC_Internal_SessionAppContext* sessionContext = NULL;
253
0
    SOPC_ExtensionObject* userToken = NULL;
254
0
    SOPC_Internal_DiscoveryContext* discoveryContext = NULL;
255
0
    SOPC_Internal_EventContext* eventContext = NULL;
256
0
    SOPC_DateTime currentTime = 0;
257
258
0
    switch (event)
259
0
    {
260
0
    case SE_TO_SE_SC_ALL_DISCONNECTED:
261
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER,
262
0
                               "ServicesMgr: SE_TO_SE_SC_ALL_DISCONNECTED clientOnly=%" PRIuPTR, params);
263
        // Call directly toolkit configuration callback
264
0
        SOPC_Internal_AllClientSecureChannelsDisconnected((bool) params);
265
0
        break;
266
267
0
    case SE_TO_SE_ACTIVATE_ORPHANED_SESSION:
268
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER,
269
0
                               "ServicesMgr: SE_TO_SE_ACTIVATE_ORPHANED_SESSION session=%" PRIu32 " scCfgIdx=%" PRIuPTR,
270
0
                               id, auxParam);
271
272
0
        SOPC_ASSERT(auxParam <= constants__t_channel_config_idx_i_max);
273
0
        io_dispatch_mgr__internal_client_activate_orphaned_session(id, (constants__t_channel_config_idx_i) auxParam);
274
0
        break;
275
0
    case SE_TO_SE_CREATE_SESSION:
276
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER,
277
0
                               "ServicesMgr: SE_TO_SE_CREATE_SESSION session=%" PRIu32 " scCfgIdx=%" PRIuPTR, id,
278
0
                               auxParam);
279
0
        SOPC_ASSERT(auxParam <= constants__t_channel_config_idx_i_max);
280
0
        io_dispatch_mgr__internal_client_create_session((constants__t_session_i) id,
281
0
                                                        (constants__t_channel_config_idx_i) auxParam);
282
0
        break;
283
0
    case SE_TO_SE_ACTIVATE_SESSION:
284
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER, "ServicesMgr: SE_TO_SE_ACTIVATE_SESSION session=%" PRIu32,
285
0
                               id);
286
287
0
        if (NULL != (void*) params)
288
0
        {
289
0
            io_dispatch_mgr__client_reactivate_session_new_user(id, (constants__t_user_token_i) params);
290
0
        }
291
0
        else
292
0
        {
293
0
            SOPC_Logger_TraceError(SOPC_LOG_MODULE_CLIENTSERVER,
294
0
                                   "ServicesMgr: SE_TO_SE_ACTIVATE_SESSION session=%" PRIu32 " user parameter is NULL",
295
0
                                   id);
296
0
            sCode = constants_statuscodes_bs__e_sc_bad_generic;
297
0
        }
298
0
        break;
299
0
    case SE_TO_SE_SERVER_DATA_CHANGED:
300
        /* Server side only:
301
           params = (SOPC_Array*) array of SOPC_WriteDataChanged
302
         */
303
0
        SOPC_ASSERT((void*) params != NULL);
304
305
0
        dataOrNodeChangedArray = (SOPC_Array*) params;
306
0
        bres = true;
307
0
        length = SOPC_Array_Size(dataOrNodeChangedArray);
308
0
        for (size_t i = 0; i < length; i++)
309
0
        {
310
0
            writeDataChanged = (SOPC_WriteDataChanged*) SOPC_Array_Get_Ptr(dataOrNodeChangedArray, i);
311
0
            SOPC_ASSERT(writeDataChanged != NULL);
312
0
            old_value = writeDataChanged->oldValue;
313
0
            new_value = writeDataChanged->newValue;
314
            /* Note: write values deallocation managed by B model */
315
0
            io_dispatch_mgr__internal_server_data_changed(old_value, new_value, &lbres);
316
0
            bres = bres && lbres;
317
0
        }
318
0
        SOPC_Array_Delete(dataOrNodeChangedArray);
319
0
        if (bres == false)
320
0
        {
321
0
            SOPC_Logger_TraceError(SOPC_LOG_MODULE_CLIENTSERVER,
322
0
                                   "ServicesMgr: SE_TO_SE_SERVER_DATA_CHANGED session=%" PRIu32 " treatment failed",
323
0
                                   id);
324
0
        }
325
0
        break;
326
0
    case SE_TO_SE_SERVER_NODE_CHANGED:
327
        /* Server side only:
328
           params = (SOPC_Array*) array of SOPC_NodeChanged
329
         */
330
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER,
331
0
                               "ServicesMgr: SE_TO_SE_SERVER_NODE_CHANGED batched notifications");
332
333
0
        SOPC_ASSERT(NULL != (void*) params);
334
0
        dataOrNodeChangedArray = (SOPC_Array*) params;
335
0
        length = SOPC_Array_Size(dataOrNodeChangedArray);
336
0
        lbres = SOPC_LOG_LEVEL_DEBUG == SOPC_Logger_GetTraceLogLevel();
337
0
        for (size_t i = 0; i < length; i++)
338
0
        {
339
0
            nodeChanged = (SOPC_NodeChanged*) SOPC_Array_Get_Ptr(dataOrNodeChangedArray, i);
340
0
            SOPC_ASSERT(NULL != nodeChanged);
341
0
            if (lbres)
342
0
            {
343
0
                nodeIdStr = SOPC_NodeId_ToCString(nodeChanged->nodeId);
344
0
                SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER,
345
0
                                       "ServicesMgr: SE_TO_SE_SERVER_NODE_CHANGED %s nodeId: %s",
346
0
                                       nodeChanged->added ? "added" : "deleted", nodeIdStr);
347
0
                SOPC_Free(nodeIdStr);
348
0
            }
349
0
            io_dispatch_mgr__internal_server_node_changed(nodeChanged->added, nodeChanged->nodeId);
350
0
            SOPC_NodeId_Clear(nodeChanged->nodeId);
351
0
            SOPC_Free(nodeChanged->nodeId);
352
0
        }
353
0
        SOPC_Array_Delete(dataOrNodeChangedArray);
354
0
        break;
355
0
    case SE_TO_SE_SERVER_INACTIVATED_SESSION_PRIO:
356
        /* Server side only:
357
           id = session id
358
           auxParam = (int32_t) session state
359
         */
360
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER,
361
0
                               "ServicesMgr: SE_TO_SE_SERVER_INACTIVATED_SESSION_PRIO session=%" PRIu32
362
0
                               " sessionState=%" PRIuPTR,
363
0
                               id, auxParam);
364
365
0
        io_dispatch_mgr__internal_server_inactive_session_prio_event((constants__t_session_i) id,
366
0
                                                                     (constants__t_sessionState_i) auxParam, &bres);
367
368
0
        if (bres == false)
369
0
        {
370
0
            SOPC_Logger_TraceError(
371
0
                SOPC_LOG_MODULE_CLIENTSERVER,
372
0
                "ServicesMgr: SE_TO_SE_SERVER_INACTIVATED_SESSION_PRIO session=%" PRIu32 " treatment failed", id);
373
0
        }
374
0
        break;
375
0
    case SE_TO_SE_SERVER_SEND_ASYNC_PUB_RESP_PRIO:
376
        /* Server side only:
377
           id = session id
378
           params = (SOPC_Internal_AsyncSendMsgData*)
379
         */
380
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER,
381
0
                               "ServicesMgr: SE_TO_SE_SERVER_SEND_ASYNC_PUB_RESP_PRIO session=%" PRIu32, id);
382
383
0
        msg_data = (void*) params;
384
0
        SOPC_ASSERT(msg_data != NULL);
385
386
0
        io_dispatch_mgr__internal_server_send_publish_response_prio_event(
387
0
            (constants__t_session_i) id, msg_data->requestHandle, msg_data->requestId, msg_data->msgToSend,
388
0
            (constants_statuscodes_bs__t_StatusCode_i) msg_data->bStatusCode, &bres);
389
0
        SOPC_Free(msg_data);
390
391
0
        if (!bres)
392
0
        {
393
0
            SOPC_Logger_TraceError(
394
0
                SOPC_LOG_MODULE_CLIENTSERVER,
395
0
                "ServicesMgr: SE_TO_SE_SERVER_SEND_ASYNC_PUB_RESP_PRIO session=%" PRIu32 " treatment failed", id);
396
0
        }
397
0
        break;
398
0
    case SE_TO_SE_SERVER_ASYNC_CLOSE_SUBSCRIPTION:
399
        /* Server side only:
400
           id = subscription id
401
         */
402
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER,
403
0
                               "ServicesMgr: SE_TO_SE_SERVER_ASYNC_CLOSE_SUBSCRIPTION subscription=%" PRIu32, id);
404
405
0
        io_dispatch_mgr__internal_server_close_subscription((constants__t_subscription_i) id, &bres);
406
407
0
        if (!bres)
408
0
        {
409
0
            SOPC_Logger_TraceError(
410
0
                SOPC_LOG_MODULE_CLIENTSERVER,
411
0
                "ServicesMgr: SE_TO_SE_SERVER_ASYNC_CLOSE_SUBSCRIPTION subscription=%" PRIu32 " treatment failed", id);
412
0
        }
413
0
        break;
414
0
    case TIMER_SE_EVAL_SESSION_TIMEOUT:
415
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER,
416
0
                               "ServicesMgr: TIMER_SE_EVAL_SESSION_TIMEOUT session=%" PRIu32, id);
417
0
        io_dispatch_mgr__internal_server_evaluate_session_timeout((constants__t_session_i) id);
418
0
        break;
419
0
    case TIMER_SE_PUBLISH_CYCLE_TIMEOUT:
420
        /* Server side only: id = subscription id */
421
0
        io_dispatch_mgr__internal_server_subscription_publish_timeout((constants__t_subscription_i) id, &bres);
422
0
        if (bres == false)
423
0
        {
424
0
            SOPC_Logger_TraceError(
425
0
                SOPC_LOG_MODULE_CLIENTSERVER,
426
0
                "ServicesMgr: TIMER_SE_PUBLISH_CYCLE_TIMEOUT subscription=%" PRIu32 " treatment failed", id);
427
0
        }
428
0
        break;
429
430
    /* App to Services events */
431
0
    case APP_TO_SE_OPEN_ENDPOINT:
432
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER, "ServicesMgr: APP_TO_SE_OPEN_ENDPOINT epCfgIdx=%" PRIu32,
433
0
                               id);
434
435
        // id ==  endpoint configuration index
436
        // => B model entry point to add
437
0
        epConfig = SOPC_ToolkitServer_GetEndpointConfig(id);
438
0
        if (NULL == epConfig)
439
0
        {
440
0
            status = SOPC_App_EnqueueComEvent(SE_CLOSED_ENDPOINT, id, (uintptr_t) NULL, SOPC_STATUS_INVALID_PARAMETERS);
441
0
            SOPC_ASSERT(SOPC_STATUS_OK == status);
442
0
        }
443
0
        else
444
0
        {
445
0
            status = SOPC_SecureChannels_EnqueueEvent(EP_OPEN,
446
0
                                                      id, // Server endpoint config idx
447
0
                                                      (uintptr_t) NULL, 0);
448
0
            SOPC_ASSERT(SOPC_STATUS_OK == status);
449
0
        }
450
0
        break;
451
0
    case APP_TO_SE_CLOSE_ENDPOINT:
452
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER, "ServicesMgr: APP_TO_SE_CLOSE_ENDPOINT epCfgIdx=%" PRIu32,
453
0
                               id);
454
455
        // id ==  endpoint configuration index
456
        // => B model entry point to add
457
0
        epConfig = SOPC_ToolkitServer_GetEndpointConfig(id);
458
0
        if (NULL == epConfig)
459
0
        {
460
0
            status = SOPC_App_EnqueueComEvent(SE_CLOSED_ENDPOINT, id, (uintptr_t) NULL, SOPC_STATUS_INVALID_PARAMETERS);
461
0
            SOPC_ASSERT(SOPC_STATUS_OK == status);
462
0
        }
463
0
        else
464
0
        {
465
0
            status = SOPC_SecureChannels_EnqueueEvent(EP_CLOSE, id, (uintptr_t) NULL, 0);
466
0
            SOPC_ASSERT(SOPC_STATUS_OK == status);
467
0
        }
468
0
        break;
469
470
0
    case APP_TO_SE_LOCAL_SERVICE_REQUEST:
471
0
        if ((void*) params != NULL)
472
0
        {
473
0
            encType = *(SOPC_EncodeableType**) params;
474
0
        }
475
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER,
476
0
                               "ServicesMgr: APP_TO_SE_LOCAL_SERVICE_REQUEST epCfgIdx=%" PRIu32
477
0
                               " msgType=%s ctx=%" PRIuPTR,
478
0
                               id, SOPC_EncodeableType_GetName(encType), auxParam);
479
480
        // id =  endpoint configuration index
481
        // params = local service request
482
        // auxParam = user application session context
483
0
        SOPC_ASSERT(id <= INT32_MAX);
484
485
0
        io_dispatch_mgr__server_treat_local_service_request(id, (constants__t_msg_i) params, auxParam, &sCode);
486
0
        if (constants_statuscodes_bs__e_sc_ok != sCode)
487
0
        {
488
            // Error case
489
0
            status = SOPC_EncodeableObject_Create(&OpcUa_ServiceFault_EncodeableType, &msg);
490
0
            if (SOPC_STATUS_OK == status && NULL != msg)
491
0
            {
492
0
                util_status_code__B_to_C(sCode, &((OpcUa_ServiceFault*) msg)->ResponseHeader.ServiceResult);
493
0
            }
494
0
            else
495
0
            {
496
0
                msg = NULL;
497
0
            }
498
0
            status = SOPC_App_EnqueueComEvent(SE_LOCAL_SERVICE_RESPONSE, id, (uintptr_t) msg, auxParam);
499
0
            SOPC_ASSERT(SOPC_STATUS_OK == status);
500
0
            SOPC_Logger_TraceWarning(SOPC_LOG_MODULE_CLIENTSERVER,
501
0
                                     "ServicesMgr: APP_TO_SE_LOCAL_SERVICE_REQUEST failed epCfgIdx=%" PRIu32
502
0
                                     " msgType=%s ctx=%" PRIuPTR,
503
0
                                     id, SOPC_EncodeableType_GetName(encType), auxParam);
504
0
        }
505
0
        break;
506
0
    case APP_TO_SE_TRIGGER_EVENT:
507
        // params =  (SOPC_Internal_EventContext*)
508
0
        eventContext = (SOPC_Internal_EventContext*) params;
509
0
        SOPC_ASSERT(NULL != eventContext);
510
0
        nodeIdStr = SOPC_NodeId_ToCString(&eventContext->notifierNodeId);
511
0
        nodeId2 = SOPC_Event_GetEventTypeId(eventContext->event);
512
0
        nodeIdStr2 = (NULL == nodeId2 ? SOPC_strdup("") : SOPC_NodeId_ToCString(nodeId2));
513
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER,
514
0
                               "ServicesMgr: APP_TO_SE_TRIGGER_EVENT eventTypeId=%s, notifierId=%s", nodeIdStr2,
515
0
                               nodeIdStr);
516
517
        // Update the receiveTime variable (and time variable if not set)
518
0
        currentTime = SOPC_Time_GetCurrentTimeUTC();
519
0
        status = SOPC_Event_SetReceiveTime(eventContext->event, currentTime);
520
0
        SOPC_ASSERT(SOPC_STATUS_OK == status);
521
0
        if (0 == SOPC_Event_GetTime(eventContext->event))
522
0
        {
523
0
            status = SOPC_Event_SetTime(eventContext->event, currentTime);
524
0
            SOPC_ASSERT(SOPC_STATUS_OK == status);
525
0
        }
526
527
0
        io_dispatch_mgr__internal_server_event_triggered(&eventContext->notifierNodeId, eventContext->event,
528
0
                                                         eventContext->optSessionId, eventContext->optSubscriptionId,
529
0
                                                         eventContext->optMonitoredItemId, &bres);
530
0
        if (!bres)
531
0
        {
532
0
            SOPC_Logger_TraceError(SOPC_LOG_MODULE_CLIENTSERVER,
533
0
                                   "ServicesMgr: failure in treatment of APP_TO_SE_TRIGGER_EVENT eventTypeId=%s, "
534
0
                                   "notifierId=%s",
535
0
                                   nodeIdStr2, nodeIdStr);
536
0
        }
537
0
        SOPC_Free(nodeIdStr);
538
0
        SOPC_Free(nodeIdStr2);
539
540
0
        SOPC_NodeId_Clear(&eventContext->notifierNodeId);
541
0
        SOPC_Event_Delete(&eventContext->event);
542
0
        SOPC_Free(eventContext);
543
0
        break;
544
0
    case APP_TO_SE_OPEN_REVERSE_ENDPOINT:
545
        /* id = reverse endpoint description config index */
546
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER,
547
0
                               "ServicesMgr: APP_TO_SE_OPEN_REVERSE_ENDPOINT reverseEpCfgIdx=%" PRIu32, id);
548
        // Check config index is valid
549
0
        reverseEndpointURL = SOPC_ToolkitClient_GetReverseEndpointURL(id);
550
0
        SOPC_ASSERT(NULL != reverseEndpointURL && "Invalid reverse endpoint configuration index provided");
551
0
        status = SOPC_SecureChannels_EnqueueEvent(REVERSE_EP_OPEN,
552
0
                                                  id, // Reverse endpoint config idx
553
0
                                                  (uintptr_t) NULL, 0);
554
0
        SOPC_ASSERT(SOPC_STATUS_OK == status);
555
0
        break;
556
0
    case APP_TO_SE_CLOSE_REVERSE_ENDPOINT:
557
        /* id = reverse endpoint description config index */
558
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER,
559
0
                               "ServicesMgr: APP_TO_SE_CLOSE_REVERSE_ENDPOINT reverseEpCfgIdx=%" PRIu32, id);
560
        // Check config index is valid
561
0
        reverseEndpointURL = SOPC_ToolkitClient_GetReverseEndpointURL(id);
562
0
        SOPC_ASSERT(NULL != reverseEndpointURL && "Invalid reverse endpoint configuration index provided");
563
0
        status = SOPC_SecureChannels_EnqueueEvent(REVERSE_EP_CLOSE, id, (uintptr_t) NULL, 0);
564
0
        SOPC_ASSERT(SOPC_STATUS_OK == status);
565
0
        break;
566
0
    case APP_TO_SE_ACTIVATE_SESSION:
567
        // id = secure channel config index,
568
        // params = reverse endpoint connection index or 0 if not a reverse connection
569
        // auxParam = (SOPC_Internal_SessionAppContext*)
570
0
        SOPC_ASSERT(id <= constants__t_channel_config_idx_i_max);
571
0
        SOPC_ASSERT((void*) auxParam != NULL);
572
0
        sessionContext = (SOPC_Internal_SessionAppContext*) auxParam;
573
0
        userToken = sessionContext->userToken;
574
0
        sessionContext->userToken = NULL; // Provided as separated parameter
575
576
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER,
577
0
                               "ServicesMgr: APP_TO_SE_ACTIVATE_SESSION scCfgIdx=%" PRIu32 " reverseEpCfgIdx=%" PRIuPTR
578
0
                               " ctx=%" PRIuPTR,
579
0
                               id, params, sessionContext->userSessionContext);
580
581
0
        io_dispatch_mgr__client_activate_new_session(id, (uint32_t) params, userToken, sessionContext, &bres);
582
583
0
        if (!bres)
584
0
        {
585
0
            SOPC_App_EnqueueComEvent(SE_SESSION_ACTIVATION_FAILURE,
586
0
                                     0,                                   // session id (not yet defined)
587
0
                                     (uintptr_t) NULL,                    // user ?
588
0
                                     sessionContext->userSessionContext); // user application session context
589
0
            SOPC_Logger_TraceWarning(SOPC_LOG_MODULE_CLIENTSERVER,
590
0
                                     "ServicesMgr: APP_TO_SE_ACTIVATE_SESSION failed scCfgIdx=%" PRIu32
591
0
                                     " reverseEpCfgIdx=%" PRIuPTR " ctx=%" PRIuPTR,
592
0
                                     id, params, auxParam);
593
0
            SOPC_ExtensionObject_Clear(userToken);
594
0
            SOPC_Free(userToken);
595
0
            SOPC_Free(sessionContext);
596
0
        }
597
0
        break;
598
0
    case APP_TO_SE_SEND_SESSION_REQUEST:
599
0
        if ((void*) params != NULL)
600
0
        {
601
0
            encType = *(SOPC_EncodeableType**) params;
602
0
        }
603
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER,
604
0
                               "ServicesMgr: APP_TO_SE_SEND_SESSION_REQUEST  session=%" PRIu32
605
0
                               " msgType=%s ctx=%" PRIuPTR,
606
0
                               id, SOPC_EncodeableType_GetName(encType), auxParam);
607
608
        // id == session id
609
        // params = request
610
0
        SOPC_ASSERT(id <= constants__t_session_i_max);
611
612
0
        io_dispatch_mgr__client_send_service_request(id, (constants__t_msg_i) params, auxParam, &sCode);
613
0
        if (sCode != constants_statuscodes_bs__e_sc_ok)
614
0
        {
615
0
            status = SOPC_App_EnqueueComEvent(SE_SND_REQUEST_FAILED, util_status_code__B_to_return_status_C(sCode),
616
0
                                              (uintptr_t) encType, auxParam);
617
0
            SOPC_ASSERT(SOPC_STATUS_OK == status);
618
619
0
            SOPC_Logger_TraceWarning(SOPC_LOG_MODULE_CLIENTSERVER,
620
0
                                     "ServicesMgr: APP_TO_SE_SEND_SESSION_REQUEST failed session=%" PRIu32
621
0
                                     " msgType=%s ctx=%" PRIuPTR,
622
0
                                     id, SOPC_EncodeableType_GetName(encType), auxParam);
623
0
        }
624
0
        break;
625
0
    case APP_TO_SE_CLOSE_SESSION:
626
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER, "ServicesMgr: APP_TO_SE_CLOSE_SESSION  session=%" PRIu32,
627
0
                               id);
628
629
        // id == session id
630
0
        SOPC_ASSERT(id <= constants__t_session_i_max);
631
632
0
        io_dispatch_mgr__client_send_close_session_request(id, &sCode);
633
0
        if (sCode != constants_statuscodes_bs__e_sc_ok)
634
0
        {
635
0
            SOPC_Logger_TraceError(SOPC_LOG_MODULE_CLIENTSERVER,
636
0
                                   "ServicesMgr: APP_TO_SE_CLOSE_SESSION failed session=%" PRIu32, id);
637
0
        }
638
0
        break;
639
0
    case APP_TO_SE_CLOSE_CONNECTION:
640
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER,
641
0
                               "ServicesMgr: APP_TO_SE_CLOSE_CONNECTION  scCfgIdx=%" PRIu32, id);
642
        // id = secure channel config index
643
0
        io_dispatch_mgr__client_close_channel(id, auxParam, &bres);
644
0
        if (!bres)
645
0
        {
646
0
            SOPC_App_EnqueueComEvent(SE_CLOSED_CHANNEL, id, (uintptr_t) false, auxParam);
647
0
        }
648
0
        break;
649
0
    case APP_TO_SE_SEND_DISCOVERY_REQUEST:
650
        // id = secure channel config index,
651
        // params = reverse endpoint connection index or 0 if not a reverse connection
652
        // auxParam = (SOPC_Internal_DiscoveryContext*)
653
0
        SOPC_ASSERT(id <= constants_bs__t_channel_config_idx_i_max);
654
0
        SOPC_ASSERT((void*) auxParam != NULL);
655
656
0
        discoveryContext = (SOPC_Internal_DiscoveryContext*) auxParam;
657
658
0
        if (discoveryContext->opcuaMessage != NULL)
659
0
        {
660
0
            encType = *(SOPC_EncodeableType**) discoveryContext->opcuaMessage;
661
0
        }
662
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER,
663
0
                               "ServicesMgr: APP_TO_SE_SEND_DISCOVERY_REQUEST scCfgIdx=%" PRIu32
664
0
                               " reverseEpCfgIdx=%" PRIuPTR " msgType=%s ctx=%" PRIuPTR,
665
0
                               id, params, SOPC_EncodeableType_GetName(encType), discoveryContext->discoveryAppContext);
666
667
0
        io_dispatch_mgr__client_send_discovery_request(id, (uint32_t) params,
668
0
                                                       (constants__t_msg_i) discoveryContext->opcuaMessage,
669
0
                                                       discoveryContext->discoveryAppContext, &sCode);
670
0
        if (sCode != constants_statuscodes_bs__e_sc_ok)
671
0
        {
672
0
            status = SOPC_App_EnqueueComEvent(SE_SND_REQUEST_FAILED, util_status_code__B_to_return_status_C(sCode),
673
0
                                              (uintptr_t) encType, discoveryContext->discoveryAppContext);
674
0
            SOPC_ASSERT(SOPC_STATUS_OK == status);
675
676
0
            SOPC_Logger_TraceWarning(SOPC_LOG_MODULE_CLIENTSERVER,
677
0
                                     "ServicesMgr: APP_TO_SE_SEND_DISCOVERY_REQUEST failed scCfgIdx=%" PRIu32
678
0
                                     " reverseEpCfgIdx=%" PRIuPTR " msgType=%s ctx=%" PRIuPTR,
679
0
                                     id, params, SOPC_EncodeableType_GetName(encType), auxParam);
680
0
        }
681
0
        SOPC_Free(discoveryContext);
682
0
        break;
683
0
    case APP_TO_SE_CLOSE_ALL_CONNECTIONS:
684
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER,
685
0
                               "ServicesMgr: APP_TO_SE_CLOSE_ALL_CONNECTIONS clientOnly=%" PRIuPTR, params);
686
687
0
        io_dispatch_mgr__close_all_active_connections((bool) params, &bres);
688
0
        if (!bres)
689
0
        {
690
            // All connections already closed: simulate new service event
691
0
            onServiceEvent(handler, SE_TO_SE_SC_ALL_DISCONNECTED, id, params, auxParam);
692
0
        }
693
0
        break;
694
0
    case APP_TO_SE_REEVALUATE_SCS:
695
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER,
696
0
                               "ServicesMgr: APP_TO_SE_REEVALUATE_SCS isServer=%" PRIuPTR " isOwnCert=%" PRIuPTR,
697
0
                               params, auxParam);
698
0
        status = SOPC_SecureChannels_EnqueueEvent(SCS_REEVALUATE_SCS, id, params, auxParam);
699
0
        SOPC_ASSERT(SOPC_STATUS_OK == status);
700
0
        break;
701
0
    case APP_TO_SE_EVAL_USR_CRT_SESSIONS:
702
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER, "ServicesMgr: APP_TO_SE_EVAL_USR_CRT_SESSION");
703
0
        io_dispatch_mgr__internal_server_evaluate_all_session_user_cert();
704
0
        break;
705
0
    case APP_TO_SE_UNINITIALIZE_SERVICES:
706
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER, "ServicesMgr: APP_TO_SE_UNINITIALIZE_SERVICES");
707
0
        io_dispatch_mgr__UNINITIALISATION();
708
0
        break;
709
0
    default:
710
0
        SOPC_ASSERT(false);
711
0
    }
712
0
}
713
714
void SOPC_Services_EnqueueEvent(SOPC_Services_Event seEvent, uint32_t id, uintptr_t params, uintptr_t auxParam)
715
0
{
716
0
    SOPC_ASSERT(servicesEventHandler != NULL);
717
0
    SOPC_EventHandler_Post(servicesEventHandler, (int32_t) seEvent, id, params, auxParam);
718
0
}
719
720
uint32_t SOPC_Services_Get_QueueSize(void)
721
0
{
722
0
    return SOPC_EventHandler_Get_QueueSize(servicesEventHandler);
723
0
}
724
725
void SOPC_Services_Initialize(SOPC_SetListenerFunc* setSecureChannelsListener)
726
0
{
727
0
    SOPC_ReturnStatus status = SOPC_STATUS_NOK;
728
729
0
    servicesLooper = SOPC_Looper_Create("Services");
730
0
    SOPC_ASSERT(servicesLooper != NULL);
731
732
0
    servicesEventHandler = SOPC_EventHandler_Create(servicesLooper, onServiceEvent);
733
0
    SOPC_ASSERT(servicesEventHandler != NULL);
734
735
0
    secureChannelsEventHandler = SOPC_EventHandler_Create(servicesLooper, onSecureChannelEvent);
736
0
    SOPC_ASSERT(secureChannelsEventHandler != NULL);
737
738
    // Init async close management flag
739
0
    status = SOPC_Mutex_Initialization(&closeAllConnectionsSync.mutex);
740
0
    SOPC_ASSERT(status == SOPC_STATUS_OK);
741
742
0
    status = SOPC_Condition_Init(&closeAllConnectionsSync.cond);
743
0
    SOPC_ASSERT(status == SOPC_STATUS_OK);
744
745
0
    setSecureChannelsListener(secureChannelsEventHandler);
746
747
    /* Init B model */
748
0
    INITIALISATION();
749
0
}
750
751
void SOPC_Services_CloseAllSCs(bool clientOnly)
752
0
{
753
0
    SOPC_Mutex_Lock(&closeAllConnectionsSync.mutex);
754
0
    closeAllConnectionsSync.requestedFlag = true;
755
0
    closeAllConnectionsSync.clientOnlyFlag = clientOnly;
756
    // Do a synchronous connections closed (effective on client only)
757
0
    SOPC_EventHandler_Post(servicesEventHandler, APP_TO_SE_CLOSE_ALL_CONNECTIONS, 0, (uintptr_t) clientOnly, 0);
758
0
    while (!closeAllConnectionsSync.allDisconnectedFlag)
759
0
    {
760
0
        SOPC_Mutex_UnlockAndWaitCond(&closeAllConnectionsSync.cond, &closeAllConnectionsSync.mutex);
761
0
    }
762
0
    closeAllConnectionsSync.allDisconnectedFlag = false;
763
0
    closeAllConnectionsSync.clientOnlyFlag = false;
764
0
    closeAllConnectionsSync.requestedFlag = false;
765
0
    SOPC_Mutex_Unlock(&closeAllConnectionsSync.mutex);
766
0
}
767
768
void SOPC_Services_Clear(void)
769
0
{
770
0
    SOPC_EventHandler_Post(servicesEventHandler, APP_TO_SE_UNINITIALIZE_SERVICES, 0, 0, 0);
771
772
    // Set to NULL handlers deallocated by SOPC_Looper_Delete call
773
0
    servicesEventHandler = NULL;
774
0
    secureChannelsEventHandler = NULL;
775
0
    SOPC_Looper_Delete(servicesLooper);
776
0
    servicesLooper = NULL;
777
778
0
    closeAllConnectionsSync.allDisconnectedFlag = false;
779
0
    closeAllConnectionsSync.clientOnlyFlag = false;
780
    closeAllConnectionsSync.requestedFlag = false;
781
0
    SOPC_Mutex_Clear(&closeAllConnectionsSync.mutex);
782
0
    SOPC_Condition_Clear(&closeAllConnectionsSync.cond);
783
0
}