water

package module
v0.6.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 18, 2024 License: Apache-2.0 Imports: 16 Imported by: 1

README

W.A.T.E.R.: WebAssembly Transport Executables Runtime

Apache-2.0 FOSSA CI Go Doc

WATER-go provides a Go runtime for WebAssembly Transport Modules(WATM) as a pluggable application-layer transport protocol provider. It is designed to be highly portable and lightweight, allowing for rapidly deployable pluggable transports. While other pluggable transport implementations require a fresh client deployment (and app-store review) to update their protocol WATER allows dynamic delivery of new transports in real time over the network or out-of-band.

WATER wasm transport

To build a WATM in Go, please refer to watm for examples and helper libraries interfacing Pluggable Transports-like interfaces. Official Go compiler is currently not supported until further notice.

You can contact one of developers personally via gaukas.wang@colorado.edu, or simply opening an issue.

The Rust implementation of the runtime library and information about writing, building, and using WebAssembly Transport Modules(WATM) from Rust can be found in water-rs.

Cite our work

If you quoted or used our work in your own project/paper/research, please cite our paper Just add WATER: WebAssembly-based Circumvention Transports, which is published in the proceedings of Free and Open Communications on the Internet (FOCI) in 2024 issue 1, pages 22-28.

BibTeX
@inproceedings{water-foci24,
    author = {Erik Chi and Gaukas Wang and J. Alex Halderman and Eric Wustrow and Jack Wampler},
    title = {Just add {WATER}: {WebAssembly}-based Circumvention Transports},
    booktitle = {Free and Open Communications on the Internet},
    publisher = {},
    year = {2024},
    url = {https://www.petsymposium.org/foci/2024/foci-2024-0003.pdf},
}

Be Water

Empty your mind, be formless, shapeless, like water. If you put water into a cup, it becomes the cup. You put water into a bottle and it becomes the bottle. You put it in a teapot, it becomes the teapot. Now, water can flow or it can crash. Be water, my friend.

-- Bruce Lee

License

This project is licensed under Apache 2.0 license.

Contents

This repo contains a Go package water, which implements the runtime library used to interact with .wasm WebAssembly Transport Modules(WATM).

Usage

Based on WASI Snapshot Preview 1 (wasip1), currently W.A.T.E.R. provides a set of net-like APIs via Dialer, Listener and Relay.

Versioning

W.A.T.E.R. is designed to be future-proof with the automated multi-version WebAssembly Transport Module(WATM) support. In order to minimize the size of compiled application binaries importing water, the support for each WATM version is implemented in separate sub-packages and by default none will be enabled. The developer MUST manually enable each version to be supported by importing the corresponding package:

import (
	// ...

	_ "github.com/refraction-networking/water/transport/v0"

	// ...
)

Otherwise, it is possible that the W.A.T.E.R. runtime cannot determine the version of the WATM and therefore fail to select the corresponding runtime:

panic: failed to listen: water: listener version not found
Customizable Version

TODO: add documentations for customizable WATM version.

Components

Dialer

A Dialer connects to a remote address and returns a net.Conn to the caller if the connection can be successfully established. The net.Conn then provides tunnelled read and write to the remote endpoint with the WebAssembly module wrapping / encrypting / transforming the traffic.

Dialer is used to encapsulate the caller's connection into an outbound, transport-wrapped connection.

	wasm, _ := os.ReadFile("./examples/v0/plain/plain.wasm")

	config := &water.Config{
		TransportModuleBin: wasm,
	}

	dialer, _ := water.NewDialerWithContext(context.Background(), config)
	conn, _ := dialer.DialContext(context.Background(),"tcp", remoteAddr)
	// ...
Listener

A Listener listens on a local address for incoming connections which it Accept()s, returning a net.Conn for the caller to handle. The WebAssembly Module is responsible for the initial accpt allowing it to implement both the server side handshake as well as any unwrap / decrypt /reform operations required to validate and re-assemble the stream. The net.Conn returned provides the normalized stream, and allows the caller to write back to the client with the WebAssembly module encoding / encrypting / transforming traffic to be obfuscated on the wire on the way to the remote client.

Listener is used to decapsulate incoming transport-wrapped connections for the caller to handle, managing the tunnel obfuscation once a connection is established.

	wasm, _ := os.ReadFile("./examples/v0/plain/plain.wasm")

	config := &water.Config{
		TransportModuleBin: wasm,
	}

	lis, _ := config.ListenContext(context.Background(), "tcp", localAddr)
	defer lis.Close()
	log.Printf("Listening on %s", lis.Addr().String())

	for {
		conn, err := lis.Accept()
		handleConn(conn)
	}

	// ...
Relay

A Relay combines the role of Dialer and Listener. It listens on a local address Accept()-ing incoming connections and Dial()-ing the remote endpoints on establishment. The connecions are tunneled through the WebAssembly Transport Module allowing the module to handshake, encode, transform, pad, etc. without any caller interaction. The internal Relay manages the incoming connections as well as the associated outgoing connectons.

Relay is a managed many-to-many handler for incoming connections that uses the WebAssemble module to tunnel traffic.

	wasm, _ := os.ReadFile("./examples/v0/plain/plain.wasm")

	config := &water.Config{
		TransportModuleBin: wasm,
	}

	relay, _ := water.NewRelayWithContext(context.Background(), config)

	relay.ListenAndRelayTo("tcp", localAddr, "tcp", remoteAddr) // blocking

Example

See examples for example usecase of W.A.T.E.R. API, including Dialer, Listener and Relay.

Submodules

watm has its own licensing policy, please refer to watm for more information.

Cross-platform Support

W.A.T.E.R. is designed to be cross-platform (and cross-architecture). Currently, it supports the following platforms:

Target Compiles? Tests Pass?
linux/amd64
linux/arm64
linux/riscv64
macos/amd64
macos/arm64
windows/amd64
windows/arm64
others

Acknowledgments

  • We thank GitHub.com for providing GitHub Actions runners for all targets below:

  • We thank FlyCI.net for providing GitHub Actions runners on macos/arm64 (Apple M1) in the past. (We switched to GitHub's macos-14 runner as of Jan 31 2024)

We are currently actively looking for a CI provider for more target platforms. Please reach out and let us know if you would like to help.

Documentation

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	ErrModuleNotImported = fmt.Errorf("water: importing a module not imported by the WebAssembly module")
	ErrFuncNotImported   = fmt.Errorf("water: importing a function not imported by the WebAssembly module")
)
View Source
var (
	ErrDialerAlreadyRegistered = errors.New("water: dialer already registered")
	ErrDialerVersionNotFound   = errors.New("water: dialer version not found")
	ErrUnimplementedDialer     = errors.New("water: unimplemented dialer")
)
View Source
var (
	ErrListenerAlreadyRegistered = errors.New("water: listener already registered")
	ErrListenerVersionNotFound   = errors.New("water: listener version not found")
	ErrUnimplementedListener     = errors.New("water: unimplemented Listener")
)
View Source
var (
	ErrRelayAlreadyRegistered = errors.New("water: relay already registered")
	ErrRelayVersionNotFound   = errors.New("water: relay version not found")
	ErrUnimplementedRelay     = errors.New("water: unimplemented relay")
	ErrRelayAlreadyStarted    = errors.New("water: relay already started") // RelayTo and ListenAndRelayTo may return this error if a relay was reused.

)

Functions

func RegisterWATMDialer

func RegisterWATMDialer(version string, dialer newDialerFunc) error

RegisterWATMDialer is a function used by Transport Module drivers (e.g., `transport/v0`) to register a function that spawns a new Dialer from a given Config for a specific version. Renamed from RegisterDialer.

This is not a part of WATER API and should not be used by developers wishing to integrate WATER into their applications.

func RegisterWATMListener

func RegisterWATMListener(version string, listener newListenerFunc) error

RegisterWATMListener is a function used by Transport Module drivers (e.g., `transport/v0`) to register a function that spawns a new Listener from a given Config for a specific version. Renamed from RegisterListener.

This is not a part of WATER API and should not be used by developers wishing to integrate WATER into their applications.

func RegisterWATMRelay

func RegisterWATMRelay(version string, relay newRelayFunc) error

RegisterWATMRelay is a function used by Transport Module drivers (e.g., `transport/v0`) to register a function that spawns a new Relay from a given Config for a specific version. Renamed from RegisterRelay.

This is not a part of WATER API and should not be used by developers wishing to integrate WATER into their applications.

func SetDefaultLogHandler

func SetDefaultLogHandler(handler log.Handler)

SetDefaultLogHandler sets the handler to be used by the package if no logger is specifically configured for each component. Renamed from SetDefaultHandler.

It overrides the logger specified by SetDefaultLogger.

func SetDefaultLogger

func SetDefaultLogger(logger *log.Logger)

SetDefaultLogger sets the logger to be used by the package if no logger is specifically configured for each component.

By default, slog.Default() is used.

func SetGlobalCompilationCache

func SetGlobalCompilationCache(cache wazero.CompilationCache)

SetGlobalCompilationCache sets the global CompilationCache for the WebAssembly runtime. This is useful for sharing the cache between multiple WebAssembly modules and should be called before any WebAssembly module is instantiated.

Types

type Config

type Config struct {
	// TransportModuleBin contains the binary format of the WebAssembly
	// Transport Module.
	// In practice, this mandatory field could be populated by loading
	// a .wasm file, downloading from a remote host, or generating from
	// a .wat (WebAssembly Text Format) file.
	TransportModuleBin []byte

	// TransportModuleConfig optionally provides a configuration file to be pushed into
	// the WASM Transport Module.
	TransportModuleConfig TransportModuleConfig

	// NetworkDialerFunc specifies a func that dials the specified address on the
	// named network. This optional field can be set to override the Go
	// default dialer func:
	// 	net.Dial(network, address)
	NetworkDialerFunc func(network, address string) (net.Conn, error)

	// NetworkListener specifies a net.listener implementation that listens
	// on the specified address on the named network. This optional field
	// will be used to provide (incoming) network connections from a
	// presumably remote source to the WASM instance.
	//
	// Calling (*Config).Listen will override this field.
	NetworkListener net.Listener

	// ModuleConfigFactory is used to configure the system resource of
	// each WASM instance created. This field is for advanced use cases
	// and/or debugging purposes only.
	//
	// Caller is supposed to call c.ModuleConfig() to get the pointer to the
	// ModuleConfigFactory. If the pointer is nil, a new ModuleConfigFactory will
	// be created and returned.
	ModuleConfigFactory *WazeroModuleConfigFactory

	RuntimeConfigFactory *WazeroRuntimeConfigFactory

	OverrideLogger *log.Logger // essentially a *slog.Logger, currently using an alias to flatten the version discrepancy
}

Config defines the configuration for the WATER Dialer/Config interface.

func (*Config) Clone

func (c *Config) Clone() *Config

Clone creates a deep copy of the Config.

func (*Config) Listen deprecated

func (c *Config) Listen(network, address string) (Listener, error)

Listen creates a new Listener from the config on the specified network and address.

For now, only TCP is supported.

Deprecated: use ListenContext instead.

func (*Config) ListenContext

func (c *Config) ListenContext(ctx context.Context, network, address string) (Listener, error)

ListenContext creates a new Listener from the config on the specified network and address with the given context.

For now, only TCP is supported.

func (*Config) Logger

func (c *Config) Logger() *log.Logger

func (*Config) ModuleConfig

func (c *Config) ModuleConfig() *WazeroModuleConfigFactory

ModuleConfig returns the ModuleConfigFactory. If the pointer is nil, a new ModuleConfigFactory will be created and returned.

func (*Config) NetworkDialerFuncOrDefault

func (c *Config) NetworkDialerFuncOrDefault() func(network, address string) (net.Conn, error)

NetworkDialerFuncOrDefault returns the DialerFunc if it is not nil, otherwise returns the default net.Dial function.

func (*Config) NetworkListenerOrPanic

func (c *Config) NetworkListenerOrPanic() net.Listener

NetworkListenerOrDefault returns the NetworkListener if it is not nil, otherwise it panics.

func (*Config) RuntimeConfig

func (c *Config) RuntimeConfig() *WazeroRuntimeConfigFactory

func (*Config) UnmarshalJSON

func (c *Config) UnmarshalJSON(data []byte) error

UnmarshalJSON implements the json.Unmarshaler interface.

func (*Config) UnmarshalProto

func (c *Config) UnmarshalProto(b []byte) error

UnmarshalProto provides a way to unmarshal a protobuf message into a Config.

The message definition is defined in configbuilder/pb/config.proto.

func (*Config) WATMBinOrPanic

func (c *Config) WATMBinOrPanic() []byte

WATMBinOrDefault returns the WATMBin if it is not nil, otherwise it panics.

type Conn

type Conn interface {
	net.Conn
	// contains filtered or unexported methods
}

Conn is an abstracted connection interface which is expected to encapsulate a Core.

type Core

type Core interface {
	// Config returns the Config used to create the Core.
	//
	// Practically, this function is not supposed to be used
	// to retrieve the Config to be used for creating another
	// Core. Instead, it is used to retrieve the Config for
	// inspection/debugging purposes.
	Config() *Config

	// Context returns the base context used by the Core.
	Context() context.Context

	// Close closes the Core and releases all the resources
	// associated with it.
	Close() error

	// Exports dumps all the exported functions and globals which
	// are provided by the WebAssembly module.
	//
	// This function returns a map of export name to the type of
	// the export.
	Exports() map[string]api.ExternType

	// ExportedFunction returns the exported function with the
	// given name. If no function with the given name is exported,
	// this function returns nil.
	//
	// It is caller's responsibility to ensure that the function
	// returned has the correct signature, which can be checked
	// by inspecting the returned api.Function.Definition().
	ExportedFunction(name string) api.Function

	// Imports dumps all the imported functions and globals which
	// are required to be provided by the host environment to
	// instantiate the WebAssembly module.
	//
	// This function returns a map of module name to a map of
	// import name to the type of the import.
	ImportedFunctions() map[string]map[string]api.FunctionDefinition

	// ImportFunction imports a function into the WebAssembly module.
	//
	// The f argument must be a function with the signature matching
	// the signature of the function to be imported. Otherwise, the
	// behavior of the WebAssembly Transport Module after initialization
	// is undefined.
	//
	// This function can be called ONLY BEFORE calling Instantiate().
	ImportFunction(module, name string, f any) error

	// InsertConn inserts a net.Conn into the WebAssembly Transport
	// Module and returns the key of the inserted connection as a
	// file descriptor accessible from the WebAssembly instance.
	//
	// This function SHOULD be called only if the WebAssembly instance
	// execution is blocked/halted/stopped. Otherwise, race conditions
	// or undefined behaviors may occur.
	InsertConn(conn net.Conn) (fd int32, err error)

	// InsertListener inserts a net.Listener into the WebAssembly
	// Transport Module and returns the key of the inserted listener
	// as a file descriptor accessible from the WebAssembly instance.
	//
	// This function SHOULD be called only if the WebAssembly instance
	// execution is blocked/halted/stopped. Otherwise, race conditions
	// or undefined behaviors may occur.
	InsertListener(tcpListener net.Listener) (fd int32, err error)

	// InsertFile inserts a file into the WebAssembly Transport Module
	// and returns the key of the inserted file as a file descriptor
	// accessible from the WebAssembly instance.
	//
	// This function SHOULD be called only if the WebAssembly instance
	// execution is blocked/halted/stopped. Otherwise, race conditions
	// or undefined behaviors may occur.
	InsertFile(osFile *os.File) (fd int32, err error)

	// Instantiate instantiates the module into a new instance of
	// WebAssembly Transport Module.
	Instantiate() error

	// Invoke invokes a function in the WebAssembly instance.
	//
	// If the target function is not exported, this function returns an error.
	Invoke(funcName string, params ...uint64) (results []uint64, err error)

	// WASIPreview1 enables the WASI preview1 API.
	//
	// It is recommended that this function only to be invoked if
	// the WATM expects the WASI preview1 API to be available.
	//
	// Note that at the time of writing, all WATM implementations
	// expect the WASI preview1 API to be available.
	WASIPreview1() error

	// Logger returns the logger used by the Core. If not set, it
	// should return the default global logger instead of nil.
	Logger() *log.Logger
}

Core provides the low-level access to the WebAssembly runtime environment.

func NewCore deprecated

func NewCore(config *Config) (Core, error)

NewCore creates a new Core with the given config.

It uses the default implementation of interface.Core as defined in this file.

Deprecated: use NewCoreWithContext instead.

func NewCoreWithContext

func NewCoreWithContext(ctx context.Context, config *Config) (Core, error)

NewCoreWithContext creates a new Core with the given context and config.

It uses the default implementation of interface.Core as defined in this file.

The context is used to control the lifetime of the call to function calls into the WebAssembly module. If the context is canceled or reaches its deadline, any current and future function call will return with an error. Call WazeroRuntimeConfigFactory.SetCloseOnContextDone with false to disable this behavior.

type Dialer

type Dialer interface {
	// Dial dials the remote network address and returns a net.Conn.
	//
	// It is recommended to use DialContext instead of Dial.
	Dial(network, address string) (Conn, error)

	// DialContext dials the remote network address with the given context
	// and returns a net.Conn.
	DialContext(ctx context.Context, network, address string) (Conn, error)
	// contains filtered or unexported methods
}

Dialer dials a remote network address upon caller calling Dial() and returns a net.Conn which is upgraded by the WebAssembly Transport Module.

The structure of a Dialer is as follows:

        dial +----------------+ dial
       ----->|        Upgrade |------>
Caller       |   WebAssembly  |        Remote
       <-----| Downgrade      |<------
             +----------------+
                   Dialer
Example

ExampleDialer demonstrates how to use water.Dialer.

This example is expected to demonstrate how to use the LATEST version of W.A.T.E.R. API, while other older examples could be found under transport/vX, where X is the version number (e.g. v0, v1, etc.).

It is worth noting that unless the W.A.T.E.R. API changes, the version upgrade does not bring any essential changes to this example other than the import path and wasm file path.

config := &water.Config{
	TransportModuleBin:  wasmReverse,
	ModuleConfigFactory: water.NewWazeroModuleConfigFactory(),
}

waterDialer, err := water.NewDialer(config)
if err != nil {
	panic(err)
}

// create a local TCP listener
tcpListener, err := net.Listen("tcp", "localhost:0")
if err != nil {
	panic(err)
}
defer tcpListener.Close() // skipcq: GO-S2307

waterConn, err := waterDialer.DialContext(context.Background(), "tcp", tcpListener.Addr().String())
if err != nil {
	panic(err)
}
defer waterConn.Close() // skipcq: GO-S2307

tcpConn, err := tcpListener.Accept()
if err != nil {
	panic(err)
}
defer tcpConn.Close() // skipcq: GO-S2307

var msg = []byte("hello")
n, err := waterConn.Write(msg)
if err != nil {
	panic(err)
}
if n != len(msg) {
	panic("short write")
}

buf := make([]byte, 1024)
n, err = tcpConn.Read(buf)
if err != nil {
	panic(err)
}
if n != len(msg) {
	panic("short read")
}

fmt.Println(string(buf[:n]))
Output:

olleh

func NewDialer deprecated

func NewDialer(c *Config) (Dialer, error)

NewDialer creates a new Dialer from the given Config.

It automatically detects the version of the WebAssembly Transport Module specified in the config.

Deprecated: use NewDialerWithContext instead.

func NewDialerWithContext

func NewDialerWithContext(ctx context.Context, c *Config) (Dialer, error)

NewDialerWithContext creates a new Dialer from the Config with the given context.Context.

It automatically detects the version of the WebAssembly Transport Module specified in the config.

The context is passed to NewCoreWithContext and the registered versioned dialer creation function to control the lifetime of the call to function calls into the WebAssembly module. If the context is canceled or reaches its deadline, any current and future function call will return with an error. Call WazeroRuntimeConfigFactory.SetCloseOnContextDone with false to disable this behavior.

The context SHOULD be used as the default context for call to [Dialer.Dial] by the dialer implementation.

type Listener

type Listener interface {
	// Listener implements net.Listener
	net.Listener

	// AcceptWATER waits for and returns the next connection to the listener
	// as a water.Conn.
	AcceptWATER() (Conn, error)
	// contains filtered or unexported methods
}

Listener listens on a local network address and upon caller calling Accept(), it accepts an incoming connection and returns the net.Conn upgraded by the WebAssembly Transport Module.

The structure of a Listener is as follows:

            +---------------+ accept +---------------+ accept
       ---->|               |------->|     Downgrade |------->
Source      |  net.Listener |        |  WebAssembly  |         Caller
       <----|               |<-------| Upgrade       |<-------
            +---------------+        +---------------+
                     \                      /
                      \------Listener------/

As shown above, a Listener consists of a net.Listener to accept incoming connections and a WATM to handle the incoming connections from an external source. Accept() returns a net.Conn that caller may Read()-from or Write()-to.

Example

ExampleListener demonstrates how to use water.Listener.

This example is expected to demonstrate how to use the LATEST version of W.A.T.E.R. API, while other older examples could be found under transport/vX, where X is the version number (e.g. v0, v1, etc.).

It is worth noting that unless the W.A.T.E.R. API changes, the version upgrade does not bring any essential changes to this example other than the import path and wasm file path.

config := &water.Config{
	TransportModuleBin:  wasmReverse,
	ModuleConfigFactory: water.NewWazeroModuleConfigFactory(),
}

waterListener, err := config.ListenContext(context.Background(), "tcp", "localhost:0")
if err != nil {
	panic(err)
}
defer waterListener.Close() // skipcq: GO-S2307

tcpConn, err := net.Dial("tcp", waterListener.Addr().String())
if err != nil {
	panic(err)
}
defer tcpConn.Close() // skipcq: GO-S2307

waterConn, err := waterListener.Accept()
if err != nil {
	panic(err)
}
defer waterConn.Close() // skipcq: GO-S2307

var msg = []byte("hello")
n, err := tcpConn.Write(msg)
if err != nil {
	panic(err)
}
if n != len(msg) {
	panic("short write")
}

buf := make([]byte, 1024)
n, err = waterConn.Read(buf)
if err != nil {
	panic(err)
}
if n != len(msg) {
	panic("short read")
}

fmt.Println(string(buf[:n]))
Output:

olleh

func NewListener deprecated

func NewListener(c *Config) (Listener, error)

NewListener creates a new Listener from the given Config.

It automatically detects the version of the WebAssembly Transport Module specified in the config.

Deprecated: use NewListenerWithContext instead.

func NewListenerWithContext

func NewListenerWithContext(ctx context.Context, c *Config) (Listener, error)

NewListenerWithContext creates a new Listener from the Config with the given context.Context.

It automatically detects the version of the WebAssembly Transport Module specified in the config.

The context is passed to NewCoreWithContext and the registered versioned listener creation function to control the lifetime of the call to function calls into the WebAssembly module. If the context is canceled or reaches its deadline, any current and future function call will return with an error. Call WazeroRuntimeConfigFactory.SetCloseOnContextDone with false to disable this behavior.

type Relay

type Relay interface {
	// RelayTo relays the incoming connection to the address specified
	// by network and address.
	RelayTo(network, address string) error

	// ListenAndRelayTo listens on the local network address and relays
	// the incoming connection to the address specified by rnetwork
	// and raddress.
	ListenAndRelayTo(lnetwork, laddress, rnetwork, raddress string) error

	// Close closes the relay. No further incoming connections will be
	// accepted and no further outbound connections will be dialed. It
	// does not close the established connections.
	Close() error

	// Addr returns the local address the relay is listening on.
	//
	// If no address is available, instead of panicking it returns nil.
	Addr() net.Addr
	// contains filtered or unexported methods
}

Relay listens on a local network address and handles requests on incoming connections by passing the incoming connection to the WebAssembly Transport Module and dial corresponding outbound connections to a pre-defined destination address. By doing so, WATM upgrades the incoming connection.

The structure of a Relay is as follows:

        accept +---------------+      +---------------+ dial
       ------->|               |----->|       Upgrade |----->
Source         |  net.Listener |      |  WebAssembly  |       Remote
       <-------|               |<-----| Downgrade     |<-----
               +---------------+      +---------------+
                        \                    /
                         \------Relay-------/
Example

ExampleRelay demonstrates how to use water.Relay.

This example is expected to demonstrate how to use the LATEST version of W.A.T.E.R. API, while other older examples could be found under transport/vX, where X is the version number (e.g. v0, v1, etc.).

It is worth noting that unless the W.A.T.E.R. API changes, the version upgrade does not bring any essential changes to this example other than the import path and wasm file path.

// Relay destination: a local TCP server
tcpListener, err := net.Listen("tcp", "localhost:0")
if err != nil {
	panic(err)
}
defer tcpListener.Close() // skipcq: GO-S2307

config := &water.Config{
	TransportModuleBin:  wasmReverse,
	ModuleConfigFactory: water.NewWazeroModuleConfigFactory(),
}

waterRelay, err := water.NewRelayWithContext(context.Background(), config)
if err != nil {
	panic(err)
}
defer waterRelay.Close() // skipcq: GO-S2307

// in a goroutine, start relay
go func() {
	err := waterRelay.ListenAndRelayTo("tcp", "localhost:0", "tcp", tcpListener.Addr().String())
	if err != nil {
		panic(err)
	}
}()
time.Sleep(100 * time.Millisecond) // 100ms to spin up relay

// test source: a local TCP client
clientConn, err := net.Dial("tcp", waterRelay.Addr().String())
if err != nil {
	panic(err)
}
defer clientConn.Close() // skipcq: GO-S2307

serverConn, err := tcpListener.Accept()
if err != nil {
	panic(err)
}
defer serverConn.Close() // skipcq: GO-S2307

var msg = []byte("hello")
n, err := clientConn.Write(msg)
if err != nil {
	panic(err)
}
if n != len(msg) {
	panic("short write")
}

buf := make([]byte, 1024)
n, err = serverConn.Read(buf)
if err != nil {
	panic(err)
}
if n != len(msg) {
	panic("short read")
}

fmt.Println(string(buf[:n]))
Output:

olleh

func NewRelay deprecated

func NewRelay(c *Config) (Relay, error)

NewRelay creates a new Relay from the given Config.

It automatically detects the version of the WebAssembly Transport Module specified in the config.

Deprecated: use NewRelayWithContext instead.

func NewRelayWithContext

func NewRelayWithContext(ctx context.Context, c *Config) (Relay, error)

NewRelayWithContext creates a new Relay from the Config with the given context.Context.

It automatically detects the version of the WebAssembly Transport Module specified in the config.

The context is passed to NewCoreWithContext and the registered versioned relay creation function to control the lifetime of the call to function calls into the WebAssembly module. If the context is canceled or reaches its deadline, any current and future function call will return with an error. Call WazeroRuntimeConfigFactory.SetCloseOnContextDone with false to disable this behavior.

type TransportModuleConfig

type TransportModuleConfig interface {
	// AsFile returns the TransportModuleConfig as a file, which
	// then can be loaded into the WebAssembly Transport Module.
	//
	// If the returned error is nil, the *os.File MUST be valid
	// and in a readable state.
	AsFile() (*os.File, error)
}

TransportModuleConfig defines the configuration file used by the WebAssembly Transport Module.

It is optional to WATER, but may be mandatory according to the WebAssembly Transport Module implementation.

func TransportModuleConfigFromBytes

func TransportModuleConfigFromBytes(configBytes []byte) TransportModuleConfig

TransportModuleConfigFromBytes creates a TransportModuleConfig from the given byte slice.

func TransportModuleConfigFromFile

func TransportModuleConfigFromFile(filePath string) (TransportModuleConfig, error)

TransportModuleConfigFromFile creates a TransportModuleConfig from the given file path.

type UnimplementedConn

type UnimplementedConn struct{}

UnimplementedConn is used to provide forward compatibility for implementations of Conn, such that if new methods are added to the interface, old implementations will not be required to implement each of them.

type UnimplementedDialer

type UnimplementedDialer struct{}

UnimplementedDialer is a Dialer that always returns errors.

It is used to ensure forward compatibility of the Dialer interface.

func (*UnimplementedDialer) Dial

func (*UnimplementedDialer) Dial(_, _ string) (Conn, error)

Dial implements Dialer.Dial().

func (*UnimplementedDialer) DialContext

func (*UnimplementedDialer) DialContext(_ context.Context, _, _ string) (Conn, error)

DialContext implements Dialer.DialContext().

type UnimplementedListener

type UnimplementedListener struct{}

UnimplementedListener is a Listener that always returns errors.

It is used to ensure forward compatibility of the Listener interface.

func (*UnimplementedListener) AcceptWATER

func (*UnimplementedListener) AcceptWATER() (Conn, error)

AcceptWATER implements water.Listener.AcceptWATER().

type UnimplementedRelay

type UnimplementedRelay struct{}

UnimplementedRelay is a Relay that always returns errors.

It is used to ensure forward compatibility of the Relay interface.

func (*UnimplementedRelay) Addr

func (*UnimplementedRelay) Addr() net.Addr

Addr implements Relay.Addr().

func (*UnimplementedRelay) Close

func (*UnimplementedRelay) Close() error

Close implements Relay.Close().

func (*UnimplementedRelay) ListenAndRelayTo

func (*UnimplementedRelay) ListenAndRelayTo(_, _, _, _ string) error

ListenAndRelayTo implements Relay.ListenAndRelayTo().

func (*UnimplementedRelay) RelayTo

func (*UnimplementedRelay) RelayTo(_, _ string) error

RelayTo implements Relay.RelayTo().

type WazeroModuleConfigFactory

type WazeroModuleConfigFactory struct {
	// contains filtered or unexported fields
}

WazeroModuleConfigFactory is used to spawn wazero.ModuleConfig.

func NewWazeroModuleConfigFactory

func NewWazeroModuleConfigFactory() *WazeroModuleConfigFactory

NewWazeroModuleConfigFactory creates a new WazeroModuleConfigFactory.

func (*WazeroModuleConfigFactory) Clone

func (*WazeroModuleConfigFactory) GetConfig

func (wmcf *WazeroModuleConfigFactory) GetConfig() wazero.ModuleConfig

GetConfig returns the latest wazero.ModuleConfig.

func (*WazeroModuleConfigFactory) InheritArgv

func (wmcf *WazeroModuleConfigFactory) InheritArgv()

InheritArgv sets the arguments for the WebAssembly module to os.Args.

Warning: this isn't a recommended way to pass configuration to the WebAssembly module. Instead, use TransportModuleConfig for a serializable configuration file. Currently, this function is not implemented and will panic.

func (*WazeroModuleConfigFactory) InheritEnv

func (wmcf *WazeroModuleConfigFactory) InheritEnv()

InheritEnv sets the environment variables for the WebAssembly module to os.Environ.

Warning: this isn't a recommended way to pass configuration to the WebAssembly module. Instead, use TransportModuleConfig for a serializable configuration file. Currently, this function is not implemented and will panic.

func (*WazeroModuleConfigFactory) InheritStderr

func (wmcf *WazeroModuleConfigFactory) InheritStderr()

InheritStderr sets the standard error for the WebAssembly module to os.Stderr.

func (*WazeroModuleConfigFactory) InheritStdin

func (wmcf *WazeroModuleConfigFactory) InheritStdin()

InheritStdin sets the standard input for the WebAssembly module to os.Stdin.

func (*WazeroModuleConfigFactory) InheritStdout

func (wmcf *WazeroModuleConfigFactory) InheritStdout()

InheritStdout sets the standard output for the WebAssembly module to os.Stdout.

func (*WazeroModuleConfigFactory) SetArgv

func (wmcf *WazeroModuleConfigFactory) SetArgv(argv []string)

SetArgv sets the arguments for the WebAssembly module.

Warning: this isn't a recommended way to pass configuration to the WebAssembly module. Instead, use TransportModuleConfig for a serializable configuration file.

func (*WazeroModuleConfigFactory) SetEnv

func (wmcf *WazeroModuleConfigFactory) SetEnv(keys, values []string)

SetEnv sets the environment variables for the WebAssembly module.

Warning: this isn't a recommended way to pass configuration to the WebAssembly module. Instead, use TransportModuleConfig for a serializable configuration file.

func (*WazeroModuleConfigFactory) SetPreopenDir

func (wmcf *WazeroModuleConfigFactory) SetPreopenDir(path string, guestPath string)

SetPreopenDir sets the preopened directory for the WebAssembly module.

func (*WazeroModuleConfigFactory) SetStderr

func (wmcf *WazeroModuleConfigFactory) SetStderr(w io.Writer)

SetStderr sets the standard error for the WebAssembly module.

func (*WazeroModuleConfigFactory) SetStdin

func (wmcf *WazeroModuleConfigFactory) SetStdin(r io.Reader)

SetStdin sets the standard input for the WebAssembly module.

func (*WazeroModuleConfigFactory) SetStdout

func (wmcf *WazeroModuleConfigFactory) SetStdout(w io.Writer)

SetStdout sets the standard output for the WebAssembly module.

type WazeroRuntimeConfigFactory

type WazeroRuntimeConfigFactory struct {
	// contains filtered or unexported fields
}

WazeroRuntimeConfigFactory is used to spawn wazero.RuntimeConfig.

func NewWazeroRuntimeConfigFactory

func NewWazeroRuntimeConfigFactory() *WazeroRuntimeConfigFactory

NewWazeroRuntimeConfigFactory creates a new WazeroRuntimeConfigFactory.

func (*WazeroRuntimeConfigFactory) Clone

Clone returns a copy of the WazeroRuntimeConfigFactory.

func (*WazeroRuntimeConfigFactory) Compiler

func (wrcf *WazeroRuntimeConfigFactory) Compiler()

Compiler sets the WebAssembly module to run in the compiler mode. It may bring performance improvements, but meanwhile it will cause the program to panic if the architecture/platform is not supported.

If no mode is set, the WebAssembly module will run in the compiler mode if supported, otherwise it will run in the interpreter mode.

func (*WazeroRuntimeConfigFactory) GetConfig

GetConfig returns the latest wazero.RuntimeConfig.

func (*WazeroRuntimeConfigFactory) Interpreter

func (wrcf *WazeroRuntimeConfigFactory) Interpreter()

Interpreter sets the WebAssembly module to run in the interpreter mode. In this mode, the WebAssembly module will run slower but it is available on all architectures/platforms.

If no mode is set, the WebAssembly module will run in the compiler mode if supported, otherwise it will run in the interpreter mode.

func (*WazeroRuntimeConfigFactory) SetCloseOnContextDone

func (wrcf *WazeroRuntimeConfigFactory) SetCloseOnContextDone(close bool)

SetCloseOnContextDone sets the closeOnContextDone for the WebAssembly module. It closes the module when the context is done and prevents any further calls to the module, including all exported functions.

By default it is set to true.

func (*WazeroRuntimeConfigFactory) SetCompilationCache

func (wrcf *WazeroRuntimeConfigFactory) SetCompilationCache(cache wazero.CompilationCache)

SetCompilationCache sets the CompilationCache for the WebAssembly module.

Calling this function will not update the global CompilationCache and therefore disable the automatic sharing of the cache between multiple WebAssembly modules.

Directories

Path Synopsis
pb
examples
internal
log
transport
v0
watm module

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL