gio/
socket.rs

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