Beispiel #1
0
 internal sealed override bool Write(WriteBuffer buf)
 {
     Contract.Assume(Length < buf.UsableSize, $"Message of type {GetType().Name} has length {Length} which is bigger than the buffer ({buf.UsableSize})");
     if (buf.WriteSpaceLeft < Length)
         return false;
     WriteFully(buf);
     return true;
 }
Beispiel #2
0
        internal void WriteCancelRequest(int backendProcessId, int backendSecretKey)
        {
            const int len = sizeof(int) +  // Length
                            sizeof(int) +  // Cancel request code
                            sizeof(int) +  // Backend process id
                            sizeof(int);   // Backend secret key

            Debug.Assert(backendProcessId != 0);

            if (WriteBuffer.WriteSpaceLeft < len)
            {
                Flush(false).GetAwaiter().GetResult();
            }

            WriteBuffer.WriteInt32(len);
            WriteBuffer.WriteInt32(1234 << 16 | 5678);
            WriteBuffer.WriteInt32(backendProcessId);
            WriteBuffer.WriteInt32(backendSecretKey);
        }
Beispiel #3
0
        internal async Task WriteParse(string sql, string statementName, List <NpgsqlParameter> inputParameters, bool async)
        {
            Debug.Assert(statementName.All(c => c < 128));

            var queryByteLen = TextEncoding.GetByteCount(sql);

            if (WriteBuffer.WriteSpaceLeft < 1 + 4 + statementName.Length + 1)
            {
                await Flush(async);
            }

            var messageLength =
                sizeof(byte) +                        // Message code
                sizeof(int) +                         // Length
                statementName.Length +                // Statement name
                sizeof(byte) +                        // Null terminator for the statement name
                queryByteLen + sizeof(byte) +         // SQL query length plus null terminator
                sizeof(ushort) +                      // Number of parameters
                inputParameters.Count * sizeof(int);  // Parameter OIDs

            WriteBuffer.WriteByte(FrontendMessageCode.Parse);
            WriteBuffer.WriteInt32(messageLength - 1);
            WriteBuffer.WriteNullTerminatedString(statementName);

            await WriteBuffer.WriteString(sql, queryByteLen, async);

            if (WriteBuffer.WriteSpaceLeft < 1 + 2)
            {
                await Flush(async);
            }
            WriteBuffer.WriteByte(0); // Null terminator for the query
            WriteBuffer.WriteUInt16((ushort)inputParameters.Count);

            foreach (var p in inputParameters)
            {
                if (WriteBuffer.WriteSpaceLeft < 4)
                {
                    await Flush(async);
                }

                WriteBuffer.WriteInt32((int)p.Handler !.PostgresType.OID);
            }
        }
Beispiel #4
0
        internal async Task WritePassword(byte[] payload, int offset, int count, bool async, CancellationToken cancellationToken = default)
        {
            if (WriteBuffer.WriteSpaceLeft < sizeof(byte) + sizeof(int))
            {
                await WriteBuffer.Flush(async, cancellationToken);
            }
            WriteBuffer.WriteByte(FrontendMessageCode.Password);
            WriteBuffer.WriteInt32(sizeof(int) + count);

            if (count <= WriteBuffer.WriteSpaceLeft)
            {
                // The entire array fits in our WriteBuffer, copy it into the WriteBuffer as usual.
                WriteBuffer.WriteBytes(payload, offset, count);
                return;
            }

            await WriteBuffer.Flush(async, cancellationToken);

            await WriteBuffer.DirectWrite(new ReadOnlyMemory <byte>(payload, offset, count), async, cancellationToken);
        }
Beispiel #5
0
        internal async Task WritePassword(byte[] payload, int offset, int count, bool async)
        {
            if (WriteBuffer.WriteSpaceLeft < sizeof(byte) + sizeof(int))
            {
                await WriteBuffer.Flush(async);
            }
            WriteBuffer.WriteByte(FrontendMessageCode.Password);
            WriteBuffer.WriteInt32(sizeof(int) + count);

            if (count <= WriteBuffer.WriteSpaceLeft)
            {
                // The entire array fits in our WriteBuffer, copy it into the WriteBuffer as usual.
                WriteBuffer.WriteBytes(payload, offset, count);
                return;
            }

            await WriteBuffer.Flush(async);

            await WriteBuffer.DirectWrite(payload, offset, count, async);
        }
Beispiel #6
0
        internal sealed override async Task WriteWithLength(object value, WriteBuffer buf, LengthCache lengthCache, NpgsqlParameter parameter,
                                                            bool async, CancellationToken cancellationToken)
        {
            if (value == null || value is DBNull)
            {
                if (buf.WriteSpaceLeft < 4)
                {
                    await buf.Flush(async, cancellationToken);
                }
                buf.WriteInt32(-1);
                return;
            }

            var elementLen = ValidateAndGetLength(value, parameter);

            if (buf.WriteSpaceLeft < 4 + elementLen)
            {
                await buf.Flush(async, cancellationToken);
            }
            buf.WriteInt32(elementLen);
            Write(value, buf, parameter);
        }
 internal NpgsqlRawCopyStream(NpgsqlConnector connector, string copyCommand)
 {
     _connector = connector;
     _readBuf = connector.ReadBuffer;
     _writeBuf = connector.WriteBuffer;
     _connector.SendQuery(copyCommand);
     var msg = _connector.ReadMessage(DataRowLoadingMode.NonSequential);
     switch (msg.Code)
     {
     case BackendMessageCode.CopyInResponse:
         var copyInResponse = (CopyInResponseMessage) msg;
         IsBinary = copyInResponse.IsBinary;
         _canWrite = true;
         break;
     case BackendMessageCode.CopyOutResponse:
         var copyOutResponse = (CopyOutResponseMessage) msg;
         IsBinary = copyOutResponse.IsBinary;
         _canRead = true;
         break;
     default:
         throw _connector.UnexpectedMessageReceived(msg.Code);
     }
 }
Beispiel #8
0
        internal async Task WriteQuery(string sql, bool async)
        {
            var queryByteLen = TextEncoding.GetByteCount(sql);

            if (WriteBuffer.WriteSpaceLeft < 1 + 4)
            {
                await Flush(async);
            }

            WriteBuffer.WriteByte(FrontendMessageCode.Query);
            WriteBuffer.WriteInt32(
                sizeof(int) +         // Message length (including self excluding code)
                queryByteLen +        // Query byte length
                sizeof(byte));        // Null terminator

            await WriteBuffer.WriteString(sql, queryByteLen, async);

            if (WriteBuffer.WriteSpaceLeft < 1)
            {
                await Flush(async);
            }
            WriteBuffer.WriteByte(0);  // Null terminator
        }
Beispiel #9
0
 /// <param name="value">the value to be written</param>
 /// <param name="buf"></param>
 /// <param name="lengthCache">a cache in which to store length(s) of values to be written</param>
 /// <param name="parameter">
 /// the <see cref="NpgsqlParameter"/> containing <paramref name="value"/>. Consulted for settings
 /// which impact how to send the parameter, e.g. <see cref="NpgsqlParameter.Size"/>. Can be null.
 /// <see cref="NpgsqlParameter.Size"/>.
 /// </param>
 public abstract void PrepareWrite(object value, WriteBuffer buf, LengthCache lengthCache, [CanBeNull] NpgsqlParameter parameter);
Beispiel #10
0
 public override void PrepareWrite(object value, WriteBuffer buf, LengthCache lengthCache, NpgsqlParameter parameter = null)
 {
     Contract.Requires(buf != null);
     Contract.Requires(value != null);
 }
        async Task AuthenticateSASL(List <string> mechanisms, bool async, CancellationToken cancellationToken)
        {
            // At the time of writing PostgreSQL only supports SCRAM-SHA-256
            if (!mechanisms.Contains("SCRAM-SHA-256"))
            {
                throw new NpgsqlException("No supported SASL mechanism found (only SCRAM-SHA-256 is supported for now). " +
                                          "Mechanisms received from server: " + string.Join(", ", mechanisms));
            }
            var mechanism = "SCRAM-SHA-256";

            var passwd = GetPassword() ??
                         throw new NpgsqlException($"No password has been provided but the backend requires one (in SASL/{mechanism})");

            // Assumption: the write buffer is big enough to contain all our outgoing messages
            var clientNonce = GetNonce();

            await new SASLInitialResponseMessage(mechanism, PGUtil.UTF8Encoding.GetBytes("n,,n=*,r=" + clientNonce))
            .Write(WriteBuffer, async, cancellationToken);
            await WriteBuffer.Flush(async, cancellationToken);

            var saslContinueMsg = await ReadExpecting <AuthenticationSASLContinueMessage>(async);

            if (saslContinueMsg.AuthRequestType != AuthenticationRequestType.AuthenticationSASLContinue)
            {
                throw new NpgsqlException("[SASL] AuthenticationSASLFinal message expected");
            }
            var firstServerMsg = new AuthenticationSCRAMServerFirstMessage(saslContinueMsg.Payload);

            if (!firstServerMsg.Nonce.StartsWith(clientNonce))
            {
                throw new InvalidOperationException("[SCRAM] Malformed SCRAMServerFirst message: server nonce doesn't start with client nonce");
            }

            var scramFinalClientMsg = new SCRAMClientFinalMessage(passwd, firstServerMsg.Nonce, firstServerMsg.Salt, firstServerMsg.Iteration, clientNonce);
            await scramFinalClientMsg.Write(WriteBuffer, async, cancellationToken);

            await WriteBuffer.Flush(async, cancellationToken);

            var saslFinalServerMsg = await ReadExpecting <AuthenticationSASLFinalMessage>(async);

            if (saslFinalServerMsg.AuthRequestType != AuthenticationRequestType.AuthenticationSASLFinal)
            {
                throw new NpgsqlException("[SASL] AuthenticationSASLFinal message expected");
            }
            var scramFinalServerMsg = new AuthenticationSCRAMServerFinalMessage(saslFinalServerMsg.Payload);

            if (scramFinalServerMsg.ServerSignature != Convert.ToBase64String(scramFinalClientMsg.ServerSignature))
            {
                throw new NpgsqlException("[SCRAM] Unable to verify server signature");
            }

            var okMsg = await ReadExpecting <AuthenticationRequestMessage>(async);

            if (okMsg.AuthRequestType != AuthenticationRequestType.AuthenticationOk)
            {
                throw new NpgsqlException("[SASL] Expected AuthenticationOK message");
            }

            string GetNonce()
            {
                var nonceLength = 18;
                var rncProvider = RandomNumberGenerator.Create();
                var nonceBytes  = new byte[nonceLength];

                rncProvider.GetBytes(nonceBytes);
                return(Convert.ToBase64String(nonceBytes));
            }
        }
Beispiel #12
0
 public abstract void Write(object value, WriteBuffer buf, NpgsqlParameter parameter);
Beispiel #13
0
 internal void Flush() => WriteBuffer.Flush(false).GetAwaiter().GetResult();
Beispiel #14
0
 internal Task Flush(bool async) => WriteBuffer.Flush(async);
Beispiel #15
0
 public void SetUp()
 {
     Underlying = new MemoryStream();
     WriteBuffer = new WriteBuffer(null, Underlying, ReadBuffer.DefaultBufferSize, PGUtil.UTF8Encoding);
 }
Beispiel #16
0
 /// <param name="buf">the buffer into which to write the message.</param>
 /// <returns>
 /// Whether there was enough space in the buffer to contain the entire message.
 /// If false, the buffer should be flushed and write should be called again.
 /// </returns>
 internal abstract bool Write(WriteBuffer buf);
Beispiel #17
0
 /// <param name="buf">the buffer into which to write the message.</param>
 /// <returns>
 /// Whether there was enough space in the buffer to contain the entire message.
 /// If false, the buffer should be flushed and write should be called again.
 /// </returns>
 internal abstract bool Write(WriteBuffer buf);
Beispiel #18
0
 protected abstract Task Write(object value, WriteBuffer buf, LengthCache lengthCache, NpgsqlParameter parameter,
                               bool async, CancellationToken cancellationToken);
Beispiel #19
0
 /// <summary>
 /// Writes the message contents into the buffer.
 /// </summary>
 internal abstract void WriteFully(WriteBuffer buf);
 void Cleanup()
 {
     _connector = null;
     _readBuf = null;
     _writeBuf = null;
     _isDisposed = true;
 }
Beispiel #21
0
 internal Task Flush(bool async, CancellationToken cancellationToken = default) => WriteBuffer.Flush(async, cancellationToken);
Beispiel #22
0
 protected abstract void Write(object value, WriteBuffer buf, NpgsqlParameter parameter = null);
Beispiel #23
0
 /// <param name="buf">the buffer into which to write the message.</param>
 /// <param name="async"></param>
 /// <param name="cancellationToken"></param>
 /// <returns>
 /// Whether there was enough space in the buffer to contain the entire message.
 /// If false, the buffer should be flushed and write should be called again.
 /// </returns>
 internal abstract Task Write(WriteBuffer buf, bool async, CancellationToken cancellationToken);
Beispiel #24
0
 internal abstract Task WriteWithLength([CanBeNull] object value, WriteBuffer buf, LengthCache lengthCache,
                                        NpgsqlParameter parameter,
                                        bool async, CancellationToken cancellationToken);
Beispiel #25
0
        internal async Task WriteBind(
            List <NpgsqlParameter> inputParameters,
            string portal,
            string statement,
            bool allResultTypesAreUnknown,
            bool[]?unknownResultTypeList,
            bool async)
        {
            Debug.Assert(statement.All(c => c < 128));
            Debug.Assert(portal.All(c => c < 128));

            var headerLength =
                sizeof(byte) +                        // Message code
                sizeof(int) +                         // Message length
                sizeof(byte) +                        // Portal is always empty (only a null terminator)
                statement.Length + sizeof(byte) +     // Statement name plus null terminator
                sizeof(short);                        // Number of parameter format codes that follow

            if (WriteBuffer.WriteSpaceLeft < headerLength)
            {
                Debug.Assert(WriteBuffer.Size >= headerLength, "Write buffer too small for Bind header");
                await Flush(async);
            }

            var formatCodesSum = 0;
            var paramsLength   = 0;

            foreach (var p in inputParameters)
            {
                formatCodesSum += (int)p.FormatCode;
                p.LengthCache?.Rewind();
                paramsLength += p.ValidateAndGetLength();
            }

            var formatCodeListLength = formatCodesSum == 0 ? 0 : formatCodesSum == inputParameters.Count ? 1 : inputParameters.Count;

            var messageLength = headerLength +
                                sizeof(short) * formatCodeListLength +                // List of format codes
                                sizeof(short) +                                       // Number of parameters
                                sizeof(int) * inputParameters.Count +                 // Parameter lengths
                                paramsLength +                                        // Parameter values
                                sizeof(short) +                                       // Number of result format codes
                                sizeof(short) * (unknownResultTypeList?.Length ?? 1); // Result format codes

            WriteBuffer.WriteByte(FrontendMessageCode.Bind);
            WriteBuffer.WriteInt32(messageLength - 1);
            Debug.Assert(portal == string.Empty);
            WriteBuffer.WriteByte(0);  // Portal is always empty

            WriteBuffer.WriteNullTerminatedString(statement);
            WriteBuffer.WriteInt16(formatCodeListLength);

            // 0 length implicitly means all-text, 1 means all-binary, >1 means mix-and-match
            if (formatCodeListLength == 1)
            {
                if (WriteBuffer.WriteSpaceLeft < 2)
                {
                    await Flush(async);
                }
                WriteBuffer.WriteInt16((short)FormatCode.Binary);
            }
            else if (formatCodeListLength > 1)
            {
                foreach (var p in inputParameters)
                {
                    if (WriteBuffer.WriteSpaceLeft < 2)
                    {
                        await Flush(async);
                    }
                    WriteBuffer.WriteInt16((short)p.FormatCode);
                }
            }

            if (WriteBuffer.WriteSpaceLeft < 2)
            {
                await Flush(async);
            }

            WriteBuffer.WriteInt16(inputParameters.Count);

            foreach (var param in inputParameters)
            {
                param.LengthCache?.Rewind();
                await param.WriteWithLength(WriteBuffer, async);
            }

            if (unknownResultTypeList != null)
            {
                if (WriteBuffer.WriteSpaceLeft < 2 + unknownResultTypeList.Length * 2)
                {
                    await Flush(async);
                }
                WriteBuffer.WriteInt16(unknownResultTypeList.Length);
                foreach (var t in unknownResultTypeList)
                {
                    WriteBuffer.WriteInt16(t ? 0 : 1);
                }
            }
            else
            {
                if (WriteBuffer.WriteSpaceLeft < 4)
                {
                    await Flush(async);
                }
                WriteBuffer.WriteInt16(1);
                WriteBuffer.WriteInt16(allResultTypesAreUnknown ? 0 : 1);
            }
        }
Beispiel #26
0
 /// <summary>
 /// Writes the message contents into the buffer.
 /// </summary>
 internal abstract void WriteFully(WriteBuffer buf);
Beispiel #27
0
 internal Task WriteWithLength(WriteBuffer buf, bool async, CancellationToken cancellationToken)
 => Handler.WriteWithLength(Value, buf, LengthCache, this, async, cancellationToken);