/*
 * Copyright (c) 2003-2006 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_li.c,v 1.15 2006/04/02 06:34:20 ca Exp $")
#include "sm/error.h"
#include "sm/assert.h"
#include "sm/memops.h"
#include "smar.h"
#include "sm/qmgr-int.h"
#include "log.h"

/*
**  SMAR_LI -- Handle new connections
**
**	Parameters:
**		tsk -- evthr task
**
**	Returns:
**		EVTHR_WAITQ
**
**	Last code review:
**	Last code change: 2006-03-10 06:27:33
*/

sm_ret_T
smar_li(sm_evthr_task_P tsk)
{
	int fd, r, i;
	uint32_t j;
	sm_ret_T ret;
	sm_evthr_task_P	task;
	smar_ctx_P smar_ctx;
	smar_clt_ctx_P smar_clt_ctx;

	SM_IS_EVTHR_TSK(tsk);
	SM_REQUIRE(tsk->evthr_t_nc != NULL);
	smar_ctx = (smar_ctx_P) tsk->evthr_t_actx;
	SM_IS_SMAR_CTX(smar_ctx);

	SMAR_LEV_DPRINTF(5, (SMAR_DEBFP, "sev=DBG, func=smar_li, new connection\n"));

	fd = tsk->evthr_t_nc->evthr_a_fd;
	if (!is_valid_fd(fd))
	{
		sm_log_write(smar_ctx->smar_lctx,
			AR_LCAT_RESOLVER, AR_LMOD_RESOLVER,
			SM_LOG_ERROR, 6,
			"sev=ERROR, func=smar_li, fd=%d", fd);
		return EVTHR_WAITQ;
	}

	/* add the new connection */
	r = pthread_mutex_lock(&smar_ctx->smar_mutex);
	SM_LOCK_OK(r);
	if (r != 0)
	{
		sm_log_write(smar_ctx->smar_lctx,
			AR_LCAT_RESOLVER, AR_LMOD_RESOLVER,
			SM_LOG_CRIT, 1,
			"sev=CRIT, func=smar_li, lock=%d",
			r);
		goto error;
	}
	SMAR_LEV_DPRINTF(6, (SMAR_DEBFP, "sev=DBG, func=smar_li, got lock\n"));

	/* search for free client context */
	for (j = 1, i = 0; i < SMAR_MAX_CLTS; i++, j *= 2)
	{
		if ((smar_ctx->smar_clt_used & j) == 0)
		{
			smar_ctx->smar_clt_used |= j;
			smar_clt_ctx = smar_ctx->smar_clt_ctx[i];
			SM_IS_SMAR_CLT_CTX(smar_clt_ctx);
			smar_clt_ctx->smac_status = SMAC_ST_NONE;
			smar_clt_ctx->smac_bit = j;
			smar_clt_ctx->smac_idx = i;
			break;
		}
	}
	if (i >= SMAR_MAX_CLTS)
	{
		sm_log_write(smar_ctx->smar_lctx,
			AR_LCAT_RESOLVER, AR_LMOD_RESOLVER,
			SM_LOG_ERROR, 4,
			"sev=ERROR, func=smar_li, status=too_many_connections");
		goto err2;
	}

	SMAR_LEV_DPRINTF(5, (SMAR_DEBFP, "sev=DBG, func=smar_li, i=%d, clt_ctx=%p\n", i, smar_clt_ctx));
	ret = sm_rcb_open_rcv(smar_clt_ctx->smac_com_ctx.rcbcom_rdrcb);
	if (sm_is_err(ret))
	{
		sm_log_write(smar_ctx->smar_lctx,
			AR_LCAT_RESOLVER, AR_LMOD_RESOLVER,
			SM_LOG_ERROR, 4,
			"sev=ERROR, func=smar_li, sm_rcb_open_rcv=%m"
			, ret);
		goto err2;
	}

	ret = sm_fd_nonblock(fd, true);
	if (sm_is_err(ret))
	{
		sm_log_write(smar_ctx->smar_lctx,
			AR_LCAT_RESOLVER, AR_LMOD_RESOLVER,
			SM_LOG_ERROR, 4,
			"sev=ERROR, func=smar_li, sm_fd_nonblock=%m"
			, ret);
		goto err2;
	}

	/* start a task for the new client */
	ret = evthr_task_new(smar_ctx->smar_ev_ctx, &task,
			EVTHR_EV_RD, fd, NULL, smar_clt,
			(void *) smar_clt_ctx);
	if (sm_is_err(ret))
	{
		sm_log_write(smar_ctx->smar_lctx,
			AR_LCAT_RESOLVER, AR_LMOD_RESOLVER,
			SM_LOG_ERROR, 4,
			"sev=ERROR, func=smar_li, evthr_task_new=%m"
			, ret);
		goto err2;
	}
	SM_IS_EVTHR_TSK(task);
	EVTHRT_SET_FLAG(task, EVTHRT_FL_BLK_RD);
	smar_clt_ctx->smac_com_ctx.rcbcom_tsk = task;
	SMAR_LEV_DPRINTF(6, (SMAR_DEBFP, "sev=DBG, func=smar_li, new tsk=%p, fd=%d\n", task, task->evthr_t_fd));
	r = pthread_mutex_unlock(&smar_ctx->smar_mutex);
	return EVTHR_WAITQ;

  err2:
	r = pthread_mutex_unlock(&smar_ctx->smar_mutex);
  error:
	if (is_valid_fd(fd))
		close(fd);
	return EVTHR_WAITQ;
}


syntax highlighted by Code2HTML, v. 0.9.1