Skip to content

Commit

Permalink
add stackListenTCP
Browse files Browse the repository at this point in the history
  • Loading branch information
soypat committed Nov 18, 2023
1 parent d819494 commit ec6e6ae
Show file tree
Hide file tree
Showing 7 changed files with 300 additions and 149 deletions.
37 changes: 32 additions & 5 deletions control.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,9 @@ type ControlBlock struct {
// 1 - old sequence numbers which have been acknowledged
// 2 - sequence numbers allowed for new reception
// 3 - future sequence numbers which are not yet allowed
rcv recvSpace
rstPtr Value // RST pointer. See RFC 3540.
rcv recvSpace
// When FlagRST is set in pending flags rstPtr will contain the sequence number of the RST segment to make it "believable" (See RFC9293)
rstPtr Value
// pending and state are modified by rcv* methods and Close method.
// The pending flags are only updated if the Recv method finishes with no error.
pending Flags
Expand All @@ -78,7 +79,7 @@ type recvSpace struct {
WND Size // receive window defined by local. Permitted number unacked octets in flight.
}

// Segment represents a TCP segment as the sequence number of the first octet and the length of the segment.
// Segment represents an incoming/outgoing TCP segment in the sequence space.
type Segment struct {
SEQ Value // sequence number of first octet of segment. If SYN is set it is the initial sequence number (ISN) and the first data octet is ISN+1.
ACK Value // acknowledgment number. If ACK is set it is sequence number of first octet the sender of the segment is expecting to receive next.
Expand Down Expand Up @@ -112,6 +113,11 @@ func (tcb *ControlBlock) PendingSegment(payloadLen int) (_ Segment, ok bool) {
payloadLen = int(tcb.snd.WND)
}

pending := tcb.pending
if payloadLen > 0 {
pending |= FlagPSH
}

var ack Value
if tcb.pending.HasAny(FlagACK) {
ack = tcb.rcv.NXT
Expand All @@ -126,7 +132,7 @@ func (tcb *ControlBlock) PendingSegment(payloadLen int) (_ Segment, ok bool) {
SEQ: seq,
ACK: ack,
WND: tcb.rcv.WND,
Flags: tcb.pending,
Flags: pending,
DATALEN: Size(payloadLen),
}
return seg, true
Expand Down Expand Up @@ -326,6 +332,25 @@ func (tcb *ControlBlock) validateOutgoingSegment(seg Segment) (err error) {
return err
}

// close sets ControlBlock state to closed and resets all sequence numbers and pending flag.
func (tcb *ControlBlock) close() {
tcb.state = StateClosed
tcb.pending = 0
tcb.resetRcv(0, 0)
tcb.resetSnd(0, 0)
tcb.debuglog += "close tcb\n"
}

// hasIRS checks if the ControlBlock has received a valid initial sequence number (IRS).
func (tcb *ControlBlock) hasIRS() bool {
return tcb.isOpen() && tcb.state != StateSynSent && tcb.state != StateListen
}

// isOpen checks if the ControlBlock is in a state that allows sending and/or receiving data.
func (tcb *ControlBlock) isOpen() bool {
return tcb.state != StateClosed && tcb.state != StateTimeWait
}

// Flags is a TCP flags masked implementation i.e: SYN, FIN, ACK.
type Flags uint16

Expand All @@ -339,8 +364,10 @@ const (
FlagECE // FlagECE - ECN-Echo has a nonce-sum in the SYN/ACK.
FlagCWR // FlagCWR - Congestion Window Reduced.
FlagNS // FlagNS - Nonce Sum flag (see RFC 3540).
)

// The union of SYN and ACK flags is commonly found throughout the specification, so we define a shorthand.
// The union of SYN|FIN|PSH and ACK flags is commonly found throughout the specification, so we define unexported shorthands.
const (
synack = FlagSYN | FlagACK
finack = FlagFIN | FlagACK
pshack = FlagPSH | FlagACK
Expand Down
21 changes: 17 additions & 4 deletions control_user.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ func (tcb *ControlBlock) Open(iss Value, wnd Size, state State) (err error) {
tcb.state = state
tcb.resetRcv(wnd, 0)
tcb.resetSnd(iss, 1)
tcb.pending = 0
if state == StateSynSent {
tcb.pending = FlagSYN
}
Expand Down Expand Up @@ -98,7 +99,7 @@ func (tcb *ControlBlock) Recv(seg Segment) (err error) {
case StateCloseWait:
case StateLastAck:
if seg.Flags.HasAny(FlagACK) {
tcb.state = StateClosed
tcb.close()
}
default:
err = errors.New("rcv: unexpected state " + tcb.state.String())
Expand All @@ -122,8 +123,20 @@ func (tcb *ControlBlock) Recv(seg Segment) (err error) {
return err
}

// RecvNext returns the next sequence number expected to be received.
// RecvNext returns the next sequence number expected to be received from remote.
// This implementation will reject segments that are not the next expected sequence.
func (tcb *ControlBlock) RecvNext() Value {
return tcb.rcv.NXT
// RecvNext returns 0 before StateSynRcvd.
func (tcb *ControlBlock) RecvNext() Value { return tcb.rcv.NXT }

// ISS returns the initial sequence number of the connection that was defined on a call to Open by user.
func (tcb *ControlBlock) ISS() Value { return tcb.snd.ISS }

// MaxOutgoingSegmentSize returns the maximum size of a segment that can be sent by taking into account
// the send window size and the unacked data. Returns 0 before StateSynRcvd.
func (tcb *ControlBlock) MaxOutgoingSegmentSize() Size {
if !tcb.hasIRS() {
return 0 // SYN not yet received.
}
unacked := Sizeof(tcb.snd.UNA, tcb.snd.NXT)
return tcb.snd.WND - unacked - 1 // TODO: is this -1 supposed to be here?
}
Loading

0 comments on commit ec6e6ae

Please sign in to comment.