diff options
author | Alyssa Ross <hi@alyssa.is> | 2020-03-25 08:38:01 +0000 |
---|---|---|
committer | Alyssa Ross <hi@alyssa.is> | 2020-06-15 09:37:12 +0000 |
commit | b6549a605935e29ab0ae4291737f8b0158bca1fb (patch) | |
tree | 7f4242993ce003cb787b242a264e3b8ea47e3430 | |
parent | 2885f9ca1a79d30421deeb025e92ae0118fc6d3a (diff) | |
download | crosvm-b6549a605935e29ab0ae4291737f8b0158bca1fb.tar crosvm-b6549a605935e29ab0ae4291737f8b0158bca1fb.tar.gz crosvm-b6549a605935e29ab0ae4291737f8b0158bca1fb.tar.bz2 crosvm-b6549a605935e29ab0ae4291737f8b0158bca1fb.tar.lz crosvm-b6549a605935e29ab0ae4291737f8b0158bca1fb.tar.xz crosvm-b6549a605935e29ab0ae4291737f8b0158bca1fb.tar.zst crosvm-b6549a605935e29ab0ae4291737f8b0158bca1fb.zip |
recursive deserialization
-rw-r--r-- | Cargo.lock | 3 | ||||
-rw-r--r-- | devices/Cargo.toml | 1 | ||||
-rw-r--r-- | devices/src/lib.rs | 7 | ||||
-rw-r--r-- | devices/src/pci/pci_root.rs | 15 | ||||
-rw-r--r-- | devices/src/virtio/controller.rs | 316 | ||||
-rw-r--r-- | devices/src/virtio/queue.rs | 5 | ||||
-rw-r--r-- | msg_socket2/Cargo.toml | 9 | ||||
-rw-r--r-- | msg_socket2/LICENSE-APACHE | 201 | ||||
-rw-r--r-- | msg_socket2/LICENSE-MIT | 23 | ||||
-rw-r--r-- | msg_socket2/README | 12 | ||||
-rw-r--r-- | msg_socket2/src/de.rs | 731 | ||||
-rw-r--r-- | msg_socket2/src/error.rs | 3 | ||||
-rw-r--r-- | msg_socket2/src/fd.rs | 59 | ||||
-rw-r--r-- | msg_socket2/src/lib.rs | 55 | ||||
-rw-r--r-- | msg_socket2/src/ser.rs | 147 | ||||
-rw-r--r-- | msg_socket2/src/socket.rs | 18 | ||||
-rw-r--r-- | msg_socket2/tests/round_trip.rs | 79 | ||||
-rw-r--r-- | vm_control/Cargo.toml | 1 | ||||
-rw-r--r-- | vm_control/src/lib.rs | 16 |
19 files changed, 1359 insertions, 342 deletions
diff --git a/Cargo.lock b/Cargo.lock index 9ad31d6..8e079d2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -206,7 +206,6 @@ dependencies = [ "msg_on_socket_derive 0.1.0", "msg_socket 0.1.0", "msg_socket2 0.1.0", - "msg_socket2_derive 0.1.0", "net_sys 0.1.0", "net_util 0.1.0", "p9 0.1.0", @@ -505,6 +504,7 @@ name = "msg_socket2" version = "0.1.0" dependencies = [ "bincode 1.3.0 (git+https://github.com/alyssais/bincode?branch=from_slice)", + "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", "msg_socket2_derive 0.1.0", "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", "sys_util 0.1.0", @@ -846,7 +846,6 @@ dependencies = [ "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", "msg_socket 0.1.0", "msg_socket2 0.1.0", - "msg_socket2_derive 0.1.0", "resources 0.1.0", "sys_util 0.1.0", ] diff --git a/devices/Cargo.toml b/devices/Cargo.toml index 4d6c4d8..830cb86 100644 --- a/devices/Cargo.toml +++ b/devices/Cargo.toml @@ -35,7 +35,6 @@ linux_input_sys = { path = "../linux_input_sys" } msg_on_socket_derive = { path = "../msg_socket/msg_on_socket_derive" } msg_socket = { path = "../msg_socket" } msg_socket2 = { path = "../msg_socket2" } -msg_socket2_derive = { path = "../msg_socket2/derive" } net_sys = { path = "../net_sys" } net_util = { path = "../net_util" } p9 = { path = "../p9" } diff --git a/devices/src/lib.rs b/devices/src/lib.rs index 7df9c62..ce57e61 100644 --- a/devices/src/lib.rs +++ b/devices/src/lib.rs @@ -49,12 +49,9 @@ pub use self::usb::xhci::xhci_controller::XhciController; pub use self::vfio::{VfioContainer, VfioDevice}; pub use self::virtio::VirtioPciDevice; -use msg_socket::MsgOnSocket; -use serde::{Deserialize, Serialize}; +use msg_socket2::{Deserialize, DeserializeWithFds, Serialize, SerializeWithFds}; -use msg_socket2_derive::SerializeWithFds; - -#[derive(Clone, Copy, Debug, MsgOnSocket, Serialize, SerializeWithFds, Deserialize)] +#[derive(Clone, Copy, Debug, Serialize, SerializeWithFds, Deserialize, DeserializeWithFds)] #[msg_socket2(strategy = "serde")] pub struct MemoryParams { /// Physical memory size in bytes for the VM. diff --git a/devices/src/pci/pci_root.rs b/devices/src/pci/pci_root.rs index 76f9d82..d100941 100644 --- a/devices/src/pci/pci_root.rs +++ b/devices/src/pci/pci_root.rs @@ -8,8 +8,7 @@ use std::fmt::{self, Display}; use std::os::unix::io::RawFd; use std::sync::Arc; -use msg_socket2_derive::SerializeWithFds; -use serde::{Deserialize, Serialize}; +use msg_socket2::{Deserialize, DeserializeWithFds, Serialize, SerializeWithFds}; use sync::Mutex; use crate::pci::pci_configuration::{ @@ -45,7 +44,17 @@ impl PciDevice for PciRootConfiguration { /// PCI Device Address, AKA Bus:Device.Function #[derive( - Clone, Copy, Debug, Deserialize, Eq, Ord, PartialEq, PartialOrd, Serialize, SerializeWithFds, + Clone, + Copy, + Debug, + Deserialize, + DeserializeWithFds, + Eq, + Ord, + PartialEq, + PartialOrd, + Serialize, + SerializeWithFds, )] #[msg_socket2(strategy = "serde")] pub struct PciAddress { diff --git a/devices/src/virtio/controller.rs b/devices/src/virtio/controller.rs index 0a59072..644ece1 100644 --- a/devices/src/virtio/controller.rs +++ b/devices/src/virtio/controller.rs @@ -28,8 +28,6 @@ //! the virtio queue, and routing messages in and out of `WlState`. Possible events include the kill //! event, available descriptors on the `in` or `out` queue, and incoming data on any vfd's socket. -use std::os::unix::prelude::*; - use std::collections::BTreeMap as Map; use std::fmt::{self, Formatter}; use std::os::unix::io::{AsRawFd, RawFd}; @@ -38,10 +36,9 @@ use std::sync::Arc; use std::thread; use msg_socket::{MsgReceiver, MsgSocket}; +use msg_socket2::de::{EnumAccessWithFds, SeqAccessWithFds, VariantAccessWithFds, VisitorWithFds}; use msg_socket2::ser::{SerializeStructVariantFds, SerializeTupleVariantFds}; use msg_socket2::{DeserializeWithFds, DeserializerWithFds, FdSerializer, SerializeWithFds}; -use msg_socket2_derive::SerializeWithFds; -use serde::de::{Deserializer, EnumAccess, SeqAccess, VariantAccess}; use serde::ser::{SerializeStructVariant, SerializeTupleVariant, Serializer}; use serde::{Deserialize, Serialize}; use sys_util::net::UnixSeqpacket; @@ -136,11 +133,9 @@ impl SerializeWithFds for Request { vm_socket: _, memory_params, } => { - let mut sv = serializer.serialize_struct_variant("Request", 0, "Create", 1)?; - - sv.skip_field("vm_socket")?; + let mut sv = serializer.serialize_struct_variant("Request", 0, "Create", 2)?; + sv.serialize_field("vm_socket", &())?; sv.serialize_field("memory_params", memory_params)?; - sv.end() } @@ -180,16 +175,14 @@ impl SerializeWithFds for Request { in_queue_evt: _, out_queue_evt: _, } => { - let mut sv = serializer.serialize_struct_variant("Request", 8, "Activate", 2)?; - - sv.skip_field("shm")?; - sv.skip_field("interrupt")?; - sv.skip_field("interrupt_resample_evt")?; + let mut sv = serializer.serialize_struct_variant("Request", 8, "Activate", 7)?; + sv.serialize_field("shm", &())?; + sv.serialize_field("interrupt", &())?; + sv.serialize_field("interrupt_resample_evt", &())?; sv.serialize_field("in_queue", in_queue)?; sv.serialize_field("out_queue", out_queue)?; - sv.skip_field("in_queue_evt")?; - sv.skip_field("out_queue_evt")?; - + sv.serialize_field("in_queue_evt", &())?; + sv.serialize_field("out_queue_evt", &())?; sv.end() } @@ -284,26 +277,20 @@ impl SerializeWithFds for Request { } impl<'de> DeserializeWithFds<'de> for Request { - fn deserialize<I, De>(deserializer: DeserializerWithFds<I, De>) -> Result<Self, De::Error> - where - I: Iterator<Item = RawFd>, - De: Deserializer<'de>, - { - struct Visitor<'iter, Iter> { - fds: &'iter mut Iter, - } - - impl<'iter, 'de, Iter> serde::de::Visitor<'de> for Visitor<'iter, Iter> - where - Iter: Iterator<Item = RawFd>, - { + fn deserialize<D: DeserializerWithFds<'de>>(deserializer: D) -> Result<Self, D::Error> { + struct Visitor; + + impl<'de> VisitorWithFds<'de> for Visitor { type Value = Request; fn expecting(&self, f: &mut Formatter) -> fmt::Result { write!(f, "enum Request") } - fn visit_enum<A: EnumAccess<'de>>(self, data: A) -> Result<Self::Value, A::Error> { + fn visit_enum<A: EnumAccessWithFds<'de>>( + self, + data: A, + ) -> Result<Self::Value, A::Error> { #[derive(Debug, Deserialize)] enum Variant { Create, @@ -323,54 +310,38 @@ impl<'de> DeserializeWithFds<'de> for Request { match data.variant()? { (Variant::Create, variant) => { - struct Visitor<'iter, Iter> { - fds: &'iter mut Iter, - } + struct Visitor; - impl<'iter, 'de, Iter> serde::de::Visitor<'de> for Visitor<'iter, Iter> - where - Iter: Iterator<Item = RawFd>, - { + impl<'de> VisitorWithFds<'de> for Visitor { type Value = Request; fn expecting(&self, f: &mut Formatter) -> fmt::Result { write!(f, "struct variant Request::Create") } - fn visit_seq<A: SeqAccess<'de>>( + fn visit_seq<A: SeqAccessWithFds<'de>>( self, mut seq: A, ) -> Result<Request, A::Error> { use serde::de::Error; + fn too_short<E: Error>(len: usize) -> E { + E::invalid_length( + len, + &"struct variant Request::Create with 2 elements", + ) + } + Ok(Request::Create { - vm_socket: match self.fds.next() { - Some(vm_socket) => MaybeOwnedFd::Owned(unsafe { - UnixSeqpacket::from_raw_fd(vm_socket) - }), - None => { - return Err(Error::invalid_length( - 0, - &"struct variant Request::Create with 2 elements", - )) - } - }, - - memory_params: match seq.next_element()? { - Some(memory_params) => memory_params, - None => { - return Err(Error::invalid_length( - 1, - &"struct variant Request::Create with 2 elements", - )) - } - }, + vm_socket: seq.next_element()?.ok_or_else(|| too_short(0))?, + memory_params: seq + .next_element()? + .ok_or_else(|| too_short(1))?, }) } } - let visitor = Visitor { fds: self.fds }; - variant.struct_variant(&["memory_params"], visitor) + variant.struct_variant(&["vm_socket", "memory_params"], Visitor) } (Variant::DebugLabel, variant) => { @@ -400,35 +371,29 @@ impl<'de> DeserializeWithFds<'de> for Request { (Variant::ReadConfig, variant) => { struct Visitor; - impl<'de> serde::de::Visitor<'de> for Visitor { + impl<'de> VisitorWithFds<'de> for Visitor { type Value = Request; fn expecting(&self, f: &mut Formatter) -> fmt::Result { write!(f, "struct variant Request::ReadConfig") } - fn visit_seq<A: SeqAccess<'de>>( + fn visit_seq<A: SeqAccessWithFds<'de>>( self, mut seq: A, ) -> Result<Request, A::Error> { use serde::de::Error; + fn too_short<E: Error>(len: usize) -> E { + E::invalid_length( + len, + &"struct variant Request::ReadConfig with 2 elements", + ) + } + Ok(Request::ReadConfig { - offset: match seq.next_element()? { - Some(offset) => offset, - None => return Err(Error::invalid_length( - 0, - &"struct variant Request::ReadConfig with 2 elements", - )), - }, - - len: match seq.next_element()? { - Some(len) => len, - None => return Err(Error::invalid_length( - 1, - &"struct variant Request::ReadConfig with 2 elements", - )), - }, + offset: seq.next_element()?.ok_or_else(|| too_short(0))?, + len: seq.next_element()?.ok_or_else(|| too_short(1))?, }) } } @@ -439,35 +404,29 @@ impl<'de> DeserializeWithFds<'de> for Request { (Variant::WriteConfig, variant) => { struct Visitor; - impl<'de> serde::de::Visitor<'de> for Visitor { + impl<'de> VisitorWithFds<'de> for Visitor { type Value = Request; fn expecting(&self, f: &mut Formatter) -> fmt::Result { write!(f, "struct variant Request::WriteConfig") } - fn visit_seq<A: SeqAccess<'de>>( + fn visit_seq<A: SeqAccessWithFds<'de>>( self, mut seq: A, ) -> Result<Request, A::Error> { use serde::de::Error; + fn too_short<E: Error>(len: usize) -> E { + E::invalid_length( + len, + &"struct variant Request::WriteConfig with 2 elements", + ) + } + Ok(Request::WriteConfig { - offset: match seq.next_element()? { - Some(offset) => offset, - None => return Err(Error::invalid_length( - 0, - &"struct variant Request::WriteConfig with 2 elements", - )), - }, - - data: match seq.next_element()? { - Some(data) => data, - None => return Err(Error::invalid_length( - 1, - &"struct variant Request::WriteConfig with 2 elements", - )), - }, + offset: seq.next_element()?.ok_or_else(|| too_short(0))?, + data: seq.next_element()?.ok_or_else(|| too_short(1))?, }) } } @@ -476,114 +435,58 @@ impl<'de> DeserializeWithFds<'de> for Request { } (Variant::Activate, variant) => { - struct Visitor<'iter, Iter> { - fds: &'iter mut Iter, - } + struct Visitor; - impl<'iter, 'de, Iter> serde::de::Visitor<'de> for Visitor<'iter, Iter> - where - Iter: Iterator<Item = RawFd>, - { + impl<'de> VisitorWithFds<'de> for Visitor { type Value = Request; fn expecting(&self, f: &mut Formatter) -> fmt::Result { write!(f, "struct variant Request::Activate") } - fn visit_seq<A: SeqAccess<'de>>( + fn visit_seq<A: SeqAccessWithFds<'de>>( self, mut seq: A, ) -> Result<Request, A::Error> { use serde::de::Error; + fn too_short<E: Error>(len: usize) -> E { + E::invalid_length( + len, + &"struct variant Request::Activate with 7 elements", + ) + } + Ok(Request::Activate { - shm: match self.fds.next() { - Some(shm) => MaybeOwnedFd::Owned(unsafe { - FromRawFd::from_raw_fd(shm) - }), - None => { - return Err(Error::invalid_length( - 0, - &"struct variant Request::Activate with 7 elements", - )) - } - }, - - interrupt: match self.fds.next() { - Some(interrupt) => MaybeOwnedFd::Owned(unsafe { - UnixSeqpacket::from_raw_fd(interrupt) - }), - None => { - return Err(Error::invalid_length( - 1, - &"struct variant Request::Activate with 7 elements", - )) - } - }, - - interrupt_resample_evt: match self.fds.next() { - Some(interrupt_resample_evt) => { - MaybeOwnedFd::Owned(unsafe { - EventFd::from_raw_fd(interrupt_resample_evt) - }) - } - None => { - return Err(Error::invalid_length( - 2, - &"struct variant Request::Activate with 7 elements", - )) - } - }, - - in_queue: match seq.next_element()? { - Some(in_queue) => in_queue, - None => { - return Err(Error::invalid_length( - 3, - &"struct variant Request::Activate with 7 elements", - )) - } - }, - - out_queue: match seq.next_element()? { - Some(out_queue) => out_queue, - None => { - return Err(Error::invalid_length( - 4, - &"struct variant Request::Activate with 7 elements", - )) - } - }, - - in_queue_evt: match self.fds.next() { - Some(in_queue_evt) => MaybeOwnedFd::Owned(unsafe { - EventFd::from_raw_fd(in_queue_evt) - }), - None => { - return Err(Error::invalid_length( - 5, - &"struct variant Request::Activate with 7 elements", - )) - } - }, - - out_queue_evt: match self.fds.next() { - Some(out_queue_evt) => MaybeOwnedFd::Owned(unsafe { - EventFd::from_raw_fd(out_queue_evt) - }), - None => { - return Err(Error::invalid_length( - 6, - &"struct variant Request::Activate with 7 elements", - )) - } - }, + shm: seq.next_element()?.ok_or_else(|| too_short(0))?, + interrupt: seq.next_element()?.ok_or_else(|| too_short(1))?, + interrupt_resample_evt: seq + .next_element()? + .ok_or_else(|| too_short(2))?, + in_queue: seq.next_element()?.ok_or_else(|| too_short(3))?, + out_queue: seq.next_element()?.ok_or_else(|| too_short(4))?, + in_queue_evt: seq + .next_element()? + .ok_or_else(|| too_short(5))?, + out_queue_evt: seq + .next_element()? + .ok_or_else(|| too_short(6))?, }) } } - let visitor = Visitor { fds: self.fds }; - variant.struct_variant(&["in_queue", "out_queue"], visitor) + variant.struct_variant( + &[ + "shm", + "interrupt", + "interrupt_resample_evt", + "in_queue", + "out_queue", + "in_queue_evt", + "out_queue_evt", + ], + Visitor, + ) } (Variant::Reset, variant) => { @@ -594,28 +497,29 @@ impl<'de> DeserializeWithFds<'de> for Request { (Variant::GetDeviceBars, variant) => { struct Visitor; - impl<'de> serde::de::Visitor<'de> for Visitor { + impl<'de> VisitorWithFds<'de> for Visitor { type Value = Request; fn expecting(&self, f: &mut Formatter) -> fmt::Result { write!(f, "struct variant Request::GetDeviceBars") } - fn visit_seq<A: SeqAccess<'de>>( + fn visit_seq<A: SeqAccessWithFds<'de>>( self, mut seq: A, ) -> Result<Request, A::Error> { use serde::de::Error; - Ok(Request::GetDeviceBars(match seq.next_element()? { - Some(address) => address, - None => { - return Err(Error::invalid_length( - 0, - &"struct variant Request::GetDeviceBars with 1 element", - )) - } - })) + fn too_short<E: Error>(len: usize) -> E { + E::invalid_length( + len, + &"struct variant Request::GetDeviceBars with 2 elements", + ) + } + + Ok(Request::GetDeviceBars( + seq.next_element()?.ok_or_else(|| too_short(0))?, + )) } } @@ -635,11 +539,6 @@ impl<'de> DeserializeWithFds<'de> for Request { } } - let DeserializerWithFds { - mut fds, - deserializer, - } = deserializer; - let visitor = Visitor { fds: &mut fds }; deserializer.deserialize_enum( "Request", &[ @@ -657,12 +556,12 @@ impl<'de> DeserializeWithFds<'de> for Request { "GetDeviceCaps", "Kill", ], - visitor, + Visitor, ) } } -#[derive(Debug, Deserialize, Serialize, SerializeWithFds)] +#[derive(Debug, Deserialize, DeserializeWithFds, Serialize, SerializeWithFds)] #[msg_socket2(strategy = "serde")] pub enum Response { DebugLabel(String), @@ -676,15 +575,6 @@ pub enum Response { Kill, } -impl<'de> DeserializeWithFds<'de> for Response { - fn deserialize<I, De>(deserializer: DeserializerWithFds<I, De>) -> Result<Self, De::Error> - where - De: Deserializer<'de>, - { - Deserialize::deserialize(deserializer.deserializer) - } -} - type Socket = msg_socket2::Socket<Request, Response>; // TODO: support arbitrary number of queues diff --git a/devices/src/virtio/queue.rs b/devices/src/virtio/queue.rs index f2310fa..c4c5217 100644 --- a/devices/src/virtio/queue.rs +++ b/devices/src/virtio/queue.rs @@ -6,8 +6,7 @@ use std::cmp::min; use std::num::Wrapping; use std::sync::atomic::{fence, Ordering}; -use msg_socket::MsgOnSocket; -use msg_socket2_derive::SerializeWithFds; +use msg_socket2::{DeserializeWithFds, SerializeWithFds}; use sys_util::{error, GuestAddress, GuestMemory}; use virtio_sys::virtio_ring::VIRTIO_RING_F_EVENT_IDX; @@ -203,7 +202,7 @@ impl<'a, 'b> Iterator for AvailIter<'a, 'b> { use serde::{Deserialize, Serialize}; -#[derive(Clone, Debug, MsgOnSocket, Serialize, SerializeWithFds, Deserialize)] +#[derive(Clone, Debug, Serialize, SerializeWithFds, Deserialize, DeserializeWithFds)] #[msg_socket2(strategy = "serde")] /// A virtio queue's parameters. pub struct Queue { diff --git a/msg_socket2/Cargo.toml b/msg_socket2/Cargo.toml index 7a7cf73..1662ab3 100644 --- a/msg_socket2/Cargo.toml +++ b/msg_socket2/Cargo.toml @@ -1,12 +1,19 @@ +# SPDX-License-Identifier: MIT OR Apache-2.0 +# Copyright 2020, Alyssa Ross + [package] name = "msg_socket2" version = "0.1.0" authors = ["Alyssa Ross <hi@alyssa.is>"] +license = "MIT OR Apache-2.0" edition = "2018" +description = "Send messages over Unix domain sockets, including file descriptors" +readme = "README" [dependencies] +libc = "*" msg_socket2_derive = { path = "derive" } -serde = "1.0.104" +serde = { version = "1.0.104" } sys_util = { path = "../sys_util" } bincode = { git = "https://github.com/alyssais/bincode", branch = "from_slice" } diff --git a/msg_socket2/LICENSE-APACHE b/msg_socket2/LICENSE-APACHE new file mode 100644 index 0000000..16fe87b --- /dev/null +++ b/msg_socket2/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/msg_socket2/LICENSE-MIT b/msg_socket2/LICENSE-MIT new file mode 100644 index 0000000..31aa793 --- /dev/null +++ b/msg_socket2/LICENSE-MIT @@ -0,0 +1,23 @@ +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/msg_socket2/README b/msg_socket2/README new file mode 100644 index 0000000..96ae145 --- /dev/null +++ b/msg_socket2/README @@ -0,0 +1,12 @@ +msg_socket2 +=========== + +A library for sending messages over Unix domain sockets, including +file descriptors. + +HTML usage documentation can be generated with: + + cargo doc + +Licensed under either of Apache License (LICENSE-APACHE), Version 2.0 +or MIT license (LICENSE-MIT) at your option. diff --git a/msg_socket2/src/de.rs b/msg_socket2/src/de.rs index 1d3a9e1..0dec746 100644 --- a/msg_socket2/src/de.rs +++ b/msg_socket2/src/de.rs @@ -1,21 +1,730 @@ -use serde::Deserializer; -use std::os::unix::prelude::*; +// SPDX-License-Identifier: MIT OR Apache-2.0 +// Copyright 2020, Alyssa Ross +// +// Portions Copyright Erick Tryzelaar and David Tolnay. +// Licensed under either of Apache License, Version 2.0 +// or MIT license at your option. +//! Data structure deserialization framework for Unix domain sockets. +//! +//! Much like `serde::de`, except receiving file descriptors is also +//! supported. + +use crate::Fd; +use std::cmp::min; +use std::collections::BTreeMap; +use std::fmt::{self, Formatter}; +use std::marker::PhantomData; + +pub use serde::de::{ + Deserialize, DeserializeSeed, Deserializer, EnumAccess, Error, SeqAccess, StdError, + VariantAccess, Visitor, +}; + +/// A generic container for an inner serde type, and some file descriptors. +/// +/// Useful for implementing assorted `*WithFds` traits in terms of +/// their serde equivalents. +#[derive(Debug)] +pub(crate) struct WithFds<'fds, T, F> { + pub inner: T, + pub fds: &'fds mut F, +} + +/// Like `Deserialize`, but provides file descriptors as well as data. pub trait DeserializeWithFds<'de>: Sized { - fn deserialize<I, De>(deserializer: DeserializerWithFds<I, De>) -> Result<Self, De::Error> + /// Like `Deserialize::deserialize`, but `deserializer` is a + /// `DeserializerWithFds` instead of a `Deserializer`. + fn deserialize<D: DeserializerWithFds<'de>>(deserializer: D) -> Result<Self, D::Error>; +} + +/// Like `DeserializeSeed`, but provides file descriptors as well as +/// data. +pub trait DeserializeWithFdsSeed<'de>: Sized { + /// Like `DeserializeSeed::Value`. + type Value; + + /// Like `DeserializeSeed::deserialize`, but `deserializer` is a + /// `DeserializerWithFds` instead of a `Deserializer`. + fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error> + where + D: DeserializerWithFds<'de>; +} + +impl<'de, T: DeserializeWithFds<'de>> DeserializeWithFdsSeed<'de> for PhantomData<T> { + type Value = T; + + fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error> + where + D: DeserializerWithFds<'de>, + { + T::deserialize(deserializer) + } +} + +impl<'fds, 'de, T, F> DeserializeSeed<'de> for WithFds<'fds, T, F> +where + F: Iterator<Item = Fd>, + T: DeserializeWithFdsSeed<'de>, +{ + type Value = T::Value; + + fn deserialize<D: Deserializer<'de>>(self, deserializer: D) -> Result<Self::Value, D::Error> { + let deserializer_with_fds = WithFds { + inner: deserializer, + fds: self.fds, + }; + + self.inner.deserialize(deserializer_with_fds) + } +} + +/// Like `Deserializer` but provides file descriptors as well as data. +pub trait DeserializerWithFds<'de> { + /// Like `Deserializer::Error`. + type Error: Error; + + /// Deserialize a file descriptor. + fn deserialize_fd(self) -> Result<Fd, Self::Error>; + + /// Like `Deserializer::deserialize_option`, but `visitor` is a + /// `VisitorWithFds` instead of a `Visitor`. + fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error> where - I: Iterator<Item = RawFd>, - De: Deserializer<'de>; + V: VisitorWithFds<'de>; + + /// Like `Deserializer::deserialize_seq` but `visitor` is a + /// `VisitorWithFds` instead of a `Visitor`. + fn deserialize_seq<V: VisitorWithFds<'de>>(self, visitor: V) -> Result<V::Value, Self::Error>; + + /// Like `Deserializer::deserialize_map` but `visitor` is a + /// `VisitorWithFds` instead of a `Visitor`. + fn deserialize_tuple_struct<V: VisitorWithFds<'de>>( + self, + name: &'static str, + len: usize, + visitor: V, + ) -> Result<V::Value, Self::Error>; + + /// Like `Deserializer::deserialize_map` but `visitor` is a + /// `VisitorWithFds` instead of a `Visitor`. + fn deserialize_map<V: VisitorWithFds<'de>>(self, visitor: V) -> Result<V::Value, Self::Error>; + + /// Like `Deserializer::deserialize_struct` but `visitor` is a + /// `VisitorWithFds` instead of a `Visitor`. + fn deserialize_struct<V: VisitorWithFds<'de>>( + self, + name: &'static str, + fields: &'static [&'static str], + visitor: V, + ) -> Result<V::Value, Self::Error>; + + /// Like `Deserializer::deserialize_enum` but `visitor` is a + /// `VisitorWithFds` instead of a `Visitor`. + fn deserialize_enum<V: VisitorWithFds<'de>>( + self, + name: &'static str, + variants: &'static [&'static str], + visitor: V, + ) -> Result<V::Value, Self::Error>; + + /// Invite a `Visitor` to visit a `Some` value. + /// + /// The purpose of this indirection is to allow implementations to + /// control how `Visitor::visit_some` is called. This means that + /// whatever way they get a `Deserializer` to pass to it doesn't + /// have to be exposed publicly through the trait. + /// + /// This looks a lot like a `deserialize_*` method, but it takes a + /// `Visitor` instead of a `VisitorWithFds`, and it's not part of + /// the serde interface. + fn invite_visit_some<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error>; + + /// Invite a `Deserialize` to deserialize. + /// + /// The purpose of this indirection is to allow implementations to + /// control how `Deserialize::deserialize` is called. This means + /// that whatever way they get a `Deserializer` to pass to it + /// doesn't have to be exposed publicly through the trait. + fn invite_deserialize<T: Deserialize<'de>>(self) -> Result<T, Self::Error>; +} + +impl<'fds, 'de, D, F> DeserializerWithFds<'de> for WithFds<'fds, D, F> +where + D: Deserializer<'de>, + F: Iterator<Item = Fd>, +{ + type Error = D::Error; + + fn deserialize_fd(self) -> Result<Fd, Self::Error> { + struct UnitVisitor; + + impl<'de> Visitor<'de> for UnitVisitor { + type Value = (); + + fn expecting(&self, f: &mut Formatter) -> fmt::Result { + write!(f, "expecting unit") + } + + fn visit_unit<E>(self) -> Result<Self::Value, E> { + Ok(()) + } + } + + // This is probably not necessary, since unit should be + // serialized to nothing, but it's more correct to do this, + // because unit was serialized, and so unit should be + // deserialized. + self.inner.deserialize_unit(UnitVisitor)?; + + self.fds + .next() + .ok_or_else(|| Self::Error::custom("no fds to deserialize")) + } + + fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: VisitorWithFds<'de>, + { + let wrapper = WithFds { + inner: visitor, + fds: self.fds, + }; + + self.inner.deserialize_option(wrapper) + } + + fn deserialize_seq<V: VisitorWithFds<'de>>(self, visitor: V) -> Result<V::Value, D::Error> { + let wrapper = WithFds { + inner: visitor, + fds: self.fds, + }; + + self.inner.deserialize_seq(wrapper) + } + + fn deserialize_tuple_struct<V: VisitorWithFds<'de>>( + self, + name: &'static str, + len: usize, + visitor: V, + ) -> Result<V::Value, D::Error> { + let wrapper = WithFds { + inner: visitor, + fds: self.fds, + }; + + self.inner.deserialize_tuple_struct(name, len, wrapper) + } + + fn deserialize_map<V: VisitorWithFds<'de>>(self, visitor: V) -> Result<V::Value, D::Error> { + let wrapper = WithFds { + inner: visitor, + fds: self.fds, + }; + + self.inner.deserialize_map(wrapper) + } + + fn deserialize_struct<V: VisitorWithFds<'de>>( + self, + name: &'static str, + fields: &'static [&'static str], + visitor: V, + ) -> Result<V::Value, D::Error> { + let wrapper = WithFds { + inner: visitor, + fds: self.fds, + }; + + self.inner.deserialize_struct(name, fields, wrapper) + } + + fn deserialize_enum<V: VisitorWithFds<'de>>( + self, + name: &'static str, + variants: &'static [&'static str], + visitor: V, + ) -> Result<V::Value, D::Error> { + let wrapper = WithFds { + inner: visitor, + fds: self.fds, + }; + + self.inner.deserialize_enum(name, variants, wrapper) + } + + fn invite_visit_some<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, D::Error> { + visitor.visit_some(self.inner) + } + + fn invite_deserialize<T: Deserialize<'de>>(self) -> Result<T, D::Error> { + T::deserialize(self.inner) + } } +/// A type implementing `Visitor` without any overrides. +/// +/// This allows for referring to the default serde implementation of +/// the `Visitor` methods from our own overrides. #[derive(Debug)] -pub struct DeserializerWithFds<'iter, Iter, De> { - pub deserializer: De, - pub fds: &'iter mut Iter, +struct VisitorDefaults<'a, V>(PhantomData<&'a V>); + +impl<'a, 'de, V> Visitor<'de> for VisitorDefaults<'a, V> { + type Value = V; + + fn expecting(&self, _: &mut Formatter) -> fmt::Result { + unreachable!() + } +} + +/// Like `SeqAccess`, but elements provide access to file descriptors +/// as well as data. +pub trait SeqAccessWithFds<'de> { + /// Like `SeqAccess::Error`. + type Error: Error; + + /// Like `SeqAccess::next_element_seed`, but `seed` is a + /// `DeserializeWithFdsSeed` instead of a `DeserializeSeed`. + fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error> + where + T: DeserializeWithFdsSeed<'de>; + + /// Like `SeqAccess::next_element`, but returns a + /// `DeserializeWithFds` instead of a `Deserialize`. + fn next_element<T: DeserializeWithFds<'de>>(&mut self) -> Result<Option<T>, Self::Error> { + self.next_element_seed(PhantomData) + } + + /// See `SeqAccess::size_hint`. + fn size_hint(&self) -> Option<usize> { + None + } + + /// Invite a `Visitor` to visit. The inverse of `Visitor::visit`. + /// + /// The purpose of this indirection is to allow implementations to + /// control how `Visitor::visit_seq` is called. This means that + /// whatever way they get a `SeqAccess` to pass to it doesn't have + /// to be exposed publicly through the trait. + fn invite<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error>; +} + +impl<'de, 'fds, A, F> SeqAccessWithFds<'de> for WithFds<'fds, A, F> +where + A: SeqAccess<'de>, + F: Iterator<Item = Fd>, +{ + type Error = A::Error; + + fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error> + where + T: DeserializeWithFdsSeed<'de>, + { + let wrapper = WithFds { + inner: seed, + fds: self.fds, + }; + + self.inner.next_element_seed(wrapper) + } + + fn size_hint(&self) -> Option<usize> { + self.inner.size_hint() + } + + fn invite<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> { + visitor.visit_seq(self.inner) + } } -impl<'iter, Iter, De> DeserializerWithFds<'iter, Iter, De> { - pub fn new(fds: &'iter mut Iter, deserializer: De) -> Self { - Self { deserializer, fds } +/// Like `MapAccess`, but keys and values provide access to file +/// descriptors as well as data. +pub trait MapAccessWithFds<'de>: Sized { + /// Like `MapAccess::Error`. + type Error: Error; + + /// Like `MapAccess::next_key_seed`, but `seed` is a + /// `DeserializeWithFdsSeed` instead of a `DeserializeSeed`. + fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Self::Error> + where + K: DeserializeWithFdsSeed<'de>; + + /// Like `MapAccess::next_value_seed`, but `seed` is a + /// `DeserializeWithFdsSeed` instead of a `DeserializeSeed`. + fn next_value_seed<V>(&mut self, seed: V) -> Result<Option<V::Value>, Self::Error> + where + V: DeserializeWithFdsSeed<'de>; + + /// Like `MapAccess::next_entry_seed`, but `kseed` and `vseed` are + /// `DeserializeWithFdsSeed` instead of `DeserializeSeed`. + fn next_entry_seed<K: DeserializeWithFdsSeed<'de>, V: DeserializeWithFdsSeed<'de>>( + &mut self, + kseed: K, + vseed: V, + ) -> Result<Option<(K::Value, V::Value)>, Self::Error>; + + /// Like `MapAccess::next_key`, but returns a `DeserializeWithFds` + /// instead of a `Deserialize`. + fn next_key<K: DeserializeWithFds<'de>>(&mut self) -> Result<Option<K>, Self::Error> { + self.next_key_seed(PhantomData) + } + + /// Like `MapAccess::next_value`, but returns a `DeserializeWithFds` + /// instead of a `Deserialize`. + fn next_value<K: DeserializeWithFds<'de>>(&mut self) -> Result<Option<K>, Self::Error> { + self.next_value_seed(PhantomData) + } + + /// Like `MapAccess:next_entry`, but return values are + /// `DeserializeWithFds` instead of `Deserialize`. + fn next_entry<K, V>(&mut self) -> Result<Option<(K, V)>, Self::Error> + where + K: DeserializeWithFds<'de>, + V: DeserializeWithFds<'de>, + { + self.next_entry_seed(PhantomData, PhantomData) + } + + /// Like `MapAccess::size_hint`. + fn size_hint(&self) -> Option<usize> { + None + } + + /// Invite a `Visitor` to visit. The inverse of `Visitor::visit`. + /// + /// The purpose of this indirection is to allow implementations to + /// control how `Visitor::visit_map` is called. This means that + /// whatever way they get a `MapAccess` to pass to it doesn't have + /// to be exposed publicly through the trait. + fn invite<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error>; +} + +/// Like `EnumAccess`, but variants provide access to file descriptors +/// as well as data. +pub trait EnumAccessWithFds<'de>: Sized { + /// Like `EnumAccess::Error`. + type Error: Error; + + /// Like `EnumAccess::Variant`, but also provides access to file + /// descriptors. + type Variant: VariantAccessWithFds<'de, Error = Self::Error>; + + /// Like `EnumAccess::variant_seed`, but `seed` is a + /// `DeserializeWithFdsSeed` instead of a `DeserializeSeed`. + fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error> + where + V: DeserializeSeed<'de>; + + /// Like `EnumAccess::variant`, but returns a `DeserializeWithFds` + /// instead of a `Deserialize`. + fn variant<V>(self) -> Result<(V, Self::Variant), Self::Error> + where + V: Deserialize<'de>, + { + self.variant_seed(PhantomData) + } + + /// Invite a `Visitor` to visit. The inverse of `Visitor::visit`. + /// + /// The purpose of this indirection is to allow implementations to + /// control how `Visitor::visit_enum` is called. This means that + /// whatever way they get an `EnumAccess` to pass to it doesn't + /// have to be exposed publicly through the trait. + fn invite<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error>; +} + +impl<'fds, 'de, A, F> EnumAccessWithFds<'de> for WithFds<'fds, A, F> +where + A: EnumAccess<'de>, + F: Iterator<Item = Fd>, +{ + type Error = A::Error; + type Variant = WithFds<'fds, A::Variant, F>; + + fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error> + where + V: DeserializeSeed<'de>, + { + let (value, variant) = self.inner.variant_seed(seed)?; + let variant_with_fds = WithFds { + inner: variant, + fds: self.fds, + }; + + Ok((value, variant_with_fds)) + } + + fn invite<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> { + visitor.visit_enum(self.inner) + } +} + +/// Like `VariantAccess`, but provides file descriptors as well as data. +pub trait VariantAccessWithFds<'de>: Sized { + /// Like `VariantAccess::Error`. + type Error: Error; + + /// Like `VariantAccess::unit_variant`. + fn unit_variant(self) -> Result<(), Self::Error>; + + /// Like `VariantAccess::newtype_variant_seed`, but `seed` is a + /// `DeserializeWithFdsSeed` instead of a `DeserializeSeed`. + fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value, Self::Error> + where + T: DeserializeWithFdsSeed<'de>; + + /// Like `VariantAccess::newtype_variant`, but returns a + /// `DeserializeWithFds` instead of a `Deserialize`. + fn newtype_variant<T: DeserializeWithFds<'de>>(self) -> Result<T, Self::Error> { + self.newtype_variant_seed(PhantomData) + } + + /// Like `VariantAccess::struct_variant`, but returns a + /// `DeserializeWithFds` instead of a `Deserialize`. + fn struct_variant<V: VisitorWithFds<'de>>( + self, + fields: &'static [&'static str], + visitor: V, + ) -> Result<V::Value, Self::Error>; +} + +impl<'de, 'fds, A, F> VariantAccessWithFds<'de> for WithFds<'fds, A, F> +where + A: VariantAccess<'de>, + F: Iterator<Item = Fd>, +{ + type Error = A::Error; + + fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value, Self::Error> + where + T: DeserializeWithFdsSeed<'de>, + { + let wrapper = WithFds { + inner: seed, + fds: self.fds, + }; + + self.inner.newtype_variant_seed(wrapper) + } + + fn unit_variant(self) -> Result<(), Self::Error> { + self.inner.unit_variant() + } + + fn struct_variant<V: VisitorWithFds<'de>>( + self, + fields: &'static [&'static str], + visitor: V, + ) -> Result<V::Value, Self::Error> { + let wrapper = WithFds { + inner: visitor, + fds: self.fds, + }; + + self.inner.struct_variant(fields, wrapper) + } +} + +/// Like `Visitor`, but provides file descriptors as well as data. +pub trait VisitorWithFds<'de>: Sized { + /// Like `Visitor::Value`. + type Value; + + /// Like `Visitor::expecting`. + fn expecting(&self, f: &mut Formatter) -> fmt::Result; + + /// Like `Visitor::visit_none`. + fn visit_none<E: Error>(self) -> Result<Self::Value, E> { + VisitorDefaults(PhantomData).visit_none() + } + + /// Like `Visitor:::visit_some`, but `deserializer` is a + /// `DeserializerWithFds` instead of a `Deserializer`. + fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error> + where + D: DeserializerWithFds<'de>, + { + deserializer.invite_visit_some(VisitorDefaults(PhantomData)) + } + + /// Like `Visitor::visit_seq`, but `seq` is a `SeqAccessWithFds` + /// instead of a `SeqAccess`. + fn visit_seq<A: SeqAccessWithFds<'de>>(self, seq: A) -> Result<Self::Value, A::Error> { + seq.invite(VisitorDefaults(PhantomData)) + } + + /// Like `Visitor::visit_map`, but `map` is a `MapAccessWithFds` + /// instead of a `MapAccess`. + fn visit_map<A: MapAccessWithFds<'de>>(self, map: A) -> Result<Self::Value, A::Error> { + map.invite(VisitorDefaults(PhantomData)) + } + + /// Like `Visitor::visit_enum`, but `data` is an + /// `EnumAccessWithFds` instead of an `EnumAccess`. + fn visit_enum<A: EnumAccessWithFds<'de>>(self, data: A) -> Result<Self::Value, A::Error> { + data.invite(VisitorDefaults(PhantomData)) + } +} + +impl<'de, 'fds, V, F> Visitor<'de> for WithFds<'fds, V, F> +where + V: VisitorWithFds<'de>, + F: Iterator<Item = Fd>, +{ + type Value = V::Value; + + fn expecting(&self, f: &mut Formatter) -> fmt::Result { + self.inner.expecting(f) + } + + fn visit_seq<A: SeqAccess<'de>>(self, data: A) -> Result<Self::Value, A::Error> { + self.inner.visit_seq(WithFds { + inner: data, + fds: self.fds, + }) + } + + fn visit_enum<A: EnumAccess<'de>>(self, data: A) -> Result<Self::Value, A::Error> { + self.inner.visit_enum(WithFds { + inner: data, + fds: self.fds, + }) + } +} + +macro_rules! deserialize_impl { + ($type:ty) => { + impl<'de> DeserializeWithFds<'de> for $type { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: DeserializerWithFds<'de>, + { + deserializer.invite_deserialize() + } + } + }; +} + +macro_rules! fd_impl { + ($type:ty) => { + impl<'de> DeserializeWithFds<'de> for $type { + fn deserialize<D: DeserializerWithFds<'de>>(deserializer: D) -> Result<Self, D::Error> { + deserializer.deserialize_fd().map(|x| x.specialize()) + } + } + }; +} + +deserialize_impl!(()); + +deserialize_impl!(u8); +deserialize_impl!(u16); +deserialize_impl!(u32); +deserialize_impl!(u64); +deserialize_impl!(usize); + +deserialize_impl!(String); +deserialize_impl!(std::path::PathBuf); + +fd_impl!(std::fs::File); +fd_impl!(std::net::TcpListener); +fd_impl!(std::net::TcpStream); +fd_impl!(std::net::UdpSocket); +fd_impl!(std::os::unix::net::UnixDatagram); +fd_impl!(std::os::unix::net::UnixListener); +fd_impl!(std::os::unix::net::UnixStream); +fd_impl!(sys_util::net::UnixSeqpacket); + +impl<'de, T: DeserializeWithFds<'de>> DeserializeWithFds<'de> for Option<T> { + fn deserialize<D: DeserializerWithFds<'de>>(deserializer: D) -> Result<Self, D::Error> { + struct Visitor<T>(PhantomData<T>); + + impl<'de, T: DeserializeWithFds<'de>> VisitorWithFds<'de> for Visitor<T> { + type Value = Option<T>; + + fn expecting(&self, f: &mut Formatter) -> fmt::Result { + write!(f, "option") + } + + fn visit_none<E: Error>(self) -> Result<Self::Value, E> { + Ok(None) + } + + fn visit_some<D>(self, deserializer: D) -> Result<Self::Value, D::Error> + where + D: DeserializerWithFds<'de>, + { + T::deserialize(deserializer).map(Some) + } + } + + deserializer.deserialize_option(Visitor(PhantomData)) + } +} + +impl<'de, T: DeserializeWithFds<'de>> DeserializeWithFds<'de> for Vec<T> { + fn deserialize<D: DeserializerWithFds<'de>>(deserializer: D) -> Result<Self, D::Error> { + struct Visitor<T>(PhantomData<T>); + + impl<'de, T: DeserializeWithFds<'de>> VisitorWithFds<'de> for Visitor<T> { + type Value = Vec<T>; + + fn expecting(&self, f: &mut Formatter) -> fmt::Result { + write!(f, "a sequence") + } + + fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error> + where + A: SeqAccessWithFds<'de>, + { + let mut values = Vec::with_capacity(min(seq.size_hint().unwrap_or(0), 4096)); + + while let Some(value) = seq.next_element()? { + values.push(value); + } + + Ok(values) + } + } + + deserializer.deserialize_seq(Visitor(PhantomData)) + } +} + +impl<'de, K, V> DeserializeWithFds<'de> for BTreeMap<K, V> +where + K: DeserializeWithFds<'de> + Ord, + V: DeserializeWithFds<'de>, +{ + fn deserialize<D: DeserializerWithFds<'de>>(deserializer: D) -> Result<Self, D::Error> { + struct Visitor<K, V>(PhantomData<(K, V)>); + + impl<'de, K, V> VisitorWithFds<'de> for Visitor<K, V> + where + K: DeserializeWithFds<'de> + Ord, + V: DeserializeWithFds<'de>, + { + type Value = BTreeMap<K, V>; + + fn expecting(&self, f: &mut Formatter) -> fmt::Result { + write!(f, "a map") + } + + fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error> + where + A: MapAccessWithFds<'de>, + { + let mut values = BTreeMap::new(); + + while let Some((key, value)) = map.next_entry()? { + values.insert(key, value); + } + + Ok(values) + } + } + + deserializer.deserialize_map(Visitor(PhantomData)) } } diff --git a/msg_socket2/src/error.rs b/msg_socket2/src/error.rs index 2daa450..3aa0dd5 100644 --- a/msg_socket2/src/error.rs +++ b/msg_socket2/src/error.rs @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// Copyright 2020, Alyssa Ross + use std::fmt::{self, Display, Formatter}; #[derive(Debug)] diff --git a/msg_socket2/src/fd.rs b/msg_socket2/src/fd.rs new file mode 100644 index 0000000..648be3e --- /dev/null +++ b/msg_socket2/src/fd.rs @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// Copyright 2020, Alyssa Ross + +use libc::close; +use std::mem::forget; +use std::os::unix::prelude::*; + +/// A type representing ownership of a file descriptor. +pub struct Fd(RawFd); + +impl Fd { + /// Construct an owned `Fd` from a raw file descriptor. + /// + /// This function is unsafe because `Fd` must be the sole owner of + /// the file descriptor, so that it can be closed when the `Fd` is + /// dropped. + pub unsafe fn new(fd: RawFd) -> Self { + Self(fd) + } + + /// Converts this `Fd` into a different implementation of + /// `FromRawFd` containing the same file descriptor. + /// + /// No checks that the file descriptor is of the appropriate type + /// are performed. The file descriptor will remain open. + pub fn specialize<T: FromRawFd>(self) -> T { + let fd = self.into_raw_fd(); + + // Safe because we transfer ownership of the file descriptor. + unsafe { T::from_raw_fd(fd) } + } +} + +impl IntoRawFd for Fd { + fn into_raw_fd(self) -> RawFd { + let fd = self.0; + forget(self); + fd + } +} + +impl AsRawFd for Fd { + fn as_raw_fd(&self) -> RawFd { + self.0 + } +} + +impl FromRawFd for Fd { + unsafe fn from_raw_fd(fd: RawFd) -> Self { + Self(fd) + } +} + +impl Drop for Fd { + fn drop(&mut self) { + // Safe because we have sole ownership of fd. + unsafe { close(self.0) }; + } +} diff --git a/msg_socket2/src/lib.rs b/msg_socket2/src/lib.rs index 9bb2526..00500bb 100644 --- a/msg_socket2/src/lib.rs +++ b/msg_socket2/src/lib.rs @@ -1,36 +1,39 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 // Copyright 2020, Alyssa Ross -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// * Neither the name of the <organization> nor the -// names of its contributors may be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY -// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -mod de; +//! A library for sending messages over Unix domain sockets, including +//! file descriptors. +//! +//! The serialization and deserialization interface is a wrapper on +//! top of bincode and serde. `Serializer` and `Deserializer` are +//! very large interfaces, so they have so far only been implemented +//! on-demand. But, implementing other methods as required should be +//! extremely straightforward to do based on the methods that have +//! already been implemented. +//! +//! In addition to serialization and deserialization, the library +//! provides a `Socket` type. This is a wrapper around a Unix +//! SOCK_SEQPACKET socket that automatically serializes outgoing +//! messages, and deserializes incoming ones. This might be changed +//! to `UnixStream`, to remove the dependency on `sys_util`. + +// TODO: document macros. + +pub mod de; mod error; +mod fd; pub mod ser; mod socket; pub(crate) use ser::FdSerializerImpl; -pub use de::{DeserializeWithFds, DeserializerWithFds}; +pub use de::{DeserializeWithFds, Deserializer, DeserializerWithFds}; pub use error::Error; -pub use ser::{FdSerializer, Serialize, SerializeWithFds, Serializer}; +use fd::Fd; +pub use msg_socket2_derive::{DeserializeWithFds, SerializeWithFds}; +pub use ser::{FdSerializer, SerializeWithFds, Serializer}; pub use socket::Socket; + +// Don't use ser and de re-exports, because they import from +// serde::ser and serde::de, so won't pick up derives. +pub use serde::{Deserialize, Serialize}; diff --git a/msg_socket2/src/ser.rs b/msg_socket2/src/ser.rs index e2b9900..07ead80 100644 --- a/msg_socket2/src/ser.rs +++ b/msg_socket2/src/ser.rs @@ -1,45 +1,22 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 // Copyright 2020, Alyssa Ross -// All rights reserved. // -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// * Neither the name of the <organization> nor the -// names of its contributors may be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY -// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Portions Copyright Erick Tryzelaar and David Tolnay, +// Portions Copyright Erick Tryzelaar and David Tolnay. // Licensed under either of Apache License, Version 2.0 // or MIT license at your option. //! Data structure serialization framework for Unix domain sockets. //! -//! Much like serde::ser, except sending file descriptors is also +//! Much like `serde::ser`, except sending file descriptors is also //! supported. -use serde::ser::*; use std::collections::BTreeMap; use std::fmt::{self, Display, Formatter}; use std::os::unix::prelude::*; pub use serde::ser::{ - Serialize, SerializeSeq, SerializeStruct, SerializeStructVariant, SerializeTupleStruct, - SerializeTupleVariant, Serializer, + Error, Serialize, SerializeMap, SerializeSeq, SerializeStruct, SerializeStructVariant, + SerializeTupleStruct, SerializeTupleVariant, Serializer, StdError, }; #[derive(Debug)] @@ -64,15 +41,21 @@ pub(crate) struct Composite<'ser, S> { serializer: &'ser mut S, } -/// Returned from `SerializerWithFds::serialize_seq`. +/// Like `SerializeSeq`, but accepts file descriptors as well as data. pub trait SerializeSeqFds { + /// Like `SerializeSeq::Ok`. type Ok; + + /// Like `SerializeSeq::Error`. type Error: Error; + /// Like `SerializeSeq::serialize_element`, but `value` is a + /// `SerializeWithFds` instead of a `Serialize`. fn serialize_element<T>(&mut self, value: &T) -> Result<(), Self::Error> where T: SerializeWithFds + ?Sized; + /// Like `SerializeSeq::end`. fn end(self) -> Result<Self::Ok, Self::Error>; } @@ -93,15 +76,21 @@ impl<'ser, 'fds> SerializeSeqFds for Composite<'ser, FdSerializerImpl<'fds>> { } } -/// Returned from `SerializerWithFds::serialize_tuple_struct`. +/// Like `SerializeTupleStruct`, but accepts file descriptors as well as data. pub trait SerializeTupleStructFds { + /// Like `SerializeTupleStruct::Ok`. type Ok; + + /// Like `SerializeTupleStruct::Error`. type Error: Error; + /// Like `SerializeTupleStruct::serialize_field`, but `value` is a + /// `SerializeWithFds` instead of a `Serialize`. fn serialize_field<T>(&mut self, value: &T) -> Result<(), Self::Error> where T: SerializeWithFds + ?Sized; + /// Like `SerializeTupleStruct::end`. fn end(self) -> Result<Self::Ok, Self::Error>; } @@ -122,15 +111,22 @@ impl<'ser, 'fds> SerializeTupleStructFds for Composite<'ser, FdSerializerImpl<'f } } -/// Returned from `SerializerWithFds::serialize_tuple_variant`. +/// Like `SerializeTupleVariant`, but accepts file descriptors as well +/// as data. pub trait SerializeTupleVariantFds { + /// Like `SerializeTupleVariant::Ok`. type Ok; + + /// Like `SerializeTupleVariant::Error`. type Error: Error; + /// Like `SerializeTupleVariant::serialize_field`, but `value` is + /// a `SerializeWithFds` instead of a `Serialize`. fn serialize_field<T>(&mut self, value: &T) -> Result<(), Self::Error> where T: SerializeWithFds + ?Sized; + /// Like `SerializeTupleVariant::end`. fn end(self) -> Result<Self::Ok, Self::Error>; } @@ -151,17 +147,24 @@ impl<'ser, 'fds> SerializeTupleVariantFds for Composite<'ser, FdSerializerImpl<' } } -/// Returned from `SerializerWithFds::serialize_map`. +/// Like `SerializeMap`, but provides file descriptors as well as data. pub trait SerializeMapFds { + /// Like `SerializeMap::Ok`. type Ok; + + /// Like `SerializeMap::Error`. type Error: Error; + /// Like `SerializeMap::serialize_key`, but `key` is a `SerializeWithFds` instead of a `Serialize`. fn serialize_key<T: SerializeWithFds + ?Sized>(&mut self, key: &T) -> Result<(), Self::Error>; + /// Like `SerializeMap::serialize_value`, but `value` is a `SerializeWithFds` instead of a `Serialize`. fn serialize_value<T>(&mut self, value: &T) -> Result<(), Self::Error> where T: SerializeWithFds + ?Sized; + /// Like `SerializeMap::serialize_key`, but `key` and `value` are + /// `SerializeWithFds` instead of `Serialize`. fn serialize_entry<K: SerializeWithFds + ?Sized, V: SerializeWithFds + ?Sized>( &mut self, key: &K, @@ -171,6 +174,7 @@ pub trait SerializeMapFds { self.serialize_value(value) } + /// Like `SerializeMap::end`. fn end(self) -> Result<Self::Ok, Self::Error>; } @@ -196,20 +200,28 @@ impl<'ser, 'fds> SerializeMapFds for Composite<'ser, FdSerializerImpl<'fds>> { } } -/// Returned from `SerializerWithFds::serialize_struct`. +/// Like `SerializeStruct`, but provides file descriptors as well as +/// data. pub trait SerializeStructFds { + /// Like `SerializeStruct::Ok`. type Ok; + + /// Like `SerializeStruct::Error`. type Error: Error; + /// Like `SerializeStruct::serialize_field`, but `value` is a + /// `SerializeWithFds` instead of a `Serialize`. fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error> where T: SerializeWithFds + ?Sized; + /// Like `SerializeStruct::skip_field`. fn skip_field(&mut self, key: &'static str) -> Result<(), Self::Error> { let _ = key; Ok(()) } + /// Like `SerializeStruct::end`. fn end(self) -> Result<Self::Ok, Self::Error>; } @@ -230,20 +242,28 @@ impl<'ser, 'fds> SerializeStructFds for Composite<'ser, FdSerializerImpl<'fds>> } } -/// Returned from `SerializerWithFds::serialize_struct_variant`. +/// Like `SerializeStructVariant`, but provides file descriptors as +/// well as data. pub trait SerializeStructVariantFds { + /// Like `SerializeStructVariant::Ok`. type Ok; + + /// Like `SerializeStructVariant::Error`. type Error: Error; + /// Like `SerializeStructVariant::serialize_field`, but `key` and + /// `value` are `SerializeWithFds` instead of `Serialize`. fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error> where T: SerializeWithFds + ?Sized; + /// Like `SerializeStructVariant::skip_field`. fn skip_field(&mut self, key: &'static str) -> Result<(), Self::Error> { let _ = key; Ok(()) } + /// Like `SerializeStructVariant::end`. fn end(self) -> Result<Self::Ok, Self::Error>; } @@ -264,28 +284,54 @@ impl<'ser, 'fds> SerializeStructVariantFds for Composite<'ser, FdSerializerImpl< } } -/// A **data format** that can send file descriptors between Unix processes. +/// Like `Serializer`, but accepts file descriptors instead of data. pub trait FdSerializer: Sized { + /// Like `Serializer::Ok`. type Ok; + + /// Like `Serializer::Error`. type Error: Error; + /// Like `Serializer::SerializeSeq`, but serializes + /// `SerializeWithFds` instead of `Serialize`. type SerializeSeqFds: SerializeSeqFds<Ok = Self::Ok, Error = Self::Error>; + + /// Like `Serializer::SerializeTupleStruct`, but serializes + /// `SerializeWithFds` instead of `Serialize`. type SerializeTupleStructFds: SerializeTupleStructFds<Ok = Self::Ok, Error = Self::Error>; + + /// Like `Serializer::SerializeTupleVariant`, but serializes + /// `SerializeWithFds` instead of `Serialize`. type SerializeTupleVariantFds: SerializeTupleVariantFds<Ok = Self::Ok, Error = Self::Error>; + + /// Like `Serializer::SerializeMap`, but serializes + /// `SerializeWithFds` instead of `Serialize`. type SerializeMapFds: SerializeMapFds<Ok = Self::Ok, Error = Self::Error>; + + /// Like `Serializer::SerializeStruct`, but serializes + /// `SerializeWithFds` instead of `Serialize`. type SerializeStructFds: SerializeStructFds<Ok = Self::Ok, Error = Self::Error>; + + /// Like `Serializer::SerializeStructVariant`, but serializes + /// `SerializeWithFds` instead of `Serialize`. type SerializeStructVariantFds: SerializeStructVariantFds<Ok = Self::Ok, Error = Self::Error>; + /// Serialize a file descriptor. fn serialize_raw_fd(self, value: RawFd) -> Result<Self::Ok, Self::Error>; + /// Like `Serializer::serialize_none`. fn serialize_none(self) -> Result<Self::Ok, Self::Error>; + /// Like `Serializer::serialize_some`, but `value` is a + /// `SerializeWithFds` instead of a `Serialize`. fn serialize_some<T>(self, value: &T) -> Result<Self::Ok, Self::Error> where T: SerializeWithFds + ?Sized; + /// Like `Serializer::serialize_unit`. fn serialize_unit(self) -> Result<Self::Ok, Self::Error>; + /// Like `Serializer::serialize_unit_variant`. fn serialize_unit_variant( self, name: &'static str, @@ -293,14 +339,23 @@ pub trait FdSerializer: Sized { variant: &'static str, ) -> Result<Self::Ok, Self::Error>; + /// Like `Serializer::serialize_seq`, but returns a + /// `SerializeSeqFds`, which serializes file descriptors as well + /// as data. fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeqFds, Self::Error>; + /// Like `Serializer::serialize_tuple_struct`, but returns a + /// `SerializeTupleStructFds`, which serializes file descriptors as well + /// as data. fn serialize_tuple_struct( self, name: &'static str, len: usize, ) -> Result<Self::SerializeTupleStructFds, Self::Error>; + /// Like `Serializer::serialize_tuple_variant`, but returns a + /// `SerializeTupleVariantFds`, which serializes file descriptors + /// as well as data. fn serialize_tuple_variant( self, name: &'static str, @@ -309,14 +364,23 @@ pub trait FdSerializer: Sized { len: usize, ) -> Result<Self::SerializeTupleVariantFds, Self::Error>; + /// Like `Serializer::serialize_map`, but returns a + /// `SerializeMapFds`, which serializes file descriptors as well + /// as data. fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMapFds, Self::Error>; + /// Like `Serializer::serialize_struct`, but returns a + /// `SerializeStructFds`, which serializes file descriptors as + /// well as data. fn serialize_struct( self, name: &'static str, len: usize, ) -> Result<Self::SerializeStructFds, Self::Error>; + /// Like `Serializer::serialize_struct_variant`, but returns a + /// `SerializeStructVariantFds`, which serializes file descriptors + /// as well as data. fn serialize_struct_variant( self, name: &'static str, @@ -416,10 +480,16 @@ impl<'ser, 'fds> FdSerializer for &'ser mut FdSerializerImpl<'fds> { } } -/// A **data structure** that can be sent over a Unix domain socket. +/// Like `Serialize`, but additionally provides the `serialize_fds` method. pub trait SerializeWithFds { - fn serialize<Ser: Serializer>(&self, serializer: Ser) -> Result<Ser::Ok, Ser::Error>; - fn serialize_fds<Ser: FdSerializer>(&self, serializer: Ser) -> Result<Ser::Ok, Ser::Error>; + /// Like `Serialize::serialize`. + fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error>; + + /// Serialize all file descriptors associated with this value, recursively. + /// + /// In most cases, the implementation should largely mirror the + /// `serialize` implementation. + fn serialize_fds<S: FdSerializer>(&self, serializer: S) -> Result<S::Ok, S::Error>; } macro_rules! serialize_impl { @@ -489,6 +559,7 @@ fd_impl!(std::os::unix::net::UnixStream); fd_impl!(std::process::ChildStderr); fd_impl!(std::process::ChildStdin); fd_impl!(std::process::ChildStdout); +fd_impl!(sys_util::net::UnixSeqpacket); impl<T: SerializeWithFds> SerializeWithFds for Option<T> { fn serialize<Ser: Serializer>(&self, serializer: Ser) -> Result<Ser::Ok, Ser::Error> { diff --git a/msg_socket2/src/socket.rs b/msg_socket2/src/socket.rs index b836365..bd1bc00 100644 --- a/msg_socket2/src/socket.rs +++ b/msg_socket2/src/socket.rs @@ -1,11 +1,16 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +// Copyright 2020, Alyssa Ross + use bincode::{DefaultOptions, Deserializer, Serializer}; use std::io::IoSlice; use std::marker::PhantomData; use std::os::unix::prelude::*; use sys_util::{net::UnixSeqpacket, ScmSocket}; -use crate::{DeserializeWithFds, DeserializerWithFds, Error, FdSerializerImpl, SerializeWithFds}; +use crate::{de, DeserializeWithFds, Error, Fd, FdSerializerImpl, SerializeWithFds}; +/// A Unix **SOCK_SEQPACKET** socket that can send and receive values +/// consisting of binary data and file descriptors. #[derive(Debug)] pub struct Socket<Send, Recv> { sock: UnixSeqpacket, @@ -39,11 +44,16 @@ impl<Send: SerializeWithFds, Recv> Socket<Send, Recv> { impl<Send, Recv: for<'de> DeserializeWithFds<'de>> Socket<Send, Recv> { pub fn recv(&self) -> Result<Recv, Error> { - let (bytes, fds) = self.sock.recv_as_vec_with_fds()?; - let mut fds_iter = fds.into_iter(); + let (bytes, raw_fds) = self.sock.recv_as_vec_with_fds()?; + + // Safe because we just received ownership of the fds. + let mut fds = raw_fds.into_iter().map(|fd| unsafe { Fd::new(fd) }); let mut deserializer = Deserializer::from_slice(&bytes, DefaultOptions::new()); - let deserializer_with_fds = DeserializerWithFds::new(&mut fds_iter, &mut deserializer); + let deserializer_with_fds = de::WithFds { + inner: &mut deserializer, + fds: &mut fds, + }; Ok(Recv::deserialize(deserializer_with_fds)?) } diff --git a/msg_socket2/tests/round_trip.rs b/msg_socket2/tests/round_trip.rs index 1bb6636..a89f414 100644 --- a/msg_socket2/tests/round_trip.rs +++ b/msg_socket2/tests/round_trip.rs @@ -1,20 +1,18 @@ -use std::os::unix::prelude::*; - use std::fmt::{self, Formatter}; -use std::marker::PhantomData; +use std::fs::File; use msg_socket2::{ + de::{SeqAccessWithFds, VisitorWithFds}, ser::{ - SerializeAdapter, SerializeRawFd, SerializeStruct, SerializeStructFds, - SerializeTupleStruct, SerializeTupleStructFds, + SerializeAdapter, SerializeStruct, SerializeStructFds, SerializeTupleStruct, + SerializeTupleStructFds, }, DeserializeWithFds, DeserializerWithFds, FdSerializer, SerializeWithFds, Serializer, Socket, }; -use serde::de::{Deserializer, SeqAccess}; use sys_util::net::UnixSeqpacket; #[derive(Debug)] -struct Inner(RawFd, u16); +struct Inner(File, u16); impl SerializeWithFds for Inner { fn serialize<Ser: Serializer>(&self, serializer: Ser) -> Result<Ser::Ok, Ser::Error> { @@ -25,14 +23,43 @@ impl SerializeWithFds for Inner { fn serialize_fds<Ser: FdSerializer>(&self, serializer: Ser) -> Result<Ser::Ok, Ser::Error> { let mut state = serializer.serialize_tuple_struct("Inner", 1)?; - state.serialize_field(&SerializeRawFd::new(&self.0))?; + state.serialize_field(&self.0)?; state.end() } } +impl<'de> DeserializeWithFds<'de> for Inner { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: DeserializerWithFds<'de>, + { + struct Visitor; + + impl<'de> VisitorWithFds<'de> for Visitor { + type Value = Inner; + + fn expecting(&self, f: &mut Formatter) -> fmt::Result { + write!(f, "struct Inner") + } + + fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error> + where + A: SeqAccessWithFds<'de>, + { + Ok(Inner( + seq.next_element()?.unwrap(), + seq.next_element()?.unwrap(), + )) + } + } + + deserializer.deserialize_tuple_struct("Inner", 2, Visitor) + } +} + #[derive(Debug)] struct Test { - fd: RawFd, + fd: File, inner: Inner, } @@ -46,44 +73,38 @@ impl SerializeWithFds for Test { fn serialize_fds<Ser: FdSerializer>(&self, serializer: Ser) -> Result<Ser::Ok, Ser::Error> { let mut state = serializer.serialize_struct("Test", 2)?; - state.serialize_field("fd", &SerializeRawFd::new(&self.fd))?; + state.serialize_field("fd", &self.fd)?; state.serialize_field("inner", &self.inner)?; state.end() } } impl<'de> DeserializeWithFds<'de> for Test { - fn deserialize<I, De>(deserializer: DeserializerWithFds<I, De>) -> Result<Self, De::Error> + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where - I: Iterator<Item = RawFd>, - De: Deserializer<'de>, + D: DeserializerWithFds<'de>, { - struct Visitor<'iter, 'de, Iter>(&'iter mut Iter, PhantomData<&'de ()>); + struct Visitor; - impl<'iter, 'de, Iter: Iterator<Item = RawFd>> serde::de::Visitor<'de> - for Visitor<'iter, 'de, Iter> - { + impl<'de> VisitorWithFds<'de> for Visitor { type Value = Test; fn expecting(&self, f: &mut Formatter) -> fmt::Result { write!(f, "struct Test") } - fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> { + fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error> + where + A: SeqAccessWithFds<'de>, + { Ok(Test { - fd: self.0.next().unwrap(), - inner: Inner(self.0.next().unwrap(), seq.next_element()?.unwrap()), + fd: seq.next_element()?.unwrap(), + inner: seq.next_element()?.unwrap(), }) } } - let DeserializerWithFds { - mut fds, - deserializer, - } = deserializer; - - let visitor = Visitor(&mut fds, PhantomData); - deserializer.deserialize_struct("Test", &["fd", "inner"], visitor) + deserializer.deserialize_struct("Test", &["fd", "inner"], Visitor) } } @@ -94,8 +115,8 @@ fn round_trip() { let s2: Socket<(), Test> = Socket::new(f2); s1.send(Test { - fd: 0, - inner: Inner(1, 0xACAB), + fd: File::open("/dev/null").unwrap(), + inner: Inner(File::open("/dev/null").unwrap(), 0xACAB), }) .unwrap(); diff --git a/vm_control/Cargo.toml b/vm_control/Cargo.toml index 3a6ec3f..8bde359 100644 --- a/vm_control/Cargo.toml +++ b/vm_control/Cargo.toml @@ -10,6 +10,5 @@ kvm = { path = "../kvm" } libc = "*" msg_socket = { path = "../msg_socket" } msg_socket2 = { path = "../msg_socket2" } -msg_socket2_derive = { path = "../msg_socket2/derive" } resources = { path = "../resources" } sys_util = { path = "../sys_util" } diff --git a/vm_control/src/lib.rs b/vm_control/src/lib.rs index 3ec6be7..99fae7e 100644 --- a/vm_control/src/lib.rs +++ b/vm_control/src/lib.rs @@ -20,22 +20,22 @@ use libc::{EINVAL, EIO, ENODEV}; use kvm::{IrqRoute, IrqSource, Vm}; use msg_socket::{MsgError, MsgOnSocket, MsgResult, MsgSocket, UnixSeqpacketExt}; -use msg_socket2_derive::SerializeWithFds; +use msg_socket2::{DeserializeWithFds, SerializeWithFds}; use resources::{Alloc, GpuMemoryDesc, MmioType, SystemAllocator}; use sys_util::net::UnixSeqpacket; use sys_util::{error, Error as SysError, EventFd, GuestAddress, MemoryMapping, MmapError, Result}; /// A data structure that either owns or borrows a file descriptor. -#[derive(SerializeWithFds, Debug)] +#[derive(Debug, DeserializeWithFds, SerializeWithFds)] #[msg_socket2(strategy = "AsRawFd")] -pub enum MaybeOwnedFd<Owned: AsRawFd> { +pub enum MaybeOwnedFd<Owned: AsRawFd + FromRawFd> { /// Owned by this enum variant, and will be destructed automatically if not moved out. Owned(Owned), /// A file descriptor borrwed by this enum. Borrowed(RawFd), } -impl<Owned: AsRawFd> MaybeOwnedFd<Owned> { +impl<Owned: AsRawFd + FromRawFd> MaybeOwnedFd<Owned> { pub fn new_borrowed(fd: &dyn AsRawFd) -> Self { Self::Borrowed(fd.as_raw_fd()) } @@ -48,7 +48,7 @@ impl<Owned: AsRawFd> MaybeOwnedFd<Owned> { } } -impl<Owned: AsRawFd> AsRawFd for MaybeOwnedFd<Owned> { +impl<Owned: AsRawFd + FromRawFd> AsRawFd for MaybeOwnedFd<Owned> { fn as_raw_fd(&self) -> RawFd { match self { MaybeOwnedFd::Owned(f) => f.as_raw_fd(), @@ -57,6 +57,12 @@ impl<Owned: AsRawFd> AsRawFd for MaybeOwnedFd<Owned> { } } +impl<Owned: AsRawFd + FromRawFd> FromRawFd for MaybeOwnedFd<Owned> { + unsafe fn from_raw_fd(fd: RawFd) -> Self { + Self::Owned(Owned::from_raw_fd(fd)) + } +} + // When sent, it could be owned or borrowed. On the receiver end, it always owned. impl<Owned: AsRawFd + FromRawFd + MsgOnSocket> MsgOnSocket for MaybeOwnedFd<Owned> { fn uses_fd() -> bool { |