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/turn.mt
ADDED
|
@@ -0,0 +1,459 @@
|
|
|
1
|
+
import std.async as aio
|
|
2
|
+
import std.binary as bin
|
|
3
|
+
import std.bytes as bytes
|
|
4
|
+
import std.crypto as crypto
|
|
5
|
+
import std.fmt as fmt
|
|
6
|
+
import std.libuv as libuv
|
|
7
|
+
import std.net as net
|
|
8
|
+
import std.string as string
|
|
9
|
+
|
|
10
|
+
const stun_magic_cookie: uint = 0x2112A442
|
|
11
|
+
|
|
12
|
+
const allocate_request: ushort = 0x0003
|
|
13
|
+
const allocate_success: ushort = 0x0103
|
|
14
|
+
const allocate_error: ushort = 0x0113
|
|
15
|
+
const send_indication: ushort = 0x0016
|
|
16
|
+
const data_indication: ushort = 0x0017
|
|
17
|
+
|
|
18
|
+
const attr_xor_relayed_address: ushort = 0x0016
|
|
19
|
+
const attr_xor_peer_address: ushort = 0x0017
|
|
20
|
+
const attr_data: ushort = 0x0012
|
|
21
|
+
const attr_requested_transport: ushort = 0x0019
|
|
22
|
+
|
|
23
|
+
const turn_header_len: ptr_uint = 20
|
|
24
|
+
|
|
25
|
+
const err_tid_failed: int = -1
|
|
26
|
+
const err_send_failed: int = -2
|
|
27
|
+
const err_recv_failed: int = -3
|
|
28
|
+
const err_allocate_rejected: int = -4
|
|
29
|
+
const err_timeout: int = -5
|
|
30
|
+
const err_parse_failed: int = -6
|
|
31
|
+
const err_invalid_address: int = -7
|
|
32
|
+
const err_no_data_attribute: int = -8
|
|
33
|
+
|
|
34
|
+
public struct TurnAllocation:
|
|
35
|
+
relay_address: net.SocketAddress
|
|
36
|
+
|
|
37
|
+
public struct TurnDatagram:
|
|
38
|
+
peer_address: net.SocketAddress
|
|
39
|
+
data: bytes.Bytes
|
|
40
|
+
|
|
41
|
+
public struct Error:
|
|
42
|
+
code: int
|
|
43
|
+
message: string.String
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
extending Error:
|
|
47
|
+
public editable function release() -> void:
|
|
48
|
+
this.message.release()
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
extending TurnAllocation:
|
|
52
|
+
public editable function release() -> void:
|
|
53
|
+
this.relay_address.release()
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
extending TurnDatagram:
|
|
57
|
+
public editable function release() -> void:
|
|
58
|
+
this.peer_address.release()
|
|
59
|
+
this.data.release()
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
function turn_error(code: int, msg: str) -> Error:
|
|
63
|
+
return Error(code = code, message = string.String.from_str(msg))
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
function read_ushort_be(data: span[ubyte], offset: ptr_uint) -> ushort:
|
|
67
|
+
let hi = uint<-data[offset]
|
|
68
|
+
let lo = uint<-data[offset + 1z]
|
|
69
|
+
return ushort<-((hi << 8) | lo)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
function read_uint_be(data: span[ubyte], offset: ptr_uint) -> uint:
|
|
73
|
+
let b0 = uint<-data[offset]
|
|
74
|
+
let b1 = uint<-data[offset + 1z]
|
|
75
|
+
let b2 = uint<-data[offset + 2z]
|
|
76
|
+
let b3 = uint<-data[offset + 3z]
|
|
77
|
+
return (b0 << 24) | (b1 << 16) | (b2 << 8) | b3
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
function format_ipv4(addr: uint) -> string.String:
|
|
81
|
+
let a = (addr & 0xFFu)
|
|
82
|
+
let b = ((addr >> 8u) & 0xFFu)
|
|
83
|
+
let c = ((addr >> 16u) & 0xFFu)
|
|
84
|
+
let d = ((addr >> 24u) & 0xFFu)
|
|
85
|
+
var s = string.String.with_capacity(16)
|
|
86
|
+
fmt.append_uint(ref_of(s), d)
|
|
87
|
+
s.append(".")
|
|
88
|
+
fmt.append_uint(ref_of(s), c)
|
|
89
|
+
s.append(".")
|
|
90
|
+
fmt.append_uint(ref_of(s), b)
|
|
91
|
+
s.append(".")
|
|
92
|
+
fmt.append_uint(ref_of(s), a)
|
|
93
|
+
let result = string.String.from_str(s.as_str())
|
|
94
|
+
s.release()
|
|
95
|
+
return result
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
function transaction_id_from_bytes(data: bytes.Bytes) -> array[ubyte, 12]:
|
|
99
|
+
let span = data.as_span()
|
|
100
|
+
var tid = zero[array[ubyte, 12]]
|
|
101
|
+
var i: ptr_uint = 0
|
|
102
|
+
while i < 12z:
|
|
103
|
+
tid[i] = span[i]
|
|
104
|
+
i += 1
|
|
105
|
+
return tid
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
public function build_allocate_request(tid: array[ubyte, 12]) -> bytes.Bytes:
|
|
109
|
+
var w = bin.Writer.with_capacity(turn_header_len + 8z)
|
|
110
|
+
|
|
111
|
+
w.write_ubyte(0x00)
|
|
112
|
+
w.write_ubyte(0x03)
|
|
113
|
+
w.write_ubyte(0x00)
|
|
114
|
+
w.write_ubyte(0x08)
|
|
115
|
+
|
|
116
|
+
w.write_ubyte(0x21)
|
|
117
|
+
w.write_ubyte(0x12)
|
|
118
|
+
w.write_ubyte(0xA4)
|
|
119
|
+
w.write_ubyte(0x42)
|
|
120
|
+
|
|
121
|
+
var i: ptr_uint = 0
|
|
122
|
+
while i < 12z:
|
|
123
|
+
w.write_ubyte(tid[i])
|
|
124
|
+
i += 1
|
|
125
|
+
|
|
126
|
+
w.write_ubyte(0x00)
|
|
127
|
+
w.write_ubyte(0x19)
|
|
128
|
+
w.write_ubyte(0x00)
|
|
129
|
+
w.write_ubyte(0x04)
|
|
130
|
+
w.write_ubyte(0x11)
|
|
131
|
+
w.write_ubyte(0x00)
|
|
132
|
+
w.write_ubyte(0x00)
|
|
133
|
+
w.write_ubyte(0x00)
|
|
134
|
+
|
|
135
|
+
return w.finish()
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
public function parse_allocate_response(
|
|
139
|
+
packet: bytes.Bytes,
|
|
140
|
+
expected_tid: array[ubyte, 12]
|
|
141
|
+
) -> Result[TurnAllocation, Error]:
|
|
142
|
+
let data = packet.as_span()
|
|
143
|
+
if data.len < turn_header_len:
|
|
144
|
+
return Result[TurnAllocation, Error].failure(
|
|
145
|
+
error = turn_error(err_parse_failed, "packet too small for TURN header")
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
let msg_type = read_ushort_be(data, 0z)
|
|
149
|
+
if msg_type == allocate_error:
|
|
150
|
+
return Result[TurnAllocation, Error].failure(
|
|
151
|
+
error = turn_error(err_allocate_rejected, "server rejected allocation")
|
|
152
|
+
)
|
|
153
|
+
if msg_type != allocate_success:
|
|
154
|
+
return Result[TurnAllocation, Error].failure(
|
|
155
|
+
error = turn_error(err_parse_failed, "not an allocate success response")
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
let cookie = read_uint_be(data, 4z)
|
|
159
|
+
if cookie != stun_magic_cookie:
|
|
160
|
+
return Result[TurnAllocation, Error].failure(
|
|
161
|
+
error = turn_error(err_parse_failed, "invalid magic cookie")
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
var j: ptr_uint = 0
|
|
165
|
+
while j < 12z:
|
|
166
|
+
if data[8z + j] != expected_tid[j]:
|
|
167
|
+
return Result[TurnAllocation, Error].failure(
|
|
168
|
+
error = turn_error(err_parse_failed, "transaction ID mismatch")
|
|
169
|
+
)
|
|
170
|
+
j += 1
|
|
171
|
+
|
|
172
|
+
var attr_len: ptr_uint = read_ushort_be(data, 2z)
|
|
173
|
+
var offset: ptr_uint = turn_header_len
|
|
174
|
+
while attr_len >= 4z:
|
|
175
|
+
if offset + 4z > data.len:
|
|
176
|
+
break
|
|
177
|
+
let attr_type = read_ushort_be(data, offset)
|
|
178
|
+
let alen = ptr_uint<-read_ushort_be(data, offset + 2z)
|
|
179
|
+
let padded = (alen + 3z) & (~3z)
|
|
180
|
+
if offset + 4z + alen > data.len:
|
|
181
|
+
break
|
|
182
|
+
|
|
183
|
+
if attr_type == attr_xor_relayed_address and alen >= 8z:
|
|
184
|
+
let family = data[offset + 5z]
|
|
185
|
+
if family == 0x01:
|
|
186
|
+
let xport = read_ushort_be(data, offset + 6z)
|
|
187
|
+
let port = xport ^ ushort<-((stun_magic_cookie >> 16u) & 0xFFFFu)
|
|
188
|
+
let xaddr = read_uint_be(data, offset + 8z)
|
|
189
|
+
let ip = xaddr ^ stun_magic_cookie
|
|
190
|
+
var ip_str = format_ipv4(ip)
|
|
191
|
+
defer ip_str.release()
|
|
192
|
+
let addr_result = net.ipv4(ip_str.as_str(), int<-port)
|
|
193
|
+
match addr_result:
|
|
194
|
+
Result.success as ap:
|
|
195
|
+
return Result[TurnAllocation, Error].success(
|
|
196
|
+
value = TurnAllocation(relay_address = ap.value)
|
|
197
|
+
)
|
|
198
|
+
Result.failure:
|
|
199
|
+
pass
|
|
200
|
+
|
|
201
|
+
offset = offset + 4z + padded
|
|
202
|
+
attr_len = attr_len - 4z - padded
|
|
203
|
+
|
|
204
|
+
return Result[TurnAllocation, Error].failure(
|
|
205
|
+
error = turn_error(err_parse_failed, "no XOR-RELAYED-ADDRESS found")
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
public async function allocate(
|
|
210
|
+
socket: net.UdpSocket,
|
|
211
|
+
turn_server: net.SocketAddress
|
|
212
|
+
) -> Result[TurnAllocation, Error]:
|
|
213
|
+
let rand_result = crypto.random_bytes(12)
|
|
214
|
+
match rand_result:
|
|
215
|
+
Result.failure:
|
|
216
|
+
return Result[TurnAllocation, Error].failure(
|
|
217
|
+
error = turn_error(err_tid_failed, "failed to generate transaction ID")
|
|
218
|
+
)
|
|
219
|
+
Result.success as rp:
|
|
220
|
+
let tid = transaction_id_from_bytes(rp.value)
|
|
221
|
+
rp.value.release()
|
|
222
|
+
var request = build_allocate_request(tid)
|
|
223
|
+
defer request.release()
|
|
224
|
+
let send_result = await socket.send_to(request.as_span(), turn_server)
|
|
225
|
+
match send_result:
|
|
226
|
+
Result.failure:
|
|
227
|
+
return Result[TurnAllocation, Error].failure(
|
|
228
|
+
error = turn_error(err_send_failed, "failed to send allocate request")
|
|
229
|
+
)
|
|
230
|
+
Result.success:
|
|
231
|
+
pass
|
|
232
|
+
|
|
233
|
+
var frame: uint = 0
|
|
234
|
+
let recv_task = socket.recv_from(512)
|
|
235
|
+
while frame < 40:
|
|
236
|
+
if aio.completed(recv_task):
|
|
237
|
+
let recv_result = aio.result(recv_task)
|
|
238
|
+
match recv_result:
|
|
239
|
+
Result.failure:
|
|
240
|
+
return Result[TurnAllocation, Error].failure(
|
|
241
|
+
error = turn_error(err_recv_failed, "recv failed")
|
|
242
|
+
)
|
|
243
|
+
Result.success as dp:
|
|
244
|
+
var datagram = dp.value
|
|
245
|
+
let parse_result = parse_allocate_response(datagram.data, tid)
|
|
246
|
+
datagram.data.release()
|
|
247
|
+
datagram.source.release()
|
|
248
|
+
match parse_result:
|
|
249
|
+
Result.failure:
|
|
250
|
+
continue
|
|
251
|
+
Result.success as ap:
|
|
252
|
+
return Result[TurnAllocation, Error].success(value = ap.value)
|
|
253
|
+
await aio.sleep(50)
|
|
254
|
+
frame += 1
|
|
255
|
+
|
|
256
|
+
return Result[TurnAllocation, Error].failure(
|
|
257
|
+
error = turn_error(err_timeout, "allocate request timed out")
|
|
258
|
+
)
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
function addr_to_raw_ipv4(addr: net.SocketAddress) -> uint:
|
|
262
|
+
let storage = addr.storage else:
|
|
263
|
+
return 0
|
|
264
|
+
let in_ptr = unsafe: ptr[libuv.sockaddr_in]<-storage
|
|
265
|
+
return (unsafe: read(in_ptr)).sin_addr
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
public function build_send_indication(
|
|
269
|
+
tid: array[ubyte, 12],
|
|
270
|
+
peer: net.SocketAddress,
|
|
271
|
+
data: span[ubyte]
|
|
272
|
+
) -> Result[bytes.Bytes, Error]:
|
|
273
|
+
let port_result = peer.port()
|
|
274
|
+
match port_result:
|
|
275
|
+
Result.failure:
|
|
276
|
+
return Result[bytes.Bytes, Error].failure(
|
|
277
|
+
error = turn_error(err_invalid_address, "failed to get peer port")
|
|
278
|
+
)
|
|
279
|
+
Result.success as pp:
|
|
280
|
+
let host_port = pp.value
|
|
281
|
+
let xport = ushort<-host_port ^ ushort<-((stun_magic_cookie >> 16u) & 0xFFFFu)
|
|
282
|
+
let ip_raw = addr_to_raw_ipv4(peer)
|
|
283
|
+
let xip = ip_raw ^ stun_magic_cookie
|
|
284
|
+
|
|
285
|
+
let data_len = data.len
|
|
286
|
+
let attr_total: ptr_uint = 12z + data_len
|
|
287
|
+
var w = bin.Writer.with_capacity(turn_header_len + attr_total)
|
|
288
|
+
|
|
289
|
+
w.write_ubyte(0x00)
|
|
290
|
+
w.write_ubyte(0x16)
|
|
291
|
+
w.write_ubyte(ubyte<-((ushort<-attr_total >> 8) & 0xFF))
|
|
292
|
+
w.write_ubyte(ubyte<-(ushort<-attr_total & 0xFF))
|
|
293
|
+
w.write_ubyte(0x21)
|
|
294
|
+
w.write_ubyte(0x12)
|
|
295
|
+
w.write_ubyte(0xA4)
|
|
296
|
+
w.write_ubyte(0x42)
|
|
297
|
+
var i: ptr_uint = 0
|
|
298
|
+
while i < 12z:
|
|
299
|
+
w.write_ubyte(tid[i])
|
|
300
|
+
i += 1
|
|
301
|
+
|
|
302
|
+
w.write_ubyte(0x00)
|
|
303
|
+
w.write_ubyte(0x17)
|
|
304
|
+
w.write_ubyte(0x00)
|
|
305
|
+
w.write_ubyte(0x08)
|
|
306
|
+
w.write_ubyte(0x00)
|
|
307
|
+
w.write_ubyte(0x01)
|
|
308
|
+
w.write_ubyte(ubyte<-((xport >> 8) & 0xFF))
|
|
309
|
+
w.write_ubyte(ubyte<-(xport & 0xFF))
|
|
310
|
+
w.write_ubyte(ubyte<-((xip >> 24) & 0xFF))
|
|
311
|
+
w.write_ubyte(ubyte<-((xip >> 16) & 0xFF))
|
|
312
|
+
w.write_ubyte(ubyte<-((xip >> 8) & 0xFF))
|
|
313
|
+
w.write_ubyte(ubyte<-(xip & 0xFF))
|
|
314
|
+
|
|
315
|
+
w.write_ubyte(0x00)
|
|
316
|
+
w.write_ubyte(0x12)
|
|
317
|
+
w.write_ubyte(ubyte<-((ushort<-data_len >> 8) & 0xFF))
|
|
318
|
+
w.write_ubyte(ubyte<-(ushort<-data_len & 0xFF))
|
|
319
|
+
var j: ptr_uint = 0
|
|
320
|
+
while j < data_len:
|
|
321
|
+
w.write_ubyte(data[j])
|
|
322
|
+
j += 1
|
|
323
|
+
|
|
324
|
+
return Result[bytes.Bytes, Error].success(value = w.finish())
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
public function parse_data_indication(
|
|
328
|
+
packet: bytes.Bytes
|
|
329
|
+
) -> Result[TurnDatagram, Error]:
|
|
330
|
+
let data = packet.as_span()
|
|
331
|
+
if data.len < turn_header_len:
|
|
332
|
+
return Result[TurnDatagram, Error].failure(
|
|
333
|
+
error = turn_error(err_parse_failed, "packet too small")
|
|
334
|
+
)
|
|
335
|
+
|
|
336
|
+
let msg_type = read_ushort_be(data, 0z)
|
|
337
|
+
if msg_type != data_indication:
|
|
338
|
+
return Result[TurnDatagram, Error].failure(
|
|
339
|
+
error = turn_error(err_parse_failed, "not a data indication")
|
|
340
|
+
)
|
|
341
|
+
|
|
342
|
+
var attr_len: ptr_uint = read_ushort_be(data, 2z)
|
|
343
|
+
var offset: ptr_uint = turn_header_len
|
|
344
|
+
var found_peer: bool = false
|
|
345
|
+
var peer_addr: net.SocketAddress = zero[net.SocketAddress]
|
|
346
|
+
var found_data: bool = false
|
|
347
|
+
var payload: bytes.Bytes = bytes.Bytes.empty()
|
|
348
|
+
|
|
349
|
+
while attr_len >= 4z:
|
|
350
|
+
if offset + 4z > data.len:
|
|
351
|
+
break
|
|
352
|
+
let attr_type = read_ushort_be(data, offset)
|
|
353
|
+
let alen = ptr_uint<-read_ushort_be(data, offset + 2z)
|
|
354
|
+
let padded = (alen + 3z) & (~3z)
|
|
355
|
+
if offset + 4z + alen > data.len:
|
|
356
|
+
break
|
|
357
|
+
|
|
358
|
+
if attr_type == attr_xor_peer_address and alen >= 8z:
|
|
359
|
+
let family = data[offset + 5z]
|
|
360
|
+
if family == 0x01:
|
|
361
|
+
let xport = read_ushort_be(data, offset + 6z)
|
|
362
|
+
let port = xport ^ ushort<-((stun_magic_cookie >> 16u) & 0xFFFFu)
|
|
363
|
+
let xaddr = read_uint_be(data, offset + 8z)
|
|
364
|
+
let ip = xaddr ^ stun_magic_cookie
|
|
365
|
+
var ip_str = format_ipv4(ip)
|
|
366
|
+
defer ip_str.release()
|
|
367
|
+
let addr_result = net.ipv4(ip_str.as_str(), int<-port)
|
|
368
|
+
match addr_result:
|
|
369
|
+
Result.success as ap:
|
|
370
|
+
peer_addr = ap.value
|
|
371
|
+
found_peer = true
|
|
372
|
+
Result.failure:
|
|
373
|
+
pass
|
|
374
|
+
|
|
375
|
+
if attr_type == attr_data and alen > 0z:
|
|
376
|
+
var buf = bin.Writer.with_capacity(alen)
|
|
377
|
+
var k: ptr_uint = 0
|
|
378
|
+
while k < alen:
|
|
379
|
+
buf.write_ubyte(data[offset + 4z + k])
|
|
380
|
+
k += 1
|
|
381
|
+
payload = buf.finish()
|
|
382
|
+
found_data = true
|
|
383
|
+
|
|
384
|
+
offset = offset + 4z + padded
|
|
385
|
+
attr_len = attr_len - 4z - padded
|
|
386
|
+
|
|
387
|
+
if not found_peer or not found_data:
|
|
388
|
+
if found_data:
|
|
389
|
+
payload.release()
|
|
390
|
+
return Result[TurnDatagram, Error].failure(
|
|
391
|
+
error = turn_error(err_no_data_attribute, "data indication missing attributes")
|
|
392
|
+
)
|
|
393
|
+
|
|
394
|
+
return Result[TurnDatagram, Error].success(
|
|
395
|
+
value = TurnDatagram(peer_address = peer_addr, data = payload)
|
|
396
|
+
)
|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
public async function send_data(
|
|
400
|
+
socket: net.UdpSocket,
|
|
401
|
+
turn_server: net.SocketAddress,
|
|
402
|
+
peer: net.SocketAddress,
|
|
403
|
+
payload: span[ubyte]
|
|
404
|
+
) -> Result[ptr_uint, Error]:
|
|
405
|
+
let rand_result = crypto.random_bytes(12)
|
|
406
|
+
match rand_result:
|
|
407
|
+
Result.failure:
|
|
408
|
+
return Result[ptr_uint, Error].failure(
|
|
409
|
+
error = turn_error(err_tid_failed, "failed to generate transaction ID")
|
|
410
|
+
)
|
|
411
|
+
Result.success as rp:
|
|
412
|
+
let tid = transaction_id_from_bytes(rp.value)
|
|
413
|
+
rp.value.release()
|
|
414
|
+
let build_result = build_send_indication(tid, peer, payload)
|
|
415
|
+
match build_result:
|
|
416
|
+
Result.failure as bp:
|
|
417
|
+
return Result[ptr_uint, Error].failure(error = bp.error)
|
|
418
|
+
Result.success as bp:
|
|
419
|
+
var packet = bp.value
|
|
420
|
+
defer packet.release()
|
|
421
|
+
let send_result = await socket.send_to(packet.as_span(), turn_server)
|
|
422
|
+
match send_result:
|
|
423
|
+
Result.failure as sp:
|
|
424
|
+
return Result[ptr_uint, Error].failure(
|
|
425
|
+
error = turn_error(err_send_failed, "send indication failed")
|
|
426
|
+
)
|
|
427
|
+
Result.success as nrp:
|
|
428
|
+
return Result[ptr_uint, Error].success(value = nrp.value)
|
|
429
|
+
|
|
430
|
+
|
|
431
|
+
public async function recv_data(
|
|
432
|
+
socket: net.UdpSocket
|
|
433
|
+
) -> Result[TurnDatagram, Error]:
|
|
434
|
+
var frame: uint = 0
|
|
435
|
+
let recv_task = socket.recv_from(4096)
|
|
436
|
+
while frame < 40:
|
|
437
|
+
if aio.completed(recv_task):
|
|
438
|
+
let recv_result = aio.result(recv_task)
|
|
439
|
+
match recv_result:
|
|
440
|
+
Result.failure:
|
|
441
|
+
return Result[TurnDatagram, Error].failure(
|
|
442
|
+
error = turn_error(err_recv_failed, "recv failed")
|
|
443
|
+
)
|
|
444
|
+
Result.success as dp:
|
|
445
|
+
var datagram = dp.value
|
|
446
|
+
let parse_result = parse_data_indication(datagram.data)
|
|
447
|
+
datagram.data.release()
|
|
448
|
+
datagram.source.release()
|
|
449
|
+
match parse_result:
|
|
450
|
+
Result.failure:
|
|
451
|
+
continue
|
|
452
|
+
Result.success as tp:
|
|
453
|
+
return Result[TurnDatagram, Error].success(value = tp.value)
|
|
454
|
+
await aio.sleep(50)
|
|
455
|
+
frame += 1
|
|
456
|
+
|
|
457
|
+
return Result[TurnDatagram, Error].failure(
|
|
458
|
+
error = turn_error(err_timeout, "recv from relay timed out")
|
|
459
|
+
)
|