/// <summary> /// Creates a new instance of a sampling group. /// </summary> public SamplingGroup( IServerInternal server, INodeManager nodeManager, List<SamplingRateGroup> samplingRates, OperationContext context, double samplingInterval) { if (server == null) throw new ArgumentNullException("server"); if (nodeManager == null) throw new ArgumentNullException("nodeManager"); if (samplingRates == null) throw new ArgumentNullException("samplingRates"); m_server = server; m_nodeManager = nodeManager; m_samplingRates = samplingRates; m_session = context.Session; m_diagnosticsMask = (DiagnosticsMasks)context.DiagnosticsMask & DiagnosticsMasks.OperationAll; m_samplingInterval = AdjustSamplingInterval(samplingInterval); m_itemsToAdd = new List<ISampledDataChangeMonitoredItem>(); m_itemsToRemove = new List<ISampledDataChangeMonitoredItem>(); m_items = new Dictionary<uint, ISampledDataChangeMonitoredItem>(); // create a event to signal shutdown. m_shutdownEvent = new ManualResetEvent(true); }
/// <summary> /// Initializes a new instance of the <see cref="SystemContext"/> class. /// </summary> /// <param name="server">The server.</param> /// <param name="context">The context.</param> public ServerSystemContext(IServerInternal server, OperationContext context) { OperationContext = context; NamespaceUris = server.NamespaceUris; ServerUris = server.ServerUris; TypeTable = server.TypeTree; EncodeableFactory = server.Factory; }
/// <summary> /// Initializes a new instance of the <see cref="AsyncPublishOperation"/> class. /// </summary> /// <param name="context">The context.</param> /// <param name="request">The request.</param> /// <param name="server">The server.</param> public AsyncPublishOperation( OperationContext context, IEndpointIncomingRequest request, StandardServer server) { m_context = context; m_request = request; m_server = server; m_response = new PublishResponse(); m_request.Calldata = this; }
/// <summary> /// Handles the GetWheels test method. /// </summary> public Wheel[] OnGetWheels(OperationContext context, NodeSource target, Vehicle vehicle) { GenericEvent e = GenericEvent.Construct(Server, new NodeId(ObjectTypes.MaintenanceEventType, GetNamespaceIndex(Namespaces.Sample))); e.InitializeNewEvent(); e.Message.Value = "Some unknown problem."; e.SetProperty(new QualifiedName(BrowseNames.MustCompleteByDate, GetNamespaceIndex(Namespaces.Sample)), new DateTime(1987,2,3)); ReportEvent(e); return vehicle.Wheels.ToArray(); }
/// <summary> /// Subscribes or unsubscribes to events produced by all event sources. /// </summary> /// <remarks> /// This method is called when a event subscription is created or deleted. The node /// manager must start/stop reporting events for all objects that it manages. /// </remarks> public override ServiceResult SubscribeToAllEvents( Opc.Ua.Server.OperationContext context, uint subscriptionId, IEventMonitoredItem monitoredItem, bool unsubscribe) { ServerSystemContext serverSystemContext = SystemContext.Copy(context); lock (Lock) { // A client has subscribed to the Server object which means all events produced // by this manager must be reported. This is done by incrementing the monitoring // reference count for all root notifiers. if (_rootNotifiers != null) { for (int ii = 0; ii < _rootNotifiers.Count; ii++) { SubscribeToEvents(serverSystemContext, _rootNotifiers[ii], monitoredItem, unsubscribe); } } return(ServiceResult.Good); } }
/// <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++]; }
/// <summary> /// Removes a message from the message queue. /// </summary> public ServiceResult Acknowledge(OperationContext context, uint sequenceNumber) { lock (m_lock) { // check session. VerifySession(context); // clear lifetime counter. ResetLifetimeCount(); // find message in queue. for (int ii = 0; ii < m_sentMessages.Count; ii++) { if (m_sentMessages[ii].SequenceNumber == sequenceNumber) { if (m_lastSentMessage > ii) { m_lastSentMessage--; } m_sentMessages.RemoveAt(ii); return null; } } if (sequenceNumber == 0) { return StatusCodes.BadSequenceNumberInvalid; } // TraceState("ACK " + sequenceNumber.ToString()); // message not found. return StatusCodes.BadSequenceNumberUnknown; } }
/// <summary> /// Throws an exception if the session is not the owner. /// </summary> private void VerifySession(OperationContext context) { if (m_expired) { throw new ServiceResultException(StatusCodes.BadSubscriptionIdInvalid); } if (!Object.ReferenceEquals(context.Session, m_session)) { throw new ServiceResultException(StatusCodes.BadSessionIdInvalid, "Session no longer owns the subscription."); } }
/// <summary> /// Verifies that a condition refresh operation is permitted. /// </summary> public void ValidateConditionRefresh(OperationContext context) { lock (m_lock) { VerifySession(context); if (m_refreshInProgress) { throw new ServiceResultException(StatusCodes.BadRefreshInProgress); } } }
/// <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"); } }
/// <summary> /// Modifies monitored items in a subscription. /// </summary> public void ModifyMonitoredItems( OperationContext context, TimestampsToReturn timestampsToReturn, MonitoredItemModifyRequestCollection itemsToModify, out MonitoredItemModifyResultCollection results, out DiagnosticInfoCollection diagnosticInfos) { if (context == null) throw new ArgumentNullException("context"); if (itemsToModify == null) throw new ArgumentNullException("itemsToModify"); int count = itemsToModify.Count; // allocate results. bool diagnosticsExist = false; results = new MonitoredItemModifyResultCollection(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); List<MonitoringFilterResult> filterResults = new List<MonitoringFilterResult>(count); double[] originalSamplingIntervals = new double[count]; bool validItems = false; lock (m_lock) { // check session. VerifySession(context); // clear lifetime counter. ResetLifetimeCount(); for (int ii = 0; ii < count; ii++) { filterResults.Add(null); LinkedListNode<IMonitoredItem> node = null; if (!m_monitoredItems.TryGetValue(itemsToModify[ii].MonitoredItemId, 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); originalSamplingIntervals[ii] = monitoredItem.SamplingInterval; errors.Add(null); validItems = true; // update diagnostics. if ((context.DiagnosticsMask & DiagnosticsMasks.OperationAll) != 0) { diagnosticInfos.Add(null); } } } // update items. if (validItems) { m_server.NodeManager.ModifyMonitoredItems( context, timestampsToReturn, monitoredItems, itemsToModify, errors, filterResults); } lock (m_lock) { // create results. for (int ii = 0; ii < errors.Count; ii++) { ServiceResult error = errors[ii]; MonitoredItemModifyResult result = null; if (ServiceResult.IsGood(error)) { error = monitoredItems[ii].GetModifyResult(out result); } if (result == null) { result = new MonitoredItemModifyResult(); } if (error == null) { result.StatusCode = StatusCodes.Good; } else { result.StatusCode = error.StatusCode; } // update diagnostics. if (ServiceResult.IsGood(error)) { ModifyItemSamplingInterval(originalSamplingIntervals[ii], result.RevisedSamplingInterval, monitoredItems[ii].MonitoringMode); } if (filterResults[ii] != null) { result.FilterResult = new ExtensionObject(filterResults[ii]); } results.Add(result); 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(); } // TraceState("ITEMS MODIFIED"); } }
/// <summary> /// Activates an existing session /// </summary> public virtual bool ActivateSession( OperationContext context, NodeId authenticationToken, SignatureData clientSignature, List <SoftwareCertificate> clientSoftwareCertificates, ExtensionObject userIdentityToken, SignatureData userTokenSignature, StringCollection localeIds, out byte[] serverNonce) { serverNonce = null; Session session = null; UserIdentityToken newIdentity = null; UserTokenPolicy userTokenPolicy = null; lock (m_lock) { // find session. if (!m_sessions.TryGetValue(authenticationToken, out session)) { throw new ServiceResultException(StatusCodes.BadSessionClosed); } // create new server nonce. serverNonce = Utils.Nonce.CreateNonce((uint)m_minNonceLength); // validate before activation. session.ValidateBeforeActivate( context, clientSignature, clientSoftwareCertificates, userIdentityToken, userTokenSignature, localeIds, serverNonce, out newIdentity, out userTokenPolicy); } IUserIdentity identity = null; IUserIdentity effectiveIdentity = null; ServiceResult error = null; try { // check if the application has a callback which validates the identity tokens. lock (m_eventLock) { if (m_ImpersonateUser != null) { ImpersonateEventArgs args = new ImpersonateEventArgs(newIdentity, userTokenPolicy); m_ImpersonateUser(session, args); if (ServiceResult.IsBad(args.IdentityValidationError)) { error = args.IdentityValidationError; } else { identity = args.Identity; effectiveIdentity = args.EffectiveIdentity; } } } // parse the token manually if the identity is not provided. if (identity == null) { identity = new UserIdentity(newIdentity); } // use the identity as the effectiveIdentity if not provided. if (effectiveIdentity == null) { effectiveIdentity = identity; } } catch (Exception e) { if (e is ServiceResultException) { throw e; } throw ServiceResultException.Create( StatusCodes.BadIdentityTokenInvalid, e, "Could not validate user identity token: {0}", newIdentity); } // check for validation error. if (ServiceResult.IsBad(error)) { throw new ServiceResultException(error); } // activate session. bool contextChanged = session.Activate( context, clientSoftwareCertificates, newIdentity, identity, effectiveIdentity, localeIds, serverNonce); // raise session related event. if (contextChanged) { RaiseSessionEvent(session, SessionEventReason.Activated); } // indicates that the identity context for the session has changed. return(contextChanged); }
/// <summary> /// Refreshes the conditions for the specified subscription. /// </summary> /// <param name="context">The context.</param> /// <param name="subscriptionId">The subscription identifier.</param> public void ConditionRefresh(OperationContext context, uint subscriptionId) { m_subscriptionManager.ConditionRefresh(context, subscriptionId); }
/// <summary> /// Closes the specified session. /// </summary> /// <param name="context">The context.</param> /// <param name="sessionId">The session identifier.</param> /// <param name="deleteSubscriptions">if set to <c>true</c> subscriptions are to be deleted.</param> public void CloseSession(OperationContext context, NodeId sessionId, bool deleteSubscriptions) { m_nodeManager.SessionClosing(context, sessionId, deleteSubscriptions); m_subscriptionManager.SessionClosing(context, sessionId, deleteSubscriptions); m_sessionManager.CloseSession(sessionId); }
/// <summary> /// Updates the publishing parameters for the subscription. /// </summary> public void Modify( OperationContext context, double publishingInterval, uint maxLifetimeCount, uint maxKeepAliveCount, uint maxNotificationsPerPublish, byte priority) { lock (m_lock) { // check session. VerifySession(context); // clear lifetime counter. ResetLifetimeCount(); m_maxLifetimeCount = maxLifetimeCount; // update publishing interval. if (publishingInterval != m_publishingInterval) { m_publishingInterval = publishingInterval; m_publishTimerExpiry = (HiResClock.UtcNow.Ticks/TimeSpan.TicksPerMillisecond) + (long)publishingInterval; ResetKeepaliveCount(); } // update keep alive count. if (maxKeepAliveCount != m_maxKeepAliveCount) { m_maxKeepAliveCount = maxKeepAliveCount; } m_maxNotificationsPerPublish = maxNotificationsPerPublish; // update priority. m_priority = priority; // update diagnostics lock (m_diagnostics) { m_diagnostics.ModifyCount++; m_diagnostics.PublishingInterval = m_publishingInterval; m_diagnostics.MaxKeepAliveCount = m_maxKeepAliveCount; m_diagnostics.MaxLifetimeCount = m_maxLifetimeCount; m_diagnostics.Priority = m_priority; m_diagnostics.MaxNotificationsPerPublish = m_maxNotificationsPerPublish; } // TraceState("MODIFIED"); } }
/// <summary> /// Publishes all available data change notifications. /// </summary> public virtual bool Publish( OperationContext context, Queue<MonitoredItemNotification> notifications, Queue<DiagnosticInfo> diagnostics) { if (context == null) throw new ArgumentNullException("context"); if (notifications == null) throw new ArgumentNullException("notifications"); if (diagnostics == null) throw new ArgumentNullException("diagnostics"); lock (m_lock) { // check if the item reports data changes. if ((m_typeMask & MonitoredItemTypeMask.DataChange) == 0) { return false; } // only publish if reporting. if (!IsReadyToPublish) { return false; } // pull any unprocessed data. if (m_calculator != null) { if (m_calculator.HasEndTimePassed(DateTime.UtcNow)) { DataValue processedValue = m_calculator.GetProcessedValue(false); while (processedValue != null) { AddValueToQueue(processedValue, null); } processedValue = m_calculator.GetProcessedValue(true); AddValueToQueue(processedValue, null); } } // go to the next sampling interval. IncrementSampleTime(); // check if queueing enabled. if (m_queue != null) { DataValue value = null; ServiceResult error = null; while (m_queue.Publish(out value, out error)) { Publish(context, notifications, diagnostics, value, error); } } // publish last value if no queuing. else { Utils.Trace("DEQUEUE VALUE: Value={0} CODE={1}<{1:X8}> OVERFLOW={2}", m_lastValue.WrappedValue, m_lastValue.StatusCode.Code, m_lastValue.StatusCode.Overflow); Publish(context, notifications, diagnostics, m_lastValue, m_lastError); } // reset state variables. m_overflow = false; m_readyToPublish = false; m_readyToTrigger = false; m_triggered = false; return false; } }
/// <summary> /// Does any processing before a transition occurs. /// </summary> protected virtual void OnBeforeTransition(OperationContext context, Transition transition, QualifiedName cause) { // raise a notification that a transition is about to occur. if (m_TransitionInitiated != null) { StateMachineTransitionEventArgs args = new StateMachineTransitionEventArgs(transition.FromState.BrowseName, transition.ToState.BrowseName, cause); m_TransitionInitiated(context, this, args); if (args.Cancel) { throw ServiceResultException.Create(StatusCodes.Bad, "Transition to State '{0}' was cancelled because: '{1}'.", transition.ToState.DisplayName, args.CancelReason); } } }
/// <summary> /// Adds monitored items to a subscription. /// </summary> public void CreateMonitoredItems( OperationContext context, TimestampsToReturn timestampsToReturn, MonitoredItemCreateRequestCollection itemsToCreate, out MonitoredItemCreateResultCollection results, out DiagnosticInfoCollection diagnosticInfos) { if (context == null) throw new ArgumentNullException("context"); if (itemsToCreate == null) throw new ArgumentNullException("itemsToCreate"); int count = itemsToCreate.Count; lock (m_lock) { // check session. VerifySession(context); // clear lifetime counter. ResetLifetimeCount(); } // create the monitored items. List<IMonitoredItem> monitoredItems = new List<IMonitoredItem>(count); List<ServiceResult> errors = new List<ServiceResult>(count); List<MonitoringFilterResult> filterResults = new List<MonitoringFilterResult>(count); for (int ii = 0; ii < count; ii++) { monitoredItems.Add(null); errors.Add(null); filterResults.Add(null); } m_server.NodeManager.CreateMonitoredItems( context, this.m_id, m_publishingInterval, timestampsToReturn, itemsToCreate, errors, filterResults, monitoredItems); // allocate results. bool diagnosticsExist = false; results = new MonitoredItemCreateResultCollection(count); diagnosticInfos = null; if ((context.DiagnosticsMask & DiagnosticsMasks.OperationAll) != 0) { diagnosticInfos = new DiagnosticInfoCollection(count); } lock (m_lock) { // check session again after CreateMonitoredItems. VerifySession(context); for (int ii = 0; ii < errors.Count; ii++) { // update results. MonitoredItemCreateResult result = null; if (ServiceResult.IsBad(errors[ii])) { result = new MonitoredItemCreateResult(); result.StatusCode = errors[ii].Code; if (filterResults[ii] != null) { result.FilterResult = new ExtensionObject(filterResults[ii]); } } else { IMonitoredItem monitoredItem = monitoredItems[ii]; if (monitoredItem != null) { monitoredItem.SubscriptionCallback = this; LinkedListNode<IMonitoredItem> node = m_itemsToCheck.AddLast(monitoredItem); m_monitoredItems.Add(monitoredItem.Id, node); errors[ii] = monitoredItem.GetCreateResult(out result); // update sampling interval diagnostics. AddItemToSamplingInterval(result.RevisedSamplingInterval, itemsToCreate[ii].MonitoringMode); } } results.Add(result); // update diagnostics. if ((context.DiagnosticsMask & DiagnosticsMasks.OperationAll) != 0) { DiagnosticInfo diagnosticInfo = null; if (errors[ii] != null && errors[ii].Code != StatusCodes.Good) { diagnosticInfo = ServerUtils.CreateDiagnosticInfo(m_server, context, errors[ii]); diagnosticsExist = true; } diagnosticInfos.Add(diagnosticInfo); } } // 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 CREATED"); } }
/// <summary> /// Does any processing after a transition occurs. /// </summary> protected virtual void OnAfterTransition(OperationContext context, Transition transition, QualifiedName cause) { // raise a notification that a transition has occurred. if (m_TransitionCompleted != null) { StateMachineTransitionEventArgs args = new StateMachineTransitionEventArgs( transition.FromState.BrowseName, transition.ToState.BrowseName, cause); m_TransitionCompleted(context, this, args); } }
/// <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> /// Ends a transition (reports events for all effects). /// </summary> protected virtual void EndTransition(OperationContext context, Transition transition, QualifiedName cause) { if (transition != null) { foreach (NodeId effectId in transition.Effects) { // check if the effects are being surpressed. if (m_suppressEffects) { m_unreportedEffect = true; return; } ReportEffect(context, transition, cause, effectId); } } }
/// <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> /// Reports an effect which is an effect of a transition. /// </summary> protected virtual void ReportEffect( OperationContext context, Transition transition, QualifiedName cause, NodeId effectId) { if (effectId == ObjectTypes.TransitionEventType) { TransitionEvent e = TransitionEvent.Construct(Server); e.InitializeNewEvent(); e.Message.Value = Utils.Format("StateMachine has moved to the {0} state.", transition.ToState.DisplayName); e.SourceNode.Value = NodeId; e.SourceName.Value = BrowseName.Name; e.Severity.Value = 10; e.ReceiveTime.Value = DateTime.UtcNow; e.FromState.Value = transition.FromState.DisplayName; e.ToState.Value = transition.ToState.DisplayName; ReportEvent(e); } }
/// <summary> /// Refreshes the conditions. /// </summary> public void ConditionRefresh() { ServerSystemContext systemContext = m_server.DefaultSystemContext.Copy(m_session); List<IEventMonitoredItem> monitoredItems = new List<IEventMonitoredItem>(); lock (m_lock) { // generate start event. RefreshStartEventState e = new RefreshStartEventState(null); TranslationInfo message = new TranslationInfo( "RefreshStartEvent", "en-US", "Condition refresh started for subscription {0}.", m_id); e.Initialize( systemContext, null, EventSeverity.Low, new LocalizedText(message)); e.SetChildValue(systemContext, BrowseNames.SourceNode, m_diagnosticsId, false); e.SetChildValue(systemContext, BrowseNames.SourceName, Utils.Format("Subscription/{0}", m_id), false); e.SetChildValue(systemContext, BrowseNames.ReceiveTime, DateTime.UtcNow, false); // build list of items to refresh. foreach (LinkedListNode<IMonitoredItem> monitoredItem in m_monitoredItems.Values) { MonitoredItem eventMonitoredItem = monitoredItem.Value as MonitoredItem; if (eventMonitoredItem.EventFilter != null) { // queue start refresh event. eventMonitoredItem.QueueEvent(e, true); // add to list that gets reported to the NodeManagers. monitoredItems.Add(eventMonitoredItem); } } // nothing to do if no event subscriptions. if (monitoredItems.Count == 0) { return; } } // tell the NodeManagers to report the current state of the conditions. try { m_refreshInProgress = true; OperationContext operationContext = new OperationContext(m_session, DiagnosticsMasks.None); m_server.NodeManager.ConditionRefresh(operationContext, monitoredItems); } finally { m_refreshInProgress = false; } lock (m_lock) { // generate start event. RefreshEndEventState e = new RefreshEndEventState(null); TranslationInfo message = new TranslationInfo( "RefreshEndEvent", "en-US", "Condition refresh completed for subscription {0}.", m_id); e.Initialize( systemContext, null, EventSeverity.Low, new LocalizedText(message)); e.SetChildValue(systemContext, BrowseNames.SourceNode, m_diagnosticsId, false); e.SetChildValue(systemContext, BrowseNames.SourceName, Utils.Format("Subscription/{0}", m_id), false); e.SetChildValue(systemContext, BrowseNames.ReceiveTime, DateTime.UtcNow, false); // send refresh end event. for (int ii = 0; ii < monitoredItems.Count; ii++) { MonitoredItem monitoredItem = monitoredItems[ii] as MonitoredItem; if (monitoredItem.EventFilter != null) { monitoredItem.QueueEvent(e, true); } } // TraceState("CONDITION REFRESH"); } }
/// <summary> /// Reports an audit event for the cause. /// </summary> protected virtual void ReportAuditEvent(OperationContext context, Transition transition, QualifiedName cause, Exception exception) { AuditUpdateStateEvent e = CreateAuditEvent(context, transition, cause, exception); e.InitializeNewEvent(); e.Message.Value = Utils.Format("Method {0} was called.", cause); e.SourceNode.Value = NodeId; e.SourceName.Value = "Method/Call"; e.Severity.Value = 1; e.ReceiveTime.Value = DateTime.UtcNow; e.ActionTimeStamp.Value = DateTime.UtcNow; e.OldStateId.Value = m_currentStateName.StateNumber; e.NewStateId.Value = m_currentStateName.StateNumber; if (context != null) { e.ClientAuditEntryId.Value = context.AuditEntryId; e.ClientUserId.Value = context.Session.Identity.DisplayName; } if (transition != null) { e.OldStateId.Value = transition.FromState.StateNumber; e.NewStateId.Value = transition.ToState.StateNumber; } ReportEvent(e); }
/// <summary> /// Deletes the subscription. /// </summary> public void Delete(OperationContext context) { // delete the diagnostics. if (m_diagnosticsId != null && !m_diagnosticsId.IsNullNodeId) { ServerSystemContext systemContext = m_server.DefaultSystemContext.Copy(m_session); m_server.DiagnosticsNodeManager.DeleteSubscriptionDiagnostics(systemContext, m_diagnosticsId); } lock (m_lock) { try { // TraceState("DELETED"); // the context may be null if the server is cleaning up expired subscriptions. // in this case we create a context with a dummy request and use the current session. if (context == null) { RequestHeader requestHeader = new RequestHeader(); requestHeader.ReturnDiagnostics = (uint)(int)DiagnosticsMasks.OperationSymbolicIdAndText; context = new OperationContext(requestHeader, RequestType.Unknown); } StatusCodeCollection results; DiagnosticInfoCollection diagnosticInfos; DeleteMonitoredItems( context, new UInt32Collection(m_monitoredItems.Keys), true, out results, out diagnosticInfos); } catch (Exception e) { Utils.Trace(e, "Delete items for subscription failed."); } } }
/// <summary> /// Creates an audit event for the cause. /// </summary> protected virtual AuditUpdateStateEvent CreateAuditEvent( OperationContext context, Transition transition, QualifiedName cause, Exception exception) { return AuditUpdateStateEvent.Construct(Server); }
/// <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> /// 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> /// Returns a cached notification message. /// </summary> public NotificationMessage Republish( OperationContext context, uint retransmitSequenceNumber) { if (context == null) throw new ArgumentNullException("context"); lock (m_diagnostics) { m_diagnostics.RepublishMessageRequestCount++; } lock (m_lock) { // check session. VerifySession(context); // clear lifetime counter. ResetLifetimeCount(); lock (m_diagnostics) { m_diagnostics.RepublishRequestCount++; m_diagnostics.RepublishMessageRequestCount++; } // find message. foreach (NotificationMessage sentMessage in m_sentMessages) { if (sentMessage.SequenceNumber == retransmitSequenceNumber) { lock (m_diagnostics) { m_diagnostics.RepublishMessageCount++; } return sentMessage; } } // message not available. throw new ServiceResultException(StatusCodes.BadMessageNotAvailable); } }
/// <summary> /// Enables/disables publishing for the subscription. /// </summary> public void SetPublishingMode( OperationContext context, bool publishingEnabled) { lock (m_lock) { // check session. VerifySession(context); // clear lifetime counter. ResetLifetimeCount(); // update publishing interval. if (publishingEnabled != m_publishingEnabled) { m_publishingEnabled = publishingEnabled; // update diagnostics lock (m_diagnostics) { m_diagnostics.PublishingEnabled = m_publishingEnabled; if (m_publishingEnabled) { m_diagnostics.EnableCount++; } else { m_diagnostics.DisableCount++; } } } // TraceState((publishingEnabled)?"ENABLED":"DISABLED"); } }
/// <summary> /// Publishes all available event notifications. /// </summary> public virtual bool Publish(OperationContext context, Queue<EventFieldList> notifications) { if (context == null) throw new ArgumentNullException("context"); if (notifications == null) throw new ArgumentNullException("notifications"); lock (m_lock) { // check if the item reports events. if ((m_typeMask & MonitoredItemTypeMask.Events) == 0) { return false; } // only publish if reporting. if (!IsReadyToPublish) { return false; } // go to the next sampling interval. IncrementSampleTime(); // publish events. if (m_events != null) { Utils.Trace("MONITORED ITEM: Publish(QueueSize={0})", notifications.Count); EventFieldList overflowEvent = null; if (m_overflow) { // construct event. EventQueueOverflowEventState e = new EventQueueOverflowEventState(null); TranslationInfo message = new TranslationInfo( "EventQueueOverflowEventState", "en-US", "Events lost due to queue overflow."); ISystemContext systemContext = new ServerSystemContext(m_server, context); e.Initialize( systemContext, null, EventSeverity.Low, new LocalizedText(message)); e.SetChildValue(systemContext, BrowseNames.SourceNode, ObjectIds.Server, false); e.SetChildValue(systemContext, BrowseNames.SourceName, "Internal", false); // fetch the event fields. overflowEvent = GetEventFields( new FilterContext(m_server.NamespaceUris, m_server.TypeTree, m_session.PreferredLocales), m_filterToUse as EventFilter, e); } // place event at the beginning of the queue. if (overflowEvent != null && m_discardOldest) { notifications.Enqueue(overflowEvent); } for (int ii = 0; ii < m_events.Count; ii++) { EventFieldList fields = (EventFieldList)m_events[ii]; // apply any diagnostic masks. for (int jj = 0; jj < fields.EventFields.Count; jj++) { object value = fields.EventFields[jj].Value; StatusResult result = value as StatusResult; if (result != null) { result.ApplyDiagnosticMasks(context.DiagnosticsMask, context.StringTable); } } notifications.Enqueue((EventFieldList)m_events[ii]); } m_events.Clear(); // place event at the end of the queue. if (overflowEvent != null && !m_discardOldest) { notifications.Enqueue(overflowEvent); } Utils.Trace("MONITORED ITEM: Publish(QueueSize={0})", notifications.Count); } // reset state variables. m_overflow = false; m_readyToPublish = false; m_readyToTrigger = false; m_triggered = false; return false; } }
/// <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> /// Publishes a single data change notifications. /// </summary> protected virtual bool Publish( OperationContext context, Queue<MonitoredItemNotification> notifications, Queue<DiagnosticInfo> diagnostics, DataValue value, ServiceResult error) { // set semantics changed bit. if (m_semanticsChanged) { if (value != null) { value.StatusCode = value.StatusCode.SetSemanticsChanged(true); } if (error != null) { error = new ServiceResult( error.StatusCode.SetSemanticsChanged(true), error.SymbolicId, error.NamespaceUri, error.LocalizedText, error.AdditionalInfo, error.InnerResult); } m_semanticsChanged = false; } // set structure changed bit. if (m_structureChanged) { if (value != null) { value.StatusCode = value.StatusCode.SetStructureChanged(true); } if (error != null) { error = new ServiceResult( error.StatusCode.SetStructureChanged(true), error.SymbolicId, error.NamespaceUri, error.LocalizedText, error.AdditionalInfo, error.InnerResult); } m_structureChanged = false; } // copy data value. MonitoredItemNotification item = new MonitoredItemNotification(); item.ClientHandle = m_clientHandle; item.Value = value; // apply timestamp filter. if (m_timestampsToReturn != TimestampsToReturn.Server && m_timestampsToReturn != TimestampsToReturn.Both) { item.Value.ServerTimestamp = DateTime.MinValue; } if (m_timestampsToReturn != TimestampsToReturn.Source && m_timestampsToReturn != TimestampsToReturn.Both) { item.Value.SourceTimestamp = DateTime.MinValue; } ServerUtils.ReportPublishValue(m_nodeId, m_id, item.Value); notifications.Enqueue(item); // update diagnostic info. DiagnosticInfo diagnosticInfo = null; if ((m_diagnosticsMasks & DiagnosticsMasks.OperationAll) != 0) { diagnosticInfo = ServerUtils.CreateDiagnosticInfo(m_server, context, error); } diagnostics.Enqueue(diagnosticInfo); return false; }
/// <summary> /// Creates a new session. /// </summary> public virtual Session CreateSession( OperationContext context, X509Certificate2 serverCertificate, string sessionName, byte[] clientNonce, ApplicationDescription clientDescription, string endpointUrl, X509Certificate2 clientCertificate, double requestedSessionTimeout, uint maxResponseMessageSize, out NodeId sessionId, out NodeId authenticationToken, out byte[] serverNonce, out double revisedSessionTimeout) { sessionId = 0; revisedSessionTimeout = requestedSessionTimeout; Session session = null; lock (m_lock) { // check session count. if (m_maxSessionCount > 0 && m_sessions.Count >= m_maxSessionCount) { throw new ServiceResultException(StatusCodes.BadTooManySessions); } // check for same Nonce in another session if (clientNonce != null) { foreach (Session sessionIterator in m_sessions.Values) { if (Utils.CompareNonce(sessionIterator.ClientNonce, clientNonce)) { throw new ServiceResultException(StatusCodes.BadNonceInvalid); } } } // can assign a simple identifier if secured. authenticationToken = null; if (!String.IsNullOrEmpty(context.ChannelContext.SecureChannelId)) { if (context.ChannelContext.EndpointDescription.SecurityMode != MessageSecurityMode.None) { authenticationToken = Utils.IncrementIdentifier(ref m_lastSessionId); } } // must assign a hard-to-guess id if not secured. if (authenticationToken == null) { byte[] token = Utils.Nonce.CreateNonce(32); authenticationToken = new NodeId(token); } // determine session timeout. if (requestedSessionTimeout > m_maxSessionTimeout) { revisedSessionTimeout = m_maxSessionTimeout; } if (requestedSessionTimeout < m_minSessionTimeout) { revisedSessionTimeout = m_minSessionTimeout; } // create server nonce. serverNonce = Utils.Nonce.CreateNonce((uint)m_minNonceLength); // assign client name. if (String.IsNullOrEmpty(sessionName)) { sessionName = Utils.Format("Session {0}", sessionId); } // create instance of session. session = CreateSession( context, m_server, serverCertificate, authenticationToken, clientNonce, serverNonce, sessionName, clientDescription, endpointUrl, clientCertificate, revisedSessionTimeout, maxResponseMessageSize, m_maxRequestAge, m_maxBrowseContinuationPoints); // get the session id. sessionId = session.Id; // save session. m_sessions.Add(authenticationToken, session); } // raise session related event. RaiseSessionEvent(session, SessionEventReason.Created); // return session. return(session); }