Cached at:
06/29/26, 08:31 PM
# Solod v0.2: Networking, new targets, friendlier interop
Source: [https://antonz.org/solod-v0-2/](https://antonz.org/solod-v0-2/)
Solod \(**So**\) is a system\-level language with Go syntax, zero runtime, and a familiar standard library\. It's designed for two main audiences:
- Go developers who want low\-level control and zero\-cost C interop without having to learn Zig or Odin\.
- C developers who like Go's style\.
The[previous version](https://antonz.org/solod-v0-1)\(v0\.1\) focused on porting core Go stdlib packages and providing convenient C interop\. At the end of that post, I said the next release would focus on networking, concurrency, or both\. Now, networking is here — the v0\.2 release I'm sharing today includes support for TCP, UDP, and Unix domain sockets\. Concurrency is still planned for the future, so for now, servers handle one connection at a time\.
This release also lets you compile So to more targets, like 32\-bit platforms, WebAssembly, and bare metal\. And C interop even smoother\!
[Networking](https://antonz.org/solod-v0-2/#networking)•[TCP server](https://antonz.org/solod-v0-2/#tcp-server)•[TCP client](https://antonz.org/solod-v0-2/#tcp-client)•[Deadlines](https://antonz.org/solod-v0-2/#deadlines)•[IP addresses](https://antonz.org/solod-v0-2/#ip-addresses)•[Targets](https://antonz.org/solod-v0-2/#new-targets)•[Interop](https://antonz.org/solod-v0-2/#friendlier-interop)•[Stdlib](https://antonz.org/solod-v0-2/#more-stdlib)•[Wrapping up](https://antonz.org/solod-v0-2/#wrapping-up)
## Networking
The main feature in v0\.2 is the`net`package\. It's a simplified version of Go's`net`package which supports the three most commonly used transports:
- **TCP**\(networks`tcp`,`tcp4`,`tcp6`\) via`ResolveTCPAddr`,`DialTCP`, and`ListenTCP`, with the`TCPConn`and`TCPListener`types\.
- **UDP**\(networks`udp`,`udp4`,`udp6`\) via`ResolveUDPAddr`,`DialUDP`\(a connected socket\), and`ListenUDP`\(an unconnected socket with`ReadFrom`/`WriteTo`\)\.
- **Unix domain sockets**\(`unix`for streams,`unixgram`for datagrams\) via`ResolveUnixAddr`,`DialUnix`,`ListenUnix`, and`ListenUnixgram`\.
The API mirrors Go closely, so most of it will feel familiar\. The big difference is that So has no goroutines, so there's no concurrent server support — you accept and serve connections sequentially\. More on that in a moment\.
## TCP server
Let's build a classic: an echo server that accepts a connection, reads a message, and sends it back\.
```
package main
import "solod.dev/so/net"
func main() {
// Resolve the local address to listen on.
laddr, err := net.ResolveTCPAddr("tcp", "127.0.0.1:8080")
if err != nil {
panic(err)
}
// Start listening on the local address.
ln, err := net.ListenTCP("tcp", &laddr)
if err != nil {
panic(err)
}
defer ln.Close()
println("listening on", "127.0.0.1:8080")
// Accept connections and serve them in a loop.
for {
conn, err := ln.Accept()
if err != nil {
panic(err)
}
serve(&conn)
}
}
// serve reads one message from the connection, echoes it back,
// and closes the connection.
func serve(conn *net.TCPConn) {
defer conn.Close()
var buf [256]byte
n, err := conn.Read(buf[:])
if err != nil {
return
}
conn.Write(buf[:n])
}
```
```
listening on 127.0.0.1:8080
```
If you've written a TCP server in Go, this should look familiar —`ListenTCP`, an`Accept`loop, and`Read`/`Write`on the connection\. The only thing missing is a`go serve\(conn\)`: without goroutines, each connection is handled to completion before moving on to the next`Accept`\.
## TCP client
The client starts the connection using`DialTCP`, then uses`Write`to send a request and`Read`to get the reply:
```
package main
import "solod.dev/so/net"
func main() {
// Resolve the server address.
raddr, err := net.ResolveTCPAddr("tcp", "127.0.0.1:8080")
if err != nil {
panic(err)
}
// A nil laddr lets the system choose the local address.
conn, err := net.DialTCP("tcp", nil, &raddr)
if err != nil {
panic(err)
}
defer conn.Close()
// Send a request and read the reply.
conn.Write([]byte("hello"))
var buf [256]byte
n, err := conn.Read(buf[:])
if err != nil {
panic(err)
}
println(string(buf[:n]))
}
```
UDP and Unix domain sockets work in a similar way\. For UDP, an unconnected`ListenUDP`socket uses`ReadFrom`to get data and the sender's address, and`WriteTo`to send a reply\. For Unix sockets, there are`ListenUnix`\(stream\) and`ListenUnixgram`\(datagram\)\.
## Deadlines
By default,`Accept`,`Read`, and`Write`are blocking\. In Go, you'd typically use goroutines and contexts to prevent getting stuck forever\. Since that's not available in So \(yet\), every connection and listener supports deadlines instead:
```
// Give the client 5 seconds to send something.
conn.SetReadDeadline(time.Now().Add(5 * time.Second))
n, err := conn.Read(buf[:])
if err == net.ErrTimeout {
// The client went quiet; drop the connection.
return
}
```
`SetDeadline`,`SetReadDeadline`, and`SetWriteDeadline`are available on`TCPConn`,`UDPConn`,`UnixConn`, and listener types\. When the deadline passes, any pending call fails with`net\.ErrTimeout`\. If you don't set a deadline, a blocked call will wait forever\. This isn't concurrency, but it's enough to keep a single\-threaded server responsive\.
## IP addresses
Along with`net`, v0\.2 ports Go's`net/netip`package, which provides small, allocation\-free value types for IP addresses\.`Addr`represents an IP address,`AddrPort`combines an IP address with a port, and`Prefix`is an IP with a prefix length \(a CIDR block\):
```
addr, err := netip.ParseAddr("192.168.1.10")
if err != nil {
panic(err)
}
println(addr.Is4()) // true
ap := netip.AddrPortFrom(addr, 8080)
println(ap.Port()) // 8080
prefix := netip.MustParsePrefix("192.168.1.0/24")
println(prefix.Contains(addr)) // true
```
These are simple value types that don't use any heap allocation, which fits well with So's explicit\-memory approach\. The`net`package also provides`SplitHostPort`and`JoinHostPort`functions to help you work with`host:port`strings\.
## New targets
Solod compiles to plain C, which \(in theory\) means it can target anything a C compiler can\. Because of this, v0\.2 adds new targets:
- **32\-bit platforms**\. The compiler and stdlib now work correctly on 32\-bit platforms, where`int`and pointers are narrower\.
- **WebAssembly \(WASI\)**\. You can compile a So program to`wasm32\-wasi`and run it under any WASI runtime\.
- **Freestanding mode**\. So programs can run on bare\-metal systems without any C standard library\. No libc means no malloc, but you can use`mem\.Arena`instead\.
Here's the complete toolchain you need to build a freestanding`wasm32`binary using`zig cc`:
```
export CC="zig cc"
export CFLAGS="-Oz --target=wasm32-freestanding -nostdlib -Wl,--no-entry -Wl,--export=main"
so build -o main.wasm .
```
A large part of the standard library \(`bytes`,`strings`,`strconv`,`slices`,`maps`,`math`,`encoding/binary`, and more\) works just fine in freestanding mode\. For more details, check out the[freestanding guide](https://github.com/solod-dev/solod/blob/main/doc/freestanding.md)\.
## Friendlier interop
A bunch of smaller changes make Solod nicer to write\.
**Three new directives**for low\-level work, all documented in the[interop guide](https://github.com/solod-dev/solod/blob/main/doc/interop.md):
```
//so:volatile
var counter int // emits a C volatile
//so:thread_local
var perThread int // emits C11 _Thread_local
//so:attr packed
type header struct { // emits __attribute__((packed))
version byte
length int
}
```
`so:attr`works with variables, constants, types, and functions\. You can use it on multiple lines, and the attributes will stack\. For example,`//so:attr aligned\(16\)`will combine with`//so:attr packed`\.
**Type aliases**\. So now supports Go\-style type aliases:
**Numeric C types**\. The`so/c`package now includes named types for C's numeric types —`Int`,`UInt`,`Long`,`Short`,`UChar`,`LongLong`, and others\. When you declare an extern function, you can use the actual C types in its signature instead of trying to guess the correct fixed\-width Go type for your platform\.
**Third\-party packages**\. You can now add external So packages using`go install`or by vendoring, and you can organize your own code into multiple modules\. So doesn't have a real package ecosystem yet, but it's a good start\.
**Better diagnostics**\. By default, panic messages report the C file and line\. Pass`\-\-track\-source`to report the original So source location instead:
There's also an optional`\-\-check\-nil`flag that adds nil\-pointer checks when accessing struct fields and calling interface methods\. This way, if there's a bad dereference, the program will panic cleanly instead of causing a segmentation fault\. Both options are off by default to keep the generated code more readable\.
## More stdlib
Beyond`net`and`net/netip`, v0\.2 adds a few more packages:
- `encoding/hex`— hex encoding and decoding, including`Dump`for hexdump\-style output\.
- `uuid`— generating and parsing UUIDs \(v4 and v7\), with random components from a cryptographically secure source\.
And a small but handy update to memory management:`mem\.Arena\.Free`now reclaims the last allocation if you give it the matching pointer\. It's a minor optimization, but it means a quick alloc/free pair on an arena no longer wastes space\.
[Stdlib documentation](https://github.com/solod-dev/solod/blob/main/doc/stdlib.md)
## Wrapping up
With v0\.2, Solod has evolved from just "command\-line tools and C glue" into something you can actually use on a network — like a TCP or UDP server, a small protocol client, or a Unix\-socket daemon\. The new targets \(32\-bit, WASM, freestanding\) mean the same code can now run in more places, even down to bare metal\.
The big thing that's still missing is concurrency\. A server that handles requests one at a time works for some tasks, but a real network service needs to manage many connections at once\. That's the obvious goal for v0\.3 — adding some kind of concurrency, along with the stdlib packages that support it\.
If you're interested, take a look at So's[readme](https://github.com/solod-dev/solod#readme)— it has everything you need to get started\. Or[try So online](https://codapi.org/so)without installing anything\.
[★ Subscribe](https://antonz.org/subscribe/)to keep up with new posts\.