private void sendExit(int tag, Erlang.Pid from, Erlang.Pid dest, System.String reason) { if (!connected) { throw new System.IO.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_string(reason); // fix up length in preamble header.poke4BE(0, header.count() - 4); do_send(header); }
/* * Remove a link between the local node and the specified process on * the remote node. This method deactivates links created with * {@link #sendLink link()}. * * @param dest the Erlang PID of the remote process. * * @exception C#.io.IOException if the connection is not active or * a communication error occurs. **/ protected internal virtual void sendUnlink(Erlang.Pid from, Erlang.Pid dest) { if (!connected) { throw new System.IO.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(3); header.write_long((long)OtpMsg.Tag.unlinkTag); header.write_any(from); header.write_any(dest); // fix up length in preamble header.poke4BE(0, header.count() - 4); do_send(header); }
/* * Send a pre-encoded message to a process on a remote node. * * @param dest the Erlang PID of the remote process. * @param msg the encoded message to send. * * @exception C#.io.IOException if the connection is not active * or a communication error occurs. **/ protected internal virtual void sendBuf(Erlang.Pid from, Erlang.Pid dest, OtpOutputStream payload) { if (!connected) { throw new System.IO.IOException("Not connected"); } 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 info header.write_tuple_head(3); header.write_long((long)OtpMsg.Tag.sendTag); if (sendCookie) header.write_atom(auth_cookie); else header.write_atom(""); header.write_any(dest); // version for payload header.write1(version); // fix up length in preamble header.poke4BE(0, header.count() + payload.count() - 4); do_send(header, payload); }
/*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, Erlang.Atom 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((long)OtpMsg.Tag.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]}} Erlang.Object[] msg = new Erlang.Object[2]; Erlang.Object[] msgbody = new Erlang.Object[3]; msgbody[0] = new Erlang.Atom("print"); msgbody[1] = new Erlang.String("~n** Bad cookie sent to " + local + " **~n"); // Erlang will crash and burn if there is no third argument here... msgbody[2] = new Erlang.List(); // empty list msg[0] = new Erlang.Atom("$gen_cast"); msg[1] = new Erlang.Tuple(msgbody); OtpOutputStream payload = new OtpOutputStream(new Erlang.Tuple(msg)); // fix up length in preamble header.poke4BE(0, header.count() + payload.count() - 4); try { do_send(header, payload); } catch (System.IO.IOException) { } // ignore } finally { close(); throw new OtpAuthException("Remote cookie not authorized: " + cookie.atomValue()); } }
// used by send and send_reg (message types with payload) protected internal virtual void do_send(OtpOutputStream header, OtpOutputStream payload) { lock(this) { try { if (traceLevel >= OtpTrace.Type.sendThreshold) { // Need to decode header and output buffer to show trace message! // First make OtpInputStream, then decode. try { if (traceLevel >= OtpTrace.Type.wireThreshold) { Erlang.Object h = (header.getOtpInputStream(5)).read_any(); Erlang.Binary hb = header.ToBinary(); Erlang.Binary ob = payload.ToBinary(); System.Text.StringBuilder s = new System.Text.StringBuilder(); s.AppendFormat("-> {0} {1} (header_sz={2}, msg_sz={3})\n" + " Header: {4}\n" + " Msg: {5}", headerType(h), h.ToString(), hb.size(), ob.size(), hb.ToBinaryString(), ob.ToBinaryString()); OtpTrace.TraceEvent(s.ToString()); h = null; hb = null; ob = null; } else { Erlang.Object h = (header.getOtpInputStream(5)).read_any(); OtpTrace.TraceEvent("-> " + headerType(h) + " " + h.ToString()); Erlang.Object o = (payload.getOtpInputStream(0)).read_any(); OtpTrace.TraceEvent(" " + o.ToString()); h = null; o = null; } } catch (Erlang.Exception e) { OtpTrace.TraceEvent(" " + "can't decode output buffer:" + e); } } header.writeTo((System.IO.Stream) socket.GetStream()); payload.writeTo((System.IO.Stream) socket.GetStream()); long written = header.count() + payload.count(); sentBytes += written; sentMsgs++; if (onReadWrite != null) onReadWrite(this, Operation.Write, written, sentBytes, sentMsgs); } catch (System.Exception e) { close(); throw e; } } }