globus_fifo_t *
globus_fifo_copy (
    const globus_fifo_t *                                 fifo)
{
    globus_fifo_t *                                 copy;
    struct globus_fifo_s *                          s_copy;
    struct globus_fifo_s *                          s_fifo;

    if (fifo == GLOBUS_NULL) 
		return NULL;
    s_fifo = *fifo;
    if(s_fifo==GLOBUS_NULL) 
		return NULL;

    copy = globus_malloc (sizeof(globus_fifo_t));
    if (copy == NULL) 
		return NULL;

    globus_fifo_init(copy);

    s_copy = *copy;
    s_copy->head = globus_list_copy(s_fifo->head);
    s_copy->tail = s_copy->head;

    while(!globus_list_empty(globus_list_rest(s_copy->tail))) 
    {
        s_copy->tail = globus_list_rest (s_copy->tail);
    }
 
	s_copy->size = s_fifo->size;
	return copy;
}
int
globus_fifo_move(
    globus_fifo_t *				                    fifo_dest,
    globus_fifo_t *				                    fifo_src)
{
    struct globus_fifo_s *                          s_fifo_dest;
    struct globus_fifo_s *                          s_fifo_src;

	if(fifo_dest == GLOBUS_NULL || fifo_src == GLOBUS_NULL)
    {
        return -1;
    }
    globus_fifo_init(fifo_dest);
    s_fifo_dest = *fifo_dest;
    s_fifo_src = *fifo_src;
    if(s_fifo_dest == GLOBUS_NULL || s_fifo_src == GLOBUS_NULL)
    {
        return -1;
    }

    s_fifo_dest->head = s_fifo_src->head;
    s_fifo_dest->tail = s_fifo_src->tail;
    s_fifo_dest->size = s_fifo_src->size;

    s_fifo_src->head = GLOBUS_NULL;
    s_fifo_src->tail = GLOBUS_NULL;
    s_fifo_src->size = 0;

    return 0;
}
/**
 * Create a copy of a restart marker.
 * @ingroup globus_ftp_client_restart_marker
 *
 * This function copies the contents of marker to new_marker.
 *
 * @param new_marker
 *        A pointer to a new restart marker.
 * @param marker
 *        The marker to copy.
 *
 * @see globus_ftp_client_restart_marker_init(),
 * globus_ftp_client_restart_marker_destroy()
 */
globus_result_t
globus_ftp_client_restart_marker_copy(
    globus_ftp_client_restart_marker_t *	new_marker,
    globus_ftp_client_restart_marker_t *	marker)
{
    globus_fifo_t * tmp;
    GlobusFuncName(globus_ftp_client_restart_marker_copy);

    if(new_marker == GLOBUS_NULL)
    {
        return globus_error_put(
		GLOBUS_I_FTP_CLIENT_ERROR_NULL_PARAMETER("new_marker"));
    }
    if(marker == GLOBUS_NULL)
    {
        return globus_error_put(
		GLOBUS_I_FTP_CLIENT_ERROR_NULL_PARAMETER("marker"));
    }

    globus_ftp_client_restart_marker_init(new_marker);

    new_marker->type = marker->type;

    switch(new_marker->type)
    {
    case GLOBUS_FTP_CLIENT_RESTART_NONE:
	break;
    case GLOBUS_FTP_CLIENT_RESTART_STREAM:
	new_marker->stream.offset = marker->stream.offset;
	break;
    case GLOBUS_FTP_CLIENT_RESTART_EXTENDED_BLOCK:

	globus_fifo_init(&new_marker->extended_block.ranges);

	if(globus_fifo_empty(&marker->extended_block.ranges))
	{
	    break;
	}
	tmp = globus_fifo_copy(&marker->extended_block.ranges);

	while(!globus_fifo_empty(tmp))
	{
	    globus_i_ftp_client_range_t *	range;

	    range = (globus_i_ftp_client_range_t *) globus_fifo_dequeue(tmp);

	    globus_ftp_client_restart_marker_insert_range(new_marker,
							  range->offset,
							  range->end_offset);
	}
	
	globus_fifo_destroy(tmp);
	globus_free(tmp);
	break;
    }
    return GLOBUS_SUCCESS;
}
globus_result_t
gfs_i_xio_cp_start(
    gfs_i_xio_cp_handle_t **            cp_h_out,
    globus_fifo_t *                     read_handle_fifo,
    globus_fifo_t *                     write_handle_fifo,
    globus_callback_func_t              complete_cb,
    globus_callback_func_t              update_cb,
    void *                              user_arg)
{
    globus_fifo_t *                     read_q;
    gfs_i_xio_cp_handle_t *             cp_h;

    cp_h = (gfs_i_xio_cp_handle_t *)
        globus_calloc(1, sizeof(gfs_i_xio_cp_handle_t));
    cp_h->read_all_q = globus_fifo_copy(net_handle_fifo);
    cp_h->write_all_q = globus_fifo_copy(net_handle_fifo);
    cp_h->write_q = globus_fifo_copy(net_handle_fifo);
    globus_fifo_init(&cp_h->read_buffer_q);
    cp_h->block_size = block_size;
    cp_h->cb = complete_cb;
    cp_h->user_arg = user_arg;
    globus_mutex_init(&cp_h->mutex, NULL);
    cp_h->state = GFS_XIO_CP_STATE_OPEN;
    read_q = globus_fifo_copy(net_handle_fifo);

    cp_h->read_handle_count = globus_fifo_size(cp_h->read_all_q);
    cp_h->write_handle_count = globus_fifo_size(cp_h->write_all_q);

    *cp_h_out = cp_h;

    globus_mutex_lock(&cp_h->mutex);
    {
        while(!globus_fifo_empty(read_q))
        {
            xio_h = (globus_xio_handle_t) globus_fifo_dequeue(cp_h->read_q);

            read_buf = (gfs_l_xio_read_buffer_t *)
                globus_calloc(sizeof(gfs_l_xio_read_buffer_t)+block_size, 1);
            read_buf->block_size = block_size;
            read_buf->whos_my_daddy = cp_h;

            gfs_l_xio_cp_post_read(xio_h, read_buf);
        }
    }
    globus_mutex_unlock(&cp_h->mutex);

    globus_fifo_destroy(read_q);

    return GLOBUS_SUCCESS;
}
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;
}
int 
globus_args_scan(
    int  *                                argc,
    char ***                              argv,
    int                                   option_count,
    globus_args_option_descriptor_t  *    options,
    const char *                          name,
    const globus_version_t *              version,
    const char *                          oneline_usage,
    const char *                          long_usage,
    globus_list_t **                      options_found,
    char **                               error_msg    )
{
    static globus_mutex_t   args_mutex;
    static globus_bool_t    args_mutex_initialized = GLOBUS_FALSE;
    int                     rc;
    int                     my_argc;
    char *                  my_arg;
    int                     len;
    int                     i;
    char **                 alias;
    char **                 arglist;
    globus_fifo_t           fifo;
    globus_bool_t           done;
    globus_bool_t           found;

    globus_libc_lock();
    if (!args_mutex_initialized)
    {
	globus_mutex_init(&args_mutex,
			  (globus_mutexattr_t *) GLOBUS_NULL);
	args_mutex_initialized = GLOBUS_TRUE;
    }
    globus_libc_unlock();    

    globus_mutex_lock(&args_mutex);

    rc = GLOBUS_SUCCESS;
    globus_fifo_init(&fifo);
    *options_found = GLOBUS_NULL;
    if (error_msg)
	*error_msg = GLOBUS_NULL;

    /* precheck : are the options correct? */
    rc = globus_l_args_check_options(option_count, options, error_msg);
    done = (rc==GLOBUS_SUCCESS) ? GLOBUS_FALSE : GLOBUS_TRUE;

    my_argc=1;
    while (!done)
    {
        /* any more options? */ 
        if (my_argc == *argc)
        {
            done=GLOBUS_TRUE;
            continue;
        }

        my_arg = (*argv)[my_argc];
        len = strlen(my_arg);

        if (my_arg[0]!='-' || len<2)
        {
	    /* unrecognized option */
            done=GLOBUS_TRUE;
            continue;
        }

        /* '--*' is a special case : if '*' is non-null, it's an error.
            Otherwise, it signals end of parsing. */
        if (!strncmp(my_arg,"--",2))
        {
            if (len == 2)  /* end of parsing */
            {
                /* next argument is first "unrecognized" option */
                my_argc++;
            }
            else
            {
                rc = GLOBUS_FAILURE;
                globus_l_args_create_error_msg(
		    error_msg,
		    my_argc,
		    my_arg,
		    _GCSL("double-dashed option syntax is not allowed"),
		    oneline_usage                               );
            }
            done = GLOBUS_TRUE;
            continue;
        }

        /* four specials : -help, -usage, -version, -versions */
        if (!strcmp("-help",my_arg))
        {
            globus_l_args_create_msg( error_msg ,
				      (char *) long_usage );
	    rc = GLOBUS_ARGS_HELP;
            done = GLOBUS_TRUE;
            continue;
        }
        if(!strcmp("-usage",my_arg))
        {
            globus_l_args_create_msg( error_msg ,
				      (char *) oneline_usage );
	    rc = GLOBUS_ARGS_HELP;
            done = GLOBUS_TRUE;
            continue;
        }
        if (!strcmp("-version",my_arg))
        {
            globus_version_print(
                name,
                version,
                stderr,
                GLOBUS_FALSE);
                
	    rc = GLOBUS_ARGS_VERSION;
            done = GLOBUS_TRUE;
            continue;
        }
        if (!strcmp("-versions",my_arg))
        {
	    globus_version_print(
                name,
                version,
                stderr,
                GLOBUS_TRUE);
            
            globus_module_print_activated_versions(stderr, GLOBUS_TRUE);
                
	    rc = GLOBUS_ARGS_VERSION;
            done = GLOBUS_TRUE;
            continue;
        }
        
        /* is it a known flag? */
        found=GLOBUS_FALSE;
        for (i=0; !found && !rc && i<option_count; i++)
        {
            for (alias=options[i].names; !found && !rc && *alias; alias++)
            {
                if (!strcmp(my_arg, *alias))
                {
                    found = GLOBUS_TRUE;
                    arglist = GLOBUS_NULL;
                    if (options[i].arity > 0)
                    {
                        if (my_argc+options[i].arity >= *argc)
                        {
                            globus_l_args_create_error_msg(
				error_msg,
				my_argc,
				my_arg,
				_GCSL("not enough arguments"),
				oneline_usage  );

                            rc = GLOBUS_FAILURE;
                            continue;
                        }

			rc = globus_l_args_validate( &options[i],
						     my_argc,
						     (*argv),
						     &arglist,
						     oneline_usage,
						     error_msg    );
                    } /* if */

                    if (rc==GLOBUS_SUCCESS)
                    {
			/* option successfully detected: add it */
                        globus_l_args_add_instance( &fifo,
                                                    &options[i],
                                                    arglist );
                        my_argc += 1+options[i].arity;
                    }
                }           /* strcmp(my_arg,*alias)) */
            }               /* alias */
        }                   /* i */
	if (!found)
	{
	    /* my_arg contains an unregistered option */
	    rc = GLOBUS_FAILURE;
	    globus_l_args_create_error_msg( error_msg,
					    my_argc,
					    my_arg,
					    _GCSL("unknown option"),
					    oneline_usage  );
	}
        if (rc!=GLOBUS_SUCCESS)
        {
            done = GLOBUS_TRUE;
            continue;
        }
    } /* while (!done) */

    if (rc==GLOBUS_SUCCESS)
    {
	/* if successful, return number of options found */
	rc = globus_fifo_size(&fifo);
        *options_found = globus_fifo_convert_to_list( &fifo );

	/* modify argc/argv */
	if (my_argc>1)
	{
	    for (i = my_argc; i < *argc; i++)
		(*argv)[i-my_argc+1] = (*argv)[i];

	    *argc -= my_argc - 1;
	}
    }
    
    globus_fifo_destroy(&fifo);
    globus_mutex_unlock(&args_mutex);
    return rc;
}
int
main(
    int						argc,
    char *					argv[])
{
    int						i;
    int						nitems;
    long					thread_id;
    globus_thread_t                             thread;

    globus_thread_set_model("pthread");
    globus_module_activate(GLOBUS_COMMON_MODULE);

    if (argc != 4)
    {
        globus_stdio_lock();
        {
            printf("\nusage: globus_thread_test "
                   "nproducers nconsumers nitems\n\n");
        }
        globus_stdio_unlock();

        exit(1);
    }

    nproducers = atoi(argv[1]);
    nconsumers = atoi(argv[2]);
    nitems = atoi(argv[3]);

    /*
     * Initialize queue and queue concurrency control structures
     */
    globus_fifo_init(&queue);
    globus_mutex_init(&queue_mutex, (globus_mutexattr_t *) GLOBUS_NULL);
    globus_cond_init(&queue_cond, (globus_condattr_t *) GLOBUS_NULL);

    /*
     * Initialize shared (common) concurrency control structures
     */
    globus_mutex_init(&common_mutex, (globus_mutexattr_t *) GLOBUS_NULL);
    globus_cond_init(&common_cond, (globus_condattr_t *) GLOBUS_NULL);

    /*
     * Assign a thread id to the main thread so that it's output is uniquely
     * tagged.  Note: we do not use the return value of globus_thread_self()
     * since it could be a pointer or a structure, the latter which is
     * extremely hard to print without knowing the implementation details.
     */
    thread_id_assign();

    thread_id = thread_id_get();

    /*
     * Start producer and consumer threads
     */
    globus_stdio_lock();
    {
        printf("%04ld: main() - starting %d producer and %d consumer threads\n",
               thread_id,
               nproducers,
               nconsumers);
    }
    globus_stdio_unlock();

    for (i = 0 ; i < nproducers ; i ++)
    {
        int					rc;
        int					nitems_per_thread;

        nitems_per_thread = nitems / nproducers +
                            ((i < nitems % nproducers) ? 1 : 0);

        rc =
            globus_thread_create(
                &thread,
                NULL,
                producer,
                (void *) nitems_per_thread);

        if (rc != 0)
        {
            globus_stdio_lock();
            {
                printf("%04ld: main() - ERROR: "
                       "unable to create producer thread %d\n",
                       thread_id,
                       i);
                exit(1);
            }
            globus_stdio_unlock();
        }
    }

    for (i = 0 ; i < nconsumers ; i ++)
    {
        int					rc;
        int					nitems_per_thread;

        nitems_per_thread = nitems / nconsumers +
                            ((i < nitems % nconsumers) ? 1 : 0);

        rc =
            globus_thread_create(
                &thread,
                NULL,
                consumer,
                (void *) nitems_per_thread);

        if (rc != 0)
        {
            globus_stdio_lock();
            {
                printf("%04ld: main() - ERROR: "
                       "unable to create consumer thread %d\n",
                       thread_id,
                       i);
                exit(1);
            }
            globus_stdio_unlock();
        }
    }

    /*
     * Wait for all threads to be started
     */
    wait_for_all();

    globus_stdio_lock();
    {
        printf("%04ld: main() - all threads started\n",
               thread_id);
    }
    globus_stdio_unlock();

    /*
     * Wait for all threads to complete their work
     */
    wait_for_all();

    globus_stdio_lock();
    {
        printf("%04ld: main() - all threads have completed their work\n",
               thread_id);
    }
    globus_stdio_unlock();

    /*
     * Wait for all thread id data to be destroyed
     */
    while (thread_ids_destruct_cnt < nproducers + nconsumers)
    {
        globus_thread_yield();
    }

    globus_stdio_lock();
    {
        printf("%04ld: main() - all threads terminated\n",
               thread_id);
    }
    globus_stdio_unlock();

    globus_cond_destroy(&common_cond);
    globus_mutex_destroy(&common_mutex);

    globus_cond_destroy(&queue_cond);
    globus_mutex_destroy(&queue_mutex);
    globus_fifo_destroy(&queue);

    globus_module_deactivate(GLOBUS_COMMON_MODULE);

    exit(0);
}
static
globus_result_t
globus_l_gfork_child_start(
    gfork_child_handle_t *              out_handle,
    const char *                        in_env_suffix,
    globus_gfork_open_func_t            open_cb,
    globus_gfork_closed_func_t          close_cb,
    globus_gfork_incoming_cb_t          incoming_cb,
    globus_gfork_error_func_t           error_cb,
    void *                              user_arg,
    globus_bool_t                       master)
{
    globus_result_t                     result;
    gfork_i_lib_handle_t *            handle;
    char *                              env;
    char *                              env_suffix;
    int                                 read_fd;
    int                                 write_fd;

    handle = (gfork_i_lib_handle_t *)
             globus_calloc(1, sizeof(gfork_i_lib_handle_t));

    handle->state = GFORK_STATE_OPEN;
    handle->open_cb = open_cb;
    handle->close_cb = close_cb;
    handle->error_cb = error_cb;
    handle->incoming_cb = incoming_cb;
    handle->user_arg = user_arg;
    handle->master = master;
    globus_mutex_init(&handle->mutex, NULL);
    globus_fifo_init(&handle->write_q);

    if(in_env_suffix == NULL)
    {
        env_suffix = "";
    }
    else
    {
        env_suffix = (char *) in_env_suffix;
    }
    env = globus_common_create_string("%s%s", GFORK_CHILD_READ_ENV, env_suffix);
    result = gfork_l_get_env_fd(env, &read_fd);

    globus_free(env);
    if(result != GLOBUS_SUCCESS)
    {
        goto error_read_env;
    }

    env = globus_common_create_string("%s%s",GFORK_CHILD_WRITE_ENV,env_suffix);
    result = gfork_l_get_env_fd(env, &write_fd);
    globus_free(env);
    if(result != GLOBUS_SUCCESS)
    {
        goto error_write_env;
    }

    result = gfork_i_make_xio_handle(&handle->read_xio, read_fd);
    if(result != GLOBUS_SUCCESS)
    {
        goto error_read_convert;
    }
    result = gfork_i_make_xio_handle(&handle->write_xio, write_fd);
    if(result != GLOBUS_SUCCESS)
    {
        goto error_write_convert;
    }

    globus_mutex_lock(&handle->mutex);
    {
        result = globus_xio_register_read(
                     handle->read_xio,
                     (globus_byte_t *)&handle->header,
                     sizeof(gfork_i_msg_header_t),
                     sizeof(gfork_i_msg_header_t),
                     NULL,
                     gfork_l_child_read_header_cb,
                     handle);
        if(result != GLOBUS_SUCCESS)
        {
            goto error_post;
        }
    }
    globus_mutex_unlock(&handle->mutex);

    *out_handle = handle;

    return GLOBUS_SUCCESS;

error_post:
    gfork_l_child_error(handle, result);
    globus_mutex_unlock(&handle->mutex);
error_write_convert:
    globus_xio_close(handle->read_xio, NULL);
error_read_convert:
error_write_env:
error_read_env:
    globus_fifo_destroy(&handle->write_q);
    globus_mutex_destroy(&handle->mutex);
    globus_free(handle);

    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;
}
/**
 * Insert a range into a restart marker
 * @ingroup globus_ftp_client_restart_marker
 *
 * This function updates a restart marker with a new byte range,
 * suitable for using to restart an extended block mode transfer.
 * Adjacent ranges within the marker will be combined into a single
 * entry in the marker.
 *
 * The marker must first be initialized by calling
 * globus_ftp_client_restart_marker_init() or
 * globus_ftp_client_restart_marker_copy().
 *
 * A marker can only hold a range list or a stream offset. Calling
 * this function after calling
 * globus_ftp_client_restart_marker_set_offset() will result in a marker
 * suitable only for use restarting an extended block mode transfer.
 *
 * @param marker
 *        A restart marker
 * @param offset
 *        The starting offset of the range.
 * @param end_offset
 *        The ending offset of the range.
 *
 * @see globus_ftp_client_restart_marker_set_offset()
 * globus_ftp_client_operationattr_set_mode()
 */
globus_result_t
globus_ftp_client_restart_marker_insert_range(
    globus_ftp_client_restart_marker_t *	marker,
    globus_off_t				offset,
    globus_off_t				end_offset)
{
    globus_fifo_t				tmp;
    globus_i_ftp_client_range_t *		range;
    globus_i_ftp_client_range_t *		newrange;
    globus_object_t *				err = GLOBUS_SUCCESS;
    GlobusFuncName(globus_ftp_client_insert_range);

    if(marker == GLOBUS_NULL)
    {
        return globus_error_put(
		GLOBUS_I_FTP_CLIENT_ERROR_NULL_PARAMETER("marker"));
    }
    if(marker->type != GLOBUS_FTP_CLIENT_RESTART_EXTENDED_BLOCK)
    {
	memset(marker,
	       '\0',
	       sizeof(globus_ftp_client_restart_extended_block_t));

	marker->type = GLOBUS_FTP_CLIENT_RESTART_EXTENDED_BLOCK;
	globus_fifo_init(&marker->extended_block.ranges);
    }
    globus_fifo_move(&tmp, &marker->extended_block.ranges);

    while(!globus_fifo_empty(&tmp))
    {
	range = globus_fifo_dequeue(&tmp);
	if(offset <= range->offset)
	{
	    if(end_offset+1 < range->offset)
	    {
		newrange = globus_malloc(sizeof(globus_i_ftp_client_range_t));
		if(newrange == NULL)
		{
		    err = GLOBUS_I_FTP_CLIENT_ERROR_OUT_OF_MEMORY();
		    if(!err)
			err = GLOBUS_ERROR_NO_INFO;

		    goto copy_rest;
		}
		newrange->offset = offset;
		newrange->end_offset = end_offset;

		globus_fifo_enqueue(&marker->extended_block.ranges, newrange);
		globus_fifo_enqueue(&marker->extended_block.ranges, range);
		goto copy_rest;
	    }
	    else if(end_offset+1 == range->offset)
	    {
		end_offset = range->end_offset;
		globus_libc_free(range);
	    }
	    else
	    {
		/* weird.... overlapping data */
		if(end_offset < range->end_offset)
		{
		    end_offset = range->end_offset;
		}
		globus_libc_free(range);
	    }
	}
	else
	{
	    if(range->end_offset < offset - 1)
	    {
		globus_fifo_enqueue(&marker->extended_block.ranges, range);
	    }
	    else if(range->end_offset >= offset - 1)
	    {
		offset = range->offset;
		if(end_offset < range->end_offset)
		{
		    end_offset = range->end_offset;
		}
		globus_libc_free(range);
	    }
	    else
	    {
		globus_fifo_enqueue(&marker->extended_block.ranges, range);
	    }
	}
    }

    newrange = globus_malloc(sizeof(globus_i_ftp_client_range_t));
    if(newrange == GLOBUS_NULL)
    {
	err = GLOBUS_I_FTP_CLIENT_ERROR_OUT_OF_MEMORY();
	if(!err)
	    err = GLOBUS_ERROR_NO_INFO;

	goto copy_rest;
    }
    newrange->offset = offset;
    newrange->end_offset = end_offset;
    globus_fifo_enqueue(&marker->extended_block.ranges, newrange);
copy_rest:
    while(! globus_fifo_empty(&tmp))
    {
	globus_fifo_enqueue(&marker->extended_block.ranges,
			    globus_fifo_dequeue(&tmp));
    }
    globus_fifo_destroy(&tmp);
    
    return err ? globus_error_put(err) : GLOBUS_SUCCESS;
}
/**
 * Initialize a gass_transfer request handle.
 *
 * This function creates a #globus_gass_transfer_request_struct_t and
 * associates it with a #gass_transfer_request_t handle. The structure
 * is initialized with the information passed as the arguments to the
 * function.
 *
 * @note This function must be called with the request handle mutex lock.
 *
 * @param request
 *        The request handle to initialize. If this function is successful, 
 *        the value pointed to by this will be initialized to the new
 *        handle id; otherwise, the it will be set to 
 *        GLOBUS_NULL_HANDLE.
 * @param attr
 *        The request attributes to use to create the handle. If non-NULL,
 *        they are copied into the request structure.
 * @param url
 *        An URL string containing the location of the file to access. A
 *        copy of this is stored in the request handle.
 * @param type
 *        The type of file transfer that this request will be used for.
 * @param callback
 *        The callback function to be called once the request is in the
 *        ready state.
 * @param user_arg
 *        User-supplied argument to the callback function.
 *
 * @retval void
 */
void
globus_i_gass_transfer_request_init(
    globus_gass_transfer_request_t *            request,
    globus_gass_transfer_requestattr_t *        attr,
    char *                                      url,
    globus_gass_transfer_request_type_t         type,
    globus_gass_transfer_callback_t             callback,
    void *                                      user_arg)
{
    globus_gass_transfer_request_struct_t *	req;

    req = globus_malloc(sizeof(globus_gass_transfer_request_struct_t));
    if(req == GLOBUS_NULL)
    {
	goto error_exit;
    }

    if(url)
    {
	req->url = globus_libc_strdup(url);
        if(req->url == GLOBUS_NULL)
        {
	    goto free_req;
        }
    }
    else
    {
	req->url = GLOBUS_NULL;
    }
    req->type			= type;
    req->status			= GLOBUS_GASS_TRANSFER_REQUEST_STARTING;
    req->referral_url		= GLOBUS_NULL;
    req->referral_count		= 0;
    req->callback		= callback;
    req->callback_arg		= user_arg;
    req->proto			= GLOBUS_NULL;
    req->subject		= GLOBUS_NULL;
    req->denial_reason		= 0;
    req->denial_message		= GLOBUS_NULL;
    req->handled_length		= 0;
    req->posted_length		= 0;
    req->fail_callback		= GLOBUS_NULL;
    req->client_side		= GLOBUS_FALSE;
    req->user_pointer		= GLOBUS_NULL;

    globus_fifo_init(&req->pending_data);
    if(attr)
    {
	if(*attr)
	{
	    req->attr = globus_object_copy(*attr);
	    if(req->attr == GLOBUS_NULL)
	    {
	        goto free_fifo;
	    }
	}
	else
	{
	    req->attr = GLOBUS_NULL;
	}
    }
    else
    {
	req->attr = GLOBUS_NULL;
    }

    *request = globus_handle_table_insert(&globus_i_gass_transfer_request_handles,
					  (void *) req,
					  2);
    globus_list_insert(&globus_i_gass_transfer_requests,
		       (void *) (intptr_t) (*request));
    
    return;

  free_fifo:
    globus_fifo_destroy(&req->pending_data);
    globus_free(req->url);
  free_req:
    globus_free(req);
  error_exit:
    *request = GLOBUS_NULL_HANDLE;
    return;
}
static
int
globus_l_seg_stdout_activate(void)
{
    globus_result_t                     result;
    globus_xio_attr_t                   out_attr;
    globus_xio_attr_t                   in_attr;
    int                                 rc;

    globus_l_seg_output_handle = NULL;
    globus_l_seg_input_handle = NULL;
    globus_l_seg_file_stack = NULL;
    globus_l_seg_file_driver = NULL;
    globus_l_seg_timestamp = 0;
    globus_l_seg_write_registered = GLOBUS_FALSE;
    globus_l_seg_shutdown = 0;

    rc = globus_module_activate(GLOBUS_COMMON_MODULE);

    if (rc != GLOBUS_SUCCESS)
    {
        goto error;
    }

    rc = globus_module_activate(GLOBUS_SCHEDULER_EVENT_GENERATOR_MODULE);

    if (rc != GLOBUS_SUCCESS)
    {
        goto deactivate_common_error;
    }

    rc = globus_fifo_init(&globus_l_seg_buffers);
    if (rc != GLOBUS_SUCCESS)
    {
        goto deactivate_seg_error;
    }

    rc = globus_module_activate(GLOBUS_XIO_MODULE);
    if (rc != GLOBUS_SUCCESS)
    {
        goto destroy_fifo_error;
    }

    result = globus_xio_driver_load("file", &globus_l_seg_file_driver);
    if (result != GLOBUS_SUCCESS)
    {
        goto deactivate_xio_error;
    }
    result = globus_xio_stack_init(&globus_l_seg_file_stack, NULL);
    if (result != GLOBUS_SUCCESS)
    {
        goto unload_driver_error;
    }
    result = globus_xio_stack_push_driver(globus_l_seg_file_stack,
            globus_l_seg_file_driver);
    if (result != GLOBUS_SUCCESS)
    {
        goto destroy_stack_error;
    }

    result = globus_xio_attr_init(&out_attr);
    if (result != GLOBUS_SUCCESS)
    {
        goto destroy_stack_error;
    }

    result = globus_xio_attr_cntl(
            out_attr,
            globus_l_seg_file_driver,
            GLOBUS_XIO_FILE_SET_FLAGS,
            GLOBUS_XIO_FILE_WRONLY);
    if (result != GLOBUS_SUCCESS)
    {
        goto destroy_out_attr_error;
    }

    result = globus_xio_attr_cntl(
            out_attr,
            globus_l_seg_file_driver,
            GLOBUS_XIO_FILE_SET_HANDLE,
            fileno(stdout));

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

    result = globus_xio_attr_init(&in_attr);
    if (result != GLOBUS_SUCCESS)
    {
        goto destroy_out_attr_error;
    }

    result = globus_xio_attr_cntl(
            in_attr,
            globus_l_seg_file_driver,
            GLOBUS_XIO_FILE_SET_FLAGS,
            GLOBUS_XIO_FILE_RDONLY);

    if (result != GLOBUS_SUCCESS)
    {
        goto destroy_in_attr_error;
    }
    result = globus_xio_attr_cntl(
            in_attr,
            globus_l_seg_file_driver,
            GLOBUS_XIO_FILE_SET_HANDLE,
            fileno(stdin));

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

    result = globus_xio_handle_create(
            &globus_l_seg_output_handle,
            globus_l_seg_file_stack);
    if (result != GLOBUS_SUCCESS)
    {
        goto destroy_in_attr_error;
    }

    result = globus_xio_open(globus_l_seg_output_handle, "", out_attr);
    if (result != GLOBUS_SUCCESS)
    {
        goto close_out_handle_error;
    }

    result = globus_xio_handle_create(
            &globus_l_seg_input_handle,
            globus_l_seg_file_stack);
    if (result != GLOBUS_SUCCESS)
    {

        goto close_out_handle_error;
    
    }

    result = globus_xio_open(globus_l_seg_input_handle, "", in_attr);
    if (result != GLOBUS_SUCCESS)
    {
        goto close_in_handle_error;
    }
    rc = globus_mutex_init(&globus_l_seg_mutex, NULL);
    if (rc != GLOBUS_SUCCESS)
    {
        goto close_in_handle_error;
    }
    rc = globus_cond_init(&globus_l_seg_cond, NULL);
    if (rc != GLOBUS_SUCCESS)
    {
        goto destroy_mutex_error;
    }

    result = globus_xio_register_read(
            globus_l_seg_input_handle,
            globus_l_seg_input_buffer,
            sizeof(globus_l_seg_input_buffer),
            1,
            NULL,
            globus_l_xio_read_eof_callback,
            NULL);

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

    globus_xio_attr_destroy(in_attr);
    globus_xio_attr_destroy(out_attr);

    return 0;

destroy_cond_error:
    globus_cond_destroy(&globus_l_seg_cond);
destroy_mutex_error:
    globus_mutex_destroy(&globus_l_seg_mutex);
close_in_handle_error:
    globus_xio_close(globus_l_seg_input_handle, NULL);
close_out_handle_error:
    globus_xio_close(globus_l_seg_output_handle, NULL);
destroy_in_attr_error:
    globus_xio_attr_destroy(in_attr);
destroy_out_attr_error:
    globus_xio_attr_destroy(out_attr);
destroy_stack_error:
    globus_xio_stack_destroy(globus_l_seg_file_stack);
unload_driver_error:
    globus_xio_driver_unload(globus_l_seg_file_driver);
deactivate_xio_error:
    globus_module_deactivate(GLOBUS_XIO_MODULE);
destroy_fifo_error:
    globus_fifo_destroy(&globus_l_seg_buffers);
deactivate_seg_error:
    globus_module_deactivate(GLOBUS_SCHEDULER_EVENT_GENERATOR_MODULE);
deactivate_common_error:
    globus_module_deactivate(GLOBUS_COMMON_MODULE);
error:
    return 1;
}