feat(udp): Udp.* - polled IPv4 datagrams on macOS and Windows
Udp.open/port/send/recv/from_ip/from_port/close/resolve/local_ip/ip/ip_text, native BSD sockets (udp.ll) and Winsock (udp_win.ll, -lws2_32), linked only when a program uses Udp.*; example, docs and tests. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
6a7f1dd393
commit
ebb1a00352
24 changed files with 68630 additions and 66360 deletions
9
docs/language/udp/_section.md
Normal file
9
docs/language/udp/_section.md
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
---
|
||||
id: udp
|
||||
title: Udp
|
||||
order: 9
|
||||
---
|
||||
|
||||
Plain IPv4 datagrams, polled — the transport under a game's own netcode: peer-to-peer play, a LAN lobby, a STUN query. Open a socket with <a href="udp-open.html"><code>Udp.open</code></a>, send with <a href="udp-send.html"><code>Udp.send</code></a>, and each frame drain what arrived with <a href="udp-recv.html"><code>Udp.recv</code></a>, which returns <code>0</code> when nothing is waiting and never blocks. The sender of the last datagram read is <a href="udp-from_ip.html"><code>Udp.from_ip</code></a> / <a href="udp-from_port.html"><code>from_port</code></a>.
|
||||
|
||||
An address is an <code>int</code>: <code>a.b.c.d</code> is <code>(a << 24) | (b << 16) | (c << 8) | d</code>, converted by <a href="udp-ip.html"><code>Udp.ip</code></a> and <a href="udp-ip_text.html"><code>Udp.ip_text</code></a>. Datagrams can be lost, repeated and reordered; the protocol a game builds on top says what to do about that. Like <code>Http.*</code> it is <strong>out-of-band</strong> and must never feed the deterministic lockstep/replay simulation directly. BSD sockets on macOS, Winsock on Windows.
|
||||
23
docs/language/udp/udp-close.md
Normal file
23
docs/language/udp/udp-close.md
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
---
|
||||
id: udp-close
|
||||
name: Udp.close
|
||||
category: udp
|
||||
kind: namespace-method
|
||||
tokens: Udp.close
|
||||
sig: Udp.close(socket) -> void
|
||||
tip: Close a socket.
|
||||
order: 6
|
||||
ns: Udp
|
||||
member: close
|
||||
---
|
||||
|
||||
Closes the socket and frees its handle.
|
||||
|
||||
```ludic
|
||||
program Demo {
|
||||
entry {
|
||||
let s = Udp.open(port: 0)
|
||||
Udp.close(socket: s)
|
||||
}
|
||||
}
|
||||
```
|
||||
23
docs/language/udp/udp-from_ip.md
Normal file
23
docs/language/udp/udp-from_ip.md
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
---
|
||||
id: udp-from_ip
|
||||
name: Udp.from_ip
|
||||
category: udp
|
||||
kind: namespace-method
|
||||
tokens: Udp.from_ip
|
||||
sig: Udp.from_ip(socket) -> int
|
||||
tip: The sender of the last datagram read.
|
||||
order: 4
|
||||
ns: Udp
|
||||
member: from_ip
|
||||
---
|
||||
|
||||
The address the last datagram read on this socket came from - the one to answer.
|
||||
|
||||
```ludic
|
||||
program Demo {
|
||||
entry {
|
||||
let s = Udp.open(port: 0)
|
||||
print(Udp.from_ip(socket: s))
|
||||
}
|
||||
}
|
||||
```
|
||||
23
docs/language/udp/udp-from_port.md
Normal file
23
docs/language/udp/udp-from_port.md
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
---
|
||||
id: udp-from_port
|
||||
name: Udp.from_port
|
||||
category: udp
|
||||
kind: namespace-method
|
||||
tokens: Udp.from_port
|
||||
sig: Udp.from_port(socket) -> int
|
||||
tip: The sender's port.
|
||||
order: 5
|
||||
ns: Udp
|
||||
member: from_port
|
||||
---
|
||||
|
||||
The port the last datagram read on this socket came from.
|
||||
|
||||
```ludic
|
||||
program Demo {
|
||||
entry {
|
||||
let s = Udp.open(port: 0)
|
||||
print(Udp.from_port(socket: s))
|
||||
}
|
||||
}
|
||||
```
|
||||
22
docs/language/udp/udp-ip.md
Normal file
22
docs/language/udp/udp-ip.md
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
---
|
||||
id: udp-ip
|
||||
name: Udp.ip
|
||||
category: udp
|
||||
kind: namespace-method
|
||||
tokens: Udp.ip
|
||||
sig: Udp.ip(text) -> int
|
||||
tip: Parse a dotted address.
|
||||
order: 9
|
||||
ns: Udp
|
||||
member: ip
|
||||
---
|
||||
|
||||
Turns <code>"a.b.c.d"</code> into an address, or <code>0</code> when the text is not one.
|
||||
|
||||
```ludic
|
||||
program Demo {
|
||||
entry {
|
||||
print(Udp.ip(text: "10.0.0.2"))
|
||||
}
|
||||
}
|
||||
```
|
||||
22
docs/language/udp/udp-ip_text.md
Normal file
22
docs/language/udp/udp-ip_text.md
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
---
|
||||
id: udp-ip_text
|
||||
name: Udp.ip_text
|
||||
category: udp
|
||||
kind: namespace-method
|
||||
tokens: Udp.ip_text
|
||||
sig: Udp.ip_text(ip) -> string
|
||||
tip: Format an address.
|
||||
order: 10
|
||||
ns: Udp
|
||||
member: ip_text
|
||||
---
|
||||
|
||||
Turns an address back into <code>"a.b.c.d"</code>.
|
||||
|
||||
```ludic
|
||||
program Demo {
|
||||
entry {
|
||||
print(Udp.ip_text(ip: Udp.ip(text: "192.168.1.11")))
|
||||
}
|
||||
}
|
||||
```
|
||||
22
docs/language/udp/udp-local_ip.md
Normal file
22
docs/language/udp/udp-local_ip.md
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
---
|
||||
id: udp-local_ip
|
||||
name: Udp.local_ip
|
||||
category: udp
|
||||
kind: namespace-method
|
||||
tokens: Udp.local_ip
|
||||
sig: Udp.local_ip() -> int
|
||||
tip: This machine's address.
|
||||
order: 8
|
||||
ns: Udp
|
||||
member: local_ip
|
||||
---
|
||||
|
||||
The address this machine reaches the internet from - the one a player on the same network would dial. No packet is sent; <code>0</code> when there is no route.
|
||||
|
||||
```ludic
|
||||
program Demo {
|
||||
entry {
|
||||
print(Udp.ip_text(ip: Udp.local_ip()))
|
||||
}
|
||||
}
|
||||
```
|
||||
23
docs/language/udp/udp-open.md
Normal file
23
docs/language/udp/udp-open.md
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
---
|
||||
id: udp-open
|
||||
name: Udp.open
|
||||
category: udp
|
||||
kind: namespace-method
|
||||
tokens: Udp.open
|
||||
sig: Udp.open(port) -> int
|
||||
tip: Open a socket on a port.
|
||||
order: 0
|
||||
ns: Udp
|
||||
member: open
|
||||
---
|
||||
|
||||
Opens a non-blocking IPv4 socket bound to <code>port</code> on every interface and returns its handle, or <code>0</code> when it could not. Port <code>0</code> lets the system pick a free one; <a href="udp-port.html"><code>Udp.port</code></a> says which.
|
||||
|
||||
```ludic
|
||||
program Demo {
|
||||
entry {
|
||||
let s = Udp.open(port: 0)
|
||||
print(s > 0)
|
||||
}
|
||||
}
|
||||
```
|
||||
23
docs/language/udp/udp-port.md
Normal file
23
docs/language/udp/udp-port.md
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
---
|
||||
id: udp-port
|
||||
name: Udp.port
|
||||
category: udp
|
||||
kind: namespace-method
|
||||
tokens: Udp.port
|
||||
sig: Udp.port(socket) -> int
|
||||
tip: The port a socket is bound to.
|
||||
order: 1
|
||||
ns: Udp
|
||||
member: port
|
||||
---
|
||||
|
||||
Returns the port the socket is bound to - the one the system chose when it was opened on port <code>0</code>.
|
||||
|
||||
```ludic
|
||||
program Demo {
|
||||
entry {
|
||||
let s = Udp.open(port: 0)
|
||||
print(Udp.port(socket: s) > 0)
|
||||
}
|
||||
}
|
||||
```
|
||||
24
docs/language/udp/udp-recv.md
Normal file
24
docs/language/udp/udp-recv.md
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
---
|
||||
id: udp-recv
|
||||
name: Udp.recv
|
||||
category: udp
|
||||
kind: namespace-method
|
||||
tokens: Udp.recv
|
||||
sig: Udp.recv(socket, bytes, cap) -> int
|
||||
tip: Read the next waiting datagram.
|
||||
order: 3
|
||||
ns: Udp
|
||||
member: recv
|
||||
---
|
||||
|
||||
Copies the next waiting datagram, up to <code>cap</code> bytes, into <code>bytes</code> and returns its length, or <code>0</code> when nothing is waiting. It never blocks: call it in a loop each frame until it returns <code>0</code>. The sender is <a href="udp-from_ip.html"><code>Udp.from_ip</code></a> / <a href="udp-from_port.html"><code>from_port</code></a>.
|
||||
|
||||
```ludic
|
||||
program Demo {
|
||||
entry {
|
||||
let s = Udp.open(port: 0)
|
||||
let buf = Memory.bytes(64)
|
||||
print(Udp.recv(socket: s, bytes: buf, cap: 64))
|
||||
}
|
||||
}
|
||||
```
|
||||
22
docs/language/udp/udp-resolve.md
Normal file
22
docs/language/udp/udp-resolve.md
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
---
|
||||
id: udp-resolve
|
||||
name: Udp.resolve
|
||||
category: udp
|
||||
kind: namespace-method
|
||||
tokens: Udp.resolve
|
||||
sig: Udp.resolve(name) -> int
|
||||
tip: Look a host name up.
|
||||
order: 7
|
||||
ns: Udp
|
||||
member: resolve
|
||||
---
|
||||
|
||||
Returns the first IPv4 address of a host name, or <code>0</code>. It waits for the system's resolver, so call it outside the frame loop.
|
||||
|
||||
```ludic
|
||||
program Demo {
|
||||
entry {
|
||||
print(Udp.ip_text(ip: Udp.resolve(name: "localhost")))
|
||||
}
|
||||
}
|
||||
```
|
||||
25
docs/language/udp/udp-send.md
Normal file
25
docs/language/udp/udp-send.md
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
---
|
||||
id: udp-send
|
||||
name: Udp.send
|
||||
category: udp
|
||||
kind: namespace-method
|
||||
tokens: Udp.send
|
||||
sig: Udp.send(socket, ip, port, bytes, len) -> int
|
||||
tip: Send one datagram.
|
||||
order: 2
|
||||
ns: Udp
|
||||
member: send
|
||||
---
|
||||
|
||||
Sends the first <code>len</code> bytes of <code>bytes</code> to <code>ip</code>:<code>port</code> as one datagram and returns the number of bytes sent, or <code>-1</code>.
|
||||
|
||||
```ludic
|
||||
program Demo {
|
||||
entry {
|
||||
let s = Udp.open(port: 0)
|
||||
let buf = Memory.bytes(4)
|
||||
Memory.poke(buf, 0, 1)
|
||||
print(Udp.send(socket: s, ip: Udp.ip(text: "127.0.0.1"), port: Udp.port(socket: s), bytes: buf, len: 1))
|
||||
}
|
||||
}
|
||||
```
|
||||
Loading…
Add table
Add a link
Reference in a new issue