/* ======================================================================== * Copyright (c) 2005-2020 The OPC Foundation, Inc. All rights reserved. * * OPC Foundation MIT License 1.00 * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * The complete license agreement can be found here: * http://opcfoundation.org/License/MIT/1.00/ * ======================================================================*/ using System; using System.Collections.Generic; using System.Threading; namespace Opc.Ua.Server { /// /// Stores information used while a thread is completing an operation on behalf of a client. /// public class OperationContext : IOperationContext { #region Constructors /// /// Initializes the context with a session. /// /// The request header. /// Type of the request. /// The identity used in the request. public OperationContext(RequestHeader requestHeader, RequestType requestType, IUserIdentity identity = null) { if (requestHeader == null) throw new ArgumentNullException(nameof(requestHeader)); m_channelContext = SecureChannelContext.Current; m_session = null; m_identity = identity; m_preferredLocales = new string[0]; m_diagnosticsMask = (DiagnosticsMasks)requestHeader.ReturnDiagnostics; m_stringTable = new StringTable(); m_auditLogEntryId = requestHeader.AuditEntryId; m_requestId = Utils.IncrementIdentifier(ref s_lastRequestId); m_requestType = requestType; m_clientHandle = requestHeader.RequestHandle; m_operationDeadline = DateTime.MaxValue; if (requestHeader.TimeoutHint > 0) { m_operationDeadline = DateTime.UtcNow.AddMilliseconds(requestHeader.TimeoutHint); } } /// /// Initializes the context with a session. /// /// The request header. /// Type of the request. /// The session. public OperationContext(RequestHeader requestHeader, RequestType requestType, Session session) { if (requestHeader == null) throw new ArgumentNullException(nameof(requestHeader)); if (session == null) throw new ArgumentNullException(nameof(session)); m_channelContext = SecureChannelContext.Current; m_session = session; m_identity = session.EffectiveIdentity; m_preferredLocales = session.PreferredLocales; m_diagnosticsMask = (DiagnosticsMasks)requestHeader.ReturnDiagnostics; m_stringTable = new StringTable(); m_auditLogEntryId = requestHeader.AuditEntryId; m_requestId = Utils.IncrementIdentifier(ref s_lastRequestId); m_requestType = requestType; m_clientHandle = requestHeader.RequestHandle; m_operationDeadline = DateTime.MaxValue; if (requestHeader.TimeoutHint > 0) { m_operationDeadline = DateTime.UtcNow.AddMilliseconds(requestHeader.TimeoutHint); } } /// /// Initializes the context with a session. /// /// The session. /// The diagnostics masks. public OperationContext(Session session, DiagnosticsMasks diagnosticsMasks) { if (session == null) throw new ArgumentNullException(nameof(session)); m_channelContext = null; m_session = session; m_identity = session.EffectiveIdentity; m_preferredLocales = session.PreferredLocales; m_diagnosticsMask = diagnosticsMasks; m_stringTable = new StringTable(); m_auditLogEntryId = null; m_requestId = 0; m_requestType = RequestType.Unknown; m_clientHandle = 0; m_operationDeadline = DateTime.MaxValue; } /// /// Initializes the context with a monitored item. /// /// The monitored item. public OperationContext(IMonitoredItem monitoredItem) { if (monitoredItem == null) throw new ArgumentNullException(nameof(monitoredItem)); m_channelContext = null; m_session = monitoredItem.Session; if (m_session != null) { m_identity = m_session.Identity; m_preferredLocales = m_session.PreferredLocales; } m_diagnosticsMask = DiagnosticsMasks.SymbolicId; m_stringTable = new StringTable(); m_auditLogEntryId = null; m_requestId = 0; m_requestType = RequestType.Unknown; m_clientHandle = 0; m_operationDeadline = DateTime.MaxValue; } #endregion #region Public Properties /// /// The context for the secure channel used to send the request. /// /// The channel context. public SecureChannelContext ChannelContext { get { return m_channelContext; } } /// /// The session associated with the context. /// /// The session. public Session Session { get { return m_session; } } /// /// The security policy used for the secure channel. /// /// The security policy URI. public string SecurityPolicyUri { get { if (m_channelContext != null && m_channelContext.EndpointDescription != null) { return m_channelContext.EndpointDescription.SecurityPolicyUri; } return null; } } /// /// The type of request. /// /// The type of the request. public RequestType RequestType { get { return m_requestType; } } /// /// A unique identifier assigned to the request by the server. /// /// The request id. public uint RequestId { get { return m_requestId; } } /// /// The handle assigned by the client to the request. /// /// The client handle. public uint ClientHandle { get { return m_clientHandle; } } /// /// Updates the status code (thread safe). /// /// The status code. public void SetStatusCode(StatusCode statusCode) { Interlocked.Exchange(ref m_operationStatus, (long)statusCode.Code); } #endregion #region IOperationContext Members /// /// The identifier for the session (null if multiple sessions are associated with the operation). /// /// The session id. public NodeId SessionId { get { if (m_session != null) { return m_session.Id; } return null; } } /// /// The identity context to use when processing the request. /// /// The user identity. public IUserIdentity UserIdentity { get { return m_identity; } } /// /// The locales to use for the operation. /// /// The preferred locales. public IList PreferredLocales { get { return m_preferredLocales; } } /// /// The diagnostics mask specified with the request. /// /// The diagnostics mask. public DiagnosticsMasks DiagnosticsMask { get { return m_diagnosticsMask; } } /// /// A table of diagnostics strings to return in the response. /// /// The string table. /// /// This object is thread safe. /// public StringTable StringTable { get { return m_stringTable; } } /// /// When the request times out. /// /// The operation deadline. public DateTime OperationDeadline { get { return m_operationDeadline; } } /// /// The current status of the request (used to check for timeouts/client cancel requests). /// /// The operation status. public StatusCode OperationStatus { get { return (uint)m_operationStatus; } } /// /// The audit log entry id provided by the client which must be included in an audit events generated by the server. /// /// The audit entry id. public string AuditEntryId { get { return m_auditLogEntryId; } } #endregion #region Private Fields private SecureChannelContext m_channelContext; private Session m_session; private IUserIdentity m_identity; private IList m_preferredLocales; private DiagnosticsMasks m_diagnosticsMask; private StringTable m_stringTable; private string m_auditLogEntryId; private uint m_requestId; private RequestType m_requestType; private uint m_clientHandle; private DateTime m_operationDeadline; private long m_operationStatus; private static long s_lastRequestId; #endregion } }