mt-lang 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/docs/index.html +4 -3
- data/lib/milk_tea/base.rb +1 -1
- data/std/asset_pack.mt +267 -0
- data/std/async/libuv_runtime.mt +539 -0
- data/std/async/mailbox.mt +191 -0
- data/std/async/runtime.mt +87 -0
- data/std/async.mt +87 -0
- data/std/base64.mt +185 -0
- data/std/behavior_tree.mt +396 -0
- data/std/binary.mt +314 -0
- data/std/binary_heap.mt +157 -0
- data/std/bitset.mt +239 -0
- data/std/box2d.mt +535 -0
- data/std/bytes.mt +46 -0
- data/std/c/box2d.mt +1254 -0
- data/std/c/cgltf.mt +647 -0
- data/std/c/cjson.mt +106 -0
- data/std/c/crypto.mt +11 -0
- data/std/c/crypto_support.h +51 -0
- data/std/c/ctype.mt +19 -0
- data/std/c/ctype_bindgen.h +29 -0
- data/std/c/curl.mt +1223 -0
- data/std/c/enet.mt +473 -0
- data/std/c/errno.mt +41 -0
- data/std/c/errno_bindgen.h +53 -0
- data/std/c/flecs.mt +2945 -0
- data/std/c/fs.linux.mt +43 -0
- data/std/c/fs.windows.mt +43 -0
- data/std/c/fs_support.h +954 -0
- data/std/c/gl.mt +2065 -0
- data/std/c/gl_registry_helpers.h +10748 -0
- data/std/c/glfw.mt +499 -0
- data/std/c/libc.mt +167 -0
- data/std/c/libuv.mt +1491 -0
- data/std/c/math.mt +22 -0
- data/std/c/math_bindgen.h +31 -0
- data/std/c/miniaudio.mt +3420 -0
- data/std/c/pcre2.mt +735 -0
- data/std/c/process.mt +58 -0
- data/std/c/process_support.h +1147 -0
- data/std/c/raygui.mt +1602 -0
- data/std/c/raylib.mt +1245 -0
- data/std/c/raymath.mt +163 -0
- data/std/c/rlgl.mt +434 -0
- data/std/c/rpng.mt +60 -0
- data/std/c/rres.mt +187 -0
- data/std/c/sdl3.mt +4132 -0
- data/std/c/sqlite3.mt +951 -0
- data/std/c/stb_image.mt +52 -0
- data/std/c/stb_image_resize2.mt +128 -0
- data/std/c/stb_image_write.mt +19 -0
- data/std/c/stb_rect_pack.mt +38 -0
- data/std/c/stb_truetype.mt +175 -0
- data/std/c/stb_vorbis.mt +31 -0
- data/std/c/stdio.mt +90 -0
- data/std/c/steamworks.h +5769 -0
- data/std/c/steamworks.mt +4771 -0
- data/std/c/string.mt +16 -0
- data/std/c/string_bindgen.h +36 -0
- data/std/c/sync.mt +33 -0
- data/std/c/sync_support.h +219 -0
- data/std/c/terminal.mt +24 -0
- data/std/c/terminal_support.h +408 -0
- data/std/c/time.mt +26 -0
- data/std/c/tls.mt +24 -0
- data/std/c/tls_support.h +626 -0
- data/std/c/tracy.mt +53 -0
- data/std/c/zlib.mt +20 -0
- data/std/c/zlib_support.h +239 -0
- data/std/c/zstd.mt +231 -0
- data/std/cell.mt +60 -0
- data/std/cgltf.mt +115 -0
- data/std/cjson.mt +90 -0
- data/std/cli.mt +768 -0
- data/std/cookie.mt +198 -0
- data/std/counter.mt +160 -0
- data/std/crypto.mt +74 -0
- data/std/cstring.mt +13 -0
- data/std/ctype.mt +52 -0
- data/std/curl/runtime.mt +261 -0
- data/std/curl.mt +38 -0
- data/std/deque.mt +348 -0
- data/std/encoding.mt +93 -0
- data/std/enet.mt +133 -0
- data/std/env.mt +41 -0
- data/std/errno.mt +47 -0
- data/std/flecs.mt +978 -0
- data/std/fmt.mt +271 -0
- data/std/fs.linux.mt +696 -0
- data/std/fs.windows.mt +711 -0
- data/std/fsm.mt +267 -0
- data/std/gl.mt +2062 -0
- data/std/glfw.mt +471 -0
- data/std/goap.mt +342 -0
- data/std/graph.mt +521 -0
- data/std/gzip.mt +77 -0
- data/std/hash.mt +429 -0
- data/std/http/server.mt +810 -0
- data/std/http.mt +1227 -0
- data/std/intern.mt +53 -0
- data/std/jobs.mt +288 -0
- data/std/json.mt +627 -0
- data/std/libc.mt +34 -0
- data/std/libuv.mt +554 -0
- data/std/linear_algebra.mt +243 -0
- data/std/linked_map.mt +372 -0
- data/std/linked_map_view.mt +49 -0
- data/std/linked_set.mt +117 -0
- data/std/log.mt +69 -0
- data/std/map.mt +418 -0
- data/std/math.mt +24 -0
- data/std/mem/arena.mt +137 -0
- data/std/mem/endian.mt +51 -0
- data/std/mem/heap.mt +298 -0
- data/std/mem/pool.mt +164 -0
- data/std/mem/stack.mt +47 -0
- data/std/mem/tracking.mt +119 -0
- data/std/miniaudio.mt +1299 -0
- data/std/multiset.mt +191 -0
- data/std/net/channel.mt +727 -0
- data/std/net/clock.mt +237 -0
- data/std/net/discovery.mt +277 -0
- data/std/net/lobby.mt +813 -0
- data/std/net/manager.mt +539 -0
- data/std/net/mux.mt +839 -0
- data/std/net/nat.mt +122 -0
- data/std/net/packet.mt +219 -0
- data/std/net/punch.mt +162 -0
- data/std/net/rpc.mt +119 -0
- data/std/net/session.mt +1157 -0
- data/std/net/stun.mt +252 -0
- data/std/net/sync.mt +183 -0
- data/std/net/turn.mt +459 -0
- data/std/net.mt +2944 -0
- data/std/oauth2.mt +408 -0
- data/std/option.mt +51 -0
- data/std/ordered_map.mt +497 -0
- data/std/ordered_set.mt +348 -0
- data/std/path.mt +368 -0
- data/std/pcre2/runtime.mt +35 -0
- data/std/pcre2.mt +78 -0
- data/std/priority_queue.mt +55 -0
- data/std/process.mt +837 -0
- data/std/queue.mt +55 -0
- data/std/random.mt +146 -0
- data/std/raygui.mt +99 -0
- data/std/raylib/debug_console.mt +71 -0
- data/std/raylib/easing.mt +388 -0
- data/std/raylib/packed_assets.mt +255 -0
- data/std/raylib/runtime.mt +30 -0
- data/std/raylib/tracy_gpu.mt +37 -0
- data/std/raylib.mt +1510 -0
- data/std/raymath.mt +153 -0
- data/std/result.mt +89 -0
- data/std/rlgl.mt +268 -0
- data/std/rpng.mt +46 -0
- data/std/rres.mt +36 -0
- data/std/sdl3/runtime.mt +54 -0
- data/std/sdl3.mt +1731 -0
- data/std/serialize.mt +68 -0
- data/std/set.mt +124 -0
- data/std/spatial.mt +176 -0
- data/std/sqlite3.mt +151 -0
- data/std/stack.mt +55 -0
- data/std/stb_image.mt +47 -0
- data/std/stb_image_resize2.mt +41 -0
- data/std/stb_image_write.mt +17 -0
- data/std/stb_rect_pack.mt +15 -0
- data/std/stb_truetype.mt +77 -0
- data/std/stb_vorbis.mt +16 -0
- data/std/stdio.mt +88 -0
- data/std/steamworks.mt +1542 -0
- data/std/str.mt +293 -0
- data/std/string.mt +234 -0
- data/std/sync.mt +194 -0
- data/std/tar.mt +704 -0
- data/std/terminal.mt +1002 -0
- data/std/testing.mt +266 -0
- data/std/thread.mt +120 -0
- data/std/time.mt +105 -0
- data/std/tls.mt +616 -0
- data/std/toml.mt +1310 -0
- data/std/tracy.mt +42 -0
- data/std/uri.mt +118 -0
- data/std/url.mt +372 -0
- data/std/vec.mt +433 -0
- data/std/zstd.mt +94 -0
- metadata +187 -2
data/std/net/channel.mt
ADDED
|
@@ -0,0 +1,727 @@
|
|
|
1
|
+
import std.async as aio
|
|
2
|
+
import std.bytes as bytes
|
|
3
|
+
import std.net as net
|
|
4
|
+
import std.string as string
|
|
5
|
+
import std.vec as vec
|
|
6
|
+
|
|
7
|
+
const header_magic: uint = 0x4D545331
|
|
8
|
+
const header_bytes: ptr_uint = 17
|
|
9
|
+
const reliable_flag: ubyte = 1
|
|
10
|
+
const ack_only_flag: ubyte = 2
|
|
11
|
+
const ack_window_size: ptr_uint = 32
|
|
12
|
+
const max_uint_value: ulong = 0xFFFFFFFF
|
|
13
|
+
const half_sequence_range: uint = 0x80000000
|
|
14
|
+
|
|
15
|
+
public struct Config:
|
|
16
|
+
max_payload_bytes: ptr_uint
|
|
17
|
+
max_pending_reliable: ptr_uint
|
|
18
|
+
resend_after_frames: uint
|
|
19
|
+
|
|
20
|
+
public struct Message:
|
|
21
|
+
sequence: uint
|
|
22
|
+
reliable: bool
|
|
23
|
+
payload: bytes.Bytes
|
|
24
|
+
|
|
25
|
+
public struct HostMessage:
|
|
26
|
+
source: net.SocketAddress
|
|
27
|
+
sequence: uint
|
|
28
|
+
reliable: bool
|
|
29
|
+
payload: bytes.Bytes
|
|
30
|
+
|
|
31
|
+
public struct Channel:
|
|
32
|
+
socket: net.UdpSocket
|
|
33
|
+
config: Config
|
|
34
|
+
protocol: ProtocolState
|
|
35
|
+
|
|
36
|
+
public struct Host:
|
|
37
|
+
socket: net.UdpSocket
|
|
38
|
+
config: Config
|
|
39
|
+
peers: vec.Vec[PeerState]
|
|
40
|
+
|
|
41
|
+
struct PacketHeader:
|
|
42
|
+
sequence: uint
|
|
43
|
+
ack: uint
|
|
44
|
+
ack_bits: uint
|
|
45
|
+
packet_flags: ubyte
|
|
46
|
+
|
|
47
|
+
struct PendingReliable:
|
|
48
|
+
sequence: uint
|
|
49
|
+
payload: bytes.Bytes
|
|
50
|
+
last_sent_frame: uint
|
|
51
|
+
|
|
52
|
+
struct ProtocolState:
|
|
53
|
+
next_sequence: uint
|
|
54
|
+
received_initialized: bool
|
|
55
|
+
received_sequence: uint
|
|
56
|
+
received_mask: uint
|
|
57
|
+
pending_reliable: vec.Vec[PendingReliable]
|
|
58
|
+
|
|
59
|
+
struct PeerState:
|
|
60
|
+
address: net.SocketAddress
|
|
61
|
+
protocol: ProtocolState
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
function encode_uint(value: uint) -> array[ubyte, 4]:
|
|
65
|
+
return array[ubyte, 4](
|
|
66
|
+
ubyte<-((value >> 24) & 255),
|
|
67
|
+
ubyte<-((value >> 16) & 255),
|
|
68
|
+
ubyte<-((value >> 8) & 255),
|
|
69
|
+
ubyte<-(value & 255)
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
function decode_uint(data: span[ubyte], offset: ptr_uint) -> uint:
|
|
74
|
+
return (
|
|
75
|
+
((uint<-data[offset]) << 24)
|
|
76
|
+
| ((uint<-data[offset + 1]) << 16)
|
|
77
|
+
| ((uint<-data[offset + 2]) << 8)
|
|
78
|
+
| (uint<-data[offset + 3])
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
function sequence_gap(newer: uint, older: uint) -> uint:
|
|
83
|
+
if newer >= older:
|
|
84
|
+
return newer - older
|
|
85
|
+
|
|
86
|
+
return uint<-((ulong<-newer) + (max_uint_value - ulong<-older) + 1)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
function sequence_more_recent(left: uint, right: uint) -> bool:
|
|
90
|
+
let forward_gap = sequence_gap(left, right)
|
|
91
|
+
return forward_gap != 0 and forward_gap < half_sequence_range
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
function sequence_is_acked(sequence: uint, ack: uint, ack_bits: uint) -> bool:
|
|
95
|
+
if sequence == ack:
|
|
96
|
+
return true
|
|
97
|
+
|
|
98
|
+
if sequence_more_recent(sequence, ack):
|
|
99
|
+
return false
|
|
100
|
+
|
|
101
|
+
let distance = sequence_gap(ack, sequence)
|
|
102
|
+
if distance == 0 or distance > uint<-ack_window_size:
|
|
103
|
+
return false
|
|
104
|
+
|
|
105
|
+
let mask = (1u) << (distance - 1)
|
|
106
|
+
return (ack_bits & mask) != 0
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
function create_protocol_state() -> ProtocolState:
|
|
110
|
+
return ProtocolState(
|
|
111
|
+
next_sequence = 0,
|
|
112
|
+
received_initialized = false,
|
|
113
|
+
received_sequence = 0,
|
|
114
|
+
received_mask = 0,
|
|
115
|
+
pending_reliable = vec.Vec[PendingReliable].create()
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
function release_protocol_state(protocol: ptr[ProtocolState]) -> void:
|
|
120
|
+
while true:
|
|
121
|
+
let removed = unsafe: read(protocol).pending_reliable.pop()
|
|
122
|
+
if removed.is_none():
|
|
123
|
+
break
|
|
124
|
+
var entry = removed.unwrap()
|
|
125
|
+
entry.payload.release()
|
|
126
|
+
|
|
127
|
+
unsafe: read(protocol).pending_reliable.release()
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
function release_peer_state(peer: ptr[PeerState]) -> void:
|
|
131
|
+
let protocol = unsafe: ptr_of(read(peer).protocol)
|
|
132
|
+
release_protocol_state(protocol)
|
|
133
|
+
unsafe: read(peer).address.release()
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
function allocate_sequence(protocol: ptr[ProtocolState]) -> uint:
|
|
137
|
+
let sequence = unsafe: read(protocol).next_sequence
|
|
138
|
+
unsafe: read(protocol).next_sequence += 1
|
|
139
|
+
return sequence
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
function pending_window_limit(config: Config) -> ptr_uint:
|
|
143
|
+
if config.max_pending_reliable < ack_window_size:
|
|
144
|
+
return config.max_pending_reliable
|
|
145
|
+
|
|
146
|
+
return ack_window_size
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
function build_packet(
|
|
150
|
+
sequence: uint,
|
|
151
|
+
ack: uint,
|
|
152
|
+
ack_bits: uint,
|
|
153
|
+
packet_flags: ubyte,
|
|
154
|
+
content: span[ubyte]
|
|
155
|
+
) -> bytes.Bytes:
|
|
156
|
+
var buffer = vec.Vec[ubyte].with_capacity(header_bytes + content.len)
|
|
157
|
+
defer buffer.release()
|
|
158
|
+
|
|
159
|
+
buffer.append_array(encode_uint(header_magic))
|
|
160
|
+
buffer.append_array(encode_uint(sequence))
|
|
161
|
+
buffer.append_array(encode_uint(ack))
|
|
162
|
+
buffer.append_array(encode_uint(ack_bits))
|
|
163
|
+
buffer.push(packet_flags)
|
|
164
|
+
buffer.append_span(content)
|
|
165
|
+
return bytes.Bytes.copy(buffer.as_span())
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
function decode_header(packet: bytes.Bytes) -> Result[PacketHeader, net.Error]:
|
|
169
|
+
if packet.len < header_bytes:
|
|
170
|
+
return Result[PacketHeader, net.Error].failure(error = net.Error(
|
|
171
|
+
code = -1,
|
|
172
|
+
message = string.String.from_str("udp channel packet is too small")
|
|
173
|
+
))
|
|
174
|
+
|
|
175
|
+
let packet_span = packet.as_span()
|
|
176
|
+
let magic = decode_uint(packet_span, 0)
|
|
177
|
+
if magic != header_magic:
|
|
178
|
+
return Result[PacketHeader, net.Error].failure(error = net.Error(
|
|
179
|
+
code = -1,
|
|
180
|
+
message = string.String.from_str("udp channel packet has an invalid header")
|
|
181
|
+
))
|
|
182
|
+
|
|
183
|
+
return Result[PacketHeader, net.Error].success(value = PacketHeader(
|
|
184
|
+
sequence = decode_uint(packet_span, 4),
|
|
185
|
+
ack = decode_uint(packet_span, 8),
|
|
186
|
+
ack_bits = decode_uint(packet_span, 12),
|
|
187
|
+
packet_flags = packet_span[16]
|
|
188
|
+
))
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
function copy_payload(packet: bytes.Bytes) -> bytes.Bytes:
|
|
192
|
+
if packet.len == header_bytes:
|
|
193
|
+
return bytes.Bytes.empty()
|
|
194
|
+
|
|
195
|
+
let packet_span = packet.as_span()
|
|
196
|
+
unsafe:
|
|
197
|
+
return bytes.Bytes.copy(span[ubyte](
|
|
198
|
+
data = packet_span.data + header_bytes,
|
|
199
|
+
len = packet_span.len - header_bytes
|
|
200
|
+
))
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
function remove_acked_pending(protocol: ptr[ProtocolState], ack: uint, ack_bits: uint) -> void:
|
|
204
|
+
var index: ptr_uint = 0
|
|
205
|
+
while true:
|
|
206
|
+
let pending_len = unsafe: read(protocol).pending_reliable.len()
|
|
207
|
+
if index >= pending_len:
|
|
208
|
+
break
|
|
209
|
+
|
|
210
|
+
let entry_ptr = unsafe: read(protocol).pending_reliable.get(index) else:
|
|
211
|
+
fatal(c"udp channel pending entry missing storage")
|
|
212
|
+
|
|
213
|
+
if sequence_is_acked(unsafe: read(entry_ptr).sequence, ack, ack_bits):
|
|
214
|
+
let removed = unsafe: read(protocol).pending_reliable.remove(index)
|
|
215
|
+
var entry = removed.expect("udp channel pending entry removal failed")
|
|
216
|
+
entry.payload.release()
|
|
217
|
+
continue
|
|
218
|
+
|
|
219
|
+
index += 1
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
function mark_received(protocol: ptr[ProtocolState], sequence: uint) -> bool:
|
|
223
|
+
let received_initialized = unsafe: read(protocol).received_initialized
|
|
224
|
+
if not received_initialized:
|
|
225
|
+
unsafe:
|
|
226
|
+
read(protocol).received_initialized = true
|
|
227
|
+
read(protocol).received_sequence = sequence
|
|
228
|
+
read(protocol).received_mask = 0
|
|
229
|
+
return true
|
|
230
|
+
|
|
231
|
+
let current_sequence = unsafe: read(protocol).received_sequence
|
|
232
|
+
if sequence == current_sequence:
|
|
233
|
+
return false
|
|
234
|
+
|
|
235
|
+
if sequence_more_recent(sequence, current_sequence):
|
|
236
|
+
let distance = sequence_gap(sequence, current_sequence)
|
|
237
|
+
if distance > uint<-ack_window_size:
|
|
238
|
+
unsafe: read(protocol).received_mask = 0
|
|
239
|
+
else:
|
|
240
|
+
if distance < uint<-ack_window_size:
|
|
241
|
+
unsafe: read(protocol).received_mask = read(protocol).received_mask << distance
|
|
242
|
+
else:
|
|
243
|
+
unsafe: read(protocol).received_mask = 0
|
|
244
|
+
|
|
245
|
+
unsafe: read(protocol).received_mask |= (1) << (distance - 1)
|
|
246
|
+
|
|
247
|
+
unsafe: read(protocol).received_sequence = sequence
|
|
248
|
+
return true
|
|
249
|
+
|
|
250
|
+
let current_mask = unsafe: read(protocol).received_mask
|
|
251
|
+
let distance = sequence_gap(current_sequence, sequence)
|
|
252
|
+
if distance == 0 or distance > uint<-ack_window_size:
|
|
253
|
+
return false
|
|
254
|
+
|
|
255
|
+
let mask = (1u) << (distance - 1)
|
|
256
|
+
if (current_mask & mask) != 0:
|
|
257
|
+
return false
|
|
258
|
+
|
|
259
|
+
unsafe: read(protocol).received_mask |= mask
|
|
260
|
+
return true
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
async function send_connected_packet(
|
|
264
|
+
socket: net.UdpSocket,
|
|
265
|
+
protocol: ptr[ProtocolState],
|
|
266
|
+
sequence: uint,
|
|
267
|
+
packet_flags: ubyte,
|
|
268
|
+
content: span[ubyte]
|
|
269
|
+
) -> Result[bool, net.Error]:
|
|
270
|
+
var ack: uint = 0
|
|
271
|
+
var ack_bits: uint = 0
|
|
272
|
+
let received_initialized = unsafe: read(protocol).received_initialized
|
|
273
|
+
if received_initialized:
|
|
274
|
+
ack = unsafe: read(protocol).received_sequence
|
|
275
|
+
ack_bits = unsafe: read(protocol).received_mask
|
|
276
|
+
|
|
277
|
+
var framed = build_packet(sequence, ack, ack_bits, packet_flags, content)
|
|
278
|
+
defer framed.release()
|
|
279
|
+
|
|
280
|
+
(await socket.send(framed.as_span()))?
|
|
281
|
+
return Result[bool, net.Error].success(value = true)
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
async function send_packet_to(
|
|
285
|
+
socket: net.UdpSocket,
|
|
286
|
+
destination: net.SocketAddress,
|
|
287
|
+
protocol: ptr[ProtocolState],
|
|
288
|
+
sequence: uint,
|
|
289
|
+
packet_flags: ubyte,
|
|
290
|
+
content: span[ubyte]
|
|
291
|
+
) -> Result[bool, net.Error]:
|
|
292
|
+
var ack: uint = 0
|
|
293
|
+
var ack_bits: uint = 0
|
|
294
|
+
let received_initialized = unsafe: read(protocol).received_initialized
|
|
295
|
+
if received_initialized:
|
|
296
|
+
ack = unsafe: read(protocol).received_sequence
|
|
297
|
+
ack_bits = unsafe: read(protocol).received_mask
|
|
298
|
+
|
|
299
|
+
var framed = build_packet(sequence, ack, ack_bits, packet_flags, content)
|
|
300
|
+
defer framed.release()
|
|
301
|
+
|
|
302
|
+
(await socket.send_to(framed.as_span(), destination))?
|
|
303
|
+
return Result[bool, net.Error].success(value = true)
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
async function send_connected_ack_only(socket: net.UdpSocket, protocol: ptr[ProtocolState]) -> Result[bool, net.Error]:
|
|
307
|
+
let sequence = allocate_sequence(protocol)
|
|
308
|
+
return await send_connected_packet(socket, protocol, sequence, ack_only_flag, bytes.Bytes.empty().as_span())
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
async function send_ack_only_to(
|
|
312
|
+
socket: net.UdpSocket,
|
|
313
|
+
destination: net.SocketAddress,
|
|
314
|
+
protocol: ptr[ProtocolState]
|
|
315
|
+
) -> Result[bool, net.Error]:
|
|
316
|
+
let sequence = allocate_sequence(protocol)
|
|
317
|
+
return await send_packet_to(socket, destination, protocol, sequence, ack_only_flag, bytes.Bytes.empty().as_span())
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
function find_peer_index(host: ref[Host], address: net.SocketAddress) -> Option[ptr_uint]:
|
|
321
|
+
var index: ptr_uint = 0
|
|
322
|
+
while index < host.peers.len():
|
|
323
|
+
let peer_ptr = host.peers.get(index) else:
|
|
324
|
+
fatal(c"udp channel host peer missing storage")
|
|
325
|
+
|
|
326
|
+
let same_address = unsafe: read(peer_ptr).address.equal(address)
|
|
327
|
+
if same_address:
|
|
328
|
+
return Option[ptr_uint].some(value = index)
|
|
329
|
+
|
|
330
|
+
index += 1
|
|
331
|
+
|
|
332
|
+
return Option[ptr_uint].none
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
function get_or_create_peer(host: ref[Host], address: net.SocketAddress) -> Result[ptr[PeerState], net.Error]:
|
|
336
|
+
match find_peer_index(host, address):
|
|
337
|
+
Option.some as payload:
|
|
338
|
+
let peer_ptr = host.peers.get(payload.value) else:
|
|
339
|
+
fatal(c"udp channel host peer lookup missing storage")
|
|
340
|
+
return Result[ptr[PeerState], net.Error].success(value = peer_ptr)
|
|
341
|
+
Option.none:
|
|
342
|
+
let addr = address.copy()?
|
|
343
|
+
host.peers.push(PeerState(address = addr, protocol = create_protocol_state()))
|
|
344
|
+
let peer_ptr = host.peers.last() else:
|
|
345
|
+
fatal(c"udp channel host peer insertion missing storage")
|
|
346
|
+
return Result[ptr[PeerState], net.Error].success(value = peer_ptr)
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
public function wrap_connected(socket: net.UdpSocket, config: Config) -> Channel:
|
|
350
|
+
return Channel(socket = socket, config = config, protocol = create_protocol_state())
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
public function connect_on(
|
|
354
|
+
runtime: aio.Runtime,
|
|
355
|
+
local_address: net.SocketAddress,
|
|
356
|
+
remote_address: net.SocketAddress,
|
|
357
|
+
config: Config
|
|
358
|
+
) -> Result[Channel, net.Error]:
|
|
359
|
+
var socket = net.udp_bind_on(runtime, local_address)?
|
|
360
|
+
match socket.connect(remote_address):
|
|
361
|
+
Result.failure as connect_payload:
|
|
362
|
+
socket.release()
|
|
363
|
+
return Result[Channel, net.Error].failure(error = connect_payload.error)
|
|
364
|
+
Result.success as connect_payload:
|
|
365
|
+
if not connect_payload.value:
|
|
366
|
+
socket.release()
|
|
367
|
+
return Result[Channel, net.Error].failure(error = net.Error(
|
|
368
|
+
code = -1,
|
|
369
|
+
message = string.String.from_str("udp connect did not complete")
|
|
370
|
+
))
|
|
371
|
+
return Result[Channel, net.Error].success(value = wrap_connected(socket, config))
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
public function connect(
|
|
375
|
+
local_address: net.SocketAddress,
|
|
376
|
+
remote_address: net.SocketAddress,
|
|
377
|
+
config: Config
|
|
378
|
+
) -> Result[Channel, net.Error]:
|
|
379
|
+
return connect_on(aio.current_runtime(), local_address, remote_address, config)
|
|
380
|
+
|
|
381
|
+
|
|
382
|
+
public function listen_on(
|
|
383
|
+
runtime: aio.Runtime,
|
|
384
|
+
local_address: net.SocketAddress,
|
|
385
|
+
config: Config
|
|
386
|
+
) -> Result[Host, net.Error]:
|
|
387
|
+
let socket = net.udp_bind_on(runtime, local_address)?
|
|
388
|
+
return Result[Host, net.Error].success(value = Host(
|
|
389
|
+
socket = socket,
|
|
390
|
+
config = config,
|
|
391
|
+
peers = vec.Vec[PeerState].create()
|
|
392
|
+
))
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
public function listen(local_address: net.SocketAddress, config: Config) -> Result[Host, net.Error]:
|
|
396
|
+
return listen_on(aio.current_runtime(), local_address, config)
|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
extending Config:
|
|
400
|
+
public static function default(max_payload_bytes: ptr_uint) -> Config:
|
|
401
|
+
return Config(
|
|
402
|
+
max_payload_bytes = max_payload_bytes,
|
|
403
|
+
max_pending_reliable = ack_window_size,
|
|
404
|
+
resend_after_frames = 5
|
|
405
|
+
)
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
extending Message:
|
|
409
|
+
public editable function release() -> void:
|
|
410
|
+
this.payload.release()
|
|
411
|
+
|
|
412
|
+
|
|
413
|
+
extending HostMessage:
|
|
414
|
+
public editable function release() -> void:
|
|
415
|
+
this.payload.release()
|
|
416
|
+
this.source.release()
|
|
417
|
+
|
|
418
|
+
|
|
419
|
+
extending Channel:
|
|
420
|
+
public editable function release() -> void:
|
|
421
|
+
let protocol = unsafe: ptr_of(this.protocol)
|
|
422
|
+
release_protocol_state(protocol)
|
|
423
|
+
this.socket.release()
|
|
424
|
+
|
|
425
|
+
|
|
426
|
+
public function local_address() -> Result[net.SocketAddress, net.Error]:
|
|
427
|
+
return this.socket.local_address()
|
|
428
|
+
|
|
429
|
+
|
|
430
|
+
public function peer_address() -> Result[net.SocketAddress, net.Error]:
|
|
431
|
+
return this.socket.peer_address()
|
|
432
|
+
|
|
433
|
+
|
|
434
|
+
public function pending_reliable_len() -> ptr_uint:
|
|
435
|
+
return this.protocol.pending_reliable.len()
|
|
436
|
+
|
|
437
|
+
|
|
438
|
+
public async editable function send(content: span[ubyte]) -> Result[uint, net.Error]:
|
|
439
|
+
if content.len > this.config.max_payload_bytes:
|
|
440
|
+
return Result[uint, net.Error].failure(error = net.Error(
|
|
441
|
+
code = -2,
|
|
442
|
+
message = string.String.from_str("udp channel payload exceeds configured maximum")
|
|
443
|
+
))
|
|
444
|
+
|
|
445
|
+
let protocol = unsafe: ptr_of(this.protocol)
|
|
446
|
+
let sequence = allocate_sequence(protocol)
|
|
447
|
+
(await send_connected_packet(this.socket, protocol, sequence, 0, content))?
|
|
448
|
+
return Result[uint, net.Error].success(value = sequence)
|
|
449
|
+
|
|
450
|
+
|
|
451
|
+
public async editable function send_reliable(content: span[ubyte], frame: uint) -> Result[uint, net.Error]:
|
|
452
|
+
if content.len > this.config.max_payload_bytes:
|
|
453
|
+
return Result[uint, net.Error].failure(error = net.Error(
|
|
454
|
+
code = -2,
|
|
455
|
+
message = string.String.from_str("udp channel payload exceeds configured maximum")
|
|
456
|
+
))
|
|
457
|
+
|
|
458
|
+
let protocol = unsafe: ptr_of(this.protocol)
|
|
459
|
+
let pending_len = unsafe: read(protocol).pending_reliable.len()
|
|
460
|
+
if pending_len >= pending_window_limit(this.config):
|
|
461
|
+
return Result[uint, net.Error].failure(error = net.Error(
|
|
462
|
+
code = -3,
|
|
463
|
+
message = string.String.from_str("udp channel reliable window is full")
|
|
464
|
+
))
|
|
465
|
+
|
|
466
|
+
let sequence = allocate_sequence(protocol)
|
|
467
|
+
(await send_connected_packet(this.socket, protocol, sequence, reliable_flag, content))?
|
|
468
|
+
unsafe: read(protocol).pending_reliable.push(PendingReliable(
|
|
469
|
+
sequence = sequence,
|
|
470
|
+
payload = bytes.Bytes.copy(content),
|
|
471
|
+
last_sent_frame = frame
|
|
472
|
+
))
|
|
473
|
+
return Result[uint, net.Error].success(value = sequence)
|
|
474
|
+
|
|
475
|
+
|
|
476
|
+
public async editable function recv() -> Result[Option[Message], net.Error]:
|
|
477
|
+
var packet = (await this.socket.recv(this.config.max_payload_bytes + header_bytes))?
|
|
478
|
+
defer packet.release()
|
|
479
|
+
|
|
480
|
+
let header = decode_header(packet)?
|
|
481
|
+
let protocol = unsafe: ptr_of(this.protocol)
|
|
482
|
+
remove_acked_pending(protocol, header.ack, header.ack_bits)
|
|
483
|
+
let is_new = mark_received(protocol, header.sequence)
|
|
484
|
+
let is_reliable = (header.packet_flags & reliable_flag) != 0
|
|
485
|
+
if is_reliable:
|
|
486
|
+
(await send_connected_ack_only(this.socket, protocol))?
|
|
487
|
+
|
|
488
|
+
if (header.packet_flags & ack_only_flag) != 0:
|
|
489
|
+
return Result[Option[Message], net.Error].success(value = Option[Message].none)
|
|
490
|
+
|
|
491
|
+
if not is_new:
|
|
492
|
+
return Result[Option[Message], net.Error].success(value = Option[Message].none)
|
|
493
|
+
|
|
494
|
+
return Result[Option[Message], net.Error].success(value = Option[Message].some(value = Message(
|
|
495
|
+
sequence = header.sequence,
|
|
496
|
+
reliable = is_reliable,
|
|
497
|
+
payload = copy_payload(packet)
|
|
498
|
+
)))
|
|
499
|
+
|
|
500
|
+
|
|
501
|
+
public async editable function tick(frame: uint) -> Result[ptr_uint, net.Error]:
|
|
502
|
+
let protocol = unsafe: ptr_of(this.protocol)
|
|
503
|
+
var resent: ptr_uint = 0
|
|
504
|
+
var index: ptr_uint = 0
|
|
505
|
+
while true:
|
|
506
|
+
let pending_len = unsafe: read(protocol).pending_reliable.len()
|
|
507
|
+
if index >= pending_len:
|
|
508
|
+
break
|
|
509
|
+
|
|
510
|
+
let entry_ptr = unsafe: read(protocol).pending_reliable.get(index) else:
|
|
511
|
+
fatal(c"udp channel pending entry missing storage")
|
|
512
|
+
|
|
513
|
+
let last_sent_frame = unsafe: read(entry_ptr).last_sent_frame
|
|
514
|
+
if sequence_gap(frame, last_sent_frame) < this.config.resend_after_frames:
|
|
515
|
+
index += 1
|
|
516
|
+
continue
|
|
517
|
+
|
|
518
|
+
(await send_connected_packet(
|
|
519
|
+
this.socket,
|
|
520
|
+
protocol,
|
|
521
|
+
unsafe: read(entry_ptr).sequence,
|
|
522
|
+
reliable_flag,
|
|
523
|
+
unsafe: read(entry_ptr).payload.as_span()
|
|
524
|
+
))?
|
|
525
|
+
unsafe: read(entry_ptr).last_sent_frame = frame
|
|
526
|
+
resent += 1
|
|
527
|
+
|
|
528
|
+
index += 1
|
|
529
|
+
|
|
530
|
+
return Result[ptr_uint, net.Error].success(value = resent)
|
|
531
|
+
|
|
532
|
+
|
|
533
|
+
extending Host:
|
|
534
|
+
public editable function release() -> void:
|
|
535
|
+
while true:
|
|
536
|
+
let removed = this.peers.pop()
|
|
537
|
+
if removed.is_none():
|
|
538
|
+
break
|
|
539
|
+
var peer = removed.unwrap()
|
|
540
|
+
let peer_ptr = unsafe: ptr_of(peer)
|
|
541
|
+
release_peer_state(peer_ptr)
|
|
542
|
+
|
|
543
|
+
this.peers.release()
|
|
544
|
+
this.socket.release()
|
|
545
|
+
|
|
546
|
+
|
|
547
|
+
public function local_address() -> Result[net.SocketAddress, net.Error]:
|
|
548
|
+
return this.socket.local_address()
|
|
549
|
+
|
|
550
|
+
|
|
551
|
+
public function peer_count() -> ptr_uint:
|
|
552
|
+
return this.peers.len()
|
|
553
|
+
|
|
554
|
+
|
|
555
|
+
public function pending_reliable_len() -> ptr_uint:
|
|
556
|
+
var total: ptr_uint = 0
|
|
557
|
+
var index: ptr_uint = 0
|
|
558
|
+
while index < this.peers.len():
|
|
559
|
+
let peer_ptr = this.peers.get(index) else:
|
|
560
|
+
fatal(c"udp channel host peer missing storage")
|
|
561
|
+
|
|
562
|
+
let protocol = unsafe: ptr_of(read(peer_ptr).protocol)
|
|
563
|
+
total += unsafe: read(protocol).pending_reliable.len()
|
|
564
|
+
index += 1
|
|
565
|
+
|
|
566
|
+
return total
|
|
567
|
+
|
|
568
|
+
|
|
569
|
+
public async editable function send(
|
|
570
|
+
destination: net.SocketAddress,
|
|
571
|
+
content: span[ubyte]
|
|
572
|
+
) -> Result[uint, net.Error]:
|
|
573
|
+
if content.len > this.config.max_payload_bytes:
|
|
574
|
+
return Result[uint, net.Error].failure(error = net.Error(
|
|
575
|
+
code = -2,
|
|
576
|
+
message = string.String.from_str("udp channel payload exceeds configured maximum")
|
|
577
|
+
))
|
|
578
|
+
|
|
579
|
+
let peer_ptr = get_or_create_peer(ref_of(this), destination)?
|
|
580
|
+
let protocol = unsafe: ptr_of(read(peer_ptr).protocol)
|
|
581
|
+
let sequence = allocate_sequence(protocol)
|
|
582
|
+
(await send_packet_to(
|
|
583
|
+
this.socket,
|
|
584
|
+
unsafe: read(peer_ptr).address,
|
|
585
|
+
protocol,
|
|
586
|
+
sequence,
|
|
587
|
+
0,
|
|
588
|
+
content
|
|
589
|
+
))?
|
|
590
|
+
return Result[uint, net.Error].success(value = sequence)
|
|
591
|
+
|
|
592
|
+
|
|
593
|
+
public async editable function send_reliable(
|
|
594
|
+
destination: net.SocketAddress,
|
|
595
|
+
content: span[ubyte],
|
|
596
|
+
frame: uint
|
|
597
|
+
) -> Result[uint, net.Error]:
|
|
598
|
+
if content.len > this.config.max_payload_bytes:
|
|
599
|
+
return Result[uint, net.Error].failure(error = net.Error(
|
|
600
|
+
code = -2,
|
|
601
|
+
message = string.String.from_str("udp channel payload exceeds configured maximum")
|
|
602
|
+
))
|
|
603
|
+
|
|
604
|
+
let peer_ptr = get_or_create_peer(ref_of(this), destination)?
|
|
605
|
+
let protocol = unsafe: ptr_of(read(peer_ptr).protocol)
|
|
606
|
+
let pending_len = unsafe: read(protocol).pending_reliable.len()
|
|
607
|
+
if pending_len >= pending_window_limit(this.config):
|
|
608
|
+
return Result[uint, net.Error].failure(error = net.Error(
|
|
609
|
+
code = -3,
|
|
610
|
+
message = string.String.from_str("udp channel reliable window is full")
|
|
611
|
+
))
|
|
612
|
+
|
|
613
|
+
let sequence = allocate_sequence(protocol)
|
|
614
|
+
(await send_packet_to(
|
|
615
|
+
this.socket,
|
|
616
|
+
unsafe: read(peer_ptr).address,
|
|
617
|
+
protocol,
|
|
618
|
+
sequence,
|
|
619
|
+
reliable_flag,
|
|
620
|
+
content
|
|
621
|
+
))?
|
|
622
|
+
unsafe: read(protocol).pending_reliable.push(PendingReliable(
|
|
623
|
+
sequence = sequence,
|
|
624
|
+
payload = bytes.Bytes.copy(content),
|
|
625
|
+
last_sent_frame = frame
|
|
626
|
+
))
|
|
627
|
+
return Result[uint, net.Error].success(value = sequence)
|
|
628
|
+
|
|
629
|
+
|
|
630
|
+
public async editable function recv() -> Result[Option[HostMessage], net.Error]:
|
|
631
|
+
var datagram = (await this.socket.recv_from(this.config.max_payload_bytes + header_bytes))?
|
|
632
|
+
|
|
633
|
+
let header_result = decode_header(datagram.data)
|
|
634
|
+
match header_result:
|
|
635
|
+
Result.failure as header_payload:
|
|
636
|
+
datagram.release()
|
|
637
|
+
return Result[Option[HostMessage], net.Error].failure(error = header_payload.error)
|
|
638
|
+
Result.success as header_payload:
|
|
639
|
+
let peer_result = get_or_create_peer(ref_of(this), datagram.source)
|
|
640
|
+
match peer_result:
|
|
641
|
+
Result.failure as peer_payload:
|
|
642
|
+
datagram.release()
|
|
643
|
+
return Result[Option[HostMessage], net.Error].failure(error = peer_payload.error)
|
|
644
|
+
Result.success as peer_payload:
|
|
645
|
+
let peer_ptr = peer_payload.value
|
|
646
|
+
let protocol = unsafe: ptr_of(read(peer_ptr).protocol)
|
|
647
|
+
let header = header_payload.value
|
|
648
|
+
remove_acked_pending(protocol, header.ack, header.ack_bits)
|
|
649
|
+
let is_new = mark_received(protocol, header.sequence)
|
|
650
|
+
let is_reliable = (header.packet_flags & reliable_flag) != 0
|
|
651
|
+
if is_reliable:
|
|
652
|
+
let ack_result = await send_ack_only_to(this.socket, datagram.source, protocol)
|
|
653
|
+
match ack_result:
|
|
654
|
+
Result.failure as ack_payload:
|
|
655
|
+
datagram.release()
|
|
656
|
+
return Result[
|
|
657
|
+
Option[HostMessage],
|
|
658
|
+
net.Error
|
|
659
|
+
].failure(error = ack_payload.error)
|
|
660
|
+
Result.success as ack_payload:
|
|
661
|
+
ack_payload.value
|
|
662
|
+
|
|
663
|
+
if (header.packet_flags & ack_only_flag) != 0:
|
|
664
|
+
datagram.release()
|
|
665
|
+
return Result[
|
|
666
|
+
Option[HostMessage],
|
|
667
|
+
net.Error
|
|
668
|
+
].success(value = Option[HostMessage].none)
|
|
669
|
+
|
|
670
|
+
if not is_new:
|
|
671
|
+
datagram.release()
|
|
672
|
+
return Result[
|
|
673
|
+
Option[HostMessage],
|
|
674
|
+
net.Error
|
|
675
|
+
].success(value = Option[HostMessage].none)
|
|
676
|
+
|
|
677
|
+
let payload = copy_payload(datagram.data)
|
|
678
|
+
datagram.data.release()
|
|
679
|
+
return Result[
|
|
680
|
+
Option[HostMessage],
|
|
681
|
+
net.Error
|
|
682
|
+
].success(value = Option[HostMessage].some(value = HostMessage(
|
|
683
|
+
source = datagram.source,
|
|
684
|
+
sequence = header.sequence,
|
|
685
|
+
reliable = is_reliable,
|
|
686
|
+
payload = payload
|
|
687
|
+
)))
|
|
688
|
+
|
|
689
|
+
|
|
690
|
+
public async editable function tick(frame: uint) -> Result[ptr_uint, net.Error]:
|
|
691
|
+
var resent: ptr_uint = 0
|
|
692
|
+
var peer_index: ptr_uint = 0
|
|
693
|
+
while peer_index < this.peers.len():
|
|
694
|
+
let peer_ptr = this.peers.get(peer_index) else:
|
|
695
|
+
fatal(c"udp channel host peer missing storage")
|
|
696
|
+
|
|
697
|
+
let protocol = unsafe: ptr_of(read(peer_ptr).protocol)
|
|
698
|
+
var index: ptr_uint = 0
|
|
699
|
+
while true:
|
|
700
|
+
let pending_len = unsafe: read(protocol).pending_reliable.len()
|
|
701
|
+
if index >= pending_len:
|
|
702
|
+
break
|
|
703
|
+
|
|
704
|
+
let entry_ptr = unsafe: read(protocol).pending_reliable.get(index) else:
|
|
705
|
+
fatal(c"udp channel pending entry missing storage")
|
|
706
|
+
|
|
707
|
+
let last_sent_frame = unsafe: read(entry_ptr).last_sent_frame
|
|
708
|
+
if sequence_gap(frame, last_sent_frame) < this.config.resend_after_frames:
|
|
709
|
+
index += 1
|
|
710
|
+
continue
|
|
711
|
+
|
|
712
|
+
(await send_packet_to(
|
|
713
|
+
this.socket,
|
|
714
|
+
unsafe: read(peer_ptr).address,
|
|
715
|
+
protocol,
|
|
716
|
+
unsafe: read(entry_ptr).sequence,
|
|
717
|
+
reliable_flag,
|
|
718
|
+
unsafe: read(entry_ptr).payload.as_span()
|
|
719
|
+
))?
|
|
720
|
+
unsafe: read(entry_ptr).last_sent_frame = frame
|
|
721
|
+
resent += 1
|
|
722
|
+
|
|
723
|
+
index += 1
|
|
724
|
+
|
|
725
|
+
peer_index += 1
|
|
726
|
+
|
|
727
|
+
return Result[ptr_uint, net.Error].success(value = resent)
|