mirror of
https://github.com/tinygo-org/net.git
synced 2026-08-20 20:39:00 +00:00
BUG Fix: return proper net.OpError's for Read/Write operations
Need to return the same error structure/content as regular Go for net.Conn Read/Write operations. Found/fixed when testing deadlines on Read/Write operations.
This commit is contained in:
committed by
deadprogram
parent
ad745d61ae
commit
7898c5e946
@@ -161,6 +161,15 @@ func (e *OpError) Error() string {
|
|||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type timeout interface {
|
||||||
|
Timeout() bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *OpError) Timeout() bool {
|
||||||
|
t, ok := e.Err.(timeout)
|
||||||
|
return ok && t.Timeout()
|
||||||
|
}
|
||||||
|
|
||||||
// A ParseError is the error type of literal network address parsers.
|
// A ParseError is the error type of literal network address parsers.
|
||||||
type ParseError struct {
|
type ParseError struct {
|
||||||
// Type is the type of string that was expected, such as
|
// Type is the type of string that was expected, such as
|
||||||
|
|||||||
@@ -45,8 +45,8 @@ type netdever interface {
|
|||||||
Connect(sockfd int, host string, ip IP, port int) error
|
Connect(sockfd int, host string, ip IP, port int) error
|
||||||
Listen(sockfd int, backlog int) error
|
Listen(sockfd int, backlog int) error
|
||||||
Accept(sockfd int, ip IP, port int) (int, error)
|
Accept(sockfd int, ip IP, port int) (int, error)
|
||||||
Send(sockfd int, buf []byte, flags int, timeout time.Duration) (int, error)
|
Send(sockfd int, buf []byte, flags int, deadline time.Time) (int, error)
|
||||||
Recv(sockfd int, buf []byte, flags int, timeout time.Duration) (int, error)
|
Recv(sockfd int, buf []byte, flags int, deadline time.Time) (int, error)
|
||||||
Close(sockfd int) error
|
Close(sockfd int) error
|
||||||
SetSockOpt(sockfd int, level int, opt int, value interface{}) error
|
SetSockOpt(sockfd int, level int, opt int, value interface{}) error
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-26
@@ -9,6 +9,7 @@ package net
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"internal/itoa"
|
"internal/itoa"
|
||||||
|
"io"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"strconv"
|
"strconv"
|
||||||
"syscall"
|
"syscall"
|
||||||
@@ -116,6 +117,7 @@ func ResolveTCPAddr(network, address string) (*TCPAddr, error) {
|
|||||||
// connections.
|
// connections.
|
||||||
type TCPConn struct {
|
type TCPConn struct {
|
||||||
fd int
|
fd int
|
||||||
|
net string
|
||||||
laddr *TCPAddr
|
laddr *TCPAddr
|
||||||
raddr *TCPAddr
|
raddr *TCPAddr
|
||||||
readDeadline time.Time
|
readDeadline time.Time
|
||||||
@@ -159,6 +161,7 @@ func DialTCP(network string, laddr, raddr *TCPAddr) (*TCPConn, error) {
|
|||||||
|
|
||||||
return &TCPConn{
|
return &TCPConn{
|
||||||
fd: fd,
|
fd: fd,
|
||||||
|
net: network,
|
||||||
laddr: laddr,
|
laddr: laddr,
|
||||||
raddr: raddr,
|
raddr: raddr,
|
||||||
}, nil
|
}, nil
|
||||||
@@ -167,44 +170,26 @@ func DialTCP(network string, laddr, raddr *TCPAddr) (*TCPConn, error) {
|
|||||||
// TINYGO: Use netdev for Conn methods: Read = Recv, Write = Send, etc.
|
// TINYGO: Use netdev for Conn methods: Read = Recv, Write = Send, etc.
|
||||||
|
|
||||||
func (c *TCPConn) Read(b []byte) (int, error) {
|
func (c *TCPConn) Read(b []byte) (int, error) {
|
||||||
var timeout time.Duration
|
n, err := netdev.Recv(c.fd, b, 0, c.readDeadline)
|
||||||
|
|
||||||
now := time.Now()
|
|
||||||
|
|
||||||
if !c.readDeadline.IsZero() {
|
|
||||||
if c.readDeadline.Before(now) {
|
|
||||||
return 0, fmt.Errorf("Read deadline expired")
|
|
||||||
} else {
|
|
||||||
timeout = c.readDeadline.Sub(now)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
n, err := netdev.Recv(c.fd, b, 0, timeout)
|
|
||||||
// Turn the -1 socket error into 0 and let err speak for error
|
// Turn the -1 socket error into 0 and let err speak for error
|
||||||
if n < 0 {
|
if n < 0 {
|
||||||
n = 0
|
n = 0
|
||||||
}
|
}
|
||||||
|
if err != nil && err != io.EOF {
|
||||||
|
err = &OpError{Op: "read", Net: c.net, Source: c.laddr, Addr: c.raddr, Err: err}
|
||||||
|
}
|
||||||
return n, err
|
return n, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *TCPConn) Write(b []byte) (int, error) {
|
func (c *TCPConn) Write(b []byte) (int, error) {
|
||||||
var timeout time.Duration
|
n, err := netdev.Send(c.fd, b, 0, c.writeDeadline)
|
||||||
|
|
||||||
now := time.Now()
|
|
||||||
|
|
||||||
if !c.writeDeadline.IsZero() {
|
|
||||||
if c.writeDeadline.Before(now) {
|
|
||||||
return 0, fmt.Errorf("Write deadline expired")
|
|
||||||
} else {
|
|
||||||
timeout = c.writeDeadline.Sub(now)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
n, err := netdev.Send(c.fd, b, 0, timeout)
|
|
||||||
// Turn the -1 socket error into 0 and let err speak for error
|
// Turn the -1 socket error into 0 and let err speak for error
|
||||||
if n < 0 {
|
if n < 0 {
|
||||||
n = 0
|
n = 0
|
||||||
}
|
}
|
||||||
|
if err != nil {
|
||||||
|
err = &OpError{Op: "write", Net: c.net, Source: c.laddr, Addr: c.raddr, Err: err}
|
||||||
|
}
|
||||||
return n, err
|
return n, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -262,6 +247,7 @@ func (l *listener) Accept() (Conn, error) {
|
|||||||
|
|
||||||
return &TCPConn{
|
return &TCPConn{
|
||||||
fd: fd,
|
fd: fd,
|
||||||
|
net: "tcp",
|
||||||
laddr: l.laddr,
|
laddr: l.laddr,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|||||||
+63
-76
@@ -9,12 +9,39 @@
|
|||||||
package net
|
package net
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"internal/itoa"
|
||||||
|
"io"
|
||||||
"strconv"
|
"strconv"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// TLSAddr represents the address of a TLS end point.
|
||||||
|
type TLSAddr struct {
|
||||||
|
Host string
|
||||||
|
Port int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *TLSAddr) Network() string { return "tls" }
|
||||||
|
|
||||||
|
func (a *TLSAddr) String() string {
|
||||||
|
if a == nil {
|
||||||
|
return "<nil>"
|
||||||
|
}
|
||||||
|
return JoinHostPort(a.Host, itoa.Itoa(a.Port))
|
||||||
|
}
|
||||||
|
|
||||||
|
// A TLSConn represents a secured connection.
|
||||||
|
// It implements the net.Conn interface.
|
||||||
|
type TLSConn struct {
|
||||||
|
fd int
|
||||||
|
net string
|
||||||
|
laddr *TLSAddr
|
||||||
|
raddr *TLSAddr
|
||||||
|
readDeadline time.Time
|
||||||
|
writeDeadline time.Time
|
||||||
|
}
|
||||||
|
|
||||||
func DialTLS(addr string) (*TLSConn, error) {
|
func DialTLS(addr string) (*TLSConn, error) {
|
||||||
|
|
||||||
host, sport, err := SplitHostPort(addr)
|
host, sport, err := SplitHostPort(addr)
|
||||||
@@ -42,97 +69,33 @@ func DialTLS(addr string) (*TLSConn, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &TLSConn{
|
return &TLSConn{
|
||||||
fd: fd,
|
fd: fd,
|
||||||
|
net: "tls",
|
||||||
|
raddr: &TLSAddr{host, port},
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// A TLSConn represents a secured connection.
|
|
||||||
// It implements the net.Conn interface.
|
|
||||||
type TLSConn struct {
|
|
||||||
fd int
|
|
||||||
readDeadline time.Time
|
|
||||||
writeDeadline time.Time
|
|
||||||
}
|
|
||||||
|
|
||||||
// Access to net.Conn methods.
|
|
||||||
// Cannot just embed net.Conn because that would
|
|
||||||
// export the struct field too.
|
|
||||||
|
|
||||||
// LocalAddr returns the local network address.
|
|
||||||
func (c *TLSConn) LocalAddr() Addr {
|
|
||||||
// TODO
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoteAddr returns the remote network address.
|
|
||||||
func (c *TLSConn) RemoteAddr() Addr {
|
|
||||||
// TODO
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetDeadline sets the read and write deadlines associated with the connection.
|
|
||||||
// A zero value for t means Read and Write will not time out.
|
|
||||||
// After a Write has timed out, the TLS state is corrupt and all future writes will return the same error.
|
|
||||||
func (c *TLSConn) SetDeadline(t time.Time) error {
|
|
||||||
c.readDeadline = t
|
|
||||||
c.writeDeadline = t
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetReadDeadline sets the read deadline on the underlying connection.
|
|
||||||
// A zero value for t means Read will not time out.
|
|
||||||
func (c *TLSConn) SetReadDeadline(t time.Time) error {
|
|
||||||
c.readDeadline = t
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetWriteDeadline sets the write deadline on the underlying connection.
|
|
||||||
// A zero value for t means Write will not time out.
|
|
||||||
// After a Write has timed out, the TLS state is corrupt and all future writes will return the same error.
|
|
||||||
func (c *TLSConn) SetWriteDeadline(t time.Time) error {
|
|
||||||
c.writeDeadline = t
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *TLSConn) Read(b []byte) (int, error) {
|
func (c *TLSConn) Read(b []byte) (int, error) {
|
||||||
var timeout time.Duration
|
n, err := netdev.Recv(c.fd, b, 0, c.readDeadline)
|
||||||
|
|
||||||
now := time.Now()
|
|
||||||
|
|
||||||
if !c.readDeadline.IsZero() {
|
|
||||||
if c.readDeadline.Before(now) {
|
|
||||||
return 0, fmt.Errorf("Read deadline expired")
|
|
||||||
} else {
|
|
||||||
timeout = c.readDeadline.Sub(now)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
n, err := netdev.Recv(c.fd, b, 0, timeout)
|
|
||||||
// Turn the -1 socket error into 0 and let err speak for error
|
// Turn the -1 socket error into 0 and let err speak for error
|
||||||
if n < 0 {
|
if n < 0 {
|
||||||
n = 0
|
n = 0
|
||||||
}
|
}
|
||||||
|
if err != nil && err != io.EOF {
|
||||||
|
err = &OpError{Op: "read", Net: c.net, Source: c.laddr, Addr: c.raddr, Err: err}
|
||||||
|
}
|
||||||
return n, err
|
return n, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *TLSConn) Write(b []byte) (int, error) {
|
func (c *TLSConn) Write(b []byte) (int, error) {
|
||||||
var timeout time.Duration
|
n, err := netdev.Send(c.fd, b, 0, c.writeDeadline)
|
||||||
|
|
||||||
now := time.Now()
|
|
||||||
|
|
||||||
if !c.writeDeadline.IsZero() {
|
|
||||||
if c.writeDeadline.Before(now) {
|
|
||||||
return 0, fmt.Errorf("Write deadline expired")
|
|
||||||
} else {
|
|
||||||
timeout = c.writeDeadline.Sub(now)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
n, err := netdev.Send(c.fd, b, 0, timeout)
|
|
||||||
// Turn the -1 socket error into 0 and let err speak for error
|
// Turn the -1 socket error into 0 and let err speak for error
|
||||||
if n < 0 {
|
if n < 0 {
|
||||||
n = 0
|
n = 0
|
||||||
}
|
}
|
||||||
|
if err != nil {
|
||||||
|
err = &OpError{Op: "write", Net: c.net, Source: c.laddr, Addr: c.raddr, Err: err}
|
||||||
|
}
|
||||||
return n, err
|
return n, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,6 +103,30 @@ func (c *TLSConn) Close() error {
|
|||||||
return netdev.Close(c.fd)
|
return netdev.Close(c.fd)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *TLSConn) LocalAddr() Addr {
|
||||||
|
return c.laddr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *TLSConn) RemoteAddr() Addr {
|
||||||
|
return c.raddr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *TLSConn) SetDeadline(t time.Time) error {
|
||||||
|
c.readDeadline = t
|
||||||
|
c.writeDeadline = t
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *TLSConn) SetReadDeadline(t time.Time) error {
|
||||||
|
c.readDeadline = t
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *TLSConn) SetWriteDeadline(t time.Time) error {
|
||||||
|
c.writeDeadline = t
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Handshake runs the client or server handshake
|
// Handshake runs the client or server handshake
|
||||||
// protocol if it has not yet been run.
|
// protocol if it has not yet been run.
|
||||||
//
|
//
|
||||||
|
|||||||
+11
-26
@@ -9,6 +9,7 @@ package net
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"internal/itoa"
|
"internal/itoa"
|
||||||
|
"io"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"strconv"
|
"strconv"
|
||||||
"syscall"
|
"syscall"
|
||||||
@@ -116,6 +117,7 @@ func ResolveUDPAddr(network, address string) (*UDPAddr, error) {
|
|||||||
// for UDP network connections.
|
// for UDP network connections.
|
||||||
type UDPConn struct {
|
type UDPConn struct {
|
||||||
fd int
|
fd int
|
||||||
|
net string
|
||||||
laddr *UDPAddr
|
laddr *UDPAddr
|
||||||
raddr *UDPAddr
|
raddr *UDPAddr
|
||||||
readDeadline time.Time
|
readDeadline time.Time
|
||||||
@@ -187,6 +189,7 @@ func DialUDP(network string, laddr, raddr *UDPAddr) (*UDPConn, error) {
|
|||||||
|
|
||||||
return &UDPConn{
|
return &UDPConn{
|
||||||
fd: fd,
|
fd: fd,
|
||||||
|
net: network,
|
||||||
laddr: laddr,
|
laddr: laddr,
|
||||||
raddr: raddr,
|
raddr: raddr,
|
||||||
}, nil
|
}, nil
|
||||||
@@ -195,44 +198,26 @@ func DialUDP(network string, laddr, raddr *UDPAddr) (*UDPConn, error) {
|
|||||||
// TINYGO: Use netdev for Conn methods: Read = Recv, Write = Send, etc.
|
// TINYGO: Use netdev for Conn methods: Read = Recv, Write = Send, etc.
|
||||||
|
|
||||||
func (c *UDPConn) Read(b []byte) (int, error) {
|
func (c *UDPConn) Read(b []byte) (int, error) {
|
||||||
var timeout time.Duration
|
n, err := netdev.Recv(c.fd, b, 0, c.readDeadline)
|
||||||
|
|
||||||
now := time.Now()
|
|
||||||
|
|
||||||
if !c.readDeadline.IsZero() {
|
|
||||||
if c.readDeadline.Before(now) {
|
|
||||||
return 0, fmt.Errorf("Read deadline expired")
|
|
||||||
} else {
|
|
||||||
timeout = c.readDeadline.Sub(now)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
n, err := netdev.Recv(c.fd, b, 0, timeout)
|
|
||||||
// Turn the -1 socket error into 0 and let err speak for error
|
// Turn the -1 socket error into 0 and let err speak for error
|
||||||
if n < 0 {
|
if n < 0 {
|
||||||
n = 0
|
n = 0
|
||||||
}
|
}
|
||||||
|
if err != nil && err != io.EOF {
|
||||||
|
err = &OpError{Op: "read", Net: c.net, Source: c.laddr, Addr: c.raddr, Err: err}
|
||||||
|
}
|
||||||
return n, err
|
return n, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *UDPConn) Write(b []byte) (int, error) {
|
func (c *UDPConn) Write(b []byte) (int, error) {
|
||||||
var timeout time.Duration
|
n, err := netdev.Send(c.fd, b, 0, c.writeDeadline)
|
||||||
|
|
||||||
now := time.Now()
|
|
||||||
|
|
||||||
if !c.writeDeadline.IsZero() {
|
|
||||||
if c.writeDeadline.Before(now) {
|
|
||||||
return 0, fmt.Errorf("Write deadline expired")
|
|
||||||
} else {
|
|
||||||
timeout = c.writeDeadline.Sub(now)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
n, err := netdev.Send(c.fd, b, 0, timeout)
|
|
||||||
// Turn the -1 socket error into 0 and let err speak for error
|
// Turn the -1 socket error into 0 and let err speak for error
|
||||||
if n < 0 {
|
if n < 0 {
|
||||||
n = 0
|
n = 0
|
||||||
}
|
}
|
||||||
|
if err != nil {
|
||||||
|
err = &OpError{Op: "write", Net: c.net, Source: c.laddr, Addr: c.raddr, Err: err}
|
||||||
|
}
|
||||||
return n, err
|
return n, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user