Skip to content

Commit

Permalink
add ring
Browse files Browse the repository at this point in the history
  • Loading branch information
soypat committed Nov 18, 2023
1 parent 0d337c9 commit 87fcde4
Show file tree
Hide file tree
Showing 2 changed files with 152 additions and 7 deletions.
106 changes: 102 additions & 4 deletions stack/socket_tcp.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package stack

import (
"errors"
"io"
"net/netip"
"time"

Expand All @@ -11,19 +13,31 @@ type tcp struct {
stack *PortStack
scb seqs.ControlBlock
localPort uint16
iss seqs.Value
wnd seqs.Size
lastTx time.Time
lastRx time.Time
// Remote fields discovered during an active open.
remote netip.AddrPort
remoteMAC [6]byte
tx ring
}

func (t *tcp) State() seqs.State {
return t.scb.State()
}

func (t *tcp) Send(b []byte) error {
if t.tx.buf == nil {
t.tx = ring{
buf: make([]byte, 2048),
}
}
_, err := t.tx.Write(b)
if err != nil {
return err
}
return nil
}

// DialTCP opens an active TCP connection to the given remote address.
func DialTCP(stack *PortStack, localPort uint16, remoteMAC [6]byte, remote netip.AddrPort, iss seqs.Value, window seqs.Size) (*tcp, error) {
t := tcp{
Expand Down Expand Up @@ -147,8 +161,6 @@ func (t *tcp) mustSendSyn() bool {

func (t *tcp) close() {
t.remote = netip.AddrPort{}
t.wnd = 0
t.iss = 0
t.scb = seqs.ControlBlock{}
t.lastTx = time.Time{}
t.lastRx = time.Time{}
Expand All @@ -162,3 +174,89 @@ func (t *tcp) synsentSegment() seqs.Segment {
WND: t.scb.RecvWindow(),
}
}

type ring struct {
buf []byte
off int
end int
}

func (r *ring) Write(b []byte) (int, error) {
free := r.Free()
if len(b) > free {
return 0, errors.New("no more space")
}
midFree := r.midFree()
if midFree > 0 {
n := copy(r.buf[r.end:], b)
r.end += n
return n, nil
}

n := copy(r.buf[r.end:], b)
r.end = n
if n < len(b) {
n2 := copy(r.buf, b[n:])
r.end = n2
n += n2
}
return n, nil
}

func (r *ring) Read(b []byte) (int, error) {
if r.Buffered() == 0 {
return 0, io.EOF
}

if r.end >= r.off {
// start off end len(buf)
// | sfree | used | efree |
n := copy(b, r.buf[r.off:])
r.off += n
r.onReadEnd()
return n, nil
}
// start end off len(buf)
// | used | mfree | used |
n := copy(b, r.buf[r.off:])
r.off += n
if n < len(b) {
n2 := copy(b[n:], r.buf)
r.off = n2
n += n2
}
r.onReadEnd()
return n, nil
}

func (r *ring) Buffered() int {
return len(r.buf) - r.Free()
}

func (r *ring) Free() int {
if r.end >= r.off {
// start off end len(buf)
// | sfree | used | efree |
startFree := r.off
endFree := len(r.buf) - r.end
return startFree + endFree
}
// start end off len(buf)
// | used | mfree | used |
return r.off - r.end
}

func (r *ring) midFree() int {
if r.end >= r.off {
return 0
}
return r.off - r.end
}

func (r *ring) onReadEnd() {
if r.off == r.end {
// We read everything, reset.
r.off = 0
r.end = 0
}
}
53 changes: 50 additions & 3 deletions stack/stack_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,9 @@ func TestStackEstablish(t *testing.T) {
if numBytesSent < expectedData {
t.Error("too little data exchanged", numBytesSent, " want>=", expectedData)
}
if txDone >= 4 {
if txDone >= 3 {
t.Error("too many exchanges for a 3 way handshake")
}
if txDone <= 1 {
} else if txDone <= 1 {
t.Error("too few exchanges for a 3 way handshake")
}
if clientTCP.State() != seqs.StateEstablished {
Expand All @@ -72,6 +71,54 @@ func TestStackEstablish(t *testing.T) {
}
}

func TestStackSendReceive(t *testing.T) {
const (
clientISS = 100
clientWND = 1000

serverISS = 300
serverWND = 1300
)

var (
macClient = [6]byte{0x01, 0x00, 0x00, 0x00, 0x00, 0x00}
ipClient = netip.MustParseAddrPort("192.168.1.1:1025")
macServer = [6]byte{0x02, 0x00, 0x00, 0x00, 0x00, 0x00}
ipServer = netip.MustParseAddrPort("192.168.1.2:80")
)

Client := stack.NewPortStack(stack.PortStackConfig{
MAC: macClient[:],
IP: ipClient.Addr(),
MaxOpenPortsTCP: 1,
})
clientTCP, err := stack.DialTCP(Client, ipClient.Port(), macServer, ipServer, clientISS, clientWND)
if err != nil {
t.Fatal(err)
}
err = Client.FlagTCPPending(ipClient.Port())
if err != nil {
t.Fatal(err)
}

Server := stack.NewPortStack(stack.PortStackConfig{
MAC: macServer[:],
IP: ipServer.Addr(),
MaxOpenPortsTCP: 1,
})
serverTCP, err := stack.ListenTCP(Server, ipServer.Port(), serverISS, serverWND)
if err != nil {
t.Fatal(err)
}

// 3 way handshake needs2 exchanges to complete.
txStacks(t, 2, Client, Server)
if clientTCP.State() != seqs.StateEstablished || serverTCP.State() != seqs.StateEstablished {
t.Fatal("not established")
}

}

func isDroppedPacket(err error) bool {
return err != nil && (errors.Is(err, stack.ErrDroppedPacket) || strings.HasPrefix(err.Error(), "drop"))
}
Expand Down

0 comments on commit 87fcde4

Please sign in to comment.