Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris

Pass filehandles around between (unrelated) processes on Windows

by Corion (Pope)
on Jan 12, 2011 at 14:18 UTC ( #881897=CUFP: print w/replies, xml ) Need Help??

I recently looked again at PPerl, because I wanted to fix some other behaviour, and found that it doesn't build on Windows. After a quick converstation with the author, Matt Sergeant, I found that PPerl doesn't cater for Windows because the functionality it needs, sendfd() and SOCK_PERM, only exists on Linux and some other unixish OSes and not on Windows.

Almost by chance, I happened over the DuplicateHandle() API of Windows, which allows to duplicate a file handle for use in another process. My test file implementing this is below.

I use a child process, to which I print the handle number on STDIN. The child process then reads from that filehandle which it knows no name of. With a child process, the same could well have been done using input/output redirection, but the use of a child process is only to alleviate permission issues and general coordination issues, like how the two processes find each other.

#!perl -w use strict; use Win32::API; use Win32; use Win32API::File qw(FdGetOsFHandle); Win32::API->Import( 'kernel32', 'DuplicateHandle', 'NNNPNNN', 'N', ); Win32::API->Import( 'kernel32', 'OpenProcess', 'NNN', 'N', ); # This is the child process that reads the number from STDIN, opens th +at handle, and reads from it my $cmd = q(| perl -MWin32API::File=OsFHandleOpen -e "$fileno=0+<> or +die;OsFHandleOpen(FH, $fileno,'r') or die $!; print for <FH>"); my $child = open my $child_fh, $cmd or die "Can't spawn child [$cmd]: $! / $? / $^E"; print "1..2\n"; print "1 "; print $child ? "" : "not "; print "ok # spawned child\n"; # 0x400 for PROCESS_QUERY_INFORMATION # 0x040 for PROCESS_DUP_HANDLE my $childHandle = OpenProcess(0x440,0,$child) or die $^E; my $buf = "\0\0\0\0"; my $fhandle = FdGetOsFHandle( fileno *DATA ); DuplicateHandle(-1, $fhandle, $childHandle, $buf, 0, 1, 3 ) or die $^E; $buf = unpack "V", $buf; # Now tell our child from what handle it should read print {$child_fh} "$buf\n"; # The parent is done close $child_fh; __DATA__ 2 ok # output read from child process

As is the case on Windows, sockets are outside of this scheme, unfortunately. If you want to pass around sockets between processes, you need to look at WSADuplicateSocket

Replies are listed 'Best First'.
Re: Pass filehandles around between (unrelated) processes on Windows
by zentara (Archbishop) on Jan 12, 2011 at 22:05 UTC
    This is interesting. In linux, all filehandles in a threaded app can be shared thru the fileno, which can be very useful. I guess in the MSWindows kernel, everything is a thread, and all filno's can be accesed?

    Just how does the Microsoft kernel differ from the modern linux kernel in protecting filehandles?

    I'm not really a human, but I play one on earth.
    Old Perl Programmer Haiku ................... flash japh

      No. There would be no need for this API if file handles were shared as you describe in Win32. The API has the kernel create in one process a new file handle that points to the same kernel data structure as an existing file handle of another process. This is the same thing that happens in Unix when you pass an open file descriptor over a socket. It is just that the interface for getting it done is different.

      File handles in Windows are actually very similar to file handles in Unix in many ways (including that they can't be used by another process but can be used by other threads of the same process). For example, the seek position is shared between the two file handles/descriptors in the two processes after this type of operation in both Windows and Unix.

      One difference between the two scenarios regarding protections is that the Windows API requires that one process be able to get a handle to another process (or to the other two processes) with sufficient access to be allowed to copy or create the other process's handle. With the Unix API, the processes need to cooperate (of course) but neither process needs any special access permissions to the other.

      Interestingly, giving out access to your process such that DuplicateHandle() can be used on that process actually means that one can also fairly easily get unrestricted access to the process. So security concerns could easily make the use of this API unacceptable in some scenarios.

      In contrast, one of the example scenarios for the use of the Unix API is to allow processes to share privileges while keeping more control.

      For example, you could have a server process that has special access to manage the directory where log files are kept. A client could be given a file handle that only allows them to append to a log file, a log file that they have no permissions to access in a directory that they have no permissions to access. Yet they can write directly to the log file, not having to pass data through some server process to have it append it for them. (But if the server process is compromised, it only has access to log files, it can't read/write pages of memory of every potential client process.)

      - tye        

      As far as I'm aware, each handle (not a fileno, necessarily, as Windows handles exist for UI-Windows, process/thread handles, mutexes and various other things) is only valid per-thread. To pass a handle to another thread (or another process), you need to DuplicateHandle() it for the recipient.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: CUFP [id://881897]
Approved by marto
Front-paged by ww
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others about the Monastery: (6)
As of 2018-06-19 03:44 GMT
Find Nodes?
    Voting Booth?
    Should cpanminus be part of the standard Perl release?

    Results (111 votes). Check out past polls.