/*
* Copyright (c) 2002-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: clt2ar.c,v 1.93 2007/06/03 17:03:04 ca Exp $")
#include "sm/error.h"
#include "sm/assert.h"
#include "sm/memops.h"
#include "sm/io.h"
#include "sm/net.h"
#include "sm/rcb.h"
#include "sm/mta.h"
#include "sm/rfc2821.h"
#include "smar.h"
#include "reverse.h"
#include "log.h"
#include "sm/qmgrcomm.h"
#include "sm/reccom.h"
/*
** SMAR_SET_MAX_THRDS -- set maximum number of threads
**
** Parameters:
** smar_ctx -- SMAR context
**
** Returns:
** usual sm_error code
**
** input: smar_ctx->smar_max_reqs
** Side Effects: may change number of threads in evthr and values
** in smar_ctx
**
** Last code review:
** Last code change:
*/
static sm_ret_T
smar_set_max_threads(smar_ctx_P smar_ctx)
{
#if SMAR_SET_MAX_THREADS
SMAR_LEV_DPRINTF(4, (SMAR_DEBFP,
"sev=DBG, func=smar_set_max_threads, max_reqs=%u, max_thrds_s=%u, max_thrds_h=%u\n",
smar_ctx->smar_max_reqs, smar_ctx->smar_max_thrds_s,
smar_ctx->smar_max_thrds_h));
if (smar_ctx->smar_max_reqs <= smar_ctx->smar_max_thrds_s)
return SM_SUCCESS;
smar_ctx->smar_max_thrds_s = smar_ctx->smar_max_reqs;
if (smar_ctx->smar_max_thrds_s <= smar_ctx->smar_cnf.smar_cnf_maxthr)
return SM_SUCCESS;
if (smar_ctx->smar_max_thrds_s > smar_ctx->smar_max_thrds_h)
{
smar_ctx->smar_max_thrds_h = smar_ctx->smar_max_thrds_s * 2;
/* overflow? */
if (smar_ctx->smar_max_thrds_s > smar_ctx->smar_max_thrds_h)
smar_ctx->smar_max_thrds_h = UINT_MAX;
evthr_set_max_h(smar_ctx->smar_ev_ctx,
smar_ctx->smar_max_thrds_h);
}
evthr_set_max_s(smar_ctx->smar_ev_ctx, smar_ctx->smar_max_thrds_s);
#endif /* SMAR_SET_MAX_THREADS */
return SM_SUCCESS;
}
/*
** SMAR_REACT -- Decode data received from client and act accordingly
**
** Parameters:
** smar_clt_ctx -- SMAR client context
** tsk -- evthr task
**
** Returns:
** usual sm_error code
**
** Last code review:
** Last code change:
*/
static sm_ret_T
smar_react(smar_clt_ctx_P smar_clt_ctx, sm_evthr_task_P tsk)
{
uint32_t v, l, rt, tl;
sm_ret_T ret, res;
sm_rcb_P rcb;
sm_rcbe_P rcbe;
bool inwaitq;
smar_rcpt_P smar_rcpt;
smar_rcpts_P smar_rcpts;
smar_ctx_P smar_ctx;
SM_IS_SMAR_CLT_CTX(smar_clt_ctx);
smar_ctx = smar_clt_ctx->smac_ar_ctx;
SM_IS_SMAR_CTX(smar_ctx);
ret = res = SM_SUCCESS;
inwaitq = false;
smar_rcpt = NULL;
smar_rcpts = NULL;
rcbe = NULL;
/* Decode rcb */
rcb = smar_clt_ctx->smac_com_ctx.rcbcom_rdrcb;
ret = sm_rcb_open_dec(rcb);
if (sm_is_err(ret))
goto error;
/* Total length of record */
ret = sm_rcb_getuint32(rcb, &tl);
if (sm_is_err(ret) || tl > QM_AR_MAX_REC_LEN || tl > sm_rcb_getlen(rcb)) {
res = sm_error_perm(SM_EM_AR_Q2AR, EINVAL);
goto err2;
}
/* protocol header: version */
ret = sm_rcb_get3uint32(rcb, &l, &rt, &v);
if (sm_is_err(ret) || l != 4 || rt != RT_PROT_VER || v != PROT_VER_RT) {
res = sm_error_perm(SM_EM_AR_Q2AR, EINVAL);
goto err2;
}
/* what's the protocol? */
/*
QMGR -> AR:
RT_Q2R_RCPT_ID: rcpt_id
RT_Q2R_RCPT_PA: rcpt_pa
RT_Q2R_FLAGS: flags for resolver
SMTPS -> AR:
RT_S2A_NID SMTPS id
RT_S2A_ID SMTPS id
RT_S2A_TAID transaction id
RT_S2A_RCPT rcpt to
RT_S2A_RCPT_IDX rcpt idx
RT_S2A_LTYPE lookup type
RT_S2A_LFLAGS lookup flags
*/
ret = sm_rcb_get2uint32(rcb, &l, &rt);
if (sm_is_err(ret)) {
res = ret;
goto err2;
}
/* SMTPS -> AR; this is slightly ugly, put it into a different fct? */
if (l == 4 && rt == RT_S2A_NID)
{
SMAR_LEV_DPRINTF(2, (SMAR_DEBFP, "sev=DBG, func=smar_react, got=RT_S2A_NID\n"));
ret = sm_rcb_getuint32(rcb, &v);
if (sm_is_err(ret)) {
res = ret;
goto err2;
}
ret = sm_rcb_get3uint32(rcb, &l, &rt, &v);
if (sm_is_err(ret) || l != 4 || rt != RT_S2A_MAXTHRDS) {
SMAR_LEV_DPRINTF(0, (SMAR_DEBFP, "sev=DBG, func=smar_react, l=%d, rt=%X, expected=RT_S2A_MAXTHRDS\n", l, rt));
res = sm_error_perm(SM_EM_AR_Q2AR, EINVAL);
goto err2;
}
/* SM_ASSERT(smar_clt_ctx->smac_idx >= 0); */
SM_ASSERT(smar_clt_ctx->smac_idx <
SM_ARRAY_SIZE(smar_ctx->smar_clt_reqs));
smar_ctx->smar_clt_reqs[smar_clt_ctx->smac_idx] = v;
smar_ctx->smar_max_reqs += v;
(void) smar_set_max_threads(smar_ctx);
/* ignore return value... */
ret = sm_rcb_get3uint32(rcb, &l, &rt, &v);
if (sm_is_err(ret) || l != 4 || rt != RT_S2A_FLAGS) {
res = sm_error_perm(SM_EM_AR_Q2AR, EINVAL);
goto err2;
}
smar_clt_ctx->smac_cl_flags = v;
if (SM_IS_FLAG(smar_clt_ctx->smac_cl_flags, SMARCL_FL_ACC) &&
!SMAR_IS_FLAG(smar_ctx, SMAR_FL_HASACCESS))
{
sm_log_write(smar_ctx->smar_lctx,
AR_LCAT_COMM, AR_LMOD_FROM_QMGR,
SM_LOG_ERROR, 2,
"sev=ERROR, func=smar_react, where=startup, status=access map requested but not available");
}
/* question: Send a reply?? e.g., "connection accepted"? */
goto done;
}
else if (l == 4 && rt == RT_S2A_ID) {
smar_addr_P smar_addr;
/* from SMTPS.... */
/* do something about it */
smar_addr = NULL;
ret = smar_addr_new(smar_clt_ctx, &smar_addr);
if (sm_is_err(ret))
goto err_a;
ret = sm_rcb_getuint32(rcb, &v);
if (sm_is_err(ret)) {
res = ret;
goto err2;
}
smar_addr->ara_id = v;
ret = sm_rcb_get2uint32(rcb, &l, &rt);
if (sm_is_err(ret) || l != SMTP_STID_SIZE
|| (rt != RT_S2A_TAID && rt != RT_S2A_SEID))
{
res = sm_error_perm(SM_EM_AR_Q2AR, EINVAL);
goto err_a;
}
ret = sm_rcb_getn(rcb, (uchar *) (smar_addr->ara_taid), l);
if (sm_is_err(ret))
goto err_a;
ret = sm_rcb_get2uint32(rcb, &l, &rt);
if (sm_is_err(ret)
|| (rt != RT_S2A_RCPT && rt != RT_S2A_MAIL
&& rt != RT_S2A_CLT_A && rt != RT_S2A_CERTISS
&& rt != RT_S2A_EHLO
)
)
{
res = sm_error_perm(SM_EM_AR_Q2AR, EINVAL);
goto err_a; /* check also l? too large? */
}
ret = sm_rcb_getnstr(rcb, &smar_addr->ara_pa, l);
SMAR_LEV_DPRINTF(4, (SMAR_DEBFP, "sev=DBG, func=smar_react, pa=%S, ret=%r\n", smar_addr->ara_pa, ret));
if (sm_is_err(ret))
goto err_a;
if (RT_S2A_RCPT == rt) {
ret = sm_rcb_get3uint32(rcb, &l, &rt, &v);
if (sm_is_err(ret) || l != 4 || rt != RT_S2A_RCPT_IDX) {
res = sm_error_perm(SM_EM_AR_Q2AR, EINVAL);
goto err_a;
}
}
else
v = 0; /* dummy rcpt index... use a different one? */
smar_addr->ara_rcpt_idx = (rcpt_idx_T) v;
/* lookup type and flags are transferred in one entry */
ret = sm_rcb_get4uint32(rcb, &l, &rt, &v, &tl);
if (sm_is_err(ret) || l != 8 || rt != RT_S2A_LTYPE) {
res = sm_error_perm(SM_EM_AR_Q2AR, EINVAL);
goto err_a;
}
smar_addr->ara_ltype = v;
smar_addr->ara_lflags = tl;
/* don't check DNS BLs if none is configured */
if (SMARA_IS_LFLAG(smar_addr, SMARA_LFL_DNSBL) &&
!SMAR_IS_FLAG(smar_ctx, SMAR_FL_HASDNSBL))
{
SMARA_CLR_LFLAG(smar_addr, SMARA_LFL_DNSBL);
#if 0
/* currently SMTPS always requests this */
if (!SMAR_IS_FLAG(smar_ctx, SMAR_FL_DNSBLCOMPL)) {
sm_log_write(smar_ctx->smar_lctx, AR_LCAT_COMM,
AR_LMOD_FROM_QMGR, SM_LOG_ERROR, 2,
"sev=ERROR, func=smar_react, status=dnsbl requested but not available");
/* NOT locked! */
SMAR_SET_FLAG(smar_ctx, SMAR_FL_DNSBLCOMPL);
}
#endif
}
/* don't try greylisting if it isn't configured */
if (SM_IS_FLAG(smar_addr->ara_ltype, SMARA_LT_GREY) &&
!SMAR_IS_FLAG(smar_ctx, SMAR_FL_HASGREY))
{
SM_CLR_FLAG(smar_addr->ara_ltype, SMARA_LT_GREY);
if (!SMAR_IS_FLAG(smar_ctx, SMAR_FL_GREYCOMPL)) {
sm_log_write(smar_ctx->smar_lctx, AR_LCAT_COMM,
AR_LMOD_FROM_QMGR, SM_LOG_ERROR, 2,
"sev=ERROR, func=smar_react, status=greylisting requested but not available");
/* NOT locked! */
SMAR_SET_FLAG(smar_ctx, SMAR_FL_GREYCOMPL);
}
}
/* don't try access map if it isn't configured */
if (SM_IS_FLAG(smar_addr->ara_ltype, SMAR_LT_ACCESS) &&
!SMAR_IS_FLAG(smar_ctx, SMAR_FL_HASACCESS))
{
if (!SMAR_IS_FLAG(smar_ctx, SMAR_FL_ACCESSCOMPL)) {
sm_log_write(smar_ctx->smar_lctx,
AR_LCAT_COMM, AR_LMOD_FROM_QMGR,
SM_LOG_ERROR, 2,
"sev=ERROR, func=smar_react, status=access map requested but not available");
/* NOT locked! */
SMAR_SET_FLAG(smar_ctx, SMAR_FL_ACCESSCOMPL);
}
}
while (!SM_RCB_ISEOB(rcb)) {
ret = sm_rcb_get2uint32(rcb, &l, &rt);
if (sm_is_err(ret)) {
res = sm_error_perm(SM_EM_AR_Q2AR, EINVAL);
goto err_a;
}
switch (rt)
{
case RT_S2A_MAIL: /* for protected rcpt */
case RT_S2A_CERTSUB:
ret = sm_rcb_getnstr(rcb, &smar_addr->ara_pa2, l);
if (sm_is_err(ret))
goto err_a;
break;
case RT_S2A_IPV4: /* protected rcpt, greylisting */
if (l != 4) {
res = sm_error_perm(SM_EM_AR_Q2AR, EINVAL);
goto err_a;
}
ret = sm_rcb_getuint32(rcb, &v);
if (sm_is_err(ret))
goto err_a;
smar_addr->ara_ipv4 = v;
SMARA_SET_FLAG(smar_addr, SMARA_FL_RCVDIPV4);
break;
case RT_S2A_TIME: /* greylisting */
if (8 == l) {
uint64_t ul;
ret = sm_rcb_getuint64(rcb, &ul);
if (sm_is_err(ret))
goto err_a;
smar_addr->ara_conn_time = ul;
}
else if (4 == l) {
ret = sm_rcb_getuint32(rcb, &v);
if (sm_is_err(ret))
goto err_a;
smar_addr->ara_conn_time = v;
}
else {
res = sm_error_perm(SM_EM_AR_Q2AR, EINVAL);
goto err_a;
}
break;
default:
res = sm_error_perm(SM_EM_AR_Q2AR, EINVAL);
goto err_a;
}
}
ret = sm_rcbcom_prerep(&smar_clt_ctx->smac_com_ctx, tsk, &rcbe);
if (sm_is_err(ret))
goto err_a;
inwaitq = true;
smar_addr->ara_rcbe = rcbe;
/* call the correct function based on type! */
if (SM_IS_FLAG(smar_addr->ara_ltype, SMARA_LT_RCPT_LOCAL))
ret = smar_addr_check(smar_ctx, smar_addr);
else
ret = smar_access_check(smar_ctx, smar_addr);
if (sm_is_err(ret))
goto error; /* need more cleanup here? */
return SMAR_R_ASYNC;
err_a:
smar_addr_free(smar_addr);
goto error;
}
else if (l == SMTP_STID_SIZE && rt == RT_C2A_SEID) {
/* RT_C2A_* is currently only for t-smar-rvrs-0! */
smar_rvrs_P smar_rvrs;
/* from SMTPS.... */
/* do something about it */
smar_rvrs = NULL;
ret = smar_rvrs_new(smar_ctx, smar_clt_ctx, &smar_rvrs);
if (sm_is_err(ret))
goto err_c;
ret = sm_rcb_getn(rcb, (uchar *) (smar_rvrs->arv_seid), l);
if (sm_is_err(ret))
goto err_c;
ret = sm_rcb_get3uint32(rcb, &l, &rt, &v);
if (sm_is_err(ret) || l != 4 || rt != RT_C2A_IPV4) {
res = sm_error_perm(SM_EM_AR_Q2AR, EINVAL);
goto err_c; /* check also l? too large? */
}
smar_rvrs->arv_ipv4 = v;
/* lookup type and flags are transferred in one entry */
ret = sm_rcb_get4uint32(rcb, &l, &rt, &v, &tl);
if (sm_is_err(ret) || l != 8 || rt != RT_C2A_LTYPE) {
res = sm_error_perm(SM_EM_AR_Q2AR, EINVAL);
goto err_c;
}
smar_rvrs->arv_ltype = v;
smar_rvrs->arv_lflags = tl;
smar_rvrs->arv_cbf = smar_rvrs_re;
ret = sm_rcbcom_prerep(&smar_clt_ctx->smac_com_ctx, tsk, &rcbe);
if (sm_is_err(ret))
goto err_c;
inwaitq = true;
smar_rvrs->arv_rcbe = rcbe;
ret = smar_rvrs_rslv(smar_ctx, smar_rvrs, 0u);
if (sm_is_err(ret))
goto err_c; /* need more cleanup here? */
return SMAR_R_ASYNC;
err_c:
smar_rvrs_free(smar_rvrs);
goto error;
}
if (l != SMTP_RCPTID_SIZE || rt != RT_Q2R_RCPT_ID)
goto err2;
ret = smar_rcpts_new(smar_ctx, smar_clt_ctx, &smar_rcpts);
if (sm_is_err(ret))
goto err2;
ret = smar_rcpt_new(&smar_rcpt);
if (sm_is_err(ret))
goto err2;
smar_rcpts->arrs_rcpt = smar_rcpt;
SMARR_SET_FLAG(smar_rcpt, SMARR_FL_ORCPT);
ret = sm_rcb_getn(rcb, (uchar *) (smar_rcpt->arr_id), l);
if (sm_is_err(ret))
goto err2;
RCPT_ID_COPY(smar_rcpts->arrs_rcpt_id, smar_rcpt->arr_id);
ret = sm_rcb_get2uint32(rcb, &l, &rt);
if (sm_is_err(ret) || rt != RT_Q2R_RCPT_PA) { /* check l? too large? */
res = sm_error_perm(SM_EM_AR_Q2AR, EINVAL);
goto err2;
}
ret = sm_rcb_getnstr(rcb, &smar_rcpt->arr_pa, l);
SMAR_LEV_DPRINTF(4, (SMAR_DEBFP, "sev=DBG, func=smar_react, pa=%S, ret=%r\n", smar_rcpt->arr_pa, ret));
if (sm_is_err(ret))
goto err2;
ret = sm_rcb_get3uint32(rcb, &l, &rt, &v);
if (sm_is_err(ret) || l != 4 || rt != RT_Q2R_FLAGS) {
SMAR_LEV_DPRINTF(0, (SMAR_DEBFP, "sev=ERROR, func=smar_react, rt=%#x, v=%d, l=%d, ret=%r, res=%r\n", rt, v, l, ret, res));
res = sm_error_perm(SM_EM_AR_Q2AR, EINVAL);
goto err2;
}
smar_rcpt->arr_rqflags = v;
smar_rcpt->arr_cnf_lfl = SMMAP_LFL_ALL|SMMAP_LFL_NOAT; /* default */
if (!SM_RCB_ISEOB(rcb) &&
sm_is_success(sm_rcb_peek2uint32(rcb, &l, &rt)) &&
4 == l && RT_R2Q_RCPT_CNF_LKP_FL == rt)
{
ret = sm_rcb_get3uint32(rcb, &l, &rt, &v);
if (sm_is_err(ret) || l != 4 || rt != RT_R2Q_RCPT_CNF_LKP_FL) {
SMAR_LEV_DPRINTF(0, (SMAR_DEBFP, "sev=ERROR, func=smar_react, rt=%#x, v=%d, l=%d, ret=rx, res=rx\n", rt, v, l, ret, res));
res = sm_error_perm(SM_EM_AR_Q2AR, EINVAL);
goto err2;
}
smar_rcpt->arr_cnf_lfl = v;
}
if (!SM_RCB_ISEOB(rcb)) {
ret = sm_rcb_get3uint32(rcb, &l, &rt, &v);
if (sm_is_err(ret) || l != 4 || rt != RT_Q2R_TIMEOUT) {
SMAR_LEV_DPRINTF(0, (SMAR_DEBFP, "sev=ERROR, func=smar_react, rt=%#x, v=%d, l=%d, ret=rx, res=rx\n", rt, v, l, ret, res));
res = sm_error_perm(SM_EM_AR_Q2AR, EINVAL);
goto err2;
}
smar_rcpt->arr_timeout = v;
}
ret = sm_rcbcom_prerep(&smar_clt_ctx->smac_com_ctx, tsk, &rcbe);
if (sm_is_err(ret)) {
SMAR_LEV_DPRINTF(0, (SMAR_DEBFP, "sev=ERROR, func=smar_react, sm_rcbcom_prerep=%r\n", ret));
goto err0;
}
inwaitq = true;
res = SMAR_R_ASYNC;
/* XXX Check proper cleanup of data: who free()s what? */
SMARR_SET_FLAG(smar_rcpt, SMARR_FL_A4MT);
smar_rcpts->arrs_rcbe = rcbe;
ret = smar_rcpt_rslv(smar_ctx, smar_rcpts);
smar_rcpt = NULL; /* smar_rcpt_rslv() took over responsibility */
smar_rcpts = NULL; /* smar_rcpt_rslv() took over responsibility */
if (sm_is_err(ret)) {
/* in which case is this a fatal error? none? */
SMAR_LEV_DPRINTF(0, (SMAR_DEBFP, "sev=ERROR, func=smar_react, smar_rcpt_rslv=%r\n", ret));
/* need more cleanup here? */
goto errret;
}
return SMAR_R_ASYNC;
done:
ret = sm_rcb_close_dec(smar_clt_ctx->smac_com_ctx.rcbcom_rdrcb);
(void) sm_rcb_open_rcv(smar_clt_ctx->smac_com_ctx.rcbcom_rdrcb);
if (ret == SM_SUCCESS && inwaitq)
return SMAR_R_ASYNC;
return ret;
/* preserve original error code! */
err2:
if (!inwaitq) {
/* use rcb functions that don't check the state */
(void) sm_rcb_close_decn(smar_clt_ctx->smac_com_ctx.rcbcom_rdrcb);
}
error:
if (!inwaitq) {
/* open rcb for receiving next record */
(void) sm_rcb_open_rcvn(smar_clt_ctx->smac_com_ctx.rcbcom_rdrcb);
}
err0:
(void) smar_rcpt_free(smar_rcpt, NULL);
(void) smar_rcpts_free(smar_rcpts);
errret:
sm_log_write(smar_ctx->smar_lctx, AR_LCAT_COMM,
AR_LMOD_FROM_QMGR, SM_LOG_ERROR, 0,
"sev=ERROR, func=smar_react, status=%#x, rt=%#x, v=%d, l=%d, ret=%m, res=%m",
smar_ctx->smar_status, rt, v, l, ret, res);
return res;
}
/*
** SMAR_CLT_CLOSE -- close connection to client
**
** Parameters:
** tsk -- evthr task
**
** Returns:
** usual sm_error code
*/
static sm_ret_T
smar_clt_close(sm_evthr_task_P tsk)
{
smar_clt_ctx_P smar_clt_ctx;
smar_ctx_P smar_ctx;
SM_IS_EVTHR_TSK(tsk);
smar_clt_ctx = (smar_clt_ctx_P) tsk->evthr_t_actx;
SM_IS_SMAR_CLT_CTX(smar_clt_ctx);
smar_ctx = smar_clt_ctx->smac_ar_ctx;
SM_IS_SMAR_CTX(smar_ctx);
close(tsk->evthr_t_fd);
/* See comment in qm_fr_ss()!! */
tsk->evthr_t_fd = INVALID_FD;
smar_ctx->smar_clt_used &= ~(smar_clt_ctx->smac_bit);
smar_clt_ctx->smac_bit = 0;
smar_clt_ctx->smac_status = SMAC_ST_NONE;
/* "close" client context... put this into a function? */
/* SM_ASSERT(smar_clt_ctx->smac_idx >= 0); */
SM_ASSERT(smar_clt_ctx->smac_idx < SM_ARRAY_SIZE(smar_ctx->smar_clt_reqs));
smar_ctx->smar_max_reqs -= smar_ctx->smar_clt_reqs[smar_clt_ctx->smac_idx];
smar_ctx->smar_clt_reqs[smar_clt_ctx->smac_idx] = 0;
smar_clt_ctx->smac_idx = UINT32_MAX;
/* more cleanup? */
sm_rcb_close_decn(smar_clt_ctx->smac_com_ctx.rcbcom_rdrcb);
smar_clt_ctx->smac_com_ctx.rcbcom_tsk = NULL;
return SM_SUCCESS;
}
/*
** SMAR_CLT2AR -- client - AR interface
** invoked by smar_clt() to deal with RCB receiption
**
** Parameters:
** tsk -- evthr task
**
** Returns:
** usual sm_error code
*/
static sm_ret_T
smar_clt2ar(sm_evthr_task_P tsk)
{
int fd;
sm_ret_T ret;
smar_clt_ctx_P smar_clt_ctx;
smar_ctx_P smar_ctx;
SM_IS_EVTHR_TSK(tsk);
smar_clt_ctx = (smar_clt_ctx_P) tsk->evthr_t_actx;
SM_IS_SMAR_CLT_CTX(smar_clt_ctx);
smar_ctx = smar_clt_ctx->smac_ar_ctx;
SM_IS_SMAR_CTX(smar_ctx);
fd = tsk->evthr_t_fd; /* checked in caller */
ret = sm_rcb_rcv(fd, smar_clt_ctx->smac_com_ctx.rcbcom_rdrcb,
QSS_RC_MINSZ);
SMAR_LEV_DPRINTF(5, (SMAR_DEBFP, "sev=DBG, func=smar_clt2ar, fd=%d, ret=%r, buf=%d, len=%d, smar_status=%#x\n",
fd, ret, smar_clt_ctx->smac_com_ctx.rcbcom_rdrcb->sm_rcb_base[0], sm_rcb_getlen(smar_clt_ctx->smac_com_ctx.rcbcom_rdrcb), smar_ctx->smar_status));
if (ret > 0) {
#if 0
if (buf[0] == 'Q')
return EVTHR_TERM|EVTHR_DEL;
#endif /* 0 */
return EVTHR_WAITQ;
}
else if (0 == ret) {
ret = sm_rcb_close_rcv(smar_clt_ctx->smac_com_ctx.rcbcom_rdrcb);
/* start appropriate function ... */
ret = smar_react(smar_clt_ctx, tsk);
SMAR_LEV_DPRINTF(5, (SMAR_DEBFP, "sev=DBG, func=smar_clt2ar, sm_smar_react=%r\n", ret));
if (sm_is_err(ret))
goto termit; /* too harsh? */
else if (SMAR_R_WAITQ == ret)
return EVTHR_WAITQ;
else if (SMAR_R_ASYNC == ret)
return EVTHR_OK;
else if (EVTHR_DEL == ret)
goto termit; /* terminate this client */
else
return ret;
}
else if (SM_IO_EOF == ret) {
ret = sm_rcb_close_rcv(smar_clt_ctx->smac_com_ctx.rcbcom_rdrcb);
termit:
SMAR_LEV_DPRINTF(1, (SMAR_DEBFP, "sev=DBG, func=smar_clt2ar, task=%p, status=terminate, ret=%r\n", smar_clt_ctx->smac_com_ctx.rcbcom_tsk, ret));
(void) smar_clt_close(tsk);
return EVTHR_DEL;
}
else /* if (ret < 0) */
{
sm_log_write(smar_ctx->smar_lctx,
AR_LCAT_COMM, AR_LMOD_FROM_QMGR,
SM_LOG_ERROR, 0,
"sev=ERROR, func=smar_clt2ar, ret=%m, errno=%d"
, ret, errno);
goto termit;
}
sm_log_write(smar_ctx->smar_lctx,
AR_LCAT_COMM, AR_LMOD_FROM_QMGR,
SM_LOG_ERROR, 0,
"sev=ERROR, func=smar_clt2ar, fd=%d", fd);
#if 0
error:
#endif
return EVTHR_DEL;
}
/*
** SMAR_AR2CLT -- SMAR 2 client (QMGR/SMTPS) interface
**
** Parameters:
** tsk -- evthr task
**
** Returns:
** usual sm_error code
*/
static sm_ret_T
smar_ar2clt(sm_evthr_task_P tsk)
{
smar_clt_ctx_P smar_clt_ctx;
SM_IS_EVTHR_TSK(tsk);
smar_clt_ctx = (smar_clt_ctx_P) tsk->evthr_t_actx;
SM_IS_SMAR_CLT_CTX(smar_clt_ctx);
SMAR_LEV_DPRINTF(5, (SMAR_DEBFP, "smar_ar2clt: tsk=%p, fd=%d\n", tsk, tsk->evthr_t_fd));
return sm_rcbcom2mod(tsk, &smar_clt_ctx->smac_com_ctx);
}
/*
** SMAR_CLT -- SMAR - client interface
** This runs as a task.
**
** Parameters:
** tsk -- evthr task
**
** Returns:
** usual sm_error code
*/
sm_ret_T
smar_clt(sm_evthr_task_P tsk)
{
sm_ret_T ret;
SM_IS_EVTHR_TSK(tsk);
if (is_valid_fd(tsk->evthr_t_fd)) {
/*
** Note: The first call is not allowed to put the
** task back into the wait queue since then the second
** function acts on a "non-locked" tsk.
*/
ret = EVTHR_WAITQ;
SMAR_LEV_DPRINTF(5, (SMAR_DEBFP, "sev=DBG, func=smar_clt, tsk=%p, flags=%#x, fd=%d\n", tsk, tsk->evthr_t_evocc, tsk->evthr_t_fd));
if (evthr_got_wr(tsk)) {
ret = smar_ar2clt(tsk);
if (sm_is_err(ret))
goto error;
}
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 = smar_clt2ar(tsk);
if (sm_is_err(ret))
goto error;
}
return ret;
}
return EVTHR_DEL;
error:
(void) smar_clt_close(tsk);
return EVTHR_DEL;
}
syntax highlighted by Code2HTML, v. 0.9.1