/*
* Copyright (c) 2003-2006 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: ssocc.c,v 1.22 2007/10/25 01:42:30 ca Exp $")
#include "sm/types.h"
#include "sm/assert.h"
#include "sm/magic.h"
#include "sm/error.h"
#include "sm/heap.h"
#include "sm/memops.h"
#include "sm/time.h"
#include "sm/mta.h"
#include "sm/bhtable.h"
#include "sm/ssocc.h"
#include "sm/qmgr-int.h"
/*
** SSOCC_CLOSE -- close a SSOCC_CTX
**
** Parameters:
** ssocc_ctx -- SSOCC context
**
** Returns:
** usual sm_error code
**
** Locking: no locking, destroys SSOCC (and hence lock)
*/
sm_ret_T
ssocc_close(ssocc_ctx_P ssocc_ctx)
{
if (ssocc_ctx == NULL)
return SM_SUCCESS;
SM_IS_SSOCC(ssocc_ctx);
#if SSOCC_RSC
rsc_free(ssocc_ctx->ssocc_ht);
#else
bht_destroy(ssocc_ctx->ssocc_ht, NULL, NULL);
#endif
sm_connctl_free(ssocc_ctx->ssocc_cctx);
(void) pthread_mutex_destroy(&ssocc_ctx->ssocc_mutex);
sm_free_size(ssocc_ctx, sizeof(*ssocc_ctx));
return SM_SUCCESS;
}
/*
** SSOCC_OPEN -- open a new SSOCC
**
** Parameters:
** pssocc_ctx -- pointer to SSOCC context (output)
** size -- maximum size of SSOCC
** connctl_size -- size of connection control table
**
** Returns:
** usual sm_error code
*/
sm_ret_T
ssocc_open(ssocc_ctx_P *pssocc_ctx, uint size, uint connctl_size)
{
int r;
sm_ret_T ret;
ssocc_ctx_P ssocc_ctx;
SM_REQUIRE(pssocc_ctx != NULL);
ssocc_ctx = (ssocc_ctx_P) sm_zalloc(sizeof(*ssocc_ctx));
if (ssocc_ctx == NULL)
{
ret = sm_error_temp(SM_EM_Q, ENOMEM);
goto error;
}
#if SSOCC_RSC
ssocc_ctx->ssocc_ht = rsc_new(size * 2, size * 3,
rsc_occe_create, rsc_occe_delete, (void *) ssocc_ctx);
#else
ssocc_ctx->ssocc_ht = bht_new(size, size * 2);
#endif
if (ssocc_ctx->ssocc_ht == NULL)
{
ret = sm_error_temp(SM_EM_Q, ENOMEM);
goto errfree;
}
OCCFL_INIT(&ssocc_ctx->ssocc_fl_hd);
/* CONF constants? configuration parameters? */
ret = sm_connctl_new(connctl_size, 5, &ssocc_ctx->ssocc_cctx);
if (sm_is_err(ret))
goto errfree;
r = pthread_mutex_init(&ssocc_ctx->ssocc_mutex, SM_PTHREAD_MUTEXATTR);
if (r != 0)
{
ret = sm_error_perm(SM_EM_Q, r);
goto errfree;
}
#if SSOCC_CHECK
ssocc_ctx->sm_magic = SM_SSOCC_MAGIC;
#endif
*pssocc_ctx = ssocc_ctx;
return SM_SUCCESS;
errfree:
if (ssocc_ctx != NULL)
{
#if SSOCC_RSC
rsc_free(ssocc_ctx->ssocc_ht);
#else
bht_destroy(ssocc_ctx->ssocc_ht, NULL, NULL);
#endif
sm_connctl_free(ssocc_ctx->ssocc_cctx);
sm_free_size(ssocc_ctx, sizeof(*ssocc_ctx));
}
error:
return ret;
}
/*
** SSOCC_ENTRY_FREE -- free SSOCC entry (return it to free-list)
**
** Parameters:
** ssocc_ctx -- SSOCC context
** ssocc_entry -- SSOCC entry
** locktype -- kind of locking
**
** Returns:
** usual sm_error code
**
** Locking: check unlocking! XXX
*/
sm_ret_T
ssocc_entry_free(ssocc_ctx_P ssocc_ctx, ssocc_entry_P ssocc_entry, thr_lock_T locktype)
{
int r;
SM_IS_SSOCC(ssocc_ctx);
if (ssocc_entry == NULL)
return SM_SUCCESS;
if (thr_lock_it(locktype))
{
r = pthread_mutex_lock(&ssocc_ctx->ssocc_mutex);
SM_LOCK_OK(r);
if (r != 0)
return sm_error_perm(SM_EM_Q, r);
}
SM_IS_SSOCCE(ssocc_entry);
#if SSOCC_RSC
(void) rsc_rm(ssocc_ctx->ssocc_ht,
(char *)&ssocc_entry->ssocce_srv_ipv4,
sizeof(ssocc_entry->ssocce_srv_ipv4), THR_NO_LOCK);
#else /* SSOCC_RSC */
(void) bht_rm(ssocc_ctx->ssocc_ht,
(char *)&ssocc_entry->ssocce_srv_ipv4,
sizeof(ssocc_entry->ssocce_srv_ipv4),
NULL, NULL);
#endif /* SSOCC_RSC */
ssocc_entry->ssocce_srv_ipv4 = 0;
ssocc_entry->ssocce_open_se = 0;
ssocc_entry->ssocce_open_se_exc = 0;
ssocc_entry->ssocce_last_conn = 0;
SSOCCFL_PRE(&ssocc_ctx->ssocc_fl_hd, ssocc_entry);
/* XXX free entry if there are too many? */
/* do not reset ssocc_entry->sm_magic, the entry can be reused */
if (thr_unl_always(locktype))
{
r = pthread_mutex_unlock(&ssocc_ctx->ssocc_mutex);
if (r != 0)
{
QM_LEV_DPRINTF(1, (QM_DEBFP, "sev=ERROR, func=ssocc_entry_free, unlock=%d\n", r));
/* XXX ??? COMPLAIN */
return sm_error_perm(SM_EM_Q, r);
}
}
return SM_SUCCESS;
}
#if 0
/*
** SSOCC_ENTRY_GET -- get/create new SSOCC entry
**
** Parameters:
** ssocc_ctx -- SSOCC context
** pssocc_entry -- pointer to SSOCC entry (output)
** locktype -- kind of locking
**
** Returns:
** usual sm_error code
*/
sm_ret_T
ssocc_entry_get(ssocc_ctx_P ssocc_ctx, ssocc_entry_P *pssocc_entry, thr_lock_T locktype)
{
sm_ret_T ret;
int r;
ssocc_entry_P ssocc_entry;
SM_IS_SSOCC(ssocc_ctx);
if (thr_lock_it(locktype))
{
r = pthread_mutex_lock(&ssocc_ctx->ssocc_mutex);
SM_LOCK_OK(r);
if (r != 0)
return sm_error_perm(SM_EM_Q, r);
}
if (SSOCCFL_EMPTY(&ssocc_ctx->ssocc_fl_hd))
{
ssocc_entry = (ssocc_entry_P) sm_zalloc(sizeof(*ssocc_entry));
if (ssocc_entry == NULL)
goto enomem;
#if SSOCC_CHECK
ssocc_entry->sm_magic = SM_SSOCCE_MAGIC;
#endif
}
else
{
ssocc_entry = SSOCCFL_FIRST(&ssocc_ctx->ssocc_fl_hd);
SM_IS_SSOCCE(ssocc_entry);
SSOCCFL_REMOVE(&ssocc_ctx->ssocc_fl_hd);
}
*pssocc_entry = ssocc_entry;
if (thr_unl_no_err(locktype))
{
r = pthread_mutex_unlock(&ssocc_ctx->ssocc_mutex);
if (r != 0)
{
/* XXX ??? COMPLAIN */
return sm_error_perm(SM_EM_Q, r);
}
}
return SM_SUCCESS;
enomem:
ret = sm_error_temp(SM_EM_Q, ENOMEM);
/* clean up...? nothing to do right now */
if (thr_unl_if_err(locktype))
(void) pthread_mutex_unlock(&ssocc_ctx->ssocc_mutex);
return ret;
}
#endif /* 0 */
/*
** SSOCC_ENTRY_NEW -- get/create new SSOCC entry
**
** Parameters:
** ssocc_ctx -- SSOCC context
** ipv4 -- IPv4 address of server (HACK)
** pssocc_entry -- pointer to SSOCC entry (output)
** locktype -- kind of locking
**
** Returns:
** usual sm_error code
*/
sm_ret_T
ssocc_entry_new(ssocc_ctx_P ssocc_ctx, ipv4_T ipv4, ssocc_entry_P *pssocc_entry, thr_lock_T locktype)
{
sm_ret_T ret;
int r;
ssocc_entry_P ssocc_entry;
#if !SSOCC_RSC
bht_entry_P bht_entry;
#endif
SM_IS_SSOCC(ssocc_ctx);
ssocc_entry = NULL;
if (thr_lock_it(locktype))
{
r = pthread_mutex_lock(&ssocc_ctx->ssocc_mutex);
SM_LOCK_OK(r);
if (r != 0)
return sm_error_perm(SM_EM_Q, r);
}
QM_LEV_DPRINTF(5, (QM_DEBFP, "func=ssocc_entry_new, empty=%d\n", SSOCCFL_EMPTY(&ssocc_ctx->ssocc_fl_hd)));
if (SSOCCFL_EMPTY(&ssocc_ctx->ssocc_fl_hd))
{
ssocc_entry = (ssocc_entry_P) sm_zalloc(sizeof(*ssocc_entry));
if (ssocc_entry == NULL)
goto enomem;
#if SSOCC_CHECK
ssocc_entry->sm_magic = SM_SSOCCE_MAGIC;
#endif
}
else
{
ssocc_entry = SSOCCFL_FIRST(&ssocc_ctx->ssocc_fl_hd);
SM_IS_SSOCCE(ssocc_entry);
SSOCCFL_REMOVE(&ssocc_ctx->ssocc_fl_hd);
}
ssocc_entry->ssocce_srv_ipv4 = ipv4; /* XXX HACK! */
#if 0
ssocc_entry->ssocce_init_conc = 0;
ssocc_entry->ssocce_cur_conc = 0;
ssocc_entry->ssocce_max_conc = 0;
#endif
QM_LEV_DPRINTF(4, (QM_DEBFP, "func=ssocc_entry_new, ssocc_entry=%p, ipv4=%A\n", ssocc_entry, (ipv4_T) ipv4));
#if SSOCC_RSC
ret = rsc_add(ssocc_ctx->ssocc_ht, true,
(char *)&ssocc_entry->ssocce_srv_ipv4,
sizeof(ssocc_entry->ssocce_srv_ipv4),
ssocc_entry, NULL, THR_NO_LOCK);
#else /* SSOCC_RSC */
ret = bht_add(ssocc_ctx->ssocc_ht,
(char *)&ssocc_entry->ssocce_srv_ipv4,
sizeof(ssocc_entry->ssocce_srv_ipv4),
ssocc_entry, &bht_entry);
#endif /* SSOCC_RSC */
if (sm_is_err(ret))
{
QM_LEV_DPRINTF(1, (QM_DEBFP, "sev=ERROR, func=ssocc_entry_new, bht_add=%x\n", ret));
goto error;
}
*pssocc_entry = ssocc_entry;
if (thr_unl_no_err(locktype))
{
r = pthread_mutex_unlock(&ssocc_ctx->ssocc_mutex);
if (r != 0)
{
QM_LEV_DPRINTF(1, (QM_DEBFP, "sev=ERROR, func=ssocc_entry_new, unlock=%d", r));
/* XXX ??? COMPLAIN */
return sm_error_perm(SM_EM_Q, r);
}
}
return ret;
enomem:
ret = sm_error_temp(SM_EM_Q, ENOMEM);
error:
if (ssocc_entry != NULL)
{
/*
** Don't call ssocc_entry_free() because it calls bht_rm()
** but the entry hasn't been added (that's the error cause!)
** Maybe free() the entry instead (esp. if it was allocated)?
*/
ssocc_entry->ssocce_srv_ipv4 = 0;
ssocc_entry->ssocce_open_se = 0;
ssocc_entry->ssocce_open_se_exc = 0;
ssocc_entry->ssocce_last_conn = 0;
SSOCCFL_PRE(&ssocc_ctx->ssocc_fl_hd, ssocc_entry);
ssocc_entry = NULL;
}
/* clean up...? nothing to do right now */
if (thr_unl_if_err(locktype))
{
(void) pthread_mutex_unlock(&ssocc_ctx->ssocc_mutex);
QM_LEV_DPRINTF(2, (QM_DEBFP, "func=ssocc_entry_new, err_unlock\n"));
}
return ret;
}
/*
** SSOCC_ENTRY_FIND -- find a session in SSOCC by IPv4 address
**
** Parameters:
** ssocc_ctx -- SSOCC context
** ipv4 -- IPv4 address
** pssocc_entry -- pointer to SSOCC entry (output)
** locktype -- kind of locking
**
** Returns:
** usual sm_error code; SM_E_NOTFOUND, (un)lock errors
*/
sm_ret_T
ssocc_entry_find(ssocc_ctx_P ssocc_ctx, ipv4_T ipv4, ssocc_entry_P *pssocc_entry, thr_lock_T locktype)
{
sm_ret_T ret;
int r;
ssocc_entry_P ssocc_entry;
SM_IS_SSOCC(ssocc_ctx);
SM_REQUIRE(pssocc_entry != NULL);
*pssocc_entry = NULL;
if (thr_lock_it(locktype))
{
r = pthread_mutex_lock(&ssocc_ctx->ssocc_mutex);
SM_LOCK_OK(r);
if (r != 0)
return sm_error_perm(SM_EM_Q, r);
}
ret = SM_SUCCESS;
#if SSOCC_RSC
ssocc_entry = (ssocc_entry_P) rsc_lookup(ssocc_ctx->ssocc_ht,
(const char *)&ipv4, sizeof(ipv4), THR_NO_LOCK);
#else
ssocc_entry = (ssocc_entry_P) bht_find(ssocc_ctx->ssocc_ht,
(const char *)&ipv4, sizeof(ipv4));
#endif
QM_LEV_DPRINTF(5, (QM_DEBFP, "func=ssocc_entry_find, entry=%p\n", ssocc_entry));
if (ssocc_entry == NULL)
{
ret = sm_error_perm(SM_EM_Q, SM_E_NOTFOUND);
goto error;
}
else
{
SM_IS_SSOCCE(ssocc_entry);
#if 0
if (ssocc_entry->ssocce_cur_conc == 0
&& ssocc_entry->ssocce_last_conn + SSOCCE_TO < time(NULLT))
ssocc_entry->ssocce_cur_conc = ssocc_entry->ssocce_init_conc;
#endif /* 0 */
*pssocc_entry = ssocc_entry;
}
if (thr_unl_no_err(locktype))
{
r = pthread_mutex_unlock(&ssocc_ctx->ssocc_mutex);
QM_LEV_DPRINTF(1, (QM_DEBFP, "func=ssocc_entry_find, unlock=%d\n", r));
if (r != 0)
{
/* XXX ??? COMPLAIN */
return sm_error_perm(SM_EM_Q, r);
}
}
return ret;
error:
/* clean up...? nothing to do right now */
if (thr_unl_if_err(locktype))
{
(void) pthread_mutex_unlock(&ssocc_ctx->ssocc_mutex);
QM_LEV_DPRINTF(1, (QM_DEBFP, "func=ssocc_entry_find, err_unlock\n"));
}
return ret;
}
syntax highlighted by Code2HTML, v. 0.9.1