mirror of
https://github.com/tinygo-org/net.git
synced 2026-08-14 08:23:39 +00:00
Add network device driver model, netdev
This PR adds a network device driver model called netdev. There will be a companion PR for TinyGo drivers to update the netdev drivers and network examples. This PR covers the core "net" package. An RFC for the work is here: #tinygo-org/drivers#487. Some things have changed from the RFC, but nothing major. The "net" package is a partial port of Go's "net" package, version 1.19.3. The src/net/README file has details on what is modified from Go's "net" package. Most "net" features are working as they would in normal Go. TCP/UDP/TLS protocol support is there. As well as HTTP client and server support. Standard Go network packages such as golang.org/x/net/websockets and Paho MQTT client work as-is. Other packages are likely to work as-is. Testing results are here (https://docs.google.com/spreadsheets/d/e/2PACX-1vT0cCjBvwXf9HJf6aJV2Sw198F2ief02gmbMV0sQocKT4y4RpfKv3dh6Jyew8lQW64FouZ8GwA2yjxI/pubhtml?gid=1013173032&single=true).
This commit is contained in:
committed by
deadprogram
parent
b46e2ec2ac
commit
693edae782
+231
-2
@@ -1,8 +1,18 @@
|
||||
// TINYGO: The following is copied and modified from Go 1.19.3 official implementation.
|
||||
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package net
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"internal/itoa"
|
||||
"net/netip"
|
||||
"strconv"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
// TCPAddr represents the address of a TCP end point.
|
||||
@@ -54,12 +64,231 @@ func (a *TCPAddr) opAddr() Addr {
|
||||
return a
|
||||
}
|
||||
|
||||
// ResolveTCPAddr returns an address of TCP end point.
|
||||
//
|
||||
// The network must be a TCP network name.
|
||||
//
|
||||
// If the host in the address parameter is not a literal IP address or
|
||||
// the port is not a literal port number, ResolveTCPAddr resolves the
|
||||
// address to an address of TCP end point.
|
||||
// Otherwise, it parses the address as a pair of literal IP address
|
||||
// and port number.
|
||||
// The address parameter can use a host name, but this is not
|
||||
// recommended, because it will return at most one of the host name's
|
||||
// IP addresses.
|
||||
//
|
||||
// See func Dial for a description of the network and address
|
||||
// parameters.
|
||||
func ResolveTCPAddr(network, address string) (*TCPAddr, error) {
|
||||
|
||||
switch network {
|
||||
case "tcp", "tcp4":
|
||||
default:
|
||||
return nil, fmt.Errorf("Network '%s' not supported", network)
|
||||
}
|
||||
|
||||
// TINYGO: Use netdev resolver
|
||||
|
||||
host, sport, err := SplitHostPort(address)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
port, err := strconv.Atoi(sport)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Error parsing port '%s' in address: %s",
|
||||
sport, err)
|
||||
}
|
||||
|
||||
if host == "" {
|
||||
return &TCPAddr{Port: port}, nil
|
||||
}
|
||||
|
||||
ip, err := netdev.GetHostByName(host)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Lookup of host name '%s' failed: %s", host, err)
|
||||
}
|
||||
|
||||
return &TCPAddr{IP: ip, Port: port}, nil
|
||||
}
|
||||
|
||||
// TCPConn is an implementation of the Conn interface for TCP network
|
||||
// connections.
|
||||
type TCPConn struct {
|
||||
conn
|
||||
fd int
|
||||
laddr *TCPAddr
|
||||
raddr *TCPAddr
|
||||
readDeadline time.Time
|
||||
writeDeadline time.Time
|
||||
}
|
||||
|
||||
// DialTCP acts like Dial for TCP networks.
|
||||
//
|
||||
// The network must be a TCP network name; see func Dial for details.
|
||||
//
|
||||
// If laddr is nil, a local address is automatically chosen.
|
||||
// If the IP field of raddr is nil or an unspecified IP address, the
|
||||
// local system is assumed.
|
||||
func DialTCP(network string, laddr, raddr *TCPAddr) (*TCPConn, error) {
|
||||
|
||||
switch network {
|
||||
case "tcp", "tcp4":
|
||||
default:
|
||||
return nil, fmt.Errorf("Network '%s' not supported", network)
|
||||
}
|
||||
|
||||
// TINYGO: Use netdev to create TCP socket and connect
|
||||
|
||||
if raddr == nil {
|
||||
raddr = &TCPAddr{}
|
||||
}
|
||||
|
||||
if raddr.IP.IsUnspecified() {
|
||||
return nil, fmt.Errorf("Sorry, localhost isn't available on Tinygo")
|
||||
}
|
||||
|
||||
fd, err := netdev.Socket(syscall.AF_INET, syscall.SOCK_STREAM, syscall.IPPROTO_TCP)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err = netdev.Connect(fd, "", raddr.IP, raddr.Port); err != nil {
|
||||
netdev.Close(fd)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &TCPConn{
|
||||
fd: fd,
|
||||
laddr: laddr,
|
||||
raddr: raddr,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// TINYGO: Use netdev for Conn methods: Read = Recv, Write = Send, etc.
|
||||
|
||||
func (c *TCPConn) Read(b []byte) (int, error) {
|
||||
var timeout time.Duration
|
||||
|
||||
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
|
||||
if n < 0 {
|
||||
n = 0
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
|
||||
func (c *TCPConn) Write(b []byte) (int, error) {
|
||||
var timeout time.Duration
|
||||
|
||||
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
|
||||
if n < 0 {
|
||||
n = 0
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
|
||||
func (c *TCPConn) Close() error {
|
||||
return netdev.Close(c.fd)
|
||||
}
|
||||
|
||||
func (c *TCPConn) LocalAddr() Addr {
|
||||
return c.laddr
|
||||
}
|
||||
|
||||
func (c *TCPConn) RemoteAddr() Addr {
|
||||
return c.raddr
|
||||
}
|
||||
|
||||
func (c *TCPConn) SetDeadline(t time.Time) error {
|
||||
c.readDeadline = t
|
||||
c.writeDeadline = t
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *TCPConn) SetKeepAlive(keepalive bool) error {
|
||||
return netdev.SetSockOpt(c.fd, syscall.SOL_SOCKET, syscall.SO_KEEPALIVE, keepalive)
|
||||
}
|
||||
|
||||
func (c *TCPConn) SetKeepAlivePeriod(d time.Duration) error {
|
||||
// Units are 1/2 seconds
|
||||
return netdev.SetSockOpt(c.fd, syscall.SOL_TCP, syscall.TCP_KEEPINTVL, 2*d.Seconds())
|
||||
}
|
||||
|
||||
func (c *TCPConn) SetReadDeadline(t time.Time) error {
|
||||
c.readDeadline = t
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *TCPConn) SetWriteDeadline(t time.Time) error {
|
||||
c.writeDeadline = t
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *TCPConn) CloseWrite() error {
|
||||
return &OpError{"close", "", nil, nil, ErrNotImplemented}
|
||||
return fmt.Errorf("CloseWrite not implemented")
|
||||
}
|
||||
|
||||
type listener struct {
|
||||
fd int
|
||||
laddr *TCPAddr
|
||||
}
|
||||
|
||||
func (l *listener) Accept() (Conn, error) {
|
||||
fd, err := netdev.Accept(l.fd, IP{}, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &TCPConn{
|
||||
fd: fd,
|
||||
laddr: l.laddr,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (l *listener) Close() error {
|
||||
return netdev.Close(l.fd)
|
||||
}
|
||||
|
||||
func (l *listener) Addr() Addr {
|
||||
return l.laddr
|
||||
}
|
||||
|
||||
func listenTCP(laddr *TCPAddr) (Listener, error) {
|
||||
fd, err := netdev.Socket(syscall.AF_INET, syscall.SOCK_STREAM, syscall.IPPROTO_TCP)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = netdev.Bind(fd, laddr.IP, laddr.Port)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = netdev.Listen(fd, 5)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &listener{fd: fd, laddr: laddr}, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user