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