Coverage Report

Created: 2026-02-14 06:32

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/open62541/arch/posix/eventloop_posix_udp.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 2021-2022 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
6
 *    Copyright 2021 (c) Fraunhofer IOSB (Author: Jan Hermes)
7
 */
8
9
#include "eventloop_posix.h"
10
11
#if defined(UA_ARCHITECTURE_POSIX) && !defined(UA_ARCHITECTURE_LWIP) || defined(UA_ARCHITECTURE_WIN32)
12
13
568
#define IPV4_PREFIX_MASK 0xF0
14
568
#define IPV4_MULTICAST_PREFIX 0xE0
15
#if UA_IPV6
16
0
# define IPV6_PREFIX_MASK 0xFF
17
0
# define IPV6_MULTICAST_PREFIX 0xFF
18
#endif
19
20
/* Configuration parameters */
21
22
547
#define UDP_MANAGERPARAMS 2
23
24
static UA_KeyValueRestriction udpManagerParams[UDP_MANAGERPARAMS] = {
25
    {{0, UA_STRING_STATIC("recv-bufsize")}, &UA_TYPES[UA_TYPES_UINT32], false, true, false},
26
    {{0, UA_STRING_STATIC("send-bufsize")}, &UA_TYPES[UA_TYPES_UINT32], false, true, false}
27
};
28
29
568
#define UDP_PARAMETERSSIZE 9
30
568
#define UDP_PARAMINDEX_LISTEN 0
31
568
#define UDP_PARAMINDEX_ADDR 1
32
568
#define UDP_PARAMINDEX_PORT 2
33
568
#define UDP_PARAMINDEX_INTERFACE 3
34
568
#define UDP_PARAMINDEX_TTL 4
35
568
#define UDP_PARAMINDEX_LOOPBACK 5
36
568
#define UDP_PARAMINDEX_REUSE 6
37
568
#define UDP_PARAMINDEX_SOCKPRIO 7
38
568
#define UDP_PARAMINDEX_VALIDATE 8
39
40
static UA_KeyValueRestriction udpConnectionParams[UDP_PARAMETERSSIZE] = {
41
    {{0, UA_STRING_STATIC("listen")}, &UA_TYPES[UA_TYPES_BOOLEAN], false, true, false},
42
    {{0, UA_STRING_STATIC("address")}, &UA_TYPES[UA_TYPES_STRING], false, true, true},
43
    {{0, UA_STRING_STATIC("port")}, &UA_TYPES[UA_TYPES_UINT16], true, true, false},
44
    {{0, UA_STRING_STATIC("interface")}, &UA_TYPES[UA_TYPES_STRING], false, true, false},
45
    {{0, UA_STRING_STATIC("ttl")}, &UA_TYPES[UA_TYPES_UINT32], false, true, false},
46
    {{0, UA_STRING_STATIC("loopback")}, &UA_TYPES[UA_TYPES_BOOLEAN], false, true, false},
47
    {{0, UA_STRING_STATIC("reuse")}, &UA_TYPES[UA_TYPES_BOOLEAN], false, true, false},
48
    {{0, UA_STRING_STATIC("sockpriority")}, &UA_TYPES[UA_TYPES_UINT32], false, true, false},
49
    {{0, UA_STRING_STATIC("validate")}, &UA_TYPES[UA_TYPES_BOOLEAN], false, true, false}
50
};
51
52
/* A registered file descriptor with an additional method pointer */
53
typedef struct {
54
    UA_RegisteredFD rfd;
55
56
    UA_ConnectionManager_connectionCallback applicationCB;
57
    void *application;
58
    void *context;
59
60
    struct sockaddr_storage sendAddr;
61
#ifdef UA_ARCHITECTURE_WIN32
62
    size_t sendAddrLength;
63
#else
64
    socklen_t sendAddrLength;
65
#endif
66
} UDP_FD;
67
68
typedef enum {
69
    MULTICASTTYPE_NONE = 0,
70
    MULTICASTTYPE_IPV4,
71
    MULTICASTTYPE_IPV6
72
} MultiCastType;
73
74
typedef union {
75
#if !defined(ip_mreqn)
76
    struct ip_mreq ipv4;
77
#else
78
    struct ip_mreqn ipv4;
79
#endif
80
#if UA_IPV6
81
    struct ipv6_mreq ipv6;
82
#endif
83
} MulticastRequest;
84
85
static UA_Boolean
86
568
isMulticastAddress(const UA_Byte *address, UA_Byte mask, UA_Byte prefix) {
87
568
    return (address[0] & mask) == prefix;
88
568
}
89
90
static MultiCastType
91
568
multiCastType(struct addrinfo *info) {
92
568
    const UA_Byte *address;
93
568
    if(info->ai_family == AF_INET) {
94
568
        address = (UA_Byte *)&((struct sockaddr_in *)info->ai_addr)->sin_addr;
95
568
        if(isMulticastAddress(address, IPV4_PREFIX_MASK, IPV4_MULTICAST_PREFIX))
96
568
            return MULTICASTTYPE_IPV4;
97
568
#if UA_IPV6
98
568
    } else if(info->ai_family == AF_INET6) {
99
0
        address = (UA_Byte *)&((struct sockaddr_in6 *)info->ai_addr)->sin6_addr;
100
0
        if(isMulticastAddress(address, IPV6_PREFIX_MASK, IPV6_MULTICAST_PREFIX))
101
0
            return MULTICASTTYPE_IPV6;
102
0
#endif
103
0
    }
104
0
    return MULTICASTTYPE_NONE;
105
568
}
106
107
#ifdef UA_ARCHITECTURE_WIN32
108
109
#define ADDR_BUFFER_SIZE 15000 /* recommended size in the MSVC docs */
110
111
static UA_StatusCode
112
setMulticastInterface(const char *netif, struct addrinfo *info,
113
                      MulticastRequest *req, const UA_Logger *logger) {
114
    ULONG outBufLen = ADDR_BUFFER_SIZE;
115
    UA_STACKARRAY(char, addrBuf, ADDR_BUFFER_SIZE);
116
117
    /* Get the network interface descriptions */
118
    ULONG flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST |
119
        GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME;
120
    PIP_ADAPTER_ADDRESSES ifaddr = (IP_ADAPTER_ADDRESSES *)addrBuf;
121
    DWORD ret = GetAdaptersAddresses(info->ai_family, flags, NULL, ifaddr, &outBufLen);
122
    if(ret != NO_ERROR) {
123
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SERVER,
124
                     "UDP\t| Interface configuration preparation failed");
125
        return UA_STATUSCODE_BADINTERNALERROR;
126
    }
127
128
    /* Iterate through linked list of network interfaces */
129
    char sourceAddr[64];
130
    unsigned int idx = 0;
131
    for(PIP_ADAPTER_ADDRESSES ifa = ifaddr; ifa != NULL; ifa = ifa->Next) {
132
        idx = (info->ai_family == AF_INET) ? ifa->IfIndex : ifa->Ipv6IfIndex;
133
134
        /* Check if network interface name matches */
135
        if(strcmp(ifa->AdapterName, netif) == 0)
136
            goto done;
137
138
        /* Check if ip address matches */
139
        for(PIP_ADAPTER_UNICAST_ADDRESS u = ifa->FirstUnicastAddress; u; u = u->Next) {
140
            LPSOCKADDR addr = u->Address.lpSockaddr;
141
            if(addr->sa_family == AF_INET) {
142
                inet_ntop(AF_INET, &((struct sockaddr_in*)addr)->sin_addr,
143
                          sourceAddr, sizeof(sourceAddr));
144
            } else if(addr->sa_family == AF_INET6) {
145
                inet_ntop(AF_INET6, &((struct sockaddr_in6*)addr)->sin6_addr,
146
                          sourceAddr, sizeof(sourceAddr));
147
            } else {
148
                continue;
149
            }
150
            if(strcmp(sourceAddr, netif) == 0)
151
                goto done;
152
        }
153
    }
154
155
    /* Not matching interface found */
156
    UA_LOG_ERROR(logger, UA_LOGCATEGORY_SERVER,
157
                 "UDP\t| Interface configuration preparation failed "
158
                 "(interface %s not found)", netif);
159
    return UA_STATUSCODE_BADINTERNALERROR;
160
161
 done:
162
    /* Write the interface index */
163
    if(info->ai_family == AF_INET)
164
        /* MSVC documentation of struct ip_mreq: To use an interface index of 1
165
         * would be the same as an IP address of 0.0.0.1. */
166
        req->ipv4.imr_interface.s_addr = htonl(idx);
167
#if UA_IPV6
168
    else /* if(info->ai_family == AF_INET6) */
169
        req->ipv6.ipv6mr_interface = idx;
170
#endif
171
    return UA_STATUSCODE_GOOD;
172
}
173
174
#else
175
176
static UA_StatusCode
177
setMulticastInterface(const char *netif, struct addrinfo *info,
178
0
                      MulticastRequest *req, const UA_Logger *logger) {
179
0
    UA_RESET_ERRNO;
180
0
    struct ifaddrs *ifaddr;
181
0
    int ret = getifaddrs(&ifaddr);
182
0
    if(ret == -1) {
183
0
        UA_LOG_SOCKET_ERRNO_WRAP(
184
0
           UA_LOG_ERROR(logger, UA_LOGCATEGORY_SERVER,
185
0
                        "UDP\t| Interface configuration preparation failed "
186
0
                        "(getifaddrs error: %s)", errno_str));
187
0
        return UA_STATUSCODE_BADINTERNALERROR;
188
0
    }
189
190
    /* Iterate over the interfaces */
191
0
    unsigned int idx = 0;
192
0
    struct ifaddrs *ifa = NULL;
193
0
    for(ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
194
0
        if(!ifa->ifa_addr)
195
0
            continue;
196
197
        /* Does the protocol family match? */
198
0
        if(ifa->ifa_addr->sa_family != info->ai_family)
199
0
            continue;
200
201
#if defined(UA_ARCHITECTURE_WIN32) || defined(ip_mreqn)
202
        idx = UA_if_nametoindex(ifa->ifa_name);
203
        if(idx == 0)
204
            continue;
205
#endif
206
207
        /* Found network interface by name */
208
0
        if(strcmp(ifa->ifa_name, netif) == 0)
209
0
            break;
210
211
        /* Check if the interface name is an IP address that matches */
212
0
        UA_RESET_ERRNO;
213
0
        char host[NI_MAXHOST];
214
0
        ret = getnameinfo(ifa->ifa_addr,
215
0
                          (info->ai_family == AF_INET) ?
216
0
                          sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6),
217
0
                          host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
218
0
        if(ret != 0) {
219
0
            UA_LOG_SOCKET_ERRNO_WRAP(
220
0
               UA_LOG_ERROR(logger, UA_LOGCATEGORY_SERVER,
221
0
                            "UDP\t| Interface configuration preparation "
222
0
                            "failed (Error: %s).", errno_str));
223
0
            freeifaddrs(ifaddr);
224
0
            return UA_STATUSCODE_BADINTERNALERROR;
225
0
        }
226
0
        if(strcmp(host, netif) == 0)
227
0
            break;
228
0
    }
229
230
0
    freeifaddrs(ifaddr);
231
0
    if(!ifa)
232
0
        return UA_STATUSCODE_BADINTERNALERROR;
233
234
    /* Write the interface index */
235
0
    if(info->ai_family == AF_INET) {
236
#if defined(ip_mreqn)
237
        req->ipv4.imr_ifindex = idx;
238
#endif
239
0
#if UA_IPV6
240
0
    } else { /* if(info->ai_family == AF_INET6) */
241
0
        req->ipv6.ipv6mr_interface = idx;
242
0
#endif
243
0
    }
244
0
    return UA_STATUSCODE_GOOD;
245
0
}
246
247
#endif /* UA_ARCHITECTURE_WIN32 */
248
249
static UA_StatusCode
250
setupMulticastRequest(UA_FD socket, MulticastRequest *req, const UA_KeyValueMap *params,
251
568
                      struct addrinfo *info, const UA_Logger *logger) {
252
    /* Initialize the address information */
253
568
    if(info->ai_family == AF_INET) {
254
568
        struct sockaddr_in *sin = (struct sockaddr_in *)info->ai_addr;
255
568
        req->ipv4.imr_multiaddr = sin->sin_addr;
256
568
#if !defined(ip_mreqn)
257
568
        req->ipv4.imr_interface.s_addr = htonl(INADDR_ANY); /* default ANY */
258
#else
259
        req->ipv4.imr_address.s_addr = htonl(INADDR_ANY); /* default ANY */
260
        req->ipv4.imr_ifindex = 0;
261
#endif
262
568
#if UA_IPV6
263
568
    } else if(info->ai_family == AF_INET6) {
264
0
        struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)info->ai_addr;
265
0
        req->ipv6.ipv6mr_multiaddr = sin6->sin6_addr;
266
0
        req->ipv6.ipv6mr_interface = 0; /* default ANY interface */
267
0
#endif
268
0
    } else {
269
0
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SERVER,
270
0
                     "UDP\t| Multicast configuration failed: Unknown protocol family");
271
0
        return UA_STATUSCODE_BADINTERNALERROR;
272
0
    }
273
274
    /* Was an interface (or local IP address) defined? */
275
568
    const UA_String *netif = (const UA_String*)
276
568
        UA_KeyValueMap_getScalar(params, udpConnectionParams[UDP_PARAMINDEX_INTERFACE].name,
277
568
                                 &UA_TYPES[UA_TYPES_STRING]);
278
568
    if(!netif) {
279
568
        UA_LOG_INFO(logger, UA_LOGCATEGORY_NETWORK,
280
568
                    "UDP %u\t| No network interface defined for multicast. "
281
568
                    "The first suitable network interface is used.",
282
568
                    (unsigned)socket);
283
568
        return UA_STATUSCODE_GOOD;
284
568
    }
285
286
    /* Set the interface index */
287
0
    UA_STACKARRAY(char, interfaceAsChar, sizeof(char) * netif->length + 1);
288
0
    memcpy(interfaceAsChar, netif->data, netif->length);
289
0
    interfaceAsChar[netif->length] = 0;
290
0
    return setMulticastInterface(interfaceAsChar, info, req, logger);
291
568
}
292
293
/* Retrieves hostname and port from given key value parameters.
294
 *
295
 * @param[in] params the parameter map to retrieve from
296
 * @param[out] hostname the retrieved hostname when present, NULL otherwise
297
 * @param[out] portStr the retrieved port when present, NULL otherwise
298
 * @param[in] logger the logger to log information
299
 * @return -1 upon error, 0 if there was no host or port parameter, 1 if
300
 *         host and port are present */
301
static int
302
getHostAndPortFromParams(const UA_KeyValueMap *params, char *hostname,
303
284
                         char *portStr, const UA_Logger *logger) {
304
    /* Prepare the port parameter as a string */
305
284
    const UA_UInt16 *port = (const UA_UInt16*)
306
284
        UA_KeyValueMap_getScalar(params, udpConnectionParams[UDP_PARAMINDEX_PORT].name,
307
284
                                 &UA_TYPES[UA_TYPES_UINT16]);
308
284
    UA_assert(port); /* checked before */
309
284
    mp_snprintf(portStr, UA_MAXPORTSTR_LENGTH, "%d", *port);
310
311
    /* Prepare the hostname string */
312
284
    const UA_String *host = (const UA_String*)
313
284
        UA_KeyValueMap_getScalar(params, udpConnectionParams[UDP_PARAMINDEX_ADDR].name,
314
284
                                 &UA_TYPES[UA_TYPES_STRING]);
315
284
    if(!host) {
316
0
        UA_LOG_DEBUG(logger, UA_LOGCATEGORY_NETWORK,
317
0
                     "UDP\t| No address configured");
318
0
        return -1;
319
0
    }
320
284
    if(host->length >= UA_MAXHOSTNAME_LENGTH) {
321
0
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_EVENTLOOP,
322
0
                     "UDP\t| Open UDP Connection: Hostname too long, aborting");
323
0
        return -1;
324
0
    }
325
284
    strncpy(hostname, (const char*)host->data, host->length);
326
284
    hostname[host->length] = 0;
327
284
    return 1;
328
284
}
329
330
static int
331
getConnectionInfoFromParams(const UA_KeyValueMap *params,
332
                            char *hostname, char *portStr,
333
284
                            struct addrinfo **info, const UA_Logger *logger) {
334
284
    int foundParams = getHostAndPortFromParams(params, hostname, portStr, logger);
335
284
    if(foundParams < 0)
336
0
        return -1;
337
338
    /* Create the socket description from the connectString
339
     * TODO: Make this non-blocking */
340
284
    UA_RESET_ERRNO;
341
284
    struct addrinfo hints;
342
284
    memset(&hints, 0, sizeof(struct addrinfo));
343
284
    hints.ai_family = AF_UNSPEC;
344
284
    hints.ai_socktype = SOCK_DGRAM;
345
284
    int error = UA_getaddrinfo(hostname, portStr, &hints, info);
346
284
    if(error != 0) {
347
#ifdef UA_ARCHITECTURE_WIN32
348
        UA_LOG_SOCKET_ERRNO_GAI_WRAP(
349
            UA_LOG_WARNING(logger, UA_LOGCATEGORY_NETWORK,
350
                           "UDP\t| Lookup of %s failed with error %d - %s",
351
                           hostname, error, errno_str));
352
#else
353
0
        UA_LOG_WARNING(logger, UA_LOGCATEGORY_NETWORK,
354
0
                       "UDP\t| Lookup of %s failed with error %s",
355
0
                       hostname, gai_strerror(error));
356
0
#endif
357
0
        return -1;
358
0
    }
359
284
    return 1;
360
284
}
361
362
/* Set loop back data to your host */
363
static UA_StatusCode
364
setLoopBackData(UA_SOCKET sockfd, UA_Boolean enableLoopback,
365
0
                int ai_family, const UA_Logger *logger) {
366
0
    UA_RESET_ERRNO;
367
    /* The loopback option has a different integer size between IPv4 and IPv6.
368
     * Some operating systems (e.g. OpenBSD) handle this very strict. Hence the
369
     * different "enable" variables below are required. */
370
0
    int retcode;
371
0
#if UA_IPV6
372
0
    if(ai_family == AF_INET6) {
373
0
        unsigned int enable6 = enableLoopback;
374
0
        retcode = UA_setsockopt(sockfd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
375
0
                                &enable6, sizeof(enable6));
376
0
    } else
377
0
#endif
378
0
    {
379
0
        unsigned char enable = enableLoopback;
380
0
        retcode = UA_setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_LOOP,
381
0
                                &enable, sizeof (enable));
382
0
    }
383
0
    if(retcode < 0) {
384
0
        UA_LOG_SOCKET_ERRNO_WRAP(
385
0
            UA_LOG_ERROR(logger, UA_LOGCATEGORY_NETWORK,
386
0
                         "UDP %u\t| Loopback setup failed: "
387
0
                         "Cannot set socket option IP_MULTICAST_LOOP. Error: %s",
388
0
                         (unsigned)sockfd, errno_str));
389
0
        return UA_STATUSCODE_BADINTERNALERROR;
390
0
    }
391
0
    return UA_STATUSCODE_GOOD;
392
0
}
393
394
static UA_StatusCode
395
setTimeToLive(UA_SOCKET sockfd, UA_UInt32 messageTTL,
396
568
              int ai_family, const UA_Logger *logger) {
397
568
    UA_RESET_ERRNO;
398
    /* Set Time to live (TTL). Value of 1 prevent forward beyond the local network. */
399
568
#if UA_IPV6
400
568
    if(UA_setsockopt(sockfd,
401
568
                     ai_family == PF_INET6 ? IPPROTO_IPV6 : IPPROTO_IP,
402
568
                     ai_family == PF_INET6 ? IPV6_MULTICAST_HOPS : IP_MULTICAST_TTL,
403
568
                     (const char *)&messageTTL,
404
568
                     sizeof(messageTTL)) < 0)
405
#else
406
    if(UA_setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_TTL,
407
                     (const char *)&messageTTL,
408
                     sizeof(messageTTL)) < 0)
409
#endif
410
0
    {
411
0
        UA_LOG_SOCKET_ERRNO_WRAP(
412
0
            UA_LOG_WARNING(logger, UA_LOGCATEGORY_NETWORK,
413
0
                           "UDP %u\t| Time to live setup failed: "
414
0
                           "Cannot set socket option IP_MULTICAST_TTL. Error: %s",
415
0
                           (unsigned)sockfd, errno_str));
416
0
        return UA_STATUSCODE_BADINTERNALERROR;
417
0
    }
418
568
    return UA_STATUSCODE_GOOD;
419
568
}
420
421
static UA_StatusCode
422
568
setReuseAddress(UA_SOCKET sockfd, UA_Boolean enableReuse, const UA_Logger *logger) {
423
    /* Set reuse address -> enables sharing of the same listening address on
424
     * different sockets */
425
568
    UA_RESET_ERRNO;
426
568
    int enableReuseVal = (enableReuse) ? 1 : 0;
427
568
    if(UA_setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
428
568
                     (const char*)&enableReuseVal, sizeof(enableReuseVal)) < 0) {
429
0
        UA_LOG_SOCKET_ERRNO_WRAP(
430
0
            UA_LOG_WARNING(logger, UA_LOGCATEGORY_NETWORK,
431
0
                           "UDP %u\t| Reuse address setup failed: "
432
0
                           "Cannot set socket option SO_REUSEADDR. Error: %s",
433
0
                           (unsigned)sockfd, errno_str));
434
0
        return UA_STATUSCODE_BADINTERNALERROR;
435
0
    }
436
568
    return UA_STATUSCODE_GOOD;
437
568
}
438
439
#ifdef __linux__
440
static UA_StatusCode
441
setSocketPriority(UA_SOCKET sockfd, UA_UInt32 socketPriority,
442
0
                  const UA_Logger *logger) {
443
0
    UA_RESET_ERRNO;
444
0
    int prio = (int)socketPriority;
445
0
    if(UA_setsockopt(sockfd, SOL_SOCKET, SO_PRIORITY, &prio, sizeof(int)) < 0) {
446
0
        UA_LOG_SOCKET_ERRNO_WRAP(
447
0
            UA_LOG_ERROR(logger, UA_LOGCATEGORY_NETWORK,
448
0
                         "UDP %u\t| Socket priority setup failed: "
449
0
                         "Cannot set socket option SO_PRIORITY. Error: %s",
450
0
                         (unsigned)sockfd, errno_str));
451
0
        return UA_STATUSCODE_BADINTERNALERROR;
452
0
    }
453
0
    return UA_STATUSCODE_GOOD;
454
0
}
455
#endif
456
457
static UA_StatusCode
458
setConnectionConfig(UA_FD socket, const UA_KeyValueMap *params,
459
568
                    int ai_family, const UA_Logger *logger) {
460
    /* Set socket config that is always set */
461
568
    UA_StatusCode res = UA_STATUSCODE_GOOD;
462
568
    res |= UA_EventLoopPOSIX_setNonBlocking(socket);
463
568
    res |= UA_EventLoopPOSIX_setNoSigPipe(socket);
464
568
    if(res != UA_STATUSCODE_GOOD)
465
0
        return res;
466
467
    /* Some Linux distributions have net.ipv6.bindv6only not activated. So
468
     * sockets can double-bind to IPv4 and IPv6. This leads to problems. Use
469
     * AF_INET6 sockets only for IPv6. */
470
568
#if UA_IPV6
471
568
    int optval = 1;
472
568
    if(ai_family == AF_INET6 &&
473
0
       UA_setsockopt(socket, IPPROTO_IPV6, IPV6_V6ONLY,
474
0
                     (const char*)&optval, sizeof(optval)) == -1) {
475
0
        UA_LOG_WARNING(logger, UA_LOGCATEGORY_NETWORK,
476
0
                       "UDP %u\t| Could not set an IPv6 socket to IPv6 only, closing",
477
0
                       (unsigned)socket);
478
0
        return UA_STATUSCODE_BADCONNECTIONREJECTED;
479
0
    }
480
568
#endif
481
482
568
    UA_RESET_ERRNO;
483
484
    /* Set socket settings from the parameters */
485
568
    const UA_UInt32 *messageTTL = (const UA_UInt32*)
486
568
        UA_KeyValueMap_getScalar(params, udpConnectionParams[UDP_PARAMINDEX_TTL].name,
487
568
                                 &UA_TYPES[UA_TYPES_UINT32]);
488
568
    if(messageTTL)
489
568
        res |= setTimeToLive(socket, *messageTTL, ai_family, logger);
490
491
568
    const UA_Boolean *enableLoopback = (const UA_Boolean*)
492
568
        UA_KeyValueMap_getScalar(params, udpConnectionParams[UDP_PARAMINDEX_LOOPBACK].name,
493
568
                                 &UA_TYPES[UA_TYPES_BOOLEAN]);
494
568
    if(enableLoopback)
495
0
        res |= setLoopBackData(socket, *enableLoopback, ai_family, logger);
496
497
568
    const UA_Boolean *enableReuse = (const UA_Boolean*)
498
568
        UA_KeyValueMap_getScalar(params, udpConnectionParams[UDP_PARAMINDEX_REUSE].name,
499
568
                                 &UA_TYPES[UA_TYPES_BOOLEAN]);
500
568
    if(enableReuse)
501
568
        res |= setReuseAddress(socket, *enableReuse, logger);
502
503
568
#ifdef __linux__
504
568
    const UA_UInt32 *socketPriority = (const UA_UInt32*)
505
568
        UA_KeyValueMap_getScalar(params, udpConnectionParams[UDP_PARAMINDEX_SOCKPRIO].name,
506
568
                                 &UA_TYPES[UA_TYPES_UINT32]);
507
568
    if(socketPriority)
508
0
        res |= setSocketPriority(socket, *socketPriority, logger);
509
568
#endif
510
511
568
    if(res != UA_STATUSCODE_GOOD) {
512
0
        UA_LOG_SOCKET_ERRNO_WRAP(
513
0
            UA_LOG_WARNING(logger, UA_LOGCATEGORY_NETWORK,
514
0
                           "UDP\t| Could not set socket options: %s", errno_str));
515
0
    }
516
568
    return res;
517
568
}
518
519
static UA_StatusCode
520
setupListenMultiCast(UA_FD fd, struct addrinfo *info, const UA_KeyValueMap *params,
521
284
                     MultiCastType multiCastType, const UA_Logger *logger) {
522
284
    MulticastRequest req;
523
284
    UA_StatusCode res = setupMulticastRequest(fd, &req, params, info, logger);
524
284
    if(res != UA_STATUSCODE_GOOD)
525
0
        return res;
526
527
284
    UA_RESET_ERRNO;
528
284
    int result = -1;
529
284
    if(info->ai_family == AF_INET && multiCastType == MULTICASTTYPE_IPV4) {
530
284
        result = UA_setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
531
284
                               &req.ipv4, sizeof(req.ipv4));
532
284
#if UA_IPV6
533
284
    } else if(info->ai_family == AF_INET6 && multiCastType == MULTICASTTYPE_IPV6) {
534
0
        result = UA_setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP,
535
0
                               &req.ipv6, sizeof(req.ipv6));
536
0
#endif
537
0
    }
538
539
284
    if(result < 0) {
540
0
        UA_LOG_SOCKET_ERRNO_WRAP(
541
0
            UA_LOG_ERROR(logger, UA_LOGCATEGORY_NETWORK,
542
0
                         "UDP %u\t| Cannot set socket for multicast receiving. Error: %s",
543
0
                         (unsigned)fd, errno_str));
544
0
        return UA_STATUSCODE_BADINTERNALERROR;
545
0
    }
546
284
    return UA_STATUSCODE_GOOD;
547
284
}
548
549
static UA_StatusCode
550
setupSendMultiCast(UA_FD fd, struct addrinfo *info, const UA_KeyValueMap *params,
551
284
                   MultiCastType multiCastType, const UA_Logger *logger) {
552
284
    MulticastRequest req;
553
284
    UA_StatusCode res = setupMulticastRequest(fd, &req, params, info, logger);
554
284
    if(res != UA_STATUSCODE_GOOD)
555
0
        return res;
556
557
284
    UA_RESET_ERRNO;
558
284
    int result = -1;
559
284
    if(info->ai_family == AF_INET && multiCastType == MULTICASTTYPE_IPV4) {
560
#ifdef UA_ARCHITECTURE_WIN32
561
        result = UA_setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
562
                            (const char *)&req.ipv4.imr_interface,
563
                            sizeof(struct in_addr));
564
#else
565
284
        result = UA_setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
566
284
                            &req.ipv4, sizeof(req.ipv4));
567
284
#endif
568
284
#if UA_IPV6
569
284
    } else if(info->ai_family == AF_INET6 && multiCastType == MULTICASTTYPE_IPV6) {
570
0
        result = UA_setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
571
0
                            (const char *)
572
0
                            &req.ipv6.ipv6mr_interface, sizeof(req.ipv6.ipv6mr_interface));
573
0
#endif
574
0
    }
575
576
284
    if(result < 0) {
577
0
        UA_LOG_SOCKET_ERRNO_WRAP(
578
0
            UA_LOG_ERROR(logger, UA_LOGCATEGORY_NETWORK,
579
0
                         "UDP %u\t| Cannot set socket for multicast sending. Error: %s",
580
0
                         (unsigned)fd, errno_str));
581
0
        return UA_STATUSCODE_BADINTERNALERROR;
582
0
    }
583
284
    return UA_STATUSCODE_GOOD;
584
284
}
585
586
/* Test if the ConnectionManager can be stopped */
587
static void
588
1.11k
UDP_checkStopped(UA_POSIXConnectionManager *pcm) {
589
1.11k
    UA_LOCK_ASSERT(&((UA_EventLoopPOSIX*)pcm->cm.eventSource.eventLoop)->elMutex);
590
591
1.11k
    if(pcm->fdsSize == 0 &&
592
831
       pcm->cm.eventSource.state == UA_EVENTSOURCESTATE_STOPPING) {
593
547
        UA_LOG_DEBUG(pcm->cm.eventSource.eventLoop->logger, UA_LOGCATEGORY_NETWORK,
594
547
                     "UDP\t| All sockets closed, the EventLoop has stopped");
595
547
        pcm->cm.eventSource.state = UA_EVENTSOURCESTATE_STOPPED;
596
547
    }
597
1.11k
}
598
599
/* This method must not be called from the application directly, but from within
600
 * the EventLoop. Otherwise we cannot be sure whether the file descriptor is
601
 * still used after calling close. */
602
static void
603
568
UDP_close(UA_POSIXConnectionManager *pcm, UDP_FD *conn) {
604
568
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)pcm->cm.eventSource.eventLoop;
605
568
    UA_LOCK_ASSERT(&el->elMutex);
606
607
568
    UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
608
568
                 "UDP %u\t| Closing connection",
609
568
                 (unsigned)conn->rfd.fd);
610
611
    /* Deregister from the EventLoop */
612
568
    UA_EventLoopPOSIX_deregisterFD(el, &conn->rfd);
613
614
    /* Deregister internally */
615
568
    ZIP_REMOVE(UA_FDTree, &pcm->fds, &conn->rfd);
616
568
    UA_assert(pcm->fdsSize > 0);
617
568
    pcm->fdsSize--;
618
619
    /* Signal closing to the application */
620
568
    conn->applicationCB(&pcm->cm, (uintptr_t)conn->rfd.fd,
621
568
                        conn->application, &conn->context,
622
568
                        UA_CONNECTIONSTATE_CLOSING,
623
568
                        &UA_KEYVALUEMAP_NULL, UA_BYTESTRING_NULL);
624
625
    /* Close the socket */
626
568
    UA_RESET_ERRNO;
627
568
    int ret = UA_close(conn->rfd.fd);
628
568
    if(ret == 0) {
629
568
        UA_LOG_INFO(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
630
568
                    "UDP %u\t| Socket closed", (unsigned)conn->rfd.fd);
631
568
    } else {
632
0
        UA_LOG_SOCKET_ERRNO_WRAP(
633
0
           UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
634
0
                          "UDP %u\t| Could not close the socket (%s)",
635
0
                          (unsigned)conn->rfd.fd, errno_str));
636
0
    }
637
638
568
    UA_free(conn);
639
640
    /* Stop if the ucm is stopping and this was the last open socket */
641
568
    UDP_checkStopped(pcm);
642
568
}
643
644
static void
645
568
UDP_delayedClose(void *application, void *context) {
646
568
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)application;
647
568
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)pcm->cm.eventSource.eventLoop;
648
568
    UDP_FD *conn = (UDP_FD*)context;
649
568
    UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
650
568
                 "UDP %u\t| Delayed closing of the connection",
651
568
                 (unsigned)conn->rfd.fd);
652
568
    UA_LOCK(&el->elMutex);
653
568
    UDP_close(pcm, conn);
654
568
    UA_UNLOCK(&el->elMutex);
655
568
}
656
657
/* Gets called when a socket receives data or closes */
658
static void
659
UDP_connectionSocketCallback(UA_POSIXConnectionManager *pcm, UDP_FD *conn,
660
0
                             short event) {
661
0
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)pcm->cm.eventSource.eventLoop;
662
0
    UA_LOCK_ASSERT(&el->elMutex);
663
664
0
    UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
665
0
                 "UDP %u\t| Activity on the socket",
666
0
                 (unsigned)conn->rfd.fd);
667
668
0
    if(event == UA_FDEVENT_ERR) {
669
0
        UA_LOG_SOCKET_ERRNO_WRAP(
670
0
           UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
671
0
                        "UDP %u\t| recv signaled the socket was shutdown (%s)",
672
0
                        (unsigned)conn->rfd.fd, errno_str));
673
0
        UDP_close(pcm, conn);
674
0
        return;
675
0
    }
676
677
0
    UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
678
0
                 "UDP %u\t| Allocate receive buffer", (unsigned)conn->rfd.fd);
679
680
    /* Use the already allocated receive-buffer */
681
0
    UA_ByteString response = pcm->rxBuffer;
682
683
    /* Receive */
684
0
    UA_RESET_ERRNO;
685
0
    struct sockaddr_storage source;
686
0
#ifndef UA_ARCHITECTURE_WIN32
687
0
    socklen_t sourceSize = (socklen_t)sizeof(struct sockaddr_storage);
688
0
    ssize_t ret = UA_recvfrom(conn->rfd.fd, (char*)response.data, response.length,
689
0
                           MSG_DONTWAIT, (struct sockaddr*)&source, &sourceSize);
690
#else
691
    int sourceSize = (int)sizeof(struct sockaddr_storage);
692
    int ret = UA_recvfrom(conn->rfd.fd, (char*)response.data, (int)response.length,
693
                       MSG_DONTWAIT, (struct sockaddr*)&source, &sourceSize);
694
#endif
695
696
    /* Receive has failed */
697
0
    if(ret <= 0) {
698
0
        if(UA_ERRNO == UA_INTERRUPTED)
699
0
            return;
700
701
        /* Orderly shutdown of the socket. We can immediately close as no method
702
         * "below" in the call stack will use the socket in this iteration of
703
         * the EventLoop. */
704
0
        UA_LOG_SOCKET_ERRNO_WRAP(
705
0
           UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
706
0
                        "UDP %u\t| recv signaled the socket was shutdown (%s)",
707
0
                        (unsigned)conn->rfd.fd, errno_str));
708
0
        UDP_close(pcm, conn);
709
0
        return;
710
0
    }
711
712
0
    response.length = (size_t)ret; /* Set the length of the received buffer */
713
714
    /* Extract message source and port */
715
0
    char sourceAddr[64];
716
0
    UA_UInt16 sourcePort;
717
0
    switch(source.ss_family) {
718
0
        case AF_INET:
719
0
            UA_inet_ntop(AF_INET, &((struct sockaddr_in *)&source)->sin_addr,
720
0
                    sourceAddr, 64);
721
0
            sourcePort = htons(((struct sockaddr_in *)&source)->sin_port);
722
0
            break;
723
0
        case AF_INET6:
724
0
            UA_inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)&source)->sin6_addr),
725
0
                    sourceAddr, 64);
726
0
            sourcePort = htons(((struct sockaddr_in6 *)&source)->sin6_port);
727
0
            break;
728
0
        default:
729
0
            sourceAddr[0] = 0;
730
0
            sourcePort = 0;
731
0
    }
732
733
0
    UA_String sourceAddrStr = UA_STRING(sourceAddr);
734
0
    UA_KeyValuePair kvp[2];
735
0
    kvp[0].key = UA_QUALIFIEDNAME(0, "remote-address");
736
0
    UA_Variant_setScalar(&kvp[0].value, &sourceAddrStr, &UA_TYPES[UA_TYPES_STRING]);
737
0
    kvp[1].key = UA_QUALIFIEDNAME(0, "remote-port");
738
0
    UA_Variant_setScalar(&kvp[1].value, &sourcePort, &UA_TYPES[UA_TYPES_UINT16]);
739
0
    UA_KeyValueMap kvm = {2, kvp};
740
741
0
    UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
742
0
                 "UDP %u\t| Received message of size %u from %s on port %u",
743
0
                 (unsigned)conn->rfd.fd, (unsigned)ret,
744
0
                 sourceAddr, sourcePort);
745
746
    /* Callback to the application layer */
747
0
    conn->applicationCB(&pcm->cm, (uintptr_t)conn->rfd.fd,
748
0
                        conn->application, &conn->context,
749
0
                        UA_CONNECTIONSTATE_ESTABLISHED,
750
0
                        &kvm, response);
751
0
}
752
753
static UA_StatusCode
754
UDP_registerListenSocket(UA_POSIXConnectionManager *pcm, UA_UInt16 port,
755
                         struct addrinfo *info, const UA_KeyValueMap *params,
756
                         void *application, void *context,
757
                         UA_ConnectionManager_connectionCallback connectionCallback,
758
284
                         UA_Boolean validate) {
759
284
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)pcm->cm.eventSource.eventLoop;
760
284
    UA_LOCK_ASSERT(&el->elMutex);
761
762
    /* Get logging information */
763
284
    UA_RESET_ERRNO;
764
284
    char hoststr[UA_MAXHOSTNAME_LENGTH];
765
284
    int get_res = UA_getnameinfo(info->ai_addr, info->ai_addrlen,
766
284
                                 hoststr, sizeof(hoststr),
767
284
                                 NULL, 0, NI_NUMERICHOST);
768
284
    if(get_res != 0) {
769
0
        hoststr[0] = 0;
770
0
        UA_LOG_SOCKET_ERRNO_WRAP(
771
0
           UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
772
0
                          "UDP\t| Could not resolve the hostname (Error: %s)", errno_str));
773
0
        if(validate)
774
0
            return UA_STATUSCODE_BADCONNECTIONREJECTED;
775
0
    }
776
777
    /* Create the listen socket */
778
284
    UA_RESET_ERRNO;
779
284
    UA_FD listenSocket = UA_socket(info->ai_family, info->ai_socktype, info->ai_protocol);
780
284
    if(listenSocket == UA_INVALID_FD) {
781
0
        UA_LOG_SOCKET_ERRNO_WRAP(
782
0
           UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
783
0
                          "UDP\t| Error opening the listen socket for "
784
0
                          "\"%s\" on port %u (Error: %s)",
785
0
                          (unsigned)listenSocket, hoststr, port, errno_str));
786
0
        return UA_STATUSCODE_BADCONNECTIONREJECTED;
787
0
    }
788
789
    /* Set the socket configuration per the parameters */
790
284
    UA_StatusCode res =
791
284
        setConnectionConfig(listenSocket, params,
792
284
                            info->ai_family, el->eventLoop.logger);
793
284
    if(res != UA_STATUSCODE_GOOD) {
794
0
        UA_close(listenSocket);
795
0
        return UA_STATUSCODE_BADCONNECTIONREJECTED;
796
0
    }
797
798
    /* Are we going to prepare a socket for multicast? */
799
284
    MultiCastType mc = multiCastType(info);
800
801
    /* Bind socket to the address */
802
284
    UA_RESET_ERRNO;
803
#ifdef UA_ARCHITECTURE_WIN32
804
    /* On windows we need to bind the socket to INADDR_ANY before registering
805
     * for the multicast group */
806
    int ret = -1;
807
    if(mc != MULTICASTTYPE_NONE) {
808
        if(info->ai_family == AF_INET) {
809
            struct sockaddr_in *orig = (struct sockaddr_in *)info->ai_addr;
810
            struct sockaddr_in sin;
811
            memset(&sin, 0, sizeof(sin));
812
            sin.sin_family = AF_INET;
813
            sin.sin_addr.s_addr = htonl(INADDR_ANY);
814
            sin.sin_port = orig->sin_port;
815
            ret = bind(listenSocket, (struct sockaddr*)&sin, sizeof(sin));
816
        } else if(info->ai_family == AF_INET6) {
817
            struct sockaddr_in6 *orig = (struct sockaddr_in6 *)info->ai_addr;
818
            struct sockaddr_in6 sin6;
819
            memset(&sin6, 0, sizeof(sin6));
820
            sin6.sin6_family = AF_INET6;
821
            sin6.sin6_addr = in6addr_any;
822
            sin6.sin6_port = orig->sin6_port;
823
            ret = bind(listenSocket, (struct sockaddr*)&sin6, sizeof(sin6));
824
        }
825
    } else {
826
        ret = UA_bind(listenSocket, info->ai_addr, (socklen_t)info->ai_addrlen);
827
    }
828
#else
829
284
    int ret = UA_bind(listenSocket, info->ai_addr, (socklen_t)info->ai_addrlen);
830
284
#endif
831
832
    /* Get the port being used if dynamic porting was used */
833
284
    if(port == 0) {
834
0
        struct sockaddr_in sin;
835
0
        memset(&sin, 0, sizeof(sin));
836
0
        socklen_t len = sizeof(sin);
837
0
        if(getsockname(listenSocket, (struct sockaddr *)&sin, &len) != 0) {
838
0
            UA_LOG_SOCKET_ERRNO_WRAP(
839
0
                UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
840
0
                            "UDP %u\t| getsockname failed (%s)",
841
0
                            (unsigned)listenSocket, errno_str));
842
0
            UA_close(listenSocket);
843
0
            return UA_STATUSCODE_BADCONNECTIONREJECTED;
844
0
        }
845
0
        port = ntohs(sin.sin_port);
846
0
    }
847
848
284
    if(ret < 0) {
849
0
        UA_LOG_SOCKET_ERRNO_WRAP(
850
0
            UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
851
0
                           "UDP\t| Failed to bind listen socket for \"%s\" on port %u "
852
0
                           "(Error: %s)", hoststr, port, errno_str));
853
0
        UA_close(listenSocket);
854
0
        return UA_STATUSCODE_BADCONNECTIONREJECTED;
855
0
    }
856
857
    /* Enable multicast if this is a multicast address */
858
284
    if(mc != MULTICASTTYPE_NONE) {
859
284
        UA_RESET_ERRNO;
860
284
        res = setupListenMultiCast(listenSocket, info, params, mc,
861
284
                                   (validate) ? NULL : el->eventLoop.logger);
862
284
        if(res != UA_STATUSCODE_GOOD) {
863
0
            if(!validate) {
864
0
                UA_LOG_SOCKET_ERRNO_GAI_WRAP(
865
0
                   UA_LOG_WARNING(pcm->cm.eventSource.eventLoop->logger,
866
0
                                  UA_LOGCATEGORY_NETWORK,
867
0
                                  "UDP\t| Failed to set up multicast for \"%s\" on port %u (%s)",
868
0
                                  hoststr, port, errno_str));
869
0
            } else {
870
0
                UA_LOG_SOCKET_ERRNO_GAI_WRAP(
871
0
                   UA_LOG_WARNING(pcm->cm.eventSource.eventLoop->logger, UA_LOGCATEGORY_NETWORK,
872
0
                                  "UDP\t| Failed to validate multicast for \"%s\" on port %u (%s)",
873
0
                                  hoststr, port, errno_str));
874
0
            }
875
0
            UA_close(listenSocket);
876
0
            return res;
877
0
        }
878
284
    }
879
880
    /* Validation is complete - close and return */
881
284
    if(validate) {
882
0
        UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
883
0
                    "UDP\t| Listen socket for \"%s\" on port %u validated", hoststr, port);
884
0
        UA_close(listenSocket);
885
0
        return UA_STATUSCODE_GOOD;
886
0
    }
887
888
284
    UA_LOG_INFO(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
889
284
                "UDP %u\t| New listen socket for \"%s\" on port %u",
890
284
                (unsigned)listenSocket, hoststr, port);
891
892
    /* Allocate the UA_RegisteredFD */
893
284
    UDP_FD *newudpfd = (UDP_FD*)UA_calloc(1, sizeof(UDP_FD));
894
284
    if(!newudpfd) {
895
0
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
896
0
                       "UDP %u\t| Error allocating memory for the socket, closing",
897
0
                       (unsigned)listenSocket);
898
0
        UA_close(listenSocket);
899
0
        return UA_STATUSCODE_BADCONNECTIONREJECTED;
900
0
    }
901
902
284
    newudpfd->rfd.fd = listenSocket;
903
284
    newudpfd->rfd.es = &pcm->cm.eventSource;
904
284
    newudpfd->rfd.listenEvents = UA_FDEVENT_IN;
905
284
    newudpfd->rfd.eventSourceCB = (UA_FDCallback)UDP_connectionSocketCallback;
906
284
    newudpfd->applicationCB = connectionCallback;
907
284
    newudpfd->application = application;
908
284
    newudpfd->context = context;
909
910
    /* Register in the EventLoop */
911
284
    res = UA_EventLoopPOSIX_registerFD(el, &newudpfd->rfd);
912
284
    if(res != UA_STATUSCODE_GOOD) {
913
0
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
914
0
                       "UDP %u\t| Error registering the socket, closing",
915
0
                       (unsigned)listenSocket);
916
0
        UA_free(newudpfd);
917
0
        UA_close(listenSocket);
918
0
        return res;
919
0
    }
920
921
    /* Register internally in the EventSource */
922
284
    ZIP_INSERT(UA_FDTree, &pcm->fds, &newudpfd->rfd);
923
284
    pcm->fdsSize++;
924
925
    /* Register the listen socket in the application */
926
284
    connectionCallback(&pcm->cm, (uintptr_t)newudpfd->rfd.fd,
927
284
                       application, &newudpfd->context,
928
284
                       UA_CONNECTIONSTATE_ESTABLISHED,
929
284
                       &UA_KEYVALUEMAP_NULL, UA_BYTESTRING_NULL);
930
284
    return UA_STATUSCODE_GOOD;
931
284
}
932
933
static UA_StatusCode
934
UDP_registerListenSockets(UA_POSIXConnectionManager *pcm, const char *hostname,
935
                          UA_UInt16 port, const UA_KeyValueMap *params,
936
                          void *application, void *context,
937
                          UA_ConnectionManager_connectionCallback connectionCallback,
938
284
                          UA_Boolean validate) {
939
284
    UA_LOCK_ASSERT(&((UA_EventLoopPOSIX*)pcm->cm.eventSource.eventLoop)->elMutex);
940
941
    /* Get all the interface and IPv4/6 combinations for the configured hostname */
942
284
    struct addrinfo hints, *res;
943
284
    memset(&hints, 0, sizeof hints);
944
284
#if UA_IPV6
945
284
    hints.ai_family = AF_UNSPEC; /* Allow IPv4 and IPv6 */
946
#else
947
    hints.ai_family = AF_INET;   /* IPv4 only */
948
#endif
949
284
    hints.ai_socktype = SOCK_DGRAM;
950
284
    hints.ai_protocol = IPPROTO_UDP;
951
284
    hints.ai_flags = AI_PASSIVE;
952
953
    /* Set up the port string */
954
284
    char portstr[6];
955
284
    mp_snprintf(portstr, 6, "%d", port);
956
957
284
    UA_RESET_ERRNO;
958
284
    int retcode = UA_getaddrinfo(hostname, portstr, &hints, &res);
959
284
    if(retcode != 0) {
960
#ifdef UA_ARCHITECTURE_WIN32
961
        UA_LOG_SOCKET_ERRNO_GAI_WRAP(
962
           UA_LOG_WARNING(pcm->cm.eventSource.eventLoop->logger,
963
                          UA_LOGCATEGORY_NETWORK,
964
                          "UDP\t| getaddrinfo lookup for \"%s\" on port %u failed (%s)",
965
                          hostname, port, errno_str));
966
#else
967
0
        UA_LOG_WARNING(pcm->cm.eventSource.eventLoop->logger, UA_LOGCATEGORY_NETWORK,
968
0
                       "UDP\t| getaddrinfo lookup for \"%s\" on port %u failed (%s)",
969
0
                       hostname, port, gai_strerror(retcode));
970
0
#endif
971
0
        return UA_STATUSCODE_BADCONNECTIONREJECTED;
972
0
    }
973
974
    /* Add listen sockets */
975
284
    struct addrinfo *ai = res;
976
284
    UA_StatusCode rv = UA_STATUSCODE_GOOD;
977
568
    while(ai) {
978
284
        rv = UDP_registerListenSocket(pcm, port, ai, params, application,
979
284
                                      context, connectionCallback, validate);
980
284
        if(rv != UA_STATUSCODE_GOOD)
981
0
            break;
982
284
        ai = ai->ai_next;
983
284
    }
984
284
    UA_freeaddrinfo(res);
985
284
    return rv;
986
284
}
987
988
/* Close the connection via a delayed callback */
989
static void
990
568
UDP_shutdown(UA_ConnectionManager *cm, UA_RegisteredFD *rfd) {
991
568
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX *)cm->eventSource.eventLoop;
992
568
    UA_LOCK_ASSERT(&el->elMutex);
993
994
568
    if(rfd->dc.callback) {
995
0
        UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
996
0
                     "UDP %u\t| Cannot close - already closing",
997
0
                     (unsigned)rfd->fd);
998
0
        return;
999
0
    }
1000
1001
    /* Shutdown the socket to cancel the current select/epoll */
1002
568
    UA_shutdown(rfd->fd, UA_SHUT_RDWR);
1003
1004
568
    UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
1005
568
                 "UDP %u\t| Shutdown called", (unsigned)rfd->fd);
1006
1007
568
    UA_DelayedCallback *dc = &rfd->dc;
1008
568
    dc->callback = UDP_delayedClose;
1009
568
    dc->application = cm;
1010
568
    dc->context = rfd;
1011
1012
    /* Adding a delayed callback does not take a lock */
1013
568
    UA_EventLoopPOSIX_addDelayedCallback((UA_EventLoop*)el, dc);
1014
568
}
1015
1016
static UA_StatusCode
1017
568
UDP_shutdownConnection(UA_ConnectionManager *cm, uintptr_t connectionId) {
1018
568
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)cm;
1019
568
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX *)cm->eventSource.eventLoop;
1020
568
    UA_FD fd = (UA_FD)connectionId;
1021
1022
568
    UA_LOCK(&el->elMutex);
1023
568
    UA_RegisteredFD *rfd = ZIP_FIND(UA_FDTree, &pcm->fds, &fd);
1024
568
    if(!rfd) {
1025
0
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
1026
0
                       "UDP\t| Cannot close UDP connection %u - not found",
1027
0
                       (unsigned)connectionId);
1028
0
        UA_UNLOCK(&el->elMutex);
1029
0
        return UA_STATUSCODE_BADNOTFOUND;
1030
0
    }
1031
568
    UDP_shutdown(cm, rfd);
1032
568
    UA_UNLOCK(&el->elMutex);
1033
568
    return UA_STATUSCODE_GOOD;
1034
568
}
1035
1036
static UA_StatusCode
1037
UDP_sendWithConnection(UA_ConnectionManager *cm, uintptr_t connectionId,
1038
                       const UA_KeyValueMap *params,
1039
0
                       UA_ByteString *buf) {
1040
0
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)cm;
1041
0
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)cm->eventSource.eventLoop;
1042
1043
0
    UA_LOCK(&el->elMutex);
1044
1045
    /* Look up the registered UDP socket */
1046
0
    UA_FD fd = (UA_FD)connectionId;
1047
0
    UDP_FD *conn = (UDP_FD*)ZIP_FIND(UA_FDTree, &pcm->fds, &fd);
1048
0
    if(!conn) {
1049
0
        UA_UNLOCK(&el->elMutex);
1050
0
        UA_EventLoopPOSIX_freeNetworkBuffer(cm, connectionId, buf);
1051
0
        return UA_STATUSCODE_BADINTERNALERROR;
1052
0
    }
1053
1054
    /* Send the full buffer. This may require several calls to send */
1055
0
    size_t nWritten = 0;
1056
0
    do {
1057
0
        ssize_t n = 0;
1058
0
        do {
1059
0
            UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
1060
0
                         "UDP %u\t| Attempting to send", (unsigned)connectionId);
1061
1062
            /* Prevent OS signals when sending to a closed socket */
1063
0
            UA_RESET_ERRNO;
1064
0
            int flags = MSG_NOSIGNAL;
1065
0
            size_t bytes_to_send = buf->length - nWritten;
1066
0
            n = UA_sendto((UA_FD)connectionId, (const char*)buf->data + nWritten,
1067
0
                          bytes_to_send, flags, (struct sockaddr*)&conn->sendAddr,
1068
0
                          conn->sendAddrLength);
1069
0
            if(n < 0) {
1070
                /* An error we cannot recover from? */
1071
0
                if(UA_ERRNO != UA_INTERRUPTED &&
1072
0
                   UA_ERRNO != UA_WOULDBLOCK &&
1073
0
                   UA_ERRNO != UA_AGAIN) {
1074
0
                    UA_LOG_SOCKET_ERRNO_WRAP(
1075
0
                       UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
1076
0
                                    "UDP %u\t| Send failed with error %s",
1077
0
                                    (unsigned)connectionId, errno_str));
1078
0
                    UA_UNLOCK(&el->elMutex);
1079
0
                    UDP_shutdownConnection(cm, connectionId);
1080
0
                    UA_EventLoopPOSIX_freeNetworkBuffer(cm, connectionId, buf);
1081
0
                    return UA_STATUSCODE_BADCONNECTIONCLOSED;
1082
0
                }
1083
1084
                /* Poll for the socket resources to become available and retry
1085
                 * (blocking) */
1086
0
                int poll_ret;
1087
0
                struct pollfd tmp_poll_fd;
1088
0
                tmp_poll_fd.fd = (UA_FD)connectionId;
1089
0
                tmp_poll_fd.events = UA_POLLOUT;
1090
0
                do {
1091
0
                    UA_RESET_ERRNO;
1092
0
                    poll_ret = UA_poll(&tmp_poll_fd, 1, 100);
1093
0
                    if(poll_ret < 0 && UA_ERRNO != UA_INTERRUPTED) {
1094
0
                        UA_LOG_SOCKET_ERRNO_WRAP(
1095
0
                           UA_LOG_ERROR(el->eventLoop.logger,
1096
0
                                        UA_LOGCATEGORY_NETWORK,
1097
0
                                        "UDP %u\t| Send failed with error %s",
1098
0
                                        (unsigned)connectionId, errno_str));
1099
0
                        UA_EventLoopPOSIX_freeNetworkBuffer(cm, connectionId, buf);
1100
0
                        UDP_shutdown(cm, &conn->rfd);
1101
0
                        UA_UNLOCK(&el->elMutex);
1102
0
                        return UA_STATUSCODE_BADCONNECTIONCLOSED;
1103
0
                    }
1104
0
                } while(poll_ret <= 0);
1105
0
            }
1106
0
        } while(n < 0);
1107
0
        nWritten += (size_t)n;
1108
0
    } while(nWritten < buf->length);
1109
1110
    /* Free the buffer */
1111
0
    UA_UNLOCK(&el->elMutex);
1112
0
    UA_EventLoopPOSIX_freeNetworkBuffer(cm, connectionId, buf);
1113
0
    return UA_STATUSCODE_GOOD;
1114
0
}
1115
1116
static UA_StatusCode
1117
registerSocketAndDestinationForSend(const UA_KeyValueMap *params,
1118
                                    const char *hostname, struct addrinfo *info,
1119
                                    int error, UDP_FD *ufd, UA_FD *sock,
1120
284
                                    const UA_Logger *logger, UA_Boolean validate) {
1121
284
    UA_RESET_ERRNO;
1122
284
    UA_FD newSock = UA_socket(info->ai_family, info->ai_socktype, info->ai_protocol);
1123
284
    *sock = newSock;
1124
284
    if(newSock == UA_INVALID_FD) {
1125
0
        UA_LOG_SOCKET_ERRNO_WRAP(
1126
0
            UA_LOG_WARNING(logger, UA_LOGCATEGORY_NETWORK,
1127
0
                           "UDP\t| Could not create socket to connect to %s (%s)",
1128
0
                           hostname, errno_str));
1129
0
        return UA_STATUSCODE_BADDISCONNECT;
1130
0
    }
1131
284
    UA_StatusCode res = setConnectionConfig(newSock, params, info->ai_family, logger);
1132
284
    if(res != UA_STATUSCODE_GOOD) {
1133
0
        UA_close(newSock);
1134
0
        return res;
1135
0
    }
1136
1137
    /* Prepare socket for multicast */
1138
284
    MultiCastType mc = multiCastType(info);
1139
284
    if(mc != MULTICASTTYPE_NONE) {
1140
284
        res = setupSendMultiCast(newSock, info, params, mc, (validate) ? NULL : logger);
1141
284
        if(res != UA_STATUSCODE_GOOD) {
1142
0
            UA_close(newSock);
1143
0
            return res;
1144
0
        }
1145
284
    }
1146
1147
284
    memcpy(&ufd->sendAddr, info->ai_addr, info->ai_addrlen);
1148
284
    ufd->sendAddrLength = info->ai_addrlen;
1149
284
    return UA_STATUSCODE_GOOD;
1150
284
}
1151
1152
static UA_StatusCode
1153
UDP_openSendConnection(UA_POSIXConnectionManager *pcm, const UA_KeyValueMap *params,
1154
                       void *application, void *context,
1155
                       UA_ConnectionManager_connectionCallback connectionCallback,
1156
284
                       UA_Boolean validate) {
1157
284
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX *)pcm->cm.eventSource.eventLoop;
1158
284
    UA_LOCK_ASSERT(&el->elMutex);
1159
1160
    /* Get the connection parameters */
1161
284
    char hostname[UA_MAXHOSTNAME_LENGTH];
1162
284
    char portStr[UA_MAXPORTSTR_LENGTH];
1163
284
    struct addrinfo *info = NULL;
1164
1165
284
    int error = getConnectionInfoFromParams(params, hostname,
1166
284
                                            portStr, &info, el->eventLoop.logger);
1167
284
    if(error < 0 || info == NULL) {
1168
0
        if(info != NULL) {
1169
0
            UA_freeaddrinfo(info);
1170
0
        }
1171
0
        UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
1172
0
                     "UDP\t| Opening a connection failed");
1173
0
        return UA_STATUSCODE_BADCONNECTIONREJECTED;
1174
0
    }
1175
1176
284
    UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
1177
284
                 "UDP\t| Open a connection to \"%s\" on port %s", hostname, portStr);
1178
1179
    /* Allocate the UA_RegisteredFD */
1180
284
    UDP_FD *conn = (UDP_FD*)UA_calloc(1, sizeof(UDP_FD));
1181
284
    if(!conn) {
1182
0
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
1183
0
                       "UDP\t| Error allocating memory for the socket, closing");
1184
0
        return UA_STATUSCODE_BADOUTOFMEMORY;
1185
0
    }
1186
1187
    /* Create a socket and register the destination address from the provided parameters */
1188
284
    UA_RESET_ERRNO;
1189
284
    UA_FD newSock = UA_INVALID_FD;
1190
284
    UA_StatusCode res =
1191
284
        registerSocketAndDestinationForSend(params, hostname, info,
1192
284
                                            error, conn, &newSock,
1193
284
                                            el->eventLoop.logger, validate);
1194
284
    UA_freeaddrinfo(info);
1195
284
    if(validate && res == UA_STATUSCODE_GOOD) {
1196
0
        UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
1197
0
                     "UDP\t| Connection parameters to \"%s\" on port %s have been validated",
1198
0
                     hostname, portStr);
1199
0
        UA_close(newSock);
1200
0
        UA_free(conn);
1201
0
        return UA_STATUSCODE_GOOD;
1202
0
    }
1203
284
    if(res != UA_STATUSCODE_GOOD) {
1204
0
        if(!validate) {
1205
0
            UA_LOG_SOCKET_ERRNO_WRAP(
1206
0
                UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
1207
0
                             "UDP\t| Connection to \"%s\" on port %s could not be opened "
1208
0
                             "with error: %s", hostname, portStr, errno_str));
1209
0
        } else {
1210
0
            UA_LOG_SOCKET_ERRNO_WRAP(
1211
0
                UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
1212
0
                             "UDP\t| Invalid connection parameters to \"%s\" on "
1213
0
                             "port %s (Error: %s)", hostname, portStr, errno_str));
1214
0
        }
1215
0
        UA_free(conn);
1216
0
        return res;
1217
0
    }
1218
1219
284
    conn->rfd.fd = newSock;
1220
284
    conn->rfd.listenEvents = 0;
1221
284
    conn->rfd.es = &pcm->cm.eventSource;
1222
284
    conn->rfd.eventSourceCB = (UA_FDCallback)UDP_connectionSocketCallback;
1223
284
    conn->applicationCB = connectionCallback;
1224
284
    conn->application = application;
1225
284
    conn->context = context;
1226
1227
    /* Register the fd to trigger when output is possible (the connection is open) */
1228
284
    res = UA_EventLoopPOSIX_registerFD(el, &conn->rfd);
1229
284
    if(res != UA_STATUSCODE_GOOD) {
1230
0
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
1231
0
                       "UDP\t| Registering the socket for %s failed", hostname);
1232
0
        UA_close(newSock);
1233
0
        UA_free(conn);
1234
0
        return res;
1235
0
    }
1236
1237
    /* Register internally in the EventSource */
1238
284
    ZIP_INSERT(UA_FDTree, &pcm->fds, &conn->rfd);
1239
284
    pcm->fdsSize++;
1240
1241
284
    UA_LOG_INFO(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
1242
284
                "UDP %u\t| New connection to \"%s\" on port %s",
1243
284
                (unsigned)newSock, hostname, portStr);
1244
1245
    /* Signal the connection as opening. The connection fully opens in the next
1246
     * iteration of the EventLoop */
1247
284
    connectionCallback(&pcm->cm, (uintptr_t)newSock, application,
1248
284
                       &conn->context, UA_CONNECTIONSTATE_ESTABLISHED,
1249
284
                       &UA_KEYVALUEMAP_NULL, UA_BYTESTRING_NULL);
1250
1251
284
    return UA_STATUSCODE_GOOD;
1252
284
}
1253
1254
static UA_StatusCode
1255
UDP_openReceiveConnection(UA_POSIXConnectionManager *pcm, const UA_KeyValueMap *params,
1256
                          void *application, void *context,
1257
                          UA_ConnectionManager_connectionCallback connectionCallback,
1258
284
                          UA_Boolean validate) {
1259
284
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)pcm->cm.eventSource.eventLoop;
1260
284
    UA_LOCK_ASSERT(&el->elMutex);
1261
1262
    /* Get the port */
1263
284
    const UA_UInt16 *port = (const UA_UInt16*)
1264
284
        UA_KeyValueMap_getScalar(params, udpConnectionParams[UDP_PARAMINDEX_PORT].name,
1265
284
                                 &UA_TYPES[UA_TYPES_UINT16]);
1266
284
    UA_assert(port); /* checked before */
1267
1268
    /* Get the hostname configuration */
1269
284
    const UA_Variant *addrs =
1270
284
        UA_KeyValueMap_get(params, udpConnectionParams[UDP_PARAMINDEX_ADDR].name);
1271
284
    size_t addrsSize = 0;
1272
284
    if(addrs) {
1273
284
        UA_assert(addrs->type == &UA_TYPES[UA_TYPES_STRING]);
1274
284
        if(UA_Variant_isScalar(addrs))
1275
284
            addrsSize = 1;
1276
0
        else
1277
0
            addrsSize = addrs->arrayLength;
1278
284
    }
1279
1280
    /* No hostname configured -> listen on all interfaces */
1281
284
    if(addrsSize == 0) {
1282
0
        UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
1283
0
                     "UDP\t| Listening on all interfaces");
1284
0
        return UDP_registerListenSockets(pcm, NULL, *port, params, application,
1285
0
                                         context, connectionCallback, validate);
1286
0
    }
1287
1288
    /* Iterate over the configured hostnames */
1289
284
    UA_String *hostStrings = (UA_String*)addrs->data;
1290
568
    for(size_t i = 0; i < addrsSize; i++) {
1291
284
        char hn[UA_MAXHOSTNAME_LENGTH];
1292
284
        if(hostStrings[i].length >= sizeof(hn))
1293
0
            continue;
1294
284
        memcpy(hn, hostStrings[i].data, hostStrings->length);
1295
284
        hn[hostStrings->length] = '\0';
1296
284
        UA_StatusCode rv =
1297
284
            UDP_registerListenSockets(pcm, hn, *port, params, application,
1298
284
                                      context, connectionCallback, validate);
1299
284
        if(rv != UA_STATUSCODE_GOOD)
1300
0
            return rv;
1301
284
    }
1302
1303
284
    return UA_STATUSCODE_GOOD;
1304
284
}
1305
1306
static UA_StatusCode
1307
UDP_openConnection(UA_ConnectionManager *cm, const UA_KeyValueMap *params,
1308
                   void *application, void *context,
1309
568
                   UA_ConnectionManager_connectionCallback connectionCallback) {
1310
568
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)cm;
1311
568
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)cm->eventSource.eventLoop;
1312
568
    UA_LOCK(&el->elMutex);
1313
1314
568
    if(cm->eventSource.state != UA_EVENTSOURCESTATE_STARTED) {
1315
0
        UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
1316
0
                     "UDP\t| Cannot open a connection for a "
1317
0
                     "ConnectionManager that is not started");
1318
0
        UA_UNLOCK(&el->elMutex);
1319
0
        return UA_STATUSCODE_BADINTERNALERROR;
1320
0
    }
1321
1322
    /* Check the parameters */
1323
568
    UA_StatusCode res =
1324
568
        UA_KeyValueRestriction_validate(el->eventLoop.logger, "UDP",
1325
568
                                        udpConnectionParams,
1326
568
                                        UDP_PARAMETERSSIZE, params);
1327
568
    if(res != UA_STATUSCODE_GOOD) {
1328
0
        UA_UNLOCK(&el->elMutex);
1329
0
        return res;
1330
0
    }
1331
1332
568
    UA_Boolean validate = false;
1333
568
    const UA_Boolean *validationValue = (const UA_Boolean*)
1334
568
        UA_KeyValueMap_getScalar(params, udpConnectionParams[UDP_PARAMINDEX_VALIDATE].name,
1335
568
                                 &UA_TYPES[UA_TYPES_BOOLEAN]);
1336
568
    if(validationValue)
1337
0
        validate = *validationValue;
1338
1339
568
    UA_Boolean listen = false;
1340
568
    const UA_Boolean *listenValue = (const UA_Boolean*)
1341
568
        UA_KeyValueMap_getScalar(params, udpConnectionParams[UDP_PARAMINDEX_LISTEN].name,
1342
568
                                 &UA_TYPES[UA_TYPES_BOOLEAN]);
1343
568
    if(listenValue)
1344
568
        listen = *listenValue;
1345
1346
568
    if(listen) {
1347
284
        res = UDP_openReceiveConnection(pcm, params, application, context,
1348
284
                                        connectionCallback, validate);
1349
284
    } else {
1350
284
        res = UDP_openSendConnection(pcm, params, application, context,
1351
284
                                     connectionCallback, validate);
1352
284
    }
1353
568
    UA_UNLOCK(&el->elMutex);
1354
568
    return res;
1355
568
}
1356
1357
static UA_StatusCode
1358
547
UDP_eventSourceStart(UA_ConnectionManager *cm) {
1359
547
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)cm;
1360
547
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)cm->eventSource.eventLoop;
1361
547
    if(!el)
1362
0
        return UA_STATUSCODE_BADINTERNALERROR;
1363
1364
547
    UA_LOCK(&el->elMutex);
1365
1366
    /* Check the state */
1367
547
    if(cm->eventSource.state != UA_EVENTSOURCESTATE_STOPPED) {
1368
0
        UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
1369
0
                     "UDP\t| To start the ConnectionManager, "
1370
0
                     "it has to be registered in an EventLoop and not started");
1371
0
        UA_UNLOCK(&el->elMutex);
1372
0
        return UA_STATUSCODE_BADINTERNALERROR;
1373
0
    }
1374
1375
    /* Check the parameters */
1376
547
    UA_StatusCode res =
1377
547
        UA_KeyValueRestriction_validate(el->eventLoop.logger, "UDP",
1378
547
                                        udpManagerParams, UDP_MANAGERPARAMS,
1379
547
                                        &cm->eventSource.params);
1380
547
    if(res != UA_STATUSCODE_GOOD)
1381
0
        goto finish;
1382
1383
    /* Allocate the rx buffer */
1384
547
    res = UA_EventLoopPOSIX_allocateStaticBuffers(pcm);
1385
547
    if(res != UA_STATUSCODE_GOOD)
1386
0
        goto finish;
1387
1388
    /* Set the EventSource to the started state */
1389
547
    cm->eventSource.state = UA_EVENTSOURCESTATE_STARTED;
1390
1391
547
 finish:
1392
547
    UA_UNLOCK(&el->elMutex);
1393
547
    return res;
1394
547
}
1395
1396
static void *
1397
0
UDP_shutdownCB(void *application, UA_RegisteredFD *rfd) {
1398
0
    UA_ConnectionManager *cm = (UA_ConnectionManager*)application;
1399
0
    UDP_shutdown(cm, rfd);
1400
0
    return NULL;
1401
0
}
1402
1403
static void
1404
547
UDP_eventSourceStop(UA_ConnectionManager *cm) {
1405
547
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)cm;
1406
547
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)cm->eventSource.eventLoop;
1407
547
    (void)el;
1408
547
    UA_LOCK(&el->elMutex);
1409
1410
547
    UA_LOG_DEBUG(cm->eventSource.eventLoop->logger, UA_LOGCATEGORY_NETWORK,
1411
547
                 "UDP\t| Shutting down the ConnectionManager");
1412
1413
    /* Prevent new connections to open */
1414
547
    cm->eventSource.state = UA_EVENTSOURCESTATE_STOPPING;
1415
1416
    /* Shutdown all existing connection */
1417
547
    ZIP_ITER(UA_FDTree, &pcm->fds, UDP_shutdownCB, cm);
1418
1419
    /* Check if stopped once more (also checking inside UDP_close, but there we
1420
     * don't check if there is no rfd at all) */
1421
547
    UDP_checkStopped(pcm);
1422
1423
547
    UA_UNLOCK(&el->elMutex);
1424
547
}
1425
1426
static UA_StatusCode
1427
547
UDP_eventSourceDelete(UA_ConnectionManager *cm) {
1428
547
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)cm;
1429
547
    if(cm->eventSource.state >= UA_EVENTSOURCESTATE_STARTING) {
1430
0
        UA_LOG_ERROR(cm->eventSource.eventLoop->logger, UA_LOGCATEGORY_EVENTLOOP,
1431
0
                     "UDP\t| The EventSource must be stopped before it can be deleted");
1432
0
        return UA_STATUSCODE_BADINTERNALERROR;
1433
0
    }
1434
1435
547
    UA_ByteString_clear(&pcm->rxBuffer);
1436
547
    UA_ByteString_clear(&pcm->txBuffer);
1437
547
    UA_KeyValueMap_clear(&cm->eventSource.params);
1438
547
    UA_String_clear(&cm->eventSource.name);
1439
547
    UA_free(cm);
1440
1441
547
    return UA_STATUSCODE_GOOD;
1442
547
}
1443
1444
static const char *udpName = "udp";
1445
1446
UA_ConnectionManager *
1447
547
UA_ConnectionManager_new_POSIX_UDP(const UA_String eventSourceName) {
1448
547
    UA_POSIXConnectionManager *cm = (UA_POSIXConnectionManager*)
1449
547
        UA_calloc(1, sizeof(UA_POSIXConnectionManager));
1450
547
    if(!cm)
1451
0
        return NULL;
1452
1453
547
    cm->cm.eventSource.eventSourceType = UA_EVENTSOURCETYPE_CONNECTIONMANAGER;
1454
547
    UA_String_copy(&eventSourceName, &cm->cm.eventSource.name);
1455
547
    cm->cm.eventSource.start = (UA_StatusCode (*)(UA_EventSource *))UDP_eventSourceStart;
1456
547
    cm->cm.eventSource.stop = (void (*)(UA_EventSource *))UDP_eventSourceStop;
1457
547
    cm->cm.eventSource.free = (UA_StatusCode (*)(UA_EventSource *))UDP_eventSourceDelete;
1458
547
    cm->cm.protocol = UA_STRING((char*)(uintptr_t)udpName);
1459
547
    cm->cm.openConnection = UDP_openConnection;
1460
547
    cm->cm.allocNetworkBuffer = UA_EventLoopPOSIX_allocNetworkBuffer;
1461
547
    cm->cm.freeNetworkBuffer = UA_EventLoopPOSIX_freeNetworkBuffer;
1462
547
    cm->cm.sendWithConnection = UDP_sendWithConnection;
1463
547
    cm->cm.closeConnection = UDP_shutdownConnection;
1464
547
    return &cm->cm;
1465
547
}
1466
1467
#endif