7
7
// option. This file may not be copied, modified, or distributed
8
8
// except according to those terms.
9
9
10
+ // Most of this file won't compile without `windows-shared-memory-equality` feature on Windows since `PartialEq` won't be implemented for `IpcSharedMemory`.
11
+ #![ cfg( any( not( target_os = "windows" ) , all( target_os = "windows" , feature = "windows-shared-memory-equality" ) ) ) ]
12
+
10
13
use crate :: platform:: { self , OsIpcChannel , OsIpcReceiverSet } ;
11
14
use crate :: platform:: { OsIpcSharedMemory } ;
12
15
use std:: collections:: HashMap ;
13
16
use std:: sync:: Arc ;
14
17
use std:: time:: { Duration , Instant } ;
15
18
use std:: thread;
16
19
20
+ #[ cfg( not( any( feature = "force-inprocess" , target_os = "android" , target_os = "ios" ) ) ) ]
21
+ use libc;
17
22
use crate :: platform:: { OsIpcSender , OsIpcOneShotServer } ;
18
23
#[ cfg( not( any( feature = "force-inprocess" , target_os = "windows" , target_os = "android" , target_os = "ios" ) ) ) ]
19
24
use libc:: { kill, SIGSTOP , SIGCONT } ;
20
25
#[ cfg( not( any( feature = "force-inprocess" , target_os = "windows" , target_os = "android" , target_os = "ios" ) ) ) ]
21
26
use crate :: test:: { fork, Wait } ;
22
27
28
+ // Helper to get a channel_name argument passed in; used for the
29
+ // cross-process spawn server tests.
30
+ #[ cfg( not( any( feature = "force-inprocess" , target_os = "android" , target_os = "ios" ) ) ) ]
31
+ use crate :: test:: { get_channel_name_arg, spawn_server} ;
32
+
23
33
#[ test]
24
34
fn simple ( ) {
25
35
let ( tx, rx) = platform:: channel ( ) . unwrap ( ) ;
@@ -209,7 +219,8 @@ fn with_n_fds(n: usize, size: usize) {
209
219
210
220
// These tests only apply to platforms that need fragmentation.
211
221
#[ cfg( all( not( feature = "force-inprocess" ) , any( target_os = "linux" ,
212
- target_os = "freebsd" ) ) ) ]
222
+ target_os = "freebsd" ,
223
+ target_os = "windows" ) ) ) ]
213
224
mod fragment_tests {
214
225
use crate :: platform;
215
226
use super :: with_n_fds;
@@ -656,9 +667,32 @@ fn server_connect_first() {
656
667
( data, vec![ ] , vec![ ] ) ) ;
657
668
}
658
669
670
+ #[ cfg( not( any( feature = "force-inprocess" , target_os = "android" , target_os = "ios" ) ) ) ]
671
+ #[ test]
672
+ fn cross_process_spawn ( ) {
673
+ let data: & [ u8 ] = b"1234567" ;
674
+
675
+ let channel_name = get_channel_name_arg ( "server" ) ;
676
+ if let Some ( channel_name) = channel_name {
677
+ let tx = OsIpcSender :: connect ( channel_name) . unwrap ( ) ;
678
+ tx. send ( data, vec ! [ ] , vec ! [ ] ) . unwrap ( ) ;
679
+
680
+ unsafe { libc:: exit ( 0 ) ; }
681
+ }
682
+
683
+ let ( server, name) = OsIpcOneShotServer :: new ( ) . unwrap ( ) ;
684
+ let mut child_pid = spawn_server ( "cross_process_spawn" , & [ ( "server" , & * name) ] ) ;
685
+
686
+ let ( _, received_data, received_channels, received_shared_memory_regions) =
687
+ server. accept ( ) . unwrap ( ) ;
688
+ child_pid. wait ( ) . expect ( "failed to wait on child" ) ;
689
+ assert_eq ! ( ( & received_data[ ..] , received_channels, received_shared_memory_regions) ,
690
+ ( data, vec![ ] , vec![ ] ) ) ;
691
+ }
692
+
659
693
#[ cfg( not( any( feature = "force-inprocess" , target_os = "windows" , target_os = "android" , target_os = "ios" ) ) ) ]
660
694
#[ test]
661
- fn cross_process ( ) {
695
+ fn cross_process_fork ( ) {
662
696
let ( server, name) = OsIpcOneShotServer :: new ( ) . unwrap ( ) ;
663
697
let data: & [ u8 ] = b"1234567" ;
664
698
@@ -674,9 +708,42 @@ fn cross_process() {
674
708
( data, vec![ ] , vec![ ] ) ) ;
675
709
}
676
710
711
+ #[ cfg( not( any( feature = "force-inprocess" , target_os = "android" , target_os = "ios" ) ) ) ]
712
+ #[ test]
713
+ fn cross_process_sender_transfer_spawn ( ) {
714
+ let channel_name = get_channel_name_arg ( "server" ) ;
715
+ if let Some ( channel_name) = channel_name {
716
+ let super_tx = OsIpcSender :: connect ( channel_name) . unwrap ( ) ;
717
+ let ( sub_tx, sub_rx) = platform:: channel ( ) . unwrap ( ) ;
718
+ let data: & [ u8 ] = b"foo" ;
719
+ super_tx. send ( data, vec ! [ OsIpcChannel :: Sender ( sub_tx) ] , vec ! [ ] ) . unwrap ( ) ;
720
+ sub_rx. recv ( ) . unwrap ( ) ;
721
+ let data: & [ u8 ] = b"bar" ;
722
+ super_tx. send ( data, vec ! [ ] , vec ! [ ] ) . unwrap ( ) ;
723
+
724
+ unsafe { libc:: exit ( 0 ) ; }
725
+ }
726
+
727
+ let ( server, name) = OsIpcOneShotServer :: new ( ) . unwrap ( ) ;
728
+ let mut child_pid = spawn_server ( "cross_process_sender_transfer_spawn" , & [ ( "server" , & * name) ] ) ;
729
+
730
+ let ( super_rx, _, mut received_channels, _) = server. accept ( ) . unwrap ( ) ;
731
+ assert_eq ! ( received_channels. len( ) , 1 ) ;
732
+ let sub_tx = received_channels[ 0 ] . to_sender ( ) ;
733
+ let data: & [ u8 ] = b"baz" ;
734
+ sub_tx. send ( data, vec ! [ ] , vec ! [ ] ) . unwrap ( ) ;
735
+
736
+ let data: & [ u8 ] = b"bar" ;
737
+ let ( received_data, received_channels, received_shared_memory_regions) =
738
+ super_rx. recv ( ) . unwrap ( ) ;
739
+ child_pid. wait ( ) . expect ( "failed to wait on child" ) ;
740
+ assert_eq ! ( ( & received_data[ ..] , received_channels, received_shared_memory_regions) ,
741
+ ( data, vec![ ] , vec![ ] ) ) ;
742
+ }
743
+
677
744
#[ cfg( not( any( feature = "force-inprocess" , target_os = "windows" , target_os = "android" , target_os = "ios" ) ) ) ]
678
745
#[ test]
679
- fn cross_process_sender_transfer ( ) {
746
+ fn cross_process_sender_transfer_fork ( ) {
680
747
let ( server, name) = OsIpcOneShotServer :: new ( ) . unwrap ( ) ;
681
748
682
749
let child_pid = unsafe { fork ( || {
@@ -691,7 +758,7 @@ fn cross_process_sender_transfer() {
691
758
692
759
let ( super_rx, _, mut received_channels, _) = server. accept ( ) . unwrap ( ) ;
693
760
assert_eq ! ( received_channels. len( ) , 1 ) ;
694
- let sub_tx = received_channels. pop ( ) . unwrap ( ) . to_sender ( ) ;
761
+ let sub_tx = received_channels[ 0 ] . to_sender ( ) ;
695
762
let data: & [ u8 ] = b"baz" ;
696
763
sub_tx. send ( data, vec ! [ ] , vec ! [ ] ) . unwrap ( ) ;
697
764
@@ -981,3 +1048,82 @@ mod sync_test {
981
1048
platform:: OsIpcSender :: test_not_sync ( ) ;
982
1049
}
983
1050
}
1051
+
1052
+ // This test panics on Windows, because the other process will panic
1053
+ // when it detects that it receives handles that are intended for another
1054
+ // process. It's marked as ignore/known-fail on Windows for this reason.
1055
+ //
1056
+ // TODO -- this fails on OSX as well with a MACH_SEND_INVALID_RIGHT!
1057
+ // Needs investigation. It may be a similar underlying issue, just done by
1058
+ // the kernel instead of explicitly (ports in a message that's already
1059
+ // buffered are intended for only one process).
1060
+ #[ cfg( not( any( feature = "force-inprocess" , target_os = "android" , target_os = "ios" ) ) ) ]
1061
+ #[ cfg_attr( any( target_os = "windows" , target_os = "macos" ) , ignore) ]
1062
+ #[ test]
1063
+ fn cross_process_two_step_transfer_spawn ( ) {
1064
+ let cookie: & [ u8 ] = b"cookie" ;
1065
+
1066
+ let channel_name = get_channel_name_arg ( "server" ) ;
1067
+ if let Some ( channel_name) = channel_name {
1068
+ // connect by name to our other process
1069
+ let super_tx = OsIpcSender :: connect ( channel_name) . unwrap ( ) ;
1070
+
1071
+ // create a channel for real communication between the two processes
1072
+ let ( sub_tx, sub_rx) = platform:: channel ( ) . unwrap ( ) ;
1073
+
1074
+ // send the other process the tx side, so it can send us the channels
1075
+ super_tx. send ( & [ ] , vec ! [ OsIpcChannel :: Sender ( sub_tx) ] , vec ! [ ] ) . unwrap ( ) ;
1076
+
1077
+ // get two_rx from the other process
1078
+ let ( _, mut received_channels, _) = sub_rx. recv ( ) . unwrap ( ) ;
1079
+ assert_eq ! ( received_channels. len( ) , 1 ) ;
1080
+ let two_rx = received_channels[ 0 ] . to_receiver ( ) ;
1081
+
1082
+ // get one_rx from two_rx's buffer
1083
+ let ( _, mut received_channels, _) = two_rx. recv ( ) . unwrap ( ) ;
1084
+ assert_eq ! ( received_channels. len( ) , 1 ) ;
1085
+ let one_rx = received_channels[ 0 ] . to_receiver ( ) ;
1086
+
1087
+ // get a cookie from one_rx
1088
+ let ( data, _, _) = one_rx. recv ( ) . unwrap ( ) ;
1089
+ assert_eq ! ( & data[ ..] , cookie) ;
1090
+
1091
+ // finally, send a cookie back
1092
+ super_tx. send ( & data, vec ! [ ] , vec ! [ ] ) . unwrap ( ) ;
1093
+
1094
+ // terminate
1095
+ unsafe { libc:: exit ( 0 ) ; }
1096
+ }
1097
+
1098
+ // create channel 1
1099
+ let ( one_tx, one_rx) = platform:: channel ( ) . unwrap ( ) ;
1100
+ // put data in channel 1's pipe
1101
+ one_tx. send ( cookie, vec ! [ ] , vec ! [ ] ) . unwrap ( ) ;
1102
+
1103
+ // create channel 2
1104
+ let ( two_tx, two_rx) = platform:: channel ( ) . unwrap ( ) ;
1105
+ // put channel 1's rx end in channel 2's pipe
1106
+ two_tx. send ( & [ ] , vec ! [ OsIpcChannel :: Receiver ( one_rx) ] , vec ! [ ] ) . unwrap ( ) ;
1107
+
1108
+ // create a one-shot server, and spawn another process
1109
+ let ( server, name) = OsIpcOneShotServer :: new ( ) . unwrap ( ) ;
1110
+ let mut child_pid = spawn_server ( "cross_process_two_step_transfer_spawn" ,
1111
+ & [ ( "server" , & * name) ] ) ;
1112
+
1113
+ // The other process will have sent us a transmit channel in received channels
1114
+ let ( super_rx, _, mut received_channels, _) = server. accept ( ) . unwrap ( ) ;
1115
+ assert_eq ! ( received_channels. len( ) , 1 ) ;
1116
+ let sub_tx = received_channels[ 0 ] . to_sender ( ) ;
1117
+
1118
+ // Send the outer payload channel, so the server can use it to
1119
+ // retrive the inner payload and the cookie
1120
+ sub_tx. send ( & [ ] , vec ! [ OsIpcChannel :: Receiver ( two_rx) ] , vec ! [ ] ) . unwrap ( ) ;
1121
+
1122
+ // Then we wait for the cookie to make its way back to us
1123
+ let ( received_data, received_channels, received_shared_memory_regions) =
1124
+ super_rx. recv ( ) . unwrap ( ) ;
1125
+ let child_exit_code = child_pid. wait ( ) . expect ( "failed to wait on child" ) ;
1126
+ assert ! ( child_exit_code. success( ) ) ;
1127
+ assert_eq ! ( ( & received_data[ ..] , received_channels, received_shared_memory_regions) ,
1128
+ ( cookie, vec![ ] , vec![ ] ) ) ;
1129
+ }
0 commit comments