Esempio n. 1
0
        /// <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;
            var encoder = new BinaryEncoder(new MemoryStream(sendBuffer, 0, MinBufferSize, true, false));

            try
            {
                encoder.WriteUInt32(null, UaTcpMessageTypes.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);
            }
            finally
            {
                encoder.Dispose();
            }

            // receive response
            count = await ReceiveAsync(receiveBuffer, 0, MinBufferSize, token).ConfigureAwait(false);

            if (count == 0)
            {
                throw new ObjectDisposedException("socket");
            }

            // decode 'ack' or 'err'.
            var decoder = new BinaryDecoder(new MemoryStream(receiveBuffer, 0, count, false, false));

            try
            {
                var type = decoder.ReadUInt32(null);
                var len  = decoder.ReadUInt32(null);
                if (type == UaTcpMessageTypes.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 == UaTcpMessageTypes.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.");
            }
            finally
            {
                decoder.Dispose();
            }
        }
Esempio n. 2
0
        /// <inheritdoc/>
        protected override async Task OnOpenAsync(CancellationToken token)
        {
            token.ThrowIfCancellationRequested();
            this.sendBuffer    = new byte[MinBufferSize];
            this.receiveBuffer = new byte[MinBufferSize];

            this.tcpClient = new TcpClient {
                NoDelay = true
            };
            var uri = new UriBuilder(this.RemoteEndpoint.EndpointUrl);

            await this.tcpClient.ConnectAsync(uri.Host, uri.Port).WithTimeoutAfter(ConnectTimeout).ConfigureAwait(false);

            this.stream = this.tcpClient.GetStream();

            // send 'hello'.
            int count;
            var encoder = new BinaryEncoder(new MemoryStream(this.sendBuffer, 0, MinBufferSize, true, false));

            try
            {
                encoder.WriteUInt32(null, UaTcpMessageTypes.HELF);
                encoder.WriteUInt32(null, 0u);
                encoder.WriteUInt32(null, ProtocolVersion);
                encoder.WriteUInt32(null, this.LocalReceiveBufferSize);
                encoder.WriteUInt32(null, this.LocalSendBufferSize);
                encoder.WriteUInt32(null, this.LocalMaxMessageSize);
                encoder.WriteUInt32(null, this.LocalMaxChunkCount);
                encoder.WriteString(null, uri.ToString());
                count            = encoder.Position;
                encoder.Position = 4;
                encoder.WriteUInt32(null, (uint)count);
                encoder.Position = count;

                await this.SendAsync(this.sendBuffer, 0, count, token).ConfigureAwait(false);
            }
            finally
            {
                encoder.Dispose();
            }

            // receive response
            count = await this.ReceiveAsync(this.receiveBuffer, 0, MinBufferSize, token).ConfigureAwait(false);

            if (count == 0)
            {
                throw new ObjectDisposedException("socket");
            }

            // decode 'ack' or 'err'.
            var decoder = new BinaryDecoder(new MemoryStream(this.receiveBuffer, 0, count, false, false));

            try
            {
                var type = decoder.ReadUInt32(null);
                var len  = decoder.ReadUInt32(null);
                if (type == UaTcpMessageTypes.ACKF)
                {
                    var remoteProtocolVersion = decoder.ReadUInt32(null);
                    if (remoteProtocolVersion < ProtocolVersion)
                    {
                        throw new ServiceResultException(StatusCodes.BadProtocolVersionUnsupported);
                    }

                    this.RemoteSendBufferSize    = decoder.ReadUInt32(null);
                    this.RemoteReceiveBufferSize = decoder.ReadUInt32(null);
                    this.RemoteMaxMessageSize    = decoder.ReadUInt32(null);
                    this.RemoteMaxChunkCount     = decoder.ReadUInt32(null);
                    return;
                }
                else if (type == UaTcpMessageTypes.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("UaTcpTransportChannel.OnOpenAsync received unexpected message type.");
            }
            finally
            {
                decoder.Dispose();
            }
        }