Skip to main content

zlink_core/connection/
mod.rs

1//! Contains connection related API.
2//!
3//! The [`Connection`] type provides a low-level API for sending and receiving Varlink messages.
4//! For most use cases, you'll want to use the higher-level [`proxy`] and [`service`] attribute
5//! macros instead, which generate type-safe client and server code respectively.
6//!
7//! # Client Usage with `proxy` Macro
8//!
9//! The [`proxy`] macro generates methods on `Connection<S>` for calling remote service methods:
10//!
11//! ```
12//! #[zlink_core::proxy(
13//!     interface = "org.example.Calculator",
14//!     // Not needed in the real code because you'll use `proxy` through `zlink` crate.
15//!     crate = "zlink_core",
16//! )]
17//! trait CalculatorProxy {
18//!     async fn add(&mut self, a: f64, b: f64) -> zlink_core::Result<Result<f64, CalcError>>;
19//! }
20//!
21//! #[derive(Debug, zlink_core::ReplyError)]
22//! #[zlink(
23//!     interface = "org.example.Calculator",
24//!     // Not needed in the real code because you'll use `ReplyError` through `zlink` crate.
25//!     crate = "zlink_core",
26//! )]
27//! enum CalcError {}
28//! ```
29//!
30//! # Server Usage with `service` Macro
31//!
32//! The [`service`] macro generates the [`Service`] trait implementation. See the [`service`] macro
33//! documentation for details and examples.
34//!
35//! # Low-Level API
36//!
37//! For advanced use cases that require more control, the [`Connection`] type provides direct access
38//! to message sending and receiving via methods like [`Connection::send_call`],
39//! [`Connection::receive_reply`], and [`Connection::chain_call`] for pipelining.
40//!
41//! [`proxy`]: macro@crate::proxy
42//! [`service`]: macro@crate::service
43//! [`Service`]: crate::service::Service
44
45#[cfg(feature = "std")]
46mod credentials;
47mod read_connection;
48#[cfg(feature = "std")]
49pub use credentials::Credentials;
50#[cfg(feature = "std")]
51pub use credentials::PassedCredentials;
52pub use read_connection::ReadConnection;
53#[cfg(feature = "std")]
54pub use rustix::{process::Gid, process::Pid, process::Uid};
55pub mod chain;
56pub mod socket;
57#[cfg(test)]
58mod tests;
59mod write_connection;
60use crate::{
61    Call, Result,
62    reply::{self, Reply},
63};
64#[cfg(feature = "std")]
65use alloc::vec;
66pub use chain::Chain;
67use core::{fmt::Debug, sync::atomic::AtomicUsize};
68#[cfg(feature = "std")]
69use socket::FetchPeerCredentials;
70pub use write_connection::WriteConnection;
71
72use serde::{Deserialize, Serialize};
73pub use socket::Socket;
74
75// Type alias for receive methods - std returns FDs, no_std doesn't
76#[cfg(feature = "std")]
77type RecvResult<T> = (T, Vec<std::os::fd::OwnedFd>);
78#[cfg(not(feature = "std"))]
79type RecvResult<T> = T;
80
81/// A connection.
82///
83/// The low-level API to send and receive messages.
84///
85/// Each connection gets a unique identifier when created that can be queried using
86/// [`Connection::id`]. This ID is shared between the read and write halves of the connection. It
87/// can be used to associate the read and write halves of the same connection.
88///
89/// # Cancel safety
90///
91/// All async methods of this type are cancel safe unless explicitly stated otherwise in its
92/// documentation.
93#[derive(Debug)]
94pub struct Connection<S: Socket> {
95    read: ReadConnection<S::ReadHalf>,
96    write: WriteConnection<S::WriteHalf>,
97    #[cfg(feature = "std")]
98    credentials: Option<std::sync::Arc<Credentials>>,
99}
100
101impl<S> Connection<S>
102where
103    S: Socket,
104{
105    /// Create a new connection.
106    pub fn new(socket: S) -> Self {
107        let (read, write) = socket.split();
108        let id = NEXT_ID.fetch_add(1, core::sync::atomic::Ordering::Relaxed);
109        Self {
110            read: ReadConnection::new(read, id),
111            write: WriteConnection::new(write, id),
112            #[cfg(feature = "std")]
113            credentials: None,
114        }
115    }
116
117    /// The reference to the read half of the connection.
118    pub fn read(&self) -> &ReadConnection<S::ReadHalf> {
119        &self.read
120    }
121
122    /// The mutable reference to the read half of the connection.
123    pub fn read_mut(&mut self) -> &mut ReadConnection<S::ReadHalf> {
124        &mut self.read
125    }
126
127    /// The reference to the write half of the connection.
128    pub fn write(&self) -> &WriteConnection<S::WriteHalf> {
129        &self.write
130    }
131
132    /// The mutable reference to the write half of the connection.
133    pub fn write_mut(&mut self) -> &mut WriteConnection<S::WriteHalf> {
134        &mut self.write
135    }
136
137    /// Split the connection into read and write halves.
138    ///
139    /// Note: This consumes any cached credentials. If you need the credentials after splitting,
140    /// call [`Connection::peer_credentials`] before splitting.
141    pub fn split(self) -> (ReadConnection<S::ReadHalf>, WriteConnection<S::WriteHalf>) {
142        (self.read, self.write)
143    }
144
145    /// Join the read and write halves into a connection (the opposite of [`Connection::split`]).
146    pub fn join(read: ReadConnection<S::ReadHalf>, write: WriteConnection<S::WriteHalf>) -> Self {
147        Self {
148            read,
149            write,
150            #[cfg(feature = "std")]
151            credentials: None,
152        }
153    }
154
155    /// Release sent FDs that the read half has confirmed receiving via `recvmsg`.
156    /// See `WriteConnection::held_fds` for details on the macOS kernel issue.
157    #[cfg(all(feature = "std", target_os = "macos"))]
158    fn drain_held_fds(&mut self) {
159        let to_drain = self.read.fd_recvs;
160        for _ in 0..to_drain {
161            self.write.held_fds.pop_front();
162        }
163        self.read.fd_recvs -= to_drain;
164    }
165
166    /// The unique identifier of the connection.
167    pub fn id(&self) -> usize {
168        assert_eq!(self.read.id(), self.write.id());
169        self.read.id()
170    }
171
172    /// Sends a method call.
173    ///
174    /// Convenience wrapper around [`WriteConnection::send_call`].
175    pub async fn send_call<Method>(
176        &mut self,
177        call: &Call<Method>,
178        #[cfg(feature = "std")] fds: Vec<std::os::fd::OwnedFd>,
179    ) -> Result<()>
180    where
181        Method: Serialize + Debug,
182    {
183        #[cfg(feature = "std")]
184        {
185            self.write.send_call(call, fds).await
186        }
187        #[cfg(not(feature = "std"))]
188        {
189            self.write.send_call(call).await
190        }
191    }
192
193    /// Receives a method call reply.
194    ///
195    /// Convenience wrapper around [`ReadConnection::receive_reply`].
196    pub async fn receive_reply<'r, ReplyParams, ReplyError>(
197        &'r mut self,
198    ) -> Result<RecvResult<reply::Result<ReplyParams, ReplyError>>>
199    where
200        ReplyParams: Deserialize<'r> + Debug,
201        ReplyError: Deserialize<'r> + Debug,
202    {
203        self.read.receive_reply().await
204    }
205
206    /// Call a method and receive a reply.
207    ///
208    /// This is a convenience method that combines [`Connection::send_call`] and
209    /// [`Connection::receive_reply`].
210    pub async fn call_method<'r, Method, ReplyParams, ReplyError>(
211        &'r mut self,
212        call: &Call<Method>,
213        #[cfg(feature = "std")] fds: Vec<std::os::fd::OwnedFd>,
214    ) -> Result<RecvResult<reply::Result<ReplyParams, ReplyError>>>
215    where
216        Method: Serialize + Debug,
217        ReplyParams: Deserialize<'r> + Debug,
218        ReplyError: Deserialize<'r> + Debug,
219    {
220        #[cfg(feature = "std")]
221        self.send_call(call, fds).await?;
222        #[cfg(not(feature = "std"))]
223        self.send_call(call).await?;
224
225        self.receive_reply().await
226    }
227
228    /// Receive a method call over the socket.
229    ///
230    /// Convenience wrapper around [`ReadConnection::receive_call`].
231    pub async fn receive_call<'m, Method>(&'m mut self) -> Result<RecvResult<Call<Method>>>
232    where
233        Method: Deserialize<'m> + Debug,
234    {
235        self.read.receive_call().await
236    }
237
238    /// Send a reply over the socket.
239    ///
240    /// Convenience wrapper around [`WriteConnection::send_reply`].
241    pub async fn send_reply<ReplyParams>(
242        &mut self,
243        reply: &Reply<ReplyParams>,
244        #[cfg(feature = "std")] fds: Vec<std::os::fd::OwnedFd>,
245    ) -> Result<()>
246    where
247        ReplyParams: Serialize + Debug,
248    {
249        #[cfg(all(feature = "std", target_os = "macos"))]
250        self.drain_held_fds();
251        #[cfg(feature = "std")]
252        {
253            self.write.send_reply(reply, fds).await
254        }
255        #[cfg(not(feature = "std"))]
256        {
257            self.write.send_reply(reply).await
258        }
259    }
260
261    /// Send an error reply over the socket.
262    ///
263    /// Convenience wrapper around [`WriteConnection::send_error`].
264    pub async fn send_error<ReplyError>(
265        &mut self,
266        error: &ReplyError,
267        #[cfg(feature = "std")] fds: Vec<std::os::fd::OwnedFd>,
268    ) -> Result<()>
269    where
270        ReplyError: Serialize + Debug,
271    {
272        #[cfg(all(feature = "std", target_os = "macos"))]
273        self.drain_held_fds();
274        #[cfg(feature = "std")]
275        {
276            self.write.send_error(error, fds).await
277        }
278        #[cfg(not(feature = "std"))]
279        {
280            self.write.send_error(error).await
281        }
282    }
283
284    /// Enqueue a call to the server.
285    ///
286    /// Convenience wrapper around [`WriteConnection::enqueue_call`].
287    pub fn enqueue_call<Method>(&mut self, method: &Call<Method>) -> Result<()>
288    where
289        Method: Serialize + Debug,
290    {
291        #[cfg(feature = "std")]
292        {
293            self.write.enqueue_call(method, vec![])
294        }
295        #[cfg(not(feature = "std"))]
296        {
297            self.write.enqueue_call(method)
298        }
299    }
300
301    /// Flush the connection.
302    ///
303    /// Convenience wrapper around [`WriteConnection::flush`].
304    pub async fn flush(&mut self) -> Result<()> {
305        self.write.flush().await
306    }
307
308    /// Start a chain of method calls.
309    ///
310    /// This allows batching multiple calls together and sending them in a single write operation.
311    ///
312    /// # Examples
313    ///
314    /// ## Basic Usage with Sequential Access
315    ///
316    /// ```no_run
317    /// use zlink_core::{Connection, Call, reply};
318    /// use serde::{Serialize, Deserialize};
319    /// use serde_prefix_all::prefix_all;
320    /// use futures_util::{pin_mut, stream::StreamExt};
321    ///
322    /// # async fn example() -> zlink_core::Result<()> {
323    /// # let mut conn: Connection<zlink_core::connection::socket::impl_for_doc::Socket> = todo!();
324    ///
325    /// #[prefix_all("org.example.")]
326    /// #[derive(Debug, Serialize, Deserialize)]
327    /// #[serde(tag = "method", content = "parameters")]
328    /// enum Methods {
329    ///     GetUser { id: u32 },
330    ///     GetProject { id: u32 },
331    /// }
332    ///
333    /// #[derive(Debug, Deserialize)]
334    /// struct User { name: String }
335    ///
336    /// #[derive(Debug, Deserialize)]
337    /// struct Project { title: String }
338    ///
339    /// #[derive(Debug, zlink_core::ReplyError)]
340    /// #[zlink(
341    ///     interface = "org.example",
342    ///     // Not needed in the real code because you'll use `ReplyError` through `zlink` crate.
343    ///     crate = "zlink_core",
344    /// )]
345    /// enum ApiError {
346    ///     UserNotFound { code: i32 },
347    ///     ProjectNotFound { code: i32 },
348    /// }
349    ///
350    /// let get_user = Call::new(Methods::GetUser { id: 1 });
351    /// let get_project = Call::new(Methods::GetProject { id: 2 });
352    ///
353    /// // Chain calls and send them in a batch
354    /// # #[cfg(feature = "std")]
355    /// let replies = conn
356    ///     .chain_call::<Methods>(&get_user, vec![])?
357    ///     .append(&get_project, vec![])?
358    ///     .send::<User, ApiError>().await?;
359    /// # #[cfg(not(feature = "std"))]
360    /// # let replies = conn
361    /// #     .chain_call::<Methods>(&get_user)?
362    /// #     .append(&get_project)?
363    /// #     .send::<User, ApiError>().await?;
364    /// pin_mut!(replies);
365    ///
366    /// // Access replies sequentially.
367    /// # #[cfg(feature = "std")]
368    /// # {
369    /// let (user_reply, _fds) = replies.next().await.unwrap()?;
370    /// let (project_reply, _fds) = replies.next().await.unwrap()?;
371    ///
372    /// match user_reply {
373    ///     Ok(user) => println!("User: {}", user.parameters().unwrap().name),
374    ///     Err(error) => println!("User error: {:?}", error),
375    /// }
376    /// # }
377    /// # #[cfg(not(feature = "std"))]
378    /// # {
379    /// # let user_reply = replies.next().await.unwrap()?;
380    /// # let _project_reply = replies.next().await.unwrap()?;
381    /// #
382    /// # match user_reply {
383    /// #     Ok(user) => println!("User: {}", user.parameters().unwrap().name),
384    /// #     Err(error) => println!("User error: {:?}", error),
385    /// # }
386    /// # }
387    /// # Ok(())
388    /// # }
389    /// ```
390    ///
391    /// ## Arbitrary Number of Calls
392    ///
393    /// ```no_run
394    /// # use zlink_core::{Connection, Call, reply};
395    /// # use serde::{Serialize, Deserialize};
396    /// # use futures_util::{pin_mut, stream::StreamExt};
397    /// # use serde_prefix_all::prefix_all;
398    /// # async fn example() -> zlink_core::Result<()> {
399    /// # let mut conn: Connection<zlink_core::connection::socket::impl_for_doc::Socket> = todo!();
400    /// # #[prefix_all("org.example.")]
401    /// # #[derive(Debug, Serialize, Deserialize)]
402    /// # #[serde(tag = "method", content = "parameters")]
403    /// # enum Methods {
404    /// #     GetUser { id: u32 },
405    /// # }
406    /// # #[derive(Debug, Deserialize)]
407    /// # struct User { name: String }
408    /// # #[derive(Debug, zlink_core::ReplyError)]
409    /// #[zlink(
410    ///     interface = "org.example",
411    ///     // Not needed in the real code because you'll use `ReplyError` through `zlink` crate.
412    ///     crate = "zlink_core",
413    /// )]
414    /// # enum ApiError {
415    /// #     UserNotFound { code: i32 },
416    /// #     ProjectNotFound { code: i32 },
417    /// # }
418    /// # let get_user = Call::new(Methods::GetUser { id: 1 });
419    ///
420    /// // Chain many calls (no upper limit)
421    /// # #[cfg(feature = "std")]
422    /// let mut chain = conn.chain_call::<Methods>(&get_user, vec![])?;
423    /// # #[cfg(not(feature = "std"))]
424    /// # let mut chain = conn.chain_call::<Methods>(&get_user)?;
425    /// # #[cfg(feature = "std")]
426    /// for i in 2..100 {
427    ///     chain = chain.append(&Call::new(Methods::GetUser { id: i }), vec![])?;
428    /// }
429    /// # #[cfg(not(feature = "std"))]
430    /// # for i in 2..100 {
431    /// #     chain = chain.append(&Call::new(Methods::GetUser { id: i }))?;
432    /// # }
433    ///
434    /// let replies = chain.send::<User, ApiError>().await?;
435    /// pin_mut!(replies);
436    ///
437    /// // Process all replies sequentially.
438    /// # #[cfg(feature = "std")]
439    /// while let Some(result) = replies.next().await {
440    ///     let (user_reply, _fds) = result?;
441    ///     // Handle each reply...
442    ///     match user_reply {
443    ///         Ok(user) => println!("User: {}", user.parameters().unwrap().name),
444    ///         Err(error) => println!("Error: {:?}", error),
445    ///     }
446    /// }
447    /// # #[cfg(not(feature = "std"))]
448    /// # while let Some(result) = replies.next().await {
449    /// #     let user_reply = result?;
450    /// #     // Handle each reply...
451    /// #     match user_reply {
452    /// #         Ok(user) => println!("User: {}", user.parameters().unwrap().name),
453    /// #         Err(error) => println!("Error: {:?}", error),
454    /// #     }
455    /// # }
456    /// # Ok(())
457    /// # }
458    /// ```
459    ///
460    /// # Performance Benefits
461    ///
462    /// Instead of multiple write operations, the chain sends all calls in a single
463    /// write operation, reducing context switching and therefore minimizing latency.
464    pub fn chain_call<'c, Method>(
465        &'c mut self,
466        call: &Call<Method>,
467        #[cfg(feature = "std")] fds: alloc::vec::Vec<std::os::fd::OwnedFd>,
468    ) -> Result<Chain<'c, S>>
469    where
470        Method: Serialize + Debug,
471    {
472        Chain::new(
473            self,
474            call,
475            #[cfg(feature = "std")]
476            fds,
477        )
478    }
479
480    /// Create a chain from an iterator of method calls.
481    ///
482    /// This allows creating a chain from any iterator yielding method types or calls. Each item
483    /// is automatically converted to a [`Call`] via [`Into<Call<Method>>`]. Unlike
484    /// [`Connection::chain_call`], this method allows building chains from dynamically-sized
485    /// collections.
486    ///
487    /// # Errors
488    ///
489    /// Returns [`Error::EmptyChain`] if the iterator is empty.
490    ///
491    /// # Examples
492    ///
493    /// ```no_run
494    /// use zlink_core::Connection;
495    /// use serde::{Serialize, Deserialize};
496    /// use serde_prefix_all::prefix_all;
497    /// use futures_util::{pin_mut, stream::StreamExt};
498    ///
499    /// # async fn example() -> zlink_core::Result<()> {
500    /// # let mut conn: Connection<zlink_core::connection::socket::impl_for_doc::Socket> = todo!();
501    ///
502    /// #[prefix_all("org.example.")]
503    /// #[derive(Debug, Serialize, Deserialize)]
504    /// #[serde(tag = "method", content = "parameters")]
505    /// enum Methods {
506    ///     GetUser { id: u32 },
507    /// }
508    ///
509    /// #[derive(Debug, Deserialize)]
510    /// struct User { name: String }
511    ///
512    /// #[derive(Debug, zlink_core::ReplyError)]
513    /// #[zlink(interface = "org.example", crate = "zlink_core")]
514    /// enum ApiError {
515    ///     UserNotFound { code: i32 },
516    /// }
517    ///
518    /// let user_ids = [1, 2, 3, 4, 5];
519    /// let replies = conn
520    ///     .chain_from_iter::<Methods, _, _>(
521    ///         user_ids.iter().map(|&id| Methods::GetUser { id })
522    ///     )?
523    ///     .send::<User, ApiError>()
524    ///     .await?;
525    /// pin_mut!(replies);
526    ///
527    /// # #[cfg(feature = "std")]
528    /// while let Some(result) = replies.next().await {
529    ///     let (user_reply, _fds) = result?;
530    ///     // Handle each reply...
531    /// }
532    /// # Ok(())
533    /// # }
534    /// ```
535    ///
536    /// [`Error::EmptyChain`]: crate::Error::EmptyChain
537    pub fn chain_from_iter<'c, Method, MethodCall, MethodCalls>(
538        &'c mut self,
539        calls: MethodCalls,
540    ) -> Result<Chain<'c, S>>
541    where
542        Method: Serialize + Debug,
543        MethodCall: Into<Call<Method>>,
544        MethodCalls: IntoIterator<Item = MethodCall>,
545    {
546        let mut iter = calls.into_iter();
547        let first: Call<Method> = iter.next().ok_or(crate::Error::EmptyChain)?.into();
548
549        #[cfg(feature = "std")]
550        let mut chain = Chain::new(self, &first, alloc::vec::Vec::new())?;
551        #[cfg(not(feature = "std"))]
552        let mut chain = Chain::new(self, &first)?;
553
554        for call in iter {
555            let call: Call<Method> = call.into();
556            #[cfg(feature = "std")]
557            {
558                chain = chain.append(&call, alloc::vec::Vec::new())?;
559            }
560            #[cfg(not(feature = "std"))]
561            {
562                chain = chain.append(&call)?;
563            }
564        }
565
566        Ok(chain)
567    }
568
569    /// Create a chain from an iterator of method calls with file descriptors.
570    ///
571    /// Similar to [`Connection::chain_from_iter`], but allows passing file descriptors with each
572    /// call. Each item in the iterator is a tuple of a method type (or [`Call`]) and its
573    /// associated file descriptors.
574    ///
575    /// # Errors
576    ///
577    /// Returns [`Error::EmptyChain`] if the iterator is empty.
578    ///
579    /// # Examples
580    ///
581    /// ```no_run
582    /// use zlink_core::Connection;
583    /// use serde::{Serialize, Deserialize};
584    /// use serde_prefix_all::prefix_all;
585    /// use std::os::fd::OwnedFd;
586    ///
587    /// # async fn example() -> zlink_core::Result<()> {
588    /// # let mut conn: Connection<zlink_core::connection::socket::impl_for_doc::Socket> = todo!();
589    ///
590    /// #[prefix_all("org.example.")]
591    /// #[derive(Debug, Serialize, Deserialize)]
592    /// #[serde(tag = "method", content = "parameters")]
593    /// enum Methods {
594    ///     SendFile { name: String },
595    /// }
596    ///
597    /// #[derive(Debug, Deserialize)]
598    /// struct FileResult { success: bool }
599    ///
600    /// #[derive(Debug, zlink_core::ReplyError)]
601    /// #[zlink(interface = "org.example", crate = "zlink_core")]
602    /// enum ApiError {
603    ///     SendFailed { reason: String },
604    /// }
605    ///
606    /// let calls_with_fds: Vec<(Methods, Vec<OwnedFd>)> = vec![
607    ///     (Methods::SendFile { name: "file1.txt".into() }, vec![/* fd1 */]),
608    ///     (Methods::SendFile { name: "file2.txt".into() }, vec![/* fd2 */]),
609    /// ];
610    ///
611    /// let replies = conn
612    ///     .chain_from_iter_with_fds::<Methods, _, _>(calls_with_fds)?
613    ///     .send::<FileResult, ApiError>()
614    ///     .await?;
615    /// # Ok(())
616    /// # }
617    /// ```
618    ///
619    /// [`Error::EmptyChain`]: crate::Error::EmptyChain
620    #[cfg(feature = "std")]
621    pub fn chain_from_iter_with_fds<'c, Method, MethodCall, MethodCalls>(
622        &'c mut self,
623        calls: MethodCalls,
624    ) -> Result<Chain<'c, S>>
625    where
626        Method: Serialize + Debug,
627        MethodCall: Into<Call<Method>>,
628        MethodCalls: IntoIterator<Item = (MethodCall, alloc::vec::Vec<std::os::fd::OwnedFd>)>,
629    {
630        let mut iter = calls.into_iter();
631        let (first, first_fds) = iter.next().ok_or(crate::Error::EmptyChain)?;
632        let first: Call<Method> = first.into();
633        let mut chain = Chain::new(self, &first, first_fds)?;
634
635        for (call, fds) in iter {
636            let call: Call<Method> = call.into();
637            chain = chain.append(&call, fds)?;
638        }
639
640        Ok(chain)
641    }
642
643    /// Get the peer credentials.
644    ///
645    /// This method caches the credentials on the first call.
646    #[cfg(feature = "std")]
647    pub async fn peer_credentials(&mut self) -> std::io::Result<&std::sync::Arc<Credentials>>
648    where
649        S::ReadHalf: socket::FetchPeerCredentials,
650    {
651        if self.credentials.is_none() {
652            let creds = self.read.read_half().fetch_peer_credentials().await?;
653            self.credentials = Some(std::sync::Arc::new(creds));
654        }
655
656        // Safety: `unwrap` won't panic because we ensure above that it's set correctly if the
657        // method doesn't error out.
658        Ok(self.credentials.as_ref().unwrap())
659    }
660
661    /// The credentials passed through over the socket with the latest message (if any).
662    #[cfg(all(feature = "std", target_os = "linux"))]
663    pub fn received_credentials(&self) -> Option<&std::sync::Arc<PassedCredentials>>
664    where
665        S::ReadHalf: socket::UnixSocket,
666    {
667        self.read.received_credentials()
668    }
669
670    /// Set the credentials to send with all subsequent writes.
671    ///
672    /// This is only available for `std` feature and `linux` target.
673    #[cfg(all(feature = "std", target_os = "linux"))]
674    pub fn set_credentials(&mut self, credentials: Option<PassedCredentials>) {
675        self.write.set_credentials(credentials);
676    }
677}
678
679impl<S> From<S> for Connection<S>
680where
681    S: Socket,
682{
683    fn from(socket: S) -> Self {
684        Self::new(socket)
685    }
686}
687
688pub(crate) const BUFFER_SIZE: usize = 256;
689const MAX_BUFFER_SIZE: usize = 100 * 1024 * 1024; // Don't allow buffers over 100MB.
690
691static NEXT_ID: AtomicUsize = AtomicUsize::new(0);