Coverage Report

Created: 2024-02-16 06:13

/src/open62541/plugins/eventloop/posix/eventloop_posix.c
Line
Count
Source (jump to first uncovered line)
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 2021 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
6
 *    Copyright 2021 (c) Fraunhofer IOSB (Author: Jan Hermes)
7
 */
8
9
#include "eventloop_posix.h"
10
#include "open62541/plugin/eventloop.h"
11
12
#if defined(UA_ARCHITECTURE_POSIX) && !defined(__APPLE__) && !defined(__MACH__)
13
#include <time.h>
14
#endif
15
16
/*********/
17
/* Timer */
18
/*********/
19
20
static UA_DateTime
21
892
UA_EventLoopPOSIX_nextCyclicTime(UA_EventLoop *public_el) {
22
892
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)public_el;
23
892
    return UA_Timer_nextRepeatedTime(&el->timer);
24
892
}
25
26
static UA_StatusCode
27
UA_EventLoopPOSIX_addTimedCallback(UA_EventLoop *public_el,
28
                                   UA_Callback callback,
29
                                   void *application, void *data,
30
                                   UA_DateTime date,
31
0
                                   UA_UInt64 *callbackId) {
32
0
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)public_el;
33
0
    return UA_Timer_addTimedCallback(&el->timer, callback, application,
34
0
                                     data, date, callbackId);
35
0
}
36
37
static UA_StatusCode
38
UA_EventLoopPOSIX_addCyclicCallback(UA_EventLoop *public_el,
39
                                    UA_Callback cb,
40
                                    void *application, void *data,
41
                                    UA_Double interval_ms,
42
                                    UA_DateTime *baseTime,
43
                                    UA_TimerPolicy timerPolicy,
44
1.00k
                                    UA_UInt64 *callbackId) {
45
1.00k
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)public_el;
46
1.00k
    return UA_Timer_addRepeatedCallback(&el->timer, cb, application,
47
1.00k
                                        data, interval_ms,
48
1.00k
                                        public_el->dateTime_nowMonotonic(public_el),
49
1.00k
                                        baseTime, timerPolicy, callbackId);
50
1.00k
}
51
52
static UA_StatusCode
53
UA_EventLoopPOSIX_modifyCyclicCallback(UA_EventLoop *public_el,
54
                                       UA_UInt64 callbackId,
55
                                       UA_Double interval_ms,
56
                                       UA_DateTime *baseTime,
57
0
                                       UA_TimerPolicy timerPolicy) {
58
0
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)public_el;
59
0
    return UA_Timer_changeRepeatedCallback(&el->timer, callbackId, interval_ms,
60
0
                                           public_el->dateTime_nowMonotonic(public_el),
61
0
                                           baseTime, timerPolicy);
62
0
}
63
64
static void
65
UA_EventLoopPOSIX_removeCyclicCallback(UA_EventLoop *public_el,
66
1.00k
                                       UA_UInt64 callbackId) {
67
1.00k
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)public_el;
68
1.00k
    UA_Timer_removeCallback(&el->timer, callbackId);
69
1.00k
}
70
71
static void
72
UA_EventLoopPOSIX_addDelayedCallback(UA_EventLoop *public_el,
73
675
                                     UA_DelayedCallback *dc) {
74
675
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)public_el;
75
675
    UA_LOCK(&el->elMutex);
76
675
    dc->next = el->delayedCallbacks;
77
675
    el->delayedCallbacks = dc;
78
675
    UA_UNLOCK(&el->elMutex);
79
675
}
80
81
static void
82
UA_EventLoopPOSIX_removeDelayedCallback(UA_EventLoop *public_el,
83
0
                                     UA_DelayedCallback *dc) {
84
0
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)public_el;
85
0
    UA_LOCK(&el->elMutex);
86
0
    UA_DelayedCallback **prev = &el->delayedCallbacks;
87
0
    while(*prev) {
88
0
        if(*prev == dc) {
89
0
            *prev = (*prev)->next;
90
0
            UA_UNLOCK(&el->elMutex);
91
0
            return;
92
0
        }
93
0
        prev = &(*prev)->next;
94
0
    }
95
0
    UA_UNLOCK(&el->elMutex);
96
0
}
97
98
/* Process and then free registered delayed callbacks */
99
static void
100
2.33k
processDelayed(UA_EventLoopPOSIX *el) {
101
2.33k
    UA_LOG_TRACE(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
102
2.33k
                 "Process delayed callbacks");
103
104
2.33k
    UA_LOCK_ASSERT(&el->elMutex, 1);
105
106
    /* First empty the linked list in the el. So a delayed callback can add
107
     * (itself) to the list. New entries are then processed during the next
108
     * iteration. */
109
2.33k
    UA_DelayedCallback *dc = el->delayedCallbacks, *next = NULL;
110
2.33k
    el->delayedCallbacks = NULL;
111
112
4.40k
    for(; dc; dc = next) {
113
2.06k
        next = dc->next;
114
        /* Delayed Callbacks might have no callback set. We don't return a
115
         * StatusCode during "add" and don't validate. So test here. */
116
2.06k
        if(!dc->callback)
117
0
            continue;
118
2.06k
        UA_UNLOCK(&el->elMutex);
119
2.06k
        dc->callback(dc->application, dc->context);
120
2.06k
        UA_LOCK(&el->elMutex);
121
2.06k
    }
122
2.33k
}
123
124
/***********************/
125
/* EventLoop Lifecycle */
126
/***********************/
127
128
static UA_StatusCode
129
712
UA_EventLoopPOSIX_start(UA_EventLoopPOSIX *el) {
130
712
    UA_LOCK(&el->elMutex);
131
132
712
    if(el->eventLoop.state != UA_EVENTLOOPSTATE_FRESH &&
133
712
       el->eventLoop.state != UA_EVENTLOOPSTATE_STOPPED) {
134
0
        UA_UNLOCK(&el->elMutex);
135
0
        return UA_STATUSCODE_BADINTERNALERROR;
136
0
    }
137
138
712
    UA_LOG_INFO(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
139
712
                "Starting the EventLoop");
140
141
    /* Setting the clock source */
142
712
    const UA_Int32 *cs = (const UA_Int32*)
143
712
        UA_KeyValueMap_getScalar(&el->eventLoop.params,
144
712
                                 UA_QUALIFIEDNAME(0, "clock-source"),
145
712
                                 &UA_TYPES[UA_TYPES_INT32]);
146
712
    const UA_Int32 *csm = (const UA_Int32*)
147
712
        UA_KeyValueMap_getScalar(&el->eventLoop.params,
148
712
                                 UA_QUALIFIEDNAME(0, "clock-source-monotonic"),
149
712
                                 &UA_TYPES[UA_TYPES_INT32]);
150
712
#if defined(UA_ARCHITECTURE_POSIX) && !defined(__APPLE__) && !defined(__MACH__)
151
712
    el->clockSource = CLOCK_REALTIME;
152
712
    if(cs)
153
0
        el->clockSource = *cs;
154
155
712
# ifdef CLOCK_MONOTONIC_RAW
156
712
    el->clockSourceMonotonic = CLOCK_MONOTONIC_RAW;
157
# else
158
    el->clockSourceMonotonic = CLOCK_MONOTONIC;
159
# endif
160
712
    if(csm)
161
0
        el->clockSourceMonotonic = *csm;
162
#else
163
    if(cs || csm) {
164
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
165
                       "Eventloop\t| Cannot set a custom clock source");
166
    }
167
#endif
168
169
712
#ifdef UA_HAVE_EPOLL
170
712
    el->epollfd = epoll_create1(0);
171
712
    if(el->epollfd == -1) {
172
0
        UA_LOG_SOCKET_ERRNO_WRAP(
173
0
           UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
174
0
                          "Eventloop\t| Could not create the epoll socket (%s)",
175
0
                          errno_str));
176
0
        UA_UNLOCK(&el->elMutex);
177
0
        return UA_STATUSCODE_BADINTERNALERROR;
178
0
    }
179
712
#endif
180
181
712
    UA_StatusCode res = UA_STATUSCODE_GOOD;
182
712
    UA_EventSource *es = el->eventLoop.eventSources;
183
3.52k
    while(es) {
184
2.81k
        UA_UNLOCK(&el->elMutex);
185
2.81k
        res |= es->start(es);
186
2.81k
        UA_LOCK(&el->elMutex);
187
2.81k
        es = es->next;
188
2.81k
    }
189
190
    /* Dirty-write the state that is const "from the outside" */
191
712
    *(UA_EventLoopState*)(uintptr_t)&el->eventLoop.state =
192
712
        UA_EVENTLOOPSTATE_STARTED;
193
194
712
    UA_UNLOCK(&el->elMutex);
195
712
    return res;
196
712
}
197
198
static void
199
1.13k
checkClosed(UA_EventLoopPOSIX *el) {
200
1.13k
    UA_LOCK_ASSERT(&el->elMutex, 1);
201
202
1.13k
    UA_EventSource *es = el->eventLoop.eventSources;
203
5.64k
    while(es) {
204
4.51k
        if(es->state != UA_EVENTSOURCESTATE_STOPPED)
205
0
            return;
206
4.51k
        es = es->next;
207
4.51k
    }
208
209
    /* Not closed until all delayed callbacks are processed */
210
1.13k
    if(el->delayedCallbacks != NULL)
211
424
        return;
212
213
    /* Dirty-write the state that is const "from the outside" */
214
712
    *(UA_EventLoopState*)(uintptr_t)&el->eventLoop.state =
215
712
        UA_EVENTLOOPSTATE_STOPPED;
216
217
    /* Close the epoll/IOCP socket once all EventSources have shut down */
218
712
#ifdef UA_HAVE_EPOLL
219
712
    close(el->epollfd);
220
712
#endif
221
222
712
    UA_LOG_INFO(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
223
712
                "The EventLoop has stopped");
224
712
}
225
226
static void
227
712
UA_EventLoopPOSIX_stop(UA_EventLoopPOSIX *el) {
228
712
    UA_LOCK(&el->elMutex);
229
230
712
    if(el->eventLoop.state != UA_EVENTLOOPSTATE_STARTED) {
231
0
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
232
0
                       "The EventLoop is not running, cannot be stopped");
233
0
        UA_UNLOCK(&el->elMutex);
234
0
        return;
235
0
    }
236
237
712
    UA_LOG_INFO(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
238
712
                "Stopping the EventLoop");
239
240
    /* Set to STOPPING to prevent "normal use" */
241
712
    *(UA_EventLoopState*)(uintptr_t)&el->eventLoop.state =
242
712
        UA_EVENTLOOPSTATE_STOPPING;
243
244
    /* Stop all event sources (asynchronous) */
245
712
    UA_EventSource *es = el->eventLoop.eventSources;
246
3.52k
    for(; es; es = es->next) {
247
2.81k
        if(es->state == UA_EVENTSOURCESTATE_STARTING ||
248
2.81k
           es->state == UA_EVENTSOURCESTATE_STARTED) {
249
2.77k
            UA_UNLOCK(&el->elMutex);
250
2.77k
            es->stop(es);
251
2.77k
            UA_LOCK(&el->elMutex);
252
2.77k
        }
253
2.81k
    }
254
255
    /* Set to STOPPED if all EventSources are STOPPED */
256
712
    checkClosed(el);
257
258
712
    UA_UNLOCK(&el->elMutex);
259
712
}
260
261
static UA_StatusCode
262
1.62k
UA_EventLoopPOSIX_run(UA_EventLoopPOSIX *el, UA_UInt32 timeout) {
263
1.62k
    UA_LOCK(&el->elMutex);
264
265
1.62k
    if(el->executing) {
266
0
        UA_LOG_ERROR(el->eventLoop.logger,
267
0
                     UA_LOGCATEGORY_EVENTLOOP,
268
0
                     "Cannot run EventLoop from the run method itself");
269
0
        UA_UNLOCK(&el->elMutex);
270
0
        return UA_STATUSCODE_BADINTERNALERROR;
271
0
    }
272
273
1.62k
    el->executing = true;
274
275
1.62k
    if(el->eventLoop.state == UA_EVENTLOOPSTATE_FRESH ||
276
1.62k
       el->eventLoop.state == UA_EVENTLOOPSTATE_STOPPED) {
277
0
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
278
0
                       "Cannot iterate a stopped EventLoop");
279
0
        el->executing = false;
280
0
        UA_UNLOCK(&el->elMutex);
281
0
        return UA_STATUSCODE_BADINTERNALERROR;
282
0
    }
283
284
1.62k
    UA_LOG_TRACE(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
285
1.62k
                 "Iterate the EventLoop");
286
287
    /* Process cyclic callbacks */
288
1.62k
    UA_DateTime dateBefore =
289
1.62k
        el->eventLoop.dateTime_nowMonotonic(&el->eventLoop);
290
291
1.62k
    UA_UNLOCK(&el->elMutex);
292
1.62k
    UA_DateTime dateNext = UA_Timer_process(&el->timer, dateBefore);
293
1.62k
    UA_LOCK(&el->elMutex);
294
295
    /* Process delayed callbacks here:
296
     * - Removes closed sockets already here instead of polling them again.
297
     * - The timeout for polling is selected to be ready in time for the next
298
     *   cyclic callback. So we want to do little work between the timeout
299
     *   running out and executing the due cyclic callbacks. */
300
1.62k
    processDelayed(el);
301
302
    /* A delayed callback could create another delayed callback (or re-add
303
     * itself). In that case we don't want to wait (indefinitely) for an event
304
     * to happen. Process queued events but don't sleep. Then process the
305
     * delayed callbacks in the next iteration. */
306
1.62k
    if(el->delayedCallbacks != NULL)
307
0
        timeout = 0;
308
309
    /* Compute the remaining time */
310
1.62k
    UA_DateTime maxDate = dateBefore + (timeout * UA_DATETIME_MSEC);
311
1.62k
    if(dateNext > maxDate)
312
1.47k
        dateNext = maxDate;
313
1.62k
    UA_DateTime listenTimeout =
314
1.62k
        dateNext - el->eventLoop.dateTime_nowMonotonic(&el->eventLoop);
315
1.62k
    if(listenTimeout < 0)
316
618
        listenTimeout = 0;
317
318
    /* Listen on the active file-descriptors (sockets) from the
319
     * ConnectionManagers */
320
1.62k
    UA_StatusCode rv = UA_EventLoopPOSIX_pollFDs(el, listenTimeout);
321
322
    /* Check if the last EventSource was successfully stopped */
323
1.62k
    if(el->eventLoop.state == UA_EVENTLOOPSTATE_STOPPING)
324
424
        checkClosed(el);
325
326
1.62k
    el->executing = false;
327
1.62k
    UA_UNLOCK(&el->elMutex);
328
1.62k
    return rv;
329
1.62k
}
330
331
/*****************************/
332
/* Registering Event Sources */
333
/*****************************/
334
335
static UA_StatusCode
336
UA_EventLoopPOSIX_registerEventSource(UA_EventLoopPOSIX *el,
337
2.81k
                                      UA_EventSource *es) {
338
2.81k
    UA_LOCK(&el->elMutex);
339
340
    /* Already registered? */
341
2.81k
    if(es->state != UA_EVENTSOURCESTATE_FRESH) {
342
0
        UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
343
0
                     "Cannot register the EventSource \"%.*s\": "
344
0
                     "already registered",
345
0
                     (int)es->name.length, (char*)es->name.data);
346
0
        UA_UNLOCK(&el->elMutex);
347
0
        return UA_STATUSCODE_BADINTERNALERROR;
348
0
    }
349
350
    /* Add to linked list */
351
2.81k
    es->next = el->eventLoop.eventSources;
352
2.81k
    el->eventLoop.eventSources = es;
353
354
2.81k
    es->eventLoop = &el->eventLoop;
355
2.81k
    es->state = UA_EVENTSOURCESTATE_STOPPED;
356
357
    /* Start if the entire EventLoop is started */
358
2.81k
    UA_StatusCode res = UA_STATUSCODE_GOOD;
359
2.81k
    if(el->eventLoop.state == UA_EVENTLOOPSTATE_STARTED)
360
0
        res = es->start(es);
361
362
2.81k
    UA_UNLOCK(&el->elMutex);
363
2.81k
    return res;
364
2.81k
}
365
366
static UA_StatusCode
367
UA_EventLoopPOSIX_deregisterEventSource(UA_EventLoopPOSIX *el,
368
2.81k
                                        UA_EventSource *es) {
369
2.81k
    UA_LOCK(&el->elMutex);
370
371
2.81k
    if(es->state != UA_EVENTSOURCESTATE_STOPPED) {
372
0
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
373
0
                       "Cannot deregister the EventSource %.*s: "
374
0
                       "Has to be stopped first",
375
0
                       (int)es->name.length, es->name.data);
376
0
        UA_UNLOCK(&el->elMutex);
377
0
        return UA_STATUSCODE_BADINTERNALERROR;
378
0
    }
379
380
    /* Remove from the linked list */
381
2.81k
    UA_EventSource **s = &el->eventLoop.eventSources;
382
2.81k
    while(*s) {
383
2.81k
        if(*s == es) {
384
2.81k
            *s = es->next;
385
2.81k
            break;
386
2.81k
        }
387
0
        s = &(*s)->next;
388
0
    }
389
390
    /* Set the state to non-registered */
391
2.81k
    es->state = UA_EVENTSOURCESTATE_FRESH;
392
393
2.81k
    UA_UNLOCK(&el->elMutex);
394
2.81k
    return UA_STATUSCODE_GOOD;
395
2.81k
}
396
397
/***************/
398
/* Time Domain */
399
/***************/
400
401
static UA_DateTime
402
472k
UA_EventLoopPOSIX_DateTime_now(UA_EventLoop *el) {
403
472k
#if defined(UA_ARCHITECTURE_POSIX) && !defined(__APPLE__) && !defined(__MACH__)
404
472k
    UA_EventLoopPOSIX *pel = (UA_EventLoopPOSIX*)el;
405
472k
    struct timespec ts;
406
472k
    int res = clock_gettime(pel->clockSource, &ts);
407
472k
    if(UA_UNLIKELY(res != 0))
408
0
        return 0;
409
472k
    return (ts.tv_sec * UA_DATETIME_SEC) + (ts.tv_nsec / 100) + UA_DATETIME_UNIX_EPOCH;
410
#else
411
    return UA_DateTime_now();
412
#endif
413
472k
}
414
415
static UA_DateTime
416
5.61k
UA_EventLoopPOSIX_DateTime_nowMonotonic(UA_EventLoop *el) {
417
5.61k
#if defined(UA_ARCHITECTURE_POSIX) && !defined(__APPLE__) && !defined(__MACH__)
418
5.61k
    UA_EventLoopPOSIX *pel = (UA_EventLoopPOSIX*)el;
419
5.61k
    struct timespec ts;
420
5.61k
    int res = clock_gettime(pel->clockSourceMonotonic, &ts);
421
5.61k
    if(UA_UNLIKELY(res != 0))
422
0
        return 0;
423
    /* Also add the unix epoch for the monotonic clock. So we get a "normal"
424
     * output when a "normal" source is configured. */
425
5.61k
    return (ts.tv_sec * UA_DATETIME_SEC) + (ts.tv_nsec / 100) + UA_DATETIME_UNIX_EPOCH;
426
#else
427
    return UA_DateTime_nowMonotonic();
428
#endif
429
5.61k
}
430
431
static UA_Int64
432
0
UA_EventLoopPOSIX_DateTime_localTimeUtcOffset(UA_EventLoop *el) {
433
    /* TODO: Fix for custom clock sources */
434
0
    return UA_DateTime_localTimeUtcOffset();
435
0
}
436
437
/*************************/
438
/* Initialize and Delete */
439
/*************************/
440
441
static UA_StatusCode
442
712
UA_EventLoopPOSIX_free(UA_EventLoopPOSIX *el) {
443
712
    UA_LOCK(&el->elMutex);
444
445
    /* Check if the EventLoop can be deleted */
446
712
    if(el->eventLoop.state != UA_EVENTLOOPSTATE_STOPPED &&
447
712
       el->eventLoop.state != UA_EVENTLOOPSTATE_FRESH) {
448
0
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
449
0
                       "Cannot delete a running EventLoop");
450
0
        UA_UNLOCK(&el->elMutex);
451
0
        return UA_STATUSCODE_BADINTERNALERROR;
452
0
    }
453
454
    /* Deregister and delete all the EventSources */
455
3.52k
    while(el->eventLoop.eventSources) {
456
2.81k
        UA_EventSource *es = el->eventLoop.eventSources;
457
2.81k
        UA_UNLOCK(&el->elMutex);
458
2.81k
        UA_EventLoopPOSIX_deregisterEventSource(el, es);
459
2.81k
        UA_LOCK(&el->elMutex);
460
2.81k
        es->free(es);
461
2.81k
    }
462
463
    /* Remove the repeated timed callbacks */
464
712
    UA_Timer_clear(&el->timer);
465
466
    /* Process remaining delayed callbacks */
467
712
    processDelayed(el);
468
469
#ifdef _WIN32
470
    /* Stop the Windows networking subsystem */
471
    WSACleanup();
472
#endif
473
474
712
    UA_KeyValueMap_clear(&el->eventLoop.params);
475
476
    /* Clean up */
477
712
    UA_UNLOCK(&el->elMutex);
478
712
    UA_LOCK_DESTROY(&el->elMutex);
479
712
    UA_free(el);
480
712
    return UA_STATUSCODE_GOOD;
481
712
}
482
483
UA_EventLoop *
484
713
UA_EventLoop_new_POSIX(const UA_Logger *logger) {
485
713
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)
486
713
        UA_calloc(1, sizeof(UA_EventLoopPOSIX));
487
713
    if(!el)
488
1
        return NULL;
489
490
712
    UA_LOCK_INIT(&el->elMutex);
491
712
    UA_Timer_init(&el->timer);
492
493
#ifdef _WIN32
494
    /* Start the WSA networking subsystem on Windows */
495
    WSADATA wsaData;
496
    WSAStartup(MAKEWORD(2, 2), &wsaData);
497
#endif
498
499
    /* Set the public EventLoop content */
500
712
    el->eventLoop.logger = logger;
501
502
712
    el->eventLoop.start = (UA_StatusCode (*)(UA_EventLoop*))UA_EventLoopPOSIX_start;
503
712
    el->eventLoop.stop = (void (*)(UA_EventLoop*))UA_EventLoopPOSIX_stop;
504
712
    el->eventLoop.run = (UA_StatusCode (*)(UA_EventLoop*, UA_UInt32))UA_EventLoopPOSIX_run;
505
712
    el->eventLoop.free = (UA_StatusCode (*)(UA_EventLoop*))UA_EventLoopPOSIX_free;
506
507
712
    el->eventLoop.dateTime_now = UA_EventLoopPOSIX_DateTime_now;
508
712
    el->eventLoop.dateTime_nowMonotonic =
509
712
        UA_EventLoopPOSIX_DateTime_nowMonotonic;
510
712
    el->eventLoop.dateTime_localTimeUtcOffset =
511
712
        UA_EventLoopPOSIX_DateTime_localTimeUtcOffset;
512
513
712
    el->eventLoop.nextCyclicTime = UA_EventLoopPOSIX_nextCyclicTime;
514
712
    el->eventLoop.addCyclicCallback = UA_EventLoopPOSIX_addCyclicCallback;
515
712
    el->eventLoop.modifyCyclicCallback = UA_EventLoopPOSIX_modifyCyclicCallback;
516
712
    el->eventLoop.removeCyclicCallback = UA_EventLoopPOSIX_removeCyclicCallback;
517
712
    el->eventLoop.addTimedCallback = UA_EventLoopPOSIX_addTimedCallback;
518
712
    el->eventLoop.addDelayedCallback = UA_EventLoopPOSIX_addDelayedCallback;
519
712
    el->eventLoop.removeDelayedCallback = UA_EventLoopPOSIX_removeDelayedCallback;
520
521
712
    el->eventLoop.registerEventSource =
522
712
        (UA_StatusCode (*)(UA_EventLoop*, UA_EventSource*))
523
712
        UA_EventLoopPOSIX_registerEventSource;
524
712
    el->eventLoop.deregisterEventSource =
525
712
        (UA_StatusCode (*)(UA_EventLoop*, UA_EventSource*))
526
712
        UA_EventLoopPOSIX_deregisterEventSource;
527
528
712
    return &el->eventLoop;
529
713
}
530
531
/* Reusable EventSource functionality */
532
533
UA_StatusCode
534
UA_EventLoopPOSIX_allocNetworkBuffer(UA_ConnectionManager *cm,
535
                                     uintptr_t connectionId,
536
                                     UA_ByteString *buf,
537
60
                                     size_t bufSize) {
538
60
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)cm;
539
60
    if(pcm->txBuffer.length == 0)
540
60
        return UA_ByteString_allocBuffer(buf, bufSize);
541
0
    if(pcm->txBuffer.length < bufSize)
542
0
        return UA_STATUSCODE_BADOUTOFMEMORY;
543
0
    *buf = pcm->txBuffer;
544
0
    buf->length = bufSize;
545
0
    return UA_STATUSCODE_GOOD;
546
0
}
547
548
void
549
UA_EventLoopPOSIX_freeNetworkBuffer(UA_ConnectionManager *cm,
550
                                    uintptr_t connectionId,
551
60
                                    UA_ByteString *buf) {
552
60
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)cm;
553
60
    if(pcm->txBuffer.data == buf->data)
554
0
        UA_ByteString_init(buf);
555
60
    else
556
60
        UA_ByteString_clear(buf);
557
60
}
558
559
UA_StatusCode
560
2.11k
UA_EventLoopPOSIX_allocateStaticBuffers(UA_POSIXConnectionManager *pcm) {
561
2.11k
    UA_StatusCode res = UA_STATUSCODE_GOOD;
562
2.11k
    UA_UInt32 rxBufSize = 2u << 16; /* The default is 64kb */
563
2.11k
    const UA_UInt32 *configRxBufSize = (const UA_UInt32 *)
564
2.11k
        UA_KeyValueMap_getScalar(&pcm->cm.eventSource.params,
565
2.11k
                                 UA_QUALIFIEDNAME(0, "recv-bufsize"),
566
2.11k
                                 &UA_TYPES[UA_TYPES_UINT32]);
567
2.11k
    if(configRxBufSize)
568
0
        rxBufSize = *configRxBufSize;
569
2.11k
    if(pcm->rxBuffer.length != rxBufSize) {
570
2.11k
        UA_ByteString_clear(&pcm->rxBuffer);
571
2.11k
        res = UA_ByteString_allocBuffer(&pcm->rxBuffer, rxBufSize);
572
2.11k
    }
573
574
2.11k
    const UA_UInt32 *txBufSize = (const UA_UInt32 *)
575
2.11k
        UA_KeyValueMap_getScalar(&pcm->cm.eventSource.params,
576
2.11k
                                 UA_QUALIFIEDNAME(0, "send-bufsize"),
577
2.11k
                                 &UA_TYPES[UA_TYPES_UINT32]);
578
2.11k
    if(txBufSize && pcm->txBuffer.length != *txBufSize) {
579
0
        UA_ByteString_clear(&pcm->txBuffer);
580
0
        res |= UA_ByteString_allocBuffer(&pcm->txBuffer, *txBufSize);
581
0
    }
582
2.11k
    return res;
583
2.11k
}
584
585
/* Socket Handling */
586
587
enum ZIP_CMP
588
4.23k
cmpFD(const UA_FD *a, const UA_FD *b) {
589
4.23k
    if(*a == *b)
590
1.34k
        return ZIP_CMP_EQ;
591
2.89k
    return (*a < *b) ? ZIP_CMP_LESS : ZIP_CMP_MORE;
592
4.23k
}
593
594
UA_StatusCode
595
1.25k
UA_EventLoopPOSIX_setNonBlocking(UA_FD sockfd) {
596
1.25k
#ifndef _WIN32
597
1.25k
    int opts = fcntl(sockfd, F_GETFL);
598
1.25k
    if(opts < 0 || fcntl(sockfd, F_SETFL, opts | O_NONBLOCK) < 0)
599
0
        return UA_STATUSCODE_BADINTERNALERROR;
600
#else
601
    u_long iMode = 1;
602
    if(ioctlsocket(sockfd, FIONBIO, &iMode) != NO_ERROR)
603
        return UA_STATUSCODE_BADINTERNALERROR;
604
#endif
605
1.25k
    return UA_STATUSCODE_GOOD;
606
1.25k
}
607
608
UA_StatusCode
609
1.39k
UA_EventLoopPOSIX_setNoSigPipe(UA_FD sockfd) {
610
#ifdef SO_NOSIGPIPE
611
    int val = 1;
612
    int res = UA_setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, &val, sizeof(val));
613
    if(res < 0)
614
        return UA_STATUSCODE_BADINTERNALERROR;
615
#endif
616
1.39k
    return UA_STATUSCODE_GOOD;
617
1.39k
}
618
619
UA_StatusCode
620
0
UA_EventLoopPOSIX_setReusable(UA_FD sockfd) {
621
0
    int enableReuseVal = 1;
622
0
    int res = UA_setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
623
0
                            (const char*)&enableReuseVal, sizeof(enableReuseVal));
624
0
    return (res == 0) ? UA_STATUSCODE_GOOD : UA_STATUSCODE_BADINTERNALERROR;
625
0
}