worker_init(struct worker* worker, struct config_file *cfg, 
	struct listen_port* ports, int do_sigs)
{
#ifdef USE_DNSTAP
	struct dt_env* dtenv = &worker->dtenv;
#else
	void* dtenv = NULL;
#endif
	worker->need_to_exit = 0;
	worker->base = comm_base_create(do_sigs);
	if(!worker->base) {
		log_err("could not create event handling base");
		worker_delete(worker);
		return 0;
	}
	comm_base_set_slow_accept_handlers(worker->base, &worker_stop_accept,
		&worker_start_accept, worker);
	if(do_sigs) {
#ifdef SIGHUP
		ub_thread_sig_unblock(SIGHUP);
#endif
#ifdef SIGBREAK
		ub_thread_sig_unblock(SIGBREAK);
#endif
		ub_thread_sig_unblock(SIGINT);
#ifdef SIGQUIT
		ub_thread_sig_unblock(SIGQUIT);
#endif
		ub_thread_sig_unblock(SIGTERM);
#ifndef LIBEVENT_SIGNAL_PROBLEM
		worker->comsig = comm_signal_create(worker->base, 
			worker_sighandler, worker);
		if(!worker->comsig 
#ifdef SIGHUP
			|| !comm_signal_bind(worker->comsig, SIGHUP)
#endif
#ifdef SIGQUIT
			|| !comm_signal_bind(worker->comsig, SIGQUIT)
#endif
			|| !comm_signal_bind(worker->comsig, SIGTERM)
#ifdef SIGBREAK
			|| !comm_signal_bind(worker->comsig, SIGBREAK)
#endif
			|| !comm_signal_bind(worker->comsig, SIGINT)) {
			log_err("could not create signal handlers");
			worker_delete(worker);
			return 0;
		}
#endif /* LIBEVENT_SIGNAL_PROBLEM */
		if(!daemon_remote_open_accept(worker->daemon->rc, 
			worker->daemon->rc_ports, worker)) {
			worker_delete(worker);
			return 0;
		}
#ifdef UB_ON_WINDOWS
		wsvc_setup_worker(worker);
#endif /* UB_ON_WINDOWS */
	} else { /* !do_sigs */
		worker->comsig = NULL;
	}
#ifdef USE_DNSTAP
	if(cfg->dnstap) {
		log_assert(worker->daemon->dtenv != NULL);
		memcpy(&worker->dtenv, worker->daemon->dtenv, sizeof(struct dt_env));
		if(!dt_init(&worker->dtenv, worker->base))
			fatal_exit("dt_init failed");
	}
#endif
	worker->front = listen_create(worker->base, ports,
		cfg->msg_buffer_size, (int)cfg->incoming_num_tcp,
		cfg->do_tcp_keepalive
			? cfg->tcp_keepalive_timeout
			: cfg->tcp_idle_timeout,
		cfg->harden_large_queries, cfg->http_max_streams,
		cfg->http_endpoint, cfg->http_notls_downstream,
		worker->daemon->tcl, worker->daemon->listen_sslctx,
		dtenv, worker_handle_request, worker);
	if(!worker->front) {
		log_err("could not create listening sockets");
		worker_delete(worker);
		return 0;
	}
	worker->back = outside_network_create(worker->base,
		cfg->msg_buffer_size, (size_t)cfg->outgoing_num_ports, 
		cfg->out_ifs, cfg->num_out_ifs, cfg->do_ip4, cfg->do_ip6, 
		cfg->do_tcp?cfg->outgoing_num_tcp:0, cfg->ip_dscp,
		worker->daemon->env->infra_cache, worker->rndstate,
		cfg->use_caps_bits_for_id, worker->ports, worker->numports,
		cfg->unwanted_threshold, cfg->outgoing_tcp_mss,
		&worker_alloc_cleanup, worker,
		cfg->do_udp || cfg->udp_upstream_without_downstream,
		worker->daemon->connect_sslctx, cfg->delay_close,
		cfg->tls_use_sni, dtenv, cfg->udp_connect,
		cfg->max_reuse_tcp_queries, cfg->tcp_reuse_timeout,
		cfg->tcp_auth_query_timeout);
	if(!worker->back) {
		log_err("could not create outgoing sockets");
		worker_delete(worker);
		return 0;
	}
	iterator_set_ip46_support(&worker->daemon->mods, worker->daemon->env,
		worker->back);
	/* start listening to commands */
	if(!tube_setup_bg_listen(worker->cmd, worker->base,
		&worker_handle_control_cmd, worker)) {
		log_err("could not create control compt.");
		worker_delete(worker);
		return 0;
	}
	worker->stat_timer = comm_timer_create(worker->base, 
		worker_stat_timer_cb, worker);
	if(!worker->stat_timer) {
		log_err("could not create statistics timer");
	}

	/* we use the msg_buffer_size as a good estimate for what the 
	 * user wants for memory usage sizes */
	worker->scratchpad = regional_create_custom(cfg->msg_buffer_size);
	if(!worker->scratchpad) {
		log_err("malloc failure");
		worker_delete(worker);
		return 0;
	}

	server_stats_init(&worker->stats, cfg);
	alloc_init(&worker->alloc, &worker->daemon->superalloc, 
		worker->thread_num);
	alloc_set_id_cleanup(&worker->alloc, &worker_alloc_cleanup, worker);
	worker->env = *worker->daemon->env;
	comm_base_timept(worker->base, &worker->env.now, &worker->env.now_tv);
	worker->env.worker = worker;
	worker->env.worker_base = worker->base;
	worker->env.send_query = &worker_send_query;
	worker->env.alloc = &worker->alloc;
	worker->env.outnet = worker->back;
	worker->env.rnd = worker->rndstate;
	/* If case prefetch is triggered, the corresponding mesh will clear
	 * the scratchpad for the module env in the middle of request handling.
	 * It would be prone to a use-after-free kind of bug, so we avoid
	 * sharing it with worker's own scratchpad at the cost of having
	 * one more pad per worker. */
	worker->env.scratch = regional_create_custom(cfg->msg_buffer_size);
	if(!worker->env.scratch) {
		log_err("malloc failure");
		worker_delete(worker);
		return 0;
	}
	worker->env.mesh = mesh_create(&worker->daemon->mods, &worker->env);
	if(!worker->env.mesh) {
		log_err("malloc failure");
		worker_delete(worker);
		return 0;
	}
	/* Pass on daemon variables that we would need in the mesh area */
	worker->env.mesh->use_response_ip = worker->daemon->use_response_ip;
	worker->env.mesh->use_rpz = worker->daemon->use_rpz;

	worker->env.detach_subs = &mesh_detach_subs;
	worker->env.attach_sub = &mesh_attach_sub;
	worker->env.add_sub = &mesh_add_sub;
	worker->env.kill_sub = &mesh_state_delete;
	worker->env.detect_cycle = &mesh_detect_cycle;
	worker->env.scratch_buffer = sldns_buffer_new(cfg->msg_buffer_size);
	if(!worker->env.scratch_buffer) {
		log_err("malloc failure");
		worker_delete(worker);
		return 0;
	}
	if(!(worker->env.fwds = forwards_create()) ||
		!forwards_apply_cfg(worker->env.fwds, cfg)) {
		log_err("Could not set forward zones");
		worker_delete(worker);
		return 0;
	}
	if(!(worker->env.hints = hints_create()) ||
		!hints_apply_cfg(worker->env.hints, cfg)) {
		log_err("Could not set root or stub hints");
		worker_delete(worker);
		return 0;
	}
	/* one probe timer per process -- if we have 5011 anchors */
	if(autr_get_num_anchors(worker->env.anchors) > 0
#ifndef THREADS_DISABLED
		&& worker->thread_num == 0
#endif
		) {
		struct timeval tv;
		tv.tv_sec = 0;
		tv.tv_usec = 0;
		worker->env.probe_timer = comm_timer_create(worker->base,
			worker_probe_timer_cb, worker);
		if(!worker->env.probe_timer) {
			log_err("could not create 5011-probe timer");
		} else {
			/* let timer fire, then it can reset itself */
			comm_timer_set(worker->env.probe_timer, &tv);
		}
	}
	/* zone transfer tasks, setup once per process, if any */
	if(worker->env.auth_zones
#ifndef THREADS_DISABLED
		&& worker->thread_num == 0
#endif
		) {
		auth_xfer_pickup_initial(worker->env.auth_zones, &worker->env);
		auth_zones_pickup_zonemd_verify(worker->env.auth_zones,
			&worker->env);
	}
#ifdef USE_DNSTAP
	if(worker->daemon->cfg->dnstap
#ifndef THREADS_DISABLED
		&& worker->thread_num == 0
#endif
		) {
		if(!dt_io_thread_start(dtenv->dtio, comm_base_internal(
			worker->base), worker->daemon->num)) {
			log_err("could not start dnstap io thread");
			worker_delete(worker);
			return 0;
		}
	}
#endif /* USE_DNSTAP */
	worker_mem_report(worker, NULL);
	/* if statistics enabled start timer */
	if(worker->env.cfg->stat_interval > 0) {
		verbose(VERB_ALGO, "set statistics interval %d secs", 
			worker->env.cfg->stat_interval);
		worker_restart_timer(worker);
	}
	return 1;
}