private List <AckItem> ExtractItems(List <Loop> po1Loop) { var items = new List <AckItem>(); foreach (var po1 in po1Loop) { var pid = po1.Segments.FirstOrDefault(x => x.SegmentId == "PID"); var item = new AckItem(); item.PO101_AssignedIdentification = po1.GetElement(1); item.PO102_QuantityOrdered = po1.GetIntElement(2); item.PO103_UnitOfMeasurement = po1.GetElement(3); item.PO104_UnitPrice = po1.GetDecimalElement(4); item.PO105_BasisOfUnitPriceCode = po1.GetElement(5); item.PO106_ProductIdQualifier = po1.GetElement(6); item.PO107_ProductID = po1.GetElement(7); item.PO108_ProductIdQualifier = po1.GetElement(8); item.PO109_ProductID = po1.GetElement(9); if (pid != null) { item.PID01_ItemDescriptionType = pid.GetElement(1); item.PID05_Description = pid.GetElement(5); } items.Add(item); } return(items); }
/// <summary>Flush</summary> /// <param name="ackOnly">flush remain ack segments</param> public uint Flush(bool ackOnly) { var seg = Segment.Get(32); seg.conv = conv; seg.cmd = CMD_ACK; seg.wnd = WndUnused(); seg.una = rcv_nxt; int writeIndex = (int)reserved; void makeSpace(int space) { if (writeIndex + space > mtu) { output(buffer, writeIndex); writeIndex = (int)reserved; } } void flushBuffer() { if (writeIndex > reserved) { output(buffer, writeIndex); } } // flush acknowledges for (int i = 0; i < ackList.Count; i++) { makeSpace(OVERHEAD); AckItem ack = ackList[i]; if (ack.serialNumber >= rcv_nxt || ackList.Count - 1 == i) { seg.sn = ack.serialNumber; seg.ts = ack.timestamp; writeIndex += seg.Encode(buffer, writeIndex); } } ackList.Clear(); // flush remain ack segments if (ackOnly) { flushBuffer(); return(interval); } uint current = 0; // probe window size (if remote window size equals zero) if (RmtWnd == 0) { current = CurrentMS; if (probe_wait == 0) { probe_wait = PROBE_INIT; ts_probe = current + probe_wait; } else { if (current >= ts_probe) { probe_wait = Math.Max(probe_wait, PROBE_INIT); probe_wait += probe_wait / 2; probe_wait = Math.Min(probe_wait, PROBE_LIMIT); ts_probe = current + probe_wait; probe |= ASK_SEND; } } } else { ts_probe = 0; probe_wait = 0; } // flush window probing commands if ((probe & ASK_SEND) != 0) { seg.cmd = CMD_WASK; makeSpace(OVERHEAD); writeIndex += seg.Encode(buffer, writeIndex); } if ((probe & ASK_TELL) != 0) { seg.cmd = CMD_WINS; makeSpace(OVERHEAD); writeIndex += seg.Encode(buffer, writeIndex); } probe = 0; // calculate window size uint cwnd_ = Math.Min(SendWindowMax, RmtWnd); if (!nocwnd) { cwnd_ = Math.Min(cwnd, cwnd_); } // sliding window, controlled by snd_nxt && sna_una+cwnd int newSegsCount = 0; for (int k = 0; k < sendQueue.Count; k++) { if (snd_nxt >= snd_una + cwnd_) { break; } Segment newseg = sendQueue[k]; newseg.conv = conv; newseg.cmd = CMD_PUSH; newseg.sn = snd_nxt; sendBuffer.Add(newseg); snd_nxt++; newSegsCount++; } sendQueue.RemoveRange(0, newSegsCount); // calculate resent uint resent = (uint)fastresend; if (fastresend <= 0) { resent = 0xffffffff; } // check for retransmissions current = CurrentMS; ulong change = 0; ulong lostSegs = 0; int minrto = (int)interval; for (int k = 0; k < sendBuffer.Count; k++) { Segment segment = sendBuffer[k]; bool needSend = false; if (segment.acked) { continue; } if (segment.xmit == 0) // initial transmit { needSend = true; segment.rto = rx_rto; segment.resendts = current + segment.rto; } else if (segment.fastack >= resent || segment.fastack > 0 && newSegsCount == 0) // fast retransmit { needSend = true; segment.fastack = 0; segment.rto = rx_rto; segment.resendts = current + segment.rto; change++; } else if (current >= segment.resendts) // RTO { needSend = true; if (!noDelay) { segment.rto += rx_rto; } else { segment.rto += rx_rto / 2; } segment.fastack = 0; segment.resendts = current + segment.rto; lostSegs++; } if (needSend) { current = CurrentMS; segment.xmit++; segment.ts = current; segment.wnd = seg.wnd; segment.una = seg.una; int need = OVERHEAD + segment.data.ReadableBytes; makeSpace(need); writeIndex += segment.Encode(buffer, writeIndex); Buffer.BlockCopy(segment.data.RawBuffer, segment.data.ReaderIndex, buffer, writeIndex, segment.data.ReadableBytes); writeIndex += segment.data.ReadableBytes; } // get the nearest rto int _rto = Utils.TimeDiff(segment.resendts, current); if (_rto > 0 && _rto < minrto) { minrto = _rto; } } // flash remain segments flushBuffer(); // cwnd update if (!nocwnd) { CwndUpdate(resent, change, lostSegs); } return((uint)minrto); }