/* * 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; }
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)); } }
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()); } }
/// <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; }
/// <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; }
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)); } }
/// <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); }
/// <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); }
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()); } }