예제 #1
0
        /// <summary>
        /// Begins an asynchronous operation to send a request over the secure channel.
        /// </summary>
        public IAsyncResult BeginSendRequest(IServiceRequest request, AsyncCallback callback, object callbackData)
        {
            HttpWebRequest webRequest = (HttpWebRequest)HttpWebRequest.Create(m_url.ToString());

            webRequest.Method = "POST";

            if (m_settings.Configuration.UseBinaryEncoding)
            {
                webRequest.ContentType = "application/octet-stream";
            }
            else
            {
                StringBuilder contentType = new StringBuilder();
                contentType.Append("application/soap+xml; charset=\"utf-8\"; action=\"");
                contentType.Append(Namespaces.OpcUaWsdl);
                contentType.Append("/");

                string typeName = request.GetType().Name;
                int    index    = typeName.LastIndexOf("Request");
                contentType.Append(typeName.Substring(0, index));;
                contentType.Append("\"");

                webRequest.ContentType = contentType.ToString();
            }

            AsyncResult result = new AsyncResult(callback, callbackData, m_operationTimeout, request, webRequest);

            webRequest.BeginGetRequestStream(OnGetRequestStreamComplete, result);
            return(result);
        }
예제 #2
0
        /// <summary>
        /// Process a request.
        /// </summary>
        /// <param name="request">A service request</param>
        public void Process(IServiceRequest request)
        {
            MethodInfo method        = GetType().GetMethod(nameof(this.HandleRequest), BindingFlags.NonPublic | BindingFlags.Instance);
            MethodInfo genericMethod = method.MakeGenericMethod(request.GetType());

            try
            {
                genericMethod.Invoke(this, new[] { request });
            }
            catch (TargetInvocationException)
            {
                throw new InvalidOperationException("Handler not found!");
            }
        }
예제 #3
0
        /// <summary>
        /// Begins an asynchronous operation to send a request over the secure channel.
        /// </summary>
        public IAsyncResult BeginSendRequest(IServiceRequest request, AsyncCallback callback, object callbackData)
        {
#if !SILVERLIGHT
            if (!m_servicePointInitialized)
            {
                ServicePoint sp = System.Net.ServicePointManager.FindServicePoint(m_url);
                sp.ConnectionLimit        = 1000;
                m_servicePointInitialized = true;
            }
#endif

            HttpWebRequest webRequest = (HttpWebRequest)HttpWebRequest.Create(m_url.ToString());
            webRequest.Method = "POST";

            if (m_settings.Configuration.UseBinaryEncoding)
            {
                webRequest.ContentType = "application/octet-stream";
            }
            else
            {
                StringBuilder contentType = new StringBuilder();
                contentType.Append("application/soap+xml; charset=\"utf-8\"; action=\"");
                contentType.Append(Namespaces.OpcUaWsdl);
                contentType.Append("/");

                string typeName = request.GetType().Name;
                int    index    = typeName.LastIndexOf("Request");
                contentType.Append(typeName.Substring(0, index));
                ;
                contentType.Append("\"");

                webRequest.ContentType = contentType.ToString();

#if !SILVERLIGHT
                webRequest.Headers.Add("OPCUA-SecurityPolicy", this.m_settings.Description.SecurityPolicyUri);
#endif
            }

            AsyncResult result = new AsyncResult(callback, callbackData, m_operationTimeout, request, webRequest);
            webRequest.BeginGetRequestStream(OnGetRequestStreamComplete, result);
            return(result);
        }
        /// <summary>
        /// Begins an asynchronous operation to send a request over the secure channel.
        /// </summary>
        public IAsyncResult BeginSendRequest(IServiceRequest request, AsyncCallback callback, object callbackData)
        {
            #if !SILVERLIGHT
            if (!m_servicePointInitialized)
            {
                ServicePoint sp = System.Net.ServicePointManager.FindServicePoint(m_url);
                sp.ConnectionLimit = 1000;
                m_servicePointInitialized = true;
            }
            #endif

            HttpWebRequest webRequest = (HttpWebRequest)HttpWebRequest.Create(m_url.ToString());
            webRequest.Method = "POST";

            if (m_settings.Configuration.UseBinaryEncoding)
            {
                webRequest.ContentType = "application/octet-stream";
            }
            else
            {
                StringBuilder contentType = new StringBuilder();
                contentType.Append("application/soap+xml; charset=\"utf-8\"; action=\"");
                contentType.Append(Namespaces.OpcUaWsdl);
                contentType.Append("/");

                string typeName = request.GetType().Name;
                int index = typeName.LastIndexOf("Request");
                contentType.Append(typeName.Substring(0, index)); ;
                contentType.Append("\"");

                webRequest.ContentType = contentType.ToString();
                
                #if !SILVERLIGHT
                webRequest.Headers.Add("OPCUA-SecurityPolicy", this.m_settings.Description.SecurityPolicyUri);
                #endif
            }

            AsyncResult result = new AsyncResult(callback, callbackData, m_operationTimeout, request, webRequest);
            webRequest.BeginGetRequestStream(OnGetRequestStreamComplete, result);
            return result;
        }
        /// <summary>
        /// Begins an asynchronous operation to send a request over the secure channel.
        /// </summary>
        public IAsyncResult BeginSendRequest(IServiceRequest request, AsyncCallback callback, object callbackData)
        {
            HttpWebRequest webRequest = (HttpWebRequest)HttpWebRequest.Create(m_url.ToString());
            webRequest.Method = "POST";

            if (m_settings.Configuration.UseBinaryEncoding)
            {
                webRequest.ContentType = "application/octet-stream";
            }
            else
            {
                StringBuilder contentType = new StringBuilder();
                contentType.Append("application/soap+xml; charset=\"utf-8\"; action=\"");
                contentType.Append(Namespaces.OpcUaWsdl);
                contentType.Append("/");

                string typeName = request.GetType().Name;
                int index = typeName.LastIndexOf("Request");
                contentType.Append(typeName.Substring(0, index)); ;
                contentType.Append("\"");

                webRequest.ContentType = contentType.ToString();
            }

            AsyncResult result = new AsyncResult(callback, callbackData, m_operationTimeout, request, webRequest);
            webRequest.BeginGetRequestStream(OnGetRequestStreamComplete, result);
            return result;
        }
        private async Task SendRequestAsync(IServiceRequest request, CancellationToken token = default(CancellationToken))
        {
            await this.sendingSemaphore.WaitAsync(token).ConfigureAwait(false);
            try
            {
                this.ThrowIfClosedOrNotOpening();
                Log.Trace($"Sending {request.GetType().Name} Handle: {request.RequestHeader.RequestHandle}");
                if (request is OpenSecureChannelRequest)
                {
                    await this.SendOpenSecureChannelRequestAsync((OpenSecureChannelRequest)request, token).ConfigureAwait(false);
                }
                else if (request is CloseSecureChannelRequest)
                {
                    await this.SendCloseSecureChannelRequestAsync((CloseSecureChannelRequest)request, token).ConfigureAwait(false);

                    // in this case, the endpoint does not actually send a response
                    TaskCompletionSource<IServiceResponse> tcs;
                    if (this.pendingCompletions.TryRemove(request.RequestHeader.RequestHandle, out tcs))
                    {
                        tcs.TrySetResult(new CloseSecureChannelResponse());
                    }
                }
                else
                {
                    await this.SendServiceRequestAsync(request, token).ConfigureAwait(false);
                }
            }
            catch (Exception ex)
            {
                Log.Warn($"Error sending {request.GetType().Name} Handle: {request.RequestHeader.RequestHandle}. {ex.Message}");
                throw;
            }
            finally
            {
                this.sendingSemaphore.Release();
            }
        }
        private async Task SendServiceRequestAsync(IServiceRequest request, CancellationToken token)
        {
            var bodyStream = SerializableBytes.CreateWritableStream();
            var bodyEncoder = new BinaryEncoder(bodyStream, this);
            try
            {
                ExpandedNodeId binaryEncodingId;
                if (!TypeToBinaryEncodingIdDictionary.TryGetValue(request.GetType(), out binaryEncodingId))
                {
                    throw new ServiceResultException(StatusCodes.BadDataTypeIdUnknown);
                }

                bodyEncoder.WriteNodeId(null, ExpandedNodeId.ToNodeId(binaryEncodingId, this.NamespaceUris));
                request.Encode(bodyEncoder);
                bodyStream.Position = 0;
                if (bodyStream.Length > this.RemoteMaxMessageSize)
                {
                    throw new ServiceResultException(StatusCodes.BadEncodingLimitsExceeded);
                }

                // write chunks
                int chunkCount = 0;
                int bodyCount = (int)(bodyStream.Length - bodyStream.Position);
                while (bodyCount > 0)
                {
                    chunkCount++;
                    if (this.RemoteMaxChunkCount > 0 && chunkCount > this.RemoteMaxChunkCount)
                    {
                        throw new ServiceResultException(StatusCodes.BadEncodingLimitsExceeded);
                    }

                    var stream = new MemoryStream(this.sendBuffer, 0, (int)this.RemoteReceiveBufferSize, true, true);
                    var encoder = new BinaryEncoder(stream, this);
                    try
                    {
                        // header
                        encoder.WriteUInt32(null, UaTcpMessageTypes.MSGF);
                        encoder.WriteUInt32(null, 0u);
                        encoder.WriteUInt32(null, this.ChannelId);

                        // symmetric security header
                        encoder.WriteUInt32(null, this.TokenId);

                        // detect new TokenId
                        if (this.TokenId != this.currentClientTokenId)
                        {
                            this.currentClientTokenId = this.TokenId;

                            // update signer and encrypter with new symmetric keys
                            if (this.symIsSigned)
                            {
                                this.symSigner.Key = this.clientSigningKey;
                                if (this.symIsEncrypted)
                                {
                                    this.currentClientEncryptingKey = this.clientEncryptingKey;
                                    this.currentClientInitializationVector = this.clientInitializationVector;
                                    this.symEncryptor = this.symEncryptionAlgorithm.CreateEncryptor(this.currentClientEncryptingKey, this.currentClientInitializationVector);
                                }
                            }
                        }

                        int plainHeaderSize = encoder.Position;

                        // sequence header
                        encoder.WriteUInt32(null, this.GetNextSequenceNumber());
                        encoder.WriteUInt32(null, request.RequestHeader.RequestHandle);

                        // body
                        int paddingHeaderSize;
                        int maxBodySize;
                        int bodySize;
                        int paddingSize;
                        int chunkSize;
                        if (this.symIsEncrypted)
                        {
                            paddingHeaderSize = this.symEncryptionBlockSize > 256 ? 2 : 1;
                            maxBodySize = ((((int)this.RemoteReceiveBufferSize - plainHeaderSize - this.symSignatureSize - paddingHeaderSize) / this.symEncryptionBlockSize) * this.symEncryptionBlockSize) - SequenceHeaderSize;
                            if (bodyCount < maxBodySize)
                            {
                                bodySize = bodyCount;
                                paddingSize = (this.symEncryptionBlockSize - ((SequenceHeaderSize + bodySize + paddingHeaderSize + this.symSignatureSize) % this.symEncryptionBlockSize)) % this.symEncryptionBlockSize;
                            }
                            else
                            {
                                bodySize = maxBodySize;
                                paddingSize = 0;
                            }

                            chunkSize = plainHeaderSize + (((SequenceHeaderSize + bodySize + paddingSize + paddingHeaderSize + this.symSignatureSize) / this.symEncryptionBlockSize) * this.symEncryptionBlockSize);
                        }
                        else
                        {
                            paddingHeaderSize = 0;
                            paddingSize = 0;
                            maxBodySize = (int)this.RemoteReceiveBufferSize - plainHeaderSize - this.symSignatureSize - SequenceHeaderSize;
                            if (bodyCount < maxBodySize)
                            {
                                bodySize = bodyCount;
                            }
                            else
                            {
                                bodySize = maxBodySize;
                            }

                            chunkSize = plainHeaderSize + SequenceHeaderSize + bodySize + this.symSignatureSize;
                        }

                        bodyStream.Read(this.sendBuffer, encoder.Position, bodySize);
                        encoder.Position += bodySize;
                        bodyCount -= bodySize;

                        // padding
                        if (this.symIsEncrypted)
                        {
                            var paddingByte = (byte)(paddingSize & 0xFF);
                            encoder.WriteByte(null, paddingByte);
                            for (int i = 0; i < paddingSize; i++)
                            {
                                encoder.WriteByte(null, paddingByte);
                            }

                            if (paddingHeaderSize == 2)
                            {
                                var extraPaddingByte = (byte)((paddingSize >> 8) & 0xFF);
                                encoder.WriteByte(null, extraPaddingByte);
                            }
                        }

                        // update message type and (encrypted) length
                        var position = encoder.Position;
                        encoder.Position = 3;
                        encoder.WriteByte(null, bodyCount > 0 ? (byte)'C' : (byte)'F');
                        encoder.WriteUInt32(null, (uint)chunkSize);
                        encoder.Position = position;

                        // signature
                        if (this.symIsSigned)
                        {
                            byte[] signature = this.symSigner.ComputeHash(this.sendBuffer, 0, position);
                            if (signature != null)
                            {
                                encoder.Write(signature, 0, signature.Length);
                            }
                        }

                        // encrypt
                        position = encoder.Position;
                        if (this.symIsEncrypted)
                        {
                            using (var symEncryptor = this.symEncryptionAlgorithm.CreateEncryptor(this.currentClientEncryptingKey, this.currentClientInitializationVector))
                            {
                                int inputCount = position - plainHeaderSize;
                                Debug.Assert(inputCount % symEncryptor.InputBlockSize == 0, "Input data is not an even number of encryption blocks.");
                                symEncryptor.TransformBlock(this.sendBuffer, plainHeaderSize, position - plainHeaderSize, this.sendBuffer, plainHeaderSize);
                                symEncryptor.TransformFinalBlock(this.sendBuffer, position, 0);
                            }
                        }

                        // pass buffer to transport
                        await this.SendAsync(this.sendBuffer, 0, position, token).ConfigureAwait(false);
                    }
                    finally
                    {
                        encoder.Dispose();
                    }
                }
            }
            finally
            {
                bodyEncoder.Dispose();
            }
        }