/// <summary>
        /// Worker method to test Transfer of subscriptions to new session.
        /// </summary>
        public static void TransferSubscriptionTest(
            IServerTestServices services,
            RequestHeader requestHeader,
            UInt32Collection subscriptionIds,
            bool sendInitialData,
            bool expectAccessDenied)
        {
            Assert.AreEqual(1, subscriptionIds.Count);

            requestHeader.Timestamp = DateTime.UtcNow;
            var response = services.TransferSubscriptions(requestHeader, subscriptionIds, sendInitialData,
                                                          out TransferResultCollection transferResults, out DiagnosticInfoCollection diagnosticInfos);

            Assert.AreEqual(StatusCodes.Good, response.ServiceResult.Code);
            Assert.AreEqual(subscriptionIds.Count, transferResults.Count);
            ServerFixtureUtils.ValidateDiagnosticInfos(diagnosticInfos, subscriptionIds);

            foreach (var transferResult in transferResults)
            {
                TestContext.Out.WriteLine("TransferResult: {0}", transferResult.StatusCode);
                if (expectAccessDenied)
                {
                    Assert.AreEqual(StatusCodes.BadUserAccessDenied, transferResult.StatusCode.Code);
                }
                else
                {
                    Assert.IsTrue(StatusCode.IsGood(transferResult.StatusCode));
                    Assert.AreEqual(1, transferResult.AvailableSequenceNumbers.Count);
                }
            }

            if (expectAccessDenied)
            {
                return;
            }

            requestHeader.Timestamp = DateTime.UtcNow;
            var acknoledgements = new SubscriptionAcknowledgementCollection();

            response = services.Publish(requestHeader, acknoledgements,
                                        out uint publishedId, out UInt32Collection availableSequenceNumbers,
                                        out bool moreNotifications, out NotificationMessage notificationMessage,
                                        out StatusCodeCollection _, out diagnosticInfos);
            Assert.AreEqual(StatusCodes.Good, response.ServiceResult.Code);
            ServerFixtureUtils.ValidateResponse(response);
            ServerFixtureUtils.ValidateDiagnosticInfos(diagnosticInfos, acknoledgements);
            Assert.AreEqual(subscriptionIds[0], publishedId);
            Assert.AreEqual(sendInitialData ? 1 : 0, notificationMessage.NotificationData.Count);
            //Assert.AreEqual(0, availableSequenceNumbers.Count);

            requestHeader.Timestamp = DateTime.UtcNow;
            response = services.DeleteSubscriptions(requestHeader, subscriptionIds, out StatusCodeCollection statusResults, out diagnosticInfos);
            Assert.AreEqual(StatusCodes.Good, response.ServiceResult.Code);
        }
Esempio n. 2
0
 public ResponseHeader Publish(
     RequestHeader requestHeader,
     SubscriptionAcknowledgementCollection subscriptionAcknowledgements,
     out uint subscriptionId,
     out UInt32Collection availableSequenceNumbers,
     out bool moreNotifications,
     out NotificationMessage notificationMessage,
     out StatusCodeCollection results,
     out DiagnosticInfoCollection diagnosticInfos)
 {
     return(m_session.Publish(requestHeader, subscriptionAcknowledgements, out subscriptionId, out availableSequenceNumbers,
                              out moreNotifications, out notificationMessage, out results, out diagnosticInfos));
 }
        /// <summary>
        /// Worker method to test TransferSubscriptions of a server.
        /// </summary>
        public static UInt32Collection CreateSubscriptionForTransfer(
            IServerTestServices services,
            RequestHeader requestHeader,
            NodeId[] testNodes,
            uint queueSize       = DefaultMonitoredItemsQueueSize,
            int samplingInterval = DefaultMonitoredItemsSamplingInterval)
        {
            // start time

            requestHeader.Timestamp = DateTime.UtcNow;
            uint subscriptionId = CreateSubscription(services, requestHeader);
            uint clientHandle   = 1;

            foreach (NodeId testNode in testNodes)
            {
                CreateMonitoredItem(services, requestHeader, subscriptionId, testNode, clientHandle++, queueSize, samplingInterval);
            }

            var subscriptionIds = new UInt32Collection();

            subscriptionIds.Add(subscriptionId);

            // enable publishing
            var response = services.SetPublishingMode(requestHeader, true, subscriptionIds,
                                                      out var statuses, out var diagnosticInfos);

            ServerFixtureUtils.ValidateResponse(response);
            ServerFixtureUtils.ValidateDiagnosticInfos(diagnosticInfos, subscriptionIds);

            // wait some time to settle
            Thread.Sleep(1000);

            // publish request
            var acknoledgements = new SubscriptionAcknowledgementCollection();

            response = services.Publish(requestHeader, acknoledgements,
                                        out uint publishedId, out UInt32Collection availableSequenceNumbers,
                                        out bool moreNotifications, out NotificationMessage notificationMessage,
                                        out StatusCodeCollection _, out diagnosticInfos);
            ServerFixtureUtils.ValidateResponse(response);
            ServerFixtureUtils.ValidateDiagnosticInfos(diagnosticInfos, acknoledgements);
            Assert.AreEqual(subscriptionId, publishedId);

            // static node, do not acknoledge
            Assert.AreEqual(1, availableSequenceNumbers.Count);

            return(subscriptionIds);
        }
Esempio n. 4
0
 /// <summary>
 /// Creates the test object.
 /// </summary>
 public SubscribeTest(
     Session session,
     ServerTestConfiguration configuration,
     ReportMessageEventHandler reportMessage,
     ReportProgressEventHandler reportProgress,
     TestBase template)
 : 
     base("Subscribe", session, configuration, reportMessage, reportProgress, template)
 {
     m_subscriptions = new List<Subscription>();
     m_errorEvent = new ManualResetEvent(false);
     m_acknowledgements = new SubscriptionAcknowledgementCollection();
     m_publishPipelineDepth = 10;
     m_idealTimingError = 400;
     m_maximumTimingError = 500;
 }
Esempio n. 5
0
 public static Entry For(SubscriptionAcknowledgementCollection collection)
 {
     if (collection == null)
     {
         return(new NullEntry());
     }
     else
     {
         ArrayEntry array = new ArrayEntry();
         SubscriptionAcknowledgementCollection.Enumerator e = collection.GetEnumerator();
         while (e.MoveNext())
         {
             ObjectEntry oe = new ObjectEntry();
             oe.Add("SubscriptionId", For(e.Current.SubscriptionId));
             oe.Add("SequenceNo", For(e.Current.SequenceNumber));
             array.Add(oe);
         }
         return(array);
     }
 }
        /// <summary>
        /// Worker method to verify the SubscriptionTransferred message of a server.
        /// </summary>
        public static void VerifySubscriptionTransferred(
            IServerTestServices services,
            RequestHeader requestHeader,
            UInt32Collection subscriptionIds,
            bool deleteSubscriptions)
        {
            // start time
            requestHeader.Timestamp = DateTime.UtcNow;

            // wait some time to settle
            Thread.Sleep(100);

            // publish request
            var acknoledgements = new SubscriptionAcknowledgementCollection();
            var response        = services.Publish(requestHeader, acknoledgements,
                                                   out uint publishedId, out UInt32Collection availableSequenceNumbers,
                                                   out bool moreNotifications, out NotificationMessage notificationMessage,
                                                   out StatusCodeCollection _, out var diagnosticInfos);

            ServerFixtureUtils.ValidateResponse(response);
            ServerFixtureUtils.ValidateDiagnosticInfos(diagnosticInfos, acknoledgements);
            Assert.IsFalse(moreNotifications);
            Assert.IsTrue(subscriptionIds.Contains(publishedId));
            Assert.AreEqual(1, notificationMessage.NotificationData.Count);
            var statusMessage = notificationMessage.NotificationData[0].ToString();

            Assert.IsTrue(statusMessage.Contains("GoodSubscriptionTransferred"));

            // static node, do not acknoledge
            if (availableSequenceNumbers != null)
            {
                Assert.AreEqual(0, availableSequenceNumbers.Count);
            }

            if (deleteSubscriptions)
            {
                response = services.DeleteSubscriptions(requestHeader, subscriptionIds, out var _, out diagnosticInfos);
                ServerFixtureUtils.ValidateResponse(response);
                ServerFixtureUtils.ValidateDiagnosticInfos(diagnosticInfos, subscriptionIds);
            }
        }
Esempio n. 7
0
        /// <summary>
        /// Invokes the Publish service.
        /// </summary>
        public virtual ResponseHeader Publish(
            RequestHeader requestHeader,
            SubscriptionAcknowledgementCollection subscriptionAcknowledgements,
            out uint subscriptionId,
            out UInt32Collection availableSequenceNumbers,
            out bool moreNotifications,
            out NotificationMessage notificationMessage,
            out StatusCodeCollection results,
            out DiagnosticInfoCollection diagnosticInfos)
        {
            subscriptionId           = 0;
            availableSequenceNumbers = null;
            moreNotifications        = false;
            notificationMessage      = null;
            results         = null;
            diagnosticInfos = null;

            ValidateRequest(requestHeader);

            // Insert implementation.

            return(CreateResponse(requestHeader, StatusCodes.BadServiceUnsupported));
        }
Esempio n. 8
0
        /// <summary>
        /// Processes acknowledgements for previously published messages.
        /// </summary>
        public void Acknowledge(
            OperationContext context,
            SubscriptionAcknowledgementCollection subscriptionAcknowledgements,
            out StatusCodeCollection acknowledgeResults,
            out DiagnosticInfoCollection acknowledgeDiagnosticInfos)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }
            if (subscriptionAcknowledgements == null)
            {
                throw new ArgumentNullException("subscriptionAcknowledgements");
            }

            lock (m_lock)
            {
                bool diagnosticsExist = false;
                acknowledgeResults         = new StatusCodeCollection(subscriptionAcknowledgements.Count);
                acknowledgeDiagnosticInfos = new DiagnosticInfoCollection(subscriptionAcknowledgements.Count);

                for (int ii = 0; ii < subscriptionAcknowledgements.Count; ii++)
                {
                    SubscriptionAcknowledgement acknowledgement = subscriptionAcknowledgements[ii];

                    bool found = false;

                    for (int jj = 0; jj < m_queuedSubscriptions.Count; jj++)
                    {
                        QueuedSubscription subscription = m_queuedSubscriptions[jj];

                        if (subscription.Subscription.Id == acknowledgement.SubscriptionId)
                        {
                            ServiceResult result = subscription.Subscription.Acknowledge(context, acknowledgement.SequenceNumber);

                            if (ServiceResult.IsGood(result))
                            {
                                acknowledgeResults.Add(StatusCodes.Good);

                                if ((context.DiagnosticsMask & DiagnosticsMasks.OperationAll) != 0)
                                {
                                    acknowledgeDiagnosticInfos.Add(null);
                                }
                            }
                            else
                            {
                                acknowledgeResults.Add(result.Code);

                                if ((context.DiagnosticsMask & DiagnosticsMasks.OperationAll) != 0)
                                {
                                    DiagnosticInfo diagnosticInfo = ServerUtils.CreateDiagnosticInfo(m_server, context, result);
                                    acknowledgeDiagnosticInfos.Add(diagnosticInfo);
                                    diagnosticsExist = true;
                                }
                            }

                            found = true;
                            break;
                        }
                    }

                    if (!found)
                    {
                        ServiceResult result = new ServiceResult(StatusCodes.BadSubscriptionIdInvalid);
                        acknowledgeResults.Add(result.Code);

                        if ((context.DiagnosticsMask & DiagnosticsMasks.OperationAll) != 0)
                        {
                            DiagnosticInfo diagnosticInfo = ServerUtils.CreateDiagnosticInfo(m_server, context, result);
                            acknowledgeDiagnosticInfos.Add(diagnosticInfo);
                            diagnosticsExist = true;
                        }
                    }
                }

                if (!diagnosticsExist)
                {
                    acknowledgeDiagnosticInfos.Clear();
                }
            }
        }
        /// <summary>
        /// Invokes the Publish service.
        /// </summary>
        public virtual ResponseHeader Publish(
            RequestHeader                         requestHeader,
            SubscriptionAcknowledgementCollection subscriptionAcknowledgements,
            out uint                              subscriptionId,
            out UInt32Collection                  availableSequenceNumbers,
            out bool                              moreNotifications,
            out NotificationMessage               notificationMessage,
            out StatusCodeCollection              results,
            out DiagnosticInfoCollection          diagnosticInfos)
        {
            subscriptionId = 0;
            availableSequenceNumbers = null;
            moreNotifications = false;
            notificationMessage = null;
            results = null;
            diagnosticInfos = null;

            ValidateRequest(requestHeader);

            // Insert implementation.

            return CreateResponse(requestHeader, StatusCodes.BadServiceUnsupported);
        }
        /// <summary>
        /// Invokes the Publish service.
        /// </summary>
        /// <param name="requestHeader">The request header.</param>
        /// <param name="subscriptionAcknowledgements">The list of acknowledgements for one or more Subscriptions.</param>
        /// <param name="subscriptionId">The subscription identifier.</param>
        /// <param name="availableSequenceNumbers">The available sequence numbers.</param>
        /// <param name="moreNotifications">If set to <c>true</c> the number of Notifications that were ready to be sent could not be sent in a single response.</param>
        /// <param name="notificationMessage">The NotificationMessage that contains the list of Notifications.</param>
        /// <param name="results">The list of results for the acknowledgements.</param>
        /// <param name="diagnosticInfos">The diagnostic information for the results.</param>
        /// <returns>
        /// Returns a <see cref="ResponseHeader"/> object 
        /// </returns>
        public override ResponseHeader Publish(
            RequestHeader                         requestHeader, 
            SubscriptionAcknowledgementCollection subscriptionAcknowledgements, 
            out uint                              subscriptionId, 
            out UInt32Collection                  availableSequenceNumbers, 
            out bool                              moreNotifications, 
            out NotificationMessage               notificationMessage, 
            out StatusCodeCollection              results, 
            out DiagnosticInfoCollection          diagnosticInfos)
        {
            OperationContext context = ValidateRequest(requestHeader, RequestType.Publish);

            try
            {
                /*
                // check if there is an odd delay.
                if (DateTime.UtcNow > requestHeader.Timestamp.AddMilliseconds(100))
                {
                    Utils.Trace(
                        "WARNING. Unexpected delay receiving Publish request. Time={0:hh:mm:ss.fff}, ReceiveTime={1:hh:mm:ss.fff}",
                        DateTime.UtcNow,
                        requestHeader.Timestamp);
                }
                */
                
                Utils.Trace("PUBLISH #{0} RECIEVED. TIME={1:hh:hh:ss.fff}", requestHeader.RequestHandle, requestHeader.Timestamp);
                
                notificationMessage = ServerInternal.SubscriptionManager.Publish(
                    context,
                    subscriptionAcknowledgements,
                    null,
                    out subscriptionId,
                    out availableSequenceNumbers,
                    out moreNotifications,
                    out results,
                    out diagnosticInfos);

                /*
                if (notificationMessage != null)
                {
                    Utils.Trace(
                        "PublishResponse: SubId={0} SeqNo={1}, PublishTime={2:mm:ss.fff}, Time={3:mm:ss.fff}",
                        subscriptionId,
                        notificationMessage.SequenceNumber,
                        notificationMessage.PublishTime,
                        DateTime.UtcNow);
                }
                */

                return CreateResponse(requestHeader, context.StringTable);      
            }
            catch (ServiceResultException e)
            {
                lock (ServerInternal.DiagnosticsLock)
                {
                    ServerInternal.ServerDiagnostics.RejectedRequestsCount++;

                    if (IsSecurityError(e.StatusCode))
                    {
                        ServerInternal.ServerDiagnostics.SecurityRejectedRequestsCount++;
                    }
                }

                throw TranslateException(context, e);
            }  
            finally
            {
                OnRequestComplete(context);
            }
        }
Esempio n. 11
0
        /// <summary>
        /// Processes the response from a publish request.
        /// </summary>
        private void ProcessPublishResponse(
            ResponseHeader      responseHeader,
            uint                subscriptionId,
            UInt32Collection    availableSequenceNumbers,
            bool                moreNotifications,
            NotificationMessage notificationMessage)
        {
            Subscription subscription = null;
            
            // send notification that the server is alive.
            OnKeepAlive(m_serverState, responseHeader.Timestamp);

            // collect the current set if acknowledgements.
            lock (SyncRoot)
            {
                // clear out acknowledgements for messages that the server does not have any more.
                SubscriptionAcknowledgementCollection acknowledgementsToSend = new SubscriptionAcknowledgementCollection();

                for (int ii = 0; ii < m_acknowledgementsToSend.Count; ii++)
                {
                    SubscriptionAcknowledgement acknowledgement = m_acknowledgementsToSend[ii];

                    if (acknowledgement.SubscriptionId != subscriptionId)
                    {
                        acknowledgementsToSend.Add(acknowledgement);
                    }
                    else
                    {
                        if (availableSequenceNumbers == null || availableSequenceNumbers.Contains(acknowledgement.SequenceNumber))
                        {
                            acknowledgementsToSend.Add(acknowledgement);
                        }
                    }
                }

                // create an acknowledgement to be sent back to the server.
                if (notificationMessage.NotificationData.Count > 0)
                {
                    SubscriptionAcknowledgement acknowledgement = new SubscriptionAcknowledgement();

                    acknowledgement.SubscriptionId = subscriptionId;
                    acknowledgement.SequenceNumber = notificationMessage.SequenceNumber;

                    acknowledgementsToSend.Add(acknowledgement);
                }

                uint lastSentSequenceNumber = 0;
                if (availableSequenceNumbers != null)
                {
                    foreach (uint availableSequenceNumber in availableSequenceNumbers)
                    {
                        if (m_latestAcknowledgementsSent.ContainsKey(subscriptionId))
                        {
                            lastSentSequenceNumber = m_latestAcknowledgementsSent[subscriptionId];

                            // If the last sent sequence number is uint.Max do not display the warning; the counter rolled over
                            // If the last sent sequence number is greater or equal to the available sequence number (returned by the publish), a warning must be logged.
                            if (((lastSentSequenceNumber >= availableSequenceNumber) && (lastSentSequenceNumber != uint.MaxValue)) || (lastSentSequenceNumber == availableSequenceNumber) && (lastSentSequenceNumber == uint.MaxValue))
                            {
                                Utils.Trace("Received sequence number which was already acknowledged={0}", availableSequenceNumber);
                            }
                        }
                    }
                }

                if (m_latestAcknowledgementsSent.ContainsKey(subscriptionId))
                {
                    lastSentSequenceNumber = m_latestAcknowledgementsSent[subscriptionId];

                    // If the last sent sequence number is uint.Max do not display the warning; the counter rolled over
                    // If the last sent sequence number is greater or equal to the notificationMessage's sequence number (returned by the publish), a warning must be logged.
                    if (((lastSentSequenceNumber >= notificationMessage.SequenceNumber) && (lastSentSequenceNumber != uint.MaxValue)) || (lastSentSequenceNumber == notificationMessage.SequenceNumber) && (lastSentSequenceNumber == uint.MaxValue))
                    {
                        Utils.Trace("Received sequence number which was already acknowledged={0}", notificationMessage.SequenceNumber);
                    }
                }

                if (availableSequenceNumbers != null)
                {
                    foreach (var acknowledgement in acknowledgementsToSend)
                    {
                        if (acknowledgement.SubscriptionId == subscriptionId && !availableSequenceNumbers.Contains(acknowledgement.SequenceNumber))
                        {
                            Utils.Trace("Sequence number={0} was not received in the available sequence numbers.", acknowledgement.SequenceNumber);
                        }
                    }
                }

                m_acknowledgementsToSend = acknowledgementsToSend;

                if (notificationMessage.IsEmpty)
                {
                    Utils.Trace("Empty notification message received for SessionId {0} with PublishTime {1}", SessionId, notificationMessage.PublishTime.ToLocalTime());
                }

                // find the subscription.
                foreach (Subscription current in m_subscriptions)
                {
                    if (current.Id == subscriptionId)
                    {
                        subscription = current;                            
                        break;
                    }
                }                    
            }

            // ignore messages with a subscription that has been deleted.
            if (subscription != null)
            {
                // Validate publish time and reject old values.
                if (notificationMessage.PublishTime.AddMilliseconds(subscription.CurrentPublishingInterval * subscription.CurrentLifetimeCount) < DateTime.UtcNow)
                {
                    Utils.Trace("PublishTime {0} in publish response is too old for SubscriptionId {1}.", notificationMessage.PublishTime.ToLocalTime(), subscription.Id);
                }

                // Validate publish time and reject old values.
                if (notificationMessage.PublishTime > DateTime.UtcNow.AddMilliseconds(subscription.CurrentPublishingInterval * subscription.CurrentLifetimeCount))
                {
                    Utils.Trace("PublishTime {0} in publish response is newer than actual time for SubscriptionId {1}.", notificationMessage.PublishTime.ToLocalTime(), subscription.Id);
                }

                // update subscription cache.                                 
                subscription.SaveMessageInCache(
                    availableSequenceNumbers, 
                    notificationMessage, 
                    responseHeader.StringTable);

                // raise the notification.
                lock (m_eventLock)
                {
                    NotificationEventArgs args = new NotificationEventArgs(subscription, notificationMessage, responseHeader.StringTable);

                    if (m_Publish != null)
                    {
                        ThreadPool.QueueUserWorkItem(OnRaisePublishNotification, args);
                    }
                }
            }
            else
            {
                Utils.Trace("Received Publish Response for Unknown SubscriptionId={0}", subscriptionId);
            }
        }
Esempio n. 12
0
        /// <summary>
        /// Sends an additional publish request.
        /// </summary>
        public IAsyncResult BeginPublish(int timeout)
        { 
            // do not publish if reconnecting.
            if (m_reconnecting)
            {
                Utils.Trace("Published skipped due to reconnect");
                return null;
            }

            SubscriptionAcknowledgementCollection acknowledgementsToSend = null;

            // collect the current set if acknowledgements.
            lock (SyncRoot)
            {
                acknowledgementsToSend = m_acknowledgementsToSend;
                m_acknowledgementsToSend = new SubscriptionAcknowledgementCollection();
                foreach (var toSend in acknowledgementsToSend)
                {
                    if (m_latestAcknowledgementsSent.ContainsKey(toSend.SubscriptionId))
                    {
                        m_latestAcknowledgementsSent[toSend.SubscriptionId] = toSend.SequenceNumber;
                    }
                    else
                    {
                        m_latestAcknowledgementsSent.Add(toSend.SubscriptionId, toSend.SequenceNumber);
                    }
                }
            }

            // send publish request.
            RequestHeader requestHeader = new RequestHeader();

            // ensure the publish request is discarded before the timeout occurs to ensure the channel is dropped.
            requestHeader.TimeoutHint       = (uint)OperationTimeout/2;
            requestHeader.ReturnDiagnostics = (uint)(int)ReturnDiagnostics;
            requestHeader.RequestHandle     = Utils.IncrementIdentifier(ref m_publishCounter);
            
            AsyncRequestState state = new AsyncRequestState();

            state.RequestTypeId = DataTypes.PublishRequest;
            state.RequestId = requestHeader.RequestHandle;
            state.Timestamp = DateTime.UtcNow;

            try
            {                
                IAsyncResult result = BeginPublish(
                    requestHeader, 
                    acknowledgementsToSend, 
                    OnPublishComplete, 
                    new object[] { SessionId, acknowledgementsToSend, requestHeader });
                    
                AsyncRequestStarted(result, requestHeader.RequestHandle, DataTypes.PublishRequest);

                // Utils.Trace("PUBLISH #{0} SENT", requestHeader.RequestHandle);

                return result;
            }
            catch (Exception e)
            {   
                Utils.Trace(e, "Unexpected error sending publish request.");
                return null;
            }
        }
Esempio n. 13
0
        /// <summary>
        /// Sets the object members to default values.
        /// </summary>
        private void Initialize()
        {
            m_sessionTimeout        = 0;
            m_namespaceUris         = new NamespaceTable();
            m_serverUris            = new StringTable();
            m_factory               = EncodeableFactory.GlobalFactory;
            m_nodeCache             = new NodeCache(this);
            m_configuration         = null;
            m_instanceCertificate   = null;
            m_endpoint              = null;
            m_subscriptions         = new List<Subscription>();
            m_dictionaries          = new Dictionary<NodeId,DataDictionary>();
            m_acknowledgementsToSend = new SubscriptionAcknowledgementCollection();
            m_latestAcknowledgementsSent = new Dictionary<uint, uint>();
            m_identityHistory       = new List<IUserIdentity>();
            m_outstandingRequests   = new LinkedList<AsyncRequestState>();
            m_keepAliveInterval     = 5000;
            
            m_defaultSubscription = new Subscription();

            m_defaultSubscription.DisplayName        = "Subscription";
            m_defaultSubscription.PublishingInterval = 1000;
            m_defaultSubscription.KeepAliveCount     = 10;
            m_defaultSubscription.LifetimeCount      = 1000;
            m_defaultSubscription.Priority           = 255;
            m_defaultSubscription.PublishingEnabled  = true;
        }
        /// <summary>
        /// Processes the response from a publish request.
        /// </summary>
        private void ProcessPublishResponse(
            ResponseHeader responseHeader,
            uint subscriptionId,
            UInt32Collection availableSequenceNumbers,
            bool moreNotifications,
            NotificationMessage notificationMessage)
        {
            Subscription subscription = null;

            // send notification that the server is alive.
            OnKeepAlive(m_serverState, responseHeader.Timestamp);

            // collect the current set if acknowledgements.
            lock (SyncRoot)
            {
                // clear out acknowledgements for messages that the server does not have any more.
                SubscriptionAcknowledgementCollection acknowledgementsToSend = new SubscriptionAcknowledgementCollection();

                for (int ii = 0; ii < m_acknowledgementsToSend.Count; ii++)
                {
                    SubscriptionAcknowledgement acknowledgement = m_acknowledgementsToSend[ii];

                    if (acknowledgement.SubscriptionId != subscriptionId)
                    {
                        acknowledgementsToSend.Add(acknowledgement);
                    }
                    else
                    {
                        if (availableSequenceNumbers == null || availableSequenceNumbers.Contains(acknowledgement.SequenceNumber))
                        {
                            acknowledgementsToSend.Add(acknowledgement);
                        }
                    }
                }

                // create an acknowledgement to be sent back to the server.
                if (notificationMessage.NotificationData.Count > 0)
                {
                    SubscriptionAcknowledgement acknowledgement = new SubscriptionAcknowledgement();

                    acknowledgement.SubscriptionId = subscriptionId;
                    acknowledgement.SequenceNumber = notificationMessage.SequenceNumber;

                    acknowledgementsToSend.Add(acknowledgement);
                }

                m_acknowledgementsToSend = acknowledgementsToSend;

                // find the subscription.
                foreach (Subscription current in m_subscriptions)
                {
                    if (current.Id == subscriptionId)
                    {
                        subscription = current;
                        break;
                    }
                }
            }

            // ignore messages with a subscription that has been deleted.
            if (subscription != null)
            {
                // update subscription cache.                                 
                subscription.SaveMessageInCache(
                    availableSequenceNumbers,
                    notificationMessage,
                    responseHeader.StringTable);

                // raise the notification.
                lock (m_eventLock)
                {
                    NotificationEventArgs args = new NotificationEventArgs(subscription, notificationMessage, responseHeader.StringTable);

                    if (m_Publish != null)
                    {
                        Task.Run(() =>
                        {
                            OnRaisePublishNotification(args);
                        });
                    }
                }
            }
        }
Esempio n. 15
0
 /// <summary>
 /// Returns the acknowledgements to send to the server with the publish.
 /// </summary>
 private SubscriptionAcknowledgementCollection GetAcknowledgements()
 {
     lock (m_acknowledgements)
     {
         SubscriptionAcknowledgementCollection acknowledgements = new SubscriptionAcknowledgementCollection();
         acknowledgements.AddRange(m_acknowledgements);
         m_acknowledgements.Clear();
         return acknowledgements;
     }
 }
        public void ResendData()
        {
            var serverTestServices = new ServerTestServices(m_server);
            // save old security context, test fixture can only work with one session
            var securityContext = SecureChannelContext.Current;

            try
            {
                var      namespaceUris = m_server.CurrentInstance.NamespaceUris;
                NodeId[] testSet       = CommonTestWorkers.NodeIdTestSetStatic.Select(n => ExpandedNodeId.ToNodeId(n, namespaceUris)).ToArray();
                //Re-use method CreateSubscriptionForTransfer to create a subscription
                CommonTestWorkers.CreateSubscriptionForTransfer(serverTestServices, m_requestHeader,
                                                                testSet, out var subscriptionIds);

                RequestHeader resendDataRequestHeader   = m_server.CreateAndActivateSession("ResendData");
                var           resendDataSecurityContext = SecureChannelContext.Current;

                // After the ResendData call there will be data to publish again
                MethodState methodStateInstance = (MethodState)m_server.CurrentInstance.
                                                  DiagnosticsNodeManager.FindPredefinedNode(MethodIds.Server_ResendData, typeof(MethodState));
                var nodesToCall = new CallMethodRequestCollection();
                nodesToCall.Add(new CallMethodRequest()
                {
                    ObjectId       = ObjectIds.Server,
                    MethodId       = MethodIds.Server_ResendData,
                    InputArguments = new VariantCollection()
                    {
                        new Variant(subscriptionIds.Last())
                    }
                });

                //call ResendData method from the same session context
                m_requestHeader.Timestamp = DateTime.UtcNow;
                var response = m_server.Call(m_requestHeader,
                                             nodesToCall,
                                             out var results,
                                             out var diagnosticInfos);

                Assert.IsTrue(StatusCode.IsGood(results[0].StatusCode));
                ServerFixtureUtils.ValidateResponse(response);

                Thread.Sleep(1000);

                // Make sure publish queue becomes empty by consuming it
                Assert.AreEqual(1, subscriptionIds.Count);
                // Issue a Publish request
                m_requestHeader.Timestamp = DateTime.UtcNow;
                var acknoledgements = new SubscriptionAcknowledgementCollection();
                response = serverTestServices.Publish(m_requestHeader, acknoledgements,
                                                      out uint publishedId, out UInt32Collection availableSequenceNumbers,
                                                      out bool moreNotifications, out NotificationMessage notificationMessage,
                                                      out StatusCodeCollection _, out diagnosticInfos);

                Assert.AreEqual(StatusCodes.Good, response.ServiceResult.Code);
                ServerFixtureUtils.ValidateResponse(response);
                ServerFixtureUtils.ValidateDiagnosticInfos(diagnosticInfos, acknoledgements);
                Assert.AreEqual(subscriptionIds[0], publishedId);
                Assert.AreEqual(1, notificationMessage.NotificationData.Count);

                // Validate nothing to publish a few times
                const int timesToCallPublish = 3;
                for (int i = 0; i < timesToCallPublish; i++)
                {
                    m_requestHeader.Timestamp = DateTime.UtcNow;
                    response = serverTestServices.Publish(m_requestHeader, acknoledgements,
                                                          out publishedId, out availableSequenceNumbers,
                                                          out moreNotifications, out notificationMessage,
                                                          out StatusCodeCollection _, out diagnosticInfos);

                    Assert.AreEqual(StatusCodes.Good, response.ServiceResult.Code);
                    ServerFixtureUtils.ValidateResponse(response);
                    ServerFixtureUtils.ValidateDiagnosticInfos(diagnosticInfos, acknoledgements);
                    Assert.AreEqual(subscriptionIds[0], publishedId);
                    Assert.AreEqual(0, notificationMessage.NotificationData.Count);
                }

                // Validate ResendData method call from same and different session contexts

                // call ResendData method from different session context
                resendDataRequestHeader.Timestamp = DateTime.UtcNow;
                response = m_server.Call(resendDataRequestHeader,
                                         nodesToCall,
                                         out results,
                                         out diagnosticInfos);

                Assert.AreEqual(StatusCodes.BadUserAccessDenied, results[0].StatusCode.Code);
                ServerFixtureUtils.ValidateResponse(response);

                // Still nothing to publish since previous ResendData call did not execute
                m_requestHeader.Timestamp = DateTime.UtcNow;
                response = serverTestServices.Publish(m_requestHeader, acknoledgements,
                                                      out publishedId, out availableSequenceNumbers,
                                                      out moreNotifications, out notificationMessage,
                                                      out StatusCodeCollection _, out diagnosticInfos);

                Assert.AreEqual(StatusCodes.Good, response.ServiceResult.Code);
                ServerFixtureUtils.ValidateResponse(response);
                ServerFixtureUtils.ValidateDiagnosticInfos(diagnosticInfos, acknoledgements);
                Assert.AreEqual(subscriptionIds[0], publishedId);
                Assert.AreEqual(0, notificationMessage.NotificationData.Count);

                //call ResendData method from the same session context
                m_requestHeader.Timestamp = DateTime.UtcNow;
                response = m_server.Call(m_requestHeader,
                                         nodesToCall,
                                         out results,
                                         out diagnosticInfos);

                Assert.IsTrue(StatusCode.IsGood(results[0].StatusCode));
                ServerFixtureUtils.ValidateResponse(response);

                // Data should be available for publishing now
                m_requestHeader.Timestamp = DateTime.UtcNow;
                response = serverTestServices.Publish(m_requestHeader, acknoledgements,
                                                      out publishedId, out availableSequenceNumbers,
                                                      out moreNotifications, out notificationMessage,
                                                      out StatusCodeCollection _, out diagnosticInfos);

                Assert.AreEqual(StatusCodes.Good, response.ServiceResult.Code);
                ServerFixtureUtils.ValidateResponse(response);
                ServerFixtureUtils.ValidateDiagnosticInfos(diagnosticInfos, acknoledgements);
                Assert.AreEqual(subscriptionIds[0], publishedId);
                Assert.AreEqual(1, notificationMessage.NotificationData.Count);

                // Call ResendData method with invalid subscription Id
                nodesToCall = new CallMethodRequestCollection();
                nodesToCall.Add(new CallMethodRequest()
                {
                    ObjectId       = ObjectIds.Server,
                    MethodId       = MethodIds.Server_ResendData,
                    InputArguments = new VariantCollection()
                    {
                        new Variant(subscriptionIds.Last() + 20)
                    }
                });
                m_requestHeader.Timestamp = DateTime.UtcNow;
                response = m_server.Call(m_requestHeader,
                                         nodesToCall,
                                         out results,
                                         out diagnosticInfos);

                Assert.AreEqual(StatusCodes.BadSubscriptionIdInvalid, results[0].StatusCode.Code);
                ServerFixtureUtils.ValidateResponse(response);

                // Nothing to publish since previous ResendData call did not execute
                m_requestHeader.Timestamp = DateTime.UtcNow;
                response = serverTestServices.Publish(m_requestHeader, acknoledgements,
                                                      out publishedId, out availableSequenceNumbers,
                                                      out moreNotifications, out notificationMessage,
                                                      out StatusCodeCollection _, out diagnosticInfos);

                Assert.AreEqual(StatusCodes.Good, response.ServiceResult.Code);
                ServerFixtureUtils.ValidateResponse(response);
                ServerFixtureUtils.ValidateDiagnosticInfos(diagnosticInfos, acknoledgements);
                Assert.AreEqual(subscriptionIds[0], publishedId);
                Assert.AreEqual(0, notificationMessage.NotificationData.Count);

                resendDataRequestHeader.Timestamp = DateTime.UtcNow;
                SecureChannelContext.Current      = resendDataSecurityContext;
                m_server.CloseSession(resendDataRequestHeader);
            }
            finally
            {
                //restore security context, that close connection can work
                SecureChannelContext.Current = securityContext;
            }
        }
Esempio n. 17
0
        /// <summary>
        /// Worker method to test subscriptions of a server.
        /// </summary>
        /// <param name="services"></param>
        /// <param name="requestHeader"></param>
        public static void SubscriptionTest(
            IServerTestServices services,
            RequestHeader requestHeader)
        {
            // start time
            requestHeader.Timestamp = DateTime.UtcNow;

            // create subscription
            double publishingInterval        = 1000.0;
            uint   lifetimeCount             = 60;
            uint   maxKeepAliveCount         = 2;
            uint   maxNotificationPerPublish = 0;
            byte   priority  = 128;
            bool   enabled   = false;
            uint   queueSize = 5;

            var response = services.CreateSubscription(requestHeader,
                                                       publishingInterval, lifetimeCount, maxKeepAliveCount,
                                                       maxNotificationPerPublish, enabled, priority,
                                                       out uint id, out double revisedPublishingInterval, out uint revisedLifetimeCount, out uint revisedMaxKeepAliveCount);

            Assert.AreEqual(publishingInterval, revisedPublishingInterval);
            Assert.AreEqual(lifetimeCount, revisedLifetimeCount);
            Assert.AreEqual(maxKeepAliveCount, revisedMaxKeepAliveCount);
            ServerFixtureUtils.ValidateResponse(response);

            MonitoredItemCreateRequestCollection itemsToCreate = new MonitoredItemCreateRequestCollection();
            // check badnothingtodo
            var sre = Assert.Throws <ServiceResultException>(() =>
                                                             services.CreateMonitoredItems(requestHeader, id, TimestampsToReturn.Neither, itemsToCreate,
                                                                                           out MonitoredItemCreateResultCollection mockResults, out DiagnosticInfoCollection mockInfos));

            Assert.AreEqual(StatusCodes.BadNothingToDo, sre.StatusCode);

            // add item
            uint handleCounter = 1;

            itemsToCreate.Add(new MonitoredItemCreateRequest()
            {
                ItemToMonitor = new ReadValueId()
                {
                    AttributeId = Attributes.Value,
                    NodeId      = VariableIds.Server_ServerStatus_CurrentTime
                },
                MonitoringMode      = MonitoringMode.Reporting,
                RequestedParameters = new MonitoringParameters()
                {
                    ClientHandle     = ++handleCounter,
                    SamplingInterval = -1,
                    Filter           = null,
                    DiscardOldest    = true,
                    QueueSize        = queueSize
                }
            });
            response = services.CreateMonitoredItems(requestHeader, id, TimestampsToReturn.Neither, itemsToCreate,
                                                     out MonitoredItemCreateResultCollection itemCreateResults, out DiagnosticInfoCollection diagnosticInfos);
            ServerFixtureUtils.ValidateResponse(response);
            ServerFixtureUtils.ValidateDiagnosticInfos(diagnosticInfos, itemsToCreate);

            // modify subscription
            response = services.ModifySubscription(requestHeader, id,
                                                   publishingInterval, lifetimeCount, maxKeepAliveCount,
                                                   maxNotificationPerPublish, priority,
                                                   out revisedPublishingInterval, out revisedLifetimeCount, out revisedMaxKeepAliveCount);
            Assert.AreEqual(publishingInterval, revisedPublishingInterval);
            Assert.AreEqual(lifetimeCount, revisedLifetimeCount);
            Assert.AreEqual(maxKeepAliveCount, revisedMaxKeepAliveCount);
            ServerFixtureUtils.ValidateResponse(response);

            // modify monitored item, just timestamps to return
            var itemsToModify = new MonitoredItemModifyRequestCollection();

            foreach (var itemCreated in itemCreateResults)
            {
                itemsToModify.Add(
                    new MonitoredItemModifyRequest()
                {
                    MonitoredItemId = itemCreated.MonitoredItemId
                });
            }
            ;
            response = services.ModifyMonitoredItems(requestHeader, id, TimestampsToReturn.Both, itemsToModify,
                                                     out MonitoredItemModifyResultCollection modifyResults, out diagnosticInfos);
            ServerFixtureUtils.ValidateResponse(response);
            ServerFixtureUtils.ValidateDiagnosticInfos(diagnosticInfos, itemsToModify);

            // publish request
            var acknoledgements = new SubscriptionAcknowledgementCollection();

            response = services.Publish(requestHeader, acknoledgements,
                                        out uint subscriptionId, out UInt32Collection availableSequenceNumbers,
                                        out bool moreNotifications, out NotificationMessage notificationMessage,
                                        out StatusCodeCollection statuses, out diagnosticInfos);
            ServerFixtureUtils.ValidateResponse(response);
            ServerFixtureUtils.ValidateDiagnosticInfos(diagnosticInfos, acknoledgements);
            Assert.AreEqual(id, subscriptionId);
            Assert.AreEqual(0, availableSequenceNumbers.Count);

            // enable publishing
            enabled = true;
            var subscriptions = new UInt32Collection()
            {
                id
            };

            response = services.SetPublishingMode(requestHeader, enabled, subscriptions,
                                                  out statuses, out diagnosticInfos);
            ServerFixtureUtils.ValidateResponse(response);
            ServerFixtureUtils.ValidateDiagnosticInfos(diagnosticInfos, subscriptions);

            // wait some time to fill queue
            int loopCounter = (int)queueSize;

            Thread.Sleep(loopCounter * 1000);

            acknoledgements = new SubscriptionAcknowledgementCollection();
            do
            {
                // get publish responses
                response = services.Publish(requestHeader, acknoledgements,
                                            out subscriptionId, out availableSequenceNumbers,
                                            out moreNotifications, out notificationMessage,
                                            out statuses, out diagnosticInfos);
                ServerFixtureUtils.ValidateResponse(response);
                ServerFixtureUtils.ValidateDiagnosticInfos(diagnosticInfos, acknoledgements);
                Assert.AreEqual(id, subscriptionId);

                var dataChangeNotification = notificationMessage.NotificationData[0].Body as DataChangeNotification;
                TestContext.Out.WriteLine("Notification: {0} {1} {2}",
                                          notificationMessage.SequenceNumber,
                                          dataChangeNotification?.MonitoredItems[0].Value.ToString(),
                                          notificationMessage.PublishTime);

                acknoledgements.Clear();
                acknoledgements.Add(new SubscriptionAcknowledgement()
                {
                    SubscriptionId = id,
                    SequenceNumber = notificationMessage.SequenceNumber
                });
            } while (acknoledgements.Count > 0 && --loopCounter > 0);

            // republish
            response = services.Republish(requestHeader, subscriptionId, notificationMessage.SequenceNumber, out notificationMessage);
            ServerFixtureUtils.ValidateResponse(response);

            // disable publishing
            enabled  = false;
            response = services.SetPublishingMode(requestHeader, enabled, subscriptions,
                                                  out statuses, out diagnosticInfos);
            ServerFixtureUtils.ValidateResponse(response);
            ServerFixtureUtils.ValidateDiagnosticInfos(diagnosticInfos, subscriptions);

            // delete subscription
            response = services.DeleteSubscriptions(requestHeader, subscriptions, out statuses, out diagnosticInfos);
            ServerFixtureUtils.ValidateResponse(response);
            ServerFixtureUtils.ValidateDiagnosticInfos(diagnosticInfos, subscriptions);
        }
		/// <summary>
		/// Publishes a subscription.
		/// </summary>
        public NotificationMessage Publish(
            OperationContext                      context, 
            SubscriptionAcknowledgementCollection subscriptionAcknowledgements,
            AsyncPublishOperation                 operation,
            out uint                              subscriptionId, 
            out UInt32Collection                  availableSequenceNumbers, 
            out bool                              moreNotifications, 
            out StatusCodeCollection              acknowledgeResults, 
            out DiagnosticInfoCollection          acknowledgeDiagnosticInfos)
        {
            availableSequenceNumbers = null;
            moreNotifications = false;

            // get publish queue for session.
            SessionPublishQueue queue = null;
            
            lock (m_lock)
            {
                if (!m_publishQueues.TryGetValue(context.Session.Id, out queue))
                {
                    if (m_subscriptions.Count == 0)
                    {
                        throw new ServiceResultException(StatusCodes.BadNoSubscription);
                    }

                    throw new ServiceResultException(StatusCodes.BadSessionClosed);
                }
            }

            // acknowlege previous messages.
            queue.Acknowledge(
                context,
                subscriptionAcknowledgements, 
                out acknowledgeResults,
                out acknowledgeDiagnosticInfos);
            
            // update diagnostics.
            if (context.Session != null)
            {
                lock (context.Session.DiagnosticsLock)
                {
                    SessionDiagnosticsDataType diagnostics = context.Session.SessionDiagnostics;
                    diagnostics.CurrentPublishRequestsInQueue++;
                }
            }

            // save results for asynchrounous operation.
            if (operation != null)
            {
                operation.Response.Results = acknowledgeResults;
                operation.Response.DiagnosticInfos = acknowledgeDiagnosticInfos;
            }

            // gets the next message that is ready to publish.
            NotificationMessage message = GetNextMessage(
                context,
                queue,
                operation,
                out subscriptionId,
                out availableSequenceNumbers,
                out moreNotifications);

            // if no message and no async operation then a timeout occurred.
            if (message == null && operation == null)
            {
                throw new ServiceResultException(StatusCodes.BadTimeout);
            }
            
            // return message.
            return message;
        }
Esempio n. 19
0
        /// <summary>
        /// Begins an asynchronous invocation of the Publish service.
        /// </summary>
        public IAsyncResult BeginPublish(
            RequestHeader                         requestHeader,
            SubscriptionAcknowledgementCollection subscriptionAcknowledgements,
            AsyncCallback                         callback,
            object                                asyncState)
        {
            PublishRequest request = new PublishRequest();

            request.RequestHeader                = requestHeader;
            request.SubscriptionAcknowledgements = subscriptionAcknowledgements;

            UpdateRequestHeader(request, requestHeader == null, "Publish");

            if (UseTransportChannel)
            {
                return TransportChannel.BeginSendRequest(request, callback, asyncState);
            }

            return InnerChannel.BeginPublish(new PublishMessage(request), callback, asyncState);
        }
Esempio n. 20
0
        /// <summary>
        /// Invokes the Publish service.
        /// </summary>
        public virtual ResponseHeader Publish(
            RequestHeader                         requestHeader,
            SubscriptionAcknowledgementCollection subscriptionAcknowledgements,
            out uint                              subscriptionId,
            out UInt32Collection                  availableSequenceNumbers,
            out bool                              moreNotifications,
            out NotificationMessage               notificationMessage,
            out StatusCodeCollection              results,
            out DiagnosticInfoCollection          diagnosticInfos)
        {
            PublishRequest request = new PublishRequest();
            PublishResponse response = null;

            request.RequestHeader                = requestHeader;
            request.SubscriptionAcknowledgements = subscriptionAcknowledgements;

            UpdateRequestHeader(request, requestHeader == null, "Publish");

            try
            {
                if (UseTransportChannel)
                {
                    IServiceResponse genericResponse = TransportChannel.SendRequest(request);

                    if (genericResponse == null)
                    {
                        throw new ServiceResultException(StatusCodes.BadUnknownResponse);
                    }

                    ValidateResponse(genericResponse.ResponseHeader);
                    response = (PublishResponse)genericResponse;
                }
                else
                {
                    PublishResponseMessage responseMessage = InnerChannel.Publish(new PublishMessage(request));

                    if (responseMessage == null || responseMessage.PublishResponse == null)
                    {
                        throw new ServiceResultException(StatusCodes.BadUnknownResponse);
                    }

                    response = responseMessage.PublishResponse;
                    ValidateResponse(response.ResponseHeader);
                }

                subscriptionId           = response.SubscriptionId;
                availableSequenceNumbers = response.AvailableSequenceNumbers;
                moreNotifications        = response.MoreNotifications;
                notificationMessage      = response.NotificationMessage;
                results                  = response.Results;
                diagnosticInfos          = response.DiagnosticInfos;
            }
            finally
            {
                RequestCompleted(request, response, "Publish");
            }

            return response.ResponseHeader;
        }
        /// <summary>
        /// Processes acknowledgements for previously published messages.
        /// </summary>
        public void Acknowledge(
            OperationContext                      context,
            SubscriptionAcknowledgementCollection subscriptionAcknowledgements, 
            out StatusCodeCollection              acknowledgeResults, 
            out DiagnosticInfoCollection          acknowledgeDiagnosticInfos)
        {
            if (context == null) throw new ArgumentNullException("context");
            if (subscriptionAcknowledgements == null) throw new ArgumentNullException("subscriptionAcknowledgements");

            lock (m_lock)
            {                
                bool diagnosticsExist = false;
                acknowledgeResults = new StatusCodeCollection(subscriptionAcknowledgements.Count);
                acknowledgeDiagnosticInfos = new DiagnosticInfoCollection(subscriptionAcknowledgements.Count);

                for (int ii = 0; ii < subscriptionAcknowledgements.Count; ii++)
                {
                    SubscriptionAcknowledgement acknowledgement = subscriptionAcknowledgements[ii];

                    bool found = false;
                    
                    for (int jj = 0; jj < m_queuedSubscriptions.Count; jj++)
                    {
                        QueuedSubscription subscription = m_queuedSubscriptions[jj];

                        if (subscription.Subscription.Id == acknowledgement.SubscriptionId)
                        {
                            ServiceResult result = subscription.Subscription.Acknowledge(context, acknowledgement.SequenceNumber);

                            if (ServiceResult.IsGood(result))
                            {
                                acknowledgeResults.Add(StatusCodes.Good);
                                
                                if ((context.DiagnosticsMask & DiagnosticsMasks.OperationAll) != 0)
                                {
                                    acknowledgeDiagnosticInfos.Add(null);
                                }
                            }
                            else
                            {
                                acknowledgeResults.Add(result.Code);
                                
                                if ((context.DiagnosticsMask & DiagnosticsMasks.OperationAll) != 0)
                                {                                    
                                    DiagnosticInfo diagnosticInfo = ServerUtils.CreateDiagnosticInfo(m_server, context, result);
                                    acknowledgeDiagnosticInfos.Add(diagnosticInfo);
                                    diagnosticsExist = true;
                                }
                            }

                            found = true;
                            break;
                        }
                    }

                    if (!found)
                    {
                        ServiceResult result = new ServiceResult(StatusCodes.BadSubscriptionIdInvalid);
                        acknowledgeResults.Add(result.Code);
                        
                        if ((context.DiagnosticsMask & DiagnosticsMasks.OperationAll) != 0)
                        {
                            DiagnosticInfo diagnosticInfo = ServerUtils.CreateDiagnosticInfo(m_server, context, result);
                            acknowledgeDiagnosticInfos.Add(diagnosticInfo);
                            diagnosticsExist = true;
                        }
                    }
                }

                if (!diagnosticsExist)
                {
                    acknowledgeDiagnosticInfos.Clear();
                }
            }
        }
Esempio n. 22
0
        public void ResendData(bool updateValues, uint queueSize)
        {
            var serverTestServices = new ServerTestServices(m_server);
            // save old security context, test fixture can only work with one session
            var securityContext = SecureChannelContext.Current;

            try
            {
                var namespaceUris = m_server.CurrentInstance.NamespaceUris;
                NodeIdCollection testSetCollection = CommonTestWorkers.NodeIdTestSetStatic.Select(n => ExpandedNodeId.ToNodeId(n, namespaceUris)).ToArray();
                testSetCollection.AddRange(CommonTestWorkers.NodeIdTestDataSetStatic.Select(n => ExpandedNodeId.ToNodeId(n, namespaceUris)).ToArray());
                NodeId[] testSet = testSetCollection.ToArray();

                //Re-use method CreateSubscriptionForTransfer to create a subscription
                var subscriptionIds = CommonTestWorkers.CreateSubscriptionForTransfer(serverTestServices, m_requestHeader, testSet, queueSize, 0);

                RequestHeader resendDataRequestHeader   = m_server.CreateAndActivateSession("ResendData");
                var           resendDataSecurityContext = SecureChannelContext.Current;

                SecureChannelContext.Current = securityContext;
                // After the ResendData call there will be data to publish again
                var nodesToCall = ResendDataCall(StatusCodes.Good, subscriptionIds);

                Thread.Sleep(1000);

                // Make sure publish queue becomes empty by consuming it
                Assert.AreEqual(1, subscriptionIds.Count);

                // Issue a Publish request
                m_requestHeader.Timestamp = DateTime.UtcNow;
                var acknoledgements = new SubscriptionAcknowledgementCollection();
                var response        = serverTestServices.Publish(m_requestHeader, acknoledgements,
                                                                 out uint publishedId, out UInt32Collection availableSequenceNumbers,
                                                                 out bool moreNotifications, out NotificationMessage notificationMessage,
                                                                 out StatusCodeCollection _, out DiagnosticInfoCollection diagnosticInfos);

                Assert.AreEqual(StatusCodes.Good, response.ServiceResult.Code);
                ServerFixtureUtils.ValidateResponse(response);
                ServerFixtureUtils.ValidateDiagnosticInfos(diagnosticInfos, acknoledgements);
                Assert.AreEqual(subscriptionIds[0], publishedId);
                Assert.AreEqual(1, notificationMessage.NotificationData.Count);

                // Validate nothing to publish a few times
                const int timesToCallPublish = 3;
                for (int i = 0; i < timesToCallPublish; i++)
                {
                    m_requestHeader.Timestamp = DateTime.UtcNow;
                    response = serverTestServices.Publish(m_requestHeader, acknoledgements,
                                                          out publishedId, out availableSequenceNumbers,
                                                          out moreNotifications, out notificationMessage,
                                                          out StatusCodeCollection _, out diagnosticInfos);

                    Assert.AreEqual(StatusCodes.Good, response.ServiceResult.Code);
                    ServerFixtureUtils.ValidateResponse(response);
                    ServerFixtureUtils.ValidateDiagnosticInfos(diagnosticInfos, acknoledgements);
                    Assert.AreEqual(subscriptionIds[0], publishedId);
                    Assert.AreEqual(0, notificationMessage.NotificationData.Count);
                }

                // Validate ResendData method call returns error from different session contexts

                // call ResendData method from different session context
                SecureChannelContext.Current      = resendDataSecurityContext;
                resendDataRequestHeader.Timestamp = DateTime.UtcNow;
                response = m_server.Call(resendDataRequestHeader,
                                         nodesToCall,
                                         out var results,
                                         out diagnosticInfos);

                SecureChannelContext.Current = securityContext;

                Assert.AreEqual(StatusCodes.BadUserAccessDenied, results[0].StatusCode.Code);
                ServerFixtureUtils.ValidateResponse(response);

                // Still nothing to publish since previous ResendData call did not execute
                m_requestHeader.Timestamp = DateTime.UtcNow;
                response = serverTestServices.Publish(m_requestHeader, acknoledgements,
                                                      out publishedId, out availableSequenceNumbers,
                                                      out moreNotifications, out notificationMessage,
                                                      out StatusCodeCollection _, out diagnosticInfos);

                Assert.AreEqual(StatusCodes.Good, response.ServiceResult.Code);
                ServerFixtureUtils.ValidateResponse(response);
                ServerFixtureUtils.ValidateDiagnosticInfos(diagnosticInfos, acknoledgements);
                Assert.AreEqual(subscriptionIds[0], publishedId);
                Assert.AreEqual(0, notificationMessage.NotificationData.Count);

                if (updateValues)
                {
                    UpdateValues(testSet);

                    // fill queues, but only a single value per resend publish shall be returned
                    for (int i = 1; i < queueSize; i++)
                    {
                        UpdateValues(testSet);
                    }
                }

                // call ResendData method from the same session context
                ResendDataCall(StatusCodes.Good, subscriptionIds);

                // Data should be available for publishing now
                m_requestHeader.Timestamp = DateTime.UtcNow;
                response = serverTestServices.Publish(m_requestHeader, acknoledgements,
                                                      out publishedId, out availableSequenceNumbers,
                                                      out moreNotifications, out notificationMessage,
                                                      out StatusCodeCollection _, out diagnosticInfos);

                Assert.AreEqual(StatusCodes.Good, response.ServiceResult.Code);
                ServerFixtureUtils.ValidateResponse(response);
                ServerFixtureUtils.ValidateDiagnosticInfos(diagnosticInfos, acknoledgements);
                Assert.AreEqual(subscriptionIds[0], publishedId);
                Assert.AreEqual(1, notificationMessage.NotificationData.Count);
                var items = notificationMessage.NotificationData.FirstOrDefault();
                Assert.IsTrue(items.Body is Opc.Ua.DataChangeNotification);
                var monitoredItemsCollection = ((Opc.Ua.DataChangeNotification)items.Body).MonitoredItems;
                Assert.AreEqual(testSet.Length, monitoredItemsCollection.Count);

                Thread.Sleep(1000);

                if (updateValues && queueSize > 1)
                {
                    // remaining queue Data should be sent in this publish
                    m_requestHeader.Timestamp = DateTime.UtcNow;
                    response = serverTestServices.Publish(m_requestHeader, acknoledgements,
                                                          out publishedId, out availableSequenceNumbers,
                                                          out moreNotifications, out notificationMessage,
                                                          out StatusCodeCollection _, out diagnosticInfos);

                    Assert.AreEqual(StatusCodes.Good, response.ServiceResult.Code);
                    ServerFixtureUtils.ValidateResponse(response);
                    ServerFixtureUtils.ValidateDiagnosticInfos(diagnosticInfos, acknoledgements);
                    Assert.AreEqual(subscriptionIds[0], publishedId);
                    Assert.AreEqual(1, notificationMessage.NotificationData.Count);
                    items = notificationMessage.NotificationData.FirstOrDefault();
                    Assert.IsTrue(items.Body is Opc.Ua.DataChangeNotification);
                    monitoredItemsCollection = ((Opc.Ua.DataChangeNotification)items.Body).MonitoredItems;
                    Assert.AreEqual(testSet.Length * (queueSize - 1), monitoredItemsCollection.Count, testSet.Length);
                }

                // Call ResendData method with invalid subscription Id
                ResendDataCall(StatusCodes.BadSubscriptionIdInvalid, new UInt32Collection()
                {
                    subscriptionIds.Last() + 20
                });

                // Nothing to publish since previous ResendData call did not execute
                m_requestHeader.Timestamp = DateTime.UtcNow;
                response = serverTestServices.Publish(m_requestHeader, acknoledgements,
                                                      out publishedId, out availableSequenceNumbers,
                                                      out moreNotifications, out notificationMessage,
                                                      out StatusCodeCollection _, out diagnosticInfos);

                Assert.AreEqual(StatusCodes.Good, response.ServiceResult.Code);
                ServerFixtureUtils.ValidateResponse(response);
                ServerFixtureUtils.ValidateDiagnosticInfos(diagnosticInfos, acknoledgements);
                Assert.AreEqual(subscriptionIds[0], publishedId);
                Assert.AreEqual(0, notificationMessage.NotificationData.Count);

                resendDataRequestHeader.Timestamp = DateTime.UtcNow;
                SecureChannelContext.Current      = resendDataSecurityContext;
                m_server.CloseSession(resendDataRequestHeader);
            }
            finally
            {
                //restore security context, that close connection can work
                SecureChannelContext.Current = securityContext;
            }
        }