Coverage Report

Created: 2024-05-16 12:16

/__w/smoldot/smoldot/repo/wasm-node/rust/src/bindings.rs
Line
Count
Source (jump to first uncovered line)
1
// Smoldot
2
// Copyright (C) 2019-2022  Parity Technologies (UK) Ltd.
3
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
4
5
// This program is free software: you can redistribute it and/or modify
6
// it under the terms of the GNU General Public License as published by
7
// the Free Software Foundation, either version 3 of the License, or
8
// (at your option) any later version.
9
10
// This program is distributed in the hope that it will be useful,
11
// but WITHOUT ANY WARRANTY; without even the implied warranty of
12
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
// GNU General Public License for more details.
14
15
// You should have received a copy of the GNU General Public License
16
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18
//! Imports and exports of the WebAssembly module.
19
//!
20
//! This module contains all the functions that tie together the Rust code and its host (i.e.
21
//! the JavaScript code, normally).
22
//!
23
//! The functions found in the `extern` block are the functions that the Rust code *imports*, and
24
//! need to be implemented on the host side and provided to the WebAssembly virtual machine. The
25
//! other functions are functions that the Rust code *exports*, and can be called by the host.
26
//!
27
//! # Re-entrency
28
//!
29
//! As a rule, none of the implementations of the functions that the host provides is allowed
30
//! to call a function exported by Rust.
31
//!
32
//! For example, the implementation of [`start_timer`] isn't allowed to call [`timer_finished`].
33
//! Instead, it must return, and later [`timer_finished`] be called independently.
34
//!
35
//! This avoids potential stack overflows and tricky borrowing-related situations.
36
//!
37
//! # About `u32`s and JavaScript
38
//!
39
//! Many functions below accept as parameter or return a `u32`. In reality, however, the
40
//! WebAssembly specification doesn't mention unsigned integers. Only signed integers (and
41
//! floating points) can be passed through the FFI layer.
42
//!
43
//! This isn't important when the Rust code provides a value that must later be provided back, as
44
//! the conversion from the guest to the host is symmetrical to the conversion from the host to
45
//! the guest.
46
//!
47
//! It is, however, important when the value needs to be interpreted from the host side, such as
48
//! for example the `message_ptr` parameter of [`panic()`]. When using JavaScript as the host, you
49
//! must do `>>> 0` on all the `u32` values before interpreting them, in order to be certain than
50
//! they are treated as unsigned integers by the JavaScript.
51
//!
52
53
use alloc::vec::Vec;
54
55
#[link(wasm_import_module = "smoldot")]
56
extern "C" {
57
    /// Must stop the execution immediately. The message is a UTF-8 string found in the memory of
58
    /// the WebAssembly at offset `message_ptr` and with length `message_len`.
59
    ///
60
    /// > **Note**: This function is typically implemented using `throw`.
61
    ///
62
    /// After this function has been called, no further Wasm functions must be called again on
63
    /// this Wasm virtual machine. Explanation below.
64
    ///
65
    /// # About throwing and safety
66
    ///
67
    /// Rust programs can be configured in two panicking modes: `abort`, or `unwind`. Safe or
68
    /// unsafe Rust code must be written by keeping in mind that the execution of a function can
69
    /// be suddenly interrupted by a panic, but can rely on the fact that this panic will either
70
    /// completely abort the program, or unwind the stack. In the latter case, they can rely on
71
    /// the fact that `std::panic::catch_unwind` will catch this unwinding and let them perform
72
    /// some additional clean-ups.
73
    ///
74
    /// This function is typically implemented using `throw`. However, "just" throwing a JavaScript
75
    /// exception from within the implementation of this function is neither `abort`, because the
76
    /// JavaScript could call into the Wasm again later, nor `unwind`, because it isn't caught by
77
    /// `std::panic::catch_unwind`. By being neither of the two, it breaks the assumptions that
78
    /// some Rust codes might rely on for either correctness or safety.
79
    /// In order to solve this problem, we enforce that `panic` must behave like `abort`, and
80
    /// forbid calling into the Wasm virtual machine again.
81
    ///
82
    /// Beyond the `panic` function itself, any other FFI function that throws must similarly
83
    /// behave like `abort` and prevent any further execution.
84
    pub fn panic(message_ptr: u32, message_len: u32);
85
86
    /// Called in response to [`add_chain`] once the initialization of the chain is complete.
87
    ///
88
    /// If `error_msg_ptr` is equal to 0, then the chain initialization is successful. Otherwise,
89
    /// `error_msg_ptr` and `error_msg_len` designate a buffer in the memory of the WebAssembly
90
    /// virtual machine where a UTF-8 diagnostic error message can be found.
91
    pub fn chain_initialized(chain_id: u32, error_msg_ptr: u32, error_msg_len: u32);
92
93
    /// Fills the buffer of the WebAssembly virtual machine with random data, starting at `ptr`
94
    /// and for `len` bytes.
95
    ///
96
    /// This data will be used in order to generate secrets. Do not use a dummy implementation!
97
    pub fn random_get(ptr: u32, len: u32);
98
99
    /// Returns the system clock in number of microseconds since the UNIX epoch, ignoring leap
100
    /// seconds.
101
    ///
102
    /// This clock is allowed to go backwards.
103
    ///
104
    /// Must never return a negative number. Implementers should be aware that the system clock
105
    /// can be negative, and abort execution if that is the case.
106
    pub fn unix_timestamp_us() -> u64;
107
108
    /// Returns the number of microseconds since an especified point in time. Must never decrease
109
    /// over time.
110
    pub fn monotonic_clock_us() -> u64;
111
112
    /// Copies the entire content of the buffer with the given index to the memory of the
113
    /// WebAssembly at offset `target_pointer`.
114
    ///
115
    /// In situations where a buffer must be provided from the JavaScript to the Rust code, the
116
    /// JavaScript must (prior to calling the Rust function that requires the buffer) assign a
117
    /// "buffer index" to the buffer it wants to provide. The Rust code then calls the
118
    /// [`buffer_size`] and [`buffer_copy`] functions in order to obtain the length and content
119
    /// of the buffer.
120
    pub fn buffer_copy(buffer_index: u32, target_pointer: u32);
121
122
    /// Returns the size (in bytes) of the buffer with the given index.
123
    ///
124
    /// See the documentation of [`buffer_copy`] for context.
125
    pub fn buffer_size(buffer_index: u32) -> u32;
126
127
    /// The queue of JSON-RPC responses of the given chain is no longer empty.
128
    ///
129
    /// This function is only ever called after [`json_rpc_responses_peek`] has returned a `len`
130
    /// of 0.
131
    ///
132
    /// This function might be called spuriously, however this behavior must not be relied upon.
133
    pub fn json_rpc_responses_non_empty(chain_id: u32);
134
135
    /// Client is emitting a log entry.
136
    ///
137
    /// Each log entry is made of a log level (`1 = Error, 2 = Warn, 3 = Info, 4 = Debug,
138
    /// 5 = Trace`), a log target (e.g. "network"), and a log message.
139
    ///
140
    /// The log target and message is a UTF-8 string found in the memory of the WebAssembly
141
    /// virtual machine at offset `ptr` and with length `len`.
142
    pub fn log(level: u32, target_ptr: u32, target_len: u32, message_ptr: u32, message_len: u32);
143
144
    /// Called when [`advance_execution`] should be executed again.
145
    ///
146
    /// This function might be called from within [`advance_execution`], in which case
147
    /// [`advance_execution`] should be called again immediately after it returns.
148
    pub fn advance_execution_ready();
149
150
    /// After at least `milliseconds` milliseconds have passed, [`timer_finished`] must be called.
151
    ///
152
    /// It is not a logic error to call [`timer_finished`] *before* `milliseconds` milliseconds
153
    /// have passed, and this will likely cause smoldot to restart a new timer for the remainder
154
    /// of the duration.
155
    ///
156
    /// When [`timer_finished`] is called, the value of the monotonic clock (in the bindings)
157
    /// must have increased by at least the given number of `milliseconds`.
158
    ///
159
    /// If `milliseconds` is 0, [`timer_finished`] should be called as soon as possible.
160
    ///
161
    /// `milliseconds` never contains a negative number, `NaN` or infinite.
162
    pub fn start_timer(milliseconds: f64);
163
164
    /// Must return the host supports connecting to a certain type of address.
165
    ///
166
    /// The `ty` parameter is equal to the first byte of the encoded address that would be passed
167
    /// to [`connection_new`]. See [`connection_new`] for more information.
168
    ///
169
    /// An additional `ty` value of `7` is supported, and means "non-secure WebSocket connection
170
    /// to localhost".
171
    ///
172
    /// Returns a non-zero value if the address is supported. Returns `0` if the address isn't
173
    /// supported.
174
    pub fn connection_type_supported(ty: u8) -> u32;
175
176
    /// Must initialize a new connection that tries to connect to the given address.
177
    ///
178
    /// The address to connect to is in the WebAssembly memory at offset `addr_ptr` and with
179
    /// `addr_len` bytes. The format is as follows:
180
    ///
181
    /// - One `type` byte (see below).
182
    /// - Two big-endian bytes representing the port (either TCP or UDP depending on the `type`)
183
    /// to connect to.
184
    /// - (optional) The 32 bytes SHA-256 hash of the certificate of the remote.
185
    /// - An UTF-8-encoded IP address or domain name. Use the `addr_len` parameter to determine
186
    /// its length. When using an IPv4, it is encoded as `a.b.c.d`. When using an IPv6, it is
187
    /// encoded according to RFC5952.
188
    ///
189
    /// The `type` byte defines the type of connection and whether the optional field is present:
190
    ///
191
    /// - `0`: TCP/IPv4 connection, with a port and an IPv4 address.
192
    /// - `1`: TCP/IPv6 connection, with a port and an IPv6 address.
193
    /// - `2`: TCP/IP connection, with a port and a domain name.
194
    /// - `4`: WebSocket connection, with a port and an IPv4 address.
195
    /// - `5`: WebSocket connection, with a port and an IPv6 address.
196
    /// - `6`: WebSocket connection, with a port and a domain name.
197
    /// - `14`: WebSocket secure connection, with a port and a domaine name.
198
    /// - `16`: WebRTC connection, with a port, an IPv4 address, and a remote certificate hash.
199
    /// - `17`: WebRTC connection, with a port, an IPv6 address, and a remote certificate hash.
200
    ///
201
    /// > **Note**: While these numbers seem arbitrary, they actually loosely follow a certain
202
    /// >           scheme. The lowest 2 bits indicate the type of IP address, while the highest
203
    /// >           bits indicate the type of connection.
204
    ///
205
    /// The `id` parameter is an identifier for this connection, as chosen by the Rust code. It
206
    /// must be passed on every interaction with this connection.
207
    ///
208
    /// At any time, a connection can be in either the `Open` (the initial state) or the `Reset`
209
    /// state.
210
    /// When in the `Open` state, the connection can transition to the `Reset` state if the remote
211
    /// closes the connection or refuses the connection altogether. When that happens,
212
    /// [`connection_reset`] must be called. Once in the `Reset` state, the connection cannot
213
    /// transition back to the `Open` state.
214
    ///
215
    /// If the connection is a multistream connection, then
216
    /// [`connection_multi_stream_set_handshake_info`] must later be called as soon as possible.
217
    ///
218
    /// There exists two kind of connections: single-stream and multi-stream. Single-stream
219
    /// connections are assumed to have a single stream open at all time and the encryption and
220
    /// multiplexing are handled internally by smoldot. Multi-stream connections open and close
221
    /// streams over time using [`connection_stream_opened`] and [`stream_reset`], and the
222
    /// encryption and multiplexing are handled by the user of these bindings.
223
    pub fn connection_new(id: u32, addr_ptr: u32, addr_len: u32);
224
225
    /// Abruptly close a connection previously initialized with [`connection_new`].
226
    ///
227
    /// This destroys the identifier passed as parameter. This identifier must never be passed
228
    /// through the FFI boundary, unless the same identifier is later allocated again with
229
    /// [`connection_new`].
230
    ///
231
    /// Must never be called if [`connection_reset`] has been called on that object in the past.
232
    ///
233
    /// The connection must be closed in the background. The Rust code isn't interested in incoming
234
    /// messages from this connection anymore.
235
    ///
236
    /// > **Note**: In JavaScript, remember to unregister event handlers before calling for
237
    /// >           example `WebSocket.close()`.
238
    pub fn reset_connection(id: u32);
239
240
    /// Queues a new outbound substream opening. The [`connection_stream_opened`] function must
241
    /// later be called when the substream has been successfully opened.
242
    ///
243
    /// This function will only be called for multi-stream connections. The connection must
244
    /// currently be in the `Open` state. See the documentation of [`connection_new`] for details.
245
    ///
246
    /// > **Note**: No mechanism exists in this API to handle the situation where a substream fails
247
    /// >           to open, as this is not supposed to happen. If you need to handle such a
248
    /// >           situation, either try again opening a substream again or reset the entire
249
    /// >           connection.
250
    pub fn connection_stream_open(connection_id: u32);
251
252
    /// Abruptly closes an existing substream of a multi-stream connection. The substream must
253
    /// currently be in the `Open` state.
254
    ///
255
    /// Must never be called if [`stream_reset`] has been called on that object in the past.
256
    ///
257
    /// This function will only be called for multi-stream connections. The connection must
258
    /// currently be in the `Open` state. See the documentation of [`connection_new`] for details.
259
    pub fn connection_stream_reset(connection_id: u32, stream_id: u32);
260
261
    /// Queues data on the given stream.
262
    ///
263
    /// `ptr` is a memory address where `len` consecutive elements of type [`StreamSendIoVector`]
264
    /// are found. Each element consists in two little-endian 32 bits unsigned integers: the first
265
    /// one is a pointer, and the second one is a length in bytes. The data to write on the stream
266
    /// consists in the concatenation of all these buffers.
267
    ///
268
    /// > **Note**: This interface is similar the famous UNIX function `writev`. `ptr` is the same
269
    /// >           as `iov`, and `len` the same as `iovcnt`.
270
    /// >           See <https://linux.die.net/man/2/writev>.
271
    ///
272
    /// If `connection_id` is a single-stream connection, then the value of `stream_id` should
273
    /// be ignored. If `connection_id` is a multi-stream connection, then the value of `stream_id`
274
    /// contains the identifier of the stream on which to send the data, as was provided to
275
    /// [`connection_stream_opened`].
276
    ///
277
    /// The connection associated with that stream (and, in the case of a multi-stream connection,
278
    /// the stream itself must currently be in the `Open` state. See the documentation of
279
    /// [`connection_new`] for details.
280
    ///
281
    /// The size of the buffer must not exceed the number of writable bytes of the given stream.
282
    /// Use [`stream_writable_bytes`] to notify that more data can be sent on the stream.
283
    pub fn stream_send(connection_id: u32, stream_id: u32, ptr: u32, len: u32);
284
285
    /// Close the sending side of the given stream of the given connection.
286
    ///
287
    /// Never called for connection types where this isn't possible to implement (i.e. WebSocket
288
    /// and WebRTC at the moment).
289
    ///
290
    /// If `connection_id` is a single-stream connection, then the value of `stream_id` should
291
    /// be ignored. If `connection_id` is a multi-stream connection, then the value of `stream_id`
292
    /// contains the identifier of the stream whose sending side should be closed, as was provided
293
    /// to [`connection_stream_opened`].
294
    ///
295
    /// The connection associated with that stream (and, in the case of a multi-stream connection,
296
    /// the stream itself must currently be in the `Open` state. See the documentation of
297
    /// [`connection_new`] for details.
298
    pub fn stream_send_close(connection_id: u32, stream_id: u32);
299
300
    /// Called when the Wasm execution enters the context of a certain task. This is useful for
301
    /// debugging purposes.
302
    ///
303
    /// Only one task can be currently executing at any time.
304
    ///
305
    /// The name of the task is a UTF-8 string found in the memory of the WebAssembly virtual
306
    /// machine at offset `ptr` and with length `len`.
307
    pub fn current_task_entered(ptr: u32, len: u32);
308
309
    /// Called when the Wasm execution leave the context of a certain task. This is useful for
310
    /// debugging purposes.
311
    ///
312
    /// Only one task can be currently executing at any time.
313
    pub fn current_task_exit();
314
}
315
316
/// See [`stream_send`].
317
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
318
#[repr(C)]
319
pub struct StreamSendIoVector {
320
    /// Pointer to a buffer of data to write.
321
    pub ptr: u32,
322
    /// Length of the buffer of data.
323
    pub len: u32,
324
}
325
326
/// Initializes the client.
327
///
328
/// This is the first function that must be called. Failure to do so before calling another
329
/// method will lead to a Rust panic. Calling this function multiple times will also lead to a
330
/// panic.
331
///
332
/// The client will emit log messages by calling the [`log()`] function, provided the log level is
333
/// inferior or equal to the value of `max_log_level` passed here.
334
#[no_mangle]
335
0
pub extern "C" fn init(max_log_level: u32) {
336
0
    crate::init(max_log_level);
337
0
}
338
339
/// Advances the execution of the client, performing CPU-heavy tasks.
340
///
341
/// This function **must** be called regularly, otherwise nothing will happen.
342
///
343
/// After this function is called or during a call to this function, [`advance_execution_ready`]
344
/// might be called, indicating that [`advance_execution`] should be called again.
345
#[no_mangle]
346
0
pub extern "C" fn advance_execution() {
347
0
    super::advance_execution()
348
0
}
349
350
/// Adds a chain to the client. The client will try to stay connected and synchronize this chain.
351
///
352
/// Assign a so-called "buffer index" (a `u32`) representing the chain specification, database
353
/// content, and list of potential relay chains, then provide these buffer indices to the function.
354
/// The Rust code will call [`buffer_size`] and [`buffer_copy`] in order to obtain the content of
355
/// these buffers. The buffer indices can be de-assigned and buffers destroyed once this function
356
/// returns.
357
///
358
/// The content of the chain specification and database content must be in UTF-8.
359
///
360
/// > **Note**: The database content is an opaque string that can be obtained by calling
361
/// >           the `chainHead_unstable_finalizedDatabase` JSON-RPC function.
362
///
363
/// The list of potential relay chains is a buffer containing a list of 32-bits-little-endian chain
364
/// ids. If the chain specification refer to a parachain, these chain ids are the ones that will be
365
/// looked up to find the corresponding relay chain.
366
///
367
/// `json_rpc_max_pending_requests` indicates the size of the queue of JSON-RPC requests that
368
/// haven't been answered yet.
369
/// If `json_rpc_max_pending_requests` is 0, then no JSON-RPC service will be started and it is
370
/// forbidden to send JSON-RPC requests targeting this chain. This can be used to save up
371
/// resources.
372
/// If `json_rpc_max_pending_requests` is 0, then the value of `json_rpc_max_subscriptions` is
373
/// ignored.
374
///
375
/// Calling this function allocates a chain id and starts the chain initialization in the
376
/// background. Once the initialization is complete, the [`chain_initialized`] function will be
377
/// called by smoldot.
378
/// It is possible to call [`remove_chain`] while the initialization is still in progress in
379
/// order to cancel it.
380
#[no_mangle]
381
0
pub extern "C" fn add_chain(
382
0
    chain_spec_buffer_index: u32,
383
0
    database_content_buffer_index: u32,
384
0
    json_rpc_max_pending_requests: u32,
385
0
    json_rpc_max_subscriptions: u32,
386
0
    potential_relay_chains_buffer_index: u32,
387
0
) -> u32 {
388
0
    super::add_chain(
389
0
        get_buffer(chain_spec_buffer_index),
390
0
        get_buffer(database_content_buffer_index),
391
0
        json_rpc_max_pending_requests,
392
0
        json_rpc_max_subscriptions,
393
0
        get_buffer(potential_relay_chains_buffer_index),
394
0
    )
395
0
}
396
397
/// Removes a chain previously added using [`add_chain`]. Instantly unsubscribes all the JSON-RPC
398
/// subscriptions and cancels all in-progress requests corresponding to that chain.
399
///
400
/// Can be called on a chain which hasn't finished initializing yet.
401
#[no_mangle]
402
0
pub extern "C" fn remove_chain(chain_id: u32) {
403
0
    super::remove_chain(chain_id);
404
0
}
405
406
/// Emit a JSON-RPC request or notification towards the given chain previously added using
407
/// [`add_chain`].
408
///
409
/// A buffer containing a UTF-8 JSON-RPC request or notification must be passed as parameter. The
410
/// format of the JSON-RPC requests and notifications is described in
411
/// [the standard JSON-RPC 2.0 specification](https://www.jsonrpc.org/specification).
412
///
413
/// If the buffer isn't a valid JSON-RPC request, then an error JSON-RPC response with an `id`
414
/// equal to `null` is generated, in accordance with the JSON-RPC 2.0 specification.
415
///
416
/// Assign a so-called "buffer index" (a `u32`) representing the buffer containing the UTF-8
417
/// request, then provide this buffer index to the function. The Rust code will call
418
/// [`buffer_size`] and [`buffer_copy`] in order to obtain the content of this buffer. The buffer
419
/// index can be de-assigned and buffer destroyed once this function returns.
420
///
421
/// Responses and notifications are notified using [`json_rpc_responses_non_empty`], and can
422
/// be read with [`json_rpc_responses_peek`].
423
///
424
/// It is forbidden to call this function on a chain which hasn't finished initializing yet or a
425
/// chain that was created with `json_rpc_running` equal to 0.
426
///
427
/// This function returns:
428
/// - 0 on success.
429
/// - 1 if the chain has too many pending JSON-RPC requests and refuses to queue another one.
430
///
431
#[no_mangle]
432
0
pub extern "C" fn json_rpc_send(text_buffer_index: u32, chain_id: u32) -> u32 {
433
0
    super::json_rpc_send(get_buffer(text_buffer_index), chain_id)
434
0
}
435
436
/// Obtains information about the first response in the queue of JSON-RPC responses.
437
///
438
/// This function returns a pointer within the memory of the WebAssembly virtual machine where is
439
/// stored a struct of type [`JsonRpcResponseInfo`]. This pointer remains valid until
440
/// [`json_rpc_responses_pop`] or [`remove_chain`] is called with the same `chain_id`.
441
///
442
/// The response or notification is a UTF-8 string found in the memory of the WebAssembly
443
/// virtual machine at offset `ptr` and with length `len`, where `ptr` and `len` are found in the
444
/// [`JsonRpcResponseInfo`].
445
///
446
/// If `len` is equal to 0, this indicates that the queue of JSON-RPC responses is empty.
447
/// When a `len` of 0 is returned, [`json_rpc_responses_non_empty`] will later be called to
448
/// indicate that it is no longer empty.
449
///
450
/// After having read the response or notification, use [`json_rpc_responses_pop`] to remove it
451
/// from the queue. You can then call [`json_rpc_responses_peek`] again to read the next response.
452
#[no_mangle]
453
0
pub extern "C" fn json_rpc_responses_peek(chain_id: u32) -> u32 {
454
0
    super::json_rpc_responses_peek(chain_id)
455
0
}
456
457
/// See [`json_rpc_responses_peek`].
458
#[repr(C)]
459
pub struct JsonRpcResponseInfo {
460
    /// Pointer in memory where the JSON-RPC response can be found.
461
    pub ptr: u32,
462
    /// Length of the JSON-RPC response in bytes. If 0, indicates that the queue is empty.
463
    pub len: u32,
464
}
465
466
/// Removes the first response from the queue of JSON-RPC responses. This is the response whose
467
/// information can be retrieved using [`json_rpc_responses_peek`].
468
///
469
/// Calling this function invalidates the pointer previously returned by a call to
470
/// [`json_rpc_responses_peek`] with the same `chain_id`.
471
///
472
/// It is forbidden to call this function on a chain that hasn't finished initializing yet, or a
473
/// chain that was created with `json_rpc_running` equal to 0.
474
#[no_mangle]
475
0
pub extern "C" fn json_rpc_responses_pop(chain_id: u32) {
476
0
    super::json_rpc_responses_pop(chain_id);
477
0
}
478
479
/// Must be called in response to [`start_timer`] after the given duration has passed.
480
#[no_mangle]
481
0
pub extern "C" fn timer_finished() {
482
0
    crate::timers::timer_finished();
483
0
}
484
485
/// Called by the JavaScript code in order to provide information about a multistream connection.
486
///
487
/// Must be called at most once per connection object.
488
///
489
/// See also [`connection_new`].
490
///
491
/// Assign a so-called "buffer index" (a `u32`) representing the buffer containing the handshake
492
/// type, then provide this buffer index to the function. The Rust code will call [`buffer_size`]
493
/// and [`buffer_copy`] in order to obtain the content of this buffer. The buffer index can be
494
/// de-assigned and buffer destroyed once this function returns.
495
///
496
/// The buffer must contain a single 0 byte (indicating WebRTC), followed with the SHA-256 hash of
497
/// the local node's TLS certificate.
498
#[no_mangle]
499
0
pub extern "C" fn connection_multi_stream_set_handshake_info(
500
0
    connection_id: u32,
501
0
    handshake_ty_buffer_index: u32,
502
0
) {
503
0
    crate::platform::connection_multi_stream_set_handshake_info(
504
0
        connection_id,
505
0
        get_buffer(handshake_ty_buffer_index),
506
0
    );
507
0
}
508
509
/// Notify of a message being received on the stream. The connection associated with that stream
510
/// (and, in the case of a multi-stream connection, the stream itself) must be in the `Open` state.
511
///
512
/// Assign a so-called "buffer index" (a `u32`) representing the buffer containing the message,
513
/// then provide this buffer index to the function. The Rust code will call [`buffer_size`] and
514
/// [`buffer_copy`] in order to obtain the content of this buffer. The buffer index can be
515
/// de-assigned and buffer destroyed once this function returns.
516
///
517
/// If `connection_id` is a single-stream connection, then the value of `stream_id` is ignored.
518
/// If `connection_id` is a multi-stream connection, then `stream_id` corresponds to the stream
519
/// on which the data was received, as was provided to [`connection_stream_opened`].
520
///
521
/// See also [`connection_new`].
522
#[no_mangle]
523
0
pub extern "C" fn stream_message(connection_id: u32, stream_id: u32, buffer_index: u32) {
524
0
    crate::platform::stream_message(connection_id, stream_id, get_buffer(buffer_index));
525
0
}
526
527
/// Notify that extra bytes can be written onto the stream. The connection associated with that
528
/// stream (and, in the case of a multi-stream connection, the stream itself) must be in the
529
/// `Open` state.
530
///
531
/// The total of writable bytes must not go beyond reasonable values (e.g. a few megabytes). It
532
/// is not legal to provide a dummy implementation that simply passes an exceedingly large value.
533
///
534
/// If `connection_id` is a single-stream connection, then the value of `stream_id` is ignored.
535
/// If `connection_id` is a multi-stream connection, then `stream_id` corresponds to the stream
536
/// on which the data was received, as was provided to [`connection_stream_opened`].
537
#[no_mangle]
538
0
pub extern "C" fn stream_writable_bytes(connection_id: u32, stream_id: u32, num_bytes: u32) {
539
0
    crate::platform::stream_writable_bytes(connection_id, stream_id, num_bytes);
540
0
}
541
542
/// Called by the JavaScript code when the given multi-stream connection has a new substream.
543
///
544
/// `connection_id` *must* be a multi-stream connection.
545
///
546
/// The value of `stream_id` is chosen at the discretion of the caller. It is illegal to use the
547
/// same `stream_id` as an existing stream on that same connection that is still open.
548
///
549
/// For the `outbound` parameter, pass `0` if the substream has been opened by the remote, and any
550
/// value other than `0` if the substream has been opened in response to a call to
551
/// [`connection_stream_open`].
552
#[no_mangle]
553
0
pub extern "C" fn connection_stream_opened(connection_id: u32, stream_id: u32, outbound: u32) {
554
0
    crate::platform::connection_stream_opened(connection_id, stream_id, outbound);
555
0
}
556
557
/// Can be called at any point by the JavaScript code if the connection switches to the `Reset`
558
/// state.
559
///
560
/// Must only be called once per connection object.
561
/// Must never be called if [`reset_connection`] has been called on that object in the past.
562
///
563
/// Assign a so-called "buffer index" (a `u32`) representing the buffer containing the UTF-8
564
/// reason for closing, then provide this buffer index to the function. The Rust code will call
565
/// [`buffer_size`] and [`buffer_copy`] in order to obtain the content of this buffer. The buffer
566
/// index can be de-assigned and buffer destroyed once this function returns.
567
///
568
/// See also [`connection_new`].
569
#[no_mangle]
570
0
pub extern "C" fn connection_reset(connection_id: u32, buffer_index: u32) {
571
0
    crate::platform::connection_reset(connection_id, get_buffer(buffer_index));
572
0
}
573
574
/// Can be called at any point by the JavaScript code if the stream switches to the `Reset`
575
/// state.
576
///
577
/// Must only be called once per stream.
578
/// Must never be called if [`connection_stream_reset`] has been called on that object in the past.
579
///
580
/// The `stream_id` becomes dead and can be re-used for another stream on the same connection.
581
///
582
/// It is illegal to call this function on a single-stream connections.
583
///
584
/// Assign a so-called "buffer index" (a `u32`) representing the buffer containing the UTF-8
585
/// reason for closing, then provide this buffer index to the function. The Rust code will call
586
/// [`buffer_size`] and [`buffer_copy`] in order to obtain the content of this buffer. The buffer
587
/// index can be de-assigned and buffer destroyed once this function returns.
588
///
589
/// See also [`connection_new`].
590
#[no_mangle]
591
0
pub extern "C" fn stream_reset(connection_id: u32, stream_id: u32, buffer_index: u32) {
592
0
    crate::platform::stream_reset(connection_id, stream_id, get_buffer(buffer_index));
593
0
}
594
595
0
pub(crate) fn get_buffer(buffer_index: u32) -> Vec<u8> {
596
0
    unsafe {
597
0
        let len = usize::try_from(buffer_size(buffer_index)).unwrap();
598
0
599
0
        let mut buffer = Vec::<u8>::with_capacity(len);
600
0
        buffer_copy(
601
0
            buffer_index,
602
0
            buffer.spare_capacity_mut().as_mut_ptr() as usize as u32,
603
0
        );
604
0
        buffer.set_len(len);
605
0
        buffer
606
0
    }
607
0
}