Example #1
0
File: ErlMsg.cs Project: mjaric/nfx
        /*
         * internal ErlMsg(Tag tag, ErlMsg msg)
         *  : this(tag, msg.Sender, msg.Recipient, msg.Ref, msg.Reason, msg.Payload,
         *         msg.m_Paybuf, msg.TraceToken)
         * {}
         */

        internal ErlMsg(Tag tag, IErlObject /* Pid or Atom */ from,
                        IErlObject /* Pid or Atom */ to, ErlRef?eref = null, IErlObject reason = null,
                        IErlObject payload = null, ErlInputStream paybuf = null,
                        ErlAtom?cookie     = null, ErlTrace trace        = null)
        {
            if (!(from is ErlPid || from is ErlAtom))
            {
                throw new ErlException(StringConsts.ERL_INVALID_VALUE_TYPE_ERROR.Args("sender", from.GetType().Name));
            }
            if (!(to is ErlPid || to is ErlAtom))
            {
                throw new ErlException(StringConsts.ERL_INVALID_VALUE_TYPE_ERROR.Args("recipient", from.GetType().Name));
            }

            m_From     = from;
            m_To       = to;
            Type       = tag;
            Paybuf     = paybuf;
            m_Payload  = payload;
            Reason     = reason;
            Ref        = eref.HasValue ? eref.Value : ErlRef.Null;
            Cookie     = cookie.HasValue ? cookie.Value : ErlAtom.Null;
            TraceToken = trace;
        }
Example #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));
      }
    }
Example #3
0
        public void ErlTermSerializeTest()
        {
            {
            var b = new byte[] { 131, 100, 0, 3, 97, 98, 99 };
            var t = new ErlAtom("abc");
            var os = new ErlOutputStream(t);
            Assert.AreEqual(b, os.GetBuffer().TakeWhile((_, i) => i < b.Length).ToArray());
            var es = new ErlInputStream(b);
            Assert.AreEqual(t, es.Read());
              }
              {
            var b = new byte[] { 131, 109, 0, 0, 0, 3, 1, 2, 3 };
            var t = new ErlBinary(new byte[] { 1, 2, 3 });
            var os = new ErlOutputStream(t);
            Assert.AreEqual(b, os.GetBuffer().TakeWhile((_, i) => i < b.Length).ToArray());
            var es = new ErlInputStream(b);
            Assert.AreEqual(t, es.Read());
              }
              {
            var b1 = new byte[] { 131, 100, 0, 4, 116, 114, 117, 101 };
            var t1 = new ErlBoolean(true);
            var os1 = new ErlOutputStream(t1);
            Assert.AreEqual(b1, os1.GetBuffer().TakeWhile((_, i) => i < b1.Length).ToArray());
            var es1 = new ErlInputStream(b1);
            Assert.AreEqual(t1, es1.Read());

            var b2 = new byte[] { 131, 100, 0, 5, 102, 97, 108, 115, 101 };
            var t2 = new ErlBoolean(false);
            var os2 = new ErlOutputStream(t2);
            Assert.AreEqual(b2, os2.GetBuffer().TakeWhile((_, i) => i < b2.Length).ToArray());
            var es2 = new ErlInputStream(b2);
            Assert.AreEqual(t2, es2.Read());
              }
              {
            var b = new byte[] { 131, 97, 127 };
            var t = new ErlByte(127);
            var os = new ErlOutputStream(t);
            Assert.AreEqual(b, os.GetBuffer().TakeWhile((_, i) => i < b.Length).ToArray());
            var es = new ErlInputStream(b);
            Assert.AreEqual(t, es.Read());
              }
              {
            var b = new byte[] { 131, 70, 64, 36, 62, 249, 219, 34, 208, 229 };
            var t = new ErlDouble(10.123);
            var os = new ErlOutputStream(t);
            Assert.AreEqual(b, os.GetBuffer().TakeWhile((_, i) => i < b.Length).ToArray());
            var es = new ErlInputStream(b);
            Assert.AreEqual(t, es.Read());
              }
              {
            var b = new byte[] { 131, 108, 0, 0, 0, 2, 107, 0, 1, 1, 107, 0, 1, 2, 106 };
            var t = new ErlList(new ErlList(1), new ErlList(2));
            var os = new ErlOutputStream(t);
            Assert.AreEqual(b, os.GetBuffer().TakeWhile((_, i) => i < b.Length).ToArray());
            var es = new ErlInputStream(b);
            Assert.AreEqual(t, es.Read());
              }
              {
            var b = new byte[] { 131,108,0,0,0,2,108,0,0,0,2,97,1,107,0,1,2,106,107,0,1,3,106 };
            var t = new ErlList(new ErlList(1, new ErlList(2)), new ErlList(3));
            var os = new ErlOutputStream(t);
            Assert.AreEqual(b, os.GetBuffer().TakeWhile((_, i) => i < b.Length).ToArray());
            var es = new ErlInputStream(b);
            Assert.AreEqual(t, es.Read());
              }
              {
            var b = new byte[] { 131,108,0,0,0,3,97,1,70,64,36,61,112,163,215,10,61,108,0,0,0,2,
                             100,0,4,116,114,117,101,107,0,1,97,106,106 };
            var t = new ErlList(1, 10.12, new ErlList(true, "a"));
            var os = new ErlOutputStream(t);
            Assert.AreEqual(b, os.GetBuffer().TakeWhile((_, i) => i < b.Length).ToArray());
            var es = new ErlInputStream(b);
            Assert.AreEqual(t, es.Read());
              }
              {
            var b = new byte[] {
              131,108,0,0,0,3,97,23,97,4,104,1,108,0,0,0,1,104,2,109,0,0,0,5,101,118,101,
              110,116,104,1,108,0,0,0,2,104,2,109,0,0,0,10,102,108,101,101,116,95,104,97,
              115,104,109,0,0,0,36,97,54,97,50,50,100,49,52,45,56,52,56,51,45,52,49,102,99,
              45,97,52,54,98,45,50,56,51,98,57,55,55,55,99,50,97,50,104,2,109,0,0,0,4,116,
              121,112,101,109,0,0,0,13,102,108,101,101,116,95,99,104,97,110,103,101,100,
              106,106,106 };
            var t = ErlObject.Parse("[23,4,{[{<<\"event\">>,"+
                                "{[{<<\"fleet_hash\">>,<<\"a6a22d14-8483-41fc-a46b-283b9777c2a2\">>},"+
                                "{<<\"type\">>,<<\"fleet_changed\">>}]}}]}]");
            var os = new ErlOutputStream(t);
            Assert.AreEqual(b, os.GetBuffer().TakeWhile((_, i) => i < b.Length).ToArray());
            var es = new ErlInputStream(b);
            Assert.AreEqual(t, es.Read());
              }
              {
            var b1 = new byte[] { 131, 98, 255, 255, 255, 251 };
            var t1 = new ErlLong(-5);
            var os1 = new ErlOutputStream(t1);
            Assert.AreEqual(b1, os1.GetBuffer().TakeWhile((_, i) => i < b1.Length).ToArray());
            var es1 = new ErlInputStream(b1);
            Assert.AreEqual(t1, es1.Read());

            var b2 = new byte[] { 131, 97, 5 };
            var t2 = new ErlLong(5);
            var os2 = new ErlOutputStream(t2);
            Assert.AreEqual(b2, os2.GetBuffer().TakeWhile((_, i) => i < b2.Length).ToArray());
            var es2 = new ErlInputStream(b2);
            Assert.AreEqual(t2, es2.Read());

            var b3 = new byte[] { 131, 98, 0, 16, 0, 0 };
            var t3 = new ErlLong(1024 * 1024);
            var os3 = new ErlOutputStream(t3);
            Assert.AreEqual(b3, os3.GetBuffer().TakeWhile((_, i) => i < b3.Length).ToArray());
            var es3 = new ErlInputStream(b3);
            Assert.AreEqual(t3, es3.Read());

            var b4 = new byte[] { 131, 110, 6, 0, 0, 0, 0, 0, 0, 4 };
            var t4 = new ErlLong(1024L * 1024 * 1024 * 1024 * 4);
            var os4 = new ErlOutputStream(t4);
            Assert.AreEqual(b4, os4.GetBuffer().TakeWhile((_, i) => i < b4.Length).ToArray());
            var es4 = new ErlInputStream(b4);
            Assert.AreEqual(t4, es4.Read());

            var b5 = new byte[] { 131, 110, 8, 1, 0, 0, 0, 0, 0, 0, 0, 128 };
            var t5 = new ErlLong(1L << 63);
            var os5 = new ErlOutputStream(t5);
            Assert.AreEqual(b5, os5.GetBuffer().TakeWhile((_, i) => i < b5.Length).ToArray());
            var es5 = new ErlInputStream(b5);
            Assert.AreEqual(t5, es5.Read());

            var b6 = new byte[] { 131, 110, 8, 1, 0, 0, 0, 0, 0, 0, 0, 128 };
            var t6 = new ErlLong(-1L << 63);
            var os6 = new ErlOutputStream(t6);
            Assert.AreEqual(b6, os6.GetBuffer().TakeWhile((_, i) => i < b6.Length).ToArray());
            var es6 = new ErlInputStream(b6);
            Assert.AreEqual(t6, es6.Read());

            var b7 = new byte[] { 131, 110, 8, 0, 255, 255, 255, 255, 255, 255, 255, 255 };
            var es7 = new ErlInputStream(b7);
            var t7 = new ErlLong(-1);
            Assert.AreEqual(t7, es7.Read());
            var bi7 = new byte[] {131, 98, 255, 255, 255, 255};
            var os7 = new ErlOutputStream(t7);
            Assert.AreEqual(bi7, os7.GetBuffer().TakeWhile((_, i) => i < bi7.Length).ToArray());
              }
              {
            var b = new byte[] { 131, 103, 100, 0, 7, 98, 64, 112, 105, 112, 105, 116, 0, 0, 0, 38, 0, 0, 0, 0, 1 };
            var t = new ErlPid("b@pipit", 38, 0, 1);
            var os = new ErlOutputStream(t);
            Assert.AreEqual(b, os.GetBuffer().TakeWhile((_, i) => i < b.Length).ToArray());
            var es = new ErlInputStream(b);
            Assert.AreEqual(t, es.Read());
              }
              {
            var b = new byte[] { 131, 102, 100, 0, 7, 98, 64, 112, 105, 112, 105, 116, 0, 0, 0, 38, 1 };
            var t = new ErlPort("b@pipit", 38, 1);
            var os = new ErlOutputStream(t);
            Assert.AreEqual(b, os.GetBuffer().TakeWhile((_, i) => i < b.Length).ToArray());
            var es = new ErlInputStream(b);
            Assert.AreEqual(t, es.Read());
              }
              {
            var b = new byte[] { 131, 114, 0, 3, 100, 0, 7, 98, 64, 112, 105, 112, 105, 116, 1, 0, 0, 0, 181, 0, 0, 0, 0, 0, 0, 0, 0 };
            var t = new ErlRef("b@pipit", 181, 0, 0, 1);
            var os = new ErlOutputStream(t);
            Assert.AreEqual(b, os.GetBuffer().TakeWhile((_, i) => i < b.Length).ToArray());
            var es = new ErlInputStream(b);
            Assert.AreEqual(t, es.Read());
              }
              {
            var b = new byte[] { 131, 107, 0, 3, 115, 116, 114 };
            var t = new ErlString("str");
            var os = new ErlOutputStream(t);
            Assert.AreEqual(b, os.GetBuffer().TakeWhile((_, i) => i < b.Length).ToArray());
            var es = new ErlInputStream(b);
            Assert.AreEqual(t, es.Read());
              }
              {
            var b = new byte[] { 131, 104, 3, 97, 1, 100, 0, 1, 97, 104, 2, 97, 10, 70, 63, 241, 247, 206, 217, 22, 135, 43 };
            var t = new ErlTuple(1, new ErlAtom("a"), new ErlTuple(10, 1.123));
            var os = new ErlOutputStream(t);
            Assert.AreEqual(b, os.GetBuffer().TakeWhile((_, i) => i < b.Length).ToArray());
            var es = new ErlInputStream(b);
            Assert.AreEqual(t, es.Read());
              }
        }
Example #4
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;
        }
Example #5
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;
        }
Example #6
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));
            }
        }
Example #7
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);
        }
Example #8
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);
        }
Example #9
0
    public void ErlTermSerializeTest()
    {
      {
        var b = new byte[] { 131, 100, 0, 3, 97, 98, 99 };
        var t = new ErlAtom("abc");
        var os = new ErlOutputStream(t);
        Assert.AreEqual(b, os.GetBuffer().TakeWhile((_, i) => i < b.Length).ToArray());
        var es = new ErlInputStream(b);
        Assert.AreEqual(t, es.Read());
      }
      {
        var b = new byte[] { 131, 109, 0, 0, 0, 3, 1, 2, 3 };
        var t = new ErlBinary(new byte[] { 1, 2, 3 });
        var os = new ErlOutputStream(t);
        Assert.AreEqual(b, os.GetBuffer().TakeWhile((_, i) => i < b.Length).ToArray());
        var es = new ErlInputStream(b);
        Assert.AreEqual(t, es.Read());
      }
      {
        var b1 = new byte[] { 131, 100, 0, 4, 116, 114, 117, 101 };
        var t1 = new ErlBoolean(true);
        var os1 = new ErlOutputStream(t1);
        Assert.AreEqual(b1, os1.GetBuffer().TakeWhile((_, i) => i < b1.Length).ToArray());
        var es1 = new ErlInputStream(b1);
        Assert.AreEqual(t1, es1.Read());

        var b2 = new byte[] { 131, 100, 0, 5, 102, 97, 108, 115, 101 };
        var t2 = new ErlBoolean(false);
        var os2 = new ErlOutputStream(t2);
        Assert.AreEqual(b2, os2.GetBuffer().TakeWhile((_, i) => i < b2.Length).ToArray());
        var es2 = new ErlInputStream(b2);
        Assert.AreEqual(t2, es2.Read());
      }
      {
        var b = new byte[] { 131, 97, 127 };
        var t = new ErlByte(127);
        var os = new ErlOutputStream(t);
        Assert.AreEqual(b, os.GetBuffer().TakeWhile((_, i) => i < b.Length).ToArray());
        var es = new ErlInputStream(b);
        Assert.AreEqual(t, es.Read());
      }
      {
        var b = new byte[] { 131, 70, 64, 36, 62, 249, 219, 34, 208, 229 };
        var t = new ErlDouble(10.123);
        var os = new ErlOutputStream(t);
        Assert.AreEqual(b, os.GetBuffer().TakeWhile((_, i) => i < b.Length).ToArray());
        var es = new ErlInputStream(b);
        Assert.AreEqual(t, es.Read());
      }
      {
        var b = new byte[] { 131,108,0,0,0,3,97,1,70,64,36,61,112,163,215,10,61,108,0,0,0,2,
                             100,0,4,116,114,117,101,107,0,1,97,106,106 };
        var t = new ErlList(1, 10.12, new ErlList(true, "a"));
        var os = new ErlOutputStream(t);
        Assert.AreEqual(b, os.GetBuffer().TakeWhile((_, i) => i < b.Length).ToArray());
        var es = new ErlInputStream(b);
        Assert.AreEqual(t, es.Read());
      }
      {
        var b1 = new byte[] { 131, 98, 255, 255, 255, 251 };
        var t1 = new ErlLong(-5);
        var os1 = new ErlOutputStream(t1);
        Assert.AreEqual(b1, os1.GetBuffer().TakeWhile((_, i) => i < b1.Length).ToArray());
        var es1 = new ErlInputStream(b1);
        Assert.AreEqual(t1, es1.Read());

        var b2 = new byte[] { 131, 97, 5 };
        var t2 = new ErlLong(5);
        var os2 = new ErlOutputStream(t2);
        Assert.AreEqual(b2, os2.GetBuffer().TakeWhile((_, i) => i < b2.Length).ToArray());
        var es2 = new ErlInputStream(b2);
        Assert.AreEqual(t2, es2.Read());

        var b3 = new byte[] { 131, 98, 0, 16, 0, 0 };
        var t3 = new ErlLong(1024 * 1024);
        var os3 = new ErlOutputStream(t3);
        Assert.AreEqual(b3, os3.GetBuffer().TakeWhile((_, i) => i < b3.Length).ToArray());
        var es3 = new ErlInputStream(b3);
        Assert.AreEqual(t3, es3.Read());

        var b4 = new byte[] { 131, 110, 6, 0, 0, 0, 0, 0, 0, 4 };
        var t4 = new ErlLong(1024L * 1024 * 1024 * 1024 * 4);
        var os4 = new ErlOutputStream(t4);
        Assert.AreEqual(b4, os4.GetBuffer().TakeWhile((_, i) => i < b4.Length).ToArray());
        var es4 = new ErlInputStream(b4);
        Assert.AreEqual(t4, es4.Read());

        var b5 = new byte[] { 131, 110, 8, 0, 0, 0, 0, 0, 0, 0, 0, 128 };
        var t5 = new ErlLong(1L << 63);
        var os5 = new ErlOutputStream(t5);
        Assert.AreEqual(b5, os5.GetBuffer().TakeWhile((_, i) => i < b5.Length).ToArray());
        var es5 = new ErlInputStream(b5);
        Assert.AreEqual(t5, es5.Read());

        var b6 = new byte[] { 131, 110, 8, 0, 0, 0, 0, 0, 0, 0, 0, 128 };
        var t6 = new ErlLong(-1L << 63);
        var os6 = new ErlOutputStream(t6);
        Assert.AreEqual(b6, os6.GetBuffer().TakeWhile((_, i) => i < b6.Length).ToArray());
        var es6 = new ErlInputStream(b6);
        Assert.AreEqual(t6, es6.Read());

        var b7 = new byte[] { 131, 110, 8, 0, 255, 255, 255, 255, 255, 255, 255, 255 };
        var es7 = new ErlInputStream(b7);
        var t7 = new ErlLong(-1);
        Assert.AreEqual(t7, es7.Read());
        var bi7 = new byte[] {131, 98, 255, 255, 255, 255};
        var os7 = new ErlOutputStream(t7);
        Assert.AreEqual(bi7, os7.GetBuffer().TakeWhile((_, i) => i < bi7.Length).ToArray());
      }
      {
        var b = new byte[] { 131, 103, 100, 0, 7, 98, 64, 112, 105, 112, 105, 116, 0, 0, 0, 38, 0, 0, 0, 0, 1 };
        var t = new ErlPid("b@pipit", 38, 0, 1);
        var os = new ErlOutputStream(t);
        Assert.AreEqual(b, os.GetBuffer().TakeWhile((_, i) => i < b.Length).ToArray());
        var es = new ErlInputStream(b);
        Assert.AreEqual(t, es.Read());
      }
      {
        var b = new byte[] { 131, 102, 100, 0, 7, 98, 64, 112, 105, 112, 105, 116, 0, 0, 0, 38, 1 };
        var t = new ErlPort("b@pipit", 38, 1);
        var os = new ErlOutputStream(t);
        Assert.AreEqual(b, os.GetBuffer().TakeWhile((_, i) => i < b.Length).ToArray());
        var es = new ErlInputStream(b);
        Assert.AreEqual(t, es.Read());
      }
      {
        var b = new byte[] { 131, 114, 0, 3, 100, 0, 7, 98, 64, 112, 105, 112, 105, 116, 1, 0, 0, 0, 181, 0, 0, 0, 0, 0, 0, 0, 0 };
        var t = new ErlRef("b@pipit", 181, 0, 0, 1);
        var os = new ErlOutputStream(t);
        Assert.AreEqual(b, os.GetBuffer().TakeWhile((_, i) => i < b.Length).ToArray());
        var es = new ErlInputStream(b);
        Assert.AreEqual(t, es.Read());
      }
      {
        var b = new byte[] { 131, 107, 0, 3, 115, 116, 114 };
        var t = new ErlString("str");
        var os = new ErlOutputStream(t);
        Assert.AreEqual(b, os.GetBuffer().TakeWhile((_, i) => i < b.Length).ToArray());
        var es = new ErlInputStream(b);
        Assert.AreEqual(t, es.Read());
      }
      {
        var b = new byte[] { 131, 104, 3, 97, 1, 100, 0, 1, 97, 104, 2, 97, 10, 70, 63, 241, 247, 206, 217, 22, 135, 43 };
        var t = new ErlTuple(1, new ErlAtom("a"), new ErlTuple(10, 1.123));
        var os = new ErlOutputStream(t);
        Assert.AreEqual(b, os.GetBuffer().TakeWhile((_, i) => i < b.Length).ToArray());
        var es = new ErlInputStream(b);
        Assert.AreEqual(t, es.Read());
      }
    }