Exemple #1
0
static int replace_network_address(struct sdp_chopper *chop, struct network_address *address,
		struct packet_stream *ps, struct sdp_ng_flags *flags)
{
	char buf[64];
	int len;
	struct packet_stream *sink = packet_stream_sink(ps);

	if (is_addr_unspecified(&address->parsed)
			&& !(sink && is_trickle_ice_address(&sink->advertised_endpoint)))
		return 0;

	if (copy_up_to(chop, &address->address_type))
		return -1;

	if (flags->media_address.s && is_addr_unspecified(&flags->parsed_media_address))
		__parse_address(&flags->parsed_media_address, NULL, NULL, &flags->media_address);

	if (!is_addr_unspecified(&flags->parsed_media_address)) {
		if (IN6_IS_ADDR_V4MAPPED(&flags->parsed_media_address))
			len = sprintf(buf, "IP4 " IPF, IPP(flags->parsed_media_address.s6_addr32[3]));
		else {
			memcpy(buf, "IP6 ", 4);
			inet_ntop(AF_INET6, &flags->parsed_media_address, buf + 4, sizeof(buf)-4);
			len = strlen(buf);
		}
	}
	else
		call_stream_address(buf, ps, SAF_NG, &len);
	chopper_append_dup(chop, buf, len);

	if (skip_over(chop, &address->address))
		return -1;

	return 0;
}
Exemple #2
0
static int fill_endpoint(struct endpoint *ep, const struct sdp_media *media, struct sdp_ng_flags *flags,
		struct network_address *address, long int port) {
	struct sdp_session *session = media->session;

	if (!flags->trust_address) {
		if (is_addr_unspecified(&flags->parsed_received_from)) {
			if (__parse_address(&flags->parsed_received_from, NULL, &flags->received_from_family,
						&flags->received_from_address))
				return -1;
		}
		ep->ip46 = flags->parsed_received_from;
	}
	else if (address && !is_addr_unspecified(&address->parsed))
		ep->ip46 = address->parsed;
	else if (media->connection.parsed)
		ep->ip46 = media->connection.address.parsed;
	else if (session->connection.parsed)
		ep->ip46 = session->connection.address.parsed;
	else
		return -1;

	ep->port = port;

	return 0;
}
Exemple #3
0
static int replace_network_address(struct sdp_chopper *chop, struct network_address *address,
		struct packet_stream *ps, struct sdp_ng_flags *flags)
{
	char buf[64];
	int len;
	struct packet_stream *sink = packet_stream_sink(ps);

	if (is_addr_unspecified(&address->parsed)
			&& !(sink && is_trickle_ice_address(&sink->advertised_endpoint)))
		return 0;

	if (copy_up_to(chop, &address->address_type))
		return -1;

	if (flags->media_address.s && is_addr_unspecified(&flags->parsed_media_address))
		__parse_address(&flags->parsed_media_address, NULL, NULL, &flags->media_address);

	if (!is_addr_unspecified(&flags->parsed_media_address))
		len = sprintf(buf, "%s %s",
				flags->parsed_media_address.family->rfc_name,
				sockaddr_print_buf(&flags->parsed_media_address));
	else
		call_stream_address46(buf, ps, SAF_NG, &len, NULL);
	chopper_append_dup(chop, buf, len);

	if (skip_over(chop, &address->address))
		return -1;

	return 0;
}
Exemple #4
0
int main(int argc, char **argv) {
	struct main_context ctx;
	int idx=0;

	options(&argc, &argv);
	init_everything();
	create_everything(&ctx);

	ilog(LOG_INFO, "Startup complete, version %s", RTPENGINE_VERSION);

	thread_create_detach(sighandler, NULL);
	thread_create_detach(poller_timer_loop, ctx.p);

	if (!is_addr_unspecified(&redis_ep.address))
		thread_create_detach(redis_notify_loop, ctx.m);

	if (!is_addr_unspecified(&graphite_ep.address))
		thread_create_detach(graphite_loop, ctx.m);

	thread_create_detach(ice_thread_run, NULL);

	if (num_threads < 1) {
#ifdef _SC_NPROCESSORS_ONLN
		num_threads = sysconf( _SC_NPROCESSORS_ONLN );
#endif
		if (num_threads < 1)
			num_threads = 4;
	}

	for (;idx<num_threads;++idx) {
		thread_create_detach(poller_loop, ctx.p);
	}

	while (!g_shutdown) {
		usleep(100000);
		threads_join_all(0);
	}

	redis_notify_event_base_action(ctx.m, EVENT_BASE_LOOPBREAK);

	threads_join_all(1);

	ilog(LOG_INFO, "Version %s shutting down", RTPENGINE_VERSION);

	return 0;
}
Exemple #5
0
struct homer_sender *homer_sender_new(const endpoint_t *ep, int protocol, int capture_id) {
	struct homer_sender *ret;

	if (is_addr_unspecified(&ep->address))
		return NULL;

	ret = malloc(sizeof(*ret));
	ZERO(*ret);
	mutex_init(&ret->lock);
	ret->endpoint = *ep;
	ret->protocol = protocol;
	ret->capture_id = capture_id;
	ret->retry = time(NULL);

	ret->state = __no_socket;

	return ret;
}
Exemple #6
0
int main(int argc, char **argv) {
	int idx;

	early_init();
	options(&argc, &argv);
	init_everything();
	create_everything();
	fill_initial_rtpe_cfg(&initial_rtpe_config);

	ilog(LOG_INFO, "Startup complete, version %s", RTPENGINE_VERSION);

	thread_create_detach(sighandler, NULL);
	thread_create_detach_prio(poller_timer_loop, rtpe_poller, rtpe_config.idle_scheduling, rtpe_config.idle_priority);
	thread_create_detach_prio(load_thread, NULL, rtpe_config.idle_scheduling, rtpe_config.idle_priority);

	if (!is_addr_unspecified(&rtpe_config.redis_ep.address))
		thread_create_detach(redis_notify_loop, NULL);

	if (!is_addr_unspecified(&rtpe_config.graphite_ep.address))
		thread_create_detach(graphite_loop, NULL);

	thread_create_detach(ice_thread_run, NULL);

	if (rtpe_config.num_threads < 1) {
#ifdef _SC_NPROCESSORS_ONLN
		rtpe_config.num_threads = sysconf( _SC_NPROCESSORS_ONLN ) + 3;
#endif
		if (rtpe_config.num_threads <= 1)
			rtpe_config.num_threads = 4;
	}

	service_notify("READY=1\n");

	for (idx = 0; idx < rtpe_config.num_threads; ++idx)
		thread_create_detach_prio(poller_loop, rtpe_poller, rtpe_config.scheduling, rtpe_config.priority);

	if (rtpe_config.media_num_threads < 0)
		rtpe_config.media_num_threads = rtpe_config.num_threads;
	for (idx = 0; idx < rtpe_config.media_num_threads; ++idx) {
#ifdef WITH_TRANSCODING
		thread_create_detach_prio(media_player_loop, NULL, rtpe_config.scheduling, rtpe_config.priority);
#endif
		thread_create_detach_prio(send_timer_loop, NULL, rtpe_config.scheduling, rtpe_config.priority);
	}


	while (!rtpe_shutdown) {
		usleep(100000);
		threads_join_all(0);
	}

	service_notify("STOPPING=1\n");

	if (!is_addr_unspecified(&rtpe_config.redis_ep.address)) {
		redis_notify_event_base_action(EVENT_BASE_LOOPBREAK);
		redis_notify_event_base_action(EVENT_BASE_FREE);
	}

	threads_join_all(1);

	ilog(LOG_INFO, "Version %s shutting down", RTPENGINE_VERSION);

	return 0;
}
Exemple #7
0
static void create_everything(void) {
	struct control_tcp *ct;
	struct control_udp *cu;
	struct cli *cl;
	struct timeval tmp_tv;
	struct timeval redis_start, redis_stop;
	double redis_diff = 0;

	if (rtpe_config.kernel_table < 0)
		goto no_kernel;
	if (kernel_setup_table(rtpe_config.kernel_table)) {
		if (rtpe_config.no_fallback) {
			ilog(LOG_CRIT, "Userspace fallback disallowed - exiting");
			exit(-1);
		}
		goto no_kernel;
	}

no_kernel:
	rtpe_poller = poller_new();
	if (!rtpe_poller)
		die("poller creation failed");

	dtls_timer(rtpe_poller);

	if (call_init())
		abort();

        rwlock_init(&rtpe_config.config_lock);
	if (rtpe_config.max_sessions < -1) {
		rtpe_config.max_sessions = -1;
	}

	if (rtpe_config.redis_num_threads < 1) {
#ifdef _SC_NPROCESSORS_ONLN
		rtpe_config.redis_num_threads = sysconf( _SC_NPROCESSORS_ONLN );
#endif
		if (rtpe_config.redis_num_threads < 1) {
			rtpe_config.redis_num_threads = REDIS_RESTORE_NUM_THREADS;
		}
	}

	ct = NULL;
	if (rtpe_config.tcp_listen_ep.port) {
		ct = control_tcp_new(rtpe_poller, &rtpe_config.tcp_listen_ep);
		if (!ct)
			die("Failed to open TCP control connection port");
	}

	cu = NULL;
	if (rtpe_config.udp_listen_ep.port) {
		interfaces_exclude_port(rtpe_config.udp_listen_ep.port);
		cu = control_udp_new(rtpe_poller, &rtpe_config.udp_listen_ep);
		if (!cu)
			die("Failed to open UDP control connection port");
	}

	rtpe_control_ng = NULL;
	if (rtpe_config.ng_listen_ep.port) {
		interfaces_exclude_port(rtpe_config.ng_listen_ep.port);
		rtpe_control_ng = control_ng_new(rtpe_poller, &rtpe_config.ng_listen_ep, rtpe_config.control_tos);
		if (!rtpe_control_ng)
			die("Failed to open UDP control connection port");
	}

	cl = NULL;
	if (rtpe_config.cli_listen_ep.port) {
		interfaces_exclude_port(rtpe_config.cli_listen_ep.port);
	    cl = cli_new(rtpe_poller, &rtpe_config.cli_listen_ep);
	    if (!cl)
	        die("Failed to open UDP CLI connection port");
	}

	if (!is_addr_unspecified(&rtpe_config.redis_write_ep.address)) {
		rtpe_redis_write = redis_new(&rtpe_config.redis_write_ep,
				rtpe_config.redis_write_db, rtpe_config.redis_write_auth,
				ANY_REDIS_ROLE, rtpe_config.no_redis_required);
		if (!rtpe_redis_write)
			die("Cannot start up without running Redis %s write database! See also NO_REDIS_REQUIRED parameter.",
				endpoint_print_buf(&rtpe_config.redis_write_ep));
	}

		if (!is_addr_unspecified(&rtpe_config.redis_ep.address)) {
			rtpe_redis = redis_new(&rtpe_config.redis_ep, rtpe_config.redis_db, rtpe_config.redis_auth, rtpe_redis_write ? ANY_REDIS_ROLE : MASTER_REDIS_ROLE, rtpe_config.no_redis_required);
			rtpe_redis_notify = redis_new(&rtpe_config.redis_ep, rtpe_config.redis_db, rtpe_config.redis_auth, rtpe_redis_write ? ANY_REDIS_ROLE : MASTER_REDIS_ROLE, rtpe_config.no_redis_required);
			if (!rtpe_redis || !rtpe_redis_notify)
			die("Cannot start up without running Redis %s database! See also NO_REDIS_REQUIRED parameter.",
				endpoint_print_buf(&rtpe_config.redis_ep));

		if (!rtpe_redis_write)
			rtpe_redis_write = rtpe_redis;
	}

	daemonize();
	wpidfile();

	homer_sender_init(&rtpe_config.homer_ep, rtpe_config.homer_protocol, rtpe_config.homer_id);

	rtcp_init(); // must come after Homer init

	if (rtpe_redis) {
		// start redis restore timer
		gettimeofday(&redis_start, NULL);

		// restore
		if (redis_restore(rtpe_redis))
			die("Refusing to continue without working Redis database");

		// stop redis restore timer
		gettimeofday(&redis_stop, NULL);

		// print redis restore duration
		redis_diff += timeval_diff(&redis_stop, &redis_start) / 1000.0;
		ilog(LOG_INFO, "Redis restore time = %.0lf ms", redis_diff);
	}

	gettimeofday(&rtpe_latest_graphite_interval_start, NULL);

	timeval_from_us(&tmp_tv, (long long) rtpe_config.graphite_interval*1000000);
	set_graphite_interval_tv(&tmp_tv);
}
Exemple #8
0
static int if_addr_parse(GQueue *q, char *s, struct ifaddrs *ifas) {
	str name;
	char *c;
	sockaddr_t *addr, adv;
	GQueue addrs = G_QUEUE_INIT;
	struct intf_config *ifa;

	/* name */
	c = strchr(s, '/');
	if (c) {
		*c++ = 0;
		str_init(&name, s);
		s = c;
	}
	else
		str_init(&name, "default");

	/* advertised address */
	c = strchr(s, '!');
	if (c)
		*c++ = 0;

	/* address */
	addr = g_slice_alloc(sizeof(*addr));
	if (!sockaddr_parse_any(addr, s)) {
		if (is_addr_unspecified(addr))
			return -1;
		g_queue_push_tail(&addrs, addr);
	}
	else {
		// could be an interface name?
		ilog(LOG_DEBUG, "Could not parse '%s' as network address, checking to see if "
				"it's an interface", s);
		for (struct ifaddrs *ifa = ifas; ifa; ifa = ifa->ifa_next) {
			if (strcmp(ifa->ifa_name, s))
				continue;
			if (!(ifa->ifa_flags & IFF_UP))
				continue;
			if (!ifa->ifa_addr)
				continue;
			if (ifa->ifa_addr->sa_family == AF_INET) {
				struct sockaddr_in *sin = (void *) ifa->ifa_addr;
				addr->family = __get_socket_family_enum(SF_IP4);
				addr->u.ipv4 = sin->sin_addr;
			}
			else if (ifa->ifa_addr->sa_family == AF_INET6) {
				struct sockaddr_in6 *sin = (void *) ifa->ifa_addr;
				if (sin->sin6_scope_id)
					continue; // link-local
				addr->family = __get_socket_family_enum(SF_IP6);
				addr->u.ipv6 = sin->sin6_addr;
			}
			else
				continue;

			// got one
			ilog(LOG_DEBUG, "Determined address %s for interface '%s'",
					sockaddr_print_buf(addr), s);
			g_queue_push_tail(&addrs, addr);
			addr = g_slice_alloc(sizeof(*addr));
		}

		// free last unused entry
		g_slice_free1(sizeof(*addr), addr);
	}

	if (!addrs.length) // nothing found
		return -1;

	ZERO(adv);
	if (c) {
		if (sockaddr_parse_any(&adv, c))
			return -1;
		if (is_addr_unspecified(&adv))
			return -1;
	}

	while ((addr = g_queue_pop_head(&addrs))) {
		ifa = g_slice_alloc0(sizeof(*ifa));
		ifa->name = name;
		ifa->local_address.addr = *addr;
		ifa->local_address.type = socktype_udp;
		ifa->advertised_address.addr = adv;
		if (is_addr_unspecified(&ifa->advertised_address.addr))
			ifa->advertised_address.addr = *addr;
		ifa->advertised_address.type = ifa->local_address.type;
		ifa->port_min = rtpe_config.port_min;
		ifa->port_max = rtpe_config.port_max;

		// handle "base:suffix" separation for round-robin selection
		ifa->name_rr_spec = ifa->name;
		str_token(&ifa->name_base, &ifa->name_rr_spec, ':'); // sets name_rr_spec to null string if no ':' found

		g_queue_push_tail(q, ifa);

		g_slice_free1(sizeof(*addr), addr);
	}

	return 0;
}
Exemple #9
0
void create_everything(struct main_context *ctx) {
	struct callmaster_config mc;
	struct control_tcp *ct;
	struct control_udp *cu;
	struct control_ng *cn;
	struct cli *cl;
	int kfd = -1;
	struct timeval tmp_tv;
	struct timeval redis_start, redis_stop;
	double redis_diff = 0;

	if (table < 0)
		goto no_kernel;
	if (kernel_create_table(table)) {
		fprintf(stderr, "FAILED TO CREATE KERNEL TABLE %i, KERNEL FORWARDING DISABLED\n", table);
		ilog(LOG_CRIT, "FAILED TO CREATE KERNEL TABLE %i, KERNEL FORWARDING DISABLED\n", table);
		if (no_fallback)
			exit(-1);
		goto no_kernel;
	}
	kfd = kernel_open_table(table);
	if (kfd == -1) {
		fprintf(stderr, "FAILED TO OPEN KERNEL TABLE %i, KERNEL FORWARDING DISABLED\n", table);
		ilog(LOG_CRIT, "FAILED TO OPEN KERNEL TABLE %i, KERNEL FORWARDING DISABLED\n", table);
		if (no_fallback)
			exit(-1);
		goto no_kernel;
	}

no_kernel:
	ctx->p = poller_new();
	if (!ctx->p)
		die("poller creation failed");

	ctx->m = callmaster_new(ctx->p);
	if (!ctx->m)
		die("callmaster creation failed");

	dtls_timer(ctx->p);

	ZERO(mc);
	mc.kernelfd = kfd;
	mc.kernelid = table;
	if (max_sessions < -1) {
		max_sessions = -1;
	}
	mc.max_sessions = max_sessions;
	mc.timeout = timeout;
	mc.silent_timeout = silent_timeout;
	mc.delete_delay = delete_delay;
	mc.default_tos = tos;
	mc.b2b_url = b2b_url;
	mc.fmt = xmlrpc_fmt;
	mc.graphite_ep = graphite_ep;
	mc.graphite_interval = graphite_interval;

	ct = NULL;
	if (tcp_listen_ep.port) {
		ct = control_tcp_new(ctx->p, &tcp_listen_ep, ctx->m);
		if (!ct)
			die("Failed to open TCP control connection port");
	}

	cu = NULL;
	if (udp_listen_ep.port) {
		interfaces_exclude_port(udp_listen_ep.port);
		cu = control_udp_new(ctx->p, &udp_listen_ep, ctx->m);
		if (!cu)
			die("Failed to open UDP control connection port");
	}

	cn = NULL;
	if (ng_listen_ep.port) {
		interfaces_exclude_port(ng_listen_ep.port);
		cn = control_ng_new(ctx->p, &ng_listen_ep, ctx->m);
		if (!cn)
			die("Failed to open UDP control connection port");
	}

	cl = NULL;
	if (cli_listen_ep.port) {
		interfaces_exclude_port(cli_listen_ep.port);
	    cl = cli_new(ctx->p, &cli_listen_ep, ctx->m);
	    if (!cl)
	        die("Failed to open UDP CLI connection port");
	}

	if (!is_addr_unspecified(&redis_ep.address)) {
		mc.redis = redis_new(&redis_ep, redis_db, MASTER_REDIS_ROLE);
		if (!mc.redis)
			die("Cannot start up without Redis database");
	}

	if (!is_addr_unspecified(&redis_read_ep.address)) {
		mc.redis_read = redis_new(&redis_read_ep, redis_read_db, ANY_REDIS_ROLE);
		if (!mc.redis_read)
			die("Cannot start up without Redis read database");
	}

	if (!is_addr_unspecified(&redis_write_ep.address)) {
		mc.redis_write = redis_new(&redis_write_ep, redis_write_db, ANY_REDIS_ROLE);
		if (!mc.redis_write)
			die("Cannot start up without Redis write database");
	}

	ctx->m->conf = mc;

	if (!foreground)
		daemonize();
	wpidfile();

	// start redis restore timer
	gettimeofday(&redis_start, NULL);

	// restore
	if (mc.redis_read) {
		if (redis_restore(ctx->m, mc.redis_read, ANY_REDIS_ROLE))
			die("Refusing to continue without working Redis read database");
	} else if (mc.redis) {
		if (redis_restore(ctx->m, mc.redis, MASTER_REDIS_ROLE))
			die("Refusing to continue without working Redis database");
	}

	// stop redis restore timer
	gettimeofday(&redis_stop, NULL);

	// print redis restore duration
	redis_diff += timeval_diff(&redis_start, &redis_stop) / 1000.0;
	ilog(LOG_INFO, "Redis restore time = %.0lf ms", redis_diff);

	gettimeofday(&ctx->m->latest_graphite_interval_start, NULL);

	timeval_from_us(&tmp_tv, graphite_interval*1000000);
	set_graphite_interval_tv(&tmp_tv);
}
Exemple #10
0
static void create_everything(struct main_context *ctx) {
	struct callmaster_config mc;
	struct control_tcp *ct;
	struct control_udp *cu;
	struct control_ng *cn;
	struct cli *cl;
	int kfd = -1;
	struct timeval tmp_tv;
	struct timeval redis_start, redis_stop;
	double redis_diff = 0;

	if (table < 0)
		goto no_kernel;
	if (kernel_create_table(table)) {
		fprintf(stderr, "FAILED TO CREATE KERNEL TABLE %i, KERNEL FORWARDING DISABLED\n", table);
		ilog(LOG_CRIT, "FAILED TO CREATE KERNEL TABLE %i, KERNEL FORWARDING DISABLED\n", table);
		if (no_fallback)
			exit(-1);
		goto no_kernel;
	}
	kfd = kernel_open_table(table);
	if (kfd == -1) {
		fprintf(stderr, "FAILED TO OPEN KERNEL TABLE %i, KERNEL FORWARDING DISABLED\n", table);
		ilog(LOG_CRIT, "FAILED TO OPEN KERNEL TABLE %i, KERNEL FORWARDING DISABLED\n", table);
		if (no_fallback)
			exit(-1);
		goto no_kernel;
	}

no_kernel:
	ctx->p = poller_new();
	if (!ctx->p)
		die("poller creation failed");

	ctx->m = callmaster_new(ctx->p);
	if (!ctx->m)
		die("callmaster creation failed");

	dtls_timer(ctx->p);

	ZERO(mc);
        rwlock_init(&mc.config_lock);
	mc.kernelfd = kfd;
	mc.kernelid = table;
	if (max_sessions < -1) {
		max_sessions = -1;
	}
	mc.max_sessions = max_sessions;
	mc.timeout = timeout;
	mc.silent_timeout = silent_timeout;
	mc.final_timeout = final_timeout;
	mc.delete_delay = delete_delay;
	mc.default_tos = tos;
	mc.b2b_url = b2b_url;
	mc.fmt = xmlrpc_fmt;
	mc.graphite_ep = graphite_ep;
	mc.graphite_interval = graphite_interval;
	mc.redis_subscribed_keyspaces = g_queue_copy(&keyspaces);

	if (redis_num_threads < 1) {
#ifdef _SC_NPROCESSORS_ONLN
		redis_num_threads = sysconf( _SC_NPROCESSORS_ONLN );
#endif
		if (redis_num_threads < 1) {
			redis_num_threads = REDIS_RESTORE_NUM_THREADS;
		}
	}
	mc.redis_num_threads = redis_num_threads;

	ct = NULL;
	if (tcp_listen_ep.port) {
		ct = control_tcp_new(ctx->p, &tcp_listen_ep, ctx->m);
		if (!ct)
			die("Failed to open TCP control connection port");
	}

	cu = NULL;
	if (udp_listen_ep.port) {
		interfaces_exclude_port(udp_listen_ep.port);
		cu = control_udp_new(ctx->p, &udp_listen_ep, ctx->m);
		if (!cu)
			die("Failed to open UDP control connection port");
	}

	cn = NULL;
	if (ng_listen_ep.port) {
		interfaces_exclude_port(ng_listen_ep.port);
		cn = control_ng_new(ctx->p, &ng_listen_ep, ctx->m);
		if (!cn)
			die("Failed to open UDP control connection port");
	}

	cl = NULL;
	if (cli_listen_ep.port) {
		interfaces_exclude_port(cli_listen_ep.port);
	    cl = cli_new(ctx->p, &cli_listen_ep, ctx->m);
	    if (!cl)
	        die("Failed to open UDP CLI connection port");
	}

	if (!is_addr_unspecified(&redis_write_ep.address)) {
		mc.redis_write = redis_new(&redis_write_ep, redis_write_db, redis_write_auth, ANY_REDIS_ROLE, no_redis_required);
		if (!mc.redis_write)
			die("Cannot start up without running Redis %s write database! See also NO_REDIS_REQUIRED paramter.",
				endpoint_print_buf(&redis_write_ep));
	}

	if (!is_addr_unspecified(&redis_ep.address)) {
		mc.redis = redis_new(&redis_ep, redis_db, redis_auth, mc.redis_write ? ANY_REDIS_ROLE : MASTER_REDIS_ROLE, no_redis_required);
		mc.redis_notify = redis_new(&redis_ep, redis_db, redis_auth, mc.redis_write ? ANY_REDIS_ROLE : MASTER_REDIS_ROLE, no_redis_required);
		if (!mc.redis || !mc.redis_notify)
			die("Cannot start up without running Redis %s database! See also NO_REDIS_REQUIRED paramter.",
				endpoint_print_buf(&redis_ep));

		if (!mc.redis_write)
			mc.redis_write = mc.redis;
	}

	mc.redis_expires_secs = redis_expires;

	ctx->m->conf = mc;

	if (!foreground)
		daemonize();
	wpidfile();

	ctx->m->homer = homer_sender_new(&homer_ep, homer_protocol, homer_id);

	if (mc.redis) {
		// start redis restore timer
		gettimeofday(&redis_start, NULL);

		// restore
		if (redis_restore(ctx->m, mc.redis))
			die("Refusing to continue without working Redis database");

		// stop redis restore timer
		gettimeofday(&redis_stop, NULL);

		// print redis restore duration
		redis_diff += timeval_diff(&redis_stop, &redis_start) / 1000.0;
		ilog(LOG_INFO, "Redis restore time = %.0lf ms", redis_diff);
	}

	gettimeofday(&ctx->m->latest_graphite_interval_start, NULL);

	timeval_from_us(&tmp_tv, graphite_interval*1000000);
	set_graphite_interval_tv(&tmp_tv);
}