globus_result_t
globus_xio_system_socket_getsockopt(
    globus_xio_system_socket_t          socket,
    int                                 level,
    int                                 optname,
    void *                              optval,
    socklen_t *                         optlen)
{
    globus_result_t                     result;
    GlobusXIOName(globus_xio_system_socket_getsockopt);
    
    GlobusXIOSystemDebugEnterFD(socket);
    
    if(getsockopt(socket, level, optname, optval, optlen) == SOCKET_ERROR)
    {
        result = GlobusXIOErrorSystemError("getsockopt", WSAGetLastError());
        goto error_getsockopt;
    }
    
    GlobusXIOSystemDebugExitFD(socket);
    return GLOBUS_SUCCESS;

error_getsockopt:
    GlobusXIOSystemDebugExitWithErrorFD(socket);
    return result;
}
globus_result_t
globus_xio_system_socket_create(
    globus_xio_system_socket_t *        sock,
    int                                 domain,
    int                                 type,
    int                                 protocol)
{
    globus_result_t                     result;
    GlobusXIOName(globus_xio_system_socket_create);
    
    *sock = INVALID_SOCKET;
    GlobusXIOSystemDebugEnter();
    
    *sock = socket(domain, type, protocol);
    if(*sock == INVALID_SOCKET)
    {
        result = GlobusXIOErrorSystemError("socket", WSAGetLastError());
        goto error_socket;
    }

    /* all handles created by me are closed on exec */
    SetHandleInformation((HANDLE)*sock, HANDLE_FLAG_INHERIT, 0);

    GlobusXIOSystemDebugExitFD(*sock);
    return GLOBUS_SUCCESS;

error_socket:
    GlobusXIOSystemDebugExitWithErrorFD(*sock);
    return result;
}
globus_result_t
globus_i_xio_system_try_sendto(
    globus_xio_system_socket_t          fd,
    void *                              buf,
    globus_size_t                       buflen,
    int                                 flags,
    const globus_sockaddr_t *           to,
    globus_size_t *                     nbytes)
{
    globus_ssize_t                      rc = 0;
    globus_result_t                     result;
    GlobusXIOName(globus_i_xio_system_try_sendto);

    GlobusXIOSystemDebugEnterFD(fd);

    if(buflen)
    {
        do
        {
            rc = sendto(
                fd,
                buf,
                buflen,
                flags,
                (struct sockaddr *) to,
                GlobusLibcSockaddrLen(to));
            GlobusXIOSystemUpdateErrno();
        } while(rc < 0 && errno == EINTR);

        if(rc < 0)
        {
            if(GlobusLXIOSystemWouldBlock(errno))
            {
                rc = 0;
            }
            else
            {
                result = GlobusXIOErrorSystemError("sendto", errno);
                goto error_errno;
            }
        }

        GlobusXIOSystemDebugPrintf(
            GLOBUS_I_XIO_SYSTEM_DEBUG_DATA,
            ("[%s] Wrote %d bytes\n", _xio_name, rc));

        GlobusXIOSystemDebugRawBuffer(rc, buf);
    }

    *nbytes = rc;

    GlobusXIOSystemDebugExitFD(fd);
    return GLOBUS_SUCCESS;

error_errno:
    *nbytes = 0;
    GlobusXIOSystemDebugExitWithErrorFD(fd);
    return result;
}
globus_result_t
globus_i_xio_system_try_readv(
    globus_xio_system_file_t            fd,
    const globus_xio_iovec_t *          iov,
    int                                 iovc,
    globus_size_t *                     nbytes)
{
    globus_ssize_t                      rc;
    globus_result_t                     result;
    GlobusXIOName(globus_i_xio_system_try_readv);

    GlobusXIOSystemDebugEnterFD(fd);

    do
    {
#ifdef HAVE_READV
        rc = readv(fd, iov,
                (iovc > globus_l_xio_iov_max) ? globus_l_xio_iov_max : iovc);
#else
        rc = read(fd, iov[0].iov_base,iov[0].iov_len);
#endif
        GlobusXIOSystemUpdateErrno();
    } while(rc < 0 && errno == EINTR);

    if(rc < 0)
    {
        if(GlobusLXIOSystemWouldBlock(errno))
        {
            rc = 0;
        }
        else
        {
            result = GlobusXIOErrorSystemError("readv", errno);
            goto error_errno;
        }
    }
    else if(rc == 0)
    {
        result = GlobusXIOErrorEOF();
        goto error_eof;
    }

    *nbytes = rc;

    GlobusXIOSystemDebugPrintf(
        GLOBUS_I_XIO_SYSTEM_DEBUG_DATA,
        ("[%s] Read %d bytes\n", _xio_name, rc));

    GlobusXIOSystemDebugRawIovec(rc, iov);

    GlobusXIOSystemDebugExitFD(fd);
    return GLOBUS_SUCCESS;

error_errno:
error_eof:
    *nbytes = 0;
    GlobusXIOSystemDebugExitWithErrorFD(fd);
    return result;
}
globus_result_t
globus_i_xio_system_try_recv(
    globus_xio_system_socket_t          fd,
    void *                              buf,
    globus_size_t                       buflen,
    int                                 flags,
    globus_size_t *                     nbytes)
{
    globus_ssize_t                      rc = 0;
    globus_result_t                     result;
    GlobusXIOName(globus_i_xio_system_try_recv);

    GlobusXIOSystemDebugEnterFD(fd);

    if(buflen)
    {
        do
        {
            rc = recv(fd, buf, buflen, flags);
            GlobusXIOSystemUpdateErrno();
        } while(rc < 0 && errno == EINTR);

        if(rc < 0)
        {
            if(GlobusLXIOSystemWouldBlock(errno))
            {
                rc = 0;
            }
            else
            {
                result = GlobusXIOErrorSystemError("recv", errno);
                goto error_errno;
            }
        }
        else if(rc == 0)
        {
            result = GlobusXIOErrorEOF();
            goto error_eof;
        }

        GlobusXIOSystemDebugPrintf(
            GLOBUS_I_XIO_SYSTEM_DEBUG_DATA,
            ("[%s] Read %d bytes\n", _xio_name, rc));

        GlobusXIOSystemDebugRawBuffer(rc, buf);
    }

    *nbytes = rc;

    GlobusXIOSystemDebugExitFD(fd);
    return GLOBUS_SUCCESS;

error_errno:
error_eof:
    *nbytes = 0;
    GlobusXIOSystemDebugExitWithErrorFD(fd);
    return result;
}
globus_result_t
globus_i_xio_system_try_read(
    globus_xio_system_file_t            fd,
    void *                              buf,
    globus_size_t                       buflen,
    globus_size_t *                     nbytes)
{
    globus_ssize_t                      rc = 0;
    globus_result_t                     result;
    GlobusXIOName(globus_i_xio_system_try_read);

    GlobusXIOSystemDebugEnterFD(fd);

    /* calls to this with buflen == 0 are requesting select only */
    if(buflen)
    {
        do
        {
            rc = read(fd, buf, buflen);
            GlobusXIOSystemUpdateErrno();
        } while(rc < 0 && errno == EINTR);

        if(rc < 0)
        {
            if(GlobusLXIOSystemWouldBlock(errno))
            {
                rc = 0;
            }
            else
            {
                result = GlobusXIOErrorSystemError("read", errno);
                goto error_errno;
            }
        }
        else if(rc == 0) /* what about UDP? */
        {
            result = GlobusXIOErrorEOF();
            goto error_eof;
        }

        GlobusXIOSystemDebugPrintf(
            GLOBUS_I_XIO_SYSTEM_DEBUG_DATA,
            ("[%s] Read %d bytes (buflen = %d)\n", _xio_name, rc, buflen));

        GlobusXIOSystemDebugRawBuffer(rc, buf);
    }

    *nbytes = rc;

    GlobusXIOSystemDebugExitFD(fd);
    return GLOBUS_SUCCESS;

error_errno:
error_eof:
    *nbytes = 0;
    GlobusXIOSystemDebugExitWithErrorFD(fd);
    return result;
}
globus_result_t
globus_xio_system_socket_register_connect(
    globus_xio_operation_t              op,
    globus_xio_system_socket_handle_t   handle,
    globus_sockaddr_t *                 addr,
    globus_xio_system_callback_t        callback,
    void *                              user_arg)
{
    globus_result_t                     result;
    int                                 error;
    globus_i_xio_system_op_info_t *     op_info;
    GlobusXIOName(globus_xio_system_socket_register_connect);
    
    GlobusXIOSystemDebugEnterFD(handle->socket);
    
    if(connect(
        handle->socket, (const struct sockaddr *) addr,
        GlobusLibcSockaddrLen(addr)) == SOCKET_ERROR &&
        (error = WSAGetLastError()) != WSAEWOULDBLOCK)
    {
        result = GlobusXIOErrorSystemError("connect", error);
        goto error_connect;
    }

    GlobusIXIOSystemAllocOperation(op_info);
    if(!op_info)
    {
        result = GlobusXIOErrorMemory("op_info");
        goto error_op_info;
    }

    op_info->type = GLOBUS_I_XIO_SYSTEM_OP_CONNECT;
    op_info->state = GLOBUS_I_XIO_SYSTEM_OP_NEW;
    op_info->op = op;
    op_info->handle = handle;
    op_info->user_arg = user_arg;
    op_info->sop.non_data.callback = callback;

    result = globus_l_xio_win32_socket_register_write(handle, op_info);
    if(result != GLOBUS_SUCCESS)
    {
        result = GlobusXIOErrorWrapFailed(
            "globus_l_xio_win32_socket_register_write", result);
        goto error_register;
    }

    GlobusXIOSystemDebugExitFD(handle->socket);
    return GLOBUS_SUCCESS;

error_register:
    GlobusIXIOSystemFreeOperation(op_info);
error_op_info:
error_connect:
    GlobusXIOSystemDebugExitWithErrorFD(handle->socket);
    return result;
}
static
globus_result_t
globus_l_xio_win32_blocking_init(
    globus_l_xio_win32_blocking_info_t ** u_blocking_info)
{
    globus_l_xio_win32_blocking_info_t * blocking_info;
    globus_result_t                     result;
    GlobusXIOName(globus_l_xio_win32_blocking_init);
    
    GlobusXIOSystemDebugEnter();
    
    blocking_info = (globus_l_xio_win32_blocking_info_t *)
        globus_calloc(1, sizeof(globus_l_xio_win32_blocking_info_t));
    if(!blocking_info)
    {
        result = GlobusXIOErrorMemory("blocking_info");
        goto error_info;
    }
    
    blocking_info->event = CreateEvent(0, FALSE, FALSE, 0);
    if(blocking_info->event == 0)
    {
        result = GlobusXIOErrorSystemError(
            "CreateEvent", GetLastError());
        goto error_create;
    }
    
    *u_blocking_info = blocking_info;
    
    GlobusXIOSystemDebugExit();
    return GLOBUS_SUCCESS;

error_create:
    globus_free(blocking_info);
error_info:
    *u_blocking_info = 0;
    GlobusXIOSystemDebugExitWithError();
    return result;
}
globus_result_t
globus_xio_system_socket_close(
    globus_xio_system_socket_t          socket)
{
    globus_result_t                     result;
    GlobusXIOName(globus_xio_system_socket_close);
    
    GlobusXIOSystemDebugEnterFD(socket);
    
    if(closesocket(socket) == SOCKET_ERROR)
    {
        result = GlobusXIOErrorSystemError("closesocket", WSAGetLastError());
        goto error_close;
    }
    
    GlobusXIOSystemDebugExitFD(socket);
    return GLOBUS_SUCCESS;

error_close:
    GlobusXIOSystemDebugExitWithErrorFD(socket);
    return result;
}
globus_result_t
globus_xio_system_socket_listen(
    globus_xio_system_socket_t          socket,
    int                                 backlog)
{
    globus_result_t                     result;
    GlobusXIOName(globus_xio_system_socket_listen);
    
    GlobusXIOSystemDebugEnterFD(socket);
    
    if(listen(socket, backlog) == SOCKET_ERROR)
    {
        result = GlobusXIOErrorSystemError("listen", WSAGetLastError());
        goto error_listen;
    }
    
    GlobusXIOSystemDebugExitFD(socket);
    return GLOBUS_SUCCESS;

error_listen:
    GlobusXIOSystemDebugExitWithErrorFD(socket);
    return result;
}
globus_result_t
globus_xio_system_socket_connect(
    globus_xio_system_socket_t          socket,
    const struct sockaddr *             addr,
    socklen_t                           addrlen)
{
    globus_result_t                     result;
    GlobusXIOName(globus_xio_system_socket_connect);
    
    GlobusXIOSystemDebugEnterFD(socket);
    
    if(connect(socket, addr, addrlen) == SOCKET_ERROR)
    {
        result = GlobusXIOErrorSystemError("connect", WSAGetLastError());
        goto error_connect;
    }
    
    GlobusXIOSystemDebugExitFD(socket);
    return GLOBUS_SUCCESS;

error_connect:
    GlobusXIOSystemDebugExitWithErrorFD(socket);
    return result;
}
globus_result_t
globus_xio_system_socket_getpeername(
    globus_xio_system_socket_t          socket,
    struct sockaddr *                   name,
    socklen_t *                         namelen)
{
    globus_result_t                     result;
    GlobusXIOName(globus_xio_system_socket_getpeername);
    
    GlobusXIOSystemDebugEnterFD(socket);
    
    if(getpeername(socket, name, namelen) == SOCKET_ERROR)
    {
        result = GlobusXIOErrorSystemError("getpeername", WSAGetLastError());
        goto error_getpeername;
    }
    
    GlobusXIOSystemDebugExitFD(socket);
    return GLOBUS_SUCCESS;

error_getpeername:
    GlobusXIOSystemDebugExitWithErrorFD(socket);
    return result;
}
globus_result_t
globus_xio_system_socket_init(
    globus_xio_system_socket_handle_t * uhandle,
    globus_xio_system_socket_t          socket,
    globus_xio_system_type_t            type)
{
    globus_result_t                     result;
    globus_l_xio_win32_socket_t *       handle;
    unsigned long                       flag;
    GlobusXIOName(globus_xio_system_socket_init);
    
    GlobusXIOSystemDebugEnterFD(socket);
    
    handle = (globus_l_xio_win32_socket_t *)
        globus_calloc(1, sizeof(globus_l_xio_win32_socket_t));
    if(!handle)
    {
        result = GlobusXIOErrorMemory("handle");
        goto error_alloc;
    }
    
    handle->socket = socket;
    win32_mutex_init(&handle->lock, 0);
    handle->ready_events = FD_READ; /* to avoid winsock fd_close bug */
    
    handle->event = WSACreateEvent();
    if(handle->event == 0)
    {
        result = GlobusXIOErrorSystemError(
            "WSACreateEvent", WSAGetLastError());
        goto error_create;
    }
    
    flag = 1;
    if(ioctlsocket(socket, FIONBIO, &flag) == SOCKET_ERROR)
    {
        result = GlobusXIOErrorSystemError(
            "ioctlsocket", WSAGetLastError());
        goto error_ioctl;
    }
    
    result = globus_i_xio_win32_event_register(
        &handle->event_entry,
        handle->event,
        globus_l_xio_win32_socket_event_cb,
        handle);
    if(result != GLOBUS_SUCCESS)
    {
        result = GlobusXIOErrorWrapFailed(
            "globus_i_xio_win32_event_register", result);
        goto error_register;
    }
    
    GlobusXIOSystemDebugPrintf(
        GLOBUS_I_XIO_SYSTEM_DEBUG_INFO,
        ("[%s] Registered event handle=%lu\n",
            _xio_name, (unsigned long) handle->event));
        
    *uhandle = handle;
    
    GlobusXIOSystemDebugExitFD(socket);
    return GLOBUS_SUCCESS;

error_register:
    flag = 0;
    ioctlsocket(socket, FIONBIO, &flag);
error_ioctl:
    WSACloseEvent(handle->event);
error_create:
    win32_mutex_destroy(&handle->lock);
    globus_free(handle);
error_alloc:
    GlobusXIOSystemDebugExitWithErrorFD(socket);
    return result;
}
/* must be safe to call from win32 thread
 */
static
void
globus_l_xio_win32_socket_handle_write(
    globus_l_xio_win32_socket_t *       handle,
    globus_i_xio_system_op_info_t *     write_info)
{
    globus_size_t                       nbytes;
    globus_result_t                     result;
    GlobusXIOName(globus_l_xio_win32_socket_handle_write);
    
    GlobusXIOSystemDebugEnterFD(handle->socket);

    result = GLOBUS_SUCCESS;

    if(write_info->op)
    {
        globus_xio_operation_refresh_timeout(write_info->op);
    }
    
    switch(write_info->type)
    {
      case GLOBUS_I_XIO_SYSTEM_OP_CONNECT:
        {
            int                         err;
            globus_socklen_t            errlen;

            errlen = sizeof(err);
            if(getsockopt(
                handle->socket, SOL_SOCKET, SO_ERROR, (char *)&err, &errlen)
                    == SOCKET_ERROR)
            {
                err = WSAGetLastError();
            }

            if(err)
            {
                result = GlobusXIOErrorSystemError("connect", err);
            }
        }
        break;

      case GLOBUS_I_XIO_SYSTEM_OP_WRITE:
        /* we loop repeatedly here to use up all available space until
         * the write would return EWOULDBLOCK.  at that time, we'll get
         * another event to land us back here
         */
        do
        {
            result = globus_i_xio_system_socket_try_write(
                handle->socket,
                write_info->sop.data.iov,
                write_info->sop.data.iovc,
                write_info->sop.data.flags,
                write_info->sop.data.addr,
                &nbytes);
            if(result == GLOBUS_SUCCESS)
            {
                if(nbytes > 0)
                {
                    write_info->nbytes += nbytes;
                    GlobusIXIOUtilAdjustIovec(
                        write_info->sop.data.iov,
                        write_info->sop.data.iovc, nbytes);
                }
                else if(write_info->sop.data.iovc > 0 &&
                    write_info->sop.data.iov[0].iov_len > 0)
                {
                    /* we consumed write event */
                    handle->ready_events &= ~FD_WRITE;
                }
            }
        } while(nbytes > 0 && write_info->nbytes < write_info->waitforbytes);
        break;

      default:
        globus_assert(0 && "Unexpected type for write operation");
        return;
        break;
    }
  
    if(result != GLOBUS_SUCCESS)
    {
        write_info->error = globus_error_get(result);
    }
    
    /* always true for connect operations */
    if(write_info->nbytes >= write_info->waitforbytes ||
        result != GLOBUS_SUCCESS)
    {
        write_info->state = GLOBUS_I_XIO_SYSTEM_OP_COMPLETE;
    }

    GlobusXIOSystemDebugExitFD(handle->socket);
}
globus_result_t
globus_i_xio_system_try_sendmsg(
    globus_xio_system_socket_t          fd,
    struct msghdr *                     msghdr,
    int                                 flags,
    globus_size_t *                     nbytes)
{
    globus_ssize_t                      rc;
    globus_result_t                     result;
    GlobusXIOName(globus_i_xio_system_try_sendmsg);

    GlobusXIOSystemDebugEnterFD(fd);

#ifdef WIN32
    {
        DWORD                           sent = 0;

        rc = WSASendTo(
            fd,
            (WSABUF *) msghdr->msg_iov,
            msghdr->msg_iovlen,
            &sent,
            flags,
            msghdr->msg_name,
            msghdr->msg_namelen,
            0,
            0);
        if(rc != 0)
        {
            GlobusXIOSystemUpdateErrno();
            rc = -1;
        }
        else
        {
            rc = sent;
        }
    }
#elif defined(HAVE_SENDMSG)
    {
        globus_size_t                   orig_iovc;

        orig_iovc = msghdr->msg_iovlen;
        msghdr->msg_iovlen = (orig_iovc > globus_l_xio_iov_max)
                ? globus_l_xio_iov_max : orig_iovc;

        do
        {
            rc = sendmsg(fd, msghdr, flags);
            GlobusXIOSystemUpdateErrno();
        } while(rc < 0 && errno == EINTR);

        msghdr->msg_iovlen = orig_iovc;
    }
#else
    {
        /* XXX this is not an acceptable work around for udp sockets */
        do
        {
            if (msghdr->msg_name)
            {
                rc = sendto(
                        fd,
                        msghdr->msg_iov[0].iov_base,
                        msghdr->msg_iov[0].iov_len,
                        flags,
                        (struct sockaddr *) msghdr->msg_name,
                        msghdr->msg_namelen);
            }
            else
            {
                rc = send(
                        fd,
                        msghdr->msg_iov[0].iov_base,
                        msghdr->msg_iov[0].iov_len,
                        flags);
            }
            GlobusXIOSystemUpdateErrno();
        } while (rc < 0 && errno == EINTR);
    }
#endif

    if(rc < 0)
    {
        if(GlobusLXIOSystemWouldBlock(errno))
        {
            rc = 0;
        }
        else
        {
            result = GlobusXIOErrorSystemError("sendmsg", errno);
            goto error_errno;
        }
    }

    *nbytes = rc;

    GlobusXIOSystemDebugPrintf(
        GLOBUS_I_XIO_SYSTEM_DEBUG_DATA,
        ("[%s] Wrote %d bytes\n", _xio_name, rc));

    GlobusXIOSystemDebugRawIovec(rc, msghdr->msg_iov);

    GlobusXIOSystemDebugExitFD(fd);
    return GLOBUS_SUCCESS;

error_errno:
    *nbytes = 0;
    GlobusXIOSystemDebugExitWithErrorFD(fd);
    return result;
}
/*
 *  open a file
 */
static
globus_result_t
globus_l_xio_popen_open(
    const globus_xio_contact_t *        contact_info,
    void *                              driver_link,
    void *                              driver_attr,
    globus_xio_operation_t              op)
{
    int                                 rc;
    int                                 s_fds[2];
    int                                 infds[2];
    int                                 outfds[2];
    int                                 errfds[2];
    xio_l_popen_handle_t *              handle;
    const xio_l_popen_attr_t *          attr;
    globus_result_t                     result;
    GlobusXIOName(globus_l_xio_popen_open);
    
    GlobusXIOPOpenDebugEnter();
    
#ifdef WIN32
    result = GlobusXIOErrorSystemResource("not available for windows");
#else
    attr = (const xio_l_popen_attr_t *) 
        driver_attr ? driver_attr : &xio_l_popen_attr_default;

    /* check that program exists and is exec=able first */

    rc = access(attr->program_name, R_OK | X_OK);
    if(rc != 0)
    {
        result = GlobusXIOErrorSystemError("access check", errno);
        goto error_handle;
    }

    result = globus_l_xio_popen_handle_init(&handle);
    if(result != GLOBUS_SUCCESS)
    {
        result = GlobusXIOErrorWrapFailed(
            "globus_l_xio_popen_handle_init", result);
        goto error_handle;
    }

    handle->ignore_program_errors = attr->ignore_program_errors;
    handle->use_blocking_io = attr->use_blocking_io;
    
#   if defined(USE_SOCKET_PAIR)
    {
        rc = socketpair(AF_UNIX, SOCK_STREAM, 0, s_fds);
        if(rc != 0)
        {
            result = GlobusXIOErrorSystemError("socketpair", errno);
            goto error_in_pipe;
        }

        /* trick the rest of the code into thinking it is using pipe */
        outfds[0] = s_fds[0];
        outfds[1] = s_fds[1];
        infds[0] = s_fds[0];
        infds[1] = s_fds[1];
    }
#   else
    {
        rc = pipe(infds);
        if(rc != 0)
        {
            result = GlobusXIOErrorSystemError("pipe", errno);
            goto error_in_pipe;
        }
        rc = pipe(outfds);
        if(rc != 0)
        {
            result = GlobusXIOErrorSystemError("pipe", errno);
            goto error_out_pipe;
        }
    }
#   endif

    rc = pipe(errfds);
    if(rc != 0)
    {
        result = GlobusXIOErrorSystemError("pipe", errno);
        goto error_err_pipe;
    }
    fcntl(errfds[0], F_SETFL, O_NONBLOCK);
    fcntl(errfds[1], F_SETFL, O_NONBLOCK);
    
    handle->pid = fork();
    if(handle->pid < 0)
    {
        result = GlobusXIOErrorSystemError("fork", errno);
        goto error_fork;
    }
    else if(handle->pid == 0)
    {
        globus_l_xio_popen_child(attr, contact_info, infds, outfds, errfds);
    }

#   if defined(USE_SOCKET_PAIR)
    {
        handle->infd = s_fds[0];
        handle->outfd = s_fds[0];
        
        result = globus_l_xio_popen_init_child_pipe(
            handle->infd,
            &handle->in_system);
        if(result != GLOBUS_SUCCESS)
        {
            goto error_init;
        }
        handle->out_system = handle->in_system;
        close(s_fds[1]);
    }
#   else
    {
        handle->infd = infds[0];
        handle->outfd = outfds[1];

        result = globus_l_xio_popen_init_child_pipe(
            handle->outfd,
            &handle->out_system);
        if(result != GLOBUS_SUCCESS)
        {
            goto error_init;
        }
        result = globus_l_xio_popen_init_child_pipe(
            handle->infd,
            &handle->in_system);
        if(result != GLOBUS_SUCCESS)
        {
            goto error_init;
        }
        close(outfds[0]);
        close(infds[1]);
    }
#   endif

    handle->errfd = errfds[0];
    result = globus_l_xio_popen_init_child_pipe(
        handle->errfd,
        &handle->err_system);
    if(result != GLOBUS_SUCCESS)
    {
        goto error_init;
    }
    close(errfds[1]);
    globus_xio_driver_finished_open(handle, op, GLOBUS_SUCCESS);
    
    GlobusXIOPOpenDebugExit();
    return GLOBUS_SUCCESS;

error_init:
error_fork:
    close(errfds[0]);
    close(errfds[1]);
#   if defined(USE_SOCKET_PAIR)
error_err_pipe:
    close(s_fds[0]);
    close(s_fds[1]);
#   else
error_err_pipe:
    close(outfds[0]);
    close(outfds[1]);
error_out_pipe:
    close(infds[0]);
    close(infds[1]);
#   endif
error_in_pipe:
    globus_l_xio_popen_handle_destroy(handle);
error_handle:
#endif
    GlobusXIOPOpenDebugExitWithError();
    return result;
}
/* must be safe to call from win32 thread
 */
static
void
globus_l_xio_win32_socket_handle_read(
    globus_l_xio_win32_socket_t *       handle,
    globus_i_xio_system_op_info_t *     read_info)
{
    globus_size_t                       nbytes;
    globus_result_t                     result;
    GlobusXIOName(globus_l_xio_win32_socket_handle_read);
    
    GlobusXIOSystemDebugEnterFD(handle->socket);

    result = GLOBUS_SUCCESS;

    if(read_info->op)
    {
        globus_xio_operation_refresh_timeout(read_info->op);
    }
    
    GlobusXIOSystemDebugPrintf(
        GLOBUS_I_XIO_SYSTEM_DEBUG_INFO,
        ("[%s] In globus_l_xio_win32_socket_handle_read fd=%lu, read_info->type=%d\n",
             _xio_name,
             (unsigned long)handle->socket, (int) read_info->type));
    switch(read_info->type)
    {
      case GLOBUS_I_XIO_SYSTEM_OP_ACCEPT:
        {
            SOCKET                      new_fd;

            new_fd = accept(handle->socket, 0, 0);
            
            if(new_fd == INVALID_SOCKET)
            {
                int                     error = WSAGetLastError();
                
                if(error != WSAECONNRESET && error != WSAEWOULDBLOCK)
                {
                    char errbuf[64];
                    sprintf(errbuf, "accept, fd=%ld, error=%d",
                        (long) handle->socket, error);
                    result = GlobusXIOErrorSystemError(errbuf, error);
                    GlobusXIOSystemDebugPrintf(
                        GLOBUS_I_XIO_SYSTEM_DEBUG_INFO,
                        ("[%s] Tried to accept new connection on fd=%lu, %s\n",
                             _xio_name,
                             (unsigned long)handle->socket, errbuf));

                }
                else
                {
                    char errbuf[64];
                    sprintf(errbuf, "accept, fd=%ld, error=%d",
                        (long) handle->socket, error);
                    GlobusXIOSystemDebugPrintf(
                        GLOBUS_I_XIO_SYSTEM_DEBUG_INFO,
                        ("[%s] Tried to accept new connection on fd=%lu, %s\n",
                             _xio_name,
                             (unsigned long)handle->socket, errbuf));
                }
            }
            else
            {
                unsigned long           flag = 0;
                
                /* clear inherited attrs */
                WSAEventSelect(new_fd, 0, 0);
                ioctlsocket(new_fd, FIONBIO, &flag);
    
                *read_info->sop.non_data.out_fd = new_fd;
                read_info->nbytes++;
                GlobusXIOSystemDebugPrintf(
                    GLOBUS_I_XIO_SYSTEM_DEBUG_INFO,
                    ("[%s] Accepted new connection on fd=%lu, fd=%lu\n",
                         _xio_name,
                         (unsigned long)handle->socket, (unsigned long)new_fd));
            }
        }
        break;

      case GLOBUS_I_XIO_SYSTEM_OP_READ:
        /* we loop repeatedly here to read all available data until
         * the read would return EWOULDBLOCK.  at that time, we'll get
         * another event to land us back here.
         * (This looping is necessary to work around a winsock bug where we
         * aren't notified of the peer closing the connection on short lived
         * connections)
         */
        do
        {
            result = globus_i_xio_system_socket_try_read(
                handle->socket,
                read_info->sop.data.iov,
                read_info->sop.data.iovc,
                read_info->sop.data.flags,
                read_info->sop.data.addr,
                &nbytes);
            if(result == GLOBUS_SUCCESS)
            {
                if(nbytes > 0)
                {
                    read_info->nbytes += nbytes;
                    GlobusIXIOUtilAdjustIovec(
                        read_info->sop.data.iov,
                        read_info->sop.data.iovc, nbytes);
                }
                else if(read_info->sop.data.iovc > 0 &&
                    read_info->sop.data.iov[0].iov_len > 0)
                {
                    /* we consumed read event */
                    handle->ready_events &= ~FD_READ;
                }
            }
        } while(nbytes > 0 && read_info->nbytes < read_info->waitforbytes);
        break;

      default:
        globus_assert(0 && "Unexpected type for read operation");
        return;
        break;
    }
    
    if(result != GLOBUS_SUCCESS)
    {
        read_info->error = globus_error_get(result);
    }
    
    /* always true for accept operations */
    if(read_info->nbytes >= read_info->waitforbytes ||
        result != GLOBUS_SUCCESS)
    {
        read_info->state = GLOBUS_I_XIO_SYSTEM_OP_COMPLETE;
    }

    GlobusXIOSystemDebugExitFD(handle->socket);
}
static
void
globus_l_popen_waitpid(
    xio_l_popen_handle_t *              handle,
    int                                 opts)
{
    globus_result_t                     result = GLOBUS_SUCCESS;
    int                                 status;
    int                                 rc;
    globus_reltime_t                    delay;
    GlobusXIOName(globus_l_popen_waitpid);

#ifdef WIN32
    result = GlobusXIOErrorSystemResource("not available for windows");
#else
    rc = waitpid(handle->pid, &status, opts);
    if(rc > 0)
    {
        /* if program exited normally, but with a nonzero code OR
         * program exited by signal, and we didn't signal it */
        if(((WIFEXITED(status) && WEXITSTATUS(status) != 0) || 
            (WIFSIGNALED(status) && handle->kill_state != GLOBUS_L_XIO_POPEN_NONE))
            && !handle->ignore_program_errors)
        {
            /* read programs stderr and dump it to an error result */
            globus_size_t                   nbytes = 0;
            globus_xio_iovec_t              iovec;
            char                            buf[8192];

            iovec.iov_base = buf;
            iovec.iov_len = sizeof(buf) - 1;
            
            result = globus_xio_system_file_read(
                handle->err_system, 0, &iovec, 1, 0, &nbytes);
            
            buf[nbytes] = 0;

            if(WIFEXITED(status))
            {
                result = globus_error_put(
                    globus_error_construct_error(
                        GLOBUS_XIO_MODULE,
                        GLOBUS_NULL,
                        GLOBUS_XIO_ERROR_SYSTEM_ERROR,
                        __FILE__,
                        _xio_name,
                        __LINE__,
                        _XIOSL("popened program exited with an error "
                               "(exit code: %d):\n%s"),
                        WEXITSTATUS(status), 
                        buf));
            }
            else
            {
                result = globus_error_put(
                    globus_error_construct_error(
                        GLOBUS_XIO_MODULE,
                        GLOBUS_NULL,
                        GLOBUS_XIO_ERROR_SYSTEM_ERROR,
                        __FILE__,
                        _xio_name,
                        __LINE__,
                        _XIOSL("popened program was terminated by a signal"
                               "(sig: %d)"),
                        WTERMSIG(status)));
            }
        }

        globus_xio_system_file_close(handle->errfd);
        globus_xio_system_file_destroy(handle->err_system);

        globus_xio_driver_finished_close(handle->close_op, result);
        globus_l_xio_popen_handle_destroy(handle);
    }
    else if(rc < 0 || opts == 0)
    {
        /* If the errno is ECHILD, either some other thread or part of the
         * program called wait and got this pid's exit status, or sigaction
         * with SA_NOCLDWAIT prevented the process from becoming a zombie. Not
         * really an error case.
         */
        if (errno != ECHILD)
        {
            result = GlobusXIOErrorSystemError("waitpid", errno);
        }

        globus_xio_system_file_close(handle->errfd);
        globus_xio_system_file_destroy(handle->err_system);

        globus_xio_driver_finished_close(handle->close_op, result);
        globus_l_xio_popen_handle_destroy(handle);
    }
    else
    {
        
        handle->wait_count++;
        
        if(handle->canceled)
        {
            switch(handle->kill_state)
            {
                case GLOBUS_L_XIO_POPEN_NONE:
                    if(handle->wait_count > 5000 / GLOBUS_L_XIO_POPEN_WAITPID_DELAY)
                    {
                        handle->kill_state = GLOBUS_L_XIO_POPEN_TERM;
                        kill(handle->pid, SIGTERM);
                    }
                    break;
                case GLOBUS_L_XIO_POPEN_TERM:
                    if(handle->wait_count > 15000 / GLOBUS_L_XIO_POPEN_WAITPID_DELAY)
                    {
                        handle->kill_state = GLOBUS_L_XIO_POPEN_KILL;
                        kill(handle->pid, SIGKILL);
                    }
                    break;
                default:
                    break;
            } 
        }
        
        GlobusTimeReltimeSet(delay, 0, GLOBUS_L_XIO_POPEN_WAITPID_DELAY);
        globus_callback_register_oneshot(
            NULL,
            &delay,
            globus_l_xio_popen_close_oneshot,
            handle);         
    }

#endif
    GlobusXIOPOpenDebugExit();
}