Ejemplo n.º 1
0
globus_result_t
globus_xio_attr_init(
    globus_xio_attr_t *                 attr)
{
    globus_result_t                     res;
    globus_i_xio_attr_t *               xio_attr;
    GlobusXIOName(globus_xio_attr_init);

    GlobusXIODebugEnter();
    
    if(attr == NULL)
    {
        res = GlobusXIOErrorParameter("attr");
        goto err;
    }
   
    /* allocate the attr */ 
    xio_attr = (globus_i_xio_attr_t *)
                globus_calloc(sizeof(globus_i_xio_attr_t), 1);
    if(xio_attr == NULL)
    {
        res = GlobusXIOErrorMemory("attr");
        goto err;
    }

    xio_attr->entry = (globus_i_xio_attr_ent_t *)
        globus_calloc(sizeof(globus_i_xio_attr_ent_t) *
            GLOBUS_XIO_ATTR_ARRAY_BASE_SIZE, 1);
    if(xio_attr->entry == NULL)
    {
        *attr = GLOBUS_NULL;
        globus_free(xio_attr);
        res = GlobusXIOErrorMemory("attr->entry");
        goto err;
    }

    /* zero it out */
    xio_attr->max = GLOBUS_XIO_ATTR_ARRAY_BASE_SIZE;
    xio_attr->space = GLOBUS_CALLBACK_GLOBAL_SPACE;
    
    globus_mutex_lock(&globus_i_xio_mutex);
    {
        globus_list_insert(&globus_i_xio_outstanding_attrs_list, xio_attr);
    }
    globus_mutex_unlock(&globus_i_xio_mutex);
    
    *attr = xio_attr;

    GlobusXIODebugExit();
    return GLOBUS_SUCCESS;

  err:

    GlobusXIODebugExitWithError();
    return res;
}
static
globus_result_t
globus_l_xio_popen_handle_init(
    xio_l_popen_handle_t **             handle)
{
    globus_result_t                     result;
    GlobusXIOName(globus_l_xio_popen_handle_init);
    
    GlobusXIOPOpenDebugEnter();
    
    *handle = (xio_l_popen_handle_t *)
        globus_calloc(1, sizeof(xio_l_popen_handle_t));
    if(!*handle)
    {
        result = GlobusXIOErrorMemory("handle");
        goto error_handle;
    }
    
    globus_mutex_init(&(*handle)->lock, NULL);
    
    GlobusXIOPOpenDebugExit();
    return GLOBUS_SUCCESS;

error_handle:
    GlobusXIOPOpenDebugExitWithError();
    return result;    
}
static
globus_result_t
globus_l_xio_pipe_attr_init(
    void **                             out_attr)
{
    xio_l_pipe_attr_t *                 attr;
    globus_result_t                     result;
    GlobusXIOName(globus_l_xio_pipe_attr_init);

    GlobusXIOPipeDebugEnter();
    /*
     *  create a file attr structure and intialize its values
     */
    attr = (xio_l_pipe_attr_t *) globus_malloc(sizeof(xio_l_pipe_attr_t));
    if(!attr)
    {
        result = GlobusXIOErrorMemory("attr");
        goto error_attr;
    }

    memcpy(attr, &xio_l_pipe_attr_default, sizeof(xio_l_pipe_attr_t));
    *out_attr = attr;

    GlobusXIOPipeDebugExit();
    return GLOBUS_SUCCESS;

error_attr:
    GlobusXIOPipeDebugExitWithError();
    return result;
}
static
globus_result_t
globus_l_xio_pipe_handle_init(
    xio_l_pipe_handle_t **              handle,
    xio_l_pipe_attr_t *                 attr)
{
    globus_result_t                     result;
    GlobusXIOName(globus_l_xio_pipe_handle_init);
    
    GlobusXIOPipeDebugEnter();
    
    *handle = (xio_l_pipe_handle_t *)
        globus_calloc(1, sizeof(xio_l_pipe_handle_t));
    if(!*handle)
    {
        result = GlobusXIOErrorMemory("handle");
        goto error_handle;
    }
    
    globus_mutex_init(&(*handle)->lock, NULL);
    (*handle)->use_blocking_io = attr->use_blocking_io;
    (*handle)->infd = attr->infd;
    (*handle)->outfd = attr->outfd;

    GlobusXIOPipeDebugExit();
    return GLOBUS_SUCCESS;

error_handle:
    GlobusXIOPipeDebugExitWithError();
    return result;    
}
/**
 * Copy the contents of a header information structure.
 * @ingroup globus_i_xio_http_header_info
 *
 * All values associated with the @a src header information structure will
 * be copied to the @a dest one. If this function returns a failure, then the
 * @a dest structure should be considered uninitialized.
 *
 * @param dest
 *     Header information structure to initialize. This should not be
 *     initialized before this function is called, or memory may be leaked.
 * @param src
 *     Header information structure containing valid values.
 *
 * @retval GLOBUS_SUCCESS
 *     Structure successfully copied.
 * @retval GLOBUS_XIO_ERROR_MEMORY
 *     Copy failed due to memory constraints.
 */
globus_result_t
globus_i_xio_http_header_info_copy(
    globus_i_xio_http_header_info_t *   dest,
    const globus_i_xio_http_header_info_t *
                                        src)
{
    int                                 rc;
    globus_result_t                     result = GLOBUS_SUCCESS;

    GlobusXIOName(globus_i_xio_http_header_info_init);
    rc = globus_hashtable_copy(
            &dest->headers,
            (globus_hashtable_t *) &src->headers,
            globus_i_xio_http_header_copy);
    if (rc != GLOBUS_SUCCESS)
    {
        result = GlobusXIOErrorMemory("hashtable");

        goto error_exit;
    }

    dest->content_length = src->content_length;
    dest->transfer_encoding = src->transfer_encoding;
    dest->flags = src->flags;

    return result;

error_exit:
    return result;
}
/*
 *  copy an attribute structure
 */
static
globus_result_t
globus_l_xio_pipe_attr_copy(
    void **                             dst,
    void *                              src)
{
    xio_l_pipe_attr_t *                 attr;
    xio_l_pipe_attr_t *                 src_attr;
    globus_result_t                     result;
    GlobusXIOName(globus_l_xio_pipe_attr_copy);

    GlobusXIOPipeDebugEnter();

    src_attr = (xio_l_pipe_attr_t *) src;
    attr = (xio_l_pipe_attr_t *) globus_malloc(sizeof(xio_l_pipe_attr_t));
    if(!attr)
    {
        result = GlobusXIOErrorMemory("attr");
        goto error_attr;
    }

    memcpy(attr, src_attr, sizeof(xio_l_pipe_attr_t));
    *dst = attr;

    GlobusXIOPipeDebugExit();
    return GLOBUS_SUCCESS;

error_attr:
    GlobusXIOPipeDebugExitWithError();
    return result;
}
globus_result_t
globus_i_xio_win32_complete(
    globus_callback_func_t              callback,
    void *                              user_arg)
{
    globus_l_xio_win32_poll_entry_t *   entry;
    globus_result_t                     result;
    GlobusXIOName(globus_i_xio_win32_complete);

    GlobusXIOSystemDebugEnter();
    
    if (! globus_i_am_only_thread())
    {
        return globus_callback_register_oneshot(
            0,
            0,
            callback,
            user_arg);
    }

    win32_mutex_lock(&globus_l_xio_win32_poll_lock);
    {
        if(globus_l_xio_win32_poll_free)
        {
            entry = globus_l_xio_win32_poll_free;
            globus_l_xio_win32_poll_free = entry->next;
        }
        else
        {
            entry = (globus_l_xio_win32_poll_entry_t *)
                globus_malloc(sizeof(globus_l_xio_win32_poll_entry_t));
            if(!entry)
            {
                result = GlobusXIOErrorMemory("entry");
                goto error_malloc;
            }
        }
        
        entry->callback = callback;
        entry->user_arg = user_arg;
    
        GlobusLWin32PollQueueEnqueue(entry);
        
        if(globus_l_xio_win32_poll_event_sleeping &&
            !globus_l_xio_win32_poll_event_pending)
        {
            SetEvent(globus_l_xio_win32_poll_event);
            globus_l_xio_win32_poll_event_pending = GLOBUS_TRUE;
        }
    }
    win32_mutex_unlock(&globus_l_xio_win32_poll_lock);
    
    GlobusXIOSystemDebugExit();

    return GLOBUS_SUCCESS;

error_malloc:
    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;
}
/*
 *  copy an attribute structure
 */
static
globus_result_t
globus_l_xio_popen_attr_copy(
    void **                             dst,
    void *                              src)
{
    xio_l_popen_attr_t *                attr;
    xio_l_popen_attr_t *                src_attr;
    globus_result_t                     result;
    int                                 i;
    GlobusXIOName(globus_l_xio_popen_attr_copy);

    GlobusXIOPOpenDebugEnter();

    src_attr = (xio_l_popen_attr_t *) src;
    attr = (xio_l_popen_attr_t *) globus_malloc(sizeof(xio_l_popen_attr_t));
    if(!attr)
    {
        result = GlobusXIOErrorMemory("attr");
        goto error_attr;
    }

    memcpy(attr, src_attr, sizeof(xio_l_popen_attr_t));
    if(src_attr->program_name != NULL)
    {
        attr->program_name = strdup(src_attr->program_name);
    }
    if(src_attr->argc > 0)
    {
        attr->argv = (char **)globus_calloc(attr->argc+1, sizeof(char*));
        for(i = 0; i < attr->argc; i++)
        {
            attr->argv[i] = strdup(src_attr->argv[i]);
        }
        attr->argv[i] = NULL;
    }
    if(src_attr->env_count > 0)
    {
        attr->env = (char **)globus_calloc(attr->env_count+1, sizeof(char*));
        for(i = 0; i < attr->env_count; i++)
        {
            attr->env[i] = strdup(src_attr->env[i]);
        }
        attr->env[i] = NULL;
    }
    *dst = attr;

    GlobusXIOPOpenDebugExit();
    return GLOBUS_SUCCESS;

error_attr:
    GlobusXIOPOpenDebugExitWithError();
    return result;
}
Ejemplo n.º 10
0
/** Copy an HTTP attribute
 * @ingroup globus_i_xio_http_attr
 *
 * Copies all values associated with the @a src http attribute to
 * a newly allocated attribute in @a dst. If this function returns a
 * failure, then the @a dst should be considered uninitiailized.  This is
 * called by the XIO driver via globus_xio_attr_copy().
 *
 * @param dst
 *     Void ** which will be set to point to a newly allocated attribute
 *     with equivalent values to those in @a src.
 * @param src
 *     Void * pointing to a #globus_i_xio_http_attr_t which contains the
 *     attributes we want to copy.
 *
 * @return
 *     This function returns GLOBUS_SUCCESS or GLOBUS_XIO_ERROR_MEMORY itself.
 *     Other errors generated by globus_i_xio_http_request_copy() may be
 *     returned as well.
 *
 * @retval GLOBUS_SUCCESS
 *     Attribute successfully copied.
 * @retval GLOBUS_XIO_ERROR_MEMORY
 *     Attribute copy failed due to memory constraints.
 */
globus_result_t
globus_i_xio_http_attr_copy(
    void **                             dst,
    void *                              src)
{
    globus_result_t                     result;
    globus_i_xio_http_attr_t *          http_dst;
    globus_i_xio_http_attr_t *          http_src = src;
    GlobusXIOName(globus_i_xio_http_attr_copy);

    /*
     * Don't use globus_i_xio_http_request_init() here or the call to
     * globus_i_xio_http_request_copy() below will leak.
     */
    http_dst = globus_libc_malloc(sizeof(globus_i_xio_http_attr_t));
    if (http_dst == NULL)
    {
        result = GlobusXIOErrorMemory(dst);
        goto error_exit;
    }

    /* Copy request attrs */
    result = globus_i_xio_http_request_copy(
            &http_dst->request,
            &http_src->request);
    if (result != GLOBUS_SUCCESS)
    {
        goto free_http_dst_exit;
    }

    /* Copy response attrs */
    result = globus_i_xio_http_response_copy(
            &http_dst->response,
            &http_src->response);
    if (result != GLOBUS_SUCCESS)
    {
        goto free_http_dst_request_exit;
    }
    http_dst->delay_write_header = http_src->delay_write_header;

    *dst = http_dst;

    return GLOBUS_SUCCESS;
free_http_dst_request_exit:
    globus_i_xio_http_request_destroy(&http_dst->request);
free_http_dst_exit:
    globus_libc_free(http_dst);
error_exit:
    return result;
}
Ejemplo n.º 11
0
globus_result_t
globus_xio_stack_copy(
    globus_xio_stack_t *                dst,
    globus_xio_stack_t                  src)
{
    globus_i_xio_stack_t *		xio_stack_src;
    globus_i_xio_stack_t *		xio_stack_dst;
    globus_result_t                     res;
    GlobusXIOName(globus_xio_stack_push_driver);
                    
    GlobusXIODebugEnter();
    if(dst == NULL)
    {
        res = GlobusXIOErrorParameter("dst");
        goto err;
    }

    if(src == NULL)
    {
        res = GlobusXIOErrorParameter("src");
        goto err;
    }

    xio_stack_src = src;

    xio_stack_dst = (globus_i_xio_stack_t *)
        globus_calloc(1, sizeof(globus_i_xio_stack_t));

    /* check for memory alloc failure */
    if(xio_stack_dst == NULL)
    {
        res = GlobusXIOErrorMemory("xio_stack_dst");
        goto err;
    }

    xio_stack_dst->size = xio_stack_src->size;
    xio_stack_dst->driver_stack = globus_list_copy(
					xio_stack_src->driver_stack);
    *dst = xio_stack_dst;

    GlobusXIODebugExit();

    return GLOBUS_SUCCESS;

  err:

    GlobusXIODebugExitWithError();
    return res;
}
globus_result_t
globus_xio_system_socket_register_accept(
    globus_xio_operation_t              op,
    globus_xio_system_socket_handle_t   listener_handle,
    globus_xio_system_socket_t *        out_handle,
    globus_xio_system_callback_t        callback,
    void *                              user_arg)
{
    globus_result_t                     result;
    globus_i_xio_system_op_info_t *     op_info;
    GlobusXIOName(globus_xio_system_socket_register_accept);
    
    GlobusXIOSystemDebugEnterFD(listener_handle->socket);
    
    GlobusIXIOSystemAllocOperation(op_info);
    if(!op_info)
    {
        result = GlobusXIOErrorMemory("op_info");
        goto error_op_info;
    }

    op_info->type = GLOBUS_I_XIO_SYSTEM_OP_ACCEPT;
    op_info->state = GLOBUS_I_XIO_SYSTEM_OP_NEW;
    op_info->op = op;
    op_info->handle = listener_handle;
    op_info->user_arg = user_arg;
    op_info->sop.non_data.callback = callback;
    op_info->sop.non_data.out_fd = out_handle;
    op_info->waitforbytes = 1;

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

    GlobusXIOSystemDebugExitFD(listener_handle->socket);
    return GLOBUS_SUCCESS;

error_register:
    GlobusIXIOSystemFreeOperation(op_info);
error_op_info:
    GlobusXIOSystemDebugExitWithErrorFD(listener_handle->socket);
    return result;
}
/**
 * Copy the contents of an HTTP response
 * @ingroup globus_i_xio_http_response
 *
 * All values associated with the @a src response will be copied
 * to the corresponding fields of the @a dest response. If this function
 * returns a failure, then the @a dest should be considered uninitialized.
 *
 * @param dest
 *     Response to be initialized with values from src. This should
 *     not be initialized before this is called, or memory may be
 *     leaked.
 * @param src
 *     Response containing known values.
 *
 * @retval GLOBUS_SUCCESS
 *     Response successfully copied.
 * @retval GLOBUS_XIO_ERROR_MEMORY
 *     Response copy failed due to memory constraints.
 */
globus_result_t
globus_i_xio_http_response_copy(
    globus_i_xio_http_response_t *      dest,
    const globus_i_xio_http_response_t *src)
{
    globus_result_t                     res = GLOBUS_SUCCESS;
    GlobusXIOName(globus_i_xio_http_response_copy);

    dest->status_code = src->status_code;

    if (src->reason_phrase == NULL)
    {
        dest->reason_phrase = NULL;
    }
    else
    {
        dest->reason_phrase = globus_libc_strdup(src->reason_phrase);
        if (dest->reason_phrase == NULL)
        {
            res = GlobusXIOErrorMemory("reason_phrase");

            goto error_exit;
        }
    }

    dest->http_version = src->http_version;

    res = globus_i_xio_http_header_info_copy(
            &dest->headers,
            &src->headers);

    if (res != GLOBUS_SUCCESS)
    {
        goto free_reason_phrase_exit;
    }

    return res;

free_reason_phrase_exit:
    if (dest->reason_phrase != NULL)
    {
        globus_libc_free(dest->reason_phrase);
        dest->reason_phrase = NULL;
    }
error_exit:
    return res;
}
Ejemplo n.º 14
0
/**
 * Allocate and initialize an HTTP attribute
 * @ingroup globus_i_xio_http_attr
 *
 * Creates a new attribute with default values. This is called by the XIO
 * driver via globus_xio_attr_init().
 *
 * @param out_attr
 *     Pointer value will be set to point to a 
 *     newly allocated and initilized #globus_i_xio_http_attr_t
 *     structure.
 *
 * @retval GLOBUS_SUCCESS
 *     Attribute successfully initialized.
 * @retval GLOBUS_XIO_ERROR_MEMORY
 *     Initialization failed due to memory constraints.
 *
 * @see globus_i_xio_http_attr_destroy()
 */
globus_result_t
globus_i_xio_http_attr_init(
    void **                             out_attr)
{
    globus_result_t                     res;
    globus_i_xio_http_attr_t *          attr;
    GlobusXIOName(globus_i_xio_http_attr_init);

    attr = globus_libc_malloc(sizeof(globus_i_xio_http_attr_t));
    if (attr == NULL)
    {
        res = GlobusXIOErrorMemory("attr");

        goto error_exit;
    }

    res = globus_i_xio_http_request_init(&attr->request);

    if (res != GLOBUS_SUCCESS)
    {
        goto free_attr_exit;
    }
    res = globus_i_xio_http_response_init(&attr->response);

    if (res != GLOBUS_SUCCESS)
    {
        goto free_request_exit;
    }
    attr->delay_write_header = GLOBUS_FALSE;

    *out_attr = attr;
    return GLOBUS_SUCCESS;

free_request_exit:
    globus_i_xio_http_request_destroy(&attr->request);
free_attr_exit:
    globus_libc_free(attr);
error_exit:
    return res;
}
/**
 * Accept callback
 * @ingroup globus_i_xio_http_server
 *
 * Callback function called when the transport completes accepting
 * a connection for the request. Generates a new target to associate with
 * the result of this accept. This target will be passed to
 * globus_xio_open() or globus_xio_register_open() to begin processing the
 * request.
 *
 * @param op
 *     XIO Data structure passed through to globus_xio_driver_finished_accept().
 * @param result
 *     Result from the transport's attempt to accept a new connection.
 * @param user_arg
 *     Not used.
 *
 * @return void
 *
 * @todo When implemented in the XIO driver framework, parse the request
 * header before returning from this, so the target is populated with
 * meaningful information for the user. This will help enable persistent
 * connections.
 */
static
void
globus_l_xio_http_accept_callback(
    globus_xio_operation_t              op,
    globus_result_t                     result,
    void *                              user_arg)
{
    globus_i_xio_http_target_t *        target_info = NULL;
    GlobusXIOName(globus_l_xio_http_accept_callback);
    
    if (result == GLOBUS_SUCCESS)
    {
        target_info = globus_i_xio_http_target_new();

        if (target_info == NULL)
        {
            result = GlobusXIOErrorMemory("target");
        }
    }

    globus_xio_driver_finished_accept(op, target_info, 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;
}
/**
 * Initialize an HTTP header info structure
 * @ingroup globus_i_xio_http_header_info
 *
 * All fields of the @a header_info structure will be initialized to their
 * default values. If this function returns a failre, the header_info
 * should be considered uninitialized.
 *
 * @param header_info
 *     Header information structure to initialize.
 *
 * @retval GLOBUS_SUCCESS
 *     Header initialized successfully.
 * @retval GLOBUS_XIO_ERROR_MEMORY
 *     Initialization failed due to memory constraints.
 */
globus_result_t
globus_i_xio_http_header_info_init(
    globus_i_xio_http_header_info_t *   header_info)
{
    int                                 rc;
    globus_result_t                     result = GLOBUS_SUCCESS;
    GlobusXIOName(globus_i_xio_http_header_info_init);

    memset(header_info, '\0', sizeof(globus_i_xio_http_header_info_t));

    rc = globus_hashtable_init(
            &header_info->headers,
            16,
            globus_hashtable_string_hash,
            globus_hashtable_string_keyeq);

    if (rc != GLOBUS_SUCCESS)
    {
        result = GlobusXIOErrorMemory("hashtable");
    }
    return result;
}
Ejemplo n.º 18
0
static globus_result_t
globus_l_xio_telnet_attr_init(
    void **                             out_driver_attr)
{
    globus_l_xio_telnet_attr_t *        attr;
    globus_result_t                     res;
    GlobusXIOName(globus_l_xio_telnet_attr_init);
    
    attr = (globus_l_xio_telnet_attr_t *)
        globus_calloc(sizeof(globus_l_xio_telnet_attr_t), 1);
    if(!attr)
    {
        res = GlobusXIOErrorMemory("attr");
        goto error;
    }

    *out_driver_attr = attr;
    
    return GLOBUS_SUCCESS;

error:
    return res;
}
Ejemplo n.º 19
0
/**
 * Modify the state of an HTTP attribute
 * @ingroup globus_i_xio_http_attr
 *
 * Modify the state of an attribute. This is called by the XIO driver via
 * globus_xio_attr_cntl().
 *
 * @param driver_attr
 *     Void pointer to a #globus_i_xio_http_attr_t structure containing
 *     the attribute's values.
 * @param cmd
 *     Integer value indicating which attribute will be changed. Valid
 *     commands values are in the set defined by  #globus_xio_http_attr_cmd_t
 * @param ap
 *     Variable-length argument list containing any cmd-specific parameters.
 *
 * @retval GLOBUS_SUCCESS
 *     Attribute successfully modified.
 * @retval GLOBUS_XIO_ERROR_MEMORY
 *     Attribute control failed due to memory constraints.
 * @retval GLOBUS_XIO_ERROR_PARAMETER
 *     Invalid @a cmd parameter or invalid value for cmd-specific parameters
 *     in @a ap.
 */
globus_result_t
globus_i_xio_http_attr_cntl(
    void *                              driver_attr,
    int                                 cmd,
    va_list                             ap)
{
    globus_result_t                     res = GLOBUS_SUCCESS;
    globus_i_xio_http_attr_t *          attr = driver_attr;
    char *                              in_string;
    char *                              save_string;
    globus_xio_http_version_t           in_http_version;
    char *                              in_header_name;
    char *                              in_header_value;
    char **                             out_method;
    char **                             out_uri;
    globus_xio_http_version_t *         out_http_version;
    globus_hashtable_t *                out_headers;
    int *                               out_status_code;
    char **                             out_reason_phrase;

    GlobusXIOName(globus_i_xio_http_attr_cntl);

    switch (cmd)
    {
        case GLOBUS_XIO_HTTP_ATTR_SET_REQUEST_METHOD:
            save_string = attr->request.method;

            in_string = va_arg(ap, char *);

            if (in_string == NULL)
            {
                res = GlobusXIOErrorParameter("method");
                break;
            }

            attr->request.method = globus_libc_strdup(in_string);
            if (attr->request.method == NULL)
            {
                attr->request.method = save_string;
                res = GlobusXIOErrorMemory("method");
                break;
            }

            if (save_string != NULL)
            {
                globus_libc_free(save_string);
            }
            break;

        case GLOBUS_XIO_HTTP_ATTR_SET_REQUEST_HTTP_VERSION:
            in_http_version = va_arg(ap, globus_xio_http_version_t);

            if (in_http_version != GLOBUS_XIO_HTTP_VERSION_1_0 &&
                    in_http_version != GLOBUS_XIO_HTTP_VERSION_1_1)
            {
                res = GlobusXIOErrorParameter("version");
                break;
            }
            attr->request.http_version = in_http_version;
            break;

        case GLOBUS_XIO_HTTP_ATTR_SET_REQUEST_HEADER:
            in_header_name = va_arg(ap, char *);
            if (in_header_name == NULL)
            {
                res = GlobusXIOErrorParameter("name");
                break;
            }

            in_header_value = va_arg(ap, char *);
            if (in_header_value == NULL)
            {
                res = GlobusXIOErrorParameter("value");
                break;
            }

            res = globus_i_xio_http_header_info_set_header(
                    &attr->request.headers,
                    in_header_name,
                    in_header_value,
                    GLOBUS_FALSE);
            break;

        case GLOBUS_XIO_HTTP_ATTR_DELAY_WRITE_HEADER:
            attr->delay_write_header = 1;
            break;

        case GLOBUS_XIO_HTTP_GET_REQUEST:
            out_method = va_arg(ap, char **);
            out_uri = va_arg(ap, char **);
            out_http_version = va_arg(ap, globus_xio_http_version_t *);
            out_headers = va_arg(ap, globus_hashtable_t *);

            if (out_method != NULL)
            {
                *out_method = attr->request.method;
            }
            if (out_uri != NULL)
            {
                *out_uri = attr->request.uri;
            }
            if (out_http_version != NULL)
            {
                *out_http_version = attr->request.http_version;
            }
            if (out_headers != NULL)
            {
                *out_headers = attr->request.headers.headers;
            }
            break;
        case GLOBUS_XIO_HTTP_GET_RESPONSE:
            out_status_code = va_arg(ap, int *);
            out_reason_phrase = va_arg(ap, char **);
            out_http_version = va_arg(ap, globus_xio_http_version_t *);
            out_headers = va_arg(ap, globus_hashtable_t *);

            if (out_status_code != NULL)
            {
                *out_status_code = attr->response.status_code;
            }
            if (out_reason_phrase != NULL)
            {
                *out_reason_phrase = attr->response.reason_phrase;
            }
            if (out_http_version != NULL)
            {
                *out_http_version = attr->response.http_version;
            }
            if (out_headers != NULL)
            {
                *out_headers = attr->response.headers.headers;
            }
            break;
        default:
            res = GlobusXIOErrorParameter("cmd");
    }

    return res;
}
/**
 * Set the value of a header in a hashtable
 * @ingroup globus_i_xio_http_header
 *
 * Adds a new header to a header info structure, or updates the value of an
 * existing header. Copies of the name and value will be stored in a
 * #globus_xio_http_header_t in a hashtable in the header info structure.
 *
 * @param headers
 *     Pointer to the header info structure.
 * @param header_name
 *     Name of the header.
 * @param header_value
 *     Value of the header.
 *
 * @retval GLOBUS_SUCCESS
 *     Header successfully added to the hashtable.
 * @retval GLOBUS_XIO_ERROR_MEMORY
 *     Unable to add header due to memory constraints.
 */
globus_result_t
globus_i_xio_http_header_info_set_header(
    globus_i_xio_http_header_info_t *   headers,
    const char *                        header_name,
    const char *                        header_value)
{
    char *                              save_header;
    globus_result_t                     result = GLOBUS_SUCCESS;
    globus_xio_http_header_t *          header;
    int                                 rc;
    unsigned long                       length;
    GlobusXIOName(globus_l_xio_http_header_set);

    /* Special cases for entity-body handling headers */
    if (strcmp(header_name, "Content-Length") == 0)
    {
        rc = sscanf(header_value, "%lu", &length);

        if (rc < 1)
        {
            result = GlobusXIOHttpErrorInvalidHeader(header_name, header_value);

            goto error_exit;
        }
        headers->content_length = length;
        headers->flags |= GLOBUS_I_XIO_HTTP_HEADER_CONTENT_LENGTH_SET;
    }
    else if (strcmp(header_name, "Transfer-Encoding") == 0)
    {
        if (strcmp(header_value, "identity") == 0)
        {
            headers->transfer_encoding =
                GLOBUS_XIO_HTTP_TRANSFER_ENCODING_IDENTITY;
        }
        else if (strcmp(header_value, "chunked") == 0)
        {
            headers->transfer_encoding =
                GLOBUS_XIO_HTTP_TRANSFER_ENCODING_CHUNKED;
        }
        else
        {
            result = GlobusXIOHttpErrorInvalidHeader(header_name, header_value);

            goto error_exit;
        }
    }
    else if (strcmp(header_name, "Connection") == 0)
    {
        if (strcmp(header_value, "close") == 0)
        {
            headers->flags |= GLOBUS_I_XIO_HTTP_HEADER_CONNECTION_CLOSE;
        }
        else if (strcmp(header_value, "keep-alive") == 0)
        {
            headers->flags &= ~GLOBUS_I_XIO_HTTP_HEADER_CONNECTION_CLOSE;
        }
        else
        {
            result = GlobusXIOHttpErrorInvalidHeader(header_name, header_value);

            goto error_exit;
        }
    }
    else
    {
        /*
         * Either modify the header's value in the hashtable, if it's a
         * duplicate, or create a new entry in the hashtable
         */
        header = globus_hashtable_lookup(
                &headers->headers,
                (void *) header_name);

        if (header != NULL)
        {
            /* Replace current header's value */
            save_header = header->value;

            header->value = globus_libc_strdup(header_value);

            if (header->value == NULL)
            {
                header->value = save_header;

                result = GlobusXIOErrorMemory("header");

                goto error_exit;
            }
            globus_libc_free(save_header);
        }
        else
        {
            header = globus_libc_malloc(sizeof(globus_xio_http_header_t));

            if (header == NULL)
            {
                result = GlobusXIOErrorMemory("header");

                goto error_exit;
            }
            header->name = globus_libc_strdup(header_name);

            if (header->name == NULL)
            {
                result = GlobusXIOErrorMemory("header");
                goto free_header_exit;
            }

            header->value = globus_libc_strdup(header_value);

            if (header->value == NULL)
            {
                result = GlobusXIOErrorMemory("header");
                goto free_header_name_exit;
            }

            rc = globus_hashtable_insert(
                    &headers->headers,
                    header->name,
                    header);

            if (rc != GLOBUS_SUCCESS)
            {
                result = GlobusXIOErrorMemory("header");

                goto free_header_value_exit;
            }
        }
    }
    return result;

free_header_value_exit:
    globus_libc_free(header->value);
free_header_name_exit:
    globus_libc_free(header->name);
free_header_exit:
    globus_libc_free(header);
error_exit:
    return result;
}
/**
 * Modify the state of an HTTP handle
 * @ingroup globus_i_xio_http_handle
 *
 * Modify the state of an HTTP handle. This is called by the XIO driver via
 * globus_xio_handle_cntl().
 *
 * @param handle
 *     Void pointer to a #globus_i_xio_http_handle_t structure containing
 *     information an HTTP request/response transaction.
 * @param cmd
 *     Integer value indicating what command will be executed on the handle.
 *     Valid command values are in the set defined by
 *     #globus_xio_http_handle_cmd_t.
 * @param ap
 *     Variable-length argument list containing any cmd-specific parameters.
 *
 * @retval GLOBUS_SUCCESS
 *     The command was sucessfully executed.
 * @retval GLOBUS_XIO_ERROR_MEMORY
 *     The command failed due to memory constraints.
 * @retval GLOBUS_XIO_ERROR_PARAMETER
 *     Invalid @a cmd parameter or invlaid value of cmd-specific parameters 
 *     in @a ap
 */
globus_result_t
globus_i_xio_http_handle_cntl(
    void *                              handle,
    int                                 cmd,
    va_list                             ap)
{
    char *                              in_header_name;
    char *                              in_header_value;
    globus_result_t                     result = GLOBUS_SUCCESS;
    globus_i_xio_http_handle_t *        http_handle = handle;
    char *                              in_str;
    char *                              in_str2;
    char *                              save_str;
    int                                 in_int;
    GlobusXIOName(globus_i_xio_http_handle_cntl);

    globus_mutex_lock(&http_handle->mutex);

    switch (cmd)
    {
        case GLOBUS_XIO_HTTP_HANDLE_SET_RESPONSE_HEADER:
            if (http_handle->target_info.is_client)
            {
                result = GlobusXIOErrorParameter("handle");
                break;
            }

            if (http_handle->send_state != GLOBUS_XIO_HTTP_STATUS_LINE)
            {
                result = GlobusXIOErrorParameter("handle");
                break;
            }
            in_str = va_arg(ap, char *);
            in_str2 = va_arg(ap, char *);

            result = globus_i_xio_http_header_info_set_header(
                    &http_handle->response_info.headers,
                    in_str,
                    in_str2);

            break;

        case GLOBUS_XIO_HTTP_HANDLE_SET_RESPONSE_STATUS_CODE:
            if (http_handle->target_info.is_client)
            {
                result = GlobusXIOErrorParameter("handle");
                break;
            }

            if (http_handle->send_state != GLOBUS_XIO_HTTP_STATUS_LINE)
            {
                result = GlobusXIOErrorParameter("handle");
                break;
            }
            in_int = va_arg(ap, int);

            if (in_int < 100 || in_int > 599)
            {
                result = GlobusXIOErrorParameter("status_code");
                break;
            }

            http_handle->response_info.status_code = in_int;

            break;

        case GLOBUS_XIO_HTTP_HANDLE_SET_RESPONSE_REASON_PHRASE:
            if (http_handle->target_info.is_client)
            {
                result = GlobusXIOErrorParameter("handle");
                break;
            }

            if (http_handle->send_state != GLOBUS_XIO_HTTP_STATUS_LINE)
            {
                result = GlobusXIOErrorParameter("handle");
                break;
            }
            in_str = va_arg(ap, char *);

            if (in_str == NULL)
            {
                result = GlobusXIOErrorParameter("reason_phrase");
            }
            save_str = http_handle->response_info.reason_phrase;

            http_handle->response_info.reason_phrase =
                    globus_libc_strdup(in_str);

            if (http_handle->response_info.reason_phrase == NULL)
            {
                result = GlobusXIOErrorMemory("reason_phrase");
                break;
            }

            if (save_str)
            {
                globus_libc_free(save_str);
            }
            break;
        case GLOBUS_XIO_HTTP_HANDLE_SET_RESPONSE_HTTP_VERSION:
            if (http_handle->target_info.is_client)
            {
                result = GlobusXIOErrorParameter("handle");
                break;
            }

            if (http_handle->send_state != GLOBUS_XIO_HTTP_STATUS_LINE)
            {
                result = GlobusXIOErrorParameter("handle");
                break;
            }

            http_handle->response_info.http_version =
                    va_arg(ap, globus_xio_http_version_t);
            break;
        case GLOBUS_XIO_HTTP_HANDLE_SET_END_OF_ENTITY:
            result = globus_i_xio_http_set_end_of_entity(http_handle);

            break;

        case GLOBUS_XIO_HTTP_HANDLE_SET_REQUEST_HEADER:
            in_header_name = va_arg(ap, char *);
            if (in_header_name == NULL)
            {
                result = GlobusXIOErrorParameter("name");
                break;
            }

            in_header_value = va_arg(ap, char *);
            if (in_header_value == NULL)
            {
                result = GlobusXIOErrorParameter("value");
                break;
            }

            result = globus_i_xio_http_header_info_set_header(
                    &http_handle->request_info.headers,
                    in_header_name,
                    in_header_value);
            break;

        default:
            result = GlobusXIOErrorParameter("cmd");
            break;
    }
    globus_mutex_unlock(&http_handle->mutex);
    return result;
}
Ejemplo n.º 22
0
static globus_result_t
globus_l_xio_telnet_open(
    const globus_xio_contact_t *        contact_info,
    void *                              driver_link,
    void *                              driver_attr,
    globus_xio_operation_t              op)
{
    globus_result_t                     res;
    globus_l_xio_telnet_attr_t *       attr;
    globus_l_xio_telnet_handle_t *     handle;
    GlobusXIOName(globus_l_xio_telnet_open);

    /* decide what attr to use */
    if(driver_attr != NULL)
    {
        attr = (globus_l_xio_telnet_attr_t *) driver_attr;
    }
    else if(driver_link != NULL)
    {
        attr = (globus_l_xio_telnet_attr_t *) driver_link;
    }
    else
    {
        /* default */
        attr = NULL;
    }

    handle = (globus_l_xio_telnet_handle_t *) globus_calloc(
        sizeof(globus_l_xio_telnet_handle_t), 1);
    if(handle == NULL)
    {
        res = GlobusXIOErrorMemory("handle");
        goto error_handle_alloc;
    }

    if(attr != NULL && attr->force_server)
    {
        handle->client = GLOBUS_FALSE;
    }
    else
    {       
        handle->client = driver_link ? GLOBUS_FALSE : GLOBUS_TRUE;
    }

    handle->read_buffer_length = GLOBUS_L_XIO_TELNET_DEFAULT_BUFFER_SIZE;
    handle->read_buffer = globus_malloc(handle->read_buffer_length);
    if(handle->read_buffer == NULL)
    {
        res = GlobusXIOErrorMemory("buffer");
        goto error_buffer_alloc;
    }
    globus_mutex_init(&handle->mutex, NULL);
    globus_fifo_init(&handle->write_q);

    handle->create_buffer_mode = attr 
        ? attr->create_buffer_mode : GLOBUS_FALSE;

    res = globus_xio_driver_pass_open(
        op,
        contact_info,
        globus_l_xio_telnet_open_cb,
        handle);
    if(res != GLOBUS_SUCCESS)
    {
        goto error_pass;
    }

    return GLOBUS_SUCCESS;
error_pass:
    globus_free(handle->read_buffer);
    globus_mutex_destroy(&handle->mutex);
    globus_fifo_destroy(&handle->write_q);
error_buffer_alloc:
    globus_free(handle);
error_handle_alloc:
    return res;
}
/* if waitforbytes == 0 and iov[0].iov_len == 0
 * behave like select()... ie notify when data ready
 */
globus_result_t
globus_l_xio_system_socket_register_read(
    globus_xio_operation_t              op,
    globus_xio_system_socket_handle_t   handle,
    const globus_xio_iovec_t *          u_iov,
    int                                 u_iovc,
    globus_size_t                       waitforbytes,
    globus_size_t                       nbytes,
    int                                 flags,
    globus_sockaddr_t *                 out_from,
    globus_xio_system_data_callback_t   callback,
    void *                              user_arg)
{
    globus_result_t                     result;
    globus_i_xio_system_op_info_t *     op_info;
    struct iovec *                      iov;
    int                                 iovc;
    GlobusXIOName(globus_l_xio_system_socket_register_read);
    
    GlobusXIOSystemDebugEnterFD(handle->socket);
    GlobusXIOSystemDebugPrintf(
        GLOBUS_I_XIO_SYSTEM_DEBUG_DATA,
        ("[%s] Waiting for %ld bytes\n", _xio_name, (long) waitforbytes));
    
    GlobusIXIOSystemAllocOperation(op_info);
    if(!op_info)
    {
        result = GlobusXIOErrorMemory("op_info");
        goto error_op_info;
    }
    
    GlobusIXIOSystemAllocIovec(u_iovc, iov);
    if(!iov)
    {
        result = GlobusXIOErrorMemory("iov");
        goto error_iovec;
    }
    
    GlobusIXIOUtilTransferIovec(iov, u_iov, u_iovc);
    iovc = u_iovc;
    
    op_info->type = GLOBUS_I_XIO_SYSTEM_OP_READ;
    op_info->sop.data.start_iov = iov;
    op_info->sop.data.start_iovc = iovc;
    
    GlobusIXIOUtilAdjustIovec(iov, iovc, nbytes);
    op_info->sop.data.iov = iov;
    op_info->sop.data.iovc = iovc;
    op_info->sop.data.addr = out_from;
    op_info->sop.data.flags = flags;
    
    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.data.callback = callback;
    op_info->waitforbytes = waitforbytes;
    op_info->nbytes = nbytes;
    
    result = globus_l_xio_win32_socket_register_read(handle, op_info);
    if(result != GLOBUS_SUCCESS)
    {
        result = GlobusXIOErrorWrapFailed(
            "globus_l_xio_win32_socket_register_read", result);
        goto error_register;
    }

    GlobusXIOSystemDebugExitFD(handle->socket);
    return GLOBUS_SUCCESS;

error_register:
    GlobusIXIOSystemFreeIovec(u_iovc, op_info->sop.data.start_iov);
error_iovec:
    GlobusIXIOSystemFreeOperation(op_info);
error_op_info:
    GlobusXIOSystemDebugExitWithErrorFD(handle->socket);
    return result;
}
/**
 * Write the response to an HTTP request
 * @ingroup globus_i_xio_http_server
 *
 * Generates an HTTP response line from a handle, and passes it to the
 * transport. The globus_l_xio_http_server_write_response_callback() will
 * be called once the transport has sent the response.
 *
 * This call may be triggered by either the first write on a server handle,
 * or by calling the #GLOBUS_XIO_HTTP_HANDLE_SET_END_OF_ENTITY handle
 * control function.
 *
 * Called with my mutex lock.
 *
 * @param http_handle
 *     Handle associated with this HTTP stream.
 * @param iovec
 *     Array of globus_xio_iovec_t structs associated with the user's write.
 * @param iovec_count
 *     Length of the @a iovec array. If this is zero, we assume that the
 *     response is being generated by the
 *     #GLOBUS_XIO_HTTP_HANDLE_SET_END_OF_ENTITY control.
 * @param op
 *     Operation associated with the write. If this is NULL (in the case
 *     of the GLOBUS_XIO_HTTP_HANDLE_SET_END_OF_ENTITY control), one
 *     will be created in this function.
 *
 * This function returns GLOBUS_SUCCESS, GLOBUS_XIO_ERROR_MEMORY, or an
 * error result from globus_xio_driver_operation_create(), or
 * globus_xio_driver_pass_write().
 *
 * @retval GLOBUS_SUCCESS
 *     Response was passed to the transport for writing. If this was generated
 *     by a user writing data, then the write will occur after the 
 *     globus_l_xio_http_server_write_response_callback() has been called.
 * @retval GLOBUS_XIO_ERROR_MEMORY
 *     Unable to compose the response due to memory constraints.
 */
globus_result_t
globus_i_xio_http_server_write_response(
    globus_i_xio_http_handle_t *        http_handle,
    const globus_xio_iovec_t *          iovec,
    int                                 iovec_count,
    globus_xio_operation_t              op)
{
    globus_result_t                     result;
    globus_fifo_t                       iovecs;
    const char *                        str;
    char                                code_str[5];
    globus_xio_iovec_t *                iov;
    int                                 rc;
    int                                 i;
    int                                 send_size;
    char *                              size_buffer = NULL;
    globus_bool_t                       free_op = GLOBUS_FALSE;
    globus_xio_http_header_t *          current_header;
    GlobusXIOName(globus_i_xio_server_write_response);

    globus_assert(http_handle->send_state == GLOBUS_XIO_HTTP_STATUS_LINE);
    rc = globus_fifo_init(&iovecs);

    if (rc != GLOBUS_SUCCESS)
    {
        result = GlobusXIOErrorMemory("iovecs");

        goto error_exit;
    }

    /* Compose HTTP Response:
     * HTTP-Version SP Status-Code SP Reason-Phrase CRLF
     */
    if (http_handle->response_info.http_version == GLOBUS_XIO_HTTP_VERSION_1_0)
    {
        str = "HTTP/1.0 ";
    }
    else
    {
        http_handle->response_info.http_version = GLOBUS_XIO_HTTP_VERSION_1_1;
        str = "HTTP/1.1 ";
    }
    GLOBUS_XIO_HTTP_COPY_BLOB(&iovecs, str, 9, free_iovecs_error);

    sprintf(code_str, "%d ", http_handle->response_info.status_code);
    GLOBUS_XIO_HTTP_COPY_BLOB(&iovecs, code_str, 4, free_iovecs_error);

    if (http_handle->response_info.reason_phrase != NULL)
    {
        str = http_handle->response_info.reason_phrase;
    }
    else
    {
        str = globus_i_xio_http_lookup_reason(
                http_handle->response_info.status_code);
    }

    GLOBUS_XIO_HTTP_COPY_BLOB(&iovecs, str, strlen(str), free_iovecs_error);
    GLOBUS_XIO_HTTP_COPY_BLOB(&iovecs, "\r\n", 2, free_iovecs_error);

    current_header = globus_hashtable_first(
            &http_handle->response_info.headers.headers);

    while (current_header)
    {
        GLOBUS_XIO_HTTP_COPY_BLOB(&iovecs,
                current_header->name,
                strlen(current_header->name),
                free_iovecs_error);

        GLOBUS_XIO_HTTP_COPY_BLOB(&iovecs,
                ": ",
                2,
                free_iovecs_error);

        GLOBUS_XIO_HTTP_COPY_BLOB(&iovecs,
                current_header->value,
                strlen(current_header->value),
                free_iovecs_error);

        GLOBUS_XIO_HTTP_COPY_BLOB(&iovecs,
                "\r\n",
                2,
                free_iovecs_error);
        current_header = globus_hashtable_next(
                &http_handle->response_info.headers.headers);
    }

    /*
     * Special headers we generate.
     */
    if (GLOBUS_I_XIO_HTTP_HEADER_IS_CONNECTION_CLOSE(
                &http_handle->response_info.headers) ||
            (http_handle->request_info.http_version ==
                GLOBUS_XIO_HTTP_VERSION_1_0) ||
            (http_handle->response_info.headers.transfer_encoding
                == GLOBUS_XIO_HTTP_TRANSFER_ENCODING_IDENTITY &&
             GLOBUS_I_XIO_HTTP_HEADER_IS_CONTENT_LENGTH_SET(
                &http_handle->response_info.headers)))
    {
        http_handle->response_info.headers.flags |= 
                GLOBUS_I_XIO_HTTP_HEADER_CONNECTION_CLOSE;

        GLOBUS_XIO_HTTP_COPY_BLOB(&iovecs,
                "Connection: close\r\n",
                19,
                free_iovecs_error);
    }
    if (iovec_count > 0)
    {
        /*
         * We are sending a body, so we'll set the appropriate entity-related
         * headers
         */
        if (http_handle->request_info.http_version
                == GLOBUS_XIO_HTTP_VERSION_1_0 ||
            (http_handle->response_info.headers.transfer_encoding
                == GLOBUS_XIO_HTTP_TRANSFER_ENCODING_IDENTITY &&
             GLOBUS_I_XIO_HTTP_HEADER_IS_CONTENT_LENGTH_SET(
                     &http_handle->response_info.headers)))
        {
            http_handle->response_info.headers.transfer_encoding
                = GLOBUS_XIO_HTTP_TRANSFER_ENCODING_IDENTITY;
            /* Transfer-Encoding mustn't be sent to a HTTP/1.0 client */
            if (http_handle->request_info.http_version
                != GLOBUS_XIO_HTTP_VERSION_1_0)
            {
                GLOBUS_XIO_HTTP_COPY_BLOB(&iovecs,
                        "Transfer-Encoding: identity\r\n",
                        29,
                        free_iovecs_error);
            }
            /*
             * When we know the content-length beforehand we can set it here,
             * otherwise, we will use the connection: close header
             */
            if (GLOBUS_I_XIO_HTTP_HEADER_IS_CONTENT_LENGTH_SET(
                    &http_handle->response_info.headers))
            {
                GLOBUS_XIO_HTTP_COPY_BLOB(&iovecs,
                        "Content-Length: ",
                        16,
                        free_iovecs_error);

                size_buffer = globus_common_create_string(
                        "%lu\r\n",
                        (unsigned long)
                            http_handle->response_info.headers.content_length);

                if (size_buffer == NULL)
                {
                    result = GlobusXIOErrorMemory("iovec.iov_base");

                    goto free_iovecs_error;
                }
                GLOBUS_XIO_HTTP_COPY_BLOB(&iovecs,
                        size_buffer,
                        strlen(size_buffer),
                        free_iovecs_error);

                free(size_buffer);

                size_buffer = NULL;
            }
        }
        else
        {
            http_handle->response_info.headers.transfer_encoding
                = GLOBUS_XIO_HTTP_TRANSFER_ENCODING_CHUNKED;
            GLOBUS_XIO_HTTP_COPY_BLOB(&iovecs,
                    "Transfer-Encoding: chunked\r\n",
                    28,
                    free_iovecs_error);
        }
    }
    GLOBUS_XIO_HTTP_COPY_BLOB(&iovecs, "\r\n", 2, free_iovecs_error);

    http_handle->header_iovcnt = globus_fifo_size(&iovecs);
    http_handle->header_iovec = globus_libc_malloc(
            http_handle->header_iovcnt * sizeof(globus_xio_iovec_t));
    if (http_handle->header_iovec == NULL)
    {
        goto free_iovecs_error;
    }

    /* Convert fifo to iovec array, counting up size for wait_for_nbytes
     * parameter to globus_xio_driver_pass_write.
     */
    for (i = 0, send_size = 0; i < http_handle->header_iovcnt; i++)
    {
        iov = globus_fifo_dequeue(&iovecs);

        globus_assert(iov != NULL);

        http_handle->header_iovec[i].iov_base = iov->iov_base;
        http_handle->header_iovec[i].iov_len = iov->iov_len;

        send_size += iov->iov_len;

        globus_libc_free(iov);
    }

    if (op == NULL)
    {
        result = globus_xio_driver_operation_create(
                &op,
                http_handle->handle);

        free_op = GLOBUS_TRUE;
        if (result != GLOBUS_SUCCESS)
        {
            goto free_headers_exit;
        }
    }

    /* Stash user buffer info until we've sent response headers */
    http_handle->write_operation.operation = op;
    http_handle->write_operation.iov = (globus_xio_iovec_t *) iovec;
    http_handle->write_operation.iovcnt = iovec_count;
    http_handle->write_operation.wait_for = 0;

    result = globus_xio_driver_pass_write(
            http_handle->write_operation.operation,
            http_handle->header_iovec,
            http_handle->header_iovcnt,
            send_size,
            globus_l_xio_http_server_write_response_callback,
            http_handle);
    if (result != GLOBUS_SUCCESS)
    {
        goto free_operation_exit;
    }
    globus_fifo_destroy(&iovecs);

    if (iovec_count == 0)
    {
        http_handle->send_state = GLOBUS_XIO_HTTP_EOF;
    }
    else if (http_handle->response_info.headers.transfer_encoding ==
            GLOBUS_XIO_HTTP_TRANSFER_ENCODING_CHUNKED)
    {
        http_handle->send_state = GLOBUS_XIO_HTTP_CHUNK_BODY;
    }
    else
    {
        http_handle->send_state = GLOBUS_XIO_HTTP_IDENTITY_BODY;
    }

    return GLOBUS_SUCCESS;

free_operation_exit:
    if (free_op)
    {
        globus_xio_driver_operation_destroy(
                http_handle->write_operation.operation);
    }
free_headers_exit:
    http_handle->write_operation.operation = NULL;
    http_handle->write_operation.driver_handle = NULL;
    http_handle->write_operation.iov = NULL;
    http_handle->write_operation.iovcnt = 0;
    http_handle->write_operation.wait_for = 0;

    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;

free_iovecs_error:
    while (!globus_fifo_empty(&iovecs))
    {
        iov = globus_fifo_dequeue(&iovecs);

        globus_libc_free(iov->iov_base);
        globus_libc_free(iov);
    }
    globus_fifo_destroy(&iovecs);
    if (size_buffer != NULL)
    {
        free(size_buffer);
    }

error_exit:
    return result;
}
/**
 * Parse an HTTP request
 * @ingroup globus_i_xio_http_server
 *
 * Parses the HTTP request line and then uses globus_i_xio_http_header_parse()
 * to parse the header bock .If the entire request header section is reqad, the
 * boolean pointed to by @a done will be modified to be GLOBUS_TRUE
 *
 * Called with mutex locked.
 *
 * @param http_handle
 * @param done
 *
 * @return
 *     This function returns GLOBUS_SUCCESS, GLOBUS_XIO_HTTP_ERROR_PARSE,  or
 *     GLOBUS_XIO_ERROR_MEMORY. Other errors may be generated from
 *     globus_i_xio_http_header_parse()
 *
 * @retval GLOBUS_SUCCESS
 *     No parsing errors occurred while parsing the status line or headers.
 *     Parsing may still be incomplete, depending on the final value of @a
 *     done.
 * @retval <driver>::GLOBUS_XIO_HTTP_ERROR_PARSE
 *     Parse error reading the HTTP request line
 * @retval GLOBUS_XIO_ERROR_MEMORY
 *     Parsing failed because of memory constraints.
 */
static
globus_result_t
globus_l_xio_http_server_parse_request(
    globus_i_xio_http_handle_t *        http_handle,
    globus_bool_t *                     done)
{
    globus_result_t                     result;
    char *                              eol;
    char *                              current_offset;
    int                                 parsed;
    int                                 rc;
    int                                 http_major;
    int                                 http_minor;
    GlobusXIOName(globus_l_xio_http_server_parse_request);

    if (http_handle->parse_state == GLOBUS_XIO_HTTP_REQUEST_LINE)
    {
        /*
         * Make sure any old request info has been freed so we don't leak here
         * when reusing a handle (or have old headers around)
         */
        globus_i_xio_http_request_destroy(&http_handle->request_info);
        result = globus_i_xio_http_request_init(&http_handle->request_info);

        if (result != GLOBUS_SUCCESS)
        {
            goto error_exit_init;
        }

        /* Parse the request line:
         *
         * Method SP Request-URI SP HTTP-Version CRLF
         */
        current_offset = ((char *) (http_handle->read_buffer.iov_base))
                + http_handle->read_buffer_offset;

        eol = globus_i_xio_http_find_eol(
                current_offset,
                http_handle->read_buffer_valid);
        if (eol == NULL)
        {
            *done = GLOBUS_FALSE;

            return GLOBUS_SUCCESS;
        }
        *eol = '\0';

        rc = sscanf(current_offset, "%*s %n", &parsed);

        if (rc < 0)
        {
            result = GlobusXIOHttpErrorParse("Method", current_offset);

            goto error_exit;
        }

        http_handle->request_info.method = globus_libc_malloc(parsed+1);
        if (http_handle->request_info.method == NULL)
        {
            result = GlobusXIOErrorMemory("method");

            goto error_exit;
        }

        rc = sscanf(current_offset, "%s ", http_handle->request_info.method);
        globus_assert(rc == 1);

        current_offset += parsed;
        
        rc = sscanf(current_offset, "%*s %n", &parsed);
        if (rc < 0)
        {
            result = GlobusXIOHttpErrorParse("Request-URI", current_offset);

            goto error_exit;
        }

        http_handle->request_info.uri = globus_libc_malloc(parsed+1);
        if (http_handle->request_info.uri == NULL)
        {
            result = GlobusXIOErrorMemory("uri");

            goto error_exit;
        }
        rc = sscanf(current_offset, "%s ", http_handle->request_info.uri);
        globus_assert(rc == 1);

        current_offset += parsed;

        rc = sscanf(current_offset, "HTTP/%d.%d", &http_major, &http_minor);

        if (rc < 2)
        {
            result = GlobusXIOHttpErrorParse("Http-Version", current_offset);

            goto error_exit;
        }

        http_handle->request_info.http_version =
            globus_i_xio_http_guess_version(http_major, http_minor);

        /* Set current offset to end of CRLF at the end of this line */
        current_offset = eol+2;

        parsed = current_offset - ((char *) http_handle->read_buffer.iov_base
                + http_handle->read_buffer_offset);
        http_handle->read_buffer_valid -= parsed;
        http_handle->read_buffer_offset += parsed;
        http_handle->parse_state = GLOBUS_XIO_HTTP_HEADERS;
    }
    return globus_i_xio_http_header_parse(http_handle, done);

error_exit:
    parsed = current_offset - ((char *) http_handle->read_buffer.iov_base
                + http_handle->read_buffer_offset);

    /* Chop of what we managed to parse from the buffer */
    http_handle->read_buffer_valid -= parsed;
    http_handle->read_buffer_offset += parsed;

error_exit_init:
    return result;
}
Ejemplo n.º 26
0
globus_result_t
globus_xio_data_descriptor_init( 
    globus_xio_data_descriptor_t *      data_desc,
    globus_xio_handle_t                 handle)
{
    globus_result_t                     res = GLOBUS_SUCCESS;
    globus_i_xio_op_t *                 op;
    globus_i_xio_context_t *            context;
    GlobusXIOName(globus_xio_data_descriptor_init);

    GlobusXIODebugEnter();
    
    if(data_desc == NULL)
    {
        res = GlobusXIOErrorParameter("data_desc");
        goto err_parm;
    }
    if(handle == NULL)
    {
        res = GlobusXIOErrorParameter("handle");
        goto err;
    }

    context = handle->context;
    globus_mutex_lock(&context->mutex);
    {
        GlobusXIOOperationCreate(op, context);
        if(op != NULL)
        {
            op->type = GLOBUS_XIO_OPERATION_TYPE_DD;
            handle->ref++;
            GlobusXIODebugPrintf(
                    GLOBUS_XIO_DEBUG_INFO_VERBOSE,
                    (_XIOSL("[globus_xio_data_descriptor_init] :: handle ref at %d.\n"), handle->ref));

            op->_op_handle = handle;
            op->ref = 1;
            op->is_user_dd = GLOBUS_TRUE;
        }
        else
        {
            res = GlobusXIOErrorMemory("xio_dd");
        }
    }
    globus_mutex_unlock(&context->mutex);

    if(res != GLOBUS_SUCCESS)
    {
        goto err;
    }
    *data_desc = op;
    
    globus_mutex_lock(&globus_i_xio_mutex);
    {
        globus_list_insert(&globus_i_xio_outstanding_dds_list, op);
    }
    globus_mutex_unlock(&globus_i_xio_mutex);
    
    GlobusXIODebugExit();
    return GLOBUS_SUCCESS;

  err:
    *data_desc = NULL;
  err_parm:
    GlobusXIODebugExitWithError();
    return res;
}
void
globus_i_xio_http_server_read_request_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;
    globus_bool_t                       done;
    globus_result_t                     eof_result = GLOBUS_SUCCESS;
    globus_i_xio_http_attr_t *          descriptor;
    globus_bool_t                       registered_again = GLOBUS_FALSE;
    GlobusXIOName(globus_i_xio_http_server_read_request_callback);

    globus_mutex_lock(&http_handle->mutex);

    if (result != GLOBUS_SUCCESS)
    {
        if (globus_xio_error_is_eof(result))
        {
            eof_result = result;
        }
        else
        {
            goto error_exit;
        }
    }

    /* Haven't parsed request and headers yet */
    http_handle->read_buffer_valid += nbytes;

    result = globus_l_xio_http_server_parse_request(http_handle, &done);
    if (result == GLOBUS_SUCCESS && !done)
    {
        goto reregister_read;
    }
    else if (result != GLOBUS_SUCCESS)
    {
        goto error_exit;
    }

    /* Determine whether we should expect an entity along with the
     * request
     */
    if ((http_handle->request_info.http_version == GLOBUS_XIO_HTTP_VERSION_1_1)
            && (http_handle->request_info.headers.transfer_encoding
            == GLOBUS_XIO_HTTP_TRANSFER_ENCODING_CHUNKED))
    {
        http_handle->parse_state = GLOBUS_XIO_HTTP_CHUNK_LINE;
    }
    else if (GLOBUS_I_XIO_HTTP_HEADER_IS_CONTENT_LENGTH_SET(
                &http_handle->request_info.headers))
    {
        http_handle->parse_state = GLOBUS_XIO_HTTP_IDENTITY_BODY;
    }

    if (GLOBUS_I_XIO_HTTP_HEADER_IS_CONNECTION_CLOSE(
                &http_handle->request_info.headers))
    {
        http_handle->response_info.headers.flags |=
                GLOBUS_I_XIO_HTTP_HEADER_CONNECTION_CLOSE;
    }

    http_handle->send_state = GLOBUS_XIO_HTTP_STATUS_LINE;

    descriptor = globus_xio_operation_get_data_descriptor(op, GLOBUS_TRUE);
    if (descriptor == NULL)
    {
        result = GlobusXIOErrorMemory("descriptor");
        
        goto error_exit;
    }
    globus_i_xio_http_request_destroy(&descriptor->request);
    result = globus_i_xio_http_request_copy(
            &descriptor->request,
            &http_handle->request_info);
    if (result != GLOBUS_SUCCESS)
    {
        goto error_exit;
    }

    result = globus_i_xio_http_parse_residue(http_handle, &registered_again);

    if ((http_handle->read_operation.wait_for <= 0 && !registered_again) ||
        result != GLOBUS_SUCCESS)
    {
        if (http_handle->response_info.headers.transfer_encoding !=
                GLOBUS_XIO_HTTP_TRANSFER_ENCODING_CHUNKED &&
            GLOBUS_I_XIO_HTTP_HEADER_IS_CONTENT_LENGTH_SET(
                    &http_handle->response_info.headers) &&
            http_handle->response_info.headers.content_length == 0)
        {
            /* Synthesize EOF if we've read all of the entity content */
            result = GlobusXIOErrorEOF();
        }
        /*
         * Either we've read enough, hit end of chunk, no entity was present,
         * or pass to transport failed. Call finished_read
         */
        nbytes = http_handle->read_operation.nbytes;
        globus_libc_free(http_handle->read_operation.iov);
        http_handle->read_operation.iov = NULL;
        http_handle->read_operation.iovcnt = 0;
        http_handle->read_operation.operation = NULL;
        http_handle->read_operation.driver_handle = NULL;
        http_handle->read_operation.nbytes = 0;

        globus_mutex_unlock(&http_handle->mutex);
        
        globus_xio_driver_finished_read(op, result, nbytes);

        return;
    }
    else if (registered_again)
    {
        globus_mutex_unlock(&http_handle->mutex);
        return;
    }

    /* FALLSTHROUGH */
reregister_read:
    globus_assert(op == http_handle->read_operation.operation);
    if (eof_result != GLOBUS_SUCCESS)
    {
        /* Header block wasn't complete before eof */
        result = eof_result;
        goto error_exit;
    }
    result = globus_i_xio_http_clean_read_buffer(http_handle);

    if (result != GLOBUS_SUCCESS)
    {
        goto error_exit;
    }

    result = globus_xio_driver_pass_read(
            op,
            &http_handle->read_iovec,
            1,
            1,
            globus_i_xio_http_server_read_request_callback,
            http_handle);

    if (result != GLOBUS_SUCCESS)
    {
        goto error_exit;
    }

    globus_mutex_unlock(&http_handle->mutex);
    return;

error_exit:
    globus_libc_free(http_handle->read_operation.iov);
    http_handle->read_operation.iov = NULL;
    http_handle->read_operation.iovcnt = 0;
    http_handle->read_operation.operation = NULL;
    http_handle->read_operation.driver_handle = NULL;
    http_handle->read_operation.nbytes = 0;
    globus_mutex_unlock(&http_handle->mutex);

    globus_xio_driver_finished_read(op, result, 0);
}
/**
 * Allocate and initialize an HTTP handle
 * @ingroup globus_i_xio_http_handle
 *
 * Creates a new handle with values derived from the attr and target. This
 * is called internally by the HTTP driver's open implementation.
 *
 * @param http_handle
 *     Pointer to an uninitialized handle.
 * @param attr
 *     HTTP attributes associated with open operation.
 * @param target
 *     Target which is being opened.
 *
 * This function may return GLOBUS_SUCCESS, or an error generated by
 * globus_i_xio_http_response_init(), globus_i_xio_http_request_copy(),
 * or globus_i_xio_http_target_copy().
 */
globus_result_t
globus_i_xio_http_handle_init(
    globus_i_xio_http_handle_t *        http_handle,
    globus_i_xio_http_attr_t *          attr,
    globus_i_xio_http_target_t *        target)
{
    globus_result_t                     result;
    int                                 rc;
    GlobusXIOName(globus_i_xio_http_handle_init);

    rc = globus_mutex_init(&http_handle->mutex, NULL);

    if (rc != 0)
    {
        result = GlobusXIOErrorMemory("mutex");
        goto error_exit;
    }

    if (target->is_client && attr != NULL)
    {
        result = globus_i_xio_http_request_copy(
                &http_handle->request_info,
                &attr->request);
    }
    else
    {
        result = globus_i_xio_http_request_init(&http_handle->request_info);
    }

    if (target->is_client)
    {
        http_handle->parse_state = GLOBUS_XIO_HTTP_STATUS_LINE;
        http_handle->send_state = GLOBUS_XIO_HTTP_PRE_REQUEST_LINE;
    }
    else
    {
        http_handle->parse_state = GLOBUS_XIO_HTTP_PRE_REQUEST_LINE;
        http_handle->send_state = GLOBUS_XIO_HTTP_STATUS_LINE;
    }

    if (result != GLOBUS_SUCCESS)
    {
        goto free_mutex_exit;
    }

    result = globus_i_xio_http_response_init(&http_handle->response_info);
    if (result != GLOBUS_SUCCESS)
    {
        goto free_request_exit;
    }

    result = globus_i_xio_http_target_copy(&http_handle->target_info, target);
    if (result != GLOBUS_SUCCESS)
    {
        goto free_response_exit;
    }
    http_handle->header_iovec = NULL;
    http_handle->header_iovcnt = 0;
    http_handle->read_buffer.iov_base = NULL;
    http_handle->read_buffer.iov_len = 0;
    http_handle->close_operation = NULL;
    http_handle->response_read_operation = NULL;
    http_handle->read_operation.iov = NULL;
    http_handle->read_operation.iovcnt = 0;
    http_handle->read_operation.operation = NULL;
    http_handle->read_operation.driver_handle = NULL;
    http_handle->read_operation.nbytes = 0;
    http_handle->write_operation.iov = NULL;
    http_handle->write_operation.iovcnt = 0;
    http_handle->write_operation.operation = NULL;
    http_handle->write_operation.driver_handle = NULL;
    http_handle->write_operation.nbytes = 0;
    http_handle->user_close = GLOBUS_FALSE;
    http_handle->read_response = GLOBUS_FALSE;

    return GLOBUS_SUCCESS;

free_response_exit:
    globus_i_xio_http_response_destroy(&http_handle->response_info);
free_request_exit:
    globus_i_xio_http_request_destroy(&http_handle->request_info);
free_mutex_exit:
    globus_mutex_destroy(&http_handle->mutex);
error_exit:
    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;
}
Ejemplo n.º 30
0
globus_result_t
globus_xio_attr_copy(
    globus_xio_attr_t *                 dst,
    globus_xio_attr_t                   src)
{
    globus_i_xio_attr_t *               xio_attr_src;
    globus_i_xio_attr_t *               xio_attr_dst;
    globus_result_t                     res;
    int                                 ctr;
    int                                 ctr2;
    GlobusXIOName(globus_xio_attr_copy);

    GlobusXIODebugEnter();
    
    if(dst == NULL)
    {
        res = GlobusXIOErrorParameter("dst");
        goto err;
    }

    if(src == NULL)
    {
        res = GlobusXIOErrorParameter("src");
        goto err;
    }

    xio_attr_src = src;

    xio_attr_dst = (globus_i_xio_attr_t *)
            globus_malloc(sizeof(globus_i_xio_attr_t));

    /* check for memory alloc failure */
    if(xio_attr_dst == NULL)
    {
        res = GlobusXIOErrorMemory("xio_attr_dst");
        goto err;
    }
    
    memset(xio_attr_dst, 0, sizeof(globus_i_xio_attr_t));
    xio_attr_dst->entry = (globus_i_xio_attr_ent_t *)
        globus_malloc(sizeof(globus_i_xio_attr_ent_t) *
            GLOBUS_XIO_ATTR_ARRAY_BASE_SIZE);
    if(xio_attr_dst->entry == NULL)
    {
        globus_free(xio_attr_dst);
        res = GlobusXIOErrorMemory("xio_attr_dst->entry");
        goto err;
    }

    memset(xio_attr_dst->entry, 0, 
        sizeof(globus_i_xio_attr_ent_t) * GLOBUS_XIO_ATTR_ARRAY_BASE_SIZE);

    /* copy all general attrs */
    xio_attr_dst->max = xio_attr_src->max;
    xio_attr_dst->ndx = xio_attr_src->ndx;
    xio_attr_dst->space = xio_attr_src->space;
    globus_callback_space_reference(xio_attr_dst->space);

    xio_attr_dst->open_timeout_cb = xio_attr_src->open_timeout_cb;
    xio_attr_dst->open_timeout_period = xio_attr_src->open_timeout_period;
    xio_attr_dst->read_timeout_cb = xio_attr_src->read_timeout_cb;
    xio_attr_dst->read_timeout_period = xio_attr_src->read_timeout_period;
    xio_attr_dst->write_timeout_cb = xio_attr_src->write_timeout_cb;
    xio_attr_dst->write_timeout_period = xio_attr_src->write_timeout_period;
    xio_attr_dst->close_timeout_cb = xio_attr_src->close_timeout_cb;
    xio_attr_dst->close_timeout_period = xio_attr_src->close_timeout_period;
    xio_attr_dst->accept_timeout_cb = xio_attr_src->accept_timeout_cb;
    xio_attr_dst->accept_timeout_period = xio_attr_src->accept_timeout_period;
    xio_attr_dst->cancel_open = xio_attr_src->cancel_open;
    xio_attr_dst->cancel_close = xio_attr_src->cancel_close;
    xio_attr_dst->cancel_read = xio_attr_src->cancel_read;
    xio_attr_dst->cancel_write = xio_attr_src->cancel_write;
    xio_attr_dst->no_cancel = xio_attr_src->no_cancel;
    xio_attr_dst->timeout_arg = xio_attr_src->timeout_arg;
    
    for(ctr = 0; ctr < xio_attr_dst->ndx; ctr++)
    {
        xio_attr_dst->entry[ctr].driver = xio_attr_src->entry[ctr].driver;

        res = xio_attr_dst->entry[ctr].driver->attr_copy_func(
                &xio_attr_dst->entry[ctr].driver_data,
                xio_attr_src->entry[ctr].driver_data);
        if(res != GLOBUS_SUCCESS)
        {
            for(ctr2 = 0; ctr2 < ctr; ctr2++)
            {
                /* ignore result here */
                xio_attr_dst->entry[ctr].driver->attr_destroy_func(
                    xio_attr_dst->entry[ctr].driver_data);
            }
            globus_free(xio_attr_dst->entry);
            globus_free(xio_attr_dst);

            goto err;
        }
    }
    
    globus_mutex_lock(&globus_i_xio_mutex);
    {
        globus_list_insert(&globus_i_xio_outstanding_attrs_list, xio_attr_dst);
    }
    globus_mutex_unlock(&globus_i_xio_mutex);
    
    *dst = xio_attr_dst;

    GlobusXIODebugExit();
    return GLOBUS_SUCCESS;

  err:

    GlobusXIODebugExitWithError();
    return res;
}