/// <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); }
/// <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!"); } }
/// <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(); } }