mirror of
https://github.com/soypat/lneto.git
synced 2026-08-18 21:54:01 +00:00
changes to TCP stack to enable xnet functionality
This commit is contained in:
@@ -249,7 +249,7 @@ func (stack *Stack) OpenTCPListener(port uint16) (*internet.NodeTCPListener, err
|
|||||||
func (stack *Stack) OpenPassiveTCP(port uint16, iss tcp.Value) (*tcp.Conn, error) {
|
func (stack *Stack) OpenPassiveTCP(port uint16, iss tcp.Value) (*tcp.Conn, error) {
|
||||||
mtu := stack.ethernet.MTU()
|
mtu := stack.ethernet.MTU()
|
||||||
conn := new(tcp.Conn)
|
conn := new(tcp.Conn)
|
||||||
err := conn.Configure(&tcp.ConnConfig{
|
err := conn.Configure(tcp.ConnConfig{
|
||||||
RxBuf: make([]byte, mtu),
|
RxBuf: make([]byte, mtu),
|
||||||
TxBuf: make([]byte, mtu),
|
TxBuf: make([]byte, mtu),
|
||||||
TxPacketQueueSize: 3,
|
TxPacketQueueSize: 3,
|
||||||
@@ -296,7 +296,7 @@ func (naiveTCPPool) GetTCP() (*tcp.Conn, tcp.Value) {
|
|||||||
rand.Read(buf[:])
|
rand.Read(buf[:])
|
||||||
randVal := binary.LittleEndian.Uint32(buf[:])
|
randVal := binary.LittleEndian.Uint32(buf[:])
|
||||||
var conn tcp.Conn
|
var conn tcp.Conn
|
||||||
err := conn.Configure(&tcp.ConnConfig{
|
err := conn.Configure(tcp.ConnConfig{
|
||||||
RxBuf: make([]byte, 1024),
|
RxBuf: make([]byte, 1024),
|
||||||
TxBuf: make([]byte, 1024),
|
TxBuf: make([]byte, 1024),
|
||||||
TxPacketQueueSize: 3,
|
TxPacketQueueSize: 3,
|
||||||
|
|||||||
@@ -182,7 +182,7 @@ func NewEthernetTCPStack(ourMAC, gwMAC [6]byte, ip netip.AddrPort, mtu uint16, s
|
|||||||
lport: 0,
|
lport: 0,
|
||||||
})
|
})
|
||||||
var conn tcp.Conn
|
var conn tcp.Conn
|
||||||
err = conn.Configure(&tcp.ConnConfig{
|
err = conn.Configure(tcp.ConnConfig{
|
||||||
RxBuf: make([]byte, mtu),
|
RxBuf: make([]byte, mtu),
|
||||||
TxBuf: make([]byte, mtu),
|
TxBuf: make([]byte, mtu),
|
||||||
TxPacketQueueSize: 3,
|
TxPacketQueueSize: 3,
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ func run() error {
|
|||||||
flagInterface = "tap0"
|
flagInterface = "tap0"
|
||||||
)
|
)
|
||||||
flag.StringVar(&flagInterface, "i", flagInterface, "Interface to select. tap* creates a tap interface. Any other name will create a bridge to the name of the interface i.e: 'enp7s0', 'wlp8s0', 'lo'")
|
flag.StringVar(&flagInterface, "i", flagInterface, "Interface to select. tap* creates a tap interface. Any other name will create a bridge to the name of the interface i.e: 'enp7s0', 'wlp8s0', 'lo'")
|
||||||
|
flag.Parse()
|
||||||
var (
|
var (
|
||||||
flagNet = "192.168.10.1/24"
|
flagNet = "192.168.10.1/24"
|
||||||
flagiface = "tap0"
|
flagiface = "tap0"
|
||||||
|
|||||||
+50
-1
@@ -12,8 +12,10 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/soypat/lneto/dns"
|
"github.com/soypat/lneto/dns"
|
||||||
|
"github.com/soypat/lneto/http/httpraw"
|
||||||
"github.com/soypat/lneto/internal"
|
"github.com/soypat/lneto/internal"
|
||||||
"github.com/soypat/lneto/internal/ltesto"
|
"github.com/soypat/lneto/internal/ltesto"
|
||||||
|
"github.com/soypat/lneto/internet/pcap"
|
||||||
"github.com/soypat/lneto/x/xnet"
|
"github.com/soypat/lneto/x/xnet"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -35,9 +37,11 @@ func run() (err error) {
|
|||||||
flagHostToResolve = ""
|
flagHostToResolve = ""
|
||||||
flagRequestedIP = ""
|
flagRequestedIP = ""
|
||||||
flagDoNTP = false
|
flagDoNTP = false
|
||||||
|
flagHTTPGet = false
|
||||||
)
|
)
|
||||||
|
flag.BoolVar(&flagHTTPGet, "httpget", flagHTTPGet, "Do an HTTP GET request ")
|
||||||
flag.StringVar(&flagInterface, "i", flagInterface, "Interface to use. Either tap* or the name of an existing interface to bridge to.")
|
flag.StringVar(&flagInterface, "i", flagInterface, "Interface to use. Either tap* or the name of an existing interface to bridge to.")
|
||||||
flag.BoolVar(&flagUseHTTP, "http", flagUseHTTP, "Use HTTP tap interface.")
|
flag.BoolVar(&flagUseHTTP, "ihttp", flagUseHTTP, "Use HTTP tap interface.")
|
||||||
flag.StringVar(&flagHostToResolve, "host", flagHostToResolve, "Hostname to resolve via DNS.")
|
flag.StringVar(&flagHostToResolve, "host", flagHostToResolve, "Hostname to resolve via DNS.")
|
||||||
flag.StringVar(&flagRequestedIP, "addr", flagRequestedIP, "IP address to request via DHCP.")
|
flag.StringVar(&flagRequestedIP, "addr", flagRequestedIP, "IP address to request via DHCP.")
|
||||||
flag.BoolVar(&flagDoNTP, "ntp", flagDoNTP, "Do NTP round and print result time")
|
flag.BoolVar(&flagDoNTP, "ntp", flagDoNTP, "Do NTP round and print result time")
|
||||||
@@ -89,6 +93,9 @@ func run() (err error) {
|
|||||||
RandSeed: softRand,
|
RandSeed: softRand,
|
||||||
HardwareAddress: brHW,
|
HardwareAddress: brHW,
|
||||||
MTU: uint16(mtu),
|
MTU: uint16(mtu),
|
||||||
|
MaxTCPConns: 1,
|
||||||
|
TCPBufferSizeTx: 2048,
|
||||||
|
TCPBufferSizeRx: 2048,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -97,12 +104,17 @@ func run() (err error) {
|
|||||||
go func() {
|
go func() {
|
||||||
lastAction := time.Now()
|
lastAction := time.Now()
|
||||||
buf := make([]byte, mtu)
|
buf := make([]byte, mtu)
|
||||||
|
var cap pcap.PacketBreakdown
|
||||||
for {
|
for {
|
||||||
clear(buf)
|
clear(buf)
|
||||||
nwrite, err := stack.Encapsulate(buf[:], 0)
|
nwrite, err := stack.Encapsulate(buf[:], 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("ERR:ENCAPSULATE", err)
|
fmt.Println("ERR:ENCAPSULATE", err)
|
||||||
} else if nwrite > 0 {
|
} else if nwrite > 0 {
|
||||||
|
frames, err := cap.CaptureEthernet(nil, buf[:nwrite], 0)
|
||||||
|
if len(frames) > 0 {
|
||||||
|
fmt.Println("OUT", frames)
|
||||||
|
}
|
||||||
n, err := iface.Write(buf[:nwrite])
|
n, err := iface.Write(buf[:nwrite])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("groutine encapsulate:", err)
|
log.Fatal("groutine encapsulate:", err)
|
||||||
@@ -179,6 +191,43 @@ func run() (err error) {
|
|||||||
return fmt.Errorf("DNS of host %q failed: %w", flagHostToResolve, err)
|
return fmt.Errorf("DNS of host %q failed: %w", flagHostToResolve, err)
|
||||||
}
|
}
|
||||||
fmt.Printf("DNS resolution of %q complete and resolved to %v\n", flagHostToResolve, addrs)
|
fmt.Printf("DNS resolution of %q complete and resolved to %v\n", flagHostToResolve, addrs)
|
||||||
|
if flagHTTPGet {
|
||||||
|
var hdr httpraw.Header
|
||||||
|
hdr.SetMethod("GET")
|
||||||
|
hdr.SetRequestURI("/")
|
||||||
|
hdr.SetProtocol("HTTP/1.1")
|
||||||
|
hdr.Set("Host", flagHostToResolve)
|
||||||
|
hdr.Set("User-Agent", "lneto")
|
||||||
|
hdr.Set("Accept-Language", "en-US,en;q=0.5")
|
||||||
|
req, err := hdr.AppendRequest(nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
target := netip.AddrPortFrom(addrs[0], 80)
|
||||||
|
conn, err := rstack.DoDialTCP(uint16(softRand&0xefff)+1024, target, internetTimeout, internetRetries)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("TCP failed: %w", err)
|
||||||
|
}
|
||||||
|
conn.SetDeadline(time.Now().Add(internetTimeout))
|
||||||
|
_, err = conn.Write(req)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
rxbuf := make([]byte, 2048)
|
||||||
|
var page []byte
|
||||||
|
for {
|
||||||
|
var n int
|
||||||
|
n, err = conn.Read(rxbuf)
|
||||||
|
page = append(page, rxbuf[:n]...)
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(page) == 0 {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
os.Stdout.Write(page)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -93,15 +93,24 @@ func (ps *StackPorts) Demux(b []byte, offset int) (err error) {
|
|||||||
func (ps *StackPorts) Register(h StackNode) error {
|
func (ps *StackPorts) Register(h StackNode) error {
|
||||||
port := h.LocalPort()
|
port := h.LocalPort()
|
||||||
proto := h.Protocol()
|
proto := h.Protocol()
|
||||||
|
|
||||||
if port <= 0 {
|
if port <= 0 {
|
||||||
return errZeroPort
|
return errZeroPort
|
||||||
} else if proto != uint64(ps.protocol) {
|
} else if proto != uint64(ps.protocol) {
|
||||||
return errInvalidProto
|
return errInvalidProto
|
||||||
}
|
}
|
||||||
|
var cid uint64
|
||||||
|
cidPtr := h.ConnectionID()
|
||||||
|
if cidPtr != nil {
|
||||||
|
cid = *cidPtr
|
||||||
|
}
|
||||||
return registerNode(&ps.handlers, node{
|
return registerNode(&ps.handlers, node{
|
||||||
demux: h.Demux,
|
demux: h.Demux,
|
||||||
encapsulate: h.Encapsulate,
|
encapsulate: h.Encapsulate,
|
||||||
port: port,
|
port: port,
|
||||||
|
currConnID: cid,
|
||||||
|
connID: cidPtr,
|
||||||
|
proto: uint16(proto),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ func setupClientServer(t *testing.T, rng *rand.Rand, client, server *StackIP, co
|
|||||||
server.Reset(svip.Addr(), maxNodes)
|
server.Reset(svip.Addr(), maxNodes)
|
||||||
client.Reset(clip.Addr(), maxNodes)
|
client.Reset(clip.Addr(), maxNodes)
|
||||||
|
|
||||||
err := connServer.Configure(&tcp.ConnConfig{
|
err := connServer.Configure(tcp.ConnConfig{
|
||||||
RxBuf: make([]byte, bufsize),
|
RxBuf: make([]byte, bufsize),
|
||||||
TxBuf: make([]byte, bufsize),
|
TxBuf: make([]byte, bufsize),
|
||||||
TxPacketQueueSize: 3,
|
TxPacketQueueSize: 3,
|
||||||
@@ -103,7 +103,7 @@ func setupClientServer(t *testing.T, rng *rand.Rand, client, server *StackIP, co
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
err = connClient.Configure(&tcp.ConnConfig{
|
err = connClient.Configure(tcp.ConnConfig{
|
||||||
RxBuf: make([]byte, bufsize),
|
RxBuf: make([]byte, bufsize),
|
||||||
TxBuf: make([]byte, bufsize),
|
TxBuf: make([]byte, bufsize),
|
||||||
TxPacketQueueSize: 3,
|
TxPacketQueueSize: 3,
|
||||||
|
|||||||
+9
-1
@@ -44,7 +44,7 @@ type ConnConfig struct {
|
|||||||
Logger *slog.Logger
|
Logger *slog.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
func (conn *Conn) Configure(config *ConnConfig) (err error) {
|
func (conn *Conn) Configure(config ConnConfig) (err error) {
|
||||||
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
|
||||||
@@ -109,9 +109,17 @@ func (conn *Conn) Abort() {
|
|||||||
h: conn.h,
|
h: conn.h,
|
||||||
remoteAddr: conn.remoteAddr[:0],
|
remoteAddr: conn.remoteAddr[:0],
|
||||||
logger: conn.logger,
|
logger: conn.logger,
|
||||||
|
ipID: conn.ipID,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// InternalHandler returns the internal [Handler] instance. The Handler contains lower level implementation logic for a TCP connection.
|
||||||
|
// Typical users should not be using this method unless implementing a stack which manages several TCP connections and thus need
|
||||||
|
// access to low level internals for careful memory management.
|
||||||
|
func (conn *Conn) InternalHandler() *Handler {
|
||||||
|
return &conn.h
|
||||||
|
}
|
||||||
|
|
||||||
// Write writes argument data to the TCPConns's output buffer which is queued to be sent.
|
// Write writes argument data to the TCPConns's output buffer which is queued to be sent.
|
||||||
func (conn *Conn) Write(b []byte) (int, error) {
|
func (conn *Conn) Write(b []byte) (int, error) {
|
||||||
err := conn.checkPipeOpen()
|
err := conn.checkPipeOpen()
|
||||||
|
|||||||
+11
-5
@@ -53,16 +53,17 @@ func (h *Handler) ConnectionID() *uint64 {
|
|||||||
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.
|
// SetBuffers sets the internal buffers used to receive and transmit bytes asynchronously via [Handler.Write] and [Handler.Read] calls.
|
||||||
|
// If the argument buffer is nil then the respective currently set buffer will be reused.
|
||||||
func (h *Handler) SetBuffers(txbuf, rxbuf []byte, packets int) error {
|
func (h *Handler) SetBuffers(txbuf, rxbuf []byte, packets int) error {
|
||||||
|
if h.bufRx.Buf == nil && (len(rxbuf) < minBufferSize || len(txbuf) < minBufferSize) {
|
||||||
|
return errors.New("tcp: short buffer")
|
||||||
|
}
|
||||||
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")
|
||||||
}
|
}
|
||||||
if rxbuf != nil {
|
if rxbuf != nil {
|
||||||
h.bufRx.Buf = rxbuf
|
h.bufRx.Buf = rxbuf
|
||||||
}
|
}
|
||||||
if len(h.bufRx.Buf) < minBufferSize {
|
|
||||||
return errors.New("short rx buffer")
|
|
||||||
}
|
|
||||||
h.scb.SetRecvWindow(Size(h.bufRx.Size()))
|
h.scb.SetRecvWindow(Size(h.bufRx.Size()))
|
||||||
h.bufRx.Reset()
|
h.bufRx.Reset()
|
||||||
return h.bufTx.ResetOrReuse(txbuf, packets, 0)
|
return h.bufTx.ResetOrReuse(txbuf, packets, 0)
|
||||||
@@ -270,11 +271,16 @@ func (h *Handler) Send(b []byte) (int, error) {
|
|||||||
return int(offset)*4 + int(segment.DATALEN), nil
|
return int(offset)*4 + 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.
|
// FreeTx 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) FreeTx() int {
|
||||||
return h.bufTx.Free()
|
return h.bufTx.Free()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SizeRx returns the size of the TCP receive ring buffer.
|
||||||
|
func (h *Handler) SizeRx() int {
|
||||||
|
return h.bufRx.Size()
|
||||||
|
}
|
||||||
|
|
||||||
// Write implements [io.Writer] by copying b to a internal buffer to be sent over the network on the next
|
// 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.
|
// [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) {
|
||||||
|
|||||||
+34
-1
@@ -2,6 +2,7 @@ package xnet
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"io"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
@@ -16,6 +17,10 @@ import (
|
|||||||
"github.com/soypat/lneto/tcp"
|
"github.com/soypat/lneto/tcp"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
minTCPBuffer = 256
|
||||||
|
)
|
||||||
|
|
||||||
type StackAsync struct {
|
type StackAsync struct {
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
hostname string
|
hostname string
|
||||||
@@ -52,6 +57,8 @@ type StackConfig struct {
|
|||||||
NTPServer netip.Addr
|
NTPServer netip.Addr
|
||||||
Hostname string
|
Hostname string
|
||||||
MaxTCPConns int
|
MaxTCPConns int
|
||||||
|
TCPBufferSizeTx int // Size of transmit buffer for TCP connections.
|
||||||
|
TCPBufferSizeRx int // Size of receive buffer for TCP connections.
|
||||||
RandSeed int64
|
RandSeed int64
|
||||||
HardwareAddress [6]byte
|
HardwareAddress [6]byte
|
||||||
MTU uint16
|
MTU uint16
|
||||||
@@ -112,9 +119,35 @@ func (s *StackAsync) Reset(cfg StackConfig) error {
|
|||||||
|
|
||||||
// Enable TCP if connections present.
|
// Enable TCP if connections present.
|
||||||
if cfg.MaxTCPConns > 0 {
|
if cfg.MaxTCPConns > 0 {
|
||||||
|
if cfg.TCPBufferSizeRx < minTCPBuffer || cfg.TCPBufferSizeTx < minTCPBuffer {
|
||||||
|
return io.ErrShortBuffer
|
||||||
|
}
|
||||||
if cap(s.tcpconns) < cfg.MaxTCPConns {
|
if cap(s.tcpconns) < cfg.MaxTCPConns {
|
||||||
s.tcpconns = make([]tcp.Conn, cfg.MaxTCPConns)
|
s.tcpconns = make([]tcp.Conn, cfg.MaxTCPConns)
|
||||||
}
|
}
|
||||||
|
s.tcpconns = s.tcpconns[:cfg.MaxTCPConns]
|
||||||
|
for i := range s.tcpconns {
|
||||||
|
c := &s.tcpconns[i]
|
||||||
|
c.Abort() // Abort forcibly closes connection to allow buffer setting and reduce risk of race conditions.
|
||||||
|
h := c.InternalHandler()
|
||||||
|
sizetx := h.FreeTx()
|
||||||
|
sizerx := h.SizeRx()
|
||||||
|
// If size is sufficient then buffers will remain nil and memory will be reused.
|
||||||
|
var rxbuf, txbuf []byte
|
||||||
|
if sizetx < cfg.TCPBufferSizeTx || sizerx < cfg.TCPBufferSizeRx {
|
||||||
|
buf := make([]byte, cfg.TCPBufferSizeTx+cfg.TCPBufferSizeRx)
|
||||||
|
rxbuf = buf[:cfg.TCPBufferSizeRx]
|
||||||
|
txbuf = buf[cfg.TCPBufferSizeRx : cfg.TCPBufferSizeRx+cfg.TCPBufferSizeTx]
|
||||||
|
}
|
||||||
|
err = c.Configure(tcp.ConnConfig{
|
||||||
|
RxBuf: rxbuf,
|
||||||
|
TxBuf: txbuf,
|
||||||
|
TxPacketQueueSize: 4,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
err = s.tcps.ResetTCP(cfg.MaxTCPConns)
|
err = s.tcps.ResetTCP(cfg.MaxTCPConns)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -213,7 +246,7 @@ func (s *StackAsync) DialTCP(localPort uint16, addrp netip.AddrPort) (conn *tcp.
|
|||||||
}
|
}
|
||||||
for i := range s.tcpconns {
|
for i := range s.tcpconns {
|
||||||
maybeFreeConn := &s.tcpconns[i]
|
maybeFreeConn := &s.tcpconns[i]
|
||||||
state := conn.State()
|
state := maybeFreeConn.State()
|
||||||
if state.IsClosed() {
|
if state.IsClosed() {
|
||||||
conn = maybeFreeConn
|
conn = maybeFreeConn
|
||||||
break // Can be used!
|
break // Can be used!
|
||||||
|
|||||||
@@ -122,21 +122,20 @@ func (s StackBlocking) DoDialTCP(localPort uint16, addrp netip.AddrPort, timeout
|
|||||||
deadline := time.Now().Add(timeout)
|
deadline := time.Now().Add(timeout)
|
||||||
for i := 0; i < maxIter; i++ {
|
for i := 0; i < maxIter; i++ {
|
||||||
state := conn.State()
|
state := conn.State()
|
||||||
switch state {
|
if state == tcp.StateEstablished {
|
||||||
case tcp.StateEstablished:
|
return conn, nil
|
||||||
break
|
} else if state == tcp.StateSynSent || state == tcp.StateSynRcvd || conn.InternalHandler().AwaitingSynSend() {
|
||||||
case tcp.StateSynSent, tcp.StateSynRcvd:
|
|
||||||
if err = s.checkDeadline(deadline); err != nil {
|
if err = s.checkDeadline(deadline); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
time.Sleep(sleep)
|
time.Sleep(sleep)
|
||||||
default:
|
} else {
|
||||||
// Unexpected state, abort and terminate connection.
|
// Unexpected state, abort and terminate connection.
|
||||||
conn.Abort()
|
conn.Abort()
|
||||||
return nil, errTCPFailedToConnect
|
return nil, errTCPFailedToConnect
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return conn, nil
|
return conn, errDeadlineExceed
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s StackBlocking) checkDeadline(deadline time.Time) error {
|
func (s StackBlocking) checkDeadline(deadline time.Time) error {
|
||||||
|
|||||||
Reference in New Issue
Block a user