public override void WriteToStream(Stream output_stream) { NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "WriteToStream"); int packet_size = 4 + 4 + 1; for (int i = 0; i < parameterNames.Count; i++) { packet_size += (parameterNames[i].Length + parameterValues[i].Length + 2); } output_stream .WriteInt32(packet_size) .WriteInt32(PGUtil.ConvertProtocolVersion(ProtocolVersion.Version3)); for (int i = 0; i < parameterNames.Count; i++) { output_stream .WriteBytesNullTerminated(parameterNames[i]) .WriteBytesNullTerminated(parameterValues[i]); } output_stream.WriteByte(0); }
protected IEnumerable <IServerResponseObject> ProcessBackendResponses(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. BackEndMessageCode message = (BackEndMessageCode)stream.ReadByte(); switch (message) { case BackEndMessageCode.ErrorResponse: NpgsqlError error = new NpgsqlError(stream); error.ErrorSql = mediator.GetSqlSent(); errors.Add(error); NpgsqlEventLog.LogMsg("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("Log_ProtocolMessage", LogLevel.Debug, "AuthenticationRequest"); // Get the length in case we're getting AuthenticationGSSContinue int authDataLength = PGUtil.ReadInt32(stream) - 8; AuthenticationRequestType authType = (AuthenticationRequestType)PGUtil.ReadInt32(stream); switch (authType) { case AuthenticationRequestType.AuthenticationOk: NpgsqlEventLog.LogMsg("Log_AuthenticationOK", LogLevel.Debug); break; case AuthenticationRequestType.AuthenticationClearTextPassword: NpgsqlEventLog.LogMsg("Log_AuthenticationClearTextRequest", LogLevel.Debug); // Send the PasswordPacket. ChangeState(context, NpgsqlStartupState.Instance); context.Authenticate(NullTerminateArray(context.Password)); break; case AuthenticationRequestType.AuthenticationMD5Password: NpgsqlEventLog.LogMsg("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); crypt_buf = new byte[prehashbytes.Length + 4]; stream.Read(crypt_buf, prehashbytes.Length, 4); // Send the PasswordPacket. ChangeState(context, NpgsqlStartupState.Instance); // 2. prehashbytes.CopyTo(crypt_buf, 0); 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(NullTerminateArray(BackendEncoding.UTF8Encoding.GetBytes(sb.ToString()))); break; #if WINDOWS && UNMANAGED case AuthenticationRequestType.AuthenticationGSS: { if (context.IntegratedSecurity) { // For GSSAPI we have to use the supplied hostname context.SSPI = new SSPIHandler(context.Host, "POSTGRES", true); ChangeState(context, NpgsqlStartupState.Instance); context.Authenticate(context.SSPI.Continue(null)); break; } else { // TODO: correct exception throw new Exception(); } } case AuthenticationRequestType.AuthenticationSSPI: { if (context.IntegratedSecurity) { // For SSPI we have to get the IP-Address (hostname doesn't work) string ipAddressString = ((IPEndPoint)context.Socket.RemoteEndPoint).Address.ToString(); context.SSPI = new SSPIHandler(ipAddressString, "POSTGRES", false); ChangeState(context, NpgsqlStartupState.Instance); context.Authenticate(context.SSPI.Continue(null)); break; } else { // TODO: correct exception throw new Exception(); } } case AuthenticationRequestType.AuthenticationGSSContinue: { byte[] authData = new byte[authDataLength]; PGUtil.CheckedStreamRead(stream, authData, 0, authDataLength); byte[] passwd_read = context.SSPI.Continue(authData); if (passwd_read.Length != 0) { context.Authenticate(passwd_read); } break; } #endif default: // Only AuthenticationClearTextPassword and AuthenticationMD5Password supported for now. errors.Add(new NpgsqlError("Exception_AuthenticationMethodNotSupported")); throw new NpgsqlException(errors); } break; case BackEndMessageCode.RowDescription: yield return(new NpgsqlRowDescription(stream, context.OidToNameMapping, context.CompatVersion)); break; case BackEndMessageCode.ParameterDescription: // Do nothing,for instance, just read... int lenght = PGUtil.ReadInt32(stream); int nb_param = PGUtil.ReadInt16(stream); for (int i = 0; i < nb_param; i++) { int typeoid = PGUtil.ReadInt32(stream); } break; case BackEndMessageCode.DataRow: yield return(new StringRowReader(stream)); break; case BackEndMessageCode.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); stream.ReadByte(); ChangeState(context, NpgsqlReadyState.Instance); if (errors.Count != 0) { throw new NpgsqlException(errors); } yield break; case BackEndMessageCode.BackendKeyData: NpgsqlEventLog.LogMsg("Log_ProtocolMessage", LogLevel.Debug, "BackendKeyData"); // BackendKeyData message. NpgsqlBackEndKeyData backend_keydata = new NpgsqlBackEndKeyData(stream); context.BackEndKeyData = backend_keydata; // Wait for ReadForQuery message break; case BackEndMessageCode.NoticeResponse: // Notices and errors are identical except that we // just throw notices away completely ignored. context.FireNotice(new NpgsqlError(stream)); break; case BackEndMessageCode.CompletedResponse: PGUtil.ReadInt32(stream); yield return(new CompletedResponse(stream)); break; case BackEndMessageCode.ParseComplete: NpgsqlEventLog.LogMsg("Log_ProtocolMessage", LogLevel.Debug, "ParseComplete"); // Just read up the message length. PGUtil.ReadInt32(stream); break; case BackEndMessageCode.BindComplete: // NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "BindComplete"); // Just read up the message length. PGUtil.ReadInt32(stream); break; case BackEndMessageCode.EmptyQueryResponse: NpgsqlEventLog.LogMsg("Log_ProtocolMessage", LogLevel.Debug, "EmptyQueryResponse"); PGUtil.ReadInt32(stream); break; case BackEndMessageCode.NotificationResponse: // Eat the length PGUtil.ReadInt32(stream); context.FireNotification(new NpgsqlNotificationEventArgs(stream, true)); if (context.IsNotificationThreadRunning) { yield break; } break; case BackEndMessageCode.ParameterStatus: NpgsqlEventLog.LogMsg("Log_ProtocolMessage", LogLevel.Debug, "ParameterStatus"); NpgsqlParameterStatus parameterStatus = new NpgsqlParameterStatus(stream); NpgsqlEventLog.LogMsg("Log_ParameterStatus", LogLevel.Debug, parameterStatus.Parameter, parameterStatus.ParameterValue); context.AddParameterStatus(parameterStatus); if (parameterStatus.Parameter == "server_version") { // Deal with this here so that if there are // changes in a future backend version, we can handle it here in the // protocol handler and leave everybody else put of it. string versionString = parameterStatus.ParameterValue.Trim(); for (int idx = 0; idx != versionString.Length; ++idx) { char c = parameterStatus.ParameterValue[idx]; if (!char.IsDigit(c) && c != '.') { versionString = versionString.Substring(0, idx); break; } } context.ServerVersion = new Version(versionString); } break; case BackEndMessageCode.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("Log_ProtocolMessage", LogLevel.Debug, "ParameterStatus"); PGUtil.ReadInt32(stream); break; case BackEndMessageCode.CopyInResponse: // Enter COPY sub protocol and start pushing data to server NpgsqlEventLog.LogMsg("Log_ProtocolMessage", LogLevel.Debug, "CopyInResponse"); ChangeState(context, new NpgsqlCopyInState()); PGUtil.ReadInt32(stream); // length redundant context.CurrentState.StartCopy(context, ReadCopyHeader(stream)); yield break; // Either StartCopy called us again to finish the operation or control should be passed for user to feed copy data case BackEndMessageCode.CopyOutResponse: // Enter COPY sub protocol and start pulling data from server NpgsqlEventLog.LogMsg("Log_ProtocolMessage", LogLevel.Debug, "CopyOutResponse"); ChangeState(context, NpgsqlCopyOutState.Instance); PGUtil.ReadInt32(stream); // length redundant context.CurrentState.StartCopy(context, ReadCopyHeader(stream)); yield break; // Either StartCopy called us again to finish the operation or control should be passed for user to feed copy data case BackEndMessageCode.CopyData: NpgsqlEventLog.LogMsg("Log_ProtocolMessage", LogLevel.Debug, "CopyData"); Int32 len = PGUtil.ReadInt32(stream) - 4; byte[] buf = new byte[len]; PGUtil.ReadBytes(stream, buf, 0, len); context.Mediator.ReceivedCopyData = buf; yield break; // read data from server one chunk at a time while staying in copy operation mode case BackEndMessageCode.CopyDone: NpgsqlEventLog.LogMsg("Log_ProtocolMessage", LogLevel.Debug, "CopyDone"); PGUtil.ReadInt32(stream); // CopyDone can not have content so this is always 4 // This will be followed by normal CommandComplete + ReadyForQuery so no op needed break; case BackEndMessageCode.IO_ERROR: // Connection broken. Mono returns -1 instead of throwing 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)); } } } }
internal NpgsqlNotificationEventArgs(Stream stream, bool readAdditional) { PID = PGUtil.ReadInt32(stream); Condition = PGUtil.ReadString(stream); AdditionalInformation = readAdditional ? PGUtil.ReadString(stream) : string.Empty; }
public StringRowReader(Stream inputStream) : base(inputStream) { _messageSize = PGUtil.ReadInt32(inputStream); }
/*/// <value>Counts the numbers of Connections that share * /// this Connector. Used in Release() to decide wether this * /// connector is to be moved to the PooledConnectors list.</value> * // internal int mShareCount;*/ /// <summary> /// Opens the physical connection to the server. /// </summary> /// <remarks>Usually called by the RequestConnector /// Method of the connection pool manager.</remarks> internal void Open() { ServerVersion = null; // If Connection.ConnectionString specifies a protocol version, we will // not try to fall back to version 2 on failure. // Reset state to initialize new connector in pool. CurrentState = NpgsqlClosedState.Instance; // Keep track of time remaining; Even though there may be multiple timeout-able calls, // this allows us to still respect the caller's timeout expectation. int connectTimeRemaining = this.ConnectionTimeout * 1000; DateTime attemptStart = DateTime.Now; // Get a raw connection, possibly SSL... CurrentState.Open(this, connectTimeRemaining); try { // Establish protocol communication and handle authentication... CurrentState.Startup(this, settings); } catch (NpgsqlException) { if (_stream != null) { try { _stream.Dispose(); } catch { } } throw; } // Change the state of connection to open and ready. _connection_state = ConnectionState.Open; CurrentState = NpgsqlReadyState.Instance; // After attachment, the stream will close the connector (this) when the stream gets disposed. _baseStream.AttachConnector(this); // Fall back to the old way, SELECT VERSION(). // This should not happen for protocol version 3+. if (ServerVersion == null) { //NpgsqlCommand command = new NpgsqlCommand("set DATESTYLE TO ISO;select version();", this); //ServerVersion = new Version(PGUtil.ExtractServerVersion((string) command.ExecuteScalar())); using (NpgsqlCommand command = new NpgsqlCommand("set DATESTYLE TO ISO;select version();", this)) { ServerVersion = new Version(PGUtil.ExtractServerVersion((string)command.ExecuteScalar())); } } ProcessServerVersion(); StringWriter sbInitQueries = new StringWriter(); // Some connection parameters for protocol 3 had been sent in the startup packet. // The rest will be setted here. if (SupportsExtraFloatDigits3) { sbInitQueries.WriteLine("SET extra_float_digits=3;"); } if (SupportsSslRenegotiationLimit) { sbInitQueries.WriteLine("SET ssl_renegotiation_limit=0;"); } if (SupportsLcMonetary) { sbInitQueries.WriteLine("SET lc_monetary='C';"); } initQueries = sbInitQueries.ToString(); NpgsqlCommand.ExecuteBlind(this, initQueries); // Make a shallow copy of the type mapping that the connector will own. // It is possible that the connector may add types to its private // mapping that will not be valid to another connector, even // if connected to the same backend version. NativeToBackendTypeConverterOptions.OidToNameMapping = NpgsqlTypesHelper.CreateAndLoadInitialTypesMapping(this).Clone(); // The connector is now fully initialized. Beyond this point, it is // safe to release it back to the pool rather than closing it. IsInitialized = true; }
public override int DoSkip(int length) { return(PGUtil.SkipEscapedBytes(_stream, length, ref _remainingBytes)); }
public override int DoRead(byte[] output, int outputIdx, int length) { return(PGUtil.ReadEscapedBytes(_stream, output, length, ref _remainingBytes, outputIdx)); }
public override int DoRead(char[] output, int outputIdx, int length) { return(PGUtil.ReadChars(_stream, output, length, ref _remainingBytes, outputIdx)); }
public void Dispose() { PGUtil.EatStreamBytes(_stream, _remainingBytes); }
internal NpgsqlError(Stream stream) { // 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(); } } 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; } } } }
public override void WriteToStream(Stream outputStream) { if (_messageLength == 0) { _messageLength = 4 + // Message length (32 bits) _bPortalName.Length + 1 + // Portal name + null terminator _bPreparedStatementName.Length + 1 + // Statement name + null terminator 2 + // Parameter format code array length (16 bits) _parameterFormatCodes.Length * 2 + // Parameter format code array (16 bits per code) 2; // Parameter va;ue array length (16 bits) if (_parameterValues != null) { for (int i = 0; i < _parameterValues.Length; i++) { _messageLength += 4; // Parameter value length (32 bits) if (_parameterValues[i] != null) { _messageLength += _parameterValues[i].Length; // Parameter value } } } _messageLength += 2 + // Result format code array length (16 bits) _resultFormatCodes.Length * 2; // Result format code array (16 bits per code) } outputStream .WriteBytes((byte)FrontEndMessageCode.Bind) .WriteInt32(_messageLength) .WriteBytesNullTerminated(_bPortalName) .WriteBytesNullTerminated(_bPreparedStatementName) .WriteInt16((Int16)_parameterFormatCodes.Length); foreach (short code in _parameterFormatCodes) { PGUtil.WriteInt16(outputStream, code); } if (_parameterValues != null) { PGUtil.WriteInt16(outputStream, (Int16)_parameterValues.Length); for (int i = 0; i < _parameterValues.Length; i++) { Byte[] parameterValue = _parameterValues[i]; if (parameterValue == null) { PGUtil.WriteInt32(outputStream, -1); } else { outputStream .WriteInt32(parameterValue.Length) .WriteBytes(parameterValue); } } } else { PGUtil.WriteInt16(outputStream, 0); } PGUtil.WriteInt16(outputStream, (Int16)_resultFormatCodes.Length); foreach (short code in _resultFormatCodes) { PGUtil.WriteInt16(outputStream, code); } }
private int ReadNumFields(Stream stream) { PGUtil.EatStreamBytes(stream, 4); return(PGUtil.ReadInt16(stream)); }