1 // Take a look at the license at the top of the repository in the LICENSE file.
2 
3 use crate::Cancellable;
4 use crate::Socket;
5 use crate::SocketAddress;
6 use glib::object::{Cast, IsA};
7 use glib::translate::*;
8 use std::cell::RefCell;
9 use std::mem::transmute;
10 #[cfg(all(not(unix), feature = "dox"))]
11 use std::os::raw::c_int;
12 #[cfg(all(not(windows), feature = "dox"))]
13 use std::os::raw::c_void;
14 use std::pin::Pin;
15 use std::ptr;
16 
17 use futures_core::stream::Stream;
18 
19 #[cfg(unix)]
20 use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
21 
22 #[cfg(windows)]
23 use std::os::windows::io::{AsRawSocket, FromRawSocket, IntoRawSocket, RawSocket};
24 
25 impl Socket {
26     #[cfg(any(unix, feature = "dox"))]
from_fd<T: IntoRawFd>(fd: T) -> Result<Socket, glib::Error>27     pub unsafe fn from_fd<T: IntoRawFd>(fd: T) -> Result<Socket, glib::Error> {
28         let fd = fd.into_raw_fd();
29         let mut error = ptr::null_mut();
30         let ret = ffi::g_socket_new_from_fd(fd, &mut error);
31         if error.is_null() {
32             Ok(from_glib_full(ret))
33         } else {
34             Err(from_glib_full(error))
35         }
36     }
37     #[cfg(any(windows, feature = "dox"))]
from_socket<T: IntoRawSocket>(socket: T) -> Result<Socket, glib::Error>38     pub unsafe fn from_socket<T: IntoRawSocket>(socket: T) -> Result<Socket, glib::Error> {
39         let socket = socket.into_raw_socket();
40         let mut error = ptr::null_mut();
41         let ret = ffi::g_socket_new_from_fd(socket as i32, &mut error);
42         if error.is_null() {
43             Ok(from_glib_full(ret))
44         } else {
45             Err(from_glib_full(error))
46         }
47     }
48 }
49 
50 #[cfg(any(unix, feature = "dox"))]
51 impl AsRawFd for Socket {
as_raw_fd(&self) -> RawFd52     fn as_raw_fd(&self) -> RawFd {
53         unsafe { ffi::g_socket_get_fd(self.to_glib_none().0) as _ }
54     }
55 }
56 
57 #[cfg(any(windows, feature = "dox"))]
58 impl AsRawSocket for Socket {
as_raw_socket(&self) -> RawSocket59     fn as_raw_socket(&self) -> RawSocket {
60         unsafe { ffi::g_socket_get_fd(self.to_glib_none().0) as _ }
61     }
62 }
63 
64 pub trait SocketExtManual: Sized {
65     #[doc(alias = "g_socket_receive")]
receive<B: AsMut<[u8]>, C: IsA<Cancellable>>( &self, buffer: B, cancellable: Option<&C>, ) -> Result<usize, glib::Error>66     fn receive<B: AsMut<[u8]>, C: IsA<Cancellable>>(
67         &self,
68         buffer: B,
69         cancellable: Option<&C>,
70     ) -> Result<usize, glib::Error>;
71     #[doc(alias = "g_socket_receive_from")]
receive_from<B: AsMut<[u8]>, C: IsA<Cancellable>>( &self, buffer: B, cancellable: Option<&C>, ) -> Result<(usize, SocketAddress), glib::Error>72     fn receive_from<B: AsMut<[u8]>, C: IsA<Cancellable>>(
73         &self,
74         buffer: B,
75         cancellable: Option<&C>,
76     ) -> Result<(usize, SocketAddress), glib::Error>;
77     #[doc(alias = "g_socket_receive_with_blocking")]
receive_with_blocking<B: AsMut<[u8]>, C: IsA<Cancellable>>( &self, buffer: B, blocking: bool, cancellable: Option<&C>, ) -> Result<usize, glib::Error>78     fn receive_with_blocking<B: AsMut<[u8]>, C: IsA<Cancellable>>(
79         &self,
80         buffer: B,
81         blocking: bool,
82         cancellable: Option<&C>,
83     ) -> Result<usize, glib::Error>;
84 
85     #[doc(alias = "g_socket_send")]
send<B: AsRef<[u8]>, C: IsA<Cancellable>>( &self, buffer: B, cancellable: Option<&C>, ) -> Result<usize, glib::Error>86     fn send<B: AsRef<[u8]>, C: IsA<Cancellable>>(
87         &self,
88         buffer: B,
89         cancellable: Option<&C>,
90     ) -> Result<usize, glib::Error>;
91     #[doc(alias = "g_socket_send_to")]
send_to<B: AsRef<[u8]>, P: IsA<SocketAddress>, C: IsA<Cancellable>>( &self, address: Option<&P>, buffer: B, cancellable: Option<&C>, ) -> Result<usize, glib::Error>92     fn send_to<B: AsRef<[u8]>, P: IsA<SocketAddress>, C: IsA<Cancellable>>(
93         &self,
94         address: Option<&P>,
95         buffer: B,
96         cancellable: Option<&C>,
97     ) -> Result<usize, glib::Error>;
98     #[doc(alias = "g_socket_send_with_blocking")]
send_with_blocking<B: AsRef<[u8]>, C: IsA<Cancellable>>( &self, buffer: B, blocking: bool, cancellable: Option<&C>, ) -> Result<usize, glib::Error>99     fn send_with_blocking<B: AsRef<[u8]>, C: IsA<Cancellable>>(
100         &self,
101         buffer: B,
102         blocking: bool,
103         cancellable: Option<&C>,
104     ) -> Result<usize, glib::Error>;
105 
106     #[cfg(any(unix, feature = "dox"))]
107     #[cfg_attr(feature = "dox", doc(cfg(unix)))]
108     #[doc(alias = "get_fd")]
109     #[doc(alias = "g_socket_get_fd")]
fd<T: FromRawFd>(&self) -> T110     fn fd<T: FromRawFd>(&self) -> T;
111 
112     #[cfg(any(windows, feature = "dox"))]
113     #[cfg_attr(feature = "dox", doc(cfg(windows)))]
114     #[doc(alias = "get_socket")]
115     #[doc(alias = "g_socket_get_fd")]
socket<T: FromRawSocket>(&self) -> T116     fn socket<T: FromRawSocket>(&self) -> T;
117 
118     #[doc(alias = "g_socket_create_source")]
create_source<F, C>( &self, condition: glib::IOCondition, cancellable: Option<&C>, name: Option<&str>, priority: glib::Priority, func: F, ) -> glib::Source where F: FnMut(&Self, glib::IOCondition) -> glib::Continue + 'static, C: IsA<Cancellable>119     fn create_source<F, C>(
120         &self,
121         condition: glib::IOCondition,
122         cancellable: Option<&C>,
123         name: Option<&str>,
124         priority: glib::Priority,
125         func: F,
126     ) -> glib::Source
127     where
128         F: FnMut(&Self, glib::IOCondition) -> glib::Continue + 'static,
129         C: IsA<Cancellable>;
130 
create_source_future<C: IsA<Cancellable>>( &self, condition: glib::IOCondition, cancellable: Option<&C>, priority: glib::Priority, ) -> Pin<Box<dyn std::future::Future<Output = glib::IOCondition> + 'static>>131     fn create_source_future<C: IsA<Cancellable>>(
132         &self,
133         condition: glib::IOCondition,
134         cancellable: Option<&C>,
135         priority: glib::Priority,
136     ) -> Pin<Box<dyn std::future::Future<Output = glib::IOCondition> + 'static>>;
137 
create_source_stream<C: IsA<Cancellable>>( &self, condition: glib::IOCondition, cancellable: Option<&C>, priority: glib::Priority, ) -> Pin<Box<dyn Stream<Item = glib::IOCondition> + 'static>>138     fn create_source_stream<C: IsA<Cancellable>>(
139         &self,
140         condition: glib::IOCondition,
141         cancellable: Option<&C>,
142         priority: glib::Priority,
143     ) -> Pin<Box<dyn Stream<Item = glib::IOCondition> + 'static>>;
144 }
145 
146 impl<O: IsA<Socket>> SocketExtManual for O {
receive<B: AsMut<[u8]>, C: IsA<Cancellable>>( &self, mut buffer: B, cancellable: Option<&C>, ) -> Result<usize, glib::Error>147     fn receive<B: AsMut<[u8]>, C: IsA<Cancellable>>(
148         &self,
149         mut buffer: B,
150         cancellable: Option<&C>,
151     ) -> Result<usize, glib::Error> {
152         let cancellable = cancellable.map(|c| c.as_ref());
153         let gcancellable = cancellable.to_glib_none();
154         let buffer = buffer.as_mut();
155         let buffer_ptr = buffer.as_mut_ptr();
156         let count = buffer.len();
157         unsafe {
158             let mut error = ptr::null_mut();
159             let ret = ffi::g_socket_receive(
160                 self.as_ref().to_glib_none().0,
161                 buffer_ptr,
162                 count,
163                 gcancellable.0,
164                 &mut error,
165             );
166             if error.is_null() {
167                 Ok(ret as usize)
168             } else {
169                 Err(from_glib_full(error))
170             }
171         }
172     }
173 
receive_from<B: AsMut<[u8]>, C: IsA<Cancellable>>( &self, mut buffer: B, cancellable: Option<&C>, ) -> Result<(usize, SocketAddress), glib::Error>174     fn receive_from<B: AsMut<[u8]>, C: IsA<Cancellable>>(
175         &self,
176         mut buffer: B,
177         cancellable: Option<&C>,
178     ) -> Result<(usize, SocketAddress), glib::Error> {
179         let cancellable = cancellable.map(|c| c.as_ref());
180         let gcancellable = cancellable.to_glib_none();
181         let buffer = buffer.as_mut();
182         let buffer_ptr = buffer.as_mut_ptr();
183         let count = buffer.len();
184         unsafe {
185             let mut error = ptr::null_mut();
186             let mut addr_ptr = ptr::null_mut();
187 
188             let ret = ffi::g_socket_receive_from(
189                 self.as_ref().to_glib_none().0,
190                 &mut addr_ptr,
191                 buffer_ptr,
192                 count,
193                 gcancellable.0,
194                 &mut error,
195             );
196             if error.is_null() {
197                 Ok((ret as usize, from_glib_full(addr_ptr)))
198             } else {
199                 Err(from_glib_full(error))
200             }
201         }
202     }
203 
receive_with_blocking<B: AsMut<[u8]>, C: IsA<Cancellable>>( &self, mut buffer: B, blocking: bool, cancellable: Option<&C>, ) -> Result<usize, glib::Error>204     fn receive_with_blocking<B: AsMut<[u8]>, C: IsA<Cancellable>>(
205         &self,
206         mut buffer: B,
207         blocking: bool,
208         cancellable: Option<&C>,
209     ) -> Result<usize, glib::Error> {
210         let cancellable = cancellable.map(|c| c.as_ref());
211         let gcancellable = cancellable.to_glib_none();
212         let buffer = buffer.as_mut();
213         let buffer_ptr = buffer.as_mut_ptr();
214         let count = buffer.len();
215         unsafe {
216             let mut error = ptr::null_mut();
217             let ret = ffi::g_socket_receive_with_blocking(
218                 self.as_ref().to_glib_none().0,
219                 buffer_ptr,
220                 count,
221                 blocking.into_glib(),
222                 gcancellable.0,
223                 &mut error,
224             );
225             if error.is_null() {
226                 Ok(ret as usize)
227             } else {
228                 Err(from_glib_full(error))
229             }
230         }
231     }
232 
send<B: AsRef<[u8]>, C: IsA<Cancellable>>( &self, buffer: B, cancellable: Option<&C>, ) -> Result<usize, glib::Error>233     fn send<B: AsRef<[u8]>, C: IsA<Cancellable>>(
234         &self,
235         buffer: B,
236         cancellable: Option<&C>,
237     ) -> Result<usize, glib::Error> {
238         let cancellable = cancellable.map(|c| c.as_ref());
239         let gcancellable = cancellable.to_glib_none();
240         let (count, buffer_ptr) = {
241             let slice = buffer.as_ref();
242             (slice.len(), slice.as_ptr())
243         };
244         unsafe {
245             let mut error = ptr::null_mut();
246             let ret = ffi::g_socket_send(
247                 self.as_ref().to_glib_none().0,
248                 mut_override(buffer_ptr),
249                 count,
250                 gcancellable.0,
251                 &mut error,
252             );
253             if error.is_null() {
254                 Ok(ret as usize)
255             } else {
256                 Err(from_glib_full(error))
257             }
258         }
259     }
260 
send_to<B: AsRef<[u8]>, P: IsA<SocketAddress>, C: IsA<Cancellable>>( &self, address: Option<&P>, buffer: B, cancellable: Option<&C>, ) -> Result<usize, glib::Error>261     fn send_to<B: AsRef<[u8]>, P: IsA<SocketAddress>, C: IsA<Cancellable>>(
262         &self,
263         address: Option<&P>,
264         buffer: B,
265         cancellable: Option<&C>,
266     ) -> Result<usize, glib::Error> {
267         let cancellable = cancellable.map(|c| c.as_ref());
268         let gcancellable = cancellable.to_glib_none();
269         let (count, buffer_ptr) = {
270             let slice = buffer.as_ref();
271             (slice.len(), slice.as_ptr())
272         };
273         unsafe {
274             let mut error = ptr::null_mut();
275 
276             let ret = ffi::g_socket_send_to(
277                 self.as_ref().to_glib_none().0,
278                 address.map(|p| p.as_ref()).to_glib_none().0,
279                 mut_override(buffer_ptr),
280                 count,
281                 gcancellable.0,
282                 &mut error,
283             );
284             if error.is_null() {
285                 Ok(ret as usize)
286             } else {
287                 Err(from_glib_full(error))
288             }
289         }
290     }
291 
send_with_blocking<B: AsRef<[u8]>, C: IsA<Cancellable>>( &self, buffer: B, blocking: bool, cancellable: Option<&C>, ) -> Result<usize, glib::Error>292     fn send_with_blocking<B: AsRef<[u8]>, C: IsA<Cancellable>>(
293         &self,
294         buffer: B,
295         blocking: bool,
296         cancellable: Option<&C>,
297     ) -> Result<usize, glib::Error> {
298         let cancellable = cancellable.map(|c| c.as_ref());
299         let gcancellable = cancellable.to_glib_none();
300         let (count, buffer_ptr) = {
301             let slice = buffer.as_ref();
302             (slice.len(), slice.as_ptr())
303         };
304         unsafe {
305             let mut error = ptr::null_mut();
306             let ret = ffi::g_socket_send_with_blocking(
307                 self.as_ref().to_glib_none().0,
308                 mut_override(buffer_ptr),
309                 count,
310                 blocking.into_glib(),
311                 gcancellable.0,
312                 &mut error,
313             );
314             if error.is_null() {
315                 Ok(ret as usize)
316             } else {
317                 Err(from_glib_full(error))
318             }
319         }
320     }
321 
322     #[cfg(any(unix, feature = "dox"))]
323     #[cfg_attr(feature = "dox", doc(cfg(unix)))]
fd<T: FromRawFd>(&self) -> T324     fn fd<T: FromRawFd>(&self) -> T {
325         unsafe { FromRawFd::from_raw_fd(ffi::g_socket_get_fd(self.as_ref().to_glib_none().0)) }
326     }
327 
328     #[cfg(any(windows, feature = "dox"))]
329     #[cfg_attr(feature = "dox", doc(cfg(windows)))]
socket<T: FromRawSocket>(&self) -> T330     fn socket<T: FromRawSocket>(&self) -> T {
331         unsafe {
332             FromRawSocket::from_raw_socket(ffi::g_socket_get_fd(self.as_ref().to_glib_none().0) as _)
333         }
334     }
335 
create_source<F, C>( &self, condition: glib::IOCondition, cancellable: Option<&C>, name: Option<&str>, priority: glib::Priority, func: F, ) -> glib::Source where F: FnMut(&Self, glib::IOCondition) -> glib::Continue + 'static, C: IsA<Cancellable>,336     fn create_source<F, C>(
337         &self,
338         condition: glib::IOCondition,
339         cancellable: Option<&C>,
340         name: Option<&str>,
341         priority: glib::Priority,
342         func: F,
343     ) -> glib::Source
344     where
345         F: FnMut(&Self, glib::IOCondition) -> glib::Continue + 'static,
346         C: IsA<Cancellable>,
347     {
348         unsafe extern "C" fn trampoline<
349             O: IsA<Socket>,
350             F: FnMut(&O, glib::IOCondition) -> glib::Continue + 'static,
351         >(
352             socket: *mut ffi::GSocket,
353             condition: glib::ffi::GIOCondition,
354             func: glib::ffi::gpointer,
355         ) -> glib::ffi::gboolean {
356             let func: &RefCell<F> = &*(func as *const RefCell<F>);
357             let mut func = func.borrow_mut();
358             (&mut *func)(
359                 Socket::from_glib_borrow(socket).unsafe_cast_ref(),
360                 from_glib(condition),
361             )
362             .into_glib()
363         }
364         unsafe extern "C" fn destroy_closure<O, F>(ptr: glib::ffi::gpointer) {
365             Box::<RefCell<F>>::from_raw(ptr as *mut _);
366         }
367         let cancellable = cancellable.map(|c| c.as_ref());
368         let gcancellable = cancellable.to_glib_none();
369         unsafe {
370             let source = ffi::g_socket_create_source(
371                 self.as_ref().to_glib_none().0,
372                 condition.into_glib(),
373                 gcancellable.0,
374             );
375             let trampoline = trampoline::<O, F> as glib::ffi::gpointer;
376             glib::ffi::g_source_set_callback(
377                 source,
378                 Some(transmute::<
379                     _,
380                     unsafe extern "C" fn(glib::ffi::gpointer) -> glib::ffi::gboolean,
381                 >(trampoline)),
382                 Box::into_raw(Box::new(RefCell::new(func))) as glib::ffi::gpointer,
383                 Some(destroy_closure::<O, F>),
384             );
385             glib::ffi::g_source_set_priority(source, priority.into_glib());
386 
387             if let Some(name) = name {
388                 glib::ffi::g_source_set_name(source, name.to_glib_none().0);
389             }
390 
391             from_glib_full(source)
392         }
393     }
394 
create_source_future<C: IsA<Cancellable>>( &self, condition: glib::IOCondition, cancellable: Option<&C>, priority: glib::Priority, ) -> Pin<Box<dyn std::future::Future<Output = glib::IOCondition> + 'static>>395     fn create_source_future<C: IsA<Cancellable>>(
396         &self,
397         condition: glib::IOCondition,
398         cancellable: Option<&C>,
399         priority: glib::Priority,
400     ) -> Pin<Box<dyn std::future::Future<Output = glib::IOCondition> + 'static>> {
401         let cancellable: Option<Cancellable> = cancellable.map(|c| c.as_ref()).cloned();
402 
403         let obj = self.clone();
404         Box::pin(glib::SourceFuture::new(move |send| {
405             let mut send = Some(send);
406             obj.create_source(
407                 condition,
408                 cancellable.as_ref(),
409                 None,
410                 priority,
411                 move |_, condition| {
412                     let _ = send.take().unwrap().send(condition);
413                     glib::Continue(false)
414                 },
415             )
416         }))
417     }
418 
create_source_stream<C: IsA<Cancellable>>( &self, condition: glib::IOCondition, cancellable: Option<&C>, priority: glib::Priority, ) -> Pin<Box<dyn Stream<Item = glib::IOCondition> + 'static>>419     fn create_source_stream<C: IsA<Cancellable>>(
420         &self,
421         condition: glib::IOCondition,
422         cancellable: Option<&C>,
423         priority: glib::Priority,
424     ) -> Pin<Box<dyn Stream<Item = glib::IOCondition> + 'static>> {
425         let cancellable: Option<Cancellable> = cancellable.map(|c| c.as_ref()).cloned();
426 
427         let obj = self.clone();
428         Box::pin(glib::SourceStream::new(move |send| {
429             let send = Some(send);
430             obj.create_source(
431                 condition,
432                 cancellable.as_ref(),
433                 None,
434                 priority,
435                 move |_, condition| {
436                     if send.as_ref().unwrap().unbounded_send(condition).is_err() {
437                         glib::Continue(false)
438                     } else {
439                         glib::Continue(true)
440                     }
441                 },
442             )
443         }))
444     }
445 }
446 
447 #[cfg(all(not(unix), feature = "dox"))]
448 pub trait IntoRawFd {
into_raw_fd(self) -> c_int449     fn into_raw_fd(self) -> c_int;
450 }
451 
452 #[cfg(all(not(unix), feature = "dox"))]
453 pub trait FromRawFd {
from_raw_fd(fd: c_int) -> Self454     unsafe fn from_raw_fd(fd: c_int) -> Self;
455 }
456 
457 #[cfg(all(not(unix), feature = "dox"))]
458 pub trait AsRawFd {
as_raw_fd(&self) -> RawFd459     fn as_raw_fd(&self) -> RawFd;
460 }
461 
462 #[cfg(all(not(unix), feature = "dox"))]
463 pub type RawFd = c_int;
464 
465 #[cfg(all(not(windows), feature = "dox"))]
466 pub trait IntoRawSocket {
into_raw_socket(self) -> u64467     fn into_raw_socket(self) -> u64;
468 }
469 
470 #[cfg(all(not(windows), feature = "dox"))]
471 pub trait FromRawSocket {
from_raw_socket(sock: u64) -> Self472     unsafe fn from_raw_socket(sock: u64) -> Self;
473 }
474 
475 #[cfg(all(not(windows), feature = "dox"))]
476 pub trait AsRawSocket {
as_raw_socket(&self) -> RawSocket477     fn as_raw_socket(&self) -> RawSocket;
478 }
479 
480 #[cfg(all(not(windows), feature = "dox"))]
481 pub type RawSocket = *mut c_void;
482