void OnFrame(ushort channel, ulong code, List fields, ByteBuffer payload)
{
switch (code)
{
case 0x10ul: // open
Fx.DebugPrint(false, channel, "open", fields, "container-id", "host-name", "max-frame-size", "channel-max", "idle-time-out");
this.state |= OpenReceived;
// process open.idle-time-out if exists: final value is determined by the min of the local and the remote values
uint remoteValue = uint.MaxValue;
if (fields.Count >= 5 && fields[4] != null)
{
remoteValue = (uint)fields[4];
}
uint timeout = this.idleTimeout < remoteValue ? this.idleTimeout : remoteValue;
if (timeout < uint.MaxValue)
{
timeout -= 5000;
timeout = timeout > MaxIdleTimeout ? MaxIdleTimeout : timeout;
this.heartBeatTimer = new Timer(onHeartBeatTimer, this, (int)timeout, (int)timeout);
}
break;
case 0x11ul: // begin
Fx.DebugPrint(false, channel, "begin", fields, "remote-channel", "next-outgoing-id", "incoming-window", "outgoing-window", "handle-max");
this.nextIncomingId = (uint)fields[1];
this.outWindow = (uint)fields[2];
this.state |= BeginReceived;
break;
case 0x12ul: // attach
{
Fx.DebugPrint(false, channel, "attach", fields, "name", "handle", "role", "snd-mode", "rcv-mode", "source", "target");
Link link = null;
uint remoteHandle = (uint)fields[1];
Fx.AssertAndThrow(ErrorCode.ClientInvalidHandle, remoteHandle < this.links.Length);
lock (this)
{
for (int i = 0; i < this.links.Length; i++)
{
if (this.links[i] != null && this.links[i].Name.Equals(fields[0]))
{
link = this.links[i];
int index = (int)~link.RemoteHandle;
Fx.AssertAndThrow(ErrorCode.ClientInvalidHandle, index == i);
if (index != (int)remoteHandle)
{
Fx.AssertAndThrow(ErrorCode.ClientHandlInUse, this.links[(int)remoteHandle] == null);
this.links[(int)remoteHandle] = link;
this.links[i] = null;
}
break;
}
}
}
Fx.AssertAndThrow(ErrorCode.ClientLinkNotFound, link != null);
link.RemoteHandle = remoteHandle;
link.State |= AttachReceived;
link.OnAttach(fields);
break;
}
case 0x13ul: // flow
{
Fx.DebugPrint(false, channel, "flow", fields, "next-in-id", "in-window", "next-out", "out-window", "handle", "dc", "credit");
uint nextIncomingId = (uint)fields[0];
uint incomingWindow = (uint)fields[1];
lock (this)
{
this.outWindow = incomingWindow < uint.MaxValue ?
nextIncomingId + incomingWindow - this.nextOutgoingId :
uint.MaxValue;
}
if (fields[4] != null)
{
Link link = this.links[(uint)fields[4]];
Fx.AssertAndThrow(ErrorCode.ClientLinkNotFound, link != null);
link.OnFlow(fields);
}
break;
}
case 0x14ul: // transfer
{
lock (this)
{
this.nextOutgoingId++;
if (--this.inWindow == 0)
{
this.inWindow = DefaultWindowSize;
List flow = new List()
{
this.nextIncomingId, this.inWindow, this.nextOutgoingId, this.outWindow
};
this.WriteFrame(0, 0, 0x13, flow);
Fx.DebugPrint(true, 0, "flow", flow, "next-in-id", "in-window", "next-out", "out-window", "handle", "dc", "credit");
}
}
Link link = this.links[(uint)fields[0]];
Fx.AssertAndThrow(ErrorCode.ClientLinkNotFound, link != null);
((Receiver)link).OnTransfer(fields, payload);
break;
}
case 0x15ul: // disposition
{
Fx.DebugPrint(false, channel, "disposition", fields, "role", "first", "last");
bool role = (bool)fields[0];
uint first = (uint)fields[1];
uint last = fields[2] == null ? first : (uint)fields[2];
for (int i = 0; i < this.links.Length; i++)
{
Link link = this.links[i];
if (link != null && role != link.Role)
{
link.OnDisposition(first, last, fields[4] as DescribedValue);
}
}
break;
}
case 0x16ul: // dettach
{
Fx.DebugPrint(false, channel, "detach", fields, "handle");
Link link = this.links[(uint)fields[0]];
Fx.AssertAndThrow(ErrorCode.ClientLinkNotFound, link != null);
link.State |= DetachReceived;
if ((link.State & DetachSent) == 0)
{
this.CloseLink(link);
this.RaiseErrorEvent(link, GetError(fields, 2));
}
break;
}
case 0x17ul: // end
Fx.DebugPrint(false, channel, "end", null);
this.state |= EndReceived;
if ((this.state & EndSent) == 0)
{
this.WriteFrame(0, 0, 0x17ul, new List());
Fx.DebugPrint(true, channel, "end", null);
this.ClearLinks();
}
break;
case 0x18ul: // close
Fx.DebugPrint(false, channel, "close", null);
this.state |= CloseReceived;
if ((this.state & CloseSent) == 0)
{
this.Close();
this.RaiseErrorEvent(null, GetError(fields, 0));
}
break;
default:
Fx.AssertAndThrow(ErrorCode.ClientInvalidCodeOnFrame, false);
break;
}
}