Parcourir la source

major memory and array-handling redesign, closes #20

Leon Urbas il y a 11 ans
Parent
commit
548b069497

+ 2 - 2
include/Makefile.am

@@ -2,7 +2,7 @@ TOOL_DIR = ../tool
 
 all-local: opcua.h opcua_namespace_0.h
 
-opcua.h: $(TOOL_DIR)/opcua.h
+opcua.h: $(TOOL_DIR)/opcua.hgen
 	cp $< $@
-opcua_namespace_0.h: $(TOOL_DIR)/opcua_namespace_0.h
+opcua_namespace_0.h: $(TOOL_DIR)/opcua_namespace_0.hgen
 	cp $< $@

+ 3 - 1
include/opcua_basictypes.h

@@ -56,7 +56,7 @@ UA_Int32 _UA_alloc(void ** dst, int size,char*,int);
 UA_Int32 UA_Array_calcSize(UA_Int32 noElements, UA_Int32 type, void const ** ptr);
 UA_Int32 UA_Array_encode(void const **src, UA_Int32 noElements, UA_Int32 type, UA_Int32* pos, UA_Byte * dst);
 UA_Int32 UA_Array_decode(UA_Byte const * src,UA_Int32 noElements, UA_Int32 type, UA_Int32* pos, void const **dst);
-UA_Int32 UA_Array_delete(void **p,UA_Int32 noElements);
+UA_Int32 UA_Array_delete(void **p,UA_Int32 noElements, UA_Int32 type);
 UA_Int32 UA_Array_init(void **p,UA_Int32 noElements, UA_Int32 type);
 UA_Int32 UA_Array_new(void **p,UA_Int32 noElements, UA_Int32 type);
 
@@ -163,6 +163,8 @@ typedef struct T_UA_VTable {
 	UA_Int32 (*calcSize)(void const * ptr);
 	UA_Int32 (*decode)(UA_Byte const * src, UA_Int32* pos, void* dst);
 	UA_Int32 (*encode)(void const * src, UA_Int32* pos, UA_Byte* dst);
+	UA_Int32 (*new)(void ** p);
+	UA_Int32 (*delete)(void * p);
 } UA_VTable;
 
 /* VariantBinaryEncoding - Part: 6, Chapter: 5.2.2.16, Page: 22 */

+ 1 - 1
src/UA_stackInternalTypes.c

@@ -322,7 +322,7 @@ UA_Int32 UA_SecureConversationMessageFooter_delete(UA_SecureConversationMessageF
     }
 UA_Int32 UA_SecureConversationMessageFooter_deleteMembers(UA_SecureConversationMessageFooter* p) {
 	UA_Int32 retval = UA_SUCCESS;
-	retval |= UA_Array_delete((void**)p->padding,p->paddingSize);
+	retval |= UA_Array_delete((void**)p->padding,p->paddingSize,UA_BYTE);
 	return retval;
 }
 

+ 27 - 14
src/opcua_basictypes.c

@@ -49,7 +49,7 @@ UA_Int32 UA_Array_encode(void const **src, UA_Int32 noElements, UA_Int32 type, U
 	return retVal;
 }
 
-// FIXME: While calcSize and encode handle size themselfes, decode relies on others to do things correctly
+// FIXME: While calcSize and encode handle size themselves, decode relies on others to do things correctly
 UA_Int32 UA_Array_decode(UA_Byte const * src, UA_Int32 noElements, UA_Int32 type, UA_Int32* pos, void const **dst) {
 	UA_Int32 retval = UA_SUCCESS;
 	UA_Int32 i = 0;
@@ -61,29 +61,42 @@ UA_Int32 UA_Array_decode(UA_Byte const * src, UA_Int32 noElements, UA_Int32 type
 	return retval;
 }
 
-UA_Int32 UA_Array_deleteMembers(void ** p,UA_Int32 noElements) {
+UA_Int32 UA_Array_deleteMembers(void ** p,UA_Int32 noElements, UA_Int32 type) {
 	UA_Int32 retval = UA_SUCCESS;
 	UA_Int32 i = 0;
 
 	for(i=0; i<noElements; i++) {
-		retval |= UA_free((void*)p[i]);
+		retval |= UA_[type].delete((void*)p[i]);
 	}
 	return retval;
 }
 
-UA_Int32 UA_Array_delete(void **p,UA_Int32 noElements) {
+UA_Int32 UA_Array_delete(void **p,UA_Int32 noElements, UA_Int32 type) {
 	UA_Int32 retval = UA_SUCCESS;
-	retval |= UA_Array_deleteMembers(p,noElements);
+	retval |= UA_Array_deleteMembers(p,noElements,type);
 	retval |= UA_free(p);
 	return retval;
 }
-// FIXME: Implement
-UA_Int32 UA_Array_init(void **p,UA_Int32 noElements, UA_Int32 type) {
-	return UA_ERR_NOT_IMPLEMENTED;
-}
-// FIXME: Implement
+
+// FIXME: Implement? We would need to add init to the VTable...
+// UA_Int32 UA_Array_init(void **p,UA_Int32 noElements, UA_Int32 type) {
+
+/** p is the address of a pointer to an array of pointers (type**).
+ *  [p] -> [p1, p2, p3, p4]
+ *           +-> struct 1, ...
+ */
 UA_Int32 UA_Array_new(void **p,UA_Int32 noElements, UA_Int32 type) {
-	return UA_ERR_NOT_IMPLEMENTED;
+	UA_Int32 retval = UA_SUCCESS;
+	UA_Int32 i;
+	// Get memory for the pointers
+	retval |= UA_alloc(p, sizeof(void*)*noElements);
+	// Then allocate all the elements. We could allocate all the members in one chunk and
+	// calculate the addresses to prevent memory segmentation. This would however not call
+	// init for each member
+	for(i=0; i<noElements; i++) {
+		retval |= UA_[type].new(p[i]);
+	}
+	return retval;
 }
 
 UA_Int32 _UA_free(void * ptr,char* f,int l){
@@ -309,7 +322,7 @@ UA_Int32 UA_Double_decode(UA_Byte const * src, UA_Int32* pos, UA_Double * dst) {
 UA_Int32 UA_Double_encode(UA_Double const * src, UA_Int32 *pos, UA_Byte* dst) {
 	// TODO: not yet implemented
 	memcpy(&(dst[*pos]), src, sizeof(UA_Double));
-	*pos *= sizeof(UA_Double);
+	*pos += sizeof(UA_Double);
 	return UA_SUCCESS;
 }
 UA_TYPE_METHOD_DELETE_FREE(UA_Double)
@@ -355,12 +368,13 @@ UA_TYPE_METHOD_DELETE_STRUCT(UA_String)
 UA_Int32 UA_String_deleteMembers(UA_String* p) { return UA_free(p->data); }
 UA_Int32 UA_String_copy(UA_String const * src, UA_String* dst) {
 	UA_Int32 retval = UA_SUCCESS;
-	dst->length = src->length;
 	dst->data = UA_NULL;
+	dst->length = -1;
 	if (src->length > 0) {
 		retval |= UA_alloc((void**)&(dst->data), src->length);
 		if (retval == UA_SUCCESS) {
 			retval |= UA_memcpy((void*)dst->data, src->data, src->length);
+			dst->length = src->length;
 		}
 	}
 	return retval;
@@ -380,7 +394,6 @@ UA_Int32 UA_String_copycstring(char const * src, UA_String* dst) {
 
 UA_String UA_String_null = { -1, UA_NULL };
 UA_Int32 UA_String_init(UA_String* p){
-	//FIXME: is UA_String_null now depricated?
 	if(p==UA_NULL)return UA_ERROR;
 	p->length = -1;
 	p->data = UA_NULL;

+ 35 - 58
src/opcua_secureLayer.c

@@ -138,19 +138,15 @@ UA_Int32 SL_openSecureChannel(UA_connection *connection,
 	UA_Int32 pos;
 
 	UA_OpenSecureChannelResponse_new(&r);
-	UA_ResponseHeader_new(&(r->responseHeader));
-	UA_ExtensionObject_new(&(r->responseHeader->additionalHeader));
-	UA_DiagnosticInfo_new(&(r->responseHeader->serviceDiagnostics));
-	UA_ChannelSecurityToken_new(&(r->securityToken));
 
 	if (requestHeader->returnDiagnostics != 0) {
 		printf("SL_openSecureChannel - diagnostics demanded by the client\n");
 		printf(
 				"SL_openSecureChannel - retrieving diagnostics not implemented!\n");
 		//TODO fill with demanded information part 4, 7.8 - Table 123
-		r->responseHeader->serviceDiagnostics->encodingMask = 0;
+		r->responseHeader.serviceDiagnostics.encodingMask = 0;
 	} else {
-		r->responseHeader->serviceDiagnostics->encodingMask = 0;
+		r->responseHeader.serviceDiagnostics.encodingMask = 0;
 	}
 	/*--------------type ----------------------*/
 
@@ -161,22 +157,22 @@ UA_Int32 SL_openSecureChannel(UA_connection *connection,
 	responseType.namespace = 0;
 
 	/*--------------responseHeader-------------*/
-	r->responseHeader->timestamp = UA_DateTime_now();
-	r->responseHeader->requestHandle = requestHeader->requestHandle;
-	r->responseHeader->serviceResult = serviceResult;
+	r->responseHeader.timestamp = UA_DateTime_now();
+	r->responseHeader.requestHandle = requestHeader->requestHandle;
+	r->responseHeader.serviceResult = serviceResult;
 
 	//text of fields defined in the serviceDiagnostics
-	r->responseHeader->stringTableSize = 0;
-	r->responseHeader->stringTable = UA_NULL;
+	r->responseHeader.stringTableSize = 0;
+	r->responseHeader.stringTable = UA_NULL;
 
 	r->serverProtocolVersion =
 			connection->transportLayer.localConf.protocolVersion;
 
-	r->securityToken->channelId =
+	r->securityToken.channelId =
 			connection->secureLayer.securityToken.secureChannelId;
-	r->securityToken->tokenId = connection->secureLayer.securityToken.tokenId;
-	r->securityToken->createdAt = UA_DateTime_now();
-	r->securityToken->revisedLifetime =
+	r->securityToken.tokenId = connection->secureLayer.securityToken.tokenId;
+	r->securityToken.createdAt = UA_DateTime_now();
+	r->securityToken.revisedLifetime =
 			connection->secureLayer.securityToken.revisedLifetime;
 
 	UA_ByteString_copy(&(connection->secureLayer.localNonce), &(r->serverNonce));
@@ -245,9 +241,8 @@ UA_Int32 SL_processMessage(UA_connection *connection, UA_ByteString message) {
 					serviceRequestType.identifier.numeric);
 			retval = UA_ERROR;
 		} else {
-			// decode message
 			void * obj;
-			UA_alloc(&obj, UA_[namespace_index].calcSize(UA_NULL));
+			UA_[namespace_index].new(&obj);
 			UA_[namespace_index].decode(message.data, &pos, obj);
 
 			// FXIME: we need a more clever response/request architecture
@@ -261,37 +256,27 @@ UA_Int32 SL_processMessage(UA_connection *connection, UA_ByteString message) {
 
 				UA_String_printx("endpointUrl=", &(p->endpointUrl));
 				UA_GetEndpointsResponse_new(&r);
-				UA_ResponseHeader_new(&(r->responseHeader));
-				r->responseHeader->requestHandle =
-						p->requestHeader->requestHandle;
-				r->responseHeader->serviceResult = SC_Good;
-				r->responseHeader->stringTableSize = 0;
-				r->responseHeader->timestamp = UA_DateTime_now();
-				UA_DiagnosticInfo_new(&(r->responseHeader->serviceDiagnostics));
-				UA_ExtensionObject_new(&(r->responseHeader->additionalHeader));
-
-				// TODO: Arrays need to be redesigned, this is crap
+				r->responseHeader.requestHandle =
+						p->requestHeader.requestHandle;
+				r->responseHeader.serviceResult = SC_Good;
+				r->responseHeader.stringTableSize = 0;
+				r->responseHeader.timestamp = UA_DateTime_now();
+
 				r->endpointsSize = 1;
-				UA_alloc((void**) &(r->endpoints), sizeof(void*));
-				UA_EndpointDescription *epd;
-				UA_EndpointDescription_new(&epd);
-				*(r->endpoints) = epd;
+				UA_Array_new((void**) &(r->endpoints),r->endpointsSize,UA_ENDPOINTDESCRIPTION);
 
-				// FIXME: this memory gets lost
 				UA_String_copycstring("tcp.opc://localhost:16664/",
 						&(r->endpoints[0]->endpointUrl));
-				// FIXME: this memory gets lost
-				UA_ApplicationDescription_new(&(r->endpoints[0]->server));
 				// FIXME: This should be a feature of the application
 				UA_String_copycstring("http://open62541.info/applications/4711",
-						&(r->endpoints[0]->server->applicationUri));
+						&(r->endpoints[0]->server.applicationUri));
 				UA_String_copycstring("http://open62541.info/product/release",
-						&(r->endpoints[0]->server->productUri));
+						&(r->endpoints[0]->server.productUri));
 				// FIXME: This should be a feature of the application
 				UA_LocalizedText_copycstring("The open62541 application",
-						&(r->endpoints[0]->server->applicationName));
+						&(r->endpoints[0]->server.applicationName));
 				// FIXME: This should be a feature of the application and an enum
-				r->endpoints[0]->server->applicationType = 0; // Server
+				r->endpoints[0]->server.applicationType = 0; // Server
 				// all the other strings are empty by initialization
 
 				// Now let's build the response
@@ -312,8 +297,6 @@ UA_Int32 SL_processMessage(UA_connection *connection, UA_ByteString message) {
 
 				UA_ByteString_deleteMembers(&response);
 				UA_GetEndpointsResponse_delete(r);
-				UA_GetEndpointsRequest_delete(p);
-
 				retval = UA_SUCCESS;
 			}
 				break;
@@ -326,16 +309,15 @@ UA_Int32 SL_processMessage(UA_connection *connection, UA_ByteString message) {
 				UA_CreateSessionResponse* r;
 
 				UA_CreateSessionResponse_new(&r);
-				// Header
-				UA_ResponseHeader_new(&(r->responseHeader));
-				r->responseHeader->requestHandle =
-						p->requestHeader->requestHandle;
-				r->responseHeader->serviceResult = SC_Good;
-				r->responseHeader->stringTableSize = 0;
-				r->responseHeader->timestamp = UA_DateTime_now();
-				UA_DiagnosticInfo_new(&(r->responseHeader->serviceDiagnostics));
-				UA_ExtensionObject_new(&(r->responseHeader->additionalHeader));
-
+				r->responseHeader.requestHandle =
+						p->requestHeader.requestHandle;
+				r->responseHeader.serviceResult = SC_Good;
+				r->responseHeader.stringTableSize = 0;
+				r->responseHeader.timestamp = UA_DateTime_now();
+
+				// FIXME: Valgrind tells invalid write of size 4 in encode
+				UA_ByteString_printx("SL_processMessage serverNonce", &(r->serverNonce));
+				UA_ByteString_printx("SL_processMessage serverCertificate", &(r->serverCertificate));
 				// FIXME: create session
 
 				// Now let's build the response
@@ -356,7 +338,6 @@ UA_Int32 SL_processMessage(UA_connection *connection, UA_ByteString message) {
 
 				UA_ByteString_deleteMembers(&response);
 				UA_CreateSessionResponse_delete(r);
-				UA_CreateSessionRequest_delete(p);
 
 				retval = UA_SUCCESS;
 			}
@@ -365,8 +346,6 @@ UA_Int32 SL_processMessage(UA_connection *connection, UA_ByteString message) {
 			case UA_CLOSESECURECHANNELREQUEST_NS0: {
 				puts("UA_CLOSESECURECHANNELREQUEST");
 
-				UA_CloseSecureChannelRequest* p =
-						(UA_CloseSecureChannelRequest*) obj;
 				// 62451 Part 6 Chapter 7.1.4 - The server does not send a CloseSecureChannel response
 				connection->transportLayer.connectionState = connectionState_CLOSE;
 				retval = UA_SUCCESS;
@@ -377,8 +356,6 @@ UA_Int32 SL_processMessage(UA_connection *connection, UA_ByteString message) {
 
 				UA_OpenSecureChannelRequest* p =
 						(UA_OpenSecureChannelRequest*) obj;
-				UA_NodeId responseType;
-				UA_OpenSecureChannelResponse* r;
 
 				if (p->clientProtocolVersion
 						!= connection->transportLayer.remoteConf.protocolVersion) {
@@ -432,12 +409,12 @@ UA_Int32 SL_processMessage(UA_connection *connection, UA_ByteString message) {
 					break;
 				}
 
-				retval = SL_openSecureChannel(connection, p->requestHeader,
+				retval |= SL_openSecureChannel(connection, &(p->requestHeader),
 						SC_Good);
-				UA_OpenSecureChannelRequest_delete(p);
 			}
 				break;
-			}
+			} // end switch over known messages
+			retval |= UA_[namespace_index].delete(obj);
 		}
 	} else {
 		printf(

+ 28 - 34
src/opcua_transportLayer.c

@@ -116,9 +116,9 @@ UA_Int32 TL_process(UA_connection *connection,UA_Int32 packetType, UA_Int32 *pos
 {
 	UA_Int32 tmpPos = 0;
 	UA_ByteString tmpMessage;
-	UA_OPCUATcpHelloMessage *helloMessage;
-	UA_OPCUATcpAcknowledgeMessage *ackMessage;
-	UA_OPCUATcpMessageHeader *ackHeader;
+	UA_OPCUATcpHelloMessage helloMessage;
+	UA_OPCUATcpAcknowledgeMessage ackMessage;
+	UA_OPCUATcpMessageHeader ackHeader;
 
 	printf("TL_process - entered \n");
 
@@ -130,58 +130,52 @@ UA_Int32 TL_process(UA_connection *connection,UA_Int32 packetType, UA_Int32 *pos
 			printf("TL_process - extracting header information \n");
 			printf("TL_process - pos = %d \n",*pos);
 
-			UA_alloc((void**)(&helloMessage),UA_OPCUATcpHelloMessage_calcSize(UA_NULL));
-
-			UA_OPCUATcpHelloMessage_decode(connection->readData.data,pos,helloMessage);
+			UA_OPCUATcpHelloMessage_decode(connection->readData.data,pos,&helloMessage);
 
 			/* extract information from received header */
 			//UA_UInt32_decode(connection->readData.data,pos,(&(connection->transportLayer.remoteConf.protocolVersion)));
-			connection->transportLayer.remoteConf.protocolVersion = helloMessage->protocolVersion;
+			connection->transportLayer.remoteConf.protocolVersion = helloMessage.protocolVersion;
 			printf("TL_process - protocolVersion = %d \n",connection->transportLayer.remoteConf.protocolVersion);
 
-			connection->transportLayer.remoteConf.recvBufferSize = helloMessage->receiveBufferSize;
+			connection->transportLayer.remoteConf.recvBufferSize = helloMessage.receiveBufferSize;
 			printf("TL_process - recvBufferSize = %d \n",connection->transportLayer.remoteConf.recvBufferSize);
 
-			connection->transportLayer.remoteConf.sendBufferSize = helloMessage->sendBufferSize;
+			connection->transportLayer.remoteConf.sendBufferSize = helloMessage.sendBufferSize;
 			printf("TL_process - sendBufferSize = %d \n",connection->transportLayer.remoteConf.sendBufferSize);
 
-			connection->transportLayer.remoteConf.maxMessageSize = helloMessage->maxMessageSize;
+			connection->transportLayer.remoteConf.maxMessageSize = helloMessage.maxMessageSize;
 			printf("TL_process - maxMessageSize = %d \n",connection->transportLayer.remoteConf.maxMessageSize);
 
-			connection->transportLayer.remoteConf.maxChunkCount = helloMessage->maxChunkCount;
+			connection->transportLayer.remoteConf.maxChunkCount = helloMessage.maxChunkCount;
 			printf("TL_process - maxChunkCount = %d \n",connection->transportLayer.remoteConf.maxChunkCount);
 
-			UA_String_copy(&(helloMessage->endpointUrl), &(connection->transportLayer.endpointURL));
-			UA_OPCUATcpHelloMessage_delete(helloMessage);
-
-			/* send back acknowledge */
-			//memory for message
-			UA_alloc((void**)&(ackMessage),UA_OPCUATcpAcknowledgeMessage_calcSize(UA_NULL));
+			// FIXME: This memory needs to be cleaned up in the server!
+			UA_String_copy(&(helloMessage.endpointUrl), &(connection->transportLayer.endpointURL));
 
-			ackMessage->protocolVersion = connection->transportLayer.localConf.protocolVersion;
-			ackMessage->receiveBufferSize = connection->transportLayer.localConf.recvBufferSize;
-			ackMessage->maxMessageSize = connection->transportLayer.localConf.maxMessageSize;
-			ackMessage->maxChunkCount = connection->transportLayer.localConf.maxChunkCount;
+			// Clean up
+			UA_OPCUATcpHelloMessage_deleteMembers(&helloMessage);
 
-			//memory for header
-			UA_alloc((void**)&(ackHeader),UA_OPCUATcpMessageHeader_calcSize(UA_NULL));
+			/* send back acknowledge */
+			ackMessage.protocolVersion = connection->transportLayer.localConf.protocolVersion;
+			ackMessage.receiveBufferSize = connection->transportLayer.localConf.recvBufferSize;
+			ackMessage.sendBufferSize = connection->transportLayer.localConf.sendBufferSize;
+			ackMessage.maxMessageSize = connection->transportLayer.localConf.maxMessageSize;
+			ackMessage.maxChunkCount = connection->transportLayer.localConf.maxChunkCount;
 
-			ackHeader->messageType = UA_MESSAGETYPE_ACK;
-			ackHeader->isFinal = 'F';
-			ackHeader->messageSize = UA_OPCUATcpAcknowledgeMessage_calcSize(ackMessage) +
-					UA_OPCUATcpMessageHeader_calcSize(ackHeader);
+			ackHeader.messageType = UA_MESSAGETYPE_ACK;
+			ackHeader.isFinal = 'F';
+			ackHeader.messageSize = UA_OPCUATcpAcknowledgeMessage_calcSize(&ackMessage)
+			+ UA_OPCUATcpMessageHeader_calcSize(&ackHeader);
 
 			//allocate memory in stream
-			UA_alloc((void**)&(tmpMessage.data),ackHeader->messageSize);
-			tmpMessage.length = ackHeader->messageSize;
+			UA_alloc((void**)&(tmpMessage.data),ackHeader.messageSize);
+			tmpMessage.length = ackHeader.messageSize;
 
 			//encode header and message
-			UA_OPCUATcpMessageHeader_encode(ackHeader,&tmpPos,tmpMessage.data);
-			UA_OPCUATcpAcknowledgeMessage_encode(ackMessage,&tmpPos,tmpMessage.data);
+			UA_OPCUATcpMessageHeader_encode(&ackHeader,&tmpPos,tmpMessage.data);
+			UA_OPCUATcpAcknowledgeMessage_encode(&ackMessage,&tmpPos,tmpMessage.data);
 
-			printf("TL_process - Size messageToSend = %d \n",ackHeader->messageSize);
-			UA_OPCUATcpMessageHeader_delete(ackHeader);
-			UA_OPCUATcpAcknowledgeMessage_delete(ackMessage);
+			printf("TL_process - Size messageToSend = %d, pos=%d\n",ackHeader.messageSize, tmpPos);
 			/* ------------------------ Body ------------------------ */
 			// protocol version
 			printf("TL_process - localConf.protocolVersion = %d \n",connection->transportLayer.localConf.protocolVersion);

+ 2 - 2
tests/Makefile.am

@@ -5,6 +5,6 @@ INCLUDE = @CHECK_CFLAGS@ -I$(top_builddir)/src -I$(top_builddir)/include
 LDADD = $(top_builddir)/lib/libopen62541.a @CHECK_LIBS@
 
 check_PROGRAMS = $(TESTS)
-AM_LDFLAGS = $(LDADD)
+AM_LDFLAGS = $(LDADD)  --coverage
 
-AM_CFLAGS = $(GLOBAL_AM_CFLAGS) $(INCLUDE)
+AM_CFLAGS = $(GLOBAL_AM_CFLAGS) $(INCLUDE) --coverage

+ 9 - 9
tool/Makefile.am

@@ -3,23 +3,23 @@ INCLUDE_DIR = $(top_builddir)/include
 AUTO_NAME = opcua
 NS0_NAME = opcua_namespace_0
 
-all-local: $(AUTO_NAME).c $(AUTO_NAME).h $(NS0_NAME).c $(NS0_NAME).h
+all-local: $(AUTO_NAME).cgen $(AUTO_NAME).hgen $(NS0_NAME).cgen $(NS0_NAME).hgen
 
-$(AUTO_NAME).c $(AUTO_NAME).h: Opc.Ua.Types.bsd generate_builtin.py
+$(AUTO_NAME).cgen $(AUTO_NAME).hgen: Opc.Ua.Types.bsd generate_builtin.py
 	python generate_builtin.py Opc.Ua.Types.bsd $(AUTO_NAME)
-	cp $(AUTO_NAME).c $(SRC_DIR)
-	cp $(AUTO_NAME).h $(INCLUDE_DIR)
+	cp $(AUTO_NAME).cgen $(SRC_DIR)/$(AUTO_NAME).c
+	cp $(AUTO_NAME).hgen $(INCLUDE_DIR)/$(AUTO_NAME).h
 	
-$(NS0_NAME).c $(NS0_NAME).h: NodeIds.csv generate_namespace.py 
+$(NS0_NAME).cgen $(NS0_NAME).hgen: NodeIds.csv generate_namespace.py 
 	python generate_namespace.py NodeIds.csv $(NS0_NAME)
-	cp $(NS0_NAME).c $(SRC_DIR)
-	cp $(NS0_NAME).h $(INCLUDE_DIR)
+	cp $(NS0_NAME).cgen $(SRC_DIR)/$(NS0_NAME).c
+	cp $(NS0_NAME).hgen $(INCLUDE_DIR)/$(NS0_NAME).h
 
 PHONY: clean-autogenerated
 clean-autogenerated:
-	rm -rf $(AUTO_NAME).c $(AUTO_NAME).h
+	rm -rf $(AUTO_NAME).cgen $(AUTO_NAME).hgen
 	rm -rf $(SRC_DIR)/$(AUTO_NAME).c $(INCLUDE_DIR)/$(AUTO_NAME).h
-	rm -rf $(NS0_NAME).c $(NS0_NAME).h
+	rm -rf $(NS0_NAME).cgen $(NS0_NAME).hgen
 	rm -rf $(SRC_DIR)/$(NS0_NAME).c $(INCLUDE_DIR)/$(NS0_NAME).h
 
 clean-local: clean-autogenerated

+ 24 - 11
tool/generate_builtin.py

@@ -1,5 +1,6 @@
 from __future__ import print_function
 import sys
+import time
 from collections import OrderedDict
 import re
 from lxml import etree
@@ -31,7 +32,9 @@ elementary_size["DateTime"] = 8;
 elementary_size["StatusCode"] = 4;
 
 # indefinite_types = ["NodeId", "ExpandedNodeId", "QualifiedName", "LocalizedText", "ExtensionObject", "DataValue", "Variant", "DiagnosticInfo"]
-indefinite_types = ["ExpandedNodeId", "QualifiedName", "ExtensionObject", "DataValue", "Variant", "DiagnosticInfo"]
+# indefinite_types = ["ExpandedNodeId", "QualifiedName", "ExtensionObject", "DataValue", "Variant", "DiagnosticInfo"]
+# LU - pointers only for arrays (ByteString, etc.)
+indefinite_types = []
 enum_types = []
 structured_types = []
                    
@@ -114,14 +117,14 @@ def createStructured(element):
             #if childname in printed_types:
             #    childname = childname + "_Value" # attributes may not have the name of a type
             typename = stripTypename(child.get("TypeName"))
-            if typename in structured_types:
-                valuemap[childname] = typename + "*"
-                if child.get("LengthField"):
-                    valuemap[childname] = typename + "**"
-            elif typename in indefinite_types:
+            if typename in indefinite_types:
                 valuemap[childname] = typename + "*"
                 if child.get("LengthField"):
                     valuemap[childname] = typename + "**"
+#            elif typename in structured_types:
+#                valuemap[childname] = typename + "*"
+#                if child.get("LengthField"):
+#                    valuemap[childname] = typename + "**"
             elif child.get("LengthField"):
                 valuemap[childname] = typename + "**"
             else:
@@ -223,7 +226,7 @@ def createStructured(element):
     for n,t in valuemap.iteritems():
         if t not in elementary_size:
             if t.find("**") != -1:
-		print("\tretval |= UA_Array_delete((void**)p->"+n+",p->"+n+"Size);", end='\n', file=fc) #not tested
+		print("\tretval |= UA_Array_delete((void**)p->"+n+",p->"+n+"Size,UA_"+t[0:t.find("*")].upper()+");", end='\n', file=fc) #not tested
             elif t.find("*") != -1:
 		print('\tretval |= UA_' + t[0:t.find("*")] + "_delete(p->"+n+");", end='\n', file=fc)
             else:
@@ -273,9 +276,14 @@ ns = {"opc": "http://opcfoundation.org/BinarySchema/"}
 tree = etree.parse(sys.argv[1])
 types = tree.xpath("/opc:TypeDictionary/*[not(self::opc:Import)]", namespaces=ns)
 
-fh = open(sys.argv[2] + ".h",'w');
-fc = open(sys.argv[2] + ".c",'w');
-print('#include "' + sys.argv[2] + '.h"', end='\n', file=fc);
+fh = open(sys.argv[2] + ".hgen",'w');
+fc = open(sys.argv[2] + ".cgen",'w');
+print('''/**********************************************************
+ * Generated from '''+sys.argv[1]+''' with script '''+sys.argv[0]+'''
+ * on node XXX by user XXX at '''+ time.strftime("%Y-%m-%d %I:%M:%S")+'''
+ * do not modify
+ **********************************************************/
+#include "''' + sys.argv[2] + '.h"', end='\n', file=fc);
 
 # types for which we create a vector type
 arraytypes = set()
@@ -286,7 +294,12 @@ for field in fields:
 
 deferred_types = OrderedDict()
 
-print('#ifndef OPCUA_H_', end='\n', file=fh)
+print('''/**********************************************************
+ * Generated from '''+sys.argv[1]+''' with script '''+sys.argv[0]+'''
+ * on node XXX by user XXX at '''+ time.strftime("%Y-%m-%d %I:%M:%S")+'''
+ * do not modify
+ **********************************************************/
+#ifndef OPCUA_H_''', end='\n', file=fh)
 print('#define OPCUA_H_', end='\n', file=fh)
 print('#include "opcua_basictypes.h"', end='\n', file=fh)
 print('#include "opcua_namespace_0.h"', end='\n', file=fh);

+ 8 - 4
tool/generate_namespace.py

@@ -45,8 +45,8 @@ def skipType(name):
 f = open(sys.argv[1])
 rows1, rows2, rows3 = tee(csv.reader(f), 3)
 
-fh = open(sys.argv[2] + ".h",'w');
-fc = open(sys.argv[2] + ".c",'w');
+fh = open(sys.argv[2] + ".hgen",'w');
+fc = open(sys.argv[2] + ".cgen",'w');
 
 print('''/**********************************************************
  * Generated from '''+sys.argv[1]+''' with script '''+sys.argv[0]+'''
@@ -63,7 +63,11 @@ extern UA_VTable UA_[];
 
 enum UA_VTableIndex_enum {''', end='\n', file=fh)
 
-print('''/* Mapping and vTable of Namespace Zero */
+print('''/**********************************************************
+ * Generated from '''+sys.argv[1]+''' with script '''+sys.argv[0]+'''
+ * on node XXX by user XXX at '''+ time.strftime("%Y-%m-%d %I:%M:%S")+'''
+ * do not modify
+ **********************************************************/
 #include "opcua.h"
 UA_Int32 UA_toIndex(UA_Int32 id) {
     UA_Int32 retval = -1;
@@ -109,7 +113,7 @@ for row in rows2:
 
     print('#define '+name.upper()+'_NS0 '+row[1], file=fh)
 
-    print("\t{" + row[1] + ", (UA_Int32(*)(void const*)) " + name + "_calcSize, (UA_Int32(*)(UA_Byte const*,UA_Int32*,void*)) " + name + "_decode, (UA_Int32(*)(void const*,UA_Int32*,UA_Byte*))" + name + "_encode},",end='\n',file=fc) 
+    print("\t{" + row[1] + ", (UA_Int32(*)(void const*)) " + name + "_calcSize, (UA_Int32(*)(UA_Byte const*,UA_Int32*,void*)) " + name + "_decode, (UA_Int32(*)(void const*,UA_Int32*,UA_Byte*))" + name + "_encode, (UA_Int32(*)(void **))" + name + "_new, (UA_Int32(*)(void *))" + name + "_delete},",end='\n',file=fc) 
 
 print("\t{0,UA_NULL,UA_NULL,UA_NULL}\n};",file=fc)
 print('#endif /* OPCUA_NAMESPACE_0_H_ */', end='\n', file=fh)