1use crossbeam_queue::SegQueue;
62use either::Either;
63pub use gns_sys as sys;
64use std::sync::atomic::{AtomicI64, Ordering};
65use std::{
66 collections::HashMap,
67 ffi::{c_void, CStr, CString},
68 marker::PhantomData,
69 mem::MaybeUninit,
70 net::{IpAddr, Ipv4Addr, Ipv6Addr},
71 sync::{Arc, Mutex, Weak},
72 time::Duration,
73};
74use sys::*;
75
76fn get_interface() -> *mut ISteamNetworkingSockets {
77 unsafe { SteamAPI_SteamNetworkingSockets_v009() }
78}
79
80fn get_utils() -> *mut ISteamNetworkingUtils {
81 unsafe { SteamAPI_SteamNetworkingUtils_v003() }
82}
83
84pub type GnsMessageNumber = u64;
86
87pub type GnsResult<T> = Result<T, EResult>;
90
91#[repr(transparent)]
94#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
95pub struct GnsError(EResult);
96
97impl Into<EResult> for GnsError {
98 fn into(self) -> EResult {
99 self.0
100 }
101}
102
103impl GnsError {
104 pub fn into_result(self) -> GnsResult<()> {
105 self.into()
106 }
107}
108
109impl From<GnsError> for GnsResult<()> {
110 fn from(GnsError(result): GnsError) -> Self {
111 match result {
112 EResult::k_EResultOK => Ok(()),
113 e => Err(e),
114 }
115 }
116}
117
118pub struct GnsGlobal {
124 utils: GnsUtils,
125 next_queue_id: AtomicI64,
126 event_queues: Mutex<HashMap<i64, Weak<SegQueue<GnsConnectionEvent>>>>,
127}
128
129static GNS_GLOBAL: Mutex<Option<Arc<GnsGlobal>>> = Mutex::new(None);
130
131impl GnsGlobal {
132 pub fn get() -> Result<Arc<Self>, String> {
145 let mut lock = GNS_GLOBAL.lock().unwrap();
146 if let Some(gns_global) = lock.clone() {
147 Ok(gns_global)
148 } else {
149 unsafe {
150 let mut error: SteamDatagramErrMsg = MaybeUninit::zeroed().assume_init();
151 if !GameNetworkingSockets_Init(core::ptr::null(), &mut error) {
152 Err(format!(
153 "{}",
154 CStr::from_ptr(error.as_ptr()).to_str().unwrap_or("")
155 ))
156 } else {
157 let gns_global = Arc::new(GnsGlobal {
158 utils: GnsUtils(()),
159 next_queue_id: AtomicI64::new(0),
160 event_queues: Mutex::new(HashMap::new()),
161 });
162 *lock = Some(gns_global.clone());
163 Ok(gns_global)
164 }
165 }
166 }
167 }
168
169 #[inline]
170 pub fn poll_callbacks(&self) {
171 unsafe {
172 SteamAPI_ISteamNetworkingSockets_RunCallbacks(get_interface());
173 }
174 }
175
176 pub fn utils(&self) -> &GnsUtils {
177 &self.utils
178 }
179
180 fn create_queue(&self) -> (i64, Arc<SegQueue<GnsConnectionEvent>>) {
181 let queue = Arc::new(SegQueue::new());
182 let queue_id = self.next_queue_id.fetch_add(1, Ordering::SeqCst);
183 self.event_queues
184 .lock()
185 .unwrap()
186 .insert(queue_id, Arc::downgrade(&queue));
187 (queue_id, queue)
188 }
189}
190
191#[repr(transparent)]
193pub struct GnsListenSocket(HSteamListenSocket);
194
195#[repr(transparent)]
197pub struct GnsPollGroup(HSteamNetPollGroup);
198
199pub struct IsCreated;
203
204pub trait IsReady {
207 fn queue(&self) -> &SegQueue<GnsConnectionEvent>;
209 fn receive<const K: usize>(&self, messages: &mut [GnsNetworkMessage<ToReceive>; K]) -> usize;
212}
213
214pub struct IsServer {
217 queue: Arc<SegQueue<GnsConnectionEvent>>,
222 listen_socket: GnsListenSocket,
224 poll_group: GnsPollGroup,
226}
227
228impl Drop for IsServer {
229 fn drop(&mut self) {
230 unsafe {
231 SteamAPI_ISteamNetworkingSockets_CloseListenSocket(
232 get_interface(),
233 self.listen_socket.0,
234 );
235 SteamAPI_ISteamNetworkingSockets_DestroyPollGroup(get_interface(), self.poll_group.0);
236 }
237 }
238}
239
240impl IsReady for IsServer {
241 #[inline]
242 fn queue(&self) -> &SegQueue<GnsConnectionEvent> {
243 &self.queue
244 }
245
246 #[inline]
247 fn receive<const K: usize>(&self, messages: &mut [GnsNetworkMessage<ToReceive>; K]) -> usize {
248 unsafe {
249 SteamAPI_ISteamNetworkingSockets_ReceiveMessagesOnPollGroup(
250 get_interface(),
251 self.poll_group.0,
252 messages.as_mut_ptr() as _,
253 K as _,
254 ) as _
255 }
256 }
257}
258
259pub struct IsClient {
262 queue: Arc<SegQueue<GnsConnectionEvent>>,
264 connection: GnsConnection,
266}
267
268impl Drop for IsClient {
269 fn drop(&mut self) {
270 unsafe {
271 SteamAPI_ISteamNetworkingSockets_CloseConnection(
272 get_interface(),
273 self.connection.0,
274 0,
275 core::ptr::null(),
276 false,
277 );
278 }
279 }
280}
281
282impl IsReady for IsClient {
283 #[inline]
284 fn queue(&self) -> &SegQueue<GnsConnectionEvent> {
285 &self.queue
286 }
287
288 #[inline]
289 fn receive<const K: usize>(&self, messages: &mut [GnsNetworkMessage<ToReceive>; K]) -> usize {
290 unsafe {
291 SteamAPI_ISteamNetworkingSockets_ReceiveMessagesOnConnection(
292 get_interface(),
293 self.connection.0,
294 messages.as_mut_ptr() as _,
295 K as _,
296 ) as _
297 }
298 }
299}
300
301pub trait MayDrop {
302 const MUST_DROP: bool;
303}
304
305pub struct ToSend(());
306
307impl MayDrop for ToSend {
308 const MUST_DROP: bool = false;
309}
310
311pub struct ToReceive(());
312
313impl MayDrop for ToReceive {
314 const MUST_DROP: bool = true;
315}
316
317pub type Priority = u32;
319pub type Weight = u16;
321pub type GnsLane = (Priority, Weight);
323pub type GnsLaneId = u16;
325
326#[repr(transparent)]
333pub struct GnsNetworkMessage<T: MayDrop>(*mut ISteamNetworkingMessage, PhantomData<T>);
334
335impl<T> Drop for GnsNetworkMessage<T>
336where
337 T: MayDrop,
338{
339 fn drop(&mut self) {
340 if T::MUST_DROP && !self.0.is_null() {
341 unsafe {
342 SteamAPI_SteamNetworkingMessage_t_Release(self.0);
343 }
344 }
345 }
346}
347
348impl<T> GnsNetworkMessage<T>
349where
350 T: MayDrop,
351{
352 #[inline]
354 pub unsafe fn into_inner(self) -> *mut ISteamNetworkingMessage {
355 self.0
356 }
357
358 #[inline]
359 pub fn payload(&self) -> &[u8] {
360 unsafe {
361 core::slice::from_raw_parts((*self.0).m_pData as *const u8, (*self.0).m_cbSize as _)
362 }
363 }
364
365 #[inline]
366 pub fn message_number(&self) -> u64 {
367 unsafe { (*self.0).m_nMessageNumber as _ }
368 }
369
370 #[inline]
371 pub fn lane(&self) -> GnsLaneId {
372 unsafe { (*self.0).m_idxLane }
373 }
374
375 #[inline]
376 pub fn flags(&self) -> i32 {
377 unsafe { (*self.0).m_nFlags as _ }
378 }
379
380 #[inline]
381 pub fn user_data(&self) -> u64 {
382 unsafe { (*self.0).m_nUserData as _ }
383 }
384
385 #[inline]
386 pub fn connection(&self) -> GnsConnection {
387 GnsConnection(unsafe { (*self.0).m_conn })
388 }
389
390 pub fn connection_user_data(&self) -> u64 {
391 unsafe { (*self.0).m_nConnUserData as _ }
392 }
393}
394
395impl GnsNetworkMessage<ToSend> {
396 #[inline]
397 fn new(
398 ptr: *mut ISteamNetworkingMessage,
399 conn: GnsConnection,
400 flags: i32,
401 payload: &[u8],
402 ) -> Self {
403 GnsNetworkMessage(ptr, PhantomData)
404 .set_flags(flags)
405 .set_payload(payload)
406 .set_connection(conn)
407 }
408
409 #[inline]
410 pub fn set_connection(self, GnsConnection(conn): GnsConnection) -> Self {
411 unsafe { (*self.0).m_conn = conn }
412 self
413 }
414
415 #[inline]
416 pub fn set_payload(self, payload: &[u8]) -> Self {
417 unsafe {
418 core::ptr::copy_nonoverlapping(
419 payload.as_ptr(),
420 (*self.0).m_pData as *mut u8,
421 payload.len(),
422 );
423 }
424 self
425 }
426
427 #[inline]
428 pub fn set_lane(self, lane: u16) -> Self {
429 unsafe { (*self.0).m_idxLane = lane }
430 self
431 }
432
433 #[inline]
434 pub fn set_flags(self, flags: i32) -> Self {
435 unsafe { (*self.0).m_nFlags = flags as _ }
436 self
437 }
438
439 #[inline]
440 pub fn set_user_data(self, userdata: u64) -> Self {
441 unsafe { (*self.0).m_nUserData = userdata as _ }
442 self
443 }
444}
445
446#[repr(transparent)]
447#[derive(Default, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
448pub struct GnsConnection(HSteamNetConnection);
449
450#[derive(Default, Copy, Clone)]
451pub struct GnsConnectionInfo(SteamNetConnectionInfo_t);
452
453impl GnsConnectionInfo {
454 #[inline]
455 pub fn state(&self) -> ESteamNetworkingConnectionState {
456 self.0.m_eState
457 }
458
459 #[inline]
460 pub fn end_reason(&self) -> u32 {
461 self.0.m_eEndReason as u32
462 }
463
464 #[inline]
465 pub fn end_debug(&self) -> &str {
466 unsafe { CStr::from_ptr(self.0.m_szEndDebug.as_ptr()) }
467 .to_str()
468 .unwrap_or("")
469 }
470
471 #[inline]
472 pub fn remote_address(&self) -> IpAddr {
473 let ipv4 = unsafe { self.0.m_addrRemote.__bindgen_anon_1.m_ipv4 };
474 if ipv4.m_8zeros == 0 && ipv4.m_0000 == 0 && ipv4.m_ffff == 0xffff {
475 IpAddr::from(Ipv4Addr::from(ipv4.m_ip))
476 } else {
477 IpAddr::from(Ipv6Addr::from(unsafe {
478 self.0.m_addrRemote.__bindgen_anon_1.m_ipv6
479 }))
480 }
481 }
482
483 #[inline]
484 pub fn remote_port(&self) -> u16 {
485 self.0.m_addrRemote.m_port
486 }
487}
488
489#[derive(Debug, Default, Copy, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)]
490pub struct GnsConnectionRealTimeLaneStatus(SteamNetConnectionRealTimeLaneStatus_t);
491
492impl GnsConnectionRealTimeLaneStatus {
493 #[inline]
494 pub fn pending_bytes_unreliable(&self) -> u32 {
495 self.0.m_cbPendingUnreliable as _
496 }
497
498 #[inline]
499 pub fn pending_bytes_reliable(&self) -> u32 {
500 self.0.m_cbPendingReliable as _
501 }
502
503 #[inline]
504 pub fn bytes_sent_unacked_reliable(&self) -> u32 {
505 self.0.m_cbSentUnackedReliable as _
506 }
507
508 #[inline]
509 pub fn approximated_queue_time(&self) -> Duration {
510 Duration::from_micros(self.0.m_usecQueueTime as _)
511 }
512}
513
514#[derive(Default, Debug, Copy, Clone, PartialOrd, PartialEq)]
515pub struct GnsConnectionRealTimeStatus(SteamNetConnectionRealTimeStatus_t);
516
517impl GnsConnectionRealTimeStatus {
518 #[inline]
519 pub fn state(&self) -> ESteamNetworkingConnectionState {
520 self.0.m_eState
521 }
522
523 #[inline]
524 pub fn ping(&self) -> u32 {
525 self.0.m_nPing as _
526 }
527
528 #[inline]
529 pub fn quality_local(&self) -> f32 {
530 self.0.m_flConnectionQualityLocal
531 }
532
533 #[inline]
534 pub fn quality_remote(&self) -> f32 {
535 self.0.m_flConnectionQualityRemote
536 }
537
538 #[inline]
539 pub fn out_packets_per_sec(&self) -> f32 {
540 self.0.m_flOutPacketsPerSec
541 }
542
543 #[inline]
544 pub fn out_bytes_per_sec(&self) -> f32 {
545 self.0.m_flOutBytesPerSec
546 }
547
548 #[inline]
549 pub fn in_packets_per_sec(&self) -> f32 {
550 self.0.m_flInPacketsPerSec
551 }
552
553 #[inline]
554 pub fn in_bytes_per_sec(&self) -> f32 {
555 self.0.m_flInBytesPerSec
556 }
557
558 #[inline]
559 pub fn send_rate_bytes_per_sec(&self) -> u32 {
560 self.0.m_nSendRateBytesPerSecond as _
561 }
562
563 #[inline]
564 pub fn pending_bytes_unreliable(&self) -> u32 {
565 self.0.m_cbPendingUnreliable as _
566 }
567
568 #[inline]
569 pub fn pending_bytes_reliable(&self) -> u32 {
570 self.0.m_cbPendingReliable as _
571 }
572
573 #[inline]
574 pub fn bytes_sent_unacked_reliable(&self) -> u32 {
575 self.0.m_cbSentUnackedReliable as _
576 }
577
578 #[inline]
579 pub fn approximated_queue_time(&self) -> Duration {
580 Duration::from_micros(self.0.m_usecQueueTime as _)
581 }
582
583 #[inline]
590 pub fn max_jitter_usec(&self) -> Option<i32> {
591 let val = self.0.m_usecMaxJitter;
592 if val < 0 { None } else { Some(val) }
593 }
594}
595
596#[derive(Default, Copy, Clone)]
597pub struct GnsConnectionEvent(SteamNetConnectionStatusChangedCallback_t);
598
599impl GnsConnectionEvent {
600 #[inline]
601 pub fn old_state(&self) -> ESteamNetworkingConnectionState {
602 self.0.m_eOldState
603 }
604
605 #[inline]
606 pub fn connection(&self) -> GnsConnection {
607 GnsConnection(self.0.m_hConn)
608 }
609
610 #[inline]
611 pub fn info(&self) -> GnsConnectionInfo {
612 GnsConnectionInfo(self.0.m_info)
613 }
614}
615
616pub struct GnsSocket<S> {
620 global: Arc<GnsGlobal>,
621 state: S,
622}
623
624impl<S> GnsSocket<S>
625where
626 S: IsReady,
627{
628 #[inline]
631 pub fn get_connection_real_time_status(
632 &self,
633 GnsConnection(conn): GnsConnection,
634 nb_of_lanes: u32,
635 ) -> GnsResult<(
636 GnsConnectionRealTimeStatus,
637 Vec<GnsConnectionRealTimeLaneStatus>,
638 )> {
639 let mut lanes: Vec<GnsConnectionRealTimeLaneStatus> =
640 vec![Default::default(); nb_of_lanes as _];
641 let mut status: GnsConnectionRealTimeStatus = Default::default();
642 GnsError(unsafe {
643 SteamAPI_ISteamNetworkingSockets_GetConnectionRealTimeStatus(
644 get_interface(),
645 conn,
646 &mut status as *mut GnsConnectionRealTimeStatus
647 as *mut SteamNetConnectionRealTimeStatus_t,
648 nb_of_lanes as _,
649 lanes.as_mut_ptr() as *mut GnsConnectionRealTimeLaneStatus
650 as *mut SteamNetConnectionRealTimeLaneStatus_t,
651 )
652 })
653 .into_result()?;
654 Ok((status, lanes))
655 }
656
657 #[inline]
658 pub fn get_connection_info(
659 &self,
660 GnsConnection(conn): GnsConnection,
661 ) -> Option<GnsConnectionInfo> {
662 let mut info: SteamNetConnectionInfo_t = Default::default();
663 if unsafe {
664 SteamAPI_ISteamNetworkingSockets_GetConnectionInfo(get_interface(), conn, &mut info)
665 } {
666 Some(GnsConnectionInfo(info))
667 } else {
668 None
669 }
670 }
671
672 #[inline]
673 pub fn flush_messages_on_connection(
674 &self,
675 GnsConnection(conn): GnsConnection,
676 ) -> GnsResult<()> {
677 GnsError(unsafe {
678 SteamAPI_ISteamNetworkingSockets_FlushMessagesOnConnection(get_interface(), conn)
679 })
680 .into_result()
681 }
682
683 #[inline]
684 pub fn close_connection(
685 &self,
686 GnsConnection(conn): GnsConnection,
687 reason: u32,
688 debug: &str,
689 linger: bool,
690 ) -> bool {
691 let debug_c = CString::new(debug).expect("str; qed;");
692 unsafe {
693 SteamAPI_ISteamNetworkingSockets_CloseConnection(
694 get_interface(),
695 conn,
696 reason as _,
697 debug_c.as_ptr(),
698 linger,
699 )
700 }
701 }
702
703 #[inline]
704 pub fn poll_messages<const K: usize>(
705 &self,
706 mut message_callback: impl FnMut(&GnsNetworkMessage<ToReceive>),
707 ) -> Option<usize> {
708 let mut messages: [GnsNetworkMessage<ToReceive>; K] =
710 unsafe { MaybeUninit::zeroed().assume_init() };
711 let nb_of_messages = self.state.receive(&mut messages);
712 if nb_of_messages == usize::MAX {
713 None
714 } else {
715 for message in messages.into_iter().take(nb_of_messages) {
716 message_callback(&message);
717 }
718 Some(nb_of_messages)
719 }
720 }
721
722 #[inline]
723 pub fn poll_event<const K: usize>(
724 &self,
725 mut event_callback: impl FnMut(GnsConnectionEvent),
726 ) -> usize {
727 let mut processed = 0;
728 'a: while let Some(event) = self.state.queue().pop() {
729 event_callback(event);
730 processed += 1;
731 if processed == K {
732 break 'a;
733 }
734 }
735 processed
736 }
737
738 #[inline]
739 pub fn configure_connection_lanes(
740 &self,
741 GnsConnection(connection): GnsConnection,
742 lanes: &[GnsLane],
743 ) -> GnsResult<()> {
744 let (priorities, weights): (Vec<_>, Vec<_>) = lanes.iter().copied().unzip();
745 GnsError(unsafe {
746 SteamAPI_ISteamNetworkingSockets_ConfigureConnectionLanes(
747 get_interface(),
748 connection,
749 lanes.len() as _,
750 priorities.as_ptr() as *const u32 as *const i32,
751 weights.as_ptr(),
752 )
753 })
754 .into_result()
755 }
756
757 #[inline]
758 pub fn send_messages(
759 &self,
760 messages: Vec<GnsNetworkMessage<ToSend>>,
761 ) -> Vec<Either<GnsMessageNumber, EResult>> {
762 let mut result = vec![0i64; messages.len()];
763 unsafe {
764 SteamAPI_ISteamNetworkingSockets_SendMessages(
765 get_interface(),
766 messages.len() as _,
767 messages.as_ptr() as *const _,
768 result.as_mut_ptr(),
769 );
770 }
771 result
772 .into_iter()
773 .map(|value| {
774 if value < 0 {
775 Either::Right(unsafe { core::mem::transmute((-value) as u32) })
776 } else {
777 Either::Left(value as _)
778 }
779 })
780 .collect()
781 }
782}
783
784impl GnsSocket<IsCreated> {
785 unsafe extern "C" fn on_connection_state_changed(
788 info: &mut SteamNetConnectionStatusChangedCallback_t,
789 ) {
790 let gns_global = GnsGlobal::get()
791 .expect("GnsGlobal should be initialized");
793
794 let queue_id = info.m_info.m_nUserData as _;
795 let mut queues = gns_global.event_queues.lock().unwrap();
796 if let Some(queue) = queues.get(&queue_id) {
797 if let Some(queue) = queue.upgrade() {
798 queue.push(GnsConnectionEvent(*info));
799 } else {
800 queues.remove(&queue_id);
802 }
803 }
804 }
805
806 #[inline]
808 pub fn new(global: Arc<GnsGlobal>) -> Self {
809 GnsSocket {
810 global,
811 state: IsCreated,
812 }
813 }
814
815 #[inline]
816 fn setup_common(
817 address: IpAddr,
818 port: u16,
819 queue_id: int64,
820 ) -> (SteamNetworkingIPAddr, [SteamNetworkingConfigValue_t; 2]) {
821 let addr = SteamNetworkingIPAddr {
822 __bindgen_anon_1: match address {
823 IpAddr::V4(address) => SteamNetworkingIPAddr__bindgen_ty_2 {
824 m_ipv4: SteamNetworkingIPAddr_IPv4MappedAddress {
825 m_8zeros: 0,
826 m_0000: 0,
827 m_ffff: 0xffff,
828 m_ip: address.octets(),
829 },
830 },
831 IpAddr::V6(address) => SteamNetworkingIPAddr__bindgen_ty_2 {
832 m_ipv6: address.octets(),
833 },
834 },
835 m_port: port,
836 };
837 let options = [SteamNetworkingConfigValue_t {
838 m_eDataType: ESteamNetworkingConfigDataType::k_ESteamNetworkingConfig_Ptr,
839 m_eValue: ESteamNetworkingConfigValue::k_ESteamNetworkingConfig_Callback_ConnectionStatusChanged,
840 m_val: SteamNetworkingConfigValue_t__bindgen_ty_1 {
841 m_ptr: Self::on_connection_state_changed as *const fn(&SteamNetConnectionStatusChangedCallback_t) as *mut c_void
842 }
843 }, SteamNetworkingConfigValue_t {
844 m_eDataType: ESteamNetworkingConfigDataType::k_ESteamNetworkingConfig_Int64,
845 m_eValue: ESteamNetworkingConfigValue::k_ESteamNetworkingConfig_ConnectionUserData,
846 m_val: SteamNetworkingConfigValue_t__bindgen_ty_1 {
847 m_int64: queue_id
848 }
849 }];
850 (addr, options)
851 }
852
853 #[inline]
855 pub fn listen(self, address: IpAddr, port: u16) -> Result<GnsSocket<IsServer>, ()> {
856 let (queue_id, queue) = self.global.create_queue();
857 let (addr, options) = Self::setup_common(address, port, queue_id);
858 let listen_socket = unsafe {
859 SteamAPI_ISteamNetworkingSockets_CreateListenSocketIP(
860 get_interface(),
861 &addr,
862 options.len() as _,
863 options.as_ptr(),
864 )
865 };
866 if listen_socket == k_HSteamListenSocket_Invalid {
867 Err(())
868 } else {
869 let poll_group =
870 unsafe { SteamAPI_ISteamNetworkingSockets_CreatePollGroup(get_interface()) };
871 if poll_group == k_HSteamNetPollGroup_Invalid {
872 Err(())
873 } else {
874 Ok(GnsSocket {
875 global: self.global,
876 state: IsServer {
877 queue,
878 listen_socket: GnsListenSocket(listen_socket),
879 poll_group: GnsPollGroup(poll_group),
880 },
881 })
882 }
883 }
884 }
885
886 #[inline]
888 pub fn connect(self, address: IpAddr, port: u16) -> Result<GnsSocket<IsClient>, ()> {
889 let (queue_id, queue) = self.global.create_queue();
890 let (addr, options) = Self::setup_common(address, port, queue_id);
891 let connection = unsafe {
892 SteamAPI_ISteamNetworkingSockets_ConnectByIPAddress(
893 get_interface(),
894 &addr,
895 options.len() as _,
896 options.as_ptr(),
897 )
898 };
899 if connection == k_HSteamNetConnection_Invalid {
900 Err(())
901 } else {
902 Ok(GnsSocket {
903 global: self.global,
904 state: IsClient {
905 queue,
906 connection: GnsConnection(connection),
907 },
908 })
909 }
910 }
911}
912
913impl GnsSocket<IsServer> {
914 #[inline]
916 pub fn accept(&self, connection: GnsConnection) -> GnsResult<()> {
917 GnsError(unsafe {
918 SteamAPI_ISteamNetworkingSockets_AcceptConnection(get_interface(), connection.0)
919 })
920 .into_result()?;
921 if !unsafe {
922 SteamAPI_ISteamNetworkingSockets_SetConnectionPollGroup(
923 get_interface(),
924 connection.0,
925 self.state.poll_group.0,
926 )
927 } {
928 panic!("It's impossible not to be able to set the connection poll group as both the poll group and the connection must be valid at this point.");
929 }
930 Ok(())
931 }
932}
933
934impl GnsSocket<IsClient> {
935 #[inline]
937 pub fn connection(&self) -> GnsConnection {
938 self.state.connection
939 }
940}
941
942pub enum GnsConfig<'a> {
944 Float(f32),
945 Int32(u32),
946 String(&'a str),
947 Ptr(*mut c_void),
948}
949
950pub struct GnsUtils(());
951
952type MsgPtr = *const ::std::os::raw::c_char;
953
954impl GnsUtils {
955 #[inline]
956 pub fn enable_debug_output(
957 &self,
958 ty: ESteamNetworkingSocketsDebugOutputType,
959 f: fn(ty: ESteamNetworkingSocketsDebugOutputType, msg: String),
960 ) {
961 static mut F: Option<fn(ty: ESteamNetworkingSocketsDebugOutputType, msg: String)> = None;
962 unsafe {
963 F = Some(f);
964 }
965 unsafe extern "C" fn debug(ty: ESteamNetworkingSocketsDebugOutputType, msg: MsgPtr) {
966 F.unwrap()(ty, CStr::from_ptr(msg).to_string_lossy().to_string());
967 }
968 unsafe {
969 SteamAPI_ISteamNetworkingUtils_SetDebugOutputFunction(get_utils(), ty, Some(debug));
970 }
971 }
972
973 #[inline]
976 pub fn allocate_message(
977 &self,
978 conn: GnsConnection,
979 flags: i32,
980 payload: &[u8],
981 ) -> GnsNetworkMessage<ToSend> {
982 let message_ptr = unsafe {
983 SteamAPI_ISteamNetworkingUtils_AllocateMessage(get_utils(), payload.len() as _)
984 };
985 GnsNetworkMessage::new(message_ptr, conn, flags, payload)
986 }
987
988 #[inline]
990 pub fn set_global_config_value<'a>(
991 &self,
992 typ: ESteamNetworkingConfigValue,
993 value: GnsConfig<'a>,
994 ) -> Result<(), ()> {
995 let result = match value {
996 GnsConfig::Float(x) => unsafe {
997 SteamAPI_ISteamNetworkingUtils_SetGlobalConfigValueFloat(get_utils(), typ, x)
998 },
999 GnsConfig::Int32(x) => unsafe {
1000 SteamAPI_ISteamNetworkingUtils_SetGlobalConfigValueInt32(get_utils(), typ, x as i32)
1001 },
1002 GnsConfig::String(x) => unsafe {
1003 SteamAPI_ISteamNetworkingUtils_SetGlobalConfigValueString(
1004 get_utils(),
1005 typ,
1006 CString::new(x).expect("str; qed;").as_c_str().as_ptr(),
1007 )
1008 },
1009 GnsConfig::Ptr(x) => unsafe {
1010 SteamAPI_ISteamNetworkingUtils_SetGlobalConfigValuePtr(get_utils(), typ, x)
1011 },
1012 };
1013 if result {
1014 Ok(())
1015 } else {
1016 Err(())
1017 }
1018 }
1019
1020 #[inline]
1022 pub fn set_connection_config_value<'a>(
1023 &self,
1024 conn: GnsConnection,
1025 typ: ESteamNetworkingConfigValue,
1026 value: GnsConfig<'a>,
1027 ) -> Result<(), ()> {
1028 let result = match value {
1029 GnsConfig::Float(x) => unsafe {
1030 SteamAPI_ISteamNetworkingUtils_SetConnectionConfigValueFloat(
1031 get_utils(), conn.0, typ, x,
1032 )
1033 },
1034 GnsConfig::Int32(x) => unsafe {
1035 SteamAPI_ISteamNetworkingUtils_SetConnectionConfigValueInt32(
1036 get_utils(), conn.0, typ, x as i32,
1037 )
1038 },
1039 GnsConfig::String(x) => unsafe {
1040 SteamAPI_ISteamNetworkingUtils_SetConnectionConfigValueString(
1041 get_utils(),
1042 conn.0,
1043 typ,
1044 CString::new(x).expect("str; qed;").as_c_str().as_ptr(),
1045 )
1046 },
1047 GnsConfig::Ptr(_) => return Err(()),
1048 };
1049 if result {
1050 Ok(())
1051 } else {
1052 Err(())
1053 }
1054 }
1055}