Winsock Programmer's FAQ
Section 7: Articles: Passing Sockets Between Processes

Passing Sockets Between Processes

by Warren Young and Frank Schmied

If you want to pass a socket from one process to another, the only "offically sanctioned" way to do this is with Winsock 2's new WSADuplicateSocket() function. The FAQ originally covered this issue this way:

    Winsock 2 provides support for this through the WSADuplicateSocket() facility. The spec describes this method in detail in section 2.10, and MSDN has a step-by-step procedure in its documentation for this function. You should also read article Q150523 in the Microsoft Knowledge Base. It describes how socket inheritance differs between the various flavors of Windows.

    Another fun feature of the Win32 API is that it allows you to give a new process different "standard handles" (stdin, stdout and stderr) when you create it. MSKB article Q190351 addresses this. Note that this feature only allows you to do this with a child process; you can't redirect your own standard I/O handles to a socket. Also, the item notes that some processes may behave stangely when you do this to them. Clearly, this functionality is not as powerful as the Unix world's dup2() system call.

The original FAQ item then said that you can't do this with Winsock 1.1. As it turns out, Frank Schmied showed how you can do this under Microsoft's Winsock 1.1 stack on Win32, with a bit of trickery. Frank wrote:

    Winsock 1.1 lets you pass sockets from one process to another, using the Win32 call DuplicateHandle(). The handling of this call can be quite complicated. In fact, generating the "real" process handles is not as easy as its seems. Windows uses two kinds of window handles: pseudo-handles and real handles. Handles in Windows are usually memory addresses, and the instance handle is none other than the offset pointer of the code start in the current address range. So, an HINSTANCE handle of a process (the pseudo- or local handle) is usually 0x4000000. Porting with this handle from one process to another doesn't work. To get the "real" handle of the current process, you can use OpenProcess():

                OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId());
    

    Duplicating a handle looks like this:

                SOCKET ConvertProcessSocket(SOCKET oldsocket, DWORD source_pid)
                {
                    HANDLE source_handle = OpenProcess(PROCESS_ALL_ACCESS,
                            FALSE, source_pid);
                    HANDLE newhandle;
                    DuplicateHandle(source_handle, (HANDLE)oldsocket,
                            GetCurrentProcess(), &newhandle, 0, FALSE,
                            DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS);
                    CloseHandle(source_handle);
                    return (SOCKET)newhandle;
                }
    

    This works fine on my multiprocesss webserver. This function duplicates the socket into the new process and closes the handle in the old process. The handle has the same access options as the old handle but can't be inherited to child processes. To change this behaviour, alter the FALSE to a TRUE in the DuplicateHandle() call. As you see, the hosts' process handle can be a pseudo handle, the remote processes' handle must be a real handle.

As I understand it, the source process converts its local SOCKET handle to a real handle with OpenProcess(), then passes that value and its process ID to the destination process. The destination process then calls Frank's ConvertProcessSocket() function to convert the real handle to a local handle which you can use with Winsock. Notice that the DuplicateHandle() call closes the source process's handle, and then the CloseHandle() call closes the real handle you passed to the destination process.

Caveats: Frank's technique probably only works with Microsoft stacks. It does not work on Win16, and may not work on WinCE. It may or may not work in the presence of Layered Service Providers, except on Windows NT 4.0 SP 4+, which patches the Installable FileSystems (IFS) layer to make this sort of thing work. It may not work on the second Tuesday of the month, when the moon is in its third quarter, unless you chant "oompa hoozah" four times slowly before running the program. In short, this is trickery: you have been warned. :)

Copyright © 2000 by Warren Young and Frank Schmied. All rights reserved.


<< CSocket Considered Harmful Dealing with Firewalls >>
Last modified on 17 October 2001 at 16:25 UTC-7 Please send corrections to tangent@cyberport.com.
< Go to the main FAQ page << Go to the Home Page