1 package IPC::Run::Win32IO;
5 IPC::Run::Win32IO - helper routines for IPC::Run on Win32 platforms.
9 use IPC::Run::Win32IO; # Exports all by default
13 IPC::Run needs to use sockets to redirect subprocess I/O so that the select()
14 loop will work on Win32. This seems to only work on WinNT and Win2K at this
15 time, not sure if it will ever work on Win95 or Win98. If you have experience
16 in this area, please contact me at barries@slaysys.com, thanks!.
22 A specialized IO class used on Win32.
32 use Socket qw( IPPROTO_TCP TCP_NODELAY ) ;
34 use Text::ParseWords ;
36 use IPC::Run::Debug qw( :default _debugging_level );
37 use IPC::Run::Win32Helper qw( _inherit _dont_inherit );
38 use Fcntl qw( O_TEXT O_RDONLY );
40 use base qw( IPC::Run::IO );
43 ## These fields will be set to undef in _cleanup to close
46 'SEND_THROUGH_TEMP_FILE', ## Set by WinHelper::optimize()
47 'RECV_THROUGH_TEMP_FILE', ## Set by WinHelper::optimize()
48 'TEMP_FILE_NAME', ## The name of the temp file, needed for
49 ## error reporting / debugging only.
51 'PARENT_HANDLE', ## The handle of the socket for the parent
52 'PUMP_SOCKET_HANDLE', ## The socket handle for the pump
53 'PUMP_PIPE_HANDLE', ## The anon pipe handle for the pump
54 'CHILD_HANDLE', ## The anon pipe handle for the child
56 'TEMP_FILE_HANDLE', ## The Win32 filehandle for the temp file
60 ## REMOVE OSFHandleOpen
61 use Win32API::File qw(
76 FILE_ATTRIBUTE_TEMPORARY
77 FILE_FLAG_DELETE_ON_CLOSE
78 FILE_FLAG_WRITE_THROUGH
83 # FILE_ATTRIBUTE_HIDDEN
84 # FILE_ATTRIBUTE_SYSTEM
88 ## Force AUTOLOADED constants to be, well, constant by getting them
89 ## to AUTOLOAD before compilation continues. Sigh.
101 use constant temp_file_flags => (
102 FILE_ATTRIBUTE_TEMPORARY() |
103 FILE_FLAG_DELETE_ON_CLOSE() |
104 FILE_FLAG_WRITE_THROUGH()
107 # FILE_ATTRIBUTE_HIDDEN() |
108 # FILE_ATTRIBUTE_SYSTEM() |
109 my $tmp_file_counter;
113 my IPC::Run::Win32IO $self = shift;
114 my ( $harness ) = @_;
116 $self->_recv_through_temp_file( $harness )
117 if $self->{RECV_THROUGH_TEMP_FILE};
119 CloseHandle( $self->{TEMP_FILE_HANDLE} )
120 if defined $self->{TEMP_FILE_HANDLE};
122 $self->{$_} = undef for @cleanup_fields;
126 sub _create_temp_file {
127 my IPC::Run::Win32IO $self = shift;
129 ## Create a hidden temp file that Win32 will delete when we close
131 unless ( defined $tmp_dir ) {
132 $tmp_dir = File::Spec->catdir(
133 File::Spec->tmpdir, "IPC-Run.tmp"
136 ## Trust in the user's umask.
137 ## This could possibly be a security hole, perhaps
138 ## we should offer an option. Hmmmm, really, people coding
139 ## security conscious apps should audit this code and
140 ## tell me how to make it better. Nice cop-out :).
141 unless ( -d $tmp_dir ) {
142 mkdir $tmp_dir or croak "$!: $tmp_dir";
146 $self->{TEMP_FILE_NAME} = File::Spec->catfile(
147 ## File name is designed for easy sorting and not conflicting
148 ## with other processes. This should allow us to use "t"runcate
149 ## access in CreateFile in case something left some droppings
150 ## around (which should never happen because we specify
151 ## FLAG_DELETE_ON_CLOSE.
152 ## heh, belt and suspenders are better than bug reports; God forbid
153 ## that NT should ever crash before a temp file gets deleted!
154 $tmp_dir, sprintf "Win32io-%06d-%08d", $$, $tmp_file_counter++
157 $self->{TEMP_FILE_HANDLE} = createFile(
158 $self->{TEMP_FILE_NAME},
159 "trw", ## new, truncate, read, write
161 Flags => temp_file_flags,
163 ) or croak "Can't create temporary file, $self->{TEMP_FILE_NAME}: $^E";
165 $self->{TFD} = OsFHandleOpenFd $self->{TEMP_FILE_HANDLE}, 0;
169 "Win32 Optimizer: temp file (",
174 $self->{TEMP_FILE_HANDLE},
176 $self->{TEMP_FILE_NAME}
177 if _debugging_details;
181 sub _reset_temp_file_pointer {
183 SetFilePointer( $self->{TEMP_FILE_HANDLE}, 0, 0, FILE_BEGIN )
184 or confess "$^E seeking on (fd $self->{TFD}) $self->{TEMP_FILE_NAME} for kid's fd $self->{KFD}";
188 sub _send_through_temp_file {
189 my IPC::Run::Win32IO $self = shift;
192 "Win32 optimizer: optimizing "
193 . " $self->{KFD} $self->{TYPE} temp file instead of ",
194 ref $self->{SOURCE} || $self->{SOURCE}
195 if _debugging_details;
197 $self->_create_temp_file;
199 if ( defined ${$self->{SOURCE}} ) {
200 my $bytes_written = 0;
202 if ( $self->binmode ) {
203 $data_ref = $self->{SOURCE};
206 my $data = ${$self->{SOURCE}}; # Ugh, a copy.
207 $data =~ s/(?<!\r)\n/\r\n/g;
212 $self->{TEMP_FILE_HANDLE},
214 0, ## Write entire buffer
216 [], ## Not overlapped.
218 "$^E writing $self->{TEMP_FILE_NAME} for kid to read on fd $self->{KFD}";
220 "Win32 optimizer: wrote $bytes_written to temp file $self->{TEMP_FILE_NAME}"
223 $self->_reset_temp_file_pointer;
228 _debug "Win32 optimizer: kid to read $self->{KFD} from temp file on $self->{TFD}"
229 if _debugging_details;
233 sub _init_recv_through_temp_file {
234 my IPC::Run::Win32IO $self = shift;
236 $self->_create_temp_file;
240 ## TODO: USe the Win32 API in the select loop to see if the file has grown
241 ## and read it incrementally if it has.
242 sub _recv_through_temp_file {
243 my IPC::Run::Win32IO $self = shift;
245 ## This next line kicks in if the run() never got to initting things
246 ## and needs to clean up.
247 return undef unless defined $self->{TEMP_FILE_HANDLE};
249 push @{$self->{FILTERS}}, sub {
250 my ( undef, $out_ref ) = @_;
252 return undef unless defined $self->{TEMP_FILE_HANDLE};
257 $self->{TEMP_FILE_HANDLE},
259 999_999, ## Hmmm, should read the size.
262 ) or croak "$^E reading from $self->{TEMP_FILE_NAME}";
264 _debug "ReadFile( $self->{TFD} ) = $r chars '$s'" if _debugging_data ;
266 return undef unless $r;
268 $s =~ s/\r\n/\n/g unless $self->binmode;
270 my $pos = pos $$out_ref;
272 pos( $out_ref ) = $pos;
276 my ( $harness ) = @_;
278 $self->_reset_temp_file_pointer;
280 1 while $self->_do_filters( $harness );
282 pop @{$self->{FILTERS}};
284 IPC::Run::_close( $self->{TFD} );
289 my IPC::Run::Win32IO $self = shift;
291 return if $self->{SEND_THROUGH_TEMP_FILE} || $self->{RECV_THROUGH_TEMP_FILE};
293 return $self->SUPER::poll( @_ );
297 ## When threaded Perls get good enough, we should use threads here.
298 ## The problem with threaded perls is that they dup() all sorts of
299 ## filehandles and fds and don't allow sufficient control over
300 ## closing off the ones we don't want.
303 my ( $stdin, $stdout, $debug_fd, $binmode, $child_label, @opts ) = @_ ;
304 my ( $stdin_fd, $stdout_fd ) = ( fileno $stdin, fileno $stdout ) ;
306 _debug "pumper stdin = ", $stdin_fd if _debugging_details;
307 _debug "pumper stdout = ", $stdout_fd if _debugging_details;
308 _inherit $stdin_fd, $stdout_fd, $debug_fd ;
309 my @I_options = map qq{"-I$_"}, @INC;
311 my $cmd_line = join( " ",
314 qw(-MIPC::Run::Win32Pump -e 1 ),
315 ## I'm using this clunky way of passing filehandles to the child process
316 ## in order to avoid some kind of premature closure of filehandles
317 ## problem I was having with VCP's test suite when passing them
318 ## via CreateProcess. All of the ## REMOVE code is stuff I'd like
319 ## to be rid of and the ## ADD code is what I'd like to use.
320 FdGetOsFHandle( $stdin_fd ), ## REMOVE
321 FdGetOsFHandle( $stdout_fd ), ## REMOVE
322 FdGetOsFHandle( $debug_fd ), ## REMOVE
324 $$, $^T, _debugging_level, qq{"$child_label"},
328 # open SAVEIN, "<&STDIN" or croak "$! saving STDIN" ; #### ADD
329 # open SAVEOUT, ">&STDOUT" or croak "$! saving STDOUT" ; #### ADD
330 # open SAVEERR, ">&STDERR" or croak "$! saving STDERR" ; #### ADD
331 # _dont_inherit \*SAVEIN ; #### ADD
332 # _dont_inherit \*SAVEOUT ; #### ADD
333 # _dont_inherit \*SAVEERR ; #### ADD
334 # open STDIN, "<&$stdin_fd" or croak "$! dup2()ing $stdin_fd (pumper's STDIN)" ; #### ADD
335 # open STDOUT, ">&$stdout_fd" or croak "$! dup2()ing $stdout_fd (pumper's STDOUT)" ; #### ADD
336 # open STDERR, ">&$debug_fd" or croak "$! dup2()ing $debug_fd (pumper's STDERR/debug_fd)" ; #### ADD
338 _debug "pump cmd line: ", $cmd_line if _debugging_details;
341 Win32::Process::Create(
345 1, ## Inherit handles
346 NORMAL_PRIORITY_CLASS,
348 ) or croak "$!: Win32::Process::Create()" ;
350 # open STDIN, "<&SAVEIN" or croak "$! restoring STDIN" ; #### ADD
351 # open STDOUT, ">&SAVEOUT" or croak "$! restoring STDOUT" ; #### ADD
352 # open STDERR, ">&SAVEERR" or croak "$! restoring STDERR" ; #### ADD
353 # close SAVEIN or croak "$! closing SAVEIN" ; #### ADD
354 # close SAVEOUT or croak "$! closing SAVEOUT" ; #### ADD
355 # close SAVEERR or croak "$! closing SAVEERR" ; #### ADD
357 close $stdin or croak "$! closing pumper's stdin in parent" ;
358 close $stdout or croak "$! closing pumper's stdout in parent" ;
359 # Don't close $debug_fd, we need it, as do other pumpers.
361 # Pause a moment to allow the child to get up and running and emit
362 # debug messages. This does not always work.
363 # select undef, undef, undef, 1 if _debugging_details ;
365 _debug "_spawn_pumper pid = ", $process->GetProcessID
370 my $next_port = 2048 ;
371 my $loopback = inet_aton "127.0.0.1" ;
372 my $tcp_proto = getprotobyname('tcp');
373 croak "$!: getprotobyname('tcp')" unless defined $tcp_proto ;
376 my ( $server ) = @_ ;
378 my $client = gensym ;
380 my $listener = gensym ;
381 socket $listener, PF_INET, SOCK_STREAM, $tcp_proto
382 or croak "$!: socket()";
383 setsockopt $listener, SOL_SOCKET, SO_REUSEADDR, pack("l", 0)
384 or croak "$!: setsockopt()";
391 $next_port = 2048 if ++$next_port > 65_535 ;
392 unless ( bind $listener, sockaddr_in( $port, INADDR_ANY ) ) {
393 push @errors, "$! on port $port" ;
394 croak join "\n", @errors if @errors > 10 ;
395 goto PORT_FINDER_LOOP;
399 _debug "win32 port = $port" if _debugging_details;
401 listen $listener, my $queue_size = 1
402 or croak "$!: listen()" ;
405 socket $client, PF_INET, SOCK_STREAM, $tcp_proto
406 or croak "$!: socket()";
408 my $paddr = sockaddr_in($port, $loopback );
410 connect $client, $paddr
411 or croak "$!: connect()" ;
413 croak "$!: accept" unless defined $paddr ;
415 ## The windows "default" is SO_DONTLINGER, which should make
416 ## sure all socket data goes through. I have my doubts based
417 ## on experimentation, but nothing prompts me to set SO_LINGER
419 setsockopt $client, IPPROTO_TCP, TCP_NODELAY, pack("l", 0)
420 or croak "$!: setsockopt()";
424 _debug "accept()ing on port $port" if _debugging_details;
425 my $paddr = accept( $server, $listener ) ;
426 croak "$!: accept()" unless defined $paddr ;
430 "win32 _socket = ( ", fileno $server, ", ", fileno $client, " ) on port $port"
431 if _debugging_details;
432 return ( $server, $client ) ;
436 sub _open_socket_pipe {
437 my IPC::Run::Win32IO $self = shift;
438 my ( $debug_fd, $parent_handle ) = @_ ;
440 my $is_send_to_child = $self->dir eq "<";
442 $self->{CHILD_HANDLE} = gensym;
443 $self->{PUMP_PIPE_HANDLE} = gensym;
446 $self->{PARENT_HANDLE},
447 $self->{PUMP_SOCKET_HANDLE}
448 ) = _socket $parent_handle ;
450 ## These binmodes seem to have no effect on Win2K, but just to be safe
452 binmode $self->{PARENT_HANDLE} or die $!;
453 binmode $self->{PUMP_SOCKET_HANDLE} or die $!;
455 _debug "PUMP_SOCKET_HANDLE = ", fileno $self->{PUMP_SOCKET_HANDLE}
456 if _debugging_details;
458 ##$buf = "write on child end of " . fileno( $self->{WRITE_HANDLE} ) . "\n\n\n\n\n" ;
459 ##POSIX::write(fileno $self->{WRITE_HANDLE}, $buf, length $buf) or warn "$! in syswrite" ;
460 ##$buf = "write on parent end of " . fileno( $self->{CHILD_HANDLE} ) . "\r\n" ;
461 ##POSIX::write(fileno $self->{CHILD_HANDLE},$buf, length $buf) or warn "$! in syswrite" ;
462 ## $self->{CHILD_HANDLE}->autoflush( 1 ) ;
463 ## $self->{WRITE_HANDLE}->autoflush( 1 ) ;
465 ## Now fork off a data pump and arrange to return the correct fds.
466 if ( $is_send_to_child ) {
467 pipe $self->{CHILD_HANDLE}, $self->{PUMP_PIPE_HANDLE}
468 or croak "$! opening child pipe" ;
469 _debug "CHILD_HANDLE = ", fileno $self->{CHILD_HANDLE}
470 if _debugging_details;
471 _debug "PUMP_PIPE_HANDLE = ", fileno $self->{PUMP_PIPE_HANDLE}
472 if _debugging_details;
475 pipe $self->{PUMP_PIPE_HANDLE}, $self->{CHILD_HANDLE}
476 or croak "$! opening child pipe" ;
477 _debug "CHILD_HANDLE = ", fileno $self->{CHILD_HANDLE}
478 if _debugging_details;
479 _debug "PUMP_PIPE_HANDLE = ", fileno $self->{PUMP_PIPE_HANDLE}
480 if _debugging_details;
483 ## These binmodes seem to have no effect on Win2K, but just to be safe
485 binmode $self->{CHILD_HANDLE};
486 binmode $self->{PUMP_PIPE_HANDLE};
488 ## No child should ever see this.
489 _dont_inherit $self->{PARENT_HANDLE} ;
491 ## We clear the inherit flag so these file descriptors are not inherited.
492 ## It'll be dup()ed on to STDIN/STDOUT/STDERR before CreateProcess is
493 ## called and *that* fd will be inheritable.
494 _dont_inherit $self->{PUMP_SOCKET_HANDLE} ;
495 _dont_inherit $self->{PUMP_PIPE_HANDLE} ;
496 _dont_inherit $self->{CHILD_HANDLE} ;
498 ## Need to return $self so the HANDLEs don't get freed.
499 ## Return $self, $parent_fd, $child_fd
500 my ( $parent_fd, $child_fd ) = (
501 fileno $self->{PARENT_HANDLE},
502 fileno $self->{CHILD_HANDLE}
505 ## Both PUMP_..._HANDLEs will be closed, no need to worry about
507 _debug "binmode on" if _debugging_data && $self->binmode;
510 ? ( $self->{PUMP_SOCKET_HANDLE}, $self->{PUMP_PIPE_HANDLE} )
511 : ( $self->{PUMP_PIPE_HANDLE}, $self->{PUMP_SOCKET_HANDLE} ),
514 $child_fd . $self->dir . "pump" . $self->dir . $parent_fd,
519 confess "PARENT_HANDLE no longer open"
520 unless POSIX::read( $parent_fd, $foo, 0 ) ;
523 _debug "win32_fake_pipe = ( $parent_fd, $child_fd )"
524 if _debugging_details;
526 $self->{FD} = $parent_fd;
527 $self->{TFD} = $child_fd;
531 my IPC::Run::Win32IO $self = shift;
533 if ( $self->{SEND_THROUGH_TEMP_FILE} ) {
534 return $self->_send_through_temp_file( @_ );
536 elsif ( $self->{RECV_THROUGH_TEMP_FILE} ) {
537 return $self->_init_recv_through_temp_file( @_ );
540 return $self->_open_socket_pipe( @_ );
546 Barries Slaymaker <barries@slaysys.com>. Funded by Perforce Software, Inc.
550 Copyright 2001, Barrie Slaymaker, All Rights Reserved.
552 You may use this under the terms of either the GPL 2.0 ir the Artistic License.