From 0ccec70ed87346036f9bea13ef47684d7aef44ef Mon Sep 17 00:00:00 2001 From: Jackson Coxson Date: Wed, 22 Oct 2025 10:26:57 -0600 Subject: [PATCH] Implement creating an Idevice with a file descriptor --- cpp/include/idevice++/idevice.hpp | 1 + cpp/src/idevice.cpp | 9 +++++++ ffi/src/lib.rs | 41 +++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+) diff --git a/cpp/include/idevice++/idevice.hpp b/cpp/include/idevice++/idevice.hpp index 2fe93ce..b00aca9 100644 --- a/cpp/include/idevice++/idevice.hpp +++ b/cpp/include/idevice++/idevice.hpp @@ -32,6 +32,7 @@ using IdevicePtr = std::unique_ptr create(IdeviceSocketHandle* socket, const std::string& label); + static Result from_fd(int fd, const std::string& label); static Result create_tcp(const sockaddr* addr, socklen_t addr_len, const std::string& label); diff --git a/cpp/src/idevice.cpp b/cpp/src/idevice.cpp index caa490b..88e0686 100644 --- a/cpp/src/idevice.cpp +++ b/cpp/src/idevice.cpp @@ -13,6 +13,15 @@ Result Idevice::create(IdeviceSocketHandle* socket, const std return Ok(Idevice(h)); } +Result Idevice::from_fd(int fd, const std::string& label) { + IdeviceHandle* h = nullptr; + FfiError e(idevice_from_fd(fd, label.c_str(), &h)); + if (e) { + return Err(e); + } + return Ok(Idevice(h)); +} + Result Idevice::create_tcp(const sockaddr* addr, socklen_t addr_len, const std::string& label) { IdeviceHandle* h = nullptr; diff --git a/ffi/src/lib.rs b/ffi/src/lib.rs index b2623dd..fc03a00 100644 --- a/ffi/src/lib.rs +++ b/ffi/src/lib.rs @@ -48,6 +48,7 @@ use idevice::{Idevice, IdeviceSocket, ReadWrite}; use once_cell::sync::Lazy; use std::{ ffi::{CStr, CString, c_char}, + os::fd::FromRawFd, ptr::null_mut, }; use tokio::runtime::{self, Runtime}; @@ -122,6 +123,46 @@ pub unsafe extern "C" fn idevice_new( null_mut() } +/// Creates an Idevice object from a socket file descriptor +/// +/// # Safety +/// The socket FD must be valid. +/// The pointers must be valid and non-null. +#[unsafe(no_mangle)] +pub unsafe extern "C" fn idevice_from_fd( + fd: i32, + label: *const c_char, + idevice: *mut *mut IdeviceHandle, +) -> *mut IdeviceFfiError { + if label.is_null() || idevice.is_null() || fd == 0 { + return ffi_err!(IdeviceError::FfiInvalidArg); + } + + // Get socket ownership + let fd = unsafe { libc::dup(fd) }; + let socket = unsafe { std::net::TcpStream::from_raw_fd(fd) }; + if let Err(e) = socket.set_nonblocking(true) { + return ffi_err!(e); + } + let socket = match RUNTIME.block_on(async move { tokio::net::TcpStream::from_std(socket) }) { + Ok(s) => s, + Err(e) => return ffi_err!(e), + }; + + // Convert C string to Rust string + let c_str = match unsafe { CStr::from_ptr(label).to_str() } { + Ok(s) => s, + Err(_) => return ffi_err!(IdeviceError::FfiInvalidString), + }; + + // Create new Idevice instance + let dev = Idevice::new(Box::new(socket), c_str); + let boxed = Box::new(IdeviceHandle(dev)); + unsafe { *idevice = Box::into_raw(boxed) }; + + null_mut() +} + /// Creates a new Idevice connection /// /// # Arguments