/src/open62541_15/src/server/ua_server_utils.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 2016-2017 (c) Fraunhofer IOSB (Author: Julius Pfrommer) |
6 | | * Copyright 2016 (c) Lorenz Haas |
7 | | * Copyright 2017 (c) frax2222 |
8 | | * Copyright 2017 (c) Florian Palm |
9 | | * Copyright 2017-2018 (c) Stefan Profanter, fortiss GmbH |
10 | | * Copyright 2017 (c) Julian Grothoff |
11 | | */ |
12 | | |
13 | | #include "ua_server_internal.h" |
14 | | |
15 | | /****************************/ |
16 | | /* Custom DataType Handling */ |
17 | | /****************************/ |
18 | | |
19 | | const UA_DataTypeArray * |
20 | 21.7k | serverCustomTypes(UA_Server *server) { |
21 | 21.7k | if(server->customTypes_internalSize == 0) |
22 | 21.7k | return server->config.customDataTypes; |
23 | 0 | server->customTypes_internal[server->customTypes_internalSize-1].next = server->config.customDataTypes; |
24 | 0 | return server->customTypes_internal; |
25 | 21.7k | } |
26 | | |
27 | | const UA_DataTypeArray * |
28 | 0 | UA_Server_getDataTypes(UA_Server *server) { |
29 | 0 | lockServer(server); |
30 | 0 | const UA_DataTypeArray * out = serverCustomTypes(server); |
31 | 0 | unlockServer(server); |
32 | 0 | return out; |
33 | 0 | } |
34 | | |
35 | | const UA_DataType * |
36 | 0 | UA_Server_findDataType(UA_Server *server, const UA_NodeId *typeId) { |
37 | 0 | return UA_findDataTypeWithCustom(typeId, serverCustomTypes(server)); |
38 | 0 | } |
39 | | |
40 | | /* DataTypes need a stable pointer. So we allocate an array of 64 datatypes. |
41 | | * When that is full we move the server->customTypes_internal into a |
42 | | * heap-structure that gets cleaned up with the server lifecycle. */ |
43 | | static UA_StatusCode |
44 | 0 | addDataType(UA_Server *server, UA_DataType *dt) { |
45 | | /* Allocate the space for the new DataType */ |
46 | 0 | #define TYPES_LIST_SIZE 64 |
47 | 0 | UA_DataTypeArray *current = NULL; |
48 | 0 | if(server->customTypes_internalSize > 0) |
49 | 0 | current = &server->customTypes_internal[server->customTypes_internalSize-1]; |
50 | 0 | if(!current || current->typesSize == TYPES_LIST_SIZE) { |
51 | | /* Increase the list-of-lists size */ |
52 | 0 | UA_DataTypeArray *lol = (UA_DataTypeArray*) |
53 | 0 | UA_realloc(server->customTypes_internal, |
54 | 0 | sizeof(UA_DataTypeArray) * (server->customTypes_internalSize+1)); |
55 | 0 | if(!lol) |
56 | 0 | return UA_STATUSCODE_BADOUTOFMEMORY; |
57 | 0 | memset(&lol[server->customTypes_internalSize], 0, sizeof(UA_DataTypeArray)); |
58 | 0 | server->customTypes_internal = lol; |
59 | 0 | server->customTypes_internalSize++; |
60 | | |
61 | | /* Update the next-pointers for the internal DataTypeArray */ |
62 | 0 | for(size_t i = 0; i < server->customTypes_internalSize-1; i++) |
63 | 0 | lol[i].next = &lol[i+1]; |
64 | | |
65 | | /* Add a new types list. With the space for the datatypes already appended */ |
66 | 0 | current = &server->customTypes_internal[server->customTypes_internalSize-1]; |
67 | 0 | current->types = (UA_DataType*)UA_calloc(TYPES_LIST_SIZE, sizeof(UA_DataType)); |
68 | 0 | current->typesSize = 0; |
69 | 0 | if(!current->types) { |
70 | 0 | server->customTypes_internalSize--; |
71 | 0 | return UA_STATUSCODE_BADOUTOFMEMORY; |
72 | 0 | } |
73 | 0 | } |
74 | | |
75 | | /* Move the datatype into the stable location in the server */ |
76 | 0 | current->types[current->typesSize] = *dt; |
77 | 0 | current->typesSize++; |
78 | 0 | return UA_STATUSCODE_GOOD; |
79 | 0 | } |
80 | | |
81 | | UA_StatusCode |
82 | | UA_Server_addDataType(UA_Server *server, const UA_NodeId parentNodeId, |
83 | 0 | const UA_DataType *type) { |
84 | | /* Check that the type does not already exist. We do not allow changes to |
85 | | * DataTypes once they are set. */ |
86 | 0 | if(UA_Server_findDataType(server, &type->typeId)) |
87 | 0 | return UA_STATUSCODE_BADNODEIDEXISTS; |
88 | | |
89 | | /* Make a copy of the UA_DataType */ |
90 | 0 | UA_DataType dt2; |
91 | 0 | UA_StatusCode res = UA_DataType_copy(type, &dt2); |
92 | 0 | if(res != UA_STATUSCODE_GOOD) |
93 | 0 | return res; |
94 | | |
95 | | /* Add the UA_DataType to the server */ |
96 | 0 | res = addDataType(server, &dt2); |
97 | 0 | if(res != UA_STATUSCODE_GOOD) |
98 | 0 | UA_DataType_clear(&dt2); |
99 | 0 | return res; |
100 | 0 | } |
101 | | |
102 | | UA_StatusCode |
103 | | UA_Server_addDataTypeFromDescription(UA_Server *server, |
104 | 0 | const UA_ExtensionObject *description) { |
105 | | /* Translate into a new UA_DataType */ |
106 | 0 | UA_DataType dt; |
107 | 0 | UA_StatusCode res = |
108 | 0 | UA_DataType_fromDescription(&dt, description, serverCustomTypes(server)); |
109 | 0 | if(res != UA_STATUSCODE_GOOD) |
110 | 0 | return res; |
111 | | |
112 | | /* Check that the type does not already exist. We do not allow changes to |
113 | | * DataTypes once they are set. */ |
114 | 0 | if(UA_Server_findDataType(server, &dt.typeId)) { |
115 | 0 | UA_DataType_clear(&dt); |
116 | 0 | return UA_STATUSCODE_BADNODEIDEXISTS; |
117 | 0 | } |
118 | | |
119 | | /* Add the UA_DataType to the server */ |
120 | 0 | res = addDataType(server, &dt); |
121 | 0 | if(res != UA_STATUSCODE_GOOD) |
122 | 0 | UA_DataType_clear(&dt); |
123 | 0 | return res; |
124 | 0 | } |
125 | | |
126 | | /********************************/ |
127 | | /* Information Model Operations */ |
128 | | /********************************/ |
129 | | |
130 | | struct ReturnTypeContext { |
131 | | UA_Server *server; |
132 | | UA_UInt32 attributeMask; |
133 | | UA_ReferenceTypeSet references; |
134 | | UA_BrowseDirection referenceDirections; |
135 | | }; |
136 | | |
137 | | static void * |
138 | 15.4M | returnFirstType(void *context, UA_ReferenceTarget *t) { |
139 | 15.4M | struct ReturnTypeContext *ctx = (struct ReturnTypeContext*)context; |
140 | | /* Don't release the node that is returned. |
141 | | * Continues to iterate if NULL is returned. */ |
142 | 15.4M | return (void *)(uintptr_t)UA_NODESTORE_GETFROMREF_SELECTIVE( |
143 | 15.4M | ctx->server, t->targetId, ctx->attributeMask, ctx->references, |
144 | 15.4M | ctx->referenceDirections); |
145 | 15.4M | } |
146 | | |
147 | | const UA_Node * |
148 | | getNodeType(UA_Server *server, const UA_NodeHead *head, |
149 | | UA_UInt32 attributeMask, UA_ReferenceTypeSet references, |
150 | 15.4M | UA_BrowseDirection referenceDirections) { |
151 | | /* The reference to the parent is different for variable and variabletype */ |
152 | 15.4M | UA_Byte parentRefIndex; |
153 | 15.4M | UA_Boolean inverse; |
154 | 15.4M | switch(head->nodeClass) { |
155 | 1.30M | case UA_NODECLASS_OBJECT: |
156 | 15.1M | case UA_NODECLASS_VARIABLE: |
157 | 15.1M | parentRefIndex = UA_REFERENCETYPEINDEX_HASTYPEDEFINITION; |
158 | 15.1M | inverse = false; |
159 | 15.1M | break; |
160 | 0 | case UA_NODECLASS_OBJECTTYPE: |
161 | 326k | case UA_NODECLASS_VARIABLETYPE: |
162 | 326k | case UA_NODECLASS_REFERENCETYPE: |
163 | 326k | case UA_NODECLASS_DATATYPE: |
164 | 326k | parentRefIndex = UA_REFERENCETYPEINDEX_HASSUBTYPE; |
165 | 326k | inverse = true; |
166 | 326k | break; |
167 | 0 | default: |
168 | 0 | return NULL; |
169 | 15.4M | } |
170 | | |
171 | 15.4M | struct ReturnTypeContext ctx; |
172 | 15.4M | ctx.server = server; |
173 | 15.4M | ctx.attributeMask = attributeMask; |
174 | 15.4M | ctx.references = references; |
175 | 15.4M | ctx.referenceDirections = referenceDirections; |
176 | | |
177 | | /* Return the first matching candidate */ |
178 | 31.3M | for(size_t i = 0; i < head->referencesSize; ++i) { |
179 | 31.3M | UA_NodeReferenceKind *rk = &head->references[i]; |
180 | 31.3M | if(rk->isInverse != inverse) |
181 | 14.9M | continue; |
182 | 16.3M | if(rk->referenceTypeIndex != parentRefIndex) |
183 | 954k | continue; |
184 | 15.4M | const UA_Node *type = (const UA_Node*) |
185 | 15.4M | UA_NodeReferenceKind_iterate(rk, returnFirstType, &ctx); |
186 | 15.4M | if(type) |
187 | 15.4M | return type; |
188 | 15.4M | } |
189 | | |
190 | 17.6k | return NULL; |
191 | 15.4M | } |
192 | | |
193 | | UA_Boolean |
194 | 9.65k | UA_Node_hasSubTypeOrInstances(const UA_NodeHead *head) { |
195 | 30.2k | for(size_t i = 0; i < head->referencesSize; ++i) { |
196 | 20.6k | if(head->references[i].isInverse == false && |
197 | 10.9k | head->references[i].referenceTypeIndex == UA_REFERENCETYPEINDEX_HASSUBTYPE) |
198 | 2 | return true; |
199 | 20.6k | if(head->references[i].isInverse == true && |
200 | 9.65k | head->references[i].referenceTypeIndex == UA_REFERENCETYPEINDEX_HASTYPEDEFINITION) |
201 | 1 | return true; |
202 | 20.6k | } |
203 | 9.65k | return false; |
204 | 9.65k | } |
205 | | |
206 | | UA_StatusCode |
207 | | getTypeAndInterfaceHierarchy(UA_Server *server, const UA_NodeId *leafNode, |
208 | | UA_Boolean includeLeaf, UA_NodeId **typeHierarchy, |
209 | 8.80M | size_t *typeHierarchySize) { |
210 | 8.80M | UA_ReferenceTypeSet hastype = UA_REFTYPESET(UA_REFERENCETYPEINDEX_HASTYPEDEFINITION); |
211 | 8.80M | UA_ReferenceTypeSet hassubtype = UA_REFTYPESET(UA_REFERENCETYPEINDEX_HASSUBTYPE); |
212 | 8.80M | UA_ReferenceTypeSet hasinterface = UA_REFTYPESET(UA_REFERENCETYPEINDEX_HASINTERFACE); |
213 | | |
214 | | /* Initialize the tree and add the leaf */ |
215 | 8.80M | RefTree rt; |
216 | 8.80M | UA_StatusCode res = RefTree_init(&rt); |
217 | 8.80M | if(res != UA_STATUSCODE_GOOD) |
218 | 0 | return res; |
219 | 8.80M | res = RefTree_addNodeId(&rt, leafNode, NULL); |
220 | 8.80M | if(res != UA_STATUSCODE_GOOD) |
221 | 0 | goto errout; |
222 | | |
223 | | /* Get all types */ |
224 | 8.80M | res = browseRecursiveRefTree(server, &rt, UA_BROWSEDIRECTION_FORWARD, &hastype, |
225 | 8.80M | UA_NODECLASS_OBJECTTYPE | UA_NODECLASS_VARIABLETYPE); |
226 | 8.80M | if(res != UA_STATUSCODE_GOOD) |
227 | 0 | goto errout; |
228 | | |
229 | | /* Get all super types */ |
230 | 8.80M | res = browseRecursiveRefTree(server, &rt, UA_BROWSEDIRECTION_INVERSE, &hassubtype, |
231 | 8.80M | UA_NODECLASS_OBJECTTYPE | UA_NODECLASS_VARIABLETYPE); |
232 | 8.80M | if(res != UA_STATUSCODE_GOOD) |
233 | 0 | goto errout; |
234 | | |
235 | | /* Get all interfaces */ |
236 | 8.80M | res = browseRecursiveRefTree(server, &rt, UA_BROWSEDIRECTION_FORWARD, &hasinterface, |
237 | 8.80M | UA_NODECLASS_OBJECTTYPE | UA_NODECLASS_VARIABLETYPE); |
238 | | |
239 | 8.80M | errout: |
240 | 8.80M | if(res != UA_STATUSCODE_GOOD || rt.size == 0) { |
241 | 0 | RefTree_clear(&rt); |
242 | 0 | return res; |
243 | 0 | } |
244 | | |
245 | | /* Make the array of ExpandedNodeId into an array of NodeId */ |
246 | 8.80M | UA_NodeId *outArray = (UA_NodeId*)rt.targets; |
247 | 8.80M | size_t pos = 0; |
248 | 26.9M | for(size_t i = 0; i < rt.size; i++) { |
249 | 18.1M | UA_NodeId *n = &outArray[pos]; |
250 | 18.1M | UA_ExpandedNodeId *e = &rt.targets[i]; |
251 | 18.1M | if(!UA_ExpandedNodeId_isLocal(e)) { |
252 | 0 | UA_ExpandedNodeId_clear(e); |
253 | 0 | continue; |
254 | 0 | } |
255 | 18.1M | *n = e->nodeId; |
256 | 18.1M | UA_String_clear(&e->namespaceUri); |
257 | 18.1M | pos++; |
258 | 18.1M | } |
259 | | |
260 | 8.80M | *typeHierarchySize = pos; |
261 | 8.80M | *typeHierarchy = outArray; |
262 | 8.80M | return UA_STATUSCODE_GOOD; |
263 | 8.80M | } |
264 | | |
265 | | UA_StatusCode |
266 | | getAllInterfaces(UA_Server *server, const UA_NodeId *objectNode, |
267 | 947k | UA_NodeId **interfaceNodes, size_t *interfaceNodesSize) { |
268 | 947k | UA_ReferenceTypeSet hastype = UA_REFTYPESET(UA_REFERENCETYPEINDEX_HASTYPEDEFINITION); |
269 | 947k | UA_ReferenceTypeSet hassubtype = UA_REFTYPESET(UA_REFERENCETYPEINDEX_HASSUBTYPE); |
270 | 947k | UA_ReferenceTypeSet hasinterface = UA_REFTYPESET(UA_REFERENCETYPEINDEX_HASINTERFACE); |
271 | | |
272 | | /* Initialize the tree and add the leaf */ |
273 | 947k | size_t beforeInterfaces = 0; |
274 | 947k | RefTree rt; |
275 | 947k | UA_StatusCode res = RefTree_init(&rt); |
276 | 947k | if(res != UA_STATUSCODE_GOOD) |
277 | 0 | return res; |
278 | 947k | res = RefTree_addNodeId(&rt, objectNode, NULL); |
279 | 947k | if(res != UA_STATUSCODE_GOOD) |
280 | 0 | goto errout; |
281 | | |
282 | | /* Get all types */ |
283 | 947k | res = browseRecursiveRefTree(server, &rt, UA_BROWSEDIRECTION_FORWARD, &hastype, |
284 | 947k | UA_NODECLASS_OBJECTTYPE | UA_NODECLASS_VARIABLETYPE); |
285 | 947k | if(res != UA_STATUSCODE_GOOD) |
286 | 0 | goto errout; |
287 | | |
288 | | /* Get all super types */ |
289 | 947k | res = browseRecursiveRefTree(server, &rt, UA_BROWSEDIRECTION_INVERSE, &hassubtype, |
290 | 947k | UA_NODECLASS_OBJECTTYPE | UA_NODECLASS_VARIABLETYPE); |
291 | 947k | if(res != UA_STATUSCODE_GOOD) |
292 | 0 | goto errout; |
293 | | |
294 | | /* Get all interfaces */ |
295 | 947k | beforeInterfaces = rt.size; /* Return only the interfaces */ |
296 | 947k | res = browseRecursiveRefTree(server, &rt, UA_BROWSEDIRECTION_FORWARD, &hasinterface, |
297 | 947k | UA_NODECLASS_OBJECTTYPE | UA_NODECLASS_VARIABLETYPE); |
298 | | |
299 | 947k | errout: |
300 | 947k | if(res != UA_STATUSCODE_GOOD || rt.size == 0) { |
301 | 0 | RefTree_clear(&rt); |
302 | 0 | return res; |
303 | 0 | } |
304 | | |
305 | | /* Make the array of ExpandedNodeId into an array of NodeId */ |
306 | 947k | UA_NodeId *outArray = (UA_NodeId*)rt.targets; |
307 | 947k | size_t pos = 0; |
308 | 3.87M | for(size_t i = 0; i < rt.size; i++) { |
309 | 2.93M | UA_NodeId *n = &outArray[pos]; |
310 | 2.93M | UA_ExpandedNodeId *e = &rt.targets[i]; |
311 | 2.93M | if(i < beforeInterfaces || !UA_ExpandedNodeId_isLocal(e)) { |
312 | 2.93M | UA_ExpandedNodeId_clear(e); |
313 | 2.93M | continue; |
314 | 2.93M | } |
315 | 0 | *n = e->nodeId; |
316 | 0 | UA_String_clear(&e->namespaceUri); |
317 | 0 | pos++; |
318 | 0 | } |
319 | | |
320 | | /* No interfaces found */ |
321 | 947k | if(pos == 0) { |
322 | 947k | RefTree_clear(&rt); |
323 | 947k | outArray = NULL; |
324 | 947k | } |
325 | | |
326 | 947k | *interfaceNodesSize = pos; |
327 | 947k | *interfaceNodes = outArray; |
328 | 947k | return UA_STATUSCODE_GOOD; |
329 | 947k | } |
330 | | |
331 | | /* Get the node, make the changes and release */ |
332 | | UA_StatusCode |
333 | | editNode(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId, |
334 | | UA_UInt32 attributeMask, UA_ReferenceTypeSet references, |
335 | | UA_BrowseDirection referenceDirections, |
336 | 14.8M | UA_EditNodeCallback callback, void *data) { |
337 | 14.8M | UA_Node *node = |
338 | 14.8M | UA_NODESTORE_GET_EDIT_SELECTIVE(server, nodeId, attributeMask, |
339 | 14.8M | references, referenceDirections); |
340 | 14.8M | if(!node) |
341 | 12.5k | return UA_STATUSCODE_BADNODEIDUNKNOWN; |
342 | 14.8M | UA_StatusCode retval = callback(server, session, node, data); |
343 | 14.8M | UA_NODESTORE_RELEASE(server, node); |
344 | 14.8M | return retval; |
345 | 14.8M | } |
346 | | |
347 | | /**************************/ |
348 | | /* Certificate Validation */ |
349 | | /**************************/ |
350 | | |
351 | | UA_StatusCode |
352 | | validateCertificate(UA_Server *server, UA_CertificateGroup *cg, |
353 | | UA_SecureChannel *channel, UA_Session *session, |
354 | | const char *logPrefix, |
355 | | const UA_ApplicationDescription *ad, |
356 | 0 | const UA_ByteString certificate) { |
357 | | /* Verify the ApplicationUri */ |
358 | 0 | UA_StatusCode res = UA_STATUSCODE_GOOD; |
359 | 0 | if(ad) { |
360 | 0 | res = UA_CertificateUtils_verifyApplicationUri(&certificate, |
361 | 0 | &ad->applicationUri); |
362 | 0 | if(res != UA_STATUSCODE_GOOD) { |
363 | 0 | if(server->config.allowAllCertificateUris <= UA_RULEHANDLING_WARN) { |
364 | 0 | if(session) { |
365 | 0 | UA_LOG_ERROR_SESSION(server->config.logging, session, |
366 | 0 | "%s: The client's ApplicationUri " |
367 | 0 | "could not be verified against the " |
368 | 0 | "ApplicationUri %S from the client's " |
369 | 0 | "ApplicationDescription", logPrefix, |
370 | 0 | ad->applicationUri); |
371 | 0 | } else if(channel) { |
372 | 0 | UA_LOG_ERROR_CHANNEL(server->config.logging, channel, |
373 | 0 | "%s: The client certificate's ApplicationUri " |
374 | 0 | "could not be verified against the " |
375 | 0 | "ApplicationUri %S from the client's " |
376 | 0 | "ApplicationDescription", logPrefix, |
377 | 0 | ad->applicationUri); |
378 | 0 | } else { |
379 | 0 | UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER, |
380 | 0 | "%s: The server certificate's ApplicationUri " |
381 | 0 | "could not be verified against the " |
382 | 0 | "ApplicationUri %S from its " |
383 | 0 | "ApplicationDescription", logPrefix, |
384 | 0 | ad->applicationUri); |
385 | 0 | } |
386 | 0 | } |
387 | 0 | if(server->config.allowAllCertificateUris <= UA_RULEHANDLING_ABORT) |
388 | 0 | return UA_STATUSCODE_BADCERTIFICATEINVALID; |
389 | 0 | } |
390 | 0 | } |
391 | | |
392 | 0 | if(!cg->verifyCertificate) { |
393 | 0 | UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER, |
394 | 0 | "%s: Could not validate the certificate " |
395 | 0 | "as the CertificateGroup is not configured", logPrefix); |
396 | 0 | return UA_STATUSCODE_BADINTERNALERROR; |
397 | 0 | } |
398 | | |
399 | | /* Validate in the CertificateGroup */ |
400 | 0 | res = cg->verifyCertificate(cg, &certificate); |
401 | 0 | if(res != UA_STATUSCODE_GOOD) { |
402 | 0 | const char *descr = UA_StatusCode_name(res); |
403 | 0 | if(session) { |
404 | 0 | UA_LOG_ERROR_SESSION(server->config.logging, session, |
405 | 0 | "%s: The client certificate failed the verification " |
406 | 0 | "in the CertificateGroup with StatusCode %s", |
407 | 0 | logPrefix, descr); |
408 | 0 | } else if(channel) { |
409 | 0 | UA_LOG_ERROR_CHANNEL(server->config.logging, channel, |
410 | 0 | "%s: The client certificate failed the verification " |
411 | 0 | "in the CertificateGroup with StatusCode %s", |
412 | 0 | logPrefix, descr); |
413 | 0 | } else { |
414 | 0 | UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER, |
415 | 0 | "%s: The client certificate failed the verification " |
416 | 0 | "in the CertificateGroup with StatusCode %s", |
417 | 0 | logPrefix, descr); |
418 | 0 | } |
419 | 0 | } |
420 | 0 | return res; |
421 | 0 | } |
422 | | |
423 | | /*********************************/ |
424 | | /* Default attribute definitions */ |
425 | | /*********************************/ |
426 | | |
427 | | const UA_ObjectAttributes UA_ObjectAttributes_default = { |
428 | | 0, /* specifiedAttributes */ |
429 | | {{0, NULL}, {0, NULL}}, /* displayName */ |
430 | | {{0, NULL}, {0, NULL}}, /* description */ |
431 | | 0, 0, /* writeMask (userWriteMask) */ |
432 | | 0 /* eventNotifier */ |
433 | | }; |
434 | | |
435 | | const UA_VariableAttributes UA_VariableAttributes_default = { |
436 | | 0, /* specifiedAttributes */ |
437 | | {{0, NULL}, {0, NULL}}, /* displayName */ |
438 | | {{0, NULL}, {0, NULL}}, /* description */ |
439 | | 0, 0, /* writeMask (userWriteMask) */ |
440 | | {NULL, UA_VARIANT_DATA, |
441 | | 0, NULL, 0, NULL}, /* value */ |
442 | | {0, UA_NODEIDTYPE_NUMERIC, |
443 | | {UA_NS0ID_BASEDATATYPE}}, /* dataType */ |
444 | | UA_VALUERANK_ANY, /* valueRank */ |
445 | | 0, NULL, /* arrayDimensions */ |
446 | | UA_ACCESSLEVELMASK_READ | /* accessLevel */ |
447 | | UA_ACCESSLEVELMASK_STATUSWRITE | |
448 | | UA_ACCESSLEVELMASK_TIMESTAMPWRITE, |
449 | | 0, /* userAccessLevel */ |
450 | | 0.0, /* minimumSamplingInterval */ |
451 | | false /* historizing */ |
452 | | }; |
453 | | |
454 | | const UA_MethodAttributes UA_MethodAttributes_default = { |
455 | | 0, /* specifiedAttributes */ |
456 | | {{0, NULL}, {0, NULL}}, /* displayName */ |
457 | | {{0, NULL}, {0, NULL}}, /* description */ |
458 | | 0, 0, /* writeMask (userWriteMask) */ |
459 | | true, true /* executable (userExecutable) */ |
460 | | }; |
461 | | |
462 | | const UA_ObjectTypeAttributes UA_ObjectTypeAttributes_default = { |
463 | | 0, /* specifiedAttributes */ |
464 | | {{0, NULL}, {0, NULL}}, /* displayName */ |
465 | | {{0, NULL}, {0, NULL}}, /* description */ |
466 | | 0, 0, /* writeMask (userWriteMask) */ |
467 | | false /* isAbstract */ |
468 | | }; |
469 | | |
470 | | const UA_VariableTypeAttributes UA_VariableTypeAttributes_default = { |
471 | | 0, /* specifiedAttributes */ |
472 | | {{0, NULL}, {0, NULL}}, /* displayName */ |
473 | | {{0, NULL}, {0, NULL}}, /* description */ |
474 | | 0, 0, /* writeMask (userWriteMask) */ |
475 | | {NULL, UA_VARIANT_DATA, |
476 | | 0, NULL, 0, NULL}, /* value */ |
477 | | {0, UA_NODEIDTYPE_NUMERIC, |
478 | | {UA_NS0ID_BASEDATATYPE}}, /* dataType */ |
479 | | UA_VALUERANK_ANY, /* valueRank */ |
480 | | 0, NULL, /* arrayDimensions */ |
481 | | false /* isAbstract */ |
482 | | }; |
483 | | |
484 | | const UA_ReferenceTypeAttributes UA_ReferenceTypeAttributes_default = { |
485 | | 0, /* specifiedAttributes */ |
486 | | {{0, NULL}, {0, NULL}}, /* displayName */ |
487 | | {{0, NULL}, {0, NULL}}, /* description */ |
488 | | 0, 0, /* writeMask (userWriteMask) */ |
489 | | false, /* isAbstract */ |
490 | | false, /* symmetric */ |
491 | | {{0, NULL}, {0, NULL}} /* inverseName */ |
492 | | }; |
493 | | |
494 | | const UA_DataTypeAttributes UA_DataTypeAttributes_default = { |
495 | | 0, /* specifiedAttributes */ |
496 | | {{0, NULL}, {0, NULL}}, /* displayName */ |
497 | | {{0, NULL}, {0, NULL}}, /* description */ |
498 | | 0, 0, /* writeMask (userWriteMask) */ |
499 | | false /* isAbstract */ |
500 | | }; |
501 | | |
502 | | const UA_ViewAttributes UA_ViewAttributes_default = { |
503 | | 0, /* specifiedAttributes */ |
504 | | {{0, NULL}, {0, NULL}}, /* displayName */ |
505 | | {{0, NULL}, {0, NULL}}, /* description */ |
506 | | 0, 0, /* writeMask (userWriteMask) */ |
507 | | false, /* containsNoLoops */ |
508 | | 0 /* eventNotifier */ |
509 | | }; |
510 | | |