Coverage Report

Created: 2025-08-26 06:59

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