resourcelimit.c 18 KB

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