public ResponseHeader DeleteSubscriptions( RequestHeader requestHeader, UInt32Collection subscriptionIds, out StatusCodeCollection results, out DiagnosticInfoCollection diagnosticInfos) { return(m_session.DeleteSubscriptions(requestHeader, subscriptionIds, out results, out diagnosticInfos)); }
} // Read public static unsafe uint Read(this NativeReader reader, uint offset, out UInt32Collection values) { values = new UInt32Collection(reader, offset); uint count; offset = reader.DecodeUnsigned(offset, out count); offset = checked (offset + count * sizeof(UInt32)); return(offset); } // Read
public ResponseHeader TransferSubscriptions( RequestHeader requestHeader, UInt32Collection subscriptionIds, bool sendInitialValues, out TransferResultCollection results, out DiagnosticInfoCollection diagnosticInfos) { return(m_session.TransferSubscriptions(requestHeader, subscriptionIds, sendInitialValues, out results, out diagnosticInfos)); }
public ResponseHeader SetPublishingMode( RequestHeader requestHeader, bool publishingEnabled, UInt32Collection subscriptionIds, out StatusCodeCollection results, out DiagnosticInfoCollection diagnosticInfos) { return(m_session.SetPublishingMode(requestHeader, publishingEnabled, subscriptionIds, out results, out diagnosticInfos)); }
/// <summary> /// Set monitoring mode of items. /// </summary> public async Task <List <ServiceResult> > SetMonitoringModeAsync( MonitoringMode monitoringMode, IList <MonitoredItem> monitoredItems, CancellationToken ct = default) { if (monitoredItems == null) { throw new ArgumentNullException(nameof(monitoredItems)); } VerifySubscriptionState(true); if (monitoredItems.Count == 0) { return(null); } // get list of items to update. UInt32Collection monitoredItemIds = new UInt32Collection(); foreach (MonitoredItem monitoredItem in monitoredItems) { monitoredItemIds.Add(monitoredItem.Status.Id); } var response = await m_session.SetMonitoringModeAsync( null, m_id, monitoringMode, monitoredItemIds, ct).ConfigureAwait(false); StatusCodeCollection results = response.Results; ClientBase.ValidateResponse(results, monitoredItemIds); ClientBase.ValidateDiagnosticInfos(response.DiagnosticInfos, monitoredItemIds); // update results. List <ServiceResult> errors = new List <ServiceResult>(); bool noErrors = UpdateMonitoringMode( monitoredItems, errors, results, response.DiagnosticInfos, response.ResponseHeader, monitoringMode); // raise state changed event. m_changeMask |= SubscriptionChangeMask.ItemsModified; ChangesCompleted(); // return null list if no errors occurred. if (noErrors) { return(null); } return(errors); }
/// <summary> /// Display current attribute values. /// </summary> /// <param name="nodeToRead"></param> /// <param name="attrIds"></param> /// <param name="results"></param> /// /// <param name="response"></param> private void updateAttributes( NodeId nodeToRead, UInt32Collection attrIds, DataValueCollection results, ResponseHeader response) { if (attrIds.Count != results.Count) { // Error case. return; } try { for (int i = 0; i < attrIds.Count; i++) { string attributeName = (string)attrIds[i].ToString(); string attributeValue = results[i].ToString(); string attributeStatus; // Add the attribute name / value to the list view. ListViewItem item = new ListViewItem(attributeName); // Add the value item.SubItems.Add(attributeValue); if (attrIds[i] == Attributes.Value) { m_CurrentWriteValue = new WriteValue(); m_CurrentWriteValue.AttributeId = Attributes.Value; m_CurrentWriteValue.NodeId = nodeToRead; m_CurrentWriteNodeName = nodeToRead.ToString(); m_CurrentValue = results[i].Value; } // Add status. attributeStatus = results[i].StatusCode.ToString(); if (StatusCode.IsBad(results[i].StatusCode)) { item.SubItems[0].Text = (String)attributeStatus; item.SubItems[0].ForeColor = Color.Red; } // Add item to listview. this.lvAttributes.Items.Add(item); // Fit the width of the nodeid column to the size of the header. this.lvAttributes.Columns[0].Width = -2; } } catch (Exception e) { // Update status label. OnUpdateStatusLabel("Error while processing read results: " + e.Message, false); } }
/// <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); }
public KinectFaceMeshJig() { _displayFaceMesh = false; _polygonPoints = new Point3dCollection(); _polygonPositions = new Point3dCollection(); _numPolygonPositions = new UInt32Collection(); _numPolygonPoints = new UInt32Collection(); _outlineColors = new EntityColorCollection(); _fillColors = new EntityColorCollection(); _outlineTypes = new LinetypeCollection(); _fillOpacities = new TransparencyCollection(); }
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); }
public static Entry For(UInt32Collection collection) { if (collection == null) { return(new NullEntry()); } else { ArrayEntry array = new ArrayEntry(); UInt32Collection.Enumerator e = collection.GetEnumerator(); while (e.MoveNext()) { array.Add(For(e.Current)); } return(array); } }
/// <summary> /// Deletes all items that have been marked for deletion. /// </summary> public async Task <IList <MonitoredItem> > DeleteItemsAsync(CancellationToken ct) { VerifySubscriptionState(true); if (m_deletedItems.Count == 0) { return(new List <MonitoredItem>()); } List <MonitoredItem> itemsToDelete = m_deletedItems; m_deletedItems = new List <MonitoredItem>(); UInt32Collection monitoredItemIds = new UInt32Collection(); foreach (MonitoredItem monitoredItem in itemsToDelete) { monitoredItemIds.Add(monitoredItem.Status.Id); } var response = await m_session.DeleteMonitoredItemsAsync( null, m_id, monitoredItemIds, ct).ConfigureAwait(false); StatusCodeCollection results = response.Results; ClientBase.ValidateResponse(results, monitoredItemIds); ClientBase.ValidateDiagnosticInfos(response.DiagnosticInfos, monitoredItemIds); // update results. for (int ii = 0; ii < results.Count; ii++) { itemsToDelete[ii].SetDeleteResult(results[ii], ii, response.DiagnosticInfos, response.ResponseHeader); } m_changeMask |= SubscriptionChangeMask.ItemsDeleted; ChangesCompleted(); // return the list of items affected by the change. return(itemsToDelete); }
/// <summary> /// Convert value rank and dimensions to stack values /// </summary> /// <param name="valueRank"></param> /// <param name="arrayDimensions"></param> /// <returns></returns> public static (int, UInt32Collection) ToStackValue(this ValueRank valueRank, string arrayDimensions) { switch (valueRank) { case ValueRank.Array: return(ValueRanks.OneDimension, null); case ValueRank.Scalar: return(ValueRanks.Scalar, null); case ValueRank.ScalarOrArray: return(ValueRanks.ScalarOrOneDimension, null); case ValueRank.OneOrMoreDimensions: if (string.IsNullOrEmpty(arrayDimensions)) { return(ValueRanks.OneOrMoreDimensions, null); } var tokens = arrayDimensions.Split( new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); if (tokens == null || tokens.Length < 1) { return(ValueRanks.OneOrMoreDimensions, null); } var dimensions = new UInt32Collection(); foreach (var dim in tokens) { try { dimensions.Add(Convert.ToUInt32(dim)); } catch { dimensions.Add(0); } } return(dimensions.Count, dimensions); default: return(ValueRanks.Any, null); } }
/// <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); } }
public static uint[] ToArray(this UInt32Collection collection, Type enumType = null) { int count = collection.Count; uint[] result; if (enumType != null) { Debug.Assert(enumType.IsEnum); result = (uint[])Array.CreateInstance(enumType, count); } else { result = new uint[count]; } int i = 0; foreach (uint element in collection) { result[i++] = element; } Debug.Assert(i == count); return(result); }
/// <summary> /// Updates the triggers for the monitored item. /// </summary> public void SetTriggering( OperationContext context, uint triggeringItemId, UInt32Collection linksToAdd, UInt32Collection linksToRemove, out StatusCodeCollection addResults, out DiagnosticInfoCollection addDiagnosticInfos, out StatusCodeCollection removeResults, out DiagnosticInfoCollection removeDiagnosticInfos) { if (context == null) throw new ArgumentNullException("context"); if (linksToAdd == null) throw new ArgumentNullException("linksToAdd"); if (linksToRemove == null) throw new ArgumentNullException("linksToRemove"); // allocate results. bool diagnosticsExist = false; addResults = new StatusCodeCollection(); addDiagnosticInfos = null; removeResults = new StatusCodeCollection(); removeDiagnosticInfos = null; if ((context.DiagnosticsMask & DiagnosticsMasks.OperationAll) != 0) { addDiagnosticInfos = new DiagnosticInfoCollection(); removeDiagnosticInfos = new DiagnosticInfoCollection(); } // build list of items to modify. lock (m_lock) { // check session. VerifySession(context); // clear lifetime counter. ResetLifetimeCount(); // look up triggering item. LinkedListNode<IMonitoredItem> triggerNode = null; if (!m_monitoredItems.TryGetValue(triggeringItemId, out triggerNode)) { throw new ServiceResultException(StatusCodes.BadMonitoredItemIdInvalid); } // lookup existing list. List<ITriggeredMonitoredItem> triggeredItems = null; if (!m_itemsToTrigger.TryGetValue(triggeringItemId, out triggeredItems)) { m_itemsToTrigger[triggeringItemId] = triggeredItems = new List<ITriggeredMonitoredItem>(); } // remove old links. for (int ii = 0; ii < linksToRemove.Count; ii++) { removeResults.Add(StatusCodes.Good); bool found = false; for (int jj = 0; jj < triggeredItems.Count; jj++) { if (triggeredItems[jj].Id == linksToRemove[ii]) { found = true; triggeredItems.RemoveAt(jj); break; } } if (!found) { removeResults[ii] = StatusCodes.BadMonitoredItemIdInvalid; // update diagnostics. if ((context.DiagnosticsMask & DiagnosticsMasks.OperationAll) != 0) { DiagnosticInfo diagnosticInfo = ServerUtils.CreateDiagnosticInfo(m_server, context, removeResults[ii]); diagnosticsExist = true; removeDiagnosticInfos.Add(diagnosticInfo); } continue; } // update diagnostics. if ((context.DiagnosticsMask & DiagnosticsMasks.OperationAll) != 0) { removeDiagnosticInfos.Add(null); } } // add new links. for (int ii = 0; ii < linksToAdd.Count; ii++) { addResults.Add(StatusCodes.Good); LinkedListNode<IMonitoredItem> node = null; if (!m_monitoredItems.TryGetValue(linksToAdd[ii], out node)) { addResults[ii] = StatusCodes.BadMonitoredItemIdInvalid; // update diagnostics. if ((context.DiagnosticsMask & DiagnosticsMasks.OperationAll) != 0) { DiagnosticInfo diagnosticInfo = ServerUtils.CreateDiagnosticInfo(m_server, context, addResults[ii]); diagnosticsExist = true; addDiagnosticInfos.Add(diagnosticInfo); } continue; } // check if triggering interface is supported. ITriggeredMonitoredItem triggeredItem = node.Value as ITriggeredMonitoredItem; if (triggeredItem == null) { addResults[ii] = StatusCodes.BadNotSupported; // update diagnostics. if ((context.DiagnosticsMask & DiagnosticsMasks.OperationAll) != 0) { DiagnosticInfo diagnosticInfo = ServerUtils.CreateDiagnosticInfo(m_server, context, addResults[ii]); diagnosticsExist = true; addDiagnosticInfos.Add(diagnosticInfo); } continue; } // add value if not already in list. bool found = false; for (int jj = 0; jj < triggeredItems.Count; jj++) { if (triggeredItems[jj].Id == triggeredItem.Id) { found = true; break; } } if (!found) { triggeredItems.Add(triggeredItem); } // update diagnostics. if ((context.DiagnosticsMask & DiagnosticsMasks.OperationAll) != 0) { addDiagnosticInfos.Add(null); } } // remove an empty list. if (triggeredItems.Count == 0) { m_itemsToTrigger.Remove(triggeringItemId); } // clear diagnostics if not required. if (!diagnosticsExist) { if (addDiagnosticInfos != null) addDiagnosticInfos.Clear(); if (removeDiagnosticInfos != null) removeDiagnosticInfos.Clear(); } } }
/// <summary> /// Invokes the DeleteSubscriptions service. /// </summary> public virtual ResponseHeader DeleteSubscriptions( RequestHeader requestHeader, UInt32Collection subscriptionIds, out StatusCodeCollection results, out DiagnosticInfoCollection diagnosticInfos) { results = null; diagnosticInfos = null; ValidateRequest(requestHeader); // Insert implementation. return CreateResponse(requestHeader, StatusCodes.BadServiceUnsupported); }
/// <summary> /// Invokes the SetTriggering service. /// </summary> public virtual ResponseHeader SetTriggering( RequestHeader requestHeader, uint subscriptionId, uint triggeringItemId, UInt32Collection linksToAdd, UInt32Collection linksToRemove, out StatusCodeCollection addResults, out DiagnosticInfoCollection addDiagnosticInfos, out StatusCodeCollection removeResults, out DiagnosticInfoCollection removeDiagnosticInfos) { addResults = null; addDiagnosticInfos = null; removeResults = null; removeDiagnosticInfos = null; ValidateRequest(requestHeader); // Insert implementation. return CreateResponse(requestHeader, StatusCodes.BadServiceUnsupported); }
/// <summary> /// Reads a uint array from the stream. /// </summary> public UInt32Collection ReadUInt32Array(string fieldName) { bool isNil = false; UInt32Collection values = new UInt32Collection(); if (BeginField(fieldName, true, out isNil)) { PushNamespace(Namespaces.OpcUaXsd); while (MoveToElement("UInt32")) { values.Add(ReadUInt32("UInt32")); } // check the length. if (m_context.MaxArrayLength > 0 && m_context.MaxArrayLength < values.Count) { throw new ServiceResultException(StatusCodes.BadEncodingLimitsExceeded); } PopNamespace(); EndField(fieldName); return values; } if (isNil) { return null; } return values; }
/// <summary> /// Invokes the SetTriggering service. /// </summary> /// <param name="requestHeader">The request header.</param> /// <param name="subscriptionId">The subscription id.</param> /// <param name="triggeringItemId">The id for the MonitoredItem used as the triggering item.</param> /// <param name="linksToAdd">The list of ids of the items to report that are to be added as triggering links.</param> /// <param name="linksToRemove">The list of ids of the items to report for the triggering links to be deleted.</param> /// <param name="addResults">The list of StatusCodes for the items to add.</param> /// <param name="addDiagnosticInfos">The list of diagnostic information for the links to add.</param> /// <param name="removeResults">The list of StatusCodes for the items to delete.</param> /// <param name="removeDiagnosticInfos">The list of diagnostic information for the links to delete.</param> /// <returns> /// Returns a <see cref="ResponseHeader"/> object /// </returns> public override ResponseHeader SetTriggering( RequestHeader requestHeader, uint subscriptionId, uint triggeringItemId, UInt32Collection linksToAdd, UInt32Collection linksToRemove, out StatusCodeCollection addResults, out DiagnosticInfoCollection addDiagnosticInfos, out StatusCodeCollection removeResults, out DiagnosticInfoCollection removeDiagnosticInfos) { addResults = null; addDiagnosticInfos = null; removeResults = null; removeDiagnosticInfos = null; OperationContext context = ValidateRequest(requestHeader, RequestType.SetTriggering); try { if ((linksToAdd == null || linksToAdd.Count == 0) && (linksToRemove == null || linksToRemove.Count == 0)) { throw new ServiceResultException(StatusCodes.BadNothingToDo); } ServerInternal.SubscriptionManager.SetTriggering( context, subscriptionId, triggeringItemId, linksToAdd, linksToRemove, out addResults, out addDiagnosticInfos, out removeResults, out removeDiagnosticInfos); 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); } }
/// <summary> /// Writes the value of an attribute. /// </summary> /// <param name="attributeId">The attribute id.</param> /// <param name="value">The value.</param> /// <returns>The result of write operation.</returns> protected override ServiceResult Write(uint attributeId, object value) { switch (attributeId) { case Attributes.AccessLevel: { m_accessLevel = (byte)value; return ServiceResult.Good; } case Attributes.UserAccessLevel: { m_userAccessLevel = (byte)value; return ServiceResult.Good; } case Attributes.MinimumSamplingInterval: { m_minimumSamplingInterval = (int)value; return ServiceResult.Good; } case Attributes.Historizing: { m_historizing = (bool)value; return ServiceResult.Good; } // values are copied when the are written so then can be safely returned on read. case Attributes.Value: { m_value.Value = Utils.Clone(value); return ServiceResult.Good; } case Attributes.DataType: { NodeId dataType = (NodeId)value; // must ensure the value is of the correct datatype. if (dataType != m_dataType) { m_value.Value = TypeInfo.GetDefaultValue(dataType, m_valueRank); } m_dataType = dataType; return ServiceResult.Good; } case Attributes.ValueRank: { int valueRank = (int)value; if (valueRank != m_valueRank) { m_value.Value = TypeInfo.GetDefaultValue(m_dataType, valueRank); } m_valueRank = valueRank; return ServiceResult.Good; } case Attributes.ArrayDimensions: { m_arrayDimensions = new UInt32Collection((uint[])value); // ensure number of dimensions is correct. if (m_arrayDimensions.Count > 0) { if (m_arrayDimensions.Count != m_valueRank) { m_valueRank = m_arrayDimensions.Count; m_value.Value = TypeInfo.GetDefaultValue(m_dataType, m_valueRank); } } return ServiceResult.Good; } } return base.Write(attributeId, value); }
/// <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); } }
/// <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); }
} // Read public static unsafe uint Read(this NativeReader reader, uint offset, out UInt32Collection values) { values = new UInt32Collection(reader, offset); uint count; offset = reader.DecodeUnsigned(offset, out count); offset = checked(offset + count * sizeof(UInt32)); return offset; } // Read
/// <summary> /// Reads a uint array from the stream. /// </summary> public UInt32Collection ReadUInt32Array(string fieldName) { int length = ReadArrayLength(); if (length == -1) { return null; } UInt32Collection values = new UInt32Collection(length); for (int ii = 0; ii < length; ii++) { values.Add(ReadUInt32(null)); } return values; }
/// <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> /// Begins an asynchronous invocation of the DeleteSubscriptions service. /// </summary> public IAsyncResult BeginDeleteSubscriptions( RequestHeader requestHeader, UInt32Collection subscriptionIds, AsyncCallback callback, object asyncState) { DeleteSubscriptionsRequest request = new DeleteSubscriptionsRequest(); request.RequestHeader = requestHeader; request.SubscriptionIds = subscriptionIds; UpdateRequestHeader(request, requestHeader == null, "DeleteSubscriptions"); if (UseTransportChannel) { return TransportChannel.BeginSendRequest(request, callback, asyncState); } return InnerChannel.BeginDeleteSubscriptions(new DeleteSubscriptionsMessage(request), callback, asyncState); }
/// <summary> /// Invokes the DeleteSubscriptions service. /// </summary> public virtual ResponseHeader DeleteSubscriptions( RequestHeader requestHeader, UInt32Collection subscriptionIds, out StatusCodeCollection results, out DiagnosticInfoCollection diagnosticInfos) { DeleteSubscriptionsRequest request = new DeleteSubscriptionsRequest(); DeleteSubscriptionsResponse response = null; request.RequestHeader = requestHeader; request.SubscriptionIds = subscriptionIds; UpdateRequestHeader(request, requestHeader == null, "DeleteSubscriptions"); try { if (UseTransportChannel) { IServiceResponse genericResponse = TransportChannel.SendRequest(request); if (genericResponse == null) { throw new ServiceResultException(StatusCodes.BadUnknownResponse); } ValidateResponse(genericResponse.ResponseHeader); response = (DeleteSubscriptionsResponse)genericResponse; } else { DeleteSubscriptionsResponseMessage responseMessage = InnerChannel.DeleteSubscriptions(new DeleteSubscriptionsMessage(request)); if (responseMessage == null || responseMessage.DeleteSubscriptionsResponse == null) { throw new ServiceResultException(StatusCodes.BadUnknownResponse); } response = responseMessage.DeleteSubscriptionsResponse; ValidateResponse(response.ResponseHeader); } results = response.Results; diagnosticInfos = response.DiagnosticInfos; } finally { RequestCompleted(request, response, "DeleteSubscriptions"); } return response.ResponseHeader; }
/// <summary> /// Deletes the monitored items in a subscription. /// </summary> private void DeleteMonitoredItems( OperationContext context, UInt32Collection monitoredItemIds, bool doNotCheckSession, out StatusCodeCollection results, out DiagnosticInfoCollection diagnosticInfos) { if (context == null) throw new ArgumentNullException("context"); if (monitoredItemIds == null) throw new ArgumentNullException("monitoredItemIds"); int count = monitoredItemIds.Count; bool diagnosticsExist = false; results = new StatusCodeCollection(count); diagnosticInfos = null; if ((context.DiagnosticsMask & DiagnosticsMasks.OperationAll) != 0) { diagnosticInfos = new DiagnosticInfoCollection(count); } // build list of items to modify. List<IMonitoredItem> monitoredItems = new List<IMonitoredItem>(count); List<ServiceResult> errors = new List<ServiceResult>(count); double[] originalSamplingIntervals = new double[count]; MonitoringMode[] originalMonitoringModes = new MonitoringMode[count]; bool validItems = false; lock (m_lock) { // check session. if (!doNotCheckSession) { VerifySession(context); } // clear lifetime counter. ResetLifetimeCount(); for (int ii = 0; ii < count; ii++) { LinkedListNode<IMonitoredItem> node = null; if (!m_monitoredItems.TryGetValue(monitoredItemIds[ii], out node)) { monitoredItems.Add(null); errors.Add(StatusCodes.BadMonitoredItemIdInvalid); // update diagnostics. if ((context.DiagnosticsMask & DiagnosticsMasks.OperationAll) != 0) { DiagnosticInfo diagnosticInfo = ServerUtils.CreateDiagnosticInfo(m_server, context, errors[ii]); diagnosticsExist = true; diagnosticInfos.Add(diagnosticInfo); } continue; } IMonitoredItem monitoredItem = node.Value; monitoredItems.Add(monitoredItem); // remove the item from the internal lists. m_monitoredItems.Remove(monitoredItemIds[ii]); m_itemsToTrigger.Remove(monitoredItemIds[ii]); //remove the links towards the deleted monitored item List<ITriggeredMonitoredItem> triggeredItems = null; foreach (KeyValuePair<uint, List<ITriggeredMonitoredItem>> item in m_itemsToTrigger) { triggeredItems = item.Value; for (int jj = 0; jj < triggeredItems.Count; jj++) { if (triggeredItems[jj].Id == monitoredItemIds[ii]) { triggeredItems.RemoveAt(jj); break; } } } if (node.List != null) { node.List.Remove(node); } originalSamplingIntervals[ii] = monitoredItem.SamplingInterval; originalMonitoringModes[ii] = monitoredItem.MonitoringMode; errors.Add(null); validItems = true; // update diagnostics. if ((context.DiagnosticsMask & DiagnosticsMasks.OperationAll) != 0) { diagnosticInfos.Add(null); } } } // update items. if (validItems) { m_server.NodeManager.DeleteMonitoredItems( context, m_id, monitoredItems, errors); } lock (m_lock) { // update diagnostics. for (int ii = 0; ii < errors.Count; ii++) { ServiceResult error = errors[ii]; if (error == null) { results.Add(StatusCodes.Good); } else { results.Add(error.StatusCode); } // update diagnostics. if (ServiceResult.IsGood(error)) { RemoveItemToSamplingInterval(originalSamplingIntervals[ii], originalMonitoringModes[ii]); } if ((context.DiagnosticsMask & DiagnosticsMasks.OperationAll) != 0) { if (error != null && error.Code != StatusCodes.Good) { diagnosticInfos[ii] = ServerUtils.CreateDiagnosticInfo(m_server, context, error); diagnosticsExist = true; } } } // clear diagnostics if not required. if (!diagnosticsExist && diagnosticInfos != null) { diagnosticInfos.Clear(); } // update diagnostics. lock (m_diagnostics) { m_diagnostics.MonitoredItemCount = 0; m_diagnostics.DisabledMonitoredItemCount = 0; } // TraceState("ITEMS DELETED"); } }
//This test doesn't deterministically prove sequential publishing, but rather relies on a subscription not being able to handle the message load. //This test should be re-implemented with a Session that deterministically provides the wrong order of messages to Subscription. public void SequentialPublishingSubscription(bool enabled) { var subscriptionList = new List <Subscription>(); var sequenceBroken = new AutoResetEvent(false); var numOfNotifications = 0L; const int TestWaitTime = 10000; const int MonitoredItemsPerSubscription = 500; const int Subscriptions = 10; for (int i = 0; i < Subscriptions; i++) { var subscription = new Subscription(m_session.DefaultSubscription) { SequentialPublishing = enabled, PublishingInterval = 0, DisableMonitoredItemCache = true, //Not needed PublishingEnabled = false }; subscriptionList.Add(subscription); //Create many monitored items on the server status current time, and track the last reported source timestamp var list = Enumerable.Range(1, MonitoredItemsPerSubscription).Select(_ => new MonitoredItem(subscription.DefaultItem) { StartNodeId = new NodeId("Scalar_Simulation_Int32", 2), SamplingInterval = 0, }).ToList(); var dict = list.ToDictionary(item => item.ClientHandle, _ => DateTime.MinValue); subscription.AddItems(list); var result = m_session.AddSubscription(subscription); Assert.True(result); subscription.Create(); var publishInterval = (int)subscription.CurrentPublishingInterval; TestContext.Out.WriteLine($"CurrentPublishingInterval: {publishInterval}"); //Need to realize test failed, assert needs to be brought to this thread subscription.FastDataChangeCallback = (_, notification, __) => { notification.MonitoredItems.ForEach(item => { Interlocked.Increment(ref numOfNotifications); if (dict[item.ClientHandle] > item.Value.SourceTimestamp) { sequenceBroken.Set(); //Out of order encountered } dict[item.ClientHandle] = item.Value.SourceTimestamp; }); }; } UInt32Collection subscriptionIds = new UInt32Collection(); foreach (var subscription in subscriptionList) { subscriptionIds.Add(subscription.Id); } var stopwatch = Stopwatch.StartNew(); // start m_session.SetPublishingMode(null, true, subscriptionIds, out var results, out var diagnosticInfos); // Wait for out-of-order to occur var failed = sequenceBroken.WaitOne(TestWaitTime); // stop m_session.SetPublishingMode(null, false, subscriptionIds, out results, out diagnosticInfos); //Log information var elapsed = stopwatch.Elapsed.TotalMilliseconds / 1000.0; TestContext.Out.WriteLine($"Ran for: {elapsed:N} seconds"); long totalNotifications = Interlocked.Read(ref numOfNotifications); double notificationRate = totalNotifications / elapsed; foreach (var subscription in subscriptionList) { int outstandingMessageWorkers = subscription.OutstandingMessageWorkers; TestContext.Out.WriteLine($"Id: {subscription.Id} Outstanding workers: {outstandingMessageWorkers}"); } TestContext.Out.WriteLine($"Number of notifications: {totalNotifications:N0}"); TestContext.Out.WriteLine($"Notifications rate: {notificationRate:N} per second"); //How fast it processed notifications. Assert.NotZero(totalNotifications); //No notifications means nothing worked if (enabled) { //catch if Out-of-sequence occurred Assert.False(failed); } var notificationsPerSecond = Subscriptions * MonitoredItemsPerSubscription; Assert.AreEqual(notificationsPerSecond * (elapsed + 0.5), totalNotifications, notificationsPerSecond); foreach (var subscription in subscriptionList) { var result = m_session.RemoveSubscription(subscription); Assert.True(result); } }
/// <summary> /// Returns all available notifications. /// </summary> public NotificationMessage Publish( OperationContext context, out UInt32Collection availableSequenceNumbers, out bool moreNotifications) { if (context == null) throw new ArgumentNullException("context"); NotificationMessage message = null; lock (m_lock) { moreNotifications = false; availableSequenceNumbers = null; // check if expired. if (m_expired) { return null; } try { // update diagnostics. lock (m_diagnostics) { m_diagnostics.PublishRequestCount++; } message = InnerPublish(context, out availableSequenceNumbers, out moreNotifications); lock (m_diagnostics) { m_diagnostics.UnacknowledgedMessageCount = (uint)availableSequenceNumbers.Count; } } finally { // clear counters on success. if (message != null) { // TraceState(Utils.Format("PUBLISH #{0}", message.SequenceNumber)); ResetKeepaliveCount(); m_waitingForPublish = moreNotifications; ResetLifetimeCount(); } } } return message; }
/// <summary> /// Writes the value of an attribute. /// </summary> /// <param name="attributeId">The attribute id.</param> /// <param name="value">The value.</param> /// <returns>The result of write operation.</returns> protected override ServiceResult Write(uint attributeId, object value) { switch (attributeId) { // values are copied when the are written so then can be safely returned on read. case Attributes.Value: { m_value.Value = Utils.Clone(value); return ServiceResult.Good; } case Attributes.DataType: { NodeId dataType = (NodeId)value; // must ensure the value is of the correct datatype. if (dataType != m_dataType) { m_value.Value = null; } m_dataType = dataType; return ServiceResult.Good; } case Attributes.ValueRank: { int valueRank = (int)value; if (valueRank != m_valueRank) { m_value.Value = null; } m_valueRank = valueRank; return ServiceResult.Good; } case Attributes.ArrayDimensions: { m_arrayDimensions = new UInt32Collection((uint[])value); // ensure number of dimensions is correct. if (m_arrayDimensions.Count > 0) { if (m_valueRank != m_arrayDimensions.Count) { m_valueRank = m_arrayDimensions.Count; m_value.Value = null; } } return ServiceResult.Good; } } return base.Write(attributeId, value); }
/// <summary> /// Begins an asynchronous invocation of the SetPublishingMode service. /// </summary> public IAsyncResult BeginSetPublishingMode( RequestHeader requestHeader, bool publishingEnabled, UInt32Collection subscriptionIds, AsyncCallback callback, object asyncState) { SetPublishingModeRequest request = new SetPublishingModeRequest(); request.RequestHeader = requestHeader; request.PublishingEnabled = publishingEnabled; request.SubscriptionIds = subscriptionIds; UpdateRequestHeader(request, requestHeader == null, "SetPublishingMode"); if (UseTransportChannel) { return TransportChannel.BeginSendRequest(request, callback, asyncState); } return InnerChannel.BeginSetPublishingMode(new SetPublishingModeMessage(request), callback, asyncState); }
/// <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); } }
/// <summary> /// Deletes all of the active subscriptions. /// </summary> private bool DeleteSubscriptions() { try { UInt32Collection subscriptionIds = new UInt32Collection(); lock (m_subscriptions) { for (int ii = 0; ii < m_subscriptions.Count; ii++) { Subscription subscription = m_subscriptions[ii]; lock (subscription) { subscriptionIds.Add(subscription.SubscriptionId); subscription.Deleted = true; } } } RequestHeader requestHeader = new RequestHeader(); requestHeader.ReturnDiagnostics = 0; StatusCodeCollection results; DiagnosticInfoCollection diagnosticInfos; ResponseHeader responseHeader = Session.DeleteSubscriptions( requestHeader, subscriptionIds, out results, out diagnosticInfos); ClientBase.ValidateResponse(results, subscriptionIds); ClientBase.ValidateDiagnosticInfos(diagnosticInfos, subscriptionIds); if (diagnosticInfos != null && diagnosticInfos.Count > 0) { Log("Returned non-empty DiagnosticInfos array during DeleteSubscriptions."); return false; } bool success = true; lock (m_subscriptions) { for (int ii = 0; ii < m_subscriptions.Count; ii++) { if (StatusCode.IsBad(results[ii])) { Log( "Unexpected error deleting subscription {0}. StatusCode = {1}", subscriptionIds[ii], subscriptionIds); success = false; } Subscription subscription = m_subscriptions[ii]; lock (subscription) { subscription.States[subscription.States.Count - 1].End = responseHeader.Timestamp; } } } // let the queue empty. Thread.Sleep(1000); return success; } catch (Exception e) { Log(e, "DeleteSubscriptions Failed."); return false; } }
/// <summary> /// Invokes the SetMonitoringMode service. /// </summary> /// <param name="requestHeader">The request header.</param> /// <param name="subscriptionId">The subscription id.</param> /// <param name="monitoringMode">The monitoring mode to be set for the MonitoredItems.</param> /// <param name="monitoredItemIds">The list of MonitoredItems to modify.</param> /// <param name="results">The list of results for the MonitoredItems to modify.</param> /// <param name="diagnosticInfos">The diagnostic information for the results.</param> /// <returns> /// Returns a <see cref="ResponseHeader"/> object /// </returns> public override ResponseHeader SetMonitoringMode( RequestHeader requestHeader, uint subscriptionId, MonitoringMode monitoringMode, UInt32Collection monitoredItemIds, out StatusCodeCollection results, out DiagnosticInfoCollection diagnosticInfos) { OperationContext context = ValidateRequest(requestHeader, RequestType.SetMonitoringMode); try { if (monitoredItemIds == null || monitoredItemIds.Count == 0) { throw new ServiceResultException(StatusCodes.BadNothingToDo); } ServerInternal.SubscriptionManager.SetMonitoringMode( context, subscriptionId, monitoringMode, monitoredItemIds, out results, out diagnosticInfos); 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); } }
/// <summary> /// Sets the publishing enable state for the subscriptions. /// </summary> private bool SetPublishingEnabled(bool enabled) { try { UInt32Collection subscriptionIds = new UInt32Collection(); lock (m_subscriptions) { for (int ii = 0; ii < m_subscriptions.Count; ii++) { subscriptionIds.Add(m_subscriptions[ii].SubscriptionId); m_subscriptions[ii].PublishingEnabled = enabled; } } RequestHeader requestHeader = new RequestHeader(); requestHeader.ReturnDiagnostics = 0; StatusCodeCollection results; DiagnosticInfoCollection diagnosticInfos; Session.SetPublishingMode( requestHeader, enabled, subscriptionIds, out results, out diagnosticInfos); ClientBase.ValidateResponse(results, subscriptionIds); ClientBase.ValidateDiagnosticInfos(diagnosticInfos, subscriptionIds); if (diagnosticInfos != null && diagnosticInfos.Count > 0) { Log("Returned non-empty DiagnosticInfos array during SetPublishingMode."); return false; } bool success = true; for (int ii = 0; ii < results.Count; ii++) { if (StatusCode.IsBad(results[ii])) { Log( "Unexpected error setting publish enable state for subscription {0}. StatusCode = {1}", subscriptionIds[ii], subscriptionIds); success = false; } } return success; } catch (Exception e) { Log(e, "SetPublishingMode Failed."); return false; } }
/// <summary> /// Invokes the SetMonitoringMode service. /// </summary> public virtual ResponseHeader SetMonitoringMode( RequestHeader requestHeader, uint subscriptionId, MonitoringMode monitoringMode, UInt32Collection monitoredItemIds, out StatusCodeCollection results, out DiagnosticInfoCollection diagnosticInfos) { results = null; diagnosticInfos = null; ValidateRequest(requestHeader); // Insert implementation. return CreateResponse(requestHeader, StatusCodes.BadServiceUnsupported); }
/// <summary> /// Verifies the result of a publish /// </summary> private bool VerifyPublishResponse( ResponseHeader responseHeader, Subscription subscription, UInt32Collection availableSequenceNumbers, bool moreNotifications, NotificationMessage notificationMessage, StatusCodeCollection results, DiagnosticInfoCollection diagnosticInfos) { /* Utils.Trace( "PublishReceived: SubId={0} SeqNo={1}, PublishTime={2:mm:ss.fff}, Time={3:mm:ss.fff}", subscription.SubscriptionId, notificationMessage.SequenceNumber, notificationMessage.PublishTime, DateTime.UtcNow); */ // check if there is an odd delay. if (responseHeader.Timestamp > notificationMessage.PublishTime.AddMilliseconds(100)) { Log( "WARNING. Unexpected delay between PublishTime and ResponseTime. SeqNo={0}, PublishTime={1:hh:mm:ss.fff}, ResponseTime={2:hh:mm:ss.fff}", notificationMessage.SequenceNumber, notificationMessage.PublishTime, responseHeader.Timestamp); } // save results. subscription.AvailableSequenceNumbers = availableSequenceNumbers; if (notificationMessage.NotificationData.Count == 0) { // keep alives do not increment the sequence number. if (subscription.NextExpectedSequenceNumber != notificationMessage.SequenceNumber) { Log( "Incorrect sequence number for keep alive. SubscriptionId = {0}, Actual = {1}, Expected = {2}", subscription.SubscriptionId, notificationMessage.SequenceNumber, subscription.NextExpectedSequenceNumber); subscription.Failed = true; return false; } // save the message. DateTime timestamp = responseHeader.Timestamp; DateTime start = subscription.States[subscription.States.Count - 1].Start; // check if this is an old request being processed late. if (start > timestamp && subscription.States.Count > 1) { subscription.States[subscription.States.Count - 2].KeepAlives.Add(timestamp); } else { subscription.States[subscription.States.Count - 1].KeepAlives.Add(timestamp); } } else { // check for replays. if (subscription.NextExpectedSequenceNumber > notificationMessage.SequenceNumber) { // check for out of order responses. bool found = false; for (int ii = 0; ii < subscription.MissingSequenceNumbers.Count; ii++) { if (subscription.MissingSequenceNumbers[ii] == notificationMessage.SequenceNumber) { subscription.MissingSequenceNumbers.RemoveAt(ii); found = true; break; } } // oops - duplicate. if (!found) { Log( "Duplicate sequence number for message. SubscriptionId = {0}, Actual = {1}, Expected = {2}", subscription.SubscriptionId, notificationMessage.SequenceNumber, subscription.NextExpectedSequenceNumber); subscription.Failed = true; return false; } } // increment message counter. if (notificationMessage.SequenceNumber >= subscription.NextExpectedSequenceNumber) { for (uint ii = subscription.NextExpectedSequenceNumber; ii < notificationMessage.SequenceNumber; ii++) { if (!subscription.MissingSequenceNumbers.Contains(ii)) { subscription.MissingSequenceNumbers.Add(ii); } } subscription.NextExpectedSequenceNumber = notificationMessage.SequenceNumber+1; } // save the largest received message number (gap exist because of client side threading issues). if (subscription.LastReceivedSequenceNumber < notificationMessage.SequenceNumber) { subscription.LastReceivedSequenceNumber = notificationMessage.SequenceNumber; } // save the message. DateTime timestamp = responseHeader.Timestamp; DateTime start = subscription.States[subscription.States.Count-1].Start; // check if this is an old request being processed late. if (start > timestamp && subscription.States.Count > 1) { subscription.States[subscription.States.Count - 2].KeepAlives.Add(timestamp); } else { subscription.States[subscription.States.Count - 1].KeepAlives.Add(timestamp); } subscription.NotificationMessages.Add(notificationMessage); subscription.ReceiveTimes.Add(responseHeader.Timestamp); // change to keep alive mode. if (subscription.StaticData) { PublishingState state = new PublishingState(); state.KeepAliveCount = subscription.KeepAliveCount; state.PublishingInterval = subscription.PublishingInterval; state.Start = timestamp; state.KeepAliveMode = true; subscription.States[subscription.States.Count-1].End = state.Start; subscription.States.Add(state); } // save the acknowlegements. SaveAcknowledgement(subscription.SubscriptionId, notificationMessage.SequenceNumber); } return true; }
/// <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> /// Toggles the monitoring mode for the items. /// </summary> private bool ToogleDisabledState(Subscription subscription, List<MonitoredItem> monitoredItems) { UInt32Collection monitoredItemIds = new UInt32Collection(); lock (subscription) { subscription.NotificationMessages.Clear(); subscription.ReceiveTimes.Clear(); for (int ii = 0; ii < monitoredItems.Count; ii++) { monitoredItemIds.Add(monitoredItems[ii].MonitoredItemId); monitoredItems[ii].Value = null; } } StatusCodeCollection results = null; DiagnosticInfoCollection diagnosticInfos = null; Session.SetMonitoringMode( null, subscription.SubscriptionId, MonitoringMode.Disabled, monitoredItemIds, out results, out diagnosticInfos); ClientBase.ValidateResponse(results, monitoredItemIds); ClientBase.ValidateDiagnosticInfos(diagnosticInfos, monitoredItemIds); lock (subscription) { for (int ii = 0; ii < results.Count; ii++) { if (StatusCode.IsBad(results[ii])) { Log( "Error disabling MonitoredItem. ClientHandle = {0}, Node = {1}, Attribute = {2}, StatusCode = {3}", monitoredItems[ii].MonitoredItemId, monitoredItems[ii].Node, Attributes.GetBrowseName(monitoredItems[ii].AttributeId), results[ii]); return false; } } } ResponseHeader responseHeader = Session.SetMonitoringMode( null, subscription.SubscriptionId, MonitoringMode.Reporting, monitoredItemIds, out results, out diagnosticInfos); ClientBase.ValidateResponse(results, monitoredItemIds); ClientBase.ValidateDiagnosticInfos(diagnosticInfos, monitoredItemIds); lock (subscription) { for (int ii = 0; ii < results.Count; ii++) { if (StatusCode.IsBad(results[ii])) { Log( "Error enabling MonitoredItem. ClientHandle = {0}, Node = {1}, Attribute = {2}, StatusCode = {3}", monitoredItems[ii].MonitoredItemId, monitoredItems[ii].Node, Attributes.GetBrowseName(monitoredItems[ii].AttributeId), results[ii]); return false; } monitoredItems[ii].UpdateTime = responseHeader.Timestamp; } } return true; }
/// <remarks> /// This test doesn't deterministically prove sequential publishing, /// but rather relies on a subscription not being able to handle the message load. /// This test should be re-implemented with a Session that deterministically /// provides the wrong order of messages to Subscription. ///</remarks> public void SequentialPublishingSubscription(bool enabled) { var subscriptionList = new List <Subscription>(); var subscriptionIds = new UInt32Collection(); var sequenceBroken = new AutoResetEvent(false); var numOfNotifications = 0L; const int TestWaitTime = 10000; const int MonitoredItemsPerSubscription = 500; const int Subscriptions = 10; // multiple Subscriptions to enforce multiple queued publish requests for (int i = 0; i < Subscriptions; i++) { var s = new Subscription(m_session.DefaultSubscription) { SequentialPublishing = enabled, PublishingInterval = 0, DisableMonitoredItemCache = true, //Not needed PublishingEnabled = false }; subscriptionList.Add(s); } var subscription = subscriptionList[0]; // Create monitored items on the server // and track the last reported source timestamp var list = Enumerable.Range(1, MonitoredItemsPerSubscription).Select(_ => new MonitoredItem(subscription.DefaultItem) { StartNodeId = new NodeId("Scalar_Simulation_Int32", 2), SamplingInterval = 0, }).ToList(); var dict = list.ToDictionary(item => item.ClientHandle, _ => DateTime.MinValue); subscription.AddItems(list); foreach (var s in subscriptionList) { var boolResult = m_session.AddSubscription(s); Assert.True(boolResult); s.Create(); var publishInterval = (int)s.CurrentPublishingInterval; TestContext.Out.WriteLine($"CurrentPublishingInterval: {publishInterval}"); subscriptionIds.Add(s.Id); } //Need to realize test failed, assert needs to be brought to this thread subscription.FastDataChangeCallback = (_, notification, __) => { notification.MonitoredItems.ForEach(item => { Interlocked.Increment(ref numOfNotifications); if (dict[item.ClientHandle] > item.Value.SourceTimestamp) { TestContext.Out.WriteLine("Out of order encountered"); sequenceBroken.Set(); return; } dict[item.ClientHandle] = item.Value.SourceTimestamp; Thread.Sleep(10); }); }; var stopwatch = Stopwatch.StartNew(); // start m_session.SetPublishingMode(null, true, subscriptionIds, out var results, out var diagnosticInfos); // Wait for out-of-order to occur var failed = sequenceBroken.WaitOne(TestWaitTime); // stop m_session.SetPublishingMode(null, false, subscriptionIds, out results, out diagnosticInfos); //Log information var elapsed = stopwatch.Elapsed.TotalMilliseconds / 1000.0; TestContext.Out.WriteLine($"Ran for: {elapsed:N} seconds"); long totalNotifications = Interlocked.Read(ref numOfNotifications); double notificationRate = totalNotifications / elapsed; int outstandingMessageWorkers = subscription.OutstandingMessageWorkers; TestContext.Out.WriteLine($"Id: {subscription.Id} Outstanding workers: {outstandingMessageWorkers}"); // clean up before validating conditions foreach (var s in subscriptionList) { var result = m_session.RemoveSubscription(s); Assert.True(result); } TestContext.Out.WriteLine($"Number of notifications: {totalNotifications:N0}"); //How fast it processed notifications. TestContext.Out.WriteLine($"Notifications rate: {notificationRate:N} per second"); //No notifications means nothing worked Assert.NotZero(totalNotifications); // The issue more unlikely seem to appear on .NET 6 in the given timeframe if (!enabled && !failed) { Assert.Inconclusive("The test couldn't validate the issue on this platform"); } // catch if expected/unexpected Out-of-sequence occurred Assert.AreEqual(enabled, !failed); }
/// <summary> /// Begins an asynchronous invocation of the SetTriggering service. /// </summary> public IAsyncResult BeginSetTriggering( RequestHeader requestHeader, uint subscriptionId, uint triggeringItemId, UInt32Collection linksToAdd, UInt32Collection linksToRemove, AsyncCallback callback, object asyncState) { SetTriggeringRequest request = new SetTriggeringRequest(); request.RequestHeader = requestHeader; request.SubscriptionId = subscriptionId; request.TriggeringItemId = triggeringItemId; request.LinksToAdd = linksToAdd; request.LinksToRemove = linksToRemove; UpdateRequestHeader(request, requestHeader == null, "SetTriggering"); if (UseTransportChannel) { return TransportChannel.BeginSendRequest(request, callback, asyncState); } return InnerChannel.BeginSetTriggering(new SetTriggeringMessage(request), callback, asyncState); }
/// <summary> /// Deletes the monitored items in a subscription. /// </summary> public void DeleteMonitoredItems( OperationContext context, UInt32Collection monitoredItemIds, out StatusCodeCollection results, out DiagnosticInfoCollection diagnosticInfos) { DeleteMonitoredItems(context, monitoredItemIds, false, out results, out diagnosticInfos); }
/// <summary> /// Finishes an asynchronous invocation of the Publish service. /// </summary> public ResponseHeader EndPublish( IAsyncResult result, out uint subscriptionId, out UInt32Collection availableSequenceNumbers, out bool moreNotifications, out NotificationMessage notificationMessage, out StatusCodeCollection results, out DiagnosticInfoCollection diagnosticInfos) { PublishResponse response = null; try { if (UseTransportChannel) { IServiceResponse genericResponse = TransportChannel.EndSendRequest(result); if (genericResponse == null) { throw new ServiceResultException(StatusCodes.BadUnknownResponse); } ValidateResponse(genericResponse.ResponseHeader); response = (PublishResponse)genericResponse; } else { PublishResponseMessage responseMessage = InnerChannel.EndPublish(result); 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(null, response, "Publish"); } return response.ResponseHeader; }
/// <summary> /// Changes the monitoring mode for a set of items. /// </summary> public void SetMonitoringMode( OperationContext context, MonitoringMode monitoringMode, UInt32Collection monitoredItemIds, out StatusCodeCollection results, out DiagnosticInfoCollection diagnosticInfos) { if (context == null) throw new ArgumentNullException("context"); if (monitoredItemIds == null) throw new ArgumentNullException("monitoredItemIds"); int count = monitoredItemIds.Count; bool diagnosticsExist = false; results = new StatusCodeCollection(count); diagnosticInfos = null; if ((context.DiagnosticsMask & DiagnosticsMasks.OperationAll) != 0) { diagnosticInfos = new DiagnosticInfoCollection(count); } // build list of items to modify. List<IMonitoredItem> monitoredItems = new List<IMonitoredItem>(count); List<ServiceResult> errors = new List<ServiceResult>(count); MonitoringMode[] originalMonitoringModes = new MonitoringMode[count]; bool validItems = false; lock (m_lock) { // check session. VerifySession(context); // clear lifetime counter. ResetLifetimeCount(); for (int ii = 0; ii < count; ii++) { LinkedListNode<IMonitoredItem> node = null; if (!m_monitoredItems.TryGetValue(monitoredItemIds[ii], out node)) { monitoredItems.Add(null); errors.Add(StatusCodes.BadMonitoredItemIdInvalid); // update diagnostics. if ((context.DiagnosticsMask & DiagnosticsMasks.OperationAll) != 0) { DiagnosticInfo diagnosticInfo = ServerUtils.CreateDiagnosticInfo(m_server, context, errors[ii]); diagnosticsExist = true; diagnosticInfos.Add(diagnosticInfo); } continue; } IMonitoredItem monitoredItem = node.Value; monitoredItems.Add(monitoredItem); originalMonitoringModes[ii] = monitoredItem.MonitoringMode; errors.Add(null); validItems = true; // update diagnostics. if ((context.DiagnosticsMask & DiagnosticsMasks.OperationAll) != 0) { diagnosticInfos.Add(null); } } } // update items. if (validItems) { m_server.NodeManager.SetMonitoringMode( context, monitoringMode, monitoredItems, errors); } lock (m_lock) { // update diagnostics. for (int ii = 0; ii < errors.Count; ii++) { ServiceResult error = errors[ii]; if (error == null) { results.Add(StatusCodes.Good); } else { results.Add(error.StatusCode); } // update diagnostics. if (ServiceResult.IsGood(error)) { ModifyItemMonitoringMode(monitoredItems[ii].SamplingInterval, originalMonitoringModes[ii], monitoringMode); } if ((context.DiagnosticsMask & DiagnosticsMasks.OperationAll) != 0) { if (error != null && error.Code != StatusCodes.Good) { diagnosticInfos[ii] = ServerUtils.CreateDiagnosticInfo(m_server, context, error); diagnosticsExist = true; } } } // clear diagnostics if not required. if (!diagnosticsExist && diagnosticInfos != null) { diagnosticInfos.Clear(); } // update diagnostics. lock (m_diagnostics) { m_diagnostics.MonitoredItemCount = 0; m_diagnostics.DisabledMonitoredItemCount = 0; } if (monitoringMode == MonitoringMode.Disabled) { // TraceState("ITEMS DISABLED"); } else if (monitoringMode == MonitoringMode.Reporting) { // TraceState("ITEMS REPORTING ENABLED"); } else { // TraceState("ITEMS SAMPLING ENABLED"); } } }
/// <summary> /// Deletes the monitored items. /// </summary> private bool DeleteMonitoredItems( Subscription subscription, List<MonitoredItem> monitoredItems) { try { RequestHeader requestHeader = new RequestHeader(); requestHeader.ReturnDiagnostics = 0; UInt32Collection monitoredItemIds = new UInt32Collection(); for (int ii = 0; ii < monitoredItems.Count; ii++) { monitoredItemIds.Add(monitoredItems[ii].MonitoredItemId); } StatusCodeCollection results; DiagnosticInfoCollection diagnosticInfos; Session.DeleteMonitoredItems( requestHeader, subscription.SubscriptionId, monitoredItemIds, out results, out diagnosticInfos); ClientBase.ValidateResponse(results, monitoredItemIds); ClientBase.ValidateDiagnosticInfos(diagnosticInfos, monitoredItemIds); if (diagnosticInfos != null && diagnosticInfos.Count > 0) { Log("Returned non-empty DiagnosticInfos array during DeleteMonitoredItems."); return false; } bool success = true; for (int ii = 0; ii < monitoredItems.Count; ii++) { if (StatusCode.IsBad(results[ii])) { Log( "Delete monitored item failed for Node '{0}', NodeId = {1}, AttributeId = {2}, StatusCode = {3}", monitoredItems[ii].Node, monitoredItems[ii].Node.NodeId, Attributes.GetBrowseName(monitoredItems[ii].AttributeId), results[ii]); success = false; continue; } } return success; } catch (Exception e) { Log(e, "DeleteMonitoredItems Failed."); return false; } }
/// <summary> /// Returns all available notifications. /// </summary> private NotificationMessage InnerPublish( OperationContext context, out UInt32Collection availableSequenceNumbers, out bool moreNotifications) { // check session. VerifySession(context); // TraceState("PUBLISH"); // check if a keep alive should be sent if there is no data. bool keepAliveIfNoData = (m_keepAliveCounter >= m_maxKeepAliveCount); availableSequenceNumbers = new UInt32Collection(); moreNotifications = false; if (m_lastSentMessage < m_sentMessages.Count) { // return the available sequence numbers. for (int ii = 0; ii <= m_lastSentMessage && ii < m_sentMessages.Count; ii++) { availableSequenceNumbers.Add(m_sentMessages[ii].SequenceNumber); } moreNotifications = m_waitingForPublish = m_lastSentMessage < m_sentMessages.Count-1; // TraceState("PUBLISH QUEUED MESSAGE"); return m_sentMessages[m_lastSentMessage++]; } List<NotificationMessage> messages = new List<NotificationMessage>(); if (m_publishingEnabled) { DateTime start1 = DateTime.UtcNow; // collect notifications to publish. Queue<EventFieldList> events = new Queue<EventFieldList>(); Queue<MonitoredItemNotification> datachanges = new Queue<MonitoredItemNotification>(); Queue<DiagnosticInfo> datachangeDiagnostics = new Queue<DiagnosticInfo>(); // check for monitored items that are ready to publish. LinkedListNode<IMonitoredItem> current = m_itemsToPublish.First; while (current != null) { LinkedListNode<IMonitoredItem> next = current.Next; IMonitoredItem monitoredItem = current.Value; if ((monitoredItem.MonitoredItemType & MonitoredItemTypeMask.DataChange) != 0) { ((IDataChangeMonitoredItem)monitoredItem).Publish(context, datachanges, datachangeDiagnostics); } else { ((IEventMonitoredItem)monitoredItem).Publish(context, events); } // add back to list to check. m_itemsToPublish.Remove(current); m_itemsToCheck.AddLast(current); // check there are enough notifications for a message. if (m_maxNotificationsPerPublish > 0 && events.Count + datachanges.Count > m_maxNotificationsPerPublish) { // construct message. int notificationCount; int eventCount = events.Count; int dataChangeCount = datachanges.Count; NotificationMessage message = ConstructMessage( events, datachanges, datachangeDiagnostics, out notificationCount); // add to list of messages to send. messages.Add(message); lock (m_diagnostics) { m_diagnostics.DataChangeNotificationsCount += (uint)(dataChangeCount - datachanges.Count); m_diagnostics.EventNotificationsCount += (uint)(eventCount - events.Count); m_diagnostics.NotificationsCount += (uint)notificationCount; } } current = next; } // pubish the remaining notifications. while (events.Count + datachanges.Count > 0) { // construct message. int notificationCount; int eventCount = events.Count; int dataChangeCount = datachanges.Count; NotificationMessage message = ConstructMessage( events, datachanges, datachangeDiagnostics, out notificationCount); // add to list of messages to send. messages.Add(message); lock (m_diagnostics) { m_diagnostics.DataChangeNotificationsCount += (uint)(dataChangeCount - datachanges.Count); m_diagnostics.EventNotificationsCount += (uint)(eventCount - events.Count); m_diagnostics.NotificationsCount += (uint)notificationCount; } } // check for missing notifications. if (!keepAliveIfNoData && messages.Count == 0) { Utils.Trace( (int)Utils.TraceMasks.Error, "Oops! MonitoredItems queued but no notifications availabled."); m_waitingForPublish = false; return null; } DateTime end1 = DateTime.UtcNow; double delta1 = ((double)(end1.Ticks-start1.Ticks))/TimeSpan.TicksPerMillisecond; if (delta1 > 200) { TraceState(Utils.Format("PUBLISHING DELAY ({0}ms)", delta1)); } } if (messages.Count == 0) { // create a keep alive message. NotificationMessage message = new NotificationMessage(); // use the sequence number for the next message. message.SequenceNumber = (uint)m_sequenceNumber; message.PublishTime = DateTime.UtcNow; // return the available sequence numbers. for (int ii = 0; ii <= m_lastSentMessage && ii < m_sentMessages.Count; ii++) { availableSequenceNumbers.Add(m_sentMessages[ii].SequenceNumber); } // TraceState("PUBLISH KEEPALIVE"); return message; } // have to drop unsent messages if out of queue space. if (messages.Count > m_maxMessageCount) { Utils.Trace( "WARNING: QUEUE OVERFLOW. Dropping {2} Messages. Increase MaxMessageQueueSize. SubId={0}, MaxMessageQueueSize={1}", m_id, m_maxMessageCount, messages.Count - (int)m_maxMessageCount); messages.RemoveRange(0, messages.Count - (int)m_maxMessageCount); } // remove old messages if queue is full. if (m_sentMessages.Count > m_maxMessageCount - messages.Count) { lock (m_diagnostics) { m_diagnostics.UnacknowledgedMessageCount += (uint)messages.Count; } if (m_maxMessageCount <= messages.Count) { m_sentMessages.Clear(); } else { m_sentMessages.RemoveRange(0, messages.Count); } } // save new message m_lastSentMessage = m_sentMessages.Count; m_sentMessages.AddRange(messages); // check if there are more notifications to send. moreNotifications = m_waitingForPublish = messages.Count > 1; // return the available sequence numbers. for (int ii = 0; ii <= m_lastSentMessage && ii < m_sentMessages.Count; ii++) { availableSequenceNumbers.Add(m_sentMessages[ii].SequenceNumber); } // TraceState("PUBLISH NEW MESSAGE"); return m_sentMessages[m_lastSentMessage++]; }
private CallMethodRequestCollection ResendDataCall(StatusCode expectedStatus, UInt32Collection subscriptionIds) { // Find the ResendData method var nodesToCall = new CallMethodRequestCollection(); foreach (var subscriptionId in subscriptionIds) { nodesToCall.Add(new CallMethodRequest() { ObjectId = ObjectIds.Server, MethodId = MethodIds.Server_ResendData, InputArguments = new VariantCollection() { new Variant(subscriptionId) } }); } //call ResendData method with subscription ids m_requestHeader.Timestamp = DateTime.UtcNow; var response = m_server.Call(m_requestHeader, nodesToCall, out var results, out var diagnosticInfos); Assert.AreEqual(expectedStatus, results[0].StatusCode.Code); ServerFixtureUtils.ValidateResponse(response); return(nodesToCall); }