Back to index

openldap  2.4.31
slapd-read.c
Go to the documentation of this file.
00001 /* $OpenLDAP$ */
00002 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00003  *
00004  * Copyright 1999-2012 The OpenLDAP Foundation.
00005  * All rights reserved.
00006  *
00007  * Redistribution and use in source and binary forms, with or without
00008  * modification, are permitted only as authorized by the OpenLDAP
00009  * Public License.
00010  *
00011  * A copy of this license is available in file LICENSE in the
00012  * top-level directory of the distribution or, alternatively, at
00013  * <http://www.OpenLDAP.org/license.html>.
00014  */
00015 /* ACKNOWLEDGEMENTS:
00016  * This work was initially developed by Kurt Spanier for inclusion
00017  * in OpenLDAP Software.
00018  */
00019 
00020 #include "portable.h"
00021 
00022 #include <stdio.h>
00023 
00024 #include "ac/stdlib.h"
00025 
00026 #include "ac/ctype.h"
00027 #include "ac/param.h"
00028 #include "ac/socket.h"
00029 #include "ac/string.h"
00030 #include "ac/unistd.h"
00031 #include "ac/wait.h"
00032 
00033 #include "ldap.h"
00034 #include "lutil.h"
00035 
00036 #include "ldap_pvt.h"
00037 
00038 #include "slapd-common.h"
00039 
00040 #define LOOPS 100
00041 #define RETRIES      0
00042 
00043 static void
00044 do_read( char *uri, char *manager, struct berval *passwd,
00045        char *entry, LDAP **ld,
00046        char **attrs, int noattrs, int nobind, int maxloop,
00047        int maxretries, int delay, int force, int chaserefs );
00048 
00049 static void
00050 do_random( char *uri, char *manager, struct berval *passwd,
00051        char *sbase, char *filter, char **attrs, int noattrs, int nobind,
00052        int innerloop, int maxretries, int delay, int force, int chaserefs );
00053 
00054 static void
00055 usage( char *name )
00056 {
00057         fprintf( stderr,
00058               "usage: %s "
00059               "-H <uri> | ([-h <host>] -p <port>) "
00060               "-D <manager> "
00061               "-w <passwd> "
00062               "-e <entry> "
00063               "[-A] "
00064               "[-C] "
00065               "[-F] "
00066               "[-N] "
00067               "[-f filter] "
00068               "[-i <ignore>] "
00069               "[-l <loops>] "
00070               "[-L <outerloops>] "
00071               "[-r <maxretries>] "
00072               "[-t <delay>] "
00073               "[-T <attrs>] "
00074               "[<attrs>] "
00075               "\n",
00076               name );
00077        exit( EXIT_FAILURE );
00078 }
00079 
00080 /* -S: just send requests without reading responses
00081  * -SS: send all requests asynchronous and immediately start reading responses
00082  * -SSS: send all requests asynchronous; then read responses
00083  */
00084 static int swamp;
00085 
00086 int
00087 main( int argc, char **argv )
00088 {
00089        int           i;
00090        char          *uri = NULL;
00091        char          *host = "localhost";
00092        int           port = -1;
00093        char          *manager = NULL;
00094        struct berval passwd = { 0, NULL };
00095        char          *entry = NULL;
00096        char          *filter  = NULL;
00097        int           loops = LOOPS;
00098        int           outerloops = 1;
00099        int           retries = RETRIES;
00100        int           delay = 0;
00101        int           force = 0;
00102        int           chaserefs = 0;
00103        char          *srchattrs[] = { "1.1", NULL };
00104        char          **attrs = srchattrs;
00105        int           noattrs = 0;
00106        int           nobind = 0;
00107 
00108        tester_init( "slapd-read", TESTER_READ );
00109 
00110        /* by default, tolerate referrals and no such object */
00111        tester_ignore_str2errlist( "REFERRAL,NO_SUCH_OBJECT" );
00112 
00113        while ( (i = getopt( argc, argv, "ACD:e:Ff:H:h:i:L:l:p:r:St:T:w:" )) != EOF ) {
00114               switch ( i ) {
00115               case 'A':
00116                      noattrs++;
00117                      break;
00118 
00119               case 'C':
00120                      chaserefs++;
00121                      break;
00122 
00123               case 'H':            /* the server uri */
00124                      uri = strdup( optarg );
00125                      break;
00126 
00127               case 'h':            /* the servers host */
00128                      host = strdup( optarg );
00129                      break;
00130 
00131               case 'i':
00132                      tester_ignore_str2errlist( optarg );
00133                      break;
00134 
00135               case 'N':
00136                      nobind++;
00137                      break;
00138 
00139               case 'p':            /* the servers port */
00140                      if ( lutil_atoi( &port, optarg ) != 0 ) {
00141                             usage( argv[0] );
00142                      }
00143                      break;
00144 
00145               case 'D':            /* the servers manager */
00146                      manager = strdup( optarg );
00147                      break;
00148 
00149               case 'w':            /* the server managers password */
00150                      passwd.bv_val = strdup( optarg );
00151                      passwd.bv_len = strlen( optarg );
00152                      memset( optarg, '*', passwd.bv_len );
00153                      break;
00154 
00155               case 'e':            /* DN to search for */
00156                      entry = strdup( optarg );
00157                      break;
00158 
00159               case 'f':            /* the search request */
00160                      filter = strdup( optarg );
00161                      break;
00162 
00163               case 'F':
00164                      force++;
00165                      break;
00166 
00167               case 'l':            /* the number of loops */
00168                      if ( lutil_atoi( &loops, optarg ) != 0 ) {
00169                             usage( argv[0] );
00170                      }
00171                      break;
00172 
00173               case 'L':            /* the number of outerloops */
00174                      if ( lutil_atoi( &outerloops, optarg ) != 0 ) {
00175                             usage( argv[0] );
00176                      }
00177                      break;
00178 
00179               case 'r':            /* the number of retries */
00180                      if ( lutil_atoi( &retries, optarg ) != 0 ) {
00181                             usage( argv[0] );
00182                      }
00183                      break;
00184 
00185               case 'S':
00186                      swamp++;
00187                      break;
00188 
00189               case 't':            /* delay in seconds */
00190                      if ( lutil_atoi( &delay, optarg ) != 0 ) {
00191                             usage( argv[0] );
00192                      }
00193                      break;
00194 
00195               case 'T':
00196                      attrs = ldap_str2charray( optarg, "," );
00197                      if ( attrs == NULL ) {
00198                             usage( argv[0] );
00199                      }
00200                      break;
00201 
00202               default:
00203                      usage( argv[0] );
00204                      break;
00205               }
00206        }
00207 
00208        if (( entry == NULL ) || ( port == -1 && uri == NULL ))
00209               usage( argv[0] );
00210 
00211        if ( *entry == '\0' ) {
00212               fprintf( stderr, "%s: invalid EMPTY entry DN.\n",
00213                             argv[0] );
00214               exit( EXIT_FAILURE );
00215        }
00216 
00217        if ( argv[optind] != NULL ) {
00218               attrs = &argv[optind];
00219        }
00220 
00221        uri = tester_uri( uri, host, port );
00222 
00223        for ( i = 0; i < outerloops; i++ ) {
00224               if ( filter != NULL ) {
00225                      do_random( uri, manager, &passwd, entry, filter, attrs,
00226                             noattrs, nobind, loops, retries, delay, force,
00227                             chaserefs );
00228 
00229               } else {
00230                      do_read( uri, manager, &passwd, entry, NULL, attrs,
00231                             noattrs, nobind, loops, retries, delay, force,
00232                             chaserefs );
00233               }
00234        }
00235 
00236        exit( EXIT_SUCCESS );
00237 }
00238 
00239 static void
00240 do_random( char *uri, char *manager, struct berval *passwd,
00241        char *sbase, char *filter, char **srchattrs, int noattrs, int nobind,
00242        int innerloop, int maxretries, int delay, int force, int chaserefs )
00243 {
00244        LDAP   *ld = NULL;
00245        int    i = 0, do_retry = maxretries;
00246        char   *attrs[ 2 ];
00247        int     rc = LDAP_SUCCESS;
00248        int    version = LDAP_VERSION3;
00249        int    nvalues = 0;
00250        char   **values = NULL;
00251        LDAPMessage *res = NULL, *e = NULL;
00252 
00253        attrs[ 0 ] = LDAP_NO_ATTRS;
00254        attrs[ 1 ] = NULL;
00255 
00256        ldap_initialize( &ld, uri );
00257        if ( ld == NULL ) {
00258               tester_perror( "ldap_initialize", NULL );
00259               exit( EXIT_FAILURE );
00260        }
00261 
00262        (void) ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version ); 
00263        (void) ldap_set_option( ld, LDAP_OPT_REFERRALS,
00264               chaserefs ? LDAP_OPT_ON : LDAP_OPT_OFF );
00265 
00266        if ( do_retry == maxretries ) {
00267               fprintf( stderr, "PID=%ld - Read(%d): base=\"%s\", filter=\"%s\".\n",
00268                             (long) pid, innerloop, sbase, filter );
00269        }
00270 
00271        if ( nobind == 0 ) {
00272               rc = ldap_sasl_bind_s( ld, manager, LDAP_SASL_SIMPLE, passwd, NULL, NULL, NULL );
00273               if ( rc != LDAP_SUCCESS ) {
00274                      tester_ldap_error( ld, "ldap_sasl_bind_s", NULL );
00275                      switch ( rc ) {
00276                      case LDAP_BUSY:
00277                      case LDAP_UNAVAILABLE:
00278                      /* fallthru */
00279                      default:
00280                             break;
00281                      }
00282                      exit( EXIT_FAILURE );
00283               }
00284        }
00285 
00286        rc = ldap_search_ext_s( ld, sbase, LDAP_SCOPE_SUBTREE,
00287               filter, attrs, 0, NULL, NULL, NULL, LDAP_NO_LIMIT, &res );
00288        switch ( rc ) {
00289        case LDAP_SIZELIMIT_EXCEEDED:
00290        case LDAP_TIMELIMIT_EXCEEDED:
00291        case LDAP_SUCCESS:
00292               nvalues = ldap_count_entries( ld, res );
00293               if ( nvalues == 0 ) {
00294                      if ( rc ) {
00295                             tester_ldap_error( ld, "ldap_search_ext_s", NULL );
00296                      }
00297                      break;
00298               }
00299 
00300               values = malloc( ( nvalues + 1 ) * sizeof( char * ) );
00301               for ( i = 0, e = ldap_first_entry( ld, res ); e != NULL; i++, e = ldap_next_entry( ld, e ) )
00302               {
00303                      values[ i ] = ldap_get_dn( ld, e );
00304               }
00305               values[ i ] = NULL;
00306 
00307               ldap_msgfree( res );
00308 
00309               if ( do_retry == maxretries ) {
00310                      fprintf( stderr, "  PID=%ld - Read base=\"%s\" filter=\"%s\" got %d values.\n",
00311                             (long) pid, sbase, filter, nvalues );
00312               }
00313 
00314               for ( i = 0; i < innerloop; i++ ) {
00315 #if 0  /* use high-order bits for better randomness (Numerical Recipes in "C") */
00316                      int    r = rand() % nvalues;
00317 #endif
00318                      int    r = ((double)nvalues)*rand()/(RAND_MAX + 1.0);
00319 
00320                      do_read( uri, manager, passwd, values[ r ], &ld,
00321                             srchattrs, noattrs, nobind, 1, maxretries,
00322                             delay, force, chaserefs );
00323               }
00324               free( values );
00325               break;
00326 
00327        default:
00328               tester_ldap_error( ld, "ldap_search_ext_s", NULL );
00329               break;
00330        }
00331 
00332        fprintf( stderr, "  PID=%ld - Read done (%d).\n", (long) pid, rc );
00333 
00334        if ( ld != NULL ) {
00335               ldap_unbind_ext( ld, NULL, NULL );
00336        }
00337 }
00338 
00339 static void
00340 do_read( char *uri, char *manager, struct berval *passwd, char *entry,
00341        LDAP **ldp, char **attrs, int noattrs, int nobind, int maxloop,
00342        int maxretries, int delay, int force, int chaserefs )
00343 {
00344        LDAP   *ld = ldp ? *ldp : NULL;
00345        int    i = 0, do_retry = maxretries;
00346        int     rc = LDAP_SUCCESS;
00347        int           version = LDAP_VERSION3;
00348        int           *msgids = NULL, active = 0;
00349 
00350        /* make room for msgid */
00351        if ( swamp > 1 ) {
00352               msgids = (int *)calloc( sizeof(int), maxloop );
00353        }
00354 
00355 retry:;
00356        if ( ld == NULL ) {
00357               ldap_initialize( &ld, uri );
00358               if ( ld == NULL ) {
00359                      tester_perror( "ldap_initialize", NULL );
00360                      exit( EXIT_FAILURE );
00361               }
00362 
00363               (void) ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version ); 
00364               (void) ldap_set_option( ld, LDAP_OPT_REFERRALS,
00365                      chaserefs ? LDAP_OPT_ON : LDAP_OPT_OFF );
00366 
00367               if ( do_retry == maxretries ) {
00368                      fprintf( stderr, "PID=%ld - Read(%d): entry=\"%s\".\n",
00369                             (long) pid, maxloop, entry );
00370               }
00371 
00372               if ( nobind == 0 ) {
00373                      rc = ldap_sasl_bind_s( ld, manager, LDAP_SASL_SIMPLE, passwd, NULL, NULL, NULL );
00374                      if ( rc != LDAP_SUCCESS ) {
00375                             tester_ldap_error( ld, "ldap_sasl_bind_s", NULL );
00376                             switch ( rc ) {
00377                             case LDAP_BUSY:
00378                             case LDAP_UNAVAILABLE:
00379                                    if ( do_retry > 0 ) {
00380                                           ldap_unbind_ext( ld, NULL, NULL );
00381                                           ld = NULL;
00382                                           do_retry--;
00383                                           if ( delay != 0 ) {
00384                                               sleep( delay );
00385                                           }
00386                                           goto retry;
00387                                    }
00388                             /* fallthru */
00389                             default:
00390                                    break;
00391                             }
00392                             exit( EXIT_FAILURE );
00393                      }
00394               }
00395        }
00396 
00397        if ( swamp > 1 ) {
00398               do {
00399                      LDAPMessage *res = NULL;
00400                      int j, msgid;
00401 
00402                      if ( i < maxloop ) {
00403                             rc = ldap_search_ext( ld, entry, LDAP_SCOPE_BASE,
00404                                           NULL, attrs, noattrs, NULL, NULL,
00405                                           NULL, LDAP_NO_LIMIT, &msgids[i] );
00406 
00407                             active++;
00408 #if 0
00409                             fprintf( stderr,
00410                                    ">>> PID=%ld - Read maxloop=%d cnt=%d active=%d msgid=%d: "
00411                                    "entry=\"%s\"\n",
00412                                    (long) pid, maxloop, i, active, msgids[i],
00413                                    entry );
00414 #endif
00415                             i++;
00416 
00417                             if ( rc ) {
00418                                    char buf[BUFSIZ];
00419                                    int first = tester_ignore_err( rc );
00420                                    /* if ignore.. */
00421                                    if ( first ) {
00422                                           /* only log if first occurrence */
00423                                           if ( ( force < 2 && first > 0 ) || abs(first) == 1 ) {
00424                                                  tester_ldap_error( ld, "ldap_search_ext", NULL );
00425                                           }
00426                                           continue;
00427                                    }
00428               
00429                                    /* busy needs special handling */
00430                                    snprintf( buf, sizeof( buf ), "entry=\"%s\"\n", entry );
00431                                    tester_ldap_error( ld, "ldap_search_ext", buf );
00432                                    if ( rc == LDAP_BUSY && do_retry > 0 ) {
00433                                           ldap_unbind_ext( ld, NULL, NULL );
00434                                           ld = NULL;
00435                                           do_retry--;
00436                                           goto retry;
00437                                    }
00438                                    break;
00439                             }
00440 
00441                             if ( swamp > 2 ) {
00442                                    continue;
00443                             }
00444                      }
00445 
00446                      rc = ldap_result( ld, LDAP_RES_ANY, 0, NULL, &res );
00447                      switch ( rc ) {
00448                      case -1:
00449                             /* gone really bad */
00450 #if 0
00451                             fprintf( stderr,
00452                                    ">>> PID=%ld - Read maxloop=%d cnt=%d active=%d: "
00453                                    "entry=\"%s\" ldap_result()=%d\n",
00454                                    (long) pid, maxloop, i, active, entry, rc );
00455 #endif
00456                             goto cleanup;
00457        
00458                      case 0:
00459                             /* timeout (impossible) */
00460                             break;
00461        
00462                      case LDAP_RES_SEARCH_ENTRY:
00463                      case LDAP_RES_SEARCH_REFERENCE:
00464                             /* ignore */
00465                             break;
00466        
00467                      case LDAP_RES_SEARCH_RESULT:
00468                             /* just remove, no error checking (TODO?) */
00469                             msgid = ldap_msgid( res );
00470                             ldap_parse_result( ld, res, &rc, NULL, NULL, NULL, NULL, 1 );
00471                             res = NULL;
00472 
00473                             /* linear search, bah */
00474                             for ( j = 0; j < i; j++ ) {
00475                                    if ( msgids[ j ] == msgid ) {
00476                                           msgids[ j ] = -1;
00477                                           active--;
00478 #if 0
00479                                           fprintf( stderr,
00480                                                  "<<< PID=%ld - ReadDone maxloop=%d cnt=%d active=%d msgid=%d: "
00481                                                  "entry=\"%s\"\n",
00482                                                  (long) pid, maxloop, j, active, msgid, entry );
00483 #endif
00484                                           break;
00485                                    }
00486                             }
00487                             break;
00488 
00489                      default:
00490                             /* other messages unexpected */
00491                             fprintf( stderr,
00492                                    "### PID=%ld - Read(%d): "
00493                                    "entry=\"%s\" attrs=%s%s. unexpected response tag=%d\n",
00494                                    (long) pid, maxloop,
00495                                    entry, attrs[0], attrs[1] ? " (more...)" : "", rc );
00496                             break;
00497                      }
00498 
00499                      if ( res != NULL ) {
00500                             ldap_msgfree( res );
00501                      }
00502               } while ( i < maxloop || active > 0 );
00503 
00504        } else {
00505               for ( ; i < maxloop; i++ ) {
00506                      LDAPMessage *res = NULL;
00507 
00508                      if (swamp) {
00509                             int msgid;
00510                             rc = ldap_search_ext( ld, entry, LDAP_SCOPE_BASE,
00511                                           NULL, attrs, noattrs, NULL, NULL,
00512                                           NULL, LDAP_NO_LIMIT, &msgid );
00513                             if ( rc == LDAP_SUCCESS ) continue;
00514                             else break;
00515                      }
00516        
00517                      rc = ldap_search_ext_s( ld, entry, LDAP_SCOPE_BASE,
00518                                    NULL, attrs, noattrs, NULL, NULL, NULL,
00519                                    LDAP_NO_LIMIT, &res );
00520                      if ( res != NULL ) {
00521                             ldap_msgfree( res );
00522                      }
00523 
00524                      if ( rc ) {
00525                             int           first = tester_ignore_err( rc );
00526                             char          buf[ BUFSIZ ];
00527        
00528                             snprintf( buf, sizeof( buf ), "ldap_search_ext_s(%s)", entry );
00529        
00530                             /* if ignore.. */
00531                             if ( first ) {
00532                                    /* only log if first occurrence */
00533                                    if ( ( force < 2 && first > 0 ) || abs(first) == 1 ) {
00534                                           tester_ldap_error( ld, buf, NULL );
00535                                    }
00536                                    continue;
00537                             }
00538        
00539                             /* busy needs special handling */
00540                             tester_ldap_error( ld, buf, NULL );
00541                             if ( rc == LDAP_BUSY && do_retry > 0 ) {
00542                                    ldap_unbind_ext( ld, NULL, NULL );
00543                                    ld = NULL;
00544                                    do_retry--;
00545                                    goto retry;
00546                             }
00547                             break;
00548                      }
00549               }
00550        }
00551 
00552 cleanup:;
00553        if ( msgids != NULL ) {
00554               free( msgids );
00555        }
00556 
00557        if ( ldp != NULL ) {
00558               *ldp = ld;
00559 
00560        } else {
00561               fprintf( stderr, "  PID=%ld - Read done (%d).\n", (long) pid, rc );
00562 
00563               if ( ld != NULL ) {
00564                      ldap_unbind_ext( ld, NULL, NULL );
00565               }
00566        }
00567 }
00568