static
void
globus_l_xio_popen_system_write_cb(
    globus_result_t                     result,
    globus_size_t                       nbytes,
    void *                              user_arg)
{
    globus_xio_operation_t              op;
    xio_l_popen_handle_t *              handle;
    GlobusXIOName(globus_l_xio_popen_system_write_cb);
    
    GlobusXIOPOpenDebugEnter();
    
    op = (globus_xio_operation_t) user_arg;
    
    handle = (xio_l_popen_handle_t *) 
        globus_xio_operation_get_driver_specific(op);
        
    handle->canceled = globus_xio_operation_is_canceled(op);

    globus_l_xio_popen_update_position(
        handle,
        nbytes,
        SEEK_CUR);
        
    globus_xio_driver_finished_write(op, result, nbytes);
    
    GlobusXIOPOpenDebugExit();
}
static void
globus_l_xio_telnet_write_cb(
    globus_xio_operation_t              op,
    globus_result_t                     result,
    globus_size_t                       nbytes,
    void *                              user_arg)
{
    globus_xio_driver_finished_write(op, result, nbytes);
}
/*
 *  write to a file
 */
static
globus_result_t
globus_l_xio_popen_write(
    void *                              driver_specific_handle,
    const globus_xio_iovec_t *          iovec,
    int                                 iovec_count,
    globus_xio_operation_t              op)
{
    xio_l_popen_handle_t *              handle;
    globus_size_t                       nbytes;
    globus_result_t                     result;
    globus_off_t                        offset;
    GlobusXIOName(globus_l_xio_popen_write);
    
    GlobusXIOPOpenDebugEnter();
    
    handle = (xio_l_popen_handle_t *) driver_specific_handle;
    
    offset = GlobusXIOPOpenPosition(handle);
            
    /* if buflen and waitfor are both 0, we behave like register select */
    if((globus_xio_operation_get_wait_for(op) == 0 &&
        (iovec_count > 1 || iovec[0].iov_len > 0)) ||
        (handle->use_blocking_io &&
        globus_xio_driver_operation_is_blocking(op)))
    {
        result = globus_xio_system_file_write(
            handle->out_system,
            offset,
            iovec,
            iovec_count,
            globus_xio_operation_get_wait_for(op),
            &nbytes);
        
        globus_l_xio_popen_update_position(handle, nbytes, SEEK_CUR);
        globus_xio_driver_finished_write(op, result, nbytes);
        result = GLOBUS_SUCCESS;
    }
    else
    {
        result = globus_xio_system_file_register_write(
            op,
            handle->out_system,
            offset,
            iovec,
            iovec_count,
            globus_xio_operation_get_wait_for(op),
            globus_l_xio_popen_system_write_cb,
            op);
    }
    
    GlobusXIOPOpenDebugExit();
    return result;
}
static
globus_result_t
globus_l_xio_wrapblock_write(
    void *                              driver_specific_handle,
    const globus_xio_iovec_t *          iovec,
    int                                 iovec_count,
    globus_xio_operation_t              op)
{
    globus_size_t                       nbytes;
    globus_result_t                     result;
    int                                 i;
    xio_l_wrapblock_wrapper_t *         wrapper;
    xio_l_wrapblock_handle_t *          wrapblock_handle;

    wrapblock_handle = (xio_l_wrapblock_handle_t *) driver_specific_handle;
    if(globus_xio_driver_operation_is_blocking(op))
    {
        result = wrapblock_handle->wrapblock_driver->write_func(
            wrapblock_handle->driver_handle,
            iovec,
            iovec_count,
            &nbytes);
        globus_xio_driver_finished_write(op, result, nbytes);
    }
    else
    {
        wrapper = (xio_l_wrapblock_wrapper_t *)
            globus_calloc(1, sizeof(xio_l_wrapblock_wrapper_t));
        wrapper->iovec = (globus_xio_iovec_t *)
            globus_calloc(iovec_count, sizeof(globus_xio_iovec_t));
        wrapper->iovec_count = iovec_count;
        wrapper->op = op;
        wrapper->wrapblock_handle = driver_specific_handle;

        for(i = 0; i < iovec_count; i++)
        {
            wrapper->iovec[i].iov_base = iovec[i].iov_base;
            wrapper->iovec[i].iov_len = iovec[i].iov_len;
        }

        globus_callback_register_oneshot(
            NULL,
            NULL,
            globus_l_xio_wrapblock_write_kickout,
            wrapper);
    }
    return GLOBUS_SUCCESS;
}
static
void
globus_l_xio_pipe_system_write_cb(
    globus_result_t                     result,
    globus_size_t                       nbytes,
    void *                              user_arg)
{
    globus_xio_operation_t              op;
    GlobusXIOName(globus_l_xio_pipe_system_write_cb);
    
    GlobusXIOPipeDebugEnter();
    
    op = (globus_xio_operation_t) user_arg;
        
    globus_xio_driver_finished_write(op, result, nbytes);
    
    GlobusXIOPipeDebugExit();
}
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();
}
static
void
globus_l_xio_wrapblock_write_kickout(
    void *                              user_arg)
{
    globus_size_t                       nbytes;
    globus_result_t                     result;
    xio_l_wrapblock_wrapper_t *         wrapper;

    globus_thread_blocking_will_block();

    wrapper = (xio_l_wrapblock_wrapper_t *) user_arg;

    result = wrapper->wrapblock_handle->wrapblock_driver->write_func(
        wrapper->wrapblock_handle->driver_handle,
        wrapper->iovec,
        wrapper->iovec_count,
        &nbytes);
    globus_xio_driver_finished_write(wrapper->op, result, nbytes);

    xio_l_wrapblock_wrapper_destroy(wrapper);
}
/**
 * Callback after writing response
 * @ingroup globus_i_xio_http_server
 *
 * Frees the iovec array associated with the response and then if
 * writing user data was used to trigger the response, write it to the
 * transport.  If an error occurs while writing, the operation will be
 * finished. If the response was triggered by the
 * GLOBUS_XIO_HTTP_HANDLE_SET_END_OF_ENTITY control, then the operation
 * is simply destroyed.
 *
 * @return void
 */
static
void
globus_l_xio_http_server_write_response_callback(
    globus_xio_operation_t              op,
    globus_result_t                     result,
    globus_size_t                       nbytes,
    void *                              user_arg)
{
    globus_i_xio_http_handle_t *        http_handle = user_arg;
    int                                 i;

    globus_mutex_lock(&http_handle->mutex);

    for (i = 0; i < http_handle->header_iovcnt; i++)
    {
        globus_libc_free(http_handle->header_iovec[i].iov_base);
    }
    globus_libc_free(http_handle->header_iovec);

    http_handle->header_iovec = NULL;
    http_handle->header_iovcnt = 0;

    if (http_handle->write_operation.iovcnt > 0)
    {
        /* User data to be sent */
        if (http_handle->response_info.headers.transfer_encoding
                == GLOBUS_XIO_HTTP_TRANSFER_ENCODING_CHUNKED)
        {
            result = globus_i_xio_http_write_chunk(
                    http_handle,
                    http_handle->write_operation.iov,
                    http_handle->write_operation.iovcnt,
                    op);
        }
        else
        {
            result = globus_xio_driver_pass_write(
                    op,
                    http_handle->write_operation.iov,
                    http_handle->write_operation.iovcnt,
                    globus_xio_operation_get_wait_for(op),
                    globus_i_xio_http_write_callback,
                    http_handle);
        }

        if (result != GLOBUS_SUCCESS)
        {
            globus_xio_driver_finished_write(op, result, 0);
            http_handle->write_operation.operation = NULL;
            http_handle->write_operation.driver_handle = NULL;
        }
    }
    else
    {
        /* destroy synthesized operation */
        globus_xio_driver_operation_destroy(
                http_handle->write_operation.operation);
        http_handle->write_operation.operation = NULL;
        http_handle->write_operation.driver_handle = NULL;
    }

    if (http_handle->close_operation != NULL)
    {
        result = globus_xio_driver_pass_close(
                http_handle->close_operation,
                globus_i_xio_http_close_callback,
                http_handle);

        globus_mutex_unlock(&http_handle->mutex);
        if (result != GLOBUS_SUCCESS)
        {
            globus_i_xio_http_close_callback(
                http_handle->close_operation,
                result,
                http_handle);
        }
    }
    else
    {
        http_handle->parse_state = GLOBUS_XIO_HTTP_PRE_REQUEST_LINE;
        globus_mutex_unlock(&http_handle->mutex);
    }
    return;

}