private async Task Names_R4(IOtpTransport socket) { try { if (traceLevel >= traceThreshold) { Logger.Debug("<- NAMES(r4) "); } OtpOutputStream obuf = new OtpOutputStream(); obuf.Write4BE(EpmdPort); foreach (var node in portmap.Values) { byte[] bytes = Encoding.GetEncoding("ISO-8859-1").GetBytes($"name {node.Alive} at port {node.Port}\n"); obuf.WriteN(bytes); Logger.Debug($"-> name {node.Alive} at port {node.Port}"); } await obuf.WriteToAsync(socket.OutputStream); } catch (IOException e) { if (traceLevel >= traceThreshold) { Logger.Debug("<- (no response)"); } throw new IOException("Request not responding", e); } }
internal async Task <OtpInputStream> ReadRequestAsync(IOtpTransport sock) { OtpInputStream ibuf = await sock.ReadAsync(2); ibuf = await sock.ReadAsync(ibuf.Read2BE()); return(ibuf); }
/** * Make public the information needed by remote nodes that may wish to * connect to this one. This method establishes a connection to the Erlang * port mapper (Epmd) and registers the server node's name and port so that * remote nodes are able to connect. * * This method will fail if an Epmd process is not running on the localhost. * See the Erlang documentation for information about starting Epmd. * * Note that once this method has been called, the node is expected to be * available to accept incoming connections. For that reason you should make * sure that you call {@link #accept()} shortly after calling * {@link #publishPort()}. When you no longer intend to accept connections * you should call {@link #unPublishPort()}. */ public bool PublishPort() { if (Epmd is null) { Epmd = OtpEpmd.PublishPort(this); } return(Epmd != null); }
public static void Close(this IOtpTransport s) { if (s is null) { return; } try { s.Close(); } catch (Exception) { } }
private async Task Port_R4(IOtpTransport socket, OtpInputStream ibuf) { try { int len = (int)(ibuf.Length - 1); byte[] alive = ibuf.ReadN(len); string name = OtpErlangString.FromEncoding(alive); if (traceLevel >= traceThreshold) { Logger.Debug($"<- PORT (r4) {name}"); } if (!portmap.TryGetValue(name, out AbstractNode node)) { node = null; } OtpOutputStream obuf = new OtpOutputStream(); if (node != null) { obuf.Write1(port4resp); obuf.Write1(0); obuf.Write2BE(node.Port); obuf.Write1(node.Type); obuf.Write1(node.Proto); obuf.Write2BE(node.DistHigh); obuf.Write2BE(node.DistLow); obuf.Write2BE(len); obuf.WriteN(alive); obuf.Write2BE(0); if (traceLevel >= traceThreshold) { Logger.Debug("-> 0 (success)"); } } else { obuf.Write1(port4resp); obuf.Write1(1); if (traceLevel >= traceThreshold) { Logger.Debug("-> 1 (failure)"); } } await obuf.WriteToAsync(socket.OutputStream); } catch (IOException e) { if (traceLevel >= traceThreshold) { Logger.Debug("<- (no response)"); } throw new IOException("Request not responding", e); } }
private async void HandleConnectionAsync(IOtpTransport socket) { Logger.Info($"[OtpEpmd] connected {socket}"); List <string> publishedNodes = new List <string>(); try { while (true) { var ibuf = await ReadRequestAsync(socket); int request = ibuf.Read1(); // This request retains the connection if (request == ALIVE2_REQ) { publishedNodes.Add(await Publish_R4(socket, ibuf)); continue; } // These requests terminate the connection if (request == stopReq) { } else if (request == port4req) { await Port_R4(socket, ibuf); } else if (request == names4req) { await Names_R4(socket); } else { Logger.Info($"[OtpEpmd] Unknown request (request={request}, length={ibuf.Length}) from {socket}"); } break; } } catch (Exception e) { Logger.Error($"[OtpEpmd] socket {socket} error {e}"); } Logger.Info($"[OtpEpmd] closing {socket}"); OtpTransport.Close(socket); foreach (var name in publishedNodes) { portmap.TryRemove(name, out _); } }
/** * Accept an incoming connection from a remote node. Used by {@link * OtpSelf#accept() OtpSelf.accept()} to create a connection based on data * received when handshaking with the peer node, when the remote node is the * connection initiator. */ protected AbstractConnection(OtpLocalNode self, IOtpTransport s) : base("accept", true) { TraceLevel = Logger.DefaultTraceLevel; Local = self; socket = s; if (TraceLevel >= TraceHandshake) { Logger.Debug($"<- ACCEPT FROM {s}"); } Accept(); }
/** * Unregister the server node's name and port number from the Erlang port * mapper, thus preventing any new connections from remote nodes. */ public void UnPublishPort() { if (Epmd == null) { return; } // Unregister OtpEpmd.UnPublishPort(this); // Close and ignore errors OtpTransport.Close(Epmd); Epmd = null; }
/** * Close the connection to the remote node. */ public virtual void Close() { Stop(); Connected = false; lock (objRead) { if (socket != null) { if (TraceLevel >= TraceCTRL) { Logger.Debug($"-> CLOSE {socket}"); } OtpTransport.Close(socket); socket = null; } } }
/** * Accept an incoming connection from a remote node. A call to this method * will block until an incoming connection is at least attempted. */ public OtpConnection Accept() { IOtpTransport newsock = null; while (true) { try { newsock = listen.Accept(); return(new OtpConnection(this, newsock)); } catch (SocketException e) { newsock?.Dispose(); throw new IOException("Failed to accept connection", e); } } }
private async Task <string> Publish_R4(IOtpTransport socket, OtpInputStream ibuf) { try { int port = ibuf.Read2BE(); int type = ibuf.Read1(); int proto = ibuf.Read1(); int distHigh = ibuf.Read2BE(); int distLow = ibuf.Read2BE(); string name = ibuf.ReadStringData(); ibuf.ReadStringData(); // extra AbstractNode node = new AbstractNode() { Node = name, Port = port, Type = type, DistHigh = distHigh, DistLow = distLow, Proto = proto }; if (traceLevel >= traceThreshold) { Logger.Debug($"<- PUBLISH (r4) {name} port={node.Port}"); } OtpOutputStream obuf = new OtpOutputStream(); obuf.Write1(ALIVE2_RESP); obuf.Write1(0); obuf.Write2BE(NextCreation()); await obuf.WriteToAsync(socket.OutputStream); portmap.TryAdd(name, node); return(name); } catch (IOException e) { if (traceLevel >= traceThreshold) { Logger.Debug("<- (no response)"); } throw new IOException("Request not responding", e); } }
protected void Connect() { try { socket = Peer.CreateTransport(Peer.Host, Peer.Port); if (TraceLevel >= TraceHandshake) { Logger.Debug($"-> MD5 CONNECT TO {Peer.Host}:{Peer.Port}"); } int nameTag = SendName(Peer.DistChoose, Local.CapFlags, Local.Creation); RecvStatus(); int peer_challenge = RecvChallenge(); byte[] our_digest = GenDigest(peer_challenge, Local.Cookie); int our_challenge = GenChallenge(); SendComplement(nameTag); SendChallengeReply(our_challenge, our_digest); RecvChallengeAck(our_challenge); Connected = true; cookieOk = true; sendCookie = false; if (TraceLevel >= TraceHandshake) { Logger.Debug($"-> CONNECTED TO {Peer.Host}:{Peer.Port}"); } } catch (IOException) { Close(); throw; } catch (OtpAuthException) { Close(); throw; } catch (Exception e) { Close(); throw new IOException("Cannot connect to peer node", e); } }
public static async Task <OtpInputStream> ReadAsync(this IOtpTransport s, int bytes) { if (s is null) { return(default);
/* * Accept an incoming connection from a remote node. Used by {@link * OtpSelf#accept() OtpSelf.accept()} to create a connection based on data * received when handshaking with the peer node, when the remote node is the * connection intitiator. */ internal OtpConnection(OtpSelf self, IOtpTransport socket) : base(self, socket) { Self = self; Start(); }
/* * Accept an incoming connection from a remote node. Used by {@link * OtpSelf#accept() OtpSelf.accept()} to create a connection based on data * received when handshaking with the peer node, when the remote node is the * connection intitiator. */ internal OtpCookedConnection(OtpNode self, IOtpTransport s) : base(self, s) { this.self = self; Start(); }