/* * 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: edbr.c,v 1.19 2006/05/02 17:13:38 ca Exp $") #include "sm/error.h" #include "sm/memops.h" #include "sm/assert.h" #include "sm/reccom.h" #include "sm/rcb.h" #include "sm/qmgr-int.h" #include "sm/actdb-int.h" #include "edb-int.h" #include "sm/edb.h" #include "sm/pthread.h" /* ** EDB_RD_OPEN -- open a read cursor ** ** Parameters: ** edb_ctx -- EDB context ** pedb_cursor -- pointer to EDB cursor (output) ** ** Returns: ** usual sm_error code */ sm_ret_T edb_rd_open(edb_ctx_P edb_ctx, edb_cursor_P *pedb_cursor) { int r; SM_ASSERT(edb_ctx != NULL); SM_ASSERT(pedb_cursor != NULL); r = edb_ctx->edb_bdb->cursor(edb_ctx->edb_bdb, NULL, pedb_cursor, 0); if (r != 0) return sm_error_perm(SM_EM_EDB, r); return SM_SUCCESS; } /* ** EDB_RD_CLOSE -- close read cursor ** ** Parameters: ** edb_ctx -- EDB context ** edb_cursor -- EDB cursor ** ** Returns: ** usual sm_error code */ sm_ret_T edb_rd_close(edb_ctx_P edb_ctx, edb_cursor_P edb_cursor) { int r; SM_ASSERT(edb_ctx != NULL); SM_ASSERT(edb_cursor != NULL); r = edb_cursor->c_close(edb_cursor); if (r != 0) return sm_error_perm(SM_EM_EDB, r); return SM_SUCCESS; } /* ** EDB_RD_NEXT -- read next entry ** ** Parameters: ** edb_ctx -- EDB context ** edb_cursor -- EDB cursor ** edb_req -- request: contains key to read, rcb to fill (I/O) ** ** Returns: ** usual sm_error code */ sm_ret_T edb_rd_next(edb_ctx_P edb_ctx, edb_cursor_P edb_cursor, edb_req_P edb_req) { sm_rcb_P rcb; sm_ret_T ret; int r; size_t l; DBT db_key, db_data; SM_ASSERT(edb_ctx != NULL); SM_ASSERT(edb_req != NULL); r = pthread_mutex_lock(&edb_ctx->edb_mutex); SM_LOCK_OK(r); if (r != 0) { /* LOG? */ return sm_error_perm(SM_EM_EDB, r); } /* XXX This should be a transaction... check BDB doc */ ret = SM_SUCCESS; rcb = edb_req->edb_req_rcb; sm_memzero(&db_key, sizeof(db_key)); sm_memzero(&db_data, sizeof(db_data)); db_key.flags = DB_DBT_USERMEM; db_key.data = edb_req->edb_req_id; db_key.ulen = sizeof(edb_req->edb_req_id); /* SMTP_ID_SIZE */ db_data.flags = DB_DBT_USERMEM; db_data.data = sm_rcb_data(rcb); db_data.ulen = sm_rcb_getsize(rcb); ret = SM_SUCCESS; r = edb_cursor->c_get(edb_cursor, &db_key, &db_data, DB_NEXT); l = db_data.size; if (r == DB_BUFFER_SMALL && l < EDB_RC_MAXSZ && sm_rcb_getsize(rcb) < l) { l = (l + 1023) & ~1023; /* round to 1024; see BDB docs */ if (!sm_is_err(sm_rcb_resize_data(rcb, l))) { db_data.data = sm_rcb_data(rcb); db_data.ulen = sm_rcb_getsize(rcb); r = edb_cursor->c_get(edb_cursor, &db_key, &db_data, DB_NEXT); l = db_data.size; } } if (r != 0) ret = sm_error_perm(SM_EM_EDB, r); /* How to handle DB_NOTFOUND? */ else if (l < sm_rcb_getmax(rcb)) sm_rcb_setlen(edb_req->edb_req_rcb, db_data.size); /* fall through for unlocking */ r = pthread_mutex_unlock(&edb_ctx->edb_mutex); SM_ASSERT(r == 0); if (r != 0 && sm_is_success(ret)) ret = sm_error_perm(SM_EM_EDB, r); /* cleanup? */ return ret; } /* ** EDB_GET_TYPE -- extract type from edb_req ** ** Parameters: ** edb_req -- request: contains key to read, rcb to fill (I/O) ** ** Returns: ** >0: type ** <0: usual sm_error code */ sm_ret_T edb_get_type(edb_req_P edb_req) { sm_rcb_P rcb; sm_ret_T ret; uint32_t v, l, rt, tl; SM_ASSERT(edb_req != NULL); rcb = edb_req->edb_req_rcb; ret = sm_rcb_open_dec(rcb); /* Total length of record */ ret = sm_rcb_getuint32(rcb, &tl); if (sm_is_err(ret)) goto error; if (tl > EDB_RC_MAXSZ || tl > sm_rcb_getlen(rcb)) goto err0; /* transaction status */ ret = sm_rcb_get3uint32(rcb, &l, &rt, &v); if (sm_is_err(ret)) goto error; if (l != 4 || (rt != RT_EDB_TA_ST && rt != RT_EDBR_ST && rt != RT_EDB_VERSION)) goto err0; (void) sm_rcb_close_dec(rcb); if (sm_is_err(ret)) goto error; return (rt == RT_EDB_TA_ST) ? EDB_REQ_TA : ((rt == RT_EDBR_ST) ? EDB_REQ_RCPT : EDB_REQ_VRS); err0: ret = sm_error_perm(SM_EM_EDB, SM_E_PR_ERR); error: (void) sm_rcb_close_decn(rcb); /* cleanup? */ return ret; }