Fix windows issue with multiple workers

Maxim Dounin mdounin at mdounin.ru
Wed Jun 17 02:27:33 UTC 2015


Hello!

On Wed, Jun 10, 2015 at 09:48:28PM +0200, Sergey Brester wrote:

[...]

> @Maxim Dounin:
> 1) your suggested way with shared handle and bInheritHandle does not
> work, because of:
> [quote]
> Sockets. No error is returned, but the duplicate handle may not be
> recognized by Winsock at the target process. Also, using DUPLICATEHANDLE
> interferes with internal reference counting on the underlying object. 
> To duplicate a socket handle, use the WSADUPLICATESOCKET function.
> [/quote] 

The quote is from DuplicateHandle() description, which is 
irrelevant to the approach suggested.  Sockets are inheritable 
between processes, including listen ones.

Simple test code below, as adapted from the accept() MSDN example, 
demonstrates that the approach is working.


#include <winsock2.h>
#include <stdio.h>
#include <windows.h>

#pragma comment(lib, "Ws2_32.lib")

int
main(int argc, char *argv[])
{
    int                  rc;
    u_long               code;
    SOCKET               listen_socket, s;
    WSADATA              wsaData;
    struct sockaddr_in   sin;
    STARTUPINFO          si;
    PROCESS_INFORMATION  pi;
    char                 command[256];

    rc = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (rc != NO_ERROR) {
        printf("WSAStartup() failed: %d\n", rc);
        return 2;
    }

    if (argc == 2) {
        listen_socket = atoi(argv[1]);
        printf("Inherited socket: %d\n", listen_socket);
        goto accept;
    }

    listen_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (listen_socket == INVALID_SOCKET) {
        printf("socket failed with error: %ld\n", WSAGetLastError());
        return 1;
    }

    printf("Listen socket: %d\n", listen_socket);

    sin.sin_family = AF_INET;
    sin.sin_addr.s_addr = inet_addr("127.0.0.1");
    sin.sin_port = htons(8080);

    if (bind(listen_socket, (SOCKADDR *) &sin, sizeof(sin)) == SOCKET_ERROR) {
        printf("bind() failed: %ld\n", WSAGetLastError());
        return 1;
    }

    if (listen(listen_socket, 1) == SOCKET_ERROR) {
        printf("listen() failed: %ld\n", WSAGetLastError());
        return 1;
    }

    if (argc == 1) {
        ZeroMemory(&si, sizeof(si));
        si.cb = sizeof(si);
        ZeroMemory(&pi, sizeof(pi));

        _snprintf(command, sizeof(command), "%s %d", argv[0], listen_socket);

        if (CreateProcess(NULL, command,
                          NULL, NULL, 1, 0, NULL, NULL,
                          &si, &pi)
            == 0)
        {
            printf("CreateProcess() failed: %ld\n", GetLastError());
            return 1;
        }

        WaitForSingleObject(pi.hProcess, INFINITE);

        if (GetExitCodeProcess(pi.hProcess, &code) == 0) {
            printf("GetExitCodeProcess() failed: %ld\n", GetLastError());
            return 1;
        }

        printf("Child process exited: %d\n", code);

        CloseHandle(pi.hProcess);
        CloseHandle(pi.hThread);
    }

accept:

    printf("Waiting for client to connect...\n");

    s = accept(listen_socket, NULL, NULL);
    if (s == INVALID_SOCKET) {
        printf("accept() failed: %ld\n", WSAGetLastError());
        return 1;
    }

    printf("Client connected\n");

    return 0;
}

-- 
Maxim Dounin
http://nginx.org/



More information about the nginx-devel mailing list