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);