wire.bend

bend-kit-wire@0.4.3.0 · 107 lines · 0 definitions

1# Byte-exact TCP, UDP, and TLS sockets. Source: https://github.com/paymog/bend-kit/tree/main/wire
2import Base
3
4# Socket IO on octets: one Char per byte (0..255). Base's TCP/UDP effects
5# decode UTF-8, which breaks byte counts and binary protocols.
6# ms arguments are deadlines in milliseconds (0: none); a miss is ETIMEDOUT.
7#   import ./wire.bend as Wire
8
9# TCP connect to a numeric IPv4 or IPv6 address, with a deadline.
10def connect(host: String, port: U32, ms: U32) ->
11  IO(Result<&1, &1, U32 & String, Socket>):
12  import "./effs/wire.c"
13  import "./effs/wire.js"
14
15# Octet-String TCP and UDP effects are the slow path: one Char cell per byte.
16def recv(sock: Socket, max: U32, ms: U32) ->
17  IO(Socket & Result<&1, &1, U32 & String, String>):
18  import "./effs/wire.c"
19  import "./effs/wire.js"
20
21def send(sock: Socket, data: String) ->
22  IO(Socket & Result<&1, &1, U32 & String, Unit>):
23  import "./effs/wire.c"
24  import "./effs/wire.js"
25
26def recv_from(sock: Socket, max: U32, ms: U32) ->
27  IO(Socket & Result<&1, &1, U32 & String, String & U32 & String>):
28  import "./effs/wire.c"
29  import "./effs/wire.js"
30
31def send_to(sock: Socket, host: String, port: U32, data: String) ->
32  IO(Socket & Result<&1, &1, U32 & String, Unit>):
33  import "./effs/wire.c"
34  import "./effs/wire.js"
35
36# TLS over a connected TCP socket (OpenSSL 3, loaded at run time; BEND_LIBSSL
37# overrides its path). The certificate chain and host name are always checked.
38def tls.connect(sock: Socket, host: String, ms: U32) ->
39  IO(Socket & Result<&1, &1, U32 & String, Unit>):
40  import "./effs/wire.c"
41  import "./effs/wire.js"
42
43# Use a PEM certificate chain and its private key for mutual TLS.
44# A load failure is EINVAL; a handshake or server verification failure is EPROTO.
45def tls.connect.cert(sock: Socket, host: String, ms: U32, cert_path: String, key_path: String) ->
46  IO(Socket & Result<&1, &1, U32 & String, Unit>):
47  import "./effs/wire.c"
48  import "./effs/wire.js"
49
50# protos is a comma-separated ALPN list (for example "h2,http/1.1").
51def tls.connect.alpn(sock: Socket, host: String, ms: U32, protos: String) ->
52  IO(Socket & Result<&1, &1, U32 & String, String>):
53  import "./effs/wire.c"
54  import "./effs/wire.js"
55
56# The String TLS effects are the slow path: one Char cell per octet.
57def tls.send(sock: Socket, data: String) ->
58  IO(Socket & Result<&1, &1, U32 & String, Unit>):
59  import "./effs/wire.c"
60  import "./effs/wire.js"
61
62# "" once the peer sends close_notify. A bare EOF is an error.
63def tls.recv(sock: Socket, max: U32, ms: U32) ->
64  IO(Socket & Result<&1, &1, U32 & String, String>):
65  import "./effs/wire.c"
66  import "./effs/wire.js"
67
68# Ends the TLS session and closes the socket.
69def tls.close(sock: Socket) -> IO(Unit):
70  import "./effs/wire.c"
71  import "./effs/wire.js"
72
73# The .words forms move (len, words): bytes packed four to a U32, laid out as
74# bytes/bytes.bend packs them, so no String cell is made per byte.
75def recv.words(sock: Socket, max: U32, ms: U32) ->
76  IO(Socket & Result<&1, &1, U32 & String, U32 & Array<U32>>):
77  import "./effs/wire.c"
78  import "./effs/wire.js"
79
80# len past the end of words fails with EINVAL.
81def send.words(sock: Socket, len: U32, words: Array<U32>) ->
82  IO(Socket & Result<&1, &1, U32 & String, Unit>):
83  import "./effs/wire.c"
84  import "./effs/wire.js"
85
86# UDP keeps the sender address and port beside the packed datagram.
87def recv_from.words(sock: Socket, max: U32, ms: U32) ->
88  IO(Socket & Result<&1, &1, U32 & String, String & U32 & (U32 & Array<U32>)>):
89  import "./effs/wire.c"
90  import "./effs/wire.js"
91
92# len past the end of words fails with EINVAL.
93def send_to.words(sock: Socket, host: String, port: U32, len: U32, words: Array<U32>) ->
94  IO(Socket & Result<&1, &1, U32 & String, Unit>):
95  import "./effs/wire.c"
96  import "./effs/wire.js"
97
98# len 0 once the peer sends close_notify.
99def tls.recv.words(sock: Socket, max: U32, ms: U32) ->
100  IO(Socket & Result<&1, &1, U32 & String, U32 & Array<U32>>):
101  import "./effs/wire.c"
102  import "./effs/wire.js"
103
104def tls.send.words(sock: Socket, len: U32, words: Array<U32>) ->
105  IO(Socket & Result<&1, &1, U32 & String, Unit>):
106  import "./effs/wire.c"
107  import "./effs/wire.js"