Udp.open_local(port): a socket bound to 127.0.0.1 alone (udp.ll, udp_win.ll), for a port only this machine's tools reach - a dev link - where Udp.open binds every interface
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
7f476513cd
commit
f66b912cf4
6 changed files with 71 additions and 2 deletions
5
changes/udp-open-local.md
Normal file
5
changes/udp-open-local.md
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
bump: minor
|
||||||
|
type: feature
|
||||||
|
**`Udp.open_local(port)`: a socket only this machine reaches.** Bound to 127.0.0.1 alone (udp.ll,
|
||||||
|
udp_win.ll), where `Udp.open` binds every interface - for a port only local tools should talk to, such
|
||||||
|
as a development link.
|
||||||
23
docs/language/udp/udp-open_local.md
Normal file
23
docs/language/udp/udp-open_local.md
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
---
|
||||||
|
id: udp-open_local
|
||||||
|
name: Udp.open_local
|
||||||
|
category: udp
|
||||||
|
kind: namespace-method
|
||||||
|
tokens: Udp.open_local
|
||||||
|
sig: Udp.open_local(port) -> int
|
||||||
|
tip: Open a socket only this machine can reach.
|
||||||
|
order: 0
|
||||||
|
ns: Udp
|
||||||
|
member: open_local
|
||||||
|
---
|
||||||
|
|
||||||
|
Opens a non-blocking IPv4 socket like <a href="udp-open.html"><code>Udp.open</code></a>, but bound to <code>127.0.0.1</code> alone: programs on the same machine reach it, and nothing on the network can. Use it for a port only local tools should talk to, such as a development link. Returns the handle, or <code>0</code> when it could not.
|
||||||
|
|
||||||
|
```ludic
|
||||||
|
program Demo {
|
||||||
|
entry {
|
||||||
|
let s = Udp.open_local(port: 0)
|
||||||
|
print(s > 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
@ -205,6 +205,7 @@ namespace Http {
|
||||||
}
|
}
|
||||||
namespace Udp {
|
namespace Udp {
|
||||||
alias open(port) = udp_open
|
alias open(port) = udp_open
|
||||||
|
alias open_local(port) = udp_open_local
|
||||||
alias port(socket) = udp_port
|
alias port(socket) = udp_port
|
||||||
alias send(socket, ip, port, bytes, len) = udp_send
|
alias send(socket, ip, port, bytes, len) = udp_send
|
||||||
alias recv(socket, bytes, cap) = udp_recv
|
alias recv(socket, bytes, cap) = udp_recv
|
||||||
|
|
|
||||||
|
|
@ -71,14 +71,29 @@ none:
|
||||||
ret i32 -1
|
ret i32 -1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
; open: every interface (a party's port, reached from the LAN and beyond)
|
||||||
define i32 @lu_udp_open(i32 %port) {
|
define i32 @lu_udp_open(i32 %port) {
|
||||||
|
entry:
|
||||||
|
%h = call i32 @lu_udp_open_at(i32 0, i32 %port)
|
||||||
|
ret i32 %h
|
||||||
|
}
|
||||||
|
|
||||||
|
; open_local: 127.0.0.1 only - a port for this machine's own tools, never reachable from the LAN
|
||||||
|
define i32 @lu_udp_open_local(i32 %port) {
|
||||||
|
entry:
|
||||||
|
%h = call i32 @lu_udp_open_at(i32 2130706433, i32 %port)
|
||||||
|
ret i32 %h
|
||||||
|
}
|
||||||
|
|
||||||
|
; bound to one address (host order: 0 any, 0x7f000001 loopback), non-blocking, in a free slot
|
||||||
|
define internal i32 @lu_udp_open_at(i32 %ip, i32 %port) {
|
||||||
entry:
|
entry:
|
||||||
%sa = alloca [16 x i8]
|
%sa = alloca [16 x i8]
|
||||||
%fd = call i32 @socket(i32 2, i32 2, i32 17)
|
%fd = call i32 @socket(i32 2, i32 2, i32 17)
|
||||||
%bad = icmp slt i32 %fd, 0
|
%bad = icmp slt i32 %fd, 0
|
||||||
br i1 %bad, label %fail, label %bindit
|
br i1 %bad, label %fail, label %bindit
|
||||||
bindit:
|
bindit:
|
||||||
call void @lu_addr(ptr %sa, i32 0, i32 %port)
|
call void @lu_addr(ptr %sa, i32 %ip, i32 %port)
|
||||||
%b = call i32 @bind(i32 %fd, ptr %sa, i32 16)
|
%b = call i32 @bind(i32 %fd, ptr %sa, i32 16)
|
||||||
%bb = icmp ne i32 %b, 0
|
%bb = icmp ne i32 %b, 0
|
||||||
br i1 %bb, label %closefail, label %nonblock
|
br i1 %bb, label %closefail, label %nonblock
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,8 @@
|
||||||
# Like Http.* and Time.now it is OUT-OF-BAND: it depends on the network and the wall clock
|
# Like Http.* and Time.now it is OUT-OF-BAND: it depends on the network and the wall clock
|
||||||
# and must never feed a deterministic lockstep/replay simulation directly.
|
# and must never feed a deterministic lockstep/replay simulation directly.
|
||||||
#
|
#
|
||||||
|
# Udp.open_local(port) binds 127.0.0.1 alone, for a port only this machine's tools should reach.
|
||||||
|
#
|
||||||
# An address is an int: a.b.c.d is (a << 24) | (b << 16) | (c << 8) | d. Udp.ip("10.0.0.2")
|
# An address is an int: a.b.c.d is (a << 24) | (b << 16) | (c << 8) | d. Udp.ip("10.0.0.2")
|
||||||
# and Udp.ip_text(ip) convert, Udp.resolve("example.com") looks a host name up (it blocks
|
# and Udp.ip_text(ip) convert, Udp.resolve("example.com") looks a host name up (it blocks
|
||||||
# for as long as the system's resolver takes), and Udp.local_ip() is the address this
|
# for as long as the system's resolver takes), and Udp.local_ip() is the address this
|
||||||
|
|
@ -22,6 +24,7 @@
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
|
|
||||||
extern function lu_udp_open(port: int) -> int = "lu_udp_open"
|
extern function lu_udp_open(port: int) -> int = "lu_udp_open"
|
||||||
|
extern function lu_udp_open_local(port: int) -> int = "lu_udp_open_local"
|
||||||
extern function lu_udp_port(h: int) -> int = "lu_udp_port"
|
extern function lu_udp_port(h: int) -> int = "lu_udp_port"
|
||||||
extern function lu_udp_send(h: int, ip: int, port: int, buf: pointer, n: int) -> int = "lu_udp_send"
|
extern function lu_udp_send(h: int, ip: int, port: int, buf: pointer, n: int) -> int = "lu_udp_send"
|
||||||
extern function lu_udp_recv(h: int, buf: pointer, cap: int, ipport: pointer) -> int = "lu_udp_recv"
|
extern function lu_udp_recv(h: int, buf: pointer, cap: int, ipport: pointer) -> int = "lu_udp_recv"
|
||||||
|
|
@ -54,6 +57,13 @@ function udp_open(rt_udp_st: mut RtUdpState, port: int) -> int {
|
||||||
if (port < 0) or (port > 65535) { return 0 }
|
if (port < 0) or (port > 65535) { return 0 }
|
||||||
return lu_udp_open(port)
|
return lu_udp_open(port)
|
||||||
}
|
}
|
||||||
|
# the same bound to 127.0.0.1 only: a port this machine's own tools reach (a dev link) and the
|
||||||
|
# LAN never can
|
||||||
|
function udp_open_local(rt_udp_st: mut RtUdpState, port: int) -> int {
|
||||||
|
udp_init(rt_udp_st)
|
||||||
|
if (port < 0) or (port > 65535) { return 0 }
|
||||||
|
return lu_udp_open_local(port)
|
||||||
|
}
|
||||||
# the port a socket is bound to (the one the system picked, for port 0)
|
# the port a socket is bound to (the one the system picked, for port 0)
|
||||||
function udp_port(h: int) -> int { return lu_udp_port(h) }
|
function udp_port(h: int) -> int { return lu_udp_port(h) }
|
||||||
# one datagram of `n` bytes from `buf` to ip:port: the bytes sent, or -1
|
# one datagram of `n` bytes from `buf` to ip:port: the bytes sent, or -1
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,22 @@ none:
|
||||||
ret i64 -1
|
ret i64 -1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
; open: every interface (a party's port, reached from the LAN and beyond)
|
||||||
define i32 @lu_udp_open(i32 %port) {
|
define i32 @lu_udp_open(i32 %port) {
|
||||||
|
entry:
|
||||||
|
%h = call i32 @lu_udp_open_at(i32 0, i32 %port)
|
||||||
|
ret i32 %h
|
||||||
|
}
|
||||||
|
|
||||||
|
; open_local: 127.0.0.1 only - a port for this machine's own tools, never reachable from the LAN
|
||||||
|
define i32 @lu_udp_open_local(i32 %port) {
|
||||||
|
entry:
|
||||||
|
%h = call i32 @lu_udp_open_at(i32 2130706433, i32 %port)
|
||||||
|
ret i32 %h
|
||||||
|
}
|
||||||
|
|
||||||
|
; bound to one address (host order: 0 any, 0x7f000001 loopback), non-blocking, in a free slot
|
||||||
|
define internal i32 @lu_udp_open_at(i32 %ip, i32 %port) {
|
||||||
entry:
|
entry:
|
||||||
call void @lu_start()
|
call void @lu_start()
|
||||||
%sa = alloca [16 x i8]
|
%sa = alloca [16 x i8]
|
||||||
|
|
@ -80,7 +95,7 @@ entry:
|
||||||
%bad = icmp eq i64 %s, -1
|
%bad = icmp eq i64 %s, -1
|
||||||
br i1 %bad, label %fail, label %bindit
|
br i1 %bad, label %fail, label %bindit
|
||||||
bindit:
|
bindit:
|
||||||
call void @lu_addr(ptr %sa, i32 0, i32 %port)
|
call void @lu_addr(ptr %sa, i32 %ip, i32 %port)
|
||||||
%b = call i32 @bind(i64 %s, ptr %sa, i32 16)
|
%b = call i32 @bind(i64 %s, ptr %sa, i32 16)
|
||||||
%bb = icmp ne i32 %b, 0
|
%bb = icmp ne i32 %b, 0
|
||||||
br i1 %bb, label %closefail, label %nonblock
|
br i1 %bb, label %closefail, label %nonblock
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue