1use 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;