/// <summary> Creates an LdapResponse using an LdapException.
        /// Used to wake up the user following an abandon.
        /// Note: The abandon doesn't have to be user initiated
        /// but may be the result of error conditions.
        ///
        /// Referral information is available if this connection created solely
        /// to follow a referral.
        ///
        /// </summary>
        /// <param name="ex"> The exception
        ///
        /// </param>
        /// <param name="activeReferral"> The referral actually used to create the
        /// connection
        /// </param>
        public LdapResponse(InterThreadException ex, ReferralInfo activeReferral)
        {
            exception           = ex;
            this.activeReferral = activeReferral;

            return;
        }
        /// <summary> Creates an LdapResponse using an LdapException.
        /// Used to wake up the user following an abandon.
        /// Note: The abandon doesn't have to be user initiated
        /// but may be the result of error conditions.
        /// 
        /// Referral information is available if this connection created solely
        /// to follow a referral.
        /// 
        /// </summary>
        /// <param name="ex"> The exception
        /// 
        /// </param>
        /// <param name="activeReferral"> The referral actually used to create the
        /// connection
        /// </param>
        public LdapResponse(InterThreadException ex, ReferralInfo activeReferral)
        {
            exception = ex;
            this.activeReferral = activeReferral;

            return ;
        }
 /// <summary>
 ///     Creates an LdapResponse using an LdapException.
 ///     Used to wake up the user following an abandon.
 ///     Note: The abandon doesn't have to be user initiated
 ///     but may be the result of error conditions.
 ///     Referral information is available if this connection created solely
 ///     to follow a referral.
 /// </summary>
 /// <param name="ex">
 ///     The exception.
 /// </param>
 /// <param name="activeReferral">
 ///     The referral actually used to create the
 ///     connection.
 /// </param>
 public LdapResponse(InterThreadException ex, ReferralInfo activeReferral)
 {
     _exception     = ex;
     ActiveReferral = activeReferral;
 }
Exemple #4
0
        internal virtual void Abandon(LdapConstraints cons, InterThreadException informUserEx)
        {
            if (!waitForReply_Renamed_Field)
            {
                return ;
            }
            acceptReplies = false; // don't listen to anyone
            waitForReply_Renamed_Field = false; // don't let sleeping threads lie
            if (!complete)
            {
                try
                {
                    // If a bind, release bind semaphore & wake up waiting threads
                    // Must do before writing abandon message, otherwise deadlock
                    if (bindprops != null)
                    {
                        int id;
                        if (conn.BindSemIdClear)
                        {
                            // Semaphore id for normal operations
                            id = msgId;
                        }
                        else
                        {
                            // Semaphore id for sasl bind
                            id = conn.BindSemId;
                            conn.clearBindSemId();
                        }
                        conn.freeWriteSemaphore(id);
                    }

                    // Create the abandon message, but don't track it.
                    LdapControl[] cont = null;
                    if (cons != null)
                    {
                        cont = cons.getControls();
                    }
                    LdapMessage msg = new LdapAbandonRequest(msgId, cont);
                    // Send abandon message to server
                    conn.writeMessage(msg);
                }
                catch (LdapException ex)
                {
                    ; // do nothing
                }
                // If not informing user, remove message from agent
                if (informUserEx == null)
                {
                    agent.Abandon(msgId, null);
                }
                conn.removeMessage(this);
            }
            // Get rid of all replies queued
            if (informUserEx != null)
            {
                replies.Add(new LdapResponse(informUserEx, conn.ActiveReferral));
                stopTimer();
                // wake up waiting threads to receive exception
                sleepersAwake();
                // Message will get cleaned up when last response removed from queue
            }
            else
            {
                // Wake up any waiting threads, so they can terminate.
                // If informing the user, we wake sleepers after
                // caller queues dummy response with error status
                sleepersAwake();
                cleanup();
            }
            return ;
        }
        internal virtual void Abandon(LdapConstraints cons, InterThreadException informUserEx)
        {
            if (!waitForReply_Renamed_Field)
            {
                return;
            }
            acceptReplies = false;              // don't listen to anyone
            waitForReply_Renamed_Field = false; // don't let sleeping threads lie
            if (!complete)
            {
                try
                {
                    // If a bind, release bind semaphore & wake up waiting threads
                    // Must do before writing abandon message, otherwise deadlock
                    if (bindprops != null)
                    {
                        int id;
                        if (conn.BindSemIdClear)
                        {
                            // Semaphore id for normal operations
                            id = msgId;
                        }
                        else
                        {
                            // Semaphore id for sasl bind
                            id = conn.BindSemId;
                            conn.clearBindSemId();
                        }
                        conn.freeWriteSemaphore(id);
                    }

                    // Create the abandon message, but don't track it.
                    LdapControl[] cont = null;
                    if (cons != null)
                    {
                        cont = cons.getControls();
                    }
                    LdapMessage msg = new LdapAbandonRequest(msgId, cont);
                    // Send abandon message to server
                    conn.writeMessage(msg);
                }
                catch (LdapException ex)
                {
                    LogManager.GetCurrentClassLogger().Warn("Exception swallowed", ex);
                }
                // If not informing user, remove message from agent
                if (informUserEx == null)
                {
                    agent.Abandon(msgId, null);
                }
                conn.removeMessage(this);
            }
            // Get rid of all replies queued
            if (informUserEx != null)
            {
                replies.Add(new LdapResponse(informUserEx, conn.ActiveReferral));
                stopTimer();
                // wake up waiting threads to receive exception
                sleepersAwake();
                // Message will get cleaned up when last response removed from queue
            }
            else
            {
                // Wake up any waiting threads, so they can terminate.
                // If informing the user, we wake sleepers after
                // caller queues dummy response with error status
                sleepersAwake();
                cleanup();
            }
        }
		/// <summary> Cleans up resources associated with this connection.
		/// This method may be called by finalize() for the connection, or it may
		/// be called by LdapConnection.disconnect().
		/// Should not have a writeSemaphore lock in place, as deadlock can occur
		/// while abandoning connections.
		/// </summary>
		private void  shutdown(System.String reason, int semaphoreId, InterThreadException notifyUser)
		{
			Message info = null;
			if (!clientActive)
			{
				return ;
			}
			clientActive = false;
			while (true)
			{
				// remove messages from connection list and send abandon
				try
				{
					System.Object temp_object;
					temp_object = messages[0];
					messages.RemoveAt(0);
					info = (Message) temp_object;
				}
				catch (ArgumentOutOfRangeException ex)
				{
					// No more messages
					break;
				}
				info.Abandon(null, notifyUser); // also notifies the application
			}
			
			int semId = acquireWriteSemaphore(semaphoreId);
			// Now send unbind if socket not closed
			if ((bindProperties != null) && (out_Renamed != null) && (!bindProperties.Anonymous))
			{
				try
				{
					LdapMessage msg = new LdapUnbindRequest(null);
					sbyte[] ber = msg.Asn1Object.getEncoding(encoder);
					out_Renamed.Write(SupportClass.ToByteArray(ber), 0, ber.Length);
					out_Renamed.Flush();

				}
				catch (System.Exception ex)
				{
					; // don't worry about error
				}
			}
			bindProperties = null;
			
			in_Renamed = null;
			out_Renamed = null;
			if (socket != null)
			{
				// Close the socket
				try
				{
					if(Ssl)
					{
						sock.Shutdown(SocketShutdown.Both);
						sock.Close();
					}
					else
						socket.Close();
				}
				catch (System.IO.IOException ie)
				{
					// ignore problem closing socket
				}
				socket = null;
				sock = null;
			}
			freeWriteSemaphore(semId);
			return ;
		}
		/// <summary> Destroys a clone of <code>LdapConnection</code>.
		/// 
		/// This method first determines if only one <code>LdapConnection</code>
		/// object is associated with this connection, i.e. if no clone exists.
		/// 
		/// If no clone exists, the socket is closed, and the current
		/// <code>Connection</code> object is returned.
		/// 
		/// If multiple <code>LdapConnection</code> objects are associated
		/// with this connection, i.e. clones exist, a {@link #copy} of the
		/// this object is made, but is not connected to any host. This
		/// disassociates that clone from the original connection.  The new
		/// <code>Connection</code> object is returned.
		/// 
		/// Only one destroyClone instance is allowed to run at any one time.
		/// 
		/// If the connection is closed, any threads waiting for operations
		/// on that connection will wake with an LdapException indicating
		/// the connection is closed.
		/// 
		/// </summary>
		/// <param name="apiCall"><code>true</code> indicates the application is closing the
		/// connection or or creating a new one by calling either the
		/// <code>connect</code> or <code>disconnect</code> methods
		/// of <code>LdapConnection</code>.  <code>false</code>
		/// indicates that <code>LdapConnection</code> is being finalized.
		/// 
		/// </param>
		/// <returns> a Connection object or null if finalizing.
		/// </returns>
		/* package */
		internal Connection destroyClone(bool apiCall)
		{
			lock (this)
			{
				Connection conn = this;

				if (cloneCount > 0)
				{
					cloneCount--;
					// This is a clone, set a new connection object.
					if (apiCall)
					{
						conn = (Connection) this.copy();
					}
					else
					{
						conn = null;
					}
				}
				else
				{
					if (in_Renamed != null)
					{
						// Not a clone and connected
						/*
						* Either the application has called disconnect or connect
						* resulting in the current connection being closed. If the
						* application has any queues waiting on messages, we
						* need wake these up so the application does not hang.
						* The boolean flag indicates whether the close came
						* from an API call or from the object being finalized.
						*/
						InterThreadException notify = new InterThreadException((apiCall?ExceptionMessages.CONNECTION_CLOSED:ExceptionMessages.CONNECTION_FINALIZED), null, LdapException.CONNECT_ERROR, null, null);
						// Destroy old connection
						shutdown("destroy clone", 0, notify);
					}
				}
				return conn;
			}
		}
			/// <summary> This thread decodes and processes RfcLdapMessage's from the server.
			/// 
			/// Note: This thread needs a graceful shutdown implementation.
			/// </summary>
			public virtual void  Run()
			{
				
				System.String reason = "reader: thread stopping";
				InterThreadException notify = null;
				Message info = null;
				System.IO.IOException ioex = null;
				this.enclosingInstance.reader = SupportClass.ThreadClass.Current();				
//				Enclosing_Instance.reader = SupportClass.ThreadClass.Current();
//				Console.WriteLine("Inside run:" + this.enclosingInstance.reader.Name);
				try
				{
					for (; ; )
					{
						// -------------------------------------------------------
						// Decode an RfcLdapMessage directly from the socket.
						// -------------------------------------------------------
						Asn1Identifier asn1ID;
						System.IO.Stream myIn;
						/* get current value of in, keep value consistant
						* though the loop, i.e. even during shutdown
						*/
						myIn = this.enclosingInstance.in_Renamed;
						if (myIn == null)
						{
							break;
						}
						asn1ID = new Asn1Identifier(myIn);
						int tag = asn1ID.Tag;
						if (asn1ID.Tag != Asn1Sequence.TAG)
						{
							continue; // loop looking for an RfcLdapMessage identifier
						}
						
						// Turn the message into an RfcMessage class
						Asn1Length asn1Len = new Asn1Length(myIn);
						
						RfcLdapMessage msg = new RfcLdapMessage(this.enclosingInstance.decoder, myIn, asn1Len.Length);
						
						// ------------------------------------------------------------
						// Process the decoded RfcLdapMessage.
						// ------------------------------------------------------------
						int msgId = msg.MessageID;
						
						// Find the message which requested this response.
						// It is possible to receive a response for a request which
						// has been abandoned. If abandoned, throw it away
						try
						{
							info = this.enclosingInstance.messages.findMessageById(msgId);
							info.putReply(msg); // queue & wake up waiting thread
						}
						catch (System.FieldAccessException ex)
						{
							
							/*
							* We get the NoSuchFieldException when we could not find
							* a matching message id.  First check to see if this is
							* an unsolicited notification (msgID == 0). If it is not
							* we throw it away. If it is we call any unsolicited
							* listeners that might have been registered to listen for these
							* messages.
							*/
							
							
							/* Note the location of this code.  We could have required
							* that message ID 0 be just like other message ID's but
							* since message ID 0 has to be treated specially we have
							* a separate check for message ID 0.  Also note that
							* this test is after the regular message list has been
							* checked for.  We could have always checked the list
							* of messages after checking if this is an unsolicited
							* notification but that would have inefficient as
							* message ID 0 is a rare event (as of this time).
							*/
							if (msgId == 0)
							{
								
								
								// Notify any listeners that might have been registered
								this.enclosingInstance.notifyAllUnsolicitedListeners(msg);
								
								/*
								* Was this a server shutdown unsolicited notification.
								* IF so we quit. Actually calling the return will
								* first transfer control to the finally clause which
								* will do the necessary clean up.
								*/
								if (this.enclosingInstance.unsolSvrShutDnNotification)
								{
									notify = new InterThreadException(ExceptionMessages.SERVER_SHUTDOWN_REQ, new System.Object[]{this.enclosingInstance.host, this.enclosingInstance.port}, LdapException.CONNECT_ERROR, null, null);
									
									return ;
								}
							}
							else
							{
								
							}
						}
						if ((this.enclosingInstance.stopReaderMessageID == msgId) || (this.enclosingInstance.stopReaderMessageID == Novell.Directory.Ldap.Connection.STOP_READING))
						{
							// Stop the reader Thread.
							return ;
						}
					}
				}
				catch (System.IO.IOException ioe)
				{
					
					ioex = ioe;
					if ((this.enclosingInstance.stopReaderMessageID != Novell.Directory.Ldap.Connection.STOP_READING) && this.enclosingInstance.clientActive)
					{
						// Connection lost waiting for results from host:port
						notify = new InterThreadException(ExceptionMessages.CONNECTION_WAIT, new System.Object[]{this.enclosingInstance.host, this.enclosingInstance.port}, LdapException.CONNECT_ERROR, ioe, info);
					}
					// The connection is no good, don't use it any more
					this.enclosingInstance.in_Renamed = null;
					this.enclosingInstance.out_Renamed = null;
				}
				finally
				{
					/*
					* There can be four states that the reader can be in at this point:
					*  1) We are starting TLS and will be restarting the reader
					*     after we have negotiated TLS.
					*      - Indicated by whether stopReaderMessageID does not
					*        equal CONTINUE_READING.
					*      - Don't call Shutdown.
					*  2) We are stoping TLS and will be restarting after TLS is
					*     stopped.
					*      - Indicated by an IOException AND stopReaderMessageID equals
					*        STOP_READING - in which case notify will be null.
					*      - Don't call Shutdown
					*  3) We receive a Server Shutdown notification.
					*      - Indicated by messageID equal to 0.
					*      - call Shutdown.
					*  4) Another error occured
					*      - Indicated by an IOException AND notify is not NULL
					*      - call Shutdown.
					*/
					if ((!this.enclosingInstance.clientActive) || (notify != null))
					{
						//#3 & 4
						this.enclosingInstance.shutdown(reason, 0, notify);
					}
					else
					{
						this.enclosingInstance.stopReaderMessageID = Novell.Directory.Ldap.Connection.CONTINUE_READING;
					}
				}
				this.enclosingInstance.deadReaderException = ioex;
				this.enclosingInstance.deadReader = this.enclosingInstance.reader;
				this.enclosingInstance.reader = null;
				return ;
			}