mirror of
https://github.com/soypat/lneto.git
synced 2026-09-11 09:09:30 +00:00
document everything
This commit is contained in:
@@ -34,6 +34,14 @@ func TestBasicStack(t *testing.T) {
|
|||||||
exchangeAndExpectStates(tcp.StateEstablished, tcp.StateEstablished) // Client sends ACK, establishing connection in full.
|
exchangeAndExpectStates(tcp.StateEstablished, tcp.StateEstablished) // Client sends ACK, establishing connection in full.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBasicStack2(t *testing.T) {
|
||||||
|
rng := rand.New(rand.NewSource(1))
|
||||||
|
var sbCl, sbSv StackBasic
|
||||||
|
var connCl, connSv TCPConn
|
||||||
|
setupClientServerEstablished(t, rng, &sbCl, &sbSv, &connCl, &connSv)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func expectExchange(t *testing.T, from, to *StackBasic, buf []byte) {
|
func expectExchange(t *testing.T, from, to *StackBasic, buf []byte) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
n, err := from.Handle(buf)
|
n, err := from.Handle(buf)
|
||||||
@@ -49,6 +57,34 @@ func expectExchange(t *testing.T, from, to *StackBasic, buf []byte) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func setupClientServerEstablished(t *testing.T, rng *rand.Rand, client, server *StackBasic, connClient, connServer *TCPConn) {
|
||||||
|
t.Helper()
|
||||||
|
setupClientServer(t, rng, client, server, connClient, connServer)
|
||||||
|
var buf [2048]byte
|
||||||
|
nextToSend := client
|
||||||
|
nextToRecv := server
|
||||||
|
exchangeAndExpectStates := func(clState, svState tcp.State) {
|
||||||
|
t.Helper()
|
||||||
|
expectExchange(t, nextToSend, nextToRecv, buf[:])
|
||||||
|
gotCl := connClient.State()
|
||||||
|
gotSv := connServer.State()
|
||||||
|
if gotCl != clState {
|
||||||
|
t.Errorf("want client state %s, got %s", clState, gotCl)
|
||||||
|
}
|
||||||
|
if gotSv != svState {
|
||||||
|
t.Errorf("want server state %s, got %s", svState, gotSv)
|
||||||
|
}
|
||||||
|
nextToSend, nextToRecv = nextToRecv, nextToSend
|
||||||
|
}
|
||||||
|
exchangeAndExpectStates(tcp.StateSynSent, tcp.StateSynRcvd) // Client sends over first SYN and server receives it.
|
||||||
|
exchangeAndExpectStates(tcp.StateEstablished, tcp.StateSynRcvd) // server sends back SYNACK, establishing connection on client side.
|
||||||
|
exchangeAndExpectStates(tcp.StateEstablished, tcp.StateEstablished) // Client sends ACK, establishing connection in full.
|
||||||
|
if t.Failed() {
|
||||||
|
t.Error("establishment failed")
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func setupClientServer(t *testing.T, rng *rand.Rand, client, server *StackBasic, connClient, connServer *TCPConn) {
|
func setupClientServer(t *testing.T, rng *rand.Rand, client, server *StackBasic, connClient, connServer *TCPConn) {
|
||||||
bufsize := 2048
|
bufsize := 2048
|
||||||
// Ensure buffer sizes are OK with reused buffers.
|
// Ensure buffer sizes are OK with reused buffers.
|
||||||
|
|||||||
+1
-1
@@ -239,7 +239,7 @@ func (flags Flags) AppendFormat(b []byte) []byte {
|
|||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
// State enumerates states a TCP connection progresses through during its lifetime.
|
// State enumerates states a TCP connection progresses through during its lifetime as per RFC9293.
|
||||||
type State uint8
|
type State uint8
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|||||||
+19
-3
@@ -39,8 +39,10 @@ func (h *Handler) SetLoggers(handler, scb *slog.Logger) {
|
|||||||
h.scb.logger.log = scb
|
h.scb.logger.log = scb
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// State returns the state of the TCP state machine as per RFC9293. See [State].
|
||||||
func (h *Handler) State() State { return h.scb.State() }
|
func (h *Handler) State() State { return h.scb.State() }
|
||||||
|
|
||||||
|
// SetBuffers sets the internal buffers used to receive and transmit bytes asynchronously via [Handler.Write] and [Handler.Read] calls.
|
||||||
func (h *Handler) SetBuffers(txbuf, rxbuf []byte, packets int) error {
|
func (h *Handler) SetBuffers(txbuf, rxbuf []byte, packets int) error {
|
||||||
if !h.scb.State().IsClosed() {
|
if !h.scb.State().IsClosed() {
|
||||||
return errors.New("tcp.Handler must be closed before setting buffers")
|
return errors.New("tcp.Handler must be closed before setting buffers")
|
||||||
@@ -67,6 +69,8 @@ func (h *Handler) RemotePort() uint16 {
|
|||||||
return h.remotePort
|
return h.remotePort
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OpenActive opens an "active" TCP connection to a known remote port. The caller holds knowledge of the IP address.
|
||||||
|
// OpenActive is used by TCP Clients to initiate a connection.
|
||||||
func (h *Handler) OpenActive(localPort, remotePort uint16, iss Value) error {
|
func (h *Handler) OpenActive(localPort, remotePort uint16, iss Value) error {
|
||||||
if h.bufRx.Size() < minBufferSize || h.bufTx.Size() < minBufferSize {
|
if h.bufRx.Size() < minBufferSize || h.bufTx.Size() < minBufferSize {
|
||||||
return errBufferTooSmall
|
return errBufferTooSmall
|
||||||
@@ -80,7 +84,8 @@ func (h *Handler) OpenActive(localPort, remotePort uint16, iss Value) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// OpenListen prepares a passive connection.
|
// OpenListen prepares a passive TCP connection where the Handler acts as a server.
|
||||||
|
// OpenListen is used by TCP Servers to begin listening for remote connections.
|
||||||
func (h *Handler) OpenListen(localPort uint16, iss Value) error {
|
func (h *Handler) OpenListen(localPort uint16, iss Value) error {
|
||||||
if h.bufRx.Size() < minBufferSize || h.bufTx.Size() < minBufferSize {
|
if h.bufRx.Size() < minBufferSize || h.bufTx.Size() < minBufferSize {
|
||||||
return errBufferTooSmall
|
return errBufferTooSmall
|
||||||
@@ -110,11 +115,13 @@ func (h *Handler) reset(localPort, remotePort uint16, iss Value) {
|
|||||||
h.bufRx.Reset()
|
h.bufRx.Reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) Recv(b []byte) error {
|
// Recv receives an incoming TCP packet frame with the first byte being the first octet of the TCP frame.
|
||||||
|
// The [Handler]'s internal state is updated if the packet is admitted successfully.
|
||||||
|
func (h *Handler) Recv(incomingPacket []byte) error {
|
||||||
if h.isClosed() {
|
if h.isClosed() {
|
||||||
return net.ErrClosed
|
return net.ErrClosed
|
||||||
}
|
}
|
||||||
tfrm, err := NewFrame(b)
|
tfrm, err := NewFrame(incomingPacket)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -170,6 +177,9 @@ func (h *Handler) Recv(b []byte) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Send writes TCP frame to be sent over the network to the remote peer to `b`.
|
||||||
|
// It does no IP interfacing or CRC calculation of packet, which is left to the caller to perform.
|
||||||
|
// The returned integer is the length written to the argument buffer.
|
||||||
func (h *Handler) Send(b []byte) (int, error) {
|
func (h *Handler) Send(b []byte) (int, error) {
|
||||||
h.trace("tcp.Handler:start", slog.Uint64("port", uint64(h.localPort)))
|
h.trace("tcp.Handler:start", slog.Uint64("port", uint64(h.localPort)))
|
||||||
if h.isClosed() && !h.AwaitingSynSend() {
|
if h.isClosed() && !h.AwaitingSynSend() {
|
||||||
@@ -214,10 +224,13 @@ func (h *Handler) Send(b []byte) (int, error) {
|
|||||||
return sizeHeaderTCP + int(segment.DATALEN), nil
|
return sizeHeaderTCP + int(segment.DATALEN), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Free returns the amount of space free in the transmit buffer. A call to [Handler.Write] with a larger buffer will fail.
|
||||||
func (h *Handler) Free() int {
|
func (h *Handler) Free() int {
|
||||||
return h.bufTx.Free()
|
return h.bufTx.Free()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Write implements [io.Writer] by copying b to a internal buffer to be sent over the network on the next
|
||||||
|
// [Handler.Send] call that can send data to remote peer. Use [Handler.Free] to know the maximum length the argument slice can be before erroring.
|
||||||
func (h *Handler) Write(b []byte) (int, error) {
|
func (h *Handler) Write(b []byte) (int, error) {
|
||||||
if h.State().IsClosed() { // Reject write call if data cannot be sent.
|
if h.State().IsClosed() { // Reject write call if data cannot be sent.
|
||||||
return 0, net.ErrClosed
|
return 0, net.ErrClosed
|
||||||
@@ -225,6 +238,7 @@ func (h *Handler) Write(b []byte) (int, error) {
|
|||||||
return h.bufTx.Write(b)
|
return h.bufTx.Write(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Read implements [io.Reader] by reading received data from remote peer in internal buffer.
|
||||||
func (h *Handler) Read(b []byte) (int, error) {
|
func (h *Handler) Read(b []byte) (int, error) {
|
||||||
if h.State().IsClosed() { // Reject read call if state is at StateClosed. Note this is less strict than Write call condition.
|
if h.State().IsClosed() { // Reject read call if state is at StateClosed. Note this is less strict than Write call condition.
|
||||||
return 0, net.ErrClosed
|
return 0, net.ErrClosed
|
||||||
@@ -245,10 +259,12 @@ func (h *Handler) AwaitingSynResponse() bool {
|
|||||||
return h.remotePort != 0 && h.scb.State() == StateSynSent
|
return h.remotePort != 0 && h.scb.State() == StateSynSent
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AwaitingSynAck returns true if the Handler is a passive server opened with [Handler.OpenListen] and not yet received a valid SYN remote packet.
|
||||||
func (h *Handler) AwaitingSynAck() bool {
|
func (h *Handler) AwaitingSynAck() bool {
|
||||||
return h.remotePort == 0 && h.scb.State() == StateListen
|
return h.remotePort == 0 && h.scb.State() == StateListen
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AwaitingSynSend returns true if the Handler is an active client opened with [Handler.OpenActive] and not yet sent out the first SYN packet to the remote client.
|
||||||
func (h *Handler) AwaitingSynSend() bool {
|
func (h *Handler) AwaitingSynSend() bool {
|
||||||
return h.remotePort != 0 && h.scb.State() == StateClosed
|
return h.remotePort != 0 && h.scb.State() == StateClosed
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user