/// <summary> /// Construct a backend error exception based on a list of one or more /// backend errors. The basic Exception.Message will be built from the /// first (usually the only) error in the list. /// </summary> internal NpgsqlException(IList <NpgsqlError> errors) : base(errors[0].ToString()) { NpgsqlEventLog.LogMsg("Log_ExceptionOccured", LogLevel.Normal, Message); this.errors = new NpgsqlError[errors.Count]; errors.CopyTo(this.errors, 0); }
/// <summary> /// This method writes a set of bytes to the stream. It also enables logging of them. /// </summary> public static Stream WriteBytes(this Stream stream, byte[] the_bytes) { NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "WriteBytes"); NpgsqlEventLog.LogMsg("Log_BytesWritten", LogLevel.Debug, the_bytes); stream.Write(the_bytes, 0, the_bytes.Length); return(stream); }
/// <summary> /// This method writes a byte to the stream. It also enables logging of them. /// </summary> public static Stream WriteBytesNullTerminated(this Stream stream, byte the_byte) { NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "WriteByte"); NpgsqlEventLog.LogMsg("Log_BytesWritten", LogLevel.Debug, the_byte); stream.WriteByte(the_byte); stream.WriteByte(0); return(stream); }
///<summary> /// This method writes a string to the network stream. /// </summary> public static Stream WriteString(this Stream stream, String theString) { NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "WriteString"); NpgsqlEventLog.LogMsg("Log_StringWritten", LogLevel.Debug, theString); byte[] bytes = BackendEncoding.UTF8Encoding.GetBytes(theString); stream.Write(bytes, 0, bytes.Length); return(stream); }
/// <summary> /// Write each key/value pair in the connection string to the log. /// </summary> private void LogConnectionString() { if (LogLevel.Debug >= NpgsqlEventLog.Level) { return; } foreach (string key in settings.Keys) { NpgsqlEventLog.LogMsg("Log_ConnectionStringValues", LogLevel.Debug, key, settings[key]); } }
///<summary> /// This method writes a C NULL terminated string to the network stream. /// It appends a NULL terminator to the end of the String. /// </summary> public static Stream WriteStringNullTerminated(this Stream stream, String format, params object[] parameters) { NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "WriteStringNullTerminated"); string theString = string.Format(format, parameters); NpgsqlEventLog.LogMsg("Log_StringWritten", LogLevel.Debug, theString); byte[] bytes = BackendEncoding.UTF8Encoding.GetBytes(theString); stream.Write(bytes, 0, bytes.Length); stream.WriteByte(0); return(stream); }
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)); } } } }
public override void Open(NpgsqlConnector context, Int32 timeout) { try { NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Open"); IAsyncResult result; // 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. DateTime attemptStart; attemptStart = DateTime.Now; result = Dns.BeginGetHostAddresses(context.Host, null, null); if (!result.AsyncWaitHandle.WaitOne(timeout, true)) { // Timeout was used up attempting the Dns lookup throw new TimeoutException("Exception_DnsLookupTimeout"); } timeout -= Convert.ToInt32((DateTime.Now - attemptStart).TotalMilliseconds); IPAddress[] ips = Dns.EndGetHostAddresses(result); Socket socket = null; Exception lastSocketException = null; // try every ip address of the given hostname, use the first reachable one // make sure not to exceed the caller's timeout expectation by splitting the // time we have left between all the remaining ip's in the list. for (int i = 0; i < ips.Length; i++) { NpgsqlEventLog.LogMsg("Log_ConnectingTo", LogLevel.Debug, ips[i]); IPEndPoint ep = new IPEndPoint(ips[i], context.Port); socket = new Socket(ep.AddressFamily, SocketType.Stream, ProtocolType.Tcp); attemptStart = DateTime.Now; try { result = socket.BeginConnect(ep, null, null); if (!result.AsyncWaitHandle.WaitOne(timeout / (ips.Length - i), true)) { throw new TimeoutException("Exception_ConnectionTimeout"); } socket.EndConnect(result); // connect was successful, leave the loop break; } catch (Exception e) { NpgsqlEventLog.LogMsg("Log_FailedConnection", LogLevel.Normal, ips[i]); timeout -= Convert.ToInt32((DateTime.Now - attemptStart).TotalMilliseconds); lastSocketException = e; socket.Close(); socket = null; } } if (socket == null) { throw lastSocketException; } NpgsqlNetworkStream baseStream = new NpgsqlNetworkStream(socket, true); Stream sslStream = null; // If the PostgreSQL server has SSL connectors enabled Open SslClientStream if (response == 'S') { if (context.SSL || (context.SslMode == SslMode.Require) || (context.SslMode == SslMode.Prefer)) { baseStream .WriteInt32(8) .WriteInt32(80877103); throw new InvalidOperationException("Exception_Ssl_RequestError"); } context.Socket = socket; context.BaseStream = baseStream; context.Stream = new BufferedStream(sslStream == null ? baseStream : sslStream, 8192); NpgsqlEventLog.LogMsg("Log_ConnectedTo", LogLevel.Normal, context.Host, context.Port); ChangeState(context, NpgsqlConnectedState.Instance); } catch (Exception e) { throw new NpgsqlException("Exception_FailedConnection", e); } }
internal static void LogStringWritten(string theString) { NpgsqlEventLog.LogMsg("Log_StringWritten", LogLevel.Debug, theString); }