/*
* 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: qm_to_ar.c,v 1.69 2007/06/04 04:58:39 ca Exp $")
#include "sm/error.h"
#include "sm/assert.h"
#include "sm/io.h"
#include "sm/rcb.h"
#include "sm/qmgr.h"
#include "sm/qmgr-int.h"
#include "sm/reccom.h"
#include "sm/smar.h"
#include "sm/da.h"
#include "qmgr.h"
/*
** QM2AR -- Send recipient data to AR, i.e., put it into RCB
**
** Parameters:
** qmgr_ctx -- QMGR context
** aq_rcpt -- aq_rcpt
** rcbe -- RCB entry
**
** Returns:
** usual sm_error code (from sm_rcb_putv())
**
** Side Effects: fills in rcb
** if error: rcb might have partial content
**
** Locking: aq_ctx (aq_rcpt) must be locked by caller (to read aq_rcpt)
**
** Last code review: 2003-10-17 17:22:58
** Last code change:
*/
static sm_ret_T
qm2ar(qmgr_ctx_P qmgr_ctx, aq_rcpt_P aq_rcpt, sm_rcbe_P rcbe)
{
sm_rcb_P rcb;
sm_ret_T ret;
rcpt_id_T rcpt_id;
rcb = &rcbe->rcbe_rcb;
sm_snprintf(rcpt_id, sizeof(rcpt_id), SMTP_RCPTID_FORMAT,
aq_rcpt->aqr_ss_ta_id, aq_rcpt->aqr_idx);
/* send rcpt_idx and ta_id separately?? */
ret = sm_rcb_putv(rcb, RCB_PUTV_FIRST,
SM_RCBV_INT, RT_PROT_VER, PROT_VER_RT,
SM_RCBV_BUF, RT_Q2R_RCPT_ID, rcpt_id, SMTP_RCPTID_SIZE,
SM_RCBV_STR, RT_Q2R_RCPT_PA, aq_rcpt->aqr_pa,
SM_RCBV_INT, RT_Q2R_FLAGS,
(AQR_IS_FLAG(aq_rcpt, AQR_FL_ALIAS)
? SMARRQ_FL_NONE : SMARRQ_FL_ALIAS|SMARRQ_FL_OWNER|SMARRQ_FL_VERP)|
#if MTA_USE_TLS
(QCNF_IS_FLAG(qmgr_ctx, QCNF_FL_SC_LKP_RCPT_CONF)
? SMARRQ_FL_CONF : SMARRQ_FL_NONE)|
#endif
SMARRQ_FL_CHK_LU,
#if MTA_USE_TLS
SM_RCBV_INT,
(qmgr_ctx->qmgr_cnf.q_cnf_sc_lfl != SMMAP_LFL_NONE)
? RT_R2Q_RCPT_CNF_LKP_FL : RT_NOSEND,
qmgr_ctx->qmgr_cnf.q_cnf_sc_lfl,
#endif
SM_RCBV_INT, RT_Q2R_TIMEOUT,
(aq_rcpt->aqr_tries == 0 ||
aq_rcpt->aqr_err_st != DA_AR_ERR ||
aq_rcpt->aqr_status != SMTP_AR_TEMP)
? 0
: (aq_rcpt->aqr_tries < 5)
? (qmgr_ctx->qmgr_cnf.q_cnf_tmo_ar / 6 - aq_rcpt->aqr_tries)
: (qmgr_ctx->qmgr_cnf.q_cnf_tmo_ar / 2)
, SM_RCBV_END);
if (sm_is_err(ret)) goto error;
return ret;
error:
/* XXX leave rcb in a consistent state? */
QM_LEV_DPRINTFC(QDC_Q2A, 1, (QM_DEBFP, "sev=ERROR, func=qr2ar, ret=%r, rcpt_id=%s\n", ret, rcpt_id));
return ret;
}
/*
** QMGR_RCPT2AR -- send a recipient to SMAR; append to wait queue
**
** Parameters:
** qmgr_ctx -- QMGR context
** aq_rcpt -- aq_rcpt
** locktype -- kind of locking
**
** Returns:
** usual sm_error code; SM_E_NO_AR, ENOMEM, SM_E_RANGE,
** SM_E_OVFLW_NS, etc
**
** Side Effects: always add rcpt to wait queue
** if ok: increase aq_ta->aqt_rcpts_ar
**
** Locking:
** aq_ctx (aq_rcpt/aq_ta) can be locked here (locktype),
** otherwise it must be locked by caller.
**
**
** Note: Caller has to enable WR for qar_task, e.g.,
** evthr_en_wr(qmgr_ctx->qmgr_ar_tsk)
**
** Last code review:
** Last code change: 2006-03-30 02:44:09
*/
sm_ret_T
qmgr_rcpt2ar(qmgr_ctx_P qmgr_ctx, aq_rcpt_P aq_rcpt, thr_lock_T locktype)
{
sm_ret_T ret;
int r;
sm_evthr_task_P qar_tsk;
qar_ctx_P qar_ctx;
sm_rcbe_P rcbe;
aq_ta_P aq_ta;
aq_ctx_P aq_ctx;
time_T exp;
SM_IS_QMGR_CTX(qmgr_ctx);
SM_IS_AQ_RCPT(aq_rcpt);
qar_ctx = qmgr_ctx->qmgr_ar_ctx;
SM_IS_QAR_CTX(qar_ctx);
qar_tsk = qmgr_ctx->qmgr_ar_tsk;
aq_ctx = qmgr_ctx->qmgr_aq;
SM_IS_AQ(aq_ctx);
rcbe = NULL;
if (thr_lock_it(locktype)) {
r = pthread_mutex_lock(&aq_ctx->aq_mutex);
SM_LOCK_OK(r);
if (r != 0)
return sm_error_perm(SM_EM_AQ, r);
}
/* always add recipient to wait queue for cleanup to work */
(void) aq_waitq_add(qmgr_ctx->qmgr_aq, aq_rcpt, 0, AQWQ_AR, false);
exp = aq_waitq_first_tmo(qmgr_ctx->qmgr_aq, AQWQ_AR, false);
if (exp > 0)
(void) qmgr_set_aq_cleanup(qmgr_ctx->qmgr_cleanup_ctx, exp, true);
else
QM_LEV_DPRINTFC(QDC_Q2A, 3, (QM_DEBFP, "func=qmgr_rcpt2ar, exp=%7ld\n", (long) exp));
/* there might be no task... */
if (NULL == qar_tsk) {
/*
** XXX Need to ask MCP to start SMAR?
** Not really, MCP notices when a component fails and
** starts it itself (unless it fails too often).
**
** XXX Need to (un)throttle SMTPS, probably somewhere in
** qm_fr_ss.c; use qss_control().
*/
QM_LEV_DPRINTTC(QDC_Q2A, 3, (QM_DEBFP, "func=qmgr_rcpt2ar, qar_tsk=NULL\n"),
qmgr_ctx->qmgr_ev_ctx->evthr_c_time);
ret = sm_error_temp(SM_EM_Q_Q2AR, SM_E_NO_AR);
QMGR_SET_SFLAG(qmgr_ctx, QMGR_SFL_AR);
goto error;
}
if (QMGR_IS_SFLAG(qmgr_ctx, QMGR_SFL_AR))
QMGR_CLR_SFLAG(qmgr_ctx, QMGR_SFL_AR);
aq_ta = aq_rcpt->aqr_ss_ta;
SM_IS_AQ_TA(aq_ta);
ret = sm_rcbe_new_enc(&rcbe, -1, 0);
if (sm_is_err(ret)) goto error;
ret = qm2ar(qmgr_ctx, aq_rcpt, rcbe);
if (sm_is_err(ret)) goto error;
ret = sm_rcbcom_endrep(&qar_ctx->qar_com, qar_tsk, true, &rcbe);
if (sm_is_err(ret)) goto error;
AQR_SET_FLAG(aq_rcpt, AQR_FL_SENT2AR);
if (!AQR_IS_FLAG(aq_rcpt, AQR_FL_IS_BNC|AQR_FL_IS_DBNC))
++aq_ta->aqt_rcpts_ar;
QM_LEV_DPRINTTC(QDC_Q2A, 3, (QM_DEBFP, "func=qmgr_rcpt2ar, status=ok, aqt_rcpts_ar=%u, rcpt_id=%s, rcpt_pa=%S\n"
, aq_ta->aqt_rcpts_ar, aq_rcpt->aqr_ss_ta_id, aq_rcpt->aqr_pa), qmgr_ctx->qmgr_ev_ctx->evthr_c_time);
if (thr_unl_no_err(locktype)) {
r = pthread_mutex_unlock(&aq_ctx->aq_mutex);
SM_ASSERT(r == 0);
if (r != 0 && sm_is_success(ret))
ret = sm_error_perm(SM_EM_AQ, r);
}
return SM_SUCCESS;
error:
if (thr_unl_if_err(locktype)) {
r = pthread_mutex_unlock(&aq_ctx->aq_mutex);
SM_ASSERT(r == 0);
if (r != 0 && sm_is_success(ret))
ret = sm_error_perm(SM_EM_AQ, r);
}
if (rcbe != NULL)
sm_rcbe_free(rcbe);
QM_LEV_DPRINTFC(QDC_Q2A, 1, (QM_DEBFP, "sev=ERROR, func=qmgr_rcpt2ar, ret=%r\n", ret));
return ret;
}
/*
** QMGR2AR -- QMGR - AR interface
**
** Parameters:
** tsk -- evthr task
**
** Returns:
** usual sm_error code
*/
sm_ret_T
qm_to_ar(sm_evthr_task_P tsk)
{
qar_ctx_P qar_ctx;
SM_IS_EVTHR_TSK(tsk);
qar_ctx = (qar_ctx_P) tsk->evthr_t_actx;
SM_IS_QAR_CTX(qar_ctx);
QM_LEV_DPRINTFC(QDC_Q2A, 6, (QM_DEBFP, "func=qm_to_ar, tsk=%p\n", tsk));
return sm_rcbcom2mod(tsk, &qar_ctx->qar_com);
}
syntax highlighted by Code2HTML, v. 0.9.1