public virtual void Start()
{
if (!connected)
{
deliver(new System.IO.IOException("Not connected"));
return ;
}
OtpInputStream ibuf;
Erlang.Object traceobj;
int len;
byte[] header = new byte[4];
byte[] tock = new byte[]{0, 0, 0, 0};
byte[] payloadBuf = new byte[1024 * 1024];
try
{
while (!done)
{
// 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!
do
{
// read 4 bytes - get length of incoming packet
// socket.getInputStream().read(lbuf);
int n;
if ((n = readSock(socket, header, header.Length, false)) < header.Length)
throw new System.Exception(String.Format("Read {0} out of {1} bytes!", n, header.Length));
len = OtpInputStream.read4BE(header);
// received tick? send tock!
if (len == 0)
lock (this)
{
System.Byte[] temp_bytearray;
temp_bytearray = tock;
if (socket != null)
((System.IO.Stream)socket.GetStream()).Write(temp_bytearray, 0, temp_bytearray.Length);
}
}
while (len == 0); // tick_loop
if (len > maxPayloadLength)
throw new System.Exception(
String.Format("Message size too long (max={0}, got={1})", maxPayloadLength, len));
// got a real message (maybe) - read len bytes
byte[] tmpbuf = new byte[len]; // len > payloadBuf.Length ? new byte[len] : payloadBuf;
// i = socket.getInputStream().read(tmpbuf);
int m = readSock(socket, tmpbuf, len, true);
if (m != len)
throw new System.Exception(String.Format("Read {0} out of {1} bytes!", m, len));
ibuf = new OtpInputStream(tmpbuf, 0, len);
if (ibuf.read1() != passThrough)
{
goto receive_loop_brk;
}
// got a real message (really)
Erlang.Atom reason = null;
Erlang.Atom cookie = null;
Erlang.Object tmp = null;
Erlang.Tuple head = null;
Erlang.Atom toName;
Erlang.Pid to;
Erlang.Pid from;
Erlang.Ref eref;
// decode the header
tmp = ibuf.read_any();
if (!(tmp is Erlang.Tuple))
goto receive_loop_brk;
head = (Erlang.Tuple)tmp;
if (!(head.elementAt(0) is Erlang.Long))
{
goto receive_loop_brk;
}
// lets see what kind of message this is
OtpMsg.Tag tag = (OtpMsg.Tag)head.elementAt(0).longValue();
switch (tag)
{
case OtpMsg.Tag.sendTag:
case OtpMsg.Tag.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 Erlang.Atom))
{
goto receive_loop_brk;
}
cookie = (Erlang.Atom)head.elementAt(1);
if (sendCookie)
{
if (!cookie.atomValue().Equals(auth_cookie))
{
cookieError(self, cookie);
}
}
else
{
if (!cookie.atomValue().Equals(""))
{
cookieError(self, cookie);
}
}
cookieOk = true;
}
if (traceLevel >= OtpTrace.Type.sendThreshold)
{
OtpTrace.TraceEvent("<- " + headerType(head) + " " + head.ToString());
/*show received payload too */
long mark = ibuf.Position;
traceobj = ibuf.read_any();
if (traceobj != null)
OtpTrace.TraceEvent(" " + traceobj.ToString());
else
OtpTrace.TraceEvent(" (null)");
ibuf.Seek(mark, System.IO.SeekOrigin.Begin);
}
to = (Erlang.Pid)(head.elementAt(2));
deliver(new OtpMsg(to, ibuf));
break;
case OtpMsg.Tag.regSendTag:
case OtpMsg.Tag.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 Erlang.Atom))
{
goto receive_loop_brk;
}
cookie = (Erlang.Atom)head.elementAt(2);
if (sendCookie)
{
if (!cookie.atomValue().Equals(auth_cookie))
{
cookieError(self, cookie);
}
}
else
{
if (!cookie.atomValue().Equals(""))
{
cookieError(self, cookie);
}
}
cookieOk = true;
}
if (traceLevel >= OtpTrace.Type.sendThreshold)
{
OtpTrace.TraceEvent("<- " + headerType(head) + " " + head.ToString());
/*show received payload too */
long mark = ibuf.Position;
traceobj = ibuf.read_any();
if (traceobj != null)
OtpTrace.TraceEvent(" " + traceobj.ToString());
else
OtpTrace.TraceEvent(" (null)");
ibuf.Seek(mark, System.IO.SeekOrigin.Begin);
}
from = (Erlang.Pid)(head.elementAt(1));
toName = (Erlang.Atom)(head.elementAt(3));
deliver(new OtpMsg(from, toName.atomValue(), ibuf));
break;
case OtpMsg.Tag.exitTag:
case OtpMsg.Tag.exit2Tag:
// { EXIT2, FromPid, ToPid, Reason }
if (!(head.elementAt(3) is Erlang.Atom))
{
goto receive_loop_brk;
}
if (traceLevel >= OtpTrace.Type.ctrlThreshold)
{
OtpTrace.TraceEvent("<- " + headerType(head) + " " + head.ToString());
}
from = (Erlang.Pid)(head.elementAt(1));
to = (Erlang.Pid)(head.elementAt(2));
reason = (Erlang.Atom)head.elementAt(3);
deliver(new OtpMsg(tag, from, to, reason));
break;
case OtpMsg.Tag.exitTTTag:
case OtpMsg.Tag.exit2TTTag:
// { EXIT2, FromPid, ToPid, TraceToken, Reason }
// as above, but bifferent element number
if (!(head.elementAt(4) is Erlang.Atom))
{
goto receive_loop_brk;
}
if (traceLevel >= OtpTrace.Type.ctrlThreshold)
{
OtpTrace.TraceEvent("<- " + headerType(head) + " " + head.ToString());
}
from = (Erlang.Pid)(head.elementAt(1));
to = (Erlang.Pid)(head.elementAt(2));
reason = (Erlang.Atom)head.elementAt(4);
deliver(new OtpMsg(tag, from, to, reason));
break;
case OtpMsg.Tag.linkTag:
case OtpMsg.Tag.unlinkTag:
// { UNLINK, FromPid, ToPid}
if (traceLevel >= OtpTrace.Type.ctrlThreshold)
{
OtpTrace.TraceEvent("<- " + headerType(head) + " " + head.ToString());
}
from = (Erlang.Pid)(head.elementAt(1));
to = (Erlang.Pid)(head.elementAt(2));
deliver(new OtpMsg(tag, from, to));
break;
// absolutely no idea what to do with these, so we ignore them...
case OtpMsg.Tag.groupLeaderTag:
case OtpMsg.Tag.nodeLinkTag:
// { NODELINK }
// (just show trace)
if (traceLevel >= OtpTrace.Type.ctrlThreshold)
{
OtpTrace.TraceEvent("<- " + headerType(head) + " " + head.ToString());
}
break;
case OtpMsg.Tag.monitorPTag:
// {MONITOR_P, FromPid, ToProc, Ref}
case OtpMsg.Tag.demonitorPTag:
// {DEMONITOR_P, FromPid, ToProc, Ref}
if (traceLevel >= OtpTrace.Type.ctrlThreshold)
{
OtpTrace.TraceEvent("<- " + headerType(head) + " " + head.ToString());
}
from = (Erlang.Pid)(head.elementAt(1));
to = (Erlang.Pid)(head.elementAt(2));
eref = (Erlang.Ref)(head.elementAt(3));
deliver(new OtpMsg(tag, from, to, eref));
break;
case OtpMsg.Tag.monitorPexitTag:
// {MONITOR_P_EXIT, FromPid, ToProc, Ref, Reason}
if (traceLevel >= OtpTrace.Type.ctrlThreshold)
{
OtpTrace.TraceEvent("<- " + headerType(head) + " " + head.ToString());
}
from = (Erlang.Pid)(head.elementAt(1));
to = (Erlang.Pid)(head.elementAt(2));
eref = (Erlang.Ref)(head.elementAt(3));
deliver(new OtpMsg(tag, from, to, eref, reason));
break;
default:
// garbage?
if (traceLevel >= OtpTrace.Type.ctrlThreshold)
{
OtpTrace.TraceEvent("<- Unknown tag " + headerType(head) + " " + head.ToString());
}
goto receive_loop_brk;
}
}
receive_loop_brk: ;
// end receive_loop
// this section reachable only with break
// we have received garbage from peer
deliver(new Erlang.Exit("Remote is sending garbage"));
}
catch (OtpAuthException e)
{
deliver(e);
}
catch (Erlang.Exception e)
{
OtpTrace.TraceEvent(e.ToString());
deliver(new Erlang.Exit("Remote is sending garbage: " + e.ToString()));
}
catch (System.Exception e)
{
deliver(new Erlang.Exit("Remote has closed connection: " + e.ToString()));
}
finally
{
close();
OtpTrace.TraceEvent("exit connection "+System.Threading.Thread.CurrentThread.Name);
}
}