private void InterceptFlowFrame(Flow flow) { if (!State.CanReceiveFrames()) throw new AmqpException(ErrorCode.IllegalState, $"Received Flow frame but session state is {State.ToString()}."); if (State == SessionStateEnum.DISCARDING) return; nextIncomingId = flow.NextOutgoingId; // their next id remoteOutgoingWindow = flow.OutgoingWindow; // their advertised outgoing window // recalculate the remote session's advertised incoming-window based on the difference // between the advertized next-incoming-id and our actual next-outgoing-id // our outgoing-window is synchronized with the remote-incoming-window if (flow.NextIncomingId.HasValue) outgoingWindow = remoteIncomingWindow = flow.IncomingWindow + flow.NextIncomingId.Value - (uint)nextOutgoingId; else outgoingWindow = remoteIncomingWindow = flow.IncomingWindow + InitialOutgoingId - (uint)nextOutgoingId; if (outgoingWindow > 0) { // TODO: flush queued outgoing transfers } if (flow.Handle != null) { var link = GetRemoteLink(flow.Handle.Value); if (link.State == LinkStateEnum.DESTROYED) throw new AmqpException(ErrorCode.ErrantLink, "If any input (other than a detach) related to the endpoint either via the input handle or delivery-ids be received, the session MUST be terminated with an errant-link session-error."); link.HandleLinkFrame(flow); } else if (flow.Echo) { SendFlow(new Flow() { Echo = false, }); } }
private void HandleFlowFrame(Flow flow) { if (State != LinkStateEnum.ATTACHED && State != LinkStateEnum.DETACH_SENT && State != LinkStateEnum.DESTROYED) throw new AmqpException(ErrorCode.IllegalState, $"Received Flow frame but link state is {State.ToString()}."); if (State == LinkStateEnum.DESTROYED) throw new AmqpException(ErrorCode.ErrantLink, $"Received Flow frame but link state is {State.ToString()}."); // TODO end session if (State == LinkStateEnum.DETACH_SENT) return; // ignore if (IsReceiverLink) { // flow control from sender if (flow.DeliveryCount.HasValue) DeliveryCount = flow.DeliveryCount.Value; // TODO: ignoring Available field for now //if (flow.Available.HasValue) // available = flow.Available.Value; // TODO: respond to new flow control } if (IsSenderLink) { // flow control from receiver if (flow.LinkCredit.HasValue) LinkCredit = flow.LinkCredit.Value; drainFlag = flow.Drain ?? false; // TODO respond to new flow control var receivedFlowCallback = this.ReceivedFlow; if (receivedFlowCallback != null) receivedFlowCallback(this, EventArgs.Empty); } if (flow.Echo) { SendFlow(drain: false, echo: false); } }
public void SendFlow(Flow flow) { incomingWindow = DefaultWindowSize; // reset window flow.NextIncomingId = nextIncomingId; flow.NextOutgoingId = nextOutgoingId; flow.IncomingWindow = incomingWindow; flow.OutgoingWindow = outgoingWindow; SendFrame(flow); }