Zero-copy FTP/HTTP Daemon compatible with all POSIX systems
| 1 | # zftpd FFI Usage Guide |
| 2 | |
| 3 | The `zftpd` FFI (Foreign Function Interface) system allows you to integrate the FTP and HTTP servers, along with the memory manager, into other programming languages. It maintains the performance of the core C implementation while ensuring memory safety through idiomatic wrappers. |
| 4 | |
| 5 | Currently, the system natively supports: **Rust**, **Python**, **Go**, and **Java (JNI)**. |
| 6 | |
| 7 | ## Compilation |
| 8 | To compile the shared FFI library (`libzftpd_ffi.so` or `libzftpd_ffi.dylib`) and the respective bindings, use the `Makefile` and specify the desired languages: |
| 9 | |
| 10 | ```bash |
| 11 | # Compile for Rust, Python, and Go |
| 12 | make ffi_langs=rust,python,go |
| 13 | ``` |
| 14 | |
| 15 | The native output will be available in `build/<os>/<mode>/libzftpd_ffi.(so|dylib)`. |
| 16 | |
| 17 | --- |
| 18 | |
| 19 | ## 🦀 Rust |
| 20 | Rust provides the fastest and safest bindings. Thanks to the `Drop` trait, C resources are automatically destroyed when they go out of scope. |
| 21 | |
| 22 | ### Setup |
| 23 | Add the local path to your `Cargo.toml` or copy the `ffi/rust` folder. |
| 24 | |
| 25 | ### Usage Example |
| 26 | ```rust |
| 27 | use zftpd::allocator::PalAlloc; |
| 28 | use zftpd::ftp_server::FtpServer; |
| 29 | |
| 30 | fn main() { |
| 31 | // 1. Initialize the allocator before any other operation |
| 32 | PalAlloc::init_default().expect("Failed to initialize allocator"); |
| 33 | |
| 34 | // 2. Create and start the FTP server |
| 35 | // Returns a Result: safe to handle in case of bound ports |
| 36 | let server = FtpServer::new("127.0.0.1", 2121, "/var/ftp_root") |
| 37 | .expect("Failed to create FTP Server"); |
| 38 | |
| 39 | server.start().expect("Failed to start FTP server"); |
| 40 | println!("FTP Server running..."); |
| 41 | |
| 42 | // 3. Stop the server (optional: it will be stopped by the Drop trait) |
| 43 | server.stop(); |
| 44 | |
| 45 | // You don't need to manually clean up memory: RAII handles everything. |
| 46 | } |
| 47 | ``` |
| 48 | |
| 49 | --- |
| 50 | |
| 51 | ## 🐍 Python |
| 52 | Python uses `cffi` to interface with the C-core in out-of-line ABI mode. Context Managers allow you to manage resources cleanly, preventing memory leaks. |
| 53 | |
| 54 | ### Setup |
| 55 | Ensure the compiled `libzftpd_ffi` library is located in `build/.../release/` or within your `LD_LIBRARY_PATH` (or `DYLD_LIBRARY_PATH` on macOS). |
| 56 | |
| 57 | ### Usage Example |
| 58 | ```python |
| 59 | from zftpd.core import PalAlloc, FtpServer, ZftpdException |
| 60 | |
| 61 | try: |
| 62 | # 1. Initialize the memory allocator |
| 63 | PalAlloc.init_default() |
| 64 | |
| 65 | # 2. Use Context Managers to guarantee the destruction of the C-Pointer |
| 66 | with FtpServer("127.0.0.1", 2121, "/var/ftp_root") as server: |
| 67 | server.start() |
| 68 | print(f"Server started. Active sessions: {server.active_sessions()}") |
| 69 | |
| 70 | # ... logic ... |
| 71 | |
| 72 | # At the end of the 'with' block, server.destroy() is called automatically! |
| 73 | |
| 74 | except ZftpdException as e: |
| 75 | print(f"zftpd error: {e}") |
| 76 | ``` |
| 77 | |
| 78 | --- |
| 79 | |
| 80 | ## 🐹 Go |
| 81 | The Go bindings use `cgo` to communicate natively via structs. |
| 82 | *Note*: Due to the nature of Go's garbage collector, you are responsible for closing the servers by calling `.Close()` when they are no longer needed. |
| 83 | |
| 84 | ### Usage Example |
| 85 | ```go |
| 86 | package main |
| 87 | |
| 88 | import ( |
| 89 | "fmt" |
| 90 | "log" |
| 91 | |
| 92 | // Import the local mapping |
| 93 | "zftpd_ffi/ffi/go/zftpd" |
| 94 | ) |
| 95 | |
| 96 | func main() { |
| 97 | // 1. Initialize the allocator |
| 98 | if err := zftpd.PalAllocInitDefault(); err != nil { |
| 99 | log.Fatalf("Allocator error: %v", err) |
| 100 | } |
| 101 | |
| 102 | // 2. Errors reported idiomatically in Go style |
| 103 | server, err := zftpd.NewFtpServer("127.0.0.1", 2121, "/var/ftp_root") |
| 104 | if err != nil { |
| 105 | log.Fatalf("Unable to create server: %v", err) |
| 106 | } |
| 107 | // Correctly handle the closure of C pointers |
| 108 | defer server.Close() |
| 109 | |
| 110 | if err := server.Start(); err != nil { |
| 111 | log.Fatalf("Startup failed: %v", err) |
| 112 | } |
| 113 | |
| 114 | fmt.Println("FTP Server running!") |
| 115 | server.Stop() |
| 116 | } |
| 117 | ``` |
| 118 | |
| 119 | --- |
| 120 | |
| 121 | ## ☕ Java (JNI) |
| 122 | The Java APIs encapsulate the JNI binding. They leverage the `AutoCloseable` interface to operate conveniently within `try-with-resources` blocks. If you do not use this construct, you will need to call `.close()` manually, as the garbage collector does not intervene on the C side until the JNI reference is destroyed. |
| 123 | |
| 124 | ### Usage Example |
| 125 | ```java |
| 126 | import org.zftpd.ffi.PalAlloc; |
| 127 | import org.zftpd.ffi.FtpServer; |
| 128 | |
| 129 | public class Main { |
| 130 | public static void main(String[] args) { |
| 131 | // Load the native library and initialize the allocator |
| 132 | PalAlloc.initDefault(); |
| 133 | |
| 134 | // Safe AutoCloseable implementation |
| 135 | try (FtpServer server = new FtpServer("127.0.0.1", 2121, "/var/ftp_root")) { |
| 136 | |
| 137 | if (server.start() == 0) { |
| 138 | System.out.println("FTP Server started!"); |
| 139 | } |
| 140 | |
| 141 | // server.stop() / destroy() managed upon leaving the try block |
| 142 | |
| 143 | } catch (Exception e) { |
| 144 | System.err.println("Error: " + e.getMessage()); |
| 145 | } |
| 146 | } |
| 147 | } |
| 148 | ``` |
| 149 |