/*
 * Copyright (c) 2002-2005 Sendmail, Inc. and its suppliers.
 *	All rights reserved.
 *
 * By using this file, you agree to the terms and conditions set
 * forth in the LICENSE file which can be found at the top level of
 * the sendmail distribution.
 */

#include "sm/generic.h"
SM_RCSID("@(#)$Id: smar_start.c,v 1.51 2007/06/18 04:42:31 ca Exp $")
#include "sm/error.h"
#include "sm/assert.h"
#include "sm/map.h"
#include "smar.h"
#include "sm/unixsock.h"
#include "sm/signal.h"
#include "sm/misc.h"
#include "log.h"

/*
**  SMAR_STLI -- start SMAR listeners
**
**	Parameters:
**		smar_ctx -- SMAR context
**
**	Returns:
**		usual sm_error code
**
**	Question: should we store "task" in smar_ctx?
*/

static sm_ret_T
smar_stli(smar_ctx_P smar_ctx)
{
	int lfd, r;
	sm_ret_T ret;
	sm_evthr_task_P task;

	SM_IS_SMAR_CTX(smar_ctx);

	/* start listen connections */
	/* these should be in smar_ctx after the configuration has been read */

	/* QMGR */
	(void) unlink(smar_ctx->smar_cnf.smar_cnf_sock_abs);
	lfd = unix_server_listen(smar_ctx->smar_cnf.smar_cnf_sock_abs, 10);
	if (!is_valid_fd(lfd)) {
		ret = sm_error_perm(SM_EM_AR, errno);
		sm_log_write(smar_ctx->smar_lctx,
			AR_LCAT_INIT, AR_LMOD_COMM,
			SM_LOG_ERROR, 1,
			"sev=ERROR, func=smar_start, socket=%.256s, server_listen=%m",
			smar_ctx->smar_cnf.smar_cnf_sock_abs, ret);
		goto error;
	}
	r = chmod(smar_ctx->smar_cnf.smar_cnf_sock_abs, 0660);
	if (r < 0 && errno != ENOENT) {
		ret = sm_error_perm(SM_EM_AR, errno);
		sm_log_write(smar_ctx->smar_lctx,
			AR_LCAT_INIT, AR_LMOD_COMM,
			SM_LOG_ERROR, 1,
			"sev=ERROR, func=smar_stli, socket=%.256s, chmod=%m",
			smar_ctx->smar_cnf.smar_cnf_sock_abs, ret);
		goto error;
	}
#if 0
	smar_ctx->smar_sslfd = lfd;
#endif /* 0 */
	ret = evthr_task_new(smar_ctx->smar_ev_ctx, &task, EVTHR_EV_LI,
			lfd, NULL, smar_li, (void *) smar_ctx);
	if (sm_is_err(ret))
		goto error;

	return SM_SUCCESS;

  error:
	if (is_valid_fd(lfd))
		close(lfd);
	return ret;
}

#if SMAR_USE_DNS
/*
**  SMAR_DNS_START -- start DNS system for SMAR
**
**	Parameters:
**		smar_ctx -- SMAR context
**
**	Returns:
**		usual sm_error code
*/

static sm_ret_T
smar_dns_start(smar_ctx_P smar_ctx)
{
	sm_ret_T ret;
	uint u;
	dns_tsk_P dns_tsk;

	for (u = 0; u < smar_ctx->smar_dns_ntsks; u++) {
		dns_tsk = NULL;
		ret = dns_tsk_new(smar_ctx->smar_dns_mgr_ctx,
			smar_ctx->smar_cnf.smar_cnf_dns_flags,
			smar_ctx->smar_nameserveripv4s[u], &dns_tsk);
		if (sm_is_err(ret))
			goto error;
		dns_tsk->dnstsk_maxtimeouts = smar_ctx->smar_cnf.smar_cnf_dns_max_tmos;
	}
	ret = dns_tsk_start(smar_ctx->smar_dns_mgr_ctx, smar_ctx->smar_ev_ctx);
	if (sm_is_err(ret))
		goto error;
	return SM_SUCCESS;

  error:
	/* XXX How to clean up? */
	if (smar_ctx->smar_dns_mgr_ctx != NULL) {
		dns_mgr_ctx_del(smar_ctx->smar_dns_mgr_ctx);
		smar_ctx->smar_dns_mgr_ctx = NULL;
	}
	return ret;
}
#endif /* SMAR_USE_DNS */

/*
**  SMAR_USR1 -- task handler for SIGUSR1
**	reopen maps
**
**	Parameters:
**		tsk -- evthr task
**
**	Returns:
**		usual sm_error code
*/

static sm_ret_T
smar_usr1(sm_evthr_task_P tsk)
{
	sm_ret_T ret;
	smar_ctx_P smar_ctx;
	char stats[256];

	SM_IS_EVTHR_TSK(tsk);
	smar_ctx = (smar_ctx_P) tsk->evthr_t_actx;
	SM_IS_SMAR_CTX(smar_ctx);

	if (smar_ctx->smar_ev_ctx != NULL) {
		time_T now;

		now = evthr_time(smar_ctx->smar_ev_ctx);
		sm_io_fprintf(smioerr, "[");
		(void) sm_timestamp(now, smioerr);
		sm_io_fprintf(smioerr, "] sev=INFO, where=smar_usr1\n");
	}

#if SM_HEAP_CHECK
	if (HEAP_CHECK)
		sm_heap_report(smioerr, 3);
#endif /* SM_HEAP_CHECK */

	stats[0] = '\0';
	bht_stats(smar_ctx->smar_dns_mgr_ctx->dnsmgr_req_ht, stats, sizeof(stats));
	sm_io_fprintf(smioerr,
		"dns_ht_size=%u\n"
		"dns_ht_used=%u\n"
		"dns_ht_limit=%u\n"
		"%s"
		, smar_ctx->smar_dns_mgr_ctx->dnsmgr_req_ht->bht_size
		, smar_ctx->smar_dns_mgr_ctx->dnsmgr_req_ht->bht_used
		, smar_ctx->smar_dns_mgr_ctx->dnsmgr_req_ht->bht_limit
		, stats
		);

	smar_prt_cnf(&smar_ctx->smar_cnf, smioerr, true);

	if (smar_ctx->smar_aliases != NULL) {
		ret = sm_map_reopen(smar_ctx->smar_aliases, 0, SMPO_END);
		if (sm_is_err(ret)) {
			sm_io_fprintf(smioerr,
				"sev=ERROR, func=smar_usr1, map=aliases, reopen=%m\n"
				, ret);
			/* XXX close map first? */
			smar_ctx->smar_aliases = NULL;
		}
	}
	if (smar_ctx->smar_access != NULL) {
		ret = sm_map_reopen(smar_ctx->smar_access, 0, SMPO_END);
		if (sm_is_err(ret)) {
			sm_io_fprintf(smioerr,
				"sev=ERROR, func=smar_usr1, map=access, reopen=%m\n"
				, ret);
			/* XXX close map first? */
			smar_ctx->smar_access = NULL;
		}
	}
	if (smar_ctx->smar_mt_map != NULL) {
		ret = sm_map_reopen(smar_ctx->smar_mt_map, 0, SMPO_END);
		if (sm_is_err(ret)) {
			sm_io_fprintf(smioerr,
				"sev=ERROR, func=smar_usr1, map=mt, reopen=%m\n"
				, ret);
		}
	}
	return EVTHR_WAITQ;
}

/*
**  SMAR_USR2 -- task handler for SIGUSR2
**
**	Parameters:
**		tsk -- evthr task
**
**	Returns:
**		usual sm_error code
*/

static sm_ret_T
smar_usr2(sm_evthr_task_P tsk)
{
	smar_ctx_P smar_ctx;

	SM_IS_EVTHR_TSK(tsk);
	smar_ctx = (smar_ctx_P) tsk->evthr_t_actx;
	SM_IS_SMAR_CTX(smar_ctx);
	(void) sm_log_reopen(smar_ctx->smar_lctx);

	return EVTHR_WAITQ;
}

/*
**  SMAR_START -- start SMAR
**
**	Parameters:
**		smar_ctx -- SMAR context
**
**	Returns:
**		usual sm_error code
*/

sm_ret_T
smar_start(smar_ctx_P smar_ctx)
{
	sm_ret_T ret;
	sm_evthr_task_P task;

	SM_IS_SMAR_CTX(smar_ctx);

#if SMAR_USE_DNS
	ret = smar_dns_start(smar_ctx);
	if (sm_is_err(ret)) {
		sm_log_write(smar_ctx->smar_lctx,
			AR_LCAT_INIT, AR_LMOD_COMM,
			SM_LOG_ERROR, 1,
			"sev=ERROR, func=smar_start, smar_dns_start=%m",
			ret);
		goto error;
	}
#endif /* SMAR_USE_DNS */

	ret = evthr_task_new(smar_ctx->smar_ev_ctx, &task, EVTHR_EV_SG,
			SIGUSR1, NULL, smar_usr1, (void *) smar_ctx);
	if (sm_is_err(ret)) {
		sm_log_write(smar_ctx->smar_lctx,
			AR_LCAT_INIT, AR_LMOD_COMM,
			SM_LOG_ERROR, 1,
			"sev=ERROR, func=smar_start, smar_usr1=%m",
			ret);
		goto error;
	}

	ret = evthr_task_new(smar_ctx->smar_ev_ctx, &task, EVTHR_EV_SG,
			SIGUSR2, NULL, smar_usr2, (void *) smar_ctx);
	if (sm_is_err(ret)) {
		sm_log_write(smar_ctx->smar_lctx,
			AR_LCAT_INIT, AR_LMOD_COMM,
			SM_LOG_ERROR, 1,
			"sev=ERROR, func=smar_start, smar_usr2=%m",
			ret);
		goto error;
	}

	ret = smar_stli(smar_ctx);
	if (sm_is_err(ret)) {
		sm_log_write(smar_ctx->smar_lctx,
			AR_LCAT_INIT, AR_LMOD_COMM,
			SM_LOG_ERROR, 1,
			"sev=ERROR, func=smar_start, smar_stli=%m",
			ret);
		goto error;
	}
	smar_ctx->smar_status = SMAR_ST_START;
	return SM_SUCCESS;

  error:
	return ret;
}


syntax highlighted by Code2HTML, v. 0.9.1