mirror of
https://github.com/soypat/lneto.git
synced 2026-09-05 06:19:05 +00:00
rephrase tcp.Value methods; add Ring.FreeLimited; work on TxQueue
This commit is contained in:
+13
-7
@@ -23,8 +23,19 @@ type Ring struct {
|
|||||||
End int
|
End int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SizeLimited returns the amount of bytes that can be written up to the
|
||||||
|
// argument offset limitOffset. See [Ring.WriteLimited]
|
||||||
|
func (r *Ring) FreeLimited(limitOffset int) (free int) {
|
||||||
|
if limitOffset > r.End {
|
||||||
|
free = limitOffset - r.End
|
||||||
|
} else {
|
||||||
|
free = len(r.Buf) - r.End + limitOffset
|
||||||
|
}
|
||||||
|
return free
|
||||||
|
}
|
||||||
|
|
||||||
// WriteLimited performs a write that does not write over the ring buffer's
|
// WriteLimited performs a write that does not write over the ring buffer's
|
||||||
// limitOffset index, which points to a position to r.Buf.
|
// limitOffset index, which points to a position to r.Buf. Up to [Ring.FreeLimited] bytes can be written.
|
||||||
func (r *Ring) WriteLimited(b []byte, limitOffset int) (int, error) {
|
func (r *Ring) WriteLimited(b []byte, limitOffset int) (int, error) {
|
||||||
if limitOffset > len(r.Buf) {
|
if limitOffset > len(r.Buf) {
|
||||||
panic("bad limit offset")
|
panic("bad limit offset")
|
||||||
@@ -32,12 +43,7 @@ func (r *Ring) WriteLimited(b []byte, limitOffset int) (int, error) {
|
|||||||
if len(b) > len(r.Buf) {
|
if len(b) > len(r.Buf) {
|
||||||
return 0, io.ErrShortBuffer
|
return 0, io.ErrShortBuffer
|
||||||
}
|
}
|
||||||
var limit int
|
limit := r.FreeLimited(limitOffset)
|
||||||
if limitOffset > r.End {
|
|
||||||
limit = limitOffset - r.End
|
|
||||||
} else {
|
|
||||||
limit = len(r.Buf) - r.End + limitOffset
|
|
||||||
}
|
|
||||||
if len(b) > limit {
|
if len(b) > limit {
|
||||||
return 0, errRingBufferFull
|
return 0, errRingBufferFull
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-6
@@ -352,7 +352,7 @@ func (tcb *ControlBlock) validateOutgoingSegment(seg Segment) (err error) {
|
|||||||
seglast := seg.Last()
|
seglast := seg.Last()
|
||||||
// Extra check for when send Window is zero and no data is being sent.
|
// Extra check for when send Window is zero and no data is being sent.
|
||||||
zeroWindowOK := tcb.snd.WND == 0 && seg.DATALEN == 0 && seg.SEQ == tcb.snd.NXT
|
zeroWindowOK := tcb.snd.WND == 0 && seg.DATALEN == 0 && seg.SEQ == tcb.snd.NXT
|
||||||
outOfWindow := checkSeq && !InWindow(seg.SEQ, tcb.snd.NXT, tcb.snd.WND) &&
|
outOfWindow := checkSeq && !seg.SEQ.InWindow(tcb.snd.NXT, tcb.snd.WND) &&
|
||||||
!zeroWindowOK
|
!zeroWindowOK
|
||||||
switch {
|
switch {
|
||||||
case tcb.state == StateClosed:
|
case tcb.state == StateClosed:
|
||||||
@@ -375,7 +375,7 @@ func (tcb *ControlBlock) validateOutgoingSegment(seg Segment) (err error) {
|
|||||||
case checkSeq && tcb.snd.WND == 0 && seg.DATALEN > 0 && seg.SEQ == tcb.snd.NXT:
|
case checkSeq && tcb.snd.WND == 0 && seg.DATALEN > 0 && seg.SEQ == tcb.snd.NXT:
|
||||||
err = errZeroWindow
|
err = errZeroWindow
|
||||||
|
|
||||||
case checkSeq && !InWindow(seglast, tcb.snd.NXT, tcb.snd.WND) && !zeroWindowOK:
|
case checkSeq && !seglast.InWindow(tcb.snd.NXT, tcb.snd.WND) && !zeroWindowOK:
|
||||||
err = errLastNotInWindow
|
err = errLastNotInWindow
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
@@ -388,8 +388,8 @@ func (tcb *ControlBlock) validateIncomingSegment(seg Segment) (err error) {
|
|||||||
checkSEQ := !flags.HasAny(FlagSYN)
|
checkSEQ := !flags.HasAny(FlagSYN)
|
||||||
established := tcb.state == StateEstablished
|
established := tcb.state == StateEstablished
|
||||||
preestablished := tcb.state.IsPreestablished()
|
preestablished := tcb.state.IsPreestablished()
|
||||||
acksOld := hasAck && !LessThan(tcb.snd.UNA, seg.ACK)
|
acksOld := hasAck && !tcb.snd.UNA.LessThan(seg.ACK)
|
||||||
acksUnsentData := hasAck && !LessThanEq(seg.ACK, tcb.snd.NXT)
|
acksUnsentData := hasAck && !seg.ACK.LessThanEq(tcb.snd.NXT)
|
||||||
ctlOrDataSegment := established && (seg.DATALEN > 0 || flags.HasAny(FlagFIN|FlagRST))
|
ctlOrDataSegment := established && (seg.DATALEN > 0 || flags.HasAny(FlagFIN|FlagRST))
|
||||||
zeroWindowOK := tcb.rcv.WND == 0 && seg.DATALEN == 0 && seg.SEQ == tcb.rcv.NXT
|
zeroWindowOK := tcb.rcv.WND == 0 && seg.DATALEN == 0 && seg.SEQ == tcb.rcv.NXT
|
||||||
// See section 3.4 of RFC 9293 for more on these checks.
|
// See section 3.4 of RFC 9293 for more on these checks.
|
||||||
@@ -402,10 +402,10 @@ func (tcb *ControlBlock) validateIncomingSegment(seg Segment) (err error) {
|
|||||||
case checkSEQ && tcb.rcv.WND == 0 && seg.DATALEN > 0 && seg.SEQ == tcb.rcv.NXT:
|
case checkSEQ && tcb.rcv.WND == 0 && seg.DATALEN > 0 && seg.SEQ == tcb.rcv.NXT:
|
||||||
err = errZeroWindow
|
err = errZeroWindow
|
||||||
|
|
||||||
case checkSEQ && !InWindow(seg.SEQ, tcb.rcv.NXT, tcb.rcv.WND) && !zeroWindowOK:
|
case checkSEQ && !seg.SEQ.InWindow(tcb.rcv.NXT, tcb.rcv.WND) && !zeroWindowOK:
|
||||||
err = errSeqNotInWindow
|
err = errSeqNotInWindow
|
||||||
|
|
||||||
case checkSEQ && !InWindow(seg.Last(), tcb.rcv.NXT, tcb.rcv.WND) && !zeroWindowOK:
|
case checkSEQ && !seg.Last().InWindow(tcb.rcv.NXT, tcb.rcv.WND) && !zeroWindowOK:
|
||||||
err = errLastNotInWindow
|
err = errLastNotInWindow
|
||||||
|
|
||||||
case checkSEQ && seg.SEQ != tcb.rcv.NXT:
|
case checkSEQ && seg.SEQ != tcb.rcv.NXT:
|
||||||
|
|||||||
+69
-20
@@ -23,9 +23,9 @@ type ringTx struct {
|
|||||||
rawbuf []byte
|
rawbuf []byte
|
||||||
// packets contains
|
// packets contains
|
||||||
packets []ringidx
|
packets []ringidx
|
||||||
// firstPkt is the index of the oldest packet in the packets field.
|
// _firstPkt is the index of the oldest packet in the packets field.
|
||||||
firstPkt int
|
_firstPkt int
|
||||||
lastPkt int
|
_lastPkt int
|
||||||
// unsentOff is the offset of start of unsent data into rawbuf.
|
// unsentOff is the offset of start of unsent data into rawbuf.
|
||||||
unsentoff int
|
unsentoff int
|
||||||
// unsentend is the offset of end of unsent data in rawbuf.
|
// unsentend is the offset of end of unsent data in rawbuf.
|
||||||
@@ -58,21 +58,27 @@ func (tx *ringTx) BufferedSent() int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Write writes data to the underlying unsent data ring buffer.
|
// Write writes data to the underlying unsent data ring buffer.
|
||||||
func (tx *ringTx) Write(b []byte) (int, error) {
|
func (tx *ringTx) Write(b []byte) (n int, err error) {
|
||||||
first := tx.packets[tx.firstPkt]
|
first := tx.packets[tx._firstPkt]
|
||||||
r := tx.unsentRing()
|
r := tx.unsentRing()
|
||||||
if first.off < 0 {
|
if first.off < 0 {
|
||||||
// No packets in queue case.
|
// No packets in queue case.
|
||||||
return r.Write(b)
|
n, err = r.Write(b)
|
||||||
|
} else {
|
||||||
|
n, err = r.WriteLimited(b, first.off)
|
||||||
}
|
}
|
||||||
return r.WriteLimited(b, first.off)
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
tx.unsentend = tx.addOff(tx.unsentend, n)
|
||||||
|
return n, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// MakePacket reads from the unsent data ring buffer and generates a new packet segment.
|
// MakePacket reads from the unsent data ring buffer and generates a new packet segment.
|
||||||
// It fails if the sent packet queue is full.
|
// It fails if the sent packet queue is full.
|
||||||
func (tx *ringTx) MakePacket(b []byte) (int, error) {
|
func (tx *ringTx) MakePacket(b []byte) (int, error) {
|
||||||
nxtpkt := (tx.lastPkt + 1) % len(tx.packets)
|
nxtpkt := (tx._lastPkt + 1) % len(tx.packets)
|
||||||
if tx.firstPkt == nxtpkt {
|
if tx._firstPkt == nxtpkt {
|
||||||
return 0, errors.New("packet queue full")
|
return 0, errors.New("packet queue full")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,20 +88,20 @@ func (tx *ringTx) MakePacket(b []byte) (int, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return n, err
|
return n, err
|
||||||
}
|
}
|
||||||
last := &tx.packets[tx.lastPkt]
|
last := &tx.packets[tx._lastPkt]
|
||||||
rlast := tx.packetRing(tx.lastPkt)
|
rlast := tx.packetRing(tx._lastPkt)
|
||||||
tx.packets[nxtpkt].off = start
|
tx.packets[nxtpkt].off = start
|
||||||
tx.packets[nxtpkt].end = r.Off
|
tx.packets[nxtpkt].end = tx.addOff(start, n)
|
||||||
tx.packets[nxtpkt].seq = last.seq + Value(rlast.Buffered())
|
tx.packets[nxtpkt].seq = last.seq + Value(rlast.Buffered())
|
||||||
tx.lastPkt = nxtpkt
|
tx._lastPkt = nxtpkt
|
||||||
tx.unsentoff = r.Off
|
tx.unsentoff = tx.addOff(tx.unsentoff, n)
|
||||||
return n, nil
|
return n, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsQueueFull returns true if the sent packet queue is full in which
|
// IsQueueFull returns true if the sent packet queue is full in which
|
||||||
// case a call to ReadPacket is guaranteed to fail.
|
// case a call to ReadPacket is guaranteed to fail.
|
||||||
func (tx *ringTx) IsQueueFull() bool {
|
func (tx *ringTx) IsQueueFull() bool {
|
||||||
return tx.firstPkt == (tx.lastPkt+1)%len(tx.packets)
|
return tx._firstPkt == (tx._lastPkt+1)%len(tx.packets)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tx *ringTx) packetRing(i int) internal.Ring {
|
func (tx *ringTx) packetRing(i int) internal.Ring {
|
||||||
@@ -108,16 +114,16 @@ func (tx *ringTx) packetRing(i int) internal.Ring {
|
|||||||
|
|
||||||
// RecvSegment processes an incoming segment and updates the sent packet queue
|
// RecvSegment processes an incoming segment and updates the sent packet queue
|
||||||
func (tx *ringTx) RecvACK(ack Value) error {
|
func (tx *ringTx) RecvACK(ack Value) error {
|
||||||
i := tx.firstPkt
|
i := tx._firstPkt
|
||||||
for {
|
for {
|
||||||
pkt := &tx.packets[i]
|
pkt := &tx.packets[i]
|
||||||
if ack >= pkt.seq {
|
if ack >= pkt.seq {
|
||||||
// Packet was received by remote. Mark it as acked.
|
// Packet was received by remote. Mark it as acked.
|
||||||
pkt.off = -1
|
pkt.off = -1
|
||||||
tx.firstPkt++
|
tx._firstPkt++
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if i == tx.lastPkt {
|
if i == tx._lastPkt {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
i = (i + 1) % len(tx.packets)
|
i = (i + 1) % len(tx.packets)
|
||||||
@@ -129,15 +135,58 @@ func (tx *ringTx) unsentRing() internal.Ring {
|
|||||||
return tx.ring(tx.unsentoff, tx.unsentend)
|
return tx.ring(tx.unsentoff, tx.unsentend)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (tx *ringTx) freeRing() (internal.Ring, int) {
|
||||||
|
return tx.ring(tx.unsentoff, tx.unsentend), 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tx *ringTx) a() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func (tx *ringTx) sentRing() internal.Ring {
|
func (tx *ringTx) sentRing() internal.Ring {
|
||||||
first := tx.packets[tx.firstPkt]
|
first := tx.packets[tx._firstPkt]
|
||||||
if first.off < 0 {
|
if first.off < 0 {
|
||||||
return tx.ring(0, 0)
|
return tx.ring(0, 0)
|
||||||
}
|
}
|
||||||
last := tx.packets[tx.lastPkt]
|
last := tx.packets[tx._lastPkt]
|
||||||
return tx.ring(first.off, last.end)
|
return tx.ring(first.off, last.end)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tx *ringTx) ring(off, end int) internal.Ring {
|
func (tx *ringTx) ring(off, end int) internal.Ring {
|
||||||
return internal.Ring{Buf: tx.rawbuf, Off: off, End: end}
|
return internal.Ring{Buf: tx.rawbuf, Off: off, End: end}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// addOff adds two integers together and wraps the value around the ring's buffer size.
|
||||||
|
func (tx *ringTx) addOff(a, b int) int {
|
||||||
|
off := a + b
|
||||||
|
if off >= len(tx.rawbuf) {
|
||||||
|
off -= len(tx.rawbuf)
|
||||||
|
}
|
||||||
|
return off
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tx *ringTx) firstPkt() int {
|
||||||
|
seq := tx.packets[0].seq
|
||||||
|
idx := -1
|
||||||
|
for i := 0; i < len(tx.packets); i++ {
|
||||||
|
pkt := &tx.packets[i]
|
||||||
|
if (pkt.end != 0 || pkt.off != 0) && seq.LessThanEq(pkt.seq) {
|
||||||
|
seq = pkt.seq
|
||||||
|
idx = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return idx
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tx *ringTx) lastPkt() int {
|
||||||
|
seq := tx.packets[0].seq
|
||||||
|
idx := -1
|
||||||
|
for i := 0; i < len(tx.packets); i++ {
|
||||||
|
pkt := &tx.packets[i]
|
||||||
|
if (pkt.end != 0 || pkt.off != 0) && pkt.seq.LessThanEq(seq) {
|
||||||
|
seq = pkt.seq
|
||||||
|
idx = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return idx
|
||||||
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ func TestTxQueueWrite(t *testing.T) {
|
|||||||
} else if n != len(buf) {
|
} else if n != len(buf) {
|
||||||
t.Fatalf("want %d written, got %d", len(buf), n)
|
t.Fatalf("want %d written, got %d", len(buf), n)
|
||||||
}
|
}
|
||||||
|
|
||||||
n, err = rtx.MakePacket(data[:])
|
n, err = rtx.MakePacket(data[:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("making packet %d: %s", i, err)
|
t.Fatalf("making packet %d: %s", i, err)
|
||||||
|
|||||||
+6
-6
@@ -24,24 +24,24 @@ type Value uint32
|
|||||||
type Size uint32
|
type Size uint32
|
||||||
|
|
||||||
// LessThan checks if v is before w (modulo 32) i.e., v < w.
|
// LessThan checks if v is before w (modulo 32) i.e., v < w.
|
||||||
func LessThan(v, w Value) bool {
|
func (v Value) LessThan(w Value) bool {
|
||||||
return int32(v-w) < 0
|
return int32(v-w) < 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// LessThanEq returns true if v==w or v is before (modulo 32) i.e., v < w.
|
// LessThanEq returns true if v==w or v is before (modulo 32) i.e., v < w.
|
||||||
func LessThanEq(v, w Value) bool {
|
func (v Value) LessThanEq(w Value) bool {
|
||||||
return v == w || LessThan(v, w)
|
return v == w || v.LessThan(w)
|
||||||
}
|
}
|
||||||
|
|
||||||
// InRange checks if v is in the range [a,b) (modulo 32), i.e., a <= v < b.
|
// InRange checks if v is in the range [a,b) (modulo 32), i.e., a <= v < b.
|
||||||
func InRange(v, a, b Value) bool {
|
func (v Value) InRange(a, b Value) bool {
|
||||||
return v-a < b-a
|
return v-a < b-a
|
||||||
}
|
}
|
||||||
|
|
||||||
// InWindow checks if v is in the window that starts at 'first' and spans 'size'
|
// InWindow checks if v is in the window that starts at 'first' and spans 'size'
|
||||||
// sequence numbers (modulo 32).
|
// sequence numbers (modulo 32).
|
||||||
func InWindow(v, first Value, size Size) bool {
|
func (v Value) InWindow(first Value, size Size) bool {
|
||||||
return InRange(v, first, Add(first, size))
|
return v.InRange(first, Add(first, size))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add calculates the sequence number following the [v, v+s) window.
|
// Add calculates the sequence number following the [v, v+s) window.
|
||||||
|
|||||||
Reference in New Issue
Block a user