static
globus_result_t
globus_l_xio_wrapblock_open(
    const globus_xio_contact_t *        contact_info,
    void *                              driver_link,
    void *                              driver_attr,
    globus_xio_operation_t              op)
{
    globus_result_t                     result;
    xio_l_wrapblock_wrapper_t *         wrapper;
    xio_l_wrapblock_handle_t *          wrapblock_handle;
    globus_xio_driver_t                 driver;
    globus_i_xio_op_t *                 xio_op;

    xio_op = (globus_i_xio_op_t *) op;
    driver = xio_op->_op_context->entry[op->ndx - 1].driver;

    wrapblock_handle = globus_calloc(1, sizeof(xio_l_wrapblock_handle_t));
    wrapblock_handle->wrapblock_driver = driver->wrap_data;

    if(globus_xio_driver_operation_is_blocking(op))
    {
        result = wrapblock_handle->wrapblock_driver->open_func(
            contact_info,
            driver_link,
            driver_attr,
            &wrapblock_handle->driver_handle);

        globus_xio_driver_finished_open(wrapblock_handle, op, result);
    }
    else
    {
        wrapper = (xio_l_wrapblock_wrapper_t *)
            globus_calloc(1, sizeof(xio_l_wrapblock_wrapper_t));
        wrapper->wrapblock_handle = wrapblock_handle;
        wrapper->link = driver_link;
        wrapper->op = op;
        wrapper->driver = driver;

        if(driver_attr != NULL && driver->attr_copy_func != NULL)
        {
            driver->attr_copy_func(&wrapper->attr, driver_attr);
        }
        /* gotta copy contact info the hard way */
        globus_xio_contact_copy(&wrapper->ci, contact_info);

        globus_callback_register_oneshot(
            NULL,
            NULL,
            globus_l_xio_wrapblock_open_kickout,
            wrapper);
    }

    return GLOBUS_SUCCESS;
}
/*
 *  open a file
 */
static
globus_result_t
globus_l_xio_pipe_open(
    const globus_xio_contact_t *        contact_info,
    void *                              driver_link,
    void *                              driver_attr,
    globus_xio_operation_t              op)
{
    xio_l_pipe_handle_t *               handle;
    xio_l_pipe_attr_t *                 attr;
    globus_result_t                     result;
    GlobusXIOName(globus_l_xio_pipe_open);
    
    GlobusXIOPipeDebugEnter();
    
    attr = (xio_l_pipe_attr_t *)
        (driver_attr ? driver_attr : &xio_l_pipe_attr_default);
    result = globus_l_xio_pipe_handle_init(&handle, attr);
    if(result != GLOBUS_SUCCESS)
    {
        result = GlobusXIOErrorWrapFailed(
            "globus_l_xio_pipe_handle_init", result);
        goto error_handle;
    }

    result = globus_xio_system_file_init(&handle->out_system, handle->outfd);
    if(result != GLOBUS_SUCCESS)
    {
        result = GlobusXIOErrorWrapFailed(
            "globus_xio_system_file_init", result);
        goto error_init;
    }
    result = globus_xio_system_file_init(&handle->in_system, handle->infd);
    if(result != GLOBUS_SUCCESS)
    {
        result = GlobusXIOErrorWrapFailed(
            "globus_xio_system_file_init", result);
        goto error_init;
    }
    
    globus_xio_driver_finished_open(handle, op, GLOBUS_SUCCESS);
    
    GlobusXIOPipeDebugExit();
    return GLOBUS_SUCCESS;

error_init:
    globus_l_xio_pipe_handle_destroy(handle);
error_handle:
    GlobusXIOPipeDebugExitWithError();
    return result;
}
static void
test_bounce_finish_op(
    bounce_info_t *                     info,
    globus_xio_operation_t              op)
{
    GlobusXIOName(test_bounce_finish_op);

    GlobusXIOTestDebugInternalEnter();

    switch(info->start_op)
    {
        case TEST_READ:
            globus_xio_driver_finished_read(op, info->res, info->nbytes);
            break;

        case TEST_WRITE:
            globus_xio_driver_finished_write(op, info->res, info->nbytes);
            break;
    
        case TEST_OPEN:
            if(info->res != GLOBUS_SUCCESS)
            {
                bounce_handle_destroy(info->handle);
                info->handle = NULL;
            }
            globus_xio_driver_finished_open(
                info->handle, op, info->res);
            break;

        case TEST_CLOSE:
            globus_xio_driver_finished_close(op, info->res);
            bounce_handle_destroy(info->handle);
            break;

        default:
            globus_assert(0);
            break;
    }

    globus_free(info);

    GlobusXIOTestDebugInternalExit();
}
/************************************************************************
 *                  iface functions
 *                  ---------------
 *  
 ***********************************************************************/
static void
globus_l_xio_telnet_open_cb(
    globus_xio_operation_t              op,
    globus_result_t                     result,
    void *                              user_arg)
{
    globus_l_xio_telnet_handle_t *      handle;

    handle = (globus_l_xio_telnet_handle_t *) user_arg;

    if(result != GLOBUS_SUCCESS)
    {
        globus_fifo_destroy(&handle->write_q);
        globus_free(handle->read_buffer);
        globus_mutex_destroy(&handle->mutex);
        globus_free(handle);
    }

    globus_xio_driver_finished_open(handle, op, result);
}
/**
 * Server-side connection open callback
 * @ingroup globus_i_xio_http_server
 *
 * Called as a result of open at the transport level. If this was successful,
 * we will finish the open operation. If an error happens, this function will
 * close the * handle internally and call globus_xio_driver_finished_open() to
 * propagate the error.
 *
 * @param op
 *     Operation associated with the open.
 * @param result
 *     Result from the transport's attempt to open the new connection.
 * @param user_arg
 *     Void * pointing to a #globus_i_xio_http_handle_t associated with
 *     this open.
 *
 * @return void
 */
void
globus_i_xio_http_server_open_callback(
    globus_xio_operation_t              op,
    globus_result_t                     result,
    void *                              user_arg)
{
    globus_i_xio_http_handle_t *        http_handle = user_arg;
    GlobusXIOName(globus_i_xio_http_server_open_callback);

    if (result != GLOBUS_SUCCESS)
    {
        globus_i_xio_http_handle_destroy(http_handle);
        globus_libc_free(http_handle);
        http_handle = NULL;
    }

    globus_xio_driver_finished_open(
            http_handle,
            op,
            result);
    return;
}
static
void
globus_l_xio_wrapblock_open_kickout(
    void *                              user_arg)
{
    globus_result_t                     res;
    xio_l_wrapblock_wrapper_t *         wrapper;

    globus_thread_blocking_will_block();

    wrapper = (xio_l_wrapblock_wrapper_t *) user_arg;

    res = wrapper->wrapblock_handle->wrapblock_driver->open_func(
        &wrapper->ci,
        wrapper->link,
        wrapper->attr,
        &wrapper->wrapblock_handle->driver_handle);

    globus_xio_driver_finished_open(
        wrapper->wrapblock_handle, wrapper->op, res);

    xio_l_wrapblock_wrapper_destroy(wrapper);
}
/*
 *  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;
}
static
void
globus_l_xio_net_manager_accept_callback(
    globus_xio_operation_t              op,
    globus_result_t                     result,
    void                               *callback_arg)
{
    globus_l_xio_net_manager_link_t    *link = callback_arg;
    globus_l_xio_net_manager_handle_t  *handle = NULL;
    char                               *string_opts = NULL;
    globus_net_manager_attr_t          *attrs = NULL, *attr_array_out = NULL;
    globus_xio_driver_handle_t          driver_handle =
                globus_xio_operation_get_driver_handle(op);

    if (result)
    {
        goto failed_accept;
    }
    if (link == NULL)
    {
        goto no_link;
    }
    handle = malloc(sizeof(globus_l_xio_net_manager_handle_t));
    if (handle == NULL)
    {
        result = GlobusNetManagerErrorMemory("handle");
        goto malloc_handle_fail;
    }

    handle->passive = GLOBUS_TRUE;
    handle->transport_driver = link->transport_driver;
    handle->transport_name = link->transport_name;

    handle->local_contact = link->local_contact;
    link->local_contact = NULL;

    result = globus_xio_driver_handle_cntl(
            driver_handle,
            handle->transport_driver,
            GLOBUS_XIO_GET_REMOTE_NUMERIC_CONTACT,
            &handle->remote_contact);
    if (result)
    {
        goto get_remote_contact_fail;
    }
    if (!handle->remote_contact)
    {
        result = GlobusNetManagerErrorInit(
            handle->transport_name, "Unable to get remote contact.");
        goto get_remote_contact_fail;
    }

    handle->attr = link->attr;
    link->attr = NULL;

    result = globus_xio_driver_attr_cntl(
        op,
        handle->transport_driver,
        GLOBUS_XIO_GET_STRING_OPTIONS,
        &string_opts);
    if (result)
    {
        goto get_string_opts_fail;
    }
    result = globus_net_manager_attr_array_from_string(
        &attrs,
        handle->transport_name,
        string_opts);
    if (result)
    {
        goto array_from_string_fail;
    }

    result = globus_net_manager_context_post_accept(
            handle->attr->context,
            handle->attr->task_id ? handle->attr->task_id : "unset",
            handle->transport_name,
            handle->local_contact,
            handle->remote_contact,
            attrs,
            &attr_array_out);

    if (result != GLOBUS_SUCCESS)
    {
        goto post_accept_fail;
    }
    if (attr_array_out)
    {
        globus_net_manager_attr_array_delete(handle->attr->attr_array);
        handle->attr->attr_array = attr_array_out;
        attr_array_out = NULL;

        result = globus_l_xio_net_manager_transport_handle_apply(
                handle, op, attr_array_out);
        if (result != GLOBUS_SUCCESS)
        {
            goto attr_apply_fail;
        }
    }

attr_apply_fail:
post_accept_fail:
    globus_net_manager_attr_array_delete(attr_array_out);
    globus_net_manager_attr_array_delete(attrs);
array_from_string_fail:
    free(string_opts);
    if (result)
    {
get_string_opts_fail:
        globus_l_xio_net_manager_attr_destroy(handle->attr);
        free(handle->remote_contact);
get_remote_contact_fail:
        free(handle->local_contact);
        free(handle);
        handle = NULL;
    }
malloc_handle_fail:
no_link:
failed_accept:
    globus_xio_driver_finished_open(handle, op, result);
}
static
void
globus_l_xio_net_manager_connect_callback(
    globus_xio_operation_t              op,
    globus_result_t                     result,
    void *                              user_arg)
{
    globus_l_xio_net_manager_handle_t  *handle = user_arg;
    globus_net_manager_attr_t          *transport_opts = NULL,
                                       *new_transport_opts = NULL;
    globus_xio_driver_handle_t          driver_handle =
            globus_xio_operation_get_driver_handle(op);

    if (handle == NULL)
    {
        goto no_handle;
    }
    if (result)
    {
        goto failed_open;
    }

    /* Connect-side, call post-connect */
    result = globus_l_xio_net_manager_get_attr_array(
            op,
            handle->transport_driver,
            handle->transport_name,
            &transport_opts);
    if (result)
    {
        goto get_transport_opts_fail;
    }

    result = globus_xio_driver_handle_cntl(
            driver_handle,
            handle->transport_driver,
            GLOBUS_XIO_GET_LOCAL_NUMERIC_CONTACT,
            &handle->local_contact);
    if (result)
    {
        goto get_local_contact_fail;
    }

    result = globus_net_manager_context_post_connect(
            handle->attr->context,
            handle->attr->task_id ? handle->attr->task_id : "unset",
            handle->transport_name,
            handle->local_contact,
            handle->remote_contact,
            transport_opts,
            &new_transport_opts);
    if (result)
    {
        goto post_connect_fail;
    }
    if (new_transport_opts)
    {
        result = globus_l_xio_net_manager_transport_handle_apply(
                handle, op, new_transport_opts);
    }
    globus_net_manager_attr_array_delete(new_transport_opts);
    if (result)
    {
post_connect_fail:
        free(handle->remote_contact);
        free(handle->local_contact);
    }
get_local_contact_fail:
    globus_net_manager_attr_array_delete(transport_opts);
get_transport_opts_fail:
failed_open:
    if (result)
    {
        globus_l_xio_net_manager_attr_destroy(handle->attr);
        free(handle);
        handle = NULL;
    }
no_handle:
    globus_xio_driver_finished_open(handle, op, result);
}