Skip to content

Conversation

dsseng
Copy link

@dsseng dsseng commented Aug 2, 2025

  • Add _AF_INET6 for WASI sockets
  • HACK: explicitly default TCP listeners to 0.0.0.0
  • Initial WASIp2 network driver
  • fixup! Initial WASIp2 network driver
  • net: wasip2: implement GetHostByName
  • net: wasip2: refactor, support TCP connect
  • net: wasip2: UDP client

@deadprogram
Copy link
Member

Very interesting work in progress here @dsseng 👀

@dsseng
Copy link
Author

dsseng commented Aug 17, 2025

Okay, UDP server needs more work in common code, let's review this as is and keep UDP server for later

@dsseng dsseng marked this pull request as ready for review August 17, 2025 20:51
@deadprogram
Copy link
Member

Paging Dr. @dgryski 😸

@deadprogram
Copy link
Member

@dsseng this is really interesting. Can you please point me to some example of this in use, so I can try it out!

@dsseng
Copy link
Author

dsseng commented Aug 18, 2025

@dsseng this is really interesting. Can you please point me to some example of this in use, so I can try it out!

Not at my PC now. Please try http Server and Client samples from Go by example, should work for TCP. I probably also used the UDP client from there

@deadprogram
Copy link
Member

@dsseng perhaps when you are back around, you can provide specific instructions on how you built and tested this? What code you built, what command you built it with, and how you executed it please. Thank you!

@dsseng
Copy link
Author

dsseng commented Aug 19, 2025

This includes PATH env for the needed components. These are the samples that should work:

Full command: PATH=$PATH:/tmp/wasm-tools-1.236.0-x86_64-linux:/tmp/binaryen-version_123/bin/ GOOS=wasip2 GOARCH=wasm /tmp/tinygo-src/build/tinygo build -o tinygo.wasm srv.go && WASMTIME_BACKTRACE_DETAILS=1 /tmp/wasmtime-v35.0.0-x86_64-linux/wasmtime run -S inherit-network=y,inherit-env=y,allow-ip-name-lookup=y tinygo.wasm

@deadprogram
Copy link
Member

Do you need the newer (v123) binaryen from wasm-opt? I get this error with these versions:

$ WASMTIME_BACKTRACE_DETAILS=1 wasmtime run -S inherit-network=y,inherit-env=y,allow-ip-name-lookup=y srv.wasm 
panic: failed to start connecting socket: invalid-argument
Error: failed to run main module `srv.wasm`

Caused by:
    0: failed to invoke `run` function
    1: error while executing at wasm backtrace:
           0:  0x3d4e4 - runtime.abort
                           at /home/ron/Development/tinygo/tinygo-122/src/runtime/runtime_tinygowasmp2.go:55:6
                       - runtime.panicOrGoexit
                           at /home/ron/Development/tinygo/tinygo-122/src/runtime/panic.go:81:7
           1:   0x3c16 - runtime._panic
                           at /home/ron/Development/tinygo/tinygo-122/src/runtime/panic.go:55:15
           2:  0x2a629 - main.main
                       - runtime.init#1$1
                           at /home/ron/Development/tinygo/tinygo-122/src/runtime/runtime_wasip2.go:17:11
                       - internal/wasi/cli/v0.2.0/run.wasmexport_Run
                           at /home/ron/Development/tinygo/tinygo-122/src/internal/wasi/cli/v0.2.0/run/run.wasm.go:14:23
           3:  0x28757 - <goroutine wrapper>
                           at /home/ron/Development/tinygo/tinygo-122/src/internal/wasi/cli/v0.2.0/run/run.wasm.go:11:1
           4:   0x2f5a - tinygo_launch
                           at /home/ron/Development/tinygo/tinygo-122/src/internal/task/task_asyncify_wasm.S:59:0
           5:  0x28b43 - (*internal/task.Task).Resume
                           at /home/ron/Development/tinygo/tinygo-122/src/internal/task/task_asyncify.go:114:17
                       - runtime.scheduler
                           at /home/ron/Development/tinygo/tinygo-122/src/runtime/scheduler_cooperative.go:220:11
           6:  0x28643 - runtime.wasmExportRun
                           at /home/ron/Development/tinygo/tinygo-122/src/runtime/runtime_wasmentry.go:83:11
                       - internal/wasi/cli/v0.2.0/run.wasmexport_Run#wasmexport
                           at /home/ron/Development/tinygo/tinygo-122/src/internal/wasi/cli/v0.2.0/run/run.wasm.go:11:1
    2: wasm trap: wasm `unreachable` instruction executed

with these versions:

$ tinygo version
tinygo version 0.39.0-dev-3e76703f linux/amd64 (using go version go1.25.0 and LLVM version 19.1.2)

$ wasm-opt --version
wasm-opt version 116 (version_116)

$ wasmtime -V
wasmtime 35.0.0 (509af9e5f 2025-07-22)

Any thoughts?

@dsseng
Copy link
Author

dsseng commented Aug 19, 2025

Weird. I did not see such an error. Is it HTTP client? Try http server, and try adding some logging. I will probably be able to try to reproduce in no shorter than a week, unfortunately too busy now

Copy link
Member

@dgryski dgryski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are the tests for this beyond the standard net tests? Do we need to investigate fuzzing this driver?

a := []udp.OutgoingDatagram{
{
Data: cm.NewList(&buf[0], len(buf)),
// RemoteAddress: cm.Some(c.raddr),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be commented out? If so, remove. Otherwise, probably worth fixing. Does the remote address get set somewhere else?

@ErikFrankling
Copy link

This looked interesting for some work I am doing, so I tested it, but I am encountering an issue when sending data larger than 4096 bytes. What I tested:

package main

import (
	"fmt"
	"net"
)

func main() {
	conn, err := net.Dial("tcp", "localhost:8092")
	if err != nil {
		panic(err)
	}
	defer conn.Close()

	buf := make([]byte, 4097)
	n, err := conn.Read(buf)
	if err != nil {
		panic(err)
	}

	fmt.Printf("Received %d bytes\n", n)
}
package main

import (
	"fmt"
	"net"
)

func main() {
	ln, err := net.Listen("tcp", ":8092")
	if err != nil {
		panic(err)
	}
	defer ln.Close()

	fmt.Println("Server listening on :8092")

	conn, err := ln.Accept()
	if err != nil {
		panic(err)
	}
	defer conn.Close()

	data := make([]byte, 4097)
	for i := range data {
		data[i] = byte(i % 256)
	}

	n, err := conn.Write(data)
	if err != nil {
		panic(err)
	}

	fmt.Printf("Sent %d bytes\n", n)
}

In one shell run:

tinygo build -target=wasip2 -o server.wasm tcp-server.go
wasmtime run -Sinherit-network server.wasm

In another shell run:

go run tcp-client.go

You get this error:

Server listening on :8092
Error: failed to run main module `server.wasm`

Caused by:
    0: failed to invoke `run` function
    1: error while executing at wasm backtrace:
           0:  0xe5872 - wit-component:shim!indirect-wasi:io/[email protected][method]output-stream.blocking-write-and-flush
           1:  0x117fd - main!(internal/wasi/io/v0.2.0/streams.OutputStream).BlockingWriteAndFlush
           2:  0x11043 - main!main.main
           3:   0xcc04 - main!internal/wasi/cli/v0.2.0/run.wasmexport_Run
           4:   0xc849 - main!internal/wasi/cli/v0.2.0/run.wasmexport_Run$gowrapper-wasmexport
           5:   0x2aa3 - main!tinygo_rewind
           6:   0xca6b - main!runtime.scheduler
           7:   0xc73f - main!internal/wasi/cli/v0.2.0/run.wasmexport_Run#wasmexport
       note: using the `WASMTIME_BACKTRACE_DETAILS=1` environment variable may show more debugging information
    2: Buffer too large for blocking-write-and-flush (expected at most 4096)

When running normally with go runor with data smaller than 4096 bytes, it works as expected.

I think the offending code is this part: https://github.com/tinygo-org/net/blob/043bd3f10e41db40d971bbc3bcffe10b8c186214/tcp_wasip2.go#L141C1-L141C57

It is essentially the same issue that I am having with printing larger data that I reported here: tinygo-org/tinygo#5012

Sorry if I am on the wrong track, new to WASM :)

@dsseng dsseng requested a review from dgryski September 27, 2025 18:12
@dsseng
Copy link
Author

dsseng commented Sep 27, 2025

@dgryski @ErikFrankling thanks for your feedback! Sorry for long delay. Here's the test program for TCP:

PATH=$PATH:/tmp/wasm-tools-1.239.0-x86_64-linux:/tmp/binaryen-version_124/bin/ GOOS=wasip2 GOARCH=wasm /tmp/tinygo/build/tinygo build -o /tmp/srv.wasm /tmp/srv.go && WASMTIME_BACKTRACE_DETAILS=1 /tmp/wasmtime-v36.0.2-x86_64-linux/wasmtime run -S inherit-network=y,inherit-env=y,allow-ip-name-lookup=y /tmp/srv.wasm
Server
package main

import (
	"fmt"
	"net"
	"slices"
)

func main() {
	ln, err := net.Listen("tcp", ":8092")
	if err != nil {
		panic(err)
	}
	defer ln.Close()

	fmt.Println("Server listening on :8092")

	for {
		conn, err := ln.Accept()
		if err != nil {
			panic(err)
		}
		defer conn.Close()

		buf := make([]byte, 64*1024)
		n, err := conn.Read(buf)
		if err != nil {
			panic(err)
		}

		fmt.Println(string(buf[:50]) + "...")
		fmt.Println("..." + string(buf[n-50:n]))
		fmt.Printf("Received %d bytes\n", n)

		mirrored := buf[:n]
		slices.Reverse(mirrored)
		n, err = conn.Write(mirrored)
		if err != nil {
			panic(err)
		}

		fmt.Printf("Sent %d bytes\n", n)
	}
}
PATH=$PATH:/tmp/wasm-tools-1.239.0-x86_64-linux:/tmp/binaryen-version_124/bin/ GOOS=wasip2 GOARCH=wasm /tmp/tinygo/build/tinygo build -o /tmp/cl.wasm /tmp/cl.go && WASMTIME_BACKTRACE_DETAILS=1 /tmp/wasmtime-v36.0.2-x86_64-linux/wasmtime run -S inherit-network=y,inherit-env=y,allow-ip-name-lookup=y /tmp/cl.wasm
Client - feel free to replace 12000 with sth less or more, e.g. 20 to send 61 bytes total
package main

import (
	"fmt"
	"net"
	"strconv"
)

func main() {
	conn, err := net.Dial("tcp", "localhost:8092")
	if err != nil {
		panic(err)
	}
	defer conn.Close()

	str := "hello,"
	for i := range 12000 {
		str += strconv.Itoa(i) + ","
	}
	str += "world"

	n, err := conn.Write([]byte(str))
	if err != nil {
		panic(err)
	}

	fmt.Printf("Sent %d bytes\n", n)

	buf := make([]byte, 64*1024)
	n, err = conn.Read(buf)
	if err != nil {
		panic(err)
	}

	fmt.Println(string(buf[:50]) + "...")
	fmt.Println("..." + string(buf[n-50:n]))
	fmt.Printf("Received %d bytes\n", n)
}

Haven't touched the UDP part yet


const (
_AF_INET = 0x2
_AF_INET6 = 0xA
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't end up really used, nor did I test IPv6. Should we drop it for now?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants