/// <inheritdoc/> /// <seealso href="https://reference.opcfoundation.org/v104/Core/docs/Part4/5.5.2/">OPC UA specification Part 4: Services, 5.5.2</seealso> protected override async Task OnOpenAsync(CancellationToken token = default) { await base.OnOpenAsync(token).ConfigureAwait(false); var options = new TransportConnectionOptions { ReceiveBufferSize = RemoteReceiveBufferSize, SendBufferSize = RemoteSendBufferSize, MaxMessageSize = RemoteMaxMessageSize, MaxChunkCount = RemoteMaxChunkCount }; _conversation = await StackProfile.ConversationProvider.CreateAsync(RemoteEndpoint, LocalDescription, options, CertificateStore, _logger, token).ConfigureAwait(false); token.ThrowIfCancellationRequested(); _receiveResponsesTask = ReceiveResponsesAsync(_channelCts.Token); var openSecureChannelRequest = new OpenSecureChannelRequest { ClientProtocolVersion = ProtocolVersion, RequestType = SecurityTokenRequestType.Issue, SecurityMode = RemoteEndpoint.SecurityMode, ClientNonce = _conversation !.GetNextNonce(), RequestedLifetime = _tokenRequestedLifetime }; var openSecureChannelResponse = (OpenSecureChannelResponse) await RequestAsync(openSecureChannelRequest).ConfigureAwait(false); if (openSecureChannelResponse.ServerProtocolVersion < ProtocolVersion) { throw new ServiceResultException(StatusCodes.BadProtocolVersionUnsupported); } }
/// <inheritdoc/> protected override async Task OnOpenAsync(CancellationToken token) { token.ThrowIfCancellationRequested(); _connection = await StackProfile.TransportConnectionProvider.ConnectAsync(RemoteEndpoint.EndpointUrl !, token).ConfigureAwait(false); var localOptions = new TransportConnectionOptions { ReceiveBufferSize = LocalReceiveBufferSize, SendBufferSize = LocalSendBufferSize, MaxMessageSize = LocalMaxMessageSize, MaxChunkCount = LocalMaxChunkCount }; var remoteOptions = await _connection.OpenAsync(ProtocolVersion, localOptions, token).ConfigureAwait(false); RemoteSendBufferSize = remoteOptions.SendBufferSize; RemoteReceiveBufferSize = remoteOptions.ReceiveBufferSize; RemoteMaxMessageSize = remoteOptions.MaxMessageSize; RemoteMaxChunkCount = remoteOptions.MaxChunkCount; }
/// <summary> /// Opens the connection. This includes the hello message handshake. /// </summary> /// <remakes> /// The underlying network client is already opened before this class is /// constructed. The /// connection is closed with <see cref="IAsyncDisposable.DisposeAsync"/> /// method. /// </remakes> /// <param name="protocolVersion">The protocol version.</param> /// <param name="localOptions">The requested transport connection options.</param> /// <param name="token">A cancellation token used to propagate notification that this operation should be canceled.</param> /// <returns>The transport connection options to be used.</returns> /// <seealso href="https://reference.opcfoundation.org/v104/Core/docs/Part6/7.1.2/">OPC UA specification Part 6: Mappings, 7.1.2</seealso> public async Task <TransportConnectionOptions> OpenAsync(uint protocolVersion, TransportConnectionOptions localOptions, CancellationToken token) { var sendBuffer = new byte[MinBufferSize]; var receiveBuffer = new byte[MinBufferSize]; // send 'hello'. int count; using (var encoder = new BinaryEncoder(new MemoryStream(sendBuffer, 0, MinBufferSize, true, false))) { encoder.WriteUInt32(null, MessageTypes.HELF); encoder.WriteUInt32(null, 0u); encoder.WriteUInt32(null, protocolVersion); encoder.WriteUInt32(null, localOptions.ReceiveBufferSize); encoder.WriteUInt32(null, localOptions.SendBufferSize); encoder.WriteUInt32(null, localOptions.MaxMessageSize); encoder.WriteUInt32(null, localOptions.MaxChunkCount); encoder.WriteString(null, Uri.ToString()); count = encoder.Position; encoder.Position = 4; encoder.WriteUInt32(null, (uint)count); encoder.Position = count; await SendAsync(sendBuffer, 0, count, token).ConfigureAwait(false); } // receive response count = await ReceiveAsync(receiveBuffer, 0, MinBufferSize, token).ConfigureAwait(false); if (count == 0) { throw new ObjectDisposedException("socket"); } // decode 'ack' or 'err'. using (var decoder = new BinaryDecoder(new MemoryStream(receiveBuffer, 0, count, false, false))) { var type = decoder.ReadUInt32(null); var len = decoder.ReadUInt32(null); if (type == MessageTypes.ACKF) { var remoteProtocolVersion = decoder.ReadUInt32(null); if (remoteProtocolVersion < protocolVersion) { throw new ServiceResultException(StatusCodes.BadProtocolVersionUnsupported); } var remoteOptions = new TransportConnectionOptions { SendBufferSize = decoder.ReadUInt32(null), ReceiveBufferSize = decoder.ReadUInt32(null), MaxMessageSize = decoder.ReadUInt32(null), MaxChunkCount = decoder.ReadUInt32(null) }; return(remoteOptions); } else if (type == MessageTypes.ERRF) { var statusCode = decoder.ReadUInt32(null); var message = decoder.ReadString(null); if (message != null) { throw new ServiceResultException(statusCode, message); } throw new ServiceResultException(statusCode); } throw new InvalidOperationException($"{nameof(UaClientConnection)}.{nameof(OpenAsync)} received unexpected message type."); } }
/// <inheritdoc /> public async Task <IConversation> CreateAsync(EndpointDescription remoteEndpoint, ApplicationDescription localDescription, TransportConnectionOptions options, ICertificateStore?certificateStore, ILogger?logger, CancellationToken token) { var conversation = new UaSecureConversation(localDescription, options, certificateStore, logger) { SecurityMode = remoteEndpoint.SecurityMode }; await conversation.SetRemoteCertificateAsync(remoteEndpoint.SecurityPolicyUri, remoteEndpoint.ServerCertificate, token).ConfigureAwait(false); return(conversation); }