Inheritance: AbstractNode
        public OtpErlangRef(OtpLocalNode self)
        {
            OtpErlangRef r = self.createRef();

            ids = r.Ids;
            creation = r.Creation;
            node = r.Node;
        }
        public OtpErlangPid(OtpLocalNode self)
        {
            OtpErlangPid p = self.createPid();

            id = p.id;
            serial = p.serial;
            creation = p.creation;
            node = p.node;
        }
        /**
         * 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;
        }
        /*
         * Send an auth error to peer because he sent a bad cookie. The auth error
         * uses his cookie (not revealing ours). This is just like send_reg
         * otherwise
         */
        private void cookieError(OtpLocalNode local, OtpErlangAtom cookie)
        {
            try
            {
                OtpOutputStream header = new OtpOutputStream(headerLen);

                // preamble: 4 byte length + "passthrough" tag + version
                header.write4BE(0); // reserve space for length
                header.write1(passThrough);
                header.write1(version);

                header.write_tuple_head(4);
                header.write_long(regSendTag);
                header.write_any(local.createPid()); // disposable pid
                header.write_atom(cookie.atomValue()); // important: his cookie,
                // not mine...
                header.write_atom("auth");

                // version for payload
                header.write1(version);

                // the payload

                // the no_auth message (copied from Erlang) Don't change this
                // (Erlang will crash)
                // {$gen_cast, {print, "~n** Unauthorized cookie ~w **~n",
                // [foo@aule]}}
                OtpErlangObject[] msg = new OtpErlangObject[2];
                OtpErlangObject[] msgbody = new OtpErlangObject[3];

                msgbody[0] = new OtpErlangAtom("print");
                msgbody[1] = new OtpErlangString("~n** Bad cookie sent to " + local + " **~n");

                // Erlang will crash and burn if there is no third argument here...
                msgbody[2] = new OtpErlangList(); // empty list

                msg[0] = new OtpErlangAtom("$gen_cast");
                msg[1] = new OtpErlangTuple(msgbody);

                OtpOutputStream payload = new OtpOutputStream(new OtpErlangTuple(msg));

                // fix up length in preamble
                header.poke4BE(0, header.size() + payload.size() - 4);

                try
                {
                    do_send(header, payload);
                }
                catch (IOException)
                {
                } // ignore
            }
            finally
            {
                close();
            }
            throw new OtpAuthException("Remote cookie not authorized: " + cookie.atomValue());
        }
        /*
         * this function will get an exception if it tries to talk to an r3 epmd, or
         * if something else happens that it cannot forsee. In both cases we return
         * an exception (and the caller should try again, using the r3 protocol). If
         * we manage to successfully communicate with an r4 epmd, we return either
         * the socket, or null, depending on the result.
         */
        private static TcpClient r4_publish(OtpLocalNode node)
        {
            TcpClient s = null;

            try
            {
                OtpOutputStream obuf = new OtpOutputStream();
                s = new TcpClient(node.Host, EpmdPort.get());

                obuf.write2BE(node.Alive.Length + 13);

                obuf.write1(publish4req);
                obuf.write2BE(node.Port);

                obuf.write1(node.Type);

                obuf.write1(node.Proto);
                obuf.write2BE(node.DistHigh);
                obuf.write2BE(node.DistLow);

                obuf.write2BE(node.Alive.Length);
                obuf.writeN(Encoding.GetEncoding("iso-8859-1").GetBytes(node.Alive));
                obuf.write2BE(0); // No extra

                // send request
                obuf.WriteTo(s.GetStream());

                if (traceLevel >= traceThreshold)
                {
                    log.Debug("-> PUBLISH (r4) " + node + " port=" + node.Port);
                }

                // get reply
                byte[] tmpbuf = new byte[100];
                int n = s.GetStream().Read(tmpbuf, 0, tmpbuf.Length);

                if (n < 0)
                {
                    // this was an r3 node => not a failure (yet)
                    if (s != null)
                    {
                        s.Close();
                    }
                    throw new IOException("Nameserver not responding on "
                              + node.Host + " when publishing " + node.Alive);
                }

                OtpInputStream ibuf = new OtpInputStream(tmpbuf, 0);

                int response = ibuf.read1();
                if (response == publish4resp)
                {
                    int result = ibuf.read1();
                    if (result == 0)
                    {
                        node.Creation = ibuf.read2BE();
                        if (traceLevel >= traceThreshold)
                        {
                            log.Debug("<- OK");
                        }
                        return s; // success
                    }
                }

            }
            catch (SocketException)
            {
                if (traceLevel >= traceThreshold)
                {
                    log.Debug("<- (no response)");
                }
                throw new IOException("Nameserver not responding on " + node.Host);
            }
            catch (IOException)
            {
                // epmd closed the connection = fail
                if (s != null)
                {
                    s.Close();
                }
                if (traceLevel >= traceThreshold)
                {
                    log.Debug("<- (no response)");
                }
                throw new IOException("Nameserver not responding on " + node.Host
                              + " when publishing " + node.Alive);
            }
            catch (OtpErlangDecodeException)
            {
                if (s != null)
                {
                    s.Close();
                }
                if (traceLevel >= traceThreshold)
                {
                    log.Debug("<- (invalid response)");
                }
                throw new IOException("Nameserver not responding on " + node.Host
                              + " when publishing " + node.Alive);
            }

            if (s != null)
            {
                s.Close();
            }
            return null;
        }
        private static TcpClient r3_publish(OtpLocalNode node)
        {
            TcpClient s;

            try
            {
                OtpOutputStream obuf = new OtpOutputStream();
                s = new TcpClient(node.Host, EpmdPort.get());

                obuf.write2BE(node.Alive.Length + 3);

                obuf.write1(publish3req);
                obuf.write2BE(node.Port);
                obuf.writeN(Encoding.GetEncoding("iso-8859-1").GetBytes(node.Alive));

                // send request
                obuf.WriteTo(s.GetStream());
                if (traceLevel >= traceThreshold)
                {
                    log.Debug("-> PUBLISH (r3) " + node + " port=" + node.Port);
                }

                byte[] tmpbuf = new byte[100];

                int n = s.GetStream().Read(tmpbuf, 0, tmpbuf.Length);

                if (n < 0)
                {
                    if (traceLevel >= traceThreshold)
                    {
                        log.Debug("<- (no response)");
                    }
                    return null;
                }

                OtpInputStream ibuf = new OtpInputStream(tmpbuf, 0);

                if (ibuf.read1() == publish3ok)
                {
                    node.Creation = ibuf.read2BE();
                    if (traceLevel >= traceThreshold)
                    {
                        log.Debug("<- OK");
                    }
                    return s; // success - don't close socket
                }
            }
            catch (SocketException)
            {
                if (traceLevel >= traceThreshold)
                {
                    log.Debug("<- (no response)");
                }
                throw new IOException("Nameserver not responding on " + node.Host);
            }
            catch (IOException)
            {
                // epmd closed the connection = fail
                if (traceLevel >= traceThreshold)
                {
                    log.Debug("<- (no response)");
                }
                throw new IOException("Nameserver not responding on " + node.Host
                              + " when publishing " + node.Alive);
            }
            catch (OtpErlangDecodeException)
            {
                if (traceLevel >= traceThreshold)
                {
                    log.Debug("<- (invalid response)");
                }
                throw new IOException("Nameserver not responding on " + node.Host
                              + " when publishing " + node.Alive);
            }
            return null; // failure
        }
 // Ask epmd to close his end of the connection.
 // Caller should close his epmd socket as well.
 // This method is pretty forgiving...
 /**
  * Unregister from Epmd. Other nodes wishing to connect will no longer be
  * able to.
  *
  * <p>
  * This method does not report any failures.
  */
 public static void unPublishPort(OtpLocalNode node)
 {
     try
     {
         using (TcpClient s = new TcpClient(Dns.GetHostName(), EpmdPort.get()))
         {
             OtpOutputStream obuf = new OtpOutputStream();
             obuf.write2BE(node.Alive.Length + 1);
             obuf.write1(stopReq);
             obuf.writeN(Encoding.GetEncoding("iso-8859-1").GetBytes(node.Alive));
             obuf.WriteTo(s.GetStream());
             // don't even wait for a response (is there one?)
             if (traceLevel >= traceThreshold)
             {
                 log.Debug("-> UNPUBLISH " + node + " port=" + node.Port);
                 log.Debug("<- OK (assumed)");
             }
         }
     }
     catch (Exception) /* ignore all failures */
     {
     }
 }
        /**
         * Register with Epmd, so that other nodes are able to find and connect to
         * it.
         *
         * @param node
         *            the server node that should be registered with Epmd.
         *
         * @return true if the operation was successful. False if the node was
         *         already registered.
         *
         * @exception java.io.IOException
         *                if there was no response from the name server.
         */
        public static bool publishPort(OtpLocalNode node)
        {
            TcpClient s = null;

            try
            {
                s = r4_publish(node);
            }
            catch (IOException)
            {
                s = r3_publish(node);
            }

            node.setEpmd(s);

            return s != null;
        }