/*
* Copyright (c) 2004, 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: pmilter_smtps.c,v 1.12 2006/10/05 04:27:38 ca Exp $")
#include "sm/error.h"
#include "sm/assert.h"
#include "sm/io.h"
#include "sm/rcb.h"
#include "pmilter.h"
#if MTA_USE_PMILTER
/*
** SM_PMILT2SMTPS -- PMILTER - SMTPS interface
** Called if socket is writable.
**
** Parameters:
** tsk -- evthr task
**
** Returns:
** usual sm_error code
**
** Last code review:
*/
static sm_ret_T
sm_pmilt2smtps(sm_evthr_task_P tsk)
{
sm_ret_T ret;
pmss_ctx_P pmss_ctx;
SM_IS_EVTHR_TSK(tsk);
pmss_ctx = (pmss_ctx_P) tsk->evthr_t_actx;
SM_IS_PMSS_CTX(pmss_ctx);
ret = sm_rcbcom2mod(tsk, &pmss_ctx->pmss_com);
return ret;
}
/*
** SM_PMILT_SMTPS -- PMILTER - SMTPS interface
** This runs as a task.
**
** Parameters:
** tsk -- evthr task
**
** Returns:
** usual sm_error code
*/
static sm_ret_T
sm_pmilt_smtps(sm_evthr_task_P tsk)
{
sm_ret_T ret;
SM_IS_EVTHR_TSK(tsk);
PM_LEV_DPRINTF(3, (PM_DEBFP, "sev=DBG, func=sm_pmilt_smtps, fd=%d, ev_rq=%x, ev_occ=%x\n", tsk->evthr_t_fd, evthr_rqevents(tsk), tsk->evthr_t_evocc));
if (is_valid_fd(tsk->evthr_t_fd))
{
ret = EVTHR_WAITQ;
if (evthr_got_slp(tsk))
{
#if 0
sm_ret_T res;
/* don't set ret here, it's the wrong return value */
res = sm_smtps_wakeup(tsk);
if (sm_is_err(res))
{
PM_LEV_DPRINTF(3, (PM_DEBFP, "sev=DBG, func=sm_pmilt_smtps, sm_smtps_wakeup=%x\n", res));
}
#endif /* 0 */
}
if (evthr_got_wr(tsk))
{
ret = sm_pmilt2smtps(tsk);
if (sm_is_err(ret))
{
sm_io_fprintf(smioerr,
"sev=DBG, func=sm_pmilt_smtps, sm_pmilt2smtps=%x\n", ret);
/* really return here? */
return ret;
}
}
if (evthr_got_rd(tsk))
{
/*
** This routine could set EVTHR_EV_WR
** to cause data to be written back to the SMTPS.
** However, most of the routines may work
** asynchronously and hence they should return the
** correct value themselves.
*/
ret = sm_smtps2pmilt(tsk);
if (sm_is_err(ret))
{
sm_io_fprintf(smioerr,
"sev=DBG, func=sm_pmilt_smtps, sm_smtps2pmilt=%x\n", ret);
return ret;
}
}
PM_LEV_DPRINTF(3, (PM_DEBFP, "sev=DBG, func=sm_pmilt_smtps, ret=%x\n", ret));
return ret;
}
return EVTHR_DEL;
}
/*
** SM_PMILT_SMTPSLI -- Handle new connections from SMTPS
** This runs as a (listen) task.
**
** Parameters:
** tsk -- evthr task
**
** Returns:
** usual sm_error code
**
** Last code review:
*/
sm_ret_T
sm_pmilt_smtpsli(sm_evthr_task_P tsk)
{
int fd, r;
uint u;
uint32_t j;
sm_ret_T ret;
sm_evthr_task_P task;
pmg_ctx_P pmg_ctx;
pmss_ctx_P pmss_ctx;
SM_IS_EVTHR_TSK(tsk);
SM_REQUIRE(tsk->evthr_t_nc != NULL);
fd = INVALID_FD;
pmg_ctx = (pmg_ctx_P) tsk->evthr_t_actx;
SM_IS_PMG_CTX(pmg_ctx);
#if 0
PM_LEV_DPRINTF(3, (PM_DEBFP, "func=sm_pmilt_smtpsli, status=new_connection\n"));
#endif /* 0 */
/* add the new connection */
if (tsk->evthr_t_nc != NULL
&& is_valid_fd(fd = tsk->evthr_t_nc->evthr_a_fd))
{
r = pthread_mutex_lock(&pmg_ctx->pmg_mutex);
SM_LOCK_OK(r);
if (r != 0)
{
/* LOG */
sm_io_fprintf(smioerr,
"sev=ERROR, func=sm_pmilt_smtpsli, cannot get lock=%d\n", r);
goto error;
}
if (pmg_ctx->pmg_ssnfd >= SM_ARRAY_SIZE(pmg_ctx->pmg_sctx))
{
/* LOG */
/* too many: don't accept it */
/* XXX maybe turn off accept job if max is reached? */
sm_io_fprintf(smioerr,
"sev=ERROR, func=sm_pmilt_smtpsli, too many connections\n");
goto err2;
}
pmss_ctx = NULL;
/* search for free sss ctx */
for (j = 1, u = 0; u < SM_ARRAY_SIZE(pmg_ctx->pmg_sctx);
u++, j *= 2)
{
if ((pmg_ctx->pmg_sused & j) == 0)
{
pmg_ctx->pmg_sused |= j;
pmss_ctx = pmg_ctx->pmg_sctx[u];
#if 0
pmss_ctx->pmss_status = PMSS_ST_NONE;
#endif /* 0 */
pmss_ctx->pmss_id = PMSS_ID_NONE;
pmss_ctx->pmss_bit = j;
break;
}
}
if (u >= SM_ARRAY_SIZE(pmg_ctx->pmg_sctx))
{
/* see above */
sm_io_fprintf(smioerr,
"sev=ERROR, func=sm_pmilt_smtpsli, no free connection\n");
goto err2;
}
ret = sm_rcb_open_rcv(pmss_ctx->pmss_com.rcbcom_rdrcb);
if (sm_is_err(ret))
{
sm_io_fprintf(smioerr,
"sev=ERROR, func=sm_pmilt_smtpsli, sm_rcb_open_rcv failed=%x\n",
ret);
goto err3;
}
ret = sm_fd_nonblock(fd, true);
if (sm_is_err(ret))
{
sm_io_fprintf(smioerr,
"sev=ERROR, func=sm_pmilt_smtpsli, sm_fd_nonblock=%x\n",
ret);
goto err3;
}
pmg_ctx->pmg_ssnfd++;
/* start a task for the new SMTPS */
ret = evthr_task_new(pmg_ctx->pmg_ev_ctx, &task,
EVTHR_EV_RD, fd, NULL, sm_pmilt_smtps,
pmss_ctx);
if (sm_is_err(ret))
{
sm_io_fprintf(smioerr,
"sev=ERROR, func=sm_pmilt_smtpsli, evthr_task_new failed=%x\n",
ret);
goto err3;
}
else
{
PM_LEV_DPRINTF(3, (PM_DEBFP,
"sev=DBG, func=sm_pmilt_smtpsli, fd=%d, task=%p\n"
, fd, task));
}
SM_IS_EVTHR_TSK(task);
pmss_ctx->pmss_com.rcbcom_tsk = task;
}
r = pthread_mutex_unlock(&pmg_ctx->pmg_mutex);
SM_ASSERT(r == 0);
/* r isn't checked further; will fail on next iteration */
return EVTHR_WAITQ;
err3:
pmg_ctx->pmg_sused &= ~j;
err2:
r = pthread_mutex_unlock(&pmg_ctx->pmg_mutex);
SM_ASSERT(r == 0);
/* r isn't checked further; will fail on next iteration */
error:
if (is_valid_fd(fd))
close(fd);
return EVTHR_WAITQ;
}
#endif /* MTA_USE_PMILTER */
syntax highlighted by Code2HTML, v. 0.9.1