static
globus_result_t
globus_l_xio_net_manager_close(
    void                               *driver_specific_handle,
    void                               *attr,
    globus_xio_operation_t              op)
{
    globus_l_xio_net_manager_handle_t  *handle = driver_specific_handle;
    globus_result_t                     result = GLOBUS_SUCCESS;
    globus_net_manager_attr_t          *transport_opts = NULL;

    if (!handle)
    {
        goto no_handle;
    }
    result = globus_l_xio_net_manager_get_handle_attr_array(
            op,
            handle->transport_driver,
            handle->transport_name,
            &transport_opts);
    if (result)
    {
        goto get_attr_array_fail;
    }
    globus_net_manager_attr_array_delete(handle->attr->attr_array);
    handle->attr->attr_array = transport_opts;
    transport_opts = NULL;

    result = globus_net_manager_context_pre_close(
            handle->attr->context,
            handle->attr->task_id ? handle->attr->task_id : "unset",
            handle->transport_name,
            handle->local_contact,
            handle->remote_contact,
            handle->attr->attr_array);
    if (result)
    {
        goto pre_close_fail;
    }

no_handle:
    result = globus_xio_driver_pass_close(
        op, globus_l_xio_net_manager_close_cb, handle);

pre_close_fail:
    globus_net_manager_attr_array_delete(transport_opts);

get_attr_array_fail:
    return result;
}
static globus_result_t
globus_l_xio_telnet_close(
    void *                              driver_specific_handle,
    void *                              attr,
    globus_xio_operation_t              op)
{
    globus_result_t                     res;
    globus_l_xio_telnet_handle_t *     handle;

    handle = (globus_l_xio_telnet_handle_t *) driver_specific_handle;

    res = globus_xio_driver_pass_close(
        op, globus_l_xio_telnet_close_cb, handle);

    return res;
}
/**
 * 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;

}
static globus_result_t
test_bounce_next_op(
    bounce_info_t *                     info,
    globus_xio_operation_t              op)
{
    globus_result_t                     res = GLOBUS_SUCCESS;
    GlobusXIOName(test_bounce_next_op);

    GlobusXIOTestDebugInternalEnter();
    info->bounce_count++;

    switch(info->next_op)
    {
        case TEST_READ:
            if(info->bounce_count == info->max_count)
            {
                info->bounce_count = 0;
                if(info->start_op == TEST_CLOSE)
                {
                    info->next_op = TEST_CLOSE;
                }
                else if(info->start_op == TEST_READ)
                {
                    info->next_op = TEST_WRITE;
                }
                else
                {
                    info->next_op = TEST_FINISH;
                }
            }
            res = globus_xio_driver_pass_read(
                op, info->iovec, info->iovec_count,
                info->wait_for, bounce_data_cb, (void *)info);

            break;

        case TEST_WRITE:
            if(info->bounce_count == info->max_count)
            {
                info->bounce_count = 0;
                if(info->start_op == TEST_CLOSE)
                {
                    info->next_op = TEST_CLOSE;
                }
                else if(info->start_op == TEST_WRITE)
                {
                    info->next_op = TEST_READ;
                }
                else
                {
                    info->next_op = TEST_FINISH;
                }
            }

            res = globus_xio_driver_pass_write(
                op, info->iovec, info->iovec_count,
                info->wait_for, bounce_data_cb, (void *)info);
            break;

        case TEST_CLOSE:
            info->next_op = TEST_FINISH;
            res = globus_xio_driver_pass_close(op, close_bounce_cb,
                (void*)info);
            break;

        case TEST_FINISH:
            test_bounce_finish_op(info, op);
            res = GLOBUS_SUCCESS;
            break;

        default:
            globus_assert(0);
            break;
    }
    if(res != GLOBUS_SUCCESS)
    {
        goto err;
    }

    GlobusXIOTestDebugInternalExit();
    return GLOBUS_SUCCESS;

  err:
    GlobusXIOTestDebugInternalExitWithError();
    return res;
}