1 package IPC::Run::Win32IO;
7 IPC::Run::Win32IO - helper routines for IPC::Run on Win32 platforms.
11 use IPC::Run::Win32IO; # Exports all by default
15 IPC::Run needs to use sockets to redirect subprocess I/O so that the select()
16 loop will work on Win32. This seems to only work on WinNT and Win2K at this
17 time, not sure if it will ever work on Win95 or Win98. If you have experience
18 in this area, please contact me at barries@slaysys.com, thanks!.
22 A specialized IO class used on Win32.
32 use vars qw{$VERSION};
37 use Socket qw( IPPROTO_TCP TCP_NODELAY );
41 use IPC::Run::Debug qw( :default _debugging_level );
42 use IPC::Run::Win32Helper qw( _inherit _dont_inherit );
43 use Fcntl qw( O_TEXT O_RDONLY );
45 use base qw( IPC::Run::IO );
48 ## These fields will be set to undef in _cleanup to close
51 'SEND_THROUGH_TEMP_FILE', ## Set by WinHelper::optimize()
52 'RECV_THROUGH_TEMP_FILE', ## Set by WinHelper::optimize()
53 'TEMP_FILE_NAME', ## The name of the temp file, needed for
54 ## error reporting / debugging only.
56 'PARENT_HANDLE', ## The handle of the socket for the parent
57 'PUMP_SOCKET_HANDLE', ## The socket handle for the pump
58 'PUMP_PIPE_HANDLE', ## The anon pipe handle for the pump
59 'CHILD_HANDLE', ## The anon pipe handle for the child
61 'TEMP_FILE_HANDLE', ## The Win32 filehandle for the temp file
65 ## REMOVE OSFHandleOpen
66 use Win32API::File qw(
81 FILE_ATTRIBUTE_TEMPORARY
82 FILE_FLAG_DELETE_ON_CLOSE
83 FILE_FLAG_WRITE_THROUGH
88 # FILE_ATTRIBUTE_HIDDEN
89 # FILE_ATTRIBUTE_SYSTEM
93 ## Force AUTOLOADED constants to be, well, constant by getting them
94 ## to AUTOLOAD before compilation continues. Sigh.
101 INVALID_HANDLE_VALUE,
105 use constant temp_file_flags => (
106 FILE_ATTRIBUTE_TEMPORARY() |
107 FILE_FLAG_DELETE_ON_CLOSE() |
108 FILE_FLAG_WRITE_THROUGH()
111 # FILE_ATTRIBUTE_HIDDEN() |
112 # FILE_ATTRIBUTE_SYSTEM() |
113 my $tmp_file_counter;
117 my IPC::Run::Win32IO $self = shift;
118 my ( $harness ) = @_;
120 $self->_recv_through_temp_file( $harness )
121 if $self->{RECV_THROUGH_TEMP_FILE};
123 CloseHandle( $self->{TEMP_FILE_HANDLE} )
124 if defined $self->{TEMP_FILE_HANDLE};
126 close( $self->{CHILD_HANDLE} )
127 if defined $self->{CHILD_HANDLE};
129 $self->{$_} = undef for @cleanup_fields;
133 sub _create_temp_file {
134 my IPC::Run::Win32IO $self = shift;
136 ## Create a hidden temp file that Win32 will delete when we close
138 unless ( defined $tmp_dir ) {
139 $tmp_dir = File::Spec->catdir(
140 File::Spec->tmpdir, "IPC-Run.tmp"
143 ## Trust in the user's umask.
144 ## This could possibly be a security hole, perhaps
145 ## we should offer an option. Hmmmm, really, people coding
146 ## security conscious apps should audit this code and
147 ## tell me how to make it better. Nice cop-out :).
148 unless ( -d $tmp_dir ) {
149 mkdir $tmp_dir or croak "$!: $tmp_dir";
153 $self->{TEMP_FILE_NAME} = File::Spec->catfile(
154 ## File name is designed for easy sorting and not conflicting
155 ## with other processes. This should allow us to use "t"runcate
156 ## access in CreateFile in case something left some droppings
157 ## around (which should never happen because we specify
158 ## FLAG_DELETE_ON_CLOSE.
159 ## heh, belt and suspenders are better than bug reports; God forbid
160 ## that NT should ever crash before a temp file gets deleted!
161 $tmp_dir, sprintf "Win32io-%06d-%08d", $$, $tmp_file_counter++
164 $self->{TEMP_FILE_HANDLE} = createFile(
165 $self->{TEMP_FILE_NAME},
166 "trw", ## new, truncate, read, write
168 Flags => temp_file_flags,
170 ) or croak "Can't create temporary file, $self->{TEMP_FILE_NAME}: $^E";
172 $self->{TFD} = OsFHandleOpenFd $self->{TEMP_FILE_HANDLE}, 0;
176 "Win32 Optimizer: temp file (",
181 $self->{TEMP_FILE_HANDLE},
183 $self->{TEMP_FILE_NAME}
184 if _debugging_details;
188 sub _reset_temp_file_pointer {
190 SetFilePointer( $self->{TEMP_FILE_HANDLE}, 0, 0, FILE_BEGIN )
191 or confess "$^E seeking on (fd $self->{TFD}) $self->{TEMP_FILE_NAME} for kid's fd $self->{KFD}";
195 sub _send_through_temp_file {
196 my IPC::Run::Win32IO $self = shift;
199 "Win32 optimizer: optimizing "
200 . " $self->{KFD} $self->{TYPE} temp file instead of ",
201 ref $self->{SOURCE} || $self->{SOURCE}
202 if _debugging_details;
204 $self->_create_temp_file;
206 if ( defined ${$self->{SOURCE}} ) {
207 my $bytes_written = 0;
209 if ( $self->binmode ) {
210 $data_ref = $self->{SOURCE};
213 my $data = ${$self->{SOURCE}}; # Ugh, a copy.
214 $data =~ s/(?<!\r)\n/\r\n/g;
219 $self->{TEMP_FILE_HANDLE},
221 0, ## Write entire buffer
223 [], ## Not overlapped.
225 "$^E writing $self->{TEMP_FILE_NAME} for kid to read on fd $self->{KFD}";
227 "Win32 optimizer: wrote $bytes_written to temp file $self->{TEMP_FILE_NAME}"
230 $self->_reset_temp_file_pointer;
235 _debug "Win32 optimizer: kid to read $self->{KFD} from temp file on $self->{TFD}"
236 if _debugging_details;
240 sub _init_recv_through_temp_file {
241 my IPC::Run::Win32IO $self = shift;
243 $self->_create_temp_file;
247 ## TODO: Use the Win32 API in the select loop to see if the file has grown
248 ## and read it incrementally if it has.
249 sub _recv_through_temp_file {
250 my IPC::Run::Win32IO $self = shift;
252 ## This next line kicks in if the run() never got to initting things
253 ## and needs to clean up.
254 return undef unless defined $self->{TEMP_FILE_HANDLE};
256 push @{$self->{FILTERS}}, sub {
257 my ( undef, $out_ref ) = @_;
259 return undef unless defined $self->{TEMP_FILE_HANDLE};
264 $self->{TEMP_FILE_HANDLE},
266 999_999, ## Hmmm, should read the size.
269 ) or croak "$^E reading from $self->{TEMP_FILE_NAME}";
271 _debug "ReadFile( $self->{TFD} ) = $r chars '$s'" if _debugging_data;
273 return undef unless $r;
275 $s =~ s/\r\n/\n/g unless $self->binmode;
277 my $pos = pos $$out_ref;
279 pos( $out_ref ) = $pos;
283 my ( $harness ) = @_;
285 $self->_reset_temp_file_pointer;
287 1 while $self->_do_filters( $harness );
289 pop @{$self->{FILTERS}};
291 IPC::Run::_close( $self->{TFD} );
300 Windows version of IPC::Run::IP::poll.
307 my IPC::Run::Win32IO $self = shift;
309 return if $self->{SEND_THROUGH_TEMP_FILE} || $self->{RECV_THROUGH_TEMP_FILE};
311 return $self->SUPER::poll( @_ );
315 ## When threaded Perls get good enough, we should use threads here.
316 ## The problem with threaded perls is that they dup() all sorts of
317 ## filehandles and fds and don't allow sufficient control over
318 ## closing off the ones we don't want.
321 my ( $stdin, $stdout, $debug_fd, $binmode, $child_label, @opts ) = @_;
322 my ( $stdin_fd, $stdout_fd ) = ( fileno $stdin, fileno $stdout );
324 _debug "pumper stdin = ", $stdin_fd if _debugging_details;
325 _debug "pumper stdout = ", $stdout_fd if _debugging_details;
326 _inherit $stdin_fd, $stdout_fd, $debug_fd;
327 my @I_options = map qq{"-I$_"}, @INC;
329 my $cmd_line = join( " ",
332 qw(-MIPC::Run::Win32Pump -e 1 ),
333 ## I'm using this clunky way of passing filehandles to the child process
334 ## in order to avoid some kind of premature closure of filehandles
335 ## problem I was having with VCP's test suite when passing them
336 ## via CreateProcess. All of the ## REMOVE code is stuff I'd like
337 ## to be rid of and the ## ADD code is what I'd like to use.
338 FdGetOsFHandle( $stdin_fd ), ## REMOVE
339 FdGetOsFHandle( $stdout_fd ), ## REMOVE
340 FdGetOsFHandle( $debug_fd ), ## REMOVE
342 $$, $^T, _debugging_level, qq{"$child_label"},
346 # open SAVEIN, "<&STDIN" or croak "$! saving STDIN"; #### ADD
347 # open SAVEOUT, ">&STDOUT" or croak "$! saving STDOUT"; #### ADD
348 # open SAVEERR, ">&STDERR" or croak "$! saving STDERR"; #### ADD
349 # _dont_inherit \*SAVEIN; #### ADD
350 # _dont_inherit \*SAVEOUT; #### ADD
351 # _dont_inherit \*SAVEERR; #### ADD
352 # open STDIN, "<&$stdin_fd" or croak "$! dup2()ing $stdin_fd (pumper's STDIN)"; #### ADD
353 # open STDOUT, ">&$stdout_fd" or croak "$! dup2()ing $stdout_fd (pumper's STDOUT)"; #### ADD
354 # open STDERR, ">&$debug_fd" or croak "$! dup2()ing $debug_fd (pumper's STDERR/debug_fd)"; #### ADD
356 _debug "pump cmd line: ", $cmd_line if _debugging_details;
359 Win32::Process::Create(
363 1, ## Inherit handles
364 NORMAL_PRIORITY_CLASS,
366 ) or croak "$!: Win32::Process::Create()";
368 # open STDIN, "<&SAVEIN" or croak "$! restoring STDIN"; #### ADD
369 # open STDOUT, ">&SAVEOUT" or croak "$! restoring STDOUT"; #### ADD
370 # open STDERR, ">&SAVEERR" or croak "$! restoring STDERR"; #### ADD
371 # close SAVEIN or croak "$! closing SAVEIN"; #### ADD
372 # close SAVEOUT or croak "$! closing SAVEOUT"; #### ADD
373 # close SAVEERR or croak "$! closing SAVEERR"; #### ADD
375 close $stdin or croak "$! closing pumper's stdin in parent";
376 close $stdout or croak "$! closing pumper's stdout in parent";
377 # Don't close $debug_fd, we need it, as do other pumpers.
379 # Pause a moment to allow the child to get up and running and emit
380 # debug messages. This does not always work.
381 # select undef, undef, undef, 1 if _debugging_details;
383 _debug "_spawn_pumper pid = ", $process->GetProcessID
388 my $next_port = 2048;
389 my $loopback = inet_aton "127.0.0.1";
390 my $tcp_proto = getprotobyname('tcp');
391 croak "$!: getprotobyname('tcp')" unless defined $tcp_proto;
398 my $listener = gensym;
399 socket $listener, PF_INET, SOCK_STREAM, $tcp_proto
400 or croak "$!: socket()";
401 setsockopt $listener, SOL_SOCKET, SO_REUSEADDR, pack("l", 0)
402 or croak "$!: setsockopt()";
409 $next_port = 2048 if ++$next_port > 65_535;
410 unless ( bind $listener, sockaddr_in( $port, $loopback ) ) {
411 push @errors, "$! on port $port";
412 croak join "\n", @errors if @errors > 10;
413 goto PORT_FINDER_LOOP;
417 _debug "win32 port = $port" if _debugging_details;
419 listen $listener, my $queue_size = 1
420 or croak "$!: listen()";
423 socket $client, PF_INET, SOCK_STREAM, $tcp_proto
424 or croak "$!: socket()";
426 my $paddr = sockaddr_in($port, $loopback );
428 connect $client, $paddr
429 or croak "$!: connect()";
431 croak "$!: accept" unless defined $paddr;
433 ## The windows "default" is SO_DONTLINGER, which should make
434 ## sure all socket data goes through. I have my doubts based
435 ## on experimentation, but nothing prompts me to set SO_LINGER
437 setsockopt $client, IPPROTO_TCP, TCP_NODELAY, pack("l", 0)
438 or croak "$!: setsockopt()";
442 _debug "accept()ing on port $port" if _debugging_details;
443 my $paddr = accept( $server, $listener );
444 croak "$!: accept()" unless defined $paddr;
448 "win32 _socket = ( ", fileno $server, ", ", fileno $client, " ) on port $port"
449 if _debugging_details;
450 return ( $server, $client );
454 sub _open_socket_pipe {
455 my IPC::Run::Win32IO $self = shift;
456 my ( $debug_fd, $parent_handle ) = @_;
458 my $is_send_to_child = $self->dir eq "<";
460 $self->{CHILD_HANDLE} = gensym;
461 $self->{PUMP_PIPE_HANDLE} = gensym;
464 $self->{PARENT_HANDLE},
465 $self->{PUMP_SOCKET_HANDLE}
466 ) = _socket $parent_handle;
468 ## These binmodes seem to have no effect on Win2K, but just to be safe
470 binmode $self->{PARENT_HANDLE} or die $!;
471 binmode $self->{PUMP_SOCKET_HANDLE} or die $!;
473 _debug "PUMP_SOCKET_HANDLE = ", fileno $self->{PUMP_SOCKET_HANDLE}
474 if _debugging_details;
476 ##$buf = "write on child end of " . fileno( $self->{WRITE_HANDLE} ) . "\n\n\n\n\n";
477 ##POSIX::write(fileno $self->{WRITE_HANDLE}, $buf, length $buf) or warn "$! in syswrite";
478 ##$buf = "write on parent end of " . fileno( $self->{CHILD_HANDLE} ) . "\r\n";
479 ##POSIX::write(fileno $self->{CHILD_HANDLE},$buf, length $buf) or warn "$! in syswrite";
480 ## $self->{CHILD_HANDLE}->autoflush( 1 );
481 ## $self->{WRITE_HANDLE}->autoflush( 1 );
483 ## Now fork off a data pump and arrange to return the correct fds.
484 if ( $is_send_to_child ) {
485 pipe $self->{CHILD_HANDLE}, $self->{PUMP_PIPE_HANDLE}
486 or croak "$! opening child pipe";
487 _debug "CHILD_HANDLE = ", fileno $self->{CHILD_HANDLE}
488 if _debugging_details;
489 _debug "PUMP_PIPE_HANDLE = ", fileno $self->{PUMP_PIPE_HANDLE}
490 if _debugging_details;
493 pipe $self->{PUMP_PIPE_HANDLE}, $self->{CHILD_HANDLE}
494 or croak "$! opening child pipe";
495 _debug "CHILD_HANDLE = ", fileno $self->{CHILD_HANDLE}
496 if _debugging_details;
497 _debug "PUMP_PIPE_HANDLE = ", fileno $self->{PUMP_PIPE_HANDLE}
498 if _debugging_details;
501 ## These binmodes seem to have no effect on Win2K, but just to be safe
503 binmode $self->{CHILD_HANDLE};
504 binmode $self->{PUMP_PIPE_HANDLE};
506 ## No child should ever see this.
507 _dont_inherit $self->{PARENT_HANDLE};
509 ## We clear the inherit flag so these file descriptors are not inherited.
510 ## It'll be dup()ed on to STDIN/STDOUT/STDERR before CreateProcess is
511 ## called and *that* fd will be inheritable.
512 _dont_inherit $self->{PUMP_SOCKET_HANDLE};
513 _dont_inherit $self->{PUMP_PIPE_HANDLE};
514 _dont_inherit $self->{CHILD_HANDLE};
516 ## Need to return $self so the HANDLEs don't get freed.
517 ## Return $self, $parent_fd, $child_fd
518 my ( $parent_fd, $child_fd ) = (
519 fileno $self->{PARENT_HANDLE},
520 fileno $self->{CHILD_HANDLE}
523 ## Both PUMP_..._HANDLEs will be closed, no need to worry about
525 _debug "binmode on" if _debugging_data && $self->binmode;
528 ? ( $self->{PUMP_SOCKET_HANDLE}, $self->{PUMP_PIPE_HANDLE} )
529 : ( $self->{PUMP_PIPE_HANDLE}, $self->{PUMP_SOCKET_HANDLE} ),
532 $child_fd . $self->dir . "pump" . $self->dir . $parent_fd,
537 confess "PARENT_HANDLE no longer open"
538 unless POSIX::read( $parent_fd, $foo, 0 );
541 _debug "win32_fake_pipe = ( $parent_fd, $child_fd )"
542 if _debugging_details;
544 $self->{FD} = $parent_fd;
545 $self->{TFD} = $child_fd;
549 my IPC::Run::Win32IO $self = shift;
551 if ( $self->{SEND_THROUGH_TEMP_FILE} ) {
552 return $self->_send_through_temp_file( @_ );
554 elsif ( $self->{RECV_THROUGH_TEMP_FILE} ) {
555 return $self->_init_recv_through_temp_file( @_ );
558 return $self->_open_socket_pipe( @_ );
568 Barries Slaymaker <barries@slaysys.com>. Funded by Perforce Software, Inc.
572 Copyright 2001, Barrie Slaymaker, All Rights Reserved.
574 You may use this under the terms of either the GPL 2.0 or the Artistic License.