mirror of
https://github.com/rosenpass/rosenpass.git
synced 2026-02-28 06:23:08 -08:00
feat(API): AddListenSocket endpoint
This commit is contained in:
@@ -23,7 +23,7 @@ name = "api-integration-tests"
|
|||||||
required-features = ["experiment_api", "internal_testing"]
|
required-features = ["experiment_api", "internal_testing"]
|
||||||
|
|
||||||
[[test]]
|
[[test]]
|
||||||
name = "api-integration-tests-supply-keypair"
|
name = "api-integration-tests-api-setup"
|
||||||
required-features = ["experiment_api", "internal_testing"]
|
required-features = ["experiment_api", "internal_testing"]
|
||||||
|
|
||||||
[[bench]]
|
[[bench]]
|
||||||
|
|||||||
@@ -2,9 +2,13 @@ use std::{borrow::BorrowMut, collections::VecDeque, os::fd::OwnedFd};
|
|||||||
|
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use rosenpass_to::{ops::copy_slice, To};
|
use rosenpass_to::{ops::copy_slice, To};
|
||||||
use rosenpass_util::{fd::FdIo, functional::run, io::ReadExt, mem::DiscardResultExt};
|
use rosenpass_util::{
|
||||||
|
fd::FdIo, functional::run, io::ReadExt, mem::DiscardResultExt, result::OkExt,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{app_server::AppServer, protocol::BuildCryptoServer};
|
use crate::{
|
||||||
|
api::add_listen_socket_response_status, app_server::AppServer, protocol::BuildCryptoServer,
|
||||||
|
};
|
||||||
|
|
||||||
use super::{supply_keypair_response_status, Server as ApiServer};
|
use super::{supply_keypair_response_status, Server as ApiServer};
|
||||||
|
|
||||||
@@ -171,4 +175,54 @@ where
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn add_listen_socket(
|
||||||
|
&mut self,
|
||||||
|
_req: &super::boilerplate::AddListenSocketRequest,
|
||||||
|
req_fds: &mut VecDeque<OwnedFd>,
|
||||||
|
res: &mut super::boilerplate::AddListenSocketResponse,
|
||||||
|
) -> anyhow::Result<()> {
|
||||||
|
// Retrieve file descriptor
|
||||||
|
let sock_res = run(|| -> anyhow::Result<mio::net::UdpSocket> {
|
||||||
|
let sock = req_fds
|
||||||
|
.pop_front()
|
||||||
|
.context("Invalid request – socket missing.")?;
|
||||||
|
// TODO: We need to have this outside linux
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
rosenpass_util::fd::GetSocketProtocol::demand_udp_socket(&sock)?;
|
||||||
|
let sock = std::net::UdpSocket::from(sock);
|
||||||
|
sock.set_nonblocking(true)?;
|
||||||
|
mio::net::UdpSocket::from_std(sock).ok()
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut sock = match sock_res {
|
||||||
|
Ok(sock) => sock,
|
||||||
|
Err(e) => {
|
||||||
|
log::debug!("Error processing AddListenSocket API request: {e:?}");
|
||||||
|
res.payload.status = add_listen_socket_response_status::INVALID_REQUEST;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Register socket
|
||||||
|
let reg_result = run(|| -> anyhow::Result<()> {
|
||||||
|
let srv = self.app_server_mut();
|
||||||
|
srv.mio_poll.registry().register(
|
||||||
|
&mut sock,
|
||||||
|
srv.mio_token_dispenser.dispense(),
|
||||||
|
mio::Interest::READABLE,
|
||||||
|
)?;
|
||||||
|
srv.sockets.push(sock);
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
|
||||||
|
if let Err(internal_error) = reg_result {
|
||||||
|
log::warn!("Internal error processing AddListenSocket API request: {internal_error:?}");
|
||||||
|
res.payload.status = add_listen_socket_response_status::INTERNAL_ERROR;
|
||||||
|
return Ok(());
|
||||||
|
};
|
||||||
|
|
||||||
|
res.payload.status = add_listen_socket_response_status::OK;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -143,6 +143,44 @@ pub trait ByteSliceRefExt: ByteSlice {
|
|||||||
) -> anyhow::Result<Ref<Self, SupplyKeypairResponse>> {
|
) -> anyhow::Result<Ref<Self, SupplyKeypairResponse>> {
|
||||||
self.zk_parse_suffix()
|
self.zk_parse_suffix()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn add_listen_socket_request(self) -> anyhow::Result<Ref<Self, super::AddListenSocketRequest>> {
|
||||||
|
self.zk_parse()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_listen_socket_request_from_prefix(
|
||||||
|
self,
|
||||||
|
) -> anyhow::Result<Ref<Self, super::AddListenSocketRequest>> {
|
||||||
|
self.zk_parse_prefix()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_listen_socket_request_from_suffix(
|
||||||
|
self,
|
||||||
|
) -> anyhow::Result<Ref<Self, super::AddListenSocketRequest>> {
|
||||||
|
self.zk_parse_suffix()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_listen_socket_response_maker(self) -> RefMaker<Self, super::AddListenSocketResponse> {
|
||||||
|
self.zk_ref_maker()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_listen_socket_response(
|
||||||
|
self,
|
||||||
|
) -> anyhow::Result<Ref<Self, super::AddListenSocketResponse>> {
|
||||||
|
self.zk_parse()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_listen_socket_response_from_prefix(
|
||||||
|
self,
|
||||||
|
) -> anyhow::Result<Ref<Self, super::AddListenSocketResponse>> {
|
||||||
|
self.zk_parse_prefix()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_listen_socket_response_from_suffix(
|
||||||
|
self,
|
||||||
|
) -> anyhow::Result<Ref<Self, super::AddListenSocketResponse>> {
|
||||||
|
self.zk_parse_suffix()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B: ByteSlice> ByteSliceRefExt for B {}
|
impl<B: ByteSlice> ByteSliceRefExt for B {}
|
||||||
|
|||||||
@@ -21,6 +21,13 @@ const SUPPLY_KEYPAIR_REQUEST: RawMsgType =
|
|||||||
const SUPPLY_KEYPAIR_RESPONSE: RawMsgType =
|
const SUPPLY_KEYPAIR_RESPONSE: RawMsgType =
|
||||||
RawMsgType::from_le_bytes(hex!("f2dc 49bd e261 5f10 40b7 3c16 ec61 edb9"));
|
RawMsgType::from_le_bytes(hex!("f2dc 49bd e261 5f10 40b7 3c16 ec61 edb9"));
|
||||||
|
|
||||||
|
// hash domain hash of: Rosenpass IPC API -> Rosenpass Protocol Server -> Add Listen Socket Request
|
||||||
|
const ADD_LISTEN_SOCKET_REQUEST: RawMsgType =
|
||||||
|
RawMsgType::from_le_bytes(hex!("3f21 434f 87cc a08c 02c4 61e4 0816 c7da"));
|
||||||
|
// hash domain hash of: Rosenpass IPC API -> Rosenpass Protocol Server -> Add Listen Socket Response
|
||||||
|
const ADD_LISTEN_SOCKET_RESPONSE: RawMsgType =
|
||||||
|
RawMsgType::from_le_bytes(hex!("45d5 0f0d 93f0 6105 98f2 9469 5dfd 5f36"));
|
||||||
|
|
||||||
pub trait MessageAttributes {
|
pub trait MessageAttributes {
|
||||||
fn message_size(&self) -> usize;
|
fn message_size(&self) -> usize;
|
||||||
}
|
}
|
||||||
@@ -29,12 +36,14 @@ pub trait MessageAttributes {
|
|||||||
pub enum RequestMsgType {
|
pub enum RequestMsgType {
|
||||||
Ping,
|
Ping,
|
||||||
SupplyKeypair,
|
SupplyKeypair,
|
||||||
|
AddListenSocket,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Hash, PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Copy)]
|
#[derive(Hash, PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Copy)]
|
||||||
pub enum ResponseMsgType {
|
pub enum ResponseMsgType {
|
||||||
Ping,
|
Ping,
|
||||||
SupplyKeypair,
|
SupplyKeypair,
|
||||||
|
AddListenSocket,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MessageAttributes for RequestMsgType {
|
impl MessageAttributes for RequestMsgType {
|
||||||
@@ -42,6 +51,7 @@ impl MessageAttributes for RequestMsgType {
|
|||||||
match self {
|
match self {
|
||||||
Self::Ping => std::mem::size_of::<super::PingRequest>(),
|
Self::Ping => std::mem::size_of::<super::PingRequest>(),
|
||||||
Self::SupplyKeypair => std::mem::size_of::<super::SupplyKeypairRequest>(),
|
Self::SupplyKeypair => std::mem::size_of::<super::SupplyKeypairRequest>(),
|
||||||
|
Self::AddListenSocket => std::mem::size_of::<super::AddListenSocketRequest>(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -51,6 +61,7 @@ impl MessageAttributes for ResponseMsgType {
|
|||||||
match self {
|
match self {
|
||||||
Self::Ping => std::mem::size_of::<super::PingResponse>(),
|
Self::Ping => std::mem::size_of::<super::PingResponse>(),
|
||||||
Self::SupplyKeypair => std::mem::size_of::<super::SupplyKeypairResponse>(),
|
Self::SupplyKeypair => std::mem::size_of::<super::SupplyKeypairResponse>(),
|
||||||
|
Self::AddListenSocket => std::mem::size_of::<super::AddListenSocketResponse>(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -63,6 +74,7 @@ impl TryFrom<RawMsgType> for RequestMsgType {
|
|||||||
Ok(match value {
|
Ok(match value {
|
||||||
self::PING_REQUEST => E::Ping,
|
self::PING_REQUEST => E::Ping,
|
||||||
self::SUPPLY_KEYPAIR_REQUEST => E::SupplyKeypair,
|
self::SUPPLY_KEYPAIR_REQUEST => E::SupplyKeypair,
|
||||||
|
self::ADD_LISTEN_SOCKET_REQUEST => E::AddListenSocket,
|
||||||
_ => return Err(InvalidApiMessageType(value)),
|
_ => return Err(InvalidApiMessageType(value)),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -74,6 +86,7 @@ impl From<RequestMsgType> for RawMsgType {
|
|||||||
match val {
|
match val {
|
||||||
E::Ping => self::PING_REQUEST,
|
E::Ping => self::PING_REQUEST,
|
||||||
E::SupplyKeypair => self::SUPPLY_KEYPAIR_REQUEST,
|
E::SupplyKeypair => self::SUPPLY_KEYPAIR_REQUEST,
|
||||||
|
E::AddListenSocket => self::ADD_LISTEN_SOCKET_REQUEST,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -86,6 +99,7 @@ impl TryFrom<RawMsgType> for ResponseMsgType {
|
|||||||
Ok(match value {
|
Ok(match value {
|
||||||
self::PING_RESPONSE => E::Ping,
|
self::PING_RESPONSE => E::Ping,
|
||||||
self::SUPPLY_KEYPAIR_RESPONSE => E::SupplyKeypair,
|
self::SUPPLY_KEYPAIR_RESPONSE => E::SupplyKeypair,
|
||||||
|
self::ADD_LISTEN_SOCKET_RESPONSE => E::AddListenSocket,
|
||||||
_ => return Err(InvalidApiMessageType(value)),
|
_ => return Err(InvalidApiMessageType(value)),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -97,6 +111,7 @@ impl From<ResponseMsgType> for RawMsgType {
|
|||||||
match val {
|
match val {
|
||||||
E::Ping => self::PING_RESPONSE,
|
E::Ping => self::PING_RESPONSE,
|
||||||
E::SupplyKeypair => self::SUPPLY_KEYPAIR_RESPONSE,
|
E::SupplyKeypair => self::SUPPLY_KEYPAIR_RESPONSE,
|
||||||
|
E::AddListenSocket => self::ADD_LISTEN_SOCKET_RESPONSE,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -181,3 +181,87 @@ impl Message for SupplyKeypairResponse {
|
|||||||
self.msg_type = Self::MESSAGE_TYPE.into();
|
self.msg_type = Self::MESSAGE_TYPE.into();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[repr(packed)]
|
||||||
|
#[derive(Debug, Copy, Clone, Hash, AsBytes, FromBytes, FromZeroes, PartialEq, Eq)]
|
||||||
|
pub struct AddListenSocketRequestPayload {}
|
||||||
|
|
||||||
|
pub type AddListenSocketRequest = RequestEnvelope<AddListenSocketRequestPayload>;
|
||||||
|
|
||||||
|
impl Default for AddListenSocketRequest {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AddListenSocketRequest {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self::from_payload(AddListenSocketRequestPayload {})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Message for AddListenSocketRequest {
|
||||||
|
type Payload = AddListenSocketRequestPayload;
|
||||||
|
type MessageClass = RequestMsgType;
|
||||||
|
const MESSAGE_TYPE: Self::MessageClass = RequestMsgType::AddListenSocket;
|
||||||
|
|
||||||
|
fn from_payload(payload: Self::Payload) -> Self {
|
||||||
|
Self {
|
||||||
|
msg_type: Self::MESSAGE_TYPE.into(),
|
||||||
|
payload,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup<B: ByteSliceMut>(buf: B) -> anyhow::Result<Ref<B, Self>> {
|
||||||
|
let mut r: Ref<B, Self> = buf.zk_zeroized()?;
|
||||||
|
r.init();
|
||||||
|
Ok(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init(&mut self) {
|
||||||
|
self.msg_type = Self::MESSAGE_TYPE.into();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod add_listen_socket_response_status {
|
||||||
|
pub const OK: u128 = 0;
|
||||||
|
pub const INVALID_REQUEST: u128 = 1;
|
||||||
|
pub const INTERNAL_ERROR: u128 = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(packed)]
|
||||||
|
#[derive(Debug, Copy, Clone, Hash, AsBytes, FromBytes, FromZeroes, PartialEq, Eq)]
|
||||||
|
pub struct AddListenSocketResponsePayload {
|
||||||
|
pub status: u128,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type AddListenSocketResponse = ResponseEnvelope<AddListenSocketResponsePayload>;
|
||||||
|
|
||||||
|
impl AddListenSocketResponse {
|
||||||
|
pub fn new(status: u128) -> Self {
|
||||||
|
Self::from_payload(AddListenSocketResponsePayload { status })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Message for AddListenSocketResponse {
|
||||||
|
type Payload = AddListenSocketResponsePayload;
|
||||||
|
type MessageClass = ResponseMsgType;
|
||||||
|
const MESSAGE_TYPE: Self::MessageClass = ResponseMsgType::AddListenSocket;
|
||||||
|
|
||||||
|
fn from_payload(payload: Self::Payload) -> Self {
|
||||||
|
Self {
|
||||||
|
msg_type: Self::MESSAGE_TYPE.into(),
|
||||||
|
payload,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup<B: ByteSliceMut>(buf: B) -> anyhow::Result<Ref<B, Self>> {
|
||||||
|
let mut r: Ref<B, Self> = buf.zk_zeroized()?;
|
||||||
|
r.init();
|
||||||
|
Ok(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init(&mut self) {
|
||||||
|
self.msg_type = Self::MESSAGE_TYPE.into();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ impl<B: ByteSlice> RequestRef<B> {
|
|||||||
match self {
|
match self {
|
||||||
Self::Ping(_) => RequestMsgType::Ping,
|
Self::Ping(_) => RequestMsgType::Ping,
|
||||||
Self::SupplyKeypair(_) => RequestMsgType::SupplyKeypair,
|
Self::SupplyKeypair(_) => RequestMsgType::SupplyKeypair,
|
||||||
|
Self::AddListenSocket(_) => RequestMsgType::AddListenSocket,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -36,6 +37,18 @@ impl<B> From<Ref<B, PingRequest>> for RequestRef<B> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<B> From<Ref<B, super::SupplyKeypairRequest>> for RequestRef<B> {
|
||||||
|
fn from(v: Ref<B, super::SupplyKeypairRequest>) -> Self {
|
||||||
|
Self::SupplyKeypair(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<B> From<Ref<B, super::AddListenSocketRequest>> for RequestRef<B> {
|
||||||
|
fn from(v: Ref<B, super::AddListenSocketRequest>) -> Self {
|
||||||
|
Self::AddListenSocket(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<B: ByteSlice> RequestRefMaker<B> {
|
impl<B: ByteSlice> RequestRefMaker<B> {
|
||||||
fn new(buf: B) -> anyhow::Result<Self> {
|
fn new(buf: B) -> anyhow::Result<Self> {
|
||||||
let msg_type = buf.deref().request_msg_type_from_prefix()?;
|
let msg_type = buf.deref().request_msg_type_from_prefix()?;
|
||||||
@@ -52,6 +65,9 @@ impl<B: ByteSlice> RequestRefMaker<B> {
|
|||||||
RequestMsgType::SupplyKeypair => {
|
RequestMsgType::SupplyKeypair => {
|
||||||
RequestRef::SupplyKeypair(self.buf.supply_keypair_request()?)
|
RequestRef::SupplyKeypair(self.buf.supply_keypair_request()?)
|
||||||
}
|
}
|
||||||
|
RequestMsgType::AddListenSocket => {
|
||||||
|
RequestRef::AddListenSocket(self.buf.add_listen_socket_request()?)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,6 +103,7 @@ impl<B: ByteSlice> RequestRefMaker<B> {
|
|||||||
pub enum RequestRef<B> {
|
pub enum RequestRef<B> {
|
||||||
Ping(Ref<B, PingRequest>),
|
Ping(Ref<B, PingRequest>),
|
||||||
SupplyKeypair(Ref<B, super::SupplyKeypairRequest>),
|
SupplyKeypair(Ref<B, super::SupplyKeypairRequest>),
|
||||||
|
AddListenSocket(Ref<B, super::AddListenSocketRequest>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B> RequestRef<B>
|
impl<B> RequestRef<B>
|
||||||
@@ -97,6 +114,7 @@ where
|
|||||||
match self {
|
match self {
|
||||||
Self::Ping(r) => r.bytes(),
|
Self::Ping(r) => r.bytes(),
|
||||||
Self::SupplyKeypair(r) => r.bytes(),
|
Self::SupplyKeypair(r) => r.bytes(),
|
||||||
|
Self::AddListenSocket(r) => r.bytes(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -109,6 +127,7 @@ where
|
|||||||
match self {
|
match self {
|
||||||
Self::Ping(r) => r.bytes_mut(),
|
Self::Ping(r) => r.bytes_mut(),
|
||||||
Self::SupplyKeypair(r) => r.bytes_mut(),
|
Self::SupplyKeypair(r) => r.bytes_mut(),
|
||||||
|
Self::AddListenSocket(r) => r.bytes_mut(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,15 +50,28 @@ impl ResponseMsg for super::SupplyKeypairResponse {
|
|||||||
type RequestMsg = super::SupplyKeypairRequest;
|
type RequestMsg = super::SupplyKeypairRequest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl RequestMsg for super::AddListenSocketRequest {
|
||||||
|
type ResponseMsg = super::AddListenSocketResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ResponseMsg for super::AddListenSocketResponse {
|
||||||
|
type RequestMsg = super::AddListenSocketRequest;
|
||||||
|
}
|
||||||
|
|
||||||
pub type PingPair<B1, B2> = (Ref<B1, PingRequest>, Ref<B2, PingResponse>);
|
pub type PingPair<B1, B2> = (Ref<B1, PingRequest>, Ref<B2, PingResponse>);
|
||||||
pub type SupplyKeypairPair<B1, B2> = (
|
pub type SupplyKeypairPair<B1, B2> = (
|
||||||
Ref<B1, super::SupplyKeypairRequest>,
|
Ref<B1, super::SupplyKeypairRequest>,
|
||||||
Ref<B2, super::SupplyKeypairResponse>,
|
Ref<B2, super::SupplyKeypairResponse>,
|
||||||
);
|
);
|
||||||
|
pub type AddListenSocketPair<B1, B2> = (
|
||||||
|
Ref<B1, super::AddListenSocketRequest>,
|
||||||
|
Ref<B2, super::AddListenSocketResponse>,
|
||||||
|
);
|
||||||
|
|
||||||
pub enum RequestResponsePair<B1, B2> {
|
pub enum RequestResponsePair<B1, B2> {
|
||||||
Ping(PingPair<B1, B2>),
|
Ping(PingPair<B1, B2>),
|
||||||
SupplyKeypair(SupplyKeypairPair<B1, B2>),
|
SupplyKeypair(SupplyKeypairPair<B1, B2>),
|
||||||
|
AddListenSocket(AddListenSocketPair<B1, B2>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B1, B2> From<PingPair<B1, B2>> for RequestResponsePair<B1, B2> {
|
impl<B1, B2> From<PingPair<B1, B2>> for RequestResponsePair<B1, B2> {
|
||||||
@@ -73,6 +86,12 @@ impl<B1, B2> From<SupplyKeypairPair<B1, B2>> for RequestResponsePair<B1, B2> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<B1, B2> From<AddListenSocketPair<B1, B2>> for RequestResponsePair<B1, B2> {
|
||||||
|
fn from(v: AddListenSocketPair<B1, B2>) -> Self {
|
||||||
|
RequestResponsePair::AddListenSocket(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<B1, B2> RequestResponsePair<B1, B2>
|
impl<B1, B2> RequestResponsePair<B1, B2>
|
||||||
where
|
where
|
||||||
B1: ByteSlice,
|
B1: ByteSlice,
|
||||||
@@ -90,6 +109,11 @@ where
|
|||||||
let res = ResponseRef::SupplyKeypair(res.emancipate());
|
let res = ResponseRef::SupplyKeypair(res.emancipate());
|
||||||
(req, res)
|
(req, res)
|
||||||
}
|
}
|
||||||
|
Self::AddListenSocket((req, res)) => {
|
||||||
|
let req = RequestRef::AddListenSocket(req.emancipate());
|
||||||
|
let res = ResponseRef::AddListenSocket(res.emancipate());
|
||||||
|
(req, res)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,6 +143,11 @@ where
|
|||||||
let res = ResponseRef::SupplyKeypair(res.emancipate_mut());
|
let res = ResponseRef::SupplyKeypair(res.emancipate_mut());
|
||||||
(req, res)
|
(req, res)
|
||||||
}
|
}
|
||||||
|
Self::AddListenSocket((req, res)) => {
|
||||||
|
let req = RequestRef::AddListenSocket(req.emancipate_mut());
|
||||||
|
let res = ResponseRef::AddListenSocket(res.emancipate_mut());
|
||||||
|
(req, res)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ impl<B: ByteSlice> ResponseRef<B> {
|
|||||||
match self {
|
match self {
|
||||||
Self::Ping(_) => ResponseMsgType::Ping,
|
Self::Ping(_) => ResponseMsgType::Ping,
|
||||||
Self::SupplyKeypair(_) => ResponseMsgType::SupplyKeypair,
|
Self::SupplyKeypair(_) => ResponseMsgType::SupplyKeypair,
|
||||||
|
Self::AddListenSocket(_) => ResponseMsgType::AddListenSocket,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -43,6 +44,12 @@ impl<B> From<Ref<B, super::SupplyKeypairResponse>> for ResponseRef<B> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<B> From<Ref<B, super::AddListenSocketResponse>> for ResponseRef<B> {
|
||||||
|
fn from(v: Ref<B, super::AddListenSocketResponse>) -> Self {
|
||||||
|
Self::AddListenSocket(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<B: ByteSlice> ResponseRefMaker<B> {
|
impl<B: ByteSlice> ResponseRefMaker<B> {
|
||||||
fn new(buf: B) -> anyhow::Result<Self> {
|
fn new(buf: B) -> anyhow::Result<Self> {
|
||||||
let msg_type = buf.deref().response_msg_type_from_prefix()?;
|
let msg_type = buf.deref().response_msg_type_from_prefix()?;
|
||||||
@@ -59,6 +66,9 @@ impl<B: ByteSlice> ResponseRefMaker<B> {
|
|||||||
ResponseMsgType::SupplyKeypair => {
|
ResponseMsgType::SupplyKeypair => {
|
||||||
ResponseRef::SupplyKeypair(self.buf.supply_keypair_response()?)
|
ResponseRef::SupplyKeypair(self.buf.supply_keypair_response()?)
|
||||||
}
|
}
|
||||||
|
ResponseMsgType::AddListenSocket => {
|
||||||
|
ResponseRef::AddListenSocket(self.buf.add_listen_socket_response()?)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,6 +104,7 @@ impl<B: ByteSlice> ResponseRefMaker<B> {
|
|||||||
pub enum ResponseRef<B> {
|
pub enum ResponseRef<B> {
|
||||||
Ping(Ref<B, PingResponse>),
|
Ping(Ref<B, PingResponse>),
|
||||||
SupplyKeypair(Ref<B, super::SupplyKeypairResponse>),
|
SupplyKeypair(Ref<B, super::SupplyKeypairResponse>),
|
||||||
|
AddListenSocket(Ref<B, super::AddListenSocketResponse>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<B> ResponseRef<B>
|
impl<B> ResponseRef<B>
|
||||||
@@ -104,6 +115,7 @@ where
|
|||||||
match self {
|
match self {
|
||||||
Self::Ping(r) => r.bytes(),
|
Self::Ping(r) => r.bytes(),
|
||||||
Self::SupplyKeypair(r) => r.bytes(),
|
Self::SupplyKeypair(r) => r.bytes(),
|
||||||
|
Self::AddListenSocket(r) => r.bytes(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -116,6 +128,7 @@ where
|
|||||||
match self {
|
match self {
|
||||||
Self::Ping(r) => r.bytes_mut(),
|
Self::Ping(r) => r.bytes_mut(),
|
||||||
Self::SupplyKeypair(r) => r.bytes_mut(),
|
Self::SupplyKeypair(r) => r.bytes_mut(),
|
||||||
|
Self::AddListenSocket(r) => r.bytes_mut(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,13 @@ pub trait Server {
|
|||||||
res: &mut super::SupplyKeypairResponse,
|
res: &mut super::SupplyKeypairResponse,
|
||||||
) -> anyhow::Result<()>;
|
) -> anyhow::Result<()>;
|
||||||
|
|
||||||
|
fn add_listen_socket(
|
||||||
|
&mut self,
|
||||||
|
req: &super::AddListenSocketRequest,
|
||||||
|
req_fds: &mut VecDeque<OwnedFd>,
|
||||||
|
res: &mut super::AddListenSocketResponse,
|
||||||
|
) -> anyhow::Result<()>;
|
||||||
|
|
||||||
fn dispatch<ReqBuf, ResBuf>(
|
fn dispatch<ReqBuf, ResBuf>(
|
||||||
&mut self,
|
&mut self,
|
||||||
p: &mut RequestResponsePair<ReqBuf, ResBuf>,
|
p: &mut RequestResponsePair<ReqBuf, ResBuf>,
|
||||||
@@ -31,6 +38,9 @@ pub trait Server {
|
|||||||
RequestResponsePair::SupplyKeypair((req, res)) => {
|
RequestResponsePair::SupplyKeypair((req, res)) => {
|
||||||
self.supply_keypair(req, req_fds, res)
|
self.supply_keypair(req, req_fds, res)
|
||||||
}
|
}
|
||||||
|
RequestResponsePair::AddListenSocket((req, res)) => {
|
||||||
|
self.add_listen_socket(req, req_fds, res)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,6 +67,11 @@ pub trait Server {
|
|||||||
res.init();
|
res.init();
|
||||||
RequestResponsePair::SupplyKeypair((req, res))
|
RequestResponsePair::SupplyKeypair((req, res))
|
||||||
}
|
}
|
||||||
|
RequestRef::AddListenSocket(req) => {
|
||||||
|
let mut res = res.add_listen_socket_response_from_prefix()?;
|
||||||
|
res.init();
|
||||||
|
RequestResponsePair::AddListenSocket((req, res))
|
||||||
|
}
|
||||||
};
|
};
|
||||||
self.dispatch(&mut pair, req_fds)?;
|
self.dispatch(&mut pair, req_fds)?;
|
||||||
|
|
||||||
|
|||||||
@@ -78,6 +78,8 @@ fn main() -> Result<()> {
|
|||||||
Tree::Leaf("Ping Response".to_owned()),
|
Tree::Leaf("Ping Response".to_owned()),
|
||||||
Tree::Leaf("Supply Keypair Request".to_owned()),
|
Tree::Leaf("Supply Keypair Request".to_owned()),
|
||||||
Tree::Leaf("Supply Keypair Response".to_owned()),
|
Tree::Leaf("Supply Keypair Response".to_owned()),
|
||||||
|
Tree::Leaf("Add Listen Socket Request".to_owned()),
|
||||||
|
Tree::Leaf("Add Listen Socket Response".to_owned()),
|
||||||
],
|
],
|
||||||
)],
|
)],
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
use std::{
|
use std::{
|
||||||
io::{BufRead, BufReader},
|
io::{BufRead, BufReader},
|
||||||
net::ToSocketAddrs,
|
|
||||||
os::unix::net::UnixStream,
|
os::unix::net::UnixStream,
|
||||||
process::Stdio,
|
process::Stdio,
|
||||||
thread::sleep,
|
thread::sleep,
|
||||||
@@ -8,19 +7,21 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use anyhow::{bail, Context};
|
use anyhow::{bail, Context};
|
||||||
use rosenpass::api::{self, supply_keypair_response_status};
|
use rosenpass::api::{self, add_listen_socket_response_status, supply_keypair_response_status};
|
||||||
use rosenpass_util::{
|
use rosenpass_util::{
|
||||||
file::LoadValueB64,
|
file::LoadValueB64,
|
||||||
length_prefix_encoding::{decoder::LengthPrefixDecoder, encoder::LengthPrefixEncoder},
|
length_prefix_encoding::{decoder::LengthPrefixDecoder, encoder::LengthPrefixEncoder},
|
||||||
|
mio::WriteWithFileDescriptors,
|
||||||
|
zerocopy::ZerocopySliceExt,
|
||||||
};
|
};
|
||||||
use rosenpass_util::{mio::WriteWithFileDescriptors, zerocopy::ZerocopySliceExt};
|
use rustix::fd::AsFd;
|
||||||
use tempfile::TempDir;
|
use tempfile::TempDir;
|
||||||
use zerocopy::AsBytes;
|
use zerocopy::AsBytes;
|
||||||
|
|
||||||
use rosenpass::protocol::SymKey;
|
use rosenpass::protocol::SymKey;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn api_integration_test() -> anyhow::Result<()> {
|
fn api_integration_api_setup() -> anyhow::Result<()> {
|
||||||
rosenpass_secret_memory::policy::secret_policy_use_only_malloc_secrets();
|
rosenpass_secret_memory::policy::secret_policy_use_only_malloc_secrets();
|
||||||
|
|
||||||
let dir = TempDir::with_prefix("rosenpass-api-integration-test")?;
|
let dir = TempDir::with_prefix("rosenpass-api-integration-test")?;
|
||||||
@@ -33,17 +34,20 @@ fn api_integration_test() -> anyhow::Result<()> {
|
|||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
let peer_a_endpoint = "[::1]:61424";
|
let peer_a_endpoint = "[::1]:0";
|
||||||
let peer_a_osk = tempfile!("a.osk");
|
let peer_a_osk = tempfile!("a.osk");
|
||||||
let peer_b_osk = tempfile!("b.osk");
|
let peer_b_osk = tempfile!("b.osk");
|
||||||
|
|
||||||
|
let peer_a_listen = std::net::UdpSocket::bind(peer_a_endpoint)?;
|
||||||
|
let peer_a_endpoint = format!("{}", peer_a_listen.local_addr()?);
|
||||||
|
|
||||||
use rosenpass::config;
|
use rosenpass::config;
|
||||||
|
|
||||||
let peer_a_keypair = config::Keypair::new(tempfile!("a.pk"), tempfile!("a.sk"));
|
let peer_a_keypair = config::Keypair::new(tempfile!("a.pk"), tempfile!("a.sk"));
|
||||||
let peer_a = config::Rosenpass {
|
let peer_a = config::Rosenpass {
|
||||||
config_file_path: tempfile!("a.config"),
|
config_file_path: tempfile!("a.config"),
|
||||||
keypair: Some(peer_a_keypair.clone()),
|
keypair: None,
|
||||||
listen: peer_a_endpoint.to_socket_addrs()?.collect(), // TODO: This could collide by accident
|
listen: vec![], // TODO: This could collide by accident
|
||||||
verbosity: config::Verbosity::Verbose,
|
verbosity: config::Verbosity::Verbose,
|
||||||
api: api::config::ApiConfig {
|
api: api::config::ApiConfig {
|
||||||
listen_path: vec![tempfile!("a.sock")],
|
listen_path: vec![tempfile!("a.sock")],
|
||||||
@@ -62,7 +66,7 @@ fn api_integration_test() -> anyhow::Result<()> {
|
|||||||
let peer_b_keypair = config::Keypair::new(tempfile!("b.pk"), tempfile!("b.sk"));
|
let peer_b_keypair = config::Keypair::new(tempfile!("b.pk"), tempfile!("b.sk"));
|
||||||
let peer_b = config::Rosenpass {
|
let peer_b = config::Rosenpass {
|
||||||
config_file_path: tempfile!("b.config"),
|
config_file_path: tempfile!("b.config"),
|
||||||
keypair: None,
|
keypair: Some(peer_b_keypair.clone()),
|
||||||
listen: vec![],
|
listen: vec![],
|
||||||
verbosity: config::Verbosity::Verbose,
|
verbosity: config::Verbosity::Verbose,
|
||||||
api: api::config::ApiConfig {
|
api: api::config::ApiConfig {
|
||||||
@@ -118,7 +122,7 @@ fn api_integration_test() -> anyhow::Result<()> {
|
|||||||
let mut out_b = BufReader::new(proc_b.stdout.context("")?).lines();
|
let mut out_b = BufReader::new(proc_b.stdout.context("")?).lines();
|
||||||
|
|
||||||
// Now connect to the peers
|
// Now connect to the peers
|
||||||
let api_path = peer_b.api.listen_path[0].as_path();
|
let api_path = peer_a.api.listen_path[0].as_path();
|
||||||
|
|
||||||
// Wait for the socket to be created
|
// Wait for the socket to be created
|
||||||
let attempt = 0;
|
let attempt = 0;
|
||||||
@@ -132,11 +136,34 @@ fn api_integration_test() -> anyhow::Result<()> {
|
|||||||
|
|
||||||
let api = UnixStream::connect(api_path)?;
|
let api = UnixStream::connect(api_path)?;
|
||||||
|
|
||||||
|
// Send AddListenSocket request
|
||||||
|
{
|
||||||
|
let fd = peer_a_listen.as_fd();
|
||||||
|
|
||||||
|
let mut fds = vec![&fd].into();
|
||||||
|
let mut api = WriteWithFileDescriptors::<UnixStream, _, _, _>::new(&api, &mut fds);
|
||||||
|
LengthPrefixEncoder::from_message(api::AddListenSocketRequest::new().as_bytes())
|
||||||
|
.write_all_to_stdio(&mut api)?;
|
||||||
|
assert!(fds.is_empty(), "Failed to write all file descriptors");
|
||||||
|
std::mem::forget(peer_a_listen);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read response
|
||||||
|
{
|
||||||
|
let mut decoder = LengthPrefixDecoder::new([0u8; api::MAX_RESPONSE_LEN]);
|
||||||
|
let res = decoder.read_all_from_stdio(&api)?;
|
||||||
|
let res = res.zk_parse::<api::AddListenSocketResponse>()?;
|
||||||
|
assert_eq!(
|
||||||
|
*res,
|
||||||
|
api::AddListenSocketResponse::new(add_listen_socket_response_status::OK)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Send SupplyKeypairRequest
|
// Send SupplyKeypairRequest
|
||||||
{
|
{
|
||||||
use rustix::fs::{open, Mode, OFlags};
|
use rustix::fs::{open, Mode, OFlags};
|
||||||
let sk = open(peer_b_keypair.secret_key, OFlags::RDONLY, Mode::empty())?;
|
let sk = open(peer_a_keypair.secret_key, OFlags::RDONLY, Mode::empty())?;
|
||||||
let pk = open(peer_b_keypair.public_key, OFlags::RDONLY, Mode::empty())?;
|
let pk = open(peer_a_keypair.public_key, OFlags::RDONLY, Mode::empty())?;
|
||||||
|
|
||||||
let mut fds = vec![&sk, &pk].into();
|
let mut fds = vec![&sk, &pk].into();
|
||||||
let mut api = WriteWithFileDescriptors::<UnixStream, _, _, _>::new(&api, &mut fds);
|
let mut api = WriteWithFileDescriptors::<UnixStream, _, _, _>::new(&api, &mut fds);
|
||||||
@@ -147,7 +174,6 @@ fn api_integration_test() -> anyhow::Result<()> {
|
|||||||
|
|
||||||
// Read response
|
// Read response
|
||||||
{
|
{
|
||||||
//sleep(Duration::from_secs(10));
|
|
||||||
let mut decoder = LengthPrefixDecoder::new([0u8; api::MAX_RESPONSE_LEN]);
|
let mut decoder = LengthPrefixDecoder::new([0u8; api::MAX_RESPONSE_LEN]);
|
||||||
let res = decoder.read_all_from_stdio(api)?;
|
let res = decoder.read_all_from_stdio(api)?;
|
||||||
let res = res.zk_parse::<api::SupplyKeypairResponse>()?;
|
let res = res.zk_parse::<api::SupplyKeypairResponse>()?;
|
||||||
@@ -7,6 +7,20 @@ macro_rules! repeat {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! return_unless {
|
||||||
|
($cond:expr) => {
|
||||||
|
if !($cond) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
($cond:expr, $val:expr) => {
|
||||||
|
if !($cond) {
|
||||||
|
return $val;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! return_if {
|
macro_rules! return_if {
|
||||||
($cond:expr) => {
|
($cond:expr) => {
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
|
use anyhow::bail;
|
||||||
use rustix::{
|
use rustix::{
|
||||||
fd::{AsFd, BorrowedFd, FromRawFd, OwnedFd, RawFd},
|
fd::{AsFd, BorrowedFd, FromRawFd, OwnedFd, RawFd},
|
||||||
io::fcntl_dupfd_cloexec,
|
io::fcntl_dupfd_cloexec,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
use crate::{mem::Forgetting, result::OkExt};
|
||||||
use rustix::io::DupFlags;
|
|
||||||
|
|
||||||
use crate::mem::Forgetting;
|
|
||||||
|
|
||||||
/// Prepare a file descriptor for use in Rust code.
|
/// Prepare a file descriptor for use in Rust code.
|
||||||
///
|
///
|
||||||
@@ -51,7 +49,7 @@ pub fn clone_fd_cloexec<Fd: AsFd>(fd: Fd) -> rustix::io::Result<OwnedFd> {
|
|||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
pub fn clone_fd_to_cloexec<Fd: AsFd>(fd: Fd, new: &mut OwnedFd) -> rustix::io::Result<()> {
|
pub fn clone_fd_to_cloexec<Fd: AsFd>(fd: Fd, new: &mut OwnedFd) -> rustix::io::Result<()> {
|
||||||
use rustix::io::dup3;
|
use rustix::io::{dup3, DupFlags};
|
||||||
dup3(fd, new, DupFlags::CLOEXEC)
|
dup3(fd, new, DupFlags::CLOEXEC)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,6 +109,85 @@ impl<Fd: AsFd> std::io::Write for FdIo<Fd> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait StatExt {
|
||||||
|
fn is_socket(&self) -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StatExt for rustix::fs::Stat {
|
||||||
|
fn is_socket(&self) -> bool {
|
||||||
|
use rustix::fs::FileType;
|
||||||
|
let ft = FileType::from_raw_mode(self.st_mode);
|
||||||
|
matches!(ft, FileType::Socket)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait TryStatExt {
|
||||||
|
type Error;
|
||||||
|
fn is_socket(&self) -> Result<bool, Self::Error>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> TryStatExt for T
|
||||||
|
where
|
||||||
|
T: AsFd,
|
||||||
|
{
|
||||||
|
type Error = rustix::io::Errno;
|
||||||
|
|
||||||
|
fn is_socket(&self) -> Result<bool, Self::Error> {
|
||||||
|
rustix::fs::fstat(self)?.is_socket().ok()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait GetSocketType {
|
||||||
|
type Error;
|
||||||
|
fn socket_type(&self) -> Result<rustix::net::SocketType, Self::Error>;
|
||||||
|
fn is_datagram_socket(&self) -> Result<bool, Self::Error> {
|
||||||
|
use rustix::net::SocketType;
|
||||||
|
matches!(self.socket_type()?, SocketType::DGRAM).ok()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> GetSocketType for T
|
||||||
|
where
|
||||||
|
T: AsFd,
|
||||||
|
{
|
||||||
|
type Error = rustix::io::Errno;
|
||||||
|
|
||||||
|
fn socket_type(&self) -> Result<rustix::net::SocketType, Self::Error> {
|
||||||
|
rustix::net::sockopt::get_socket_type(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
pub trait GetSocketProtocol {
|
||||||
|
fn socket_protocol(&self) -> Result<Option<rustix::net::Protocol>, rustix::io::Errno>;
|
||||||
|
fn is_udp_socket(&self) -> Result<bool, rustix::io::Errno> {
|
||||||
|
self.socket_protocol()?
|
||||||
|
.map(|p| p == rustix::net::ipproto::UDP)
|
||||||
|
.unwrap_or(false)
|
||||||
|
.ok()
|
||||||
|
}
|
||||||
|
fn demand_udp_socket(&self) -> anyhow::Result<()> {
|
||||||
|
match self.socket_protocol() {
|
||||||
|
Ok(Some(rustix::net::ipproto::UDP)) => Ok(()),
|
||||||
|
Ok(Some(other_proto)) => {
|
||||||
|
bail!("Not a udp socket, instead socket protocol is: {other_proto:?}")
|
||||||
|
}
|
||||||
|
Ok(None) => bail!("getsockopt() returned empty value"),
|
||||||
|
Err(errno) => Err(errno.into_stdio_err())?,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
impl<T> GetSocketProtocol for T
|
||||||
|
where
|
||||||
|
T: AsFd,
|
||||||
|
{
|
||||||
|
fn socket_protocol(&self) -> Result<Option<rustix::net::Protocol>, rustix::io::Errno> {
|
||||||
|
rustix::net::sockopt::get_socket_protocol(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use mio::net::{UnixListener, UnixStream};
|
use mio::net::{UnixListener, UnixStream};
|
||||||
use rustix::fd::RawFd;
|
use rustix::fd::{OwnedFd, RawFd};
|
||||||
|
|
||||||
use crate::fd::claim_fd;
|
use crate::{fd::claim_fd, result::OkExt};
|
||||||
|
|
||||||
pub mod interest {
|
pub mod interest {
|
||||||
use mio::Interest;
|
use mio::Interest;
|
||||||
@@ -25,15 +25,20 @@ impl UnixListenerExt for UnixListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait UnixStreamExt: Sized {
|
pub trait UnixStreamExt: Sized {
|
||||||
|
fn from_fd(fd: OwnedFd) -> anyhow::Result<Self>;
|
||||||
fn claim_fd(fd: RawFd) -> anyhow::Result<Self>;
|
fn claim_fd(fd: RawFd) -> anyhow::Result<Self>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UnixStreamExt for UnixStream {
|
impl UnixStreamExt for UnixStream {
|
||||||
fn claim_fd(fd: RawFd) -> anyhow::Result<Self> {
|
fn from_fd(fd: OwnedFd) -> anyhow::Result<Self> {
|
||||||
use std::os::unix::net::UnixStream as StdUnixStream;
|
use std::os::unix::net::UnixStream as StdUnixStream;
|
||||||
|
|
||||||
let sock = StdUnixStream::from(claim_fd(fd)?);
|
let sock = StdUnixStream::from(fd);
|
||||||
sock.set_nonblocking(true)?;
|
sock.set_nonblocking(true)?;
|
||||||
Ok(UnixStream::from_std(sock))
|
UnixStream::from_std(sock).ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn claim_fd(fd: RawFd) -> anyhow::Result<Self> {
|
||||||
|
Self::from_fd(claim_fd(fd)?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user