@@ -156,8 +156,8 @@ impl UdpSocketState {
156156 } )
157157 }
158158
159- pub fn send ( & self , socket : UdpSockRef < ' _ > , transmits : & [ Transmit ] ) -> io:: Result < usize > {
160- send ( self , socket. 0 , transmits )
159+ pub fn send ( & self , socket : UdpSockRef < ' _ > , transmit : & Transmit ) -> io:: Result < ( ) > {
160+ send ( self , socket. 0 , transmit )
161161 }
162162
163163 pub fn recv (
@@ -213,8 +213,8 @@ fn send(
213213 #[ allow( unused_variables) ] // only used on Linux
214214 state : & UdpSocketState ,
215215 io : SockRef < ' _ > ,
216- transmits : & [ Transmit ] ,
217- ) -> io:: Result < usize > {
216+ transmit : & Transmit ,
217+ ) -> io:: Result < ( ) > {
218218 #[ allow( unused_mut) ] // only mutable on FreeBSD
219219 let mut encode_src_ip = true ;
220220 #[ cfg( target_os = "freebsd" ) ]
@@ -227,41 +227,22 @@ fn send(
227227 }
228228 }
229229 }
230- let mut msgs: [ libc:: mmsghdr ; BATCH_SIZE ] = unsafe { mem:: zeroed ( ) } ;
231- let mut iovecs: [ libc:: iovec ; BATCH_SIZE ] = unsafe { mem:: zeroed ( ) } ;
232- let mut cmsgs = [ cmsg:: Aligned ( [ 0u8 ; CMSG_LEN ] ) ; BATCH_SIZE ] ;
233- // This assume_init looks a bit weird because one might think it
234- // assumes the SockAddr data to be initialized, but that call
235- // refers to the whole array, which itself is made up of MaybeUninit
236- // containers. Their presence protects the SockAddr inside from
237- // being assumed as initialized by the assume_init call.
238- // TODO: Replace this with uninit_array once it becomes MSRV-stable
239- let mut addrs: [ MaybeUninit < socket2:: SockAddr > ; BATCH_SIZE ] =
240- unsafe { MaybeUninit :: uninit ( ) . assume_init ( ) } ;
241- for ( i, transmit) in transmits. iter ( ) . enumerate ( ) . take ( BATCH_SIZE ) {
242- let dst_addr = unsafe {
243- ptr:: write (
244- addrs[ i] . as_mut_ptr ( ) ,
245- socket2:: SockAddr :: from ( transmit. destination ) ,
246- ) ;
247- & * addrs[ i] . as_ptr ( )
248- } ;
249- prepare_msg (
250- transmit,
251- dst_addr,
252- & mut msgs[ i] . msg_hdr ,
253- & mut iovecs[ i] ,
254- & mut cmsgs[ i] ,
255- encode_src_ip,
256- state. sendmsg_einval ( ) ,
257- ) ;
258- }
259- let num_transmits = transmits. len ( ) . min ( BATCH_SIZE ) ;
230+ let mut msg_hdr: libc:: msghdr = unsafe { mem:: zeroed ( ) } ;
231+ let mut iovec: libc:: iovec = unsafe { mem:: zeroed ( ) } ;
232+ let mut cmsgs = cmsg:: Aligned ( [ 0u8 ; CMSG_LEN ] ) ;
233+ let dst_addr = socket2:: SockAddr :: from ( transmit. destination ) ;
234+ prepare_msg (
235+ transmit,
236+ & dst_addr,
237+ & mut msg_hdr,
238+ & mut iovec,
239+ & mut cmsgs,
240+ encode_src_ip,
241+ state. sendmsg_einval ( ) ,
242+ ) ;
260243
261244 loop {
262- let n = unsafe {
263- sendmmsg_with_fallback ( io. as_raw_fd ( ) , msgs. as_mut_ptr ( ) , num_transmits as _ )
264- } ;
245+ let n = unsafe { libc:: sendmsg ( io. as_raw_fd ( ) , & msg_hdr, 0 ) } ;
265246 if n == -1 {
266247 let e = io:: Error :: last_os_error ( ) ;
267248 match e. kind ( ) {
@@ -301,135 +282,57 @@ fn send(
301282 // - EMSGSIZE is expected for MTU probes. Future work might be able to avoid
302283 // these by automatically clamping the MTUD upper bound to the interface MTU.
303284 if e. raw_os_error ( ) != Some ( libc:: EMSGSIZE ) {
304- log_sendmsg_error ( & state. last_send_error , e, & transmits [ 0 ] ) ;
285+ log_sendmsg_error ( & state. last_send_error , e, transmit ) ;
305286 }
306287
307- // The ERRORS section in https://man7.org/linux/man-pages/man2/sendmmsg.2.html
308- // describes that errors will only be returned if no message could be transmitted
309- // at all. Therefore drop the first (problematic) message,
310- // and retry the remaining ones.
311- return Ok ( num_transmits. min ( 1 ) ) ;
288+ return Ok ( ( ) ) ;
312289 }
313290 }
314291 }
315- return Ok ( n as usize ) ;
292+ return Ok ( ( ) ) ;
316293 }
317294}
318295
319296#[ cfg( any( target_os = "macos" , target_os = "ios" ) ) ]
320- fn send ( state : & UdpSocketState , io : SockRef < ' _ > , transmits : & [ Transmit ] ) -> io:: Result < usize > {
297+ fn send ( state : & UdpSocketState , io : SockRef < ' _ > , transmit : & Transmit ) -> io:: Result < ( ) > {
321298 let mut hdr: libc:: msghdr = unsafe { mem:: zeroed ( ) } ;
322299 let mut iov: libc:: iovec = unsafe { mem:: zeroed ( ) } ;
323300 let mut ctrl = cmsg:: Aligned ( [ 0u8 ; CMSG_LEN ] ) ;
324- let mut sent = 0 ;
325-
326- while sent < transmits. len ( ) {
327- let addr = socket2:: SockAddr :: from ( transmits[ sent] . destination ) ;
328- prepare_msg (
329- & transmits[ sent] ,
330- & addr,
331- & mut hdr,
332- & mut iov,
333- & mut ctrl,
334- // Only tested on macOS and iOS
335- cfg ! ( target_os = "macos" ) || cfg ! ( target_os = "ios" ) ,
336- state. sendmsg_einval ( ) ,
337- ) ;
338- let n = unsafe { libc:: sendmsg ( io. as_raw_fd ( ) , & hdr, 0 ) } ;
339- if n == -1 {
340- let e = io:: Error :: last_os_error ( ) ;
341- match e. kind ( ) {
342- io:: ErrorKind :: Interrupted => {
343- // Retry the transmission
344- }
345- io:: ErrorKind :: WouldBlock if sent != 0 => return Ok ( sent) ,
346- io:: ErrorKind :: WouldBlock => return Err ( e) ,
347- _ => {
348- // Other errors are ignored, since they will usually be handled
349- // by higher level retransmits and timeouts.
350- // - PermissionDenied errors have been observed due to iptable rules.
351- // Those are not fatal errors, since the
352- // configuration can be dynamically changed.
353- // - Destination unreachable errors have been observed for other
354- // - EMSGSIZE is expected for MTU probes. Future work might be able to avoid
355- // these by automatically clamping the MTUD upper bound to the interface MTU.
356- if e. raw_os_error ( ) != Some ( libc:: EMSGSIZE ) {
357- log_sendmsg_error ( & state. last_send_error , e, & transmits[ sent] ) ;
358- }
359- sent += 1 ;
301+ let addr = socket2:: SockAddr :: from ( transmit. destination ) ;
302+ prepare_msg (
303+ transmit,
304+ & addr,
305+ & mut hdr,
306+ & mut iov,
307+ & mut ctrl,
308+ // Only tested on macOS and iOS
309+ cfg ! ( target_os = "macos" ) || cfg ! ( target_os = "ios" ) ,
310+ state. sendmsg_einval ( ) ,
311+ ) ;
312+ let n = unsafe { libc:: sendmsg ( io. as_raw_fd ( ) , & hdr, 0 ) } ;
313+ if n == -1 {
314+ let e = io:: Error :: last_os_error ( ) ;
315+ match e. kind ( ) {
316+ io:: ErrorKind :: Interrupted => {
317+ // Retry the transmission
318+ }
319+ io:: ErrorKind :: WouldBlock => return Err ( e) ,
320+ _ => {
321+ // Other errors are ignored, since they will usually be handled
322+ // by higher level retransmits and timeouts.
323+ // - PermissionDenied errors have been observed due to iptable rules.
324+ // Those are not fatal errors, since the
325+ // configuration can be dynamically changed.
326+ // - Destination unreachable errors have been observed for other
327+ // - EMSGSIZE is expected for MTU probes. Future work might be able to avoid
328+ // these by automatically clamping the MTUD upper bound to the interface MTU.
329+ if e. raw_os_error ( ) != Some ( libc:: EMSGSIZE ) {
330+ log_sendmsg_error ( & state. last_send_error , e, transmit) ;
360331 }
361332 }
362- } else {
363- sent += 1 ;
364- }
365- }
366- Ok ( sent)
367- }
368-
369- /// Implementation of `sendmmsg` with a fallback
370- /// to `sendmsg` if syscall is not available.
371- ///
372- /// It uses [`libc::syscall`] instead of [`libc::sendmmsg`]
373- /// to avoid linking error on systems where libc does not contain `sendmmsg`.
374- #[ cfg( not( any( target_os = "macos" , target_os = "ios" ) ) ) ]
375- unsafe fn sendmmsg_with_fallback (
376- sockfd : libc:: c_int ,
377- msgvec : * mut libc:: mmsghdr ,
378- vlen : libc:: c_uint ,
379- ) -> libc:: c_int {
380- let flags = 0 ;
381-
382- #[ cfg( not( target_os = "freebsd" ) ) ]
383- {
384- let ret = libc:: syscall ( libc:: SYS_sendmmsg , sockfd, msgvec, vlen, flags) as libc:: c_int ;
385- if ret != -1 {
386- return ret;
387- }
388- }
389-
390- // libc on FreeBSD implements `sendmmsg` as a high-level abstraction over `sendmsg`,
391- // thus `SYS_sendmmsg` constant and direct system call do not exist
392- #[ cfg( target_os = "freebsd" ) ]
393- {
394- let ret = libc:: sendmmsg ( sockfd, msgvec, vlen as usize , flags) as libc:: c_int ;
395- if ret != -1 {
396- return ret;
397- }
398- }
399-
400- let e = io:: Error :: last_os_error ( ) ;
401- match e. raw_os_error ( ) {
402- Some ( libc:: ENOSYS ) => {
403- // Fallback to `sendmsg`.
404- sendmmsg_fallback ( sockfd, msgvec, vlen)
405333 }
406- _ => -1 ,
407- }
408- }
409-
410- /// Fallback implementation of `sendmmsg` using `sendmsg`
411- /// for systems which do not support `sendmmsg`
412- /// such as Linux <3.0.
413- #[ cfg( not( any( target_os = "macos" , target_os = "ios" ) ) ) ]
414- unsafe fn sendmmsg_fallback (
415- sockfd : libc:: c_int ,
416- msgvec : * mut libc:: mmsghdr ,
417- vlen : libc:: c_uint ,
418- ) -> libc:: c_int {
419- let flags = 0 ;
420- if vlen == 0 {
421- return 0 ;
422- }
423-
424- let n = libc:: sendmsg ( sockfd, & ( * msgvec) . msg_hdr , flags) ;
425- if n == -1 {
426- -1
427- } else {
428- // type of `msg_len` field differs on Linux and FreeBSD,
429- // it is up to the compiler to infer and cast `n` to correct type
430- ( * msgvec) . msg_len = n as _ ;
431- 1
432334 }
335+ Ok ( ( ) )
433336}
434337
435338#[ cfg( not( any( target_os = "macos" , target_os = "ios" ) ) ) ]
0 commit comments