enum filegetter_code service_filegetter_stop(service_filegetter_tp sfg) {
	assert(sfg);

	service_filegetter_log(sfg, SFG_INFO, "shutting down filegetter");

	enum filegetter_code result = FG_SUCCESS;

	if(sfg->think_times != NULL) {
		cdf_free(sfg->think_times);
		sfg->think_times = NULL;
	}

	if(sfg->downloads != NULL) {
		g_tree_destroy(sfg->downloads);
		sfg->downloads = NULL;
	}

	if(sfg->state != SFG_DONE) {
		result = filegetter_shutdown(&sfg->fg);
		sfg->current_download = NULL;
		sfg->state = SFG_DONE;
	}

	return result;
}
enum filegetter_code service_filegetter_activate(service_filegetter_tp sfg, gint sockd) {
	assert(sfg);

start_over:

	if((sfg->state == SFG_THINKING || sfg->state == SFG_DOWNLOADING) &&
			sfg->expire.tv_sec > 0) {
		/* they set a service expiration, check if we have expired */
		struct timespec now;
		clock_gettime(CLOCK_REALTIME, &now);
		if(now.tv_sec > sfg->expire.tv_sec) {
			return service_filegetter_expire(sfg);
		}
	}

	if(sfg->state == SFG_THINKING) {
		struct timespec now;
		clock_gettime(CLOCK_REALTIME, &now);
		if(now.tv_sec >= sfg->wakeup.tv_sec) {
			/* time to wake up and download the next file */
			service_filegetter_download_next(sfg);
		} else {
			return FG_ERR_WOULDBLOCK;
		}
	}

	if(sfg->state != SFG_DOWNLOADING || sfg->fg.sockd != sockd) {
		return FG_ERR_INVALID;
	}

reactivate:;

	enum filegetter_code result = filegetter_activate(&sfg->fg);

	if(result == FG_ERR_FATAL || result == FG_ERR_SOCKSCONN) {
		/* it had to shut down */
		service_filegetter_log(sfg, SFG_NOTICE, "filegetter shutdown due to error '%s'... retrying in 60 seconds",
				filegetter_codetoa(result));
		filegetter_shutdown(&sfg->fg);
		filegetter_start(&sfg->fg, sfg->fg.epolld);

		/* set wakeup timer and call the sleep function  */
		sfg->state = SFG_THINKING;
		clock_gettime(CLOCK_REALTIME, &sfg->wakeup);
		sfg->wakeup.tv_sec += 60;
		(*sfg->sleep_cb)(sfg, 60);
		service_filegetter_log(sfg, SFG_NOTICE, "[fg-pause] pausing for 60 seconds");

		return FG_ERR_WOULDBLOCK;
	} else if(result != FG_OK_200 && result != FG_ERR_WOULDBLOCK) {
		service_filegetter_log(sfg, SFG_CRITICAL, "filegetter shutdown due to protocol error '%s'...",
				filegetter_codetoa(result));
		filegetter_shutdown(&sfg->fg);
		return result;
	}

	/* report progress */
	filegetter_filestats_t stats;
	filegetter_stat_download(&sfg->fg, &stats);

	service_filegetter_report(sfg, SFG_INFO, "[fg-download-progress]", &stats, sfg->downloads_completed+1, sfg->downloads_requested);

	if(result == FG_OK_200) {
		/* completed a download */
		sfg->downloads_completed++;

		sfg->state = SFG_THINKING;

		/* report completion stats */
		service_filegetter_report(sfg, SFG_NOTICE, "[fg-download-complete]", &stats, sfg->downloads_completed, sfg->downloads_requested);

		if(sfg->downloads_requested > 0 &&
				sfg->downloads_completed >= sfg->downloads_requested) {
			return service_filegetter_expire(sfg);
		} else {
			if(sfg->type == SFG_MULTI && sfg->think_times != NULL) {
				/* get think time and set wakeup timer */
				gdouble percentile = (gdouble)(((gdouble)rand()) / ((gdouble)RAND_MAX));
				guint sleeptime = (guint) (cdf_getValue(sfg->think_times, percentile) / 1000);

				clock_gettime(CLOCK_REALTIME, &sfg->wakeup);
				sfg->wakeup.tv_sec += sleeptime;

				/* dont sleep if it would put us beyond our expiration (if its set) */
				if(sfg->expire.tv_sec > 0 && sfg->wakeup.tv_sec > sfg->expire.tv_sec) {
					return service_filegetter_expire(sfg);
				}

				/* call the sleep function, then check if we are done thinking */
				(*sfg->sleep_cb)(sfg, sleeptime);
				goto start_over;
			} else {
				/* reset download file */
				service_filegetter_download_next(sfg);
				goto reactivate;
			}
		}
	}

	return result;
}
static enum filegetter_code filegetter_die(filegetter_tp fg, gchar* msg) {
	filegetter_shutdown(fg);
	fprintf(stderr, "%s", msg);
	return FG_ERR_FATAL;
}