/// <summary> /// Accept an incoming connection from a remote node. Used by ErlLocalNode.Accept /// to create a connection /// based on data received when handshaking with the peer node, when /// the remote node is the connection intitiator. /// </summary> protected ErlAbstractConnection(ErlLocalNode home, IErlTransport s) : this(home, new ErlRemoteNode(home), s, home.Cookie) { setSockOpts(); //this.socket.ReceiveTimeout = 5000; home.OnTrace(ErlTraceLevel.Handshake, Direction.Inbound, () => StringConsts.ERL_CONN_ACCEPT_FROM.Args( IPAddress.Parse(s.RemoteEndPoint.ToString()).ToString(), (s.RemoteEndPoint as IPEndPoint).Port.ToString())); // get his info recvName(m_Peer); // now find highest common dist value if ((m_Peer.Proto != home.Proto) || (home.DistHigh < m_Peer.DistLow) || (home.DistLow > m_Peer.DistHigh)) { Close(); throw new ErlException(StringConsts.ERL_CONN_NO_COMMON_PROTO_ERROR); } // highest common protocol version m_Peer.DistChoose = Math.Min(m_Peer.DistHigh, home.DistHigh); doAccept(); }
/// <summary> /// Unregister from Epmd. /// Other nodes wishing to connect will no longer be able to /// </summary> public static void UnPublishPort(ErlLocalNode node) { IErlTransport s = null; try { s = node.Epmd ?? new ErlTcpTransport(ErlLocalNode.LocalHost, EPMD_PORT) { NodeName = node.NodeName.Value }; ErlOutputStream obuf = new ErlOutputStream( writeVersion: false, capacity: node.AliveName.Length + 8); obuf.Write2BE(node.AliveName.Length + 1); obuf.Write1((byte)Indicator.StopReq); var buf = Encoding.ASCII.GetBytes(node.AliveName); obuf.Write(buf); obuf.WriteTo(s.GetStream()); node.OnTrace(ErlTraceLevel.Epmd, Direction.Outbound, () => StringConsts.ERL_EPMD_UNPUBLISH.Args(node.NodeName.Value, node.Port)); } catch { s = null; } finally { if (s != null) { try { s.Close(); } catch { } } node.Epmd = null; } }
private void closeSock(IErlTransport s) { try { if (s != null) { s.Close(); } } catch { } }
public void AppendSSHParamsToTransport(IErlTransport transport) { //set SSH params transport.SSHAuthenticationType = SSHAuthenticationType; transport.SSHPrivateKeyFilePath = SSHPrivateKeyFilePath; transport.SSHServerPort = SSHServerPort; transport.ConnectTimeout = ConnectTimeout; transport.SSHUserName = SSHUserName; }
private ErlAbstractConnection(ErlLocalNode home, ErlRemoteNode peer, IErlTransport s, ErlAtom? cookie = null) { m_Peer = peer; m_Home = home; m_Transport = s; m_Cookie = !cookie.HasValue || cookie.Value == ErlAtom.Null ? (peer.Cookie == ErlAtom.Null ? home.Cookie : peer.Cookie) : cookie.Value; m_SentBytes = 0; m_ReceivedBytes = 0; m_MaxPayloadLength = DEFAULT_MAX_PAYLOAD_LENGTH; if (m_Transport != null) m_Transport.Trace += (o, t, d, msg) => home.OnTrace(t, d, msg); }
private ErlAbstractConnection(ErlLocalNode home, ErlRemoteNode peer, IErlTransport s, ErlAtom?cookie = null) { m_Peer = peer; m_Home = home; m_Transport = s; m_Cookie = !cookie.HasValue || cookie.Value == ErlAtom.Null ? (peer.Cookie == ErlAtom.Null ? home.Cookie : peer.Cookie) : cookie.Value; m_SentBytes = 0; m_ReceivedBytes = 0; m_MaxPayloadLength = DEFAULT_MAX_PAYLOAD_LENGTH; if (m_Transport != null) { m_Transport.Trace += (o, t, d, msg) => home.OnTrace(t, d, msg); } }
/// <summary> /// Close the connection to the remote node /// </summary> protected virtual void Close() { m_Connected = false; if (m_Transport != null) { lock (m_Transport) { if (m_Transport != null) { m_Home.OnTrace(ErlTraceLevel.Ctrl, Direction.Inbound, "CLOSE"); try { m_Transport.Close(); } catch { } finally { m_Transport = null; } } } } }
private void doConnect(int port) { try { m_Transport = ErlTransportFactory.Create(RemoteNode.TransportClassName, RemoteNode.NodeName.Value); m_Transport.Trace += (o, t, d, msg) => m_Home.OnTrace(t, d, msg); setSockOpts(); m_Home.OnTrace(ErlTraceLevel.Handshake, Direction.Outbound, () => "MD5 CONNECT TO {0}:{1}".Args(m_Peer.Host, port)); //m_TcpClient.ReceiveTimeout = 5000; m_Transport.Connect(m_Peer.Host, port, ConnectTimeout); m_Home.OnTrace(ErlTraceLevel.Handshake, Direction.Outbound, () => "MD5 CONNECTED TO {0}:{1}".Args(m_Peer.Host, port)); sendName(m_Peer.DistChoose, ErlAbstractNode.NodeCompatibility.Flags); recvStatus(); int herChallenge = recvChallenge(); byte[] our_digest = genDigest(herChallenge, m_Cookie); int ourChallenge = genChallenge(); sendChallengeReply(ourChallenge, our_digest); recvChallengeAck(ourChallenge); m_CookieOk = true; m_ShouldSendCookie = false; } catch (ErlAuthException ae) { Close(); throw ae; } catch (Exception e) { Close(); throw new ErlConnectionException(Name, StringConsts.ERL_CONN_CANT_CONNECT_TO_NODE_ERROR.Args( "{0}:{1}{2}: {3}".Args(m_Peer.Host, port, m_Peer.NodeName == ErlAtom.Null ? "" : " [{0}]".Args(m_Peer.NodeName.Value), e.Message))); } }
/// <summary> /// Close the connection to the remote node /// </summary> protected virtual void Close() { m_Connected = false; if (m_Transport != null) lock (m_Transport) { if (m_Transport != null) { m_Home.OnTrace(ErlTraceLevel.Ctrl, Direction.Inbound, "CLOSE"); try { m_Transport.Close(); } catch { } finally { m_Transport = null; } } } }
private void closeSock(IErlTransport s) { try { if (s != null) s.Close(); } catch { } }
/// <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); } // 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) { home.OnTrace(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.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 doConnect(int port) { try { m_Transport = ErlTransportFactory.Create(RemoteNode.TransportClassName, RemoteNode.NodeName.Value); m_Transport.Trace += (o, t, d, msg) => m_Home.OnTrace(t, d, msg); setSockOpts(); //m_TcpClient.ReceiveTimeout = 5000; var connected = false; Thread thr = new Thread( () => { try { m_Transport.Connect(m_Peer.Host, port); connected = true; } catch (Exception) { } } ) { IsBackground = true, Name = "ErlSockConnectThread" }; thr.Start(); m_Home.OnTrace(ErlTraceLevel.Handshake, Direction.Outbound, () => "MD5 CONNECT TO {0}:{1}".Args(m_Peer.Host, port)); var untilTime = DateTime.Now.AddMilliseconds(ConnectTimeout); while (!connected && DateTime.Now < untilTime) Thread.Sleep(10); if (!connected) // Timeout throw new ErlException(StringConsts.ERL_CONN_TIMEOUT_ERROR.Args(m_Peer.Host, port)); m_Home.OnTrace(ErlTraceLevel.Handshake, Direction.Outbound, () => "MD5 CONNECTED TO {0}:{1}".Args(m_Peer.Host, port)); sendName(m_Peer.DistChoose, ErlAbstractNode.NodeCompatibility.Flags); recvStatus(); int herChallenge = recvChallenge(); byte[] our_digest = genDigest(herChallenge, m_Cookie); int ourChallenge = genChallenge(); sendChallengeReply(ourChallenge, our_digest); recvChallengeAck(ourChallenge); m_CookieOk = true; m_ShouldSendCookie = false; } catch (ErlAuthException ae) { Close(); throw ae; } catch (Exception e) { Close(); throw new ErlConnectionException(Name, StringConsts.ERL_CONN_CANT_CONNECT_TO_NODE_ERROR.Args( "{0}:{1}{2}: {3}".Args(m_Peer.Host, port, m_Peer.NodeName == ErlAtom.Null ? "" : " [{0}]".Args(m_Peer.NodeName.Value), e.Message))); } }
private long m_SentMsgs; // Total number of messages sent #endregion Fields #region Constructors /// <summary> /// Accept an incoming connection from a remote node. Used by ErlLocalNode.Accept /// to create a connection /// based on data received when handshaking with the peer node, when /// the remote node is the connection intitiator. /// </summary> protected ErlAbstractConnection(ErlLocalNode home, IErlTransport s) : this(home, new ErlRemoteNode(home), s, home.Cookie) { setSockOpts(); //this.socket.ReceiveTimeout = 5000; home.OnTrace(ErlTraceLevel.Handshake, Direction.Inbound, () => StringConsts.ERL_CONN_ACCEPT_FROM.Args( IPAddress.Parse(s.RemoteEndPoint.ToString()).ToString(), (s.RemoteEndPoint as IPEndPoint).Port.ToString())); // get his info recvName(m_Peer); // now find highest common dist value if ((m_Peer.Proto != home.Proto) || (home.DistHigh < m_Peer.DistLow) || (home.DistLow > m_Peer.DistHigh)) { Close(); throw new ErlException(StringConsts.ERL_CONN_NO_COMMON_PROTO_ERROR); } // highest common protocol version m_Peer.DistChoose = Math.Min(m_Peer.DistHigh, home.DistHigh); doAccept(); }
private void doConnect(int port) { try { m_Transport = ErlTransportFactory.Create(RemoteNode.TransportClassName, RemoteNode.NodeName.Value); m_Transport.Trace += (o, t, d, msg) => m_Home.OnTrace(t, d, msg); setSockOpts(); //m_TcpClient.ReceiveTimeout = 5000; var connected = false; Thread thr = new Thread( () => { try { m_Transport.Connect(m_Peer.Host, port); connected = true; } catch (Exception) { } } ) { IsBackground = true, Name = "ErlSockConnectThread" }; thr.Start(); m_Home.OnTrace(ErlTraceLevel.Handshake, Direction.Outbound, () => "MD5 CONNECT TO {0}:{1}".Args(m_Peer.Host, port)); var untilTime = DateTime.Now.AddMilliseconds(ConnectTimeout); while (!connected && DateTime.Now < untilTime) { Thread.Sleep(10); } if (!connected) // Timeout { throw new ErlException(StringConsts.ERL_CONN_TIMEOUT_ERROR.Args(m_Peer.Host, port)); } m_Home.OnTrace(ErlTraceLevel.Handshake, Direction.Outbound, () => "MD5 CONNECTED TO {0}:{1}".Args(m_Peer.Host, port)); sendName(m_Peer.DistChoose, ErlAbstractNode.NodeCompatibility.Flags); recvStatus(); int herChallenge = recvChallenge(); byte[] our_digest = genDigest(herChallenge, m_Cookie); int ourChallenge = genChallenge(); sendChallengeReply(ourChallenge, our_digest); recvChallengeAck(ourChallenge); m_CookieOk = true; m_ShouldSendCookie = false; } catch (ErlAuthException ae) { Close(); throw ae; } catch (Exception e) { Close(); throw new ErlConnectionException(Name, StringConsts.ERL_CONN_CANT_CONNECT_TO_NODE_ERROR.Args( "{0}:{1}{2}: {3}".Args(m_Peer.Host, port, m_Peer.NodeName == ErlAtom.Null ? "" : " [{0}]".Args(m_Peer.NodeName.Value), e.Message))); } }