tail_core 0.1.0

Core library for the Tail operating system
Documentation
// Copyright 2025, TAIL OS. All Rights Reserved.
//
// You must obtain a written license from and pay applicable license fees to TAIL OS
// before you may reproduce, modify, or distribute this software, or any work that
// includes all or part of this software.
//
// Free development licenses are available for evaluation, research, and non-commercial
// purposes, which may include access to the source code under these terms. Redistribution
// or commercial use without a license is strictly prohibited.
//
// This file may contain contributions from others. Please review this entire file for
// other proprietary rights or license notices, as well as the TAIL OS License Guide at
// https://tail-os.com/license-guide/ for more information.
//
// For licensing inquiries, visit https://tail-os.com or email license@tail-os.com.


use crate::syscall;
use core::ptr;
use crate::tail::SERVER_NAME_MAX_LENGTH;
use crate::service::service_request::ServiceRequestData;
use crate::service::service_reply::ServiceReplyData;
use crate::error_kind::ErrorKind;
use core::mem;

/*
#[stable(feature = "client", since = "1.0.0")]
pub struct Client<T: Server> {
    server_name: [u8; SERVER_NAME_MAX_LENGTH],
    phantom: crate::marker::PhantomData<T>,
}

impl<T: Server> Client<T> {
    #[stable(feature = "client", since = "1.0.0")]
    #[rustc_const_stable(feature = "client", since = "1.0.0")]
    pub const fn new(server_name: &str) -> Client<T> {
        let mut client = Client {
            server_name: [0; SERVER_NAME_MAX_LENGTH],
            phantom: crate::marker::PhantomData,
        };
        unsafe { ptr::copy_nonoverlapping(server_name.as_ptr(), client.server_name.as_ptr() as *mut u8, server_name.len()) };
        client
    }

    #[stable(feature = "client", since = "1.0.0")]
    pub fn request_service(&self, request_type: u64, request_message: *const u8, request_message_size: usize) -> u64 {
        let response = syscall::syscall_request_service(core::str::from_utf8(&self.server_name).unwrap_or(""), request_type, request_message, request_message_size);

        return response;
    }
}
*/

/*
#[stable(feature = "client", since = "1.0.0")]
pub fn request_service_as_ref_u8_slice<T: AsRef<[u8]>>(server_name: &str, request_message_type: u64, request_message_ref: &T,
request_message_size: usize, reply_message_ref: &T, reply_message_size: usize) -> Result<(), std::io::Error>
{
    let result = syscall::syscall_request_service(server_name, request_message_type, request_message_ref.as_ref().as_ptr(),
    request_message_size, reply_message_ref.as_ref().as_ptr(), reply_message_size);
    if (result < 0) {
        return Err(std::io::Error::new(std::io::ErrorKind::Other, "syscall failed"));
    } else {
        return Ok(());
    }
}

#[stable(feature = "client", since = "1.0.0")]
pub fn request_service_sized<T>(server_name: &str, request_message_type: u64, request_message_ref: &T,
request_message_size: usize, reply_message_ref: &T, reply_message_size: usize) -> Result<(), std::io::Error>
{
    let result = syscall::syscall_request_service(server_name, request_message_type, request_message_ref as *const T as *const u8,
    request_message_size, reply_message_ref as *const T as *const u8, reply_message_size);
    if (result < 0) {
        return Err(std::io::Error::new(std::io::ErrorKind::Other, "syscall failed"));
    } else {
        return Ok(());
    }
}
*/

/*
#[stable(feature = "client", since = "1.0.0")]
pub fn request_service_as_ref_u8_slice<T: AsRef<[u8]>>(server_name: &str, request_message_type: u64,
request_message_ref: &T, request_message_size: usize) -> Result<(&'static T, usize), crate::io::Error>
{
    match syscall::syscall_request_service(server_name, request_message_type, request_message_ref.as_ref().as_ptr(),
    request_message_size) {
        Ok((reply_message_ptr, reply_message_size)) => {
            let reply_message_ref = unsafe { &*(reply_message_ptr as *const T) };
            Ok((reply_message_ref, reply_message_size))
        }
        Err(_) => Err(crate::io::Error::new(crate::io::ErrorKind::Other, "syscall failed")),
    }
}

#[stable(feature = "client", since = "1.0.0")]
pub fn request_service_sized<T>(server_name: &str, request_message_type: u64, request_message_ref: &T, request_message_size: usize) -> Result<(&'static T, usize), crate::io::Error>
{
    match syscall::syscall_request_service(server_name, request_message_type, request_message_ref as *const T as *const u8,
    request_message_size) {
        Ok((reply_message_ptr, reply_message_size)) => {
            let reply_message_ref = unsafe { &*(reply_message_ptr as *const T) };
            Ok((reply_message_ref, reply_message_size))
        }
        Err(_) => Err(crate::io::Error::new(crate::io::ErrorKind::Other, "syscall failed")),
    }
}
*/

pub fn request_service_primitive<T: Copy + 'static, U: Copy + 'static>(server_name: &str, request_message_type: u64, request_message_ref: Option<&T>, request_message_size: usize,
reply_message_ref: Option<&mut U>, reply_message_size: usize) -> Result<i64, crate::error_kind::ErrorKind>
{
    let request_message_ptr =
        request_message_ref.map_or(ptr::null(), |r| r as *const T as *const u8);
    let reply_message_ptr =
        reply_message_ref.map_or(ptr::null_mut(), |r| r as *mut U as *mut u8);

    match syscall::syscall_request_service(server_name, request_message_type, request_message_ptr, request_message_size,
    reply_message_ptr, reply_message_size) {
        Ok(result) => Ok(result),
        Err(_) => Err(crate::error_kind::ErrorKind::Other.into()),
    }
}

/// Sends a service request and waits for a reply.
/// 
/// The `request_data` buffer is treated as read-only once passed to this function.
/// The kernel will make the buffer read-only at the MMU level before sharing it with the server,
/// ensuring memory corruption safety and FFI compliance.
/// 
/// # Safety
/// The caller must ensure that `request_data` contains valid data and will not be modified
/// after this function is called (until the reply is received and the buffer is restored).
pub fn send_service_request_and_wait_for_reply<T, U>(server_name: &str, service_request_type: u64, request_data: &ServiceRequestData<T>) -> Result<ServiceReplyData<U>, crate::error_kind::ErrorKind> {
    // Extract read-only pointers - the immutable reference ensures we can't mutate through ServiceRequestData
    let request_message_ptr = request_data.get_request_message_ptr();
    let request_message_size = request_data.get_request_message_size();

    // The kernel will make this buffer read-only at the MMU level before sharing with the server
    match syscall::syscall_send_service_request_and_wait_for_reply(server_name, service_request_type, request_message_ptr, request_message_size) {
        Ok((reply_message_ptr, reply_message_size, reply_message_error)) => {
            Ok(ServiceReplyData::new(reply_message_ptr as *const U, reply_message_size, None))
        },
        Err(e) => Err(e),
    }
}

/*
#[stable(feature = "client", since = "1.0.0")]
pub fn request_service_primitive_slice<T: ?Sized, U: ?Sized>(server_name: &str, request_message_type: u64,
request_message_ref: Option<&T>, request_message_size: usize, reply_message_ref: Option<&mut U>, mut reply_message_size: usize) -> Result<(), crate::io::Error>
{
    let request_message_ptr = request_message_ref.map_or(ptr::null(), |r| r as *const T as *const u8);
    let reply_message_ptr = reply_message_ref.map_or(ptr::null(), |r| r as *mut U as *mut u8);
    match syscall::syscall_request_service(server_name, request_message_type,
    request_message_ptr, request_message_size, reply_message_ptr, reply_message_size) {
        Ok(_) => {
            Ok(())
        },
        Err(_) => Err(crate::io::Error::new(crate::io::ErrorKind::Other, "syscall failed")),
    }
}
*/

pub fn request_service_primitive_slice<T: Copy + 'static, U: Copy + 'static>(server_name: &str, request_message_type: u64, request_message_ref: Option<&[T]>,
request_message_size: usize, reply_message_ref: Option<&[U]>, reply_message_size: usize) -> Result<i64, crate::error_kind::ErrorKind> {
    let request_message_ptr = request_message_ref
        .map_or(ptr::null(), |r| r.as_ptr() as *const u8);
    let request_message_len = request_message_size;

    let reply_message_ptr = reply_message_ref
        .map_or(ptr::null_mut(), |r| r.as_ptr() as *mut u8);
    let reply_message_len = reply_message_size;

    match syscall::syscall_request_service(server_name, request_message_type, request_message_ptr, request_message_len,
    reply_message_ptr, reply_message_len) {
        Ok(result) => Ok(result),
        Err(_) => Err(crate::error_kind::ErrorKind::Other.into()),
    }
}

pub fn request_service_primitive_array<T: Copy, const N: usize, U: Copy, const M: usize>(server_name: &str, request_message_type: u64,
request_message_ref: Option<&[T; N]>, reply_message_ref: Option<&mut [U; M]>) -> Result<i64, crate::error_kind::ErrorKind> {
    let (request_message_ptr, request_message_len) = match request_message_ref {
        Some(r) => {
            let ptr = r.as_ptr() as *const u8;
            let len = core::mem::size_of::<T>() * r.len();
            (ptr, len)
        }
        None => (ptr::null(), 0),
    };

    let (reply_message_ptr, reply_message_len) = match reply_message_ref {
        Some(r) => {
            let ptr = r.as_mut_ptr() as *mut u8;
            let len = mem::size_of::<U>() * r.len();
            (ptr, len)
        }
        None => (ptr::null_mut(), 0),
    };

    match syscall::syscall_request_service(server_name, request_message_type, request_message_ptr,
    request_message_len, reply_message_ptr, reply_message_len) {
        Ok(result) => Ok(result),
        Err(_) => Err(crate::error_kind::ErrorKind::Other.into()),
    }
}

/*
#[stable(feature = "client", since = "1.0.0")]
pub fn request_service_sized<T, U>(server_name: &str, request_message_type: u64,
request_message_ref: Option<&T>, request_message_size: usize, reply_message_ref: Option<&mut U>, mut reply_message_size: usize) -> Result<(), crate::io::Error>
{
    let request_message_ptr = request_message_ref.map_or(ptr::null(), |r| r as *const T as *const u8);
    let reply_message_ptr = reply_message_ref.map_or(ptr::null(), |r| r as *const U as *const u8);
    match syscall::syscall_request_service(server_name, request_message_type,
    request_message_ptr, request_message_size, reply_message_ptr, reply_message_size) {
        Ok(_) => {
            Ok(())
        },
        Err(_) => Err(crate::io::Error::new(crate::io::ErrorKind::Other, "syscall failed")),
    }
}*/