1- use libc:: { MSG_PEEK , c_int, c_void, size_t, sockaddr, socklen_t} ;
1+ use libc:: {
2+ CMSG_DATA , CMSG_FIRSTHDR , CMSG_LEN , CMSG_NXTHDR , MSG_PEEK , c_int, c_uint, c_void, cmsghdr,
3+ iovec, msghdr, size_t, sockaddr, sockaddr_storage, socklen_t,
4+ } ;
25
36#[ cfg( not( any( target_os = "espidf" , target_os = "nuttx" ) ) ) ]
47use crate :: ffi:: CStr ;
58use crate :: io:: { self , BorrowedBuf , BorrowedCursor , IoSlice , IoSliceMut } ;
9+ use crate :: mem:: zeroed;
610use crate :: net:: { Shutdown , SocketAddr } ;
711use crate :: os:: unix:: io:: { AsFd , AsRawFd , BorrowedFd , FromRawFd , IntoRawFd , RawFd } ;
12+ use crate :: ptr:: copy_nonoverlapping;
813use crate :: sys:: fd:: FileDesc ;
9- use crate :: sys:: net:: { getsockopt, setsockopt} ;
14+ use crate :: sys:: net:: { SockaddrLike , getsockopt, setsockopt} ;
1015use crate :: sys:: pal:: IsMinusOne ;
1116use crate :: sys_common:: { AsInner , FromInner , IntoInner } ;
1217use crate :: time:: { Duration , Instant } ;
@@ -62,6 +67,63 @@ pub fn cvt_gai(err: c_int) -> io::Result<()> {
6267 ) )
6368}
6469
70+ #[ repr( C ) ]
71+ pub union CmsgIter < ' buf > {
72+ _align : msghdr ,
73+ inner : CmsgIterInner < ' buf > ,
74+ }
75+
76+ #[ derive( Clone , Copy ) ]
77+ #[ repr( C ) ]
78+ struct CmsgIterInner < ' buf > {
79+ _padding : [ u8 ; size_of :: < usize > ( ) + size_of :: < socklen_t > ( ) + size_of :: < size_t > ( ) ] ,
80+ curr_cmsg : * mut cmsghdr ,
81+ cmsg_buf : & ' buf [ u8 ] ,
82+ cmsg_buf_len : usize ,
83+ }
84+
85+ #[ repr( transparent) ]
86+ pub struct CmsgBuf < ' buf > ( & ' buf mut [ u8 ] ) ;
87+
88+ impl < ' buf > CmsgBuf < ' buf > {
89+ pub fn new ( buf : & ' buf mut [ u8 ] ) -> io:: Result < Self > {
90+ if buf. as_ptr ( ) . align_offset ( align_of :: < cmsghdr > ( ) ) == 0 {
91+ Ok ( CmsgBuf ( buf) )
92+ } else {
93+ Err ( io:: Error :: new ( io:: ErrorKind :: InvalidInput , "unaligned buffer" ) )
94+ }
95+ }
96+
97+ pub unsafe fn new_unchecked ( buf : & ' buf mut [ u8 ] ) -> Self {
98+ CmsgBuf ( buf)
99+ }
100+ }
101+
102+ impl < ' buf > Iterator for CmsgIter < ' buf > {
103+ type Item = ( size_t , c_int , c_int , & ' buf [ u8 ] ) ;
104+
105+ fn next ( & mut self ) -> Option < Self :: Item > {
106+ unsafe {
107+ if self . inner . curr_cmsg . is_null ( ) {
108+ None
109+ } else {
110+ let curr = * self . inner . curr_cmsg ;
111+ let data_ptr = CMSG_DATA ( self . inner . curr_cmsg ) ;
112+ let ptrdiff = data_ptr. offset_from_unsigned ( self . inner . curr_cmsg as * const u8 ) ;
113+ let r = (
114+ curr. cmsg_len ,
115+ curr. cmsg_level ,
116+ curr. cmsg_type ,
117+ crate :: slice:: from_raw_parts ( data_ptr, curr. cmsg_len - ptrdiff) ,
118+ ) ;
119+ self . inner . curr_cmsg =
120+ CMSG_NXTHDR ( self as * mut _ as * mut msghdr , self . inner . curr_cmsg ) ;
121+ Some ( r)
122+ }
123+ }
124+ }
125+ }
126+
65127impl Socket {
66128 pub fn new ( addr : & SocketAddr , ty : c_int ) -> io:: Result < Socket > {
67129 let fam = match * addr {
@@ -362,11 +424,52 @@ impl Socket {
362424 }
363425
364426 #[ cfg( any( target_os = "android" , target_os = "linux" , target_os = "cygwin" ) ) ]
365- pub fn recv_msg ( & self , msg : & mut libc:: msghdr ) -> io:: Result < usize > {
427+ pub fn recv_msg_ ( & self , msg : & mut libc:: msghdr ) -> io:: Result < usize > {
366428 let n = cvt ( unsafe { libc:: recvmsg ( self . as_raw_fd ( ) , msg, libc:: MSG_CMSG_CLOEXEC ) } ) ?;
367429 Ok ( n as usize )
368430 }
369431
432+ // user is responsible of aligning cmsg_buf to cmsghdr's alignment (use align_of)
433+ pub fn recv_msg < ' a , ' b , T > (
434+ & self ,
435+ iov_buf : & mut [ IoSliceMut < ' _ > ] ,
436+ cmsg_buf : CmsgBuf < ' a > ,
437+ flags : c_int ,
438+ ) -> io:: Result < ( usize , T , c_int , CmsgIter < ' b > ) >
439+ where
440+ T : SockaddrLike ,
441+ ' a : ' b ,
442+ {
443+ unsafe {
444+ let mut msg: msghdr = zeroed ( ) ;
445+ let mut addr: sockaddr_storage = zeroed ( ) ;
446+ msg. msg_name = ( & raw mut addr) . cast ( ) ;
447+ msg. msg_namelen = mem:: size_of_val ( & addr) as _ ;
448+
449+ msg. msg_iovlen = iov_buf. len ( ) ;
450+ msg. msg_iov = iov_buf. as_mut_ptr ( ) . cast ( ) ;
451+
452+ msg. msg_controllen = cmsg_buf. 0 . len ( ) ;
453+ if msg. msg_controllen != 0 {
454+ msg. msg_control = cmsg_buf. 0 . as_mut_ptr ( ) . cast ( ) ;
455+ }
456+
457+ msg. msg_flags = 0 ;
458+
459+ let bytes = cvt ( libc:: recvmsg ( self . as_raw_fd ( ) , & raw mut msg, flags) ) ? as usize ;
460+
461+ let addr = SockaddrLike :: from_storage ( & addr, msg. msg_namelen ) ?;
462+
463+ let mut iter: CmsgIter < ' _ > = zeroed ( ) ;
464+ iter. inner . cmsg_buf = cmsg_buf. 0 ;
465+ iter. inner . cmsg_buf_len = msg. msg_controllen ;
466+ let fst_cmsg = CMSG_FIRSTHDR ( ( & raw const iter) . cast ( ) ) ;
467+ iter. inner . curr_cmsg = fst_cmsg;
468+
469+ Ok ( ( bytes, addr, msg. msg_flags , iter) )
470+ }
471+ }
472+
370473 pub fn peek_from ( & self , buf : & mut [ u8 ] ) -> io:: Result < ( usize , SocketAddr ) > {
371474 self . recv_from_with_flags ( buf, MSG_PEEK )
372475 }
@@ -385,11 +488,64 @@ impl Socket {
385488 }
386489
387490 #[ cfg( any( target_os = "android" , target_os = "linux" , target_os = "cygwin" ) ) ]
388- pub fn send_msg ( & self , msg : & mut libc:: msghdr ) -> io:: Result < usize > {
491+ pub fn send_msg_ ( & self , msg : & mut libc:: msghdr ) -> io:: Result < usize > {
389492 let n = cvt ( unsafe { libc:: sendmsg ( self . as_raw_fd ( ) , msg, 0 ) } ) ?;
390493 Ok ( n as usize )
391494 }
392495
496+ // user is responsible of aligning cmsg_buf to cmsghdr's alignment (use align_of)
497+ pub fn send_msg < T > (
498+ & self ,
499+ addr : Option < & T > ,
500+ iov : & [ IoSlice < ' _ > ] ,
501+ cmsgs : & [ ( c_int , c_int , & [ u8 ] ) ] ,
502+ cmsg_buf : CmsgBuf < ' _ > ,
503+ flags : c_int ,
504+ ) -> io:: Result < usize >
505+ where
506+ T : SockaddrLike ,
507+ {
508+ unsafe {
509+ let mut msg: msghdr = zeroed ( ) ;
510+ let mut addr_s: sockaddr_storage = zeroed ( ) ;
511+
512+ if let Some ( addr_) = addr {
513+ let len = addr_. to_storage ( & mut addr_s) ;
514+ msg. msg_namelen = len;
515+ msg. msg_name = ( & raw mut addr_s) . cast ( ) ;
516+ }
517+
518+ msg. msg_iovlen = iov. len ( ) ;
519+ msg. msg_iov = iov. as_ptr ( ) . cast :: < IoSlice < ' _ > > ( ) as * mut iovec ;
520+
521+ // cmsg
522+ msg. msg_controllen = cmsg_buf. 0 . len ( ) ;
523+ msg. msg_control = cmsg_buf. 0 . as_mut_ptr ( ) . cast ( ) ;
524+ let mut curr_cmsg_hdr = CMSG_FIRSTHDR ( & raw const msg) ;
525+ for ( cmsg_level, cmsg_type, cmsg_data) in cmsgs {
526+ if curr_cmsg_hdr. is_null ( ) {
527+ return Err ( io:: Error :: new (
528+ io:: ErrorKind :: InvalidInput ,
529+ "cmsg_buf supplied is too small to hold all control messages" ,
530+ ) ) ;
531+ }
532+
533+ ( * curr_cmsg_hdr) . cmsg_level = * cmsg_level;
534+ ( * curr_cmsg_hdr) . cmsg_type = * cmsg_type;
535+ ( * curr_cmsg_hdr) . cmsg_len = CMSG_LEN ( cmsg_data. len ( ) as c_uint ) as usize ;
536+
537+ let cmsg_data_ptr = CMSG_DATA ( curr_cmsg_hdr) ;
538+ copy_nonoverlapping ( ( * cmsg_data) . as_ptr ( ) , cmsg_data_ptr, cmsg_data. len ( ) ) ;
539+
540+ curr_cmsg_hdr = CMSG_NXTHDR ( & raw const msg, curr_cmsg_hdr as * const _ ) ;
541+ }
542+
543+ let bytes = cvt ( libc:: sendmsg ( self . as_raw_fd ( ) , & raw mut msg, flags) ) ? as usize ;
544+
545+ Ok ( bytes)
546+ }
547+ }
548+
393549 pub fn set_timeout ( & self , dur : Option < Duration > , kind : libc:: c_int ) -> io:: Result < ( ) > {
394550 let timeout = match dur {
395551 Some ( dur) => {
0 commit comments