Exemple #1
0
 /// <summary>
 /// Close this mailbox
 /// </summary>
 /// <remarks>
 /// 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 <see cref="ErlPid"/>
 /// pids they will be broken when this method is
 /// called and exit signals will be sent.
 /// </remarks>
 internal void Close()
 {
     // Notify all registered monitors that this pid is closing
     foreach (var monitor in m_Monitors)
     {
         var msg = ErlMsg.MonitorPexit(m_Self, monitor.Value, monitor.Key, ErlAtom.Normal);
         m_Node.Deliver(monitor.Value.Node, msg);
     }
     m_Node.CloseMbox(this);
     m_RegName = ErlAtom.Null;
 }
Exemple #2
0
        private void threadSpinCore()
        {
            if (!m_Connected)
            {
                Deliver(new ErlConnectionException(Name, StringConsts.ERL_CONN_NOT_CONNECTED_ERROR));
                return;
            }

            int len;

            byte[] header     = new byte[4];
            byte[] tock       = new byte[] { 0, 0, 0, 0 };
            byte[] payloadBuf = new byte[1024 * 1024];

            try
            {
                while (m_Home.Running && !this.DisposeStarted && !m_Done)
                {
                    // 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!
                    do
                    {
                        // read 4 bytes - get length of incoming packet
                        // socket.getInputStream().read(lbuf);
                        int n;
                        if ((n = ReadSock(header, header.Length, false)) < header.Length)
                        {
                            throw new ErlException(StringConsts.ERL_CONN_READ_TOO_SHORT_ERROR, n, header.Length);
                        }

                        len = header.ReadBEInt32();

                        //  received tick? send tock!
                        if (len == 0)
                        {
                            lock (this)
                            {
                                if (m_Transport != null)
                                {
                                    (m_Transport.GetStream()).Write(tock, 0, tock.Length);
                                }
                            }
                        }
                    }while (len == 0); // tick_loop

                    if (len > DEFAULT_MAX_PAYLOAD_LENGTH)
                    {
                        throw new ErlException(
                                  StringConsts.ERL_CONN_MSG_SIZE_TOO_LONG_ERROR, DEFAULT_MAX_PAYLOAD_LENGTH, len);
                    }

                    // got a real message (maybe) - read len bytes
                    byte[] tmpbuf = new byte[len]; // len > payloadBuf.Length ? new byte[len] : payloadBuf;
                                                   // i = socket.getInputStream().read(tmpbuf);
                    int m = ReadSock(tmpbuf, len, true);
                    if (m != len)
                    {
                        throw new ErlException(StringConsts.ERL_CONN_READ_TOO_SHORT_ERROR, m, len);
                    }

                    var ibuf = new ErlInputStream(tmpbuf, 0, len, checkVersion: false);

                    if (ibuf.Read1() != PASS_THROUGH)
                    {
                        goto receive_loop_brk;
                    }

                    try
                    {
                        // decode the header
                        var tmp = ibuf.Read(true);
                        if (!(tmp is ErlTuple))
                        {
                            goto receive_loop_brk;
                        }

                        var head = (ErlTuple)tmp;
                        if (!(head[0] is ErlByte))
                        {
                            goto receive_loop_brk;
                        }

                        // lets see what kind of message this is
                        ErlMsg.Tag tag = (ErlMsg.Tag)head[0].ValueAsInt;

                        switch (tag)
                        {
                        case ErlMsg.Tag.Send:
                        case ErlMsg.Tag.SendTT:
                        {
                            // { SEND, Cookie, ToPid, TraceToken }
                            if (!m_CookieOk)
                            {
                                // we only check this once, he can send us bad cookies later if he likes
                                if (!(head[1] is ErlAtom))
                                {
                                    goto receive_loop_brk;
                                }
                                var cookie = (ErlAtom)head[1];
                                if (m_ShouldSendCookie)
                                {
                                    if (!cookie.Equals(m_Cookie))
                                    {
                                        cookieError(m_Home, cookie);
                                    }
                                }
                                else if (!cookie.Empty)
                                {
                                    cookieError(m_Home, cookie);
                                }
                                m_CookieOk = true;
                            }

                            m_Home.OnTrace(ErlTraceLevel.Ctrl, Direction.Inbound, () =>
                                {
                                    long mark     = ibuf.Position;
                                    var traceobj  = ibuf.Read(true);
                                    ibuf.Position = mark;
                                    return("{0} {1} trace: {2}".Args(
                                               HeaderType(head), head.ToString(),
                                               traceobj == null ? "(null)" : traceobj.ToString()));
                                });

                            var to = (ErlPid)head[2];

                            Deliver(new ErlMsg(tag, ErlPid.Null, to, paybuf: ibuf));
                            break;
                        }

                        case ErlMsg.Tag.RegSend:
                        case ErlMsg.Tag.RegSendTT:
                        {
                            // { REG_SEND, FromPid, Cookie, ToName, TraceToken }
                            if (!m_CookieOk)
                            {
                                // we only check this once, he can send us bad cookies later if he likes
                                if (!(head[2] is ErlAtom))
                                {
                                    goto receive_loop_brk;
                                }
                                var cookie = (ErlAtom)head[2];
                                if (m_ShouldSendCookie)
                                {
                                    if (!cookie.Equals(m_Cookie))
                                    {
                                        cookieError(m_Home, cookie);
                                    }
                                }
                                else if (!cookie.Empty)
                                {
                                    cookieError(m_Home, cookie);
                                }
                                m_CookieOk = true;
                            }

                            m_Home.OnTrace(ErlTraceLevel.Ctrl, Direction.Inbound, () =>
                                {
                                    long mark     = ibuf.Position;
                                    var traceobj  = ibuf.Read(true);
                                    ibuf.Position = mark;
                                    return("{0} {1} trace: {2}".Args(
                                               HeaderType(head), head.ToString(),
                                               traceobj == null ? "(null)" : traceobj.ToString()));
                                });

                            var from   = (ErlPid)head[1];
                            var toName = (ErlAtom)head[3];

                            Deliver(new ErlMsg(tag, from, toName, paybuf: ibuf));
                            break;
                        }

                        case ErlMsg.Tag.Exit:
                        case ErlMsg.Tag.Exit2:
                        {
                            // { EXIT2, FromPid, ToPid, Reason }
                            if (!(head[3] is ErlAtom))
                            {
                                goto receive_loop_brk;
                            }

                            m_Home.OnTrace(ErlTraceLevel.Ctrl, Direction.Inbound, () =>
                                           "{0} {1}".Args(HeaderType(head), head.ToString()));

                            var from   = (ErlPid)head[1];
                            var to     = (ErlPid)head[2];
                            var reason = (ErlAtom)head[3];

                            Deliver(new ErlMsg(tag, from, to, reason: reason));
                            break;
                        }

                        case ErlMsg.Tag.ExitTT:
                        case ErlMsg.Tag.Exit2TT:
                        {
                            // { EXIT2, FromPid, ToPid, TraceToken, Reason }
                            // as above, but bifferent element number
                            if (!(head[4] is ErlAtom))
                            {
                                goto receive_loop_brk;
                            }

                            m_Home.OnTrace(ErlTraceLevel.Ctrl, Direction.Inbound, () =>
                                           "{0} {1}".Args(HeaderType(head), head.ToString()));
                            // TODO: print TraceToken

                            var from   = (ErlPid)head[1];
                            var to     = (ErlPid)head[2];
                            var trace  = (ErlTrace)head[3];
                            var reason = (ErlAtom)head[4];

                            Deliver(new ErlMsg(tag, from, to, reason: reason, trace: trace));
                            break;
                        }

                        case ErlMsg.Tag.Link:
                        case ErlMsg.Tag.Unlink:
                        {
                            // {UNLINK, FromPid, ToPid}
                            m_Home.OnTrace(ErlTraceLevel.Ctrl, Direction.Inbound, () =>
                                           "{0} {1}".Args(HeaderType(head), head.ToString()));

                            var from = (ErlPid)head[1];
                            var to   = (ErlPid)head[2];

                            Deliver(new ErlMsg(tag, from, to));
                            break;
                        }

                        case ErlMsg.Tag.GroupLeader:
                        case ErlMsg.Tag.NodeLink:
                        {
                            // No idea what to do with these, so we ignore them...
                            // {GROUP_LEADER, FromPid, ToPid},  { NODELINK }
                            // (just show trace)
                            m_Home.OnTrace(ErlTraceLevel.Ctrl, Direction.Inbound, () =>
                                           "{0} {1}".Args(HeaderType(head), head.ToString()));
                            break;
                        }

                        case ErlMsg.Tag.MonitorP:
                        case ErlMsg.Tag.DemonitorP:
                        {
                            // {MONITOR_P, FromPid, ToProc, Ref}
                            // {DEMONITOR_P, FromPid, ToProc, Ref}
                            m_Home.OnTrace(ErlTraceLevel.Ctrl, Direction.Inbound, () =>
                                           "{0} {1}".Args(HeaderType(head), head.ToString()));
                            var from = (ErlPid)head[1];
                            var to   = (ErlPid)head[2];
                            var eref = (ErlRef)head[3];

                            Deliver(new ErlMsg(tag, from, to, eref));
                            break;
                        }

                        case ErlMsg.Tag.MonitorPexit:
                        {
                            // {MONITOR_P_EXIT, FromPid, ToProc, Ref, Reason}
                            m_Home.OnTrace(ErlTraceLevel.Ctrl, Direction.Inbound, () =>
                                           "{0} {1}".Args(HeaderType(head), head.ToString()));
                            var from   = (ErlPid)head[1];
                            var to     = (ErlPid)head[2];
                            var eref   = (ErlRef)head[3];
                            var reason = head[4];

                            Deliver(ErlMsg.MonitorPexit(from, to, eref, reason));
                            break;
                        }

                        default:
                            // garbage?
                            m_Home.OnTrace(ErlTraceLevel.Ctrl, Direction.Inbound, () =>
                                           StringConsts.ERL_CONN_UNKNOWN_TAG_ERROR.Args(
                                               HeaderType(head), head.ToString()));
                            goto receive_loop_brk;
                        }
                    }
                    catch (Exception e)
                    {
                        // we have received garbage
                        m_Home.OnTrace(ErlTraceLevel.Ctrl, Direction.Inbound, e.ToString());
                        Deliver(new ErlBadDataException(
                                    Name, /* "Remote has closed connection or sending garbage: " + */
                                    e.Message));
                    }
                }

receive_loop_brk:
                // end receive_loop

                // this section reachable only with break
                // connection went down or we have received garbage from peer
                Deliver(new ErlConnectionException(Name, StringConsts.ERL_CONN_INVALID_DATA_FROM_PEER_ERROR));
            }
            catch (ErlAuthException e)
            {
                m_Home.OnTrace(ErlTraceLevel.Ctrl, Direction.Inbound, () => e.ToString());
                Deliver(e);
            }
            catch (Exception e)
            {
                m_Home.OnTrace(ErlTraceLevel.Ctrl, Direction.Inbound, () => e.ToString());
                Deliver(new ErlConnectionException(
                            Name, /* "Remote has closed connection or sending garbage: " + */
                            e.Message));
            }
            finally
            {
                m_Thread = null;
                Close();
                m_Home.OnTrace(ErlTraceLevel.Ctrl, Direction.Inbound, () =>
                               "Exiting connection (thread {0})".Args(Thread.CurrentThread.Name));
            }
        }