Beispiel #1
0
        internal static async ValueTask Write(ConnectionContext connection, GrainId grainId, NetworkProtocolVersion protocolVersion, SiloAddress siloAddress)
        {
            var output       = connection.Transport.Output;
            var outputWriter = new PrefixingBufferWriter <byte, PipeWriter>(output, sizeof(int), 1024, MemoryPool <byte> .Shared);
            var writer       = new BinaryTokenStreamWriter2 <PrefixingBufferWriter <byte, PipeWriter> >(outputWriter);

            writer.Write(grainId);
            writer.Write((byte)protocolVersion);

            if (siloAddress is null)
            {
                writer.WriteNull();
            }
            else
            {
                writer.Write((byte)SerializationTokenType.SiloAddress);
                writer.Write(siloAddress);
            }

            writer.Commit();

            var length = outputWriter.CommittedBytes;

            if (length > MaxPreambleLength)
            {
                throw new InvalidOperationException($"Created preamble of length {length}, which is greater than maximum allowed size of {MaxPreambleLength}.");
            }

            WriteLength(outputWriter, length);

            var flushResult = await output.FlushAsync();

            if (flushResult.IsCanceled)
            {
                throw new OperationCanceledException("Flush canceled");
            }

            return;
        }
Beispiel #2
0
        protected override async Task RunInternal()
        {
            Exception error = default;

            try
            {
                if (this.connectionOptions.ProtocolVersion == NetworkProtocolVersion.Version1)
                {
                    // This version of the protocol does not support symmetric preamble, so either send or receive preamble depending on
                    // Whether or not this is an inbound or outbound connection.
                    if (this.RemoteSiloAddress is null)
                    {
                        // Inbound connection
                        var protocolVersion = await ReadPreamble();

                        // To support graceful transition to higher protocol versions, send a preamble if the remote endpoint supports it.
                        if (protocolVersion >= NetworkProtocolVersion.Version2)
                        {
                            await WritePreamble();
                        }
                    }
                    else
                    {
                        // Outbound connection
                        await WritePreamble();
                    }
                }
                else
                {
                    // Later versions of the protocol send and receive preamble at both ends of the connection.
                    if (this.RemoteSiloAddress is null)
                    {
                        // Inbound connection
                        var protocolVersion = await ReadPreamble();

                        // To support graceful transition from lower protocol versions, only send a preamble if the remote endpoint supports it.
                        if (protocolVersion >= NetworkProtocolVersion.Version2)
                        {
                            await WritePreamble();
                        }
                    }
                    else
                    {
                        // Outbound connection
                        await Task.WhenAll(ReadPreamble().AsTask(), WritePreamble());
                    }
                }

                this.MessageReceivedCounter = MessagingStatisticsGroup.GetMessageReceivedCounter(this.RemoteSiloAddress);
                this.MessageSentCounter     = MessagingStatisticsGroup.GetMessageSendCounter(this.RemoteSiloAddress);
                await base.RunInternal();
            }
            catch (Exception exception) when((error = exception) is null)
            {
                Debug.Fail("Execution should not be able to reach this point.");
            }
            finally
            {
                if (!(this.RemoteSiloAddress is null))
                {
                    this.connectionManager.OnConnectionTerminated(this.RemoteSiloAddress, this, error);
                }
            }

            async Task WritePreamble()
            {
                await ConnectionPreamble.Write(
                    this.Context,
                    Constants.SiloDirectConnectionId,
                    this.connectionOptions.ProtocolVersion,
                    this.LocalSiloAddress);
            }

            async ValueTask <NetworkProtocolVersion> ReadPreamble()
            {
                var(grainId, protocolVersion, siloAddress) = await ConnectionPreamble.Read(this.Context);

                if (!grainId.Equals(Constants.SiloDirectConnectionId))
                {
                    throw new InvalidOperationException("Unexpected non-proxied connection on silo endpoint.");
                }

                if (siloAddress is object)
                {
                    this.RemoteSiloAddress = siloAddress;
                    this.connectionManager.OnConnected(siloAddress, this);
                }

                this.RemoteProtocolVersion = protocolVersion;

                return(protocolVersion);
            }
        }