/*
* 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: dadbh.c,v 1.39 2007/06/14 05:12:27 ca Exp $")
#include "sm/types.h"
#include "sm/assert.h"
#include "sm/magic.h"
#include "sm/str.h"
#include "sm/time.h"
#include "sm/mta.h"
#include "sm/memops.h"
#include "sm/qmgr.h"
#include "sm/qmgr-int.h"
#include "sm/dadb.h"
#include "sm/io.h"
#include "dadb.h"
/*
** DADB_SET_LIMIT -- Set current maximum number of entries in DA DB
** The limit may change due to resource restrictions.
**
** Parameters:
** dadb_ctx -- DADB context
** entries_lim -- new limit
** locktype -- kind of locking
**
** Returns:
** usual sm_error code; SM_E_RANGE, (un)lock
**
** Side Effects: none on error (except if unlock fails)
**
** Locking: locks dadb_ctx if requested
**
** Last code review: 2005-03-17 00:35:27
** Last code change:
*/
sm_ret_T
dadb_set_limit(dadb_ctx_P dadb_ctx, size_t entries_lim, thr_lock_T locktype)
{
#undef SMFCT
#define SMFCT "dadb_set_limit"
sm_ret_T ret;
int r;
SM_IS_DADB(dadb_ctx);
if (thr_lock_it(locktype)) {
r = pthread_mutex_lock(&dadb_ctx->dadb_mutex);
SM_LOCK_OK(r);
if (r != 0)
return sm_error_perm(SM_EM_DA, r);
}
/*
** Don't check against current number of entries as lower limit,
** the system will simple make sure that the new limit isn't
** exceeded, but it must not check against the new limit to detect
** "inconsistencies", entries_max is used for that purpose.
*/
if (entries_lim >= dadb_ctx->dadb_entries_max)
ret = sm_error_perm(SM_EM_DA, SM_E_RANGE);
else {
dadb_ctx->dadb_entries_lim = entries_lim;
ret = SM_SUCCESS;
}
if ((!sm_is_err(ret) && thr_unl_no_err(locktype))
|| (sm_is_err(ret) && thr_unl_if_err(locktype)))
{
r = pthread_mutex_unlock(&dadb_ctx->dadb_mutex);
SM_ASSERT(r == 0);
if (r != 0 && sm_is_success(ret))
ret = sm_error_perm(SM_EM_DA, r);
}
return ret;
}
/*
** DADB_ENTRY_AVAIL -- Is there a free entry in DA DB?
**
** Parameters:
** dadb_ctx -- DADB context
** pda_avail -- (pointer to) how many entries are free? (output)
** pda_idle -- (pointer to) how many entries are idle? (output)
** locktype -- kind of locking
**
** Returns:
** SM_SUCCESS except for (un)lock errors
**
** Note: it might be useful to return counters instead of bool
**
** Side Effects: none on error
**
** Locking: locks dadb_ctx if requested
**
** Last code review: 2005-03-17 00:48:15
** Last code change: 2006-02-22 00:25:40
*/
sm_ret_T
dadb_entry_avail(dadb_ctx_P dadb_ctx, uint *pda_avail, uint *pda_idle, thr_lock_T locktype)
{
#undef SMFCT
#define SMFCT "dadb_entry_avail"
int r;
SM_IS_DADB(dadb_ctx);
SM_REQUIRE(pda_avail != NULL);
*pda_avail = 0;
SM_REQUIRE(pda_idle != NULL);
*pda_idle = 0;
if (thr_lock_it(locktype)) {
r = pthread_mutex_lock(&dadb_ctx->dadb_mutex);
SM_LOCK_OK(r);
if (r != 0)
return sm_error_perm(SM_EM_DA, r);
}
if (DADB_IS_OK(dadb_ctx)) {
*pda_avail = dadb_ctx->dadb_entries_cur - dadb_ctx->dadb_entries_lim;
*pda_idle = dadb_ctx->dadb_entries_idle;
}
if (thr_unl_no_err(locktype)) {
r = pthread_mutex_unlock(&dadb_ctx->dadb_mutex);
SM_ASSERT(r == 0);
if (r != 0)
return sm_error_perm(SM_EM_DA, r);
}
return SM_SUCCESS;
}
/*
** DADB_ENTRY_GET -- get a free entry in DA DB (or allocate a new one)
**
** Parameters:
** dadb_ctx -- DADB context
** pdadb_entry -- pointer to DADB entry (output)
** pidx -- pointer to idx (output)
** locktype -- kind of locking
**
** Returns:
** usual sm_error code; ENOMEM, SM_E_FULL,
**
** Side Effects: none on error (except if unlock fails)
**
** Locking: locks dadb_ctx if requested
** *pdadb_entry will be locked (if successful)
**
** Last code review: 2005-03-17 00:55:16
** Last code change: 2006-02-18 20:21:00
*/
sm_ret_T
dadb_entry_get(dadb_ctx_P dadb_ctx, dadb_entry_P *pdadb_entry, uint *pidx, thr_lock_T locktype)
{
#undef SMFCT
#define SMFCT "dadb_entry_get"
uint i;
sm_ret_T ret;
dadb_entry_P dadb_entry;
int r;
SM_IS_DADB(dadb_ctx);
SM_REQUIRE(pdadb_entry != NULL);
SM_REQUIRE(pidx != NULL);
ret = sm_error_temp(SM_EM_DA, SM_E_FULL);
if (thr_lock_it(locktype)) {
r = pthread_mutex_lock(&dadb_ctx->dadb_mutex);
SM_LOCK_OK(r);
if (r != 0)
return sm_error_perm(SM_EM_DA, r);
}
/* too many entries already? (get rid of goto for "nicer" structure?) */
if (dadb_ctx->dadb_entries_cur >= dadb_ctx->dadb_entries_lim)
goto unl;
if (!DADB_IS_OK(dadb_ctx))
goto unl;
SM_ASSERT(dadb_ctx->dadb_entries != NULL);
/* search for a free DA DB entry */
for (i = 0; i < dadb_ctx->dadb_entries_max; i++) {
dadb_entry = (dadb_ctx->dadb_entries)[i];
if (NULL == dadb_entry) {
dadb_entry = (dadb_entry_P) sm_zalloc(sizeof(*dadb_entry));
if (NULL == dadb_entry) {
ret = sm_error_temp(SM_EM_DA, ENOMEM);
goto unl;
}
#if DADB_CHECK
dadb_entry->sm_magic = SM_DADBE_MAGIC;
#endif
#if DADBE_MUTEX
r = pthread_mutex_init(&dadb_entry->dadbe_mutex,
SM_PTHREAD_MUTEXATTR);
if (r != 0) {
ret = sm_error_perm(SM_EM_DA, r);
goto unl;
}
#endif
/* fill in more data?? */
(dadb_ctx->dadb_entries)[i] = dadb_entry;
#if DADBE_MUTEX
r = pthread_mutex_lock(&dadb_entry->dadbe_mutex);
SM_LOCK_OK(r);
if (r != 0) {
ret = sm_error_perm(SM_EM_DA, r);
goto unl;
}
#endif
break;
}
else {
#if DADBE_MUTEX
r = pthread_mutex_trylock(&dadb_entry->dadbe_mutex);
#else
r = 0;
#endif
if (r == 0 && DADBE_IS_FREE(dadb_entry))
break;
}
}
if (i < dadb_ctx->dadb_entries_max) {
dadb_ctx->dadb_entries_cur++;
#if DADB_STATS
if (dadb_ctx->dadb_entries_cur > dadb_ctx->dadb_entries_max_used)
dadb_ctx->dadb_entries_max_used = dadb_ctx->dadb_entries_cur;
#endif /* DA_DB_STATS */
*pdadb_entry = dadb_entry;
*pidx = i;
ret = SM_SUCCESS;
}
unl:
if ((!sm_is_err(ret) && thr_unl_no_err(locktype))
|| (sm_is_err(ret) && thr_unl_if_err(locktype)))
{
r = pthread_mutex_unlock(&dadb_ctx->dadb_mutex);
SM_ASSERT(r == 0);
if (r != 0 && sm_is_success(ret))
ret = sm_error_perm(SM_EM_DA, r);
}
return ret;
}
/*
** DADB_SE_FIND_BY_IPV4 -- find a free session in DADB by IPv4 address
** HACK, see smX doc for proper index to access connection cache
** Note: this is NOT a connection cache as described in the doc;
** it is missing several data entries.
** Use a hash table, see connctl.c?
**
** Parameters:
** dadb_ctx -- DADB context
** ipv4 -- IPv4 address
** time_now -- current time
** pdadb_entry -- pointer to DA DB entry (output)
**
** Returns:
** >=0: number of entries found (that is not the actual number
** of entries for that IPv4 address as the algorithm
** stops as soon as it finds a free entry).
** usual sm_error code; only (un)lock errors
**
** Locking: locks entire dadb_ctx during operation, returns unlocked
**
** Last code review: 2005-03-17 00:59:40
** Last code change: 2006-02-20 18:02:17
*/
sm_ret_T
dadb_se_find_by_ipv4(dadb_ctx_P dadb_ctx, ipv4_T ipv4, time_T time_now, dadb_entry_P *pdadb_entry)
{
#undef SMFCT
#define SMFCT "dadb_se_find_by_ipv4"
uint i;
sm_ret_T ret;
int r;
dadb_entry_P dadb_entry;
SM_IS_DADB(dadb_ctx);
SM_REQUIRE(pdadb_entry != NULL);
*pdadb_entry = NULL;
/* do we really need to lock this?? */
r = pthread_mutex_lock(&dadb_ctx->dadb_mutex);
SM_LOCK_OK(r);
if (r != 0)
return sm_error_perm(SM_EM_DA, r);
SM_ASSERT(dadb_ctx->dadb_entries != NULL);
ret = 0;
for (i = 0; i < dadb_ctx->dadb_entries_max; i++) {
dadb_entry = (dadb_ctx->dadb_entries)[i];
if (dadb_entry != NULL && DADBE_IS_ACTIVE(dadb_entry)
&& ipv4_addr_eq(dadb_entry->dadbe_srv_ipv4, ipv4))
{
++ret;
/* use first free entry that is not too old */
if (*pdadb_entry == NULL && DADBE_IS_CONN(dadb_entry)
&& (0 == dadb_entry->dadbe_lastuse ||
dadb_entry->dadbe_lastuse >= time_now ||
time_now - dadb_entry->dadbe_lastuse <= SM_SESSION_TMO))
{
SM_IS_DADBE(dadb_entry);
*pdadb_entry = dadb_entry;
break;
}
}
}
r = pthread_mutex_unlock(&dadb_ctx->dadb_mutex);
SM_ASSERT(r == 0);
if (r != 0 && sm_is_success(ret))
ret = sm_error_perm(SM_EM_DA, r);
return ret;
}
#if 0
///*
//** DADB_ENTRY_FREE -- free a DA DB entry
//**
//** Parameters:
//** dadb_ctx -- DADB context
//** dadb_entry -- DADB entry
//** locktype -- kind of locking
//**
//** Returns:
//** usual sm_error code
//*/
//
//sm_ret_T
//dadb_entry_free(dadb_ctx_P dadb_ctx, dadb_entry_P dadb_entry, thr_lock_T locktype)
//{
// int r;
//
// if (NULL == dadb_entry)
// return SM_SUCCESS;
// SM_IS_DADB(dadb_ctx);
// if (thr_lock_it(locktype))
// {
// r = pthread_mutex_lock(&dadb_ctx->dadb_mutex);
// SM_LOCK_OK(r);
// if (r != 0)
// return sm_error_perm(SM_EM_DA, r);
// }
//
// /* remove it from array?? otherwise there's no need for locking dadb */
// sm_free(dadb_entry);
// if ((!sm_is_err(ret) && thr_unl_no_err(locktype))
// || (sm_is_err(ret) && thr_unl_if_err(locktype)))
// {
// r = pthread_mutex_unlock(&dadb_ctx->dadb_mutex);
// SM_ASSERT(r == 0);
// if (r != 0 && sm_is_success(ret))
// ret = sm_error_perm(SM_EM_DA, r);
// }
// return SM_SUCCESS;
//}
#endif /* 0 */
#if 0
///*
//** DADB_ENTRY_NEW -- create new DA DB entry
//**
//** Parameters:
//** dadb_ctx -- DADB context
//** pdadb_entry -- pointer to DADB entry (output)
//** locktype -- kind of locking
//**
//** Returns:
//** usual sm_error code
//*/
//
//sm_ret_T
//dadb_entry_new(dadb_ctx_P dadb_ctx, dadb_entry_P *pdadb_entry, thr_lock_T locktype)
//{
// sm_ret_T ret;
// int r;
// dadb_entry_P dadb_entry;
//
// SM_IS_DADB(dadb_ctx);
// if (thr_lock_it(locktype))
// {
// r = pthread_mutex_lock(&dadb_ctx->dadb_mutex);
// SM_LOCK_OK(r);
// if (r != 0)
// return sm_error_perm(SM_EM_DA, r);
// }
// if (dadb_ctx->dadb_entries_cur >= dadb_ctx->dadb_entries_max)
// {
// DADB_DPRINTF((smioerr, "dadb_entry_new: cur=%d, max=%d\n", dadb_ctx->dadb_entries_cur, dadb_ctx->dadb_entries_max));
// ret = sm_error_temp(SM_EM_DA, SM_E_FULL);
// goto errunl;
// }
// dadb_entry = (dadb_entry_P) sm_zalloc(sizeof(*dadb_entry));
// if (NULL == dadb_entry)
// goto enomem;
//#if DADB_CHECK
// /* set this early, otherwise the rest of the routines will fail */
// dadb_entry->sm_magic = SM_DADBE_MAGIC;
//#endif /* DADB_CHECK */
//
// /* fill in more data?? */
//
// dadb_ctx->dadb_entries_cur++;
// *pdadb_entry = dadb_entry;
// if (thr_unl_no_err(locktype))
// {
// r = pthread_mutex_unlock(&dadb_ctx->dadb_mutex);
// SM_ASSERT(r == 0);
// if (r != 0 && sm_is_success(ret))
// ret = sm_error_perm(SM_EM_DA, r);
// }
// return SM_SUCCESS;
//
// enomem:
// ret = sm_error_temp(SM_EM_DA, ENOMEM);
//
// /* clean up...? nothing to do right now */
// errunl:
// if (thr_unl_if_err(locktype))
// (void) pthread_mutex_unlock(&dadb_ctx->dadb_mutex);
// return ret;
//}
#endif /* 0 */
#if 0
///*
//** DADB_ENTRY_UPDATE -- update DA DB entry
//**
//** Parameters:
//** dadb_ctx -- DADB context
//** sess_id -- session id from SMTPS
//** ta_id -- transaction id from SMTPS
//** dadb_entry -- entry
//**
//** Returns:
//** usual sm_error code
//**
//** Locking: locks entire dadb_ctx during operation, returns unlocked
//*/
//
//sm_ret_T
//dadb_entry_update(dadb_ctx_P dadb_ctx, sessta_id_P sess_id, sessta_id_P ta_id,
// dadb_entry_P dadb_entry)
//{
//#if 0
// sm_ret_T ret;
//#endif /* 0 */
// int r;
//
// SM_IS_DADB(dadb_ctx);
// r = pthread_mutex_lock(&dadb_ctx->dadb_mutex);
// SM_LOCK_OK(r);
// if (r != 0)
// return sm_error_perm(SM_EM_DA, r);
//
//#if 0
// ret = bht2_add(dadb_ctx->dadb_bht,
// sess_id, SMTP_STID_SIZE,
// ta_id, SMTP_STID_SIZE,
// dadb_entry,
// &bht2e);
// if (sm_is_err(ret))
// goto errunl;
//#endif /* 0 */
//
// dadb_ctx->dadb_entries_cur++;
// r = pthread_mutex_unlock(&dadb_ctx->dadb_mutex);
// SM_ASSERT(r == 0);
// if (r != 0 && sm_is_success(ret))
// ret = sm_error_perm(SM_EM_DA, r);
// return SM_SUCCESS;
//
//#if 0
// errunl:
// r = pthread_mutex_unlock(&dadb_ctx->dadb_mutex);
// return ret;
//#endif /* 0 */
//}
#endif /* 0 */
syntax highlighted by Code2HTML, v. 0.9.1