/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <string.h>
#include <errno.h>
#include <syslog.h>
#include <procfs.h>
#include <unistd.h>
#include <fcntl.h>
#include <libintl.h>
#include <atomic.h>
#include <pthread.h>
#include <time.h>
#include "solaris-int.h"
#include "ns_connmgmt.h"
#include "ns_cache_door.h"
#include "ns_internal.h"
/*
* Access (reference, shutdown, or reload) the current connection
* management control structure conn_mgmt_t.
*/
static ns_conn_mgmt_t *access_conn_mgmt(int);
ns_conn_user_t *);
static int conn_signal(ns_conn_mt_t *);
static void start_thread();
"libsldap: unable to allocate the connection management control")
"libsldap: unable to allocate the TSD key for per-thread ldap error")
"libsldap: unable to allocate the TSD key for connection management")
"libsldap: configuration has been reloaded")
"libsldap: library unloaded or configuration has been reloaded")
"libsldap: received incorrect data from ldap_cachemgr")
"libsldap: unable to allocate memory")
"libsldap: unable to start the server monitor thread (%s)")
"libsldap: server down reported by ldap_cachemgr")
{ \
if (free == 1) \
}
{ \
msg = NS_CONN_MSG_SHUTDOWN; \
msg = NS_CONN_MSG_RELOADED; \
return (NS_LDAP_OP_FAILED); \
} \
}
/*
* TSD keys ns_mtckey and ns_cmgkey are for sharing ldap connections
* and their associated connection management structure among
* multiple threads. The pointers to the per-thread ldap error
* information and the connection management structure are
* saved in ns_mtckey and ns_cmgkey.
*/
/* Per thread LDAP error resides in thread-specific data (ns_mtckey) */
struct ldap_error {
int le_errno;
char *le_matched;
char *le_errmsg;
};
/* NULL struct ldap_error */
/* destructor: free the ldap error data in the thread specific area */
static void
return;
}
}
}
static void
conn_tsd_free() {
int rc;
/* free the per-thread ldap error info */
/* detach the connection management control */
}
/* per-thread callback function for allocating a mutex */
static void *
ns_mutex_alloc(void)
{
}
}
return (mutexp);
}
/* per-thread callback function for freeing a mutex */
static void
{
}
/*
* Function for setting up thread-specific data
* where per thread LDAP error and the pointer
* to the active connection management control
* are stored.
*/
static int
{
void *tsd;
int rc;
if (rc != 0) /* must be ENOMEM */
return (-1);
/* return success if the ns_mtckey TSD is already set */
return (0);
/* allocate and set the ns_mtckey TSD */
return (-1);
if (rc != 0) { /* must be ENOMEM */
return (-1);
}
return (0);
}
/* Callback function for setting the per thread LDAP error */
/*ARGSUSED*/
static void
{
int eno;
"libsldap: set_ld_error: thr_getspecific failed (%s)."),
return;
}
/* play safe, do nothing if TSD pointer is NULL */
"libsldap: set_ld_error: TSD pointer is NULL."));
return;
}
}
}
}
/* check and allocate the thread-specific data for using a MT connection */
static int
{
if (conn_tsd_setup(cmg) != 0)
return (NS_LDAP_MEMORY);
return (NS_LDAP_SUCCESS);
}
/* Callback function for getting the per thread LDAP error */
/*ARGSUSED*/
static int
{
int eno;
"libsldap: get_ld_error: thr_getspecific failed (%s)"),
return (eno);
}
/* play safe, return NULL error data, if TSD pointer is NULL */
le = &ldap_error_NULL;
}
}
}
/* Callback function for setting per thread errno */
static void
{
}
/* Callback function for getting per thread errno */
static int
get_errno(void)
{
return (errno);
}
/* set up an ldap session 'ld' for sharing among multiple threads */
static int
{
int rc;
/*
* Set the function pointers for dealing with mutexes
* and error information
*/
/*
* Set up the ld to use those function pointers
*/
(void *) &tfns);
if (rc < 0) {
"(LDAP_OPT_THREAD_FN_PTRS)"));
return (0);
}
/*
* Set the function pointers for working with semaphores
*/
sizeof (struct ldap_extra_thread_fns));
/* Set up the ld to use those function pointers */
(void *) &extrafns);
if (rc < 0) {
"(LDAP_OPT_EXTRA_THREAD_FN_PTRS)"));
return (0);
}
return (1);
}
/* set up an MT connection for sharing among multiple threads */
static int
{
/* set up the per-thread data for using the MT connection */
gettext("libsldap: tid= %d: unable to set up TSD\n"), t);
return (-1);
}
if (setup_mt_conn(ld) == 0) {
/* multiple threads per connection not supported */
"threads per connection not supported\n"), t);
return (-1);
}
return (0);
}
/*
* Check name and UID of process, if it is nscd.
*
* Input:
* pid : PID of checked process
* check_uid : check if UID == 0
* Output:
* B_TRUE : nscd detected
* B_FALSE : nscd not confirmed
*/
static boolean_t
{
int fd;
return (B_FALSE);
return (B_TRUE);
}
}
}
return (B_FALSE);
}
/*
* Check if this process is peruser nscd.
*/
__s_api_peruser_proc(void)
{
/*
* Already checked before for this process? If yes, return cached
* response.
*/
if (my_ppid == checkedPpid) {
return (isPeruserNscd);
}
(void) mutex_lock(&nscdLock);
/* Check once more incase another thread has just complete this. */
if (my_ppid == checkedPpid) {
(void) mutex_unlock(&nscdLock);
return (isPeruserNscd);
}
/* Reinitialize to be sure there is no residue after fork. */
/* Am I the nscd process? */
/* Is my parent the nscd process with UID == 0. */
}
/* Remember for whom isPeruserNscd is. */
(void) mutex_unlock(&nscdLock);
return (isPeruserNscd);
}
/*
* Check if this process is main nscd.
*/
__s_api_nscd_proc(void)
{
/*
* Don't bother checking if this process isn't root, this cannot
* be main nscd.
*/
if (getuid() != 0)
return (B_FALSE);
/*
* Already checked before for this process? If yes, return cached
* response.
*/
if (my_pid == checkedPid) {
return (isMainNscd);
}
(void) mutex_lock(&nscdLock);
/* Check once more incase another thread has just done this. */
if (my_pid == checkedPid) {
(void) mutex_unlock(&nscdLock);
return (isMainNscd);
}
/*
* Am I the nscd process? UID is already checked, not needed from
* psinfo.
*/
/* Remember for whom isMainNscd is. */
checkedPid = my_pid;
(void) mutex_unlock(&nscdLock);
return (isMainNscd);
}
/*
* initialize a connection management control structure conn_mgmt_t
*/
{
return (NULL);
}
/* is this process nscd or peruser nscd ? */
/*
* assume the underlying libldap allows multiple threads sharing
* the same ldap connection (MT connection)
*/
/* for nscd or peruser nscd, MT connection is required */
/*
* reference (or initialize) the current Native LDAP configuration and
* if in nscd process, make it never refreshed
*/
/*
* main nscd get config change notice from ldap_cachemgr
* so won't times out and refresh the config
*/
}
return (cmg);
}
static void
{
if (op == NS_CONN_MGMT_OP_SHUTDOWN)
else
if (op == NS_CONN_MGMT_OP_RELOAD_CONFIG)
}
/*
* Return a pointer to the current connection management. If
* it has not been created, or is requested to recreate, then
* create and return the pointer. It is possible, the current
* one is created by the parent before fork, create a new
* one too in such a case.
*/
static ns_conn_mgmt_t *
{
checked_pid = mypid;
/*
* if current conn_mgmt not created yet or is from parent
* or is requested to recreate, create it
*/
/*
* We don't want to free the conn_mgmt
* allocated by the parent, since
* there may be ldap connections
* still being used. So leave it
* alone but keep it referenced,
* so that it will not be flagged
* as a piece of leaked memory.
*/
/*
* avoid lint warning; does not
* change the conn_mgmt in parent
*/
}
cmg = ns_connmgmt;
/*
* ensure it will not be destroyed until explicitly
* shut down or reloaded
*/
if (op == NS_CONN_MGMT_OP_REF)
}
}
return (cmg);
}
static ns_conn_mgmt_t *
{
(void) mutex_lock(&ns_connmgmt_lock);
/*
* connection management is not available when the libsldap is being
* unloaded or shut down
*/
if (ns_connmgmt_shutting_down == B_TRUE) {
(void) mutex_unlock(&ns_connmgmt_lock);
return (NULL);
}
if (op == NS_CONN_MGMT_OP_SHUTDOWN) {
if (ns_connmgmt != NULL) {
cmg = ns_connmgmt;
ns_connmgmt = NULL;
}
(void) mutex_unlock(&ns_connmgmt_lock);
return (cmg);
}
if (op == NS_CONN_MGMT_OP_RELOAD_CONFIG ||
op == NS_CONN_MGMT_OP_NEW_CONFIG) {
/*
* the previous cmg (cmg_prev) will be freed later
* when its ref count reaches zero
*/
ns_connmgmt = NULL;
}
(void) mutex_unlock(&ns_connmgmt_lock);
return (NULL);
}
if (op == NS_CONN_MGMT_OP_RELOAD_CONFIG ||
else { /* op is NS_CONN_MGMT_OP_REF or NS_CONN_MGMT_OP_LIB_INIT */
}
(void) mutex_unlock(&ns_connmgmt_lock);
return (cmg);
}
/*
* free a connection management control
*/
static void
{
union {
} space;
int ndata;
int adata;
int rc;
return;
/* destroy the previous config or release the current one */
else
}
/* stop the server status/config-change monitor thread */
&adata);
if (rc != NS_CACHE_SUCCESS)
gettext("libsldap: "
"free_conn_mgmt():"
" stopping door call "
" GETSTATUSCHANGE failed "
" (rc = %d)"), rc);
}
}
}
}
static ns_conn_mgmt_t *
{
return (NULL);
if (unlock_cmg == B_TRUE)
return (NULL);
} else {
gettext("libsldap: connection management "
" has a refcount of zero but the state "
}
}
return (cmg);
}
/*
* exposed function for initializing a connection management control structure
*/
{
return (NULL);
}
return (NULL);
}
return (access_conn_mgmt(NS_CONN_MGMT_OP_LIB_INIT));
}
/* initialize a connection user */
{
/* delete the reference to the previously used conn_mgmt */
return (NULL);
return (NULL);
}
return (NULL);
}
(void) conn_tsd_setup(cmg);
return (cu);
}
/*
* Free the resources used by a connection user.
* The caller should ensure this conn_user is
* not associated with any conn_mt, i.e.,
* not in any conn_mt's linked list of conn_users.
* The caller needs to free the userinfo member
* as well.
*/
void
{
return;
}
/*
* Initialize an MT connection control structure
* that will be used to represent an ldap connection
* to be shared among multiple threads and to hold
* and manage all the conn_users using the ldap
* connection.
*/
static ns_conn_mt_t *
{
return (NULL);
}
}
return (NULL);
}
return (cm);
}
/*
* Free an MT connection control structure, assume conn_mgmt is locked.
* 'unlock_cmg' is passed to release_conn_mgmt() to indicate the
* cmg needs to be unlocked or not.
*/
static ns_conn_mgmt_t *
{
return (NULL);
}
}
/* add a connection user to an MT connection */
static void
{
} else {
}
}
/* add an MT connection to the connection management */
static void
{
/*
* add connection opened for WRITE to top of list
* for garbage collection purpose. This is to
* ensure the connection will be closed after a
* certain amount of time (60 seconds).
*/
} else {
} else {
}
}
}
/* delete a connection user from an MT connection */
static void
{
return;
/* only one conn_user on list */
}
return;
}
/* more than one and cu is the first one */
return;
}
if (cu == u)
break;
pu = u;
}
} else {
"libsldap: del_cu4cm(): connection user not found"));
}
}
/* delete an MT connection from the connection management control structure */
static void
{
return;
/* only one conn_mt on list */
}
return;
}
/* more than one and cm is the first one */
return;
}
if (cm == m)
break;
pm = m;
}
} else {
"libsldap: del_cm4cmg(): MT connection not found"));
}
}
/*
* compare to see if the server and credential for authentication match
* those used by an MT connection
*/
static boolean_t
{
/* check server first */
return (B_FALSE);
}
return (B_TRUE);
/* then check cred */
}
/*
* Wait until a pending MT connection becomes available.
* Return 1 if so, 0 if error.
*
* Assume the current conn_mgmt and the input conn_mt
* are locked.
*/
static int
{
/*
* It could take some time so we don't want to hold
* cm->conn_mgmt across the wait
*/
/* check one more time see if need to wait */
/* cm->lock is locked again at this point */
}
return (1);
else {
return (0);
}
}
/*
* Check and see if the input MT connection '*cm' should be closed.
* In two cases, it should be closed. If a preferred server is
* found to be up when ldap_cachemgr is queried and reported back.
* Or when the server being used for the connection is found to
* be down. Return B_FALSE if the connection is not closed (or not marked
* to be closed), otherwise unlock mutex (*cm)->lock and return B_TRUE.
* This function assumes conn_mgmt cmg and conn_mt *cm are locked.
*/
static boolean_t
ns_conn_user_t *cu) {
int rc;
int j;
int free_cm;
/*
* check only if preferred servers are defined
*/
return (B_FALSE);
/*
* ask ldap_cachemgr for the first available server
*/
(void) __ns_ldap_freeError(&errorp);
return (B_FALSE);
}
/*
* Did ldap_cachemgr return a preferred server ?
*/
continue;
upidx = j;
break;
}
/*
* Is the server being used a preferred one ?
*/
continue;
svridx = j;
break;
}
/*
* Need to fall back to a down-but-now-up preferred server ?
* A preferred server falls back to a more preferred one.
* A regular one falls back to any preferred ones. So if
* both are preferred ones and same index, or both
* are not preferred ones, then no need to close the
* connection.
*/
return (B_FALSE);
}
/*
* otherwise, 4 cases, all may need to close the connection:
* For case 1 and 2, both servers are preferred ones:
* 1. ldap_cachemgr returned a better one to use (upidx < svridx)
* 2. the server being used is down (upidx > svridx)
* 3. ldap_cachemgr returned a preferred one, but the server
* being used is not, so need to fall back to the preferred server
* 4. ldap_cachemgr returned a non-preferred one, but the server
* being used is a preferred one, so it must be down (since
* ldap_cachemgr always returns a preferred one when possible).
* For case 1 & 3, close the READ connection when no user uses it.
* For 2 and 4, close the connection with error rc, LDAP_SERVER_DOWN.
*/
return (B_FALSE);
}
} else {
/* cu has not been attached to cm yet, use NULL as cu pointer */
(void) __ns_ldap_freeError(&ep);
}
if (free_cm == 1) {
(void) free_conn_mt(*cm, 0);
}
return (B_TRUE);
}
/*
* Check to see if a conn_mt matches the connection criteria from
* a conn_user. Return B_TRUE if yes, B_FALSE, otherwise. The input
* conn_mt pointer (*cmt) may be freed and *cmt will be set to NULL
* to indicate so.
* conn_mt *cmt and conn_mgmt cm->conn_mgmt are assumed locked.
* cm->lock is unlocked at exit if rc is B_FALSE.
*/
static boolean_t
{
int free_cm = 0;
return (B_FALSE);
}
/*
* if a conn_mt opened for WRITE is idle
* long enough, then close it. To improve
* the performance of applications, such
* as ldapaddent, a WRITE connection is
* given a short time to live in the
* connection pool, expecting the write
* requests to come in a quick succession.
* To save resource, the connection will
* be closed if idle more than 60 seconds.
*/
/*
* NS_LDAP_INTERNAL is irrelevant here. There no
* conn_user to consume the rc
*/
if (free_cm == 1) {
(void) free_conn_mt(cm, 0);
}
return (B_FALSE);
}
case NS_CONN_USER_SEARCH:
case NS_CONN_USER_GETENT:
break;
case NS_CONN_USER_WRITE:
break;
default:
break;
}
/*
* Check and drop the 'connected' connection if
* necessary. Main nscd gets status changes from
* the ldap_cachemgr daemon directly via the
* GETSTATUSCHANGE door call, the standalone
* function works in a no ldap_cachemgr environment,
* so no need to check and drop connections.
*/
return (B_FALSE);
}
}
/* check if max. users using or waiting for the connection */
}
return (matched);
}
/*
* obtain an MT connection from the connection management for a conn_user
*
* Input:
* server : server name or IP address
* flags : libsldap API flags
* cred : pointer to the user credential
* cu : pointer to the conn_user structure
* Output:
* session : hold pointer to the Connection structure
* errorp : hold pointer to error info (ns_ldap_error_t)
*/
int
{
int rc;
int i;
return (NS_LDAP_INVALID_PARAM);
/*
* for pam_ldap, always try opening a new connection
*/
return (NS_LDAP_NOTFOUND);
/* if need a new conn, then don't reuse */
if (flags & NS_LDAP_NEW_CONN)
return (NS_LDAP_NOTFOUND);
if (flags & NS_LDAP_KEEP_CONN)
/*
* We want to use MT connection only if keep-connection flag is
* set or if MT was requested (or active)
*/
return (NS_LDAP_NOTFOUND);
/* first look for a connection already open */
for (i = 0; i < 2; i++) {
continue;
/*
* as the conn_mt list could
* be different due to cn's
* deletion, scan the entire
* conn_mt list again
*/
i = -1;
break;
}
/* return a connected one if found */
return (NS_LDAP_SUCCESS);
}
/*
* if cn is not connecting, or allow only
* one user, skip it
*/
continue;
}
/* wait for the connecting conn_mt */
/*
* NS_LDAP_NOTFOUND signals that the function
* __s_api_check_libldap_MT_conn_support()
* detected that the lower libldap library
* does not support MT connection, so return
* NS_LDAP_NOTFOUND to let the caller to
* open a non-MT conneciton. Otherwise,
* connect error occurred, return
* NS_CONN_USER_CONNECT_ERROR
*/
else {
}
/* cmg->lock unlocked by wait_for_conn_mt() */
}
/* return the newly available conn_mt */
/* cmg->lock unlocked by wait_for_conn_mt() */
return (NS_LDAP_SUCCESS);
}
/* next, look for a connecting conn_mt */
if (i == 0)
}
/* no connection found, start opening one */
}
else
return (NS_LDAP_NOTFOUND);
}
/*
* add an MT connection to the connection management
*
* Input:
* con : pointer to the Connection info
* cu : pointer to the conn_user structure
* Output:
* ep : hold pointer to error info (ns_ldap_error_t)
*/
int
{
/* if the conn_mgmt is being shut down, return error */
/*
* start the change monitor thread only if it
* hasn't been started and the process is the
* main nscd (not peruser nscd)
*/
}
else
/* wake up the waiters if any */
(void) conn_signal(cm);
return (NS_LDAP_SUCCESS);
}
/*
* return an MT connection to the pool when a conn user is done using it
*
* Input:
* cu : pointer to the conn_user structure
* Output: NONE
*/
void
{
return;
return;
/*
* if this MT connection is no longer needed, or not usable, and
* no more conn_user uses it, then close it.
*/
/* use ns_conn_free (instead of 1) to avoid lint warning */
} else {
/* clean up remaining results just in case */
(void) ldap_msgfree(res);
}
}
}
}
/* save error info (rc and ns_ldap_error_t) in the conn_mt */
static void
else
}
}
/* copy error info (rc and ns_ldap_error_t) from conn_mt to conn_user */
static void
else
}
}
/* copy error info (rc and ns_ldap_error_t) from caller to conn_user */
static void
} else
}
/*
* remove an MT connection from the connection management when failed to open
*
* Input:
* cu : pointer to the conn_user structure
* rc : error code
* errorp : pointer to pointer to error info (ns_ldap_error_t)
* Output:
* errorp : set to NULL, if none NULL cm, callers do not need to free it
*/
void
{
int free_cm = 0;
return;
return;
}
}
/* all the conn_users share the same error rc and ns_ldap_error_t */
/* wake up the waiters if any */
(void) conn_signal(cm);
free_cm = 1;
}
}
/*
* check to see if the underlying libldap supports multi-threaded client
* (MT connections)
*/
int
{
int rc;
/* if no need to check, just return success */
return (NS_LDAP_SUCCESS);
/*
* If the conn_mgmt is being shut down, return error.
* if cmg is usable, cmg->lock will be locked. Otherwise,
* this function will return with rc NS_LDAP_OP_FAILED.
*/
if (rc < 0)
else {
}
}
}
}
if (rc < 0)
return (NS_LDAP_SUCCESS);
}
/*
* Close an MT connection.
* Assume cm not null and locked, assume conn_mgmt is also locked.
* Return -1 if error, 1 if the cm should be freed, otherwise 0.
*/
static int
{
ns_conn_mt_t *m;
ns_conn_user_t *u;
return (-1);
/* if the conn_mt is not in the MT connection pool, nothing to do */
if (cm == m)
break;
}
if (m == NULL)
return (-1);
/*
* If more cu exist to consume the error info, copy
* it to the cm. If the caller calls on behalf of
* a cu, cu won't be NULL. Check to see if there's
* more cu that needs the error info. If caller does
* not have a specific cu attached to it (e.g.,
* shutdown_all_conn_mt()), cu is NULL, check if at
* least one cu exists.
*/
/* wake up waiter (conn_user) if any */
(void) conn_signal(cm);
}
/* for each conn_user using the conn_mt, set bad_mt_conn flag */
u->bad_mt_conn = B_TRUE;
}
}
}
/* detach the conn_mt if no more conn_user left */
return (1);
}
return (0);
}
/*
* An MT connection becomes bad, close it and free resources.
* This function is called with a ns_conn_user_t representing
* a user of the MT connection.
*
* Input:
* cu : pointer to the conn_user structure
* rc : error code
* errorp : pointer to pointer to error info (ns_ldap_error_t)
* Output:
* errorp : set to NULL (if no error), callers do not need to free it
*/
void
{
int free_cm = 0;
return;
return;
/* close the MT connection if possible */
return;
}
} else { /* error not passed in, use those saved in the conn_mt */
}
/* detach the conn_user from the conn_mt */
}
/*
* Close an MT connection when the associated server is known to be
* down. This function is called with a ns_conn_mt_t representing
* the MT connection. That is, the caller is not a conn_user
* thread but rather the procchg thread.
*/
static void
{
int free_cm = 0;
return;
}
/* close the MT connection if possible */
return;
}
(void) __ns_ldap_freeError(&ep);
}
/*
* Close an MT connection when there is a better server to connect to.
* Mark the connection as to-be-closed-when-no-one-using so that
* any outstanding ldap operations can run to completion.
* Assume that both the conn_mt and conn_mgmt are locked.
* Return 1 if the conn_mt should be freed.
*/
static int
{
int free_cm = 0;
free_cm = 1;
} else {
}
return (free_cm);
}
/*
* Retrieve the configured preferred server list.
* This function locked the conn_mgmt and does not
* unlock at exit.
*/
static void
{
/* if already done, and no reload, then return */
return;
}
} else {
(void) __ns_ldap_freeError(&errorp);
(void) __ns_ldap_freeParam(&pservers);
}
}
/*
* This function handles the config or server status change notification
* from the ldap_cachemgr.
*/
static ns_conn_mgmt_t *
{
int cnt, i, j, k, n;
char *s;
/* if config changed, reload the configuration */
/* reload the conn_mgmt and Native LDAP config */
/* release the one obtained from access_conn_mgmt(RELOAD) */
/* release the one obtained when ocmg was created */
return (ocmg);
}
return (cmg);
/* handle down servers first */
for (i = 0; i < cnt; i++) {
continue;
/*
* look for a CONNECTED MT connection using
* the same server s, and close it
*/
while (loop) {
if (cmg_locked == B_FALSE) {
cmg_locked = B_TRUE;
}
break;
}
}
/*
* Process the next cm using server s.
* Start from the head of the cm linked
* list again, as the cm list may change
* after close_conn_mt_by_procchg() is done.
*/
continue;
}
/*
* No (more) MT connection using the down server s.
* Process the next server on the list.
*/
break;
} /* while loop */
}
/*
* Next handle servers whose status changed to up.
* Get the preferred server list first if not done yet.
* get_preferred_servers() leaves conn_mgmt locked.
*/
cmg_locked = B_TRUE;
/*
* if no preferred server configured, we don't switch MT connection
* to a more preferred server (i.e., fallback), so just return
*/
return (cmg);
}
/* for each server that is up now */
for (i = 0; i < cnt; i++) {
continue;
/*
* look for a CONNECTED MT connection which uses
* a server less preferred than s, and treat it
* as 'fallback needed' by calling
* close_conn_mt_when_nouser()
*/
k = -1;
while (loop) {
if (cmg_locked == B_FALSE) {
cmg_locked = B_TRUE;
}
/* Is s a preferred server ? */
if (k == -1) {
s) == 0) {
k = j;
break;
}
}
}
/* skip s if not a preferred server */
if (k == -1) {
break;
}
/* check each MT connection */
/*
* Find an MT connection that is connected and
* not marked, but leave WRITE or REFERRAL
* connections alone, since fallback does not
* make sense for them.
*/
n = -1;
/*
* j < k ??? should we close
* an active MT that is using s ?
* ie could s went down and up
* again, but cm is bound prior to
* the down ? Play safe here,
* and check j <= k.
*/
for (j = 0; j <= k; j++) {
if (strcasecmp(
n = j;
break;
}
}
/*
* s is preferred, if its location
* in the preferred server list is
* ahead of that of the server
* used by the cm (i.e., no match
* found before s)
*/
if (n == -1) { /* s is preferred */
int fr = 0;
cm);
/*
* break, not continue,
* because we need to
* check the entire cm
* list again. The call
* above may change the
* cm list.
*/
break;
}
}
}
/* if no (more) cm using s, check next server */
} /* while loop */
}
if (cmg_locked == B_TRUE)
return (cmg);
}
/* Shut down all MT connection managed by the connection management */
void
{
int free_cm = 0;
/* OK if returns NULL */
}
/* shut down each conn_mt, ignore errors */
if (free_cm == 1) {
(void) free_conn_mt(cm, 0);
/*
* conn_mt may change, so start from
* top of list again
*/
break;
}
}
}
(void) __ns_ldap_freeError(&ep);
}
/* free all the resources used by the connection management */
void
{
return;
(void) shutdown_all_conn_mt(cmg);
/* then destroy the conn_mgmt */
}
/*
* Reinitialize the libsldap connection management after
* a new native LDAP configuration is received.
*/
void
{
return;
return;
}
/* reload the conn_mgmt and native LDAP config */
/* release the one obtained from access_conn_mgmt(RELOAD) */
/* release the one obtained when ocmg was created */
/* release the one obtained when this function is entered */
}
/*
* Prepare to retry ldap search operation if needed.
* Return 1 if retry is needed, otherwise 0.
* If first time in, return 1. If not, return 1 if:
* - not a NS_CONN_USER_GETENT conn_user AND
* - have not retried 3 times yet AND
* - previous search failed AND
* - the retry flag is set in the ns_conn_user_t or config was reloaded
*/
int
{
/*
* if called from firstEntry(), keep conn_mt for
* the subsequent getnext requests
*/
return (0);
return (0);
}
if (*try_cnt > NS_LIST_TRY_MAX)
return (0);
*rc = NS_LDAP_MEMORY;
}
/* for 1+ try, use previous rc and errorp */
return (0);
}
/* free ldap_error_t from previous search */
(void) __ns_ldap_freeError(errorp);
return (1);
}
/* prepare to get the next entry for an enumeration */
int
{
int rc;
/*
* if using an MT connection, ensure the thread-specific data are set,
* but if the MT connection is no longer good, return the error saved.
*/
return (*ns_err);
}
if (rc != NS_LDAP_SUCCESS) {
return (rc);
}
}
return (NS_LDAP_SUCCESS);
}
/* wait for an MT connection to become available */
static int
{
return (0);
}
/* signal that an MT connection is now available */
static int
{
int c = 0;
while (tmp) {
c++;
}
return (c);
}
/*
* from ldap_cachemgr
*/
static void *
{
union {
} space;
int ndata;
int adata;
char *ptr;
int ds_cnt;
int door_rc;
int which;
int retry = 0;
char *c, *oc;
/* cmg is locked before called */
/* make sure the thread specific data are set */
(void) conn_tsd_setup(cmg);
while (loop) {
/*
* If the attached conn_mgmt has been deleted,
* then exit. The new conn_mgmt will starts it
* own monitor thread later. If libsldap is being
* unloaded or configuration reloaded, OR
* ldap_cachemgr rejected the GETSTATUSCHANGE door
* call, then exit as well.
*/
getchg_not_supported == B_TRUE) {
}
}
}
if (door_rc == NS_CACHE_SUCCESS)
&adata);
/*
* Check and see if the conn_mgmt is still current.
* If not, no need to continue.
*/
}
}
if (door_rc != NS_CACHE_SUCCESS) {
if (door_rc == NS_CACHE_NOSERVER) {
if (retry++ > 10)
else {
/*
* ldap_cachemgr may be down, give
* it time to restart
*/
(void) sleep(2);
}
} else if (door_rc == NS_CACHE_NOTFOUND)
continue;
} else
retry = 0;
/* copy info from door call return structure */
/* configuration change ? */
continue;
}
/* server status changes ? */
/*
* first check cookies, if don't match, config
* has changed
*/
continue;
}
sizeof (char *));
continue;
}
sizeof (int));
continue;
}
ds_cnt = 0;
which = 0;
/* look for DOORLINESEP or end of string */
if (*c != dsep && *c != '\0')
continue;
if (*c == dsep) { /* DOORLINESEP */
*c = '\0'; /* current value */
c += dslen; /* skip to next value */
}
if (which == 0) { /* get server info */
oc = c;
continue;
}
} else if (strcmp(NS_SERVER_CHANGE_DOWN,
oc) == 0)
else {
continue;
}
oc = c;
ds_cnt++;
if (*c == '\0')
else
which = 0; /* get server info next */
}
continue;
}
}
return (NULL);
}
/* start the thread handling the change notification from ldap_cachemgr */
static void
int errnum;
/*
* start a thread to get and process config and server status changes
*/
}
}