Coverage Report

Created: 2026-10-17 06:10

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_atomic.h"
27
#include "sopc_date_time.h"
28
#include "sopc_enums.h"
29
#include "sopc_helper_string.h"
30
#include "sopc_internal_app_dispatcher.h"
31
#include "sopc_logger.h"
32
#include "sopc_macros.h"
33
#include "sopc_mem_alloc.h"
34
#include "sopc_mutexes.h"
35
#include "sopc_secure_channels_api.h"
36
#include "sopc_services_api.h"
37
#include "sopc_services_api_internal.h"
38
#include "sopc_toolkit_config_internal.h"
39
#include "sopc_user_app_itf.h"
40
41
#include "io_dispatch_mgr.h"
42
#include "toolkit_header_init.h"
43
#include "util_b2c.h"
44
45
/**
46
 * \brief Indicates whether the server configuration is locked (configured) or not.
47
 *        When unlocked, ignore the server related events until it is locked again.
48
 */
49
static bool isServerConfigurationLocked = false;
50
51
static SOPC_Looper* servicesLooper = NULL;
52
static SOPC_EventHandler* secureChannelsEventHandler = NULL;
53
static SOPC_EventHandler* servicesEventHandler = NULL;
54
55
/* Hook called after each event treatment (SOPC_Services_EventTreatedHook*): set from any thread, read from the services
56
 * thread */
57
static void* eventTreatedHook = NULL;
58
59
// Structure used to close all connections in a synchronous way
60
// (necessary on toolkit clear)
61
static struct
62
{
63
    SOPC_Mutex mutex;
64
    SOPC_Condition cond;
65
    bool allDisconnectedFlag;
66
    bool requestedFlag;
67
    bool clientOnlyFlag;
68
} closeAllConnectionsSync = {.allDisconnectedFlag = false, .requestedFlag = false, .clientOnlyFlag = false};
69
70
SOPC_EventHandler* SOPC_Services_GetEventHandler(void)
71
0
{
72
0
    return servicesEventHandler;
73
0
}
74
75
static void SOPC_Internal_AllClientSecureChannelsDisconnected(bool clientOnly)
76
0
{
77
0
    SOPC_Mutex_Lock(&closeAllConnectionsSync.mutex);
78
0
    SOPC_ASSERT(closeAllConnectionsSync.clientOnlyFlag == clientOnly);
79
0
    if (closeAllConnectionsSync.requestedFlag)
80
0
    {
81
0
        closeAllConnectionsSync.allDisconnectedFlag = true;
82
0
        SOPC_Condition_SignalAll(&closeAllConnectionsSync.cond);
83
0
    }
84
0
    SOPC_Mutex_Unlock(&closeAllConnectionsSync.mutex);
85
0
}
86
87
static SOPC_STRONG_INLINE void call_event_treated_hook(void)
88
0
{
89
0
    SOPC_Services_EventTreatedHook* hook = (SOPC_Services_EventTreatedHook*) SOPC_Atomic_Ptr_Get(&eventTreatedHook);
90
0
    if (NULL != hook && NULL != hook->eventTreatedCb)
91
0
    {
92
0
        hook->eventTreatedCb();
93
0
    }
94
0
}
95
96
static void onSecureChannelEvent(SOPC_EventHandler* handler,
97
                                 int32_t event,
98
                                 uint32_t id,
99
                                 uintptr_t params,
100
                                 uintptr_t auxParam)
101
0
{
102
0
    SOPC_UNUSED_ARG(handler);
103
0
    SOPC_SecureChannels_OutputEvent scEvent = (SOPC_SecureChannels_OutputEvent) event;
104
0
    bool bres = false;
105
0
    uint32_t channel_config_idx = 0;
106
0
    SOPC_ReturnStatus status = SOPC_STATUS_NOK;
107
108
0
    switch (scEvent)
109
0
    {
110
0
    case EP_CONNECTED:
111
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER,
112
0
                               "ServicesMgr: SC_EP_SC_CONNECTED epCfgIdx=%" PRIu32 " scCfgIdx=%" PRIuPTR
113
0
                               " scIdx=%" PRIuPTR,
114
0
                               id, params, auxParam);
115
116
        // id ==  endpoint configuration index
117
        // params = channel configuration index
118
        // auxParam == connection Id
119
0
        SOPC_ASSERT(id <= INT32_MAX);
120
0
        channel_config_idx = (uint32_t) params;
121
0
        SOPC_ASSERT(channel_config_idx <= constants__t_channel_config_idx_i_max);
122
0
        SOPC_ASSERT(auxParam <= constants__t_channel_i_max);
123
124
0
        io_dispatch_mgr__server_channel_connected_event(id, channel_config_idx, (uint32_t) auxParam, &bres);
125
0
        if (bres == false)
126
0
        {
127
0
            SOPC_Logger_TraceError(SOPC_LOG_MODULE_CLIENTSERVER,
128
0
                                   "Services: channel state incoherent or maximum reached epCfgIdx=%" PRIu32
129
0
                                   " scIdx=%" PRIuPTR,
130
0
                                   id, auxParam);
131
132
0
            SOPC_SecureChannels_EnqueueEvent(SC_DISCONNECT, (uint32_t) auxParam,
133
0
                                             (uintptr_t) OpcUa_BadSecureChannelClosed, 0);
134
0
        }
135
136
0
        break;
137
0
    case EP_CLOSED:
138
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER,
139
0
                               "ServicesMgr: SC_EP_CLOSED epCfgIdx=%" PRIu32 " returnStatus=%" PRIuPTR, id, auxParam);
140
        // id == endpoint configuration index
141
        // params = NULL
142
        // auxParam == status
143
        // => B model entry point to add
144
0
        status = SOPC_App_EnqueueComEvent(SE_CLOSED_ENDPOINT, id, (uintptr_t) NULL, auxParam);
145
0
        SOPC_ASSERT(status == SOPC_STATUS_OK);
146
0
        break;
147
0
    case EP_REVERSE_CLOSED:
148
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER,
149
0
                               "ServicesMgr: EP_REVERSE_CLOSED reverseEpCfgIdx=%" PRIu32 " returnStatus=%" PRIuPTR, id,
150
0
                               auxParam);
151
        //  id = reverse endpoint config index,
152
        // auxParams = SOPC_ReturnStatus
153
0
        status = SOPC_App_EnqueueComEvent(SE_REVERSE_ENDPOINT_CLOSED, id, (uintptr_t) NULL, auxParam);
154
0
        SOPC_ASSERT(status == SOPC_STATUS_OK);
155
0
        break;
156
0
    case SC_CONNECTED:
157
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER,
158
0
                               "ServicesMgr: SC_SC_CONNECTED scIdx=%" PRIu32 " scCfgIdx=%" PRIuPTR, id, auxParam);
159
        // id == connection Id
160
        // auxParam == secure channel configuration index
161
        // => B model entry point to add
162
0
        SOPC_ASSERT(id <= constants__t_channel_i_max);
163
0
        SOPC_ASSERT(auxParam <= constants__t_channel_config_idx_i_max);
164
0
        io_dispatch_mgr__client_channel_connected_event((uint32_t) auxParam,
165
0
                                                        constants__c_reverse_endpoint_config_idx_indet, id);
166
0
        break;
167
0
    case SC_REVERSE_CONNECTED:
168
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER,
169
0
                               "ServicesMgr: SC_REVERSE_CONNECTED scIdx=%" PRIu32 " scCfgIdx=%" PRIuPTR, id, auxParam);
170
        // id = secure channel connection index,
171
        // params = (uint32_t) secure channel configuration index,
172
        // auxParams = (uint32) reverse endpoint configuration index
173
        // => B model entry point to add
174
0
        SOPC_ASSERT(id <= constants__t_channel_i_max);
175
0
        SOPC_ASSERT(auxParam <= constants__t_channel_config_idx_i_max);
176
0
        io_dispatch_mgr__client_channel_connected_event((uint32_t) params, (uint32_t) auxParam, id);
177
0
        break;
178
0
    case SC_CONNECTION_TIMEOUT:
179
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER, "ServicesMgr: SC_SC_CONNECTION_TIMEOUT scCfgIdx=%" PRIu32,
180
0
                               id);
181
182
        // id == secure channel configuration index
183
        // => B model entry point to add
184
0
        SOPC_ASSERT(id <= constants_bs__t_channel_config_idx_i_max);
185
0
        io_dispatch_mgr__client_secure_channel_timeout(id);
186
0
        break;
187
0
    case SC_DISCONNECTED:
188
0
        channel_config_idx = (uint32_t) params;
189
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER,
190
0
                               "ServicesMgr: SC_SC_DISCONNECTED scIdx=%" PRIu32 " scCfgIdx=%" PRIu32
191
0
                               " with status=x%08" PRIX32,
192
0
                               id, channel_config_idx, (uint32_t) auxParam);
193
        // id == connection Id
194
        // params == secure channel configuration index (server only)
195
        // auxParam = status
196
0
        io_dispatch_mgr__secure_channel_lost(id);
197
        // Acknowledge the disconnected state is set in service layer to free the connection index
198
0
        SOPC_SecureChannels_EnqueueEvent(SC_DISCONNECTED_ACK, id, params, 0);
199
0
        break;
200
0
    case SC_SERVICE_RCV_MSG:
201
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER,
202
0
                               "ServicesMgr: SC_SC_SERVICE_RCV_MSG scIdx=%" PRIu32 " reqId/0=%" PRIuPTR, id, auxParam);
203
204
        // id ==  connection Id
205
        // params = message content (byte buffer)
206
        // auxParam == requestId (server) / 0 (client)
207
0
        SOPC_ASSERT(NULL != (void*) params);
208
0
        io_dispatch_mgr__receive_msg_buffer(id, (constants__t_byte_buffer_i) params,
209
0
                                            (constants__t_request_context_i) auxParam, &bres);
210
0
        if (!bres)
211
0
        {
212
0
            SOPC_Logger_TraceError(SOPC_LOG_MODULE_CLIENTSERVER,
213
0
                                   "ServicesMgr: SC_SC_SERVICE_RCV_MSG scIdx=%" PRIu32 " reqId/0=%" PRIuPTR
214
0
                                   " received message considered invalid",
215
0
                                   id, auxParam);
216
0
        }
217
        // params is freed by services manager
218
0
        break;
219
0
    case SC_SND_FAILURE:
220
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER,
221
0
                               "ServicesMgr: SC_SND_FAILURE scIdx=%" PRIu32 " reqId/Handle=%" PRIuPTR
222
0
                               " statusCode=%" PRIXPTR,
223
0
                               id, (uintptr_t) params, auxParam);
224
225
0
        constants_statuscodes_bs__t_StatusCode_i statusCode;
226
0
        util_status_code__C_to_B((SOPC_StatusCode) auxParam, &statusCode);
227
0
        io_dispatch_mgr__snd_msg_failure(id, (constants__t_request_context_i) params, statusCode);
228
0
        break;
229
0
    case SC_REQUEST_TIMEOUT:
230
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER,
231
0
                               "ServicesMgr: SC_REQUEST_TIMEOUT scIdx=%" PRIu32 " reqHandle=%" PRIuPTR, id, auxParam);
232
233
        /* id = secure channel connection index,
234
           auxParam = request handle */
235
0
        SOPC_ASSERT(id <= constants__t_channel_i_max);
236
0
        SOPC_ASSERT(auxParam <= SOPC_MAX_PENDING_REQUESTS);
237
0
        io_dispatch_mgr__client_request_timeout(id, (uint32_t) auxParam);
238
0
        break;
239
0
    default:
240
0
        SOPC_ASSERT(false && "Unknown event");
241
0
    }
242
243
0
    call_event_treated_hook();
244
0
}
245
246
static void SOPC_Array_Free_WriteDataChanged(void* data)
247
0
{
248
0
    SOPC_WriteDataChanged* writeDataChanged = (SOPC_WriteDataChanged*) data;
249
0
    OpcUa_WriteValue_Clear(writeDataChanged->oldValue);
250
0
    SOPC_Free(writeDataChanged->oldValue);
251
0
    OpcUa_WriteValue_Clear(writeDataChanged->newValue);
252
0
    SOPC_Free(writeDataChanged->newValue);
253
0
}
254
255
static void SOPC_Array_Free_NodeChanged(void* data)
256
0
{
257
0
    SOPC_NodeChanged* nodeChanged = (SOPC_NodeChanged*) data;
258
0
    SOPC_NodeId_Clear(nodeChanged->nodeId);
259
0
    SOPC_Free(nodeChanged->nodeId);
260
0
}
261
262
static bool filterServerEvents(SOPC_Services_Event event, uint32_t id, uintptr_t params, uintptr_t auxParam)
263
0
{
264
0
    SOPC_UNUSED_ARG(id);
265
0
    SOPC_UNUSED_ARG(auxParam);
266
0
    SOPC_ReturnStatus status = SOPC_STATUS_OK;
267
0
    bool bParam = false;
268
0
    bool treatEvent = false;
269
0
    switch (event)
270
0
    {
271
0
    case APP_TO_SE_SERVER_CONFIGURED:
272
0
        bParam = (bool) params;
273
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER,
274
0
                               "ServicesMgr: APP_TO_SE_SERVER_CONFIGURED active=%" PRIuPTR, params);
275
0
        if (isServerConfigurationLocked == bParam)
276
0
        {
277
0
            SOPC_Logger_TraceWarning(
278
0
                SOPC_LOG_MODULE_CLIENTSERVER,
279
0
                "ServicesMgr: APP_TO_SE_SERVER_CONFIGURED IGNORED: received with same lock state=%s",
280
0
                bParam ? "locked" : "unlocked");
281
0
        }
282
0
        else
283
0
        {
284
0
            status = SOPC_ToolkitServer_UsingLockedConfig(bParam);
285
0
            if (SOPC_STATUS_OK == status)
286
0
            {
287
0
                isServerConfigurationLocked = bParam;
288
                // Forward to SC layer
289
0
                status = SOPC_SecureChannels_EnqueueEvent(SE_TO_SCS_SERVER_CONFIGURED, 0, (uintptr_t) params, 0);
290
0
                SOPC_ASSERT(SOPC_STATUS_OK == status);
291
0
            }
292
0
            else
293
0
            {
294
0
                SOPC_Logger_TraceError(SOPC_LOG_MODULE_CLIENTSERVER,
295
0
                                       "ServicesMgr: APP_TO_SE_SERVER_CONFIGURED FAILED: error in setting "
296
0
                                       "server config as used: %s",
297
0
                                       bParam ? "locked" : "unlocked");
298
0
            }
299
0
            if (!isServerConfigurationLocked)
300
0
            {
301
                // Clear server context in B model if configuration is unlocked (not configured anymore)
302
0
                io_dispatch_mgr__clear_server_configuration_context();
303
0
            }
304
0
        }
305
0
        break;
306
0
    case SE_TO_SE_SERVER_DATA_CHANGED:
307
0
    case SE_TO_SE_SERVER_NODE_CHANGED:
308
0
    case SE_TO_SE_SERVER_SEND_ASYNC_PUB_RESP_PRIO:
309
0
        if (!isServerConfigurationLocked)
310
0
        {
311
0
            SOPC_Logger_TraceError(SOPC_LOG_MODULE_CLIENTSERVER,
312
0
                                   "filterServerEvents: %s IGNORED: server configuration is not locked (configured)",
313
0
                                   SE_TO_SE_SERVER_DATA_CHANGED == event ? "SE_TO_SE_SERVER_DATA_CHANGED"
314
0
                                   : SE_TO_SE_SERVER_NODE_CHANGED == event
315
0
                                       ? "SE_TO_SE_SERVER_NODE_CHANGED"
316
0
                                       : "SE_TO_SE_SERVER_SEND_ASYNC_PUB_RESP_PRIO");
317
0
        }
318
0
        else
319
0
        {
320
0
            treatEvent = true;
321
0
        }
322
0
        break;
323
    /* Note: since sessions are now closed by SOPC_HelperInternal_ActualShutdownServer on Stop
324
             and clear_server_configuration_context on clear, all
325
             sessions / subscriptions  should be terminated when configuration has been cleared.
326
             But avoid inhibiting timeout and closing operations of sessions/subscriptions
327
             as those do not use the configuration at all.
328
    case SE_TO_SE_SERVER_INACTIVATED_SESSION_PRIO:
329
    case SE_TO_SE_SERVER_ASYNC_CLOSE_SUBSCRIPTION:
330
    case TIMER_SE_EVAL_SESSION_TIMEOUT:
331
    case TIMER_SE_PUBLISH_CYCLE_TIMEOUT:
332
    */
333
0
    case APP_TO_SE_OPEN_ENDPOINT:
334
0
    case APP_TO_SE_CLOSE_ENDPOINT:
335
0
    case APP_TO_SE_LOCAL_SERVICE_REQUEST:
336
0
    case APP_TO_SE_TRIGGER_EVENT:
337
0
    case APP_TO_SE_EVAL_USR_CRT_SESSIONS:
338
0
        if (!isServerConfigurationLocked)
339
0
        {
340
0
            SOPC_Logger_TraceError(SOPC_LOG_MODULE_CLIENTSERVER,
341
0
                                   "filterServerEvents: %s IGNORED: server configuration is not locked (configured)",
342
0
                                   APP_TO_SE_OPEN_ENDPOINT == event           ? "APP_TO_SE_OPEN_ENDPOINT"
343
0
                                   : APP_TO_SE_CLOSE_ENDPOINT == event        ? "APP_TO_SE_CLOSE_ENDPOINT"
344
0
                                   : APP_TO_SE_LOCAL_SERVICE_REQUEST == event ? "APP_TO_SE_LOCAL_SERVICE_REQUEST"
345
0
                                   : APP_TO_SE_TRIGGER_EVENT == event         ? "APP_TO_SE_TRIGGER_EVENT"
346
0
                                                                              : "APP_TO_SE_EVAL_USR_CRT_SESSIONS");
347
0
        }
348
0
        else
349
0
        {
350
0
            treatEvent = true;
351
0
        }
352
0
        break;
353
0
    default:
354
0
        treatEvent = true;
355
0
        break;
356
0
    }
357
0
    SOPC_Internal_EventContext* eventContext = NULL;
358
0
    SOPC_Internal_AsyncSendMsgData* msg_data = NULL;
359
0
    if (!treatEvent)
360
0
    {
361
        // Clear provided data
362
0
        switch (event)
363
0
        {
364
0
        case SE_TO_SE_SERVER_DATA_CHANGED:
365
0
            SOPC_Array_Set_Free_Func((SOPC_Array*) params, &SOPC_Array_Free_WriteDataChanged);
366
0
            SOPC_Array_Delete((SOPC_Array*) params);
367
0
            break;
368
0
        case SE_TO_SE_SERVER_NODE_CHANGED:
369
0
            SOPC_Array_Set_Free_Func((SOPC_Array*) params, &SOPC_Array_Free_NodeChanged);
370
0
            SOPC_Array_Delete((SOPC_Array*) params);
371
0
            break;
372
0
        case SE_TO_SE_SERVER_SEND_ASYNC_PUB_RESP_PRIO:
373
0
            msg_data = (SOPC_Internal_AsyncSendMsgData*) params;
374
0
            SOPC_EncodeableObject_Delete(*(SOPC_EncodeableType**) msg_data->msgToSend, (void**) &msg_data->msgToSend);
375
0
            SOPC_Free(msg_data);
376
0
            break;
377
0
        case APP_TO_SE_EVAL_USR_CRT_SESSIONS:
378
0
            break; // Nothing to clear
379
0
        case APP_TO_SE_OPEN_ENDPOINT:
380
0
        case APP_TO_SE_CLOSE_ENDPOINT:
381
0
            break; // Nothing to clear
382
0
        case APP_TO_SE_LOCAL_SERVICE_REQUEST:
383
0
            SOPC_EncodeableObject_Delete(*(SOPC_EncodeableType**) params, (void**) &params);
384
            // Note: the response context is not returned to application,
385
            // this is managed in server wrapper by using the waiting request context list
386
0
            break;
387
0
        case APP_TO_SE_TRIGGER_EVENT:
388
            // params =  (SOPC_Internal_EventContext*)
389
0
            eventContext = (SOPC_Internal_EventContext*) params;
390
0
            SOPC_ASSERT(NULL != eventContext);
391
0
            SOPC_NodeId_Clear(&eventContext->notifierNodeId);
392
0
            SOPC_Event_Delete(&eventContext->event);
393
0
            SOPC_Free(eventContext);
394
0
            break;
395
0
        default:
396
0
            break;
397
0
        }
398
0
    }
399
0
    return treatEvent;
400
0
}
401
402
static void onServiceEvent(SOPC_EventHandler* handler,
403
                           int32_t scEvent,
404
                           uint32_t id,
405
                           uintptr_t params,
406
                           uintptr_t auxParam)
407
0
{
408
0
    SOPC_Services_Event event = (SOPC_Services_Event) scEvent;
409
0
    SOPC_ReturnStatus status = SOPC_STATUS_OK;
410
0
    SOPC_Endpoint_Config* epConfig = NULL;
411
0
    constants_statuscodes_bs__t_StatusCode_i sCode = constants_statuscodes_bs__e_sc_ok;
412
0
    SOPC_EncodeableType* encType = NULL;
413
0
    bool lbres = false;
414
0
    bool bres = false;
415
0
    void* msg = NULL;
416
0
    size_t length = 0;
417
0
    SOPC_Array* dataOrNodeChangedArray = NULL;
418
0
    SOPC_WriteDataChanged* writeDataChanged = NULL;
419
0
    SOPC_NodeChanged* nodeChanged = NULL;
420
0
    OpcUa_WriteValue* old_value = NULL;
421
0
    OpcUa_WriteValue* new_value = NULL;
422
0
    SOPC_Internal_AsyncSendMsgData* msg_data;
423
0
    const SOPC_NodeId* nodeId2 = NULL;
424
0
    char* nodeIdStr = NULL;
425
0
    char* nodeIdStr2 = NULL;
426
0
    const char* reverseEndpointURL = NULL;
427
0
    SOPC_Internal_SessionAppContext* sessionContext = NULL;
428
0
    SOPC_ExtensionObject* userToken = NULL;
429
0
    SOPC_Internal_DiscoveryContext* discoveryContext = NULL;
430
0
    SOPC_Internal_EventContext* eventContext = NULL;
431
0
    SOPC_DateTime currentTime = 0;
432
433
0
    bool treatEvent = filterServerEvents(event, id, params, auxParam);
434
0
    if (!treatEvent)
435
0
    {
436
0
        return;
437
0
    }
438
439
0
    switch (event)
440
0
    {
441
0
    case SE_TO_SE_SC_ALL_DISCONNECTED:
442
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER,
443
0
                               "ServicesMgr: SE_TO_SE_SC_ALL_DISCONNECTED clientOnly=%" PRIuPTR, params);
444
        // Call directly toolkit configuration callback
445
0
        SOPC_Internal_AllClientSecureChannelsDisconnected((bool) params);
446
0
        break;
447
448
0
    case SE_TO_SE_ACTIVATE_ORPHANED_SESSION:
449
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER,
450
0
                               "ServicesMgr: SE_TO_SE_ACTIVATE_ORPHANED_SESSION session=%" PRIu32 " scCfgIdx=%" PRIuPTR,
451
0
                               id, auxParam);
452
453
0
        SOPC_ASSERT(auxParam <= constants__t_channel_config_idx_i_max);
454
0
        io_dispatch_mgr__internal_client_activate_orphaned_session(id, (constants__t_channel_config_idx_i) auxParam);
455
0
        break;
456
0
    case SE_TO_SE_CREATE_SESSION:
457
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER,
458
0
                               "ServicesMgr: SE_TO_SE_CREATE_SESSION session=%" PRIu32 " scCfgIdx=%" PRIuPTR, id,
459
0
                               auxParam);
460
0
        SOPC_ASSERT(auxParam <= constants__t_channel_config_idx_i_max);
461
0
        io_dispatch_mgr__internal_client_create_session((constants__t_session_i) id,
462
0
                                                        (constants__t_channel_config_idx_i) auxParam);
463
0
        break;
464
0
    case SE_TO_SE_ACTIVATE_SESSION:
465
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER, "ServicesMgr: SE_TO_SE_ACTIVATE_SESSION session=%" PRIu32,
466
0
                               id);
467
468
0
        if (NULL != (void*) params)
469
0
        {
470
0
            io_dispatch_mgr__client_reactivate_session_new_user(id, (constants__t_user_token_i) params);
471
0
        }
472
0
        else
473
0
        {
474
0
            SOPC_Logger_TraceError(SOPC_LOG_MODULE_CLIENTSERVER,
475
0
                                   "ServicesMgr: SE_TO_SE_ACTIVATE_SESSION session=%" PRIu32 " user parameter is NULL",
476
0
                                   id);
477
0
            sCode = constants_statuscodes_bs__e_sc_bad_generic_mask;
478
0
        }
479
0
        break;
480
0
    case SE_TO_SE_SERVER_DATA_CHANGED:
481
        /* Server side only:
482
           params = (SOPC_Array*) array of SOPC_WriteDataChanged
483
         */
484
0
        SOPC_ASSERT((void*) params != NULL);
485
486
0
        dataOrNodeChangedArray = (SOPC_Array*) params;
487
0
        bres = true;
488
0
        length = SOPC_Array_Size(dataOrNodeChangedArray);
489
0
        for (size_t i = 0; i < length; i++)
490
0
        {
491
0
            writeDataChanged = (SOPC_WriteDataChanged*) SOPC_Array_Get_Ptr(dataOrNodeChangedArray, i);
492
0
            SOPC_ASSERT(writeDataChanged != NULL);
493
0
            old_value = writeDataChanged->oldValue;
494
0
            new_value = writeDataChanged->newValue;
495
            /* Note: write values deallocation managed by B model */
496
0
            io_dispatch_mgr__internal_server_data_changed(old_value, new_value, &lbres);
497
0
            bres = bres && lbres;
498
0
        }
499
0
        SOPC_Array_Delete(dataOrNodeChangedArray);
500
0
        if (bres == false)
501
0
        {
502
0
            SOPC_Logger_TraceError(SOPC_LOG_MODULE_CLIENTSERVER,
503
0
                                   "ServicesMgr: SE_TO_SE_SERVER_DATA_CHANGED session=%" PRIu32 " treatment failed",
504
0
                                   id);
505
0
        }
506
0
        break;
507
0
    case SE_TO_SE_SERVER_NODE_CHANGED:
508
        /* Server side only:
509
           params = (SOPC_Array*) array of SOPC_NodeChanged
510
         */
511
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER,
512
0
                               "ServicesMgr: SE_TO_SE_SERVER_NODE_CHANGED batched notifications");
513
514
0
        SOPC_ASSERT(NULL != (void*) params);
515
0
        dataOrNodeChangedArray = (SOPC_Array*) params;
516
0
        length = SOPC_Array_Size(dataOrNodeChangedArray);
517
0
        lbres = SOPC_LOG_LEVEL_DEBUG == SOPC_Logger_GetTraceLogLevel();
518
0
        for (size_t i = 0; i < length; i++)
519
0
        {
520
0
            nodeChanged = (SOPC_NodeChanged*) SOPC_Array_Get_Ptr(dataOrNodeChangedArray, i);
521
0
            SOPC_ASSERT(NULL != nodeChanged);
522
0
            if (lbres)
523
0
            {
524
0
                nodeIdStr = SOPC_NodeId_ToCString(nodeChanged->nodeId);
525
0
                SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER,
526
0
                                       "ServicesMgr: SE_TO_SE_SERVER_NODE_CHANGED %s nodeId: %s",
527
0
                                       nodeChanged->added ? "added" : "deleted", nodeIdStr);
528
0
                SOPC_Free(nodeIdStr);
529
0
            }
530
0
            io_dispatch_mgr__internal_server_node_changed(nodeChanged->added, nodeChanged->nodeId);
531
0
            SOPC_NodeId_Clear(nodeChanged->nodeId);
532
0
            SOPC_Free(nodeChanged->nodeId);
533
0
        }
534
0
        SOPC_Array_Delete(dataOrNodeChangedArray);
535
0
        break;
536
0
    case SE_TO_SE_SERVER_INACTIVATED_SESSION_PRIO:
537
        /* Server side only:
538
           id = session id
539
           auxParam = (int32_t) session state
540
         */
541
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER,
542
0
                               "ServicesMgr: SE_TO_SE_SERVER_INACTIVATED_SESSION_PRIO session=%" PRIu32
543
0
                               " sessionState=%" PRIuPTR,
544
0
                               id, auxParam);
545
546
0
        io_dispatch_mgr__internal_server_inactive_session_prio_event((constants__t_session_i) id,
547
0
                                                                     (constants__t_sessionState_i) auxParam, &bres);
548
549
0
        if (bres == false)
550
0
        {
551
0
            SOPC_Logger_TraceError(
552
0
                SOPC_LOG_MODULE_CLIENTSERVER,
553
0
                "ServicesMgr: SE_TO_SE_SERVER_INACTIVATED_SESSION_PRIO session=%" PRIu32 " treatment failed", id);
554
0
        }
555
0
        break;
556
0
    case SE_TO_SE_SERVER_SEND_ASYNC_PUB_RESP_PRIO:
557
        /* Server side only:
558
           id = session id
559
           params = (SOPC_Internal_AsyncSendMsgData*)
560
         */
561
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER,
562
0
                               "ServicesMgr: SE_TO_SE_SERVER_SEND_ASYNC_PUB_RESP_PRIO session=%" PRIu32, id);
563
564
0
        msg_data = (void*) params;
565
0
        SOPC_ASSERT(msg_data != NULL);
566
567
0
        io_dispatch_mgr__internal_server_send_publish_response_prio_event(
568
0
            (constants__t_session_i) id, msg_data->requestHandle, msg_data->requestId, msg_data->msgToSend,
569
0
            (constants_statuscodes_bs__t_StatusCode_i) msg_data->bStatusCode, &bres);
570
0
        SOPC_Free(msg_data);
571
572
0
        if (!bres)
573
0
        {
574
0
            SOPC_Logger_TraceError(
575
0
                SOPC_LOG_MODULE_CLIENTSERVER,
576
0
                "ServicesMgr: SE_TO_SE_SERVER_SEND_ASYNC_PUB_RESP_PRIO session=%" PRIu32 " treatment failed", id);
577
0
        }
578
0
        break;
579
0
    case SE_TO_SE_SERVER_ASYNC_CLOSE_SUBSCRIPTION:
580
        /* Server side only:
581
           id = subscription id
582
         */
583
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER,
584
0
                               "ServicesMgr: SE_TO_SE_SERVER_ASYNC_CLOSE_SUBSCRIPTION subscription=%" PRIu32, id);
585
586
0
        io_dispatch_mgr__internal_server_close_subscription((constants__t_subscription_i) id, &bres);
587
588
0
        if (!bres)
589
0
        {
590
0
            SOPC_Logger_TraceError(
591
0
                SOPC_LOG_MODULE_CLIENTSERVER,
592
0
                "ServicesMgr: SE_TO_SE_SERVER_ASYNC_CLOSE_SUBSCRIPTION subscription=%" PRIu32 " treatment failed", id);
593
0
        }
594
0
        break;
595
0
    case TIMER_SE_EVAL_SESSION_TIMEOUT:
596
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER,
597
0
                               "ServicesMgr: TIMER_SE_EVAL_SESSION_TIMEOUT session=%" PRIu32, id);
598
0
        io_dispatch_mgr__internal_server_evaluate_session_timeout((constants__t_session_i) id);
599
0
        break;
600
0
    case TIMER_SE_PUBLISH_CYCLE_TIMEOUT:
601
        /* Server side only: id = subscription id */
602
0
        io_dispatch_mgr__internal_server_subscription_publish_timeout((constants__t_subscription_i) id, &bres);
603
0
        if (bres == false)
604
0
        {
605
0
            SOPC_Logger_TraceError(
606
0
                SOPC_LOG_MODULE_CLIENTSERVER,
607
0
                "ServicesMgr: TIMER_SE_PUBLISH_CYCLE_TIMEOUT subscription=%" PRIu32 " treatment failed", id);
608
0
        }
609
0
        break;
610
611
    /* App to Services events */
612
0
    case APP_TO_SE_SERVER_CONFIGURED:
613
        /* Already managed in filterServerEvents */
614
0
        break;
615
0
    case APP_TO_SE_OPEN_ENDPOINT:
616
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER, "ServicesMgr: APP_TO_SE_OPEN_ENDPOINT epCfgIdx=%" PRIu32,
617
0
                               id);
618
619
        // id ==  endpoint configuration index
620
        // => B model entry point to add
621
0
        epConfig = SOPC_ToolkitServer_GetEndpointConfig(id);
622
0
        if (NULL == epConfig)
623
0
        {
624
0
            status = SOPC_App_EnqueueComEvent(SE_CLOSED_ENDPOINT, id, (uintptr_t) NULL, SOPC_STATUS_INVALID_PARAMETERS);
625
0
            SOPC_ASSERT(SOPC_STATUS_OK == status);
626
0
        }
627
0
        else
628
0
        {
629
0
            status = SOPC_SecureChannels_EnqueueEvent(EP_OPEN,
630
0
                                                      id, // Server endpoint config idx
631
0
                                                      (uintptr_t) NULL, 0);
632
0
            SOPC_ASSERT(SOPC_STATUS_OK == status);
633
0
        }
634
0
        break;
635
0
    case APP_TO_SE_CLOSE_ENDPOINT:
636
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER, "ServicesMgr: APP_TO_SE_CLOSE_ENDPOINT epCfgIdx=%" PRIu32,
637
0
                               id);
638
639
        // id ==  endpoint configuration index
640
        // => B model entry point to add
641
0
        epConfig = SOPC_ToolkitServer_GetEndpointConfig(id);
642
0
        if (NULL == epConfig)
643
0
        {
644
0
            status = SOPC_App_EnqueueComEvent(SE_CLOSED_ENDPOINT, id, (uintptr_t) NULL, SOPC_STATUS_INVALID_PARAMETERS);
645
0
            SOPC_ASSERT(SOPC_STATUS_OK == status);
646
0
        }
647
0
        else
648
0
        {
649
0
            status = SOPC_SecureChannels_EnqueueEvent(EP_CLOSE, id, (uintptr_t) NULL, 0);
650
0
            SOPC_ASSERT(SOPC_STATUS_OK == status);
651
0
        }
652
0
        break;
653
654
0
    case APP_TO_SE_LOCAL_SERVICE_REQUEST:
655
0
        if ((void*) params != NULL)
656
0
        {
657
0
            encType = *(SOPC_EncodeableType**) params;
658
0
        }
659
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER,
660
0
                               "ServicesMgr: APP_TO_SE_LOCAL_SERVICE_REQUEST epCfgIdx=%" PRIu32
661
0
                               " msgType=%s ctx=%" PRIuPTR,
662
0
                               id, SOPC_EncodeableType_GetName(encType), auxParam);
663
664
        // id =  endpoint configuration index
665
        // params = local service request
666
        // auxParam = user application session context
667
0
        SOPC_ASSERT(id <= INT32_MAX);
668
669
0
        io_dispatch_mgr__server_treat_local_service_request(id, (constants__t_msg_i) params, auxParam, &sCode);
670
0
        if (constants_statuscodes_bs__e_sc_ok != sCode)
671
0
        {
672
            // Error case
673
0
            status = SOPC_EncodeableObject_Create(&OpcUa_ServiceFault_EncodeableType, &msg);
674
0
            if (SOPC_STATUS_OK == status && NULL != msg)
675
0
            {
676
0
                util_status_code__B_to_C(sCode, &((OpcUa_ServiceFault*) msg)->ResponseHeader.ServiceResult);
677
0
            }
678
0
            else
679
0
            {
680
0
                msg = NULL;
681
0
            }
682
0
            status = SOPC_App_EnqueueComEvent(SE_LOCAL_SERVICE_RESPONSE, id, (uintptr_t) msg, auxParam);
683
0
            SOPC_ASSERT(SOPC_STATUS_OK == status);
684
0
            SOPC_Logger_TraceWarning(SOPC_LOG_MODULE_CLIENTSERVER,
685
0
                                     "ServicesMgr: APP_TO_SE_LOCAL_SERVICE_REQUEST failed epCfgIdx=%" PRIu32
686
0
                                     " msgType=%s ctx=%" PRIuPTR,
687
0
                                     id, SOPC_EncodeableType_GetName(encType), auxParam);
688
0
        }
689
0
        break;
690
0
    case APP_TO_SE_TRIGGER_EVENT:
691
        // params =  (SOPC_Internal_EventContext*)
692
0
        eventContext = (SOPC_Internal_EventContext*) params;
693
0
        SOPC_ASSERT(NULL != eventContext);
694
0
        nodeIdStr = SOPC_NodeId_ToCString(&eventContext->notifierNodeId);
695
0
        nodeId2 = SOPC_Event_GetEventTypeId(eventContext->event);
696
0
        nodeIdStr2 = (NULL == nodeId2 ? SOPC_strdup("") : SOPC_NodeId_ToCString(nodeId2));
697
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER,
698
0
                               "ServicesMgr: APP_TO_SE_TRIGGER_EVENT eventTypeId=%s, notifierId=%s", nodeIdStr2,
699
0
                               nodeIdStr);
700
701
        // Update the receiveTime variable (and time variable if not set)
702
0
        currentTime = SOPC_Time_GetCurrentTimeUTC();
703
0
        status = SOPC_Event_SetReceiveTime(eventContext->event, currentTime);
704
0
        SOPC_ASSERT(SOPC_STATUS_OK == status);
705
0
        if (0 == SOPC_Event_GetTime(eventContext->event))
706
0
        {
707
0
            status = SOPC_Event_SetTime(eventContext->event, currentTime);
708
0
            SOPC_ASSERT(SOPC_STATUS_OK == status);
709
0
        }
710
711
0
        io_dispatch_mgr__internal_server_event_triggered(&eventContext->notifierNodeId, eventContext->event,
712
0
                                                         eventContext->optSessionId, eventContext->optSubscriptionId,
713
0
                                                         eventContext->optMonitoredItemId, &bres);
714
0
        if (!bres)
715
0
        {
716
0
            SOPC_Logger_TraceError(SOPC_LOG_MODULE_CLIENTSERVER,
717
0
                                   "ServicesMgr: failure in treatment of APP_TO_SE_TRIGGER_EVENT eventTypeId=%s, "
718
0
                                   "notifierId=%s",
719
0
                                   nodeIdStr2, nodeIdStr);
720
0
        }
721
0
        SOPC_Free(nodeIdStr);
722
0
        SOPC_Free(nodeIdStr2);
723
724
0
        SOPC_NodeId_Clear(&eventContext->notifierNodeId);
725
0
        SOPC_Event_Delete(&eventContext->event);
726
0
        SOPC_Free(eventContext);
727
0
        break;
728
0
    case APP_TO_SE_OPEN_REVERSE_ENDPOINT:
729
        /* id = reverse endpoint description config index */
730
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER,
731
0
                               "ServicesMgr: APP_TO_SE_OPEN_REVERSE_ENDPOINT reverseEpCfgIdx=%" PRIu32, id);
732
        // Check config index is valid
733
0
        reverseEndpointURL = SOPC_ToolkitClient_GetReverseEndpointURL(id);
734
0
        SOPC_ASSERT(NULL != reverseEndpointURL && "Invalid reverse endpoint configuration index provided");
735
0
        status = SOPC_SecureChannels_EnqueueEvent(REVERSE_EP_OPEN,
736
0
                                                  id, // Reverse endpoint config idx
737
0
                                                  (uintptr_t) NULL, 0);
738
0
        SOPC_ASSERT(SOPC_STATUS_OK == status);
739
0
        break;
740
0
    case APP_TO_SE_CLOSE_REVERSE_ENDPOINT:
741
        /* id = reverse endpoint description config index */
742
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER,
743
0
                               "ServicesMgr: APP_TO_SE_CLOSE_REVERSE_ENDPOINT reverseEpCfgIdx=%" PRIu32, id);
744
        // Check config index is valid
745
0
        reverseEndpointURL = SOPC_ToolkitClient_GetReverseEndpointURL(id);
746
0
        SOPC_ASSERT(NULL != reverseEndpointURL && "Invalid reverse endpoint configuration index provided");
747
0
        status = SOPC_SecureChannels_EnqueueEvent(REVERSE_EP_CLOSE, id, (uintptr_t) NULL, 0);
748
0
        SOPC_ASSERT(SOPC_STATUS_OK == status);
749
0
        break;
750
0
    case APP_TO_SE_ACTIVATE_SESSION:
751
        // id = secure channel config index,
752
        // params = reverse endpoint connection index or 0 if not a reverse connection
753
        // auxParam = (SOPC_Internal_SessionAppContext*)
754
0
        SOPC_ASSERT(id <= constants__t_channel_config_idx_i_max);
755
0
        SOPC_ASSERT((void*) auxParam != NULL);
756
0
        sessionContext = (SOPC_Internal_SessionAppContext*) auxParam;
757
0
        userToken = sessionContext->userToken;
758
0
        sessionContext->userToken = NULL; // Provided as separated parameter
759
760
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER,
761
0
                               "ServicesMgr: APP_TO_SE_ACTIVATE_SESSION scCfgIdx=%" PRIu32 " reverseEpCfgIdx=%" PRIuPTR
762
0
                               " ctx=%" PRIuPTR,
763
0
                               id, params, sessionContext->userSessionContext);
764
765
0
        io_dispatch_mgr__client_activate_new_session(id, (uint32_t) params, userToken, sessionContext, &bres);
766
767
0
        if (!bres)
768
0
        {
769
0
            SOPC_App_EnqueueComEvent(SE_SESSION_ACTIVATION_FAILURE,
770
0
                                     0,                                   // session id (not yet defined)
771
0
                                     (uintptr_t) NULL,                    // user ?
772
0
                                     sessionContext->userSessionContext); // user application session context
773
0
            SOPC_Logger_TraceWarning(SOPC_LOG_MODULE_CLIENTSERVER,
774
0
                                     "ServicesMgr: APP_TO_SE_ACTIVATE_SESSION failed scCfgIdx=%" PRIu32
775
0
                                     " reverseEpCfgIdx=%" PRIuPTR " ctx=%" PRIuPTR,
776
0
                                     id, params, auxParam);
777
0
            SOPC_ExtensionObject_Clear(userToken);
778
0
            SOPC_Free(userToken);
779
0
            SOPC_Free(sessionContext);
780
0
        }
781
0
        break;
782
0
    case APP_TO_SE_SEND_SESSION_REQUEST:
783
0
        if ((void*) params != NULL)
784
0
        {
785
0
            encType = *(SOPC_EncodeableType**) params;
786
0
        }
787
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER,
788
0
                               "ServicesMgr: APP_TO_SE_SEND_SESSION_REQUEST  session=%" PRIu32
789
0
                               " msgType=%s ctx=%" PRIuPTR,
790
0
                               id, SOPC_EncodeableType_GetName(encType), auxParam);
791
792
        // id == session id
793
        // params = request
794
0
        SOPC_ASSERT(id <= constants__t_session_i_max);
795
796
0
        io_dispatch_mgr__client_send_service_request(id, (constants__t_msg_i) params, auxParam, &sCode);
797
0
        if (sCode != constants_statuscodes_bs__e_sc_ok)
798
0
        {
799
0
            status = SOPC_App_EnqueueComEvent(SE_SND_REQUEST_FAILED, util_status_code__B_to_return_status_C(sCode),
800
0
                                              (uintptr_t) encType, auxParam);
801
0
            SOPC_ASSERT(SOPC_STATUS_OK == status);
802
803
0
            SOPC_Logger_TraceWarning(SOPC_LOG_MODULE_CLIENTSERVER,
804
0
                                     "ServicesMgr: APP_TO_SE_SEND_SESSION_REQUEST failed session=%" PRIu32
805
0
                                     " msgType=%s ctx=%" PRIuPTR,
806
0
                                     id, SOPC_EncodeableType_GetName(encType), auxParam);
807
0
        }
808
0
        break;
809
0
    case APP_TO_SE_CLOSE_SESSION:
810
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER, "ServicesMgr: APP_TO_SE_CLOSE_SESSION  session=%" PRIu32,
811
0
                               id);
812
813
        // id == session id
814
0
        SOPC_ASSERT(id <= constants__t_session_i_max);
815
816
0
        io_dispatch_mgr__client_send_close_session_request(id, &sCode);
817
0
        if (sCode != constants_statuscodes_bs__e_sc_ok)
818
0
        {
819
0
            SOPC_Logger_TraceError(SOPC_LOG_MODULE_CLIENTSERVER,
820
0
                                   "ServicesMgr: APP_TO_SE_CLOSE_SESSION failed session=%" PRIu32, id);
821
0
        }
822
0
        break;
823
0
    case APP_TO_SE_CLOSE_CONNECTION:
824
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER,
825
0
                               "ServicesMgr: APP_TO_SE_CLOSE_CONNECTION  scCfgIdx=%" PRIu32, id);
826
        // id = secure channel config index
827
0
        io_dispatch_mgr__client_close_channel(id, auxParam, &bres);
828
0
        if (!bres)
829
0
        {
830
0
            SOPC_App_EnqueueComEvent(SE_CLOSED_CHANNEL, id, (uintptr_t) false, auxParam);
831
0
        }
832
0
        break;
833
0
    case APP_TO_SE_SEND_DISCOVERY_REQUEST:
834
        // id = secure channel config index,
835
        // params = reverse endpoint connection index or 0 if not a reverse connection
836
        // auxParam = (SOPC_Internal_DiscoveryContext*)
837
0
        SOPC_ASSERT(id <= constants_bs__t_channel_config_idx_i_max);
838
0
        SOPC_ASSERT((void*) auxParam != NULL);
839
840
0
        discoveryContext = (SOPC_Internal_DiscoveryContext*) auxParam;
841
842
0
        if (discoveryContext->opcuaMessage != NULL)
843
0
        {
844
0
            encType = *(SOPC_EncodeableType**) discoveryContext->opcuaMessage;
845
0
        }
846
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER,
847
0
                               "ServicesMgr: APP_TO_SE_SEND_DISCOVERY_REQUEST scCfgIdx=%" PRIu32
848
0
                               " reverseEpCfgIdx=%" PRIuPTR " msgType=%s ctx=%" PRIuPTR,
849
0
                               id, params, SOPC_EncodeableType_GetName(encType), discoveryContext->discoveryAppContext);
850
851
0
        io_dispatch_mgr__client_send_discovery_request(id, (uint32_t) params,
852
0
                                                       (constants__t_msg_i) discoveryContext->opcuaMessage,
853
0
                                                       discoveryContext->discoveryAppContext, &sCode);
854
0
        if (sCode != constants_statuscodes_bs__e_sc_ok)
855
0
        {
856
0
            status = SOPC_App_EnqueueComEvent(SE_SND_REQUEST_FAILED, util_status_code__B_to_return_status_C(sCode),
857
0
                                              (uintptr_t) encType, discoveryContext->discoveryAppContext);
858
0
            SOPC_ASSERT(SOPC_STATUS_OK == status);
859
860
0
            SOPC_Logger_TraceWarning(SOPC_LOG_MODULE_CLIENTSERVER,
861
0
                                     "ServicesMgr: APP_TO_SE_SEND_DISCOVERY_REQUEST failed scCfgIdx=%" PRIu32
862
0
                                     " reverseEpCfgIdx=%" PRIuPTR " msgType=%s ctx=%" PRIuPTR,
863
0
                                     id, params, SOPC_EncodeableType_GetName(encType), auxParam);
864
0
        }
865
0
        SOPC_Free(discoveryContext);
866
0
        break;
867
0
    case APP_TO_SE_CLOSE_ALL_CONNECTIONS:
868
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER,
869
0
                               "ServicesMgr: APP_TO_SE_CLOSE_ALL_CONNECTIONS clientOnly=%" PRIuPTR, params);
870
871
0
        io_dispatch_mgr__close_all_active_connections((bool) params, &bres);
872
0
        if (!bres)
873
0
        {
874
            // All connections already closed: simulate new service event
875
0
            onServiceEvent(handler, SE_TO_SE_SC_ALL_DISCONNECTED, id, params, auxParam);
876
0
        }
877
0
        break;
878
0
    case APP_TO_SE_REEVALUATE_SCS:
879
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER,
880
0
                               "ServicesMgr: APP_TO_SE_REEVALUATE_SCS isServer=%" PRIuPTR " isOwnCert=%" PRIuPTR,
881
0
                               params, auxParam);
882
0
        status = SOPC_SecureChannels_EnqueueEvent(SCS_REEVALUATE_SCS, id, params, auxParam);
883
0
        SOPC_ASSERT(SOPC_STATUS_OK == status);
884
0
        break;
885
0
    case APP_TO_SE_EVAL_USR_CRT_SESSIONS:
886
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER, "ServicesMgr: APP_TO_SE_EVAL_USR_CRT_SESSION");
887
0
        io_dispatch_mgr__internal_server_evaluate_all_session_user_cert();
888
0
        break;
889
0
    case APP_TO_SE_UNINITIALIZE_SERVICES:
890
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER, "ServicesMgr: APP_TO_SE_UNINITIALIZE_SERVICES");
891
0
        io_dispatch_mgr__UNINITIALISATION();
892
0
        break;
893
0
    case APP_TO_SE_CLOSE_SERVER_SESSIONS:
894
0
        SOPC_Logger_TraceDebug(SOPC_LOG_MODULE_CLIENTSERVER,
895
0
                               "ServicesMgr: APP_TO_SE_CLOSE_SERVER_SESSIONS exceptSessionId=%" PRIu32 " isShutdown=%s",
896
0
                               id, ((bool) params ? "TRUE" : "FALSE"));
897
0
        io_dispatch_mgr__server_close_sessions((SOPC_SessionId) id);
898
0
        if ((bool) params)
899
0
        {
900
0
            io_dispatch_mgr__server_stopped();
901
0
        }
902
0
        break;
903
0
    default:
904
0
        SOPC_ASSERT(false);
905
0
    }
906
907
    // Note: not called for filtered events (not treated)
908
0
    call_event_treated_hook();
909
0
}
910
911
void SOPC_Services_EnqueueEvent(SOPC_Services_Event seEvent, uint32_t id, uintptr_t params, uintptr_t auxParam)
912
0
{
913
0
    SOPC_ASSERT(servicesEventHandler != NULL);
914
0
    SOPC_EventHandler_Post(servicesEventHandler, (int32_t) seEvent, id, params, auxParam);
915
0
}
916
917
void SOPC_Services_EnqueueEventAsNext(SOPC_Services_Event seEvent, uint32_t id, uintptr_t params, uintptr_t auxParam)
918
0
{
919
0
    SOPC_ASSERT(servicesEventHandler != NULL);
920
0
    SOPC_EventHandler_PostAsNext(servicesEventHandler, (int32_t) seEvent, id, params, auxParam);
921
0
}
922
923
void SOPC_Services_SetEventTreatedHook(SOPC_Services_EventTreatedHook* hook)
924
0
{
925
0
    SOPC_Atomic_Ptr_Set(&eventTreatedHook, (void*) hook);
926
0
}
927
928
uint32_t SOPC_Services_Get_QueueSize(void)
929
0
{
930
0
    return SOPC_EventHandler_Get_QueueSize(servicesEventHandler);
931
0
}
932
933
void SOPC_Services_Initialize(SOPC_SetListenerFunc* setSecureChannelsListener)
934
0
{
935
0
    SOPC_ReturnStatus status = SOPC_STATUS_NOK;
936
0
    int priority = 0;
937
0
    int cpuAffinity = -1;
938
939
0
    SOPC_ToolkitInternal_GetThreadProperties(SOPC_TOOLKIT_THREAD_SERVICES, &priority, &cpuAffinity);
940
0
    servicesLooper = SOPC_Looper_CreatePrioritized("Services", priority, cpuAffinity);
941
0
    SOPC_ASSERT(servicesLooper != NULL);
942
943
0
    servicesEventHandler = SOPC_EventHandler_Create(servicesLooper, onServiceEvent);
944
0
    SOPC_ASSERT(servicesEventHandler != NULL);
945
946
0
    secureChannelsEventHandler = SOPC_EventHandler_Create(servicesLooper, onSecureChannelEvent);
947
0
    SOPC_ASSERT(secureChannelsEventHandler != NULL);
948
949
    // Init async close management flag
950
0
    status = SOPC_Mutex_Initialization(&closeAllConnectionsSync.mutex);
951
0
    SOPC_ASSERT(status == SOPC_STATUS_OK);
952
953
0
    status = SOPC_Condition_Init(&closeAllConnectionsSync.cond);
954
0
    SOPC_ASSERT(status == SOPC_STATUS_OK);
955
956
0
    setSecureChannelsListener(secureChannelsEventHandler);
957
958
    /* Init B model */
959
0
    INITIALISATION();
960
0
}
961
962
void SOPC_Services_CloseAllSCs(bool clientOnly)
963
0
{
964
0
    SOPC_Mutex_Lock(&closeAllConnectionsSync.mutex);
965
0
    closeAllConnectionsSync.requestedFlag = true;
966
0
    closeAllConnectionsSync.clientOnlyFlag = clientOnly;
967
    // Do a synchronous connections closed (effective on client only)
968
0
    SOPC_EventHandler_Post(servicesEventHandler, APP_TO_SE_CLOSE_ALL_CONNECTIONS, 0, (uintptr_t) clientOnly, 0);
969
0
    while (!closeAllConnectionsSync.allDisconnectedFlag)
970
0
    {
971
0
        SOPC_Mutex_UnlockAndWaitCond(&closeAllConnectionsSync.cond, &closeAllConnectionsSync.mutex);
972
0
    }
973
0
    closeAllConnectionsSync.allDisconnectedFlag = false;
974
0
    closeAllConnectionsSync.clientOnlyFlag = false;
975
0
    closeAllConnectionsSync.requestedFlag = false;
976
0
    SOPC_Mutex_Unlock(&closeAllConnectionsSync.mutex);
977
0
}
978
979
void SOPC_Services_Clear(void)
980
0
{
981
0
    SOPC_EventHandler_Post(servicesEventHandler, APP_TO_SE_UNINITIALIZE_SERVICES, 0, 0, 0);
982
983
    // Set to NULL handlers deallocated by SOPC_Looper_Delete call
984
0
    servicesEventHandler = NULL;
985
0
    secureChannelsEventHandler = NULL;
986
0
    SOPC_Looper_Delete(servicesLooper);
987
0
    servicesLooper = NULL;
988
0
    SOPC_Atomic_Ptr_Set(&eventTreatedHook, NULL);
989
990
0
    closeAllConnectionsSync.allDisconnectedFlag = false;
991
0
    closeAllConnectionsSync.clientOnlyFlag = false;
992
    closeAllConnectionsSync.requestedFlag = false;
993
0
    SOPC_Mutex_Clear(&closeAllConnectionsSync.mutex);
994
0
    SOPC_Condition_Clear(&closeAllConnectionsSync.cond);
995
0
}