~ubuntu-branches/ubuntu/wily/389-ds-base/wily

« back to all changes in this revision

Viewing changes to ldap/servers/slapd/resourcelimit.c

  • Committer: Package Import Robot
  • Author(s): Krzysztof Klimonda
  • Date: 2012-03-27 14:26:16 UTC
  • Revision ID: package-import@ubuntu.com-20120327142616-xt24t6nffm3f7ybz
Tags: upstream-1.2.11.7
ImportĀ upstreamĀ versionĀ 1.2.11.7

Show diffs side-by-side

added added

removed removed

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