blob: 3a4b541a1f31d4a31000ae535a21ef8f99a183fe [file]
// Copyright 2026 The Fuchsia Authors
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT
use crate::object::{
Dispatcher, Disposition, HandleValue, ProcessDispatcher, ReadType, SocketDispatcher,
};
use crate::user_copy::{UserInPtr, UserOutPtr};
use debug::ltracef;
use syscalls_macro::syscall;
use zx_status::Status;
use zx_types::{ZX_POL_NEW_SOCKET, ZX_RIGHT_MANAGE_SOCKET, ZX_RIGHT_READ, ZX_RIGHT_WRITE};
pub const ZX_SOCKET_PEEK: u32 = 1 << 3;
const LOCAL_TRACE: u32 = 0;
#[syscall]
pub fn sys_socket_create(
options: u32,
out0: &mut HandleValue,
out1: &mut HandleValue,
) -> Result<(), Status> {
ProcessDispatcher::with_current(|up| up.enforce_basic_policy(ZX_POL_NEW_SOCKET))?;
let (handle0, handle1, rights) = SocketDispatcher::create(options)?;
let user_handle0 = handle0.make_and_add_handle(rights)?;
let user_handle1 = handle1.make_and_add_handle(rights)?;
*out0 = user_handle0;
*out1 = user_handle1;
Ok(())
}
#[syscall]
pub fn sys_socket_write(
handle: HandleValue,
options: u32,
buffer: UserInPtr<u8>,
size: usize,
actual: UserOutPtr<usize>,
) -> Result<(), Status> {
ltracef!("handle {handle:?}\n");
if size > 0 && buffer.is_null() {
return Err(Status::INVALID_ARGS);
}
if options != 0 {
return Err(Status::INVALID_ARGS);
}
let socket = Dispatcher::get_with_rights::<SocketDispatcher>(handle, ZX_RIGHT_WRITE)?;
let nwritten = socket.write(buffer.reinterpret(), size)?;
// Caller may ignore results if desired.
if !actual.is_null() {
actual.write(nwritten)?;
}
Ok(())
}
#[syscall]
pub fn sys_socket_read(
handle: HandleValue,
options: u32,
buffer: UserOutPtr<u8>,
size: usize,
actual: UserOutPtr<usize>,
) -> Result<(), Status> {
ltracef!("handle {handle:?}\n");
if buffer.is_null() && size > 0 {
return Err(Status::INVALID_ARGS);
}
if options & !ZX_SOCKET_PEEK != 0 {
return Err(Status::INVALID_ARGS);
}
let socket = Dispatcher::get_with_rights::<SocketDispatcher>(handle, ZX_RIGHT_READ)?;
let read_type =
if (options & ZX_SOCKET_PEEK) != 0 { ReadType::Peek } else { ReadType::Consume };
let nread = socket.read(read_type, buffer.reinterpret(), size)?;
// Caller may ignore results if desired.
if !actual.is_null() {
actual.write(nread)?;
}
Ok(())
}
#[syscall]
pub fn sys_socket_set_disposition(
handle: HandleValue,
disposition: u32,
disposition_peer: u32,
) -> Result<(), Status> {
let disp = Disposition::try_from(disposition)?;
let disp_peer = Disposition::try_from(disposition_peer)?;
let socket = Dispatcher::get_with_rights::<SocketDispatcher>(handle, ZX_RIGHT_MANAGE_SOCKET)?;
socket.set_disposition(disp, disp_peer)?;
Ok(())
}