/** * Create a unary tuple containing the given element. * * @param elem * the element to create the tuple from. * * @exception java.lang.IllegalArgumentException * if the element is null. */ public OtpErlangTuple(OtpErlangObject elem) { if (elem == null) { throw new ArgumentException("Tuple element cannot be null"); } else { elems = new OtpErlangObject[] { elem }; } }
public OtpErlangFun(OtpErlangPid pid, String module, long index, long uniq, OtpErlangObject[] freeVars) { this.pid = pid; this.module = module; arity = -1; md5 = null; this.index = index; old_index = 0; this.uniq = uniq; this.freeVars = freeVars; }
public OtpErlangFun(OtpErlangPid pid, String module, int arity, byte[] md5, int index, long old_index, long uniq, OtpErlangObject[] freeVars) { this.pid = pid; this.module = module; this.arity = arity; this.md5 = md5; this.index = index; this.old_index = old_index; this.uniq = uniq; this.freeVars = freeVars; }
/* * 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()); }
/** * Send an exit signal to a remote process. * * @param dest * the Erlang PID of the remote process. * @param reason * an Erlang term describing the exit reason. * * @exception java.io.IOException * if the connection is not active or a communication error * occurs. */ protected void sendExit2(OtpErlangPid from, OtpErlangPid dest, OtpErlangObject reason) { sendExit(exit2Tag, from, dest, reason); }
/** * <p> * Send an exit signal to a remote {@link OtpErlangPid pid}. This method * does not cause any links to be broken, except indirectly if the remote * {@link OtpErlangPid pid} exits as a result of this exit signal. * </p> * * @param to * the {@link OtpErlangPid pid} to which the exit signal * should be sent. * * @param reason * an Erlang term indicating the reason for the exit. */ // it's called exit, but it sends exit2 public void exit(OtpErlangPid to, OtpErlangObject reason) { exit(2, to, reason); }
/* 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); }
/** * Send a message to a named mailbox created from the same node as this * mailbox. * * @param name * the registered name of recipient mailbox. * * @param msg * the body of the message to send. * */ public void send(String name, OtpErlangObject msg) { home.deliver(new OtpMsg(self, name, (OtpErlangObject)msg.Clone())); }
/** * Get all the elements from the tuple as an array. * * @return an array containing all of the tuple's elements. */ public OtpErlangObject[] elements() { OtpErlangObject[] res = new OtpErlangObject[arity()]; Array.Copy(elems, 0, res, 0, res.Length); return res; }
public OtpErlangFun read_fun() { int tag = read1skip_version(); if (tag == OtpExternal.funTag) { int nFreeVars = read4BE(); OtpErlangPid pid = read_pid(); String module = read_atom(); long index = read_long(); long uniq = read_long(); OtpErlangObject[] freeVars = new OtpErlangObject[nFreeVars]; for (int i = 0; i < nFreeVars; ++i) { freeVars[i] = read_any(); } return new OtpErlangFun(pid, module, index, uniq, freeVars); } else if (tag == OtpExternal.newFunTag) { read4BE(); int arity = read1(); byte[] md5 = new byte[16]; readN(md5); int index = read4BE(); int nFreeVars = read4BE(); String module = read_atom(); long oldIndex = read_long(); long uniq = read_long(); OtpErlangPid pid = read_pid(); OtpErlangObject[] freeVars = new OtpErlangObject[nFreeVars]; for (int i = 0; i < nFreeVars; ++i) { freeVars[i] = read_any(); } return new OtpErlangFun(pid, module, arity, md5, index, oldIndex, uniq, freeVars); } else { throw new OtpErlangDecodeException("Wrong tag encountered, expected fun, got " + tag); } }
/* * this one called explicitely by user code => use exit2 */ public void exit2(OtpErlangPid from, OtpErlangPid to, OtpErlangObject reason) { try { base.sendExit2(from, to, reason); } catch (Exception) { } }
/** * Create a stream containing the encoded version of the given Erlang term. */ public OtpOutputStream(OtpErlangObject o) : base() { write_any(o); }
public void write_fun(OtpErlangPid pid, String module, long old_index, int arity, byte[] md5, long index, long uniq, OtpErlangObject[] freeVars) { if (arity == -1) { write1(OtpExternal.funTag); write4BE(freeVars.Length); pid.encode(this); write_atom(module); write_long(index); write_long(uniq); foreach (OtpErlangObject fv in freeVars) { fv.encode(this); } } else { write1(OtpExternal.newFunTag); int saveSizePos = getPos(); write4BE(0); // this is where we patch in the size write1(arity); writeN(md5); write4BE(index); write4BE(freeVars.Length); write_atom(module); write_long(old_index); write_long(uniq); pid.encode(this); foreach (OtpErlangObject fv in freeVars) { fv.encode(this); } poke4BE(saveSizePos, getPos() - saveSizePos); } }
/** * Write an arbitrary Erlang term to the stream in compressed format. * * @param o * the Erlang tem to write. */ public void write_compressed(OtpErlangObject o) { OtpOutputStream oos = new OtpOutputStream(o); write1(OtpExternal.compressedTag); write4BE(oos.Length); DeflateStream dos = new DeflateStream(this, CompressionMode.Compress, true); try { oos.WriteTo(dos); dos.Close(); } catch (ObjectDisposedException) { throw new ArgumentException("Intremediate stream failed for Erlang object " + o); } }
/** * Write an arbitrary Erlang term to the stream. * * @param o * the Erlang term to write. */ public void write_any(OtpErlangObject o) { // calls one of the above functions, depending on o o.encode(this); }
// this function used internally when "process" dies // since Erlang discerns between exit and exit/2. private void exit(int arity, OtpErlangPid to, OtpErlangObject reason) { try { String node = to.Node; if (node.Equals(home.Node)) { home.deliver(new OtpMsg(OtpMsg.exitTag, self, to, reason)); } else { OtpCookedConnection conn = home.getConnection(node); if (conn == null) { return; } switch (arity) { case 1: conn.exit(self, to, reason); break; case 2: conn.exit2(self, to, reason); break; } } } catch (Exception) { } }
/** * Send a message to a named mailbox created from another node. * * @param name * the registered name of recipient mailbox. * * @param node * the name of the remote node where the recipient mailbox is * registered. * * @param msg * the body of the message to send. * */ public void send(String name, String node, OtpErlangObject msg) { try { String currentNode = home.Node; if (node.Equals(currentNode)) { send(name, msg); } else if (node.IndexOf('@', 0) < 0 && node.Equals(currentNode.Substring(0, currentNode.IndexOf('@', 0)))) { send(name, msg); } else { // other node OtpCookedConnection conn = home.getConnection(node); if (conn == null) { return; } conn.send(self, name, msg); } } catch (Exception) { } }
private void sendExit(int tag, OtpErlangPid from, OtpErlangPid dest, OtpErlangObject reason) { if (!connected) { throw new IOException("Not connected"); } OtpOutputStream header = new OtpOutputStream(headerLen); // preamble: 4 byte length + "passthrough" tag header.write4BE(0); // reserve space for length header.write1(passThrough); header.write1(version); // header header.write_tuple_head(4); header.write_long(tag); header.write_any(from); header.write_any(dest); header.write_any(reason); // fix up length in preamble header.poke4BE(0, header.size() - 4); do_send(header); }
protected String headerType(OtpErlangObject h) { int tag = -1; if (h is OtpErlangTuple) { tag = (int)((OtpErlangLong)((OtpErlangTuple)h).elementAt(0)).longValue(); } switch (tag) { case linkTag: return "LINK"; case sendTag: return "SEND"; case exitTag: return "EXIT"; case unlinkTag: return "UNLINK"; case nodeLinkTag: return "NODELINK"; case regSendTag: return "REG_SEND"; case groupLeaderTag: return "GROUP_LEADER"; case exit2Tag: return "EXIT2"; case sendTTTag: return "SEND_TT"; case exitTTTag: return "EXIT_TT"; case regSendTTTag: return "REG_SEND_TT"; case exit2TTTag: return "EXIT2_TT"; } return "(unknown type)"; }
/* * send to remote name dest is recipient's registered name, the nodename is * implied by the choice of connection. */ public void send(OtpErlangPid from, String dest, OtpErlangObject msg) { // encode and send the message sendBuf(from, dest, new OtpOutputStream(msg)); }
/** * Create a tuple from an array of terms. * * @param elems * the array of terms to create the tuple from. * @param start * the offset of the first term to insert. * @param count * the number of terms to insert. * * @exception java.lang.IllegalArgumentException * if the array is empty (null) or contains null * elements. */ public OtpErlangTuple(OtpErlangObject[] elems, int start, int count) { if (elems == null) { throw new ArgumentException("Tuple content can't be null"); } else if (count < 1) { elems = NO_ELEMENTS; } else { this.elems = new OtpErlangObject[count]; for (int i = 0; i < count; i++) { if (elems[start + i] != null) { this.elems[i] = elems[start + i]; } else { throw new ArgumentException("Tuple element cannot be null (element" + (start + i) + ")"); } } } }
/** * Create a tuple from an array of terms. * * @param elems * the array of terms to create the tuple from. * * @exception java.lang.IllegalArgumentException * if the array is empty (null) or contains null * elements. */ public OtpErlangTuple(OtpErlangObject[] elems) : this(elems, 0, elems.Length) { }
/** * Send an exit signal to a remote process. * * @param dest * the Erlang PID of the remote process. * @param reason * an Erlang term describing the exit reason. * * @exception java.io.IOException * if the connection is not active or a communication * error occurs. */ public void exit(OtpErlangPid dest, OtpErlangObject reason) { base.sendExit2(self.Pid, dest, reason); }
/** * Send a message to a remote {@link OtpErlangPid pid}, representing either * another {@link OtpMbox mailbox} or an Erlang process. * * @param to * the {@link OtpErlangPid pid} identifying the intended * recipient of the message. * * @param msg * the body of the message to send. * */ public void send(OtpErlangPid to, OtpErlangObject msg) { try { String node = to.Node; if (node.Equals(home.Node)) { home.deliver(new OtpMsg(to, (OtpErlangObject)msg.Clone())); } else { OtpCookedConnection conn = home.getConnection(node); if (conn == null) { return; } conn.send(self, to, msg); } } catch (Exception) { } }
/** * Send a message to a named process on a remote node. * * @param dest * the name of the remote process. * @param msg * the message to send. * * @exception java.io.IOException * if the connection is not active or a communication * error occurs. */ public void send(String dest, OtpErlangObject msg) { // encode and send the message base.sendBuf(self.Pid, dest, new OtpOutputStream(msg)); }
/** * 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 * an array 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, OtpErlangObject[] args) { sendRPC(mod, fun, new OtpErlangList(args)); }
/** * Close the specified mailbox with the given reason. * * @param mbox * the mailbox to close. * @param reason * an Erlang term describing the reason for the termination. * * <p> * After this operation, the mailbox will no longer be able to * receive messages. Any delivered but as yet unretrieved * messages can still be retrieved however. * </p> * * <p> * If there are links from the mailbox to other * {@link OtpErlangPid pids}, they will be broken when this * method is called and exit signals with the given reason will * be sent. * </p> * */ public void closeMbox(OtpMbox mbox, OtpErlangObject reason) { if (mbox != null) { mboxes.remove(mbox); mbox.Name = null; mbox.breakLinks(reason); } }
/** * 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)); }
/* * 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; }
/** * Close this mailbox with the given reason. * * <p> * After this operation, the mailbox will no longer be able to receive * messages. Any delivered but as yet unretrieved messages can still be * retrieved however. * </p> * * <p> * If there are links from this mailbox to other {@link OtpErlangPid pids}, * they will be broken when this method is called and exit signals will be * sent. * </p> * * @param reason * an Erlang term describing the reason for the exit. */ public void exit(OtpErlangObject reason) { home.closeMbox(this, reason); }