protected GenericQueue queue; // messages get delivered here

        #endregion Fields

        #region Constructors

        /*
         * Accept an incoming connection from a remote node. Used by {@link
         * OtpSelf#accept() OtpSelf.accept()} to create a connection based on data
         * received when handshaking with the peer node, when the remote node is the
         * connection intitiator.
         *
         * @exception java.io.IOException if it was not possible to connect to the
         * peer.
         *
         * @exception OtpAuthException if handshake resulted in an authentication
         * error
         */
        // package scope
        internal OtpConnection(OtpSelf self, BufferedTcpClient s)
            : base(self, s)
        {
            this.self = self;
            queue = new GenericQueue();
            start();
        }
        /* this method now throws exception if we don't get full read */
        protected int readSock(BufferedTcpClient s, byte[] b)
        {
            int got = 0;
            int len = b.Length;
            int i;
            Stream st = null;

            lock (this)
            {
                if (s == null)
                {
                    throw new IOException("expected " + len + " bytes, socket was closed");
                }
                st = s.GetInputStream();
            }

            while (got < len)
            {
                try
                {
                    i = st.Read(b, got, len - got);
                }
                catch (IOException e)
                {
                    throw new IOException(e.Message);
                }
                catch (ObjectDisposedException e)
                {
                    throw new IOException(e.Message);
                }

                if (i < 0)
                {
                    throw new IOException("expected " + len + " bytes, got EOF after " + got + " bytes");
                }
                else if (i == 0 && len != 0)
                {
                    /*
                     * This is a corner case. According to
                     * http://java.sun.com/j2se/1.4.2/docs/api/ class InputStream
                     * is.read(,,l) can only return 0 if l==0. In other words it
                     * should not happen, but apparently did.
                     */
                    throw new IOException("Remote connection closed");
                }
                else
                {
                    got += i;
                }
            }
            return got;
        }
        protected void doConnect(int port)
        {
            try
            {
                socket = new BufferedTcpClient(new TcpClient(peer.Host, port));

                if (traceLevel >= handshakeThreshold)
                {
                    log.Debug("-> MD5 CONNECT TO " + peer.Host + ":" + port);
                }
                sendName(peer.DistChoose, self.Flags);
                recvStatus();
                int her_challenge = recvChallenge();
                byte[] our_digest = genDigest(her_challenge, self.Cookie);
                int our_challenge = genChallenge();
                sendChallengeReply(our_challenge, our_digest);
                recvChallengeAck(our_challenge);
                cookieOk = true;
                sendCookie = false;
            }
            catch (IOException e)
            {
                throw e;
            }
            catch (OtpAuthException e)
            {
                close();
                throw e;
            }
            catch (Exception)
            {
                close();
                throw new IOException("Cannot connect to peer node");
            }
        }
 /**
  * Close the connection to the remote node.
  */
 public virtual void close()
 {
     done = true;
     connected = false;
     lock (this)
     {
         try
         {
             if (socket != null)
             {
                 if (traceLevel >= ctrlThreshold)
                 {
                     log.Debug("-> CLOSE");
                 }
                 socket.Close();
             }
         }
         catch (SocketException) /* ignore socket close errors */
         {
         }
         catch (InvalidOperationException)
         {
         }
         finally
         {
             socket = null;
         }
     }
 }
        /**
         * Intiate and open a connection to a remote node.
         *
         * @exception java.io.IOException if it was not possible to connect to the
         * peer.
         *
         * @exception OtpAuthException if handshake resulted in an authentication
         * error.
         */
        protected AbstractConnection(OtpLocalNode self, OtpPeer other)
            : base("receive", true)
        {
            peer = other;
            this.self = self;
            socket = null;
            int port;

            traceLevel = defaultLevel;

            // now get a connection between the two...
            port = OtpEpmd.lookupPort(peer);

            // now find highest common dist value
            if (peer.Proto != self.Proto || self.DistHigh < peer.DistLow || self.DistLow > peer.DistHigh)
            {
                throw new IOException("No common protocol found - cannot connect");
            }

            // highest common version: min(peer.distHigh, self.distHigh)
            peer.DistChoose = peer.DistHigh > self.DistHigh ? self.DistHigh : peer.DistHigh;

            doConnect(port);

            name = peer.Node;
            connected = true;
        }
        /**
         * Accept an incoming connection from a remote node. Used by {@link
         * OtpSelf#accept() OtpSelf.accept()} to create a connection based on data
         * received when handshaking with the peer node, when the remote node is the
         * connection intitiator.
         *
         * @exception java.io.IOException if it was not possible to connect to the
         * peer.
         *
         * @exception OtpAuthException if handshake resulted in an authentication
         * error
         */
        protected AbstractConnection(OtpLocalNode self, BufferedTcpClient s)
            : base("receive", true)
        {
            this.self = self;
            peer = new OtpPeer();
            socket = s;

            traceLevel = defaultLevel;

            if (traceLevel >= handshakeThreshold)
            {
                log.Debug("<- ACCEPT FROM " + s.Client.RemoteEndPoint);
            }

            // get his info
            recvName(peer);

            // now find highest common dist value
            if (peer.Proto != self.Proto || self.DistHigh < peer.DistLow || self.DistLow > peer.DistHigh)
            {
                close();
                throw new IOException("No common protocol found - cannot accept connection");
            }
            // highest common version: min(peer.distHigh, self.distHigh)
            peer.DistChoose = peer.DistHigh > self.DistHigh ? self.DistHigh : peer.DistHigh;

            doAccept();
            name = peer.Node;
        }
 /*
  * Accept an incoming connection from a remote node. Used by {@link
  * OtpSelf#accept() OtpSelf.accept()} to create a connection based on data
  * received when handshaking with the peer node, when the remote node is the
  * connection intitiator.
  *
  * @exception java.io.IOException if it was not possible to connect to the
  * peer.
  *
  * @exception OtpAuthException if handshake resulted in an authentication
  * error
  */
 // package scope
 internal OtpCookedConnection(OtpNode self, BufferedTcpClient s)
     : base(self, s)
 {
     this.self = self;
     links = new Links(25);
     start();
 }