resourcelimit.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685
  1. /** BEGIN COPYRIGHT BLOCK
  2. * This Program is free software; you can redistribute it and/or modify it under
  3. * the terms of the GNU General Public License as published by the Free Software
  4. * Foundation; version 2 of the License.
  5. *
  6. * This Program is distributed in the hope that it will be useful, but WITHOUT
  7. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  8. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  9. *
  10. * You should have received a copy of the GNU General Public License along with
  11. * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
  12. * Place, Suite 330, Boston, MA 02111-1307 USA.
  13. *
  14. * In addition, as a special exception, Red Hat, Inc. gives You the additional
  15. * right to link the code of this Program with code not covered under the GNU
  16. * General Public License ("Non-GPL Code") and to distribute linked combinations
  17. * including the two, subject to the limitations in this paragraph. Non-GPL Code
  18. * permitted under this exception must only link to the code of this Program
  19. * through those well defined interfaces identified in the file named EXCEPTION
  20. * found in the source code files (the "Approved Interfaces"). The files of
  21. * Non-GPL Code may instantiate templates or use macros or inline functions from
  22. * the Approved Interfaces without causing the resulting work to be covered by
  23. * the GNU General Public License. Only Red Hat, Inc. may make changes or
  24. * additions to the list of Approved Interfaces. You must obey the GNU General
  25. * Public License in all respects for all of the Program code and other code used
  26. * in conjunction with the Program except the Non-GPL Code covered by this
  27. * exception. If you modify this file, you may extend this exception to your
  28. * version of the file, but you are not obligated to do so. If you do not wish to
  29. * provide this exception without modification, you must delete this exception
  30. * statement from your version and license this file solely under the GPL without
  31. * exception.
  32. *
  33. *
  34. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  35. * Copyright (C) 2005 Red Hat, Inc.
  36. * All rights reserved.
  37. * END COPYRIGHT BLOCK **/
  38. /* resourcelimit.c - binder-based resource limits implementation */
  39. /*
  40. * Implementation notes:
  41. *
  42. * At present this code only provides support for integer-based
  43. * resource limits.
  44. *
  45. * When a successful bind occurs (i.e., when bind_credentials_set() is
  46. * called), reslimit_update_from_dn() or reslimit_update_from_entry()
  47. * must be called. These functions look in the binder entry and pull
  48. * out attribute values that correspond to resource limits. Typically
  49. * operational attributes are used, e.g., nsSizeLimit to hold a
  50. * binder-specific search size limit. The attributes should be single
  51. * valued; if not, this code ignores all but the first value it finds.
  52. * The virtual attribute interface is used to retrieve the binder entry
  53. * values, so they can be based on COS, etc.
  54. *
  55. * Any resource limits found in the binder entry are cached in the
  56. * connection structure. A connection object extension is used for this
  57. * purpose. This means that if the attributes that correspond to binder
  58. * entry are changed the resource limit won't be affected until the next
  59. * bind occurs as that entry. The data in the connection extension is
  60. * protected using a single writer/multiple reader locking scheme.
  61. *
  62. * A plugin or server subsystem that wants to use the resource limit
  63. * subsystem should call slapi_reslimit_register() once for each limit it
  64. * wants tracked. Note that slapi_reslimit_register() should be called
  65. * early, i.e., before any client connections are accepted.
  66. * slapi_reslimit_register() gives back an integer handle that is used
  67. * later to refer to the limit in question. Here's a sample call:
  68. */
  69. #if SLAPI_RESLIMIT_SAMPLE_CODE
  70. static int sizelimit_reslimit_handle = -1;
  71. if ( slapi_reslimit_register( SLAPI_RESLIMIT_TYPE_INT, "nsSizeLimit",
  72. &sizelimit_reslimit_handle ) != SLAPI_RESLIMIT_STATUS_SUCCESS ) {
  73. /* limit could not be registered -- fatal error? */
  74. }
  75. ...
  76. #endif
  77. /*
  78. * A successful call to slapi_reslimit_register() results in a new
  79. * entry in the reslimit_map, which is private to this source file.
  80. * The map data structure is protected using a single writer/multiple
  81. * reader locking scheme.
  82. *
  83. * To retrieve a binder-based limit, simple call
  84. * slapi_reslimit_get_integer_limit(). If a value was present in the
  85. * binder entry, it will be given back to the caller and
  86. * SLAPI_RESLIMIT_STATUS_SUCCESS will be returned. If no value was
  87. * present or the connection is NULL, SLAPI_RESLIMIT_STATUS_NOVALUE is
  88. * returned. Other errors may be returned also. Here's a sample call:
  89. */
  90. #if SLAPI_RESLIMIT_SAMPLE_CODE
  91. int rc, sizelimit;
  92. rc = slapi_reslimit_get_integer_limit( conn, sizelimit_reslimit_handle,
  93. &sizelimit );
  94. switch( rc ) {
  95. case SLAPI_RESLIMIT_STATUS_SUCCESS: /* got a value */
  96. break;
  97. case SLAPI_RESLIMIT_STATUS_NOVALUE: /* no limit value available */
  98. sizelimit = 500; /* use a default value */
  99. break;
  100. default: /* some other error occurred */
  101. sizelimit = 500; /* use a default value */
  102. }
  103. #endif
  104. /*
  105. * The function reslimit_cleanup() is called from main() to dispose of
  106. * memory, locks, etc. so tools like Purify() don't report leaks at exit.
  107. */
  108. /* End of implementation notes */
  109. #include "slap.h"
  110. /*
  111. * Macros.
  112. */
  113. #define SLAPI_RESLIMIT_MODULE "binder-based resource limits"
  114. /* #define SLAPI_RESLIMIT_DEBUG */ /* define this to enable extra logging */
  115. /* also forces trace log messages to */
  116. /* always be logged */
  117. #ifdef SLAPI_RESLIMIT_DEBUG
  118. #define SLAPI_RESLIMIT_TRACELEVEL LDAP_DEBUG_ANY
  119. #else /* SLAPI_RESLIMIT_DEBUG */
  120. #define SLAPI_RESLIMIT_TRACELEVEL LDAP_DEBUG_TRACE
  121. #endif /* SLAPI_RESLIMIT_DEBUG */
  122. /*
  123. * Structures and types.
  124. */
  125. /* Per-connection resource limits data */
  126. typedef struct slapi_reslimit_conndata {
  127. PRRWLock *rlcd_rwlock; /* to serialize access to the rest */
  128. int rlcd_integer_count; /* size of rlcd_integer_limit array */
  129. PRBool *rlcd_integer_available; /* array that says whether each */
  130. /* value is available */
  131. int *rlcd_integer_value; /* array that holds limit values */
  132. } SLAPIResLimitConnData;
  133. /* Mapping between attribute and limit */
  134. typedef struct slapi_reslimit_map {
  135. int rlmap_type; /* always SLAPI_RESLIMIT_TYPE_INT for now */
  136. char *rlmap_at; /* attribute type name */
  137. } SLAPIResLimitMap;
  138. /*
  139. * Static variables (module globals).
  140. */
  141. static int reslimit_inited = 0;
  142. static int reslimit_connext_objtype = 0;
  143. static int reslimit_connext_handle = 0;
  144. static struct slapi_reslimit_map *reslimit_map = NULL;
  145. static int reslimit_map_count = 0;
  146. static struct slapi_componentid *reslimit_componentid=NULL;
  147. /*
  148. * reslimit_map_rwlock is used to serialize access to
  149. * reslimit_map and reslimit_map_count
  150. */
  151. static PRRWLock *reslimit_map_rwlock = NULL;
  152. /*
  153. * Static functions.
  154. */
  155. static int reslimit_init( void );
  156. static void *reslimit_connext_constructor( void *object, void *parent );
  157. static void reslimit_connext_destructor( void *extension, void *object,
  158. void *parent );
  159. static int reslimit_get_ext( Slapi_Connection *conn, const char *logname,
  160. SLAPIResLimitConnData **rlcdpp );
  161. static int reslimit_bv2int( const struct berval *bvp );
  162. static char ** reslimit_get_registered_attributes();
  163. /*
  164. * reslimit_init() must be called before any resource related work
  165. * is done. It is safe to call this more than once, but reslimit_inited
  166. * can be tested to avoid a call.
  167. *
  168. * Returns zero if all goes well and non-zero if not.
  169. */
  170. static int
  171. reslimit_init( void )
  172. {
  173. if ( reslimit_inited == 0 ) {
  174. if ( slapi_register_object_extension( SLAPI_RESLIMIT_MODULE,
  175. SLAPI_EXT_CONNECTION, reslimit_connext_constructor,
  176. reslimit_connext_destructor,
  177. &reslimit_connext_objtype, &reslimit_connext_handle )
  178. != 0 ) {
  179. slapi_log_error( SLAPI_LOG_FATAL, SLAPI_RESLIMIT_MODULE,
  180. "reslimit_init: slapi_register_object_extension()"
  181. " failed\n" );
  182. return( -1 );
  183. }
  184. if (( reslimit_map_rwlock = PR_NewRWLock( PR_RWLOCK_RANK_NONE,
  185. "resourcelimit map rwlock" )) == NULL ) {
  186. slapi_log_error( SLAPI_LOG_FATAL, SLAPI_RESLIMIT_MODULE,
  187. "reslimit_init: PR_NewRWLock() failed\n" );
  188. return( -1 );
  189. }
  190. reslimit_inited = 1;
  191. }
  192. reslimit_componentid=generate_componentid(NULL,COMPONENT_RESLIMIT);
  193. return( 0 );
  194. }
  195. /*
  196. * Dispose of any allocated memory, locks, other resources. Called when
  197. * server is shutting down.
  198. */
  199. void
  200. reslimit_cleanup( void )
  201. {
  202. int i;
  203. if ( reslimit_map != NULL ) {
  204. for ( i = 0; i < reslimit_map_count; ++i ) {
  205. if ( reslimit_map[ i ].rlmap_at != NULL ) {
  206. slapi_ch_free( (void **)&reslimit_map[ i ].rlmap_at );
  207. }
  208. }
  209. slapi_ch_free( (void **)&reslimit_map );
  210. }
  211. if ( reslimit_map_rwlock != NULL ) {
  212. PR_DestroyRWLock( reslimit_map_rwlock );
  213. }
  214. if ( reslimit_componentid != NULL ) {
  215. release_componentid( reslimit_componentid );
  216. }
  217. }
  218. /*
  219. * constructor for the connection object extension.
  220. */
  221. static void *
  222. reslimit_connext_constructor( void *object, void *parent )
  223. {
  224. SLAPIResLimitConnData *rlcdp;
  225. PRRWLock *rwlock;
  226. if (( rwlock = PR_NewRWLock( PR_RWLOCK_RANK_NONE,
  227. "resource limit connection data rwlock" )) == NULL ) {
  228. slapi_log_error( SLAPI_LOG_FATAL, SLAPI_RESLIMIT_MODULE,
  229. "reslimit_connext_constructor: PR_NewRWLock() failed\n" );
  230. return( NULL );
  231. }
  232. rlcdp = (SLAPIResLimitConnData *)slapi_ch_calloc( 1,
  233. sizeof( SLAPIResLimitConnData ));
  234. rlcdp->rlcd_rwlock = rwlock;
  235. return( rlcdp );
  236. }
  237. /*
  238. * destructor for the connection object extension.
  239. */
  240. static void
  241. reslimit_connext_destructor( void *extension, void *object, void *parent )
  242. {
  243. SLAPIResLimitConnData *rlcdp = (SLAPIResLimitConnData *)extension;
  244. if ( rlcdp->rlcd_integer_available != NULL ) {
  245. slapi_ch_free( (void **)&rlcdp->rlcd_integer_available );
  246. }
  247. if ( rlcdp->rlcd_integer_value != NULL ) {
  248. slapi_ch_free( (void **)&rlcdp->rlcd_integer_value );
  249. }
  250. PR_DestroyRWLock( rlcdp->rlcd_rwlock );
  251. slapi_ch_free( (void **)&rlcdp );
  252. }
  253. /*
  254. * utility function to retrieve the connection object extension.
  255. *
  256. * if logname is non-NULL, errors are logged.
  257. */
  258. static int
  259. reslimit_get_ext( Slapi_Connection *conn, const char *logname,
  260. SLAPIResLimitConnData **rlcdpp )
  261. {
  262. if ( !reslimit_inited && reslimit_init() != 0 ) {
  263. if ( NULL != logname ) {
  264. slapi_log_error( SLAPI_LOG_FATAL, SLAPI_RESLIMIT_MODULE,
  265. "%s: reslimit_init() failed\n", logname );
  266. }
  267. return( SLAPI_RESLIMIT_STATUS_INIT_FAILURE );
  268. }
  269. if (( *rlcdpp = (SLAPIResLimitConnData *)slapi_get_object_extension(
  270. reslimit_connext_objtype, conn,
  271. reslimit_connext_handle )) == NULL ) {
  272. if ( NULL != logname ) {
  273. slapi_log_error( SLAPI_LOG_FATAL, SLAPI_RESLIMIT_MODULE,
  274. "%s: slapi_get_object_extension() returned NULL\n", logname );
  275. }
  276. return( SLAPI_RESLIMIT_STATUS_INTERNAL_ERROR );
  277. }
  278. return( SLAPI_RESLIMIT_STATUS_SUCCESS );
  279. }
  280. /*
  281. * utility function to convert a string-represented integer to an int.
  282. *
  283. * XXXmcs: wouldn't need this if slapi_value_get_int() returned a signed int!
  284. */
  285. static int
  286. reslimit_bv2int( const struct berval *bvp )
  287. {
  288. int rc = 0;
  289. char smallbuf[ 25 ], *buf;
  290. if ( bvp != NULL ) {
  291. /* make a copy to ensure it is zero-terminated */
  292. if ( bvp->bv_len < sizeof( smallbuf )) {
  293. buf = smallbuf;
  294. } else {
  295. buf = slapi_ch_malloc( bvp->bv_len + 1 );
  296. }
  297. memcpy( buf, bvp->bv_val, bvp->bv_len);
  298. buf[ bvp->bv_len ] = '\0';
  299. rc = atoi( buf );
  300. if ( buf != smallbuf ) {
  301. slapi_ch_free( (void **)&smallbuf );
  302. }
  303. }
  304. return( rc );
  305. }
  306. /**** Semi-public functions start here ***********************************/
  307. /*
  308. * These functions are exposed to other parts of the server only, i.e.,
  309. * they are NOT part of the official SLAPI API.
  310. */
  311. /*
  312. * Set the resource limits associated with connection `conn' based on the
  313. * entry named by `dn'. If `dn' is NULL, limits are returned to their
  314. * default state.
  315. *
  316. * A SLAPI_RESLIMIT_STATUS_... code is returned.
  317. */
  318. int
  319. reslimit_update_from_dn( Slapi_Connection *conn, Slapi_DN *dn )
  320. {
  321. Slapi_Entry *e;
  322. int rc;
  323. e = NULL;
  324. if ( dn != NULL ) {
  325. char ** attrs = reslimit_get_registered_attributes();
  326. (void) slapi_search_internal_get_entry( dn, attrs, &e , reslimit_componentid);
  327. charray_free(attrs);
  328. }
  329. rc = reslimit_update_from_entry( conn, e );
  330. if ( NULL != e ) {
  331. slapi_entry_free( e );
  332. }
  333. return( rc );
  334. }
  335. /*
  336. * Set the resource limits associated with connection `conn' based on the
  337. * entry `e'. If `e' is NULL, limits are returned to their default state.
  338. * If `conn' is NULL, nothing is done.
  339. *
  340. * A SLAPI_RESLIMIT_STATUS_... code is returned.
  341. */
  342. int
  343. reslimit_update_from_entry( Slapi_Connection *conn, Slapi_Entry *e )
  344. {
  345. char *fnname = "reslimit_update_from_entry()";
  346. char *actual_type_name, *get_ext_logname;
  347. int i, rc, type_name_disposition, free_flags;
  348. SLAPIResLimitConnData *rlcdp;
  349. Slapi_ValueSet *vs;
  350. LDAPDebug( SLAPI_RESLIMIT_TRACELEVEL, "=> %s conn=0x%x, entry=0x%x\n",
  351. fnname, conn, e );
  352. rc = SLAPI_RESLIMIT_STATUS_SUCCESS; /* optimistic */
  353. /* if conn is NULL, there is nothing to be done */
  354. if ( conn == NULL ) {
  355. goto log_and_return;
  356. }
  357. if ( NULL == e ) {
  358. get_ext_logname = NULL; /* do not log errors if resetting limits */
  359. } else {
  360. get_ext_logname = fnname;
  361. }
  362. if (( rc = reslimit_get_ext( conn, get_ext_logname, &rlcdp )) !=
  363. SLAPI_RESLIMIT_STATUS_SUCCESS ) {
  364. goto log_and_return;
  365. }
  366. /* LOCK FOR READ -- map lock */
  367. PR_RWLock_Rlock( reslimit_map_rwlock );
  368. /* LOCK FOR WRITE -- conn. data lock */
  369. PR_RWLock_Wlock( rlcdp->rlcd_rwlock );
  370. if ( rlcdp->rlcd_integer_value == NULL ) {
  371. rlcdp->rlcd_integer_count = reslimit_map_count;
  372. if ( rlcdp->rlcd_integer_count > 0 ) {
  373. rlcdp->rlcd_integer_available = (PRBool *)slapi_ch_calloc(
  374. rlcdp->rlcd_integer_count, sizeof( PRBool ));
  375. rlcdp->rlcd_integer_value = (int *)slapi_ch_calloc(
  376. rlcdp->rlcd_integer_count, sizeof( int ));
  377. }
  378. }
  379. for ( i = 0; i < rlcdp->rlcd_integer_count; ++i ) {
  380. if ( reslimit_map[ i ].rlmap_type != SLAPI_RESLIMIT_TYPE_INT ) {
  381. continue;
  382. }
  383. LDAPDebug( SLAPI_RESLIMIT_TRACELEVEL,
  384. "%s: setting limit for handle %d (based on %s)\n",
  385. fnname, i, reslimit_map[ i ].rlmap_at );
  386. rlcdp->rlcd_integer_available[ i ] = PR_FALSE;
  387. if ( NULL != e && 0 == slapi_vattr_values_get( e,
  388. reslimit_map[ i ].rlmap_at, &vs, &type_name_disposition,
  389. &actual_type_name, 0, &free_flags )) {
  390. Slapi_Value *v;
  391. int index;
  392. const struct berval *bvp;
  393. if (( index = slapi_valueset_first_value( vs, &v )) != -1 &&
  394. ( bvp = slapi_value_get_berval( v )) != NULL ) {
  395. rlcdp->rlcd_integer_value[ i ] = reslimit_bv2int( bvp );
  396. rlcdp->rlcd_integer_available[ i ] = PR_TRUE;
  397. LDAPDebug( SLAPI_RESLIMIT_TRACELEVEL,
  398. "%s: set limit based on %s to %d\n",
  399. fnname, reslimit_map[ i ].rlmap_at,
  400. rlcdp->rlcd_integer_value[ i ] );
  401. if ( slapi_valueset_next_value( vs, index, &v ) != -1 ) {
  402. char ebuf[ BUFSIZ ];
  403. slapi_log_error( SLAPI_LOG_FATAL, SLAPI_RESLIMIT_MODULE,
  404. "%s: ignoring multiple values for %s in entry \n",
  405. fnname, reslimit_map[ i ].rlmap_at,
  406. escape_string( slapi_entry_get_dn_const( e ),
  407. ebuf ));
  408. }
  409. }
  410. slapi_vattr_values_free( &vs, &actual_type_name, free_flags);
  411. }
  412. }
  413. PR_RWLock_Unlock( rlcdp->rlcd_rwlock );
  414. /* UNLOCKED -- conn. data lock */
  415. PR_RWLock_Unlock( reslimit_map_rwlock );
  416. /* UNLOCKED -- map lock */
  417. log_and_return:
  418. LDAPDebug( SLAPI_RESLIMIT_TRACELEVEL, "<= %s returning status %d\n",
  419. fnname, rc, 0 );
  420. return( rc );
  421. }
  422. /* return the list of registered attributes */
  423. static char ** reslimit_get_registered_attributes()
  424. {
  425. int i;
  426. char **attrs=NULL;
  427. /* LOCK FOR READ -- map lock */
  428. PR_RWLock_Rlock( reslimit_map_rwlock );
  429. for ( i = 0; i < reslimit_map_count; ++i ) {
  430. if ( reslimit_map[ i ].rlmap_at != NULL ) {
  431. charray_add(&attrs, slapi_ch_strdup(reslimit_map[ i ].rlmap_at));
  432. }
  433. }
  434. PR_RWLock_Unlock( reslimit_map_rwlock );
  435. return attrs;
  436. }
  437. /**** Public functions can be found below this point *********************/
  438. /*
  439. * These functions are exposed to plugins, i.e., they are part of the
  440. * official SLAPI API.
  441. */
  442. /*
  443. * Register a new resource to be tracked. `type' must be
  444. * SLAPI_RESLIMIT_TYPE_INT and `attrname' is an LDAP attribute type that
  445. * is consulted in the bound entry to determine the limit's value.
  446. *
  447. * A SLAPI_RESLIMIT_STATUS_... code is returned. If it is ...SUCCESS, then
  448. * `*handlep' is set to an opaque integer value that should be used in
  449. * subsequent calls to slapi_reslimit_get_integer_limit().
  450. */
  451. int
  452. slapi_reslimit_register( int type, const char *attrname, int *handlep )
  453. {
  454. char *fnname = "slapi_reslimit_register()";
  455. int i, rc;
  456. LDAPDebug( SLAPI_RESLIMIT_TRACELEVEL, "=> %s attrname=%s\n",
  457. fnname, attrname, 0 );
  458. rc = SLAPI_RESLIMIT_STATUS_SUCCESS; /* optimistic */
  459. /* initialize if necessary */
  460. if ( !reslimit_inited && reslimit_init() != 0 ) {
  461. slapi_log_error( SLAPI_LOG_FATAL, SLAPI_RESLIMIT_MODULE,
  462. "%s: reslimit_init() failed\n", fnname );
  463. rc = SLAPI_RESLIMIT_STATUS_INIT_FAILURE;
  464. goto log_and_return;
  465. }
  466. /* sanity check parameters */
  467. if ( type != SLAPI_RESLIMIT_TYPE_INT || attrname == NULL
  468. || handlep == NULL ) {
  469. slapi_log_error( SLAPI_LOG_FATAL, SLAPI_RESLIMIT_MODULE,
  470. "%s: parameter error\n", fnname );
  471. rc = SLAPI_RESLIMIT_STATUS_PARAM_ERROR;
  472. goto log_and_return;
  473. }
  474. /* LOCK FOR WRITE -- map lock */
  475. PR_RWLock_Wlock( reslimit_map_rwlock );
  476. /*
  477. * check that attrname is not already registered
  478. */
  479. for ( i = 0; i < reslimit_map_count; ++i ) {
  480. if ( 0 == slapi_attr_type_cmp( reslimit_map[ i ].rlmap_at,
  481. attrname, SLAPI_TYPE_CMP_EXACT )) {
  482. slapi_log_error( SLAPI_LOG_FATAL, SLAPI_RESLIMIT_MODULE,
  483. "%s: parameter error (%s already registered)\n",
  484. attrname, fnname );
  485. rc = SLAPI_RESLIMIT_STATUS_PARAM_ERROR;
  486. goto unlock_and_return;
  487. }
  488. }
  489. /*
  490. * expand the map array and add the new element
  491. */
  492. reslimit_map = (SLAPIResLimitMap *)slapi_ch_realloc(
  493. (char *)reslimit_map,
  494. (1 + reslimit_map_count) * sizeof( SLAPIResLimitMap ));
  495. reslimit_map[ reslimit_map_count ].rlmap_type = type;
  496. reslimit_map[ reslimit_map_count ].rlmap_at
  497. = slapi_ch_strdup( attrname );
  498. *handlep = reslimit_map_count;
  499. ++reslimit_map_count;
  500. unlock_and_return:
  501. PR_RWLock_Unlock( reslimit_map_rwlock );
  502. /* UNLOCKED -- map lock */
  503. log_and_return:
  504. LDAPDebug( SLAPI_RESLIMIT_TRACELEVEL,
  505. "<= %s returning status=%d, handle=%d\n", fnname, rc,
  506. (handlep == NULL) ? -1 : *handlep );
  507. return( rc );
  508. }
  509. /*
  510. * Retrieve the integer limit associated with connection `conn' for
  511. * the resource identified by `handle'.
  512. *
  513. * A SLAPI_RESLIMIT_STATUS_... code is returned:
  514. *
  515. * SLAPI_RESLIMIT_STATUS_SUCCESS -- `*limitp' is set to the limit value.
  516. * SLAPI_RESLIMIT_STATUS_NOVALUE -- no limit value is available (use default).
  517. * Another SLAPI_RESLIMIT_STATUS_... code -- some more fatal error occurred.
  518. *
  519. * If `conn' is NULL, SLAPI_RESLIMIT_STATUS_NOVALUE is returned.
  520. */
  521. int
  522. slapi_reslimit_get_integer_limit( Slapi_Connection *conn, int handle,
  523. int *limitp )
  524. {
  525. char *fnname = "slapi_reslimit_get_integer_limit()";
  526. int rc;
  527. SLAPIResLimitConnData *rlcdp;
  528. LDAPDebug( SLAPI_RESLIMIT_TRACELEVEL, "=> %s conn=0x%x, handle=%d\n",
  529. fnname, conn, handle );
  530. rc = SLAPI_RESLIMIT_STATUS_SUCCESS; /* optimistic */
  531. /* sanity check parameters */
  532. if ( limitp == NULL ) {
  533. slapi_log_error( SLAPI_LOG_FATAL, SLAPI_RESLIMIT_MODULE,
  534. "%s: parameter error\n", fnname );
  535. rc = SLAPI_RESLIMIT_STATUS_PARAM_ERROR;
  536. goto log_and_return;
  537. }
  538. if ( conn == NULL ) {
  539. rc = SLAPI_RESLIMIT_STATUS_NOVALUE;
  540. goto log_and_return;
  541. }
  542. if (( rc = reslimit_get_ext( conn, fnname, &rlcdp )) !=
  543. SLAPI_RESLIMIT_STATUS_SUCCESS ) {
  544. goto log_and_return;
  545. }
  546. if(rlcdp->rlcd_integer_count==0) { /* peek at it to avoid lock */
  547. rc = SLAPI_RESLIMIT_STATUS_NOVALUE;
  548. } else {
  549. PR_RWLock_Rlock( rlcdp->rlcd_rwlock );
  550. if(rlcdp->rlcd_integer_count==0) {
  551. rc = SLAPI_RESLIMIT_STATUS_NOVALUE;
  552. } else if ( handle < 0 || handle >= rlcdp->rlcd_integer_count ) {
  553. slapi_log_error( SLAPI_LOG_FATAL, SLAPI_RESLIMIT_MODULE,
  554. "%s: unknown handle %d\n", fnname, handle );
  555. rc = SLAPI_RESLIMIT_STATUS_UNKNOWN_HANDLE;
  556. } else if ( rlcdp->rlcd_integer_available[ handle ] ) {
  557. *limitp = rlcdp->rlcd_integer_value[ handle ];
  558. } else {
  559. rc = SLAPI_RESLIMIT_STATUS_NOVALUE;
  560. }
  561. PR_RWLock_Unlock( rlcdp->rlcd_rwlock );
  562. }
  563. log_and_return:
  564. if ( LDAPDebugLevelIsSet( LDAP_DEBUG_TRACE )) {
  565. if ( rc == SLAPI_RESLIMIT_STATUS_SUCCESS ) {
  566. LDAPDebug( SLAPI_RESLIMIT_TRACELEVEL,
  567. "<= %s returning SUCCESS, value=%d\n", fnname, *limitp, 0 );
  568. } else if ( rc == SLAPI_RESLIMIT_STATUS_NOVALUE ) {
  569. LDAPDebug( SLAPI_RESLIMIT_TRACELEVEL, "<= %s returning NO VALUE\n",
  570. fnname, 0, 0 );
  571. } else {
  572. LDAPDebug( SLAPI_RESLIMIT_TRACELEVEL, "<= %s returning ERROR %d\n",
  573. fnname, rc, 0 );
  574. }
  575. }
  576. return( rc );
  577. }
  578. /**** Public functions END ***********************************************/