Coverage Report

Created: 2026-01-17 07:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/open62541/src/client/ua_client_subscriptions.c
Line
Count
Source
1
/* This Source Code Form is subject to the terms of the Mozilla Public
2
 * License, v. 2.0. If a copy of the MPL was not distributed with this
3
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
4
 *
5
 *    Copyright 2015-2018 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
6
 *    Copyright 2015 (c) Oleksiy Vasylyev
7
 *    Copyright 2016 (c) Sten Grüner
8
 *    Copyright 2017-2018 (c) Thomas Stalder, Blue Time Concept SA
9
 *    Copyright 2016-2017 (c) Florian Palm
10
 *    Copyright 2017 (c) Frank Meerkötter
11
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
12
 */
13
14
#include <open62541/client_highlevel.h>
15
#include <open62541/client_highlevel_async.h>
16
17
#include "ua_client_internal.h"
18
19
struct UA_Client_MonitoredItem_ForDelete {
20
    UA_Client *client;
21
    UA_Client_Subscription *sub;
22
    UA_UInt32 *monitoredItemId;
23
};
24
25
/*****************/
26
/* Subscriptions */
27
/*****************/
28
29
static enum ZIP_CMP
30
/* For ZIP_TREE we use clientHandle comparison */
31
0
UA_ClientHandle_cmp(const void *a, const void *b) {
32
0
    const UA_Client_MonitoredItem *aa = (const UA_Client_MonitoredItem *)a;
33
0
    const UA_Client_MonitoredItem *bb = (const UA_Client_MonitoredItem *)b;
34
0
    if(aa->clientHandle < bb->clientHandle)
35
0
        return ZIP_CMP_LESS;
36
0
    if(aa->clientHandle > bb->clientHandle)
37
0
        return ZIP_CMP_MORE;
38
0
    return ZIP_CMP_EQ;
39
0
}
40
41
0
ZIP_FUNCTIONS(MonitorItemsTree, UA_Client_MonitoredItem, zipfields,
Unexecuted instantiation: ua_client_subscriptions.c:MonitorItemsTree_ZIP_INSERT
Unexecuted instantiation: ua_client_subscriptions.c:MonitorItemsTree_ZIP_ITER
Unexecuted instantiation: ua_client_subscriptions.c:MonitorItemsTree_ZIP_REMOVE
42
              UA_Client_MonitoredItem, zipfields, UA_ClientHandle_cmp)
43
44
static void
45
MonitoredItem_delete(UA_Client *client, UA_Client_Subscription *sub,
46
                     UA_Client_MonitoredItem *mon);
47
48
static void
49
ua_Subscriptions_create(UA_Client *client, UA_Client_Subscription *newSub,
50
0
                        UA_CreateSubscriptionResponse *response) {
51
0
    UA_LOCK_ASSERT(&client->clientMutex);
52
53
0
    UA_EventLoop *el = client->config.eventLoop;
54
55
0
    newSub->subscriptionId = response->subscriptionId;
56
0
    newSub->sequenceNumber = 0;
57
0
    newSub->lastActivity = el->dateTime_nowMonotonic(el);
58
0
    newSub->publishingInterval = response->revisedPublishingInterval;
59
0
    newSub->maxKeepAliveCount = response->revisedMaxKeepAliveCount;
60
0
    ZIP_INIT(&newSub->monitoredItems);
61
0
    LIST_INSERT_HEAD(&client->subscriptions, newSub, listEntry);
62
63
    /* Immediately send the first publish requests if there are none
64
     * outstanding */
65
0
    __Client_Subscriptions_backgroundPublish(client);
66
0
}
67
68
static void
69
ua_Subscriptions_create_handler(UA_Client *client, void *data,
70
0
                                UA_UInt32 requestId, void *r) {
71
0
    UA_LOCK_ASSERT(&client->clientMutex);
72
73
0
    UA_CreateSubscriptionResponse *response = (UA_CreateSubscriptionResponse *)r;
74
0
    CustomCallback *cc = (CustomCallback *)data;
75
0
    UA_Client_Subscription *newSub = (UA_Client_Subscription *)cc->clientData;
76
0
    if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD) {
77
0
        UA_free(newSub);
78
0
        goto cleanup;
79
0
    }
80
81
    /* Prepare the internal representation */
82
0
    ua_Subscriptions_create(client, newSub, response);
83
84
0
cleanup:
85
0
    if(cc->userCallback)
86
0
        cc->userCallback(client, cc->userData, requestId, response);
87
0
    UA_free(cc);
88
0
}
89
90
UA_CreateSubscriptionResponse
91
UA_Client_Subscriptions_create(UA_Client *client,
92
                               const UA_CreateSubscriptionRequest request,
93
                               void *subscriptionContext,
94
                               UA_Client_StatusChangeNotificationCallback statusChangeCallback,
95
0
                               UA_Client_DeleteSubscriptionCallback deleteCallback) {
96
0
    lockClient(client);
97
98
0
    UA_CreateSubscriptionResponse response;
99
0
    UA_Client_Subscription *sub = (UA_Client_Subscription *)
100
0
        UA_malloc(sizeof(UA_Client_Subscription));
101
0
    if(!sub) {
102
0
        UA_CreateSubscriptionResponse_init(&response);
103
0
        response.responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
104
0
        unlockClient(client);
105
0
        return response;
106
0
    }
107
0
    sub->context = subscriptionContext;
108
0
    sub->statusChangeCallback = statusChangeCallback;
109
0
    sub->deleteCallback = deleteCallback;
110
111
    /* Send the request as a synchronous service call */
112
0
    __Client_Service(client, &request, &UA_TYPES[UA_TYPES_CREATESUBSCRIPTIONREQUEST],
113
0
                     &response, &UA_TYPES[UA_TYPES_CREATESUBSCRIPTIONRESPONSE]);
114
0
    if(response.responseHeader.serviceResult != UA_STATUSCODE_GOOD) {
115
0
        UA_free(sub);
116
0
        unlockClient(client);
117
0
        return response;
118
0
    }
119
120
0
    ua_Subscriptions_create(client, sub, &response);
121
122
0
    unlockClient(client);
123
0
    return response;
124
0
}
125
126
UA_StatusCode
127
UA_Client_Subscriptions_create_async(UA_Client *client, const UA_CreateSubscriptionRequest request,
128
                                     void *subscriptionContext,
129
                                     UA_Client_StatusChangeNotificationCallback statusChangeCallback,
130
                                     UA_Client_DeleteSubscriptionCallback deleteCallback,
131
                                     UA_ClientAsyncCreateSubscriptionCallback createCallback,
132
0
                                     void *userdata, UA_UInt32 *requestId) {
133
0
    CustomCallback *cc = (CustomCallback *)UA_calloc(1, sizeof(CustomCallback));
134
0
    if(!cc)
135
0
        return UA_STATUSCODE_BADOUTOFMEMORY;
136
137
0
    UA_Client_Subscription *sub = (UA_Client_Subscription *)
138
0
        UA_malloc(sizeof(UA_Client_Subscription));
139
0
    if(!sub) {
140
0
        UA_free(cc);
141
0
        return UA_STATUSCODE_BADOUTOFMEMORY;
142
0
    }
143
0
    sub->context = subscriptionContext;
144
0
    sub->statusChangeCallback = statusChangeCallback;
145
0
    sub->deleteCallback = deleteCallback;
146
147
0
    cc->userCallback = (UA_ClientAsyncServiceCallback)createCallback;
148
0
    cc->userData = userdata;
149
0
    cc->clientData = sub;
150
151
    /* Send the request as asynchronous service call */
152
0
    UA_StatusCode res =
153
0
        __UA_Client_AsyncService(client, &request, &UA_TYPES[UA_TYPES_CREATESUBSCRIPTIONREQUEST],
154
0
                                 ua_Subscriptions_create_handler, &UA_TYPES[UA_TYPES_CREATESUBSCRIPTIONRESPONSE],
155
0
                                 cc, requestId);
156
0
    if (res != UA_STATUSCODE_GOOD) {
157
0
        UA_free(cc);
158
0
        UA_free(sub);
159
0
    }
160
0
    return res;
161
0
}
162
163
static UA_Client_Subscription *
164
0
findSubscriptionById(const UA_Client *client, UA_UInt32 subscriptionId) {
165
0
    UA_Client_Subscription *sub = NULL;
166
0
    LIST_FOREACH(sub, &client->subscriptions, listEntry) {
167
0
        if(sub->subscriptionId == subscriptionId)
168
0
            break;
169
0
    }
170
0
    return sub;
171
0
}
172
173
static void
174
ua_Subscriptions_modify(UA_Client *client, UA_Client_Subscription *sub,
175
0
                        const UA_ModifySubscriptionResponse *response) {
176
0
    sub->publishingInterval = response->revisedPublishingInterval;
177
0
    sub->maxKeepAliveCount = response->revisedMaxKeepAliveCount;
178
0
}
179
180
static void
181
ua_Subscriptions_modify_handler(UA_Client *client, void *data, UA_UInt32 requestId,
182
0
                                void *r) {
183
0
    UA_LOCK_ASSERT(&client->clientMutex);
184
185
0
    UA_ModifySubscriptionResponse *response = (UA_ModifySubscriptionResponse *)r;
186
0
    CustomCallback *cc = (CustomCallback *)data;
187
0
    UA_Client_Subscription *sub =
188
0
        findSubscriptionById(client, (UA_UInt32)(uintptr_t)cc->clientData);
189
0
    if(sub) {
190
0
        ua_Subscriptions_modify(client, sub, response);
191
0
    } else {
192
0
        UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
193
0
                    "No internal representation of subscription %" PRIu32,
194
0
                    (UA_UInt32)(uintptr_t)cc->clientData);
195
0
    }
196
197
0
    if(cc->userCallback)
198
0
        cc->userCallback(client, cc->userData, requestId, response);
199
0
    UA_free(cc);
200
0
}
201
202
UA_StatusCode
203
UA_Client_Subscriptions_getContext(UA_Client *client, UA_UInt32 subscriptionId,
204
0
                                   void **subContext) {
205
0
  if(!client || !subContext)
206
0
    return UA_STATUSCODE_BADINVALIDARGUMENT;
207
208
0
  lockClient(client);
209
0
  UA_Client_Subscription *sub = findSubscriptionById(client, subscriptionId);
210
0
  if(!sub) {
211
0
    unlockClient(client);
212
0
    return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
213
0
  }
214
215
0
  *subContext = sub->context;
216
0
  unlockClient(client);
217
0
  return UA_STATUSCODE_GOOD;
218
0
}
219
220
UA_StatusCode
221
UA_Client_Subscriptions_setContext(UA_Client *client, UA_UInt32 subscriptionId,
222
0
                                   void *subContext) {
223
0
  if(!client)
224
0
    return UA_STATUSCODE_BADINVALIDARGUMENT;
225
226
0
  lockClient(client);
227
0
  UA_Client_Subscription *sub = findSubscriptionById(client, subscriptionId);
228
0
  if(!sub) {
229
0
    unlockClient(client);
230
0
    return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
231
0
  }
232
233
0
  sub->context = subContext;
234
0
  unlockClient(client);
235
0
  return UA_STATUSCODE_GOOD;
236
0
}
237
238
UA_ModifySubscriptionResponse
239
UA_Client_Subscriptions_modify(UA_Client *client,
240
0
                               const UA_ModifySubscriptionRequest request) {
241
0
    UA_ModifySubscriptionResponse response;
242
0
    UA_ModifySubscriptionResponse_init(&response);
243
244
    /* Find the internal representation */
245
0
    lockClient(client);
246
0
    UA_Client_Subscription *sub = findSubscriptionById(client, request.subscriptionId);
247
0
    if(!sub) {
248
0
        unlockClient(client);
249
0
        response.responseHeader.serviceResult = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
250
0
        return response;
251
0
    }
252
253
    /* Call the service */
254
0
    __Client_Service(client,
255
0
                     &request, &UA_TYPES[UA_TYPES_MODIFYSUBSCRIPTIONREQUEST],
256
0
                     &response, &UA_TYPES[UA_TYPES_MODIFYSUBSCRIPTIONRESPONSE]);
257
258
    /* Adjust the internal representation. Lookup again for thread-safety. */
259
0
    sub = findSubscriptionById(client, request.subscriptionId);
260
0
    if(!sub) {
261
0
        response.responseHeader.serviceResult = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
262
0
        unlockClient(client);
263
0
        return response;
264
0
    }
265
0
    ua_Subscriptions_modify(client, sub, &response);
266
0
    unlockClient(client);
267
0
    return response;
268
0
}
269
270
UA_StatusCode
271
UA_Client_Subscriptions_modify_async(UA_Client *client,
272
                                     const UA_ModifySubscriptionRequest request,
273
                                     UA_ClientAsyncModifySubscriptionCallback callback,
274
0
                                     void *userdata, UA_UInt32 *requestId) {
275
0
    lockClient(client);
276
277
0
    UA_Client_Subscription *sub = findSubscriptionById(client, request.subscriptionId);
278
0
    if(!sub) {
279
0
        unlockClient(client);
280
0
        return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
281
0
    }
282
283
0
    CustomCallback *cc = (CustomCallback *)UA_calloc(1, sizeof(CustomCallback));
284
0
    if(!cc) {
285
0
        unlockClient(client);
286
0
        return UA_STATUSCODE_BADOUTOFMEMORY;
287
0
    }
288
289
0
    cc->clientData = (void *)(uintptr_t)request.subscriptionId;
290
0
    cc->userData = userdata;
291
0
    cc->userCallback = (UA_ClientAsyncServiceCallback)callback;
292
293
0
    UA_StatusCode res =
294
0
        __Client_AsyncService(client, &request, &UA_TYPES[UA_TYPES_MODIFYSUBSCRIPTIONREQUEST],
295
0
                              ua_Subscriptions_modify_handler,
296
0
                              &UA_TYPES[UA_TYPES_MODIFYSUBSCRIPTIONRESPONSE],
297
0
                              cc, requestId);
298
299
0
    unlockClient(client);
300
0
    return res;
301
0
}
302
303
static void *
304
0
UA_MonitoredItem_delete_wrapper(void *data, UA_Client_MonitoredItem *mon) {
305
0
    struct UA_Client_MonitoredItem_ForDelete *deleteMonitoredItem =
306
0
        (struct UA_Client_MonitoredItem_ForDelete *)data;
307
0
    if(deleteMonitoredItem != NULL) {
308
0
        if(deleteMonitoredItem->monitoredItemId != NULL &&
309
0
           (mon->monitoredItemId != *deleteMonitoredItem->monitoredItemId)) {
310
0
            return NULL;
311
0
        }
312
0
        MonitoredItem_delete(deleteMonitoredItem->client, deleteMonitoredItem->sub, mon);
313
0
    }
314
0
    return NULL;
315
0
}
316
317
static void
318
__Client_Subscription_deleteInternal(UA_Client *client,
319
0
                                     UA_Client_Subscription *sub) {
320
    /* Remove the MonitoredItems */
321
0
    struct UA_Client_MonitoredItem_ForDelete deleteMonitoredItem;
322
0
    memset(&deleteMonitoredItem, 0, sizeof(struct UA_Client_MonitoredItem_ForDelete));
323
0
    deleteMonitoredItem.client = client;
324
0
    deleteMonitoredItem.sub = sub;
325
0
    ZIP_ITER(MonitorItemsTree, &sub->monitoredItems,
326
0
             UA_MonitoredItem_delete_wrapper, &deleteMonitoredItem);
327
328
    /* Call the delete callback */
329
0
    if(sub->deleteCallback) {
330
0
        void *subC = sub->context;
331
0
        UA_UInt32 subId = sub->subscriptionId;
332
0
        sub->deleteCallback(client, subId, subC);
333
0
    }
334
335
    /* Remove */
336
0
    LIST_REMOVE(sub, listEntry);
337
0
    UA_free(sub);
338
0
}
339
340
static void
341
__Client_Subscription_processDelete(UA_Client *client,
342
                                    const UA_DeleteSubscriptionsRequest *request,
343
0
                                    const UA_DeleteSubscriptionsResponse *response)  {
344
0
    if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD)
345
0
        return;
346
347
    /* Check that the request and response size -- use the same index for both */
348
0
    if(request->subscriptionIdsSize != response->resultsSize)
349
0
        return;
350
351
0
    for(size_t i = 0; i < request->subscriptionIdsSize; i++) {
352
0
        if(response->results[i] != UA_STATUSCODE_GOOD &&
353
0
           response->results[i] != UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID)
354
0
            continue;
355
356
        /* Get the Subscription */
357
0
        UA_Client_Subscription *sub =
358
0
            findSubscriptionById(client, request->subscriptionIds[i]);
359
0
        if(!sub) {
360
0
            UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
361
0
                        "No internal representation of subscription %" PRIu32,
362
0
                        request->subscriptionIds[i]);
363
0
            continue;
364
0
        }
365
366
        /* Delete the Subscription */
367
0
        __Client_Subscription_deleteInternal(client, sub);
368
0
    }
369
0
}
370
371
typedef struct {
372
    UA_DeleteSubscriptionsRequest request;
373
    UA_ClientAsyncServiceCallback userCallback;
374
    void *userData;
375
} DeleteSubscriptionCallback;
376
377
static void
378
ua_Subscriptions_delete_handler(UA_Client *client, void *data,
379
0
                                UA_UInt32 requestId, void *r) {
380
0
    UA_DeleteSubscriptionsResponse *response =
381
0
        (UA_DeleteSubscriptionsResponse *)r;
382
0
    DeleteSubscriptionCallback *dsc =
383
0
        (DeleteSubscriptionCallback*)data;
384
385
0
    lockClient(client);
386
387
    /* Delete */
388
0
    __Client_Subscription_processDelete(client, &dsc->request, response);
389
390
    /* Userland Callback */
391
0
    dsc->userCallback(client, dsc->userData, requestId, response);
392
393
    /* Cleanup */
394
0
    UA_DeleteSubscriptionsRequest_clear(&dsc->request);
395
0
    UA_free(dsc);
396
397
0
    unlockClient(client);
398
0
}
399
400
UA_StatusCode
401
UA_Client_Subscriptions_delete_async(UA_Client *client,
402
                                     const UA_DeleteSubscriptionsRequest request,
403
                                     UA_ClientAsyncDeleteSubscriptionsCallback callback,
404
0
                                     void *userdata, UA_UInt32 *requestId) {
405
    /* Make a copy of the request that persists into the async callback */
406
0
    DeleteSubscriptionCallback *dsc = (DeleteSubscriptionCallback*)
407
0
        UA_malloc(sizeof(DeleteSubscriptionCallback));
408
0
    if(!dsc)
409
0
        return UA_STATUSCODE_BADOUTOFMEMORY;
410
0
    dsc->userCallback = (UA_ClientAsyncServiceCallback)callback;
411
0
    dsc->userData = userdata;
412
0
    UA_StatusCode res = UA_DeleteSubscriptionsRequest_copy(&request, &dsc->request);
413
0
    if(res != UA_STATUSCODE_GOOD) {
414
0
        UA_free(dsc);
415
0
        return res;
416
0
    }
417
418
    /* Make the async call */
419
0
    res = __UA_Client_AsyncService(client, &request, &UA_TYPES[UA_TYPES_DELETESUBSCRIPTIONSREQUEST],
420
0
                                   ua_Subscriptions_delete_handler, &UA_TYPES[UA_TYPES_DELETESUBSCRIPTIONSRESPONSE],
421
0
                                   dsc, requestId);
422
0
    if (res != UA_STATUSCODE_GOOD) {
423
0
        UA_DeleteSubscriptionsRequest_clear(&dsc->request);
424
0
        UA_free(dsc);
425
0
    }
426
0
    return res;
427
0
}
428
429
UA_DeleteSubscriptionsResponse
430
UA_Client_Subscriptions_delete(UA_Client *client,
431
0
                               const UA_DeleteSubscriptionsRequest request) {
432
0
    lockClient(client);
433
434
    /* Send the request */
435
0
    UA_DeleteSubscriptionsResponse response;
436
0
    __Client_Service(client, &request, &UA_TYPES[UA_TYPES_DELETESUBSCRIPTIONSREQUEST],
437
0
                     &response, &UA_TYPES[UA_TYPES_DELETESUBSCRIPTIONSRESPONSE]);
438
439
    /* Process */
440
0
    __Client_Subscription_processDelete(client, &request, &response);
441
442
0
    unlockClient(client);
443
0
    return response;
444
0
}
445
446
UA_StatusCode
447
0
UA_Client_Subscriptions_deleteSingle(UA_Client *client, UA_UInt32 subscriptionId) {
448
0
    UA_DeleteSubscriptionsRequest request;
449
0
    UA_DeleteSubscriptionsRequest_init(&request);
450
0
    request.subscriptionIds = &subscriptionId;
451
0
    request.subscriptionIdsSize = 1;
452
453
0
    UA_DeleteSubscriptionsResponse response =
454
0
        UA_Client_Subscriptions_delete(client, request);
455
456
0
    UA_StatusCode retval = response.responseHeader.serviceResult;
457
0
    if(retval != UA_STATUSCODE_GOOD) {
458
0
        UA_DeleteSubscriptionsResponse_clear(&response);
459
0
        return retval;
460
0
    }
461
462
0
    if(response.resultsSize != 1) {
463
0
        UA_DeleteSubscriptionsResponse_clear(&response);
464
0
        return UA_STATUSCODE_BADINTERNALERROR;
465
0
    }
466
467
0
    retval = response.results[0];
468
0
    UA_DeleteSubscriptionsResponse_clear(&response);
469
0
    return retval;
470
0
}
471
472
/******************/
473
/* MonitoredItems */
474
/******************/
475
476
static void
477
MonitoredItem_delete(UA_Client *client, UA_Client_Subscription *sub,
478
0
                     UA_Client_MonitoredItem *mon) {
479
0
    UA_LOCK_ASSERT(&client->clientMutex);
480
481
0
    ZIP_REMOVE(MonitorItemsTree, &sub->monitoredItems, mon);
482
0
    if(mon->deleteCallback)
483
0
        mon->deleteCallback(client, sub->subscriptionId, sub->context,
484
0
                            mon->monitoredItemId, mon->context);
485
0
    for(size_t i = 0; i < mon->eventFields.mapSize; i++) {
486
0
        UA_Variant_init(&mon->eventFields.map[i].value);
487
0
    }
488
0
    UA_KeyValueMap_clear(&mon->eventFields);
489
0
    UA_free(mon);
490
0
}
491
492
typedef struct {
493
    void **contexts;
494
    UA_Client_DeleteMonitoredItemCallback *deleteCallbacks;
495
    void **handlingCallbacks;
496
    UA_CreateMonitoredItemsRequest request;
497
498
    /* Notify the user that the async callback was processed */
499
    UA_ClientAsyncServiceCallback userCallback;
500
    void *userData;
501
} MonitoredItems_CreateData;
502
503
static void
504
0
MonitoredItems_CreateData_clear(UA_Client *client, MonitoredItems_CreateData *data) {
505
0
    UA_free(data->contexts);
506
0
    UA_free(data->deleteCallbacks);
507
0
    UA_free(data->handlingCallbacks);
508
0
    UA_CreateMonitoredItemsRequest_clear(&data->request);
509
0
}
510
511
static UA_StatusCode
512
prepareEventFieldsMap(UA_Client_MonitoredItem *newMon,
513
0
                      UA_MonitoringParameters *params) {
514
    /* Get the EventFilter */
515
0
    UA_ExtensionObject *eo = &params->filter;
516
0
    if(eo->content.decoded.type != &UA_TYPES[UA_TYPES_EVENTFILTER])
517
0
        return UA_STATUSCODE_GOOD;
518
0
    UA_EventFilter *ef = (UA_EventFilter*)eo->content.decoded.data;
519
0
    UA_StatusCode res = UA_STATUSCODE_GOOD;
520
521
    /* Check whether there are fields */
522
0
    if(ef->selectClausesSize == 0)
523
0
        return UA_STATUSCODE_GOOD;
524
525
    /* Allocate the map */
526
0
    newMon->eventFields.map = (UA_KeyValuePair*)
527
0
        UA_calloc(ef->selectClausesSize, sizeof(UA_KeyValuePair));
528
0
    if(!newMon->eventFields.map)
529
0
        return UA_STATUSCODE_BADOUTOFMEMORY;
530
0
    newMon->eventFields.mapSize = ef->selectClausesSize;
531
532
    /* Create the key-strings for the fields */
533
0
    for(size_t i = 0; i < newMon->eventFields.mapSize; i++) {
534
0
        res |= UA_SimpleAttributeOperand_print(&ef->selectClauses[i],
535
0
                                               &newMon->eventFields.map[i].key.name);
536
0
    }
537
538
0
    return res;
539
0
}
540
541
static void
542
ua_MonitoredItems_create(UA_Client *client, MonitoredItems_CreateData *data,
543
0
                         UA_CreateMonitoredItemsResponse *response) {
544
0
    UA_CreateMonitoredItemsRequest *request = &data->request;
545
0
    UA_Client_DeleteMonitoredItemCallback *deleteCallbacks = data->deleteCallbacks;
546
547
    /* Ensure the result size matches the expectation */
548
0
    if(response->resultsSize != request->itemsToCreateSize)
549
0
        response->responseHeader.serviceResult = UA_STATUSCODE_BADINTERNALERROR;
550
551
    /* Find the subscription */
552
0
    UA_Client_Subscription *sub =
553
0
        findSubscriptionById(client, data->request.subscriptionId);
554
0
    UA_StatusCode res = (sub) ?
555
0
        response->responseHeader.serviceResult : UA_STATUSCODE_BADNOTFOUND;
556
557
    /* Abort and call the delete callbacks */
558
0
    if(res != UA_STATUSCODE_GOOD) {
559
0
        void *subC = sub ? sub->context : NULL;
560
0
        for(size_t i = 0; i < request->itemsToCreateSize; i++) {
561
0
            if(deleteCallbacks[i])
562
0
                deleteCallbacks[i](client, data->request.subscriptionId,
563
0
                                   subC, 0, data->contexts[i]);
564
0
        }
565
0
        return;
566
0
    }
567
568
    /* Add internally */
569
0
    UA_Client_MonitoredItem *newMon;
570
0
    for(size_t i = 0; i < request->itemsToCreateSize; i++) {
571
0
        if(response->results[i].statusCode != UA_STATUSCODE_GOOD)
572
0
            goto loop_errror;
573
574
0
        newMon = (UA_Client_MonitoredItem *)UA_calloc(1, sizeof(UA_Client_MonitoredItem));
575
0
        if(!newMon)
576
0
            goto loop_errror;
577
578
        /* Cache the field name map */
579
0
        newMon->isEventMonitoredItem =
580
0
            (request->itemsToCreate[i].itemToMonitor.attributeId == UA_ATTRIBUTEID_EVENTNOTIFIER);
581
0
        if(newMon->isEventMonitoredItem) {
582
0
            res = prepareEventFieldsMap(newMon, &request->itemsToCreate[i].requestedParameters);
583
0
            if(res != UA_STATUSCODE_GOOD) {
584
0
                UA_free(newMon);
585
0
                goto loop_errror;
586
0
            }
587
0
        }
588
589
0
        newMon->monitoredItemId = response->results[i].monitoredItemId;
590
0
        newMon->clientHandle = request->itemsToCreate[i].requestedParameters.clientHandle;
591
0
        newMon->context = data->contexts[i];
592
0
        newMon->deleteCallback = deleteCallbacks[i];
593
0
        newMon->handler.dataChangeCallback =
594
0
            (UA_Client_DataChangeNotificationCallback)(uintptr_t)
595
0
                data->handlingCallbacks[i];
596
0
        ZIP_INSERT(MonitorItemsTree, &sub->monitoredItems, newMon);
597
598
0
        UA_LOG_DEBUG(client->config.logging, UA_LOGCATEGORY_CLIENT,
599
0
                     "Subscription %" PRIu32 " | Added a MonitoredItem with handle %" PRIu32,
600
0
                     sub->subscriptionId, newMon->clientHandle);
601
0
        continue;
602
603
0
    loop_errror:
604
0
        if(deleteCallbacks[i])
605
0
            deleteCallbacks[i](client, sub->subscriptionId,
606
0
                               sub->context, 0, data->contexts[i]);
607
0
    }
608
0
}
609
610
static void
611
ua_MonitoredItems_create_async_handler(UA_Client *client, void *d, UA_UInt32 requestId,
612
0
                                       void *r) {
613
0
    UA_CreateMonitoredItemsResponse *response = (UA_CreateMonitoredItemsResponse *)r;
614
0
    MonitoredItems_CreateData *data = (MonitoredItems_CreateData *)d;
615
616
0
    lockClient(client);
617
618
0
    ua_MonitoredItems_create(client, data, response);
619
0
    MonitoredItems_CreateData_clear(client, data);
620
621
0
    if(data->userCallback)
622
0
        data->userCallback(client, data->userData, requestId, response);
623
624
0
    UA_free(data);
625
626
0
    unlockClient(client);
627
0
}
628
629
static UA_StatusCode
630
MonitoredItems_CreateData_prepare(UA_Client *client,
631
                                  const UA_CreateMonitoredItemsRequest *request,
632
                                  void **contexts, void **handlingCallbacks,
633
                                  UA_Client_DeleteMonitoredItemCallback *deleteCallbacks,
634
0
                                  MonitoredItems_CreateData *data) {
635
    /* Align arrays and copy over */
636
0
    UA_StatusCode retval = UA_STATUSCODE_BADOUTOFMEMORY;
637
0
    data->contexts = (void **)UA_calloc(request->itemsToCreateSize, sizeof(void *));
638
0
    if(!data->contexts)
639
0
        goto cleanup;
640
0
    if(contexts)
641
0
        memcpy(data->contexts, contexts, request->itemsToCreateSize * sizeof(void *));
642
643
0
    data->deleteCallbacks = (UA_Client_DeleteMonitoredItemCallback *)
644
0
        UA_calloc(request->itemsToCreateSize, sizeof(UA_Client_DeleteMonitoredItemCallback));
645
0
    if(!data->deleteCallbacks)
646
0
        goto cleanup;
647
0
    if(deleteCallbacks)
648
0
        memcpy(data->deleteCallbacks, deleteCallbacks,
649
0
               request->itemsToCreateSize * sizeof(UA_Client_DeleteMonitoredItemCallback));
650
651
0
    data->handlingCallbacks = (void **)
652
0
        UA_calloc(request->itemsToCreateSize, sizeof(void *));
653
0
    if(!data->handlingCallbacks)
654
0
        goto cleanup;
655
0
    if(handlingCallbacks)
656
0
        memcpy(data->handlingCallbacks, handlingCallbacks,
657
0
               request->itemsToCreateSize * sizeof(void *));
658
659
0
    retval = UA_CreateMonitoredItemsRequest_copy(request, &data->request);
660
0
    if(retval != UA_STATUSCODE_GOOD)
661
0
        goto cleanup;
662
663
    /* Set the clientHandle */
664
0
    for(size_t i = 0; i < data->request.itemsToCreateSize; i++)
665
0
        data->request.itemsToCreate[i].requestedParameters.clientHandle =
666
0
            ++client->monitoredItemHandles;
667
668
0
    return UA_STATUSCODE_GOOD;
669
670
0
cleanup:
671
0
    MonitoredItems_CreateData_clear(client, data);
672
0
    return retval;
673
0
}
674
675
static void
676
ua_Client_MonitoredItems_create(UA_Client *client,
677
                                const UA_CreateMonitoredItemsRequest *request,
678
                                void **contexts, void **handlingCallbacks,
679
                                UA_Client_DeleteMonitoredItemCallback *deleteCallbacks,
680
0
                                UA_CreateMonitoredItemsResponse *response) {
681
0
    UA_CreateMonitoredItemsResponse_init(response);
682
683
0
    if(!request->itemsToCreateSize) {
684
0
        response->responseHeader.serviceResult = UA_STATUSCODE_BADINTERNALERROR;
685
0
        return;
686
0
    }
687
688
    /* Test if the subscription is valid */
689
0
    UA_Client_Subscription *sub = findSubscriptionById(client, request->subscriptionId);
690
0
    if(!sub) {
691
0
        response->responseHeader.serviceResult = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
692
0
        return;
693
0
    }
694
695
0
    MonitoredItems_CreateData data;
696
0
    memset(&data, 0, sizeof(MonitoredItems_CreateData));
697
698
0
    UA_StatusCode res =
699
0
        MonitoredItems_CreateData_prepare(client, request, contexts, handlingCallbacks,
700
0
                                          deleteCallbacks, &data);
701
0
    if(res != UA_STATUSCODE_GOOD) {
702
0
        response->responseHeader.serviceResult = res;
703
0
        return;
704
0
    }
705
706
    /* Call the service. Use data->request as it contains the client handle
707
     * information. */
708
0
    __Client_Service(client, &data.request,
709
0
                     &UA_TYPES[UA_TYPES_CREATEMONITOREDITEMSREQUEST],
710
0
                     response, &UA_TYPES[UA_TYPES_CREATEMONITOREDITEMSRESPONSE]);
711
712
    /* Add internal representation */
713
0
    ua_MonitoredItems_create(client, &data, response);
714
715
0
    MonitoredItems_CreateData_clear(client, &data);
716
0
}
717
718
static UA_StatusCode
719
createDataChanges_async(UA_Client *client, const UA_CreateMonitoredItemsRequest request,
720
                        void **contexts, void **callbacks,
721
                        UA_Client_DeleteMonitoredItemCallback *deleteCallbacks,
722
                        UA_ClientAsyncServiceCallback createCallback,
723
                        void *userdata,
724
0
                        UA_UInt32 *requestId) {
725
0
    UA_LOCK_ASSERT(&client->clientMutex);
726
727
0
    UA_Client_Subscription *sub = findSubscriptionById(client, request.subscriptionId);
728
0
    if(!sub)
729
0
        return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
730
731
0
    MonitoredItems_CreateData *data = (MonitoredItems_CreateData *)
732
0
        UA_calloc(1, sizeof(MonitoredItems_CreateData));
733
0
    if(!data)
734
0
        return UA_STATUSCODE_BADOUTOFMEMORY;
735
736
0
    data->userCallback = createCallback;
737
0
    data->userData = userdata;
738
739
0
    UA_StatusCode res =
740
0
        MonitoredItems_CreateData_prepare(client, &request, contexts,
741
0
                                          callbacks, deleteCallbacks, data);
742
0
    if(res != UA_STATUSCODE_GOOD) {
743
0
        UA_free(data);
744
0
        return res;
745
0
    }
746
747
0
    res = __Client_AsyncService(client, &data->request,
748
0
                                &UA_TYPES[UA_TYPES_CREATEMONITOREDITEMSREQUEST],
749
0
                                ua_MonitoredItems_create_async_handler,
750
0
                                &UA_TYPES[UA_TYPES_CREATEMONITOREDITEMSRESPONSE],
751
0
                                data, requestId);
752
0
    if (res != UA_STATUSCODE_GOOD) {
753
0
        MonitoredItems_CreateData_clear(client, data);
754
0
        UA_free(data);
755
0
    }
756
0
    return res;
757
0
}
758
759
UA_CreateMonitoredItemsResponse
760
UA_Client_MonitoredItems_createDataChanges(UA_Client *client,
761
                                           const UA_CreateMonitoredItemsRequest request,
762
                                           void **contexts,
763
                                           UA_Client_DataChangeNotificationCallback *callbacks,
764
0
                                           UA_Client_DeleteMonitoredItemCallback *deleteCallbacks) {
765
0
    UA_CreateMonitoredItemsResponse response;
766
0
    lockClient(client);
767
0
    ua_Client_MonitoredItems_create(client, &request, contexts, (void **)callbacks,
768
0
                                    deleteCallbacks, &response);
769
0
    unlockClient(client);
770
0
    return response;
771
0
}
772
773
UA_StatusCode
774
UA_Client_MonitoredItems_createDataChanges_async(UA_Client *client,
775
                                                 const UA_CreateMonitoredItemsRequest request,
776
                                                 void **contexts,
777
                                                 UA_Client_DataChangeNotificationCallback *callbacks,
778
                                                 UA_Client_DeleteMonitoredItemCallback *deleteCallbacks,
779
                                                 UA_ClientAsyncCreateMonitoredItemsCallback createCallback,
780
0
                                                 void *userdata, UA_UInt32 *requestId) {
781
0
    lockClient(client);
782
0
    UA_StatusCode res =
783
0
        createDataChanges_async(client, request, contexts, (void **)callbacks, deleteCallbacks,
784
0
                                (UA_ClientAsyncServiceCallback)createCallback,
785
0
                                userdata, requestId);
786
0
    unlockClient(client);
787
0
    return res;
788
0
}
789
790
UA_MonitoredItemCreateResult
791
UA_Client_MonitoredItems_createDataChange(UA_Client *client, UA_UInt32 subscriptionId,
792
                                          UA_TimestampsToReturn timestampsToReturn,
793
                                          const UA_MonitoredItemCreateRequest item,
794
                                          void *context,
795
                                          UA_Client_DataChangeNotificationCallback callback,
796
0
                                          UA_Client_DeleteMonitoredItemCallback deleteCallback) {
797
0
    UA_CreateMonitoredItemsRequest request;
798
0
    UA_CreateMonitoredItemsRequest_init(&request);
799
0
    request.subscriptionId = subscriptionId;
800
0
    request.timestampsToReturn = timestampsToReturn;
801
0
    request.itemsToCreate = (UA_MonitoredItemCreateRequest*)(uintptr_t)&item;
802
0
    request.itemsToCreateSize = 1;
803
0
    UA_CreateMonitoredItemsResponse response =
804
0
       UA_Client_MonitoredItems_createDataChanges(client, request, &context,
805
0
                                                   &callback, &deleteCallback);
806
0
    UA_MonitoredItemCreateResult result;
807
0
    UA_MonitoredItemCreateResult_init(&result);
808
0
    if(response.responseHeader.serviceResult != UA_STATUSCODE_GOOD)
809
0
        result.statusCode = response.responseHeader.serviceResult;
810
811
0
    if(result.statusCode == UA_STATUSCODE_GOOD &&
812
0
       response.resultsSize != 1)
813
0
        result.statusCode = UA_STATUSCODE_BADINTERNALERROR;
814
815
0
    if(result.statusCode == UA_STATUSCODE_GOOD)
816
0
       UA_MonitoredItemCreateResult_copy(&response.results[0] , &result);
817
0
    UA_CreateMonitoredItemsResponse_clear(&response);
818
0
    return result;
819
0
}
820
821
UA_CreateMonitoredItemsResponse
822
UA_Client_MonitoredItems_createEvents(UA_Client *client,
823
                                      const UA_CreateMonitoredItemsRequest request,
824
                                      void **contexts,
825
                                      UA_Client_EventNotificationCallback *callback,
826
0
                                      UA_Client_DeleteMonitoredItemCallback *deleteCallback) {
827
0
    UA_CreateMonitoredItemsResponse response;
828
0
    lockClient(client);
829
0
    ua_Client_MonitoredItems_create(client, &request, contexts, (void **)callback,
830
0
                                    deleteCallback, &response);
831
0
    unlockClient(client);
832
0
    return response;
833
0
}
834
835
/* Monitor the EventNotifier attribute only */
836
UA_StatusCode
837
UA_Client_MonitoredItems_createEvents_async(UA_Client *client,
838
                                            const UA_CreateMonitoredItemsRequest request,
839
                                            void **contexts,
840
                                            UA_Client_EventNotificationCallback *callbacks,
841
                                            UA_Client_DeleteMonitoredItemCallback *deleteCallbacks,
842
                                            UA_ClientAsyncCreateMonitoredItemsCallback createCallback,
843
0
                                            void *userdata, UA_UInt32 *requestId) {
844
0
    lockClient(client);
845
0
    UA_StatusCode res =
846
0
        createDataChanges_async(client, request, contexts, (void **)callbacks, deleteCallbacks,
847
0
                                (UA_ClientAsyncServiceCallback)createCallback, userdata, requestId);
848
0
    unlockClient(client);
849
0
    return res;
850
0
}
851
852
UA_MonitoredItemCreateResult
853
UA_Client_MonitoredItems_createEvent(UA_Client *client, UA_UInt32 subscriptionId,
854
                                     UA_TimestampsToReturn timestampsToReturn,
855
                                     const UA_MonitoredItemCreateRequest item, void *context,
856
                                     UA_Client_EventNotificationCallback callback,
857
0
                                     UA_Client_DeleteMonitoredItemCallback deleteCallback) {
858
0
    UA_CreateMonitoredItemsRequest request;
859
0
    UA_CreateMonitoredItemsRequest_init(&request);
860
0
    request.subscriptionId = subscriptionId;
861
0
    request.timestampsToReturn = timestampsToReturn;
862
0
    request.itemsToCreate = (UA_MonitoredItemCreateRequest*)(uintptr_t)&item;
863
0
    request.itemsToCreateSize = 1;
864
0
    UA_CreateMonitoredItemsResponse response =
865
0
       UA_Client_MonitoredItems_createEvents(client, request, &context,
866
0
                                             &callback, &deleteCallback);
867
0
    UA_StatusCode retval = response.responseHeader.serviceResult;
868
0
    UA_MonitoredItemCreateResult result;
869
0
    UA_MonitoredItemCreateResult_init(&result);
870
0
    if(retval != UA_STATUSCODE_GOOD) {
871
0
        UA_CreateMonitoredItemsResponse_clear(&response);
872
0
        result.statusCode = retval;
873
0
        return result;
874
0
    }
875
0
    UA_MonitoredItemCreateResult_copy(response.results , &result);
876
0
    UA_CreateMonitoredItemsResponse_clear(&response);
877
0
    return result;
878
0
}
879
880
static void
881
ua_MonitoredItems_delete(UA_Client *client, UA_Client_Subscription *sub,
882
                         const UA_DeleteMonitoredItemsRequest *request,
883
0
                         const UA_DeleteMonitoredItemsResponse *response) {
884
#ifdef __clang_analyzer__
885
    return;
886
#endif
887
888
    /* Loop over deleted MonitoredItems */
889
0
    struct UA_Client_MonitoredItem_ForDelete deleteMonitoredItem;
890
0
    memset(&deleteMonitoredItem, 0, sizeof(struct UA_Client_MonitoredItem_ForDelete));
891
0
    deleteMonitoredItem.client = client;
892
0
    deleteMonitoredItem.sub = sub;
893
894
0
    for(size_t i = 0; i < response->resultsSize; i++) {
895
0
        if(response->results[i] != UA_STATUSCODE_GOOD &&
896
0
           response->results[i] != UA_STATUSCODE_BADMONITOREDITEMIDINVALID) {
897
0
            continue;
898
0
        }
899
0
        deleteMonitoredItem.monitoredItemId = &request->monitoredItemIds[i];
900
        /* Delete the internal representation */
901
0
        ZIP_ITER(MonitorItemsTree,&sub->monitoredItems,
902
0
                 UA_MonitoredItem_delete_wrapper, &deleteMonitoredItem);
903
0
    }
904
0
}
905
906
static void
907
0
ua_MonitoredItems_delete_handler(UA_Client *client, void *d, UA_UInt32 requestId, void *r) {
908
0
    UA_Client_Subscription *sub = NULL;
909
0
    CustomCallback *cc = (CustomCallback *)d;
910
0
    UA_DeleteMonitoredItemsResponse *response = (UA_DeleteMonitoredItemsResponse *)r;
911
0
    UA_DeleteMonitoredItemsRequest *request =
912
0
        (UA_DeleteMonitoredItemsRequest *)cc->clientData;
913
914
0
    lockClient(client);
915
916
0
    if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD)
917
0
        goto cleanup;
918
919
0
    sub = findSubscriptionById(client, request->subscriptionId);
920
0
    if(!sub) {
921
0
        UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
922
0
                    "No internal representation of subscription %" PRIu32,
923
0
                    request->subscriptionId);
924
0
        goto cleanup;
925
0
    }
926
927
    /* Delete MonitoredItems from the internal representation */
928
0
    ua_MonitoredItems_delete(client, sub, request, response);
929
930
0
cleanup:
931
0
    if(cc->userCallback)
932
0
        cc->userCallback(client, cc->userData, requestId, response);
933
0
    UA_DeleteMonitoredItemsRequest_delete(request);
934
0
    UA_free(cc);
935
936
0
    unlockClient(client);
937
0
}
938
939
UA_DeleteMonitoredItemsResponse
940
UA_Client_MonitoredItems_delete(UA_Client *client,
941
0
                                const UA_DeleteMonitoredItemsRequest request) {
942
    /* Send the request */
943
0
    UA_DeleteMonitoredItemsResponse response;
944
0
    __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_DELETEMONITOREDITEMSREQUEST],
945
0
                        &response, &UA_TYPES[UA_TYPES_DELETEMONITOREDITEMSRESPONSE]);
946
947
    /* A problem occured remote? */
948
0
    if(response.responseHeader.serviceResult != UA_STATUSCODE_GOOD)
949
0
        return response;
950
951
0
    lockClient(client);
952
953
    /* Find the internal subscription representation */
954
0
    UA_Client_Subscription *sub = findSubscriptionById(client, request.subscriptionId);
955
0
    if(!sub) {
956
0
        UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
957
0
                    "No internal representation of subscription %" PRIu32,
958
0
                    request.subscriptionId);
959
0
        unlockClient(client);
960
0
        return response;
961
0
    }
962
963
    /* Remove MonitoredItems in the internal representation */
964
0
    ua_MonitoredItems_delete(client, sub, &request, &response);
965
966
0
    unlockClient(client);
967
968
0
    return response;
969
0
}
970
971
UA_StatusCode
972
UA_Client_MonitoredItems_delete_async(UA_Client *client,
973
                                      const UA_DeleteMonitoredItemsRequest request,
974
                                      UA_ClientAsyncDeleteMonitoredItemsCallback callback,
975
0
                                      void *userdata, UA_UInt32 *requestId) {
976
    /* Send the request */
977
0
    CustomCallback *cc = (CustomCallback *)UA_calloc(1, sizeof(CustomCallback));
978
0
    if(!cc)
979
0
        return UA_STATUSCODE_BADOUTOFMEMORY;
980
981
0
    UA_DeleteMonitoredItemsRequest *req_copy = UA_DeleteMonitoredItemsRequest_new();
982
0
    if(!req_copy) {
983
0
        UA_free(cc);
984
0
        return UA_STATUSCODE_BADOUTOFMEMORY;
985
0
    }
986
987
0
    UA_DeleteMonitoredItemsRequest_copy(&request, req_copy);
988
0
    cc->clientData = req_copy;
989
0
    cc->userCallback = (UA_ClientAsyncServiceCallback)callback;
990
0
    cc->userData = userdata;
991
992
0
    UA_StatusCode res =
993
0
        __UA_Client_AsyncService(client, &request, &UA_TYPES[UA_TYPES_DELETEMONITOREDITEMSREQUEST],
994
0
                                 ua_MonitoredItems_delete_handler,
995
0
                                 &UA_TYPES[UA_TYPES_DELETEMONITOREDITEMSRESPONSE], cc, requestId);
996
0
    if (res != UA_STATUSCODE_GOOD) {
997
0
        UA_DeleteMonitoredItemsRequest_delete(req_copy);
998
0
        UA_free(cc);
999
0
    }
1000
0
    return res;
1001
0
}
1002
1003
UA_StatusCode
1004
UA_Client_MonitoredItems_deleteSingle(UA_Client *client, UA_UInt32 subscriptionId,
1005
0
                                      UA_UInt32 monitoredItemId) {
1006
0
    UA_DeleteMonitoredItemsRequest request;
1007
0
    UA_DeleteMonitoredItemsRequest_init(&request);
1008
0
    request.subscriptionId = subscriptionId;
1009
0
    request.monitoredItemIds = &monitoredItemId;
1010
0
    request.monitoredItemIdsSize = 1;
1011
1012
0
    UA_DeleteMonitoredItemsResponse response =
1013
0
        UA_Client_MonitoredItems_delete(client, request);
1014
1015
0
    UA_StatusCode retval = response.responseHeader.serviceResult;
1016
0
    if(retval != UA_STATUSCODE_GOOD) {
1017
0
        UA_DeleteMonitoredItemsResponse_clear(&response);
1018
0
        return retval;
1019
0
    }
1020
1021
0
    if(response.resultsSize != 1) {
1022
0
        UA_DeleteMonitoredItemsResponse_clear(&response);
1023
0
        return UA_STATUSCODE_BADINTERNALERROR;
1024
0
    }
1025
1026
0
    retval = response.results[0];
1027
0
    UA_DeleteMonitoredItemsResponse_clear(&response);
1028
0
    return retval;
1029
0
}
1030
1031
static void *
1032
0
UA_MonitoredItem_change_clientHandle_wrapper(void *data, UA_Client_MonitoredItem *mon) {
1033
0
    UA_MonitoredItemModifyRequest *monitoredItemModifyRequest =
1034
0
        (UA_MonitoredItemModifyRequest *)data;
1035
0
    if(monitoredItemModifyRequest &&
1036
0
       mon->monitoredItemId == monitoredItemModifyRequest->monitoredItemId)
1037
0
        monitoredItemModifyRequest->requestedParameters.clientHandle = mon->clientHandle;
1038
0
    return NULL;
1039
0
}
1040
1041
static void
1042
UA_MonitoredItem_change_clientHandle(UA_Client_Subscription *sub,
1043
0
                                     UA_ModifyMonitoredItemsRequest *request) {
1044
0
    for(size_t i = 0; i < request->itemsToModifySize; ++i) {
1045
0
        ZIP_ITER(MonitorItemsTree, &sub->monitoredItems,
1046
0
                 UA_MonitoredItem_change_clientHandle_wrapper,
1047
0
                 &request->itemsToModify[i]);
1048
0
    }
1049
0
}
1050
1051
UA_ModifyMonitoredItemsResponse
1052
UA_Client_MonitoredItems_modify(UA_Client *client,
1053
0
                                const UA_ModifyMonitoredItemsRequest request) {
1054
0
    UA_ModifyMonitoredItemsResponse response;
1055
0
    UA_ModifyMonitoredItemsResponse_init(&response);
1056
1057
0
    lockClient(client);
1058
0
    UA_Client_Subscription *sub = findSubscriptionById(client, request.subscriptionId);
1059
0
    if(!sub) {
1060
0
        unlockClient(client);
1061
0
        response.responseHeader.serviceResult = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
1062
0
        return response;
1063
0
    }
1064
1065
0
    UA_ModifyMonitoredItemsRequest modifiedRequest;
1066
0
    UA_ModifyMonitoredItemsRequest_copy(&request, &modifiedRequest);
1067
0
    UA_MonitoredItem_change_clientHandle(sub, &modifiedRequest);
1068
1069
0
    __Client_Service(client, &modifiedRequest,
1070
0
                     &UA_TYPES[UA_TYPES_MODIFYMONITOREDITEMSREQUEST], &response,
1071
0
                     &UA_TYPES[UA_TYPES_MODIFYMONITOREDITEMSRESPONSE]);
1072
1073
0
    unlockClient(client);
1074
0
    UA_ModifyMonitoredItemsRequest_clear(&modifiedRequest);
1075
0
    return response;
1076
0
}
1077
1078
UA_StatusCode
1079
UA_Client_MonitoredItems_modify_async(UA_Client *client,
1080
                                      const UA_ModifyMonitoredItemsRequest request,
1081
                                      UA_ClientAsyncModifyMonitoredItemsCallback callback,
1082
0
                                      void *userdata, UA_UInt32 *requestId) {
1083
0
    lockClient(client);
1084
1085
0
    UA_Client_Subscription *sub = findSubscriptionById(client, request.subscriptionId);
1086
0
    if(!sub) {
1087
0
        unlockClient(client);
1088
0
        return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
1089
0
    }
1090
1091
0
    UA_ModifyMonitoredItemsRequest modifiedRequest;
1092
0
    UA_ModifyMonitoredItemsRequest_copy(&request, &modifiedRequest);
1093
0
    UA_MonitoredItem_change_clientHandle(sub, &modifiedRequest);
1094
1095
0
    UA_StatusCode statusCode = __Client_AsyncService(
1096
0
        client, &modifiedRequest, &UA_TYPES[UA_TYPES_MODIFYMONITOREDITEMSREQUEST],
1097
0
        (UA_ClientAsyncServiceCallback)callback,
1098
0
        &UA_TYPES[UA_TYPES_MODIFYMONITOREDITEMSRESPONSE], userdata, requestId);
1099
1100
0
    unlockClient(client);
1101
0
    UA_ModifyMonitoredItemsRequest_clear(&modifiedRequest);
1102
0
    return statusCode;
1103
0
}
1104
1105
static void *
1106
0
ua_MonitoredItem_findByID(void *data, UA_Client_MonitoredItem *mon) {
1107
0
  UA_UInt32 monitorId = *(UA_UInt32*)data;
1108
0
  if(monitorId && (mon->monitoredItemId == monitorId))
1109
0
    return mon;
1110
0
  return NULL;
1111
0
}
1112
1113
static UA_Client_MonitoredItem *
1114
0
findMonitoredItemById(UA_Client_Subscription *sub, UA_UInt32 monitoredItemId) {
1115
0
  return (UA_Client_MonitoredItem *)
1116
0
    ZIP_ITER(MonitorItemsTree, &sub->monitoredItems,
1117
0
                 ua_MonitoredItem_findByID, &monitoredItemId);
1118
0
}
1119
1120
UA_StatusCode
1121
UA_Client_MonitoredItem_getContext(UA_Client *client, UA_UInt32 subscriptionId,
1122
0
                                   UA_UInt32 monitoredItemId, void **monContext) {
1123
0
  if(!client || !monContext)
1124
0
    return UA_STATUSCODE_BADINVALIDARGUMENT;
1125
1126
0
  *monContext = NULL;
1127
1128
0
  lockClient(client);
1129
0
  UA_Client_Subscription *sub = findSubscriptionById(client, subscriptionId);
1130
0
  if(!sub) {
1131
0
    unlockClient(client);
1132
0
    return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
1133
0
  }
1134
1135
0
  UA_StatusCode status = UA_STATUSCODE_BADMONITOREDITEMIDINVALID;
1136
0
  UA_Client_MonitoredItem *monItem = findMonitoredItemById(sub, monitoredItemId);
1137
0
  if(monItem) {
1138
0
    *monContext = monItem->context;
1139
0
    status = UA_STATUSCODE_GOOD;
1140
0
  }
1141
0
  unlockClient(client);
1142
0
  return status;
1143
0
}
1144
1145
UA_StatusCode
1146
UA_Client_MonitoredItem_setContext(UA_Client *client, UA_UInt32 subscriptionId,
1147
0
                                   UA_UInt32 monitoredItemId, void *monContext) {
1148
0
  if(!client)
1149
0
    return UA_STATUSCODE_BADINVALIDARGUMENT;
1150
1151
0
  lockClient(client);
1152
0
  UA_Client_Subscription *sub = findSubscriptionById(client, subscriptionId);
1153
0
  if(!sub) {
1154
0
    unlockClient(client);
1155
0
    return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
1156
0
  }
1157
1158
0
  UA_StatusCode status = UA_STATUSCODE_BADMONITOREDITEMIDINVALID;
1159
0
  UA_Client_MonitoredItem *monItem = findMonitoredItemById(sub, monitoredItemId);
1160
0
  if(monItem) {
1161
0
    monItem->context = monContext;
1162
0
    status = UA_STATUSCODE_GOOD;
1163
0
  }
1164
0
  unlockClient(client);
1165
0
  return status;
1166
0
}
1167
1168
/*************************************/
1169
/* Async Processing of Notifications */
1170
/*************************************/
1171
1172
/* Assume the request is already initialized */
1173
UA_StatusCode
1174
0
__Client_preparePublishRequest(UA_Client *client, UA_PublishRequest *request) {
1175
0
    UA_LOCK_ASSERT(&client->clientMutex);
1176
1177
    /* Count acks */
1178
0
    UA_Client_NotificationsAckNumber *ack;
1179
0
    LIST_FOREACH(ack, &client->pendingNotificationsAcks, listEntry)
1180
0
        ++request->subscriptionAcknowledgementsSize;
1181
1182
    /* Create the array. Returns a sentinel pointer if the length is zero. */
1183
0
    request->subscriptionAcknowledgements = (UA_SubscriptionAcknowledgement*)
1184
0
        UA_Array_new(request->subscriptionAcknowledgementsSize,
1185
0
                     &UA_TYPES[UA_TYPES_SUBSCRIPTIONACKNOWLEDGEMENT]);
1186
0
    if(!request->subscriptionAcknowledgements) {
1187
0
        request->subscriptionAcknowledgementsSize = 0;
1188
0
        return UA_STATUSCODE_BADOUTOFMEMORY;
1189
0
    }
1190
1191
0
    size_t i = 0;
1192
0
    UA_Client_NotificationsAckNumber *ack_tmp;
1193
0
    LIST_FOREACH_SAFE(ack, &client->pendingNotificationsAcks, listEntry, ack_tmp) {
1194
0
        request->subscriptionAcknowledgements[i].sequenceNumber = ack->subAck.sequenceNumber;
1195
0
        request->subscriptionAcknowledgements[i].subscriptionId = ack->subAck.subscriptionId;
1196
0
        ++i;
1197
0
        LIST_REMOVE(ack, listEntry);
1198
0
        UA_free(ack);
1199
0
    }
1200
0
    return UA_STATUSCODE_GOOD;
1201
0
}
1202
1203
/* According to OPC Unified Architecture, Part 4 5.13.1.1 i) */
1204
/* The value 0 is never used for the sequence number         */
1205
static UA_UInt32
1206
0
__nextSequenceNumber(UA_UInt32 sequenceNumber) {
1207
0
    UA_UInt32 nextSequenceNumber = sequenceNumber + 1;
1208
0
    if(nextSequenceNumber == 0)
1209
0
        nextSequenceNumber = 1;
1210
0
    return nextSequenceNumber;
1211
0
}
1212
1213
static void
1214
processDataChangeNotification(UA_Client *client, UA_Client_Subscription *sub,
1215
0
                              UA_DataChangeNotification *dataChangeNotification) {
1216
0
    UA_LOCK_ASSERT(&client->clientMutex);
1217
1218
0
    for(size_t j = 0; j < dataChangeNotification->monitoredItemsSize; ++j) {
1219
0
        UA_MonitoredItemNotification *min = &dataChangeNotification->monitoredItems[j];
1220
1221
        /* Find the MonitoredItem */
1222
0
        UA_Client_MonitoredItem *mon;
1223
0
        UA_Client_MonitoredItem dummy;
1224
0
        dummy.clientHandle = min->clientHandle;
1225
0
        mon = ZIP_FIND(MonitorItemsTree, &sub->monitoredItems, &dummy);
1226
1227
0
        if(!mon) {
1228
0
            UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
1229
0
                           "Could not process a notification with clienthandle %" PRIu32
1230
0
                           " on subscription %" PRIu32, min->clientHandle, sub->subscriptionId);
1231
0
            continue;
1232
0
        }
1233
1234
0
        if(mon->isEventMonitoredItem) {
1235
0
            UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
1236
0
                           "MonitoredItem is configured for Events. But received a "
1237
0
                           "DataChangeNotification.");
1238
0
            continue;
1239
0
        }
1240
1241
0
        if(mon->handler.dataChangeCallback) {
1242
0
            void *subC = sub->context;
1243
0
            void *monC = mon->context;
1244
0
            UA_UInt32 subId = sub->subscriptionId;
1245
0
            UA_UInt32 monId = mon->monitoredItemId;
1246
0
            mon->handler.dataChangeCallback(client, subId, subC, monId, monC, &min->value);
1247
0
        }
1248
0
    }
1249
0
}
1250
1251
static void
1252
processEventNotification(UA_Client *client, UA_Client_Subscription *sub,
1253
0
                         UA_EventNotificationList *eventNotificationList) {
1254
0
    UA_LOCK_ASSERT(&client->clientMutex);
1255
1256
0
    for(size_t j = 0; j < eventNotificationList->eventsSize; ++j) {
1257
0
        UA_EventFieldList *efl = &eventNotificationList->events[j];
1258
1259
        /* Find the MonitoredItem */
1260
0
        UA_Client_MonitoredItem *mon;
1261
0
        UA_Client_MonitoredItem dummy;
1262
0
        dummy.clientHandle = efl->clientHandle;
1263
0
        mon = ZIP_FIND(MonitorItemsTree, &sub->monitoredItems, &dummy);
1264
1265
0
        if(!mon) {
1266
0
            UA_LOG_DEBUG(client->config.logging, UA_LOGCATEGORY_CLIENT,
1267
0
                         "Could not process a notification with clienthandle %" PRIu32
1268
0
                         " on subscription %" PRIu32, efl->clientHandle,
1269
0
                         sub->subscriptionId);
1270
0
            continue;
1271
0
        }
1272
1273
0
        if(!mon->isEventMonitoredItem) {
1274
0
            UA_LOG_DEBUG(client->config.logging, UA_LOGCATEGORY_CLIENT,
1275
0
                         "MonitoredItem is configured for DataChanges. But received a "
1276
0
                         "EventNotification");
1277
0
            continue;
1278
0
        }
1279
1280
0
        if(mon->eventFields.mapSize != efl->eventFieldsSize) {
1281
0
            UA_LOG_DEBUG(client->config.logging, UA_LOGCATEGORY_CLIENT,
1282
0
                         "MonitoredItem received a EventNotification with the "
1283
0
                          "wrong number of event fields");
1284
0
            continue;
1285
0
        }
1286
1287
        /* Prepare the key-value map and call the callback  */
1288
0
        for(size_t i = 0; i < mon->eventFields.mapSize; i++) {
1289
0
            mon->eventFields.map[i].value = efl->eventFields[i];
1290
0
        }
1291
0
        mon->handler.eventCallback(client, sub->subscriptionId, sub->context,
1292
0
                                   mon->monitoredItemId, mon->context, mon->eventFields);
1293
0
    }
1294
0
}
1295
1296
static void
1297
processNotificationMessage(UA_Client *client, UA_Client_Subscription *sub,
1298
0
                           UA_ExtensionObject *msg) {
1299
0
    UA_LOCK_ASSERT(&client->clientMutex);
1300
1301
0
    if(msg->encoding != UA_EXTENSIONOBJECT_DECODED)
1302
0
        return;
1303
1304
    /* Handle DataChangeNotification */
1305
0
    if(msg->content.decoded.type == &UA_TYPES[UA_TYPES_DATACHANGENOTIFICATION]) {
1306
0
        UA_DataChangeNotification *dataChangeNotification =
1307
0
            (UA_DataChangeNotification *)msg->content.decoded.data;
1308
0
        processDataChangeNotification(client, sub, dataChangeNotification);
1309
0
        return;
1310
0
    }
1311
1312
    /* Handle EventNotification */
1313
0
    if(msg->content.decoded.type == &UA_TYPES[UA_TYPES_EVENTNOTIFICATIONLIST]) {
1314
0
        UA_EventNotificationList *eventNotificationList =
1315
0
            (UA_EventNotificationList *)msg->content.decoded.data;
1316
0
        processEventNotification(client, sub, eventNotificationList);
1317
0
        return;
1318
0
    }
1319
1320
    /* Handle StatusChangeNotification */
1321
0
    if(msg->content.decoded.type == &UA_TYPES[UA_TYPES_STATUSCHANGENOTIFICATION]) {
1322
0
        if(sub->statusChangeCallback) {
1323
0
            void *subC = sub->context;
1324
0
            UA_UInt32 subId = sub->subscriptionId;
1325
0
            sub->statusChangeCallback(client, subId, subC,
1326
0
                                      (UA_StatusChangeNotification*)msg->content.decoded.data);
1327
0
        } else {
1328
0
            UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
1329
0
                           "Dropped a StatusChangeNotification since no "
1330
0
                           "callback is registered");
1331
0
        }
1332
0
        return;
1333
0
    }
1334
1335
0
    UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
1336
0
                   "Unknown notification message type");
1337
0
}
1338
1339
static void
1340
__Client_Subscriptions_processPublishResponse(UA_Client *client, UA_PublishRequest *request,
1341
0
                                              UA_PublishResponse *response) {
1342
0
    UA_LOCK_ASSERT(&client->clientMutex);
1343
1344
0
    UA_NotificationMessage *msg = &response->notificationMessage;
1345
1346
0
    client->currentlyOutStandingPublishRequests--;
1347
1348
0
    if(response->responseHeader.serviceResult == UA_STATUSCODE_BADTOOMANYPUBLISHREQUESTS) {
1349
0
        if(client->config.outStandingPublishRequests > 1) {
1350
0
            client->config.outStandingPublishRequests--;
1351
0
            UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
1352
0
                           "Too many publishrequest, reduce outStandingPublishRequests "
1353
0
                           "to %" PRId16, client->config.outStandingPublishRequests);
1354
0
        } else {
1355
0
            UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
1356
0
                           "Too many publishrequest when outStandingPublishRequests = 1");
1357
0
            UA_Client_Subscriptions_deleteSingle(client, response->subscriptionId);
1358
0
        }
1359
0
        return;
1360
0
    }
1361
1362
0
    if(response->responseHeader.serviceResult == UA_STATUSCODE_BADSHUTDOWN)
1363
0
        return;
1364
1365
0
    if(response->responseHeader.serviceResult == UA_STATUSCODE_BADNOSUBSCRIPTION) 
1366
0
    {
1367
0
        UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
1368
0
                       "Received BadNoSubscription, delete internal information about subscription");
1369
0
        UA_Client_Subscription *sub = findSubscriptionById(client, response->subscriptionId);
1370
0
        if(sub != NULL)
1371
0
            __Client_Subscription_deleteInternal(client, sub);
1372
0
        return;
1373
0
    }
1374
1375
0
    if(!LIST_FIRST(&client->subscriptions)) {
1376
0
        response->responseHeader.serviceResult = UA_STATUSCODE_BADNOSUBSCRIPTION;
1377
0
        return;
1378
0
    }
1379
1380
0
    UA_Client_Subscription *sub = findSubscriptionById(client, response->subscriptionId);
1381
0
    if(!sub) {
1382
0
        response->responseHeader.serviceResult = UA_STATUSCODE_BADINTERNALERROR;
1383
0
        UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
1384
0
                       "Received Publish Response for a non-existant subscription");
1385
0
        return;
1386
0
    }
1387
1388
0
    if(response->responseHeader.serviceResult == UA_STATUSCODE_BADSESSIONCLOSED) {
1389
0
        if(client->sessionState != UA_SESSIONSTATE_ACTIVATED) {
1390
0
            UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
1391
0
                           "Received Publish Response with code %s",
1392
0
                           UA_StatusCode_name(response->responseHeader.serviceResult));
1393
0
            __Client_Subscription_deleteInternal(client, sub);
1394
0
        }
1395
0
        return;
1396
0
    }
1397
1398
0
    if(response->responseHeader.serviceResult == UA_STATUSCODE_BADTIMEOUT) {
1399
0
        if(client->config.subscriptionInactivityCallback) {
1400
0
            void *subC = sub->context;
1401
0
            UA_UInt32 subId = sub->subscriptionId;
1402
0
            client->config.subscriptionInactivityCallback(client, subId, subC);
1403
0
        }
1404
0
        UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
1405
0
                       "Received Timeout for Publish Response");
1406
0
        return;
1407
0
    }
1408
1409
0
    if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD) {
1410
0
        UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
1411
0
                       "Received Publish Response with code %s",
1412
0
                       UA_StatusCode_name(response->responseHeader.serviceResult));
1413
0
        return;
1414
0
    }
1415
1416
0
    UA_EventLoop *el = client->config.eventLoop;
1417
0
    sub->lastActivity = el->dateTime_nowMonotonic(el);
1418
1419
    /* Detect missing message - OPC Unified Architecture, Part 4 5.13.1.1 e) */
1420
0
    if(__nextSequenceNumber(sub->sequenceNumber) != msg->sequenceNumber) {
1421
0
        UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
1422
0
                       "Invalid subscription sequence number: expected %" PRIu32
1423
0
                       " but got %" PRIu32, __nextSequenceNumber(sub->sequenceNumber),
1424
0
                       msg->sequenceNumber);
1425
        /* This is an error. But we do not abort the connection. Some server
1426
         * SDKs misbehave from time to time and send out-of-order sequence
1427
         * numbers. (Probably some multi-threading synchronization issue.) */
1428
        /* UA_Client_disconnect(client);
1429
           return; */
1430
0
    }
1431
    /* According to f), a keep-alive message contains no notifications and has
1432
     * the sequence number of the next NotificationMessage that is to be sent =>
1433
     * More than one consecutive keep-alive message or a NotificationMessage
1434
     * following a keep-alive message will share the same sequence number. */
1435
0
    if (msg->notificationDataSize)
1436
0
        sub->sequenceNumber = msg->sequenceNumber;
1437
1438
    /* Process the notification messages */
1439
0
    for(size_t k = 0; k < msg->notificationDataSize; ++k)
1440
0
        processNotificationMessage(client, sub, &msg->notificationData[k]);
1441
1442
    /* Add to the list of pending acks */
1443
0
    for(size_t i = 0; i < response->availableSequenceNumbersSize; i++) {
1444
0
        if(response->availableSequenceNumbers[i] != msg->sequenceNumber)
1445
0
            continue;
1446
0
        UA_Client_NotificationsAckNumber *tmpAck = (UA_Client_NotificationsAckNumber*)
1447
0
            UA_malloc(sizeof(UA_Client_NotificationsAckNumber));
1448
0
        if(!tmpAck) {
1449
0
            UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
1450
0
                           "Not enough memory to store the acknowledgement for a publish "
1451
0
                           "message on subscription %" PRIu32, sub->subscriptionId);
1452
0
            break;
1453
0
        }
1454
0
        tmpAck->subAck.sequenceNumber = msg->sequenceNumber;
1455
0
        tmpAck->subAck.subscriptionId = sub->subscriptionId;
1456
0
        LIST_INSERT_HEAD(&client->pendingNotificationsAcks, tmpAck, listEntry);
1457
0
        break;
1458
0
    }
1459
0
}
1460
1461
static void
1462
processPublishResponseAsync(UA_Client *client, void *userdata,
1463
0
                            UA_UInt32 requestId, void *response) {
1464
0
    UA_PublishRequest *req = (UA_PublishRequest*)userdata;
1465
0
    UA_PublishResponse *res = (UA_PublishResponse*)response;
1466
1467
0
    lockClient(client);
1468
1469
    /* Process the response */
1470
0
    __Client_Subscriptions_processPublishResponse(client, req, res);
1471
1472
    /* Delete the cached request */
1473
0
    UA_PublishRequest_delete(req);
1474
1475
    /* Fill up the outstanding publish requests */
1476
0
    __Client_Subscriptions_backgroundPublish(client);
1477
1478
0
    unlockClient(client);
1479
0
}
1480
1481
void
1482
0
__Client_Subscriptions_clear(UA_Client *client) {
1483
0
    UA_Client_NotificationsAckNumber *n;
1484
0
    UA_Client_NotificationsAckNumber *tmp;
1485
0
    LIST_FOREACH_SAFE(n, &client->pendingNotificationsAcks, listEntry, tmp) {
1486
0
        LIST_REMOVE(n, listEntry);
1487
0
        UA_free(n);
1488
0
    }
1489
1490
0
    UA_Client_Subscription *sub;
1491
0
    UA_Client_Subscription *tmps;
1492
0
    LIST_FOREACH_SAFE(sub, &client->subscriptions, listEntry, tmps)
1493
0
        __Client_Subscription_deleteInternal(client, sub); /* force local removal */
1494
1495
0
    client->monitoredItemHandles = 0;
1496
0
}
1497
1498
void
1499
0
__Client_Subscriptions_backgroundPublishInactivityCheck(UA_Client *client) {
1500
0
    UA_LOCK_ASSERT(&client->clientMutex);
1501
1502
0
    UA_EventLoop *el = client->config.eventLoop;
1503
0
    UA_DateTime nowm = el->dateTime_nowMonotonic(el);
1504
1505
0
    UA_Client_Subscription *sub;
1506
0
    LIST_FOREACH(sub, &client->subscriptions, listEntry) {
1507
0
        UA_DateTime maxSilence = (UA_DateTime)
1508
0
            ((sub->publishingInterval * sub->maxKeepAliveCount) +
1509
0
             client->config.timeout) * UA_DATETIME_MSEC;
1510
0
        if(maxSilence + sub->lastActivity < nowm) {
1511
            /* Reset activity */
1512
0
            sub->lastActivity = nowm;
1513
1514
0
            if(client->config.subscriptionInactivityCallback) {
1515
0
                void *subC = sub->context;
1516
0
                UA_UInt32 subId = sub->subscriptionId;
1517
0
                client->config.subscriptionInactivityCallback(client, subId, subC);
1518
0
            }
1519
0
            UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
1520
0
                           "Inactivity for Subscription %" PRIu32 ".", sub->subscriptionId);
1521
0
        }
1522
0
    }
1523
0
}
1524
1525
void
1526
0
__Client_Subscriptions_backgroundPublish(UA_Client *client) {
1527
0
    UA_LOCK_ASSERT(&client->clientMutex);
1528
1529
0
    if(client->sessionState != UA_SESSIONSTATE_ACTIVATED)
1530
0
        return;
1531
1532
    /* The session must have at least one subscription */
1533
0
    if(!LIST_FIRST(&client->subscriptions))
1534
0
        return;
1535
1536
0
    while(client->currentlyOutStandingPublishRequests < client->config.outStandingPublishRequests) {
1537
0
        UA_PublishRequest *request = UA_PublishRequest_new();
1538
0
        if(!request)
1539
0
            return;
1540
1541
        /* Publish requests are valid for 10 minutes */
1542
0
        request->requestHeader.timeoutHint = 10 * 60 * 1000;
1543
1544
0
        UA_StatusCode retval = __Client_preparePublishRequest(client, request);
1545
0
        if(retval != UA_STATUSCODE_GOOD) {
1546
0
            UA_PublishRequest_delete(request);
1547
0
            return;
1548
0
        }
1549
1550
0
        retval = __Client_AsyncService(client, request,
1551
0
                                         &UA_TYPES[UA_TYPES_PUBLISHREQUEST],
1552
0
                                         processPublishResponseAsync,
1553
0
                                         &UA_TYPES[UA_TYPES_PUBLISHRESPONSE],
1554
0
                                         (void*)request, NULL);
1555
0
        if(retval != UA_STATUSCODE_GOOD) {
1556
0
            UA_PublishRequest_delete(request);
1557
0
            return;
1558
0
        }
1559
1560
0
        client->currentlyOutStandingPublishRequests++;
1561
0
    }
1562
0
}
1563
1564
UA_SetPublishingModeResponse
1565
UA_Client_Subscriptions_setPublishingMode(UA_Client *client,
1566
0
                                          const UA_SetPublishingModeRequest request) {
1567
0
    UA_SetPublishingModeResponse response;
1568
0
    __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_SETPUBLISHINGMODEREQUEST],
1569
0
                        &response, &UA_TYPES[UA_TYPES_SETPUBLISHINGMODERESPONSE]);
1570
0
    return response;
1571
0
}
1572
1573
UA_SetMonitoringModeResponse
1574
UA_Client_MonitoredItems_setMonitoringMode(UA_Client *client,
1575
0
                                           const UA_SetMonitoringModeRequest request) {
1576
0
    UA_SetMonitoringModeResponse response;
1577
0
    __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_SETMONITORINGMODEREQUEST],
1578
0
                        &response, &UA_TYPES[UA_TYPES_SETMONITORINGMODERESPONSE]);
1579
0
    return response;
1580
0
}
1581
1582
UA_StatusCode
1583
UA_Client_MonitoredItems_setMonitoringMode_async(UA_Client *client,
1584
                                                 const UA_SetMonitoringModeRequest request,
1585
                                                 UA_ClientAsyncSetMonitoringModeCallback callback,
1586
0
                                                 void *userdata, UA_UInt32 *requestId) {
1587
0
    return __UA_Client_AsyncService(client, &request,
1588
0
                                    &UA_TYPES[UA_TYPES_SETMONITORINGMODEREQUEST],
1589
0
                                    (UA_ClientAsyncServiceCallback)callback,
1590
0
                                    &UA_TYPES[UA_TYPES_SETMONITORINGMODERESPONSE],
1591
0
                                    userdata, requestId);
1592
0
}
1593
1594
UA_SetTriggeringResponse
1595
UA_Client_MonitoredItems_setTriggering(UA_Client *client,
1596
0
                                       const UA_SetTriggeringRequest request) {
1597
0
    UA_SetTriggeringResponse response;
1598
0
    __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_SETTRIGGERINGREQUEST],
1599
0
                        &response, &UA_TYPES[UA_TYPES_SETTRIGGERINGRESPONSE]);
1600
0
    return response;
1601
0
}
1602
1603
UA_StatusCode
1604
UA_Client_MonitoredItems_setTriggering_async(UA_Client *client,
1605
                                             const UA_SetTriggeringRequest request,
1606
                                             UA_ClientAsyncSetTriggeringCallback callback,
1607
0
                                             void *userdata, UA_UInt32 *requestId) {
1608
0
    return __UA_Client_AsyncService(client, &request,
1609
0
                                    &UA_TYPES[UA_TYPES_SETTRIGGERINGREQUEST],
1610
0
                                    (UA_ClientAsyncServiceCallback)callback,
1611
0
                                    &UA_TYPES[UA_TYPES_SETTRIGGERINGRESPONSE],
1612
0
                                    userdata, requestId);
1613
0
}