Squid 2.6 MinGW support patch for review

From: Guido Serassio <guido.serassio@dont-contact.us>
Date: Sat, 02 Sep 2006 23:44:31 +0200

Hi,

Here there is the Squid 2.6 MinGW support patch and the three new files needed.

Regards

Guido

-
========================================================
Guido Serassio
Acme Consulting S.r.l. - Microsoft Certified Partner
Via Lucia Savarino, 1 10098 - Rivoli (TO) - ITALY
Tel. : +39.011.9530135 Fax. : +39.011.9781115
Email: guido.serassio@acmeconsulting.it
WWW: http://www.acmeconsulting.it/

/*
 * $Id$
 *
 * DEBUG: section 54 Interprocess Communication
 * AUTHOR: Duane Wessels
 *
 * SQUID Web Proxy Cache http://www.squid-cache.org/
 * ----------------------------------------------------------
 *
 * Squid is the result of efforts by numerous individuals from
 * the Internet community; see the CONTRIBUTORS file for full
 * details. Many organizations have provided support for Squid's
 * development; see the SPONSORS file for full details. Squid is
 * Copyrighted (C) 2001 by the Regents of the University of
 * California; see the COPYRIGHT file for full details. Squid
 * incorporates software developed and/or copyrighted by other
 * sources; see the CREDITS file for full details.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
 *
 */

#include "squid.h"

#ifndef _MSWSOCK_
#include <mswsock.h>
#endif
#include <process.h>

struct ipc_params {
    int type;
    int crfd;
    int cwfd;
    struct sockaddr_in PS;
    const char *prog;
    char **args;
};

struct thread_params {
    int type;
    int rfd;
    int send_fd;
    const char *prog;
    pid_t pid;
};

static unsigned int __stdcall ipc_thread_1(void *params);
static unsigned int __stdcall ipc_thread_2(void *params);

static const char *ok_string = "OK\n";
static const char *err_string = "ERR\n";
static const char *shutdown_string = "$shutdown\n";

static const char *hello_string = "hi there\n";
#define HELLO_BUF_SZ 32
static char hello_buf[HELLO_BUF_SZ];

static int
ipcCloseAllFD(int prfd, int pwfd, int crfd, int cwfd)
{
    if (prfd >= 0)
        comm_close(prfd);
    if (prfd != pwfd)
        if (pwfd >= 0)
            comm_close(pwfd);
    if (crfd >= 0)
        comm_close(crfd);
    if (crfd != cwfd)
        if (cwfd >= 0)
            comm_close(cwfd);
    return -1;
}

int
ipcCreate(int type, const char *prog, const char *const args[], const char *name, int *rfd, int *wfd, HANDLE * hIpc, pid_t * ppid)
{
    unsigned long thread;
    struct ipc_params params;
    int opt;
    int optlen = sizeof(opt);
    DWORD ecode = 0;
    pid_t pid;
    struct sockaddr_in CS;
    struct sockaddr_in PS;
    int crfd = -1;
    int prfd = -1;
    int cwfd = -1;
    int pwfd = -1;
    socklen_t len;
    int x;

    requirePathnameExists(name, prog);

    if (rfd)
        *rfd = -1;
    if (wfd)
        *wfd = -1;
    if (hIpc)
        *hIpc = NULL;
    if (ppid)
        *ppid = -1;

    if (WIN32_OS_version != _WIN_OS_WINNT) {
        getsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *) &opt, &optlen);
        opt = opt & ~(SO_SYNCHRONOUS_NONALERT | SO_SYNCHRONOUS_ALERT);
        setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *) &opt, sizeof(opt));
    }
    if (type == IPC_TCP_SOCKET) {
        crfd = cwfd = comm_open(SOCK_STREAM,
            IPPROTO_TCP,
            local_addr,
            0,
            COMM_NOCLOEXEC,
            name);
        prfd = pwfd = comm_open(SOCK_STREAM,
            IPPROTO_TCP, /* protocol */
            local_addr,
            0, /* port */
            0, /* blocking */
            name);
    } else if (type == IPC_UDP_SOCKET) {
        crfd = cwfd = comm_open(SOCK_DGRAM,
            IPPROTO_UDP,
            local_addr,
            0,
            COMM_NOCLOEXEC,
            name);
        prfd = pwfd = comm_open(SOCK_DGRAM,
            IPPROTO_UDP,
            local_addr,
            0,
            0,
            name);
    } else if (type == IPC_FIFO) {
        debug(54, 0)
            ("ipcCreate: %s: use IPC_TCP_SOCKET instead of IP_FIFO on Windows\n",
            prog);
        assert(0);
    } else {
        assert(IPC_NONE);
    }
    debug(54, 3) ("ipcCreate: prfd FD %d\n", prfd);
    debug(54, 3) ("ipcCreate: pwfd FD %d\n", pwfd);
    debug(54, 3) ("ipcCreate: crfd FD %d\n", crfd);
    debug(54, 3) ("ipcCreate: cwfd FD %d\n", cwfd);

    if (WIN32_OS_version != _WIN_OS_WINNT) {
        getsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *) &opt, &optlen);
        opt = opt | SO_SYNCHRONOUS_NONALERT;
        setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *) &opt, optlen);
    }
    if (crfd < 0) {
        debug(54, 0) ("ipcCreate: Failed to create child FD.\n");
        return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
    }
    if (pwfd < 0) {
        debug(54, 0) ("ipcCreate: Failed to create server FD.\n");
        return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
    }
    if (type == IPC_TCP_SOCKET || type == IPC_UDP_SOCKET) {
        len = sizeof(PS);
        memset(&PS, '\0', len);
        if (getsockname(pwfd, (struct sockaddr *) &PS, &len) < 0) {
            debug(54, 0) ("ipcCreate: getsockname: %s\n", xstrerror());
            return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
        }
        debug(54, 3) ("ipcCreate: FD %d sockaddr %s:%d\n",
            pwfd, inet_ntoa(PS.sin_addr), ntohs(PS.sin_port));
        len = sizeof(CS);
        memset(&CS, '\0', len);
        if (getsockname(crfd, (struct sockaddr *) &CS, &len) < 0) {
            debug(54, 0) ("ipcCreate: getsockname: %s\n", xstrerror());
            return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
        }
        debug(54, 3) ("ipcCreate: FD %d sockaddr %s:%d\n",
            crfd, inet_ntoa(CS.sin_addr), ntohs(CS.sin_port));
    }
    if (type == IPC_TCP_SOCKET) {
        if (listen(crfd, 1) < 0) {
            debug(54, 1) ("ipcCreate: listen FD %d: %s\n", crfd, xstrerror());
            return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
        }
        debug(54, 3) ("ipcCreate: FD %d listening...\n", crfd);
    }
    /* flush or else we get dup data if unbuffered_logs is set */
    logsFlush();
    params.type = type;
    params.crfd = crfd;
    params.cwfd = cwfd;
    params.PS = PS;
    params.prog = prog;
    params.args = (char **) args;

    thread = _beginthreadex(NULL, 0, ipc_thread_1, &params, 0, NULL);

    if (thread == 0) {
        debug(54, 1) ("ipcCreate: _beginthread: %s\n", xstrerror());
        return ipcCloseAllFD(prfd, pwfd, crfd, cwfd);
    }
    if (comm_connect_addr(pwfd, &CS) == COMM_ERROR) {
        CloseHandle((HANDLE) thread);
        return ipcCloseAllFD(prfd, pwfd, -1, -1);
    }
    memset(hello_buf, '\0', HELLO_BUF_SZ);
    x = recv(prfd, hello_buf, HELLO_BUF_SZ - 1, 0);

    if (x < 0) {
        debug(54, 0) ("ipcCreate: PARENT: hello read test failed\n");
        debug(54, 0) ("--> read: %s\n", xstrerror());
        CloseHandle((HANDLE) thread);
        return ipcCloseAllFD(prfd, pwfd, -1, -1);
    } else if (strcmp(hello_buf, hello_string)) {
        debug(54, 0) ("ipcCreate: PARENT: hello read test failed\n");
        debug(54, 0) ("--> read returned %d\n", x);
        debug(54, 0) ("--> got '%s'\n", rfc1738_escape(hello_buf));
        CloseHandle((HANDLE) thread);
        return ipcCloseAllFD(prfd, pwfd, -1, -1);
    }
    x = send(pwfd, ok_string, strlen(ok_string), 0);

    if (x < 0) {
        debug(54, 0) ("ipcCreate: PARENT: OK write test failed\n");
        debug(54, 0) ("--> read: %s\n", xstrerror());
        CloseHandle((HANDLE) thread);
        return ipcCloseAllFD(prfd, pwfd, -1, -1);
    }
    memset(hello_buf, '\0', HELLO_BUF_SZ);
    x = recv(prfd, hello_buf, HELLO_BUF_SZ - 1, 0);

    if (x < 0) {
        debug(54, 0) ("ipcCreate: PARENT: OK read test failed\n");
        debug(54, 0) ("--> read: %s\n", xstrerror());
        CloseHandle((HANDLE) thread);
        return ipcCloseAllFD(prfd, pwfd, -1, -1);
    } else if (!strcmp(hello_buf, err_string)) {
        debug(54, 0) ("ipcCreate: PARENT: OK read test failed\n");
        debug(54, 0) ("--> read returned %d\n", x);
        debug(54, 0) ("--> got '%s'\n", rfc1738_escape(hello_buf));
        CloseHandle((HANDLE) thread);
        return ipcCloseAllFD(prfd, pwfd, -1, -1);
    }
    hello_buf[x] = '\0';
    pid = atol(hello_buf);
    commSetTimeout(prfd, -1, NULL, NULL);
    commSetNonBlocking(prfd);
    commSetNonBlocking(pwfd);
    commSetCloseOnExec(prfd);
    commSetCloseOnExec(pwfd);

    if (rfd)
        *rfd = prfd;
    if (wfd)
        *wfd = pwfd;

    fd_table[prfd].flags.ipc = 1;
    fd_table[pwfd].flags.ipc = 1;
    fd_table[crfd].flags.ipc = 1;
    fd_table[cwfd].flags.ipc = 1;

    if (Config.sleep_after_fork) {
        /* XXX emulation of usleep() */
        DWORD sl;
        sl = Config.sleep_after_fork / 1000;
        if (sl == 0)
            sl = 1;
        Sleep(sl);
    }
    if (GetExitCodeThread((HANDLE) thread, &ecode) && ecode == STILL_ACTIVE) {
        if (hIpc)
            *hIpc = (HANDLE) thread;
        if (ppid)
            *ppid = pid;
        return pwfd;
    } else {
        CloseHandle((HANDLE) thread);
        return ipcCloseAllFD(prfd, pwfd, -1, -1);
    }
}

static int
ipcSend(int cwfd, const char *buf, int len)
{
    int x;

    x = send(cwfd, buf, len, 0);

    if (x < 0) {
        debug(54, 0) ("sendto FD %d: %s\n", cwfd, xstrerror());
        debug(54, 0) ("ipcCreate: CHILD: hello write test failed\n");
    }
    return x;
}

static unsigned int __stdcall
ipc_thread_1(void *in_params)
{
    int t1, t2, t3, retval = -1;
    int p2c[2] =
    {-1, -1};
    int c2p[2] =
    {-1, -1};
    HANDLE hProcess = NULL, thread = NULL;
    pid_t pid = -1;
    struct thread_params thread_params;
    int x, tmp_s, fd = -1;
    char *str;
#if HAVE_PUTENV
    char *env_str = NULL;
#endif
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    long F;
    int prfd_ipc = -1, pwfd_ipc = -1, crfd_ipc = -1, cwfd_ipc = -1;
    char *prog = NULL, *buf1 = NULL;
    struct sockaddr_in CS_ipc, PS_ipc;

    struct ipc_params *params = (struct ipc_params *) in_params;
    int type = params->type;
    int crfd = params->crfd;
    int cwfd = params->cwfd;
    char **args = params->args;
    struct sockaddr_in PS = params->PS;

    buf1 = xcalloc(1, 8192);
    strcpy(buf1, params->prog);
    prog = strtok(buf1, w_space);

    if ((str = strrchr(prog, '/')))
        prog = ++str;
    if ((str = strrchr(prog, '\\')))
        prog = ++str;

    prog = xstrdup(prog);

    if (type == IPC_TCP_SOCKET) {
        debug(54, 3) ("ipcCreate: calling accept on FD %d\n", crfd);
        if ((fd = accept(crfd, NULL, NULL)) < 0) {
            debug(54, 0) ("ipcCreate: FD %d accept: %s\n", crfd, xstrerror());
            goto cleanup;
        }
        debug(54, 3) ("ipcCreate: CHILD accepted new FD %d\n", fd);
        comm_close(crfd);
        snprintf(buf1, 8191, "%s CHILD socket", prog);
        fd_open(fd, FD_SOCKET, buf1);
        fd_table[fd].flags.ipc = 1;
        cwfd = crfd = fd;
    } else if (type == IPC_UDP_SOCKET) {
        if (comm_connect_addr(crfd, &PS) == COMM_ERROR)
            goto cleanup;
    }
    x = send(cwfd, hello_string, strlen(hello_string) + 1, 0);

    if (x < 0) {
        debug(54, 0) ("sendto FD %d: %s\n", cwfd, xstrerror());
        debug(54, 0) ("ipcCreate: CHILD: hello write test failed\n");
        goto cleanup;
    }
#if HAVE_PUTENV
    env_str = xcalloc((tmp_s = strlen(Config.debugOptions) + 32), 1);
    snprintf(env_str, tmp_s, "SQUID_DEBUG=%s", Config.debugOptions);
    putenv(env_str);
#endif
    memset(buf1, '\0', sizeof(buf1));
    x = recv(crfd, buf1, 8191, 0);

    if (x < 0) {
        debug(54, 0) ("ipcCreate: CHILD: OK read test failed\n");
        debug(54, 0) ("--> read: %s\n", xstrerror());
        goto cleanup;
    } else if (strcmp(buf1, ok_string)) {
        debug(54, 0) ("ipcCreate: CHILD: OK read test failed\n");
        debug(54, 0) ("--> read returned %d\n", x);
        debug(54, 0) ("--> got '%s'\n", rfc1738_escape(hello_buf));
        goto cleanup;
    }
    /* assign file descriptors to child process */
    if (_pipe(p2c, 1024, _O_BINARY | _O_NOINHERIT) < 0) {
        debug(54, 0) ("ipcCreate: CHILD: pipe: %s\n", xstrerror());
        ipcSend(cwfd, err_string, strlen(err_string));
        goto cleanup;
    }
    if (_pipe(c2p, 1024, _O_BINARY | _O_NOINHERIT) < 0) {
        debug(54, 0) ("ipcCreate: CHILD: pipe: %s\n", xstrerror());
        ipcSend(cwfd, err_string, strlen(err_string));
        goto cleanup;
    }
    if (type == IPC_UDP_SOCKET) {
        snprintf(buf1, 8192, "%s(%ld) <-> ipc CHILD socket", prog, -1L);
        crfd_ipc = cwfd_ipc = comm_open(SOCK_DGRAM, IPPROTO_UDP, local_addr, 0, 0, buf1);

        if (crfd_ipc < 0) {
            debug(54, 0) ("ipcCreate: CHILD: Failed to create child FD for %s.\n",
                prog);
            ipcSend(cwfd, err_string, strlen(err_string));
            goto cleanup;
        }
        snprintf(buf1, 8192, "%s(%ld) <-> ipc PARENT socket", prog, -1L);
        prfd_ipc = pwfd_ipc = comm_open(SOCK_DGRAM, IPPROTO_UDP, local_addr, 0, 0, buf1);
        if (pwfd_ipc < 0) {
            debug(54, 0) ("ipcCreate: CHILD: Failed to create server FD for %s.\n",
                prog);
            ipcSend(cwfd, err_string, strlen(err_string));
            goto cleanup;
        }
        tmp_s = sizeof(PS_ipc);
        memset(&PS_ipc, '\0', tmp_s);
        if (getsockname(pwfd_ipc, (struct sockaddr *) &PS_ipc, &tmp_s) < 0) {
            debug(54, 0) ("ipcCreate: getsockname: %s\n", xstrerror());
            ipcSend(cwfd, err_string, strlen(err_string));
            goto cleanup;
        }
        debug(54, 3) ("ipcCreate: FD %d sockaddr %s:%d\n",
            pwfd_ipc, inet_ntoa(PS_ipc.sin_addr), ntohs(PS_ipc.sin_port));
        tmp_s = sizeof(CS_ipc);
        memset(&CS_ipc, '\0', tmp_s);
        if (getsockname(crfd_ipc, (struct sockaddr *) &CS_ipc, &tmp_s) < 0) {
            debug(54, 0) ("ipcCreate: getsockname: %s\n", xstrerror());
            ipcSend(cwfd, err_string, strlen(err_string));
            goto cleanup;
        }
        debug(54, 3) ("ipcCreate: FD %d sockaddr %s:%d\n",
            crfd_ipc, inet_ntoa(CS_ipc.sin_addr), ntohs(CS_ipc.sin_port));

        if (comm_connect_addr(pwfd_ipc, &CS_ipc) == COMM_ERROR) {
            ipcSend(cwfd, err_string, strlen(err_string));
            goto cleanup;
        }
        fd = crfd;

        if (comm_connect_addr(crfd_ipc, &PS_ipc) == COMM_ERROR) {
            ipcSend(cwfd, err_string, strlen(err_string));
            goto cleanup;
        }
    } /* IPC_UDP_SOCKET */
    t1 = dup(0);
    t2 = dup(1);
    t3 = dup(2);
    dup2(c2p[0], 0);
    dup2(p2c[1], 1);
    dup2(fileno(debug_log), 2);
    close(c2p[0]);
    close(p2c[1]);

    commUnsetNonBlocking(fd);

    memset(&si, 0, sizeof(STARTUPINFO));
    si.cb = sizeof(STARTUPINFO);
    si.hStdInput = (HANDLE) _get_osfhandle(0);
    si.hStdOutput = (HANDLE) _get_osfhandle(1);
    si.hStdError = (HANDLE) _get_osfhandle(2);
    si.dwFlags = STARTF_USESTDHANDLES;

    /* Make sure all other valid handles are not inerithable */
    for (x = 3; x < Squid_MaxFD; x++) {
        if ((F = _get_osfhandle(x)) == -1)
            continue;
        SetHandleInformation((HANDLE) F, HANDLE_FLAG_INHERIT, 0);
    }

    *buf1 = '\0';
    strcpy(buf1 + 4096, params->prog);
    str = strtok(buf1 + 4096, w_space);

    do {
        strcat(buf1, str);
        strcat(buf1, " ");
    } while ((str = strtok(NULL, w_space)));

    x = 1;

    while (args[x]) {
        strcat(buf1, args[x++]);
        strcat(buf1, " ");
    }

    if (CreateProcess(buf1 + 4096, buf1, NULL, NULL, TRUE, CREATE_NO_WINDOW,
            NULL, NULL, &si, &pi)) {
        pid = pi.dwProcessId;
        hProcess = pi.hProcess;
    } else {
        pid = -1;
        WIN32_maperror(GetLastError());
        x = errno;
    }

    dup2(t1, 0);
    dup2(t2, 1);
    dup2(t3, 2);
    close(t1);
    close(t2);
    close(t3);

    if (pid == -1) {
        errno = x;
        debug(54, 0) ("ipcCreate: CHILD: %s: %s\n", params->prog, xstrerror());
        ipcSend(cwfd, err_string, strlen(err_string));
        goto cleanup;
    }
    if (type == IPC_UDP_SOCKET) {
        WSAPROTOCOL_INFO wpi;

        memset(&wpi, 0, sizeof(wpi));
        if (SOCKET_ERROR == WSADuplicateSocket(crfd_ipc, pid, &wpi)) {
            debug(54, 0) ("ipcCreate: CHILD: WSADuplicateSocket: %s\n",
                xstrerror());
            ipcSend(cwfd, err_string, strlen(err_string));
            goto cleanup;
        }
        x = write(c2p[1], (const char *) &wpi, sizeof(wpi));
        if (x < sizeof(wpi)) {
            debug(54, 0) ("ipcCreate: CHILD: write FD %d: %s\n", c2p[1],
                xstrerror());
            debug(54, 0) ("ipcCreate: CHILD: %s: socket exchange failed\n",
                prog);
            ipcSend(cwfd, err_string, strlen(err_string));
            goto cleanup;
        }
        x = read(p2c[0], buf1, 8192);
        if (x < 0) {
            debug(54, 0) ("ipcCreate: CHILD: read FD %d: %s\n", p2c[0],
                xstrerror());
            debug(54, 0) ("ipcCreate: CHILD: %s: socket exchange failed\n",
                prog);
            ipcSend(cwfd, err_string, strlen(err_string));
            goto cleanup;
        } else if (strncmp(buf1, ok_string, strlen(ok_string))) {
            debug(54, 0) ("ipcCreate: CHILD: %s: socket exchange failed\n",
                prog);
            debug(54, 0) ("--> read returned %d\n", x);
            buf1[x] = '\0';
            debug(54, 0) ("--> got '%s'\n", rfc1738_escape(buf1));
            ipcSend(cwfd, err_string, strlen(err_string));
            goto cleanup;
        }
        x = write(c2p[1], (const char *) &PS_ipc, sizeof(PS_ipc));
        if (x < sizeof(PS_ipc)) {
            debug(54, 0) ("ipcCreate: CHILD: write FD %d: %s\n", c2p[1],
                xstrerror());
            debug(54, 0) ("ipcCreate: CHILD: %s: socket exchange failed\n",
                prog);
            ipcSend(cwfd, err_string, strlen(err_string));
            goto cleanup;
        }
        x = read(p2c[0], buf1, 8192);
        if (x < 0) {
            debug(54, 0) ("ipcCreate: CHILD: read FD %d: %s\n", p2c[0],
                xstrerror());
            debug(54, 0) ("ipcCreate: CHILD: %s: socket exchange failed\n",
                prog);
            ipcSend(cwfd, err_string, strlen(err_string));
            goto cleanup;
        } else if (strncmp(buf1, ok_string, strlen(ok_string))) {
            debug(54, 0) ("ipcCreate: CHILD: %s: socket exchange failed\n",
                prog);
            debug(54, 0) ("--> read returned %d\n", x);
            buf1[x] = '\0';
            debug(54, 0) ("--> got '%s'\n", rfc1738_escape(buf1));
            ipcSend(cwfd, err_string, strlen(err_string));
            goto cleanup;
        }
        x = send(pwfd_ipc, ok_string, strlen(ok_string), 0);
        x = recv(prfd_ipc, buf1 + 200, 8191 - 200, 0);
        assert((size_t) x == strlen(ok_string)
            && !strncmp(ok_string, buf1 + 200, strlen(ok_string)));
    } /* IPC_UDP_SOCKET */
    snprintf(buf1, 8191, "%s(%ld) CHILD socket", prog, (long int) pid);
    fd_note(fd, buf1);

    if (prfd_ipc != -1) {
        snprintf(buf1, 8191, "%s(%ld) <-> ipc CHILD socket", prog, (long int) pid);
        fd_note(crfd_ipc, buf1);
        snprintf(buf1, 8191, "%s(%ld) <-> ipc PARENT socket", prog, (long int) pid);
        fd_note(prfd_ipc, buf1);
    } /* else { // IPC_TCP_SOCKET
                                 * * * * commSetNoLinger(fd);
                                 * * * * }
                                 */
    thread_params.prog = prog;
    thread_params.send_fd = cwfd;
    thread_params.pid = pid;

    if ((thread_params.type = type) == IPC_TCP_SOCKET)
        thread_params.rfd = p2c[0];
    else
        thread_params.rfd = prfd_ipc;

    thread =
        (HANDLE) _beginthreadex(NULL, 0, ipc_thread_2, &thread_params, 0, NULL);

    if (!thread) {
        debug(54, 0) ("ipcCreate: CHILD: _beginthreadex: %s\n", xstrerror());
        ipcSend(cwfd, err_string, strlen(err_string));
        goto cleanup;
    }
    snprintf(buf1, 8191, "%ld\n", (long int) pid);

    if (-1 == ipcSend(cwfd, buf1, strlen(buf1)))
        goto cleanup;

    debug(54, 2) ("ipc(%s,%ld): started successfully\n", prog, (long int) pid);

    /* cycle */
    for (;;) {
        x = recv(crfd, buf1, 8192, 0);
        if (x <= 0) {
            debug(54, 3) ("ipc(%s,%d): %d bytes received from parent. Exiting...\n",
                prog, pid, x);
            break;
        }
        buf1[x] = '\0';
        if (type == IPC_UDP_SOCKET && !strcmp(buf1, shutdown_string)) {
            debug(54, 3)
                ("ipc(%s,%d): request for shutdown received from parent. Exiting...\n",
                prog, pid);
            TerminateProcess(hProcess, 0);
            break;
        }
        debug(54, 5) ("ipc(%s,%d): received from parent: %s\n", prog, pid,
            rfc1738_escape_unescaped(buf1));
        if (type == IPC_TCP_SOCKET)
            x = write(c2p[1], buf1, x);
        else
            x = send(pwfd_ipc, buf1, x, 0);
        if (x <= 0) {
            debug(54, 3) ("ipc(%s,%d): %d bytes written to %s. Exiting...\n",
                prog, pid, x, prog);
            break;
        }
    }

    retval = 0;

  cleanup:
    if (c2p[1] != -1)
        close(c2p[1]);

    if (fd_table[crfd].flags.open)
        ipcCloseAllFD(-1, -1, crfd, cwfd);

    if (prfd_ipc != -1) {
        send(crfd_ipc, shutdown_string, strlen(shutdown_string), 0);
        shutdown(crfd_ipc, SD_BOTH);
        shutdown(prfd_ipc, SD_BOTH);
    }
    ipcCloseAllFD(prfd_ipc, pwfd_ipc, crfd_ipc, cwfd_ipc);

    if (hProcess && WAIT_OBJECT_0 !=
        WaitForSingleObject(hProcess, type == IPC_UDP_SOCKET ? 12000 : 5000)) {

        getCurrentTime();
        debug(54, 0) ("ipc(%s,%d): WARNING: %s didn't exit in %d seconds.\n",
            prog, pid, prog, type == IPC_UDP_SOCKET ? 12 : 5);
    }
    if (thread && WAIT_OBJECT_0 != WaitForSingleObject(thread, 3000)) {
        getCurrentTime();
        debug(54, 0)
            ("ipc(%s,%d): WARNING: ipc_thread_2 didn't exit in 3 seconds.\n",
            prog, pid);
    }
    getCurrentTime();

    if (!retval)
        debug(54, 2) ("ipc(%s,%d): normal exit\n", prog, pid);

    if (buf1)
        xfree(buf1);

    if (prog)
        xfree(prog);

    if (env_str)
        xfree(env_str);

    if (thread)
        CloseHandle(thread);

    if (hProcess)
        CloseHandle(hProcess);

    if (p2c[0] != -1)
        close(p2c[0]);

    return retval;
}

static unsigned int __stdcall
ipc_thread_2(void *in_params)
{
    int x;
    struct thread_params *params = (struct thread_params *) in_params;
    int type = params->type;
    int rfd = params->rfd;
    int send_fd = params->send_fd;
    char *prog = xstrdup(params->prog);
    pid_t pid = params->pid;
    char *buf2 = xcalloc(1, 8192);

    for (;;) {
        if (type == IPC_TCP_SOCKET)
            x = read(rfd, buf2, 8192);
        else
            x = recv(rfd, buf2, 8192, 0);
        if ((x <= 0 && type == IPC_TCP_SOCKET) ||
            (x < 0 && type == IPC_UDP_SOCKET)) {
            debug(54, 3) ("ipc(%s,%d): %d bytes read from %s. Exiting...\n",
                prog, pid, x, prog);
            break;
        }
        buf2[x] = '\0';
        if (type == IPC_UDP_SOCKET && !strcmp(buf2, shutdown_string)) {
            debug(54, 3) ("ipc(%s,%d): request for shutdown received. Exiting...\n",
                prog, pid);
            break;
        }
        if (x >= 2) {
            if ((buf2[x - 1] == '\n') && (buf2[x - 2] == '\r')) {
                buf2[x - 2] = '\n';
                buf2[x - 1] = '\0';
                x--;
            }
        }
        debug(54, 5) ("ipc(%s,%d): received from child : %s\n", prog, pid,
            rfc1738_escape_unescaped(buf2));
        x = send(send_fd, buf2, x, 0);
        if ((x <= 0 && type == IPC_TCP_SOCKET) ||
            (x < 0 && type == IPC_UDP_SOCKET)) {
            debug(54, 3) ("ipc(%s,%d): %d bytes sent to parent. Exiting...\n",
                prog, pid, x);
            break;
        }
    }

    xfree(prog);
    xfree(buf2);
    return 0;
}

/*
 * $Id$
 *
 * AUTHOR: Guido Serassio & Andrey Shorin
 *
 * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
 * ----------------------------------------------------------
 *
 * Squid is the result of efforts by numerous individuals from the
 * Internet community. Development is led by Duane Wessels of the
 * National Laboratory for Applied Network Research and funded by the
 * National Science Foundation. Squid is Copyrighted (C) 1998 by
 * the Regents of the University of California. Please see the
 * COPYRIGHT file for full details. Squid incorporates software
 * developed and/or copyrighted by other sources. Please see the
 * CREDITS file for full details.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
 *
 */

#ifndef STDC_HEADERS
#define STDC_HEADERS 1
#endif

#define _WIN32_WINNT 0x0500

#if defined _FILE_OFFSET_BITS && _FILE_OFFSET_BITS == 64
# define __USE_FILE_OFFSET64 1
#endif

#if defined(_MSC_VER) /* Microsoft C Compiler ONLY */

typedef unsigned char u_char;

typedef int SOCKET;
typedef int ssize_t;
typedef int mode_t;

#if defined __USE_FILE_OFFSET64
typedef int64_t off_t;
typedef uint64_t ino_t;

#else
typedef long off_t;
typedef unsigned long ino_t;

#endif

#define INT64_MAX _I64_MAX
#define INT64_MIN _I64_MIN

#include "default_config_file.h"
/* Some tricks for MS Compilers */
#define __STDC__ 1
#pragma include_alias(<dirent.h>, <direct.h>)
#define THREADLOCAL __declspec(thread)

#elif defined(__GNUC__) /* gcc environment */

#define THREADLOCAL __attribute__((section(".tls")))

#endif

#if defined(_MSC_VER) /* Microsoft C Compiler ONLY */
#define alloca _alloca
#endif
#define chdir _chdir
#define dup _dup
#define dup2 _dup2
#define fdopen _fdopen
#if defined(_MSC_VER) /* Microsoft C Compiler ONLY */
#define fileno _fileno
#endif
#define ftruncate WIN32_ftruncate
#define getcwd _getcwd
#define getpid _getpid
#define getrusage WIN32_getrusage
#define ioctl ioctlsocket
#define memccpy _memccpy
#if defined(_MSC_VER) /* Microsoft C Compiler ONLY */
#define mkdir(p) _mkdir(p)
#endif
#define mktemp _mktemp
#define open _open
#define pclose _pclose
#define pipe WIN32_pipe
#define popen _popen
#define putenv _putenv
#define setmode _setmode
#define sleep(t) Sleep((t)*1000)
#if defined(_MSC_VER) /* Microsoft C Compiler ONLY */
#define snprintf _snprintf
#endif
#define strcasecmp _stricmp
#define strdup _strdup
#define strlwr _strlwr
#define strncasecmp _strnicmp
#define tempnam _tempnam
#define truncate WIN32_truncate
#define umask _umask
#define unlink _unlink
#if defined(_MSC_VER) /* Microsoft C Compiler ONLY */
#define vsnprintf _vsnprintf
#endif

#define O_RDONLY _O_RDONLY
#define O_WRONLY _O_WRONLY
#define O_RDWR _O_RDWR
#define O_APPEND _O_APPEND

#define O_CREAT _O_CREAT
#define O_TRUNC _O_TRUNC
#define O_EXCL _O_EXCL

#define O_TEXT _O_TEXT
#define O_BINARY _O_BINARY
#define O_RAW _O_BINARY
#define O_TEMPORARY _O_TEMPORARY
#define O_NOINHERIT _O_NOINHERIT
#define O_SEQUENTIAL _O_SEQUENTIAL
#define O_RANDOM _O_RANDOM
#define O_NDELAY 0

#define S_IRWXO 007
#if defined(_MSC_VER) /* Microsoft C Compiler ONLY */
#define S_ISDIR(m) (((m) & _S_IFDIR) == _S_IFDIR)
#endif

#ifndef SIGHUP
#define SIGHUP 1 /* hangup */
#endif
#ifndef SIGBUS
#define SIGBUS 7 /* bus error */
#endif
#ifndef SIGKILL
#define SIGKILL 9 /* kill (cannot be caught or ignored) */
#endif
#ifndef SIGSEGV
#define SIGSEGV 11 /* segment violation */
#endif
#ifndef SIGPIPE
#define SIGPIPE 13 /* write on a pipe with no one to read it */
#endif
#ifndef SIGCHLD
#define SIGCHLD 20 /* to parent on child stop or exit */
#endif
#ifndef SIGUSR1
#define SIGUSR1 30 /* user defined signal 1 */
#endif
#ifndef SIGUSR2
#define SIGUSR2 31 /* user defined signal 2 */
#endif

typedef unsigned short in_port_t;
typedef unsigned short int ushort;
typedef int uid_t;
typedef int gid_t;

#if defined __USE_FILE_OFFSET64
#define stat _stati64
#if defined(_MSC_VER) /* Microsoft C Compiler ONLY */
#define lseek _lseeki64
#endif
#define fstat _fstati64
#define tell _telli64

#else
#if defined(_MSC_VER) /* Microsoft C Compiler ONLY */
#define stat _stat
#define lseek _lseek
#define fstat _fstat
#define tell _tell
#endif

#endif

struct passwd {
    char *pw_name; /* user name */
    char *pw_passwd; /* user password */
    uid_t pw_uid; /* user id */
    gid_t pw_gid; /* group id */
    char *pw_gecos; /* real name */
    char *pw_dir; /* home directory */
    char *pw_shell; /* shell program */
};

struct group {
    char *gr_name; /* group name */
    char *gr_passwd; /* group password */
    gid_t gr_gid; /* group id */
    char **gr_mem; /* group members */
};

struct statfs {
   long f_type; /* type of filesystem (see below) */
   long f_bsize; /* optimal transfer block size */
   long f_blocks; /* total data blocks in file system */
   long f_bfree; /* free blocks in fs */
   long f_bavail; /* free blocks avail to non-superuser */
   long f_files; /* total file nodes in file system */
   long f_ffree; /* free file nodes in fs */
   long f_fsid; /* file system id */
   long f_namelen; /* maximum length of filenames */
   long f_spare[6]; /* spare for later */
};

struct timezone
  {
    int tz_minuteswest; /* minutes west of Greenwich */
    int tz_dsttime; /* type of dst correction */
  };

#define CHANGE_FD_SETSIZE 1
#if CHANGE_FD_SETSIZE && SQUID_MAXFD > DEFAULT_FD_SETSIZE
#define FD_SETSIZE SQUID_MAXFD
#endif

#include <stddef.h>
#include <process.h>
#if defined(_MSC_VER) /* Microsoft C Compiler ONLY */
/* Hack to suppress compiler warnings on FD_SET() & FD_CLR() */
#pragma warning (push)
#pragma warning (disable:4142)
#endif
/* prevent inclusion of wingdi.h */
#define NOGDI
#include <ws2spi.h>
#if defined(_MSC_VER) /* Microsoft C Compiler ONLY */
#pragma warning (pop)
#include "readdir.h"
#else
#include <io.h>
#include <stdlib.h>
#include <sys/types.h>
#endif

typedef char * caddr_t;

#undef FD_CLOSE
#undef FD_OPEN
#undef FD_READ
#undef FD_WRITE
#define EISCONN WSAEISCONN
#define EINPROGRESS WSAEINPROGRESS
#define EWOULDBLOCK WSAEWOULDBLOCK
#define EALREADY WSAEALREADY
#define ETIMEDOUT WSAETIMEDOUT
#define ECONNREFUSED WSAECONNREFUSED
#define ECONNRESET WSAECONNRESET
#define ERESTART WSATRY_AGAIN
#define ENOTCONN WSAENOTCONN

#undef h_errno
#define h_errno errno /* we'll set it ourselves */

#undef FD_CLR
#define FD_CLR(fd, set) do { \
    u_int __i; \
    SOCKET __sock = _get_osfhandle(fd); \
    for (__i = 0; __i < ((fd_set FAR *)(set))->fd_count ; __i++) { \
        if (((fd_set FAR *)(set))->fd_array[__i] == __sock) { \
            while (__i < ((fd_set FAR *)(set))->fd_count-1) { \
                ((fd_set FAR *)(set))->fd_array[__i] = \
                    ((fd_set FAR *)(set))->fd_array[__i+1]; \
                __i++; \
            } \
            ((fd_set FAR *)(set))->fd_count--; \
            break; \
        } \
    } \
} while(0)

#undef FD_SET
#define FD_SET(fd, set) do { \
    u_int __i; \
    SOCKET __sock = _get_osfhandle(fd); \
    for (__i = 0; __i < ((fd_set FAR *)(set))->fd_count; __i++) { \
        if (((fd_set FAR *)(set))->fd_array[__i] == (__sock)) { \
            break; \
        } \
    } \
    if (__i == ((fd_set FAR *)(set))->fd_count) { \
        if (((fd_set FAR *)(set))->fd_count < FD_SETSIZE) { \
            ((fd_set FAR *)(set))->fd_array[__i] = (__sock); \
            ((fd_set FAR *)(set))->fd_count++; \
        } \
    } \
} while(0)

#undef FD_ISSET
#define FD_ISSET(fd, set) __WSAFDIsSet((SOCKET)(_get_osfhandle(fd)), (fd_set FAR *)(set))

extern THREADLOCAL int ws32_result;

#define strerror(e) WIN32_strerror(e)

#define socket(f,t,p) \
        (INVALID_SOCKET == ((SOCKET)(ws32_result = (int)socket(f,t,p))) ? \
        ((WSAEMFILE == (errno = WSAGetLastError()) ? errno = EMFILE : -1), -1) : \
        (SOCKET)_open_osfhandle(ws32_result,0))
#define accept(s,a,l) \
        (INVALID_SOCKET == ((SOCKET)(ws32_result = (int)accept(_get_osfhandle(s),a,l))) ? \
        ((WSAEMFILE == (errno = WSAGetLastError()) ? errno = EMFILE : -1), -1) : \
        (SOCKET)_open_osfhandle(ws32_result,0))
#define bind(s,n,l) \
        (SOCKET_ERROR == bind(_get_osfhandle(s),n,l) ? \
        (errno = WSAGetLastError()), -1 : 0)
#define connect(s,n,l) \
        (SOCKET_ERROR == connect(_get_osfhandle(s),n,l) ? \
        (WSAEMFILE == (errno = WSAGetLastError()) ? errno = EMFILE : -1, -1) : 0)
#define listen(s,b) \
        (SOCKET_ERROR == listen(_get_osfhandle(s),b) ? \
        (WSAEMFILE == (errno = WSAGetLastError()) ? errno = EMFILE : -1, -1) : 0)
#define shutdown(s,h) \
        (SOCKET_ERROR == shutdown(_get_osfhandle(s),h) ? \
        (errno = WSAGetLastError()), -1 : 0)
#define select(n,r,w,e,t) \
        (SOCKET_ERROR == (ws32_result = select(n,r,w,e,t)) ? \
        (errno = WSAGetLastError()), -1 : ws32_result)
#define recv(s,b,l,f) \
        (SOCKET_ERROR == (ws32_result = recv(_get_osfhandle(s),b,l,f)) ? \
        (errno = WSAGetLastError()), -1 : ws32_result)
#define recvfrom(s,b,l,f,fr,frl) \
        (SOCKET_ERROR == (ws32_result = recvfrom(_get_osfhandle(s),b,l,f,fr,frl)) ? \
        (errno = WSAGetLastError()), -1 : ws32_result)
#define send(s,b,l,f) \
        (SOCKET_ERROR == (ws32_result = send(_get_osfhandle(s),b,l,f)) ? \
        (errno = WSAGetLastError()), -1 : ws32_result)
#define sendto(s,b,l,f,t,tl) \
        (SOCKET_ERROR == (ws32_result = sendto(_get_osfhandle(s),b,l,f,t,tl)) ? \
        (errno = WSAGetLastError()), -1 : ws32_result)
#define getsockname(s,n,l) \
        (SOCKET_ERROR == getsockname(_get_osfhandle(s),n,l) ? \
        (errno = WSAGetLastError()), -1 : 0)
#define getsockopt(s,l,o,v,n) \
        (Sleep(1), SOCKET_ERROR == getsockopt(_get_osfhandle(s),l,o,(char*)v,n) ? \
        (errno = WSAGetLastError()), -1 : 0)
#define setsockopt(s,l,o,v,n) \
        (SOCKET_ERROR == setsockopt(_get_osfhandle(s),l,o,v,n) ? \
        (errno = WSAGetLastError()), -1 : 0)
#define ioctlsocket(s,c,a) \
        (SOCKET_ERROR == ioctlsocket(_get_osfhandle(s),c,a) ? \
        (errno = WSAGetLastError()), -1 : 0)
#define gethostname(n,l) \
        (SOCKET_ERROR == gethostname(n,l) ? \
        (errno = WSAGetLastError()), -1 : 0)
#define gethostbyname(n) \
        (NULL == ((HOSTENT FAR*)(ws32_result = (int)gethostbyname(n))) ? \
        (errno = WSAGetLastError()), NULL : (HOSTENT FAR*)ws32_result)
#define getservbyname(n,p) \
        (NULL == ((SERVENT FAR*)(ws32_result = (int)getservbyname(n,p))) ? \
        (errno = WSAGetLastError()), NULL : (SERVENT FAR*)ws32_result)
#define gethostbyaddr(a,l,t) \
        (NULL == ((HOSTENT FAR*)(ws32_result = (int)gethostbyaddr(a,l,t))) ? \
        (errno = WSAGetLastError()), NULL : (HOSTENT FAR*)ws32_result)
#undef WSASocket
#ifdef UNICODE
#define WSASocket(a,t,p,i,g,f) \
        (INVALID_SOCKET == ((SOCKET)(ws32_result = (int)WSASocketW(a,t,p,i,g,f))) ? \
        ((WSAEMFILE == (errno = WSAGetLastError()) ? errno = EMFILE : -1), -1) : \
        (SOCKET)_open_osfhandle(ws32_result,0))
#else
#define WSASocket(a,t,p,i,g,f) \
        (INVALID_SOCKET == ((SOCKET)(ws32_result = (int)WSASocketA(a,t,p,i,g,f))) ? \
        ((WSAEMFILE == (errno = WSAGetLastError()) ? errno = EMFILE : -1), -1) : \
        (SOCKET)_open_osfhandle(ws32_result,0))
#endif /* !UNICODE */
#undef WSADuplicateSocket
#ifdef UNICODE
#define WSADuplicateSocket(s,n,l) \
        (SOCKET_ERROR == WSADuplicateSocketW(_get_osfhandle(s),n,l) ? \
        (errno = WSAGetLastError()), -1 : 0)
#else
#define WSADuplicateSocket(s,n,l) \
        (SOCKET_ERROR == WSADuplicateSocketA(_get_osfhandle(s),n,l) ? \
        (errno = WSAGetLastError()), -1 : 0)
#endif /* !UNICODE */

#if defined(UTIL_C)
#define read _read
#define write _write
#else
extern THREADLOCAL int _so_err;
extern THREADLOCAL int _so_err_siz;
#define read(fd,buf,siz) \
        (_so_err_siz = sizeof(_so_err), \
        getsockopt((fd),SOL_SOCKET,SO_ERROR,&_so_err,&_so_err_siz) \
        == 0 ? recv((fd),(buf),(siz),0) : _read((fd),(buf),(siz)))
#define write(fd,buf,siz) \
        (_so_err_siz = sizeof(_so_err), \
        getsockopt((fd),SOL_SOCKET,SO_ERROR,&_so_err,&_so_err_siz) \
        == 0 ? send((fd),(buf),(siz),0) : _write((fd),(buf),(siz)))
#endif

#if defined(COMM_C) || defined(TOOLS_C)
#define close WIN32_Close_FD_Socket
#else
#define close _close
#endif

#define RUSAGE_SELF 0 /* calling process */
#define RUSAGE_CHILDREN -1 /* terminated child processes */

struct rusage {
        struct timeval ru_utime; /* user time used */
        struct timeval ru_stime; /* system time used */
        long ru_maxrss; /* integral max resident set size */
        long ru_ixrss; /* integral shared text memory size */
        long ru_idrss; /* integral unshared data size */
        long ru_isrss; /* integral unshared stack size */
        long ru_minflt; /* page reclaims */
        long ru_majflt; /* page faults */
        long ru_nswap; /* swaps */
        long ru_inblock; /* block input operations */
        long ru_oublock; /* block output operations */
        long ru_msgsnd; /* messages sent */
        long ru_msgrcv; /* messages received */
        long ru_nsignals; /* signals received */
        long ru_nvcsw; /* voluntary context switches */
        long ru_nivcsw; /* involuntary context switches */
};

/*
 * $Id$
 *
 * * * * * * * * Legal stuff * * * * * * *
 *
 * (C) 2001 Guido Serassio <serassio@libero.it>,
 * inspired by previous work by Romeo Anghelache & Eric Stern.
 *
 * SQUID Web Proxy Cache http://www.squid-cache.org/
 * ----------------------------------------------------------
 *
 * Squid is the result of efforts by numerous individuals from
 * the Internet community; see the CONTRIBUTORS file for full
 * details. Many organizations have provided support for Squid's
 * development; see the SPONSORS file for full details. Squid is
 * Copyrighted (C) 2001 by the Regents of the University of
 * California; see the COPYRIGHT file for full details. Squid
 * incorporates software developed and/or copyrighted by other
 * sources; see the CREDITS file for full details.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
 *
 */

#include "util.h"

/* The following code section is part of an EXPERIMENTAL native */
/* Windows NT/2000 Squid port - Compiles only on MS Visual C++ */
#if defined(_SQUID_MSWIN_)

#undef strerror
#define sys_nerr _sys_nerr

#undef assert
#include <assert.h>
#include <stdio.h>
#include <limits.h>
#include <errno.h>
#include <windows.h>
#include <string.h>
#include <sys/timeb.h>
#if HAVE_WIN32_PSAPI
#include <psapi.h>
#endif

THREADLOCAL int ws32_result;
THREADLOCAL int _so_err;
THREADLOCAL int _so_err_siz = sizeof(int);
LPCRITICAL_SECTION dbg_mutex = NULL;

/* internal to Microsoft CRTLIB */
#define FPIPE 0x08 /* file handle refers to a pipe */
typedef struct {
    long osfhnd; /* underlying OS file HANDLE */
    char osfile; /* attributes of file (e.g., open in text mode?) */
    char pipech; /* one char buffer for handles opened on pipes */
#ifdef _MT
    int lockinitflag;
    CRITICAL_SECTION lock;
#endif /* _MT */
} ioinfo;

#define IOINFO_L2E 5
#define IOINFO_ARRAY_ELTS (1 << IOINFO_L2E)
#define _pioinfo(i) ( __pioinfo[(i) >> IOINFO_L2E] + ((i) & (IOINFO_ARRAY_ELTS - 1)) )
#define _osfile(i) ( _pioinfo(i)->osfile )
#define _osfhnd(i) ( _pioinfo(i)->osfhnd )

#if defined(_MSC_VER) /* Microsoft C Compiler ONLY */

extern _CRTIMP ioinfo *__pioinfo[];
int __cdecl _free_osfhnd(int);
#define FOPEN 0x01 /* file handle open */

#elif defined(__MINGW32__) /* MinGW environment */

#define FOPEN 0x01 /* file handle open */
__MINGW_IMPORT ioinfo *__pioinfo[];
int _free_osfhnd(int);

#endif

#if defined(_MSC_VER) /* Microsoft C Compiler ONLY */
size_t
getpagesize()
{
    return 4096;
}

int64_t
WIN32_strtoll(const char *nptr, char **endptr, int base)
{
    const char *s;
    int64_t acc;
    int64_t val;
    int neg, any;
    char c;

    /*
     * Skip white space and pick up leading +/- sign if any.
     * If base is 0, allow 0x for hex and 0 for octal, else
     * assume decimal; if base is already 16, allow 0x.
     */
    s = nptr;
    do {
        c = *s++;
    } while (isspace(c));
    if (c == '-') {
        neg = 1;
        c = *s++;
    } else {
        neg = 0;
        if (c == '+')
            c = *s++;
    }
    if ((base == 0 || base == 16) &&
        c == '0' && (*s == 'x' || *s == 'X')) {
        c = s[1];
        s += 2;
        base = 16;
    }
    if (base == 0)
        base = c == '0' ? 8 : 10;
    acc = any = 0;
    if (base < 2 || base > 36) {
        errno = EINVAL;
        if (endptr != NULL)
            *endptr = (char *) (any ? s - 1 : nptr);
        return acc;
    }
    /* The classic bsd implementation requires div/mod operators
     * to compute a cutoff. Benchmarking proves that is very, very
     * evil to some 32 bit processors. Instead, look for underflow
     * in both the mult and add/sub operation. Unlike the bsd impl,
     * we also work strictly in a signed int64 word as we haven't
     * implemented the unsigned type in win32.
     *
     * Set 'any' if any `digits' consumed; make it negative to indicate
     * overflow.
     */
    val = 0;
    for (;; c = *s++) {
        if (c >= '0' && c <= '9')
            c -= '0';
        else if (c >= 'A' && c <= 'Z')
            c -= 'A' - 10;
        else if (c >= 'a' && c <= 'z')
            c -= 'a' - 10;
        else
            break;
        if (c >= base)
            break;
        val *= base;
        if ((any < 0) /* already noted an over/under flow - short circuit */
            ||(neg && (val > acc || (val -= c) > acc)) /* underflow */
            ||(!neg && (val < acc || (val += c) < acc))) { /* overflow */
            any = -1; /* once noted, over/underflows never go away */
        } else {
            acc = val;
            any = 1;
        }
    }

    if (any < 0) {
        acc = neg ? INT64_MIN : INT64_MAX;
        errno = ERANGE;
    } else if (!any) {
        errno = EINVAL;
    }
    if (endptr != NULL)
        *endptr = (char *) (any ? s - 1 : nptr);
    return (acc);
}
#endif

uid_t
geteuid(void)
{
    return 100;
}

uid_t
getuid(void)
{
    return 100;
}

int
setuid(uid_t uid)
{
    return 0;
}

int
seteuid(uid_t euid)
{
    return 0;
}

gid_t
getegid(void)
{
    return 100;
}

gid_t
getgid(void)
{
    return 100;
}

int
setgid(gid_t gid)
{
    return 0;
}

int
setegid(gid_t egid)
{
    return 0;
}

int
chroot(const char *dirname)
{
    if (SetCurrentDirectory(dirname))
        return 0;
    else
        return GetLastError();
}

/* Convert from "a.b.c.d" IP address string into
 * an in_addr structure. Returns 0 on failure,
 * and 1 on success.
 */
int
inet_aton(const char *cp, struct in_addr *addr)
{
    if (cp == NULL || addr == NULL) {
        return (0);
    }
    addr->s_addr = inet_addr(cp);
    return (addr->s_addr == INADDR_NONE) ? 0 : 1;
}

void
GetProcessName(pid_t pid, char *ProcessName)
{
    HANDLE hProcess;

    strcpy(ProcessName, "unknown");
#if HAVE_WIN32_PSAPI
    /* Get a handle to the process. */
    hProcess = OpenProcess(PROCESS_QUERY_INFORMATION |
        PROCESS_VM_READ,
        FALSE, pid);
    /* Get the process name. */
    if (NULL != hProcess) {
        HMODULE hMod;
        DWORD cbNeeded;

        if (EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded))
            GetModuleBaseName(hProcess, hMod, ProcessName, sizeof(ProcessName));
        else {
            CloseHandle(hProcess);
            return;
        }
    } else
        return;
    CloseHandle(hProcess);
#endif
}

int
kill(pid_t pid, int sig)
{
    HANDLE hProcess;
    char MyProcessName[MAX_PATH];
    char ProcessNameToCheck[MAX_PATH];

    if (sig == 0) {
        if ((hProcess = OpenProcess(PROCESS_QUERY_INFORMATION |
                    PROCESS_VM_READ,
                    FALSE, pid)) == NULL)
            return -1;
        else {
            CloseHandle(hProcess);
            GetProcessName(getpid(), MyProcessName);
            GetProcessName(pid, ProcessNameToCheck);
            if (strcmp(MyProcessName, ProcessNameToCheck) == 0)
                return 0;
            return -1;
        }
    } else
        return 0;
}

int
gettimeofday(struct timeval *pcur_time, struct timezone *tz)
{

    struct _timeb current;

    _ftime(&current);

    pcur_time->tv_sec = current.time;
    pcur_time->tv_usec = current.millitm * 1000L;
    if (tz) {
        tz->tz_minuteswest = current.timezone; /* minutes west of Greenwich */
        tz->tz_dsttime = current.dstflag; /* type of dst correction */
    }
    return 0;
}

int
statfs(const char *path, struct statfs *sfs)
{
    char drive[4];
    DWORD spc, bps, freec, totalc;
    DWORD vsn, maxlen, flags;

    if (!sfs) {
        errno = EINVAL;
        return -1;
    }
    strncpy(drive, path, 2);
    drive[2] = '\0';
    strcat(drive, "\\");

    if (!GetDiskFreeSpace(drive, &spc, &bps, &freec, &totalc)) {
        errno = ENOENT;
        return -1;
    }
    if (!GetVolumeInformation(drive, NULL, 0, &vsn, &maxlen, &flags, NULL, 0)) {
        errno = ENOENT;
        return -1;
    }
    sfs->f_type = flags;
    sfs->f_bsize = spc * bps;
    sfs->f_blocks = totalc;
    sfs->f_bfree = sfs->f_bavail = freec;
    sfs->f_files = -1;
    sfs->f_ffree = -1;
    sfs->f_fsid = vsn;
    sfs->f_namelen = maxlen;
    return 0;
}

#if USE_TRUNCATE
int
WIN32_ftruncate(int fd, off_t size)
{
    HANDLE file;
    DWORD error;
    LARGE_INTEGER size64;
    LARGE_INTEGER test64;

    if (fd < 0) {
        errno = EBADF;
        return -1;
    }
    size64.QuadPart = (__int64) size;
    test64.QuadPart = 0;

    file = (HANDLE) _get_osfhandle(fd);

    /* Get current file position to check File Handle */
    test64.LowPart = SetFilePointer(file, test64.LowPart, &test64.HighPart, FILE_CURRENT);
    if ((test64.LowPart == INVALID_SET_FILE_POINTER) && ((error = GetLastError()) != NO_ERROR))
        goto WIN32_ftruncate_error;

    /* Set the current File Pointer position */
    size64.LowPart = SetFilePointer(file, size64.LowPart, &size64.HighPart, FILE_BEGIN);
    if ((size64.LowPart == INVALID_SET_FILE_POINTER) && ((error = GetLastError()) != NO_ERROR))
        goto WIN32_ftruncate_error;
    else if (!SetEndOfFile(file)) {
        int error = GetLastError();
        goto WIN32_ftruncate_error;
    }
    return 0;

  WIN32_ftruncate_error:
    switch (error) {
    case ERROR_INVALID_HANDLE:
        errno = EBADF;
        break;
    default:
        errno = EIO;
        break;
    }

    return -1;
}

int
WIN32_truncate(const char *pathname, off_t length)
{
    int fd;
    int res = -1;

    fd = open(pathname, O_RDWR);

    if (fd == -1)
        errno = EBADF;
    else {
        res = WIN32_ftruncate(fd, length);
        _close(fd);
    }

    return res;
}
#endif

static struct _wsaerrtext {
    int err;
    const char *errconst;
    const char *errdesc;
} _wsaerrtext[] = {

    {
        WSA_E_CANCELLED, "WSA_E_CANCELLED", "Lookup cancelled."
    },
    {
        WSA_E_NO_MORE, "WSA_E_NO_MORE", "No more data available."
    },
    {
        WSAEACCES, "WSAEACCES", "Permission denied."
    },
    {
        WSAEADDRINUSE, "WSAEADDRINUSE", "Address already in use."
    },
    {
        WSAEADDRNOTAVAIL, "WSAEADDRNOTAVAIL", "Cannot assign requested address."
    },
    {
        WSAEAFNOSUPPORT, "WSAEAFNOSUPPORT", "Address family not supported by protocol family."
    },
    {
        WSAEALREADY, "WSAEALREADY", "Operation already in progress."
    },
    {
        WSAEBADF, "WSAEBADF", "Bad file number."
    },
    {
        WSAECANCELLED, "WSAECANCELLED", "Operation cancelled."
    },
    {
        WSAECONNABORTED, "WSAECONNABORTED", "Software caused connection abort."
    },
    {
        WSAECONNREFUSED, "WSAECONNREFUSED", "Connection refused."
    },
    {
        WSAECONNRESET, "WSAECONNRESET", "Connection reset by peer."
    },
    {
        WSAEDESTADDRREQ, "WSAEDESTADDRREQ", "Destination address required."
    },
    {
        WSAEDQUOT, "WSAEDQUOT", "Disk quota exceeded."
    },
    {
        WSAEFAULT, "WSAEFAULT", "Bad address."
    },
    {
        WSAEHOSTDOWN, "WSAEHOSTDOWN", "Host is down."
    },
    {
        WSAEHOSTUNREACH, "WSAEHOSTUNREACH", "No route to host."
    },
    {
        WSAEINPROGRESS, "WSAEINPROGRESS", "Operation now in progress."
    },
    {
        WSAEINTR, "WSAEINTR", "Interrupted function call."
    },
    {
        WSAEINVAL, "WSAEINVAL", "Invalid argument."
    },
    {
        WSAEINVALIDPROCTABLE, "WSAEINVALIDPROCTABLE", "Invalid procedure table from service provider."
    },
    {
        WSAEINVALIDPROVIDER, "WSAEINVALIDPROVIDER", "Invalid service provider version number."
    },
    {
        WSAEISCONN, "WSAEISCONN", "Socket is already connected."
    },
    {
        WSAELOOP, "WSAELOOP", "Too many levels of symbolic links."
    },
    {
        WSAEMFILE, "WSAEMFILE", "Too many open files."
    },
    {
        WSAEMSGSIZE, "WSAEMSGSIZE", "Message too long."
    },
    {
        WSAENAMETOOLONG, "WSAENAMETOOLONG", "File name is too long."
    },
    {
        WSAENETDOWN, "WSAENETDOWN", "Network is down."
    },
    {
        WSAENETRESET, "WSAENETRESET", "Network dropped connection on reset."
    },
    {
        WSAENETUNREACH, "WSAENETUNREACH", "Network is unreachable."
    },
    {
        WSAENOBUFS, "WSAENOBUFS", "No buffer space available."
    },
    {
        WSAENOMORE, "WSAENOMORE", "No more data available."
    },
    {
        WSAENOPROTOOPT, "WSAENOPROTOOPT", "Bad protocol option."
    },
    {
        WSAENOTCONN, "WSAENOTCONN", "Socket is not connected."
    },
    {
        WSAENOTEMPTY, "WSAENOTEMPTY", "Directory is not empty."
    },
    {
        WSAENOTSOCK, "WSAENOTSOCK", "Socket operation on nonsocket."
    },
    {
        WSAEOPNOTSUPP, "WSAEOPNOTSUPP", "Operation not supported."
    },
    {
        WSAEPFNOSUPPORT, "WSAEPFNOSUPPORT", "Protocol family not supported."
    },
    {
        WSAEPROCLIM, "WSAEPROCLIM", "Too many processes."
    },
    {
        WSAEPROTONOSUPPORT, "WSAEPROTONOSUPPORT", "Protocol not supported."
    },
    {
        WSAEPROTOTYPE, "WSAEPROTOTYPE", "Protocol wrong type for socket."
    },
    {
        WSAEPROVIDERFAILEDINIT, "WSAEPROVIDERFAILEDINIT", "Unable to initialise a service provider."
    },
    {
        WSAEREFUSED, "WSAEREFUSED", "Refused."
    },
    {
        WSAEREMOTE, "WSAEREMOTE", "Too many levels of remote in path."
    },
    {
        WSAESHUTDOWN, "WSAESHUTDOWN", "Cannot send after socket shutdown."
    },
    {
        WSAESOCKTNOSUPPORT, "WSAESOCKTNOSUPPORT", "Socket type not supported."
    },
    {
        WSAESTALE, "WSAESTALE", "Stale NFS file handle."
    },
    {
        WSAETIMEDOUT, "WSAETIMEDOUT", "Connection timed out."
    },
    {
        WSAETOOMANYREFS, "WSAETOOMANYREFS", "Too many references."
    },
    {
        WSAEUSERS, "WSAEUSERS", "Too many users."
    },
    {
        WSAEWOULDBLOCK, "WSAEWOULDBLOCK", "Resource temporarily unavailable."
    },
    {
        WSANOTINITIALISED, "WSANOTINITIALISED", "Successful WSAStartup not yet performed."
    },
    {
        WSASERVICE_NOT_FOUND, "WSASERVICE_NOT_FOUND", "Service not found."
    },
    {
        WSASYSCALLFAILURE, "WSASYSCALLFAILURE", "System call failure."
    },
    {
        WSASYSNOTREADY, "WSASYSNOTREADY", "Network subsystem is unavailable."
    },
    {
        WSATYPE_NOT_FOUND, "WSATYPE_NOT_FOUND", "Class type not found."
    },
    {
        WSAVERNOTSUPPORTED, "WSAVERNOTSUPPORTED", "Winsock.dll version out of range."
    },
    {
        WSAEDISCON, "WSAEDISCON", "Graceful shutdown in progress."
    }
};

/*
 * wsastrerror() - description of WSAGetLastError()
 */
const char *
wsastrerror(int err)
{
    static char xwsaerror_buf[BUFSIZ];
    int i, errind = -1;

    if (err == 0)
        return "(0) No error.";
    for (i = 0; i < sizeof(_wsaerrtext) / sizeof(struct _wsaerrtext); i++) {
        if (_wsaerrtext[i].err != err)
            continue;
        errind = i;
        break;
    }
    if (errind == -1)
        snprintf(xwsaerror_buf, BUFSIZ, "Unknown");
    else
        snprintf(xwsaerror_buf, BUFSIZ, "%s, %s", _wsaerrtext[errind].errconst, _wsaerrtext[errind].errdesc);
    return xwsaerror_buf;
}

struct passwd *
getpwnam(char *unused)
{
    static struct passwd pwd =
    {NULL, NULL, 100, 100, NULL, NULL, NULL};
    return &pwd;
}

struct group *
getgrnam(char *unused)
{
    static struct group grp =
    {NULL, NULL, 100, NULL};
    return &grp;
}

/*
 * WIN32_strerror with argument for late notification */

const char *
WIN32_strerror(int err)
{
    static char xbstrerror_buf[BUFSIZ];

    if (err < 0 || err >= sys_nerr)
        strncpy(xbstrerror_buf, wsastrerror(err), BUFSIZ);
    else
        strncpy(xbstrerror_buf, strerror(err), BUFSIZ);
    return xbstrerror_buf;
}

int
WIN32_Close_FD_Socket(int fd)
{
    int result = 0;

    if (closesocket(_get_osfhandle(fd)) == SOCKET_ERROR) {
        errno = WSAGetLastError();
        result = 1;
    }
    _free_osfhnd(fd);
    _osfile(fd) = 0;
    return result;
}

#if defined(__MINGW32__) /* MinGW environment */
int
_free_osfhnd(int filehandle)
{
    if (((unsigned) filehandle < SQUID_MAXFD) &&
        (_osfile(filehandle) & FOPEN) &&
        (_osfhnd(filehandle) != (long) INVALID_HANDLE_VALUE)) {
        switch (filehandle) {
        case 0:
            SetStdHandle(STD_INPUT_HANDLE, NULL);
            break;
        case 1:
            SetStdHandle(STD_OUTPUT_HANDLE, NULL);
            break;
        case 2:
            SetStdHandle(STD_ERROR_HANDLE, NULL);
            break;
        }
        _osfhnd(filehandle) = (long) INVALID_HANDLE_VALUE;
        return (0);
    } else {
        errno = EBADF; /* bad handle */
        _doserrno = 0L; /* not an OS error */
        return -1;
    }
}
#endif

struct errorentry {
    unsigned long WIN32_code;
    int POSIX_errno;
};

static struct errorentry errortable[] =
{
    {ERROR_INVALID_FUNCTION, EINVAL},
    {ERROR_FILE_NOT_FOUND, ENOENT},
    {ERROR_PATH_NOT_FOUND, ENOENT},
    {ERROR_TOO_MANY_OPEN_FILES, EMFILE},
    {ERROR_ACCESS_DENIED, EACCES},
    {ERROR_INVALID_HANDLE, EBADF},
    {ERROR_ARENA_TRASHED, ENOMEM},
    {ERROR_NOT_ENOUGH_MEMORY, ENOMEM},
    {ERROR_INVALID_BLOCK, ENOMEM},
    {ERROR_BAD_ENVIRONMENT, E2BIG},
    {ERROR_BAD_FORMAT, ENOEXEC},
    {ERROR_INVALID_ACCESS, EINVAL},
    {ERROR_INVALID_DATA, EINVAL},
    {ERROR_INVALID_DRIVE, ENOENT},
    {ERROR_CURRENT_DIRECTORY, EACCES},
    {ERROR_NOT_SAME_DEVICE, EXDEV},
    {ERROR_NO_MORE_FILES, ENOENT},
    {ERROR_LOCK_VIOLATION, EACCES},
    {ERROR_BAD_NETPATH, ENOENT},
    {ERROR_NETWORK_ACCESS_DENIED, EACCES},
    {ERROR_BAD_NET_NAME, ENOENT},
    {ERROR_FILE_EXISTS, EEXIST},
    {ERROR_CANNOT_MAKE, EACCES},
    {ERROR_FAIL_I24, EACCES},
    {ERROR_INVALID_PARAMETER, EINVAL},
    {ERROR_NO_PROC_SLOTS, EAGAIN},
    {ERROR_DRIVE_LOCKED, EACCES},
    {ERROR_BROKEN_PIPE, EPIPE},
    {ERROR_DISK_FULL, ENOSPC},
    {ERROR_INVALID_TARGET_HANDLE, EBADF},
    {ERROR_INVALID_HANDLE, EINVAL},
    {ERROR_WAIT_NO_CHILDREN, ECHILD},
    {ERROR_CHILD_NOT_COMPLETE, ECHILD},
    {ERROR_DIRECT_ACCESS_HANDLE, EBADF},
    {ERROR_NEGATIVE_SEEK, EINVAL},
    {ERROR_SEEK_ON_DEVICE, EACCES},
    {ERROR_DIR_NOT_EMPTY, ENOTEMPTY},
    {ERROR_NOT_LOCKED, EACCES},
    {ERROR_BAD_PATHNAME, ENOENT},
    {ERROR_MAX_THRDS_REACHED, EAGAIN},
    {ERROR_LOCK_FAILED, EACCES},
    {ERROR_ALREADY_EXISTS, EEXIST},
    {ERROR_FILENAME_EXCED_RANGE, ENOENT},
    {ERROR_NESTING_NOT_ALLOWED, EAGAIN},
    {ERROR_NOT_ENOUGH_QUOTA, ENOMEM}
};

#define MIN_EXEC_ERROR ERROR_INVALID_STARTING_CODESEG
#define MAX_EXEC_ERROR ERROR_INFLOOP_IN_RELOC_CHAIN

#define MIN_EACCES_RANGE ERROR_WRITE_PROTECT
#define MAX_EACCES_RANGE ERROR_SHARING_BUFFER_EXCEEDED

void
WIN32_maperror(unsigned long WIN32_oserrno)
{
    int i;

    _doserrno = WIN32_oserrno;
    for (i = 0; i < (sizeof(errortable) / sizeof(struct errorentry)); ++i) {
        if (WIN32_oserrno == errortable[i].WIN32_code) {
            errno = errortable[i].POSIX_errno;
            return;
        }
    }
    if (WIN32_oserrno >= MIN_EACCES_RANGE && WIN32_oserrno <= MAX_EACCES_RANGE)
        errno = EACCES;
    else if (WIN32_oserrno >= MIN_EXEC_ERROR && WIN32_oserrno <= MAX_EXEC_ERROR)
        errno = ENOEXEC;
    else
        errno = EINVAL;
}
#endif

Received on Sat Sep 02 2006 - 15:44:55 MDT

This archive was generated by hypermail pre-2.1.9 : Sun Oct 01 2006 - 12:00:06 MDT