/*
* Copyright (c) 2003-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.
*
* $Id: wribdb.c,v 1.41 2007/06/18 04:42:30 ca Exp $
*/
#include "sm/qmibdb.h"
#ifndef DONTWR
#define dontwr(iter, id_count, rcpt_idx, isrcpt) false
#endif
#ifndef TACANCEL
#define tacancel(iter, id_count) false
#endif
/* flags for IBDB open() */
#define WRIBDB_FL_NONE 0x0000U
#define WRIBDB_FL_INCOMPL 0x0001U
#define WRIBDB_FL_RANDOM 0x0002U
#define WRIBDB_FL_HDR_PRE 0x0010U
#define WRIBDB_FL_HDR_APP 0x0020U
#define WRIBDB_FL_HDR_REM 0x0040U
#define WRIBDB_FL_LONG 0x0100U
#define WRIBDB_FL_1OPENTA 0x0200U
#define WRIBDB_FL_TRUNCATE 0x0400U
#define WRIBDB_FL_TRUNCATED 0x0800U
#define WRIBDB_IS_FLAG(flags, fl) (((flags) & (fl)) != 0)
/* context for *_action() calls (and probably others later on) */
typedef struct cl_ctx_S cl_ctx_T, *cl_ctx_P;
struct cl_ctx_S
{
ibdb_ctx_P clx_ibdbc;
bht_P clx_bht;
bht_P clx_bhr;
};
static int rand_mod = 10;
static int long_str_len = 600;
static char *long_str = NULL;
static int rcpts_per_ta = 0;
/*
** TA_CLOSE -- Close transactions (callback function)
**
** Parameters:
** info -- bht entry
** ctx -- context
**
** Returns:
** usual sm_error code
*/
static sm_ret_T
ta_close(bht_entry_P info, void *ctx)
{
sm_ret_T ret;
ibdb_ta_P ibdb_ta;
cl_ctx_P cl_ctx;
ibdb_ctx_P ibdb_ctx;
cl_ctx = (cl_ctx_P) ctx;
ibdb_ctx = cl_ctx->clx_ibdbc;
ibdb_ta = (ibdb_ta_P) info->bhe_value;
if (ibdb_ta->ibt_ta_id == NULL)
return sm_err_perm(EINVAL);
if (rand() % rand_mod == 0)
{
rcpt_id_T rcpt_id;
uint j;
ibdb_rcpt_P ibdb_rcptf;
#if SM_TEST_PRT
if (debug > 1)
{
sm_io_fprintf(smioout, "CLOSE TA(%p): ",
ibdb_ta);
sm_io_fprintf(smioout, "ta=%s, ",
ibdb_ta->ibt_ta_id);
sm_io_fprintf(smioout, "cdb=%C, ",
ibdb_ta->ibt_cdb_id);
sm_io_fprintf(smioout, "mail_pa=%S, ",
ibdb_ta->ibt_mail_pa);
sm_io_fprintf(smioout, "nrcpts=%d, ",
ibdb_ta->ibt_nrcpts);
sm_io_fprintf(smioout, "\n");
sm_io_flush(smioout);
}
#endif /* SM_TEST_PRT */
for (j = 0; j < ibdb_ta->ibt_nrcpts; j++)
{
sm_snprintf(rcpt_id, SMTP_RCPTID_SIZE,
SMTP_RCPTID_FORMAT,
ibdb_ta->ibt_ta_id,
(rcpt_idx_T) j);
ibdb_rcptf = bht_find(cl_ctx->clx_bhr, rcpt_id,
SMTP_RCPTID_SIZE);
if (ibdb_rcptf == NULL)
continue;
#if SM_TEST_PRT
if (debug > 1)
{
sm_io_fprintf(smioout, "CLOSE ALSO RCPT:(%p) ta=%s, ",
ibdb_rcptf, ibdb_ta->ibt_ta_id);
sm_io_fprintf(smioout, "rcpt_idx=%d, ", j);
sm_io_fprintf(smioout, "\n");
sm_io_flush(smioout);
}
#endif /* SM_TEST_PRT */
/* XXX HACK */
ret = ibdb_rcpt_status(ibdb_ctx, ibdb_rcptf,
IBDB_RCPT_DONE, IBDB_FL_NOROLL,
THR_LOCK_UNLOCK);
SM_TEST(ret == SM_SUCCESS);
bht_rm(cl_ctx->clx_bhr, rcpt_id, SMTP_RCPTID_SIZE,
ibdb_rcpt_free, NULL);
}
#if SM_TEST_PRT
if (debug > 1)
{
sm_io_fprintf(smioout, "2CLOSE TA(%p): ",
ibdb_ta);
sm_io_fprintf(smioout, "ta=%s, ",
ibdb_ta->ibt_ta_id);
sm_io_fprintf(smioout, "cdb=%C, ",
ibdb_ta->ibt_cdb_id);
sm_io_fprintf(smioout, "mail_pa=%S, ",
ibdb_ta->ibt_mail_pa);
sm_io_fprintf(smioout, "nrcpts=%d, ",
ibdb_ta->ibt_nrcpts);
sm_io_fprintf(smioout, "\n");
sm_io_flush(smioout);
}
#endif /* SM_TEST_PRT */
ret = ibdb_ta_status(ibdb_ctx, ibdb_ta, IBDB_TA_DONE,
IBDB_FL_NONE, 0, THR_LOCK_UNLOCK);
SM_TEST(ret == SM_SUCCESS);
bht_rm(cl_ctx->clx_bht, ibdb_ta->ibt_ta_id, SMTP_STID_SIZE,
ibdb_ta_free, NULL);
}
return SM_SUCCESS;
}
/*
** RCPT_CLOSE -- Close recipient (callback function)
**
** Parameters:
** info -- bht entry
** ctx -- context
**
** Returns:
** usual sm_error code
*/
static sm_ret_T
rcpt_close(bht_entry_P info, void *ctx)
{
sm_ret_T ret;
ibdb_rcpt_P ibdb_rcpt;
cl_ctx_P cl_ctx;
ibdb_ctx_P ibdb_ctx;
cl_ctx = (cl_ctx_P) ctx;
ibdb_ctx = cl_ctx->clx_ibdbc;
ibdb_rcpt = (ibdb_rcpt_P) info->bhe_value;
if (ibdb_rcpt->ibr_ta_id == NULL)
return sm_err_perm(EINVAL);
if (rand() % rand_mod == 0)
{
rcpt_id_T rcpt_id;
#if SM_TEST_PRT
if (debug > 1)
{
sm_io_fprintf(smioout, "CLOSE RCPT: ta=%s, ",
ibdb_rcpt->ibr_ta_id);
sm_io_fprintf(smioout, "rcpt_pa=%S, ",
ibdb_rcpt->ibr_pa);
sm_io_fprintf(smioout, "rcpt_idx=%d, ",
ibdb_rcpt->ibr_idx);
sm_io_fprintf(smioout, "\n");
}
#endif /* SM_TEST_PRT */
ret = ibdb_rcpt_status(ibdb_ctx, ibdb_rcpt, IBDB_RCPT_DONE,
IBDB_FL_NOROLL, THR_LOCK_UNLOCK);
SM_TEST(ret == SM_SUCCESS);
sm_snprintf(rcpt_id, SMTP_RCPTID_SIZE,
SMTP_RCPTID_FORMAT,
ibdb_rcpt->ibr_ta_id,
ibdb_rcpt->ibr_idx);
bht_rm(cl_ctx->clx_bhr, rcpt_id, SMTP_RCPTID_SIZE,
ibdb_rcpt_free, NULL);
}
return SM_SUCCESS;
}
/*
** TESTIDB -- write INCEDB records
**
** Parameters:
** base_dir -- name of base directory (can by NULL)
** iter -- number of iterations (transactions)
** maxs -- maximum size of an INCEDB file
** flags -- flags, see above
** bht -- hash table for transactions (might be NULL)
** bhr -- hash table for recipients (might be NULL)
**
** Returns:
** usual sm_error code.
*/
static int
testidbwr(const char *base_dir, int iter, int maxs, uint flags, bht_P bht, bht_P bhr)
{
int i, j, nrcpts;
sm_ret_T ret;
ibdb_ctx_P ibdb_ctx;
ibdb_ta_P ibdb_ta;
ibdb_rcpt_P ibdb_rcpt;
sessta_id_T ta_id;
char cdb[32];
id_count_T id_count;
bht_entry_P bhte;
rcpt_id_P rcpt_id;
cl_ctx_T cl_ctx;
ibdb_hdrmod_P ibdb_hdrmod;
char hdr[SM_MAXHDRLEN];
/* XXX either use proper free/new functions or don't free entries... */
long_str = NULL;
id_count = 1; /* better for testing (reproducible) than time(NULLT); */
ret = ibdb_open(base_dir, FNAME, SM_IO_WRONLY, init_seq, maxs,
IBDB_OFL_WRITE, NULLPTR, &ibdb_ctx);
SM_TEST(ret == SM_SUCCESS);
if (ret != SM_SUCCESS)
{
sm_io_fprintf(smioerr, "ibdb_open=%#x\n", ret);
return ret;
}
ibdb_rcpt = NULL;
ibdb_ta = (ibdb_ta_P) sm_zalloc(sizeof(*ibdb_ta));
SM_TEST(ibdb_ta != NULL);
if (ibdb_ta == NULL)
goto end;
ibdb_ta->ibt_ta_id = ta_id;
ibdb_ta->ibt_mail_pa = sm_str_new(NULL, 256, 256);
SM_TEST(ibdb_ta->ibt_mail_pa != NULL);
if (ibdb_ta->ibt_mail_pa == NULL)
goto end;
ibdb_rcpt = (ibdb_rcpt_P) sm_zalloc(sizeof(*ibdb_rcpt));
SM_TEST(ibdb_rcpt != NULL);
if (ibdb_rcpt == NULL)
goto end;
ibdb_rcpt->ibr_ta_id = ta_id;
ibdb_rcpt->ibr_pa = sm_str_new(NULL, 256, 256);
SM_TEST(ibdb_rcpt->ibr_pa != NULL);
if (ibdb_rcpt->ibr_pa == NULL)
goto end;
ibdb_hdrmod = (ibdb_hdrmod_P) sm_zalloc(sizeof(*ibdb_hdrmod));
SM_TEST(ibdb_hdrmod != NULL);
if (ibdb_hdrmod == NULL)
goto end;
ibdb_hdrmod->ibh_ta_id = ta_id;
if (WRIBDB_IS_FLAG(flags, WRIBDB_FL_1OPENTA))
{
i = INT_MAX;
sm_snprintf(ta_id, SMTP_STID_SIZE, SMTPS_STID_FORMAT, id_count,
2);
sm_str_clr(ibdb_ta->ibt_mail_pa);
ret = sm_strprintf(ibdb_ta->ibt_mail_pa,
"sender-%d@some.domain", i);
ret = sm_snprintf(cdb, sizeof(cdb), "cdb%010d", i);
ibdb_ta->ibt_cdb_id = sm_cstr_scpyn((const uchar *) cdb,
strlen(cdb));
SM_TEST_E(ibdb_ta->ibt_cdb_id != NULL);
j = INT_MAX > 2;
sm_str_clr(ibdb_rcpt->ibr_pa);
ret = sm_strprintf(ibdb_rcpt->ibr_pa,
"rcpt-%d-%d@other.Rcpt", i, j);
ibdb_rcpt->ibr_idx = (rcpt_idx_T) j;
ret = ibdb_rcpt_status(ibdb_ctx, ibdb_rcpt,
IBDB_RCPT_NEW, IBDB_FL_NONE, THR_LOCK_UNLOCK);
SM_TEST_E(ret == SM_SUCCESS);
ret = ibdb_ta_status(ibdb_ctx, ibdb_ta, IBDB_TA_NEW,
IBDB_FL_NONE, 0, THR_LOCK_UNLOCK);
SM_TEST_E(ret == SM_SUCCESS);
}
for (i = 0; i < iter; i++)
{
id_count++;
sm_snprintf(ta_id, SMTP_STID_SIZE, SMTPS_STID_FORMAT, id_count,
2);
sm_str_clr(ibdb_ta->ibt_mail_pa);
ret = sm_strprintf(ibdb_ta->ibt_mail_pa,
"sender-%d@some.domain", i);
ret = sm_snprintf(cdb, sizeof(cdb), "cdb%010d", i);
ibdb_ta->ibt_cdb_id = sm_cstr_scpyn((const uchar *) cdb,
strlen(cdb));
SM_TEST(ibdb_ta->ibt_cdb_id != NULL);
if (ibdb_ta->ibt_cdb_id == NULL)
goto end;
nrcpts = ibdb_ta->ibt_nrcpts = (rcpts_per_ta > 0)
? rcpts_per_ta : (i % 5) + 1;
/* first: write some recipients */
for (j = 0; j < nrcpts; j++)
{
sm_str_clr(ibdb_rcpt->ibr_pa);
ret = sm_strprintf(ibdb_rcpt->ibr_pa,
"rcpt-%d-%d@other.Rcpt", i, j);
ibdb_rcpt->ibr_idx = (rcpt_idx_T) j;
ret = ibdb_rcpt_status(ibdb_ctx, ibdb_rcpt,
IBDB_RCPT_NEW, IBDB_FL_NONE, THR_LOCK_UNLOCK);
SM_TEST_E(ret == SM_SUCCESS);
}
if (WRIBDB_IS_FLAG(flags, WRIBDB_FL_LONG))
{
ibdb_hdrmod->ibh_type = SM_HM_TYPE_PREPEND;
if (NULL == long_str)
{
long_str = sm_malloc(long_str_len);
SM_TEST_E(long_str != NULL);
}
j = snprintf(long_str, long_str_len,
"HeaderPreLong: prepend ta=%s i=%d",
ta_id, i);
for (; j < long_str_len - 4; j++)
long_str[j] = '0' + (j % 10);
long_str[long_str_len - 4] ='\r';
long_str[long_str_len - 3] ='\n';
long_str[long_str_len - 2] ='\0';
ibdb_hdrmod->ibh_hdr = sm_cstr_crt((uchar *)long_str,
strlen(long_str));
ret = ibdb_hdrmod_wr(ibdb_ctx, ibdb_hdrmod,
IBDB_FL_NONE, THR_LOCK_UNLOCK);
sm_free(ibdb_hdrmod->ibh_hdr);
SM_TEST_E(ret == SM_SUCCESS);
}
if (WRIBDB_IS_FLAG(flags, WRIBDB_FL_HDR_PRE))
{
ibdb_hdrmod->ibh_type = SM_HM_TYPE_PREPEND;
ret = snprintf(hdr, sizeof(hdr),
"HeaderPre: prepend ta=%s i=%d\r\n",
ta_id, i);
ibdb_hdrmod->ibh_hdr = sm_cstr_crt((uchar *)hdr,
strlen(hdr));
ret = ibdb_hdrmod_wr(ibdb_ctx, ibdb_hdrmod,
IBDB_FL_NONE, THR_LOCK_UNLOCK);
sm_free(ibdb_hdrmod->ibh_hdr);
SM_TEST(ret == SM_SUCCESS);
if (ret != SM_SUCCESS)
goto end;
}
if (WRIBDB_IS_FLAG(flags, WRIBDB_FL_HDR_REM))
{
ibdb_hdrmod->ibh_type = SM_HM_TYPE_REMOVE;
ibdb_hdrmod->ibh_pos = 2;
ibdb_hdrmod->ibh_hdr = NULL;
ret = ibdb_hdrmod_wr(ibdb_ctx, ibdb_hdrmod,
IBDB_FL_NONE, THR_LOCK_UNLOCK);
SM_TEST(ret == SM_SUCCESS);
if (ret != SM_SUCCESS)
goto end;
}
if (WRIBDB_IS_FLAG(flags, WRIBDB_FL_HDR_APP))
{
ibdb_hdrmod->ibh_type = SM_HM_TYPE_APPEND;
ret = snprintf(hdr, sizeof(hdr),
"HeaderApp: append ta=%s i=%d\r\n",
ta_id, i);
ibdb_hdrmod->ibh_hdr = sm_cstr_crt((uchar *)hdr,
strlen(hdr));
ret = ibdb_hdrmod_wr(ibdb_ctx, ibdb_hdrmod,
IBDB_FL_NONE, THR_LOCK_UNLOCK);
sm_free(ibdb_hdrmod->ibh_hdr);
SM_TEST(ret == SM_SUCCESS);
if (ret != SM_SUCCESS)
goto end;
}
/* last: write mail for this transaction */
ret = ibdb_ta_status(ibdb_ctx, ibdb_ta, IBDB_TA_NEW,
IBDB_FL_NONE, 0, THR_LOCK_UNLOCK);
SM_TEST(ret == SM_SUCCESS);
if (ret != SM_SUCCESS)
break;
if (i != iter - 1 || !WRIBDB_IS_FLAG(flags, WRIBDB_FL_INCOMPL))
{
for (j = 0; j < nrcpts; j++)
{
ibdb_rcpt->ibr_idx = (rcpt_idx_T) j;
sm_str_clr(ibdb_rcpt->ibr_pa);
ret = sm_strprintf(ibdb_rcpt->ibr_pa,
"rcpt-%d-%d@other.Rcpt", i, j);
if (dontwr(iter, id_count, j, true) &&
!tacancel(iter, id_count) &&
bhr != NULL)
{
ibdb_rcpt_P ibdb_rcpt2;
rcpt_id = (char *) sm_malloc(SMTP_RCPTID_SIZE + 1);
SM_TEST(rcpt_id != NULL);
if (rcpt_id == NULL)
{
ret = sm_err_temp(ENOMEM);
goto end;
}
sm_snprintf(rcpt_id, SMTP_RCPTID_SIZE,
SMTP_RCPTID_FORMAT,
ibdb_rcpt->ibr_ta_id,
ibdb_rcpt->ibr_idx);
ret = qm_ibdb_rcpt_new(&ibdb_rcpt2);
SM_TEST(ret == SM_SUCCESS);
if (ret != SM_SUCCESS)
goto end;
SESSTA_COPY(ibdb_rcpt2->ibr_ta_id,
ibdb_rcpt->ibr_ta_id);
ret = sm_str_cpy(ibdb_rcpt2->ibr_pa,
ibdb_rcpt->ibr_pa);
SM_TEST(ret == SM_SUCCESS);
if (ret != SM_SUCCESS)
goto end;
ibdb_rcpt2->ibr_idx = ibdb_rcpt->ibr_idx;
ret = bht_add(bhr,
rcpt_id, SMTP_RCPTID_SIZE,
ibdb_rcpt2, &bhte);
SM_TEST(ret == SM_SUCCESS);
#if SM_TEST_PRT
if (debug > 3)
{
sm_io_fprintf(smioout,
"ADD RCPT(%p): ta=%s, ",
ibdb_rcpt2,
ibdb_rcpt2->ibr_ta_id);
sm_io_fprintf(smioout,
"rcpt_idx=%04d\n", j);
}
#endif /* SM_TEST_PRT */
continue;
}
ret = ibdb_rcpt_status(ibdb_ctx, ibdb_rcpt,
IBDB_RCPT_DONE, IBDB_FL_NOROLL,
THR_LOCK_UNLOCK);
SM_TEST(ret == SM_SUCCESS);
if (ret != SM_SUCCESS)
goto end;
}
if (!dontwr(iter, id_count, 0, false))
{
ret = ibdb_ta_status(ibdb_ctx, ibdb_ta,
IBDB_TA_DONE, IBDB_FL_NONE, 0,
THR_LOCK_UNLOCK);
SM_TEST(ret == SM_SUCCESS);
if (ret != SM_SUCCESS)
break;
}
else if (tacancel(iter, id_count))
{
ret = ibdb_ta_status(ibdb_ctx, ibdb_ta,
IBDB_TA_CANCEL, IBDB_FL_NONE, 0,
THR_LOCK_UNLOCK);
SM_TEST(ret == SM_SUCCESS);
if (ret != SM_SUCCESS)
break;
}
else if (bht != NULL)
{
ibdb_ta_P ibdb_ta2;
ret = qm_ibdb_ta_new(&ibdb_ta2);
SM_TEST(ret == SM_SUCCESS);
if (ret != SM_SUCCESS)
goto end;
SESSTA_COPY(ibdb_ta2->ibt_ta_id,
ibdb_ta->ibt_ta_id);
ibdb_ta2->ibt_cdb_id = SM_CSTR_DUP(ibdb_ta->ibt_cdb_id);
ibdb_ta2->ibt_nrcpts = ibdb_ta->ibt_nrcpts;
ret = sm_str_cpy(ibdb_ta2->ibt_mail_pa,
ibdb_ta->ibt_mail_pa);
SM_TEST(ret == SM_SUCCESS);
ret = bht_add(bht,
ibdb_ta2->ibt_ta_id, SMTP_STID_SIZE,
ibdb_ta2, &bhte);
SM_TEST(ret == SM_SUCCESS);
#if SM_TEST_PRT
if (debug > 3)
{
sm_io_fprintf(smioout,
"ADD TA(%p): ta=%s\n",
ibdb_ta2, ibdb_ta2->ibt_ta_id);
}
#endif /* SM_TEST_PRT */
}
}
sm_cstr_free(ibdb_ta->ibt_cdb_id);
/* number of records per file */
j = maxs / IBDB_REC_SIZE;
if (j <= 0)
j = 1;
/* number of logfiles written */
j = iter / j;
if (j > 0 && (j % 10) == 0)
{
ret = ibdb_clean(ibdb_ctx, THR_LOCK_UNLOCK);
SM_TEST(ret == SM_SUCCESS);
}
}
if (WRIBDB_IS_FLAG(flags, WRIBDB_FL_RANDOM) &&
bht != NULL && bhr != NULL)
{
cl_ctx.clx_ibdbc = ibdb_ctx;
cl_ctx.clx_bht = bht;
cl_ctx.clx_bhr = bhr;
bht_walk(bhr, rcpt_close, &cl_ctx);
bht_walk(bht, ta_close, &cl_ctx);
}
end:
error:
if (ibdb_ta != NULL)
{
SM_STR_FREE(ibdb_ta->ibt_mail_pa);
sm_free(ibdb_ta);
}
if (ibdb_rcpt != NULL)
{
SM_STR_FREE(ibdb_rcpt->ibr_pa);
sm_free(ibdb_rcpt);
}
ret = ibdb_close(ibdb_ctx);
SM_TEST(ret == SM_SUCCESS);
return ret;
}
syntax highlighted by Code2HTML, v. 0.9.1