106 lines
3.2 KiB
Rust
106 lines
3.2 KiB
Rust
#![no_std]
|
|
#![no_main]
|
|
#![feature(alloc_error_handler)]
|
|
|
|
extern crate alloc;
|
|
use alloc::string::String;
|
|
use alloc::format;
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// 1. The Nervous System (FFI to Membrane)
|
|
// ----------------------------------------------------------------------------
|
|
extern "C" {
|
|
fn socket(domain: i32, type_: i32, protocol: i32) -> i32;
|
|
fn connect(fd: i32, addr: *const u8, len: i32) -> i32;
|
|
fn write(fd: i32, buf: *const u8, count: usize) -> isize;
|
|
fn sleep(seconds: u32);
|
|
// We also need the allocator from libnexus (clib.c or libc.nim exports)
|
|
fn malloc(size: usize) -> *mut u8;
|
|
fn free(ptr: *mut u8);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// 2. The Stomach (Global Allocator)
|
|
// ----------------------------------------------------------------------------
|
|
struct NexusAllocator;
|
|
|
|
unsafe impl core::alloc::GlobalAlloc for NexusAllocator {
|
|
unsafe fn alloc(&self, layout: core::alloc::Layout) -> *mut u8 {
|
|
malloc(layout.size())
|
|
}
|
|
unsafe fn dealloc(&self, ptr: *mut u8, _layout: core::alloc::Layout) {
|
|
free(ptr)
|
|
}
|
|
}
|
|
|
|
#[global_allocator]
|
|
static ALLOCATOR: NexusAllocator = NexusAllocator;
|
|
|
|
#[alloc_error_handler]
|
|
fn alloc_error(_layout: core::alloc::Layout) -> ! {
|
|
panic!("OOM");
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// 3. The Voice (Panic Handler)
|
|
// ----------------------------------------------------------------------------
|
|
#[panic_handler]
|
|
fn panic(info: &core::panic::PanicInfo) -> ! {
|
|
let msg = "RUST PANIC!\n";
|
|
unsafe { write(1, msg.as_ptr(), msg.len()); }
|
|
loop {}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// 4. The Astronaut (Main Logic)
|
|
// ----------------------------------------------------------------------------
|
|
// We need struct layouts for sockaddr if we want to be precise,
|
|
// but for this test, we can use the raw bytes or simple C structs.
|
|
#[repr(C)]
|
|
struct SockAddrIn {
|
|
sin_family: u16,
|
|
sin_port: u16,
|
|
sin_addr: u32, // 10.0.2.2 = 0x0202000A (Little Endian)
|
|
zero: [u8; 8],
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn main() -> i32 {
|
|
let msg = String::from("[Rust] Booting sequence...\n");
|
|
unsafe { write(1, msg.as_ptr(), msg.len()); }
|
|
|
|
let fd = unsafe { socket(2, 1, 0) }; // AF_INET, SOCK_STREAM
|
|
if fd < 0 {
|
|
let err = "[Rust] Socket failed\n";
|
|
unsafe { write(1, err.as_ptr(), err.len()); }
|
|
return 1;
|
|
}
|
|
|
|
// 10.0.2.2 = 0x0202000A
|
|
// 8080 = 0x1F90 (Big Endian)
|
|
let port_be: u16 = 8080u16.to_be();
|
|
|
|
let addr_fixed = SockAddrIn {
|
|
sin_family: 2,
|
|
sin_port: port_be,
|
|
sin_addr: 0x0202000A,
|
|
zero: [0; 8],
|
|
};
|
|
|
|
let hello = format!("[Rust] Hello from the Iron Lung! FD={}\n", fd);
|
|
|
|
unsafe {
|
|
let res = connect(fd, &addr_fixed as *const _ as *const u8, 16);
|
|
if res < 0 {
|
|
let fail = "[Rust] Connection Failed\n";
|
|
write(1, fail.as_ptr(), fail.len());
|
|
} else {
|
|
write(fd, hello.as_ptr(), hello.len());
|
|
let success = "[Rust] Payload Sent.\n";
|
|
write(1, success.as_ptr(), success.len());
|
|
}
|
|
}
|
|
|
|
loop { unsafe { sleep(1); } }
|
|
}
|