static
void
l_ticker_cb(
    void *                              user_arg)
{
    globus_l_ftp_client_restart_plugin_t *  d;
    globus_abstime_t	                    when;
    globus_bool_t                           retry = GLOBUS_TRUE;

    d = (globus_l_ftp_client_restart_plugin_t *) user_arg;

    /* no reason to do anything here if the transfer isnt running */
    if(!d->xfer_running || d->abort_pending)
    {
        return;
    }

    /* allow 1 tic to insure resolution */
    if(d->ticker > 1)
    {
        if(d->abort_pending)
        {
            return;
        }
        
        if(d->max_retries == 0)
        {
            retry = GLOBUS_FALSE;
        }
        else if(d->max_retries > 0)
        {
            d->max_retries--;
        }
        
        GlobusTimeAbstimeGetCurrent(when);
        if((d->deadline.tv_sec != 0 || d->deadline.tv_nsec != 0) &&
            globus_abstime_cmp(&when, &d->deadline) > 0)
        {
            retry = GLOBUS_FALSE;
        }

        GlobusTimeAbstimeSet(when, d->interval.tv_sec, d->interval.tv_usec);
        
        if(retry)
        {
            if(d->backoff)
            {
                GlobusTimeReltimeMultiply(d->interval, 2);
            }
            
            switch(d->operation)
            {
                case GLOBUS_FTP_CLIENT_GET:
                    globus_ftp_client_plugin_restart_get(
                        d->ticker_ftp_handle,
                        d->source_url,
                        &d->source_attr,
                        NULL,
                        &when);
                    break;
                case GLOBUS_FTP_CLIENT_PUT:
                    globus_ftp_client_plugin_restart_put(
                        d->ticker_ftp_handle,
                        d->dest_url,
                        &d->dest_attr,
                        NULL,
                        &when);
                    break;
                case GLOBUS_FTP_CLIENT_TRANSFER:
                    globus_ftp_client_plugin_restart_third_party_transfer(
                        d->ticker_ftp_handle,
                        d->source_url,
                        &d->source_attr,
                        d->dest_url,
                        &d->dest_attr,
                        NULL,
                        &when);
                    break;
    
                default:
                    globus_assert(0 && "should never happen--memory corruption");
            }
        }
    }
    d->ticker++;

    if(!retry)
    {
        globus_ftp_client_plugin_abort(d->ticker_ftp_handle);
    }
}
static
void
restart_marker_plugin_transfer_cb(
    globus_ftp_client_plugin_t *                plugin,
    void *                                      plugin_specific,
    globus_ftp_client_handle_t *                handle,
    const char *                                source_url,
    const globus_ftp_client_operationattr_t *   source_attr,
    const char *                                dest_url,
    const globus_ftp_client_operationattr_t *   dest_attr,
    globus_bool_t                               restart)
{
    restart_marker_plugin_info_t *              ps;

    ps = (restart_marker_plugin_info_t *) plugin_specific;

    if(ps->error_obj)
    {
        globus_object_free(ps->error_obj);
        ps->error_obj = GLOBUS_NULL;
    }

    if(ps->error_url)
    {
        globus_libc_free(ps->error_url);
        ps->error_url = GLOBUS_NULL;
    }

    if(restart)
    {
        /* we have been restarted.. previous fault disregarded */
        return;
    }

    ps->use_data = GLOBUS_FALSE;

    if(ps->begin_cb)
    {
        restart = ps->begin_cb(
            ps->user_arg,
            handle,
            source_url,
            dest_url,
            &ps->restart_marker);
    }

    if(restart)
    {
        globus_ftp_client_plugin_restart_third_party_transfer(
            handle,
            source_url,
            source_attr,
            dest_url,
            dest_attr,
            &ps->restart_marker,
            GLOBUS_NULL);
    }
    else
    {
        globus_ftp_client_restart_marker_init(&ps->restart_marker);
    }
}
static
void
globus_l_ftp_client_restart_plugin_fault(
    globus_ftp_client_plugin_t *		plugin,
    void *					plugin_specific,
    globus_ftp_client_handle_t *		handle,
    const char *				url,
    globus_object_t *				error)
{
    globus_l_ftp_client_restart_plugin_t *	d;
    globus_abstime_t				when;

    d = (globus_l_ftp_client_restart_plugin_t *) plugin_specific;

    if(d->abort_pending)
    {
        return;
    }

    if(d->max_retries == 0)
    {
	return;
    }
    else if(d->max_retries > 0)
    {
	d->max_retries--;
    }

    GlobusTimeAbstimeGetCurrent(when);
    if((d->deadline.tv_sec != 0 || d->deadline.tv_nsec != 0) &&
	globus_abstime_cmp(&when, &d->deadline) > 0)
    {
	return;
    }
    GlobusTimeAbstimeSet(when, d->interval.tv_sec, d->interval.tv_usec);

    switch(d->operation)
    {
	case GLOBUS_FTP_CLIENT_CHMOD:
	    globus_ftp_client_plugin_restart_chmod(
		    handle,
		    d->source_url,
		    d->chmod_file_mode,
		    &d->source_attr,
		    &when);
	    break;

	case GLOBUS_FTP_CLIENT_CKSM:
	    globus_ftp_client_plugin_restart_cksm(
		    handle,
		    d->source_url,
		    d->checksum_offset,
		    d->checksum_length,
		    d->checksum_alg,
		    &d->source_attr,
		    &when);
	    break;

	case GLOBUS_FTP_CLIENT_DELETE:
	    globus_ftp_client_plugin_restart_delete(
		    handle,
		    d->source_url,
		    &d->source_attr,
		    &when);
	    break;

	case GLOBUS_FTP_CLIENT_FEAT:
	    globus_ftp_client_plugin_restart_feat(
		    handle,
		    d->source_url,
		    &d->source_attr,
		    &when);
	    break;

        case GLOBUS_FTP_CLIENT_MKDIR:
	    globus_ftp_client_plugin_restart_mkdir(
		    handle,
		    d->source_url,
		    &d->source_attr,
		    &when);
	    break;
	case GLOBUS_FTP_CLIENT_RMDIR:
	    globus_ftp_client_plugin_restart_rmdir(
		    handle,
		    d->source_url,
		    &d->source_attr,
		    &when);
	    break;
	case GLOBUS_FTP_CLIENT_MOVE:
	    globus_ftp_client_plugin_restart_move(
		    handle,
		    d->source_url,
		    d->dest_url,
		    &d->source_attr,
		    &when);
	    break;
	case GLOBUS_FTP_CLIENT_LIST:
	    globus_ftp_client_plugin_restart_verbose_list(
		    handle,
		    d->source_url,
		    &d->source_attr,
		    &when);
	    break;
	case GLOBUS_FTP_CLIENT_NLST:
	    globus_ftp_client_plugin_restart_list(
		    handle,
		    d->source_url,
		    &d->source_attr,
		    &when);
	    break;
	case GLOBUS_FTP_CLIENT_MLSD:
	    globus_ftp_client_plugin_restart_machine_list(
		    handle,
		    d->source_url,
		    &d->source_attr,
		    &when);
	    break;
	case GLOBUS_FTP_CLIENT_MLST:
	    globus_ftp_client_plugin_restart_mlst(
		    handle,
		    d->source_url,
		    &d->source_attr,
		    &when);
	    break;
	case GLOBUS_FTP_CLIENT_STAT:
	    globus_ftp_client_plugin_restart_stat(
		    handle,
		    d->source_url,
		    &d->source_attr,
		    &when);
	    break;
	case GLOBUS_FTP_CLIENT_GET:
	    globus_ftp_client_plugin_restart_get(
		    handle,
		    d->source_url,
		    &d->source_attr,
		    GLOBUS_NULL,
		    &when);
	    break;
	case GLOBUS_FTP_CLIENT_PUT:
	    globus_ftp_client_plugin_restart_put(
		    handle,
		    d->dest_url,
		    &d->dest_attr,
		    GLOBUS_NULL,
		    &when);
	    break;
	case GLOBUS_FTP_CLIENT_TRANSFER:
	    globus_ftp_client_plugin_restart_third_party_transfer(
		    handle,
		    d->source_url,
		    &d->source_attr,
		    d->dest_url,
		    &d->dest_attr,
		    GLOBUS_NULL,
		    &when);
	    break;
	case GLOBUS_FTP_CLIENT_MDTM:
	    globus_ftp_client_plugin_restart_modification_time(
		    handle,
		    d->source_url,
		    &d->source_attr,
		    &when);
	    break;
	case GLOBUS_FTP_CLIENT_SIZE:
	    globus_ftp_client_plugin_restart_size(
		    handle,
		    d->source_url,
		    &d->source_attr,
		    &when);
	    break;
    default: /* Only state left is FTP_CLIENT_IDLE */
	  globus_assert(0 && "Unexpected state");
    }

    if(d->backoff)
    {
	GlobusTimeReltimeMultiply(d->interval, 2);
    }
}