/*
* 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: qss_ctaid.c,v 1.81 2006/11/27 03:24:52 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 "qmgr.h"
#include "log.h"
/*
** QM_SS_CTAID -- close SMTPS transaction: write IBDB record
**
** Parameters:
** qss_ctx -- QMGR/SMTPS context
** qss_ta -- transaction
**
** Returns:
** <0: usual sm_error code: only for severe problems!
** >=0: acceptance/rejection code
**
** Side Effects:
** writes transaction to IBDB
** adds transaction to AQ; does not handle error properly:
** see comments below.
**
** Last code review: 2003-10-22 20:18:56, see comments below!
*/
#define SM_IS_IBDB_DISK_FULL(ret) \
(sm_error_value(ret) == ENOSPC \
|| sm_error_value(ret) == EFBIG \
|| sm_error_value(ret) == EDQUOT)
sm_ret_T
qm_ss_ctaid(qss_ctx_P qss_ctx, qss_ta_P qss_ta)
{
sm_ret_T ret;
ibdb_ta_T ibdb_ta;
const char *func;
SM_IS_QSS_CTX(qss_ctx);
SM_IS_QS_TA(qss_ta);
ret = SM_SUCCESS;
/* Do some checks here: is it ok to accept this mail? */
/*
** assign data to ibdb_ta just for ibdb_ta_status, ibdb_ta is not
** used at all afterwards.
*/
ibdb_ta.ibt_ta_id = qss_ta->qssta_id;
ibdb_ta.ibt_mail_pa = qss_ta->qssta_mail->qsm_pa;
ibdb_ta.ibt_cdb_id = qss_ta->qssta_cdb_id;
ibdb_ta.ibt_nrcpts = qss_ta->qssta_rcpts_tot;
ret = ibdb_ta_status(qss_ctx->qss_qmgr_ctx->qmgr_ibdb, &ibdb_ta,
IBDB_TA_NEW, IBDB_FL_NONE, 0, THR_LOCK_UNLOCK);
if (sm_is_err(ret)) {
func = "ibdb_ta_status";
goto err_write;
}
ret = ibdb_hdrmodl_wr(qss_ctx->qss_qmgr_ctx->qmgr_ibdb,
qss_ta->qssta_hdrmodhd, qss_ta->qssta_id,
IBDB_FL_NONE, THR_LOCK_UNLOCK);
if (sm_is_err(ret)) {
func = "ibdb_hdrmodl_wr";
goto err_write;
}
QSS_TA_SET_FLAG(qss_ta, QSS_TA_FL_IBDB);
/* copy transaction into AQ immediately */
ret = aq_env_add_iqdb(qss_ctx->qss_qmgr_ctx->qmgr_aq, qss_ta,
qss_ctx->qss_qmgr_ctx);
/*
** XXX Error handling is far from optimal!
** Current solution: discard TA (see below).
** Alternatives:
** If the data couldn't be transferred to AQ because it is full
** - try DEFEDB
** - throttle SMTPS and try to add the TA later on to AQ.
** (Note: the transaction is still in IQDB!)
** If none of that works: reject the mail (we can't deal with it).
*/
if (sm_is_err(ret)) {
QM_LEV_DPRINTFC(QDC_Q2S, 0, (QM_DEBFP, "sev=ERROR, func=qm_ss_ctaid, aq_env_add_iqdb=%r\n", ret));
sm_log_write(qss_ctx->qss_qmgr_ctx->qmgr_lctx,
QM_LCAT_SMTPS, QM_LMOD_FROM_SMTPS,
SM_LOG_ERR, 0,
"sev=ERROR, func=qm_ss_ctaid, aq_env_add_iqdb=%m", ret);
if (sm_error_value(ret) == SM_E_FULL || sm_error_value(ret) == ENOMEM)
(void) qss_control(qss_ctx, QMGR_THROTTLE, 100,
QMGR_RFL_AQ_I, THR_LOCK_UNLOCK);
/*
** Simply discard the TA for now, see above.
** This will be done in the caller because we return
** a temporary error, except for ibdb changes.
*/
ret = ibdb_ta_status(qss_ctx->qss_qmgr_ctx->qmgr_ibdb,
&ibdb_ta, IBDB_TA_CANCEL, IBDB_FL_NONE,
0, THR_LOCK_UNLOCK);
if (sm_is_err(ret)) {
sm_log_write(qss_ctx->qss_qmgr_ctx->qmgr_lctx,
QM_LCAT_SMTPS, QM_LMOD_FROM_SMTPS,
SM_LOG_ERR, 0,
"sev=ERROR, func=qm_ss_ctaid, ibdb_ta_status=%m",
ret);
}
ret = SMTP_R_TEMP;
goto error;
}
else { /* currently not really required because of the goto above */
/*
** No error; why don't we remove the entry from IQDB now?
** See qda_upd_iqdb(), currently it uses qss_ta to update
** IBDB; maybe this can be changed to use data from AQ?
*/
(void) qss_control(qss_ctx, QMGR_THROTTLE, ret, QMGR_RFL_AQ_I,
THR_LOCK_UNLOCK);
QSS_TA_SET_FLAG(qss_ta, QSS_TA_FL_AQ);
}
return SMTP_R_OK;
err_write:
/*
** Disk full? Need to clean up IBDB or otherwise "wait" for free space.
*/
if (SM_IS_IBDB_DISK_FULL(ret)) {
(void) qss_control(qss_ctx, QMGR_THROTTLE, 100, QMGR_RFL_IBD_I,
THR_LOCK_UNLOCK);
sm_log_write(qss_ctx->qss_qmgr_ctx->qmgr_lctx,
QM_LCAT_SMTPS,
QM_LMOD_FROM_SMTPS,
SM_LOG_ALERT, 0,
"sev=ALERT, func=qm_ss_ctaid, %s=%m, status=disk_space_exceeded"
, func, ret);
}
else if (sm_error_value(ret) == ENOMEM) {
(void) qss_control(qss_ctx, QMGR_THROTTLE, 100, QMGR_RFL_MEM_I,
THR_LOCK_UNLOCK);
sm_log_write(qss_ctx->qss_qmgr_ctx->qmgr_lctx,
QM_LCAT_SMTPS,
QM_LMOD_FROM_SMTPS,
SM_LOG_ALERT, 0,
"sev=ALERT, func=qm_ss_ctaid, %s=%m, status=ENOMEM"
, func, ret);
}
else {
sm_log_write(qss_ctx->qss_qmgr_ctx->qmgr_lctx,
QM_LCAT_SMTPS,
QM_LMOD_FROM_SMTPS,
SM_LOG_ERR, 0,
"sev=ERROR, func=qm_ss_ctaid, %s=%m"
, func, ret);
}
/* change the error code to a temporary rejection XXX */
ret = SMTP_R_TEMP;
error:
sm_log_write(qss_ctx->qss_qmgr_ctx->qmgr_lctx,
QM_LCAT_SMTPS,
QM_LMOD_FROM_SMTPS,
SM_LOG_ERR, 1,
"sev=ERROR, func=qm_ss_ctaid, ret=%m", ret);
return ret;
}
/*
** QM_2SS_CTAID -- Compose reply to "close TA", put data into RCB entry
**
** Parameters:
** qss_ctx -- QMGR/SMTPS context
** qss_ta -- transaction
** rcbe -- RCB entry (must be open for encoding)
** status -- status code
**
** Returns:
** usual sm_error code
**
** Called by:
** q_ibdb_commit() (group commit)
** qm_fr_ss_react() (if something goes wrong when CTAID is received
** from SMTPS)
**
** Last code review: 2003-10-23 00:57:57
*/
sm_ret_T
qm_2ss_ctaid(qss_ctx_P qss_ctx, qss_ta_P qss_ta, sm_rcbe_P rcbe, int status)
{
sm_rcb_P rcb;
sm_ret_T ret;
SM_IS_QSS_CTX(qss_ctx);
SM_IS_QS_TA(qss_ta);
rcb = &rcbe->rcbe_rcb;
ret = sm_rcb_putv(rcb, RCB_PUTV_FIRST,
SM_RCBV_INT, RT_PROT_VER, PROT_VER_RT,
SM_RCBV_INT, RT_Q2S_ID, qss_ctx->qss_id,
SM_RCBV_BUF, RT_Q2S_TAID, qss_ta->qssta_id, SMTP_STID_SIZE,
SM_RCBV_INT, RT_Q2S_STAT, (uint32_t) status,
SM_RCBV_END);
/* can be simplified [return ret;] if debug output below is removed */
if (sm_is_err(ret))
goto error;
QM_LEV_DPRINTTC(QDC_Q2S, 1, (QM_DEBFP, "func=qm_2ss_ctaid, cdb-id=%C, stat=%d\n", qss_ta->qssta_cdb_id, status), qss_ctx->qss_qmgr_ctx->qmgr_ev_ctx->evthr_c_time);
return ret;
error:
return ret;
}
syntax highlighted by Code2HTML, v. 0.9.1