public override void CancelRequest(NpgsqlConnector context) { NpgsqlCancelRequest CancelRequestMessage = new NpgsqlCancelRequest(context.BackEndKeyData); CancelRequestMessage.WriteToStream(context.Stream); }
public override void Bind(NpgsqlConnector context, NpgsqlBind bind) { Stream stream = context.Stream; bind.WriteToStream(stream); //stream.Flush(); }
public override void Authenticate(NpgsqlConnector context, byte[] password) { NpgsqlPasswordPacket pwpck = new NpgsqlPasswordPacket(password); BufferedStream stream = new BufferedStream(context.Stream); pwpck.WriteToStream(stream); stream.Flush(); }
public override IEnumerable<IServerResponseObject> QueryEnum(NpgsqlConnector context, NpgsqlCommand command) { // Send the query request to backend. NpgsqlQuery.Send(command, context.Stream); context.Stream.Flush(); return ProcessBackendResponsesEnum(context, false); }
protected override void Dispose(bool disposing) { if (!disposing) { mContext.Close(); mContext = null; } base.Dispose(disposing); }
/// <summary> /// Called from NpgsqlOutStream.Read to read copy data from server. /// </summary> public override byte[] GetCopyData(NpgsqlConnector context) { // polling in COPY would take seconds on Windows foreach (IServerResponseObject obj in ProcessBackendResponses_Ver_3(context)) { if (obj is IDisposable) { (obj as IDisposable).Dispose(); } } return context.Mediator.ReceivedCopyData; }
public override void Startup(NpgsqlConnector context) { NpgsqlStartupPacket startupPacket = new NpgsqlStartupPacket(296, //Not used. context.Database, context.UserName, "", "", ""); startupPacket.WriteToStream(new BufferedStream(context.Stream)); context.RequireReadyForQuery = false; // This still makes part of the connection stablishment handling. // So we use the connectiontimeout here too. context.Mediator.CommandTimeout = context.ConnectionTimeout; context.Stream.Flush(); ProcessBackendResponses(context); }
/// <summary> /// Called from NpgsqlState.ProcessBackendResponses upon CopyOutResponse. /// If CopyStream is already set, it is used to write data received from server, after which the copy ends. /// Otherwise CopyStream is set to a readable NpgsqlCopyOutStream that receives data from server. /// </summary> protected override void StartCopy(NpgsqlConnector context, NpgsqlCopyFormat copyFormat) { _copyFormat = copyFormat; Stream userFeed = context.Mediator.CopyStream; if (userFeed == null) { context.Mediator.CopyStream = new NpgsqlCopyOutStream(context); } else { byte[] buf; while ((buf = GetCopyData(context)) != null) { userFeed.Write(buf, 0, buf.Length); } userFeed.Close(); } }
/// <summary> /// Called from NpgsqlState.ProcessBackendResponses upon CopyInResponse. /// If CopyStream is already set, it is used to read data to push to server, after which the copy is completed. /// Otherwise CopyStream is set to a writable NpgsqlCopyInStream that calls SendCopyData each time it is written to. /// </summary> protected override void StartCopy(NpgsqlConnector context, NpgsqlCopyFormat copyFormat) { _copyFormat = copyFormat; Stream userFeed = context.Mediator.CopyStream; if (userFeed == null) { context.Mediator.CopyStream = new NpgsqlCopyInStream(context); } else { // copy all of user feed to server at once int bufsiz = context.Mediator.CopyBufferSize; byte[] buf = new byte[bufsiz]; int len; while ((len = userFeed.Read(buf, 0, bufsiz)) > 0) { SendCopyData(context, buf, 0, len); } SendCopyDone(context); } }
public override void Describe(NpgsqlConnector context, NpgsqlDescribe describe) { describe.WriteToStream(context.Stream); //context.Stream.Flush(); }
public void EmptySync(NpgsqlConnector context) { Stream stm = context.Stream; NpgsqlSync.Send(stm); stm.Flush(); Queue<int> buffer = new Queue<int>(); //byte[] compareBuffer = new byte[6]; int newByte; for (; ; ) { switch (newByte = stm.ReadByte()) { case -1: throw new EndOfStreamException(); case 'E': case 'I': case 'T': if (buffer.Count > 4) { bool match = true; int i = 0; foreach (byte cmp in buffer) { if (cmp != messageSought[i++]) { match = false; break; } } if (match) { return; } } break; default: buffer.Enqueue(newByte); if (buffer.Count > 5) { buffer.Dequeue(); } break; } } }
// COPY methods protected virtual void StartCopy(NpgsqlConnector context, NpgsqlCopyFormat copyFormat) { throw new InvalidOperationException("Internal Error! " + this); }
public override void Open(NpgsqlConnector context) { try { IPAddress[] ips = ResolveIPHost(context.Host); Socket socket = null; // try every ip address of the given hostname, use the first reachable one foreach (IPAddress ip in ips) { IPEndPoint ep = new IPEndPoint(ip, context.Port); socket = new Socket(ep.AddressFamily, SocketType.Stream, ProtocolType.Tcp); try { IAsyncResult result = socket.BeginConnect(ep, null, null); if (!result.AsyncWaitHandle.WaitOne(context.ConnectionTimeout * 1000, true)) { socket.Close(); throw new Exception(resman.GetString("Exception_ConnectionTimeout")); } socket.EndConnect(result); // connect was successful, leave the loop break; } catch (Exception) { socket.Close(); } } if (socket == null || !socket.Connected) { throw new Exception(string.Format(resman.GetString("Exception_FailedConnection"), context.Host)); } Stream stream = new NpgsqlNetworkStream(context, socket, true); // If the PostgreSQL server has SSL connectors enabled Open SslClientStream if (response == 'S') { if (context.SSL || (context.SslMode == SslMode.Require) || (context.SslMode == SslMode.Prefer)) { PGUtil.WriteInt32(stream, 8); PGUtil.WriteInt32(stream, 80877103); // Receive response Char response = (Char)stream.ReadByte(); if (response == 'S') { //create empty collection X509CertificateCollection clientCertificates = new X509CertificateCollection(); //trigger the callback to fetch some certificates context.DefaultProvideClientCertificatesCallback(clientCertificates); stream = new SslClientStream( stream, context.Host, true, SecurityProtocolType.Default, clientCertificates); ((SslClientStream)stream).ClientCertSelectionDelegate = new CertificateSelectionCallback(context.DefaultCertificateSelectionCallback); ((SslClientStream)stream).ServerCertValidationDelegate = new CertificateValidationCallback(context.DefaultCertificateValidationCallback); ((SslClientStream)stream).PrivateKeyCertSelectionDelegate = new PrivateKeySelectionCallback(context.DefaultPrivateKeySelectionCallback); } else if (context.SslMode == SslMode.Require) { throw new InvalidOperationException(resman.GetString("Exception_Ssl_RequestError")); } } context.Stream = new BufferedStream(stream); context.Socket = socket; ChangeState(context, NpgsqlConnectedState.Instance); } //FIXME: Exceptions that come from what we are handling should be wrapped - e.g. an error connecting to //the server should definitely be presented to the uesr as an NpgsqlError. Exceptions from userland should //be passed untouched - e.g. ThreadAbortException because the user started this in a thread they created and //then aborted should be passed through. //Are there any others that should be pass through? Alternatively, are there a finite number that should //be wrapped? catch (ThreadAbortException) { throw; } catch (Exception e) { throw new NpgsqlException(e.Message, e); } }
public virtual IEnumerable<IServerResponseObject> SyncEnum(NpgsqlConnector context) { throw new InvalidOperationException("Internal Error! " + this); }
///<summary> /// This method is responsible to handle all protocol messages sent from the backend. /// It holds all the logic to do it. /// To exchange data, it uses a Mediator object from which it reads/writes information /// to handle backend requests. /// </summary> /// internal void ProcessBackendResponses(NpgsqlConnector context) { IterateThroughAllResponses(ProcessBackendResponsesEnum(context, false)); }
public virtual void Bind(NpgsqlConnector context, NpgsqlBind bind) { throw new InvalidOperationException("Internal Error! " + this); }
public virtual void SendCopyData(NpgsqlConnector context, byte[] buf, int off, int len) { throw new InvalidOperationException("Internal Error! " + this); }
/// <summary> /// Put a pooled connector into the pool queue. /// </summary> /// <param name="Connector">Connector to pool</param> private void UngetConnector(NpgsqlConnection Connection, NpgsqlConnector Connector) { ConnectorQueue queue; PooledConnectors.TryGetValue(Connection.ConnectionString, out queue); if (queue == null) { Connector.Close(); // Release connection to postgres return; // Queue may be emptied by connection problems. See ClearPool below. } Connector.ProvideClientCertificatesCallback -= Connection.ProvideClientCertificatesCallbackDelegate; Connector.CertificateSelectionCallback -= Connection.CertificateSelectionCallbackDelegate; Connector.CertificateValidationCallback -= Connection.CertificateValidationCallbackDelegate; Connector.PrivateKeySelectionCallback -= Connection.PrivateKeySelectionCallbackDelegate; bool inQueue = queue.RemoveBusy(Connector); if (!Connector.IsInitialized) { if (Connector.Transaction != null) { Connector.Transaction.Cancel(); } Connector.Close(); } else { if (Connector.Transaction != null) { try { Connector.Transaction.Rollback(); } catch { Connector.Close(); } } } if (Connector.State == ConnectionState.Open) { //If thread is good if ((Thread.CurrentThread.ThreadState & (ThreadState.Aborted | ThreadState.AbortRequested)) == 0) { // Release all resources associated with this connector. try { Connector.ReleaseResources(); } catch (Exception) { //If the connector fails to release its resources then it is probably broken, so make sure we don't add it to the queue. // Usually it already won't be in the queue as it would of broken earlier inQueue = false; } if (inQueue) { queue.EnqueueAvailable(Connector); } else { Connector.Close(); } } else { //Thread is being aborted, this connection is possibly broken. So kill it rather than returning it to the pool Connector.Close(); } } }
public void TestConnector(NpgsqlConnector context) { EmptySync(context); }
/// <summary> /// Find an available pooled connector in the non-shared pool, or create /// a new one if none found. /// </summary> private NpgsqlConnector GetPooledConnector(NpgsqlConnection Connection) { ConnectorQueue Queue; NpgsqlConnector Connector = null; // Try to find a queue. if (!PooledConnectors.TryGetValue(Connection.ConnectionString, out Queue)) { Queue = new ConnectorQueue(); Queue.ConnectionLifeTime = Connection.ConnectionLifeTime; Queue.MinPoolSize = Connection.MinPoolSize; PooledConnectors[Connection.ConnectionString] = Queue; } // Now we can simply lock on the pool itself. lock (Queue) { if (Queue.AvailableCount > 0) { // Found a queue with connectors. Grab the top one. // Check if the connector is still valid. Connector = Queue.TakeAvailable(); Queue.AddBusy(Connector); } } if (Connector != null) { if (!Connector.IsValid()) { Queue.RemoveBusy(Connector); Connector.Close(); return(GetPooledConnector(Connection)); //Try again } return(Connector); } lock (Queue) { if (Queue.AvailableCount + Queue.BusyCount < Connection.MaxPoolSize) { Connector = new NpgsqlConnector(Connection); Queue.AddBusy(Connector); } } if (Connector != null) { Connector.ProvideClientCertificatesCallback += Connection.ProvideClientCertificatesCallbackDelegate; Connector.CertificateSelectionCallback += Connection.CertificateSelectionCallbackDelegate; Connector.CertificateValidationCallback += Connection.CertificateValidationCallbackDelegate; Connector.PrivateKeySelectionCallback += Connection.PrivateKeySelectionCallbackDelegate; try { Connector.Open(); } catch { Queue.RemoveBusy(Connector); Connector.Close(); throw; } // Meet the MinPoolSize requirement if needed. if (Connection.MinPoolSize > 1) { lock (Queue) { while (Queue.AvailableCount + Queue.BusyCount < Connection.MinPoolSize) { NpgsqlConnector Spare = new NpgsqlConnector(Connection); Spare.ProvideClientCertificatesCallback += Connection.ProvideClientCertificatesCallbackDelegate; Spare.CertificateSelectionCallback += Connection.CertificateSelectionCallbackDelegate; Spare.CertificateValidationCallback += Connection.CertificateValidationCallbackDelegate; Spare.PrivateKeySelectionCallback += Connection.PrivateKeySelectionCallbackDelegate; Spare.Open(); Spare.ProvideClientCertificatesCallback -= Connection.ProvideClientCertificatesCallbackDelegate; Spare.CertificateSelectionCallback -= Connection.CertificateSelectionCallbackDelegate; Spare.CertificateValidationCallback -= Connection.CertificateValidationCallbackDelegate; Spare.PrivateKeySelectionCallback -= Connection.PrivateKeySelectionCallbackDelegate; Queue.EnqueueAvailable(Spare); } } } } return(Connector); }
private void CleanUpConnector(NpgsqlConnection Connection, NpgsqlConnector Connector) { new CleanUpConnectorDel(CleanUpConnectorMethod).BeginInvoke(Connection, Connector, null, null); }
/// <summary> /// Created only by NpgsqlCopyOutState.StartCopy() /// </summary> internal NpgsqlCopyOutStream(NpgsqlConnector context) { _context = context; }
public virtual void FunctionCall(NpgsqlConnector context, NpgsqlCommand command) { throw new InvalidOperationException("Internal Error! " + this); }
public virtual void Execute(NpgsqlConnector context, NpgsqlExecute execute) { throw new InvalidOperationException("Internal Error! " + this); }
public virtual void Parse(NpgsqlConnector context, NpgsqlParse parse) { throw new InvalidOperationException("Internal Error! " + this); }
public virtual void Describe(NpgsqlConnector context, NpgsqlDescribe describe) { throw new InvalidOperationException("Internal Error! " + this); }
public virtual void Startup(NpgsqlConnector context) { throw new InvalidOperationException("Internal Error! " + this); }
public void TestNotify(NpgsqlConnector context) { //ZA Hnotifytest CNOTIFY Z //Qlisten notifytest;notify notifytest; Stream stm = context.Stream; string uuidString = "uuid" + Guid.NewGuid().ToString("N"); PGUtil.WriteString("Qlisten " + uuidString + ";notify " + uuidString + ";", stm); Queue<byte> buffer = new Queue<byte>(); byte[] convertBuffer = new byte[36]; for (; ; ) { int newByte = stm.ReadByte(); if (newByte == -1) { throw new EndOfStreamException(); } buffer.Enqueue((byte)newByte); if (buffer.Count > 35) { buffer.CopyTo(convertBuffer, 0); if (ENCODING_UTF8.GetString(convertBuffer) == uuidString) { for (; ; ) { switch (stm.ReadByte()) { case -1: throw new EndOfStreamException(); case 'Z': //context.Query(new NpgsqlCommand("UNLISTEN *", context)); using (NpgsqlCommand cmd = new NpgsqlCommand("UNLISTEN *", context)) { context.Query(cmd); } return; } } } else { buffer.Dequeue(); } } } }
public virtual byte[] GetCopyData(NpgsqlConnector context) { throw new InvalidOperationException("Internal Error! " + this); }
///<summary> ///This method is used by the states to change the state of the context. /// </summary> protected static void ChangeState(NpgsqlConnector context, NpgsqlState newState) { context.CurrentState = newState; }
public override void Flush(NpgsqlConnector context) { _flushMessage.WriteToStream(context.Stream); context.Stream.Flush(); ProcessBackendResponses(context); }
public virtual void SendCopyFail(NpgsqlConnector context, String message) { throw new InvalidOperationException("Internal Error! " + this); }
/// <summary> /// Given command is executed upon Start() and all requested copy data is written to toStream immediately. /// </summary> public NpgsqlCopyOut(NpgsqlCommand cmd, NpgsqlConnection conn, Stream toStream) { _context = conn.Connector; _cmd = cmd; _copyStream = toStream; }
protected IEnumerable <IServerResponseObject> ProcessBackendResponses_Ver_3(NpgsqlConnector context) { try { Stream stream = context.Stream; NpgsqlMediator mediator = context.Mediator; var buffer = context.TmpBuffer; var queue = context.ArrayBuffer; List <NpgsqlError> errors = null; SCRAM scram = null; for (; ;) { // Check the first Byte of response. BackEndMessageCode message = (BackEndMessageCode)stream.ReadByte(); switch (message) { case BackEndMessageCode.ErrorResponse: NpgsqlError error = new NpgsqlError(stream, buffer, queue); error.ErrorSql = mediator.SqlSent; if (errors == null) { errors = new List <NpgsqlError>(); } errors.Add(error); // 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: // Get the length in case we're getting AuthenticationGSSContinue int authDataLength = PGUtil.ReadInt32(stream, buffer) - 8; AuthenticationRequestType authType = (AuthenticationRequestType)PGUtil.ReadInt32(stream, buffer); switch (authType) { case AuthenticationRequestType.AuthenticationOk: break; case AuthenticationRequestType.AuthenticationClearTextPassword: // Send the PasswordPacket. ChangeState(context, NpgsqlStartupState.Instance); context.Authenticate(context.Password); break; case AuthenticationRequestType.AuthenticationMD5Password: // 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 = ENCODING_UTF8.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 = ENCODING_UTF8.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(ENCODING_UTF8.GetBytes(sb.ToString())); break; #if WINDOWS && UNMANAGED 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"); 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 case AuthenticationRequestType.AuthenticationSASL: var saslAuthMechanism = PGUtil.ReadString(stream, queue); if (saslAuthMechanism == "SCRAM-SHA-256") { stream.ReadByte(); scram = new SCRAM(saslAuthMechanism, context.UserName); stream.WriteByte((byte)FrontEndMessageCode.SASL); var schemeBytes = Encoding.UTF8.GetBytes(scram.Scheme); var clientFirstMessageBytes = Encoding.UTF8.GetBytes(scram.getClientFirstMessage()); PGUtil.WriteInt32(stream, 9 + schemeBytes.Length + clientFirstMessageBytes.Length); stream.Write(schemeBytes, 0, schemeBytes.Length); stream.WriteByte(0); PGUtil.WriteInt32(stream, clientFirstMessageBytes.Length); stream.Write(clientFirstMessageBytes, 0, clientFirstMessageBytes.Length); stream.Flush(); } else { throw new NpgsqlException("Only Scram SHA 256 is supported"); } break; case AuthenticationRequestType.AuthenticationSASLContinue: if (scram == null) { throw new NpgsqlException("Invalid authentication message"); } var continueData = new byte[authDataLength]; PGUtil.CheckedStreamRead(stream, continueData, 0, authDataLength); scram.parseServerFirstMessage(Encoding.UTF8.GetString(continueData)); scram.Password = Encoding.UTF8.GetString(context.Password); var mesageBytes = Encoding.UTF8.GetBytes(scram.getClientFinalMessage()); stream.WriteByte((byte)FrontEndMessageCode.SASL); PGUtil.WriteInt32(stream, 4 + mesageBytes.Length); stream.Write(mesageBytes, 0, mesageBytes.Length); stream.Flush(); break; case AuthenticationRequestType.AuthenticationSASLFinal: if (scram == null) { throw new NpgsqlException("Invalid authentication message"); } var finalData = new byte[authDataLength]; PGUtil.CheckedStreamRead(stream, finalData, 0, authDataLength); scram.verifyServerSignature(Encoding.UTF8.GetString(finalData)); break; default: // Only AuthenticationClearTextPassword, AuthenticationMD5Password and AuthenticationSASL supported for now. if (errors == null) { errors = new List <NpgsqlError>(); } errors.Add( new NpgsqlError(String.Format("Only AuthenticationClearTextPassword, AuthenticationMD5Password and AuthenticationSASL supported for now. Received: {0}", authType))); throw new NpgsqlException(errors); } break; case BackEndMessageCode.RowDescription: yield return(context.RowDescription()); break; case BackEndMessageCode.ParameterDescription: // Do nothing,for instance, just read... int length = PGUtil.ReadInt32(stream, buffer); int nb_param = PGUtil.ReadInt16(stream, buffer); //WTF for (int i = 0; i < nb_param; i++) { int typeoid = PGUtil.ReadInt32(stream, buffer); } break; case BackEndMessageCode.DataRow: yield return(context.NextRow()); break; case BackEndMessageCode.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, buffer); stream.ReadByte(); ChangeState(context, NpgsqlReadyState.Instance); if (errors != null) { throw new NpgsqlException(errors); } yield break; case BackEndMessageCode.BackendKeyData: // BackendKeyData message. NpgsqlBackEndKeyData backend_keydata = new NpgsqlBackEndKeyData(stream, buffer); 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, buffer, queue)); break; case BackEndMessageCode.CompletedResponse: PGUtil.ReadInt32(stream, buffer); yield return(new CompletedResponse(stream, queue)); break; case BackEndMessageCode.ParseComplete: // Just read up the message length. PGUtil.ReadInt32(stream, buffer); yield break; case BackEndMessageCode.BindComplete: // Just read up the message length. PGUtil.ReadInt32(stream, buffer); yield break; case BackEndMessageCode.EmptyQueryResponse: PGUtil.ReadInt32(stream, buffer); break; case BackEndMessageCode.NotificationResponse: // Eat the length PGUtil.ReadInt32(stream, buffer); context.FireNotification(new NpgsqlNotificationEventArgs(stream, true, buffer, queue)); if (context.IsNotificationThreadRunning) { yield break; } break; case BackEndMessageCode.ParameterStatus: NpgsqlParameterStatus parameterStatus = new NpgsqlParameterStatus(stream, queue); 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. PGUtil.ReadInt32(stream, buffer); break; case BackEndMessageCode.CopyInResponse: // Enter COPY sub protocol and start pushing data to server ChangeState(context, NpgsqlCopyInState.Instance); PGUtil.ReadInt32(stream, buffer); // length redundant context.CurrentState.StartCopy(context, ReadCopyHeader(stream, buffer)); 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 ChangeState(context, NpgsqlCopyOutState.Instance); PGUtil.ReadInt32(stream, buffer); // length redundant context.CurrentState.StartCopy(context, ReadCopyHeader(stream, buffer)); 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: Int32 len = PGUtil.ReadInt32(stream, buffer) - 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: PGUtil.ReadInt32(stream, buffer); // 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)); } } } finally { context.RequireReadyForQuery = true; } }
public virtual void Authenticate(NpgsqlConnector context, byte[] password) { throw new InvalidOperationException("Internal Error! " + this); }
public void Query(NpgsqlConnector context, NpgsqlCommand command) { IterateThroughAllResponses(QueryEnum(context, command)); }
public NpgsqlRowDescription Sync(NpgsqlConnector context) { NpgsqlRowDescription lastDescription = null; foreach (IServerResponseObject obj in SyncEnum(context)) { if (obj is NpgsqlRowDescription) { lastDescription = obj as NpgsqlRowDescription; } else { if (obj is IDisposable) { (obj as IDisposable).Dispose(); } } } return lastDescription; }
public override IEnumerable <IServerResponseObject> SyncEnum(NpgsqlConnector context) { _syncMessage.WriteToStream(context.Stream); context.Stream.Flush(); return(ProcessBackendResponsesEnum(context, false)); }
/// <summary> /// Checks for context socket availability. /// Socket.Poll supports integer as microseconds parameter. /// This limits the usable command timeout value /// to 2,147 seconds: (2,147 x 1,000,000 < max_int). /// In order to bypass this limit, the availability of /// the socket is checked in 2,147 seconds cycles /// </summary> /// <returns><c>true</c>, if for context socket availability was checked, <c>false</c> otherwise.</returns> /// <param name="context">Context.</param> /// <param name="selectMode">Select mode.</param> internal bool CheckForContextSocketAvailability(NpgsqlConnector context, SelectMode selectMode) { /* Socket.Poll supports integer as microseconds parameter. * This limits the usable command timeout value * to 2,147 seconds: (2,147 x 1,000,000 < max_int). */ const int limitOfSeconds = 2147; bool socketPoolResponse = false; int secondsToWait = context.Mediator.CommandTimeout; /* In order to bypass this limit, the availability of * the socket is checked in 2,147 seconds cycles */ while ((secondsToWait > limitOfSeconds) && (!socketPoolResponse)) { // socketPoolResponse = context.Socket.Poll(1000000 * limitOfSeconds, selectMode); secondsToWait -= limitOfSeconds; } return socketPoolResponse || context.Socket.Poll(1000000 * secondsToWait, selectMode); }
public virtual IEnumerable <IServerResponseObject> SyncEnum(NpgsqlConnector context) { throw new InvalidOperationException("Internal Error! " + this); }
///<summary> /// This method is responsible to handle all protocol messages sent from the backend. /// It holds all the logic to do it. /// To exchange data, it uses a Mediator object from which it reads/writes information /// to handle backend requests. /// </summary> /// internal IEnumerable<IServerResponseObject> ProcessBackendResponsesEnum( NpgsqlConnector context, bool cancelRequestCalled) { try { // Process commandTimeout behavior. if ((context.Mediator.CommandTimeout > 0) && (!CheckForContextSocketAvailability(context, SelectMode.SelectRead))) { // If timeout occurs when establishing the session with server then // throw an exception instead of trying to cancel query. This helps to prevent loop as CancelRequest will also try to stablish a connection and sends commands. if (!((this is NpgsqlStartupState || this is NpgsqlConnectedState || cancelRequestCalled))) { try { context.CancelRequest(); foreach (IServerResponseObject obj in ProcessBackendResponsesEnum(context, true)) { if (obj is IDisposable) { (obj as IDisposable).Dispose(); } } } catch { } //We should have gotten an error from CancelRequest(). Whether we did or not, what we //really have is a timeout exception, and that will be less confusing to the user than //"operation cancelled by user" or similar, so whatever the case, that is what we'll throw. // Changed message again to report about the two possible timeouts: connection or command as the establishment timeout only was confusing users when the timeout was a command timeout. } throw new NpgsqlException(resman.GetString("Exception_ConnectionOrCommandTimeout")); } return ProcessBackendResponses_Ver_3(context); } catch (ThreadAbortException) { try { context.CancelRequest(); context.Close(); } catch { } throw; } }
public override void Close(NpgsqlConnector context) { //DO NOTHING. }
protected IEnumerable<IServerResponseObject> ProcessBackendResponses_Ver_3(NpgsqlConnector context) { using (new ContextResetter(context)) { Stream stream = context.Stream; NpgsqlMediator mediator = context.Mediator; NpgsqlRowDescription lastRowDescription = null; var buffer = context.TmpBuffer; var queue = context.ArrayBuffer; List<NpgsqlError> errors = null; for (; ; ) { // Check the first Byte of response. BackEndMessageCode message = (BackEndMessageCode)stream.ReadByte(); switch (message) { case BackEndMessageCode.ErrorResponse: NpgsqlError error = new NpgsqlError(stream, buffer, queue); error.ErrorSql = mediator.SqlSent; if (errors == null) errors = new List<NpgsqlError>(); errors.Add(error); // 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: // Get the length in case we're getting AuthenticationGSSContinue int authDataLength = PGUtil.ReadInt32(stream, buffer) - 8; AuthenticationRequestType authType = (AuthenticationRequestType)PGUtil.ReadInt32(stream, buffer); switch (authType) { case AuthenticationRequestType.AuthenticationOk: break; case AuthenticationRequestType.AuthenticationClearTextPassword: // Send the PasswordPacket. ChangeState(context, NpgsqlStartupState.Instance); context.Authenticate(context.Password); break; case AuthenticationRequestType.AuthenticationMD5Password: // 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 = ENCODING_UTF8.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 = ENCODING_UTF8.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(ENCODING_UTF8.GetBytes(sb.ToString())); break; #if WINDOWS && UNMANAGED 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"); 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. if (errors == null) errors = new List<NpgsqlError>(); errors.Add( new NpgsqlError(String.Format(resman.GetString("Exception_AuthenticationMethodNotSupported"), authType))); throw new NpgsqlException(errors); } break; case BackEndMessageCode.RowDescription: yield return lastRowDescription = new NpgsqlRowDescription(stream, context.OidToNameMapping, context.CompatVersion, buffer, queue); break; case BackEndMessageCode.ParameterDescription: // Do nothing,for instance, just read... int length = PGUtil.ReadInt32(stream, buffer); int nb_param = PGUtil.ReadInt16(stream, buffer); //WTF for (int i = 0; i < nb_param; i++) { int typeoid = PGUtil.ReadInt32(stream, buffer); } break; case BackEndMessageCode.DataRow: yield return new ForwardsOnlyRow(new StringRowReader(lastRowDescription, stream, buffer, queue)); break; case BackEndMessageCode.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, buffer); stream.ReadByte(); ChangeState(context, NpgsqlReadyState.Instance); if (errors != null) { throw new NpgsqlException(errors); } yield break; case BackEndMessageCode.BackendKeyData: // BackendKeyData message. NpgsqlBackEndKeyData backend_keydata = new NpgsqlBackEndKeyData(stream, buffer); 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, buffer, queue)); break; case BackEndMessageCode.CompletedResponse: PGUtil.ReadInt32(stream, buffer); yield return new CompletedResponse(stream, queue); break; case BackEndMessageCode.ParseComplete: // Just read up the message length. PGUtil.ReadInt32(stream, buffer); yield break; case BackEndMessageCode.BindComplete: // Just read up the message length. PGUtil.ReadInt32(stream, buffer); yield break; case BackEndMessageCode.EmptyQueryResponse: PGUtil.ReadInt32(stream, buffer); break; case BackEndMessageCode.NotificationResponse: // Eat the length PGUtil.ReadInt32(stream, buffer); context.FireNotification(new NpgsqlNotificationEventArgs(stream, true, buffer, queue)); if (context.IsNotificationThreadRunning) { yield break; } break; case BackEndMessageCode.ParameterStatus: NpgsqlParameterStatus parameterStatus = new NpgsqlParameterStatus(stream, queue); 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. PGUtil.ReadInt32(stream, buffer); break; case BackEndMessageCode.CopyInResponse: // Enter COPY sub protocol and start pushing data to server ChangeState(context, NpgsqlCopyInState.Instance); PGUtil.ReadInt32(stream, buffer); // length redundant context.CurrentState.StartCopy(context, ReadCopyHeader(stream, buffer)); 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 ChangeState(context, NpgsqlCopyOutState.Instance); PGUtil.ReadInt32(stream, buffer); // length redundant context.CurrentState.StartCopy(context, ReadCopyHeader(stream, buffer)); 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: Int32 len = PGUtil.ReadInt32(stream, buffer) - 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: PGUtil.ReadInt32(stream, buffer); // 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 NotificationThreadBlock(NpgsqlConnector connector) { (_connector = connector).StopNotificationThread(); }
public ContextResetter(NpgsqlConnector connector) { _connector = connector; }
internal NpgsqlContextHolder(NpgsqlConnector connector, NpgsqlState state) { this.connector = connector; this.state = state; }
public virtual void Flush(NpgsqlConnector context) { throw new InvalidOperationException("Internal Error! " + this); }
public NpgsqlNetworkStream(NpgsqlConnector context, Socket socket, Boolean owner) : base(socket, owner) { mContext = context; }