1*e1dd0a2fSth160488 /* 2*e1dd0a2fSth160488 * CDDL HEADER START 3*e1dd0a2fSth160488 * 4*e1dd0a2fSth160488 * The contents of this file are subject to the terms of the 5*e1dd0a2fSth160488 * Common Development and Distribution License (the "License"). 6*e1dd0a2fSth160488 * You may not use this file except in compliance with the License. 7*e1dd0a2fSth160488 * 8*e1dd0a2fSth160488 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*e1dd0a2fSth160488 * or http://www.opensolaris.org/os/licensing. 10*e1dd0a2fSth160488 * See the License for the specific language governing permissions 11*e1dd0a2fSth160488 * and limitations under the License. 12*e1dd0a2fSth160488 * 13*e1dd0a2fSth160488 * When distributing Covered Code, include this CDDL HEADER in each 14*e1dd0a2fSth160488 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*e1dd0a2fSth160488 * If applicable, add the following below this CDDL HEADER, with the 16*e1dd0a2fSth160488 * fields enclosed by brackets "[]" replaced with your own identifying 17*e1dd0a2fSth160488 * information: Portions Copyright [yyyy] [name of copyright owner] 18*e1dd0a2fSth160488 * 19*e1dd0a2fSth160488 * CDDL HEADER END 20*e1dd0a2fSth160488 */ 21*e1dd0a2fSth160488 /* 22*e1dd0a2fSth160488 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23*e1dd0a2fSth160488 * Use is subject to license terms. 24*e1dd0a2fSth160488 */ 25*e1dd0a2fSth160488 26*e1dd0a2fSth160488 27*e1dd0a2fSth160488 #ifndef _NS_CONNMGMT_H 28*e1dd0a2fSth160488 #define _NS_CONNMGMT_H 29*e1dd0a2fSth160488 30*e1dd0a2fSth160488 #pragma ident "%Z%%M% %I% %E% SMI" 31*e1dd0a2fSth160488 32*e1dd0a2fSth160488 #ifdef __cplusplus 33*e1dd0a2fSth160488 extern "C" { 34*e1dd0a2fSth160488 #endif 35*e1dd0a2fSth160488 36*e1dd0a2fSth160488 #include <thread.h> 37*e1dd0a2fSth160488 #include "ns_sldap.h" 38*e1dd0a2fSth160488 #include "ns_internal.h" 39*e1dd0a2fSth160488 #include "ns_cache_door.h" 40*e1dd0a2fSth160488 41*e1dd0a2fSth160488 struct ns_conn_user; /* connection user, forward definition */ 42*e1dd0a2fSth160488 struct ns_conn_mt; /* multi-threaded (MT) connection, forward definition */ 43*e1dd0a2fSth160488 struct ns_conn_mgmt; /* connection management, forward definition */ 44*e1dd0a2fSth160488 45*e1dd0a2fSth160488 #define NS_CONN_MT_USER_NO_MAX -1 46*e1dd0a2fSth160488 #define NS_CONN_MT_USER_MAX NS_CONN_MT_USER_NO_MAX 47*e1dd0a2fSth160488 #define NS_LIST_TRY_MAX 3 48*e1dd0a2fSth160488 49*e1dd0a2fSth160488 /* 50*e1dd0a2fSth160488 * Structure for handling the waiter of a pending multi-threaded (MT) connection 51*e1dd0a2fSth160488 */ 52*e1dd0a2fSth160488 typedef struct ns_conn_waiter { 53*e1dd0a2fSth160488 cond_t waitcv; 54*e1dd0a2fSth160488 uint8_t signaled; 55*e1dd0a2fSth160488 struct ns_conn_user *key; 56*e1dd0a2fSth160488 struct ns_conn_waiter *next, *prev; 57*e1dd0a2fSth160488 } ns_conn_waiter_t; 58*e1dd0a2fSth160488 59*e1dd0a2fSth160488 /* 60*e1dd0a2fSth160488 * type of a connection user 61*e1dd0a2fSth160488 */ 62*e1dd0a2fSth160488 typedef enum { 63*e1dd0a2fSth160488 NS_CONN_USER_SEARCH = 1, 64*e1dd0a2fSth160488 NS_CONN_USER_WRITE = 2, 65*e1dd0a2fSth160488 NS_CONN_USER_AUTH = 3, 66*e1dd0a2fSth160488 NS_CONN_USER_GETENT = 4 67*e1dd0a2fSth160488 } ns_conn_user_type_t; 68*e1dd0a2fSth160488 69*e1dd0a2fSth160488 /* 70*e1dd0a2fSth160488 * state of a connection user 71*e1dd0a2fSth160488 */ 72*e1dd0a2fSth160488 typedef enum { 73*e1dd0a2fSth160488 NS_CONN_USER_UNINITED = 0, 74*e1dd0a2fSth160488 NS_CONN_USER_ALLOCATED = 1, 75*e1dd0a2fSth160488 NS_CONN_USER_FINDING = 2, /* looking for an MT connection */ 76*e1dd0a2fSth160488 NS_CONN_USER_WAITING = 3, /* waiting for an MT connection */ 77*e1dd0a2fSth160488 NS_CONN_USER_WOKEUP = 4, 78*e1dd0a2fSth160488 NS_CONN_USER_CONNECT_ERROR = 5, 79*e1dd0a2fSth160488 NS_CONN_USER_CONNECTED = 6, 80*e1dd0a2fSth160488 NS_CONN_USER_DISCONNECTED = 7, 81*e1dd0a2fSth160488 NS_CONN_USER_FREED = 8 82*e1dd0a2fSth160488 } ns_conn_user_state_t; 83*e1dd0a2fSth160488 84*e1dd0a2fSth160488 /* 85*e1dd0a2fSth160488 * A connection user represents a request processed by libsldap. It 86*e1dd0a2fSth160488 * usually is a thread using the same connection from start to end. 87*e1dd0a2fSth160488 * Different connection users of the same type can share the same 88*e1dd0a2fSth160488 * connection opened for that type. But search and getent users can 89*e1dd0a2fSth160488 * share the same connection opened for either search or getent. AUTH 90*e1dd0a2fSth160488 * connection are not shareable. 91*e1dd0a2fSth160488 * 92*e1dd0a2fSth160488 * A getent user may have a longer lifespan and live outside of libsldap. 93*e1dd0a2fSth160488 * This is because the associated search cookie is passed back to the caller 94*e1dd0a2fSth160488 * via the firstEntry call and used in the subsequent nextEntry or endEntry 95*e1dd0a2fSth160488 * calls. Even though the firstEntry and the nextEntry/endEntry calls may 96*e1dd0a2fSth160488 * be running in a different thread, the connection being used will be the 97*e1dd0a2fSth160488 * same. It is the one assigend during the firstEntry call. 98*e1dd0a2fSth160488 */ 99*e1dd0a2fSth160488 struct ns_conn_user { 100*e1dd0a2fSth160488 ns_conn_user_type_t type; /* search, write, auth, getent, ... */ 101*e1dd0a2fSth160488 ns_conn_user_state_t state; 102*e1dd0a2fSth160488 thread_t tid; /* id of the thread starts the request */ 103*e1dd0a2fSth160488 struct ns_conn_user *next; /* next conn_user in the linked list */ 104*e1dd0a2fSth160488 struct ns_conn_mt *conn_mt; /* the MT connection being used */ 105*e1dd0a2fSth160488 struct ns_conn_mgmt *conn_mgmt; /* ref counted conn management */ 106*e1dd0a2fSth160488 void *userinfo; /* private data of the request */ 107*e1dd0a2fSth160488 ns_ldap_return_code ns_rc; /* error return code */ 108*e1dd0a2fSth160488 ns_ldap_error_t *ns_error; /* error info */ 109*e1dd0a2fSth160488 boolean_t referral; /* using a referred server ? */ 110*e1dd0a2fSth160488 boolean_t retry; /* retry the request on certain error? */ 111*e1dd0a2fSth160488 boolean_t keep_conn; /* keep the conn for reuse ? */ 112*e1dd0a2fSth160488 boolean_t use_mt_conn; /* using/used an MT connection ? */ 113*e1dd0a2fSth160488 boolean_t bad_mt_conn; /* MT connection is not usable ? */ 114*e1dd0a2fSth160488 }; 115*e1dd0a2fSth160488 116*e1dd0a2fSth160488 /* 117*e1dd0a2fSth160488 * state of an MT connection 118*e1dd0a2fSth160488 */ 119*e1dd0a2fSth160488 typedef enum { 120*e1dd0a2fSth160488 NS_CONN_MT_UNINITED = 0, 121*e1dd0a2fSth160488 NS_CONN_MT_CONNECTING = 1, 122*e1dd0a2fSth160488 NS_CONN_MT_CONNECT_ERROR = 2, 123*e1dd0a2fSth160488 NS_CONN_MT_CONNECTED = 3, 124*e1dd0a2fSth160488 NS_CONN_MT_CLOSING = 4 125*e1dd0a2fSth160488 } ns_conn_mt_state_t; 126*e1dd0a2fSth160488 127*e1dd0a2fSth160488 /* 128*e1dd0a2fSth160488 * An ns_conn_mt (or MT connection) represents an ldap connection 129*e1dd0a2fSth160488 * that can be shared among multiple threads. It also represents 130*e1dd0a2fSth160488 * the set of connection users using the ldap connection. It contains 131*e1dd0a2fSth160488 * a pointer to the Connection structure that has the physical info 132*e1dd0a2fSth160488 * of the connection (server name, address, ldap handle, etc). It 133*e1dd0a2fSth160488 * also contains a linked list of all the conn_user using the ldap 134*e1dd0a2fSth160488 * connection. The connection users can wait on an MT connection 135*e1dd0a2fSth160488 * to become available or be told to abort and clean up when one of 136*e1dd0a2fSth160488 * the connection user detects an error and knows that the connection 137*e1dd0a2fSth160488 * is no longer usable. The error info is then saved in the structure 138*e1dd0a2fSth160488 * for other users to consume. 139*e1dd0a2fSth160488 * 140*e1dd0a2fSth160488 * An MT connection is meant to be shared concurrently and persistent. 141*e1dd0a2fSth160488 * Even when there's no current user, it will be kept by the connection 142*e1dd0a2fSth160488 * management, waiting for the next user. It will be closed when 143*e1dd0a2fSth160488 * a connection error is detected, when a better server should be 144*e1dd0a2fSth160488 * used, when the Native LDAP configuration change, or when the libsldap 145*e1dd0a2fSth160488 * is being unloaded. 146*e1dd0a2fSth160488 */ 147*e1dd0a2fSth160488 typedef struct ns_conn_mt { 148*e1dd0a2fSth160488 mutex_t lock; 149*e1dd0a2fSth160488 ns_conn_mt_state_t state; 150*e1dd0a2fSth160488 pid_t pid; /* process creates the connection */ 151*e1dd0a2fSth160488 thread_t tid; /* thread creates the connection */ 152*e1dd0a2fSth160488 struct ns_conn_mt *next; /* next conn_mt in the linked list */ 153*e1dd0a2fSth160488 ns_conn_user_t *cu_head; /* head of conn_user linked list */ 154*e1dd0a2fSth160488 ns_conn_user_t *cu_tail; /* tail of conn_user linked list */ 155*e1dd0a2fSth160488 struct ns_conn_mgmt *conn_mgmt; /* ref counted conn management */ 156*e1dd0a2fSth160488 ns_conn_waiter_t waiter; /* first of the connection waiters */ 157*e1dd0a2fSth160488 uint_t cu_cnt; /* number of the using conn_user */ 158*e1dd0a2fSth160488 int32_t cu_max; /* max. allowed number of conn_user */ 159*e1dd0a2fSth160488 uint_t waiter_cnt; /* number of waiters */ 160*e1dd0a2fSth160488 ns_conn_user_type_t opened_for; /* type of conn_user opened for */ 161*e1dd0a2fSth160488 Connection *conn; /* name, IP address, ldap handle, etc */ 162*e1dd0a2fSth160488 time_t create_time; /* time when connection created */ 163*e1dd0a2fSth160488 time_t access_time; /* time when last used */ 164*e1dd0a2fSth160488 ns_ldap_return_code ns_rc; /* saved error code */ 165*e1dd0a2fSth160488 ns_ldap_error_t *ns_error; /* saved error info */ 166*e1dd0a2fSth160488 boolean_t close_when_nouser; /* close connection when */ 167*e1dd0a2fSth160488 /* last user is done ? */ 168*e1dd0a2fSth160488 boolean_t detached; /* no longer in connection pool? */ 169*e1dd0a2fSth160488 boolean_t referral; /* using a referred server ? */ 170*e1dd0a2fSth160488 } ns_conn_mt_t; 171*e1dd0a2fSth160488 172*e1dd0a2fSth160488 /* 173*e1dd0a2fSth160488 * state of a connection management 174*e1dd0a2fSth160488 * (a connection pool sharing the same native LDAP configuration) 175*e1dd0a2fSth160488 */ 176*e1dd0a2fSth160488 typedef enum { 177*e1dd0a2fSth160488 NS_CONN_MGMT_UNINITED = 0, 178*e1dd0a2fSth160488 NS_CONN_MGMT_INACTIVE = 1, /* conn sharing not yet requested */ 179*e1dd0a2fSth160488 NS_CONN_MGMT_ACTIVE = 2, /* connection sharing required/requested */ 180*e1dd0a2fSth160488 NS_CONN_MGMT_DETACHED = 3 /* on the way down, no new user allowed */ 181*e1dd0a2fSth160488 } ns_conn_mgmt_state_t; 182*e1dd0a2fSth160488 183*e1dd0a2fSth160488 /* 184*e1dd0a2fSth160488 * An ns_conn_mgmt (or connection management) represents the set of MT 185*e1dd0a2fSth160488 * connections using the same native LDAP configuration. It is a connection 186*e1dd0a2fSth160488 * pool that can adjust the MT connection status and usage based on the 187*e1dd0a2fSth160488 * change notifications it receives from the ldap_cachemgr daemon, OR When 188*e1dd0a2fSth160488 * the change is detected at config refresh time. When a server status 189*e1dd0a2fSth160488 * change (up or down) notification is received or detected, it will 190*e1dd0a2fSth160488 * close the MT connections using the server. Or mark them as to-be-closed 191*e1dd0a2fSth160488 * and close them when all users are done using them. When a config change 192*e1dd0a2fSth160488 * notice is received, it will detach itself and allow a new ns_conn_mgmt be 193*e1dd0a2fSth160488 * created for the new configuration. The old config would still be used 194*e1dd0a2fSth160488 * by the detached ns_conn_mgmt. Both will be destroyed when all existing 195*e1dd0a2fSth160488 * conn_user are done. Any conn_user and MT connection created after the 196*e1dd0a2fSth160488 * configuration switch will use the new configuration. 197*e1dd0a2fSth160488 * 198*e1dd0a2fSth160488 * Note that there's always just one current ns_conn_mgmt. Its usage is 199*e1dd0a2fSth160488 * reference counted. Any new conn_user or MT connection referencing 200*e1dd0a2fSth160488 * the ns_conn_mgmt adds 1 to the count, any release of the ns_conn_mgmt 201*e1dd0a2fSth160488 * decrement the count by 1. The ns_conn_mgmt can not be freed until 202*e1dd0a2fSth160488 * the reference count becomes zero. 203*e1dd0a2fSth160488 * 204*e1dd0a2fSth160488 * Each ns_conn_mgmt references a native LDAP configuration. The config 205*e1dd0a2fSth160488 * component of this library always maintains a global configuration. It is 206*e1dd0a2fSth160488 * referred to as the current global config. The current ns_conn_mgmt 207*e1dd0a2fSth160488 * uses that global config. When an ns_conn_mgmt is detached, or not 208*e1dd0a2fSth160488 * longer active/current, the config it uses is no longer the current global 209*e1dd0a2fSth160488 * one, which is referred as the per connection management config. When 210*e1dd0a2fSth160488 * the ns_conn_mgmt is freed, the config will also be destroyed. 211*e1dd0a2fSth160488 */ 212*e1dd0a2fSth160488 213*e1dd0a2fSth160488 typedef struct ns_conn_mgmt { 214*e1dd0a2fSth160488 mutex_t lock; 215*e1dd0a2fSth160488 ns_conn_mgmt_state_t state; 216*e1dd0a2fSth160488 pid_t pid; /* process creates the conn_mgmt */ 217*e1dd0a2fSth160488 thread_t procchg_tid; /* id of the change monitor thread */ 218*e1dd0a2fSth160488 ns_conn_mt_t *cm_head; /* head of the conn_mt linked list */ 219*e1dd0a2fSth160488 ns_conn_mt_t *cm_tail; /* tail of the conn_mt linked list */ 220*e1dd0a2fSth160488 mutex_t cfg_lock; /* lock serializes access to config */ 221*e1dd0a2fSth160488 ldap_get_chg_cookie_t cfg_cookie; /* used to detect if config changes */ 222*e1dd0a2fSth160488 ns_config_t *config; /* the native LDAP config being used */ 223*e1dd0a2fSth160488 char **pservers; /* preferred servers defined in config */ 224*e1dd0a2fSth160488 uint_t cm_cnt; /* number of MT connection in the pool */ 225*e1dd0a2fSth160488 uint_t ref_cnt; /* number of reference by conn_MT/conn_user */ 226*e1dd0a2fSth160488 boolean_t is_nscd; /* running in a nscd ? */ 227*e1dd0a2fSth160488 boolean_t is_peruser_nscd; /* running in a per-user nscd ? */ 228*e1dd0a2fSth160488 boolean_t ldap_mt; /* libldap supports multi-threaded client ? */ 229*e1dd0a2fSth160488 boolean_t do_mt_conn; /* need and able to do MT conn ? */ 230*e1dd0a2fSth160488 boolean_t shutting_down; /* on the way down ? */ 231*e1dd0a2fSth160488 boolean_t cfg_reloaded; /* config is not current ? */ 232*e1dd0a2fSth160488 boolean_t procchg_started; /* change monitor thread started ? */ 233*e1dd0a2fSth160488 boolean_t procchg_door_call; /* in door call and waiting ? */ 234*e1dd0a2fSth160488 boolean_t pservers_loaded; /* pservers array is set ? */ 235*e1dd0a2fSth160488 } ns_conn_mgmt_t; 236*e1dd0a2fSth160488 237*e1dd0a2fSth160488 /* 238*e1dd0a2fSth160488 * For a connection management and the conn_mt connections it manages, it is 239*e1dd0a2fSth160488 * very helpful to know exactly when the Native LDAP configuration changes 240*e1dd0a2fSth160488 * and when the status of the configured servers change. If the config 241*e1dd0a2fSth160488 * changes, new connection management will be created. If servers go up 242*e1dd0a2fSth160488 * or down, conn_mt connections being used need to be dropped or switched. 243*e1dd0a2fSth160488 * For processes other than the main nscd, the changes has to be detected 244*e1dd0a2fSth160488 * in a less efficient way by libsldap. For the main nscd (not including 245*e1dd0a2fSth160488 * peruser nscd), the connection management which has active conn_mt 246*e1dd0a2fSth160488 * connections can rely on the ldap_cachemgr daemon to report if there's any 247*e1dd0a2fSth160488 * change in servers' status or if the native LDAP configuration has changed. 248*e1dd0a2fSth160488 * 249*e1dd0a2fSth160488 * The mechanism for reporting of the changes is a door call sent from 250*e1dd0a2fSth160488 * libsldap to ldap_cachemgr. The call will not be returned until changes 251*e1dd0a2fSth160488 * detected by ldap_cachemgr. When the change info is passed back to 252*e1dd0a2fSth160488 * libsldap, the change monitor thread will wake up from the door call 253*e1dd0a2fSth160488 * and process the notification. For servers went from up to down, the 254*e1dd0a2fSth160488 * associated MT connections will be closed, and then all conn_users' 255*e1dd0a2fSth160488 * state will be marked as closing. When a conn_user notices it, the 256*e1dd0a2fSth160488 * operations represented by that conn_user will be ended with error 257*e1dd0a2fSth160488 * info. When a more preferred server is up, MT connections using 258*e1dd0a2fSth160488 * less preferred servers will be marked as closed-when-all-user-done, 259*e1dd0a2fSth160488 * so that new connection will be opened and using the preferred server. 260*e1dd0a2fSth160488 * A configuration change causes the current connection management and 261*e1dd0a2fSth160488 * the configuration it uses to become detached but continually being 262*e1dd0a2fSth160488 * used by the old MT connections. Any new MT connection opened will 263*e1dd0a2fSth160488 * be put in a new connection management and uses the new configuration 264*e1dd0a2fSth160488 * immediately. 265*e1dd0a2fSth160488 */ 266*e1dd0a2fSth160488 typedef enum { 267*e1dd0a2fSth160488 NS_SERVER_UP = 1, 268*e1dd0a2fSth160488 NS_SERVER_DOWN = 2 269*e1dd0a2fSth160488 } ns_server_status_t; 270*e1dd0a2fSth160488 271*e1dd0a2fSth160488 typedef struct ns_server_status_change { 272*e1dd0a2fSth160488 int num_server; 273*e1dd0a2fSth160488 boolean_t config_changed; 274*e1dd0a2fSth160488 ns_server_status_t *changes; /* array of status change */ 275*e1dd0a2fSth160488 char **servers; /* array of server */ 276*e1dd0a2fSth160488 } ns_server_status_change_t; 277*e1dd0a2fSth160488 278*e1dd0a2fSth160488 /* 279*e1dd0a2fSth160488 * connection management functions 280*e1dd0a2fSth160488 */ 281*e1dd0a2fSth160488 ns_conn_mgmt_t *__s_api_conn_mgmt_init(); 282*e1dd0a2fSth160488 int __s_api_setup_mt_ld(LDAP *ld); 283*e1dd0a2fSth160488 int __s_api_check_mtckey(); 284*e1dd0a2fSth160488 void __s_api_use_prev_conn_mgmt(int, ns_config_t *); 285*e1dd0a2fSth160488 ns_conn_user_t *__s_api_conn_user_init(int, void *, boolean_t); 286*e1dd0a2fSth160488 void __s_api_conn_mt_return(ns_conn_user_t *); 287*e1dd0a2fSth160488 void __s_api_conn_user_free(ns_conn_user_t *); 288*e1dd0a2fSth160488 int __s_api_conn_mt_add(Connection *con, ns_conn_user_t *, ns_ldap_error_t **); 289*e1dd0a2fSth160488 int __s_api_conn_mt_get(const char *, const int, const ns_cred_t *, 290*e1dd0a2fSth160488 Connection **, ns_ldap_error_t **, ns_conn_user_t *); 291*e1dd0a2fSth160488 void __s_api_conn_mt_remove(ns_conn_user_t *, int, ns_ldap_error_t **); 292*e1dd0a2fSth160488 int __s_api_check_libldap_MT_conn_support(ns_conn_user_t *, LDAP *ld, 293*e1dd0a2fSth160488 ns_ldap_error_t **); 294*e1dd0a2fSth160488 void __s_api_conn_mt_close(ns_conn_user_t *, int, ns_ldap_error_t **); 295*e1dd0a2fSth160488 void __s_api_reinit_conn_mgmt_new_config(ns_config_t *); 296*e1dd0a2fSth160488 int __s_api_setup_retry_search(ns_conn_user_t **, ns_conn_user_type_t, int *, 297*e1dd0a2fSth160488 int *, ns_ldap_error_t **); 298*e1dd0a2fSth160488 int __s_api_setup_getnext(ns_conn_user_t *, int *, ns_ldap_error_t **); 299*e1dd0a2fSth160488 void __s_api_shutdown_conn_mgmt(); 300*e1dd0a2fSth160488 301*e1dd0a2fSth160488 #ifdef __cplusplus 302*e1dd0a2fSth160488 } 303*e1dd0a2fSth160488 #endif 304*e1dd0a2fSth160488 305*e1dd0a2fSth160488 #endif /* _NS_CONNMGMT_H */ 306