Ejemplo n.º 1
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));
      }
    }
Ejemplo n.º 2
0
        /// <summary>
        /// Determine what port a node listens for incoming connections on
        /// </summary>
        /// <param name="home">Local node</param>
        /// <param name="node">Remote lode for which to look up the port number from remote EPMD</param>
        /// <param name="closeSocket">If true, close the connection to remote EPMD at return</param>
        /// <returns>the listen port for the specified node, or 0 if the node
        /// was not registered with Epmd</returns>
        public static int LookupPort(ErlLocalNode home, ErlRemoteNode node,
            bool closeSocket = false)
        {
            IErlTransport s = null;

              try
              {
            var obuf = new ErlOutputStream(writeVersion: false, capacity: 4 + 3 + node.AliveName.Length + 1);
            s = node.Epmd;

            if (s == null)
            {
              //create transport
              s = ErlTransportFactory.Create(node.TransportClassName, node.NodeName.Value);

              s.Trace += (o, t, d, msg) => home.OnTrace(t, d, msg);

              //append SSH params to transport
              node.AppendSSHParamsToTransport(s);

              //connect (I am not sure)
              s.Connect(node.Host, EPMD_PORT, node.ConnectTimeout);
            }

            // build and send epmd request
            // length[2], tag[1], alivename[n] (length = n+1)
            obuf.Write2BE(node.AliveName.Length + 1);
            obuf.Write1((byte)Indicator.Port4req);
            //UPGRADE_NOTE: This code will be optimized in the future;
            byte[] buf = Encoding.ASCII.GetBytes(node.AliveName);
            obuf.Write(buf);

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

            home.OnTrace(ErlTraceLevel.Epmd, Direction.Outbound,
                StringConsts.ERL_EPMD_LOOKUP_R4.Args(node.NodeName.Value));

            // receive and decode reply
            // resptag[1], result[1], port[2], ntype[1], proto[1],
            // disthigh[2], distlow[2], nlen[2], alivename[n],
            // elen[2], edata[m]
            buf = new byte[100];

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

            if (n < 0)
              throw new ErlException(StringConsts.ERL_EPMD_NOT_RESPONDING.Args(node.Host, node.AliveName));

            var ibuf = new ErlInputStream(buf, 0, n, checkVersion: false);

            if (Indicator.Port4resp == (Indicator)ibuf.Read1())
            {
              if (0 == ibuf.Read1())
              {
            node.Port = ibuf.Read2BE();

            node.Ntype = (ErlAbstractNode.NodeType)ibuf.Read1();
            node.Proto = ibuf.Read1();
            node.DistHigh = ibuf.Read2BE();
            node.DistLow = ibuf.Read2BE();
            // ignore rest of fields
              }
            }

            if (!closeSocket)
            {
              node.Epmd = s;
              s = null;
            }
              }
              catch (Exception e)
              {
            home.OnTrace(ErlTraceLevel.Epmd, Direction.Inbound, StringConsts.ERL_EPMD_INVALID_RESPONSE_ERROR.Args(node.Host, node.AliveName, e.ToString()));
            throw new ErlException(StringConsts.ERL_EPMD_NOT_RESPONDING.Args(node.Host, node.AliveName, e.ToString()));
              }
              finally
              {
            if (s != null)
              try { s.Close(); } catch { }
            s = null;
              }

              home.OnTrace(ErlTraceLevel.Epmd, Direction.Inbound, () =>
              node.Port == 0 ? StringConsts.ERL_EPMD_NOT_FOUND : StringConsts.ERL_EPMD_PORT.Args(node.Port));

              return node.Port;
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Publish node's port at local EPMD, so that other nodes can connect to it.
        ///
        /// On failure to connect to EPMD the function may throw if the value of
        /// ErlApp.IgnoreLocalEpmdConnectErrors variable is true.
        ///
        /// On failed connection attempt the function calls
        /// node.OnEpmdFailedConnectAttempt delegate
        /// </summary>
        /// <remarks>
        /// 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
        /// </remarks>
        public static bool PublishPort(ErlLocalNode node)
        {
            Exception error = null;
              IErlTransport s = null;

              try
              {
            ErlOutputStream obuf = new ErlOutputStream(writeVersion: false, capacity: node.AliveName.Length + 20);
            s = node.Epmd ?? new ErlTcpTransport(ErlLocalNode.LocalHost, EPMD_PORT) { NodeName = node.NodeName.Value };

            obuf.Write2BE(node.AliveName.Length + 13);

            obuf.Write1((byte)Indicator.Publish4req);
            obuf.Write2BE(node.Port);

            obuf.Write1((byte)node.Ntype);

            obuf.Write1((byte)node.Proto);
            obuf.Write2BE(node.DistHigh);
            obuf.Write2BE(node.DistLow);

            obuf.Write2BE(node.AliveName.Length);
            var buf = Encoding.ASCII.GetBytes(node.AliveName);
            //UPGRADE_NOTE: This code will be optimized in the future;
            obuf.Write(buf);
            obuf.Write2BE(0); // No extra

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

            node.OnTrace(ErlTraceLevel.Epmd, Direction.Outbound, () =>
                StringConsts.ERL_EPMD_PUBLISH.Args(node.AliveName, node.Port, "r4"));

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

            if (n < 0)
              // this was an r3 node => not a failure (yet)
              throw new ErlException(StringConsts.ERL_EPMD_NOT_RESPONDING.Args(node.Host, node.AliveName));

            ErlInputStream ibuf = new ErlInputStream(buf, 0, n, checkVersion: false);

            if (Indicator.Publish4resp == (Indicator)ibuf.Read1())
            {
              int result = ibuf.Read1();
              if (result == 0)
              {
            node.Creation = (byte)ibuf.Read2BE();
            node.OnTrace(ErlTraceLevel.Epmd, Direction.Inbound, StringConsts.ERL_EPMD_OK);

            node.Epmd = s;
            return true; // success
              }
            }
            error = new ErlException("Cannot register node '{0}' (not unique?)".Args(node.AliveName));
              }
              catch (Exception e)
              {
            error = e;
              }

              // epmd closed the connection = fail
              if (s != null)
            try { s.Close(); } catch { }

              node.Epmd = null;

              node.OnTrace(ErlTraceLevel.Epmd, Direction.Inbound, StringConsts.ERL_EPMD_NO_RESPONSE);

              node.OnEpmdFailedConnectAttempt(node.NodeName, error.Message);

              node.OnTrace(ErlTraceLevel.Epmd, Direction.Inbound, StringConsts.ERL_EPMD_FAILED_TO_CONNECT_ERROR);

              if (!ErlApp.IgnoreLocalEpmdConnectErrors)
            throw new ErlException(StringConsts.ERL_EPMD_FAILED_TO_CONNECT_ERROR + ": " + error.Message);

              node.Creation = 0;
              return false;
        }
Ejemplo n.º 4
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));
            }
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Determine what port a node listens for incoming connections on
        /// </summary>
        /// <param name="home">Local node</param>
        /// <param name="node">Remote lode for which to look up the port number from remote EPMD</param>
        /// <param name="closeSocket">If true, close the connection to remote EPMD at return</param>
        /// <returns>the listen port for the specified node, or 0 if the node
        /// was not registered with Epmd</returns>
        public static int LookupPort(ErlLocalNode home, ErlRemoteNode node,
                                     bool closeSocket = false)
        {
            TcpClient s = null;

            try
            {
                var obuf = new ErlOutputStream(
                    writeVersion: false, capacity: 4 + 3 + node.AliveName.Length + 1);
                s = node.Epmd ?? new TcpClient(node.Host, EPMD_PORT);

                // build and send epmd request
                // length[2], tag[1], alivename[n] (length = n+1)
                obuf.Write2BE(node.AliveName.Length + 1);
                obuf.Write1((byte)Indicator.Port4req);
                //UPGRADE_NOTE: This code will be optimized in the future;
                byte[] buf = Encoding.ASCII.GetBytes(node.AliveName);
                obuf.Write(buf);

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

                home.Trace(ErlTraceLevel.Epmd, Direction.Outbound,
                           StringConsts.ERL_EPMD_LOOKUP_R4.Args(node.NodeName.Value));

                // receive and decode reply
                // resptag[1], result[1], port[2], ntype[1], proto[1],
                // disthigh[2], distlow[2], nlen[2], alivename[n],
                // elen[2], edata[m]
                buf = new byte[100];

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

                if (n < 0)
                {
                    throw new ErlException(StringConsts.ERL_EPMD_NOT_RESPONDING.Args(node.Host, node.AliveName));
                }

                var ibuf = new ErlInputStream(buf, 0, n, checkVersion: false);

                if (Indicator.Port4resp == (Indicator)ibuf.Read1())
                {
                    if (0 == ibuf.Read1())
                    {
                        node.Port = ibuf.Read2BE();

                        node.Ntype    = (ErlAbstractNode.NodeType)ibuf.Read1();
                        node.Proto    = ibuf.Read1();
                        node.DistHigh = ibuf.Read2BE();
                        node.DistLow  = ibuf.Read2BE();
                        // ignore rest of fields
                    }
                }

                if (!closeSocket)
                {
                    node.Epmd = s;
                    s         = null;
                }
            }
            catch (Exception)
            {
                home.Trace(ErlTraceLevel.Epmd, Direction.Inbound, StringConsts.ERL_EPMD_INVALID_RESPONSE_ERROR);
                throw new ErlException(StringConsts.ERL_EPMD_NOT_RESPONDING.Args(node.Host, node.AliveName));
            }
            finally
            {
                if (s != null)
                {
                    try { s.Close(); } catch {}
                }
                s = null;
            }

            home.Trace(ErlTraceLevel.Epmd, Direction.Inbound, () =>
                       node.Port == 0 ? StringConsts.ERL_EPMD_NOT_FOUND : StringConsts.ERL_EPMD_PORT.Args(node.Port));

            return(node.Port);
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Publish node's port at local EPMD, so that other nodes can connect to it.
        ///
        /// On failure to connect to EPMD the function may throw if the value of
        /// ErlApp.IgnoreLocalEpmdConnectErrors variable is true.
        ///
        /// On failed connection attempt the function calls
        /// node.OnEpmdFailedConnectAttempt delegate
        /// </summary>
        /// <remarks>
        /// 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
        /// </remarks>
        public static bool PublishPort(ErlLocalNode node)
        {
            Exception error = null;
            TcpClient s     = null;

            try
            {
                ErlOutputStream obuf = new ErlOutputStream(
                    writeVersion: false, capacity: node.AliveName.Length + 20);
                s = node.Epmd ?? new TcpClient(ErlLocalNode.LocalHost, EPMD_PORT);

                obuf.Write2BE(node.AliveName.Length + 13);

                obuf.Write1((byte)Indicator.Publish4req);
                obuf.Write2BE(node.Port);

                obuf.Write1((byte)node.Ntype);

                obuf.Write1((byte)node.Proto);
                obuf.Write2BE(node.DistHigh);
                obuf.Write2BE(node.DistLow);

                obuf.Write2BE(node.AliveName.Length);
                var buf = Encoding.ASCII.GetBytes(node.AliveName);
                //UPGRADE_NOTE: This code will be optimized in the future;
                obuf.Write(buf);
                obuf.Write2BE(0); // No extra

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

                node.Trace(ErlTraceLevel.Epmd, Direction.Outbound, () =>
                           StringConsts.ERL_EPMD_PUBLISH.Args(node.AliveName, node.Port, "r4"));

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

                if (n < 0)
                {
                    // this was an r3 node => not a failure (yet)
                    throw new ErlException(StringConsts.ERL_EPMD_NOT_RESPONDING.Args(node.Host, node.AliveName));
                }

                ErlInputStream ibuf = new ErlInputStream(buf, 0, n, checkVersion: false);

                if (Indicator.Publish4resp == (Indicator)ibuf.Read1())
                {
                    int result = ibuf.Read1();
                    if (result == 0)
                    {
                        node.Creation = (byte)ibuf.Read2BE();
                        node.Trace(ErlTraceLevel.Epmd, Direction.Inbound, StringConsts.ERL_EPMD_OK);

                        node.Epmd = s;
                        return(true); // success
                    }
                }
                error = new ErlException("Cannot register node '{0}' (not unique?)".Args(node.AliveName));
            }
            catch (Exception e)
            {
                error = e;
            }

            // epmd closed the connection = fail
            if (s != null)
            {
                try { s.Close(); } catch {}
            }

            node.Epmd = null;

            node.Trace(ErlTraceLevel.Epmd, Direction.Inbound, StringConsts.ERL_EPMD_NO_RESPONSE);

            node.OnEpmdFailedConnectAttempt(node.NodeName, error.Message);

            node.Trace(ErlTraceLevel.Epmd, Direction.Inbound, StringConsts.ERL_EPMD_FAILED_TO_CONNECT_ERROR);

            if (!ErlApp.IgnoreLocalEpmdConnectErrors)
            {
                throw new ErlException(error.Message);
            }

            node.Creation = 0;
            return(false);
        }