Esempio n. 1
0
 // used to break all known links to this mbox
 public void BreakLinks(IOtpErlangObject reason)
 {
     foreach (var link in links.ClearLinks())
     {
         Exit(1, link.Remote, reason);
     }
 }
Esempio n. 2
0
 // exit (etc) has from, to, reason
 internal OtpMsg(int tag, OtpErlangPid from, OtpErlangPid to, IOtpErlangObject reason)
 {
     Type    = tag;
     FromPid = from;
     ToPid   = to;
     payload = reason;
 }
Esempio n. 3
0
        /**
         * Send an exit signal to a remote process.
         * Used internally when "processes" terminate
         */
        private void SendExit(int tag, OtpErlangPid from, OtpErlangPid dest, IOtpErlangObject reason)
        {
            if (!Connected)
            {
                throw new IOException("Not connected");
            }

            OtpOutputStream header = new OtpOutputStream(headerLen);

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

            // header
            header.WriteTupleHead(4);
            header.WriteLong(tag);
            header.WriteAny(from);
            header.WriteAny(dest);
            header.WriteAny(reason);

            // fix up length in preamble
            header.Poke4BE(0, header.Length - 4);

            DoSend(header);
        }
Esempio n. 4
0
 public void WriteCompressed(IOtpErlangObject o, CompressionLevel level)
 {
     try
     {
         OtpOutputStream oos = new OtpOutputStream(o);
         if (oos.Length < 5)
         {
             oos.WriteTo(this);
         }
         else
         {
             Write1(OtpExternal.compressedTag);
             Write4BE(oos.Length);
             DeflateStream dos = new DeflateStream(this, level, true);
             oos.WriteTo(dos);
             dos.Close();
         }
     }
     catch (ObjectDisposedException)
     {
         throw new ArgumentException("Intermediate stream failed for Erlang object " + o);
     }
     catch (IOException)
     {
         throw new ArgumentException("Intermediate stream failed for Erlang object " + o);
     }
 }
Esempio n. 5
0
        // used by send and send_reg (message types with payload)
        protected void DoSend(OtpOutputStream header, OtpOutputStream payload)
        {
            lock (objWrite)
            {
                try
                {
                    if (TraceLevel >= TraceSend)
                    {
                        // Need to decode header and output buffer to show trace
                        // message!
                        // First make OtpInputStream, then decode.
                        try
                        {
                            IOtpErlangObject h = header.Slice(5).ReadAny();
                            Logger.Debug("-> " + HeaderType(h) + " " + h);

                            IOtpErlangObject o = payload.Slice(0).ReadAny();
                            Logger.Debug("   " + o);
                        }
                        catch (OtpDecodeException e)
                        {
                            Logger.Debug("   " + "can't decode output buffer:" + e);
                        }
                    }

                    header.WriteTo(socket.OutputStream);
                    payload.WriteTo(socket.OutputStream);
                }
                catch (IOException)
                {
                    Close();
                    throw;
                }
            }
        }
Esempio n. 6
0
        // used by the other message types
        protected void DoSend(OtpOutputStream header)
        {
            lock (objWrite)
            {
                try
                {
                    if (TraceLevel >= TraceCTRL)
                    {
                        try
                        {
                            IOtpErlangObject h = header.Slice(5).ReadAny();
                            Logger.Debug("-> " + HeaderType(h) + " " + h);
                        }
                        catch (OtpDecodeException e)
                        {
                            Logger.Debug("   " + "can't decode output buffer: " + e);
                        }
                    }

                    header.WriteTo(socket.OutputStream);
                }
                catch (IOException)
                {
                    Close();
                    throw;
                }
            }
        }
Esempio n. 7
0
 // special case when reason is an atom (i.e. most of the time)
 internal OtpMsg(int tag, OtpErlangPid from, OtpErlangPid to, string reason)
 {
     Type    = tag;
     FromPid = from;
     ToPid   = to;
     payload = new OtpErlangAtom(reason);
 }
Esempio n. 8
0
        // this function used internally when "process" dies
        // since Erlang discerns between exit and exit/2.
        private void Exit(int arity, OtpErlangPid to, IOtpErlangObject reason)
        {
            try
            {
                string node = to.Node;
                if (node.Equals(home.Node))
                {
                    home.Deliver(new OtpMsg(OtpMsg.exitTag, Self, to, reason));
                    return;
                }

                OtpCookedConnection conn = home.GetConnection(node);
                if (conn == null)
                {
                    return;
                }

                switch (arity)
                {
                case 1:
                    conn.Exit(Self, to, reason);
                    break;

                case 2:
                    conn.Exit2(Self, to, reason);
                    break;
                }
            }
            catch (Exception) { }
        }
Esempio n. 9
0
 // send_reg has sender pid and receiver name
 internal OtpMsg(OtpErlangPid from, string toName, IOtpErlangObject payload)
 {
     Type         = regSendTag;
     FromPid      = from;
     ToName       = toName;
     this.payload = payload;
 }
Esempio n. 10
0
 public OtpErlangTuple CallTuple(IOtpErlangObject msg)
 {
     // { $gen_call, { self, ref }, <msg> }
     return(new OtpErlangTuple(
                new OtpErlangAtom("$gen_call"),
                new OtpErlangTuple(
                    Self,
                    home.CreateRef()),
                msg));
 }
Esempio n. 11
0
        public IOtpErlangObject Call(string node, string module, IOtpErlangObject msg, long timeout)
        {
            Send(node, module, CallTuple(msg));
            var reply = (OtpErlangTuple)Receive(timeout);

            if (reply != null && reply.Arity >= 2)
            {
                return(reply.ElementAt(1));
            }
            return(null);
        }
Esempio n. 12
0
        /**
         * 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
         */
        protected 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.WriteTupleHead(4);
                header.WriteLong(regSendTag);
                header.WriteAny(local.CreatePid()); // disposable pid
                header.WriteAtom(cookie.Value);     // important: his cookie,
                // not mine...
                header.WriteAtom("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]}}
                IOtpErlangObject[] msg     = new IOtpErlangObject[2];
                IOtpErlangObject[] msgbody = new IOtpErlangObject[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.Length + payload.Length - 4);

                try { DoSend(header, payload); }
                catch (IOException) { } // ignore
            }
            finally
            {
                Close();
            }

            throw new OtpAuthException("Remote cookie not authorized: " + cookie.Value);
        }
Esempio n. 13
0
        /**
         * Send a message to a remote {@link OtpErlangPid pid}, representing either
         * another {@link OtpMbox mailbox} or an Erlang process.
         */
        public void Send(OtpErlangPid to, IOtpErlangObject msg)
        {
            string node = to.Node;

            if (node.Equals(home.Node))
            {
                home.Deliver(new OtpMsg(to, (IOtpErlangObject)msg.Clone()));
                return;
            }

            OtpCookedConnection conn = home.GetConnection(node);

            if (conn == null)
            {
                return;
            }

            conn.Send(Self, to, msg);
        }
Esempio n. 14
0
        public OtpErlangFun ReadFun()
        {
            int tag = Read1SkipVersion();

            if (tag == OtpExternal.funTag)
            {
                int                nFreeVars = Read4BE();
                OtpErlangPid       pid       = ReadPid();
                string             module    = ReadAtom();
                long               index     = ReadLong();
                long               uniq      = ReadLong();
                IOtpErlangObject[] freeVars  = new IOtpErlangObject[nFreeVars];
                for (int i = 0; i < nFreeVars; ++i)
                {
                    freeVars[i] = ReadAny();
                }

                return(new OtpErlangFun(pid, module, index, uniq, freeVars));
            }
            else if (tag == OtpExternal.newFunTag)
            {
                Read4BE();
                int                arity     = Read1();
                byte[]             md5       = ReadN(16);
                int                index     = Read4BE();
                int                nFreeVars = Read4BE();
                string             module    = ReadAtom();
                long               oldIndex  = ReadLong();
                long               uniq      = ReadLong();
                OtpErlangPid       pid       = ReadPid();
                IOtpErlangObject[] freeVars  = new IOtpErlangObject[nFreeVars];
                for (int i = 0; i < nFreeVars; ++i)
                {
                    freeVars[i] = ReadAny();
                }

                return(new OtpErlangFun(pid, module, arity, md5, index, oldIndex, uniq, freeVars));
            }
            else
            {
                throw new OtpDecodeException("Wrong tag encountered, expected fun, got " + tag);
            }
        }
Esempio n. 15
0
        /**
         * Send a message to a named mailbox created from another node.
         */
        public void Send(string node, string name, IOtpErlangObject msg)
        {
            // this node?
            if (node.Equals(home.Node) || node.Equals(home.Alive))
            {
                Send(name, msg);
                return;
            }

            // other node
            OtpCookedConnection conn = home.GetConnection(node);

            if (conn == null)
            {
                return;
            }

            conn.Send(Self, name, msg);
        }
Esempio n. 16
0
        protected string HeaderType(IOtpErlangObject h)
        {
            int tag = -1;

            if (h is OtpErlangTuple tuple)
            {
                tag = (int)((OtpErlangLong)tuple.ElementAt(0)).LongValue();
            }

            switch (tag)
            {
            case linkTag: return("LINK");

            case sendTag: return("SEND");

            case exitTag: return("EXIT");

            case unlinkTag: return("UNLINK");

            case regSendTag: return("REG_SEND");

            case groupLeaderTag: return("GROUP_LEADER");

            case exit2Tag: return("EXIT2");

            case sendTTTag: return("SEND_TT");

            case exitTTTag: return("EXIT_TT");

            case regSendTTTag: return("REG_SEND_TT");

            case exit2TTTag: return("EXIT2_TT");
            }

            return("(unknown type)");
        }
Esempio n. 17
0
 /*
  * this one called explicitely by user code => use exit2
  */
 public void Exit2(OtpErlangPid from, OtpErlangPid to, IOtpErlangObject reason)
 {
     try { SendExit2(from, to, reason); }
     catch (Exception) { }
 }
Esempio n. 18
0
 /**
  * Create a stream containing the encoded version of the given Erlang term.
  */
 public OtpOutputStream(IOtpErlangObject o) : base() => WriteAny(o);
Esempio n. 19
0
 /**
  * Send an exit2 signal to a remote {@link OtpErlangPid pid}. This method
  * does not cause any links to be broken, except indirectly if the remote
  * {@link OtpErlangPid pid} exits as a result of this exit signal.
  */
 public void Exit(OtpErlangPid to, IOtpErlangObject reason) => Exit(2, to, reason);
Esempio n. 20
0
 /**
  * Write an arbitrary Erlang term to the stream in compressed format.
  */
 public void WriteCompressed(IOtpErlangObject o) => WriteCompressed(o, CompressionLevel.Optimal);
Esempio n. 21
0
        public override void Run()
        {
            if (!Connected)
            {
                Deliver(new IOException("Not connected"));
                return;
            }

            byte[] lbuf = new byte[4];
            int    len;

            try
            {
                while (!Stopping)
                {
                    // don't return until we get a real message
                    // or a failure of some kind (e.g. EXIT)
                    // read length and read buffer must be atomic!

                    // read 4 bytes - get length of incoming packet
                    ReadSock(lbuf);
                    OtpInputStream ibuf = new OtpInputStream(lbuf)
                    {
                        Flags = Local.Flags
                    };
                    len = ibuf.Read4BE();

                    // received tick? send tock!
                    if (len == 0)
                    {
                        lock (objWrite)
                        {
                            socket.OutputStream.Write(TOCK, 0, TOCK.Length);
                            socket.OutputStream.Flush();
                        }

                        continue;
                    }

                    // got a real message (maybe) - read len bytes
                    byte[] tmpbuf = new byte[len];
                    ReadSock(tmpbuf);
                    ibuf = new OtpInputStream(tmpbuf)
                    {
                        Flags = Local.Flags
                    };

                    if (ibuf.Read1() != passThrough)
                    {
                        continue;
                    }

                    // got a real message (really)
                    IOtpErlangObject reason = null;
                    OtpErlangAtom    cookie = null;
                    IOtpErlangObject tmp    = null;
                    OtpErlangTuple   head   = null;
                    OtpErlangAtom    toName;
                    OtpErlangPid     to;
                    OtpErlangPid     from;
                    int tag;

                    // decode the header
                    tmp = ibuf.ReadAny();
                    if (!(tmp is OtpErlangTuple))
                    {
                        continue;
                    }

                    head = (OtpErlangTuple)tmp;
                    if (!(head.ElementAt(0) is OtpErlangLong))
                    {
                        continue;
                    }

                    // lets see what kind of message this is
                    tag = (int)((OtpErlangLong)head.ElementAt(0)).LongValue();

                    switch (tag)
                    {
                    case sendTag:       // { SEND, Cookie, ToPid }
                    case sendTTTag:     // { SEND, Cookie, ToPid, TraceToken }
                        if (!cookieOk)
                        {
                            // we only check this once, he can send us bad cookies later if he likes
                            if (!(head.ElementAt(1) is OtpErlangAtom))
                            {
                                continue;
                            }

                            cookie = (OtpErlangAtom)head.ElementAt(1);
                            if (sendCookie)
                            {
                                if (cookie.Value != Local.Cookie)
                                {
                                    CookieError(Local, cookie);
                                }
                            }
                            else
                            {
                                if (cookie.Value != "")
                                {
                                    CookieError(Local, cookie);
                                }
                            }
                            cookieOk = true;
                        }

                        if (TraceLevel >= TraceSend)
                        {
                            Logger.Debug($"<- {HeaderType(head)} {head}");

                            /* show received payload too */
                            ibuf.Mark();
                            Logger.Debug($"   {ibuf.ReadAny()}");
                            ibuf.Reset();
                        }

                        to = (OtpErlangPid)head.ElementAt(2);

                        Deliver(new OtpMsg(to, ibuf));
                        break;

                    case regSendTag:       // { REG_SEND, FromPid, Cookie, ToName }
                    case regSendTTTag:     // { REG_SEND, FromPid, Cookie, ToName, TraceToken }
                        if (!cookieOk)
                        {
                            // we only check this once, he can send us bad cookies later if he likes
                            if (!(head.ElementAt(2) is OtpErlangAtom))
                            {
                                continue;
                            }

                            cookie = (OtpErlangAtom)head.ElementAt(2);
                            if (sendCookie)
                            {
                                if (cookie.Value != Local.Cookie)
                                {
                                    CookieError(Local, cookie);
                                }
                            }
                            else
                            {
                                if (cookie.Value != "")
                                {
                                    CookieError(Local, cookie);
                                }
                            }

                            cookieOk = true;
                        }

                        if (TraceLevel >= TraceSend)
                        {
                            Logger.Debug($"<- {HeaderType(head)} {head}");

                            /* show received payload too */
                            ibuf.Mark();
                            Logger.Debug($"   {ibuf.ReadAny()}");
                            ibuf.Reset();
                        }

                        from   = (OtpErlangPid)head.ElementAt(1);
                        toName = (OtpErlangAtom)head.ElementAt(3);

                        Deliver(new OtpMsg(from, toName.Value, ibuf));
                        break;

                    case exitTag:      // { EXIT, FromPid, ToPid, Reason }
                    case exit2Tag:     // { EXIT2, FromPid, ToPid, Reason }
                        if (head.ElementAt(3) == null)
                        {
                            continue;
                        }

                        if (TraceLevel >= TraceCTRL)
                        {
                            Logger.Debug($"<- {HeaderType(head)} {head}");
                        }

                        from   = (OtpErlangPid)head.ElementAt(1);
                        to     = (OtpErlangPid)head.ElementAt(2);
                        reason = head.ElementAt(3);

                        Deliver(new OtpMsg(tag, from, to, reason));
                        break;

                    case exitTTTag:      // { EXIT, FromPid, ToPid, TraceToken, Reason }
                    case exit2TTTag:     // { EXIT2, FromPid, ToPid, TraceToken, Reason }
                        // as above, but bifferent element number
                        if (head.ElementAt(4) == null)
                        {
                            continue;
                        }

                        if (TraceLevel >= TraceCTRL)
                        {
                            Logger.Debug($"<- {HeaderType(head)} {head}");
                        }

                        from   = (OtpErlangPid)head.ElementAt(1);
                        to     = (OtpErlangPid)head.ElementAt(2);
                        reason = head.ElementAt(4);

                        Deliver(new OtpMsg(tag, from, to, reason));
                        break;

                    case linkTag:       // { LINK, FromPid, ToPid}
                    case unlinkTag:     // { UNLINK, FromPid, ToPid}
                        if (TraceLevel >= TraceCTRL)
                        {
                            Logger.Debug($"<- {HeaderType(head)} {head}");
                        }

                        from = (OtpErlangPid)head.ElementAt(1);
                        to   = (OtpErlangPid)head.ElementAt(2);

                        Deliver(new OtpMsg(tag, from, to));
                        break;

                    // absolutely no idea what to do with these, so we ignore them...
                    case groupLeaderTag:     // { GROUPLEADER, FromPid, ToPid}
                        // (just show trace)
                        if (TraceLevel >= TraceCTRL)
                        {
                            Logger.Debug("<- " + HeaderType(head) + " " + head);
                        }
                        break;

                    default:
                        // garbage?
                        break;
                    }
                }

                // this section reachable only with break
                // we have received garbage from peer
                Deliver(new OtpExit("Remote is sending garbage"));
            }
            catch (OtpAuthException e)
            {
                Deliver(e);
            }
            catch (OtpDecodeException)
            {
                Deliver(new OtpExit("Remote is sending garbage"));
            }
            catch (IOException)
            {
                Deliver(new OtpExit("Remote has closed connection"));
            }
            finally
            {
                Close();
            }
        }
Esempio n. 22
0
 /**
  * Send a message to a named mailbox created from the same node as this
  * mailbox.
  */
 public void Send(string name, IOtpErlangObject msg) => home.Deliver(new OtpMsg(Self, name, (IOtpErlangObject)msg.Clone()));
Esempio n. 23
0
 /**
  * Send an exit signal to a remote process.
  */
 protected void SendExit2(OtpErlangPid from, OtpErlangPid dest, IOtpErlangObject reason)
 {
     SendExit(exit2Tag, from, dest, reason);
 }
Esempio n. 24
0
 /**
  * Send a message to a named process on a remote node.
  */
 public void Send(string dest, IOtpErlangObject msg) => SendBuf(Self.Pid, dest, new OtpOutputStream(msg));
Esempio n. 25
0
 /**
  * Send an exit signal to a remote process.
  */
 public void Exit(OtpErlangPid dest, IOtpErlangObject reason) => SendExit2(Self.Pid, dest, reason);
Esempio n. 26
0
 /**
  * Close this mailbox with the given reason.
  *
  * After this operation, the mailbox will no longer be able to receive
  * messages. Any delivered but as yet unretrieved messages can still be
  * retrieved however.
  *
  * If there are links from this mailbox to other {@link OtpErlangPid pids},
  * they will be broken when this method is called and exit signals will be
  * sent.
  */
 public void Exit(IOtpErlangObject reason) => home.CloseMbox(this, reason);
Esempio n. 27
0
 /*
  * send to remote name dest is recipient's registered name, the nodename is
  * implied by the choice of connection.
  */
 public void Send(OtpErlangPid from, string dest, IOtpErlangObject msg) => SendBuf(from, dest, new OtpOutputStream(msg));
Esempio n. 28
0
 /**
  * Create an OtpErlangExit exception with the given reason.
  */
 public OtpExit(IOtpErlangObject reason) : base(reason.ToString()) => Reason = reason;
Esempio n. 29
0
 /* Perform a gen server info to a node and module */
 public void Info(string node, string module, IOtpErlangObject msg)
 {
     // { self, <msg> }
     Send(node, module, new OtpErlangTuple(Self, msg));
 }
Esempio n. 30
0
 /* Perform a gen_cast to a node and module */
 public void Cast(string node, string module, IOtpErlangObject msg)
 {
     // { $gen_cast, { self, <msg> } }
     Send(node, module, new OtpErlangTuple(new OtpErlangAtom("$gen_cast"), msg));
 }