/src/open62541/src/server/ua_server_ns0.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 2017-2022 (c) Fraunhofer IOSB (Author: Julius Pfrommer) |
6 | | * Copyright 2017 (c) Stefan Profanter, fortiss GmbH |
7 | | * Copyright 2017 (c) Thomas Bender |
8 | | * Copyright 2017 (c) Julian Grothoff |
9 | | * Copyright 2017 (c) Henrik Norrman |
10 | | * Copyright 2018 (c) Fabian Arndt, Root-Core |
11 | | * Copyright 2019 (c) Kalycito Infotech Private Limited |
12 | | * Copyright 2021 (c) Christian von Arnim, ISW University of Stuttgart (for VDW and umati) |
13 | | * Copyright 2023 (c) Fraunhofer IOSB (Author: Andreas Ebner) |
14 | | */ |
15 | | |
16 | | #include "open62541/namespace0_generated.h" |
17 | | |
18 | | #include "ua_server_internal.h" |
19 | | #include "ua_session.h" |
20 | | #include "ua_subscription.h" |
21 | | |
22 | | static UA_StatusCode |
23 | | ns0_addNode_raw(UA_Server *server, UA_NodeClass nodeClass, |
24 | | UA_UInt32 nodeId, char *name, void *attributes, |
25 | 3.30k | const UA_DataType *attributesType) { |
26 | 3.30k | UA_AddNodesItem item; |
27 | 3.30k | UA_AddNodesItem_init(&item); |
28 | 3.30k | item.nodeClass = nodeClass; |
29 | 3.30k | item.requestedNewNodeId.nodeId = UA_NODEID_NUMERIC(0, nodeId); |
30 | 3.30k | item.browseName = UA_QUALIFIEDNAME(0, name); |
31 | 3.30k | UA_ExtensionObject_setValueNoDelete(&item.nodeAttributes, |
32 | 3.30k | attributes, attributesType); |
33 | 3.30k | return addNode_raw(server, &server->adminSession, NULL, &item, NULL); |
34 | 3.30k | } |
35 | | |
36 | | static UA_StatusCode |
37 | | ns0_addNode_finish(UA_Server *server, UA_UInt32 nodeId, |
38 | 3.30k | UA_UInt32 parentNodeId, UA_UInt32 referenceTypeId) { |
39 | 3.30k | const UA_NodeId sourceId = UA_NODEID_NUMERIC(0, nodeId); |
40 | 3.30k | const UA_NodeId refTypeId = UA_NODEID_NUMERIC(0, referenceTypeId); |
41 | 3.30k | const UA_NodeId targetId = UA_NODEID_NUMERIC(0, parentNodeId); |
42 | 3.30k | UA_StatusCode retval = addRef(server, sourceId, refTypeId, targetId, false); |
43 | 3.30k | if(retval != UA_STATUSCODE_GOOD) |
44 | 0 | return retval; |
45 | 3.30k | return addNode_finish(server, &server->adminSession, &sourceId); |
46 | 3.30k | } |
47 | | |
48 | | static UA_StatusCode |
49 | | addObjectNode(UA_Server *server, char* name, UA_UInt32 objectid, |
50 | 4.95k | UA_UInt32 parentid, UA_UInt32 referenceid, UA_UInt32 type_id) { |
51 | 4.95k | UA_ObjectAttributes object_attr = UA_ObjectAttributes_default; |
52 | 4.95k | object_attr.displayName = UA_LOCALIZEDTEXT("", name); |
53 | 4.95k | return addNode(server, UA_NODECLASS_OBJECT, UA_NODEID_NUMERIC(0, objectid), |
54 | 4.95k | UA_NODEID_NUMERIC(0, parentid), UA_NODEID_NUMERIC(0, referenceid), |
55 | 4.95k | UA_QUALIFIEDNAME(0, name), UA_NODEID_NUMERIC(0, type_id), |
56 | 4.95k | &object_attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES], |
57 | 4.95k | NULL, NULL); |
58 | 4.95k | } |
59 | | |
60 | | static UA_StatusCode |
61 | | addReferenceTypeNode(UA_Server *server, char* name, char *inverseName, UA_UInt32 referencetypeid, |
62 | 8.26k | UA_Boolean isabstract, UA_Boolean symmetric, UA_UInt32 parentid) { |
63 | 8.26k | UA_ReferenceTypeAttributes reference_attr = UA_ReferenceTypeAttributes_default; |
64 | 8.26k | reference_attr.displayName = UA_LOCALIZEDTEXT("", name); |
65 | 8.26k | reference_attr.isAbstract = isabstract; |
66 | 8.26k | reference_attr.symmetric = symmetric; |
67 | 8.26k | if(inverseName) |
68 | 6.61k | reference_attr.inverseName = UA_LOCALIZEDTEXT("", inverseName); |
69 | 8.26k | return addNode(server, UA_NODECLASS_REFERENCETYPE, UA_NODEID_NUMERIC(0, referencetypeid), |
70 | 8.26k | UA_NODEID_NUMERIC(0, parentid), UA_NODEID_NULL, UA_QUALIFIEDNAME(0, name), |
71 | 8.26k | UA_NODEID_NULL, &reference_attr, |
72 | 8.26k | &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES], NULL, NULL); |
73 | 8.26k | } |
74 | | |
75 | | /***************************/ |
76 | | /* Bootstrap NS0 hierarchy */ |
77 | | /***************************/ |
78 | | |
79 | | /* Creates the basic nodes which are expected by the nodeset compiler to be |
80 | | * already created. This is necessary to reduce the dependencies for the nodeset |
81 | | * compiler. */ |
82 | | static UA_StatusCode |
83 | 551 | createNS0_base(UA_Server *server) { |
84 | | /* Bootstrap ReferenceTypes. The order of these is important for the |
85 | | * ReferenceTypeIndex. The ReferenceTypeIndex is created with the raw node. |
86 | | * The ReferenceTypeSet of subtypes for every ReferenceType is created |
87 | | * during the call to AddNode_finish. */ |
88 | 551 | UA_StatusCode ret = UA_STATUSCODE_GOOD; |
89 | 551 | UA_ReferenceTypeAttributes references_attr = UA_ReferenceTypeAttributes_default; |
90 | 551 | references_attr.displayName = UA_LOCALIZEDTEXT("", "References"); |
91 | 551 | references_attr.isAbstract = true; |
92 | 551 | references_attr.symmetric = true; |
93 | 551 | references_attr.inverseName = UA_LOCALIZEDTEXT("", "References"); |
94 | 551 | ret |= ns0_addNode_raw(server, UA_NODECLASS_REFERENCETYPE, UA_NS0ID_REFERENCES, "References", |
95 | 551 | &references_attr, &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES]); |
96 | | |
97 | 551 | UA_ReferenceTypeAttributes hassubtype_attr = UA_ReferenceTypeAttributes_default; |
98 | 551 | hassubtype_attr.displayName = UA_LOCALIZEDTEXT("", "HasSubtype"); |
99 | 551 | hassubtype_attr.isAbstract = false; |
100 | 551 | hassubtype_attr.symmetric = false; |
101 | 551 | hassubtype_attr.inverseName = UA_LOCALIZEDTEXT("", "SubtypeOf"); |
102 | 551 | ret |= ns0_addNode_raw(server, UA_NODECLASS_REFERENCETYPE, UA_NS0ID_HASSUBTYPE, "HasSubtype", |
103 | 551 | &hassubtype_attr, &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES]); |
104 | | |
105 | 551 | UA_ReferenceTypeAttributes aggregates_attr = UA_ReferenceTypeAttributes_default; |
106 | 551 | aggregates_attr.displayName = UA_LOCALIZEDTEXT("", "Aggregates"); |
107 | 551 | aggregates_attr.isAbstract = true; |
108 | 551 | aggregates_attr.symmetric = false; |
109 | 551 | aggregates_attr.inverseName = UA_LOCALIZEDTEXT("", "AggregatedBy"); |
110 | 551 | ret |= ns0_addNode_raw(server, UA_NODECLASS_REFERENCETYPE, UA_NS0ID_AGGREGATES, "Aggregates", |
111 | 551 | &aggregates_attr, &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES]); |
112 | | |
113 | 551 | ret |= addReferenceTypeNode(server, "HierarchicalReferences", NULL, |
114 | 551 | UA_NS0ID_HIERARCHICALREFERENCES, true, false, UA_NS0ID_REFERENCES); |
115 | | |
116 | 551 | ret |= addReferenceTypeNode(server, "NonHierarchicalReferences", NULL, |
117 | 551 | UA_NS0ID_NONHIERARCHICALREFERENCES, true, true, UA_NS0ID_REFERENCES); |
118 | | |
119 | 551 | ret |= addReferenceTypeNode(server, "HasChild", NULL, UA_NS0ID_HASCHILD, |
120 | 551 | true, false, UA_NS0ID_HIERARCHICALREFERENCES); |
121 | | |
122 | 551 | ret |= addReferenceTypeNode(server, "Organizes", "OrganizedBy", UA_NS0ID_ORGANIZES, |
123 | 551 | false, false, UA_NS0ID_HIERARCHICALREFERENCES); |
124 | | |
125 | 551 | ret |= addReferenceTypeNode(server, "HasEventSource", "EventSourceOf", UA_NS0ID_HASEVENTSOURCE, |
126 | 551 | false, false, UA_NS0ID_HIERARCHICALREFERENCES); |
127 | | |
128 | 551 | ret |= addReferenceTypeNode(server, "HasModellingRule", "ModellingRuleOf", UA_NS0ID_HASMODELLINGRULE, |
129 | 551 | false, false, UA_NS0ID_NONHIERARCHICALREFERENCES); |
130 | | |
131 | 551 | ret |= addReferenceTypeNode(server, "HasEncoding", "EncodingOf", UA_NS0ID_HASENCODING, |
132 | 551 | false, false, UA_NS0ID_NONHIERARCHICALREFERENCES); |
133 | | |
134 | 551 | ret |= addReferenceTypeNode(server, "HasDescription", "DescriptionOf", UA_NS0ID_HASDESCRIPTION, |
135 | 551 | false, false, UA_NS0ID_NONHIERARCHICALREFERENCES); |
136 | | |
137 | 551 | ret |= addReferenceTypeNode(server, "HasTypeDefinition", "TypeDefinitionOf", UA_NS0ID_HASTYPEDEFINITION, |
138 | 551 | false, false, UA_NS0ID_NONHIERARCHICALREFERENCES); |
139 | | |
140 | 551 | ret |= addReferenceTypeNode(server, "GeneratesEvent", "GeneratedBy", UA_NS0ID_GENERATESEVENT, |
141 | 551 | false, false, UA_NS0ID_NONHIERARCHICALREFERENCES); |
142 | | |
143 | | /* Complete bootstrap of Aggregates */ |
144 | 551 | ret |= ns0_addNode_finish(server, UA_NS0ID_AGGREGATES, UA_NS0ID_HASCHILD, UA_NS0ID_HASSUBTYPE); |
145 | | |
146 | | /* Complete bootstrap of HasSubtype */ |
147 | 551 | ret |= ns0_addNode_finish(server, UA_NS0ID_HASSUBTYPE, UA_NS0ID_HASCHILD, UA_NS0ID_HASSUBTYPE); |
148 | | |
149 | 551 | ret |= addReferenceTypeNode(server, "HasProperty", "PropertyOf", UA_NS0ID_HASPROPERTY, |
150 | 551 | false, false, UA_NS0ID_AGGREGATES); |
151 | | |
152 | 551 | ret |= addReferenceTypeNode(server, "HasComponent", "ComponentOf", UA_NS0ID_HASCOMPONENT, |
153 | 551 | false, false, UA_NS0ID_AGGREGATES); |
154 | | |
155 | 551 | ret |= addReferenceTypeNode(server, "HasNotifier", "NotifierOf", UA_NS0ID_HASNOTIFIER, |
156 | 551 | false, false, UA_NS0ID_HASEVENTSOURCE); |
157 | | |
158 | 551 | ret |= addReferenceTypeNode(server, "HasOrderedComponent", "OrderedComponentOf", |
159 | 551 | UA_NS0ID_HASORDEREDCOMPONENT, false, false, UA_NS0ID_HASCOMPONENT); |
160 | | |
161 | 551 | ret |= addReferenceTypeNode(server, "HasInterface", "InterfaceOf", |
162 | 551 | UA_NS0ID_HASINTERFACE, false, false, UA_NS0ID_NONHIERARCHICALREFERENCES); |
163 | | |
164 | | /**************/ |
165 | | /* Data Types */ |
166 | | /**************/ |
167 | | |
168 | | /* Bootstrap BaseDataType */ |
169 | 551 | UA_DataTypeAttributes basedatatype_attr = UA_DataTypeAttributes_default; |
170 | 551 | basedatatype_attr.displayName = UA_LOCALIZEDTEXT("", "BaseDataType"); |
171 | 551 | basedatatype_attr.isAbstract = true; |
172 | 551 | ret |= ns0_addNode_raw(server, UA_NODECLASS_DATATYPE, UA_NS0ID_BASEDATATYPE, "BaseDataType", |
173 | 551 | &basedatatype_attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES]); |
174 | | |
175 | | /*****************/ |
176 | | /* VariableTypes */ |
177 | | /*****************/ |
178 | | |
179 | 551 | UA_VariableTypeAttributes basevar_attr = UA_VariableTypeAttributes_default; |
180 | 551 | basevar_attr.displayName = UA_LOCALIZEDTEXT("", "BaseVariableType"); |
181 | 551 | basevar_attr.isAbstract = true; |
182 | 551 | basevar_attr.valueRank = UA_VALUERANK_ANY; |
183 | 551 | basevar_attr.dataType = UA_NS0ID(BASEDATATYPE); |
184 | 551 | ret |= ns0_addNode_raw(server, UA_NODECLASS_VARIABLETYPE, |
185 | 551 | UA_NS0ID_BASEVARIABLETYPE, "BaseVariableType", |
186 | 551 | &basevar_attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES]); |
187 | | |
188 | 551 | UA_VariableTypeAttributes bdv_attr = UA_VariableTypeAttributes_default; |
189 | 551 | bdv_attr.displayName = UA_LOCALIZEDTEXT("", "BaseDataVariableType"); |
190 | 551 | bdv_attr.dataType = UA_NS0ID(BASEDATATYPE); |
191 | 551 | bdv_attr.valueRank = UA_VALUERANK_ANY; |
192 | 551 | ret |= addNode(server, UA_NODECLASS_VARIABLETYPE, |
193 | 551 | UA_NS0ID(BASEDATAVARIABLETYPE), UA_NS0ID(BASEVARIABLETYPE), |
194 | 551 | UA_NODEID_NULL, UA_QUALIFIEDNAME(0, "BaseDataVariableType"), |
195 | 551 | UA_NODEID_NULL, &bdv_attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES], |
196 | 551 | NULL, NULL); |
197 | | |
198 | 551 | UA_VariableTypeAttributes prop_attr = UA_VariableTypeAttributes_default; |
199 | 551 | prop_attr.displayName = UA_LOCALIZEDTEXT("", "PropertyType"); |
200 | 551 | prop_attr.dataType = UA_NS0ID(BASEDATATYPE); |
201 | 551 | prop_attr.valueRank = UA_VALUERANK_ANY; |
202 | 551 | ret |= addNode(server, UA_NODECLASS_VARIABLETYPE, |
203 | 551 | UA_NS0ID(PROPERTYTYPE), UA_NS0ID(BASEVARIABLETYPE), |
204 | 551 | UA_NODEID_NULL, UA_QUALIFIEDNAME(0, "PropertyType"), |
205 | 551 | UA_NODEID_NULL, &prop_attr, |
206 | 551 | &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES], NULL, NULL); |
207 | | |
208 | | /***************/ |
209 | | /* ObjectTypes */ |
210 | | /***************/ |
211 | | |
212 | 551 | UA_ObjectTypeAttributes baseobj_attr = UA_ObjectTypeAttributes_default; |
213 | 551 | baseobj_attr.displayName = UA_LOCALIZEDTEXT("", "BaseObjectType"); |
214 | 551 | ret |= ns0_addNode_raw(server, UA_NODECLASS_OBJECTTYPE, |
215 | 551 | UA_NS0ID_BASEOBJECTTYPE, "BaseObjectType", |
216 | 551 | &baseobj_attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES]); |
217 | | |
218 | 551 | UA_ObjectTypeAttributes folder_attr = UA_ObjectTypeAttributes_default; |
219 | 551 | folder_attr.displayName = UA_LOCALIZEDTEXT("", "FolderType"); |
220 | 551 | ret |= addNode(server, UA_NODECLASS_OBJECTTYPE, |
221 | 551 | UA_NS0ID(FOLDERTYPE), UA_NS0ID(BASEOBJECTTYPE), |
222 | 551 | UA_NODEID_NULL, UA_QUALIFIEDNAME(0, "FolderType"), |
223 | 551 | UA_NODEID_NULL, |
224 | 551 | &folder_attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES], NULL, NULL); |
225 | | |
226 | | /******************/ |
227 | | /* Root and below */ |
228 | | /******************/ |
229 | | |
230 | 551 | ret |= addObjectNode(server, "Root", UA_NS0ID_ROOTFOLDER, 0, 0, UA_NS0ID_FOLDERTYPE); |
231 | | |
232 | 551 | ret |= addObjectNode(server, "Objects", UA_NS0ID_OBJECTSFOLDER, UA_NS0ID_ROOTFOLDER, |
233 | 551 | UA_NS0ID_ORGANIZES, UA_NS0ID_FOLDERTYPE); |
234 | | |
235 | 551 | ret |= addObjectNode(server, "Types", UA_NS0ID_TYPESFOLDER, UA_NS0ID_ROOTFOLDER, |
236 | 551 | UA_NS0ID_ORGANIZES, UA_NS0ID_FOLDERTYPE); |
237 | | |
238 | 551 | ret |= addObjectNode(server, "ReferenceTypes", UA_NS0ID_REFERENCETYPESFOLDER, UA_NS0ID_TYPESFOLDER, |
239 | 551 | UA_NS0ID_ORGANIZES, UA_NS0ID_FOLDERTYPE); |
240 | 551 | ret |= ns0_addNode_finish(server, UA_NS0ID_REFERENCES, |
241 | 551 | UA_NS0ID_REFERENCETYPESFOLDER, UA_NS0ID_ORGANIZES); |
242 | | |
243 | 551 | ret |= addObjectNode(server, "DataTypes", UA_NS0ID_DATATYPESFOLDER, UA_NS0ID_TYPESFOLDER, |
244 | 551 | UA_NS0ID_ORGANIZES, UA_NS0ID_FOLDERTYPE); |
245 | 551 | ret |= ns0_addNode_finish(server, UA_NS0ID_BASEDATATYPE, |
246 | 551 | UA_NS0ID_DATATYPESFOLDER, UA_NS0ID_ORGANIZES); |
247 | | |
248 | 551 | ret |= addObjectNode(server, "VariableTypes", UA_NS0ID_VARIABLETYPESFOLDER, UA_NS0ID_TYPESFOLDER, |
249 | 551 | UA_NS0ID_ORGANIZES, UA_NS0ID_FOLDERTYPE); |
250 | 551 | ret |= ns0_addNode_finish(server, UA_NS0ID_BASEVARIABLETYPE, |
251 | 551 | UA_NS0ID_VARIABLETYPESFOLDER, UA_NS0ID_ORGANIZES); |
252 | | |
253 | 551 | ret |= addObjectNode(server, "ObjectTypes", UA_NS0ID_OBJECTTYPESFOLDER, UA_NS0ID_TYPESFOLDER, |
254 | 551 | UA_NS0ID_ORGANIZES, UA_NS0ID_FOLDERTYPE); |
255 | 551 | ret |= ns0_addNode_finish(server, UA_NS0ID_BASEOBJECTTYPE, |
256 | 551 | UA_NS0ID_OBJECTTYPESFOLDER, UA_NS0ID_ORGANIZES); |
257 | | |
258 | 551 | ret |= addObjectNode(server, "EventTypes", UA_NS0ID_EVENTTYPESFOLDER, UA_NS0ID_TYPESFOLDER, |
259 | 551 | UA_NS0ID_ORGANIZES, UA_NS0ID_FOLDERTYPE); |
260 | | |
261 | 551 | ret |= addObjectNode(server, "Views", UA_NS0ID_VIEWSFOLDER, UA_NS0ID_ROOTFOLDER, |
262 | 551 | UA_NS0ID_ORGANIZES, UA_NS0ID_FOLDERTYPE); |
263 | | |
264 | | /* Add BaseEventType */ |
265 | 551 | UA_ObjectTypeAttributes eventtype_attr = UA_ObjectTypeAttributes_default; |
266 | 551 | eventtype_attr.displayName = UA_LOCALIZEDTEXT("", "BaseEventType"); |
267 | 551 | ret |= addNode(server, UA_NODECLASS_OBJECTTYPE, UA_NS0ID(BASEEVENTTYPE), |
268 | 551 | UA_NS0ID(BASEOBJECTTYPE), UA_NODEID_NULL, |
269 | 551 | UA_QUALIFIEDNAME(0, "BaseEventType"), UA_NODEID_NULL, &eventtype_attr, |
270 | 551 | &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES], NULL, NULL); |
271 | 551 | ret |= addRef(server, UA_NS0ID(EVENTTYPESFOLDER), UA_NS0ID(ORGANIZES), |
272 | 551 | UA_NS0ID(BASEEVENTTYPE), true); |
273 | | |
274 | 551 | if(ret != UA_STATUSCODE_GOOD) |
275 | 0 | ret = UA_STATUSCODE_BADINTERNALERROR; |
276 | | |
277 | 551 | return ret; |
278 | 551 | } |
279 | | |
280 | | /****************/ |
281 | | /* Data Sources */ |
282 | | /****************/ |
283 | | |
284 | | static UA_StatusCode |
285 | | writeStatus(UA_Server *server, const UA_NodeId *sessionId, |
286 | | void *sessionContext, const UA_NodeId *nodeId, |
287 | | void *nodeContext, const UA_NumericRange *range, |
288 | 0 | const UA_DataValue *value) { |
289 | 0 | if(range) |
290 | 0 | return UA_STATUSCODE_BADINDEXRANGEINVALID; |
291 | | |
292 | 0 | if(nodeId->identifier.numeric != UA_NS0ID_SERVER_SERVERSTATUS_SECONDSTILLSHUTDOWN) |
293 | 0 | return UA_STATUSCODE_BADINTERNALERROR; |
294 | | |
295 | | /* Only the local user can write into this variable */ |
296 | 0 | if(sessionId != &server->adminSession.sessionId) |
297 | 0 | return UA_STATUSCODE_BADUSERACCESSDENIED; |
298 | | |
299 | 0 | if(!UA_Variant_hasScalarType(&value->value, &UA_TYPES[UA_TYPES_UINT32])) |
300 | 0 | return UA_STATUSCODE_BADTYPEMISMATCH; |
301 | | |
302 | 0 | UA_EventLoop *el = server->config.eventLoop; |
303 | 0 | UA_UInt32 *endTime = (UA_UInt32*)value->value.data; |
304 | 0 | server->endTime = el->dateTime_now(el) + (UA_DateTime)(*endTime * UA_DATETIME_SEC); |
305 | 0 | return UA_STATUSCODE_GOOD; |
306 | 0 | } |
307 | | |
308 | | static UA_StatusCode |
309 | | readStatus(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext, |
310 | | const UA_NodeId *nodeId, void *nodeContext, UA_Boolean sourceTimestamp, |
311 | 0 | const UA_NumericRange *range, UA_DataValue *value) { |
312 | 0 | UA_EventLoop *el = server->config.eventLoop; |
313 | |
|
314 | 0 | if(range) { |
315 | 0 | value->hasStatus = true; |
316 | 0 | value->status = UA_STATUSCODE_BADINDEXRANGEINVALID; |
317 | 0 | return UA_STATUSCODE_GOOD; |
318 | 0 | } |
319 | | |
320 | 0 | if(sourceTimestamp) { |
321 | 0 | value->hasSourceTimestamp = true; |
322 | 0 | value->sourceTimestamp = el->dateTime_now(el); |
323 | 0 | } |
324 | |
|
325 | 0 | void *data = NULL; |
326 | |
|
327 | 0 | UA_assert(nodeId->identifierType == UA_NODEIDTYPE_NUMERIC); |
328 | | |
329 | 0 | switch(nodeId->identifier.numeric) { |
330 | 0 | case UA_NS0ID_SERVER_SERVERSTATUS_SECONDSTILLSHUTDOWN: { |
331 | 0 | UA_UInt32 *shutdown = UA_UInt32_new(); |
332 | 0 | if(!shutdown) |
333 | 0 | return UA_STATUSCODE_BADOUTOFMEMORY; |
334 | 0 | if(server->endTime != 0) |
335 | 0 | *shutdown = (UA_UInt32)((server->endTime - el->dateTime_now(el)) / UA_DATETIME_SEC); |
336 | 0 | value->value.data = shutdown; |
337 | 0 | value->value.type = &UA_TYPES[UA_TYPES_UINT32]; |
338 | 0 | value->hasValue = true; |
339 | 0 | return UA_STATUSCODE_GOOD; |
340 | 0 | } |
341 | | |
342 | 0 | case UA_NS0ID_SERVER_SERVERSTATUS_STATE: { |
343 | 0 | UA_ServerState *state = UA_ServerState_new(); |
344 | 0 | if(!state) |
345 | 0 | return UA_STATUSCODE_BADOUTOFMEMORY; |
346 | 0 | if(server->endTime != 0) |
347 | 0 | *state = UA_SERVERSTATE_SHUTDOWN; |
348 | 0 | value->value.data = state; |
349 | 0 | value->value.type = &UA_TYPES[UA_TYPES_SERVERSTATE]; |
350 | 0 | value->hasValue = true; |
351 | 0 | return UA_STATUSCODE_GOOD; |
352 | 0 | } |
353 | | |
354 | 0 | case UA_NS0ID_SERVER_SERVERSTATUS: { |
355 | 0 | UA_ServerStatusDataType *statustype = UA_ServerStatusDataType_new(); |
356 | 0 | if(!statustype) |
357 | 0 | return UA_STATUSCODE_BADOUTOFMEMORY; |
358 | 0 | statustype->startTime = server->startTime; |
359 | 0 | statustype->currentTime = el->dateTime_now(el); |
360 | |
|
361 | 0 | statustype->state = UA_SERVERSTATE_RUNNING; |
362 | 0 | statustype->secondsTillShutdown = 0; |
363 | 0 | if(server->endTime != 0) { |
364 | 0 | statustype->state = UA_SERVERSTATE_SHUTDOWN; |
365 | 0 | statustype->secondsTillShutdown = (UA_UInt32) |
366 | 0 | ((server->endTime - el->dateTime_now(el)) / UA_DATETIME_SEC); |
367 | 0 | } |
368 | |
|
369 | 0 | value->value.data = statustype; |
370 | 0 | value->value.type = &UA_TYPES[UA_TYPES_SERVERSTATUSDATATYPE]; |
371 | 0 | value->hasValue = true; |
372 | 0 | return UA_BuildInfo_copy(&server->config.buildInfo, &statustype->buildInfo); |
373 | 0 | } |
374 | | |
375 | 0 | case UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO: |
376 | 0 | value->value.type = &UA_TYPES[UA_TYPES_BUILDINFO]; |
377 | 0 | data = &server->config.buildInfo; |
378 | 0 | break; |
379 | | |
380 | 0 | case UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_PRODUCTURI: |
381 | 0 | value->value.type = &UA_TYPES[UA_TYPES_STRING]; |
382 | 0 | data = &server->config.buildInfo.productUri; |
383 | 0 | break; |
384 | | |
385 | 0 | case UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_MANUFACTURERNAME: |
386 | 0 | value->value.type = &UA_TYPES[UA_TYPES_STRING]; |
387 | 0 | data = &server->config.buildInfo.manufacturerName; |
388 | 0 | break; |
389 | | |
390 | 0 | case UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_PRODUCTNAME: |
391 | 0 | value->value.type = &UA_TYPES[UA_TYPES_STRING]; |
392 | 0 | data = &server->config.buildInfo.productName; |
393 | 0 | break; |
394 | | |
395 | 0 | case UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_SOFTWAREVERSION: |
396 | 0 | value->value.type = &UA_TYPES[UA_TYPES_STRING]; |
397 | 0 | data = &server->config.buildInfo.softwareVersion; |
398 | 0 | break; |
399 | | |
400 | 0 | case UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_BUILDNUMBER: |
401 | 0 | value->value.type = &UA_TYPES[UA_TYPES_STRING]; |
402 | 0 | data = &server->config.buildInfo.buildNumber; |
403 | 0 | break; |
404 | | |
405 | 0 | case UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_BUILDDATE: |
406 | 0 | value->value.type = &UA_TYPES[UA_TYPES_DATETIME]; |
407 | 0 | data = &server->config.buildInfo.buildDate; |
408 | 0 | break; |
409 | | |
410 | 0 | default: |
411 | 0 | value->hasStatus = true; |
412 | 0 | value->status = UA_STATUSCODE_BADINTERNALERROR; |
413 | 0 | return UA_STATUSCODE_GOOD; |
414 | 0 | } |
415 | | |
416 | 0 | value->value.data = UA_new(value->value.type); |
417 | 0 | if(!value->value.data) { |
418 | 0 | value->value.type = NULL; |
419 | 0 | return UA_STATUSCODE_BADOUTOFMEMORY; |
420 | 0 | } |
421 | | |
422 | 0 | value->hasValue = true; |
423 | 0 | return UA_copy(data, value->value.data, value->value.type); |
424 | 0 | } |
425 | | |
426 | | #ifdef UA_GENERATED_NAMESPACE_ZERO |
427 | | static UA_StatusCode |
428 | | readServiceLevel(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext, |
429 | | const UA_NodeId *nodeId, void *nodeContext, UA_Boolean includeSourceTimeStamp, |
430 | 0 | const UA_NumericRange *range, UA_DataValue *value) { |
431 | 0 | UA_EventLoop *el = server->config.eventLoop; |
432 | |
|
433 | 0 | if(range) { |
434 | 0 | value->hasStatus = true; |
435 | 0 | value->status = UA_STATUSCODE_BADINDEXRANGEINVALID; |
436 | 0 | return UA_STATUSCODE_GOOD; |
437 | 0 | } |
438 | | |
439 | 0 | value->value.type = &UA_TYPES[UA_TYPES_BYTE]; |
440 | 0 | value->value.arrayLength = 0; |
441 | 0 | UA_Byte *byte = UA_Byte_new(); |
442 | 0 | if(!byte) |
443 | 0 | return UA_STATUSCODE_BADOUTOFMEMORY; |
444 | 0 | *byte = 255; |
445 | 0 | value->value.data = byte; |
446 | 0 | value->value.arrayDimensionsSize = 0; |
447 | 0 | value->value.arrayDimensions = NULL; |
448 | 0 | value->hasValue = true; |
449 | 0 | if(includeSourceTimeStamp) { |
450 | 0 | value->hasSourceTimestamp = true; |
451 | 0 | value->sourceTimestamp = el->dateTime_now(el); |
452 | 0 | } |
453 | 0 | return UA_STATUSCODE_GOOD; |
454 | 0 | } |
455 | | |
456 | | static UA_StatusCode |
457 | | readAuditing(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext, |
458 | | const UA_NodeId *nodeId, void *nodeContext, UA_Boolean includeSourceTimeStamp, |
459 | 0 | const UA_NumericRange *range, UA_DataValue *value) { |
460 | 0 | UA_EventLoop *el = server->config.eventLoop; |
461 | |
|
462 | 0 | if(range) { |
463 | 0 | value->hasStatus = true; |
464 | 0 | value->status = UA_STATUSCODE_BADINDEXRANGEINVALID; |
465 | 0 | return UA_STATUSCODE_GOOD; |
466 | 0 | } |
467 | | |
468 | 0 | value->value.type = &UA_TYPES[UA_TYPES_BOOLEAN]; |
469 | 0 | value->value.arrayLength = 0; |
470 | 0 | UA_Boolean *boolean = UA_Boolean_new(); |
471 | 0 | if(!boolean) |
472 | 0 | return UA_STATUSCODE_BADOUTOFMEMORY; |
473 | 0 | *boolean = false; |
474 | 0 | value->value.data = boolean; |
475 | 0 | value->value.arrayDimensionsSize = 0; |
476 | 0 | value->value.arrayDimensions = NULL; |
477 | 0 | value->hasValue = true; |
478 | 0 | if(includeSourceTimeStamp) { |
479 | 0 | value->hasSourceTimestamp = true; |
480 | 0 | value->sourceTimestamp = el->dateTime_now(el); |
481 | 0 | } |
482 | 0 | return UA_STATUSCODE_GOOD; |
483 | 0 | } |
484 | | #endif |
485 | | |
486 | | static UA_StatusCode |
487 | | readNamespaces(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext, |
488 | | const UA_NodeId *nodeid, void *nodeContext, UA_Boolean includeSourceTimeStamp, |
489 | | const UA_NumericRange *range, |
490 | 0 | UA_DataValue *value) { |
491 | 0 | UA_EventLoop *el = server->config.eventLoop; |
492 | | |
493 | | /* ensure that the uri for ns1 is set up from the app description */ |
494 | 0 | setupNs1Uri(server); |
495 | |
|
496 | 0 | if(range) { |
497 | 0 | value->hasStatus = true; |
498 | 0 | value->status = UA_STATUSCODE_BADINDEXRANGEINVALID; |
499 | 0 | return UA_STATUSCODE_GOOD; |
500 | 0 | } |
501 | 0 | UA_StatusCode retval; |
502 | 0 | retval = UA_Variant_setArrayCopy(&value->value, server->namespaces, |
503 | 0 | server->namespacesSize, &UA_TYPES[UA_TYPES_STRING]); |
504 | 0 | if(retval != UA_STATUSCODE_GOOD) |
505 | 0 | return retval; |
506 | 0 | value->hasValue = true; |
507 | 0 | if(includeSourceTimeStamp) { |
508 | 0 | value->hasSourceTimestamp = true; |
509 | 0 | value->sourceTimestamp = el->dateTime_now(el); |
510 | 0 | } |
511 | 0 | return UA_STATUSCODE_GOOD; |
512 | 0 | } |
513 | | |
514 | | static UA_StatusCode |
515 | | writeNamespaces(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext, |
516 | | const UA_NodeId *nodeid, void *nodeContext, const UA_NumericRange *range, |
517 | 0 | const UA_DataValue *value) { |
518 | | /* Check the data type */ |
519 | 0 | if(!value->hasValue || |
520 | 0 | value->value.type != &UA_TYPES[UA_TYPES_STRING]) |
521 | 0 | return UA_STATUSCODE_BADTYPEMISMATCH; |
522 | | |
523 | | /* Check that the variant is not empty */ |
524 | 0 | if(!value->value.data) |
525 | 0 | return UA_STATUSCODE_BADTYPEMISMATCH; |
526 | | |
527 | | /* TODO: Writing with a range is not implemented */ |
528 | 0 | if(range) |
529 | 0 | return UA_STATUSCODE_BADINTERNALERROR; |
530 | | |
531 | 0 | UA_String *newNamespaces = (UA_String*)value->value.data; |
532 | 0 | size_t newNamespacesSize = value->value.arrayLength; |
533 | | |
534 | | /* Test if we append to the existing namespaces */ |
535 | 0 | if(newNamespacesSize <= server->namespacesSize) |
536 | 0 | return UA_STATUSCODE_BADTYPEMISMATCH; |
537 | | |
538 | | /* ensure that the uri for ns1 is set up from the app description */ |
539 | 0 | setupNs1Uri(server); |
540 | | |
541 | | /* Test if the existing namespaces are unchanged */ |
542 | 0 | for(size_t i = 0; i < server->namespacesSize; ++i) { |
543 | 0 | if(!UA_String_equal(&server->namespaces[i], &newNamespaces[i])) |
544 | 0 | return UA_STATUSCODE_BADINTERNALERROR; |
545 | 0 | } |
546 | | |
547 | | /* Add namespaces */ |
548 | 0 | for(size_t i = server->namespacesSize; i < newNamespacesSize; ++i) |
549 | 0 | addNamespace(server, newNamespaces[i]); |
550 | 0 | return UA_STATUSCODE_GOOD; |
551 | 0 | } |
552 | | |
553 | | static UA_StatusCode |
554 | | readCurrentTime(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext, |
555 | | const UA_NodeId *nodeid, void *nodeContext, UA_Boolean sourceTimeStamp, |
556 | 0 | const UA_NumericRange *range, UA_DataValue *value) { |
557 | 0 | UA_EventLoop *el = server->config.eventLoop; |
558 | |
|
559 | 0 | if(range) { |
560 | 0 | value->hasStatus = true; |
561 | 0 | value->status = UA_STATUSCODE_BADINDEXRANGEINVALID; |
562 | 0 | return UA_STATUSCODE_GOOD; |
563 | 0 | } |
564 | | |
565 | 0 | UA_DateTime currentTime = el->dateTime_now(el); |
566 | 0 | UA_StatusCode retval = UA_Variant_setScalarCopy(&value->value, ¤tTime, |
567 | 0 | &UA_TYPES[UA_TYPES_DATETIME]); |
568 | 0 | if(retval != UA_STATUSCODE_GOOD) |
569 | 0 | return retval; |
570 | 0 | value->hasValue = true; |
571 | 0 | if(sourceTimeStamp) { |
572 | 0 | value->hasSourceTimestamp = true; |
573 | 0 | value->sourceTimestamp = currentTime; |
574 | 0 | } |
575 | 0 | return UA_STATUSCODE_GOOD; |
576 | 0 | } |
577 | | |
578 | | #ifdef UA_GENERATED_NAMESPACE_ZERO |
579 | | static UA_StatusCode |
580 | | readOperationLimits(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext, |
581 | | const UA_NodeId *nodeid, void *nodeContext, UA_Boolean includeSourceTimeStamp, |
582 | | const UA_NumericRange *range, |
583 | 0 | UA_DataValue *value) { |
584 | 0 | UA_StatusCode retval = UA_STATUSCODE_GOOD; |
585 | 0 | if(nodeid->identifierType != UA_NODEIDTYPE_NUMERIC) |
586 | 0 | return UA_STATUSCODE_BADNOTSUPPORTED; |
587 | 0 | switch(nodeid->identifier.numeric) { |
588 | 0 | case UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERREAD: |
589 | 0 | retval = UA_Variant_setScalarCopy(&value->value, &server->config.maxNodesPerRead, &UA_TYPES[UA_TYPES_UINT32]); |
590 | 0 | break; |
591 | 0 | case UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERWRITE: |
592 | 0 | retval = UA_Variant_setScalarCopy(&value->value, &server->config.maxNodesPerWrite, &UA_TYPES[UA_TYPES_UINT32]); |
593 | 0 | break; |
594 | 0 | case UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERMETHODCALL: |
595 | 0 | retval = UA_Variant_setScalarCopy(&value->value, &server->config.maxNodesPerMethodCall, &UA_TYPES[UA_TYPES_UINT32]); |
596 | 0 | break; |
597 | 0 | case UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERBROWSE: |
598 | 0 | retval = UA_Variant_setScalarCopy(&value->value, &server->config.maxNodesPerBrowse, &UA_TYPES[UA_TYPES_UINT32]); |
599 | 0 | break; |
600 | 0 | case UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERREGISTERNODES: |
601 | 0 | retval = UA_Variant_setScalarCopy(&value->value, &server->config.maxNodesPerRegisterNodes, &UA_TYPES[UA_TYPES_UINT32]); |
602 | 0 | break; |
603 | 0 | case UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERTRANSLATEBROWSEPATHSTONODEIDS: |
604 | 0 | retval = UA_Variant_setScalarCopy(&value->value, &server->config.maxNodesPerTranslateBrowsePathsToNodeIds, &UA_TYPES[UA_TYPES_UINT32]); |
605 | 0 | break; |
606 | 0 | case UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERNODEMANAGEMENT: |
607 | 0 | retval = UA_Variant_setScalarCopy(&value->value, &server->config.maxNodesPerNodeManagement, &UA_TYPES[UA_TYPES_UINT32]); |
608 | 0 | break; |
609 | 0 | case UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXMONITOREDITEMSPERCALL: |
610 | 0 | retval = UA_Variant_setScalarCopy(&value->value, &server->config.maxMonitoredItemsPerCall, &UA_TYPES[UA_TYPES_UINT32]); |
611 | 0 | break; |
612 | 0 | default: |
613 | 0 | retval = UA_STATUSCODE_BADNOTSUPPORTED; |
614 | 0 | } |
615 | 0 | return retval; |
616 | 0 | } |
617 | | |
618 | | static UA_StatusCode |
619 | | readMinSamplingInterval(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext, |
620 | | const UA_NodeId *nodeid, void *nodeContext, UA_Boolean includeSourceTimeStamp, |
621 | 0 | const UA_NumericRange *range, UA_DataValue *value) { |
622 | 0 | UA_EventLoop *el = server->config.eventLoop; |
623 | |
|
624 | 0 | if(range) { |
625 | 0 | value->hasStatus = true; |
626 | 0 | value->status = UA_STATUSCODE_BADINDEXRANGEINVALID; |
627 | 0 | return UA_STATUSCODE_GOOD; |
628 | 0 | } |
629 | | |
630 | 0 | UA_StatusCode retval; |
631 | 0 | UA_Duration minInterval; |
632 | 0 | #ifdef UA_ENABLE_SUBSCRIPTIONS |
633 | 0 | minInterval = server->config.samplingIntervalLimits.min; |
634 | | #else |
635 | | minInterval = 0.0; |
636 | | #endif |
637 | 0 | retval = UA_Variant_setScalarCopy(&value->value, &minInterval, &UA_TYPES[UA_TYPES_DURATION]); |
638 | 0 | if(retval != UA_STATUSCODE_GOOD) |
639 | 0 | return retval; |
640 | 0 | value->hasValue = true; |
641 | 0 | if(includeSourceTimeStamp) { |
642 | 0 | value->hasSourceTimestamp = true; |
643 | 0 | value->sourceTimestamp = el->dateTime_now(el); |
644 | 0 | } |
645 | 0 | return UA_STATUSCODE_GOOD; |
646 | 0 | } |
647 | | #endif |
648 | | |
649 | | #if defined(UA_GENERATED_NAMESPACE_ZERO) && defined(UA_ENABLE_METHODCALLS) && defined(UA_ENABLE_SUBSCRIPTIONS) |
650 | | static UA_StatusCode |
651 | | resendData(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext, |
652 | | const UA_NodeId *methodId, void *methodContext, const UA_NodeId *objectId, |
653 | | void *objectContext, size_t inputSize, const UA_Variant *input, |
654 | 0 | size_t outputSize, UA_Variant *output) { |
655 | | /* Get the input argument */ |
656 | 0 | if(inputSize != 1 || |
657 | 0 | !UA_Variant_hasScalarType(input, &UA_TYPES[UA_TYPES_UINT32])) |
658 | 0 | return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID; |
659 | 0 | UA_UInt32 subscriptionId = *((UA_UInt32*)(input[0].data)); |
660 | | |
661 | | /* Get the Session */ |
662 | 0 | lockServer(server); |
663 | 0 | UA_Session *session = getSessionById(server, sessionId); |
664 | 0 | if(!session) { |
665 | 0 | unlockServer(server); |
666 | 0 | return UA_STATUSCODE_BADINTERNALERROR; |
667 | 0 | } |
668 | | |
669 | | /* Get the Subscription */ |
670 | 0 | UA_Subscription *subscription = getSubscriptionById(server, subscriptionId); |
671 | 0 | if(!subscription) { |
672 | 0 | unlockServer(server); |
673 | 0 | return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID; |
674 | 0 | } |
675 | | |
676 | | /* The Subscription is not attached to this Session */ |
677 | 0 | if(subscription->session != session) { |
678 | 0 | unlockServer(server); |
679 | 0 | return UA_STATUSCODE_BADUSERACCESSDENIED; |
680 | 0 | } |
681 | | |
682 | 0 | UA_Subscription_resendData(server, subscription); |
683 | |
|
684 | 0 | unlockServer(server); |
685 | 0 | return UA_STATUSCODE_GOOD; |
686 | 0 | } |
687 | | static UA_StatusCode |
688 | | readMonitoredItems(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext, |
689 | | const UA_NodeId *methodId, void *methodContext, const UA_NodeId *objectId, |
690 | | void *objectContext, size_t inputSize, const UA_Variant *input, |
691 | 0 | size_t outputSize, UA_Variant *output) { |
692 | | /* Return two empty arrays by default */ |
693 | 0 | UA_Variant_setArray(&output[0], UA_Array_new(0, &UA_TYPES[UA_TYPES_UINT32]), |
694 | 0 | 0, &UA_TYPES[UA_TYPES_UINT32]); |
695 | 0 | UA_Variant_setArray(&output[1], UA_Array_new(0, &UA_TYPES[UA_TYPES_UINT32]), |
696 | 0 | 0, &UA_TYPES[UA_TYPES_UINT32]); |
697 | |
|
698 | 0 | lockServer(server); |
699 | | |
700 | | /* Get the Session */ |
701 | 0 | UA_Session *session = getSessionById(server, sessionId); |
702 | 0 | if(!session) { |
703 | 0 | unlockServer(server); |
704 | 0 | return UA_STATUSCODE_BADINTERNALERROR; |
705 | 0 | } |
706 | 0 | if(inputSize == 0 || !input[0].data) { |
707 | 0 | unlockServer(server); |
708 | 0 | return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID; |
709 | 0 | } |
710 | | |
711 | | /* Get the Subscription */ |
712 | 0 | UA_UInt32 subscriptionId = *((UA_UInt32*)(input[0].data)); |
713 | 0 | UA_Subscription *subscription = getSubscriptionById(server, subscriptionId); |
714 | 0 | if(!subscription) { |
715 | 0 | unlockServer(server); |
716 | 0 | return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID; |
717 | 0 | } |
718 | | |
719 | | /* The Subscription is not attached to this Session */ |
720 | 0 | if(subscription->session != session) { |
721 | 0 | unlockServer(server); |
722 | 0 | return UA_STATUSCODE_BADUSERACCESSDENIED; |
723 | 0 | } |
724 | | |
725 | | /* Count the MonitoredItems */ |
726 | 0 | UA_UInt32 sizeOfOutput = 0; |
727 | 0 | UA_MonitoredItem* monitoredItem; |
728 | 0 | LIST_FOREACH(monitoredItem, &subscription->monitoredItems, listEntry) { |
729 | 0 | ++sizeOfOutput; |
730 | 0 | } |
731 | 0 | if(sizeOfOutput == 0) { |
732 | 0 | unlockServer(server); |
733 | 0 | return UA_STATUSCODE_GOOD; |
734 | 0 | } |
735 | | |
736 | | /* Allocate the output arrays */ |
737 | 0 | UA_UInt32 *clientHandles = (UA_UInt32*) |
738 | 0 | UA_Array_new(sizeOfOutput, &UA_TYPES[UA_TYPES_UINT32]); |
739 | 0 | if(!clientHandles) { |
740 | 0 | unlockServer(server); |
741 | 0 | return UA_STATUSCODE_BADOUTOFMEMORY; |
742 | 0 | } |
743 | 0 | UA_UInt32 *serverHandles = (UA_UInt32*) |
744 | 0 | UA_Array_new(sizeOfOutput, &UA_TYPES[UA_TYPES_UINT32]); |
745 | 0 | if(!serverHandles) { |
746 | 0 | unlockServer(server); |
747 | 0 | UA_free(clientHandles); |
748 | 0 | return UA_STATUSCODE_BADOUTOFMEMORY; |
749 | 0 | } |
750 | | |
751 | | /* Fill the array */ |
752 | 0 | UA_UInt32 i = 0; |
753 | 0 | LIST_FOREACH(monitoredItem, &subscription->monitoredItems, listEntry) { |
754 | 0 | clientHandles[i] = monitoredItem->parameters.clientHandle; |
755 | 0 | serverHandles[i] = monitoredItem->monitoredItemId; |
756 | 0 | ++i; |
757 | 0 | } |
758 | 0 | UA_Variant_setArray(&output[0], serverHandles, sizeOfOutput, &UA_TYPES[UA_TYPES_UINT32]); |
759 | 0 | UA_Variant_setArray(&output[1], clientHandles, sizeOfOutput, &UA_TYPES[UA_TYPES_UINT32]); |
760 | |
|
761 | 0 | unlockServer(server); |
762 | 0 | return UA_STATUSCODE_GOOD; |
763 | 0 | } |
764 | | #endif /* defined(UA_ENABLE_METHODCALLS) && defined(UA_ENABLE_SUBSCRIPTIONS) */ |
765 | | |
766 | | static UA_StatusCode |
767 | | writeNs0VariableArray(UA_Server *server, UA_UInt32 id, void *v, |
768 | 1.65k | size_t length, const UA_DataType *type) { |
769 | 1.65k | UA_Variant var; |
770 | 1.65k | UA_Variant_init(&var); |
771 | 1.65k | UA_Variant_setArray(&var, v, length, type); |
772 | 1.65k | return writeValueAttribute(server, UA_NODEID_NUMERIC(0, id), &var); |
773 | 1.65k | } |
774 | | |
775 | | #ifdef UA_GENERATED_NAMESPACE_ZERO |
776 | | static UA_StatusCode |
777 | 11.0k | writeNs0Variable(UA_Server *server, UA_UInt32 id, void *v, const UA_DataType *type) { |
778 | 11.0k | UA_Variant var; |
779 | 11.0k | UA_Variant_init(&var); |
780 | 11.0k | UA_Variant_setScalar(&var, v, type); |
781 | 11.0k | return writeValueAttribute(server, UA_NODEID_NUMERIC(0, id), &var); |
782 | 11.0k | } |
783 | | #endif |
784 | | |
785 | | #ifndef UA_GENERATED_NAMESPACE_ZERO |
786 | | static UA_StatusCode |
787 | | addVariableNode(UA_Server *server, char* name, UA_UInt32 variableid, |
788 | | UA_UInt32 parentid, UA_UInt32 referenceid, |
789 | | UA_Int32 valueRank, UA_UInt32 dataType) { |
790 | | UA_VariableAttributes attr = UA_VariableAttributes_default; |
791 | | attr.displayName = UA_LOCALIZEDTEXT("", name); |
792 | | attr.dataType = UA_NODEID_NUMERIC(0, dataType); |
793 | | attr.valueRank = valueRank; |
794 | | attr.accessLevel = UA_ACCESSLEVELMASK_READ; |
795 | | return addNode(server, UA_NODECLASS_VARIABLE, UA_NODEID_NUMERIC(0, variableid), |
796 | | UA_NODEID_NUMERIC(0, parentid), UA_NODEID_NUMERIC(0, referenceid), |
797 | | UA_QUALIFIEDNAME(0, name), UA_NS0ID(BASEDATAVARIABLETYPE), |
798 | | &attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES], NULL, NULL); |
799 | | } |
800 | | |
801 | | /* A minimal server object that is not complete and does not use the mandated |
802 | | * references to a server type. To be used on very constrained devices. */ |
803 | | static UA_StatusCode |
804 | | minimalServerObject(UA_Server *server) { |
805 | | /* Server */ |
806 | | UA_StatusCode retval = addObjectNode(server, "Server", UA_NS0ID_SERVER, UA_NS0ID_OBJECTSFOLDER, |
807 | | UA_NS0ID_ORGANIZES, UA_NS0ID_BASEOBJECTTYPE); |
808 | | |
809 | | /* Use a valuerank of -2 for now. The array is added later on and the valuerank set to 1. */ |
810 | | retval |= addVariableNode(server, "ServerArray", UA_NS0ID_SERVER_SERVERARRAY, |
811 | | UA_NS0ID_SERVER, UA_NS0ID_HASPROPERTY, |
812 | | UA_VALUERANK_ANY, UA_NS0ID_BASEDATATYPE); |
813 | | |
814 | | retval |= addVariableNode(server, "NamespaceArray", UA_NS0ID_SERVER_NAMESPACEARRAY, |
815 | | UA_NS0ID_SERVER, UA_NS0ID_HASPROPERTY, |
816 | | UA_VALUERANK_ANY, UA_NS0ID_BASEDATATYPE); |
817 | | |
818 | | retval |= addVariableNode(server, "ServerStatus", UA_NS0ID_SERVER_SERVERSTATUS, |
819 | | UA_NS0ID_SERVER, UA_NS0ID_HASCOMPONENT, |
820 | | UA_VALUERANK_SCALAR, UA_NS0ID_BASEDATATYPE); |
821 | | |
822 | | retval |= addVariableNode(server, "StartTime", UA_NS0ID_SERVER_SERVERSTATUS_STARTTIME, |
823 | | UA_NS0ID_SERVER_SERVERSTATUS, UA_NS0ID_HASCOMPONENT, |
824 | | UA_VALUERANK_SCALAR, UA_NS0ID_BASEDATATYPE); |
825 | | |
826 | | retval |= addVariableNode(server, "CurrentTime", UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME, |
827 | | UA_NS0ID_SERVER_SERVERSTATUS, UA_NS0ID_HASCOMPONENT, |
828 | | UA_VALUERANK_SCALAR, UA_NS0ID_BASEDATATYPE); |
829 | | |
830 | | retval |= addVariableNode(server, "State", UA_NS0ID_SERVER_SERVERSTATUS_STATE, |
831 | | UA_NS0ID_SERVER_SERVERSTATUS, UA_NS0ID_HASCOMPONENT, |
832 | | UA_VALUERANK_SCALAR, UA_NS0ID_BASEDATATYPE); |
833 | | |
834 | | retval |= addVariableNode(server, "BuildInfo", UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO, |
835 | | UA_NS0ID_SERVER_SERVERSTATUS, UA_NS0ID_HASCOMPONENT, |
836 | | UA_VALUERANK_SCALAR, UA_NS0ID_BASEDATATYPE); |
837 | | |
838 | | retval |= addVariableNode(server, "ProductUri", UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_PRODUCTURI, |
839 | | UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO, UA_NS0ID_HASCOMPONENT, |
840 | | UA_VALUERANK_SCALAR, UA_NS0ID_BASEDATATYPE); |
841 | | |
842 | | retval |= addVariableNode(server, "ManufacturerName", |
843 | | UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_MANUFACTURERNAME, |
844 | | UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO, UA_NS0ID_HASCOMPONENT, |
845 | | UA_VALUERANK_SCALAR, UA_NS0ID_BASEDATATYPE); |
846 | | |
847 | | retval |= addVariableNode(server, "ProductName", |
848 | | UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_PRODUCTNAME, |
849 | | UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO, UA_NS0ID_HASCOMPONENT, |
850 | | UA_VALUERANK_SCALAR, UA_NS0ID_BASEDATATYPE); |
851 | | |
852 | | retval |= addVariableNode(server, "SoftwareVersion", |
853 | | UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_SOFTWAREVERSION, |
854 | | UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO, UA_NS0ID_HASCOMPONENT, |
855 | | UA_VALUERANK_SCALAR, UA_NS0ID_BASEDATATYPE); |
856 | | |
857 | | retval |= addVariableNode(server, "BuildNumber", |
858 | | UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_BUILDNUMBER, |
859 | | UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO, UA_NS0ID_HASCOMPONENT, |
860 | | UA_VALUERANK_SCALAR, UA_NS0ID_BASEDATATYPE); |
861 | | |
862 | | retval |= addVariableNode(server, "BuildDate", |
863 | | UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_BUILDDATE, |
864 | | UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO, UA_NS0ID_HASCOMPONENT, |
865 | | UA_VALUERANK_SCALAR, UA_NS0ID_BASEDATATYPE); |
866 | | |
867 | | return retval; |
868 | | } |
869 | | |
870 | | #else |
871 | | |
872 | | static void |
873 | 551 | addModellingRules(UA_Server *server) { |
874 | | /* Test if the ModellingRules folder was added. (Only for the full ns0.) */ |
875 | 551 | UA_NodeId mrNodeId = UA_NS0ID(SERVER_SERVERCAPABILITIES_MODELLINGRULES); |
876 | 551 | const UA_Node *mrnode = UA_NODESTORE_GET(server, &mrNodeId); |
877 | 551 | if(!mrnode) |
878 | 0 | return; |
879 | 551 | UA_NODESTORE_RELEASE(server, mrnode); |
880 | | |
881 | | /* Add ExposesItsArray */ |
882 | 551 | addRef(server, UA_NS0ID(SERVER_SERVERCAPABILITIES_MODELLINGRULES), |
883 | 551 | UA_NS0ID(HASCOMPONENT), UA_NS0ID(MODELLINGRULE_EXPOSESITSARRAY), true); |
884 | | |
885 | | /* Add Mandatory */ |
886 | 551 | addRef(server, UA_NS0ID(SERVER_SERVERCAPABILITIES_MODELLINGRULES), |
887 | 551 | UA_NS0ID(HASCOMPONENT), UA_NS0ID(MODELLINGRULE_MANDATORY), true); |
888 | | |
889 | | |
890 | | /* Add MandatoryPlaceholder */ |
891 | 551 | addRef(server, UA_NS0ID(SERVER_SERVERCAPABILITIES_MODELLINGRULES), |
892 | 551 | UA_NS0ID(HASCOMPONENT), UA_NS0ID(MODELLINGRULE_MANDATORYPLACEHOLDER), true); |
893 | | |
894 | | /* Add Optional */ |
895 | 551 | addRef(server, UA_NS0ID(SERVER_SERVERCAPABILITIES_MODELLINGRULES), |
896 | 551 | UA_NS0ID(HASCOMPONENT), UA_NS0ID(MODELLINGRULE_OPTIONAL), true); |
897 | | |
898 | | /* Add OptionalPlaceholder */ |
899 | 551 | addRef(server, UA_NS0ID(SERVER_SERVERCAPABILITIES_MODELLINGRULES), |
900 | 551 | UA_NS0ID(HASCOMPONENT), UA_NS0ID(MODELLINGRULE_OPTIONALPLACEHOLDER), true); |
901 | 551 | } |
902 | | |
903 | | #endif |
904 | | |
905 | | /* Initialize the nodeset 0 by using the generated code of the nodeset compiler. |
906 | | * This also initialized the data sources for various variables, such as for |
907 | | * example server time. */ |
908 | | UA_StatusCode |
909 | 551 | initNS0(UA_Server *server) { |
910 | 551 | UA_LOCK_ASSERT(&server->serviceMutex); |
911 | | |
912 | | /* Initialize base nodes which are always required an cannot be created |
913 | | * through the NS compiler */ |
914 | 551 | server->bootstrapNS0 = true; |
915 | 551 | UA_StatusCode retVal = createNS0_base(server); |
916 | | |
917 | 551 | #ifdef UA_GENERATED_NAMESPACE_ZERO |
918 | | /* Load nodes and references generated from the XML ns0 definition */ |
919 | 551 | retVal |= namespace0_generated(server); |
920 | | #else |
921 | | /* Create a minimal server object */ |
922 | | retVal |= minimalServerObject(server); |
923 | | #endif |
924 | | |
925 | 551 | server->bootstrapNS0 = false; |
926 | | |
927 | 551 | if(retVal != UA_STATUSCODE_GOOD) { |
928 | 0 | UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER, |
929 | 0 | "Initialization of Namespace 0 failed with %s. " |
930 | 0 | "See previous outputs for any error messages.", |
931 | 0 | UA_StatusCode_name(retVal)); |
932 | 0 | return UA_STATUSCODE_BADINTERNALERROR; |
933 | 0 | } |
934 | | |
935 | | /* NamespaceArray */ |
936 | 551 | UA_CallbackValueSource namespaceDataSource = {readNamespaces, writeNamespaces}; |
937 | 551 | retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_NAMESPACEARRAY), |
938 | 551 | namespaceDataSource); |
939 | 551 | retVal |= writeValueRankAttribute(server, UA_NS0ID(SERVER_NAMESPACEARRAY), 1); |
940 | | |
941 | | /* ServerArray */ |
942 | 551 | retVal |= writeNs0VariableArray(server, UA_NS0ID_SERVER_SERVERARRAY, |
943 | 551 | &server->config.applicationDescription.applicationUri, |
944 | 551 | 1, &UA_TYPES[UA_TYPES_STRING]); |
945 | 551 | retVal |= writeValueRankAttribute(server, UA_NS0ID(SERVER_SERVERARRAY), 1); |
946 | | |
947 | | /* ServerStatus */ |
948 | 551 | UA_CallbackValueSource serverStatus = {readStatus, writeStatus}; |
949 | 551 | retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERSTATUS), serverStatus); |
950 | | |
951 | | /* StartTime will be sampled in UA_Server_run_startup()*/ |
952 | | |
953 | | /* CurrentTime */ |
954 | 551 | UA_CallbackValueSource currentTime = {readCurrentTime, NULL}; |
955 | 551 | UA_NodeId currTime = UA_NS0ID(SERVER_SERVERSTATUS_CURRENTTIME); |
956 | 551 | retVal |= setVariableNode_callbackValueSource(server, currTime, currentTime); |
957 | 551 | retVal |= writeMinimumSamplingIntervalAttribute(server, currTime, 100.0); |
958 | | |
959 | | /* State */ |
960 | 551 | retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERSTATUS_STATE), |
961 | 551 | serverStatus); |
962 | | |
963 | | /* BuildInfo */ |
964 | 551 | retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERSTATUS_BUILDINFO), |
965 | 551 | serverStatus); |
966 | | |
967 | | /* BuildInfo - ProductUri */ |
968 | 551 | retVal |= setVariableNode_callbackValueSource(server, |
969 | 551 | UA_NS0ID(SERVER_SERVERSTATUS_BUILDINFO_PRODUCTURI), |
970 | 551 | serverStatus); |
971 | | |
972 | | /* BuildInfo - ManufacturerName */ |
973 | 551 | retVal |= setVariableNode_callbackValueSource(server, |
974 | 551 | UA_NS0ID(SERVER_SERVERSTATUS_BUILDINFO_MANUFACTURERNAME), |
975 | 551 | serverStatus); |
976 | | |
977 | | /* BuildInfo - ProductName */ |
978 | 551 | retVal |= setVariableNode_callbackValueSource(server, |
979 | 551 | UA_NS0ID(SERVER_SERVERSTATUS_BUILDINFO_PRODUCTNAME), |
980 | 551 | serverStatus); |
981 | | |
982 | | /* BuildInfo - SoftwareVersion */ |
983 | 551 | retVal |= setVariableNode_callbackValueSource(server, |
984 | 551 | UA_NS0ID(SERVER_SERVERSTATUS_BUILDINFO_SOFTWAREVERSION), |
985 | 551 | serverStatus); |
986 | | |
987 | | /* BuildInfo - BuildNumber */ |
988 | 551 | retVal |= setVariableNode_callbackValueSource(server, |
989 | 551 | UA_NS0ID(SERVER_SERVERSTATUS_BUILDINFO_BUILDNUMBER), |
990 | 551 | serverStatus); |
991 | | |
992 | | /* BuildInfo - BuildDate */ |
993 | 551 | retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERSTATUS_BUILDINFO_BUILDDATE), |
994 | 551 | serverStatus); |
995 | | |
996 | 551 | #ifdef UA_GENERATED_NAMESPACE_ZERO |
997 | | |
998 | | /* SecondsTillShutdown */ |
999 | 551 | retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERSTATUS_SECONDSTILLSHUTDOWN), |
1000 | 551 | serverStatus); |
1001 | | |
1002 | | /* ShutDownReason */ |
1003 | 551 | UA_LocalizedText shutdownReason; |
1004 | 551 | UA_LocalizedText_init(&shutdownReason); |
1005 | 551 | retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERSTATUS_SHUTDOWNREASON, |
1006 | 551 | &shutdownReason, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]); |
1007 | | |
1008 | | /* ServiceLevel */ |
1009 | 551 | UA_CallbackValueSource serviceLevel = {readServiceLevel, NULL}; |
1010 | 551 | retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVICELEVEL), serviceLevel); |
1011 | | |
1012 | | /* ServerDiagnostics - EnabledFlag */ |
1013 | 551 | #ifdef UA_ENABLE_DIAGNOSTICS |
1014 | 551 | UA_Boolean enabledFlag = true; |
1015 | | #else |
1016 | | UA_Boolean enabledFlag = false; |
1017 | | #endif |
1018 | 551 | retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_ENABLEDFLAG, |
1019 | 551 | &enabledFlag, &UA_TYPES[UA_TYPES_BOOLEAN]); |
1020 | | |
1021 | | /* According to Specification part-5 - pg.no-11(PDF pg.no-29), when the |
1022 | | * ServerDiagnostics is disabled the client may modify the value of |
1023 | | * enabledFlag=true in the server. By default, this node have |
1024 | | * CurrentRead/Write access. In CTT, Subscription_Minimum_1/002.js test will |
1025 | | * modify the above flag. This will not be a problem when build |
1026 | | * configuration is set at UA_NAMESPACE_ZERO="REDUCED" as NodeIds will not |
1027 | | * be present. When UA_NAMESPACE_ZERO="FULL", the test will fail. Hence made |
1028 | | * the NodeId as read only */ |
1029 | 551 | retVal |= writeAccessLevelAttribute(server, UA_NS0ID(SERVER_SERVERDIAGNOSTICS_ENABLEDFLAG), |
1030 | 551 | UA_ACCESSLEVELMASK_READ); |
1031 | | |
1032 | | /* Auditing */ |
1033 | 551 | UA_CallbackValueSource auditing = {readAuditing, NULL}; |
1034 | 551 | retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_AUDITING), auditing); |
1035 | | |
1036 | | /* Redundancy Support */ |
1037 | 551 | UA_RedundancySupport redundancySupport = UA_REDUNDANCYSUPPORT_NONE; |
1038 | 551 | retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERREDUNDANCY_REDUNDANCYSUPPORT, |
1039 | 551 | &redundancySupport, &UA_TYPES[UA_TYPES_REDUNDANCYSUPPORT]); |
1040 | | /* Remove unused subtypes of ServerRedundancy */ |
1041 | 551 | deleteNode(server, UA_NS0ID(SERVER_SERVERREDUNDANCY_CURRENTSERVERID), true); |
1042 | 551 | deleteNode(server, UA_NS0ID(SERVER_SERVERREDUNDANCY_REDUNDANTSERVERARRAY), true); |
1043 | 551 | deleteNode(server, UA_NS0ID(SERVER_SERVERREDUNDANCY_SERVERURIARRAY), true); |
1044 | 551 | deleteNode(server, UA_NS0ID(SERVER_SERVERREDUNDANCY_SERVERNETWORKGROUPS), true); |
1045 | 551 | deleteNode(server, UA_NS0ID(SERVER_SERVERCAPABILITIES_CONFORMANCEUNITS), true); |
1046 | 551 | deleteNode(server, UA_NS0ID(SERVER_URISVERSION), true); |
1047 | 551 | deleteNode(server, UA_NS0ID(SERVER_SERVERCAPABILITIES_CONFORMANCEUNITS), true); |
1048 | 551 | deleteNode(server, UA_NS0ID(SERVER_SERVERCAPABILITIES_MAXMONITOREDITEMS), true); |
1049 | 551 | deleteNode(server, UA_NS0ID(SERVER_SERVERCAPABILITIES_MAXMONITOREDITEMSPERSUBSCRIPTION), true); |
1050 | 551 | deleteNode(server, UA_NS0ID(SERVER_SERVERCAPABILITIES_MAXMONITOREDITEMSQUEUESIZE), true); |
1051 | 551 | deleteNode(server, UA_NS0ID(SERVER_SERVERCAPABILITIES_MAXSELECTCLAUSEPARAMETERS), true); |
1052 | 551 | deleteNode(server, UA_NS0ID(SERVER_SERVERCAPABILITIES_MAXSESSIONS), true); |
1053 | 551 | deleteNode(server, UA_NS0ID(SERVER_SERVERCAPABILITIES_MAXSUBSCRIPTIONS), true); |
1054 | 551 | deleteNode(server, UA_NS0ID(SERVER_SERVERCAPABILITIES_MAXSUBSCRIPTIONSPERSESSION), true); |
1055 | 551 | deleteNode(server, UA_NS0ID(SERVER_SERVERCAPABILITIES_MAXWHERECLAUSEPARAMETERS), true); |
1056 | | |
1057 | | /* ServerCapabilities - LocaleIdArray */ |
1058 | 551 | UA_LocaleId locale_en = UA_STRING("en"); |
1059 | 551 | retVal |= writeNs0VariableArray(server, UA_NS0ID_SERVER_SERVERCAPABILITIES_LOCALEIDARRAY, |
1060 | 551 | &locale_en, 1, &UA_TYPES[UA_TYPES_LOCALEID]); |
1061 | | |
1062 | | /* ServerCapabilities - MaxBrowseContinuationPoints */ |
1063 | 551 | UA_UInt16 maxBrowseContinuationPoints = UA_MAXCONTINUATIONPOINTS; |
1064 | 551 | retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERCAPABILITIES_MAXBROWSECONTINUATIONPOINTS, |
1065 | 551 | &maxBrowseContinuationPoints, &UA_TYPES[UA_TYPES_UINT16]); |
1066 | | |
1067 | | /* ServerProfileArray */ |
1068 | 551 | UA_String profileArray[3]; |
1069 | 551 | UA_UInt16 profileArraySize = 0; |
1070 | 1.65k | #define ADDPROFILEARRAY(x) profileArray[profileArraySize++] = UA_STRING(x) |
1071 | 551 | ADDPROFILEARRAY("http://opcfoundation.org/UA-Profile/Server/StandardUA2017"); |
1072 | 551 | #ifdef UA_ENABLE_NODEMANAGEMENT |
1073 | 551 | ADDPROFILEARRAY("http://opcfoundation.org/UA-Profile/Server/NodeManagement"); |
1074 | 551 | #endif |
1075 | 551 | #ifdef UA_ENABLE_METHODCALLS |
1076 | 551 | ADDPROFILEARRAY("http://opcfoundation.org/UA-Profile/Server/Methods"); |
1077 | 551 | #endif |
1078 | 551 | retVal |= writeNs0VariableArray(server, UA_NS0ID_SERVER_SERVERCAPABILITIES_SERVERPROFILEARRAY, |
1079 | 551 | profileArray, profileArraySize, &UA_TYPES[UA_TYPES_STRING]); |
1080 | | |
1081 | | /* ServerCapabilities - MaxQueryContinuationPoints */ |
1082 | 551 | UA_UInt16 maxQueryContinuationPoints = 0; |
1083 | 551 | retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERCAPABILITIES_MAXQUERYCONTINUATIONPOINTS, |
1084 | 551 | &maxQueryContinuationPoints, &UA_TYPES[UA_TYPES_UINT16]); |
1085 | | |
1086 | | /* ServerCapabilities - MaxHistoryContinuationPoints */ |
1087 | 551 | UA_UInt16 maxHistoryContinuationPoints = 0; |
1088 | 551 | retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERCAPABILITIES_MAXHISTORYCONTINUATIONPOINTS, |
1089 | 551 | &maxHistoryContinuationPoints, &UA_TYPES[UA_TYPES_UINT16]); |
1090 | | |
1091 | | /* ServerCapabilities - MinSupportedSampleRate */ |
1092 | 551 | UA_CallbackValueSource samplingInterval = {readMinSamplingInterval, NULL}; |
1093 | 551 | retVal |= setVariableNode_callbackValueSource(server, |
1094 | 551 | UA_NS0ID(SERVER_SERVERCAPABILITIES_MINSUPPORTEDSAMPLERATE), |
1095 | 551 | samplingInterval); |
1096 | | |
1097 | | /* ServerCapabilities - OperationLimits - MaxNodesPerRead */ |
1098 | 551 | UA_CallbackValueSource operationLimitRead = {readOperationLimits, NULL}; |
1099 | 551 | retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERREAD), operationLimitRead); |
1100 | | |
1101 | | /* ServerCapabilities - OperationLimits - maxNodesPerWrite */ |
1102 | 551 | retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERWRITE), operationLimitRead); |
1103 | | |
1104 | | /* ServerCapabilities - OperationLimits - MaxNodesPerMethodCall */ |
1105 | 551 | retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERMETHODCALL), operationLimitRead); |
1106 | | |
1107 | | /* ServerCapabilities - OperationLimits - MaxNodesPerBrowse */ |
1108 | 551 | retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERBROWSE), operationLimitRead); |
1109 | | |
1110 | | /* ServerCapabilities - OperationLimits - MaxNodesPerRegisterNodes */ |
1111 | 551 | retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERREGISTERNODES), operationLimitRead); |
1112 | | |
1113 | | /* ServerCapabilities - OperationLimits - MaxNodesPerTranslateBrowsePathsToNodeIds */ |
1114 | 551 | retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERTRANSLATEBROWSEPATHSTONODEIDS), operationLimitRead); |
1115 | | |
1116 | | /* ServerCapabilities - OperationLimits - MaxNodesPerNodeManagement */ |
1117 | 551 | retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERNODEMANAGEMENT), operationLimitRead); |
1118 | | |
1119 | | /* ServerCapabilities - OperationLimits - MaxMonitoredItemsPerCall */ |
1120 | 551 | retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXMONITOREDITEMSPERCALL), operationLimitRead); |
1121 | | |
1122 | | /* Remove unused operation limit components */ |
1123 | 551 | deleteNode(server, UA_NS0ID(SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERHISTORYREADDATA), true); |
1124 | 551 | deleteNode(server, UA_NS0ID(SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERHISTORYREADEVENTS), true); |
1125 | 551 | deleteNode(server, UA_NS0ID(SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERHISTORYUPDATEDATA), true); |
1126 | 551 | deleteNode(server, UA_NS0ID(SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERHISTORYUPDATEEVENTS), true); |
1127 | 551 | deleteNode(server, UA_NS0ID(SERVER_SERVERCAPABILITIES_ROLESET), true); |
1128 | 551 | deleteNode(server, UA_NS0ID(SERVER_SERVERCAPABILITIES_MAXSTRINGLENGTH), true); |
1129 | 551 | deleteNode(server, UA_NS0ID(SERVER_SERVERCAPABILITIES_MAXARRAYLENGTH), true); |
1130 | 551 | deleteNode(server, UA_NS0ID(SERVER_SERVERCAPABILITIES_MAXBYTESTRINGLENGTH), true); |
1131 | | |
1132 | | /* Remove not supported server configurations */ |
1133 | 551 | deleteNode(server, UA_NS0ID(SERVER_ESTIMATEDRETURNTIME), true); |
1134 | 551 | deleteNode(server, UA_NS0ID(SERVER_LOCALTIME), true); |
1135 | 551 | deleteNode(server, UA_NS0ID(SERVER_REQUESTSERVERSTATECHANGE), true); |
1136 | 551 | deleteNode(server, UA_NS0ID(SERVER_SETSUBSCRIPTIONDURABLE), true); |
1137 | 551 | deleteNode(server, UA_NS0ID(SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTHTTPSGROUP), true); |
1138 | 551 | #ifndef UA_ENABLE_GDS_PUSHMANAGEMENT |
1139 | 551 | deleteNode(server, UA_NS0ID(SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTAPPLICATIONGROUP), true); |
1140 | 551 | deleteNode(server, UA_NS0ID(SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTUSERTOKENGROUP), true); |
1141 | 551 | #endif |
1142 | | |
1143 | | |
1144 | 551 | #ifdef UA_ENABLE_DIAGNOSTICS |
1145 | | /* ServerDiagnostics - ServerDiagnosticsSummary */ |
1146 | 551 | UA_CallbackValueSource serverDiagSummary = {readDiagnostics, NULL}; |
1147 | 551 | retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY), serverDiagSummary); |
1148 | | |
1149 | | /* ServerDiagnostics - ServerDiagnosticsSummary - ServerViewCount */ |
1150 | 551 | retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_SERVERVIEWCOUNT), serverDiagSummary); |
1151 | | |
1152 | | /* ServerDiagnostics - ServerDiagnosticsSummary - CurrentSessionCount */ |
1153 | 551 | retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_CURRENTSESSIONCOUNT), serverDiagSummary); |
1154 | | |
1155 | | /* ServerDiagnostics - ServerDiagnosticsSummary - CumulatedSessionCount */ |
1156 | 551 | retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_CUMULATEDSESSIONCOUNT), serverDiagSummary); |
1157 | | |
1158 | | /* ServerDiagnostics - ServerDiagnosticsSummary - SecurityRejectedSessionCount */ |
1159 | 551 | retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_SECURITYREJECTEDSESSIONCOUNT), serverDiagSummary); |
1160 | | |
1161 | | /* ServerDiagnostics - ServerDiagnosticsSummary - RejectedSessionCount */ |
1162 | 551 | retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_REJECTEDSESSIONCOUNT), serverDiagSummary); |
1163 | | |
1164 | | /* ServerDiagnostics - ServerDiagnosticsSummary - SessionTimeoutCount */ |
1165 | 551 | retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_SESSIONTIMEOUTCOUNT), serverDiagSummary); |
1166 | | |
1167 | | /* ServerDiagnostics - ServerDiagnosticsSummary - SessionAbortCount */ |
1168 | 551 | retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_SESSIONABORTCOUNT), serverDiagSummary); |
1169 | | |
1170 | | /* ServerDiagnostics - ServerDiagnosticsSummary - CurrentSubscriptionCount */ |
1171 | 551 | retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_CURRENTSUBSCRIPTIONCOUNT), serverDiagSummary); |
1172 | | |
1173 | | /* ServerDiagnostics - ServerDiagnosticsSummary - CumulatedSubscriptionCount */ |
1174 | 551 | retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_CUMULATEDSUBSCRIPTIONCOUNT), serverDiagSummary); |
1175 | | |
1176 | | /* ServerDiagnostics - ServerDiagnosticsSummary - PublishingIntervalCount */ |
1177 | 551 | retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_PUBLISHINGINTERVALCOUNT), serverDiagSummary); |
1178 | | |
1179 | | /* ServerDiagnostics - ServerDiagnosticsSummary - SecurityRejectedRequestsCount */ |
1180 | 551 | retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_SECURITYREJECTEDREQUESTSCOUNT), serverDiagSummary); |
1181 | | |
1182 | | /* ServerDiagnostics - ServerDiagnosticsSummary - RejectedRequestsCount */ |
1183 | 551 | retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_REJECTEDREQUESTSCOUNT), serverDiagSummary); |
1184 | | |
1185 | | /* ServerDiagnostics - SubscriptionDiagnosticsArray */ |
1186 | 551 | #ifdef UA_ENABLE_SUBSCRIPTIONS |
1187 | 551 | UA_CallbackValueSource serverSubDiagSummary = {readSubscriptionDiagnosticsArray, NULL}; |
1188 | 551 | retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERDIAGNOSTICS_SUBSCRIPTIONDIAGNOSTICSARRAY), serverSubDiagSummary); |
1189 | 551 | #endif |
1190 | | |
1191 | | /* ServerDiagnostics - SessionDiagnosticsSummary - SessionDiagnosticsArray */ |
1192 | 551 | UA_CallbackValueSource sessionDiagSummary = {readSessionDiagnosticsArray, NULL}; |
1193 | 551 | retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERDIAGNOSTICS_SESSIONSDIAGNOSTICSSUMMARY_SESSIONDIAGNOSTICSARRAY), sessionDiagSummary); |
1194 | | |
1195 | | /* ServerDiagnostics - SessionDiagnosticsSummary - SessionSecurityDiagnosticsArray */ |
1196 | 551 | UA_CallbackValueSource sessionSecDiagSummary = {readSessionSecurityDiagnostics, NULL}; |
1197 | 551 | retVal |= setVariableNode_callbackValueSource(server, UA_NS0ID(SERVER_SERVERDIAGNOSTICS_SESSIONSDIAGNOSTICSSUMMARY_SESSIONSECURITYDIAGNOSTICSARRAY), sessionSecDiagSummary); |
1198 | | |
1199 | | #else |
1200 | | /* Removing these NodeIds make Server Object to be non-complaint with UA |
1201 | | * 1.03 in CTT (Base Inforamtion/Base Info Core Structure/ 001.js) In the |
1202 | | * 1.04 specification this has been resolved by allowing to remove these |
1203 | | * static nodes as well */ |
1204 | | deleteNode(server, UA_NS0ID(SERVER_SERVERDIAGNOSTICS_SESSIONSDIAGNOSTICSSUMMARY), true); |
1205 | | deleteNode(server, UA_NS0ID(SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY), true); |
1206 | | deleteNode(server, UA_NS0ID(SERVER_SERVERDIAGNOSTICS_SUBSCRIPTIONDIAGNOSTICSARRAY), true); |
1207 | | #endif |
1208 | | |
1209 | | /* The sampling diagnostics array is optional |
1210 | | * TODO: Add support for this diagnostics */ |
1211 | 551 | deleteNode(server, UA_NS0ID(SERVER_SERVERDIAGNOSTICS_SAMPLINGINTERVALDIAGNOSTICSARRAY), true); |
1212 | | |
1213 | | #ifndef UA_ENABLE_PUBSUB |
1214 | | deleteNode(server, UA_NS0ID(PUBLISHSUBSCRIBE), true); |
1215 | | #endif |
1216 | | |
1217 | | #ifndef UA_ENABLE_HISTORIZING |
1218 | | deleteNode(server, UA_NS0ID(HISTORYSERVERCAPABILITIES), true); |
1219 | | #else |
1220 | | /* ServerCapabilities - HistoryServerCapabilities - AccessHistoryDataCapability */ |
1221 | 551 | retVal |= writeNs0Variable(server, UA_NS0ID_HISTORYSERVERCAPABILITIES_ACCESSHISTORYDATACAPABILITY, |
1222 | 551 | &server->config.accessHistoryDataCapability, &UA_TYPES[UA_TYPES_BOOLEAN]); |
1223 | | |
1224 | | /* ServerCapabilities - HistoryServerCapabilities - MaxReturnDataValues */ |
1225 | 551 | retVal |= writeNs0Variable(server, UA_NS0ID_HISTORYSERVERCAPABILITIES_MAXRETURNDATAVALUES, |
1226 | 551 | &server->config.maxReturnDataValues, &UA_TYPES[UA_TYPES_UINT32]); |
1227 | | |
1228 | | /* ServerCapabilities - HistoryServerCapabilities - AccessHistoryEventsCapability */ |
1229 | 551 | retVal |= writeNs0Variable(server, UA_NS0ID_HISTORYSERVERCAPABILITIES_ACCESSHISTORYEVENTSCAPABILITY, |
1230 | 551 | &server->config.accessHistoryEventsCapability, &UA_TYPES[UA_TYPES_BOOLEAN]); |
1231 | | |
1232 | | /* ServerCapabilities - HistoryServerCapabilities - MaxReturnEventValues */ |
1233 | 551 | retVal |= writeNs0Variable(server, UA_NS0ID_HISTORYSERVERCAPABILITIES_MAXRETURNEVENTVALUES, |
1234 | 551 | &server->config.maxReturnEventValues, &UA_TYPES[UA_TYPES_UINT32]); |
1235 | | |
1236 | | /* ServerCapabilities - HistoryServerCapabilities - InsertDataCapability */ |
1237 | 551 | retVal |= writeNs0Variable(server, UA_NS0ID_HISTORYSERVERCAPABILITIES_INSERTDATACAPABILITY, |
1238 | 551 | &server->config.insertDataCapability, &UA_TYPES[UA_TYPES_BOOLEAN]); |
1239 | | |
1240 | | /* ServerCapabilities - HistoryServerCapabilities - InsertEventCapability */ |
1241 | 551 | retVal |= writeNs0Variable(server, UA_NS0ID_HISTORYSERVERCAPABILITIES_INSERTEVENTCAPABILITY, |
1242 | 551 | &server->config.insertEventCapability, &UA_TYPES[UA_TYPES_BOOLEAN]); |
1243 | | |
1244 | | /* ServerCapabilities - HistoryServerCapabilities - InsertAnnotationsCapability */ |
1245 | 551 | retVal |= writeNs0Variable(server, UA_NS0ID_HISTORYSERVERCAPABILITIES_INSERTANNOTATIONCAPABILITY, |
1246 | 551 | &server->config.insertAnnotationsCapability, &UA_TYPES[UA_TYPES_BOOLEAN]); |
1247 | | |
1248 | | /* ServerCapabilities - HistoryServerCapabilities - ReplaceDataCapability */ |
1249 | 551 | retVal |= writeNs0Variable(server, UA_NS0ID_HISTORYSERVERCAPABILITIES_REPLACEDATACAPABILITY, |
1250 | 551 | &server->config.replaceDataCapability, &UA_TYPES[UA_TYPES_BOOLEAN]); |
1251 | | |
1252 | | /* ServerCapabilities - HistoryServerCapabilities - ReplaceEventCapability */ |
1253 | 551 | retVal |= writeNs0Variable(server, UA_NS0ID_HISTORYSERVERCAPABILITIES_REPLACEEVENTCAPABILITY, |
1254 | 551 | &server->config.replaceEventCapability, &UA_TYPES[UA_TYPES_BOOLEAN]); |
1255 | | |
1256 | | /* ServerCapabilities - HistoryServerCapabilities - UpdateDataCapability */ |
1257 | 551 | retVal |= writeNs0Variable(server, UA_NS0ID_HISTORYSERVERCAPABILITIES_UPDATEDATACAPABILITY, |
1258 | 551 | &server->config.updateDataCapability, &UA_TYPES[UA_TYPES_BOOLEAN]); |
1259 | | |
1260 | | /* ServerCapabilities - HistoryServerCapabilities - UpdateEventCapability */ |
1261 | 551 | retVal |= writeNs0Variable(server, UA_NS0ID_HISTORYSERVERCAPABILITIES_UPDATEEVENTCAPABILITY, |
1262 | 551 | &server->config.updateEventCapability, &UA_TYPES[UA_TYPES_BOOLEAN]); |
1263 | | |
1264 | | /* ServerCapabilities - HistoryServerCapabilities - DeleteRawCapability */ |
1265 | 551 | retVal |= writeNs0Variable(server, UA_NS0ID_HISTORYSERVERCAPABILITIES_DELETERAWCAPABILITY, |
1266 | 551 | &server->config.deleteRawCapability, &UA_TYPES[UA_TYPES_BOOLEAN]); |
1267 | | |
1268 | | /* ServerCapabilities - HistoryServerCapabilities - DeleteEventCapability */ |
1269 | 551 | retVal |= writeNs0Variable(server, UA_NS0ID_HISTORYSERVERCAPABILITIES_DELETEEVENTCAPABILITY, |
1270 | 551 | &server->config.deleteEventCapability, &UA_TYPES[UA_TYPES_BOOLEAN]); |
1271 | | |
1272 | | /* ServerCapabilities - HistoryServerCapabilities - DeleteAtTimeDataCapability */ |
1273 | 551 | retVal |= writeNs0Variable(server, UA_NS0ID_HISTORYSERVERCAPABILITIES_DELETEATTIMECAPABILITY, |
1274 | 551 | &server->config.deleteAtTimeDataCapability, &UA_TYPES[UA_TYPES_BOOLEAN]); |
1275 | 551 | #endif |
1276 | | |
1277 | 551 | #if defined(UA_ENABLE_METHODCALLS) && defined(UA_ENABLE_SUBSCRIPTIONS) |
1278 | 551 | retVal |= setMethodNode_callback(server, UA_NS0ID(SERVER_GETMONITOREDITEMS), readMonitoredItems); |
1279 | 551 | retVal |= setMethodNode_callback(server, UA_NS0ID(SERVER_RESENDDATA), resendData); |
1280 | 551 | #endif |
1281 | | |
1282 | | /* The HasComponent references to the ModellingRules are not part of the |
1283 | | * Nodeset2.xml. So we add the references manually. */ |
1284 | 551 | addModellingRules(server); |
1285 | | |
1286 | 551 | #endif /* UA_GENERATED_NAMESPACE_ZERO */ |
1287 | | |
1288 | 551 | if(retVal != UA_STATUSCODE_GOOD) { |
1289 | 0 | UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER, |
1290 | 0 | "Initialization of Namespace 0 (after bootstrapping) " |
1291 | 0 | "failed with %s. See previous outputs for any error messages.", |
1292 | 0 | UA_StatusCode_name(retVal)); |
1293 | 0 | return UA_STATUSCODE_BADINTERNALERROR; |
1294 | 0 | } |
1295 | 551 | return UA_STATUSCODE_GOOD; |
1296 | 551 | } |