Back to index

openldap  2.4.31
abandon.c
Go to the documentation of this file.
00001 /* abandon.c */
00002 /* $OpenLDAP$ */
00003 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00004  *
00005  * Copyright 1998-2012 The OpenLDAP Foundation.
00006  * All rights reserved.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted only as authorized by the OpenLDAP
00010  * Public License.
00011  *
00012  * A copy of this license is available in the file LICENSE in the
00013  * top-level directory of the distribution or, alternatively, at
00014  * <http://www.OpenLDAP.org/license.html>.
00015  */
00016 /* Portions  Copyright (c) 1990 Regents of the University of Michigan.
00017  * All rights reserved.
00018  */
00019 
00020 #include "portable.h"
00021 
00022 #include <stdio.h>
00023 
00024 #include <ac/stdlib.h>
00025 
00026 #include <ac/socket.h>
00027 #include <ac/string.h>
00028 #include <ac/time.h>
00029 
00030 #include "ldap-int.h"
00031 
00032 /*
00033  * An abandon request looks like this:
00034  *            AbandonRequest ::= [APPLICATION 16] MessageID
00035  * and has no response.  (Source: RFC 4511)
00036  */
00037 #include "lutil.h"
00038 
00039 static int
00040 do_abandon(
00041        LDAP *ld,
00042        ber_int_t origid,
00043        ber_int_t msgid,
00044        LDAPControl **sctrls,
00045        int sendabandon );
00046 
00047 /*
00048  * ldap_abandon_ext - perform an ldap extended abandon operation.
00049  *
00050  * Parameters:
00051  *     ld                   LDAP descriptor
00052  *     msgid         The message id of the operation to abandon
00053  *     scntrls              Server Controls
00054  *     ccntrls              Client Controls
00055  *
00056  * ldap_abandon_ext returns a LDAP error code.
00057  *            (LDAP_SUCCESS if everything went ok)
00058  *
00059  * Example:
00060  *     ldap_abandon_ext( ld, msgid, scntrls, ccntrls );
00061  */
00062 int
00063 ldap_abandon_ext(
00064        LDAP *ld,
00065        int msgid,
00066        LDAPControl **sctrls,
00067        LDAPControl **cctrls )
00068 {
00069        int    rc;
00070 
00071        Debug( LDAP_DEBUG_TRACE, "ldap_abandon_ext %d\n", msgid, 0, 0 );
00072 
00073        /* check client controls */
00074        LDAP_MUTEX_LOCK( &ld->ld_req_mutex );
00075 
00076        rc = ldap_int_client_controls( ld, cctrls );
00077        if ( rc == LDAP_SUCCESS ) {
00078               rc = do_abandon( ld, msgid, msgid, sctrls, 1 );
00079        }
00080 
00081        LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex );
00082 
00083        return rc;
00084 }
00085 
00086 
00087 /*
00088  * ldap_abandon - perform an ldap abandon operation. Parameters:
00089  *
00090  *     ld            LDAP descriptor
00091  *     msgid         The message id of the operation to abandon
00092  *
00093  * ldap_abandon returns 0 if everything went ok, -1 otherwise.
00094  *
00095  * Example:
00096  *     ldap_abandon( ld, msgid );
00097  */
00098 int
00099 ldap_abandon( LDAP *ld, int msgid )
00100 {
00101        Debug( LDAP_DEBUG_TRACE, "ldap_abandon %d\n", msgid, 0, 0 );
00102        return ldap_abandon_ext( ld, msgid, NULL, NULL ) == LDAP_SUCCESS
00103               ? 0 : -1;
00104 }
00105 
00106 
00107 int
00108 ldap_pvt_discard(
00109        LDAP *ld,
00110        ber_int_t msgid )
00111 {
00112        int    rc;
00113 
00114        LDAP_MUTEX_LOCK( &ld->ld_req_mutex );
00115        rc = do_abandon( ld, msgid, msgid, NULL, 0 );
00116        LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex );
00117        return rc;
00118 }
00119 
00120 static int
00121 do_abandon(
00122        LDAP *ld,
00123        ber_int_t origid,
00124        ber_int_t msgid,
00125        LDAPControl **sctrls,
00126        int sendabandon )
00127 {
00128        BerElement    *ber;
00129        int           i, err;
00130        Sockbuf              *sb;
00131        LDAPRequest   *lr;
00132 
00133        Debug( LDAP_DEBUG_TRACE, "do_abandon origid %d, msgid %d\n",
00134               origid, msgid, 0 );
00135 
00136        /* find the request that we are abandoning */
00137 start_again:;
00138        lr = ld->ld_requests;
00139        while ( lr != NULL ) {
00140               /* this message */
00141               if ( lr->lr_msgid == msgid ) {
00142                      break;
00143               }
00144 
00145               /* child: abandon it */
00146               if ( lr->lr_origid == msgid && !lr->lr_abandoned ) {
00147                      (void)do_abandon( ld, lr->lr_origid, lr->lr_msgid,
00148                             sctrls, sendabandon );
00149 
00150                      /* restart, as lr may now be dangling... */
00151                      goto start_again;
00152               }
00153 
00154               lr = lr->lr_next;
00155        }
00156 
00157        if ( lr != NULL ) {
00158               if ( origid == msgid && lr->lr_parent != NULL ) {
00159                      /* don't let caller abandon child requests! */
00160                      ld->ld_errno = LDAP_PARAM_ERROR;
00161                      return( LDAP_PARAM_ERROR );
00162               }
00163               if ( lr->lr_status != LDAP_REQST_INPROGRESS ) {
00164                      /* no need to send abandon message */
00165                      sendabandon = 0;
00166               }
00167        }
00168 
00169        /* ldap_msgdelete locks the res_mutex. Give up the req_mutex
00170         * while we're in there.
00171         */
00172        LDAP_MUTEX_UNLOCK( &ld->ld_req_mutex );
00173        err = ldap_msgdelete( ld, msgid );
00174        LDAP_MUTEX_LOCK( &ld->ld_req_mutex );
00175        if ( err == 0 ) {
00176               ld->ld_errno = LDAP_SUCCESS;
00177               return LDAP_SUCCESS;
00178        }
00179 
00180        /* fetch again the request that we are abandoning */
00181        if ( lr != NULL ) {
00182               for ( lr = ld->ld_requests; lr != NULL; lr = lr->lr_next ) {
00183                      /* this message */
00184                      if ( lr->lr_msgid == msgid ) {
00185                             break;
00186                      }
00187               }
00188        }
00189 
00190        err = 0;
00191        if ( sendabandon ) {
00192               if ( ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_GET_FD, NULL ) == -1 ) {
00193                      /* not connected */
00194                      err = -1;
00195                      ld->ld_errno = LDAP_SERVER_DOWN;
00196 
00197               } else if ( ( ber = ldap_alloc_ber_with_options( ld ) ) == NULL ) {
00198                      /* BER element allocation failed */
00199                      err = -1;
00200                      ld->ld_errno = LDAP_NO_MEMORY;
00201 
00202               } else {
00203                      /*
00204                       * We already have the mutex in LDAP_R_COMPILE, so
00205                       * don't try to get it again.
00206                       *            LDAP_NEXT_MSGID(ld, i);
00207                       */
00208 
00209                      LDAP_NEXT_MSGID(ld, i);
00210 #ifdef LDAP_CONNECTIONLESS
00211                      if ( LDAP_IS_UDP(ld) ) {
00212                             struct sockaddr sa = {0};
00213                             /* dummy, filled with ldo_peer in request.c */
00214                             err = ber_write( ber, (char *) &sa, sizeof(sa), 0 );
00215                      }
00216                      if ( LDAP_IS_UDP(ld) && ld->ld_options.ldo_version ==
00217                             LDAP_VERSION2 )
00218                      {
00219                             char *dn;
00220                             LDAP_MUTEX_LOCK( &ld->ld_options.ldo_mutex );
00221                             dn = ld->ld_options.ldo_cldapdn;
00222                             if (!dn) dn = "";
00223                             err = ber_printf( ber, "{isti",  /* '}' */
00224                                    i, dn,
00225                                    LDAP_REQ_ABANDON, msgid );
00226                             LDAP_MUTEX_UNLOCK( &ld->ld_options.ldo_mutex );
00227                      } else
00228 #endif
00229                      {
00230                             /* create a message to send */
00231                             err = ber_printf( ber, "{iti",  /* '}' */
00232                                    i,
00233                                    LDAP_REQ_ABANDON, msgid );
00234                      }
00235 
00236                      if ( err == -1 ) {
00237                             /* encoding error */
00238                             ld->ld_errno = LDAP_ENCODING_ERROR;
00239 
00240                      } else {
00241                             /* Put Server Controls */
00242                             if ( ldap_int_put_controls( ld, sctrls, ber )
00243                                    != LDAP_SUCCESS )
00244                             {
00245                                    err = -1;
00246 
00247                             } else {
00248                                    /* close '{' */
00249                                    err = ber_printf( ber, /*{*/ "N}" );
00250 
00251                                    if ( err == -1 ) {
00252                                           /* encoding error */
00253                                           ld->ld_errno = LDAP_ENCODING_ERROR;
00254                                    }
00255                             }
00256                      }
00257 
00258                      if ( err == -1 ) {
00259                             ber_free( ber, 1 );
00260 
00261                      } else {
00262                             /* send the message */
00263                             if ( lr != NULL ) {
00264                                    assert( lr->lr_conn != NULL );
00265                                    sb = lr->lr_conn->lconn_sb;
00266                             } else {
00267                                    sb = ld->ld_sb;
00268                             }
00269 
00270                             if ( ber_flush2( sb, ber, LBER_FLUSH_FREE_ALWAYS ) != 0 ) {
00271                                    ld->ld_errno = LDAP_SERVER_DOWN;
00272                                    err = -1;
00273                             } else {
00274                                    err = 0;
00275                             }
00276                      }
00277               }
00278        }
00279 
00280        if ( lr != NULL ) {
00281               if ( sendabandon || lr->lr_status == LDAP_REQST_WRITING ) {
00282                      LDAP_MUTEX_LOCK( &ld->ld_conn_mutex );
00283                      ldap_free_connection( ld, lr->lr_conn, 0, 1 );
00284                      LDAP_MUTEX_UNLOCK( &ld->ld_conn_mutex );
00285               }
00286 
00287               if ( origid == msgid ) {
00288                      ldap_free_request( ld, lr );
00289 
00290               } else {
00291                      lr->lr_abandoned = 1;
00292               }
00293        }
00294 
00295        LDAP_MUTEX_LOCK( &ld->ld_abandon_mutex );
00296 
00297        /* use bisection */
00298        i = 0;
00299        if ( ld->ld_nabandoned == 0 ||
00300               ldap_int_bisect_find( ld->ld_abandoned, ld->ld_nabandoned, msgid, &i ) == 0 )
00301        {
00302               ldap_int_bisect_insert( &ld->ld_abandoned, &ld->ld_nabandoned, msgid, i );
00303        }
00304 
00305        if ( err != -1 ) {
00306               ld->ld_errno = LDAP_SUCCESS;
00307        }
00308 
00309        LDAP_MUTEX_UNLOCK( &ld->ld_abandon_mutex );
00310        return( ld->ld_errno );
00311 }
00312 
00313 /*
00314  * ldap_int_bisect_find
00315  *
00316  * args:
00317  *     v:     array of length n (in)
00318  *     n:     length of array v (in)
00319  *     id:    value to look for (in)
00320  *     idxp:  pointer to location of value/insert point
00321  *
00322  * return:
00323  *     0:     not found
00324  *     1:     found
00325  *     -1:    error
00326  */
00327 int
00328 ldap_int_bisect_find( ber_int_t *v, ber_len_t n, ber_int_t id, int *idxp )
00329 {
00330        int           begin,
00331                      end,
00332                      rc = 0;
00333 
00334        assert( id >= 0 );
00335 
00336        begin = 0;
00337        end = n - 1;
00338 
00339               if ( n <= 0 || id < v[ begin ] ) {
00340                      *idxp = 0;
00341 
00342               } else if ( id > v[ end ] ) {
00343                      *idxp = n;
00344 
00345               } else {
00346                      int           pos;
00347                      ber_int_t     curid;
00348        
00349                      do {
00350                             pos = (begin + end)/2;
00351                             curid = v[ pos ];
00352        
00353                             if ( id < curid ) {
00354                                    end = pos - 1;
00355        
00356                             } else if ( id > curid ) {
00357                                    begin = ++pos;
00358        
00359                             } else {
00360                                    /* already abandoned? */
00361                                    rc = 1;
00362                                    break;
00363                             }
00364                      } while ( end >= begin );
00365        
00366                      *idxp = pos;
00367               }
00368 
00369        return rc;
00370 }
00371 
00372 /*
00373  * ldap_int_bisect_insert
00374  *
00375  * args:
00376  *     vp:    pointer to array of length *np (in/out)
00377  *     np:    pointer to length of array *vp (in/out)
00378  *     id:    value to insert (in)
00379  *     idx:   location of insert point (as computed by ldap_int_bisect_find())
00380  *
00381  * return:
00382  *     0:     inserted
00383  *     -1:    error
00384  */
00385 int
00386 ldap_int_bisect_insert( ber_int_t **vp, ber_len_t *np, int id, int idx )
00387 {
00388        ber_int_t     *v;
00389        ber_len_t     n;
00390        int           i;
00391 
00392        assert( vp != NULL );
00393        assert( np != NULL );
00394        assert( idx >= 0 );
00395        assert( (unsigned) idx <= *np );
00396 
00397        n = *np;
00398 
00399        v = ber_memrealloc( *vp, sizeof( ber_int_t ) * ( n + 1 ) );
00400        if ( v == NULL ) {
00401               return -1;
00402        }
00403        *vp = v;
00404 
00405        for ( i = n; i > idx; i-- ) {
00406               v[ i ] = v[ i - 1 ];
00407        }
00408        v[ idx ] = id;
00409        ++(*np);
00410 
00411        return 0;
00412 }
00413 
00414 /*
00415  * ldap_int_bisect_delete
00416  *
00417  * args:
00418  *     vp:    pointer to array of length *np (in/out)
00419  *     np:    pointer to length of array *vp (in/out)
00420  *     id:    value to delete (in)
00421  *     idx:   location of value to delete (as computed by ldap_int_bisect_find())
00422  *
00423  * return:
00424  *     0:     deleted
00425  */
00426 int
00427 ldap_int_bisect_delete( ber_int_t **vp, ber_len_t *np, int id, int idx )
00428 {
00429        ber_int_t     *v;
00430        ber_len_t     i, n;
00431 
00432        assert( vp != NULL );
00433        assert( np != NULL );
00434        assert( idx >= 0 );
00435        assert( (unsigned) idx < *np );
00436 
00437        v = *vp;
00438 
00439        assert( v[ idx ] == id );
00440 
00441        --(*np);
00442        n = *np;
00443 
00444        for ( i = idx; i < n; i++ ) {
00445               v[ i ] = v[ i + 1 ];
00446        }
00447 
00448        return 0;
00449 }