-
Notifications
You must be signed in to change notification settings - Fork 0
FFI Binding
Enable the ffi feature and the crate exports a stable extern "C" surface
you can call from Kotlin (JNI), Swift, C#, Go, or plain C. It is the same
engine — same code, same semantics — behind a C bridge.
[dependencies]
typebit = { version = "0.1", features = ["ffi"] }cargo run --example ffi_demo --features ffitypebit_engine_new takes a pointer to a #[repr(C)] callback table. Every
field is a C function pointer; the 18 required callbacks must be
non-null or the engine constructor returns NULL (it validates the whole
table before first use). resolve_host is optional (may be NULL — the
DHT then stays dormant; HTTP/UDP trackers are unaffected).
typedef struct {
void *ctx; // your context, passed back
uint64_t (*now_ms)(void *);
void (*fill_random)(void *, uint8_t *, size_t);
void (*log)(void *, int level, const char *msg);
int (*http_get)(void *, const char *url, uint64_t timeout_ms,
uint8_t *out, size_t cap, size_t *written);
int (*tcp_connect)(void *, const uint8_t *ip4, uint16_t port, uint32_t *out_id);
int (*tcp_connect_done)(void *, uint32_t id);
int (*tcp_send)(void *, uint32_t id, const uint8_t *data, size_t len, size_t *sent);
int (*tcp_recv)(void *, uint32_t id, uint8_t *buf, size_t cap, size_t *got);
void (*tcp_close)(void *, uint32_t id);
int (*udp_open)(void *, uint16_t port);
int (*udp_send)(void *, const uint8_t *ip4, uint16_t port, const uint8_t *data, size_t len);
int (*udp_recv)(void *, uint8_t *buf, size_t cap, uint8_t *ip4, uint16_t *port, size_t *got);
int (*disk_open)(void *, const char *path);
int (*disk_read)(void *, uint32_t id, uint64_t off, uint8_t *buf, size_t cap, size_t *got);
int (*disk_write)(void *, uint32_t id, uint64_t off, const uint8_t *data, size_t len);
int (*disk_prealloc)(void *, uint32_t id, uint64_t size);
int (*disk_flush)(void *, uint32_t id);
void (*disk_close)(void *, uint32_t id);
int (*resolve_host)(void *, const char *host, uint16_t port, uint8_t *out_ip4, uint16_t *out_port); /* optional */
} HostCbs;Return codes: FFI_OK = 0, FFI_ERR = -1, FFI_WOULD_BLOCK = -2,
FFI_NOT_FOUND = -3, FFI_INVALID = -4. The engine treats FFI_WOULD_BLOCK
from tcp_recv/udp_recv exactly like Err(Error::WouldBlock) — do not
block in the callbacks.
| C function | Notes |
|---|---|
typebit_engine_new(cbs, listen_port, cache_bytes, dht_enabled) -> TypeBitEngine* |
NULL on bad table. dht_enabled is 0/1. |
typebit_engine_free(e) |
destroy the handle |
typebit_engine_add_torrent(e, data, len, save_dir, out_hash, out_hash_len) -> int |
writes 20/32-byte infohash |
typebit_engine_add_magnet(e, uri, save_dir, out_hash, out_hash_len) -> int |
same |
typebit_engine_start(e, hash, hash_len) -> int |
hash_len 20 (v1) or 32 (v2) |
typebit_engine_pause(e, hash, hash_len) -> int |
|
typebit_engine_resume(e, hash, hash_len) -> int |
|
typebit_engine_remove(e, hash, hash_len) -> int |
|
typebit_engine_progress(e, hash, hash_len, double *out) -> int |
0.0..=1.0 |
typebit_engine_tick(e) -> int |
call on a ~100 ms timer |
typebit_engine_take_event(e, out, out_cap) -> int |
1 = event written, 0 = none |
typebit_engine_take_event returns one event per call; call it in a
loop until it returns 0. The engine buffers internally, so events are never
dropped.
[kind:u8] followed by per-kind payload (all integers big-endian):
| kind | event | payload |
|---|---|---|
| 1 | PeerConnected |
32-byte infohash + 4-byte IPv4 + 2-byte port |
| 2 | PieceVerified |
infohash + 4-byte piece |
| 3 | HashFailure |
infohash + 4-byte piece |
| 4 | TorrentComplete |
infohash |
| 5 | MetadataComplete |
infohash |
| 6 | MetadataFailed |
infohash |
| 7 | TrackerAnnounced |
infohash + 4-byte peer count |
| 8 | DhtNodeCount |
4-byte count |
| 9 | PeerBanned |
infohash + 4-byte IPv4 + 2-byte port + reason code |
| 10 | PortMapping |
phase byte + 2-byte external port (0 = unknown) |
| 11 | Error |
code byte + NUL-terminated detail string |
#include <stdint.h>
#include <stdio.h>
#include <string.h>
/* forward declarations of your callbacks; all 18 required ones */
uint64_t my_now_ms(void *ctx) { /* ... */ return 0; }
/* ... fill_random, log, http_get, tcp_*, udp_*, disk_* ... */
int main(void) {
HostCbs cbs = {0};
cbs.ctx = NULL;
cbs.now_ms = my_now_ms;
/* ... assign every required callback ... */
TypeBitEngine *e = typebit_engine_new(&cbs, 6881, 256 * 1024 * 1024, 1);
if (!e) { fprintf(stderr, "bad callback table\n"); return 1; }
uint8_t hash[32]; size_t hash_len = 0;
if (typebit_engine_add_magnet(e,
"magnet:?xt=urn:btih:0123456789abcdef0123456789abcdef01234567",
"/tmp/dl", hash, &hash_len) != 0) { /* ... */ }
typebit_engine_start(e, hash, hash_len);
for (;;) {
typebit_engine_tick(e);
uint8_t ev[64];
while (typebit_engine_take_event(e, ev, sizeof(ev)) == 1) {
printf("event kind=%d\n", ev[0]);
}
/* sleep ~100 ms */
}
typebit_engine_free(e);
return 0;
}See examples/ffi_demo.rs for a complete self-testing C ABI harness.