/* * 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: edbci.c,v 1.8 2006/03/13 18:41:33 ca Exp $") #include "sm/error.h" #include "sm/memops.h" #include "sm/heap.h" #include "sm/assert.h" #include "sm/str.h" #include "sm/edbc.h" #include "edbc.h" #include "sm/qmgrdbg.h" /* ** EDBC_INSERT -- insert an entry to envelope database cache; may remove ** "older" entries ** ** Parameters: ** edbc_ctx -- EDBC context ** rcpt_id -- Recipient Id ** next_try -- Time for next try ** check -- check first whether entry exists ** ** Returns: ** usual sm_error code. ** ** Locking: must be performed by caller. ** ** Last code review: ** Last code change: */ sm_ret_T edbc_insert(edbc_ctx_P edbc_ctx, rcpt_id_T rcpt_id, time_T next_try, bool check) { sm_ret_T ret; bool isfull; edbc_tnode_P edbc_tnode, edbc_tnode_ret, edbc_tnode_last; edbc_node_P edbc_node; SM_REQUIRE(edbc_ctx != NULL); if (check && edbc_exists(edbc_ctx, rcpt_id, NULL)) return SM_SUCCESS; /* other code? */ isfull = (edbc_ctx->edbc_max_entries > 0 && edbc_ctx->edbc_entries >= edbc_ctx->edbc_max_entries); if (isfull) { edbc_tnode_last = RB_MAX(edbc_tree_S, &edbc_ctx->edbc_root); edbc_node = ECNL_FIRST(&edbc_tnode_last->ectn_hd); if (edbc_node->ecn_next_try <= next_try) return sm_error_temp(SM_EM_Q_EDBC, SM_E_FULL); edbc_node = NULL; } else edbc_tnode_last = NULL; edbc_tnode = NULL; edbc_node = (edbc_node_P) sm_zalloc(sizeof(*edbc_node)); if (edbc_node == NULL) return sm_error_temp(SM_EM_Q_EDBC, ENOMEM); edbc_tnode = (edbc_tnode_P) sm_zalloc(sizeof(*edbc_tnode)); if (edbc_tnode == NULL) { sm_free_size(edbc_node, sizeof(*edbc_node)); return sm_error_temp(SM_EM_Q_EDBC, ENOMEM); } /* ** Remove last entry after data has been allocated: ** advantage: allocation succeeded, hence it will be added successfully ** disadvantage: if allocation fails it may have succeeded if the ** entry would have been removed first */ if (isfull) { ret = edbct_rm(edbc_ctx, edbc_tnode_last); if (sm_is_err(ret)) goto error; } RCPT_ID_COPY(edbc_node->ecn_rcpt_id, rcpt_id); edbc_node->ecn_next_try = next_try; ECNL_INIT(&edbc_tnode->ectn_hd); ECNL_APP(&edbc_tnode->ectn_hd, edbc_node); edbc_tnode_ret = RB_FIND(edbc_tree_S, &edbc_ctx->edbc_root, edbc_tnode); if (edbc_tnode_ret == NULL) { edbc_tnode_ret = RB_INSERT(edbc_tree_S, &edbc_ctx->edbc_root, edbc_tnode); if (edbc_tnode_ret != NULL) { /* Internal error? Should not happen! */ ret = sm_error_perm(SM_EM_Q_EDBC, EEXIST); goto error; } } else { /* Check first whether it's there? */ ECNL_APP(&edbc_tnode_ret->ectn_hd, edbc_node); sm_free_size(edbc_tnode, sizeof(*edbc_tnode)); } ++edbc_ctx->edbc_entries; return SM_SUCCESS; error: SM_FREE(edbc_tnode); SM_FREE(edbc_node); return ret; }