mirror of
https://github.com/tinygo-org/drivers.git
synced 2026-07-26 10:38:41 +00:00
1bb1b621c6
Signed-off-by: deadprogram <ron@hybridgroup.com>
421 lines
12 KiB
Go
421 lines
12 KiB
Go
// package net is intended to provide compatible interfaces with the
|
|
// Go standard library's net package.
|
|
package net
|
|
|
|
import (
|
|
"errors"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// DialUDP makes a UDP network connection. raadr is the port that the messages will
|
|
// be sent to, and laddr is the port that will be listened to in order to
|
|
// receive incoming messages.
|
|
func DialUDP(network string, laddr, raddr *UDPAddr) (*UDPSerialConn, error) {
|
|
addr := raddr.IP.String()
|
|
sendport := strconv.Itoa(raddr.Port)
|
|
listenport := strconv.Itoa(laddr.Port)
|
|
|
|
// disconnect any old socket
|
|
ActiveDevice.DisconnectSocket()
|
|
|
|
// connect new socket
|
|
err := ActiveDevice.ConnectUDPSocket(addr, sendport, listenport)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &UDPSerialConn{SerialConn: SerialConn{Adaptor: ActiveDevice}, laddr: laddr, raddr: raddr}, nil
|
|
}
|
|
|
|
// ListenUDP listens for UDP connections on the port listed in laddr.
|
|
func ListenUDP(network string, laddr *UDPAddr) (*UDPSerialConn, error) {
|
|
addr := "0"
|
|
sendport := "0"
|
|
listenport := strconv.Itoa(laddr.Port)
|
|
|
|
// disconnect any old socket
|
|
ActiveDevice.DisconnectSocket()
|
|
|
|
// connect new socket
|
|
err := ActiveDevice.ConnectUDPSocket(addr, sendport, listenport)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &UDPSerialConn{SerialConn: SerialConn{Adaptor: ActiveDevice}, laddr: laddr}, nil
|
|
}
|
|
|
|
// DialTCP makes a TCP network connection. raadr is the port that the messages will
|
|
// be sent to, and laddr is the port that will be listened to in order to
|
|
// receive incoming messages.
|
|
func DialTCP(network string, laddr, raddr *TCPAddr) (*TCPSerialConn, error) {
|
|
addr := raddr.IP.String()
|
|
sendport := strconv.Itoa(raddr.Port)
|
|
|
|
// disconnect any old socket?
|
|
//ActiveDevice.DisconnectSocket()
|
|
|
|
// connect new socket
|
|
err := ActiveDevice.ConnectTCPSocket(addr, sendport)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &TCPSerialConn{SerialConn: SerialConn{Adaptor: ActiveDevice}, laddr: laddr, raddr: raddr}, nil
|
|
}
|
|
|
|
// Dial connects to the address on the named network.
|
|
// It tries to provide a mostly compatible interface
|
|
// to net.Dial().
|
|
func Dial(network, address string) (Conn, error) {
|
|
switch network {
|
|
case "tcp":
|
|
raddr, err := ResolveTCPAddr(network, address)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
c, e := DialTCP(network, &TCPAddr{}, raddr)
|
|
return c.opConn(), e
|
|
case "udp":
|
|
raddr, err := ResolveUDPAddr(network, address)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
c, e := DialUDP(network, &UDPAddr{}, raddr)
|
|
return c.opConn(), e
|
|
default:
|
|
return nil, errors.New("invalid network for dial")
|
|
}
|
|
}
|
|
|
|
// SerialConn is a loosely net.Conn compatible implementation
|
|
type SerialConn struct {
|
|
Adaptor Adapter
|
|
}
|
|
|
|
// UDPSerialConn is a loosely net.Conn compatible intended to support
|
|
// UDP over serial.
|
|
type UDPSerialConn struct {
|
|
SerialConn
|
|
laddr *UDPAddr
|
|
raddr *UDPAddr
|
|
}
|
|
|
|
// NewUDPSerialConn returns a new UDPSerialConn/
|
|
func NewUDPSerialConn(c SerialConn, laddr, raddr *UDPAddr) *UDPSerialConn {
|
|
return &UDPSerialConn{SerialConn: c, raddr: raddr}
|
|
}
|
|
|
|
// TCPSerialConn is a loosely net.Conn compatible intended to support
|
|
// TCP over serial.
|
|
type TCPSerialConn struct {
|
|
SerialConn
|
|
laddr *TCPAddr
|
|
raddr *TCPAddr
|
|
}
|
|
|
|
// NewTCPSerialConn returns a new TCPSerialConn/
|
|
func NewTCPSerialConn(c SerialConn, laddr, raddr *TCPAddr) *TCPSerialConn {
|
|
return &TCPSerialConn{SerialConn: c, raddr: raddr}
|
|
}
|
|
|
|
// Read reads data from the connection.
|
|
// TODO: implement the full method functionality:
|
|
// Read can be made to time out and return an Error with Timeout() == true
|
|
// after a fixed time limit; see SetDeadline and SetReadDeadline.
|
|
func (c *SerialConn) Read(b []byte) (n int, err error) {
|
|
// read only the data that has been received via "+IPD" socket
|
|
return c.Adaptor.ReadSocket(b)
|
|
}
|
|
|
|
// Write writes data to the connection.
|
|
// TODO: implement the full method functionality for timeouts.
|
|
// Write can be made to time out and return an Error with Timeout() == true
|
|
// after a fixed time limit; see SetDeadline and SetWriteDeadline.
|
|
func (c *SerialConn) Write(b []byte) (n int, err error) {
|
|
// specify that is a data transfer to the
|
|
// currently open socket, not commands to the ESP8266/ESP32.
|
|
err = c.Adaptor.StartSocketSend(len(b))
|
|
if err != nil {
|
|
return
|
|
}
|
|
n, err = c.Adaptor.Write(b)
|
|
if err != nil {
|
|
return n, err
|
|
}
|
|
/* TODO(bcg): this is kind of specific to espat, should maybe refactor */
|
|
_, err = c.Adaptor.Response(1000)
|
|
if err != nil {
|
|
return n, err
|
|
}
|
|
return n, err
|
|
}
|
|
|
|
// Close closes the connection.
|
|
// Currently only supports a single Read or Write operations without blocking.
|
|
func (c *SerialConn) Close() error {
|
|
c.Adaptor.DisconnectSocket()
|
|
return nil
|
|
}
|
|
|
|
// LocalAddr returns the local network address.
|
|
func (c *UDPSerialConn) LocalAddr() Addr {
|
|
return c.laddr.opAddr()
|
|
}
|
|
|
|
// RemoteAddr returns the remote network address.
|
|
func (c *UDPSerialConn) RemoteAddr() Addr {
|
|
return c.raddr.opAddr()
|
|
}
|
|
|
|
func (c *UDPSerialConn) opConn() Conn {
|
|
if c == nil {
|
|
return nil
|
|
}
|
|
return c
|
|
}
|
|
|
|
// LocalAddr returns the local network address.
|
|
func (c *TCPSerialConn) LocalAddr() Addr {
|
|
return c.laddr.opAddr()
|
|
}
|
|
|
|
// RemoteAddr returns the remote network address.
|
|
func (c *TCPSerialConn) RemoteAddr() Addr {
|
|
return c.raddr.opAddr()
|
|
}
|
|
|
|
func (c *TCPSerialConn) opConn() Conn {
|
|
if c == nil {
|
|
return nil
|
|
}
|
|
return c
|
|
}
|
|
|
|
// SetDeadline sets the read and write deadlines associated
|
|
// with the connection. It is equivalent to calling both
|
|
// SetReadDeadline and SetWriteDeadline.
|
|
//
|
|
// A deadline is an absolute time after which I/O operations
|
|
// fail with a timeout (see type Error) instead of
|
|
// blocking. The deadline applies to all future and pending
|
|
// I/O, not just the immediately following call to Read or
|
|
// Write. After a deadline has been exceeded, the connection
|
|
// can be refreshed by setting a deadline in the future.
|
|
//
|
|
// An idle timeout can be implemented by repeatedly extending
|
|
// the deadline after successful Read or Write calls.
|
|
//
|
|
// A zero value for t means I/O operations will not time out.
|
|
func (c *SerialConn) SetDeadline(t time.Time) error {
|
|
return nil
|
|
}
|
|
|
|
// 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.
|
|
func (c *SerialConn) SetReadDeadline(t time.Time) error {
|
|
return nil
|
|
}
|
|
|
|
// SetWriteDeadline sets the deadline for future Write calls
|
|
// and any currently-blocked Write call.
|
|
// Even if write times out, it may return n > 0, indicating that
|
|
// some of the data was successfully written.
|
|
// A zero value for t means Write will not time out.
|
|
func (c *SerialConn) SetWriteDeadline(t time.Time) error {
|
|
return nil
|
|
}
|
|
|
|
// ResolveTCPAddr returns an address of TCP end point.
|
|
//
|
|
// The network must be a TCP network name.
|
|
func ResolveTCPAddr(network, address string) (*TCPAddr, error) {
|
|
// TODO: make sure network is 'tcp'
|
|
// separate domain from port, if any
|
|
r := strings.Split(address, ":")
|
|
addr, err := ActiveDevice.GetDNS(r[0])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
ip := IP(addr)
|
|
if len(r) > 1 {
|
|
port, e := strconv.Atoi(r[1])
|
|
if e != nil {
|
|
return nil, e
|
|
}
|
|
return &TCPAddr{IP: ip, Port: port}, nil
|
|
}
|
|
return &TCPAddr{IP: ip}, nil
|
|
}
|
|
|
|
// ResolveUDPAddr returns an address of UDP end point.
|
|
//
|
|
// The network must be a UDP network name.
|
|
func ResolveUDPAddr(network, address string) (*UDPAddr, error) {
|
|
// TODO: make sure network is 'udp'
|
|
// separate domain from port, if any
|
|
r := strings.Split(address, ":")
|
|
addr, err := ActiveDevice.GetDNS(r[0])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
ip := IP(addr)
|
|
if len(r) > 1 {
|
|
port, e := strconv.Atoi(r[1])
|
|
if e != nil {
|
|
return nil, e
|
|
}
|
|
return &UDPAddr{IP: ip, Port: port}, nil
|
|
}
|
|
|
|
return &UDPAddr{IP: ip}, nil
|
|
}
|
|
|
|
// The following definitions are here to support a Golang standard package
|
|
// net-compatible interface for IP until TinyGo can compile the net package.
|
|
|
|
// IP is an IP address. Unlike the standard implementation, it is only
|
|
// a buffer of bytes that contains the string form of the IP address, not the
|
|
// full byte format used by the Go standard .
|
|
type IP []byte
|
|
|
|
// UDPAddr here to serve as compatible type. until TinyGo can compile the net package.
|
|
type UDPAddr struct {
|
|
IP IP
|
|
Port int
|
|
Zone string // IPv6 scoped addressing zone; added in Go 1.1
|
|
}
|
|
|
|
// Network returns the address's network name, "udp".
|
|
func (a *UDPAddr) Network() string { return "udp" }
|
|
|
|
func (a *UDPAddr) String() string {
|
|
if a == nil {
|
|
return "<nil>"
|
|
}
|
|
if a.Port != 0 {
|
|
return a.IP.String() + ":" + strconv.Itoa(a.Port)
|
|
}
|
|
return a.IP.String()
|
|
}
|
|
|
|
func (a *UDPAddr) opAddr() Addr {
|
|
if a == nil {
|
|
return nil
|
|
}
|
|
return a
|
|
}
|
|
|
|
// TCPAddr here to serve as compatible type. until TinyGo can compile the net package.
|
|
type TCPAddr struct {
|
|
IP IP
|
|
Port int
|
|
Zone string // IPv6 scoped addressing zone
|
|
}
|
|
|
|
// Network returns the address's network name, "tcp".
|
|
func (a *TCPAddr) Network() string { return "tcp" }
|
|
|
|
func (a *TCPAddr) String() string {
|
|
if a == nil {
|
|
return "<nil>"
|
|
}
|
|
if a.Port != 0 {
|
|
return a.IP.String() + ":" + strconv.Itoa(a.Port)
|
|
}
|
|
return a.IP.String()
|
|
}
|
|
|
|
func (a *TCPAddr) opAddr() Addr {
|
|
if a == nil {
|
|
return nil
|
|
}
|
|
return a
|
|
}
|
|
|
|
// ParseIP parses s as an IP address, returning the result.
|
|
func ParseIP(s string) IP {
|
|
b := strings.Split(s, ".")
|
|
if len(b) == 4 {
|
|
ip := make([]byte, 4)
|
|
|
|
for i := range ip {
|
|
x, _ := strconv.ParseUint(b[i], 10, 8)
|
|
ip[i] = byte(x)
|
|
}
|
|
|
|
return IP(ip)
|
|
}
|
|
|
|
return IP([]byte(s))
|
|
}
|
|
|
|
// String returns the string form of the IP address ip.
|
|
func (ip IP) String() string {
|
|
return string(ip)
|
|
}
|
|
|
|
// Conn is a generic stream-oriented network connection.
|
|
// This interface is from the Go standard library.
|
|
type Conn interface {
|
|
// Read reads data from the connection.
|
|
// Read can be made to time out and return an Error with Timeout() == true
|
|
// after a fixed time limit; see SetDeadline and SetReadDeadline.
|
|
Read(b []byte) (n int, err error)
|
|
|
|
// Write writes data to the connection.
|
|
// Write can be made to time out and return an Error with Timeout() == true
|
|
// after a fixed time limit; see SetDeadline and SetWriteDeadline.
|
|
Write(b []byte) (n int, err error)
|
|
|
|
// Close closes the connection.
|
|
// Any blocked Read or Write operations will be unblocked and return errors.
|
|
Close() error
|
|
|
|
// LocalAddr returns the local network address.
|
|
LocalAddr() Addr
|
|
|
|
// RemoteAddr returns the remote network address.
|
|
RemoteAddr() Addr
|
|
|
|
// SetDeadline sets the read and write deadlines associated
|
|
// with the connection. It is equivalent to calling both
|
|
// SetReadDeadline and SetWriteDeadline.
|
|
//
|
|
// A deadline is an absolute time after which I/O operations
|
|
// fail with a timeout (see type Error) instead of
|
|
// blocking. The deadline applies to all future and pending
|
|
// I/O, not just the immediately following call to Read or
|
|
// Write. After a deadline has been exceeded, the connection
|
|
// can be refreshed by setting a deadline in the future.
|
|
//
|
|
// An idle timeout can be implemented by repeatedly extending
|
|
// the deadline after successful Read or Write calls.
|
|
//
|
|
// A zero value for t means I/O operations will not time out.
|
|
SetDeadline(t time.Time) error
|
|
|
|
// 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.
|
|
SetReadDeadline(t time.Time) error
|
|
|
|
// SetWriteDeadline sets the deadline for future Write calls
|
|
// and any currently-blocked Write call.
|
|
// Even if write times out, it may return n > 0, indicating that
|
|
// some of the data was successfully written.
|
|
// A zero value for t means Write will not time out.
|
|
SetWriteDeadline(t time.Time) error
|
|
}
|
|
|
|
// Addr represents a network end point address.
|
|
type Addr interface {
|
|
Network() string // name of the network (for example, "tcp", "udp")
|
|
String() string // string form of address (for example, "192.0.2.1:25", "[2001:db8::1]:80")
|
|
}
|