ua_services_attribute.c 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884
  1. #include "ua_server_internal.h"
  2. #include "ua_services.h"
  3. /******************/
  4. /* Read Attribute */
  5. /******************/
  6. static size_t
  7. readNumber(UA_Byte *buf, size_t buflen, UA_UInt32 *number) {
  8. UA_UInt32 n = 0;
  9. size_t progress = 0;
  10. /* read numbers until the end or a non-number character appears */
  11. while(progress < buflen) {
  12. UA_Byte c = buf[progress];
  13. if('0' > c || '9' < c)
  14. break;
  15. n = (n*10) + (UA_UInt32)(c-'0');
  16. progress++;
  17. }
  18. *number = n;
  19. return progress;
  20. }
  21. static size_t
  22. readDimension(UA_Byte *buf, size_t buflen, struct UA_NumericRangeDimension *dim) {
  23. size_t progress = readNumber(buf, buflen, &dim->min);
  24. if(progress == 0)
  25. return 0;
  26. if(buflen <= progress + 1 || buf[progress] != ':') {
  27. dim->max = dim->min;
  28. return progress;
  29. }
  30. progress++;
  31. size_t progress2 = readNumber(&buf[progress], buflen - progress, &dim->max);
  32. if(progress2 == 0)
  33. return 0;
  34. /* invalid range */
  35. if(dim->min >= dim->max)
  36. return 0;
  37. return progress + progress2;
  38. }
  39. #ifndef UA_BUILD_UNIT_TESTS
  40. static
  41. #endif
  42. UA_StatusCode parse_numericrange(const UA_String *str, UA_NumericRange *range) {
  43. size_t idx = 0;
  44. size_t dimensionsMax = 0;
  45. struct UA_NumericRangeDimension *dimensions = NULL;
  46. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  47. size_t offset = 0;
  48. while(true) {
  49. /* alloc dimensions */
  50. if(idx >= dimensionsMax) {
  51. struct UA_NumericRangeDimension *newds;
  52. size_t newdssize = sizeof(struct UA_NumericRangeDimension) * (dimensionsMax + 2);
  53. newds = UA_realloc(dimensions, newdssize);
  54. if(!newds) {
  55. retval = UA_STATUSCODE_BADOUTOFMEMORY;
  56. break;
  57. }
  58. dimensions = newds;
  59. dimensionsMax = dimensionsMax + 2;
  60. }
  61. /* read the dimension */
  62. size_t progress = readDimension(&str->data[offset], str->length - offset,
  63. &dimensions[idx]);
  64. if(progress == 0) {
  65. retval = UA_STATUSCODE_BADINDEXRANGEINVALID;
  66. break;
  67. }
  68. offset += progress;
  69. idx++;
  70. /* loop into the next dimension */
  71. if(offset >= str->length)
  72. break;
  73. if(str->data[offset] != ',') {
  74. retval = UA_STATUSCODE_BADINDEXRANGEINVALID;
  75. break;
  76. }
  77. offset++;
  78. }
  79. if(retval == UA_STATUSCODE_GOOD && idx > 0) {
  80. range->dimensions = dimensions;
  81. range->dimensionsSize = idx;
  82. } else
  83. UA_free(dimensions);
  84. return retval;
  85. }
  86. #define CHECK_NODECLASS(CLASS) \
  87. if(!(node->nodeClass & (CLASS))) { \
  88. retval = UA_STATUSCODE_BADATTRIBUTEIDINVALID; \
  89. break; \
  90. }
  91. static void
  92. handleServerTimestamps(UA_TimestampsToReturn timestamps, UA_DataValue* v) {
  93. if(v && (timestamps == UA_TIMESTAMPSTORETURN_SERVER ||
  94. timestamps == UA_TIMESTAMPSTORETURN_BOTH)) {
  95. v->hasServerTimestamp = true;
  96. v->serverTimestamp = UA_DateTime_now();
  97. }
  98. }
  99. static void
  100. handleSourceTimestamps(UA_TimestampsToReturn timestamps, UA_DataValue* v) {
  101. if(timestamps == UA_TIMESTAMPSTORETURN_SOURCE ||
  102. timestamps == UA_TIMESTAMPSTORETURN_BOTH) {
  103. v->hasSourceTimestamp = true;
  104. v->sourceTimestamp = UA_DateTime_now();
  105. }
  106. }
  107. /* force cast for zero-copy reading. ensure that the variant is never written into. */
  108. static void forceVariantSetScalar(UA_Variant *v, const void *p, const UA_DataType *t) {
  109. UA_Variant_init(v);
  110. v->type = t;
  111. v->data = (void*)(uintptr_t)p;
  112. v->storageType = UA_VARIANT_DATA_NODELETE;
  113. }
  114. static UA_StatusCode
  115. getVariableNodeValue(UA_Server *server, UA_Session *session,
  116. const UA_VariableNode *vn,
  117. const UA_TimestampsToReturn timestamps,
  118. const UA_ReadValueId *id, UA_DataValue *v) {
  119. UA_NumericRange range;
  120. UA_NumericRange *rangeptr = NULL;
  121. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  122. if(id->indexRange.length > 0) {
  123. retval = parse_numericrange(&id->indexRange, &range);
  124. if(retval != UA_STATUSCODE_GOOD)
  125. return retval;
  126. rangeptr = &range;
  127. }
  128. if(vn->valueSource == UA_VALUESOURCE_VARIANT) {
  129. if(vn->value.variant.callback.onRead)
  130. vn->value.variant.callback.onRead(vn->value.variant.callback.handle, vn->nodeId,
  131. &v->value, rangeptr);
  132. if(!rangeptr) {
  133. v->value = vn->value.variant.value;
  134. v->value.storageType = UA_VARIANT_DATA_NODELETE;
  135. } else
  136. retval = UA_Variant_copyRange(&vn->value.variant.value, &v->value, range);
  137. if(retval == UA_STATUSCODE_GOOD)
  138. handleSourceTimestamps(timestamps, v);
  139. } else {
  140. if(!vn->value.dataSource.read) {
  141. UA_LOG_DEBUG_SESSION(server->config.logger, session,
  142. "DataSource cannot be read in ReadRequest");
  143. retval = UA_STATUSCODE_BADINTERNALERROR;
  144. } else {
  145. UA_Boolean sourceTimeStamp = (timestamps == UA_TIMESTAMPSTORETURN_SOURCE ||
  146. timestamps == UA_TIMESTAMPSTORETURN_BOTH);
  147. retval = vn->value.dataSource.read(vn->value.dataSource.handle, vn->nodeId,
  148. sourceTimeStamp, rangeptr, v);
  149. }
  150. }
  151. if(rangeptr)
  152. UA_free(range.dimensions);
  153. return retval;
  154. }
  155. static UA_StatusCode
  156. getVariableNodeDataType(UA_Server *server, UA_Session *session,
  157. const UA_VariableNode *vn, UA_DataValue *v) {
  158. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  159. if(vn->valueSource == UA_VALUESOURCE_VARIANT) {
  160. if(vn->value.variant.value.type) {
  161. forceVariantSetScalar(&v->value, &vn->value.variant.value.type->typeId,
  162. &UA_TYPES[UA_TYPES_NODEID]);
  163. } else {
  164. UA_NodeId nullid;
  165. UA_NodeId_init(&nullid);
  166. UA_Variant_setScalarCopy(&v->value, &nullid, &UA_TYPES[UA_TYPES_NODEID]);
  167. }
  168. } else {
  169. /* Read from the datasource to see the data type */
  170. if(!vn->value.dataSource.read) {
  171. UA_LOG_DEBUG_SESSION(server->config.logger, session,
  172. "DataSource cannot be read in ReadRequest");
  173. return UA_STATUSCODE_BADINTERNALERROR;
  174. }
  175. UA_DataValue val;
  176. UA_DataValue_init(&val);
  177. val.hasValue = false; // always assume we are not given a value by userspace
  178. retval = vn->value.dataSource.read(vn->value.dataSource.handle,
  179. vn->nodeId, false, NULL, &val);
  180. if(retval != UA_STATUSCODE_GOOD)
  181. return retval;
  182. if(val.hasValue && val.value.type)
  183. retval = UA_Variant_setScalarCopy(&v->value, &val.value.type->typeId,
  184. &UA_TYPES[UA_TYPES_NODEID]);
  185. UA_DataValue_deleteMembers(&val);
  186. }
  187. return retval;
  188. }
  189. static UA_StatusCode
  190. getVariableNodeArrayDimensions(UA_Server *server, UA_Session *session,
  191. const UA_VariableNode *vn, UA_DataValue *v) {
  192. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  193. if(vn->valueSource == UA_VALUESOURCE_VARIANT) {
  194. UA_Variant_setArray(&v->value, vn->value.variant.value.arrayDimensions,
  195. vn->value.variant.value.arrayDimensionsSize,
  196. &UA_TYPES[UA_TYPES_INT32]);
  197. v->value.storageType = UA_VARIANT_DATA_NODELETE;
  198. } else {
  199. if(!vn->value.dataSource.read) {
  200. UA_LOG_DEBUG_SESSION(server->config.logger, session,
  201. "DataSource cannot be read in ReadRequest");
  202. return UA_STATUSCODE_BADINTERNALERROR;
  203. }
  204. /* Read the datasource to see the array dimensions */
  205. UA_DataValue val;
  206. UA_DataValue_init(&val);
  207. retval = vn->value.dataSource.read(vn->value.dataSource.handle,
  208. vn->nodeId, false, NULL, &val);
  209. if(retval != UA_STATUSCODE_GOOD)
  210. return retval;
  211. retval = UA_Variant_setArrayCopy(&v->value, val.value.arrayDimensions,
  212. val.value.arrayDimensionsSize,
  213. &UA_TYPES[UA_TYPES_INT32]);
  214. UA_DataValue_deleteMembers(&val);
  215. }
  216. return retval;
  217. }
  218. static const UA_String binEncoding = {sizeof("DefaultBinary")-1, (UA_Byte*)"DefaultBinary"};
  219. /* clang complains about unused variables */
  220. // static const UA_String xmlEncoding = {sizeof("DefaultXml")-1, (UA_Byte*)"DefaultXml"};
  221. /* Reads a single attribute from a node in the nodestore */
  222. void Service_Read_single(UA_Server *server, UA_Session *session,
  223. const UA_TimestampsToReturn timestamps,
  224. const UA_ReadValueId *id, UA_DataValue *v) {
  225. UA_LOG_DEBUG_SESSION(server->config.logger, session,
  226. "Read the attribute %i", id->attributeId);
  227. if(id->dataEncoding.name.length > 0 &&
  228. !UA_String_equal(&binEncoding, &id->dataEncoding.name)) {
  229. v->hasStatus = true;
  230. v->status = UA_STATUSCODE_BADDATAENCODINGUNSUPPORTED;
  231. return;
  232. }
  233. /* index range for a non-value */
  234. if(id->indexRange.length > 0 && id->attributeId != UA_ATTRIBUTEID_VALUE){
  235. v->hasStatus = true;
  236. v->status = UA_STATUSCODE_BADINDEXRANGENODATA;
  237. return;
  238. }
  239. UA_Node const *node = UA_NodeStore_get(server->nodestore, &id->nodeId);
  240. if(!node) {
  241. v->hasStatus = true;
  242. v->status = UA_STATUSCODE_BADNODEIDUNKNOWN;
  243. return;
  244. }
  245. /* When setting the value fails in the switch, we get an error code and set
  246. hasValue to false */
  247. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  248. v->hasValue = true;
  249. switch(id->attributeId) {
  250. case UA_ATTRIBUTEID_NODEID:
  251. forceVariantSetScalar(&v->value, &node->nodeId, &UA_TYPES[UA_TYPES_NODEID]);
  252. break;
  253. case UA_ATTRIBUTEID_NODECLASS:
  254. forceVariantSetScalar(&v->value, &node->nodeClass, &UA_TYPES[UA_TYPES_NODECLASS]);
  255. break;
  256. case UA_ATTRIBUTEID_BROWSENAME:
  257. forceVariantSetScalar(&v->value, &node->browseName, &UA_TYPES[UA_TYPES_QUALIFIEDNAME]);
  258. break;
  259. case UA_ATTRIBUTEID_DISPLAYNAME:
  260. forceVariantSetScalar(&v->value, &node->displayName, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
  261. break;
  262. case UA_ATTRIBUTEID_DESCRIPTION:
  263. forceVariantSetScalar(&v->value, &node->description, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
  264. break;
  265. case UA_ATTRIBUTEID_WRITEMASK:
  266. forceVariantSetScalar(&v->value, &node->writeMask, &UA_TYPES[UA_TYPES_UINT32]);
  267. break;
  268. case UA_ATTRIBUTEID_USERWRITEMASK:
  269. forceVariantSetScalar(&v->value, &node->userWriteMask, &UA_TYPES[UA_TYPES_UINT32]);
  270. break;
  271. case UA_ATTRIBUTEID_ISABSTRACT:
  272. CHECK_NODECLASS(UA_NODECLASS_REFERENCETYPE | UA_NODECLASS_OBJECTTYPE |
  273. UA_NODECLASS_VARIABLETYPE | UA_NODECLASS_DATATYPE);
  274. forceVariantSetScalar(&v->value, &((const UA_ReferenceTypeNode*)node)->isAbstract,
  275. &UA_TYPES[UA_TYPES_BOOLEAN]);
  276. break;
  277. case UA_ATTRIBUTEID_SYMMETRIC:
  278. CHECK_NODECLASS(UA_NODECLASS_REFERENCETYPE);
  279. forceVariantSetScalar(&v->value, &((const UA_ReferenceTypeNode*)node)->symmetric,
  280. &UA_TYPES[UA_TYPES_BOOLEAN]);
  281. break;
  282. case UA_ATTRIBUTEID_INVERSENAME:
  283. CHECK_NODECLASS(UA_NODECLASS_REFERENCETYPE);
  284. forceVariantSetScalar(&v->value, &((const UA_ReferenceTypeNode*)node)->inverseName,
  285. &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
  286. break;
  287. case UA_ATTRIBUTEID_CONTAINSNOLOOPS:
  288. CHECK_NODECLASS(UA_NODECLASS_VIEW);
  289. forceVariantSetScalar(&v->value, &((const UA_ViewNode*)node)->containsNoLoops,
  290. &UA_TYPES[UA_TYPES_BOOLEAN]);
  291. break;
  292. case UA_ATTRIBUTEID_EVENTNOTIFIER:
  293. CHECK_NODECLASS(UA_NODECLASS_VIEW | UA_NODECLASS_OBJECT);
  294. forceVariantSetScalar(&v->value, &((const UA_ViewNode*)node)->eventNotifier,
  295. &UA_TYPES[UA_TYPES_BYTE]);
  296. break;
  297. case UA_ATTRIBUTEID_VALUE:
  298. CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
  299. retval = getVariableNodeValue(server, session, (const UA_VariableNode*)node, timestamps, id, v);
  300. break;
  301. case UA_ATTRIBUTEID_DATATYPE:
  302. CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
  303. retval = getVariableNodeDataType(server, session, (const UA_VariableNode*)node, v);
  304. break;
  305. case UA_ATTRIBUTEID_VALUERANK:
  306. CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
  307. forceVariantSetScalar(&v->value, &((const UA_VariableTypeNode*)node)->valueRank,
  308. &UA_TYPES[UA_TYPES_INT32]);
  309. break;
  310. case UA_ATTRIBUTEID_ARRAYDIMENSIONS:
  311. CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
  312. retval = getVariableNodeArrayDimensions(server, session, (const UA_VariableNode*)node, v);
  313. break;
  314. case UA_ATTRIBUTEID_ACCESSLEVEL:
  315. CHECK_NODECLASS(UA_NODECLASS_VARIABLE);
  316. forceVariantSetScalar(&v->value, &((const UA_VariableNode*)node)->accessLevel,
  317. &UA_TYPES[UA_TYPES_BYTE]);
  318. break;
  319. case UA_ATTRIBUTEID_USERACCESSLEVEL:
  320. CHECK_NODECLASS(UA_NODECLASS_VARIABLE);
  321. forceVariantSetScalar(&v->value, &((const UA_VariableNode*)node)->userAccessLevel,
  322. &UA_TYPES[UA_TYPES_BYTE]);
  323. break;
  324. case UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL:
  325. CHECK_NODECLASS(UA_NODECLASS_VARIABLE);
  326. forceVariantSetScalar(&v->value, &((const UA_VariableNode*)node)->minimumSamplingInterval,
  327. &UA_TYPES[UA_TYPES_DOUBLE]);
  328. break;
  329. case UA_ATTRIBUTEID_HISTORIZING:
  330. CHECK_NODECLASS(UA_NODECLASS_VARIABLE);
  331. forceVariantSetScalar(&v->value, &((const UA_VariableNode*)node)->historizing,
  332. &UA_TYPES[UA_TYPES_BOOLEAN]);
  333. break;
  334. case UA_ATTRIBUTEID_EXECUTABLE:
  335. CHECK_NODECLASS(UA_NODECLASS_METHOD);
  336. forceVariantSetScalar(&v->value, &((const UA_MethodNode*)node)->executable,
  337. &UA_TYPES[UA_TYPES_BOOLEAN]);
  338. break;
  339. case UA_ATTRIBUTEID_USEREXECUTABLE:
  340. CHECK_NODECLASS(UA_NODECLASS_METHOD);
  341. forceVariantSetScalar(&v->value, &((const UA_MethodNode*)node)->userExecutable,
  342. &UA_TYPES[UA_TYPES_BOOLEAN]);
  343. break;
  344. default:
  345. retval = UA_STATUSCODE_BADATTRIBUTEIDINVALID;
  346. break;
  347. }
  348. if(retval != UA_STATUSCODE_GOOD) {
  349. v->hasValue = false;
  350. v->hasStatus = true;
  351. v->status = retval;
  352. }
  353. // Todo: what if the timestamp from the datasource are already present?
  354. handleServerTimestamps(timestamps, v);
  355. }
  356. void Service_Read(UA_Server *server, UA_Session *session,
  357. const UA_ReadRequest *request, UA_ReadResponse *response) {
  358. UA_LOG_DEBUG_SESSION(server->config.logger, session, "Processing ReadRequest");
  359. if(request->nodesToReadSize <= 0) {
  360. response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
  361. return;
  362. }
  363. /* check if the timestampstoreturn is valid */
  364. if(request->timestampsToReturn > UA_TIMESTAMPSTORETURN_NEITHER) {
  365. response->responseHeader.serviceResult = UA_STATUSCODE_BADTIMESTAMPSTORETURNINVALID;
  366. return;
  367. }
  368. size_t size = request->nodesToReadSize;
  369. response->results = UA_Array_new(size, &UA_TYPES[UA_TYPES_DATAVALUE]);
  370. if(!response->results) {
  371. response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
  372. return;
  373. }
  374. response->resultsSize = size;
  375. if(request->maxAge < 0) {
  376. response->responseHeader.serviceResult = UA_STATUSCODE_BADMAXAGEINVALID;
  377. return;
  378. }
  379. #ifdef UA_ENABLE_EXTERNAL_NAMESPACES
  380. UA_Boolean isExternal[size];
  381. UA_UInt32 indices[size];
  382. memset(isExternal, false, sizeof(UA_Boolean) * size);
  383. for(size_t j = 0;j<server->externalNamespacesSize;j++) {
  384. size_t indexSize = 0;
  385. for(size_t i = 0;i < size;i++) {
  386. if(request->nodesToRead[i].nodeId.namespaceIndex != server->externalNamespaces[j].index)
  387. continue;
  388. isExternal[i] = true;
  389. indices[indexSize] = (UA_UInt32)i;
  390. indexSize++;
  391. }
  392. if(indexSize == 0)
  393. continue;
  394. UA_ExternalNodeStore *ens = &server->externalNamespaces[j].externalNodeStore;
  395. ens->readNodes(ens->ensHandle, &request->requestHeader, request->nodesToRead,
  396. indices, (UA_UInt32)indexSize, response->results, false,
  397. response->diagnosticInfos);
  398. }
  399. #endif
  400. for(size_t i = 0;i < size;i++) {
  401. #ifdef UA_ENABLE_EXTERNAL_NAMESPACES
  402. if(!isExternal[i])
  403. #endif
  404. Service_Read_single(server, session, request->timestampsToReturn,
  405. &request->nodesToRead[i], &response->results[i]);
  406. }
  407. #ifdef UA_ENABLE_NONSTANDARD_STATELESS
  408. /* Add an expiry header for caching */
  409. if(session->sessionId.namespaceIndex == 0 &&
  410. session->sessionId.identifierType == UA_NODEIDTYPE_NUMERIC &&
  411. session->sessionId.identifier.numeric == 0){
  412. UA_ExtensionObject additionalHeader;
  413. UA_ExtensionObject_init(&additionalHeader);
  414. additionalHeader.encoding = UA_EXTENSIONOBJECT_ENCODED_BYTESTRING;
  415. additionalHeader.content.encoded.typeId =UA_TYPES[UA_TYPES_VARIANT].typeId;
  416. UA_Variant variant;
  417. UA_Variant_init(&variant);
  418. UA_DateTime* expireArray = NULL;
  419. expireArray = UA_Array_new(request->nodesToReadSize,
  420. &UA_TYPES[UA_TYPES_DATETIME]);
  421. variant.data = expireArray;
  422. /* expires in 20 seconds */
  423. for(UA_UInt32 i = 0;i < response->resultsSize;i++) {
  424. expireArray[i] = UA_DateTime_now() + 20 * 100 * 1000 * 1000;
  425. }
  426. UA_Variant_setArray(&variant, expireArray, request->nodesToReadSize,
  427. &UA_TYPES[UA_TYPES_DATETIME]);
  428. size_t offset = 0;
  429. UA_ByteString str;
  430. size_t strlength = UA_calcSizeBinary(&variant, &UA_TYPES[UA_TYPES_VARIANT]);
  431. UA_ByteString_allocBuffer(&str, strlength);
  432. /* No chunking callback for the encoding */
  433. UA_StatusCode retval = UA_encodeBinary(&variant, &UA_TYPES[UA_TYPES_VARIANT],
  434. NULL, NULL, &str, &offset);
  435. UA_Array_delete(expireArray, request->nodesToReadSize, &UA_TYPES[UA_TYPES_DATETIME]);
  436. if(retval == UA_STATUSCODE_GOOD){
  437. additionalHeader.content.encoded.body.data = str.data;
  438. additionalHeader.content.encoded.body.length = offset;
  439. response->responseHeader.additionalHeader = additionalHeader;
  440. }
  441. }
  442. #endif
  443. }
  444. UA_DataValue
  445. UA_Server_read(UA_Server *server, const UA_ReadValueId *item,
  446. UA_TimestampsToReturn timestamps) {
  447. UA_DataValue dv;
  448. UA_DataValue_init(&dv);
  449. UA_RCU_LOCK();
  450. Service_Read_single(server, &adminSession, timestamps, item, &dv);
  451. UA_RCU_UNLOCK();
  452. return dv;
  453. }
  454. UA_StatusCode
  455. __UA_Server_read(UA_Server *server, const UA_NodeId *nodeId,
  456. const UA_AttributeId attributeId, void *v) {
  457. /* Call the read service */
  458. UA_ReadValueId item;
  459. UA_ReadValueId_init(&item);
  460. item.nodeId = *nodeId;
  461. item.attributeId = attributeId;
  462. UA_DataValue dv = UA_Server_read(server, &item, UA_TIMESTAMPSTORETURN_NEITHER);
  463. /* Check the return value */
  464. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  465. if(dv.hasStatus)
  466. retval = dv.hasStatus;
  467. else if(!dv.hasValue)
  468. retval = UA_STATUSCODE_BADUNEXPECTEDERROR;
  469. if(retval != UA_STATUSCODE_GOOD) {
  470. UA_DataValue_deleteMembers(&dv);
  471. return retval;
  472. }
  473. /* Prepare the result */
  474. if(attributeId == UA_ATTRIBUTEID_VALUE ||
  475. attributeId == UA_ATTRIBUTEID_ARRAYDIMENSIONS) {
  476. /* Return the entire variant */
  477. if(dv.value.storageType == UA_VARIANT_DATA_NODELETE) {
  478. retval = UA_Variant_copy(dv.value.data, v);
  479. } else { /* storageType is UA_VARIANT_DATA */
  480. memcpy(v, &dv.value, sizeof(UA_Variant));
  481. }
  482. } else {
  483. /* Return the variant content only */
  484. if(dv.value.storageType == UA_VARIANT_DATA_NODELETE) {
  485. retval = UA_copy(dv.value.data, v, dv.value.type);
  486. } else { /* storageType is UA_VARIANT_DATA */
  487. /* Copy the content of the type (including pointers and all)*/
  488. memcpy(v, dv.value.data, dv.value.type->memSize);
  489. /* Delete the "carrier" in the variant */
  490. UA_free(dv.value.data);
  491. }
  492. }
  493. return retval;
  494. }
  495. /*******************/
  496. /* Write Attribute */
  497. /*******************/
  498. UA_StatusCode UA_Server_editNode(UA_Server *server, UA_Session *session,
  499. const UA_NodeId *nodeId, UA_EditNodeCallback callback,
  500. const void *data) {
  501. UA_StatusCode retval;
  502. do {
  503. #ifndef UA_ENABLE_MULTITHREADING
  504. const UA_Node *node = UA_NodeStore_get(server->nodestore, nodeId);
  505. if(!node)
  506. return UA_STATUSCODE_BADNODEIDUNKNOWN;
  507. UA_Node *editNode = (UA_Node*)(uintptr_t)node; // dirty cast. use only here.
  508. retval = callback(server, session, editNode, data);
  509. return retval;
  510. #else
  511. UA_Node *copy = UA_NodeStore_getCopy(server->nodestore, nodeId);
  512. if(!copy)
  513. return UA_STATUSCODE_BADOUTOFMEMORY;
  514. retval = callback(server, session, copy, data);
  515. if(retval != UA_STATUSCODE_GOOD) {
  516. UA_NodeStore_deleteNode(copy);
  517. return retval;
  518. }
  519. retval = UA_NodeStore_replace(server->nodestore, copy);
  520. #endif
  521. } while(retval != UA_STATUSCODE_GOOD);
  522. return UA_STATUSCODE_GOOD;
  523. }
  524. #define CHECK_DATATYPE(EXP_DT) \
  525. if(!wvalue->value.hasValue || \
  526. &UA_TYPES[UA_TYPES_##EXP_DT] != wvalue->value.value.type || \
  527. !UA_Variant_isScalar(&wvalue->value.value)) { \
  528. retval = UA_STATUSCODE_BADTYPEMISMATCH; \
  529. break; \
  530. }
  531. #define CHECK_NODECLASS_WRITE(CLASS) \
  532. if((node->nodeClass & (CLASS)) == 0) { \
  533. retval = UA_STATUSCODE_BADNODECLASSINVALID; \
  534. break; \
  535. }
  536. static UA_StatusCode
  537. Service_Write_single_ValueDataSource(UA_Server *server, UA_Session *session,
  538. const UA_VariableNode *node, const UA_WriteValue *wvalue)
  539. {
  540. UA_assert(wvalue->attributeId == UA_ATTRIBUTEID_VALUE);
  541. UA_assert(node->nodeClass == UA_NODECLASS_VARIABLE ||
  542. node->nodeClass == UA_NODECLASS_VARIABLETYPE);
  543. UA_assert(node->valueSource == UA_VALUESOURCE_DATASOURCE);
  544. if(node->value.dataSource.write == NULL)
  545. return UA_STATUSCODE_BADWRITENOTSUPPORTED;
  546. UA_StatusCode retval;
  547. if(wvalue->indexRange.length <= 0) {
  548. retval = node->value.dataSource.write(node->value.dataSource.handle, node->nodeId,
  549. &wvalue->value.value, NULL);
  550. } else {
  551. UA_NumericRange range;
  552. retval = parse_numericrange(&wvalue->indexRange, &range);
  553. if(retval != UA_STATUSCODE_GOOD)
  554. return retval;
  555. retval = node->value.dataSource.write(node->value.dataSource.handle, node->nodeId,
  556. &wvalue->value.value, &range);
  557. UA_free(range.dimensions);
  558. }
  559. return retval;
  560. }
  561. enum type_equivalence {
  562. TYPE_EQUIVALENCE_NONE,
  563. TYPE_EQUIVALENCE_ENUM,
  564. TYPE_EQUIVALENCE_OPAQUE
  565. };
  566. static enum type_equivalence typeEquivalence(const UA_DataType *t) {
  567. if(t->membersSize != 1 || !t->members[0].namespaceZero)
  568. return TYPE_EQUIVALENCE_NONE;
  569. if(t->members[0].memberTypeIndex == UA_TYPES_INT32)
  570. return TYPE_EQUIVALENCE_ENUM;
  571. if(t->members[0].memberTypeIndex == UA_TYPES_BYTE && t->members[0].isArray)
  572. return TYPE_EQUIVALENCE_OPAQUE;
  573. return TYPE_EQUIVALENCE_NONE;
  574. }
  575. static UA_StatusCode
  576. CopyValueIntoNode(UA_VariableNode *node, const UA_WriteValue *wvalue) {
  577. UA_assert(wvalue->attributeId == UA_ATTRIBUTEID_VALUE);
  578. UA_assert(node->nodeClass == UA_NODECLASS_VARIABLE ||
  579. node->nodeClass == UA_NODECLASS_VARIABLETYPE);
  580. UA_assert(node->valueSource == UA_VALUESOURCE_VARIANT);
  581. /* Parse the range */
  582. UA_NumericRange range;
  583. UA_NumericRange *rangeptr = NULL;
  584. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  585. if(wvalue->indexRange.length > 0) {
  586. retval = parse_numericrange(&wvalue->indexRange, &range);
  587. if(retval != UA_STATUSCODE_GOOD)
  588. return retval;
  589. rangeptr = &range;
  590. }
  591. /* The nodeid on the wire may be != the nodeid in the node: opaque types,
  592. enums and bytestrings. nodeV contains the correct type definition. */
  593. UA_Variant *oldV = &node->value.variant.value;
  594. const UA_Variant *newV = &wvalue->value.value;
  595. UA_Variant cast_v;
  596. if(oldV->type && !UA_NodeId_equal(&oldV->type->typeId, &newV->type->typeId)) {
  597. cast_v = wvalue->value.value;
  598. newV = &cast_v;
  599. enum type_equivalence te1 = typeEquivalence(oldV->type);
  600. enum type_equivalence te2 = typeEquivalence(newV->type);
  601. if(te1 != TYPE_EQUIVALENCE_NONE && te1 == te2) {
  602. /* An enum was sent as an int32, or an opaque type as a bytestring. This is
  603. detected with the typeIndex indicated the "true" datatype. */
  604. cast_v.type = oldV->type;
  605. } else if(oldV->type == &UA_TYPES[UA_TYPES_BYTE] && !UA_Variant_isScalar(oldV) &&
  606. newV->type == &UA_TYPES[UA_TYPES_BYTESTRING] && UA_Variant_isScalar(newV)) {
  607. /* a string is written to a byte array */
  608. UA_ByteString *str = (UA_ByteString*) newV->data;
  609. cast_v.arrayLength = str->length;
  610. cast_v.data = str->data;
  611. cast_v.type = &UA_TYPES[UA_TYPES_BYTE];
  612. } else {
  613. if(rangeptr)
  614. UA_free(range.dimensions);
  615. return UA_STATUSCODE_BADTYPEMISMATCH;
  616. }
  617. }
  618. if(!rangeptr) {
  619. UA_Variant_deleteMembers(&node->value.variant.value);
  620. UA_Variant_copy(newV, &node->value.variant.value);
  621. } else
  622. retval = UA_Variant_setRangeCopy(&node->value.variant.value, newV->data,
  623. newV->arrayLength, range);
  624. if(node->value.variant.callback.onWrite)
  625. node->value.variant.callback.onWrite(node->value.variant.callback.handle, node->nodeId,
  626. &node->value.variant.value, rangeptr);
  627. if(rangeptr)
  628. UA_free(range.dimensions);
  629. return retval;
  630. }
  631. static UA_StatusCode
  632. CopyAttributeIntoNode(UA_Server *server, UA_Session *session,
  633. UA_Node *node, const UA_WriteValue *wvalue) {
  634. if(!wvalue->value.hasValue)
  635. return UA_STATUSCODE_BADTYPEMISMATCH;
  636. void *value = wvalue->value.value.data;
  637. void *target = NULL;
  638. const UA_DataType *attr_type = NULL;
  639. UA_StatusCode retval = UA_STATUSCODE_GOOD;
  640. switch(wvalue->attributeId) {
  641. case UA_ATTRIBUTEID_NODEID:
  642. case UA_ATTRIBUTEID_NODECLASS:
  643. case UA_ATTRIBUTEID_DATATYPE:
  644. retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
  645. break;
  646. case UA_ATTRIBUTEID_BROWSENAME:
  647. CHECK_DATATYPE(QUALIFIEDNAME);
  648. target = &node->browseName;
  649. attr_type = &UA_TYPES[UA_TYPES_QUALIFIEDNAME];
  650. break;
  651. case UA_ATTRIBUTEID_DISPLAYNAME:
  652. CHECK_DATATYPE(LOCALIZEDTEXT);
  653. target = &node->displayName;
  654. attr_type = &UA_TYPES[UA_TYPES_LOCALIZEDTEXT];
  655. break;
  656. case UA_ATTRIBUTEID_DESCRIPTION:
  657. CHECK_DATATYPE(LOCALIZEDTEXT);
  658. target = &node->description;
  659. attr_type = &UA_TYPES[UA_TYPES_LOCALIZEDTEXT];
  660. break;
  661. case UA_ATTRIBUTEID_WRITEMASK:
  662. CHECK_DATATYPE(UINT32);
  663. node->writeMask = *(UA_UInt32*)value;
  664. break;
  665. case UA_ATTRIBUTEID_USERWRITEMASK:
  666. CHECK_DATATYPE(UINT32);
  667. node->userWriteMask = *(UA_UInt32*)value;
  668. break;
  669. case UA_ATTRIBUTEID_ISABSTRACT:
  670. CHECK_NODECLASS_WRITE(UA_NODECLASS_OBJECTTYPE | UA_NODECLASS_REFERENCETYPE |
  671. UA_NODECLASS_VARIABLETYPE | UA_NODECLASS_DATATYPE);
  672. CHECK_DATATYPE(BOOLEAN);
  673. ((UA_ObjectTypeNode*)node)->isAbstract = *(UA_Boolean*)value;
  674. break;
  675. case UA_ATTRIBUTEID_SYMMETRIC:
  676. CHECK_NODECLASS_WRITE(UA_NODECLASS_REFERENCETYPE);
  677. CHECK_DATATYPE(BOOLEAN);
  678. ((UA_ReferenceTypeNode*)node)->symmetric = *(UA_Boolean*)value;
  679. break;
  680. case UA_ATTRIBUTEID_INVERSENAME:
  681. CHECK_NODECLASS_WRITE(UA_NODECLASS_REFERENCETYPE);
  682. CHECK_DATATYPE(LOCALIZEDTEXT);
  683. target = &((UA_ReferenceTypeNode*)node)->inverseName;
  684. attr_type = &UA_TYPES[UA_TYPES_LOCALIZEDTEXT];
  685. break;
  686. case UA_ATTRIBUTEID_CONTAINSNOLOOPS:
  687. CHECK_NODECLASS_WRITE(UA_NODECLASS_VIEW);
  688. CHECK_DATATYPE(BOOLEAN);
  689. ((UA_ViewNode*)node)->containsNoLoops = *(UA_Boolean*)value;
  690. break;
  691. case UA_ATTRIBUTEID_EVENTNOTIFIER:
  692. CHECK_NODECLASS_WRITE(UA_NODECLASS_VIEW | UA_NODECLASS_OBJECT);
  693. CHECK_DATATYPE(BYTE);
  694. ((UA_ViewNode*)node)->eventNotifier = *(UA_Byte*)value;
  695. break;
  696. case UA_ATTRIBUTEID_VALUE:
  697. CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
  698. if(((const UA_VariableNode*)node)->valueSource == UA_VALUESOURCE_VARIANT)
  699. retval = CopyValueIntoNode((UA_VariableNode*)node, wvalue);
  700. else
  701. retval = Service_Write_single_ValueDataSource(server, session,
  702. (const UA_VariableNode*)node,
  703. wvalue);
  704. break;
  705. case UA_ATTRIBUTEID_ACCESSLEVEL:
  706. CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE);
  707. CHECK_DATATYPE(BYTE);
  708. ((UA_VariableNode*)node)->accessLevel = *(UA_Byte*)value;
  709. break;
  710. case UA_ATTRIBUTEID_USERACCESSLEVEL:
  711. CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE);
  712. CHECK_DATATYPE(BYTE);
  713. ((UA_VariableNode*)node)->userAccessLevel = *(UA_Byte*)value;
  714. break;
  715. case UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL:
  716. CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE);
  717. CHECK_DATATYPE(DOUBLE);
  718. ((UA_VariableNode*)node)->minimumSamplingInterval = *(UA_Double*)value;
  719. break;
  720. case UA_ATTRIBUTEID_HISTORIZING:
  721. CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE);
  722. CHECK_DATATYPE(BOOLEAN);
  723. ((UA_VariableNode*)node)->historizing = *(UA_Boolean*)value;
  724. break;
  725. case UA_ATTRIBUTEID_EXECUTABLE:
  726. CHECK_NODECLASS_WRITE(UA_NODECLASS_METHOD);
  727. CHECK_DATATYPE(BOOLEAN);
  728. ((UA_MethodNode*)node)->executable = *(UA_Boolean*)value;
  729. break;
  730. case UA_ATTRIBUTEID_USEREXECUTABLE:
  731. CHECK_NODECLASS_WRITE(UA_NODECLASS_METHOD);
  732. CHECK_DATATYPE(BOOLEAN);
  733. ((UA_MethodNode*)node)->userExecutable = *(UA_Boolean*)value;
  734. break;
  735. default:
  736. retval = UA_STATUSCODE_BADATTRIBUTEIDINVALID;
  737. break;
  738. }
  739. if(attr_type) {
  740. UA_deleteMembers(target, attr_type);
  741. retval = UA_copy(value, target, attr_type);
  742. }
  743. return retval;
  744. }
  745. UA_StatusCode Service_Write_single(UA_Server *server, UA_Session *session,
  746. const UA_WriteValue *wvalue) {
  747. return UA_Server_editNode(server, session, &wvalue->nodeId,
  748. (UA_EditNodeCallback)CopyAttributeIntoNode, wvalue);
  749. }
  750. void Service_Write(UA_Server *server, UA_Session *session, const UA_WriteRequest *request,
  751. UA_WriteResponse *response) {
  752. UA_LOG_DEBUG_SESSION(server->config.logger, session, "Processing WriteRequest");
  753. if(request->nodesToWriteSize <= 0) {
  754. response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
  755. return;
  756. }
  757. response->results = UA_Array_new(request->nodesToWriteSize,
  758. &UA_TYPES[UA_TYPES_STATUSCODE]);
  759. if(!response->results) {
  760. response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
  761. return;
  762. }
  763. #ifdef UA_ENABLE_EXTERNAL_NAMESPACES
  764. UA_Boolean isExternal[request->nodesToWriteSize];
  765. UA_UInt32 indices[request->nodesToWriteSize];
  766. memset(isExternal, false, sizeof(UA_Boolean)*request->nodesToWriteSize);
  767. for(size_t j = 0; j < server->externalNamespacesSize; j++) {
  768. UA_UInt32 indexSize = 0;
  769. for(size_t i = 0; i < request->nodesToWriteSize; i++) {
  770. if(request->nodesToWrite[i].nodeId.namespaceIndex !=
  771. server->externalNamespaces[j].index)
  772. continue;
  773. isExternal[i] = true;
  774. indices[indexSize] = (UA_UInt32)i;
  775. indexSize++;
  776. }
  777. if(indexSize == 0)
  778. continue;
  779. UA_ExternalNodeStore *ens = &server->externalNamespaces[j].externalNodeStore;
  780. ens->writeNodes(ens->ensHandle, &request->requestHeader, request->nodesToWrite,
  781. indices, indexSize, response->results, response->diagnosticInfos);
  782. }
  783. #endif
  784. response->resultsSize = request->nodesToWriteSize;
  785. for(size_t i = 0;i < request->nodesToWriteSize;i++) {
  786. #ifdef UA_ENABLE_EXTERNAL_NAMESPACES
  787. if(!isExternal[i])
  788. #endif
  789. response->results[i] = Service_Write_single(server, session, &request->nodesToWrite[i]);
  790. }
  791. }
  792. UA_StatusCode UA_Server_write(UA_Server *server, const UA_WriteValue *value) {
  793. UA_RCU_LOCK();
  794. UA_StatusCode retval = Service_Write_single(server, &adminSession, value);
  795. UA_RCU_UNLOCK();
  796. return retval;
  797. }
  798. UA_StatusCode
  799. __UA_Server_write(UA_Server *server, const UA_NodeId *nodeId,
  800. const UA_AttributeId attributeId, const UA_DataType *attr_type,
  801. const void *value) {
  802. UA_WriteValue wvalue;
  803. UA_WriteValue_init(&wvalue);
  804. wvalue.nodeId = *nodeId;
  805. wvalue.attributeId = attributeId;
  806. if(attributeId != UA_ATTRIBUTEID_VALUE)
  807. /* hacked cast. the target WriteValue is used as const anyway */
  808. UA_Variant_setScalar(&wvalue.value.value, (void*)(uintptr_t)value, attr_type);
  809. else {
  810. if(attr_type != &UA_TYPES[UA_TYPES_VARIANT])
  811. return UA_STATUSCODE_BADTYPEMISMATCH;
  812. wvalue.value.value = *(const UA_Variant*)value;
  813. }
  814. wvalue.value.hasValue = true;
  815. UA_StatusCode retval = UA_Server_write(server, &wvalue);
  816. return retval;
  817. }