Exemple #1
0
/*
 *  Called when the LFS module is activated.
 *  Need to initialize APR ourselves
 */
int lfs_activate(void) {
    globus_extension_registry_add(
                            GLOBUS_GFS_DSI_REGISTRY,
                            "lfs",
                            GlobusExtensionMyModule(globus_gridftp_server_lfs),
                            &globus_l_gfs_lfs_dsi_iface);

    // See if we're configured to write to statsd
    char * local_host = globus_malloc(256);
    if (local_host) {
        memset(local_host, 0, 256);
        if (gethostname(local_host, 255)) {
            strcpy(local_host, "UNKNOWN");
        }
    }

    char statsd_namespace_prefix [] = "lfs.gridftp.";
    char * statsd_namespace = globus_malloc(strlen(statsd_namespace_prefix)+
                                            strlen(local_host)+1);
    strcpy(statsd_namespace, statsd_namespace_prefix);
    char * source = local_host;
    char * dest;
    for (dest = statsd_namespace + strlen(statsd_namespace_prefix);
            *source != '\0';
            ++source, ++dest) {
        if (*source == '.') {
            *dest = '_';
        } else {
            *dest = *source;
        }
    }
    *dest = '\0';

    char * lfs_statsd_link_port = getenv("GRIDFTP_LFS_STATSD_PORT");
    char * lfs_statsd_link_host = getenv("GRIDFTP_LFS_STATSD_HOST");
    if (lfs_statsd_link_host) {
        int lfs_statsd_link_port_conv = 8125;
        if (lfs_statsd_link_port) {
            lfs_statsd_link_port_conv = atoi(lfs_statsd_link_port);
        }
        lfs_statsd_link = statsd_init_with_namespace(lfs_statsd_link_host,
                          lfs_statsd_link_port_conv,
                          statsd_namespace);
        globus_gfs_log_message(GLOBUS_GFS_LOG_INFO,
                               "Sending log data to statsd %s:%i, namespace %s\n",
                               lfs_statsd_link_host,
                               lfs_statsd_link_port_conv,
                               statsd_namespace);
    } else {
        globus_gfs_log_message(GLOBUS_GFS_LOG_INFO,
                               "Not logging to statsd. Set $GRIDFTP_LFS_STATSD_HOST to enable\n");
        lfs_statsd_link = NULL;
    }
    globus_free(statsd_namespace);
    
    globus_gfs_log_message(GLOBUS_GFS_LOG_INFO, "LFS DSI activated.\n");
    STATSD_COUNT("activate",1);
    if (local_host) globus_free(local_host);
    return 0;
}
void
session_destroy_session_info(globus_gfs_session_info_t * SessionInfo)
{
	GlobusGFSName(__func__);
	GlobusGFSHpssDebugEnter();

	if (SessionInfo->username != NULL)
		globus_free(SessionInfo->username);
	if (SessionInfo->password != NULL)
		globus_free(SessionInfo->password);
	if (SessionInfo->subject != NULL)
		globus_free(SessionInfo->subject);
	if (SessionInfo->cookie != NULL)
		globus_free(SessionInfo->cookie);
	if (SessionInfo->host_id != NULL)
		globus_free(SessionInfo->host_id);

	SessionInfo->username = NULL;
	SessionInfo->password = NULL;
	SessionInfo->subject  = NULL;
	SessionInfo->cookie   = NULL;
	SessionInfo->host_id  = NULL;

	GlobusGFSHpssDebugExit();
}
globus_result_t
globus_gridftp_server_control_set_cwd(
    globus_gridftp_server_control_t         server,
    const char *                            cwd_string)
{
    GlobusGridFTPServerName(globus_gridftp_server_control_get_cwd);

    if(server == NULL)
    {
        return GlobusGridFTPServerErrorParameter("server");
    }

    globus_mutex_lock(&server->mutex);
    {
        if(cwd_string)
        {
            if(server->cwd)
            {
                globus_free(server->cwd);
            }
            server->cwd = strdup(cwd_string);
        }
        else if(server->cwd)
        {
            if(server->default_cwd)
            {
                globus_free(server->default_cwd);
            }
            server->default_cwd = strdup(server->cwd);
        }
    }
    globus_mutex_unlock(&server->mutex);

    return GLOBUS_SUCCESS;
}
void
globus_xio_driver_list_destroy(
    globus_list_t *                     driver_list,
    globus_bool_t                       unload)
{
    globus_xio_driver_list_ent_t *      ent;
    globus_list_t *                     list;

    for(list = driver_list;
        !globus_list_empty(list);
        list = globus_list_rest(list))
    {
        ent = (globus_xio_driver_list_ent_t *) globus_list_first(list);

        if(ent->driver_name != NULL)
        {
            globus_free(ent->driver_name);
        }
        if(ent->opts != NULL)
        {
            globus_free(ent->opts);
        }
        if(unload)
        {
            globus_xio_driver_unload(ent->driver);
        }
        globus_free(ent);
    }
}
static
void
gfork_l_client_writev_cb(
    globus_xio_handle_t                 xio_handle,
    globus_result_t                     result,
    globus_xio_iovec_t *                iovec,
    int                                 count,
    globus_size_t                       nbytes,
    globus_xio_data_descriptor_t        data_desc,
    void *                              user_arg)
{
    gfork_i_msg_t *                     msg;
    gfork_i_lib_handle_t *              handle;

    msg = (gfork_i_msg_t *) user_arg;
    handle = msg->lib_handle;

    /* lazy reuse of XIO callback.  perhaps we should define our own */
    if(msg->client_cb)
    {
        msg->client_cb(NULL, result, &msg->iov[1],
                       count - 1, nbytes, data_desc, msg->user_arg);
    }
    globus_free(msg->iov);
    globus_free(msg);

    globus_mutex_lock(&handle->mutex);
    {
        handle->writing = GLOBUS_FALSE;
        if(result != GLOBUS_SUCCESS)
        {
            goto error;
        }
        if(!globus_fifo_empty(&handle->write_q))
        {
            msg = (gfork_i_msg_t *) globus_fifo_dequeue(&handle->write_q);

            result = globus_xio_register_writev(
                         handle->write_xio,
                         msg->iov,
                         msg->iovc,
                         msg->nbytes,
                         NULL,
                         gfork_l_client_writev_cb,
                         msg);
            if(result != GLOBUS_SUCCESS)
            {
                goto error;
            }
            handle->writing = GLOBUS_TRUE;
        }
    }
    globus_mutex_unlock(&handle->mutex);

    return;
error:
    assert(0);
    globus_mutex_unlock(&handle->mutex);
}
void
stat_destroy(globus_gfs_stat_t * GFSStat)
{
	if (GFSStat)
	{
		if (GFSStat->symlink_target != NULL)
			globus_free(GFSStat->symlink_target);
		if (GFSStat->name != NULL)
			globus_free(GFSStat->name);
	}
	return;
}
int
globus_extension_register_builtin(
    const char *                        extension_name,
    globus_module_descriptor_t *        module_descriptor)
{
    globus_l_extension_builtin_t *      builtin;
    GlobusFuncName(globus_extension_register_builtin);
    
    GlobusExtensionDebugEnterSymbol(extension_name);
    
    builtin = (globus_l_extension_builtin_t *)
        globus_malloc(sizeof(globus_l_extension_builtin_t));
    if(!builtin)
    {
        goto error_alloc;
    }
    
    builtin->owner = (globus_l_extension_module_t *)
        globus_thread_getspecific(globus_l_extension_owner_key);
    builtin->module = module_descriptor;
    builtin->extension_name = globus_libc_strdup(extension_name);
    if(!builtin->extension_name)
    {
        goto error_strdup;
    }
    
    globus_rmutex_lock(&globus_l_extension_mutex);
    {
        int                             rc;
        
        rc = globus_hashtable_insert(
            &globus_l_extension_builtins, builtin->extension_name, builtin);
        if(rc != 0)
        {
            goto error_insert;
        }
    }
    globus_rmutex_unlock(&globus_l_extension_mutex);
    
    GlobusExtensionDebugExit();
    return GLOBUS_SUCCESS;

error_insert:
    globus_rmutex_unlock(&globus_l_extension_mutex);
    globus_free(builtin->extension_name);
error_strdup:
    globus_free(builtin);
error_alloc:
    GlobusExtensionDebugExitWithError();
    return GLOBUS_FAILURE;
}
static
void
globus_l_error_ftp_free(
    void *                              data)
{
    globus_l_error_ftp_data_t *         d;
    
    d = (globus_l_error_ftp_data_t *) data;
    
    if(d->message)
    {
        globus_free(d->message);
    }
    globus_free(d);
}
static
void
gfs_l_xio_cp_post_read(
    globus_xio_handle_t                 xio_h,
    gfs_l_xio_read_buffer_t *           read_buf)
{
    globus_result_t                     result;

    read_buf->read_xio = xio_h;
    result = globus_xio_register_read(
        xio_h,
        read_buf->buffer,
        read_buf->block_size,
        read_buf->block_size,
        gfs_l_xio_cp_read_cb,
        NULL,
        read_buf);
    if(result != GLOBUS_SUCCESS)
    {
        goto error;
    }

    return;

error:
    globus_free(read_buf);
    gfs_l_xio_cp_error(cp_h, result);
    globus_mutex_unlock(&cp_h->mutex);
}
static
globus_ftp_client_plugin_t *
restart_marker_plugin_copy_cb(
    globus_ftp_client_plugin_t *                plugin_template,
    void *                                      plugin_specific)
{
    restart_marker_plugin_info_t *              old_ps;
    globus_ftp_client_plugin_t *                new_plugin;
    globus_result_t                             result;

    old_ps = (restart_marker_plugin_info_t *) plugin_specific;

    new_plugin = (globus_ftp_client_plugin_t *)
        globus_malloc(sizeof(globus_ftp_client_plugin_t));

    if(new_plugin == GLOBUS_NULL)
    {
        return GLOBUS_NULL;
    }

    result = globus_ftp_client_restart_marker_plugin_init(
        new_plugin,
        old_ps->begin_cb,
        old_ps->marker_cb,
        old_ps->complete_cb,
        old_ps->user_arg);

    if(result != GLOBUS_SUCCESS)
    {
        globus_free(new_plugin);
        new_plugin = GLOBUS_NULL;
    }

    return new_plugin;
}
static void
bounce_handle_destroy(
    bounce_handle_t *                   handle)
{
    globus_mutex_destroy(&handle->mutex);
    globus_free(handle);
}
globus_result_t
globus_xio_stack_destroy(
    globus_xio_stack_t                  stack)
{
    globus_result_t                     res;
    GlobusXIOName(globus_xio_stack_destroy);

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

    globus_list_free(stack->driver_stack);
    globus_free(stack);

    GlobusXIODebugExit();
    return GLOBUS_SUCCESS;

  err:

    GlobusXIODebugExitWithError();
    return res;
}
/******************************************************************************
Function: globus_l_gass_server_ez_put_callback()

Description: 

Parameters: 

Returns: 
******************************************************************************/
static void
globus_l_gass_server_ez_put_callback(
				    void *arg,
				    globus_gass_transfer_request_t request,
				    globus_byte_t *     bytes,
				    globus_size_t       len,
				    globus_bool_t       last_data)
{
    int fd;

    fd = (int) arg;

    globus_libc_write(fd, bytes, len);
    if(!last_data)
    {
        globus_gass_transfer_receive_bytes(request,
                                           bytes,
                                           1024,
                                           1,
                                           globus_l_gass_server_ez_put_callback,
                                           arg);
    return ;
    }

    if((fd!=fileno(stdout)) && (fd!=fileno(stderr)))
    {
        close(fd);
    }
    globus_free(bytes);
    globus_gass_transfer_request_destroy(request);
    return ;

} /* globus_l_gass_server_ez_put_callback() */
static
void
gfs_l_dynclient_log(
    globus_result_t                     result,
    int                                 level,
    char *                              fmt,
    ...)
{
    va_list                             ap;

    if(g_quiet)
    {
        return;
    }

    va_start(ap, fmt);

    fprintf(stderr, "[gridftp gfork plugin] : ");
    if(result != GLOBUS_SUCCESS)
    {
        char * err_str = globus_error_print_friendly(
            globus_error_peek(result));

        fprintf(stderr, "ERROR : %s : ", err_str);
        globus_free(err_str);
    }
    vfprintf(stderr, fmt, ap);
    va_end(ap);
    fflush(stderr);
}
void
transfer_control_destroy(transfer_control_t * TransferControl)
{
	GlobusGFSName(__func__);
	GlobusGFSHpssDebugEnter();

	if (TransferControl != NULL)
	{
		/* Unregister to receive messages. */
		msg_unregister(TransferControl->MsgHandle, TransferControl->MsgRegisterID);

		/* Destroy the PIO control handle. */
		pio_control_destroy(TransferControl->PioControl);

/*
 * Temp workaround to make sure the thread that called us isn't still 
 * holding this lock.
 */
globus_mutex_lock(&TransferControl->Lock);
globus_mutex_unlock(&TransferControl->Lock);
		/* Dellocate the lock. */
		globus_mutex_destroy(&TransferControl->Lock);

		/* Destroy the transfer range list. */
		range_list_destroy(TransferControl->TransferRangeList);

		/* Deallocate our handle. */
		globus_free(TransferControl);
	}

    GlobusGFSHpssDebugExit();
}
void *
globus_extension_registry_remove(
    globus_extension_registry_t *       registry,
    void *                              symbol)
{
    globus_l_extension_handle_t *       entry;
    void *                              datum = NULL;
    GlobusFuncName(globus_extension_registry_remove);
    
    GlobusExtensionDebugEnterSymbol(registry->user_hashing ? "" : symbol);
    
    globus_rmutex_lock(&globus_l_extension_mutex);
    {
        if(registry->initialized)
        {
            entry = (globus_l_extension_handle_t *)
                globus_hashtable_lookup(&registry->table, (void *) symbol);
            if(entry && entry->datum)
            {
                datum = entry->datum;
                globus_hashtable_remove(&registry->table, (void *) symbol);
                if(--entry->ref == 0)
                {
                    globus_free(entry);
                }
            }
        }
    }
    globus_rmutex_unlock(&globus_l_extension_mutex);
    
    GlobusExtensionDebugExit();
    return datum;
}
globus_result_t
globus_gridftp_server_control_attr_add_mode(
    globus_gridftp_server_control_attr_t    in_attr,
    char                                    mode)
{
    char                                    ch;
    char *                                  tmp_str;
    globus_i_gsc_attr_t *                   attr;
    globus_result_t                         res;
    GlobusGridFTPServerName(globus_gridftp_server_control_attr_add_mode);

    GlobusGridFTPServerDebugEnter();
    if(in_attr == NULL)
    {
        res = GlobusGridFTPServerErrorParameter("in_attr");
        goto err;
    }
    attr = in_attr;

    ch = toupper(mode);
    tmp_str = globus_common_create_string("%s%c", attr->modes, ch);
    globus_free(attr->modes);
    attr->modes = tmp_str;

    GlobusGridFTPServerDebugExit();
    return GLOBUS_SUCCESS;

  err:

    GlobusGridFTPServerDebugExitWithError();

    return res;
}
/* stalled transfer timer has ended */
static
void
l_ticker_done(
    void *                              user_arg)
{
    globus_free(user_arg);
}
void
globus_xio_system_socket_destroy(
    globus_xio_system_socket_handle_t   handle)
{
    unsigned long                       flag = 0;
    GlobusXIOName(globus_xio_system_socket_destroy);
    
    GlobusXIOSystemDebugEnterFD(handle->socket);
    
    globus_assert(!handle->read_info && !handle->write_info);
    
    /* no need to ensure entry is still registered, as I always return true
     * in the callback and this is only place i unregister
     */
    globus_i_xio_win32_event_lock(handle->event_entry);
    
    GlobusXIOSystemDebugPrintf(
        GLOBUS_I_XIO_SYSTEM_DEBUG_INFO,
        ("[%s] Unregistering event handle=%lu for socket %ld\n",
            _xio_name, (unsigned long) handle->event, (long) handle->socket));
            
    globus_i_xio_win32_event_unregister(handle->event_entry);
    globus_i_xio_win32_event_unlock(handle->event_entry);
    
    WSAEventSelect(handle->socket, 0, 0);
    ioctlsocket(handle->socket, FIONBIO, &flag);
    WSACloseEvent(handle->event);
    win32_mutex_destroy(&handle->lock);
    
    GlobusXIOSystemDebugExitFD(handle->socket);
    globus_free(handle);
}
static void
globus_l_gsc_send_perf(
    globus_gridftp_server_control_op_t      op,
    int                                     stripe_ndx,
    int                                     stripe_count,
    globus_off_t                            nbytes)
{
    char *                                  msg;
    struct timeval                          now;
    GlobusGridFTPServerName(globus_l_gsc_send_perf);
                                                                                
    gettimeofday(&now, NULL);
    msg = globus_common_create_string(
        "112-Perf Marker\r\n"
        " Timestamp:  %ld.%01ld\r\n"
        " Stripe Index: %d\r\n"
        " Stripe Bytes Transferred: %"GLOBUS_OFF_T_FORMAT"\r\n"
        " Total Stripe Count: %d\r\n"
        "112 End.\r\n",
            now.tv_sec, now.tv_usec / 100000,
            stripe_ndx,
            nbytes,
            stripe_count);
    globus_i_gsc_intermediate_reply(op, msg);
    globus_free(msg);
}
static
void
globus_l_gsc_event_done_cb(
    void *                              user_arg)
{
    globus_i_gsc_op_t *                 op;
    globus_i_gsc_event_data_t *         event;
    globus_i_gsc_server_handle_t *      server_handle;

    op = (globus_i_gsc_op_t *) user_arg;
    event = &op->event;
    server_handle = op->server_handle;

    event->user_cb(
        op,
        GLOBUS_GRIDFTP_SERVER_CONTROL_EVENT_TRANSFER_COMPLETE,
        event->user_arg);

    if(event->stripe_total != NULL)
    {
        globus_free(event->stripe_total);
    }

    globus_mutex_lock(&server_handle->mutex);
    {
        if(op->data_destroy_obj)
        {
            globus_i_guc_data_object_destroy(
                op->server_handle, op->data_destroy_obj);
        }
        globus_i_gsc_op_destroy(op);
    }
    globus_mutex_unlock(&server_handle->mutex);
}
static
int
globus_l_usage_stats_split_targets(
    const char *                        targets_string,
    globus_list_t **                    targets)
{
    char *                              tmpstr;
    char *                              target;
    char *                              ptr;

    if(targets_string == NULL)
    {
        return -1;
    }
    
    tmpstr = globus_libc_strdup(targets_string);

    target = tmpstr;
    while((ptr = strchr(target, ',')) != NULL ||
            (ptr = strchr(target, ' ')) != NULL)
    {
        *ptr = '\0';
        globus_list_insert(targets, globus_libc_strdup(target)); 
        target = ptr + 1;
    }
    if(ptr == NULL)
    {
        globus_list_insert(targets, globus_libc_strdup(target)); 
    }               
        
    globus_free(tmpstr);             

    return 0;
}
static
void
xio_l_wrapblock_wrapper_destroy(
    xio_l_wrapblock_wrapper_t *               wrapper)
{
    globus_xio_contact_destroy(&wrapper->ci);
    if(wrapper->iovec != NULL)
    {
        globus_free(wrapper->iovec);
    }
    if(wrapper->attr && wrapper->driver && wrapper->driver->attr_destroy_func)
    {
        wrapper->driver->attr_destroy_func(wrapper->attr);
    }
    globus_free(wrapper);
}
/**
 * Destroy an instance of the GridFTP restart plugin
 * @ingroup globus_ftp_client_restart_plugin
 *
 * This function will free all restart plugin-specific instance data
 * from this plugin, and will make the plugin unusable for further ftp
 * handle creation.
 *
 * Existing FTP client handles and handle attributes will not be affected by
 * destroying a plugin associated with them, as a local copy of the plugin
 * is made upon handle initialization.
 *
 * @param plugin
 *        A pointer to a GridFTP restart plugin, previously initialized by
 *        calling globus_ftp_client_restart_plugin_init()
 *
 * @return This function returns an error if
 * - plugin is null
 * - plugin is not a restart plugin
 *
 * @see globus_ftp_client_restart_plugin_init(),
 *      globus_ftp_client_handleattr_add_plugin(),
 *      globus_ftp_client_handleattr_remove_plugin(),
 *      globus_ftp_client_handle_init()
 */
globus_result_t
globus_ftp_client_restart_plugin_destroy(
    globus_ftp_client_plugin_t *		plugin)
{
    globus_l_ftp_client_restart_plugin_t * d;
    globus_result_t result;
    GlobusFuncName(globus_ftp_client_restart_plugin_destroy);

    GLOBUS_L_FTP_CLIENT_RESTART_PLUGIN_RETURN(plugin);

    result = globus_ftp_client_plugin_get_plugin_specific(plugin,
	                                                  (void **) &d);
    if(result != GLOBUS_SUCCESS)
    {
        return result;
    }

    globus_l_ftp_client_restart_plugin_genericify(d);

    if(d->ticker_set)
    {
        d->ticker_set = GLOBUS_FALSE;
        /* XXX where is d freed? if was a previous leak free in l_ticker_done */
        globus_callback_unregister(
            d->ticker_handle, l_ticker_done, d, NULL);
    }
    else
    {
        /* XXX free d here ? */
        globus_free(d);
    }
    return globus_ftp_client_plugin_destroy(plugin);
}
void
globus_extension_release(
    globus_extension_handle_t           handle)
{
    globus_l_extension_handle_t *       entry;
    globus_l_extension_module_t *       owner = NULL;
    GlobusFuncName(globus_extension_release);
    
    entry = handle;
    GlobusExtensionDebugEnterSymbol(entry->user_hashing ? "" : entry->symbol);
    
    globus_rmutex_lock(&globus_l_extension_mutex);
    {
        if(entry)
        {
            if(entry->owner && --entry->owner->ref == 0)
            {
                owner = entry->owner;
            }
            
            if(--entry->ref == 0)
            {
                globus_free(entry);
            }
            
            if(owner)
            {
                globus_l_extension_shutdown_extension(owner, GLOBUS_FALSE);
            }
        }
    }
    globus_rmutex_unlock(&globus_l_extension_mutex);
    
    GlobusExtensionDebugExit();
}
/* XX this is crap.. no idea how big host is.  should probably be at least
 * 50 bytes
 */
void
globus_ftp_control_host_port_get_host(
    globus_ftp_control_host_port_t *                   host_port,
    char *                                             host)
{
    char *                              str;
    
    /* this api doesnt let me play nice with people that arent aware of the new
     * hostlen field in host_port.  since i have tried to assume 4 wherever
     * ipv6 is not allowed, I will assume 4 unless the len is actually 16.
     * this is in the hopes that it is not likely for a random unitialized int
     * to be 16
     */
    str = globus_libc_ints_to_contact_string(
        host_port->host, host_port->hostlen == 16 ? 16 : 4, 0);
    if(str)
    {
        strcpy(host, str);
        globus_free(str);
    }
    else
    {
        *host = 0;
    }
}
static void
globus_l_xio_telnet_cmd_write_cb(
    globus_xio_operation_t              op,
    globus_result_t                     result,
    globus_size_t                       nbytes,
    void *                              user_arg)
{
    globus_l_xio_telnet_handle_t *      handle;

    handle = (globus_l_xio_telnet_handle_t *) user_arg;

    if(result != GLOBUS_SUCCESS)
    {
        globus_xio_driver_finished_read(op, result, 0);
        return;
    }
    globus_mutex_lock(&handle->mutex);
    {
        globus_free(handle->write_iovec.iov_base);
        globus_l_xio_telnet_request_data(handle, op);
    }
    globus_mutex_unlock(&handle->mutex);
    if(handle->finish)
    {
        handle->finish = GLOBUS_FALSE;
        globus_xio_driver_finished_read(
            op, handle->finish_res, handle->finish_len);       
    }
}
static globus_result_t
globus_l_xio_telnet_attr_destroy(
    void *                              driver_attr)
{
    globus_free(driver_attr);
    return GLOBUS_SUCCESS;
}
static void
globus_l_xio_telnet_close_cb(
    globus_xio_operation_t              op,
    globus_result_t                     result,
    void *                              user_arg)
{
    globus_l_xio_telnet_handle_t *     handle;

    handle = (globus_l_xio_telnet_handle_t *) user_arg;

    globus_xio_driver_finished_close(op, result);

    globus_free(handle->read_buffer);
    globus_fifo_destroy(&handle->write_q);
    globus_mutex_destroy(&handle->mutex);
    globus_free(handle);
}
static void
globus_l_gsc_send_restart(
    globus_gridftp_server_control_op_t  op,
    globus_range_list_t                 range_list)
{
    int                                 ctr;
    char *                              tmp_msg;
    char *                              msg;
    int                                 size;
    globus_off_t                        offset;
    globus_off_t                        length;
    globus_range_list_t                 new_range_list;

    globus_range_list_merge(
        &new_range_list, op->perf_range_list, range_list);
    globus_range_list_destroy(op->perf_range_list);
    op->perf_range_list = new_range_list;

    size = globus_range_list_size(range_list);
    if(size < 1)
    {
        /* sending 0-0 is useless, and it causes a problem with our client
            when markers are sent before the retr begins
        msg = globus_common_create_string("111 Range Marker 0-0\r\n"); */
    }
    else
    {    
        msg = globus_common_create_string("111 Range Marker");
        for(ctr = 0; ctr < size; ctr++)
        {
            globus_range_list_at(range_list, ctr, &offset, &length);
    
            tmp_msg = globus_common_create_string("%s%c%"
                GLOBUS_OFF_T_FORMAT"-%"GLOBUS_OFF_T_FORMAT,
                 msg, ctr ? ',' : ' ', offset, offset + length);
            globus_free(msg);
            msg = tmp_msg;
        }
        tmp_msg = globus_common_create_string("%s%s", msg, "\r\n");
        globus_free(msg);
        msg = tmp_msg;
        
        globus_i_gsc_intermediate_reply(op, msg);
        globus_free(msg);
    }    
}