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
+ } ;
2
5
3
6
#[ cfg( not( any( target_os = "espidf" , target_os = "nuttx" ) ) ) ]
4
7
use crate :: ffi:: CStr ;
5
8
use crate :: io:: { self , BorrowedBuf , BorrowedCursor , IoSlice , IoSliceMut } ;
9
+ use crate :: mem:: zeroed;
6
10
use crate :: net:: { Shutdown , SocketAddr } ;
7
11
use crate :: os:: unix:: io:: { AsFd , AsRawFd , BorrowedFd , FromRawFd , IntoRawFd , RawFd } ;
12
+ use crate :: ptr:: copy_nonoverlapping;
8
13
use crate :: sys:: fd:: FileDesc ;
9
- use crate :: sys:: net:: { getsockopt, setsockopt} ;
14
+ use crate :: sys:: net:: { SockaddrLike , getsockopt, setsockopt} ;
10
15
use crate :: sys:: pal:: IsMinusOne ;
11
16
use crate :: sys_common:: { AsInner , FromInner , IntoInner } ;
12
17
use crate :: time:: { Duration , Instant } ;
@@ -62,6 +67,46 @@ pub fn cvt_gai(err: c_int) -> io::Result<()> {
62
67
) )
63
68
}
64
69
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
+ impl < ' buf > Iterator for CmsgIter < ' buf > {
86
+ type Item = ( size_t , c_int , c_int , & ' buf [ u8 ] ) ;
87
+
88
+ fn next ( & mut self ) -> Option < Self :: Item > {
89
+ unsafe {
90
+ if self . inner . curr_cmsg . is_null ( ) {
91
+ None
92
+ } else {
93
+ let curr = * self . inner . curr_cmsg ;
94
+ let data_ptr = CMSG_DATA ( self . inner . curr_cmsg ) ;
95
+ let ptrdiff = data_ptr. offset_from_unsigned ( self . inner . curr_cmsg as * const u8 ) ;
96
+ let r = (
97
+ curr. cmsg_len ,
98
+ curr. cmsg_level ,
99
+ curr. cmsg_type ,
100
+ crate :: slice:: from_raw_parts ( data_ptr, curr. cmsg_len - ptrdiff) ,
101
+ ) ;
102
+ self . inner . curr_cmsg =
103
+ CMSG_NXTHDR ( self as * mut _ as * mut msghdr , self . inner . curr_cmsg ) ;
104
+ Some ( r)
105
+ }
106
+ }
107
+ }
108
+ }
109
+
65
110
impl Socket {
66
111
pub fn new ( addr : & SocketAddr , ty : c_int ) -> io:: Result < Socket > {
67
112
let fam = match * addr {
@@ -362,11 +407,52 @@ impl Socket {
362
407
}
363
408
364
409
#[ cfg( any( target_os = "android" , target_os = "linux" , target_os = "cygwin" ) ) ]
365
- pub fn recv_msg ( & self , msg : & mut libc:: msghdr ) -> io:: Result < usize > {
410
+ pub fn recv_msg_ ( & self , msg : & mut libc:: msghdr ) -> io:: Result < usize > {
366
411
let n = cvt ( unsafe { libc:: recvmsg ( self . as_raw_fd ( ) , msg, libc:: MSG_CMSG_CLOEXEC ) } ) ?;
367
412
Ok ( n as usize )
368
413
}
369
414
415
+ // user is responsible of aligning cmsg_buf to cmsghdr's alignment (use align_of)
416
+ pub fn recv_msg < ' a , ' b , T > (
417
+ & self ,
418
+ iov_buf : & mut [ IoSliceMut < ' _ > ] ,
419
+ cmsg_buf : & ' a mut [ u8 ] ,
420
+ flags : c_int ,
421
+ ) -> io:: Result < ( usize , T , c_int , CmsgIter < ' b > ) >
422
+ where
423
+ T : SockaddrLike ,
424
+ ' a : ' b ,
425
+ {
426
+ unsafe {
427
+ let mut msg: msghdr = zeroed ( ) ;
428
+ let mut addr: sockaddr_storage = zeroed ( ) ;
429
+ msg. msg_name = ( & raw mut addr) . cast ( ) ;
430
+ msg. msg_namelen = mem:: size_of_val ( & addr) as _ ;
431
+
432
+ msg. msg_iovlen = iov_buf. len ( ) ;
433
+ msg. msg_iov = iov_buf. as_mut_ptr ( ) . cast ( ) ;
434
+
435
+ msg. msg_controllen = cmsg_buf. len ( ) ;
436
+ if msg. msg_controllen != 0 {
437
+ msg. msg_control = cmsg_buf. as_mut_ptr ( ) . cast ( ) ;
438
+ }
439
+
440
+ msg. msg_flags = 0 ;
441
+
442
+ let bytes = cvt ( libc:: recvmsg ( self . as_raw_fd ( ) , & raw mut msg, flags) ) ? as usize ;
443
+
444
+ let addr = SockaddrLike :: from_storage ( & addr, msg. msg_namelen ) ?;
445
+
446
+ let mut iter: CmsgIter < ' _ > = zeroed ( ) ;
447
+ iter. inner . cmsg_buf = cmsg_buf;
448
+ iter. inner . cmsg_buf_len = msg. msg_controllen ;
449
+ let fst_cmsg = CMSG_FIRSTHDR ( ( & raw const iter) . cast ( ) ) ;
450
+ iter. inner . curr_cmsg = fst_cmsg;
451
+
452
+ Ok ( ( bytes, addr, msg. msg_flags , iter) )
453
+ }
454
+ }
455
+
370
456
pub fn peek_from ( & self , buf : & mut [ u8 ] ) -> io:: Result < ( usize , SocketAddr ) > {
371
457
self . recv_from_with_flags ( buf, MSG_PEEK )
372
458
}
@@ -385,11 +471,63 @@ impl Socket {
385
471
}
386
472
387
473
#[ cfg( any( target_os = "android" , target_os = "linux" , target_os = "cygwin" ) ) ]
388
- pub fn send_msg ( & self , msg : & mut libc:: msghdr ) -> io:: Result < usize > {
474
+ pub fn send_msg_ ( & self , msg : & mut libc:: msghdr ) -> io:: Result < usize > {
389
475
let n = cvt ( unsafe { libc:: sendmsg ( self . as_raw_fd ( ) , msg, 0 ) } ) ?;
390
476
Ok ( n as usize )
391
477
}
392
478
479
+ pub fn send_msg < T > (
480
+ & self ,
481
+ addr : Option < & T > ,
482
+ iov : & [ IoSlice < ' _ > ] ,
483
+ cmsgs : & [ ( c_int , c_int , & [ u8 ] ) ] ,
484
+ cmsg_buf : & mut [ u8 ] ,
485
+ flags : c_int ,
486
+ ) -> io:: Result < usize >
487
+ where
488
+ T : SockaddrLike ,
489
+ {
490
+ unsafe {
491
+ let mut msg: msghdr = zeroed ( ) ;
492
+ let mut addr_s: sockaddr_storage = zeroed ( ) ;
493
+
494
+ if let Some ( addr_) = addr {
495
+ let len = addr_. to_storage ( & mut addr_s) ;
496
+ msg. msg_namelen = len;
497
+ msg. msg_name = ( & raw mut addr_s) . cast ( ) ;
498
+ }
499
+
500
+ msg. msg_iovlen = iov. len ( ) ;
501
+ msg. msg_iov = iov. as_ptr ( ) . cast :: < IoSlice < ' _ > > ( ) as * mut iovec ;
502
+
503
+ // cmsg
504
+ msg. msg_controllen = cmsg_buf. len ( ) ;
505
+ msg. msg_control = cmsg_buf. as_mut_ptr ( ) . cast ( ) ;
506
+ let mut curr_cmsg_hdr = CMSG_FIRSTHDR ( & raw const msg) ;
507
+ for ( cmsg_level, cmsg_type, cmsg_data) in cmsgs {
508
+ if curr_cmsg_hdr. is_null ( ) {
509
+ return Err ( io:: Error :: new (
510
+ io:: ErrorKind :: InvalidInput ,
511
+ "cmsg_buf supplied is too small to hold all control messages" ,
512
+ ) ) ;
513
+ }
514
+
515
+ ( * curr_cmsg_hdr) . cmsg_level = * cmsg_level;
516
+ ( * curr_cmsg_hdr) . cmsg_type = * cmsg_type;
517
+ ( * curr_cmsg_hdr) . cmsg_len = CMSG_LEN ( cmsg_data. len ( ) as c_uint ) as usize ;
518
+
519
+ let cmsg_data_ptr = CMSG_DATA ( curr_cmsg_hdr) ;
520
+ copy_nonoverlapping ( ( * cmsg_data) . as_ptr ( ) , cmsg_data_ptr, cmsg_data. len ( ) ) ;
521
+
522
+ curr_cmsg_hdr = CMSG_NXTHDR ( & raw const msg, curr_cmsg_hdr as * const _ ) ;
523
+ }
524
+
525
+ let bytes = cvt ( libc:: sendmsg ( self . as_raw_fd ( ) , & raw mut msg, flags) ) ? as usize ;
526
+
527
+ Ok ( bytes)
528
+ }
529
+ }
530
+
393
531
pub fn set_timeout ( & self , dur : Option < Duration > , kind : libc:: c_int ) -> io:: Result < ( ) > {
394
532
let timeout = match dur {
395
533
Some ( dur) => {
0 commit comments