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