1use crate::{
2 error::Error, ffi::get_last_error, ip::NrfSockAddr, lte_link::LteLink, CancellationToken,
3};
4use core::net::SocketAddr;
5use core::{
6 cell::RefCell,
7 ops::{BitOr, BitOrAssign, Deref, Neg},
8 sync::atomic::{AtomicU8, Ordering},
9 task::{Poll, Waker},
10};
11use critical_section::Mutex;
12use num_enum::{IntoPrimitive, TryFromPrimitive};
13
14const WAKER_SLOTS: usize = (nrfxlib_sys::NRF_MODEM_MAX_SOCKET_COUNT * 2) as usize;
17const WAKER_INIT: Option<(Waker, i32, SocketDirection)> = None;
18#[allow(clippy::type_complexity)]
19static SOCKET_WAKERS: Mutex<RefCell<[Option<(Waker, i32, SocketDirection)>; WAKER_SLOTS]>> =
20 Mutex::new(RefCell::new([WAKER_INIT; WAKER_SLOTS]));
21
22fn wake_sockets(socket_fd: i32, socket_dir: SocketDirection) {
23 critical_section::with(|cs| {
24 SOCKET_WAKERS
25 .borrow_ref_mut(cs)
26 .iter_mut()
27 .filter(|slot| {
28 if let Some((_, fd, dir)) = slot {
29 *fd == socket_fd && dir.same_direction(socket_dir)
30 } else {
31 false
32 }
33 })
34 .for_each(|slot| {
35 let (waker, _, _) = slot.take().unwrap();
36 waker.wake();
37 });
38 });
39}
40
41fn register_socket_waker(waker: Waker, socket_fd: i32, socket_dir: SocketDirection) {
42 critical_section::with(|cs| {
43 let mut wakers = SOCKET_WAKERS.borrow_ref_mut(cs);
45
46 let empty_waker = wakers.iter_mut().find(|waker| {
48 waker.is_none()
49 || waker.as_ref().map(|(_, fd, dir)| (*fd, *dir)) == Some((socket_fd, socket_dir))
50 });
51
52 if let Some(empty_waker) = empty_waker {
53 *empty_waker = Some((waker, socket_fd, socket_dir));
55 } else {
56 wakers
59 .first_mut()
60 .unwrap()
61 .replace((waker, socket_fd, socket_dir))
62 .unwrap()
63 .0
64 .wake();
65 }
66 });
67}
68
69unsafe extern "C" fn socket_poll_callback(pollfd: *mut nrfxlib_sys::nrf_pollfd) {
70 let pollfd = *pollfd;
71
72 let mut direction = SocketDirection::Neither;
73
74 if pollfd.revents as u32 & nrfxlib_sys::NRF_POLLIN != 0 {
75 direction |= SocketDirection::In;
76 }
77
78 if pollfd.revents as u32 & nrfxlib_sys::NRF_POLLOUT != 0 {
79 direction |= SocketDirection::Out;
80 }
81
82 if pollfd.revents as u32
83 & (nrfxlib_sys::NRF_POLLERR | nrfxlib_sys::NRF_POLLHUP | nrfxlib_sys::NRF_POLLNVAL)
84 != 0
85 {
86 direction |= SocketDirection::Either;
87 }
88
89 #[cfg(feature = "defmt")]
90 defmt::trace!(
91 "Socket poll callback. fd: {}, revents: {:X}, direction: {}",
92 pollfd.fd,
93 pollfd.revents,
94 direction
95 );
96
97 wake_sockets(pollfd.fd, direction);
98}
99
100#[derive(Clone, Copy, Debug, PartialEq, Eq)]
102#[cfg_attr(feature = "defmt", derive(defmt::Format))]
103enum SocketDirection {
104 Neither,
106 In,
108 Out,
110 Either,
112}
113
114impl BitOrAssign for SocketDirection {
115 fn bitor_assign(&mut self, rhs: Self) {
116 *self = *self | rhs;
117 }
118}
119
120impl BitOr for SocketDirection {
121 type Output = SocketDirection;
122
123 fn bitor(self, rhs: Self) -> Self::Output {
124 match (self, rhs) {
125 (SocketDirection::Neither, rhs) => rhs,
126 (lhs, SocketDirection::Neither) => lhs,
127 (SocketDirection::In, SocketDirection::In) => SocketDirection::In,
128 (SocketDirection::Out, SocketDirection::Out) => SocketDirection::Out,
129 (SocketDirection::In, SocketDirection::Out) => SocketDirection::Either,
130 (SocketDirection::Out, SocketDirection::In) => SocketDirection::Either,
131 (SocketDirection::Either, _) => SocketDirection::Either,
132 (_, SocketDirection::Either) => SocketDirection::Either,
133 }
134 }
135}
136
137impl SocketDirection {
138 fn same_direction(&self, other: Self) -> bool {
139 match (self, other) {
140 (SocketDirection::Neither, _) => false,
141 (_, SocketDirection::Neither) => false,
142 (SocketDirection::In, SocketDirection::In) => true,
143 (SocketDirection::Out, SocketDirection::Out) => true,
144 (SocketDirection::In, SocketDirection::Out) => false,
145 (SocketDirection::Out, SocketDirection::In) => false,
146 (_, SocketDirection::Either) => true,
147 (SocketDirection::Either, _) => true,
148 }
149 }
150}
151
152#[derive(Debug)]
158#[cfg_attr(feature = "defmt", derive(defmt::Format))]
159pub struct Socket {
160 fd: i32,
162 family: SocketFamily,
164 link: Option<LteLink>,
167 split: bool,
169}
170
171impl Socket {
172 pub async fn create(
174 family: SocketFamily,
175 s_type: SocketType,
176 protocol: SocketProtocol,
177 ) -> Result<Self, Error> {
178 #[cfg(feature = "defmt")]
179 defmt::debug!(
180 "Creating socket with family: {}, type: {}, protocol: {}",
181 family as u32 as i32,
182 s_type as u32 as i32,
183 protocol as u32 as i32
184 );
185
186 if unsafe { !nrfxlib_sys::nrf_modem_is_initialized() } {
187 return Err(Error::ModemNotInitialized);
188 }
189
190 let link = LteLink::new().await?;
192
193 let fd = unsafe {
195 nrfxlib_sys::nrf_socket(
196 family as u32 as i32,
197 s_type as u32 as i32,
198 protocol as u32 as i32,
199 )
200 };
201
202 if fd == -1 {
204 return Err(Error::NrfError(get_last_error()));
205 }
206
207 unsafe {
209 let result = nrfxlib_sys::nrf_fcntl(
210 fd,
211 nrfxlib_sys::NRF_F_SETFL as _,
212 nrfxlib_sys::NRF_O_NONBLOCK as _,
213 );
214
215 if result == -1 {
216 return Err(Error::NrfError(get_last_error()));
217 }
218 }
219
220 let poll_callback = nrfxlib_sys::nrf_modem_pollcb {
222 callback: Some(socket_poll_callback),
223 events: (nrfxlib_sys::NRF_POLLIN | nrfxlib_sys::NRF_POLLOUT) as _, oneshot: false,
225 };
226
227 unsafe {
228 let result = nrfxlib_sys::nrf_setsockopt(
229 fd,
230 nrfxlib_sys::NRF_SOL_SOCKET as _,
231 nrfxlib_sys::NRF_SO_POLLCB as _,
232 (&poll_callback as *const nrfxlib_sys::nrf_modem_pollcb).cast(),
233 core::mem::size_of::<nrfxlib_sys::nrf_modem_pollcb>() as u32,
234 );
235
236 if result == -1 {
237 return Err(Error::NrfError(get_last_error()));
238 }
239 }
240
241 Ok(Socket {
242 fd,
243 family,
244 link: Some(link),
245 split: false,
246 })
247 }
248
249 pub fn as_raw_fd(&self) -> i32 {
251 self.fd
252 }
253
254 pub async fn split(mut self) -> Result<(SplitSocketHandle, SplitSocketHandle), Error> {
260 let index = SplitSocketHandle::get_new_spot();
261 self.split = true;
262
263 Ok((
264 SplitSocketHandle {
265 inner: Some(Socket {
266 fd: self.fd,
267 family: self.family,
268 link: Some(LteLink::new().await?),
269 split: true,
270 }),
271 index,
272 },
273 SplitSocketHandle {
274 inner: Some(self),
275 index,
276 },
277 ))
278 }
279
280 pub async fn connect(&self, address: SocketAddr) -> Result<(), Error> {
284 unsafe {
285 self.connect_with_cancellation(address, &Default::default())
286 .await
287 }
288 }
289
290 pub async unsafe fn connect_with_cancellation(
298 &self,
299 address: SocketAddr,
300 token: &CancellationToken,
301 ) -> Result<(), Error> {
302 #[cfg(feature = "defmt")]
303 defmt::debug!(
304 "Connecting socket {} to {:?}",
305 self.fd,
306 defmt::Debug2Format(&address)
307 );
308
309 token.bind_to_current_task().await;
310
311 self.link
314 .as_ref()
315 .unwrap()
316 .wait_for_link_with_cancellation(token)
317 .await?;
318
319 core::future::poll_fn(|cx| {
320 #[cfg(feature = "defmt")]
321 defmt::trace!("Connecting socket {}", self.fd);
322
323 if token.is_cancelled() {
324 return Poll::Ready(Err(Error::OperationCancelled));
325 }
326
327 let address = NrfSockAddr::from(address);
329
330 register_socket_waker(cx.waker().clone(), self.fd, SocketDirection::Either);
331
332 let mut connect_result = unsafe {
334 nrfxlib_sys::nrf_connect(self.fd, address.as_ptr(), address.size() as u32)
335 } as isize;
336
337 const NRF_EINPROGRESS: isize = nrfxlib_sys::NRF_EINPROGRESS as isize;
338 const NRF_EALREADY: isize = nrfxlib_sys::NRF_EALREADY as isize;
339 const NRF_EISCONN: isize = nrfxlib_sys::NRF_EISCONN as isize;
340
341 if connect_result == -1 {
342 connect_result = get_last_error();
343 }
344
345 #[cfg(feature = "defmt")]
346 defmt::trace!("Connect result {}", connect_result);
347
348 match connect_result {
349 0 => Poll::Ready(Ok(())),
351 NRF_EISCONN => Poll::Ready(Ok(())),
353 NRF_EINPROGRESS | NRF_EALREADY => Poll::Pending,
355 error => Poll::Ready(Err(Error::NrfError(error))),
357 }
358 })
359 .await?;
360
361 Ok(())
362 }
363
364 pub async fn bind(&self, address: SocketAddr) -> Result<(), Error> {
368 unsafe {
369 self.bind_with_cancellation(address, &Default::default())
370 .await
371 }
372 }
373
374 pub async unsafe fn bind_with_cancellation(
382 &self,
383 address: SocketAddr,
384 token: &CancellationToken,
385 ) -> Result<(), Error> {
386 #[cfg(feature = "defmt")]
387 defmt::debug!(
388 "Binding socket {} to {:?}",
389 self.fd,
390 defmt::Debug2Format(&address)
391 );
392
393 token.bind_to_current_task().await;
394
395 self.link
398 .as_ref()
399 .unwrap()
400 .wait_for_link_with_cancellation(token)
401 .await?;
402
403 core::future::poll_fn(|cx| {
404 #[cfg(feature = "defmt")]
405 defmt::trace!("Binding socket {}", self.fd);
406
407 if token.is_cancelled() {
408 return Poll::Ready(Err(Error::OperationCancelled));
409 }
410
411 let address = NrfSockAddr::from(address);
413
414 register_socket_waker(cx.waker().clone(), self.fd, SocketDirection::Either);
415
416 let mut bind_result =
418 unsafe { nrfxlib_sys::nrf_bind(self.fd, address.as_ptr(), address.size() as u32) }
419 as isize;
420
421 const NRF_EINPROGRESS: isize = nrfxlib_sys::NRF_EINPROGRESS as isize;
422 const NRF_EALREADY: isize = nrfxlib_sys::NRF_EALREADY as isize;
423 const NRF_EISCONN: isize = nrfxlib_sys::NRF_EISCONN as isize;
424
425 if bind_result == -1 {
426 bind_result = get_last_error();
427 }
428
429 #[cfg(feature = "defmt")]
430 defmt::trace!("Bind result {}", bind_result);
431
432 match bind_result {
433 0 => Poll::Ready(Ok(())),
435 NRF_EISCONN => Poll::Ready(Ok(())),
437 NRF_EINPROGRESS | NRF_EALREADY => Poll::Pending,
439 error => Poll::Ready(Err(Error::NrfError(error))),
441 }
442 })
443 .await?;
444
445 Ok(())
446 }
447
448 pub async fn write(&self, buffer: &[u8]) -> Result<usize, Error> {
452 self.write_with_cancellation(buffer, &Default::default())
453 .await
454 }
455
456 pub async fn write_with_cancellation(
462 &self,
463 buffer: &[u8],
464 token: &CancellationToken,
465 ) -> Result<usize, Error> {
466 token.bind_to_current_task().await;
467
468 core::future::poll_fn(|cx| {
469 #[cfg(feature = "defmt")]
470 defmt::trace!("Sending with socket {}", self.fd);
471
472 if token.is_cancelled() {
473 return Poll::Ready(Err(Error::OperationCancelled));
474 }
475
476 register_socket_waker(cx.waker().clone(), self.fd, SocketDirection::Out);
477
478 let mut send_result = unsafe {
479 nrfxlib_sys::nrf_send(self.fd, buffer.as_ptr() as *const _, buffer.len(), 0)
480 };
481
482 if send_result == -1 {
483 send_result = get_last_error().abs().neg();
484 }
485
486 #[cfg(feature = "defmt")]
487 defmt::trace!("Send result {}", send_result);
488
489 const NRF_EWOULDBLOCK: isize = -(nrfxlib_sys::NRF_EWOULDBLOCK as isize);
490 const NRF_ENOTCONN: isize = -(nrfxlib_sys::NRF_ENOTCONN as isize);
491
492 match send_result {
493 0 if !buffer.is_empty() => Poll::Ready(Err(Error::Disconnected)),
494 NRF_ENOTCONN => Poll::Ready(Err(Error::Disconnected)),
495 bytes_sent @ 0.. => Poll::Ready(Ok(bytes_sent as usize)),
496 NRF_EWOULDBLOCK => Poll::Pending,
497 error => Poll::Ready(Err(Error::NrfError(error))),
498 }
499 })
500 .await
501 }
502
503 pub async fn receive(&self, buffer: &mut [u8]) -> Result<usize, Error> {
507 self.receive_with_cancellation(buffer, &Default::default())
508 .await
509 }
510
511 pub async fn receive_with_cancellation(
517 &self,
518 buffer: &mut [u8],
519 token: &CancellationToken,
520 ) -> Result<usize, Error> {
521 token.bind_to_current_task().await;
522
523 core::future::poll_fn(|cx| {
524 #[cfg(feature = "defmt")]
525 defmt::trace!("Receiving with socket {}", self.fd);
526
527 if token.is_cancelled() {
528 return Poll::Ready(Err(Error::OperationCancelled));
529 }
530
531 register_socket_waker(cx.waker().clone(), self.fd, SocketDirection::In);
532
533 let mut receive_result = unsafe {
534 nrfxlib_sys::nrf_recv(self.fd, buffer.as_mut_ptr() as *mut _, buffer.len(), 0)
535 };
536
537 if receive_result == -1 {
538 receive_result = get_last_error().abs().neg();
539 }
540
541 #[cfg(feature = "defmt")]
542 defmt::trace!("Receive result {}", receive_result);
543
544 const NRF_EWOULDBLOCK: isize = -(nrfxlib_sys::NRF_EWOULDBLOCK as isize);
545 const NRF_ENOTCONN: isize = -(nrfxlib_sys::NRF_ENOTCONN as isize);
546 const NRF_EMSGSIZE: isize = -(nrfxlib_sys::NRF_EMSGSIZE as isize);
547
548 match receive_result {
549 0 if !buffer.is_empty() => Poll::Ready(Err(Error::Disconnected)),
550 NRF_ENOTCONN => Poll::Ready(Err(Error::Disconnected)),
551 NRF_EMSGSIZE => Poll::Ready(Err(Error::TlsPacketTooBig)),
552 bytes_received @ 0.. => Poll::Ready(Ok(bytes_received as usize)),
553 NRF_EWOULDBLOCK => Poll::Pending,
554 error => Poll::Ready(Err(Error::NrfError(error))),
555 }
556 })
557 .await
558 }
559
560 pub async fn receive_from(&self, buffer: &mut [u8]) -> Result<(usize, SocketAddr), Error> {
564 self.receive_from_with_cancellation(buffer, &Default::default())
565 .await
566 }
567
568 pub async fn receive_from_with_cancellation(
574 &self,
575 buffer: &mut [u8],
576 token: &CancellationToken,
577 ) -> Result<(usize, SocketAddr), Error> {
578 token.bind_to_current_task().await;
579
580 core::future::poll_fn(|cx| {
581 #[cfg(feature = "defmt")]
582 defmt::trace!("Receiving with socket {}", self.fd);
583
584 if token.is_cancelled() {
585 return Poll::Ready(Err(Error::OperationCancelled));
586 }
587
588 let mut socket_addr_store =
590 [0u8; core::mem::size_of::<nrfxlib_sys::nrf_sockaddr_in6>()];
591 let socket_addr_ptr = socket_addr_store.as_mut_ptr() as *mut nrfxlib_sys::nrf_sockaddr;
592 let mut socket_addr_len = socket_addr_store.len() as u32;
593
594 register_socket_waker(cx.waker().clone(), self.fd, SocketDirection::In);
595
596 let mut receive_result = unsafe {
597 nrfxlib_sys::nrf_recvfrom(
598 self.fd,
599 buffer.as_mut_ptr() as *mut _,
600 buffer.len(),
601 0,
602 socket_addr_ptr,
603 &mut socket_addr_len as *mut u32,
604 )
605 };
606
607 if receive_result == -1 {
608 receive_result = get_last_error().abs().neg();
609 }
610
611 #[cfg(feature = "defmt")]
612 defmt::trace!("Receive result {}", receive_result);
613
614 const NRF_EWOULDBLOCK: isize = -(nrfxlib_sys::NRF_EWOULDBLOCK as isize);
615 const NRF_ENOTCONN: isize = -(nrfxlib_sys::NRF_ENOTCONN as isize);
616
617 match receive_result {
618 0 if !buffer.is_empty() => Poll::Ready(Err(Error::Disconnected)),
619 NRF_ENOTCONN => Poll::Ready(Err(Error::Disconnected)),
620 bytes_received @ 0.. => Poll::Ready(Ok((bytes_received as usize, {
621 unsafe { (*socket_addr_ptr).sa_family = self.family as u16 }
622 NrfSockAddr::from(socket_addr_ptr as *const _).into()
623 }))),
624 NRF_EWOULDBLOCK => Poll::Pending,
625 error => Poll::Ready(Err(Error::NrfError(error))),
626 }
627 })
628 .await
629 }
630
631 pub async fn send_to(&self, buffer: &[u8], address: SocketAddr) -> Result<usize, Error> {
635 self.send_to_with_cancellation(buffer, address, &Default::default())
636 .await
637 }
638
639 pub async fn send_to_with_cancellation(
645 &self,
646 buffer: &[u8],
647 address: SocketAddr,
648 token: &CancellationToken,
649 ) -> Result<usize, Error> {
650 token.bind_to_current_task().await;
651
652 core::future::poll_fn(|cx| {
653 #[cfg(feature = "defmt")]
654 defmt::trace!("Sending with socket {}", self.fd);
655
656 if token.is_cancelled() {
657 return Poll::Ready(Err(Error::OperationCancelled));
658 }
659
660 let addr = NrfSockAddr::from(address);
661
662 register_socket_waker(cx.waker().clone(), self.fd, SocketDirection::Out);
663
664 let mut send_result = unsafe {
665 nrfxlib_sys::nrf_sendto(
666 self.fd,
667 buffer.as_ptr() as *mut _,
668 buffer.len(),
669 0,
670 addr.as_ptr(),
671 addr.size() as u32,
672 )
673 };
674
675 if send_result == -1 {
676 send_result = get_last_error().abs().neg();
677 }
678
679 #[cfg(feature = "defmt")]
680 defmt::trace!("Sending result {}", send_result);
681
682 const NRF_EWOULDBLOCK: isize = -(nrfxlib_sys::NRF_EWOULDBLOCK as isize);
683 const NRF_ENOTCONN: isize = -(nrfxlib_sys::NRF_ENOTCONN as isize);
684
685 match send_result {
686 0 if !buffer.is_empty() => Poll::Ready(Err(Error::Disconnected)),
687 NRF_ENOTCONN => Poll::Ready(Err(Error::Disconnected)),
688 bytes_received @ 0.. => Poll::Ready(Ok(bytes_received as usize)),
689 NRF_EWOULDBLOCK => Poll::Pending,
690 error => Poll::Ready(Err(Error::NrfError(error))),
691 }
692 })
693 .await
694 }
695
696 pub fn set_option<'a>(&'a self, option: SocketOption<'a>) -> Result<(), SocketOptionError> {
704 let length = option.get_length();
705
706 let result = unsafe {
707 nrfxlib_sys::nrf_setsockopt(
708 self.fd,
709 option.get_level(),
710 option.get_name(),
711 option.get_value(),
712 length,
713 )
714 };
715
716 if result == -1 {
717 Err((get_last_error() as i32).into())
718 } else {
719 Ok(())
720 }
721 }
722
723 pub async fn deactivate(mut self) -> Result<(), Error> {
726 self.link.take().unwrap().deactivate().await?;
727 Ok(())
728 }
729}
730
731impl Drop for Socket {
732 fn drop(&mut self) {
733 if !self.split {
734 let e = unsafe { nrfxlib_sys::nrf_close(self.fd) };
735
736 if e == -1 {
737 panic!("{:?}", Error::NrfError(get_last_error()));
738 }
739 }
740 }
741}
742
743impl PartialEq for Socket {
744 fn eq(&self, other: &Self) -> bool {
745 self.fd == other.fd
746 }
747}
748impl Eq for Socket {}
749
750#[repr(u32)]
754#[derive(Debug, Clone, Copy, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)]
755#[cfg_attr(feature = "defmt", derive(defmt::Format))]
756pub enum SocketFamily {
757 Unspecified = nrfxlib_sys::NRF_AF_UNSPEC,
759 Ipv4 = nrfxlib_sys::NRF_AF_INET,
761 Ipv6 = nrfxlib_sys::NRF_AF_INET6,
763 Raw = nrfxlib_sys::NRF_AF_PACKET,
765}
766
767#[repr(u32)]
771#[derive(Debug, Clone, Copy, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)]
772#[cfg_attr(feature = "defmt", derive(defmt::Format))]
773pub enum SocketType {
774 Stream = nrfxlib_sys::NRF_SOCK_STREAM,
778 Datagram = nrfxlib_sys::NRF_SOCK_DGRAM,
782 Raw = nrfxlib_sys::NRF_SOCK_RAW,
786}
787
788#[repr(u32)]
792#[derive(Debug, Clone, Copy, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)]
793#[cfg_attr(feature = "defmt", derive(defmt::Format))]
794pub enum SocketProtocol {
795 IP = nrfxlib_sys::NRF_IPPROTO_IP,
797 Tcp = nrfxlib_sys::NRF_IPPROTO_TCP,
799 Udp = nrfxlib_sys::NRF_IPPROTO_UDP,
801 Ipv6 = nrfxlib_sys::NRF_IPPROTO_IPV6,
803 Raw = nrfxlib_sys::NRF_IPPROTO_RAW,
805 All = nrfxlib_sys::NRF_IPPROTO_ALL,
807 Tls1v2 = nrfxlib_sys::NRF_SPROTO_TLS1v2,
809 DTls1v2 = nrfxlib_sys::NRF_SPROTO_DTLS1v2,
811}
812
813#[allow(clippy::enum_variant_names)]
819#[derive(Debug)]
820pub enum SocketOption<'a> {
821 ReuseAddr(i32),
824 ReceiveTimeout(nrfxlib_sys::nrf_timeval),
828 SendTimeout(nrfxlib_sys::nrf_timeval),
832 BindToPdn(i32),
834 ExceptionalData(i32),
838 KeepOpen(i32),
840 Rai(i32),
844
845 SilenceAll(i32),
848 IpEchoReply(i32),
850 Ipv6EchoReply(i32),
852 Ipv6DelayedAddrRefresh(i32),
854 TcpServerSessionTimeout(i32),
856
857 TlsHostName(&'a str),
860 TlsPeerVerify(i32),
864 TlsSessionCache(i32),
866 TlsTagList(&'a [nrfxlib_sys::nrf_sec_tag_t]),
868 TlsCipherSuiteList(&'a [i32]),
870 TlsRole(i32),
874 TlsSessionCachePurge(i32),
876 DtlsHandshakeTimeout(i32),
880 DtlsCid(i32),
884 DtlsConnSave(i32),
886 DtlsConnLoad(i32),
888}
889impl SocketOption<'_> {
890 pub(crate) fn get_level(&self) -> i32 {
891 match self {
892 SocketOption::ReuseAddr(_)
894 | SocketOption::ReceiveTimeout(_)
895 | SocketOption::SendTimeout(_)
896 | SocketOption::BindToPdn(_)
897 | SocketOption::ExceptionalData(_)
898 | SocketOption::KeepOpen(_)
899 | SocketOption::Rai(_) => nrfxlib_sys::NRF_SOL_SOCKET as i32,
900
901 SocketOption::SilenceAll(_) => nrfxlib_sys::NRF_IPPROTO_ALL as i32,
903 SocketOption::IpEchoReply(_) => nrfxlib_sys::NRF_IPPROTO_IP as i32,
904 SocketOption::Ipv6EchoReply(_) | SocketOption::Ipv6DelayedAddrRefresh(_) => {
905 nrfxlib_sys::NRF_IPPROTO_IPV6 as i32
906 }
907 SocketOption::TcpServerSessionTimeout(_) => nrfxlib_sys::NRF_IPPROTO_TCP as i32,
908
909 SocketOption::TlsHostName(_)
911 | SocketOption::TlsPeerVerify(_)
912 | SocketOption::TlsSessionCache(_)
913 | SocketOption::TlsTagList(_)
914 | SocketOption::TlsCipherSuiteList(_)
915 | SocketOption::TlsRole(_)
916 | SocketOption::TlsSessionCachePurge(_)
917 | SocketOption::DtlsHandshakeTimeout(_)
918 | SocketOption::DtlsCid(_)
919 | SocketOption::DtlsConnSave(_)
920 | SocketOption::DtlsConnLoad(_) => nrfxlib_sys::NRF_SOL_SECURE as i32,
921 }
922 }
923
924 pub(crate) fn get_name(&self) -> i32 {
925 match self {
926 SocketOption::ReuseAddr(_) => nrfxlib_sys::NRF_SO_REUSEADDR as i32,
928 SocketOption::ReceiveTimeout(_) => nrfxlib_sys::NRF_SO_RCVTIMEO as i32,
929 SocketOption::SendTimeout(_) => nrfxlib_sys::NRF_SO_SNDTIMEO as i32,
930 SocketOption::BindToPdn(_) => nrfxlib_sys::NRF_SO_BINDTOPDN as i32,
931 SocketOption::ExceptionalData(_) => nrfxlib_sys::NRF_SO_EXCEPTIONAL_DATA as i32,
932 SocketOption::KeepOpen(_) => nrfxlib_sys::NRF_SO_KEEPOPEN as i32,
933 SocketOption::Rai(_) => nrfxlib_sys::NRF_SO_RAI as i32,
934
935 SocketOption::SilenceAll(_) => nrfxlib_sys::NRF_SO_SILENCE_ALL as i32,
937 SocketOption::IpEchoReply(_) => nrfxlib_sys::NRF_SO_IP_ECHO_REPLY as i32,
938 SocketOption::Ipv6EchoReply(_) => nrfxlib_sys::NRF_SO_IPV6_ECHO_REPLY as i32,
939 SocketOption::Ipv6DelayedAddrRefresh(_) => {
940 nrfxlib_sys::NRF_SO_IPV6_DELAYED_ADDR_REFRESH as i32
941 }
942 SocketOption::TcpServerSessionTimeout(_) => {
943 nrfxlib_sys::NRF_SO_TCP_SRV_SESSTIMEO as i32
944 }
945
946 SocketOption::TlsHostName(_) => nrfxlib_sys::NRF_SO_SEC_HOSTNAME as i32,
948 SocketOption::TlsPeerVerify(_) => nrfxlib_sys::NRF_SO_SEC_PEER_VERIFY as i32,
949 SocketOption::TlsSessionCache(_) => nrfxlib_sys::NRF_SO_SEC_SESSION_CACHE as i32,
950 SocketOption::TlsTagList(_) => nrfxlib_sys::NRF_SO_SEC_TAG_LIST as i32,
951 SocketOption::TlsCipherSuiteList(_) => nrfxlib_sys::NRF_SO_SEC_CIPHERSUITE_LIST as i32,
952 SocketOption::TlsRole(_) => nrfxlib_sys::NRF_SO_SEC_ROLE as i32,
953 SocketOption::TlsSessionCachePurge(_) => {
954 nrfxlib_sys::NRF_SO_SEC_SESSION_CACHE_PURGE as i32
955 }
956 SocketOption::DtlsHandshakeTimeout(_) => {
957 nrfxlib_sys::NRF_SO_SEC_DTLS_HANDSHAKE_TIMEO as i32
958 }
959 SocketOption::DtlsCid(_) => nrfxlib_sys::NRF_SO_SEC_DTLS_CID as i32,
960 SocketOption::DtlsConnSave(_) => nrfxlib_sys::NRF_SO_SEC_DTLS_CONN_SAVE as i32,
961 SocketOption::DtlsConnLoad(_) => nrfxlib_sys::NRF_SO_SEC_DTLS_CONN_LOAD as i32,
962 }
963 }
964
965 pub(crate) fn get_value(&self) -> *const core::ffi::c_void {
966 match self {
967 SocketOption::ReuseAddr(x)
969 | SocketOption::BindToPdn(x)
970 | SocketOption::ExceptionalData(x)
971 | SocketOption::KeepOpen(x)
972 | SocketOption::Rai(x) => x as *const _ as *const core::ffi::c_void,
973 SocketOption::ReceiveTimeout(x) | SocketOption::SendTimeout(x) => {
974 x as *const _ as *const core::ffi::c_void
975 }
976
977 SocketOption::SilenceAll(x)
979 | SocketOption::IpEchoReply(x)
980 | SocketOption::Ipv6EchoReply(x)
981 | SocketOption::Ipv6DelayedAddrRefresh(x)
982 | SocketOption::TcpServerSessionTimeout(x) => x as *const _ as *const core::ffi::c_void,
983
984 SocketOption::TlsHostName(s) => s.as_ptr() as *const core::ffi::c_void,
986 SocketOption::TlsPeerVerify(x)
987 | SocketOption::TlsSessionCache(x)
988 | SocketOption::TlsRole(x)
989 | SocketOption::TlsSessionCachePurge(x)
990 | SocketOption::DtlsHandshakeTimeout(x)
991 | SocketOption::DtlsCid(x)
992 | SocketOption::DtlsConnSave(x)
993 | SocketOption::DtlsConnLoad(x) => x as *const _ as *const core::ffi::c_void,
994 SocketOption::TlsTagList(x) => x.as_ptr() as *const core::ffi::c_void,
995 SocketOption::TlsCipherSuiteList(x) => x.as_ptr() as *const core::ffi::c_void,
996 }
997 }
998
999 pub(crate) fn get_length(&self) -> u32 {
1000 match self {
1001 SocketOption::ReuseAddr(x)
1003 | SocketOption::BindToPdn(x)
1004 | SocketOption::ExceptionalData(x)
1005 | SocketOption::KeepOpen(x)
1006 | SocketOption::Rai(x) => core::mem::size_of_val(x) as u32,
1007 SocketOption::ReceiveTimeout(x) | SocketOption::SendTimeout(x) => {
1008 core::mem::size_of_val(x) as u32
1009 }
1010
1011 SocketOption::SilenceAll(x)
1013 | SocketOption::IpEchoReply(x)
1014 | SocketOption::Ipv6EchoReply(x)
1015 | SocketOption::Ipv6DelayedAddrRefresh(x)
1016 | SocketOption::TcpServerSessionTimeout(x) => core::mem::size_of_val(x) as u32,
1017
1018 SocketOption::TlsHostName(s) => s.len() as u32,
1020 SocketOption::TlsPeerVerify(x)
1021 | SocketOption::TlsSessionCache(x)
1022 | SocketOption::TlsRole(x)
1023 | SocketOption::TlsSessionCachePurge(x)
1024 | SocketOption::DtlsHandshakeTimeout(x)
1025 | SocketOption::DtlsCid(x)
1026 | SocketOption::DtlsConnSave(x)
1027 | SocketOption::DtlsConnLoad(x) => core::mem::size_of_val(x) as u32,
1028 SocketOption::TlsTagList(x) => core::mem::size_of_val(*x) as u32,
1029 SocketOption::TlsCipherSuiteList(x) => core::mem::size_of_val(*x) as u32,
1030 }
1031 }
1032}
1033
1034#[derive(Debug, Copy, Clone)]
1038pub enum PeerVerification {
1039 Enabled,
1041 Optional,
1043 Disabled,
1045}
1046
1047impl PeerVerification {
1048 pub fn as_integer(self) -> i32 {
1050 match self {
1051 PeerVerification::Enabled => 2,
1052 PeerVerification::Optional => 1,
1053 PeerVerification::Disabled => 0,
1054 }
1055 }
1056}
1057
1058#[repr(i32)]
1063#[allow(non_camel_case_types)]
1064#[derive(Debug, Copy, Clone)]
1065pub enum CipherSuite {
1066 TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 =
1067 nrfxlib_sys::NRF_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 as i32,
1068 TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA =
1069 nrfxlib_sys::NRF_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA as i32,
1070 TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 =
1071 nrfxlib_sys::NRF_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 as i32,
1072 TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA =
1073 nrfxlib_sys::NRF_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA as i32,
1074 TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA = nrfxlib_sys::NRF_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA as i32,
1075 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 =
1076 nrfxlib_sys::NRF_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 as i32,
1077 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA = nrfxlib_sys::NRF_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA as i32,
1078 TLS_PSK_WITH_AES_256_CBC_SHA = nrfxlib_sys::NRF_TLS_PSK_WITH_AES_256_CBC_SHA as i32,
1079 TLS_PSK_WITH_AES_128_CBC_SHA256 = nrfxlib_sys::NRF_TLS_PSK_WITH_AES_128_CBC_SHA256 as i32,
1080 TLS_PSK_WITH_AES_128_CBC_SHA = nrfxlib_sys::NRF_TLS_PSK_WITH_AES_128_CBC_SHA as i32,
1081 TLS_PSK_WITH_AES_128_CCM_8 = nrfxlib_sys::NRF_TLS_PSK_WITH_AES_128_CCM_8 as i32,
1082 TLS_EMPTY_RENEGOTIATIONINFO_SCSV = nrfxlib_sys::NRF_TLS_EMPTY_RENEGOTIATIONINFO_SCSV as i32,
1083 TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 =
1084 nrfxlib_sys::NRF_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 as i32,
1085 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 =
1086 nrfxlib_sys::NRF_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 as i32,
1087 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 =
1088 nrfxlib_sys::NRF_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 as i32,
1089}
1090
1091#[derive(Debug, Clone)]
1093#[cfg_attr(feature = "defmt", derive(defmt::Format))]
1094pub enum SocketOptionError {
1095 TryAgain,
1097 InvalidFileDescriptor,
1099 DestinationAddressRequired,
1101 TimeoutTooBig,
1103 InvalidOption,
1105 AlreadyConnected,
1107 UnsupportedOption,
1109 NotASocket,
1111 OutOfMemory,
1113 OutOfResources,
1115 OperationNotSupported,
1117 ModemShutdown,
1119}
1120
1121impl From<i32> for SocketOptionError {
1122 fn from(errno: i32) -> Self {
1123 match errno.unsigned_abs() {
1124 nrfxlib_sys::NRF_EAGAIN => SocketOptionError::TryAgain,
1125 nrfxlib_sys::NRF_EBADF => SocketOptionError::InvalidFileDescriptor,
1126 nrfxlib_sys::NRF_EDESTADDRREQ => SocketOptionError::DestinationAddressRequired,
1127 nrfxlib_sys::NRF_EINVAL => SocketOptionError::InvalidOption,
1128 nrfxlib_sys::NRF_EISCONN => SocketOptionError::AlreadyConnected,
1129 nrfxlib_sys::NRF_ENOPROTOOPT => SocketOptionError::UnsupportedOption,
1130 nrfxlib_sys::NRF_ENOTSOCK => SocketOptionError::NotASocket,
1131 nrfxlib_sys::NRF_ENOMEM => SocketOptionError::OutOfMemory,
1132 nrfxlib_sys::NRF_ENOBUFS => SocketOptionError::OutOfResources,
1133 nrfxlib_sys::NRF_EOPNOTSUPP => SocketOptionError::OperationNotSupported,
1134 nrfxlib_sys::NRF_ESHUTDOWN => SocketOptionError::ModemShutdown,
1135 _ => panic!("Unknown error code: {}", errno),
1136 }
1137 }
1138}
1139
1140#[allow(clippy::declare_interior_mutable_const)]
1141const ATOMIC_U8_INIT: AtomicU8 = AtomicU8::new(0);
1142static ACTIVE_SPLIT_SOCKETS: [AtomicU8; nrfxlib_sys::NRF_MODEM_MAX_SOCKET_COUNT as usize] =
1143 [ATOMIC_U8_INIT; nrfxlib_sys::NRF_MODEM_MAX_SOCKET_COUNT as usize];
1144
1145pub struct SplitSocketHandle {
1154 inner: Option<Socket>,
1155 index: usize,
1156}
1157
1158impl SplitSocketHandle {
1159 pub async fn deactivate(mut self) -> Result<(), Error> {
1166 let mut inner = self.inner.take().unwrap();
1167
1168 if ACTIVE_SPLIT_SOCKETS[self.index].fetch_sub(1, Ordering::SeqCst) == 1 {
1169 inner.split = false;
1171 }
1172
1173 inner.deactivate().await?;
1174
1175 Ok(())
1176 }
1177
1178 fn get_new_spot() -> usize {
1179 for (index, count) in ACTIVE_SPLIT_SOCKETS.iter().enumerate() {
1180 if count
1181 .compare_exchange(0, 2, Ordering::SeqCst, Ordering::SeqCst)
1182 .is_ok()
1183 {
1184 return index;
1185 }
1186 }
1187
1188 unreachable!("It should not be possible to have more splits than the maximum socket count");
1189 }
1190}
1191
1192impl Deref for SplitSocketHandle {
1193 type Target = Socket;
1194
1195 fn deref(&self) -> &Self::Target {
1196 self.inner.as_ref().unwrap()
1197 }
1198}
1199
1200impl Drop for SplitSocketHandle {
1201 fn drop(&mut self) {
1202 if let Some(inner) = self.inner.as_mut() {
1203 if ACTIVE_SPLIT_SOCKETS[self.index].fetch_sub(1, Ordering::SeqCst) == 1 {
1204 inner.split = false;
1206 }
1207 }
1208 }
1209}