1use core::ffi::{c_char, c_int, c_ulong, c_void};
2use core::ptr::NonNull;
3use core::time::Duration;
4use core::{fmt, mem, ptr, str};
5use std::cell::RefCell;
6use std::collections::HashMap;
7use std::rc::Rc;
8
9#[cfg(feature = "libstrophe-0_11_0")]
10mod libstrophe_0_11 {
11 pub use std::any::TypeId;
12
13 pub use super::internals::CERT_FAIL_HANDLERS;
14 pub use crate::TlsCert;
15}
16#[cfg(feature = "libstrophe-0_11_0")]
17pub use internals::CertFailResult;
18#[cfg(feature = "libstrophe-0_11_0")]
19use libstrophe_0_11::*;
20
21#[cfg(feature = "libstrophe-0_12_0")]
22mod libstrophe_0_12 {
23 pub use super::internals::{PasswordCallback, SOCKOPT_HANDLERS};
24 pub use crate::{QueueElement, SMState};
25}
26#[cfg(feature = "libstrophe-0_12_0")]
27pub use internals::SockoptResult;
28#[cfg(feature = "libstrophe-0_12_0")]
29use libstrophe_0_12::*;
30
31#[cfg(feature = "libstrophe-0_14")]
32mod libstrophe_0_14 {
33 pub use super::internals::SmStateCallback;
34 pub use crate::sm_state::{SerializedSmState, SerializedSmStateRef};
35}
36pub use internals::HandlerResult;
37use internals::{
38 BoxedHandler, BoxedHandlers, CbAddr, ConnectionCallback, ConnectionFatHandler, ConnectionHandlers, StanzaCallback,
39 StanzaFatHandler, TimedCallback, TimedFatHandler,
40};
41#[cfg(feature = "libstrophe-0_14")]
42use libstrophe_0_14::*;
43
44use crate::connection::internals::MaybeBoxedHandler;
45use crate::error::IntoResult;
46use crate::ffi_types::Nullable;
47use crate::{ConnectClientError, ConnectionError, ConnectionFlags, Context, Error, FFI, Result, Stanza, StreamError};
48
49#[macro_use]
50mod internals;
51
52#[derive(Debug)]
71pub struct Connection<'cb, 'cx> {
72 inner: NonNull<sys::xmpp_conn_t>,
73 ctx: Option<Context<'cx, 'cb>>,
74 owned: bool,
75 handlers: Rc<RefCell<ConnectionHandlers<'cb, 'cx>>>,
76}
77
78impl<'cb, 'cx> Connection<'cb, 'cx> {
79 #[inline]
80 pub fn new(ctx: Context<'cx, 'cb>) -> Self {
82 unsafe {
83 Self::from_owned(
84 sys::xmpp_conn_new(ctx.as_ptr()),
85 ctx,
86 Rc::new(RefCell::new(ConnectionHandlers {
87 connection: None,
88 timed: BoxedHandlers::new(4),
89 stanza: BoxedHandlers::new(4),
90 #[cfg(feature = "libstrophe-0_11_0")]
91 cert_fail_handler_id: None,
92 #[cfg(feature = "libstrophe-0_12_0")]
93 sockopt_handler_id: None,
94 #[cfg(feature = "libstrophe-0_12_0")]
95 password: None,
96 #[cfg(feature = "libstrophe-0_14")]
97 sm_state: None,
98 })),
99 )
100 }
101 }
102
103 unsafe fn with_inner(
104 inner: *mut sys::xmpp_conn_t,
105 ctx: Context<'cx, 'cb>,
106 owned: bool,
107 handlers: Rc<RefCell<ConnectionHandlers<'cb, 'cx>>>,
108 ) -> Self {
109 Connection {
110 inner: NonNull::new(inner).expect("Cannot allocate memory for Connection"),
111 ctx: Some(ctx),
112 owned,
113 handlers,
114 }
115 }
116
117 unsafe fn from_owned(
118 inner: *mut sys::xmpp_conn_t,
119 ctx: Context<'cx, 'cb>,
120 handlers: Rc<RefCell<ConnectionHandlers<'cb, 'cx>>>,
121 ) -> Self {
122 unsafe { Self::with_inner(inner, ctx, true, handlers) }
123 }
124
125 unsafe fn from_ref_mut(inner: *mut sys::xmpp_conn_t, handlers: Rc<RefCell<ConnectionHandlers<'cb, 'cx>>>) -> Self {
126 unsafe {
127 let ctx = Context::from_ref(sys::xmpp_conn_get_context(inner));
128 Self::with_inner(inner, ctx, false, handlers)
129 }
130 }
131
132 unsafe extern "C" fn connection_handler_cb<CB>(
133 conn_ptr: *mut sys::xmpp_conn_t,
134 event: sys::xmpp_conn_event_t,
135 error: c_int,
136 stream_error: *mut sys::xmpp_stream_error_t,
137 userdata: *mut c_void,
138 ) where
139 CB: FnMut(&Context<'cx, 'cb>, &mut Connection<'cb, 'cx>, ConnectionEvent) + Send + 'cb,
140 {
141 let connection_handler = unsafe { ConnectionFatHandler::from_userdata(userdata) };
142 if let Some(fat_handlers) = connection_handler.handlers.upgrade() {
143 let mut conn = unsafe { Self::from_ref_mut(conn_ptr, fat_handlers) };
144 let event = match event {
145 sys::xmpp_conn_event_t::XMPP_CONN_RAW_CONNECT => ConnectionEvent::RawConnect,
146 sys::xmpp_conn_event_t::XMPP_CONN_CONNECT => ConnectionEvent::Connect,
147 sys::xmpp_conn_event_t::XMPP_CONN_DISCONNECT => {
148 let stream_error = unsafe { stream_error.as_ref() }.map(StreamError::from);
149 ConnectionEvent::Disconnect(ConnectionError::from((error, stream_error)))
150 }
151 sys::xmpp_conn_event_t::XMPP_CONN_FAIL => unreachable!("XMPP_CONN_FAIL is never used in the underlying library"),
152 };
153 let ctx = unsafe { conn.context_detached() };
154 ensure_unique!(CB, conn_ptr, userdata, ctx, &mut conn, ConnectionEvent::Connect);
155 (connection_handler.handler)(ctx, &mut conn, event);
156 }
157 }
158
159 unsafe extern "C" fn timed_handler_cb<CB>(conn_ptr: *mut sys::xmpp_conn_t, userdata: *mut c_void) -> c_int
160 where
161 CB: FnMut(&Context<'cx, 'cb>, &mut Connection<'cb, 'cx>) -> HandlerResult + Send + 'cb,
162 {
163 let timed_handler = unsafe { TimedFatHandler::from_userdata(userdata) };
164 if let Some(fat_handlers) = timed_handler.handlers.upgrade() {
165 let mut conn = unsafe { Self::from_ref_mut(conn_ptr, fat_handlers) };
166 let ctx = unsafe { conn.context_detached() };
167 ensure_unique!(CB, conn_ptr, userdata, ctx, &mut conn);
168 let res = (timed_handler.handler)(ctx, &mut conn);
169 if matches!(res, HandlerResult::RemoveHandler) {
170 conn
171 .handlers
172 .borrow_mut()
173 .timed
174 .drop_handler(Self::timed_handler_cb::<CB> as CbAddr);
175 }
176 res as c_int
177 } else {
178 HandlerResult::RemoveHandler as c_int
179 }
180 }
181
182 unsafe extern "C" fn handler_cb<CB>(
183 conn_ptr: *mut sys::xmpp_conn_t,
184 stanza: *mut sys::xmpp_stanza_t,
185 userdata: *mut c_void,
186 ) -> c_int
187 where
188 CB: FnMut(&Context<'cx, 'cb>, &mut Connection<'cb, 'cx>, &Stanza) -> HandlerResult + Send + 'cb,
189 {
190 let stanza_handler = unsafe { StanzaFatHandler::from_userdata(userdata) };
191 if let Some(fat_handlers) = stanza_handler.handlers.upgrade() {
192 let mut conn = unsafe { Self::from_ref_mut(conn_ptr, fat_handlers) };
193 let stanza = unsafe { Stanza::from_ref(stanza) };
194 let ctx = unsafe { conn.context_detached() };
195 ensure_unique!(CB, conn_ptr, userdata, ctx, &mut conn, &stanza);
196 let res = (stanza_handler.handler)(ctx, &mut conn, &stanza);
197 if matches!(res, HandlerResult::RemoveHandler) {
198 conn
199 .handlers
200 .borrow_mut()
201 .stanza
202 .drop_handler(Self::handler_cb::<CB> as CbAddr);
203 }
204 res as c_int
205 } else {
206 HandlerResult::RemoveHandler as c_int
207 }
208 }
209
210 #[inline]
211 unsafe fn context_detached<'a>(&self) -> &'a Context<'cx, 'cb> {
212 self
213 .ctx
214 .as_ref()
215 .map(|ctx| ctx as *const Context)
216 .and_then(|ctx| unsafe { ctx.as_ref() })
217 .unwrap()
218 }
219
220 #[inline]
221 pub fn flags(&self) -> ConnectionFlags {
223 ConnectionFlags::from_bits(unsafe { sys::xmpp_conn_get_flags(self.inner.as_ptr()) }).unwrap()
224 }
225
226 #[inline]
227 pub fn set_flags(&mut self, flags: ConnectionFlags) -> Result<()> {
229 unsafe { sys::xmpp_conn_set_flags(self.inner.as_mut(), flags.bits()) }.into_result()
230 }
231
232 #[inline]
233 pub fn jid(&self) -> Option<&str> {
235 unsafe { FFI(sys::xmpp_conn_get_jid(self.inner.as_ptr())).receive() }
236 }
237
238 #[inline]
239 pub fn bound_jid(&self) -> Option<&str> {
241 unsafe { FFI(sys::xmpp_conn_get_bound_jid(self.inner.as_ptr())).receive() }
242 }
243
244 #[inline]
245 pub fn set_jid(&mut self, jid: impl AsRef<str>) {
247 let jid = FFI(jid.as_ref()).send();
248 unsafe { sys::xmpp_conn_set_jid(self.inner.as_mut(), jid.as_ptr()) }
249 }
250
251 #[inline]
252 pub fn pass(&self) -> Option<&str> {
254 unsafe { FFI(sys::xmpp_conn_get_pass(self.inner.as_ptr())).receive() }
255 }
256
257 #[inline]
258 pub fn set_pass(&mut self, pass: impl AsRef<str>) {
260 let pass = FFI(pass.as_ref()).send();
261 unsafe { sys::xmpp_conn_set_pass(self.inner.as_mut(), pass.as_ptr()) }
262 }
263
264 #[inline]
265 #[deprecated = "replaced by set_flags()"]
266 pub fn disable_tls(&mut self) {
268 unsafe { sys::xmpp_conn_disable_tls(self.inner.as_mut()) }
269 }
270
271 #[inline]
272 pub fn is_secured(&self) -> bool {
274 unsafe { FFI(sys::xmpp_conn_is_secured(self.inner.as_ptr())).receive_bool() }
275 }
276
277 #[inline]
278 #[cfg_attr(feature = "libstrophe-0_12_0", deprecated = "replaced by set_sockopt_callback()")]
279 pub fn set_keepalive(&mut self, timeout: Duration, interval: Duration) {
281 unsafe {
282 sys::xmpp_conn_set_keepalive(
283 self.inner.as_mut(),
284 c_int::try_from(timeout.as_secs()).unwrap_or(c_int::MAX),
285 c_int::try_from(interval.as_secs()).unwrap_or(c_int::MAX),
286 )
287 }
288 }
289
290 #[cfg(feature = "libstrophe-0_10_0")]
291 #[inline]
292 pub fn is_connecting(&self) -> bool {
294 unsafe { FFI(sys::xmpp_conn_is_connecting(self.inner.as_ptr())).receive_bool() }
295 }
296
297 #[cfg(feature = "libstrophe-0_10_0")]
298 #[inline]
299 pub fn is_connected(&self) -> bool {
301 unsafe { FFI(sys::xmpp_conn_is_connected(self.inner.as_ptr())).receive_bool() }
302 }
303
304 #[cfg(feature = "libstrophe-0_10_0")]
305 #[inline]
306 pub fn is_disconnected(&self) -> bool {
308 unsafe { FFI(sys::xmpp_conn_is_disconnected(self.inner.as_ptr())).receive_bool() }
309 }
310
311 #[cfg(feature = "libstrophe-0_11_0")]
312 #[inline]
313 pub fn set_cafile(&mut self, path: impl AsRef<str>) {
315 let path = FFI(path.as_ref()).send();
316 unsafe { sys::xmpp_conn_set_cafile(self.inner.as_ptr(), path.as_ptr()) }
317 }
318
319 #[cfg(feature = "libstrophe-0_11_0")]
320 #[inline]
321 pub fn set_capath(&mut self, path: impl AsRef<str>) {
323 let path = FFI(path.as_ref()).send();
324 unsafe { sys::xmpp_conn_set_capath(self.inner.as_ptr(), path.as_ptr()) }
325 }
326
327 #[cfg(feature = "libstrophe-0_11_0")]
328 pub fn set_certfail_handler<CB>(&mut self, handler: CB)
333 where
334 CB: Fn(&TlsCert, &str) -> CertFailResult + Send + Sync + 'static,
335 {
336 let callback = internals::certfail_handler_cb::<CB>;
337 if let Ok(mut handlers) = CERT_FAIL_HANDLERS.write() {
338 let type_id = TypeId::of::<CB>();
339 handlers.insert(type_id, Box::new(handler));
340 if let Some(prev_handler_id) = self.handlers.borrow_mut().cert_fail_handler_id.replace(type_id) {
341 handlers.remove(&prev_handler_id);
342 }
343 };
344 unsafe { sys::xmpp_conn_set_certfail_handler(self.inner.as_ptr(), Some(callback)) }
345 }
346
347 #[cfg(feature = "libstrophe-0_11_0")]
348 #[inline]
349 pub fn peer_cert(&self) -> Option<TlsCert> {
351 unsafe {
352 let cert = sys::xmpp_conn_get_peer_cert(self.inner.as_ptr());
353 if cert.is_null() {
354 None
355 } else {
356 Some(TlsCert::from_owned(cert))
357 }
358 }
359 }
360
361 #[cfg(feature = "libstrophe-0_11_0")]
362 #[inline]
363 pub fn set_client_cert(&mut self, cert_path: &str, key_path: &str) {
365 let cert_path = FFI(cert_path).send();
366 let key_path = FFI(key_path).send();
367 unsafe {
368 sys::xmpp_conn_set_client_cert(self.inner.as_ptr(), cert_path.as_ptr(), key_path.as_ptr());
369 }
370 }
371
372 #[cfg(feature = "libstrophe-0_11_0")]
373 #[inline]
374 pub fn cert_xmppaddr_num(&self) -> u32 {
376 unsafe { sys::xmpp_conn_cert_xmppaddr_num(self.inner.as_ptr()) }
377 }
378
379 #[cfg(feature = "libstrophe-0_11_0")]
380 #[inline]
381 pub fn cert_xmppaddr(&self, n: u32) -> Option<String> {
383 unsafe { FFI(sys::xmpp_conn_cert_xmppaddr(self.inner.as_ptr(), n)).receive_with_free(|x| crate::ALLOC_CONTEXT.free(x)) }
384 }
385
386 #[cfg(feature = "libstrophe-0_12_0")]
387 #[inline]
388 pub fn set_password_callback<CB>(&mut self, handler: CB)
395 where
396 CB: Fn(&Connection<'cb, 'cx>, usize) -> Option<String> + Send + 'cb,
397 {
398 let callback = internals::password_handler_cb;
399 let handler = BoxedHandler::make(
400 &self.handlers,
401 Box::new(handler) as Box<PasswordCallback>,
402 callback as CbAddr,
403 (),
404 );
405 let mut handlers = self.handlers.borrow_mut();
406 let (_old_handler, new_handler) = handlers.password.set_handler(handler);
408 unsafe {
409 sys::xmpp_conn_set_password_callback(self.inner.as_mut(), Some(callback), new_handler.as_userdata());
410 }
411 }
412
413 #[cfg(feature = "libstrophe-0_12_0")]
414 #[inline]
415 pub fn clear_password_callback(&mut self) -> usize {
419 unsafe { sys::xmpp_conn_set_password_callback(self.inner.as_mut(), None, ptr::null_mut()) }
420 self.handlers.borrow_mut().password.take().into_iter().count()
421 }
422
423 #[cfg(feature = "libstrophe-0_12_0")]
424 pub fn set_sockopt_callback<CB>(&mut self, handler: CB)
429 where
430 CB: Fn(*mut c_void) -> SockoptResult + Send + Sync + 'static,
431 {
432 let callback = internals::sockopt_callback::<CB>;
433 if let Ok(mut handlers) = SOCKOPT_HANDLERS.write() {
434 let type_id = TypeId::of::<CB>();
435 handlers.insert(type_id, Box::new(handler));
436 if let Some(prev_handler_id) = self.handlers.borrow_mut().sockopt_handler_id.replace(type_id) {
437 handlers.remove(&prev_handler_id);
438 }
439 };
440 unsafe { sys::xmpp_conn_set_sockopt_callback(self.inner.as_mut(), Some(callback)) }
441 }
442
443 #[cfg(feature = "libstrophe-0_12_0")]
444 #[inline]
445 pub fn set_default_sockopt_callback(&mut self) {
451 unsafe { sys::xmpp_conn_set_sockopt_callback(self.inner.as_mut(), Some(sys::xmpp_sockopt_cb_keepalive)) }
452 }
453
454 #[cfg(feature = "libstrophe-0_12_0")]
455 #[inline]
456 pub fn set_password_retries(&mut self, n: u32) {
458 unsafe { sys::xmpp_conn_set_password_retries(self.inner.as_ptr(), n) }
459 }
460
461 #[cfg(feature = "libstrophe-0_12_0")]
462 #[inline]
463 pub fn get_keyfile(&self) -> Option<&str> {
465 unsafe { FFI(sys::xmpp_conn_get_keyfile(self.inner.as_ptr())).receive() }
466 }
467
468 #[cfg(feature = "libstrophe-0_12_0")]
469 #[inline]
470 pub fn send_queue_len(&self) -> i32 {
472 unsafe { sys::xmpp_conn_send_queue_len(self.inner.as_ptr()) }
473 }
474
475 #[cfg(feature = "libstrophe-0_12_0")]
476 #[inline]
477 pub fn send_queue_drop_element(&mut self, which: QueueElement) -> Option<String> {
479 unsafe {
480 FFI(sys::xmpp_conn_send_queue_drop_element(self.inner.as_ptr(), which))
481 .receive_with_free(|x| crate::ALLOC_CONTEXT.free(x))
482 }
483 }
484
485 #[cfg(feature = "libstrophe-0_12_0")]
486 #[inline]
487 pub fn sm_state(&mut self) -> Option<SMState<'_, '_>> {
492 let inner = unsafe { sys::xmpp_conn_get_sm_state(self.inner.as_mut()) };
493 if inner.is_null() {
494 None
495 } else {
496 Some(unsafe { SMState::new(inner) })
497 }
498 }
499
500 #[cfg(feature = "libstrophe-0_14")]
501 #[inline]
502 pub fn set_sm_callback<CB>(&mut self, handler: CB)
504 where
505 CB: FnMut(&mut Connection<'cb, 'cx>, SerializedSmStateRef) + Send + 'cb,
507 {
508 let callback = internals::sm_state_handler_cb;
509 let new_handler = BoxedHandler::make(
510 &self.handlers,
511 Box::new(handler) as Box<SmStateCallback>,
512 callback as CbAddr,
513 (),
514 );
515 let mut handlers = self.handlers.borrow_mut();
516 let (_old_handler, new_handler) = handlers.sm_state.set_handler(new_handler);
518 unsafe { sys::xmpp_conn_set_sm_callback(self.inner.as_mut(), Some(callback), new_handler.as_userdata()) }
519 }
520
521 #[cfg(feature = "libstrophe-0_14")]
522 #[inline]
523 pub fn clear_sm_callback(&mut self) -> usize {
527 unsafe { sys::xmpp_conn_set_sm_callback(self.inner.as_mut(), None, ptr::null_mut()) }
528 self.handlers.borrow_mut().sm_state.take().into_iter().count()
529 }
530
531 #[cfg(feature = "libstrophe-0_14")]
532 #[inline]
533 pub fn restore_sm_state(&mut self, sm_state: SerializedSmState) -> Result<()> {
535 unsafe { sys::xmpp_conn_restore_sm_state(self.inner.as_mut(), sm_state.buf.as_ptr(), sm_state.buf.len()) }.into_result()
536 }
537
538 pub fn connect_client<CB>(
541 mut self,
542 alt_host: Option<&str>,
543 alt_port: impl Into<Option<u16>>,
544 handler: CB,
545 ) -> Result<Context<'cx, 'cb>, ConnectClientError<'cb, 'cx>>
546 where
547 CB: FnMut(&Context<'cx, 'cb>, &mut Connection<'cb, 'cx>, ConnectionEvent) + Send + 'cb,
548 {
549 let alt_host = FFI(alt_host).send();
550 let alt_port = Nullable::from(alt_port.into());
551 if self.jid().is_none() {
552 return Err(ConnectClientError {
553 conn: self,
554 error: Error::InvalidOperation,
555 });
556 }
557 let callback = Self::connection_handler_cb::<CB>;
558 let new_handler = BoxedHandler::make(
559 &self.handlers,
560 Box::new(handler) as Box<ConnectionCallback>,
561 callback as CbAddr,
562 (),
563 );
564 let (res, old_handler) = {
565 let mut handlers = self.handlers.borrow_mut();
566 let (old_handler, fat_handler) = handlers.connection.set_handler(new_handler);
567 let res = unsafe {
568 sys::xmpp_connect_client(
569 self.inner.as_mut(),
570 alt_host.as_ptr(),
571 alt_port.val(),
572 Some(callback),
573 fat_handler.as_userdata(),
574 )
575 }
576 .into_result();
577 (res, old_handler)
578 };
579 match res {
580 Ok(_) => {
581 let mut out = self.ctx.take().expect("Internal context is empty, it must never happen");
582 out.consume_connection(self);
583 Ok(out)
584 }
585 Err(e) => {
586 self.handlers.borrow_mut().connection = old_handler;
587 Err(ConnectClientError { conn: self, error: e })
588 }
589 }
590 }
591
592 pub fn connect_component<CB>(
597 mut self,
598 host: impl AsRef<str>,
599 port: impl Into<Option<u16>>,
600 handler: CB,
601 ) -> Result<Context<'cx, 'cb>, ConnectClientError<'cb, 'cx>>
602 where
603 CB: FnMut(&Context<'cx, 'cb>, &mut Connection<'cb, 'cx>, ConnectionEvent) + Send + 'cb,
604 {
605 let host = FFI(host.as_ref()).send();
606 let port = Nullable::from(port.into());
607 let callback = Self::connection_handler_cb::<CB>;
608 let new_handler = BoxedHandler::make(
609 &self.handlers,
610 Box::new(handler) as Box<ConnectionCallback>,
611 callback as CbAddr,
612 (),
613 );
614 let (res, old_handler) = {
615 let mut handlers = self.handlers.borrow_mut();
616 let (old_handler, new_handler) = handlers.connection.set_handler(new_handler);
617 let res = unsafe {
618 sys::xmpp_connect_component(
619 self.inner.as_mut(),
620 host.as_ptr(),
621 port.val(),
622 Some(callback),
623 new_handler.as_userdata(),
624 )
625 }
626 .into_result();
627 (res, old_handler)
628 };
629 match res {
630 Ok(_) => {
631 let mut out = self.ctx.take().expect("Internal context is empty, it must never happen");
632 out.consume_connection(self);
633 Ok(out)
634 }
635 Err(e) => {
636 self.handlers.borrow_mut().connection = old_handler;
637 Err(ConnectClientError { conn: self, error: e })
638 }
639 }
640 }
641
642 pub fn connect_raw<CB>(
647 mut self,
648 alt_host: Option<&str>,
649 alt_port: impl Into<Option<u16>>,
650 handler: CB,
651 ) -> Result<Context<'cx, 'cb>, ConnectClientError<'cb, 'cx>>
652 where
653 CB: FnMut(&Context<'cx, 'cb>, &mut Connection<'cb, 'cx>, ConnectionEvent) + Send + 'cb,
654 {
655 let alt_host = FFI(alt_host).send();
656 let alt_port = Nullable::from(alt_port.into());
657 if self.jid().is_none() {
658 return Err(ConnectClientError {
659 conn: self,
660 error: Error::InvalidOperation,
661 });
662 }
663 let callback = Self::connection_handler_cb::<CB>;
664 let new_handler = BoxedHandler::make(
665 &self.handlers,
666 Box::new(handler) as Box<ConnectionCallback>,
667 callback as CbAddr,
668 (),
669 );
670 let (res, old_handler) = {
671 let mut handlers = self.handlers.borrow_mut();
672 let (old_handler, new_handler) = handlers.connection.set_handler(new_handler);
673 let res = unsafe {
674 sys::xmpp_connect_raw(
675 self.inner.as_mut(),
676 alt_host.as_ptr(),
677 alt_port.val(),
678 Some(callback),
679 new_handler.as_userdata(),
680 )
681 }
682 .into_result();
683 (res, old_handler)
684 };
685 match res {
686 Ok(_) => {
687 let mut out = self.ctx.take().expect("Internal context is empty, it must never happen");
688 out.consume_connection(self);
689 Ok(out)
690 }
691 Err(e) => {
692 self.handlers.borrow_mut().connection = old_handler;
693 Err(ConnectClientError { conn: self, error: e })
694 }
695 }
696 }
697
698 #[inline]
699 pub fn open_stream_default(&self) -> Result<()> {
703 unsafe { sys::xmpp_conn_open_stream_default(self.inner.as_ptr()) }.into_result()
704 }
705
706 pub fn open_stream(&self, attributes: &HashMap<&str, &str>) -> Result<()> {
710 let mut storage = Vec::with_capacity(attributes.len() * 2);
711 for (name, val) in attributes {
712 storage.push(FFI(*name).send());
713 storage.push(FFI(*val).send());
714 }
715 let mut attrs = storage.iter().map(|s| s.as_ptr().cast_mut()).collect::<Vec<_>>();
716 unsafe { sys::xmpp_conn_open_stream(self.inner.as_ptr(), attrs.as_mut_ptr(), attrs.len()) }.into_result()
717 }
718
719 #[inline]
720 pub fn tls_start(&self) -> Result<()> {
724 unsafe { sys::xmpp_conn_tls_start(self.inner.as_ptr()) }.into_result()
725 }
726
727 #[inline]
728 pub fn disconnect(&mut self) {
730 unsafe { sys::xmpp_disconnect(self.inner.as_mut()) }
731 }
732
733 #[inline]
734 pub fn send_raw_string(&mut self, data: impl AsRef<str>) {
738 let data = FFI(data.as_ref()).send();
739 unsafe {
740 sys::xmpp_send_raw_string(self.inner.as_mut(), data.as_ptr());
741 }
742 }
743
744 pub fn send_raw(&mut self, data: impl AsRef<[u8]>) {
746 let data = data.as_ref();
747 #[cfg(feature = "log")]
748 if log::log_enabled!(log::Level::Debug) {
749 use std::fmt::Write;
750
751 use crate::LogLevel;
752
753 let ctx = unsafe { sys::xmpp_conn_get_context(self.inner.as_ptr()) };
754 let mut data_str = "SENT: ".to_owned();
755 if let Ok(data) = str::from_utf8(data) {
756 data_str.push_str(data);
757 } else {
758 write!(&mut data_str, "{data:?}").expect("Can't write to string");
759 }
760 unsafe {
761 crate::context::ctx_log(ctx, LogLevel::XMPP_LEVEL_DEBUG, "conn", &data_str);
762 }
763 }
764 unsafe {
765 sys::xmpp_send_raw(self.inner.as_mut(), data.as_ptr().cast::<c_char>(), data.len());
766 }
767 }
768
769 #[inline]
770 pub fn send(&mut self, stanza: &Stanza) {
772 unsafe { sys::xmpp_send(self.inner.as_mut(), stanza.as_ptr()) }
773 }
774
775 pub fn timed_handler_add<CB>(&mut self, handler: CB, period: Duration) -> Option<TimedHandlerId>
780 where
781 CB: FnMut(&Context<'cx, 'cb>, &mut Connection<'cb, 'cx>) -> HandlerResult + Send + 'cb,
782 {
783 let callback = Self::timed_handler_cb::<CB>;
784 let handler = BoxedHandler::make(
785 &self.handlers,
786 Box::new(handler) as Box<TimedCallback>,
787 callback as CbAddr,
788 (),
789 );
790 self.handlers.borrow_mut().timed.store(handler).map(|handler| {
791 unsafe {
792 sys::xmpp_timed_handler_add(
793 self.inner.as_mut(),
794 Some(callback),
795 c_ulong::try_from(period.as_millis()).unwrap_or(c_ulong::MAX),
796 handler.as_userdata(),
797 );
798 }
799 TimedHandlerId(handler.cb_addr())
800 })
801 }
802
803 pub fn timed_handler_delete(&mut self, handler_id: TimedHandlerId) -> usize {
807 #![allow(clippy::needless_pass_by_value)]
808 unsafe {
809 sys::xmpp_timed_handler_delete(
810 self.inner.as_mut(),
811 Some(mem::transmute::<
812 CbAddr,
813 unsafe extern "C" fn(conn: *mut sys::xmpp_conn_t, userdata: *mut c_void) -> c_int,
814 >(handler_id.0)),
815 )
816 }
817 self.handlers.borrow_mut().timed.drop_handler(handler_id.0)
818 }
819
820 pub fn timed_handlers_clear(&mut self) -> usize {
822 let mut removed_count = 0;
823 self.handlers.borrow_mut().timed.retain(|handler| {
824 unsafe {
825 sys::xmpp_timed_handler_delete(
826 self.inner.as_mut(),
827 Some(mem::transmute::<
828 CbAddr,
829 unsafe extern "C" fn(conn: *mut sys::xmpp_conn_t, userdata: *mut c_void) -> c_int,
830 >(handler.cb_addr)),
831 )
832 };
833 removed_count += 1;
834 false
835 });
836 removed_count
837 }
838
839 pub fn id_handler_add<CB>(&mut self, handler: CB, id: impl Into<String>) -> Option<IdHandlerId>
844 where
845 CB: FnMut(&Context<'cx, 'cb>, &mut Connection<'cb, 'cx>, &Stanza) -> HandlerResult + Send + 'cb,
846 {
847 let id = id.into();
848 let ffi_id = FFI(id.as_str()).send();
849 let callback = Self::handler_cb::<CB>;
850 let handler = BoxedHandler::make(
851 &self.handlers,
852 Box::new(handler) as Box<StanzaCallback>,
853 callback as CbAddr,
854 Some(id),
855 );
856 self.handlers.borrow_mut().stanza.store(handler).map(|handler| {
857 unsafe {
858 sys::xmpp_id_handler_add(self.inner.as_mut(), Some(callback), ffi_id.as_ptr(), handler.as_userdata());
859 }
860 IdHandlerId(handler.cb_addr())
861 })
862 }
863
864 pub fn id_handler_delete(&mut self, handler_id: IdHandlerId) -> usize {
868 #![allow(clippy::needless_pass_by_value)]
869 if let Some(fat_handler) = self.handlers.borrow().stanza.validate(handler_id.0) {
870 let id = FFI(fat_handler.extra.as_ref().unwrap().as_str()).send();
871 unsafe {
872 sys::xmpp_id_handler_delete(
873 self.inner.as_mut(),
874 Some(mem::transmute::<
875 CbAddr,
876 unsafe extern "C" fn(
877 conn: *mut sys::xmpp_conn_t,
878 stanza: *mut sys::xmpp_stanza_t,
879 userdata: *mut c_void,
880 ) -> c_int,
881 >(handler_id.0)),
882 id.as_ptr(),
883 )
884 }
885 }
886 self.handlers.borrow_mut().stanza.drop_handler(handler_id.0)
887 }
888
889 pub fn id_handlers_clear(&mut self) -> usize {
891 let mut removed_count = 0;
892 self.handlers.borrow_mut().stanza.retain(|handler| {
893 let keep_it = if let Some(ref id) = handler.extra {
894 unsafe {
895 sys::xmpp_id_handler_delete(
896 self.inner.as_ptr(),
897 Some(mem::transmute::<
898 CbAddr,
899 unsafe extern "C" fn(
900 conn: *mut sys::xmpp_conn_t,
901 stanza: *mut sys::xmpp_stanza_t,
902 userdata: *mut c_void,
903 ) -> c_int,
904 >(handler.cb_addr)),
905 FFI(id.as_str()).send().as_ptr(),
906 )
907 };
908 false
909 } else {
910 true
911 };
912 if !keep_it {
913 removed_count += 1;
914 }
915 keep_it
916 });
917 removed_count
918 }
919
920 pub fn handler_add<CB>(&mut self, handler: CB, ns: Option<&str>, name: Option<&str>, typ: Option<&str>) -> Option<HandlerId>
925 where
926 CB: FnMut(&Context<'cx, 'cb>, &mut Connection<'cb, 'cx>, &Stanza) -> HandlerResult + Send + 'cb,
927 {
928 let ns = FFI(ns).send();
929 let name = FFI(name).send();
930 let typ = FFI(typ).send();
931 let callback = Self::handler_cb::<CB>;
932 let handler = BoxedHandler::make(
933 &self.handlers,
934 Box::new(handler) as Box<StanzaCallback>,
935 callback as CbAddr,
936 None,
937 );
938 self.handlers.borrow_mut().stanza.store(handler).map(|handler| {
939 unsafe {
940 sys::xmpp_handler_add(
941 self.inner.as_mut(),
942 Some(callback),
943 ns.as_ptr(),
944 name.as_ptr(),
945 typ.as_ptr(),
946 handler.as_userdata(),
947 )
948 }
949 HandlerId(handler.cb_addr())
950 })
951 }
952
953 pub fn handler_delete(&mut self, handler_id: HandlerId) -> usize {
959 #![allow(clippy::needless_pass_by_value)]
960 unsafe {
961 sys::xmpp_handler_delete(
962 self.inner.as_mut(),
963 Some(mem::transmute::<
964 CbAddr,
965 unsafe extern "C" fn(conn: *mut sys::xmpp_conn_t, stanza: *mut sys::xmpp_stanza_t, userdata: *mut c_void) -> c_int,
966 >(handler_id.0)),
967 )
968 }
969 self.handlers.borrow_mut().stanza.drop_handler(handler_id.0)
970 }
971
972 pub fn handlers_clear(&mut self) -> usize {
978 let mut removed_count = 0;
979 self.handlers.borrow_mut().stanza.retain(|handler| {
980 let keep_it = if handler.extra.is_none() {
981 unsafe {
982 sys::xmpp_handler_delete(
983 self.inner.as_ptr(),
984 Some(mem::transmute::<
985 CbAddr,
986 unsafe extern "C" fn(
987 conn: *mut sys::xmpp_conn_t,
988 stanza: *mut sys::xmpp_stanza_t,
989 userdata: *mut c_void,
990 ) -> c_int,
991 >(handler.cb_addr)),
992 )
993 };
994 false
995 } else {
996 true
997 };
998 if !keep_it {
999 removed_count += 1;
1000 }
1001 keep_it
1002 });
1003 removed_count
1004 }
1005
1006 #[allow(dead_code)]
1007 pub(crate) fn timed_handlers_same<L, R>(_left: L, _right: R) -> bool
1008 where
1009 L: FnMut(&Context<'cx, 'cb>, &mut Connection<'cb, 'cx>) -> HandlerResult + Send + 'cb,
1010 R: FnMut(&Context<'cx, 'cb>, &mut Connection<'cb, 'cx>) -> HandlerResult + Send + 'cb,
1011 {
1012 ptr::eq(
1013 Self::timed_handler_cb::<L> as *const (),
1014 Self::timed_handler_cb::<R> as *const (),
1015 )
1016 }
1017
1018 #[allow(dead_code)]
1019 pub(crate) fn stanza_handlers_same<L, R>(_left: L, _right: R) -> bool
1020 where
1021 L: FnMut(&Context<'cx, 'cb>, &mut Connection<'cb, 'cx>, &Stanza) -> HandlerResult + Send + 'cb,
1022 R: FnMut(&Context<'cx, 'cb>, &mut Connection<'cb, 'cx>, &Stanza) -> HandlerResult + Send + 'cb,
1023 {
1024 ptr::eq(Self::handler_cb::<L> as *const (), Self::handler_cb::<R> as *const ())
1025 }
1026
1027 #[allow(dead_code)]
1028 pub(crate) fn connection_handlers_same<L, R>(_left: L, _right: R) -> bool
1029 where
1030 L: FnMut(&Context<'cx, 'cb>, &mut Connection<'cb, 'cx>, ConnectionEvent) + Send + 'cb,
1031 R: FnMut(&Context<'cx, 'cb>, &mut Connection<'cb, 'cx>, ConnectionEvent) + Send + 'cb,
1032 {
1033 ptr::eq(
1034 Self::connection_handler_cb::<L> as *const (),
1035 Self::connection_handler_cb::<R> as *const (),
1036 )
1037 }
1038}
1039
1040impl PartialEq for Connection<'_, '_> {
1041 fn eq(&self, other: &Connection) -> bool {
1042 self.inner == other.inner
1043 }
1044}
1045
1046impl Eq for Connection<'_, '_> {}
1047
1048impl Drop for Connection<'_, '_> {
1049 fn drop(&mut self) {
1051 if self.owned {
1052 unsafe {
1053 sys::xmpp_conn_release(self.inner.as_mut());
1054 }
1055 #[cfg(feature = "libstrophe-0_11_0")]
1056 if let Ok(mut handlers) = CERT_FAIL_HANDLERS.write() {
1057 if let Some(handler_id) = self.handlers.borrow_mut().cert_fail_handler_id.take() {
1058 handlers.remove(&handler_id);
1059 }
1060 }
1061 #[cfg(feature = "libstrophe-0_12_0")]
1062 if let Ok(mut handlers) = SOCKOPT_HANDLERS.write() {
1063 if let Some(handler_id) = self.handlers.borrow_mut().sockopt_handler_id.take() {
1064 handlers.remove(&handler_id);
1065 }
1066 }
1067 }
1068 }
1069}
1070
1071unsafe impl Send for Connection<'_, '_> {}
1072
1073#[derive(Debug)]
1074pub struct HandlerId(CbAddr);
1075
1076#[derive(Debug)]
1077pub struct TimedHandlerId(CbAddr);
1078
1079#[derive(Debug)]
1080pub struct IdHandlerId(CbAddr);
1081
1082#[derive(Debug)]
1083pub enum ConnectionEvent<'t, 's> {
1084 RawConnect,
1085 Connect,
1086 Disconnect(Option<ConnectionError<'t, 's>>),
1087 }
1089
1090impl fmt::Display for ConnectionEvent<'_, '_> {
1091 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1092 match self {
1093 ConnectionEvent::RawConnect => write!(f, "Raw connect"),
1094 ConnectionEvent::Connect => write!(f, "Connect"),
1095 ConnectionEvent::Disconnect(None) => write!(f, "Disconnect"),
1096 ConnectionEvent::Disconnect(Some(e)) => write!(f, "Disconnect, error: {e}"),
1097 }
1098 }
1099}
1100
1101#[test]
1102fn callbacks() {
1103 {
1104 let a = |_: &Context, _: &mut Connection| {
1105 print!("1");
1106 HandlerResult::KeepHandler
1107 };
1108 let b = |_: &Context, _: &mut Connection| {
1109 print!("2");
1110 HandlerResult::RemoveHandler
1111 };
1112
1113 assert!(Connection::timed_handlers_same(a, a));
1114 assert!(!Connection::timed_handlers_same(a, b));
1115 }
1116
1117 {
1118 let a = |_: &Context, _: &mut Connection, _: &Stanza| {
1119 print!("1");
1120 HandlerResult::KeepHandler
1121 };
1122 let b = |_: &Context, _: &mut Connection, _: &Stanza| {
1123 print!("2");
1124 HandlerResult::KeepHandler
1125 };
1126
1127 assert!(Connection::stanza_handlers_same(a, a));
1128 assert!(!Connection::stanza_handlers_same(a, b));
1129 }
1130
1131 {
1132 let a = |_: &Context, _: &mut Connection, _: ConnectionEvent| print!("1");
1133 let b = |_: &Context, _: &mut Connection, _: ConnectionEvent| print!("2");
1134
1135 assert!(Connection::connection_handlers_same(a, a));
1136 assert!(!Connection::connection_handlers_same(a, b));
1137 }
1138}