/* * this method simulates net_kernel only for the purpose of replying to * pings. */ private bool netKernel(OtpMsg m) { OtpMbox mbox = null; try { OtpErlangTuple t = (OtpErlangTuple)m.getMsg(); OtpErlangTuple req = (OtpErlangTuple)t.elementAt(1); // actual // request OtpErlangPid pid = (OtpErlangPid)req.elementAt(0); // originating // pid OtpErlangObject[] pong = new OtpErlangObject[2]; pong[0] = req.elementAt(1); // his #Ref pong[1] = new OtpErlangAtom("yes"); mbox = createMbox(true); mbox.send(pid, new OtpErlangTuple(pong)); return(true); } catch (Exception) { } finally { closeMbox(mbox); } return(false); }
/** * <p> * Determine if another node is alive. This method has the side effect of * setting up a connection to the remote node (if possible). Only a single * outgoing message is sent; the timeout is how long to wait for a response. * </p> * * <p> * Only a single attempt is made to connect to the remote node, so for * example it is not possible to specify an extremely long timeout and * expect to be notified when the node eventually comes up. If you wish to * wait for a remote node to be started, the following construction may be * useful: * </p> * * <pre> * // ping every 2 seconds until positive response * while (!me.ping(him, 2000)) * ; * </pre> * * @param node * the name of the node to ping. * * @param timeout * the time, in milliseconds, to wait for response before * returning false. * * @return true if the node was alive and the correct ping response was * returned. false if the correct response was not returned on time. */ /* * internal info about the message formats... * * the request: -> REG_SEND {6,#Pid<[email protected]>,'',net_kernel} * {'$gen_call',{#Pid<[email protected]>,#Ref<[email protected]>},{is_auth,bingo@aule}} * * the reply: <- SEND {2,'',#Pid<[email protected]>} {#Ref<[email protected]>,yes} */ public bool ping(String node, long timeout) { if (node.Equals(this.Node)) { return(true); } else if (node.IndexOf('@', 0) < 0 && node.Equals(this.Node.Substring(0, this.Node.IndexOf('@', 0)))) { return(true); } // other node OtpMbox mbox = null; try { mbox = createMbox(true); mbox.send("net_kernel", node, getPingTuple(mbox)); OtpErlangObject reply = mbox.receive(timeout); OtpErlangTuple t = (OtpErlangTuple)reply; OtpErlangAtom a = (OtpErlangAtom)t.elementAt(1); return("yes".Equals(a.atomValue())); } catch (Exception) { } finally { closeMbox(mbox); } return(false); }
/** * Determine if two atoms are equal. * * @param o * the other object to compare to. * * @return true if the atoms are equal, false otherwise. */ public override bool Equals(Object o) { if (!(o is OtpErlangAtom)) { return(false); } OtpErlangAtom atom = (OtpErlangAtom)o; return(this.atom.Equals(atom.atom)); }
/** * Send an auth error to peer because he sent a bad cookie. The auth error * uses his cookie (not revealing ours). This is just like send_reg * otherwise */ protected void CookieError(OtpLocalNode local, OtpErlangAtom cookie) { try { OtpOutputStream header = new OtpOutputStream(headerLen); // preamble: 4 byte length + "passthrough" tag + version header.Write4BE(0); // reserve space for length header.Write1(passThrough); header.Write1(version); header.WriteTupleHead(4); header.WriteLong(regSendTag); header.WriteAny(local.CreatePid()); // disposable pid header.WriteAtom(cookie.Value); // important: his cookie, // not mine... header.WriteAtom("auth"); // version for payload header.Write1(version); // the payload // the no_auth message (copied from Erlang) Don't change this // (Erlang will crash) // {$gen_cast, {print, "~n** Unauthorized cookie ~w **~n", // [foo@aule]}} IOtpErlangObject[] msg = new IOtpErlangObject[2]; IOtpErlangObject[] msgbody = new IOtpErlangObject[3]; msgbody[0] = new OtpErlangAtom("print"); msgbody[1] = new OtpErlangString("~n** Bad cookie sent to " + local + " **~n"); // Erlang will crash and burn if there is no third argument here... msgbody[2] = new OtpErlangList(); // empty list msg[0] = new OtpErlangAtom("$gen_cast"); msg[1] = new OtpErlangTuple(msgbody); OtpOutputStream payload = new OtpOutputStream(new OtpErlangTuple(msg)); // fix up length in preamble header.Poke4BE(0, header.Length + payload.Length - 4); try { DoSend(header, payload); } catch (IOException) { } // ignore } finally { Close(); } throw new OtpAuthException("Remote cookie not authorized: " + cookie.Value); }
/* ping remote node */ public bool Ping(string node, long timeout) { try { Send(node, "net_kernel", PingTuple()); var reply = (OtpErlangTuple)Receive(timeout); if (reply != null && reply.Arity >= 2) { OtpErlangAtom a = (OtpErlangAtom)reply.ElementAt(1); return("yes".Equals(a?.Value)); } } catch (Exception) { } return(false); }
/** * Send an RPC request to the remote Erlang node. This convenience function * creates the following message and sends it to 'rex' on the remote node: * * <pre> * { self, { call, Mod, Fun, Args, user } } * </pre> * * <p> * Note that this method has unpredicatble results if the remote node is not * an Erlang node. * </p> * * @param mod * the name of the Erlang module containing the function to * be called. * @param fun * the name of the function to call. * @param args * a list of Erlang terms, to be used as arguments to the * function. * * @exception java.io.IOException * if the connection is not active or a communication * error occurs. */ public void sendRPC(String mod, String fun, OtpErlangList args) { OtpErlangObject[] rpc = new OtpErlangObject[2]; OtpErlangObject[] call = new OtpErlangObject[5]; /* {self, { call, Mod, Fun, Args, user}} */ call[0] = new OtpErlangAtom("call"); call[1] = new OtpErlangAtom(mod); call[2] = new OtpErlangAtom(fun); call[3] = args; call[4] = new OtpErlangAtom("user"); rpc[0] = self.Pid; rpc[1] = new OtpErlangTuple(call); send("rex", new OtpErlangTuple(rpc)); }
/* create the outgoing ping message */ private OtpErlangTuple getPingTuple(OtpMbox mbox) { OtpErlangObject[] ping = new OtpErlangObject[3]; OtpErlangObject[] pid = new OtpErlangObject[2]; OtpErlangObject[] node = new OtpErlangObject[2]; pid[0] = mbox.Self; pid[1] = createRef(); node[0] = new OtpErlangAtom("is_auth"); node[1] = new OtpErlangAtom(Node); ping[0] = new OtpErlangAtom("$gen_call"); ping[1] = new OtpErlangTuple(pid); ping[2] = new OtpErlangTuple(node); return(new OtpErlangTuple(ping)); }
/* * this method simulates net_kernel only for the purpose of replying to * pings. */ private bool netKernel(OtpMsg m) { OtpMbox mbox = null; try { OtpErlangTuple t = (OtpErlangTuple)m.getMsg(); OtpErlangTuple req = (OtpErlangTuple)t.elementAt(1); // actual // request OtpErlangPid pid = (OtpErlangPid)req.elementAt(0); // originating // pid OtpErlangObject[] pong = new OtpErlangObject[2]; pong[0] = req.elementAt(1); // his #Ref pong[1] = new OtpErlangAtom("yes"); mbox = createMbox(true); mbox.send(pid, new OtpErlangTuple(pong)); return true; } catch (Exception) { } finally { closeMbox(mbox); } return false; }
/* create the outgoing ping message */ private OtpErlangTuple getPingTuple(OtpMbox mbox) { OtpErlangObject[] ping = new OtpErlangObject[3]; OtpErlangObject[] pid = new OtpErlangObject[2]; OtpErlangObject[] node = new OtpErlangObject[2]; pid[0] = mbox.Self; pid[1] = createRef(); node[0] = new OtpErlangAtom("is_auth"); node[1] = new OtpErlangAtom(Node); ping[0] = new OtpErlangAtom("$gen_call"); ping[1] = new OtpErlangTuple(pid); ping[2] = new OtpErlangTuple(node); return new OtpErlangTuple(ping); }
public override void Run() { if (!Connected) { Deliver(new IOException("Not connected")); return; } byte[] lbuf = new byte[4]; int len; try { while (!Stopping) { // 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! // read 4 bytes - get length of incoming packet ReadSock(lbuf); OtpInputStream ibuf = new OtpInputStream(lbuf) { Flags = Local.Flags }; len = ibuf.Read4BE(); // received tick? send tock! if (len == 0) { lock (objWrite) { socket.OutputStream.Write(TOCK, 0, TOCK.Length); socket.OutputStream.Flush(); } continue; } // got a real message (maybe) - read len bytes byte[] tmpbuf = new byte[len]; ReadSock(tmpbuf); ibuf = new OtpInputStream(tmpbuf) { Flags = Local.Flags }; if (ibuf.Read1() != passThrough) { continue; } // got a real message (really) IOtpErlangObject reason = null; OtpErlangAtom cookie = null; IOtpErlangObject tmp = null; OtpErlangTuple head = null; OtpErlangAtom toName; OtpErlangPid to; OtpErlangPid from; int tag; // decode the header tmp = ibuf.ReadAny(); if (!(tmp is OtpErlangTuple)) { continue; } head = (OtpErlangTuple)tmp; if (!(head.ElementAt(0) is OtpErlangLong)) { continue; } // lets see what kind of message this is tag = (int)((OtpErlangLong)head.ElementAt(0)).LongValue(); switch (tag) { case sendTag: // { SEND, Cookie, ToPid } case sendTTTag: // { SEND, Cookie, ToPid, TraceToken } if (!cookieOk) { // we only check this once, he can send us bad cookies later if he likes if (!(head.ElementAt(1) is OtpErlangAtom)) { continue; } cookie = (OtpErlangAtom)head.ElementAt(1); if (sendCookie) { if (cookie.Value != Local.Cookie) { CookieError(Local, cookie); } } else { if (cookie.Value != "") { CookieError(Local, cookie); } } cookieOk = true; } if (TraceLevel >= TraceSend) { Logger.Debug($"<- {HeaderType(head)} {head}"); /* show received payload too */ ibuf.Mark(); Logger.Debug($" {ibuf.ReadAny()}"); ibuf.Reset(); } to = (OtpErlangPid)head.ElementAt(2); Deliver(new OtpMsg(to, ibuf)); break; case regSendTag: // { REG_SEND, FromPid, Cookie, ToName } case regSendTTTag: // { REG_SEND, FromPid, Cookie, ToName, TraceToken } if (!cookieOk) { // we only check this once, he can send us bad cookies later if he likes if (!(head.ElementAt(2) is OtpErlangAtom)) { continue; } cookie = (OtpErlangAtom)head.ElementAt(2); if (sendCookie) { if (cookie.Value != Local.Cookie) { CookieError(Local, cookie); } } else { if (cookie.Value != "") { CookieError(Local, cookie); } } cookieOk = true; } if (TraceLevel >= TraceSend) { Logger.Debug($"<- {HeaderType(head)} {head}"); /* show received payload too */ ibuf.Mark(); Logger.Debug($" {ibuf.ReadAny()}"); ibuf.Reset(); } from = (OtpErlangPid)head.ElementAt(1); toName = (OtpErlangAtom)head.ElementAt(3); Deliver(new OtpMsg(from, toName.Value, ibuf)); break; case exitTag: // { EXIT, FromPid, ToPid, Reason } case exit2Tag: // { EXIT2, FromPid, ToPid, Reason } if (head.ElementAt(3) == null) { continue; } if (TraceLevel >= TraceCTRL) { Logger.Debug($"<- {HeaderType(head)} {head}"); } from = (OtpErlangPid)head.ElementAt(1); to = (OtpErlangPid)head.ElementAt(2); reason = head.ElementAt(3); Deliver(new OtpMsg(tag, from, to, reason)); break; case exitTTTag: // { EXIT, FromPid, ToPid, TraceToken, Reason } case exit2TTTag: // { EXIT2, FromPid, ToPid, TraceToken, Reason } // as above, but bifferent element number if (head.ElementAt(4) == null) { continue; } if (TraceLevel >= TraceCTRL) { Logger.Debug($"<- {HeaderType(head)} {head}"); } from = (OtpErlangPid)head.ElementAt(1); to = (OtpErlangPid)head.ElementAt(2); reason = head.ElementAt(4); Deliver(new OtpMsg(tag, from, to, reason)); break; case linkTag: // { LINK, FromPid, ToPid} case unlinkTag: // { UNLINK, FromPid, ToPid} if (TraceLevel >= TraceCTRL) { Logger.Debug($"<- {HeaderType(head)} {head}"); } from = (OtpErlangPid)head.ElementAt(1); to = (OtpErlangPid)head.ElementAt(2); Deliver(new OtpMsg(tag, from, to)); break; // absolutely no idea what to do with these, so we ignore them... case groupLeaderTag: // { GROUPLEADER, FromPid, ToPid} // (just show trace) if (TraceLevel >= TraceCTRL) { Logger.Debug("<- " + HeaderType(head) + " " + head); } break; default: // garbage? break; } } // this section reachable only with break // we have received garbage from peer Deliver(new OtpExit("Remote is sending garbage")); } catch (OtpAuthException e) { Deliver(e); } catch (OtpDecodeException) { Deliver(new OtpExit("Remote is sending garbage")); } catch (IOException) { Deliver(new OtpExit("Remote has closed connection")); } finally { Close(); } }
private OtpErlangObject ErlangObjectFromPCVMObject(PCObj input) { if (input is PCFloat) return new OtpErlangFloat(((PCFloat)input).val); if (input is PCInt) return new OtpErlangInt(((PCInt)input).val); if (input is PCBool) return new OtpErlangBoolean(((PCBool)input).val); if (input is PCSym) return new OtpErlangAtom(((PCSym)input).val); if (input is PCStr) return new OtpErlangString(((PCStr)input).val); if (input is PCMark) return new OtpErlangString(((PCMark)input).ToString()); if (input is PCUUID) return new OtpErlangString(((PCUUID)input).ToString()); if (input is PCVector2) { OtpErlangObject[] items = new OtpErlangObject[2]; items[0] = new OtpErlangFloat(((PCVector2)input).val.X); items[1] = new OtpErlangFloat(((PCVector2)input).val.Y); return new OtpErlangTuple(items); } if (input is PCVector3) { OtpErlangObject[] items = new OtpErlangObject[3]; items[0] = new OtpErlangFloat(((PCVector3)input).val.X); items[1] = new OtpErlangFloat(((PCVector3)input).val.Y); items[2] = new OtpErlangFloat(((PCVector3)input).val.Z); return new OtpErlangTuple(items); } if (input is PCVector4) { OtpErlangObject[] items = new OtpErlangObject[4]; items[0] = new OtpErlangFloat(((PCVector4)input).val.X); items[1] = new OtpErlangFloat(((PCVector4)input).val.Y); items[2] = new OtpErlangFloat(((PCVector4)input).val.Z); items[3] = new OtpErlangFloat(((PCVector4)input).val.W); return new OtpErlangTuple(items); } if (input is PCNull) return new OtpErlangAtom(((PCNull)input).ToString()); if (input is PCOp) return new OtpErlangAtom(((PCOp)input).ToString()); if (input is PCFun) return new OtpErlangAtom(((PCFun)input).ToString()); if (input is PCDict) { PCDict dict = (PCDict)input; OtpErlangObject[] items = new OtpErlangObject[dict.Dict.Count*2]; int i = 0; foreach (KeyValuePair<string, PCObj> pair in dict.Dict) { items[i * 2] = new OtpErlangAtom(pair.Key); items[i * 2 + 1] = ErlangObjectFromPCVMObject(pair.Value); i++; } return new OtpErlangList(items); } if (input is PCArray) { PCArray array = (PCArray)input; OtpErlangObject[] items = new OtpErlangObject[array.Length]; for (int i = 0; i < array.Length; i++) { items[i] = ErlangObjectFromPCVMObject(array[i]); } return new OtpErlangList(items); } if (input is PCSceneObjectPart) return ErlangObjectFromPCVMObject(new PCUUID(((PCSceneObjectPart)input).val.UUID)); if (input is PCSceneSnapshot) { PCSceneSnapshot.SnapshotItem[] array = ((PCSceneSnapshot)input).val; OtpErlangObject[] items = new OtpErlangObject[array.Length]; for (int i = 0; i < array.Length; i++) { items[i] = ErlangObjectFromPCVMObject(array[i].PCSceneObjectPart); } return new OtpErlangList(items); } return new OtpErlangAtom("nonobject"); }
public override IEnumerator<OtpActor.Continuation> GetEnumerator() { m_log.Info("[Distributed PC] New PCVM is ready: " + m_mbox.Self); while (true) { OtpMsg msg = null; yield return (delegate(OtpMsg received) { msg = received; }); OtpErlangObject obj = msg.getMsg(); if (obj is OtpErlangAtom) { string atom = ((OtpErlangAtom)obj).atomValue(); if (!String.IsNullOrEmpty(atom) && atom == "noconnection") { break; } } OtpErlangPid sender = null; OtpErlangObject[] reply = new OtpErlangObject[3]; try { OtpErlangTuple t = (OtpErlangTuple)obj; sender = (OtpErlangPid)t.elementAt(0); reply[0] = sender; reply[1] = new OtpErlangAtom("ok"); string instr = ((OtpErlangAtom)t.elementAt(1)).ToString(); if (instr == "load") { Parser parser = PCVM.MakeParser(); string script = String.Empty; if (t.elementAt(2) is OtpErlangString) { script = ((OtpErlangString)t.elementAt(2)).stringValue(); } else { script = OtpErlangString.newString(((OtpErlangBinary)t.elementAt(2)).binaryValue()); } bool debug = ((OtpErlangAtom)t.elementAt(3)).boolValue(); SYMBOL ast = parser.Parse(script); m_vm.Call((Compiler.ExpPair)ast); if (debug) { reply[2] = new OtpErlangAtom("continue"); } else { Queue<PCObj> popped = new Queue<PCObj>(); try { m_vm.Finish(popped); } finally { reply = new OtpErlangObject[] { reply[0], reply[1], new OtpErlangAtom("finished"), ErlangObjectFromPCVMObject(popped.ToArray()) }; } } } else if (instr == "step") { bool cont = true; Queue<PCObj> popped = new Queue<PCObj>(); try { cont = m_vm.Step(popped); } finally { reply = new OtpErlangObject[] { reply[0], reply[1], new OtpErlangAtom(cont ? "continue" : "finished"), ErlangObjectFromPCVMObject(popped.ToArray()) }; } } else if (instr == "finish") { Queue<PCObj> popped = new Queue<PCObj>(); try { m_vm.Finish(popped); } finally { reply = new OtpErlangObject[] { reply[0], reply[1], new OtpErlangAtom("finished"), ErlangObjectFromPCVMObject(popped.ToArray()) }; } } else if (instr == "echo") { reply[2] = t.elementAt(2); } else if (instr == "exit") { reply[2] = new OtpErlangAtom("bye"); break; } } catch (Exception e) { m_log.Debug("[Distributed PC] Invalid message format: " + msg.getMsg()); reply[1] = new OtpErlangAtom("error"); reply[2] = new OtpErlangString(e.Message); } finally { if (sender != null) { m_mbox.send(sender, new OtpErlangTuple(reply)); } } } m_log.Info("[Distributed PC] Delete PCVM instance: " + m_mbox.Self); m_vm.Dispose(); }
public override IEnumerator<OtpActor.Continuation> GetEnumerator() { while (true) { OtpMsg msg = null; OtpErlangPid sender = null; OtpErlangTuple reply = null; yield return (delegate(OtpMsg received) { msg = received; }); try { OtpErlangTuple t = (OtpErlangTuple)msg.getMsg(); sender = (OtpErlangPid)t.elementAt(0); string instr = ((OtpErlangAtom)t.elementAt(1)).ToString(); if (instr == "echo") { OtpErlangObject[] v = new OtpErlangObject[3]; v[0] = sender; v[1] = new OtpErlangAtom("ok"); v[2] = t.elementAt(2); reply = new OtpErlangTuple(v); } else if (instr == "new") { OtpActorMbox newmbox = (OtpActorMbox)m_node.createMbox(false); PCVMActor newactor = new PCVMActor(m_scene, m_source, m_node, newmbox); m_node.react(newactor); OtpErlangObject[] v = new OtpErlangObject[3]; v[0] = sender; v[1] = new OtpErlangAtom("ok"); v[2] = newmbox.Self; reply = new OtpErlangTuple(v); } } catch (Exception e) { m_log.Debug("[Distributed PC] Invalid message format: " + msg.getMsg()); OtpErlangObject[] v = new OtpErlangObject[3]; v[0] = sender; v[1] = new OtpErlangAtom("error"); v[2] = new OtpErlangString(e.Message); reply = new OtpErlangTuple(v); } finally { if (sender != null) { m_mbox.send(sender, reply); } } } }
/* * Send an auth error to peer because he sent a bad cookie. The auth error * uses his cookie (not revealing ours). This is just like send_reg * otherwise */ private void cookieError(OtpLocalNode local, OtpErlangAtom cookie) { try { OtpOutputStream header = new OtpOutputStream(headerLen); // preamble: 4 byte length + "passthrough" tag + version header.write4BE(0); // reserve space for length header.write1(passThrough); header.write1(version); header.write_tuple_head(4); header.write_long(regSendTag); header.write_any(local.createPid()); // disposable pid header.write_atom(cookie.atomValue()); // important: his cookie, // not mine... header.write_atom("auth"); // version for payload header.write1(version); // the payload // the no_auth message (copied from Erlang) Don't change this // (Erlang will crash) // {$gen_cast, {print, "~n** Unauthorized cookie ~w **~n", // [foo@aule]}} OtpErlangObject[] msg = new OtpErlangObject[2]; OtpErlangObject[] msgbody = new OtpErlangObject[3]; msgbody[0] = new OtpErlangAtom("print"); msgbody[1] = new OtpErlangString("~n** Bad cookie sent to " + local + " **~n"); // Erlang will crash and burn if there is no third argument here... msgbody[2] = new OtpErlangList(); // empty list msg[0] = new OtpErlangAtom("$gen_cast"); msg[1] = new OtpErlangTuple(msgbody); OtpOutputStream payload = new OtpOutputStream(new OtpErlangTuple(msg)); // fix up length in preamble header.poke4BE(0, header.size() + payload.size() - 4); try { do_send(header, payload); } catch (IOException) { } // ignore } finally { close(); } throw new OtpAuthException("Remote cookie not authorized: " + cookie.atomValue()); }