mirror of
https://github.com/soypat/lneto.git
synced 2026-09-02 12:59:04 +00:00
add lock to tcp.Conn; claude Fix ARP handler not responding after DHCP
Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -115,6 +115,9 @@ func run() (err error) {
|
|||||||
fmt.Println("ERR:ENCAPSULATE", err)
|
fmt.Println("ERR:ENCAPSULATE", err)
|
||||||
} else if nwrite > 0 {
|
} else if nwrite > 0 {
|
||||||
frames, err = cap.CaptureEthernet(frames[:0], buf[:nwrite], 0)
|
frames, err = cap.CaptureEthernet(frames[:0], buf[:nwrite], 0)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("ERR capture", err)
|
||||||
|
}
|
||||||
if len(frames) > 0 {
|
if len(frames) > 0 {
|
||||||
fmt.Println("OUT", frames)
|
fmt.Println("OUT", frames)
|
||||||
}
|
}
|
||||||
|
|||||||
+71
-12
@@ -8,6 +8,7 @@ import (
|
|||||||
"net/netip"
|
"net/netip"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/soypat/lneto"
|
"github.com/soypat/lneto"
|
||||||
@@ -27,6 +28,7 @@ var (
|
|||||||
// Note that the complete emulation of [net.TCPConn] at this level of abstraction is yet a non-goal,
|
// Note that the complete emulation of [net.TCPConn] at this level of abstraction is yet a non-goal,
|
||||||
// even though the functionality provided is similar.
|
// even though the functionality provided is similar.
|
||||||
type Conn struct {
|
type Conn struct {
|
||||||
|
mu sync.Mutex
|
||||||
h Handler
|
h Handler
|
||||||
remoteAddr []byte
|
remoteAddr []byte
|
||||||
|
|
||||||
@@ -46,6 +48,8 @@ type ConnConfig struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (conn *Conn) Configure(config ConnConfig) (err error) {
|
func (conn *Conn) Configure(config ConnConfig) (err error) {
|
||||||
|
conn.mu.Lock()
|
||||||
|
defer conn.mu.Unlock()
|
||||||
err = conn.h.SetBuffers(config.TxBuf, config.RxBuf, config.TxPacketQueueSize)
|
err = conn.h.SetBuffers(config.TxBuf, config.RxBuf, config.TxPacketQueueSize)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -55,29 +59,59 @@ func (conn *Conn) Configure(config ConnConfig) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// LocalPort returns the local port on which the socket is listening or connected to.
|
// LocalPort returns the local port on which the socket is listening or connected to.
|
||||||
func (conn *Conn) LocalPort() uint16 { return conn.h.LocalPort() }
|
func (conn *Conn) LocalPort() uint16 {
|
||||||
|
conn.mu.Lock()
|
||||||
|
defer conn.mu.Unlock()
|
||||||
|
return conn.h.LocalPort()
|
||||||
|
}
|
||||||
|
|
||||||
// RemotePort returns the port of the incoming remote connection. Is non-zero if connection is established.
|
// RemotePort returns the port of the incoming remote connection. Is non-zero if connection is established.
|
||||||
func (conn *Conn) RemotePort() uint16 { return conn.h.RemotePort() }
|
func (conn *Conn) RemotePort() uint16 {
|
||||||
|
conn.mu.Lock()
|
||||||
|
defer conn.mu.Unlock()
|
||||||
|
return conn.h.RemotePort()
|
||||||
|
}
|
||||||
|
|
||||||
func (conn *Conn) RemoteAddr() []byte { return conn.remoteAddr }
|
func (conn *Conn) RemoteAddr() []byte {
|
||||||
|
conn.mu.Lock()
|
||||||
|
defer conn.mu.Unlock()
|
||||||
|
return conn.remoteAddr
|
||||||
|
}
|
||||||
|
|
||||||
// State returns the TCP state of the socket.
|
// State returns the TCP state of the socket.
|
||||||
func (conn *Conn) State() State { return conn.h.State() }
|
func (conn *Conn) State() State {
|
||||||
|
conn.mu.Lock()
|
||||||
|
defer conn.mu.Unlock()
|
||||||
|
return conn.h.State()
|
||||||
|
}
|
||||||
|
|
||||||
// BufferedInput returns the number of bytes in the socket's receive(input) buffer
|
// BufferedInput returns the number of bytes in the socket's receive(input) buffer
|
||||||
// and available to read via a [Conn.Read] call.
|
// and available to read via a [Conn.Read] call.
|
||||||
func (conn *Conn) BufferedInput() int { return conn.h.BufferedInput() }
|
func (conn *Conn) BufferedInput() int {
|
||||||
|
conn.mu.Lock()
|
||||||
|
defer conn.mu.Unlock()
|
||||||
|
return conn.h.BufferedInput()
|
||||||
|
}
|
||||||
|
|
||||||
func (conn *Conn) AvailableInput() int { return conn.h.FreeRx() }
|
func (conn *Conn) AvailableInput() int {
|
||||||
|
conn.mu.Lock()
|
||||||
|
defer conn.mu.Unlock()
|
||||||
|
return conn.h.FreeRx()
|
||||||
|
}
|
||||||
|
|
||||||
// AvailableOutput returns amount of bytes available to write to output
|
// AvailableOutput returns amount of bytes available to write to output
|
||||||
// before [Conn.Write] returns an error due to insufficient space to store outgoing data.
|
// before [Conn.Write] returns an error due to insufficient space to store outgoing data.
|
||||||
func (conn *Conn) AvailableOutput() int { return conn.h.AvailableOutput() }
|
func (conn *Conn) AvailableOutput() int {
|
||||||
|
conn.mu.Lock()
|
||||||
|
defer conn.mu.Unlock()
|
||||||
|
return conn.h.AvailableOutput()
|
||||||
|
}
|
||||||
|
|
||||||
// OpenActive opens a connection to a remote peer with a known IP address and port combination.
|
// OpenActive opens a connection to a remote peer with a known IP address and port combination.
|
||||||
// iss is the initial send sequence number which is ideally a random number which is far away from the last sequence number used on a connection to the same host.
|
// iss is the initial send sequence number which is ideally a random number which is far away from the last sequence number used on a connection to the same host.
|
||||||
func (conn *Conn) OpenActive(localPort uint16, remote netip.AddrPort, iss Value) error {
|
func (conn *Conn) OpenActive(localPort uint16, remote netip.AddrPort, iss Value) error {
|
||||||
|
conn.mu.Lock()
|
||||||
|
defer conn.mu.Unlock()
|
||||||
if !remote.IsValid() {
|
if !remote.IsValid() {
|
||||||
return errInvalidIP
|
return errInvalidIP
|
||||||
}
|
}
|
||||||
@@ -100,6 +134,8 @@ func (conn *Conn) OpenActive(localPort uint16, remote netip.AddrPort, iss Value)
|
|||||||
// OpenListen opens a passive connection which listens for the first SYN packet to be received on a local port.
|
// OpenListen opens a passive connection which listens for the first SYN packet to be received on a local port.
|
||||||
// iss is the initial send sequence number which is usually a randomly chosen number.
|
// iss is the initial send sequence number which is usually a randomly chosen number.
|
||||||
func (conn *Conn) OpenListen(localPort uint16, iss Value) error {
|
func (conn *Conn) OpenListen(localPort uint16, iss Value) error {
|
||||||
|
conn.mu.Lock()
|
||||||
|
defer conn.mu.Unlock()
|
||||||
err := conn.h.OpenListen(localPort, iss)
|
err := conn.h.OpenListen(localPort, iss)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -109,14 +145,19 @@ func (conn *Conn) OpenListen(localPort uint16, iss Value) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (conn *Conn) Close() error {
|
func (conn *Conn) Close() error {
|
||||||
|
conn.mu.Lock()
|
||||||
|
defer conn.mu.Unlock()
|
||||||
conn.trace("TCPConn.Close")
|
conn.trace("TCPConn.Close")
|
||||||
return conn.h.Close()
|
return conn.h.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Abort terminates all state of the connection forcibly.
|
// Abort terminates all state of the connection forcibly.
|
||||||
func (conn *Conn) Abort() {
|
func (conn *Conn) Abort() {
|
||||||
|
conn.mu.Lock()
|
||||||
|
defer conn.mu.Unlock()
|
||||||
conn.h.Abort()
|
conn.h.Abort()
|
||||||
*conn = Conn{
|
*conn = Conn{
|
||||||
|
mu: conn.mu,
|
||||||
h: conn.h,
|
h: conn.h,
|
||||||
remoteAddr: conn.remoteAddr[:0],
|
remoteAddr: conn.remoteAddr[:0],
|
||||||
logger: conn.logger,
|
logger: conn.logger,
|
||||||
@@ -140,7 +181,7 @@ func (conn *Conn) Write(b []byte) (int, error) {
|
|||||||
plen := len(b)
|
plen := len(b)
|
||||||
conn.trace("TCPConn.Write:start")
|
conn.trace("TCPConn.Write:start")
|
||||||
connid := conn.h.ConnectionID()
|
connid := conn.h.ConnectionID()
|
||||||
if conn.deadlineExceeded(conn.wdead) {
|
if conn.deadlineExceeded(&conn.wdead) {
|
||||||
return 0, errDeadlineExceeded
|
return 0, errDeadlineExceeded
|
||||||
} else if plen == 0 {
|
} else if plen == 0 {
|
||||||
return 0, nil
|
return 0, nil
|
||||||
@@ -153,7 +194,9 @@ func (conn *Conn) Write(b []byte) (int, error) {
|
|||||||
} else if connid != conn.h.ConnectionID() {
|
} else if connid != conn.h.ConnectionID() {
|
||||||
return n, net.ErrClosed
|
return n, net.ErrClosed
|
||||||
}
|
}
|
||||||
|
conn.mu.Lock()
|
||||||
ngot, _ := conn.h.Write(b)
|
ngot, _ := conn.h.Write(b)
|
||||||
|
conn.mu.Unlock()
|
||||||
n += ngot
|
n += ngot
|
||||||
b = b[ngot:]
|
b = b[ngot:]
|
||||||
if n == plen {
|
if n == plen {
|
||||||
@@ -165,7 +208,7 @@ func (conn *Conn) Write(b []byte) (int, error) {
|
|||||||
backoff.Miss()
|
backoff.Miss()
|
||||||
}
|
}
|
||||||
conn.trace("TCPConn.Write:insuf-buf", slog.Int("missing", plen-n))
|
conn.trace("TCPConn.Write:insuf-buf", slog.Int("missing", plen-n))
|
||||||
if conn.deadlineExceeded(conn.wdead) {
|
if conn.deadlineExceeded(&conn.wdead) {
|
||||||
return n, errDeadlineExceeded
|
return n, errDeadlineExceeded
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -188,12 +231,14 @@ func (conn *Conn) Read(b []byte) (int, error) {
|
|||||||
} else if connid != conn.h.ConnectionID() {
|
} else if connid != conn.h.ConnectionID() {
|
||||||
return 0, net.ErrClosed
|
return 0, net.ErrClosed
|
||||||
}
|
}
|
||||||
if conn.deadlineExceeded(conn.rdead) {
|
if conn.deadlineExceeded(&conn.rdead) {
|
||||||
return 0, errDeadlineExceeded
|
return 0, errDeadlineExceeded
|
||||||
}
|
}
|
||||||
backoff.Miss()
|
backoff.Miss()
|
||||||
}
|
}
|
||||||
|
conn.mu.Lock()
|
||||||
n, err := conn.h.Read(b)
|
n, err := conn.h.Read(b)
|
||||||
|
conn.mu.Unlock()
|
||||||
return n, err
|
return n, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -209,6 +254,8 @@ func (conn *Conn) checkPipeOpen() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (conn *Conn) Demux(buf []byte, off int) (err error) {
|
func (conn *Conn) Demux(buf []byte, off int) (err error) {
|
||||||
|
conn.mu.Lock()
|
||||||
|
defer conn.mu.Unlock()
|
||||||
conn.trace("tcpconn.Recv:start")
|
conn.trace("tcpconn.Recv:start")
|
||||||
if off >= len(buf) {
|
if off >= len(buf) {
|
||||||
return errors.New("bad offset in TCPConn.Recv")
|
return errors.New("bad offset in TCPConn.Recv")
|
||||||
@@ -232,6 +279,8 @@ func (conn *Conn) Demux(buf []byte, off int) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (conn *Conn) Encapsulate(buf []byte, off int) (n int, err error) {
|
func (conn *Conn) Encapsulate(buf []byte, off int) (n int, err error) {
|
||||||
|
conn.mu.Lock()
|
||||||
|
defer conn.mu.Unlock()
|
||||||
if len(conn.remoteAddr) == 0 {
|
if len(conn.remoteAddr) == 0 {
|
||||||
return 0, errNoRemoteAddr
|
return 0, errNoRemoteAddr
|
||||||
}
|
}
|
||||||
@@ -262,8 +311,12 @@ func (conn *Conn) isRaddrSet() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (conn *Conn) reset(h Handler) {
|
func (conn *Conn) reset(h Handler) {
|
||||||
|
if conn.mu.TryLock() {
|
||||||
|
panic("reset must be called from within locked conn")
|
||||||
|
}
|
||||||
*conn = Conn{
|
*conn = Conn{
|
||||||
h: h,
|
h: h,
|
||||||
|
mu: conn.mu,
|
||||||
remoteAddr: conn.remoteAddr[:0],
|
remoteAddr: conn.remoteAddr[:0],
|
||||||
logger: conn.logger,
|
logger: conn.logger,
|
||||||
}
|
}
|
||||||
@@ -273,6 +326,8 @@ func (conn *Conn) reset(h Handler) {
|
|||||||
// with the connection. It is equivalent to calling both
|
// with the connection. It is equivalent to calling both
|
||||||
// SetReadDeadline and SetWriteDeadline. Implements [net.Conn].
|
// SetReadDeadline and SetWriteDeadline. Implements [net.Conn].
|
||||||
func (conn *Conn) SetDeadline(t time.Time) error {
|
func (conn *Conn) SetDeadline(t time.Time) error {
|
||||||
|
conn.mu.Lock()
|
||||||
|
defer conn.mu.Unlock()
|
||||||
err := conn.SetReadDeadline(t)
|
err := conn.SetReadDeadline(t)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -283,6 +338,8 @@ func (conn *Conn) SetDeadline(t time.Time) error {
|
|||||||
// SetReadDeadline sets the deadline for future Read calls
|
// SetReadDeadline sets the deadline for future Read calls
|
||||||
// and any currently-blocked Read call. A zero value for t means Read will not time out.
|
// and any currently-blocked Read call. A zero value for t means Read will not time out.
|
||||||
func (conn *Conn) SetReadDeadline(t time.Time) error {
|
func (conn *Conn) SetReadDeadline(t time.Time) error {
|
||||||
|
conn.mu.Lock()
|
||||||
|
defer conn.mu.Unlock()
|
||||||
conn.trace("TCPConn.SetReadDeadline:start")
|
conn.trace("TCPConn.SetReadDeadline:start")
|
||||||
err := conn.checkPipeOpen()
|
err := conn.checkPipeOpen()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@@ -305,8 +362,10 @@ func (conn *Conn) SetWriteDeadline(t time.Time) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (conn *Conn) deadlineExceeded(deadline time.Time) bool {
|
func (conn *Conn) deadlineExceeded(deadline *time.Time) bool {
|
||||||
return !deadline.IsZero() && time.Since(deadline) > 0
|
conn.mu.Lock()
|
||||||
|
defer conn.mu.Unlock()
|
||||||
|
return !deadline.IsZero() && time.Since(*deadline) > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (conn *Conn) ConnectionID() *uint64 {
|
func (conn *Conn) ConnectionID() *uint64 {
|
||||||
|
|||||||
+11
-2
@@ -135,11 +135,11 @@ func (s *StackAsync) Reset(cfg StackConfig) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Now setup stacks.
|
// Now setup stacks.
|
||||||
err = s.link.Register(&s.ip) // IPv4 | IPv6
|
err = s.link.Register(&s.arp) // ARP.
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = s.link.Register(&s.arp) // ARP.
|
err = s.link.Register(&s.ip) // IPv4 | IPv6
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -232,6 +232,8 @@ func (s *StackAsync) Gateway6() [6]byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *StackAsync) DialTCP(conn *tcp.Conn, localPort uint16, addrp netip.AddrPort) (err error) {
|
func (s *StackAsync) DialTCP(conn *tcp.Conn, localPort uint16, addrp netip.AddrPort) (err error) {
|
||||||
|
s.mu.Lock()
|
||||||
|
defer s.mu.Unlock()
|
||||||
err = conn.OpenActive(localPort, addrp, tcp.Value(s.Prand32()))
|
err = conn.OpenActive(localPort, addrp, tcp.Value(s.Prand32()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -245,6 +247,8 @@ func (s *StackAsync) DialTCP(conn *tcp.Conn, localPort uint16, addrp netip.AddrP
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *StackAsync) ListenTCP(conn *tcp.Conn, localPort uint16) (err error) {
|
func (s *StackAsync) ListenTCP(conn *tcp.Conn, localPort uint16) (err error) {
|
||||||
|
s.mu.Lock()
|
||||||
|
defer s.mu.Unlock()
|
||||||
err = conn.OpenListen(localPort, tcp.Value(s.Prand32()))
|
err = conn.OpenListen(localPort, tcp.Value(s.Prand32()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -436,6 +440,11 @@ func (stack *StackAsync) AssimilateDHCPResults(results *DHCPResults) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
// Reset ARP handler with new IP address so it can respond to ARP requests.
|
||||||
|
err = stack.resetARP()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if len(results.DNSServers) > 0 {
|
if len(results.DNSServers) > 0 {
|
||||||
if !results.DNSServers[0].IsValid() || !results.DNSServers[0].Is4() {
|
if !results.DNSServers[0].IsValid() || !results.DNSServers[0].Is4() {
|
||||||
|
|||||||
Reference in New Issue
Block a user