@@ -68,7 +68,7 @@ impl Default for UdpSocketState {
68
68
69
69
fn init ( io : SockRef < ' _ > ) -> io:: Result < ( ) > {
70
70
let mut cmsg_platform_space = 0 ;
71
- if cfg ! ( target_os = "linux" ) {
71
+ if cfg ! ( target_os = "linux" ) || cfg ! ( target_os = "freebsd" ) || cfg ! ( target_os = "macos" ) {
72
72
cmsg_platform_space +=
73
73
unsafe { libc:: CMSG_SPACE ( mem:: size_of :: < libc:: in6_pktinfo > ( ) as _ ) as usize } ;
74
74
}
@@ -164,13 +164,20 @@ fn init(io: SockRef<'_>) -> io::Result<()> {
164
164
if rc == -1 {
165
165
return Err ( io:: Error :: last_os_error ( ) ) ;
166
166
}
167
-
167
+ }
168
+ }
169
+ #[ cfg( any( target_os = "freebsd" , target_os = "macos" ) ) ]
170
+ // IP_RECVDSTADDR == IP_SENDSRCADDR on FreeBSD
171
+ // macOS uses only IP_RECVDSTADDR, no IP_SENDSRCADDR on macOS
172
+ // macOS also supports IP_PKTINFO
173
+ {
174
+ if is_ipv4 {
168
175
let on: libc:: c_int = 1 ;
169
176
let rc = unsafe {
170
177
libc:: setsockopt (
171
178
io. as_raw_fd ( ) ,
172
- libc:: IPPROTO_IPV6 ,
173
- libc:: IPV6_RECVPKTINFO ,
179
+ libc:: IPPROTO_IP ,
180
+ libc:: IP_RECVDSTADDR ,
174
181
& on as * const _ as _ ,
175
182
mem:: size_of_val ( & on) as _ ,
176
183
)
@@ -180,7 +187,23 @@ fn init(io: SockRef<'_>) -> io::Result<()> {
180
187
}
181
188
}
182
189
}
190
+
191
+ // IPV6_RECVPKTINFO is standardized
183
192
if !is_ipv4 {
193
+ let on: libc:: c_int = 1 ;
194
+ let rc = unsafe {
195
+ libc:: setsockopt (
196
+ io. as_raw_fd ( ) ,
197
+ libc:: IPPROTO_IPV6 ,
198
+ libc:: IPV6_RECVPKTINFO ,
199
+ & on as * const _ as _ ,
200
+ mem:: size_of_val ( & on) as _ ,
201
+ )
202
+ } ;
203
+ if rc == -1 {
204
+ return Err ( io:: Error :: last_os_error ( ) ) ;
205
+ }
206
+
184
207
let on: libc:: c_int = 1 ;
185
208
let rc = unsafe {
186
209
libc:: setsockopt (
@@ -200,11 +223,24 @@ fn init(io: SockRef<'_>) -> io::Result<()> {
200
223
201
224
#[ cfg( not( any( target_os = "macos" , target_os = "ios" ) ) ) ]
202
225
fn send (
226
+ #[ allow( unused_variables) ] // only used on Linux
203
227
state : & UdpState ,
204
228
io : SockRef < ' _ > ,
205
229
last_send_error : & mut Instant ,
206
230
transmits : & [ Transmit ] ,
207
231
) -> io:: Result < usize > {
232
+ #[ allow( unused_mut) ] // only mutable on FeeBSD
233
+ let mut encode_src_ip = true ;
234
+ #[ cfg( target_os = "freebsd" ) ]
235
+ {
236
+ let addr = io. local_addr ( ) ?;
237
+ let is_ipv4 = addr. family ( ) == libc:: AF_INET as libc:: sa_family_t ;
238
+ if is_ipv4 {
239
+ if let Some ( socket) = addr. as_socket_ipv4 ( ) {
240
+ encode_src_ip = socket. ip ( ) == & Ipv4Addr :: UNSPECIFIED ;
241
+ }
242
+ }
243
+ }
208
244
let mut msgs: [ libc:: mmsghdr ; BATCH_SIZE ] = unsafe { mem:: zeroed ( ) } ;
209
245
let mut iovecs: [ libc:: iovec ; BATCH_SIZE ] = unsafe { mem:: zeroed ( ) } ;
210
246
let mut cmsgs = [ cmsg:: Aligned ( [ 0u8 ; CMSG_LEN ] ) ; BATCH_SIZE ] ;
@@ -230,13 +266,13 @@ fn send(
230
266
& mut msgs[ i] . msg_hdr ,
231
267
& mut iovecs[ i] ,
232
268
& mut cmsgs[ i] ,
269
+ encode_src_ip,
233
270
) ;
234
271
}
235
272
let num_transmits = transmits. len ( ) . min ( BATCH_SIZE ) ;
236
273
237
274
loop {
238
- let n =
239
- unsafe { libc:: sendmmsg ( io. as_raw_fd ( ) , msgs. as_mut_ptr ( ) , num_transmits as u32 , 0 ) } ;
275
+ let n = unsafe { libc:: sendmmsg ( io. as_raw_fd ( ) , msgs. as_mut_ptr ( ) , num_transmits as _ , 0 ) } ;
240
276
if n == -1 {
241
277
let e = io:: Error :: last_os_error ( ) ;
242
278
match e. kind ( ) {
@@ -292,9 +328,18 @@ fn send(
292
328
let mut iov: libc:: iovec = unsafe { mem:: zeroed ( ) } ;
293
329
let mut ctrl = cmsg:: Aligned ( [ 0u8 ; CMSG_LEN ] ) ;
294
330
let mut sent = 0 ;
331
+
295
332
while sent < transmits. len ( ) {
296
333
let addr = socket2:: SockAddr :: from ( transmits[ sent] . destination ) ;
297
- prepare_msg ( & transmits[ sent] , & addr, & mut hdr, & mut iov, & mut ctrl) ;
334
+ prepare_msg (
335
+ & transmits[ sent] ,
336
+ & addr,
337
+ & mut hdr,
338
+ & mut iov,
339
+ & mut ctrl,
340
+ // Only tested on macOS
341
+ cfg ! ( target_os = "macos" ) ,
342
+ ) ;
298
343
let n = unsafe { libc:: sendmsg ( io. as_raw_fd ( ) , & hdr, 0 ) } ;
299
344
if n == -1 {
300
345
let e = io:: Error :: last_os_error ( ) ;
@@ -341,7 +386,7 @@ fn recv(io: SockRef<'_>, bufs: &mut [IoSliceMut<'_>], meta: &mut [RecvMeta]) ->
341
386
libc:: recvmmsg (
342
387
io. as_raw_fd ( ) ,
343
388
hdrs. as_mut_ptr ( ) ,
344
- bufs. len ( ) . min ( BATCH_SIZE ) as libc :: c_uint ,
389
+ bufs. len ( ) . min ( BATCH_SIZE ) as _ ,
345
390
0 ,
346
391
ptr:: null_mut ( ) ,
347
392
)
@@ -401,6 +446,8 @@ fn prepare_msg(
401
446
hdr : & mut libc:: msghdr ,
402
447
iov : & mut libc:: iovec ,
403
448
ctrl : & mut cmsg:: Aligned < [ u8 ; CMSG_LEN ] > ,
449
+ #[ allow( unused_variables) ] // only used on FreeBSD & macOS
450
+ encode_src_ip : bool ,
404
451
) {
405
452
iov. iov_base = transmit. contents . as_ptr ( ) as * const _ as * mut _ ;
406
453
iov. iov_len = transmit. contents . len ( ) ;
@@ -432,9 +479,10 @@ fn prepare_msg(
432
479
}
433
480
434
481
if let Some ( ip) = & transmit. src_ip {
435
- if cfg ! ( target_os = "linux" ) {
436
- match ip {
437
- IpAddr :: V4 ( v4) => {
482
+ match ip {
483
+ IpAddr :: V4 ( v4) => {
484
+ #[ cfg( target_os = "linux" ) ]
485
+ {
438
486
let pktinfo = libc:: in_pktinfo {
439
487
ipi_ifindex : 0 ,
440
488
ipi_spec_dst : libc:: in_addr {
@@ -444,16 +492,25 @@ fn prepare_msg(
444
492
} ;
445
493
encoder. push ( libc:: IPPROTO_IP , libc:: IP_PKTINFO , pktinfo) ;
446
494
}
447
- IpAddr :: V6 ( v6 ) => {
448
- let pktinfo = libc :: in6_pktinfo {
449
- ipi6_ifindex : 0 ,
450
- ipi6_addr : libc:: in6_addr {
451
- s6_addr : v6 . octets ( ) ,
452
- } ,
453
- } ;
454
- encoder . push ( libc :: IPPROTO_IPV6 , libc :: IPV6_PKTINFO , pktinfo ) ;
495
+ # [ cfg ( any ( target_os = "freebsd" , target_os = "macos" ) ) ]
496
+ {
497
+ if encode_src_ip {
498
+ let addr = libc:: in_addr {
499
+ s_addr : u32 :: from_ne_bytes ( v4 . octets ( ) ) ,
500
+ } ;
501
+ encoder . push ( libc :: IPPROTO_IP , libc :: IP_RECVDSTADDR , addr ) ;
502
+ }
455
503
}
456
504
}
505
+ IpAddr :: V6 ( v6) => {
506
+ let pktinfo = libc:: in6_pktinfo {
507
+ ipi6_ifindex : 0 ,
508
+ ipi6_addr : libc:: in6_addr {
509
+ s6_addr : v6. octets ( ) ,
510
+ } ,
511
+ } ;
512
+ encoder. push ( libc:: IPPROTO_IPV6 , libc:: IPV6_PKTINFO , pktinfo) ;
513
+ }
457
514
}
458
515
}
459
516
@@ -504,12 +561,18 @@ fn decode_recv(
504
561
ecn_bits = cmsg:: decode :: < libc:: c_int > ( cmsg) as u8 ;
505
562
}
506
563
} ,
564
+ #[ cfg( target_os = "linux" ) ]
507
565
( libc:: IPPROTO_IP , libc:: IP_PKTINFO ) => {
508
566
let pktinfo = unsafe { cmsg:: decode :: < libc:: in_pktinfo > ( cmsg) } ;
509
567
dst_ip = Some ( IpAddr :: V4 ( Ipv4Addr :: from (
510
568
pktinfo. ipi_addr . s_addr . to_ne_bytes ( ) ,
511
569
) ) ) ;
512
570
}
571
+ #[ cfg( any( target_os = "freebsd" , target_os = "macos" ) ) ]
572
+ ( libc:: IPPROTO_IP , libc:: IP_RECVDSTADDR ) => {
573
+ let in_addr = unsafe { cmsg:: decode :: < libc:: in_addr > ( cmsg) } ;
574
+ dst_ip = Some ( IpAddr :: V4 ( Ipv4Addr :: from ( in_addr. s_addr . to_ne_bytes ( ) ) ) ) ;
575
+ }
513
576
( libc:: IPPROTO_IPV6 , libc:: IPV6_PKTINFO ) => {
514
577
let pktinfo = unsafe { cmsg:: decode :: < libc:: in6_pktinfo > ( cmsg) } ;
515
578
dst_ip = Some ( IpAddr :: V6 ( Ipv6Addr :: from ( pktinfo. ipi6_addr . s6_addr ) ) ) ;
0 commit comments