1#![allow(clippy::bad_bit_mask)] use crate::{
10 object_get_info_single, object_get_property, object_set_property, ok, sys, AsHandleRef, Handle,
11 HandleBased, HandleRef, ObjectQuery, Peered, Property, PropertyQuery, Status, Topic,
12};
13use bitflags::bitflags;
14use std::mem::MaybeUninit;
15
16#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
21#[repr(transparent)]
22pub struct Socket(Handle);
23impl_handle_based!(Socket);
24impl Peered for Socket {}
25
26bitflags! {
27 #[repr(transparent)]
28 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
29 pub struct SocketOpts: u32 {
30 const STREAM = 0 << 0;
31 const DATAGRAM = 1 << 0;
32 }
33}
34
35bitflags! {
36 #[repr(transparent)]
37 #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
38 pub struct SocketReadOpts: u32 {
39 const PEEK = 1 << 3;
40 }
41}
42
43bitflags! {
44 #[repr(transparent)]
45 #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
46 pub struct SocketWriteOpts: u32 {
47 }
48}
49
50#[derive(Debug, PartialEq, Eq, Clone, Copy)]
53pub enum SocketWriteDisposition {
54 Enabled,
56 Disabled,
58}
59
60impl SocketWriteDisposition {
61 pub fn from_raw(raw: u32) -> Result<Option<SocketWriteDisposition>, Status> {
64 match raw {
65 0 => Ok(None),
66 sys::ZX_SOCKET_DISPOSITION_WRITE_ENABLED => Ok(Some(SocketWriteDisposition::Enabled)),
67 sys::ZX_SOCKET_DISPOSITION_WRITE_DISABLED => Ok(Some(SocketWriteDisposition::Disabled)),
68 _ => Err(Status::INVALID_ARGS),
69 }
70 }
71}
72
73impl From<SocketWriteDisposition> for u32 {
74 fn from(disposition: SocketWriteDisposition) -> Self {
75 match disposition {
76 SocketWriteDisposition::Enabled => sys::ZX_SOCKET_DISPOSITION_WRITE_ENABLED,
77 SocketWriteDisposition::Disabled => sys::ZX_SOCKET_DISPOSITION_WRITE_DISABLED,
78 }
79 }
80}
81
82#[repr(C)]
83#[derive(Debug, Copy, Clone, Eq, PartialEq)]
84pub struct SocketInfo {
85 pub options: SocketOpts,
86 pub rx_buf_max: usize,
87 pub rx_buf_size: usize,
88 pub rx_buf_available: usize,
89 pub tx_buf_max: usize,
90 pub tx_buf_size: usize,
91}
92
93impl Default for SocketInfo {
94 fn default() -> SocketInfo {
95 SocketInfo {
96 options: SocketOpts::STREAM,
97 rx_buf_max: 0,
98 rx_buf_size: 0,
99 rx_buf_available: 0,
100 tx_buf_max: 0,
101 tx_buf_size: 0,
102 }
103 }
104}
105
106impl From<sys::zx_info_socket_t> for SocketInfo {
107 fn from(socket: sys::zx_info_socket_t) -> SocketInfo {
108 SocketInfo {
109 options: SocketOpts::from_bits_truncate(socket.options),
110 rx_buf_max: socket.rx_buf_max,
111 rx_buf_size: socket.rx_buf_size,
112 rx_buf_available: socket.rx_buf_available,
113 tx_buf_max: socket.tx_buf_max,
114 tx_buf_size: socket.tx_buf_size,
115 }
116 }
117}
118
119struct SocketInfoQuery;
121unsafe impl ObjectQuery for SocketInfoQuery {
122 const TOPIC: Topic = Topic::SOCKET;
123 type InfoTy = sys::zx_info_socket_t;
124}
125
126impl Socket {
127 pub fn create_stream() -> (Socket, Socket) {
138 Self::try_create(SocketOpts::STREAM).expect("socket creation can't fail with valid options")
139 }
140
141 pub fn create_datagram() -> (Socket, Socket) {
152 Self::try_create(SocketOpts::DATAGRAM)
153 .expect("socket creation can't fail with valid options")
154 }
155
156 fn try_create(sock_opts: SocketOpts) -> Result<(Socket, Socket), Status> {
157 unsafe {
158 let mut out0 = 0;
159 let mut out1 = 0;
160 let status = sys::zx_socket_create(sock_opts.bits(), &mut out0, &mut out1);
161 ok(status)?;
162 Ok((Self::from(Handle::from_raw(out0)), Self::from(Handle::from_raw(out1))))
163 }
164 }
165
166 pub fn write(&self, bytes: &[u8]) -> Result<usize, Status> {
173 self.write_opts(bytes, SocketWriteOpts::default())
174 }
175
176 pub unsafe fn write_raw(&self, bytes: *const u8, len: usize) -> Result<usize, Status> {
187 unsafe { self.write_raw_opts(bytes, len, SocketWriteOpts::default()) }
189 }
190
191 pub fn write_opts(&self, bytes: &[u8], opts: SocketWriteOpts) -> Result<usize, Status> {
198 unsafe { self.write_raw_opts(bytes.as_ptr(), bytes.len(), opts) }
200 }
201
202 pub unsafe fn write_raw_opts(
213 &self,
214 bytes: *const u8,
215 len: usize,
216 opts: SocketWriteOpts,
217 ) -> Result<usize, Status> {
218 let mut actual = 0;
219 let status = unsafe {
221 sys::zx_socket_write(self.raw_handle(), opts.bits(), bytes, len, &mut actual)
222 };
223 ok(status).map(|()| actual)
224 }
225
226 pub fn read(&self, bytes: &mut [u8]) -> Result<usize, Status> {
232 self.read_opts(bytes, SocketReadOpts::default())
233 }
234
235 pub fn read_opts(&self, bytes: &mut [u8], opts: SocketReadOpts) -> Result<usize, Status> {
241 unsafe { self.read_raw_opts(bytes.as_mut_ptr(), bytes.len(), opts) }
243 }
244
245 pub unsafe fn read_raw(&self, bytes: *mut u8, len: usize) -> Result<usize, Status> {
256 unsafe { self.read_raw_opts(bytes, len, SocketReadOpts::default()) }
258 }
259
260 pub unsafe fn read_raw_opts(
271 &self,
272 bytes: *mut u8,
273 len: usize,
274 opts: SocketReadOpts,
275 ) -> Result<usize, Status> {
276 let mut actual = 0;
277 let status =
279 unsafe { sys::zx_socket_read(self.raw_handle(), opts.bits(), bytes, len, &mut actual) };
280 ok(status).map(|()| actual)
281 }
282
283 pub fn read_uninit<'a>(
285 &self,
286 bytes: &'a mut [MaybeUninit<u8>],
287 ) -> Result<&'a mut [u8], Status> {
288 self.read_uninit_opts(bytes, SocketReadOpts::default())
289 }
290
291 pub fn read_uninit_opts<'a>(
294 &self,
295 bytes: &'a mut [MaybeUninit<u8>],
296 opts: SocketReadOpts,
297 ) -> Result<&'a mut [u8], Status> {
298 let actual =
301 unsafe { self.read_raw_opts(bytes.as_mut_ptr().cast::<u8>(), bytes.len(), opts)? };
302 let (valid, _uninit) = bytes.split_at_mut(actual);
303
304 Ok(unsafe { std::slice::from_raw_parts_mut(valid.as_mut_ptr().cast::<u8>(), valid.len()) })
307 }
308
309 pub fn half_close(&self) -> Result<(), Status> {
314 self.set_disposition(None, Some(SocketWriteDisposition::Disabled))
315 }
316
317 pub fn set_disposition(
322 &self,
323 disposition: Option<SocketWriteDisposition>,
324 disposition_peer: Option<SocketWriteDisposition>,
325 ) -> Result<(), Status> {
326 let status = unsafe {
327 sys::zx_socket_set_disposition(
328 self.raw_handle(),
329 disposition.map(u32::from).unwrap_or(0),
330 disposition_peer.map(u32::from).unwrap_or(0),
331 )
332 };
333 ok(status)
334 }
335
336 pub fn outstanding_read_bytes(&self) -> Result<usize, Status> {
338 Ok(self.info()?.rx_buf_available)
339 }
340
341 pub fn info(&self) -> Result<SocketInfo, Status> {
345 Ok(SocketInfo::from(object_get_info_single::<SocketInfoQuery>(self.as_handle_ref())?))
346 }
347}
348
349unsafe_handle_properties!(object: Socket,
350 props: [
351 {query_ty: SOCKET_RX_THRESHOLD, tag: SocketRxThresholdTag, prop_ty: usize, get:get_rx_threshold, set: set_rx_threshold},
352 {query_ty: SOCKET_TX_THRESHOLD, tag: SocketTxThresholdTag, prop_ty: usize, get:get_tx_threshold, set: set_tx_threshold},
353 ]
354);
355
356#[cfg(test)]
359mod tests {
360 use std::mem::MaybeUninit;
361
362 use super::*;
363
364 fn socket_basic_helper(opts: SocketOpts) {
365 let (s1, s2) = match opts {
366 SocketOpts::STREAM => Socket::create_stream(),
367 SocketOpts::DATAGRAM => Socket::create_datagram(),
368 _ => panic!("unsupported socket options"),
369 };
370
371 assert_eq!(s1.write(b"hello").unwrap(), 5);
373 assert_eq!(s1.write(b"world").unwrap(), 5);
374
375 let mut read_vec = vec![0; 11];
376 if opts == SocketOpts::DATAGRAM {
377 assert_eq!(s2.read(&mut read_vec).unwrap(), 5);
378 assert_eq!(&read_vec[0..5], b"hello");
379
380 assert_eq!(s2.read(&mut read_vec).unwrap(), 5);
381 assert_eq!(&read_vec[0..5], b"world");
382 } else {
383 assert_eq!(s2.read(&mut read_vec).unwrap(), 10);
384 assert_eq!(&read_vec[0..10], b"helloworld");
385 }
386
387 assert_eq!(s2.read(&mut read_vec), Err(Status::SHOULD_WAIT));
389
390 assert!(s1.half_close().is_ok());
392 assert_eq!(s2.write(b"fail"), Err(Status::BAD_STATE));
393 assert_eq!(s1.read(&mut read_vec), Err(Status::BAD_STATE));
394
395 assert_eq!(s2.read(&mut read_vec), Err(Status::SHOULD_WAIT));
397 assert_eq!(s1.write(b"back").unwrap(), 4);
398 assert_eq!(s2.read(&mut read_vec).unwrap(), 4);
399 assert_eq!(&read_vec[0..4], b"back");
400 }
401
402 #[test]
403 fn socket_basic() {
404 socket_basic_helper(SocketOpts::STREAM);
405 socket_basic_helper(SocketOpts::DATAGRAM);
406 }
407
408 #[test]
409 fn socket_info() {
410 let (s1, s2) = Socket::create_stream();
411 let s1info = s1.info().unwrap();
412 assert_eq!(s1info.rx_buf_available, 0);
414 assert_eq!(s1info.rx_buf_size, 0);
415 assert_eq!(s1info.tx_buf_size, 0);
416
417 assert_eq!(s1.write(b"hello").unwrap(), 5);
419
420 let s1info = s1.info().unwrap();
422 let s2info = s2.info().unwrap();
423 assert_eq!(s1info.tx_buf_size, 5);
424 assert_eq!(s1info.rx_buf_size, 0);
425 assert_eq!(s2info.rx_buf_size, 5);
426 assert_eq!(s2info.rx_buf_available, 5);
427 assert_eq!(s2info.tx_buf_size, 0);
428 }
429
430 #[test]
431 fn socket_disposition() {
432 const PAYLOAD: &'static [u8] = b"Hello";
433 let (s1, s2) = Socket::create_stream();
434 assert_eq!(
436 s1.set_disposition(
437 Some(SocketWriteDisposition::Disabled),
438 Some(SocketWriteDisposition::Enabled)
439 ),
440 Ok(())
441 );
442 assert_eq!(s2.write(PAYLOAD), Ok(PAYLOAD.len()));
443 assert_eq!(s1.write(PAYLOAD), Err(Status::BAD_STATE));
444 let mut buf = [0u8; PAYLOAD.len() + 1];
445 assert_eq!(s1.read(&mut buf[..]), Ok(PAYLOAD.len()));
446 assert_eq!(&buf[..PAYLOAD.len()], PAYLOAD);
447 assert_eq!(s1.set_disposition(None, None), Ok(()));
449 assert_eq!(s2.write(PAYLOAD), Ok(PAYLOAD.len()));
450 assert_eq!(s1.write(PAYLOAD), Err(Status::BAD_STATE));
451 }
452
453 #[test]
454 fn read_uninit() {
455 let (s1, s2) = Socket::create_stream();
456 let message = b"hello";
457 assert_eq!(s1.write(&message[..]).unwrap(), 5);
458 let mut recv = [MaybeUninit::<u8>::uninit(); 16];
459 let got = s2.read_uninit(&mut recv[..]).unwrap();
460 assert_eq!(got, &message[..]);
461 }
462}