public override void run()
{
if (!connected)
{
deliver(new IOException("Not connected"));
return;
}
byte[] lbuf = new byte[4];
OtpInputStream ibuf;
OtpErlangObject traceobj;
int len;
byte[] tock = { 0, 0, 0, 0 };
try
{
receive_loop:
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);
readSock(socket, lbuf);
ibuf = new OtpInputStream(lbuf, flags);
len = ibuf.read4BE();
// received tick? send tock!
if (len == 0)
{
lock (this)
{
socket.GetOutputStream().Write(tock, 0, tock.Length);
socket.GetOutputStream().Flush();
}
}
} while (len == 0); // tick_loop
// got a real message (maybe) - read len bytes
byte[] tmpbuf = new byte[len];
// i = socket.getInputStream().read(tmpbuf);
readSock(socket, tmpbuf);
ibuf = new OtpInputStream(tmpbuf, flags);
if (ibuf.read1() != passThrough)
{
goto receive_loop;
}
// got a real message (really)
OtpErlangObject reason = null;
OtpErlangAtom cookie = null;
OtpErlangObject tmp = null;
OtpErlangTuple head = null;
OtpErlangAtom toName;
OtpErlangPid to;
OtpErlangPid from;
int tag;
// decode the header
tmp = ibuf.read_any();
if (!(tmp is OtpErlangTuple))
{
goto receive_loop;
}
head = (OtpErlangTuple)tmp;
if (!(head.elementAt(0) is OtpErlangLong))
{
goto receive_loop;
}
// 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))
{
goto receive_loop;
}
cookie = (OtpErlangAtom)head.elementAt(1);
if (sendCookie)
{
if (!cookie.atomValue().Equals(self.Cookie))
{
cookieError(self, cookie);
}
}
else
{
if (!cookie.atomValue().Equals(""))
{
cookieError(self, cookie);
}
}
cookieOk = true;
}
if (traceLevel >= sendThreshold)
{
log.Debug("<- " + headerType(head) + " " + head);
/* show received payload too */
ibuf.Mark(0);
traceobj = ibuf.read_any();
if (traceobj != null)
{
log.Debug(" " + traceobj);
}
else
{
log.Debug(" (null)");
}
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))
{
goto receive_loop;
}
cookie = (OtpErlangAtom)head.elementAt(2);
if (sendCookie)
{
if (!cookie.atomValue().Equals(self.Cookie))
{
cookieError(self, cookie);
}
}
else
{
if (!cookie.atomValue().Equals(""))
{
cookieError(self, cookie);
}
}
cookieOk = true;
}
if (traceLevel >= sendThreshold)
{
log.Debug("<- " + headerType(head) + " " + head);
/* show received payload too */
ibuf.Mark(0);
traceobj = ibuf.read_any();
if (traceobj != null)
{
log.Debug(" " + traceobj);
}
else
{
log.Debug(" (null)");
}
ibuf.Reset();
}
from = (OtpErlangPid)head.elementAt(1);
toName = (OtpErlangAtom)head.elementAt(3);
deliver(new OtpMsg(from, toName.atomValue(), ibuf));
break;
case exitTag: // { EXIT, FromPid, ToPid, Reason }
case exit2Tag: // { EXIT2, FromPid, ToPid, Reason }
if (head.elementAt(3) == null)
{
goto receive_loop;
}
if (traceLevel >= ctrlThreshold)
{
log.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)
{
goto receive_loop;
}
if (traceLevel >= ctrlThreshold)
{
log.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 >= ctrlThreshold)
{
log.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}
case nodeLinkTag: // { NODELINK }
// (just show trace)
if (traceLevel >= ctrlThreshold)
{
log.Debug("<- " + headerType(head) + " " + head);
}
break;
default:
// garbage?
goto receive_loop;
}
} // end receive_loop
// this section reachable only with break
// we have received garbage from peer
deliver(new OtpErlangExit("Remote is sending garbage"));
} // try
catch (OtpAuthException e)
{
deliver(e);
}
catch (OtpErlangDecodeException)
{
deliver(new OtpErlangExit("Remote is sending garbage"));
}
catch (IOException)
{
deliver(new OtpErlangExit("Remote has closed connection"));
}
finally
{
close();
}
}