Ver código fonte

Added configuration options for OperationLimits

Henrik Norrman 7 anos atrás
pai
commit
6b7c458dc3

+ 15 - 0
include/ua_server_config.h

@@ -74,6 +74,20 @@ struct UA_ServerConfig {
     UA_UInt16 maxSessions;
     UA_Double maxSessionTimeout; /* in ms */
 
+    /* Operation limits */
+    UA_UInt32 maxNodesPerRead;
+    UA_UInt32 maxNodesPerWrite;
+    UA_UInt32 maxNodesPerMethodCall;
+    UA_UInt32 maxNodesPerBrowse;
+    UA_UInt32 maxNodesPerRegisterNodes;
+    UA_UInt32 maxNodesPerTranslateBrowsePathsToNodeIds;
+    UA_UInt32 maxNodesPerNodeManagement;
+    UA_UInt32 maxMonitoredItemsPerCall;
+
+    /* Limits for Requests */
+    UA_UInt32 maxReferencesPerNode;
+    UA_UInt16 maxBrowseContinuationPoints;
+
     /* Limits for Subscriptions */
     UA_DurationRange publishingIntervalLimits;
     UA_UInt32Range lifeTimeCountLimits;
@@ -84,6 +98,7 @@ struct UA_ServerConfig {
     /* Limits for MonitoredItems */
     UA_DurationRange samplingIntervalLimits;
     UA_UInt32Range queueSizeLimits; /* Negotiated with the client */
+    UA_Double minSupportedSampleRate;
 
     /* Discovery */
 #ifdef UA_ENABLE_DISCOVERY

+ 32 - 0
src/server/ua_server_ns0.c

@@ -687,6 +687,38 @@ UA_Server_initNS0(UA_Server *server) {
     retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERREDUNDANCY_REDUNDANCYSUPPORT,
                                &redundancySupport, &UA_TYPES[UA_TYPES_REDUNDANCYSUPPORT]);
 
+    /* ServerCapabilities - OperationLimits - MaxNodesPerRead */
+    retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERREAD,
+                               &server->config.maxNodesPerRead, &UA_TYPES[UA_TYPES_UINT32]);
+
+    /* ServerCapabilities - OperationLimits - maxNodesPerWrite */
+    retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERWRITE,
+                               &server->config.maxNodesPerWrite, &UA_TYPES[UA_TYPES_UINT32]);
+
+    /* ServerCapabilities - OperationLimits - MaxNodesPerMethodCall */
+    retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERMETHODCALL,
+                               &server->config.maxNodesPerMethodCall, &UA_TYPES[UA_TYPES_UINT32]);
+
+    /* ServerCapabilities - OperationLimits - MaxNodesPerBrowse */
+    retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERBROWSE,
+                               &server->config.maxNodesPerBrowse, &UA_TYPES[UA_TYPES_UINT32]);
+
+    /* ServerCapabilities - OperationLimits - MaxNodesPerRegisterNodes */
+    retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERREGISTERNODES,
+                               &server->config.maxNodesPerRegisterNodes, &UA_TYPES[UA_TYPES_UINT32]);
+
+    /* ServerCapabilities - OperationLimits - MaxNodesPerTranslateBrowsePathsToNodeIds */
+    retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERTRANSLATEBROWSEPATHSTONODEIDS,
+                               &server->config.maxNodesPerTranslateBrowsePathsToNodeIds, &UA_TYPES[UA_TYPES_UINT32]);
+
+    /* ServerCapabilities - OperationLimits - MaxNodesPerNodeManagement */
+    retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERNODEMANAGEMENT,
+                               &server->config.maxNodesPerNodeManagement, &UA_TYPES[UA_TYPES_UINT32]);
+
+    /* ServerCapabilities - OperationLimits - MaxMonitoredItemsPerCall */
+    retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXMONITOREDITEMSPERCALL,
+                               &server->config.maxMonitoredItemsPerCall, &UA_TYPES[UA_TYPES_UINT32]);
+
 #if defined(UA_ENABLE_METHODCALLS) && defined(UA_ENABLE_SUBSCRIPTIONS)
     retVal |= UA_Server_setMethodNode_callback(server,
                         UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_GETMONITOREDITEMS), readMonitoredItems);

+ 12 - 0
src/server/ua_services_attribute.c

@@ -359,6 +359,12 @@ void Service_Read(UA_Server *server, UA_Session *session,
         return;
     }
 
+    if(server->config.maxNodesPerRead != 0 &&
+       request->nodesToReadSize > server->config.maxNodesPerRead) {
+        response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS;
+        return;
+    }
+
     response->responseHeader.serviceResult = 
         UA_Server_processServiceOperations(server, session,
                   (UA_ServiceOperation)Operation_Read,
@@ -1190,6 +1196,12 @@ Service_Write(UA_Server *server, UA_Session *session,
     UA_LOG_DEBUG_SESSION(server->config.logger, session,
                          "Processing WriteRequest");
 
+    if(server->config.maxNodesPerWrite != 0 &&
+       request->nodesToWriteSize > server->config.maxNodesPerWrite) {
+        response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS;
+        return;
+    }
+
     response->responseHeader.serviceResult = 
         UA_Server_processServiceOperations(server, session,
                   (UA_ServiceOperation)Operation_Write,

+ 6 - 0
src/server/ua_services_call.c

@@ -223,6 +223,12 @@ void Service_Call(UA_Server *server, UA_Session *session,
     UA_LOG_DEBUG_SESSION(server->config.logger, session,
                          "Processing CallRequest");
 
+    if(server->config.maxNodesPerMethodCall != 0 &&
+       request->methodsToCallSize > server->config.maxNodesPerMethodCall) {
+        response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS;
+        return;
+    }
+
     response->responseHeader.serviceResult = 
         UA_Server_processServiceOperations(server, session,
                   (UA_ServiceOperation)Operation_CallMethod,

+ 28 - 0
src/server/ua_services_nodemanagement.c

@@ -888,6 +888,13 @@ Service_AddNodes(UA_Server *server, UA_Session *session,
                       UA_AddNodesResponse *response) {
     UA_LOG_DEBUG_SESSION(server->config.logger, session,
                          "Processing AddNodesRequest");
+
+    if(server->config.maxNodesPerNodeManagement != 0 &&
+       request->nodesToAddSize > server->config.maxNodesPerNodeManagement) {
+        response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS;
+        return;
+    }
+
     response->responseHeader.serviceResult = 
         UA_Server_processServiceOperations(server, session,
                   (UA_ServiceOperation)Service_AddNode,
@@ -1107,6 +1114,13 @@ void Service_DeleteNodes(UA_Server *server, UA_Session *session,
                          UA_DeleteNodesResponse *response) {
     UA_LOG_DEBUG_SESSION(server->config.logger, session,
                          "Processing DeleteNodesRequest");
+
+    if(server->config.maxNodesPerNodeManagement != 0 &&
+       request->nodesToDeleteSize > server->config.maxNodesPerNodeManagement) {
+        response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS;
+        return;
+    }
+
     response->responseHeader.serviceResult =
         UA_Server_processServiceOperations(server, session,
                                            (UA_ServiceOperation)deleteNodeOperation,
@@ -1195,6 +1209,13 @@ void Service_AddReferences(UA_Server *server, UA_Session *session,
                            UA_AddReferencesResponse *response) {
     UA_LOG_DEBUG_SESSION(server->config.logger, session,
                          "Processing AddReferencesRequest");
+
+    if(server->config.maxNodesPerNodeManagement != 0 &&
+       request->referencesToAddSize > server->config.maxNodesPerNodeManagement) {
+        response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS;
+        return;
+    }
+
     response->responseHeader.serviceResult =
         UA_Server_processServiceOperations(server, session,
                                            (UA_ServiceOperation) addReference,
@@ -1261,6 +1282,13 @@ Service_DeleteReferences(UA_Server *server, UA_Session *session,
                          UA_DeleteReferencesResponse *response) {
     UA_LOG_DEBUG_SESSION(server->config.logger, session,
                          "Processing DeleteReferencesRequest");
+
+    if(server->config.maxNodesPerNodeManagement != 0 &&
+       request->referencesToDeleteSize > server->config.maxNodesPerNodeManagement) {
+        response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS;
+        return;
+    }
+
     response->responseHeader.serviceResult =
         UA_Server_processServiceOperations(server, session,
                                            (UA_ServiceOperation) deleteReference,

+ 24 - 0
src/server/ua_services_subscription.c

@@ -279,6 +279,12 @@ Service_CreateMonitoredItems(UA_Server *server, UA_Session *session,
     UA_LOG_DEBUG_SESSION(server->config.logger, session,
                          "Processing CreateMonitoredItemsRequest");
 
+    if(server->config.maxMonitoredItemsPerCall != 0 &&
+       request->itemsToCreateSize > server->config.maxMonitoredItemsPerCall) {
+        response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS;
+        return;
+    }
+
     /* Check if the timestampstoreturn is valid */
     op_timestampsToReturn2 = request->timestampsToReturn;
     if(op_timestampsToReturn2 > UA_TIMESTAMPSTORETURN_NEITHER) {
@@ -327,6 +333,12 @@ void Service_ModifyMonitoredItems(UA_Server *server, UA_Session *session,
     UA_LOG_DEBUG_SESSION(server->config.logger, session,
                          "Processing ModifyMonitoredItemsRequest");
 
+    if(server->config.maxMonitoredItemsPerCall != 0 &&
+       request->itemsToModifySize > server->config.maxMonitoredItemsPerCall) {
+        response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS;
+        return;
+    }
+
     /* Check if the timestampstoreturn is valid */
     if(request->timestampsToReturn > UA_TIMESTAMPSTORETURN_NEITHER) {
         response->responseHeader.serviceResult = UA_STATUSCODE_BADTIMESTAMPSTORETURNINVALID;
@@ -380,6 +392,12 @@ void Service_SetMonitoringMode(UA_Server *server, UA_Session *session,
     UA_LOG_DEBUG_SESSION(server->config.logger, session,
                          "Processing SetMonitoringMode");
 
+    if(server->config.maxMonitoredItemsPerCall != 0 &&
+       request->monitoredItemIdsSize > server->config.maxMonitoredItemsPerCall) {
+        response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS;
+        return;
+    }
+
     /* Get the subscription */
     op_sub = UA_Session_getSubscriptionByID(session, request->subscriptionId);
     if(!op_sub) {
@@ -533,6 +551,12 @@ void Service_DeleteMonitoredItems(UA_Server *server, UA_Session *session,
     UA_LOG_DEBUG_SESSION(server->config.logger, session,
                          "Processing DeleteMonitoredItemsRequest");
 
+    if(server->config.maxMonitoredItemsPerCall != 0 &&
+       request->monitoredItemIdsSize > server->config.maxMonitoredItemsPerCall) {
+        response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS;
+        return;
+    }
+
     /* Get the subscription */
     op_sub = UA_Session_getSubscriptionByID(session, request->subscriptionId);
     if(!op_sub) {

+ 38 - 2
src/server/ua_services_view.c

@@ -72,8 +72,17 @@ browseReferences(UA_Server *server, const UA_Node *node,
 
     /* How many references can we return at most? */
     size_t maxrefs = cp->maxReferences;
-    if(maxrefs == 0)
-        maxrefs = UA_INT32_MAX;
+    if(maxrefs == 0) {
+        if(server->config.maxReferencesPerNode != 0) {
+            maxrefs = server->config.maxReferencesPerNode;
+        } else {
+            maxrefs = UA_INT32_MAX;
+        }
+    } else {
+        if(server->config.maxReferencesPerNode != 0 && maxrefs > server->config.maxReferencesPerNode) {
+            maxrefs = server->config.maxReferencesPerNode;
+        }
+    }
 
     /* Allocate the results array */
     size_t refs_size = 2; /* True size of the array */
@@ -127,6 +136,8 @@ browseReferences(UA_Server *server, const UA_Node *node,
             /* Make enough space in the array */
             if(result->referencesSize >= refs_size) {
                 refs_size *= 2;
+                if(refs_size > maxrefs)
+                    refs_size = maxrefs;
                 UA_ReferenceDescription *rd = (UA_ReferenceDescription*)
                     UA_realloc(result->references, sizeof(UA_ReferenceDescription) * refs_size);
                 if(!rd) {
@@ -296,6 +307,12 @@ void Service_Browse(UA_Server *server, UA_Session *session,
         return;
     }
 
+    if(server->config.maxNodesPerBrowse != 0 &&
+       request->nodesToBrowseSize > server->config.maxNodesPerBrowse) {
+        response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS;
+        return;
+    }
+
     size_t size = request->nodesToBrowseSize;
     response->results =
         (UA_BrowseResult*)UA_Array_new(size, &UA_TYPES[UA_TYPES_BROWSERESULT]);
@@ -679,6 +696,13 @@ Service_TranslateBrowsePathsToNodeIds(UA_Server *server, UA_Session *session,
                                       UA_TranslateBrowsePathsToNodeIdsResponse *response) {
     UA_LOG_DEBUG_SESSION(server->config.logger, session,
                          "Processing TranslateBrowsePathsToNodeIdsRequest");
+
+    if(server->config.maxNodesPerTranslateBrowsePathsToNodeIds != 0 &&
+       request->browsePathsSize > server->config.maxNodesPerTranslateBrowsePathsToNodeIds) {
+        response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS;
+        return;
+    }
+
     response->responseHeader.serviceResult = 
         UA_Server_processServiceOperations(server, session,
                   (UA_ServiceOperation)Operation_TranslateBrowsePathToNodeIds,
@@ -698,6 +722,12 @@ void Service_RegisterNodes(UA_Server *server, UA_Session *session,
         return;
     }
 
+    if(server->config.maxNodesPerRegisterNodes != 0 &&
+       request->nodesToRegisterSize > server->config.maxNodesPerRegisterNodes) {
+        response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS;
+        return;
+    }
+
     response->responseHeader.serviceResult =
         UA_Array_copy(request->nodesToRegister, request->nodesToRegisterSize,
                       (void**)&response->registeredNodeIds, &UA_TYPES[UA_TYPES_NODEID]);
@@ -714,4 +744,10 @@ void Service_UnregisterNodes(UA_Server *server, UA_Session *session,
     //TODO: remove the nodeids from the session if really needed
     if(request->nodesToUnregisterSize == 0)
         response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
+
+    if(server->config.maxNodesPerRegisterNodes != 0 &&
+       request->nodesToUnregisterSize > server->config.maxNodesPerRegisterNodes) {
+        response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS;
+        return;
+    }
 }

+ 88 - 0
tools/schema/Opc.Ua.NodeSet2.Minimal.xml

@@ -1277,6 +1277,94 @@
       <Reference ReferenceType="HasProperty" IsForward="false">i=2296</Reference>
     </References>
   </UAVariable>
+  <UAObject BrowseName="OperationLimits" NodeId="i=11551" ParentNodeId="i=2013">
+    <DisplayName>OperationLimits</DisplayName>
+    <Description>Defines the limits supported by the server for different operations.</Description>
+    <References>
+      <Reference ReferenceType="HasTypeDefinition">i=11564</Reference>
+      <Reference ReferenceType="HasModellingRule">i=80</Reference>
+      <Reference ReferenceType="HasComponent" IsForward="false">i=2013</Reference>
+    </References>
+  </UAObject>
+  <UAObjectType NodeId="i=11564" BrowseName="OperationLimitsType">
+    <DisplayName>OperationLimitsType</DisplayName>
+    <Description>Identifies the operation limits imposed by the server.</Description>
+    <References>
+      <Reference ReferenceType="HasSubtype" IsForward="false">i=58</Reference>
+    </References>
+  </UAObjectType>
+  <UAObject NodeId="i=11704" BrowseName="OperationLimits" ParentNodeId="i=2268">
+    <DisplayName>OperationLimits</DisplayName>
+    <Description>Defines the limits supported by the server for different operations.</Description>
+    <References>
+      <Reference ReferenceType="HasTypeDefinition">i=11564</Reference>
+      <Reference ReferenceType="HasComponent" IsForward="false">i=2268</Reference>
+    </References>
+  </UAObject>
+  <UAVariable NodeId="i=11705" BrowseName="MaxNodesPerRead" ParentNodeId="i=11704" DataType="UInt32">
+    <DisplayName>MaxNodesPerRead</DisplayName>
+    <Description>The maximum number of operations in a single Read request.</Description>
+    <References>
+      <Reference ReferenceType="HasTypeDefinition">i=68</Reference>
+      <Reference ReferenceType="HasProperty" IsForward="false">i=11704</Reference>
+    </References>
+  </UAVariable>
+  <UAVariable NodeId="i=11707" BrowseName="MaxNodesPerWrite" ParentNodeId="i=11704" DataType="UInt32">
+    <DisplayName>MaxNodesPerWrite</DisplayName>
+    <Description>The maximum number of operations in a single Write request.</Description>
+    <References>
+      <Reference ReferenceType="HasTypeDefinition">i=68</Reference>
+      <Reference ReferenceType="HasProperty" IsForward="false">i=11704</Reference>
+    </References>
+  </UAVariable>
+  <UAVariable NodeId="i=11709" BrowseName="MaxNodesPerMethodCall" ParentNodeId="i=11704" DataType="UInt32">
+    <DisplayName>MaxNodesPerMethodCall</DisplayName>
+    <Description>The maximum number of operations in a single Call request.</Description>
+    <References>
+      <Reference ReferenceType="HasTypeDefinition">i=68</Reference>
+      <Reference ReferenceType="HasProperty" IsForward="false">i=11704</Reference>
+    </References>
+  </UAVariable>
+  <UAVariable NodeId="i=11710" BrowseName="MaxNodesPerBrowse" ParentNodeId="i=11704" DataType="UInt32">
+    <DisplayName>MaxNodesPerBrowse</DisplayName>
+    <Description>The maximum number of operations in a single Browse request.</Description>
+    <References>
+      <Reference ReferenceType="HasTypeDefinition">i=68</Reference>
+      <Reference ReferenceType="HasProperty" IsForward="false">i=11704</Reference>
+    </References>
+  </UAVariable>
+  <UAVariable NodeId="i=11711" BrowseName="MaxNodesPerRegisterNodes" ParentNodeId="i=11704" DataType="UInt32">
+    <DisplayName>MaxNodesPerRegisterNodes</DisplayName>
+    <Description>The maximum number of operations in a single RegisterNodes request.</Description>
+    <References>
+      <Reference ReferenceType="HasTypeDefinition">i=68</Reference>
+      <Reference ReferenceType="HasProperty" IsForward="false">i=11704</Reference>
+    </References>
+  </UAVariable>
+  <UAVariable NodeId="i=11712" BrowseName="MaxNodesPerTranslateBrowsePathsToNodeIds" ParentNodeId="i=11704" DataType="UInt32">
+    <DisplayName>MaxNodesPerTranslateBrowsePathsToNodeIds</DisplayName>
+    <Description>The maximum number of operations in a single TranslateBrowsePathsToNodeIds request.</Description>
+    <References>
+      <Reference ReferenceType="HasTypeDefinition">i=68</Reference>
+      <Reference ReferenceType="HasProperty" IsForward="false">i=11704</Reference>
+    </References>
+  </UAVariable>
+  <UAVariable NodeId="i=11713" BrowseName="MaxNodesPerNodeManagement" ParentNodeId="i=11704" DataType="UInt32">
+    <DisplayName>MaxNodesPerNodeManagement</DisplayName>
+    <Description>The maximum number of operations in a single AddNodes, AddReferences, DeleteNodes or DeleteReferences request.</Description>
+    <References>
+      <Reference ReferenceType="HasTypeDefinition">i=68</Reference>
+      <Reference ReferenceType="HasProperty" IsForward="false">i=11704</Reference>
+    </References>
+  </UAVariable>
+  <UAVariable NodeId="i=11714" BrowseName="MaxMonitoredItemsPerCall" ParentNodeId="i=11704" DataType="UInt32">
+    <DisplayName>MaxMonitoredItemsPerCall</DisplayName>
+    <Description>The maximum number of operations in a single MonitoredItem related request.</Description>
+    <References>
+      <Reference ReferenceType="HasTypeDefinition">i=68</Reference>
+      <Reference ReferenceType="HasProperty" IsForward="false">i=11704</Reference>
+    </References>
+  </UAVariable>
   <UAMethod NodeId="i=11492" BrowseName="GetMonitoredItems" ParentNodeId="i=2253" MethodDeclarationId="i=11489">
     <DisplayName>GetMonitoredItems</DisplayName>
     <References>