Exemplo n.º 1
0
 public NpgsqlParameterStatus(Stream stream)
 {
     //Read message length
     PGUtil.EatStreamBytes(stream, 4);
     Parameter      = PGUtil.ReadString(stream);
     ParameterValue = PGUtil.ReadString(stream);
 }
 public FieldDataV2(Stream stream, NpgsqlBackendTypeMapping typeMapping)
 {
     Name         = PGUtil.ReadString(stream);
     TypeInfo     = typeMapping[TypeOID = PGUtil.ReadInt32(stream)];
     TypeSize     = PGUtil.ReadInt16(stream);
     TypeModifier = PGUtil.ReadInt32(stream);
 }
 public FieldDataV3(Stream stream, NpgsqlBackendTypeMapping typeMapping)
 {
     Name     = PGUtil.ReadString(stream);
     TableOID = PGUtil.ReadInt32(stream);
     ColumnAttributeNumber = PGUtil.ReadInt16(stream);
     TypeInfo     = typeMapping[TypeOID = PGUtil.ReadInt32(stream)];
     TypeSize     = PGUtil.ReadInt16(stream);
     TypeModifier = PGUtil.ReadInt32(stream);
     FormatCode   = (FormatCode)PGUtil.ReadInt16(stream);
 }
        public void ReadFromStream(Stream inputStream, Encoding encoding)
        {
            //Read message length
            Byte[] inputBuffer = new Byte[4];
            PGUtil.CheckedStreamRead(inputStream, inputBuffer, 0, 4);

            Int32 messageLength = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(inputBuffer, 0));

            _parameter      = PGUtil.ReadString(inputStream, encoding);
            _parameterValue = PGUtil.ReadString(inputStream, encoding);
        }
Exemplo n.º 5
0
        private void ReadFromStream_Ver_2(Stream input_stream, Encoding encoding, NpgsqlBackendTypeMapping type_mapping)
        {
            NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ReadFromStream_Ver_2");

            Byte[] input_buffer = new Byte[10]; // Max read will be 4 + 2 + 4

            // Read the number of fields.
            input_stream.Read(input_buffer, 0, 2);
            Int16 num_fields = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(input_buffer, 0));


            // Temporary FieldData object to get data from stream and put in array.
            NpgsqlRowDescriptionFieldData fd;

            fields_data  = new NpgsqlRowDescriptionFieldData[num_fields];
            fields_index = new string[num_fields];

            field_name_index_table = new Hashtable(num_fields);


            // Now, iterate through each field getting its data.
            for (Int16 i = 0; i < num_fields; i++)
            {
                fd = new NpgsqlRowDescriptionFieldData();

                // Set field name.
                fd.name = PGUtil.ReadString(input_stream, encoding);

                // Read type_oid(Int32), type_size(Int16), type_modifier(Int32)
                input_stream.Read(input_buffer, 0, 4 + 2 + 4);

                fd.type_oid      = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(input_buffer, 0));
                fd.type_info     = type_mapping[fd.type_oid];
                fd.type_size     = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(input_buffer, 4));
                fd.type_modifier = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(input_buffer, 6));

                // Add field data to array.
                fields_data[i] = fd;

                fields_index[i] = fd.name;

                if (!field_name_index_table.ContainsKey(fd.name))
                {
                    field_name_index_table.Add(fd.name, i);
                }
            }
        }
Exemplo n.º 6
0
 public CompletedResponse(Stream stream)
 {
     string[] tokens = PGUtil.ReadString(stream).Split();
     if (tokens.Length > 1)
     {
         int rowsAffected;
         if (int.TryParse(tokens[tokens.Length - 1], out rowsAffected))
         {
             _rowsAffected = rowsAffected;
         }
         else
         {
             _rowsAffected = null;
         }
     }
     _lastInsertedOID = (tokens.Length > 2 && tokens[0].Trim().ToUpperInvariant() == "INSERT")
                            ? long.Parse(tokens[1])
                            : (long?)null;
 }
Exemplo n.º 7
0
        private void ReadFromStream_Ver_3(Stream input_stream, Encoding encoding, NpgsqlBackendTypeMapping type_mapping)
        {
            NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ReadFromStream_Ver_3");

            Byte[] input_buffer = new Byte[4]; // Max read will be 4 + 2 + 4 + 2 + 4 + 2

            // Read the length of message.
            // [TODO] Any use for now?
            PGUtil.ReadInt32(input_stream, input_buffer);
            Int16 num_fields = PGUtil.ReadInt16(input_stream, input_buffer);

            // Temporary FieldData object to get data from stream and put in array.
            NpgsqlRowDescriptionFieldData fd;

            fields_data            = new NpgsqlRowDescriptionFieldData[num_fields];
            fields_index           = new string[num_fields];
            field_name_index_table = new Hashtable(num_fields);

            for (Int16 i = 0; i < num_fields; i++)
            {
                fd = new NpgsqlRowDescriptionFieldData();

                fd.name      = PGUtil.ReadString(input_stream, encoding);
                fd.table_oid = PGUtil.ReadInt32(input_stream, input_buffer);
                fd.column_attribute_number = PGUtil.ReadInt16(input_stream, input_buffer);
                fd.type_oid      = PGUtil.ReadInt32(input_stream, input_buffer);
                fd.type_info     = type_mapping[fd.type_oid];
                fd.type_size     = PGUtil.ReadInt16(input_stream, input_buffer);
                fd.type_modifier = PGUtil.ReadInt32(input_stream, input_buffer);
                fd.format_code   = (FormatCode)PGUtil.ReadInt16(input_stream, input_buffer);

                fields_data[i]  = fd;
                fields_index[i] = fd.name;

                if (!field_name_index_table.ContainsKey(fd.name))
                {
                    field_name_index_table.Add(fd.name, i);
                }
            }
        }
Exemplo n.º 8
0
        private void ReadFromStream_Ver_2(Stream inputStream, Encoding encoding)
        {
            NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ReadFromStream_Ver_2");

            String Raw;

            String[] Parts;

            Raw = PGUtil.ReadString(inputStream, encoding);

            Parts = Raw.Split(new char[] { ':' }, 2);

            if (Parts.Length == 2)
            {
                _severity = Parts[0].Trim();
                _message  = Parts[1].Trim();
            }
            else
            {
                _message = Parts[0].Trim();
            }
        }
        protected IEnumerable <IServerResponseObject> ProcessBackendResponses_Ver_2(NpgsqlConnector context)
        {
            NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ProcessBackendResponses");

            using (new ContextResetter(context))
            {
                Stream             stream   = context.Stream;
                NpgsqlMediator     mediator = context.Mediator;
                List <NpgsqlError> errors   = new List <NpgsqlError>();

                for (;;)
                {
                    // Check the first Byte of response.
                    switch ((BackEndMessageCode)stream.ReadByte())
                    {
                    case BackEndMessageCode.ErrorResponse:

                    {
                        NpgsqlError error = new NpgsqlError(context.BackendProtocolVersion, stream);
                        error.ErrorSql = mediator.GetSqlSent();

                        errors.Add(error);

                        NpgsqlEventLog.LogMsg(resman, "Log_ErrorResponse", LogLevel.Debug, error.Message);
                    }

                        // Return imediately if it is in the startup state or connected state as
                        // there is no more messages to consume.
                        // Possible error in the NpgsqlStartupState:
                        //        Invalid password.
                        // Possible error in the NpgsqlConnectedState:
                        //        No pg_hba.conf configured.

                        if (!context.RequireReadyForQuery)
                        {
                            throw new NpgsqlException(errors);
                        }

                        break;

                    case BackEndMessageCode.AuthenticationRequest:
                        NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "AuthenticationRequest");
                        AuthenticationRequestType authType = (AuthenticationRequestType)PGUtil.ReadInt32(stream);
                        switch (authType)
                        {
                        case AuthenticationRequestType.AuthenticationOk:
                            NpgsqlEventLog.LogMsg(resman, "Log_AuthenticationOK", LogLevel.Debug);
                            break;

                        case AuthenticationRequestType.AuthenticationClearTextPassword:
                            NpgsqlEventLog.LogMsg(resman, "Log_AuthenticationClearTextRequest", LogLevel.Debug);
                            // Send the PasswordPacket.
                            ChangeState(context, NpgsqlStartupState.Instance);
                            context.Authenticate(context.Password);
                            context.Stream.Flush();

                            break;

                        case AuthenticationRequestType.AuthenticationMD5Password:
                            NpgsqlEventLog.LogMsg(resman, "Log_AuthenticationMD5Request", LogLevel.Debug);
                            // Now do the "MD5-Thing"
                            // for this the Password has to be:
                            // 1. md5-hashed with the username as salt
                            // 2. md5-hashed again with the salt we get from the backend

                            MD5 md5 = MD5.Create();

                            // 1.
                            byte[] passwd       = context.Password;
                            byte[] saltUserName = BackendEncoding.UTF8Encoding.GetBytes(context.UserName);

                            byte[] crypt_buf = new byte[passwd.Length + saltUserName.Length];

                            passwd.CopyTo(crypt_buf, 0);
                            saltUserName.CopyTo(crypt_buf, passwd.Length);

                            StringBuilder sb         = new StringBuilder();
                            byte[]        hashResult = md5.ComputeHash(crypt_buf);
                            foreach (byte b in hashResult)
                            {
                                sb.Append(b.ToString("x2"));
                            }

                            String prehash = sb.ToString();

                            byte[] prehashbytes = BackendEncoding.UTF8Encoding.GetBytes(prehash);

                            byte[] saltServer = new byte[4];
                            stream.Read(saltServer, 0, 4);
                            // Send the PasswordPacket.
                            ChangeState(context, NpgsqlStartupState.Instance);

                            // 2.

                            crypt_buf = new byte[prehashbytes.Length + saltServer.Length];
                            prehashbytes.CopyTo(crypt_buf, 0);
                            saltServer.CopyTo(crypt_buf, prehashbytes.Length);

                            sb         = new StringBuilder("md5"); // This is needed as the backend expects md5 result starts with "md5"
                            hashResult = md5.ComputeHash(crypt_buf);
                            foreach (byte b in hashResult)
                            {
                                sb.Append(b.ToString("x2"));
                            }

                            context.Authenticate(BackendEncoding.UTF8Encoding.GetBytes(sb.ToString()));
                            context.Stream.Flush();

                            break;

                        default:
                            // Only AuthenticationClearTextPassword and AuthenticationMD5Password supported for now.
                            errors.Add(
                                new NpgsqlError(context.BackendProtocolVersion,
                                                String.Format(resman.GetString("Exception_AuthenticationMethodNotSupported"), authType)));
                            throw new NpgsqlException(errors);
                        }
                        break;

                    case BackEndMessageCode.RowDescription:
                        yield return(new NpgsqlRowDescriptionV2(stream, context.OidToNameMapping, context.CompatVersion));

                        break;

                    case BackEndMessageCode.DataRow:
                        yield return(new StringRowReaderV2(stream));

                        break;

                    case BackEndMessageCode.BinaryRow:
                        throw new NotSupportedException();

                    case BackEndMessageCode.ReadyForQuery:
                        ChangeState(context, NpgsqlReadyState.Instance);
                        if (errors.Count != 0)
                        {
                            throw new NpgsqlException(errors);
                        }
                        yield break;

                    case BackEndMessageCode.BackendKeyData:
                        context.BackEndKeyData = new NpgsqlBackEndKeyData(context.BackendProtocolVersion, stream);
                        break;

                    case BackEndMessageCode.NoticeResponse:
                        context.FireNotice(new NpgsqlError(context.BackendProtocolVersion, stream));
                        break;

                    case BackEndMessageCode.CompletedResponse:
                        yield return(new CompletedResponse(stream));

                        break;

                    case BackEndMessageCode.CursorResponse:
                        // This is the cursor response message.
                        // It is followed by a C NULL terminated string with the name of
                        // the cursor in a FETCH case or 'blank' otherwise.
                        // In this case it should be always 'blank'.
                        // [FIXME] Get another name for this function.
                        NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "CursorResponse");

                        String cursorName = PGUtil.ReadString(stream);
                        // Continue waiting for ReadyForQuery message.
                        break;

                    case BackEndMessageCode.EmptyQueryResponse:
                        NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "EmptyQueryResponse");
                        PGUtil.ReadString(stream);
                        break;

                    case BackEndMessageCode.NotificationResponse:
                        context.FireNotification(new NpgsqlNotificationEventArgs(stream, false));
                        if (context.IsNotificationThreadRunning)
                        {
                            yield break;
                        }
                        break;

                    case BackEndMessageCode.IO_ERROR:
                        // Connection broken. Mono returns -1 instead of throw an exception as ms.net does.
                        throw new IOException();

                    default:
                        // This could mean a number of things
                        //   We've gotten out of sync with the backend?
                        //   We need to implement this type?
                        //   Backend has gone insane?
                        throw new DataException("Backend sent unrecognized response type");
                    }
                }
            }
        }
Exemplo n.º 10
0
        private void ReadFromStream_Ver_3(Stream inputStream, Encoding encoding)
        {
            NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ReadFromStream_Ver_3");

            Int32 messageLength = PGUtil.ReadInt32(inputStream, new Byte[4]);

            // [TODO] Would this be the right way to do?
            // Check the messageLength value. If it is 1178686529, this would be the
            // "FATA" string, which would mean a protocol 2.0 error string.
            if (messageLength == 1178686529)
            {
                String   Raw;
                String[] Parts;

                Raw = "FATA" + PGUtil.ReadString(inputStream, encoding);

                Parts = Raw.Split(new char[] { ':' }, 2);

                if (Parts.Length == 2)
                {
                    _severity = Parts[0].Trim();
                    _message  = Parts[1].Trim();
                }
                else
                {
                    _message = Parts[0].Trim();
                }

                protocol_version = ProtocolVersion.Version2;

                return;
            }

            Char   field;
            String fieldValue;

            field = (Char)inputStream.ReadByte();

            // Now start to read fields.
            while (field != 0)
            {
                fieldValue = PGUtil.ReadString(inputStream, encoding);

                switch (field)
                {
                case 'S':
                    _severity = fieldValue;
                    break;

                case 'C':
                    _code = fieldValue;
                    break;

                case 'M':
                    _message = fieldValue;
                    break;

                case 'D':
                    _detail = fieldValue;
                    break;

                case 'H':
                    _hint = fieldValue;
                    break;

                case 'P':
                    _position = fieldValue;
                    break;

                case 'W':
                    _where = fieldValue;
                    break;

                case 'F':
                    _file = fieldValue;
                    break;

                case 'L':
                    _line = fieldValue;
                    break;

                case 'R':
                    _routine = fieldValue;
                    break;
                }

                field = (Char)inputStream.ReadByte();
            }
        }
Exemplo n.º 11
0
        internal NpgsqlError(ProtocolVersion protocolVersion, Stream stream)
        {
            switch (protocol_version = protocolVersion)
            {
            case ProtocolVersion.Version2:
                string[] parts = PGUtil.ReadString(stream).Split(new char[] { ':' }, 2);
                if (parts.Length == 2)
                {
                    _severity = parts[0].Trim();
                    _message  = parts[1].Trim();
                }
                else
                {
                    _severity = string.Empty;
                    _message  = parts[0].Trim();
                }
                break;

            case ProtocolVersion.Version3:
                // Check the messageLength value. If it is 1178686529, this would be the
                // "FATA" string, which would mean a protocol 2.0 error string.
                if (PGUtil.ReadInt32(stream) == 1178686529)
                {
                    string[] v2Parts = ("FATA" + PGUtil.ReadString(stream)).Split(new char[] { ':' }, 2);
                    if (v2Parts.Length == 2)
                    {
                        _severity = v2Parts[0].Trim();
                        _message  = v2Parts[1].Trim();
                    }
                    else
                    {
                        _severity = string.Empty;
                        _message  = v2Parts[0].Trim();
                    }
                    protocol_version = ProtocolVersion.Version2;
                }
                else
                {
                    for (char field = (char)stream.ReadByte(); field != 0; field = (char)stream.ReadByte())
                    {
                        switch (field)
                        {
                        case 'S':
                            _severity = PGUtil.ReadString(stream);
                            ;
                            break;

                        case 'C':
                            _code = PGUtil.ReadString(stream);
                            ;
                            break;

                        case 'M':
                            _message = PGUtil.ReadString(stream);
                            ;
                            break;

                        case 'D':
                            _detail = PGUtil.ReadString(stream);
                            ;
                            break;

                        case 'H':
                            _hint = PGUtil.ReadString(stream);
                            ;
                            break;

                        case 'P':
                            _position = PGUtil.ReadString(stream);
                            ;
                            break;

                        case 'p':
                            _internalPosition = PGUtil.ReadString(stream);
                            ;
                            break;

                        case 'q':
                            _internalQuery = PGUtil.ReadString(stream);
                            ;
                            break;

                        case 'W':
                            _where = PGUtil.ReadString(stream);
                            ;
                            break;

                        case 'F':
                            _file = PGUtil.ReadString(stream);
                            ;
                            break;

                        case 'L':
                            _line = PGUtil.ReadString(stream);
                            ;
                            break;

                        case 'R':
                            _routine = PGUtil.ReadString(stream);
                            ;
                            break;
                        }
                    }
                }
                break;
            }
        }
 internal NpgsqlNotificationEventArgs(Stream stream, bool readAdditional)
 {
     PID                   = PGUtil.ReadInt32(stream);
     Condition             = PGUtil.ReadString(stream);
     AdditionalInformation = readAdditional ? PGUtil.ReadString(stream) : string.Empty;
 }
Exemplo n.º 13
0
        internal NpgsqlError(ProtocolVersion protocolVersion, Stream stream)
        {
            switch (protocol_version = protocolVersion)
            {
            case ProtocolVersion.Version2:
                string[] parts = PGUtil.ReadString(stream).Split(new char[] { ':' }, 2);
                if (parts.Length == 2)
                {
                    _severity = parts[0].Trim();
                    _message  = parts[1].Trim();
                }
                else
                {
                    _severity = string.Empty;
                    _message  = parts[0].Trim();
                }
                break;

            case ProtocolVersion.Version3:
                // Check the messageLength value. If it is 1178686529, this would be the
                // "FATA" string, which would mean a protocol 2.0 error string.
                if (PGUtil.ReadInt32(stream) == 1178686529)
                {
                    string[] v2Parts = ("FATA" + PGUtil.ReadString(stream)).Split(new char[] { ':' }, 2);
                    if (v2Parts.Length == 2)
                    {
                        _severity = v2Parts[0].Trim();
                        _message  = v2Parts[1].Trim();
                    }
                    else
                    {
                        _severity = string.Empty;
                        _message  = v2Parts[0].Trim();
                    }
                    protocol_version = ProtocolVersion.Version2;
                }
                else
                {
                    bool done = false;
                    int  fieldCode;

                    while (!done && (fieldCode = stream.ReadByte()) != -1)
                    {
                        switch ((byte)fieldCode)
                        {
                        case 0:
                            // Null terminator; error message fully consumed.
                            done = true;
                            ;
                            break;

                        case (byte)ErrorFieldTypeCodes.Severity:
                            _severity = PGUtil.ReadString(stream);
                            ;
                            break;

                        case (byte)ErrorFieldTypeCodes.Code:
                            _code = PGUtil.ReadString(stream);
                            ;
                            break;

                        case (byte)ErrorFieldTypeCodes.Message:
                            _message = PGUtil.ReadString(stream);
                            ;
                            break;

                        case (byte)ErrorFieldTypeCodes.Detail:
                            _detail = PGUtil.ReadString(stream);
                            ;
                            break;

                        case (byte)ErrorFieldTypeCodes.Hint:
                            _hint = PGUtil.ReadString(stream);
                            ;
                            break;

                        case (byte)ErrorFieldTypeCodes.Position:
                            _position = PGUtil.ReadString(stream);
                            ;
                            break;

                        case (byte)ErrorFieldTypeCodes.InternalPosition:
                            _internalPosition = PGUtil.ReadString(stream);
                            ;
                            break;

                        case (byte)ErrorFieldTypeCodes.InternalQuery:
                            _internalQuery = PGUtil.ReadString(stream);
                            ;
                            break;

                        case (byte)ErrorFieldTypeCodes.Where:
                            _where = PGUtil.ReadString(stream);
                            ;
                            break;

                        case (byte)ErrorFieldTypeCodes.File:
                            _file = PGUtil.ReadString(stream);
                            ;
                            break;

                        case (byte)ErrorFieldTypeCodes.Line:
                            _line = PGUtil.ReadString(stream);
                            ;
                            break;

                        case (byte)ErrorFieldTypeCodes.Routine:
                            _routine = PGUtil.ReadString(stream);
                            ;
                            break;

                        case (byte)ErrorFieldTypeCodes.SchemaName:
                            _schemaName = PGUtil.ReadString(stream);
                            ;
                            break;

                        case (byte)ErrorFieldTypeCodes.TableName:
                            _tableName = PGUtil.ReadString(stream);
                            ;
                            break;

                        case (byte)ErrorFieldTypeCodes.ColumnName:
                            _columnName = PGUtil.ReadString(stream);
                            ;
                            break;

                        case (byte)ErrorFieldTypeCodes.DataTypeName:
                            _datatypeName = PGUtil.ReadString(stream);
                            ;
                            break;

                        case (byte)ErrorFieldTypeCodes.ConstraintName:
                            _constraintName = PGUtil.ReadString(stream);
                            ;
                            break;

                        default:
                            // Unknown error field; consume and discard.
                            PGUtil.ReadString(stream);
                            ;
                            break;
                        }
                    }
                }

                break;
            }
        }
Exemplo n.º 14
0
        protected virtual void ProcessBackendResponses_Ver_3(NpgsqlConnector context)
        {
            NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ProcessBackendResponses");

            Stream         stream   = context.Stream;
            NpgsqlMediator mediator = context.Mediator;

            // Often used buffers
            Byte[] inputBuffer = new Byte[4];
            String Str;

            Boolean readyForQuery = false;

            byte[] asciiRowBytes = new byte[300];
            char[] asciiRowChars = new char[300];

            while (!readyForQuery)
            {
                // Check the first Byte of response.
                Int32 message = stream.ReadByte();
                switch (message)
                {
                case NpgsqlMessageTypes_Ver_3.ErrorResponse:

                {
                    NpgsqlError error = new NpgsqlError(context.BackendProtocolVersion);
                    error.ReadFromStream(stream, context.Encoding);
                    error.ErrorSql = mediator.SqlSent;

                    mediator.Errors.Add(error);

                    NpgsqlEventLog.LogMsg(resman, "Log_ErrorResponse", LogLevel.Debug, error.Message);
                }

                    // Return imediately if it is in the startup state or connected state as
                    // there is no more messages to consume.
                    // Possible error in the NpgsqlStartupState:
                    //		Invalid password.
                    // Possible error in the NpgsqlConnectedState:
                    //		No pg_hba.conf configured.

                    if (!mediator.RequireReadyForQuery)
                    {
                        return;
                    }

                    break;


                case NpgsqlMessageTypes_Ver_3.AuthenticationRequest:

                    NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "AuthenticationRequest");

                    // Eat length
                    PGUtil.ReadInt32(stream, inputBuffer);

                    {
                        Int32 authType = PGUtil.ReadInt32(stream, inputBuffer);

                        if (authType == NpgsqlMessageTypes_Ver_3.AuthenticationOk)
                        {
                            NpgsqlEventLog.LogMsg(resman, "Log_AuthenticationOK", LogLevel.Debug);

                            break;
                        }

                        if (authType == NpgsqlMessageTypes_Ver_3.AuthenticationClearTextPassword)
                        {
                            NpgsqlEventLog.LogMsg(resman, "Log_AuthenticationClearTextRequest", LogLevel.Debug);

                            // Send the PasswordPacket.

                            ChangeState(context, NpgsqlStartupState.Instance);
                            context.Authenticate(context.Password);

                            break;
                        }


                        if (authType == NpgsqlMessageTypes_Ver_3.AuthenticationMD5Password)
                        {
                            NpgsqlEventLog.LogMsg(resman, "Log_AuthenticationMD5Request", LogLevel.Debug);
                            // Now do the "MD5-Thing"
                            // for this the Password has to be:
                            // 1. md5-hashed with the username as salt
                            // 2. md5-hashed again with the salt we get from the backend


                            MD5 md5 = MD5.Create();


                            // 1.
                            byte[] passwd       = context.Encoding.GetBytes(context.Password);
                            byte[] saltUserName = context.Encoding.GetBytes(context.UserName);

                            byte[] crypt_buf = new byte[passwd.Length + saltUserName.Length];

                            passwd.CopyTo(crypt_buf, 0);
                            saltUserName.CopyTo(crypt_buf, passwd.Length);



                            StringBuilder sb         = new StringBuilder();
                            byte[]        hashResult = md5.ComputeHash(crypt_buf);
                            foreach (byte b in hashResult)
                            {
                                sb.Append(b.ToString("x2"));
                            }


                            String prehash = sb.ToString();

                            byte[] prehashbytes = context.Encoding.GetBytes(prehash);



                            stream.Read(inputBuffer, 0, 4);
                            // Send the PasswordPacket.
                            ChangeState(context, NpgsqlStartupState.Instance);


                            // 2.

                            crypt_buf = new byte[prehashbytes.Length + 4];
                            prehashbytes.CopyTo(crypt_buf, 0);
                            inputBuffer.CopyTo(crypt_buf, prehashbytes.Length);

                            sb         = new StringBuilder("md5"); // This is needed as the backend expects md5 result starts with "md5"
                            hashResult = md5.ComputeHash(crypt_buf);
                            foreach (byte b in hashResult)
                            {
                                sb.Append(b.ToString("x2"));
                            }

                            context.Authenticate(sb.ToString());

                            break;
                        }

                        // Only AuthenticationClearTextPassword and AuthenticationMD5Password supported for now.
                        mediator.Errors.Add(new NpgsqlError(context.BackendProtocolVersion, String.Format(resman.GetString("Exception_AuthenticationMethodNotSupported"), authType)));
                    }

                    return;

                case NpgsqlMessageTypes_Ver_3.RowDescription:
                    // This is the RowDescription message.
                    NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "RowDescription");
                    {
                        NpgsqlRowDescription rd = new NpgsqlRowDescription(context.BackendProtocolVersion);
                        rd.ReadFromStream(stream, context.Encoding, context.OidToNameMapping);

                        mediator.AddRowDescription(rd);
                    }

                    // Now wait for the AsciiRow messages.
                    break;

                case NpgsqlMessageTypes_Ver_3.ParameterDescription:

                    // Do nothing,for instance,  just read...
                    int lenght   = PGUtil.ReadInt32(stream, inputBuffer);
                    int nb_param = PGUtil.ReadInt16(stream, inputBuffer);
                    for (int i = 0; i < nb_param; i++)
                    {
                        int typeoid = PGUtil.ReadInt32(stream, inputBuffer);
                    }

                    break;

                case NpgsqlMessageTypes_Ver_3.DataRow:
                    // This is the AsciiRow message.
                    NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "DataRow");
                    {
                        NpgsqlAsciiRow asciiRow = new NpgsqlAsciiRow(context.Mediator.LastRowDescription, context.BackendProtocolVersion, asciiRowBytes, asciiRowChars);
                        asciiRow.ReadFromStream(stream, context.Encoding);

                        // Add this row to the rows array.
                        mediator.AddAsciiRow(asciiRow);
                    }

                    // Now wait for CompletedResponse message.
                    break;

                case NpgsqlMessageTypes_Ver_3.ReadyForQuery:

                    NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "ReadyForQuery");

                    // Possible status bytes returned:
                    //   I = Idle (no transaction active).
                    //   T = In transaction, ready for more.
                    //   E = Error in transaction, queries will fail until transaction aborted.
                    // Just eat the status byte, we have no use for it at this time.
                    PGUtil.ReadInt32(stream, inputBuffer);
                    PGUtil.ReadString(stream, context.Encoding, 1);

                    readyForQuery = true;
                    ChangeState(context, NpgsqlReadyState.Instance);

                    break;

                case NpgsqlMessageTypes_Ver_3.BackendKeyData:

                    NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "BackendKeyData");
                    // BackendKeyData message.
                    NpgsqlBackEndKeyData backend_keydata = new NpgsqlBackEndKeyData(context.BackendProtocolVersion);
                    backend_keydata.ReadFromStream(stream);
                    mediator.SetBackendKeydata(backend_keydata);


                    // Wait for ReadForQuery message
                    break;

                case NpgsqlMessageTypes_Ver_3.NoticeResponse:

                    // Notices and errors are identical except that we
                    // just throw notices away completely ignored.
                {
                    NpgsqlError notice = new NpgsqlError(context.BackendProtocolVersion);
                    notice.ReadFromStream(stream, context.Encoding);

                    mediator.Notices.Add(notice);

                    NpgsqlEventLog.LogMsg(resman, "Log_NoticeResponse", LogLevel.Debug, notice.Message);
                }

                    // Wait for ReadForQuery message
                    break;

                case NpgsqlMessageTypes_Ver_3.CompletedResponse:
                    // This is the CompletedResponse message.
                    // Get the string returned.

                    PGUtil.ReadInt32(stream, inputBuffer);
                    Str = PGUtil.ReadString(stream, context.Encoding);

                    NpgsqlEventLog.LogMsg(resman, "Log_CompletedResponse", LogLevel.Debug, Str);

                    // Add result from the processing.
                    mediator.AddCompletedResponse(Str);

                    break;

                case NpgsqlMessageTypes_Ver_3.ParseComplete:
                    NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "ParseComplete");
                    // Just read up the message length.
                    PGUtil.ReadInt32(stream, inputBuffer);
                    readyForQuery = true;
                    break;

                case NpgsqlMessageTypes_Ver_3.BindComplete:
                    NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "BindComplete");
                    // Just read up the message length.
                    PGUtil.ReadInt32(stream, inputBuffer);
                    readyForQuery = true;
                    break;

                case NpgsqlMessageTypes_Ver_3.EmptyQueryResponse:
                    NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "EmptyQueryResponse");
                    PGUtil.ReadInt32(stream, inputBuffer);
                    break;

                case NpgsqlMessageTypes_Ver_3.NotificationResponse:
                    NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "NotificationResponse");

                    // Eat the length
                    PGUtil.ReadInt32(stream, inputBuffer);
                    {
                        // Process ID sending notification
                        Int32 PID = PGUtil.ReadInt32(stream, inputBuffer);
                        // Notification string
                        String notificationResponse = PGUtil.ReadString(stream, context.Encoding);
                        // Additional info, currently not implemented by PG (empty string always), eat it
                        PGUtil.ReadString(stream, context.Encoding);
                        mediator.AddNotification(new NpgsqlNotificationEventArgs(PID, notificationResponse));
                    }

                    if (context.IsNotificationThreadRunning)
                    {
                        readyForQuery = true;
                    }

                    // Wait for ReadForQuery message
                    break;

                case NpgsqlMessageTypes_Ver_3.ParameterStatus:
                    NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "ParameterStatus");
                    NpgsqlParameterStatus parameterStatus = new NpgsqlParameterStatus();
                    parameterStatus.ReadFromStream(stream, context.Encoding);

                    NpgsqlEventLog.LogMsg(resman, "Log_ParameterStatus", LogLevel.Debug, parameterStatus.Parameter, parameterStatus.ParameterValue);

                    mediator.AddParameterStatus(parameterStatus.Parameter, parameterStatus);

                    if (parameterStatus.Parameter == "server_version")
                    {
                        // Add this one under our own name so that if the parameter name
                        // changes in a future backend version, we can handle it here in the
                        // protocol handler and leave everybody else put of it.
                        mediator.AddParameterStatus("__npgsql_server_version", parameterStatus);
                        //                        context.ServerVersionString = parameterStatus.ParameterValue;
                    }

                    break;

                case NpgsqlMessageTypes_Ver_3.NoData:
                    // This nodata message may be generated by prepare commands issued with queries which doesn't return rows
                    // for example insert, update or delete.
                    // Just eat the message.
                    NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "ParameterStatus");
                    PGUtil.ReadInt32(stream, inputBuffer);
                    break;


                case -1:
                    // Connection broken. Mono returns -1 instead of throw an exception as ms.net does.
                    throw new IOException();

                default:
                    // This could mean a number of things
                    //   We've gotten out of sync with the backend?
                    //   We need to implement this type?
                    //   Backend has gone insane?
                    // FIXME
                    // what exception should we really throw here?
                    throw new NotSupportedException(String.Format("Backend sent unrecognized response type: {0}", (Char)message));
                }
            }
        }
Exemplo n.º 15
0
        protected virtual void ProcessBackendResponses_Ver_2(NpgsqlConnector context)
        {
            NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ProcessBackendResponses");

            Stream         stream   = context.Stream;
            NpgsqlMediator mediator = context.Mediator;

            // Often used buffer
            Byte[] inputBuffer = new Byte[4];

            Boolean readyForQuery = false;

            byte[] asciiRowBytes = new byte[300];
            char[] asciiRowChars = new char[300];

            while (!readyForQuery)
            {
                // Check the first Byte of response.
                switch (stream.ReadByte())
                {
                case NpgsqlMessageTypes_Ver_2.ErrorResponse:

                {
                    NpgsqlError error = new NpgsqlError(context.BackendProtocolVersion);
                    error.ReadFromStream(stream, context.Encoding);
                    error.ErrorSql = mediator.SqlSent;

                    mediator.Errors.Add(error);

                    NpgsqlEventLog.LogMsg(resman, "Log_ErrorResponse", LogLevel.Debug, error.Message);
                }

                    // Return imediately if it is in the startup state or connected state as
                    // there is no more messages to consume.
                    // Possible error in the NpgsqlStartupState:
                    //		Invalid password.
                    // Possible error in the NpgsqlConnectedState:
                    //		No pg_hba.conf configured.

                    if (!mediator.RequireReadyForQuery)
                    {
                        return;
                    }

                    break;


                case NpgsqlMessageTypes_Ver_2.AuthenticationRequest:

                    NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "AuthenticationRequest");

                    {
                        Int32 authType = PGUtil.ReadInt32(stream, inputBuffer);

                        if (authType == NpgsqlMessageTypes_Ver_2.AuthenticationOk)
                        {
                            NpgsqlEventLog.LogMsg(resman, "Log_AuthenticationOK", LogLevel.Debug);

                            break;
                        }

                        if (authType == NpgsqlMessageTypes_Ver_2.AuthenticationClearTextPassword)
                        {
                            NpgsqlEventLog.LogMsg(resman, "Log_AuthenticationClearTextRequest", LogLevel.Debug);

                            // Send the PasswordPacket.

                            ChangeState(context, NpgsqlStartupState.Instance);
                            context.Authenticate(context.Password);

                            break;
                        }


                        if (authType == NpgsqlMessageTypes_Ver_2.AuthenticationMD5Password)
                        {
                            NpgsqlEventLog.LogMsg(resman, "Log_AuthenticationMD5Request", LogLevel.Debug);
                            // Now do the "MD5-Thing"
                            // for this the Password has to be:
                            // 1. md5-hashed with the username as salt
                            // 2. md5-hashed again with the salt we get from the backend


                            MD5 md5 = MD5.Create();


                            // 1.
                            byte[] passwd       = context.Encoding.GetBytes(context.Password);
                            byte[] saltUserName = context.Encoding.GetBytes(context.UserName);

                            byte[] crypt_buf = new byte[passwd.Length + saltUserName.Length];

                            passwd.CopyTo(crypt_buf, 0);
                            saltUserName.CopyTo(crypt_buf, passwd.Length);



                            StringBuilder sb         = new StringBuilder();
                            byte[]        hashResult = md5.ComputeHash(crypt_buf);
                            foreach (byte b in hashResult)
                            {
                                sb.Append(b.ToString("x2"));
                            }


                            String prehash = sb.ToString();

                            byte[] prehashbytes = context.Encoding.GetBytes(prehash);



                            byte[] saltServer = new byte[4];
                            stream.Read(saltServer, 0, 4);
                            // Send the PasswordPacket.
                            ChangeState(context, NpgsqlStartupState.Instance);


                            // 2.

                            crypt_buf = new byte[prehashbytes.Length + saltServer.Length];
                            prehashbytes.CopyTo(crypt_buf, 0);
                            saltServer.CopyTo(crypt_buf, prehashbytes.Length);

                            sb         = new StringBuilder("md5"); // This is needed as the backend expects md5 result starts with "md5"
                            hashResult = md5.ComputeHash(crypt_buf);
                            foreach (byte b in hashResult)
                            {
                                sb.Append(b.ToString("x2"));
                            }

                            context.Authenticate(sb.ToString());

                            break;
                        }

                        // Only AuthenticationClearTextPassword and AuthenticationMD5Password supported for now.

                        mediator.Errors.Add(new NpgsqlError(context.BackendProtocolVersion, String.Format(resman.GetString("Exception_AuthenticationMethodNotSupported"), authType)));
                    }

                    return;

                case NpgsqlMessageTypes_Ver_2.RowDescription:
                    // This is the RowDescription message.
                    NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "RowDescription");

                    {
                        NpgsqlRowDescription rd = new NpgsqlRowDescription(context.BackendProtocolVersion);
                        rd.ReadFromStream(stream, context.Encoding, context.OidToNameMapping);

                        // Initialize the array list which will contain the data from this rowdescription.
                        mediator.AddRowDescription(rd);
                    }

                    // Now wait for the AsciiRow messages.
                    break;

                case NpgsqlMessageTypes_Ver_2.AsciiRow:
                    // This is the AsciiRow message.
                    NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "AsciiRow");

                    {
                        NpgsqlAsciiRow asciiRow = new NpgsqlAsciiRow(context.Mediator.LastRowDescription, context.BackendProtocolVersion, asciiRowBytes, asciiRowChars);
                        asciiRow.ReadFromStream(stream, context.Encoding);

                        // Add this row to the rows array.
                        mediator.AddAsciiRow(asciiRow);
                    }

                    // Now wait for CompletedResponse message.
                    break;

                case NpgsqlMessageTypes_Ver_2.BinaryRow:
                    NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "BinaryRow");

                    {
                        NpgsqlBinaryRow binaryRow = new NpgsqlBinaryRow(context.Mediator.LastRowDescription);
                        binaryRow.ReadFromStream(stream, context.Encoding);

                        mediator.AddBinaryRow(binaryRow);
                    }

                    break;

                case NpgsqlMessageTypes_Ver_2.ReadyForQuery:

                    NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "ReadyForQuery");
                    readyForQuery = true;
                    ChangeState(context, NpgsqlReadyState.Instance);
                    break;

                case NpgsqlMessageTypes_Ver_2.BackendKeyData:

                    NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "BackendKeyData");
                    // BackendKeyData message.
                    NpgsqlBackEndKeyData backend_keydata = new NpgsqlBackEndKeyData(context.BackendProtocolVersion);
                    backend_keydata.ReadFromStream(stream);
                    mediator.SetBackendKeydata(backend_keydata);


                    // Wait for ReadForQuery message
                    break;
                    ;

                case NpgsqlMessageTypes_Ver_2.NoticeResponse:

                {
                    NpgsqlError notice = new NpgsqlError(context.BackendProtocolVersion);
                    notice.ReadFromStream(stream, context.Encoding);

                    mediator.Notices.Add(notice);

                    NpgsqlEventLog.LogMsg(resman, "Log_NoticeResponse", LogLevel.Debug, notice.Message);
                }

                    // Wait for ReadForQuery message
                    break;

                case NpgsqlMessageTypes_Ver_2.CompletedResponse:
                    // This is the CompletedResponse message.
                    // Get the string returned.


                    String result = PGUtil.ReadString(stream, context.Encoding);

                    NpgsqlEventLog.LogMsg(resman, "Log_CompletedResponse", LogLevel.Debug, result);
                    // Add result from the processing.

                    mediator.AddCompletedResponse(result);

                    // Now wait for ReadyForQuery message.
                    break;

                case NpgsqlMessageTypes_Ver_2.CursorResponse:
                    // This is the cursor response message.
                    // It is followed by a C NULL terminated string with the name of
                    // the cursor in a FETCH case or 'blank' otherwise.
                    // In this case it should be always 'blank'.
                    // [FIXME] Get another name for this function.
                    NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "CursorResponse");

                    String cursorName = PGUtil.ReadString(stream, context.Encoding);
                    // Continue waiting for ReadyForQuery message.
                    break;

                case NpgsqlMessageTypes_Ver_2.EmptyQueryResponse:
                    NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "EmptyQueryResponse");
                    PGUtil.ReadString(stream, context.Encoding);
                    break;

                case NpgsqlMessageTypes_Ver_2.NotificationResponse:

                    NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "NotificationResponse");

                    Int32  PID = PGUtil.ReadInt32(stream, inputBuffer);
                    String notificationResponse = PGUtil.ReadString(stream, context.Encoding);
                    mediator.AddNotification(new NpgsqlNotificationEventArgs(PID, notificationResponse));

                    if (context.IsNotificationThreadRunning)
                    {
                        readyForQuery = true;
                    }

                    // Wait for ReadForQuery message
                    break;

                case -1:
                    // Connection broken. Mono returns -1 instead of throw an exception as ms.net does.
                    throw new IOException();

                default:
                    // This could mean a number of things
                    //   We've gotten out of sync with the backend?
                    //   We need to implement this type?
                    //   Backend has gone insane?
                    // FIXME
                    // what exception should we really throw here?
                    throw new NotSupportedException("Backend sent unrecognized response type");
                }
            }
        }