steamworks/
networking_sockets_callback.rs

1use crate::networking_sockets::NetConnection;
2use crate::networking_types::{
3    AppNetConnectionEnd, NetConnectionEnd, NetConnectionStatusChanged, NetworkingConnectionState,
4};
5use crate::{register_callback, CallbackHandle, Inner};
6use std::sync::{Arc, Weak};
7use steamworks_sys as sys;
8use sys::ISteamNetworkingSockets;
9
10/// All independent connections (to a remote host) and listening sockets share the same Callback for
11/// `NetConnectionStatusChangedCallback`. This function either returns the existing handle, or creates a new
12/// handler.
13pub(crate) fn get_or_create_connection_callback(
14    inner: Arc<Inner>,
15    sockets: *mut ISteamNetworkingSockets,
16) -> Arc<CallbackHandle> {
17    let mut network_socket_data = inner.networking_sockets_data.lock().unwrap();
18    if let Some(callback) = network_socket_data.connection_callback.upgrade() {
19        callback
20    } else {
21        let handler = ConnectionCallbackHandler {
22            inner: Arc::downgrade(&inner),
23            sockets,
24        };
25        let callback = unsafe {
26            register_callback(&inner, move |event: NetConnectionStatusChanged| {
27                handler.callback(event);
28            })
29        };
30
31        let callback = Arc::new(callback);
32        network_socket_data.connection_callback = Arc::downgrade(&callback);
33        callback
34    }
35}
36
37pub(crate) struct ConnectionCallbackHandler {
38    inner: Weak<Inner>,
39    sockets: *mut ISteamNetworkingSockets,
40}
41
42unsafe impl Send for ConnectionCallbackHandler {}
43unsafe impl Sync for ConnectionCallbackHandler {}
44
45impl ConnectionCallbackHandler {
46    pub(crate) fn callback(&self, event: NetConnectionStatusChanged) {
47        if let Some(socket) = event.connection_info.listen_socket() {
48            self.listen_socket_callback(socket, event);
49        } else {
50            self.independent_connection_callback(event);
51        }
52    }
53
54    fn listen_socket_callback(
55        &self,
56        socket_handle: sys::HSteamListenSocket,
57        event: NetConnectionStatusChanged,
58    ) {
59        if let Some(inner) = self.inner.upgrade() {
60            let data = inner.networking_sockets_data.lock().unwrap();
61            if let Some((socket, sender)) = data
62                .sockets
63                .get(&socket_handle)
64                .and_then(|(socket, sender)| socket.upgrade().map(|socket| (socket, sender)))
65            {
66                let connection_handle = event.connection;
67                let state = event.connection_info.state().expect("invalid state");
68                if let Ok(event) = event.into_listen_socket_event(socket) {
69                    if let Err(_err) = sender.send(event) {
70                        // If the main socket was dropped, but the inner socket still exists, reject all new connections,
71                        // as there's no way to accept them.
72                        if let NetworkingConnectionState::Connecting = state {
73                            self.reject_connection(connection_handle);
74                        }
75                    }
76                } else {
77                    // Ignore events that couldn't be converted
78                }
79            }
80        }
81    }
82
83    fn reject_connection(&self, connection_handle: sys::HSteamNetConnection) {
84        if let Some(inner) = self.inner.upgrade() {
85            NetConnection::new_internal(connection_handle, self.sockets, inner.clone()).close(
86                NetConnectionEnd::App(AppNetConnectionEnd::generic_normal()).into(),
87                Some("no new connections will be accepted"),
88                false,
89            );
90        }
91    }
92
93    fn independent_connection_callback(&self, _event: NetConnectionStatusChanged) {
94        // TODO: Handle event for independent connections
95    }
96}