/* * 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: t-edbi-0.c,v 1.10 2007/06/18 04:42:31 ca Exp $") #include "sm/assert.h" #include "sm/magic.h" #include "sm/error.h" #include "sm/memops.h" #include "sm/test.h" #include "sm/edb.h" #include "sm/edbcnf.h" #include "sm/actdb-int.h" #define QMGR_DEBUG_DEFINE 1 #include "sm/qmgrdbg.h" #include "edb-int.h" /* ** Write some DEFEDB entries and read them back to check whether it worked. ** Interactive to perform some other operations. ** This is mostly a program to play around and see what happens, it ** does not run as a test program. */ #define RCPT_MAX_LEN 256 /* Options for test; use bitmap? */ #define OPT_NO_DEL 1 #define OPT_INTER 0 static sm_ret_T cmp_aq_rcpt(aq_rcpt_P aq_rcpt, aq_rcpt_P aq_rcpt_rd) { SM_TEST(sm_memeq(aq_rcpt->aqr_ss_ta_id, aq_rcpt_rd->aqr_ss_ta_id, SMTP_STID_SIZE)); SM_TEST(sm_memeq(sm_str_data(aq_rcpt->aqr_pa), sm_str_data(aq_rcpt_rd->aqr_pa), sm_str_getlen(aq_rcpt->aqr_pa))); if (aq_rcpt->aqr_msg != NULL && aq_rcpt_rd->aqr_msg != NULL) { SM_TEST(sm_memeq(sm_str_data(aq_rcpt->aqr_msg), sm_str_data(aq_rcpt_rd->aqr_msg), sm_str_getlen(aq_rcpt->aqr_msg))); } SM_TEST(aq_rcpt->aqr_addrs[0].aqra_ipv4 == aq_rcpt_rd->aqr_addrs[0].aqra_ipv4); SM_TEST(aq_rcpt->aqr_da_idx == aq_rcpt_rd->aqr_da_idx); SM_TEST(aq_rcpt->aqr_st_time == aq_rcpt_rd->aqr_st_time); SM_TEST(aq_rcpt->aqr_idx == aq_rcpt_rd->aqr_idx); SM_TEST(aq_rcpt->aqr_status == aq_rcpt_rd->aqr_status); SM_TEST(aq_rcpt->aqr_tries == aq_rcpt_rd->aqr_tries); SM_TEST(aq_rcpt->aqr_next_try == aq_rcpt_rd->aqr_next_try); SM_TEST(aq_rcpt->aqr_last_try == aq_rcpt_rd->aqr_last_try); return SM_SUCCESS; } static sm_ret_T chg_rcpt(aq_rcpt_P aq_rcpt, int ta, int pid, int index) { sessta_id_T ta_id; sm_str_P str; sm_ret_T ret; char buf[RCPT_MAX_LEN]; /* lots of stuff just to get a valid aq_rcpt entry... */ ret = SM_SUCCESS; sm_snprintf(ta_id, sizeof(ta_id), SMTPS_STID_FORMAT, (ulonglong_T) ta, pid); SESSTA_COPY(aq_rcpt->aqr_ss_ta_id, ta_id); sm_snprintf(buf, sizeof(buf), "", index); str = sm_str_scpy0(NULL, buf, RCPT_MAX_LEN); if (aq_rcpt->aqr_pa != NULL) sm_str_free(aq_rcpt->aqr_pa); aq_rcpt->aqr_pa = str; sm_snprintf(buf, sizeof(buf), "451 Just some text %d", index); str = sm_str_scpy0(NULL, buf, RCPT_MAX_LEN); if (aq_rcpt->aqr_msg != NULL) sm_str_free(aq_rcpt->aqr_msg); aq_rcpt->aqr_msg = str; /* would require htonl, but not really needed here */ aq_rcpt->aqr_addrs[0].aqra_ipv4 = 0x7f000001; aq_rcpt->aqr_addrs[0].aqra_expt = 0x7fffffff; aq_rcpt->aqr_addrs[0].aqra_pref = 1; aq_rcpt->aqr_addr_max = 1; aq_rcpt->aqr_da_idx = 0; aq_rcpt->aqr_st_time = 123456; aq_rcpt->aqr_idx = index; aq_rcpt->aqr_status = AQR_ST_NEW; aq_rcpt->aqr_tries = 3; aq_rcpt->aqr_last_try = 123567; aq_rcpt->aqr_next_try = 123789; return ret; } static sm_ret_T chg_req_rcpt(edb_req_P edb_req, int ta, int pid, int index) { sessta_id_T ta_id; sm_ret_T ret; ret = SM_SUCCESS; sm_snprintf(ta_id, sizeof(ta_id), SMTPS_STID_FORMAT, (ulonglong_T) ta, pid); sm_snprintf(edb_req->edb_req_id, sizeof(edb_req->edb_req_id), SMTP_RCPTID_FORMAT, ta_id, index); edb_req->edb_req_type = EDB_REQ_RCPT; return ret; } static aq_rcpt_P new_rcpt(void) { aq_rcpt_P aq_rcpt; aq_rcpt = (aq_rcpt_P) sm_zalloc(sizeof(*aq_rcpt)); SM_TEST(aq_rcpt != NULL); if (aq_rcpt == NULL) return NULL; aq_rcpt->aqr_addrs = (aq_raddr_P) sm_malloc(sizeof(*(aq_rcpt->aqr_addrs))); if (aq_rcpt->aqr_addrs == NULL) return NULL; #if AQ_RCPT_CHECK aq_rcpt->sm_magic = SM_AQ_RCPT_MAGIC; #endif /* AQ_TA_CHECK */ return aq_rcpt; } static sm_ret_T chg_req_ta(edb_req_P edb_req, int ta, int pid) { sm_ret_T ret; ret = SM_SUCCESS; sm_snprintf(edb_req->edb_req_id, sizeof(edb_req->edb_req_id), SMTPS_STID_FORMAT, (ulonglong_T) ta, pid); edb_req->edb_req_type = EDB_REQ_TA; return ret; } static sm_ret_T cmp_aq_ta(aq_ta_P aq_ta, aq_ta_P aq_ta_rd) { SM_TEST(sm_memeq(sm_str_data(aq_ta->aqt_mail->aqm_pa), sm_str_data(aq_ta_rd->aqt_mail->aqm_pa), sm_str_getlen(aq_ta->aqt_mail->aqm_pa))); #if 0 SM_TEST(aq_rcpt->aqr_status == aq_rcpt_rd->aqr_status); #endif /* 0 */ return SM_SUCCESS; } static sm_ret_T chg_ta(aq_ta_P aq_ta, int ta, int pid, int index) { sessta_id_T ta_id; sm_str_P str; sm_ret_T ret; char mail_pa[RCPT_MAX_LEN]; /* lots of stuff just to get a valid aq_ta entry... */ ret = SM_SUCCESS; sm_snprintf(ta_id, sizeof(ta_id), SMTPS_STID_FORMAT, (ulonglong_T) ta, pid); SESSTA_COPY(aq_ta->aqt_ss_ta_id, ta_id); sm_snprintf(mail_pa, sizeof(mail_pa), "", index); str = sm_str_scpy0(NULL, mail_pa, RCPT_MAX_LEN); aq_ta->aqt_mail->aqm_pa = str; aq_ta->aqt_st_time = 123457; aq_ta->aqt_rcpts_tot = 4; /* total number recipients */ aq_ta->aqt_rcpts_left = 4; /* rcpts still to deliver */ aq_ta->aqt_rcpts_temp = 1; aq_ta->aqt_rcpts_perm = 0; aq_ta->aqt_rcpts_ar = 4; aq_ta->aqt_state = 400; aq_ta->aqt_cdb_id = sm_cstr_scpyn((const uchar *) ta_id, SMTP_STID_SIZE); SM_TEST(aq_ta->aqt_cdb_id != NULL); return ret; } static aq_ta_P new_ta(void) { aq_ta_P aq_ta; aq_ta = (aq_ta_P) sm_zalloc(sizeof(*aq_ta)); SM_TEST(aq_ta != NULL); if (aq_ta == NULL) return NULL; aq_ta->aqt_mail = (aq_mail_P) sm_malloc(sizeof(*(aq_ta->aqt_mail))); SM_TEST(aq_ta->aqt_mail != NULL); if (aq_ta->aqt_mail == NULL) return NULL; #if AQ_TA_CHECK aq_ta->sm_magic = SM_AQ_TA_MAGIC; #endif /* AQ_TA_CHECK */ return aq_ta; } static void free_rcpt(aq_rcpt_P aq_rcpt) { if (aq_rcpt == NULL) return; if (aq_rcpt->aqr_pa != NULL) SM_STR_FREE(aq_rcpt->aqr_pa); sm_free(aq_rcpt); } static void free_ta(aq_ta_P aq_ta) { if (aq_ta == NULL) return; if (aq_ta->aqt_mail != NULL) { SM_STR_FREE(aq_ta->aqt_mail->aqm_pa); SM_FREE(aq_ta->aqt_mail); } SM_CSTR_FREE(aq_ta->aqt_cdb_id); sm_free(aq_ta); } static void edbi0(int opts) { sm_ret_T ret; edb_ctx_P edb_ctx; aq_ctx_P aq_ctx; aq_ctx_T aq_ctx_s; aq_rcpt_P aq_rcpt; aq_rcpt_P aq_rcpt_rd; aq_ta_P aq_ta; aq_ta_P aq_ta_rd; smtp_status_T rcpt_st; edb_req_P edb_req; int i; edb_ctx = NULL; aq_ctx = &aq_ctx_s; edb_req = NULL; aq_ta = NULL; aq_ta_rd = NULL; aq_rcpt = NULL; aq_rcpt_rd = NULL; ret = edb_open(NULL, NULL, NULL, &edb_ctx); SM_TEST(ret == SM_SUCCESS); if (sm_is_err(ret)) return; ret = aq_open(NULL, &aq_ctx, 256, 0); SM_TEST(ret == SM_SUCCESS); if (sm_is_err(ret)) goto error; aq_rcpt = new_rcpt(); SM_TEST(aq_rcpt != NULL); if (aq_rcpt == NULL) goto error; aq_rcpt_rd = new_rcpt(); SM_TEST(aq_rcpt_rd != NULL); if (aq_rcpt_rd == NULL) goto error; aq_ta = new_ta(); SM_TEST(aq_ta != NULL); if (aq_ta == NULL) goto error; aq_ta_rd = new_ta(); SM_TEST(aq_ta_rd != NULL); if (aq_ta_rd == NULL) goto error; /* no entries */ ret = edb_wr_status(edb_ctx, NULL); SM_TEST(ret == SM_SUCCESS); ret = chg_ta(aq_ta, 0, 1, 0); SM_TEST(ret == SM_SUCCESS); ret = edb_ta_app(edb_ctx, aq_ta, NULL, 450); SM_TEST(ret == SM_SUCCESS); ret = edb_wr_status(edb_ctx, NULL); SM_TEST(ret == SM_SUCCESS); if (sm_is_err(ret)) goto error; ret = chg_rcpt(aq_rcpt, 0, 1, 0); SM_TEST(ret == SM_SUCCESS); rcpt_st = 451; ret = edb_rcpt_app(edb_ctx, aq_rcpt, NULL, rcpt_st); SM_TEST(ret == SM_SUCCESS); ret = edb_wr_status(edb_ctx, NULL); SM_TEST(ret == SM_SUCCESS); if (sm_is_err(ret)) goto error; /* add some recipient data */ for (i = 0; i < 4; i++) { ret = chg_rcpt(aq_rcpt, i, 1, 2); SM_TEST(ret == SM_SUCCESS); rcpt_st = 452 + i; ret = edb_rcpt_app(edb_ctx, aq_rcpt, NULL, rcpt_st); SM_TEST(ret == SM_SUCCESS); } /* write it out */ ret = edb_wr_status(edb_ctx, NULL); SM_TEST(ret == SM_SUCCESS); if (sm_is_err(ret)) goto error; ret = edb_req_new(edb_ctx, EDB_RQF_NONE, &edb_req, false); SM_TEST(ret == SM_SUCCESS); if (sm_is_err(ret)) goto error; /* read ta data back and compare */ ret = chg_req_ta(edb_req, 0, 1); SM_TEST(ret == SM_SUCCESS); ret = chg_ta(aq_ta, 0, 1, 0); SM_TEST(ret == SM_SUCCESS); ret = edb_rd_req(edb_ctx, edb_req); SM_TEST(ret == SM_SUCCESS); ret = edb_ta_dec(edb_req, aq_ta_rd); SM_TEST(ret == SM_SUCCESS); aq_ta->aqt_state = 400; ret = cmp_aq_ta(aq_ta, aq_ta_rd); SM_TEST(ret == SM_SUCCESS); /* read rcpt data back and compare */ ret = chg_req_rcpt(edb_req, 0, 1, 0); SM_TEST(ret == SM_SUCCESS); ret = chg_rcpt(aq_rcpt, 0, 1, 0); SM_TEST(ret == SM_SUCCESS); ret = edb_rd_req(edb_ctx, edb_req); SM_TEST(ret == SM_SUCCESS); ret = edb_rcpt_dec(edb_req, aq_rcpt_rd); SM_TEST(ret == SM_SUCCESS); aq_rcpt->aqr_status = 451; ret = cmp_aq_rcpt(aq_rcpt, aq_rcpt_rd); SM_TEST(ret == SM_SUCCESS); /* read rcpt data back and compare */ for (i = 0; i < 4; i++) { ret = chg_rcpt(aq_rcpt, i, 1, 2); SM_TEST(ret == SM_SUCCESS); aq_rcpt->aqr_status = 452 + i; ret = chg_req_rcpt(edb_req, i, 1, 2); SM_TEST(ret == SM_SUCCESS); ret = edb_rd_req(edb_ctx, edb_req); SM_TEST(ret == SM_SUCCESS); ret = edb_rcpt_dec(edb_req, aq_rcpt_rd); SM_TEST(ret == SM_SUCCESS); ret = cmp_aq_rcpt(aq_rcpt, aq_rcpt_rd); SM_TEST(ret == SM_SUCCESS); SM_STR_FREE(aq_rcpt->aqr_pa); } if (opts == OPT_NO_DEL) goto done; if (opts == OPT_INTER) { bool stop; int c; stop = false; while ((c = getchar()) != EOF && !stop) { switch (c) { case 'c': ret = edb_ctx->edb_bdbenv->txn_checkpoint( edb_ctx->edb_bdbenv, /* kbyte If the kbyte parameter is non-zero, a checkpoint will be done if more than kbyte kilobytes of log data have been written since the last checkpoint. min If the min parameter is non-zero, a checkpoint will be done if more than min minutes have passed since the last checkpoint. */ /* u_int32_t kbyte, u_int32_t min */ 0, 0, 0); if (ret != 0) edb_ctx->edb_bdbenv->err( edb_ctx->edb_bdbenv, ret, "checkpoint"); break; case 's': stop = true; break; default: break; } } } /* Delete rcpts: directly */ for (i = 0; i < 2; i++) { ret = chg_rcpt(aq_rcpt, i, 1, 2); SM_TEST(ret == SM_SUCCESS); ret = chg_req_rcpt(edb_req, i, 1, 2); SM_TEST(ret == SM_SUCCESS); ret = edb_rcpt_rm(edb_ctx, edb_req->edb_req_id); SM_TEST(ret == SM_SUCCESS); } /* Delete rcpts: add requests */ for (i = 2; i < 4; i++) { ret = chg_rcpt(aq_rcpt, i, 1, 2); SM_TEST(ret == SM_SUCCESS); ret = chg_req_rcpt(edb_req, i, 1, 2); SM_TEST(ret == SM_SUCCESS); ret = edb_rcpt_rm_req(edb_ctx, edb_req->edb_req_id, NULL); SM_TEST(ret == SM_SUCCESS); } /* Delete rcpts: commit requests */ ret = edb_wr_status(edb_ctx, NULL); SM_TEST(ret == SM_SUCCESS); done: free_rcpt(aq_rcpt); free_rcpt(aq_rcpt_rd); free_ta(aq_ta); free_ta(aq_ta_rd); ret = edb_req_rel(edb_ctx, edb_req, 0, THR_NO_LOCK); SM_TEST(ret == SM_SUCCESS); ret = aq_close(aq_ctx); SM_TEST(ret == SM_SUCCESS); ret = edb_close(edb_ctx); SM_TEST(ret == SM_SUCCESS); return; error: /* always close db */ ret = edb_close(edb_ctx); SM_TEST(ret == SM_SUCCESS); return; } int main(int argc, char *argv[]) { int opts, c; opts = 0; while ((c = getopt(argc, argv, "d")) != -1) { switch (c) { case 'd': opts = OPT_NO_DEL; break; default: /* usage(argv[0]); */ return 1; } } sm_test_begin(argc, argv, "test edb 0"); /* Ignore result, directory may already exist */ (void) mkdir(EDB_HOME, 0700); edbi0(opts); return sm_test_end(); }