]> git.sur5r.net Git - openldap/blobdiff - libraries/libldap/abandon.c
ITS#5571 prevent Adds from displacing {0}config
[openldap] / libraries / libldap / abandon.c
index 30742ea8258ae5fb495fde4457f20c768c2bed80..8f2fb3419499583f22babc83938cba956afc923e 100644 (file)
@@ -2,7 +2,7 @@
 /* $OpenLDAP$ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
- * Copyright 1998-2006 The OpenLDAP Foundation.
+ * Copyright 1998-2008 The OpenLDAP Foundation.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 /* Portions  Copyright (c) 1990 Regents of the University of Michigan.
  * All rights reserved.
  */
-/* Portions Copyright (C) The Internet Society (1997).
- * ASN.1 fragments are from RFC 2251; see RFC for full legal notices.
- */
-
-/*
- * An abandon request looks like this:
- *     AbandonRequest ::= MessageID
- */
 
 #include "portable.h"
 
 
 #include "ldap-int.h"
 
+/*
+ * An abandon request looks like this:
+ *             AbandonRequest ::= [APPLICATION 16] MessageID
+ * and has no response.  (Source: RFC 4511)
+ */
+#include "lutil.h"
+
 static int
 do_abandon(
        LDAP *ld,
@@ -110,7 +109,7 @@ ldap_abandon( LDAP *ld, int msgid )
 
 
 int
-ldap_int_discard(
+ldap_pvt_discard(
        LDAP *ld,
        ber_int_t msgid )
 {
@@ -139,22 +138,23 @@ do_abandon(
 {
        BerElement      *ber;
        int             i, err;
-       ber_int_t       *old_abandon;
        Sockbuf         *sb;
        LDAPRequest     *lr;
 
-       Debug( LDAP_DEBUG_TRACE, "ldap_int_discard origid %d, msgid %d\n",
+       Debug( LDAP_DEBUG_TRACE, "do_abandon origid %d, msgid %d\n",
                origid, msgid, 0 );
 
        /* find the request that we are abandoning */
 start_again:;
        lr = ld->ld_requests;
        while ( lr != NULL ) {
-               if ( lr->lr_msgid == msgid ) {  /* this message */
+               /* this message */
+               if ( lr->lr_msgid == msgid ) {
                        break;
                }
 
-               if ( lr->lr_origid == msgid ) {/* child:  abandon it */
+               /* child: abandon it */
+               if ( lr->lr_origid == msgid && !lr->lr_abandoned ) {
                        (void)do_abandon( ld, lr->lr_origid, lr->lr_msgid,
                                sctrls, sendabandon );
 
@@ -224,8 +224,9 @@ start_again:;
                        i = ++(ld)->ld_msgid;
 #ifdef LDAP_CONNECTIONLESS
                        if ( LDAP_IS_UDP(ld) ) {
-                               err = ber_write( ber, ld->ld_options.ldo_peer,
-                                       sizeof(struct sockaddr), 0);
+                               struct sockaddr sa = {0};
+                               /* dummy, filled with ldo_peer in request.c */
+                               err = ber_write( ber, &sa, sizeof(sa), 0 );
                        }
                        if ( LDAP_IS_UDP(ld) && ld->ld_options.ldo_version ==
                                LDAP_VERSION2 )
@@ -295,6 +296,9 @@ start_again:;
 
                if ( origid == msgid ) {
                        ldap_free_request( ld, lr );
+
+               } else {
+                       lr->lr_abandoned = 1;
                }
        }
 
@@ -307,76 +311,162 @@ start_again:;
 
        /* use bisection */
        i = 0;
-       if ( ld->ld_abandoned != NULL ) {
-               int             begin,
-                               end;
-
-               assert( ld->ld_nabandoned >= 0 );
+       if ( ld->ld_nabandoned == 0 ||
+               ldap_int_bisect_find( ld->ld_abandoned, ld->ld_nabandoned, msgid, &i ) == 0 )
+       {
+               ldap_int_bisect_insert( &ld->ld_abandoned, &ld->ld_nabandoned, msgid, i );
+       }
 
-               begin = 0;
-               end = ld->ld_nabandoned - 1;
+       if ( err != -1 ) {
+               ld->ld_errno = LDAP_SUCCESS;
+       }
 
-               if ( ld->ld_nabandoned == 0 || ld->ld_abandoned[ begin ] > msgid ) {
-                       i = 0;
+#ifdef LDAP_R_COMPILE
+       ldap_pvt_thread_mutex_unlock( &ld->ld_res_mutex );
+       ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex );
+#endif
+       return( ld->ld_errno );
+}
 
-               } else if ( ld->ld_abandoned[ end ] < msgid ) {
-                       i = ld->ld_nabandoned;
+/*
+ * ldap_int_bisect_find
+ *
+ * args:
+ *     v:      array of length n (in)
+ *     n:      length of array v (in)
+ *     id:     value to look for (in)
+ *     idxp:   pointer to location of value/insert point
+ *
+ * return:
+ *     0:      not found
+ *     1:      found
+ *     -1:     error
+ */
+int
+ldap_int_bisect_find( ber_int_t *v, ber_len_t n, ber_int_t id, int *idxp )
+{
+       int             begin,
+                       end,
+                       rc = 0;
 
-               } else {
-                       int     pos, curid;
+       assert( n >= 0 );
+       assert( id >= 0 );
 
-                       while ( end >= begin ) {
-                               pos = (begin + end)/2;
-                               curid = ld->ld_abandoned[ pos ];
+       begin = 0;
+       end = n - 1;
 
-                               if ( msgid < curid ) {
-                                       end = pos - 1;
+               if ( n <= 0 || id < v[ begin ] ) {
+                       *idxp = 0;
 
-                               } else if ( msgid > curid ) {
-                                       begin = pos + 1;
+               } else if ( id > v[ end ] ) {
+                       *idxp = n;
 
+               } else {
+                       int             pos;
+                       ber_int_t       curid;
+       
+                       do {
+                               pos = (begin + end)/2;
+                               curid = v[ pos ];
+       
+                               if ( id < curid ) {
+                                       end = pos - 1;
+       
+                               } else if ( id > curid ) {
+                                       begin = ++pos;
+       
                                } else {
                                        /* already abandoned? */
-                                       i = -1;
+                                       rc = 1;
                                        break;
                                }
-                       }
-
-                       if ( i == 0 ) {
-                               i = pos;
-                       }
+                       } while ( end >= begin );
+       
+                       *idxp = pos;
                }
-       }
 
-       if ( i != -1 ) {
-               int     pos = i;
+       return rc;
+}
 
-               old_abandon = ld->ld_abandoned;
+/*
+ * ldap_int_bisect_insert
+ *
+ * args:
+ *     vp:     pointer to array of length *np (in/out)
+ *     np:     pointer to length of array *vp (in/out)
+ *     id:     value to insert (in)
+ *     idx:    location of insert point (as computed by ldap_int_bisect_find())
+ *
+ * return:
+ *     0:      inserted
+ *     -1:     error
+ */
+int
+ldap_int_bisect_insert( ber_int_t **vp, ber_len_t *np, int id, int idx )
+{
+       ber_int_t       *v;
+       ber_len_t       n;
+       int             i;
 
-               ld->ld_abandoned = (ber_int_t *) LDAP_REALLOC( (char *)ld->ld_abandoned,
-                       ( ld->ld_nabandoned + 1 ) * sizeof( ber_int_t ) );
+       assert( vp != NULL );
+       assert( np != NULL );
+       assert( *np >= 0 );
+       assert( idx >= 0 );
+       assert( idx <= *np );
 
-               if ( ld->ld_abandoned == NULL ) {
-                       ld->ld_abandoned = old_abandon;
-                       ld->ld_errno = LDAP_NO_MEMORY;
-                       goto done;
-               }
+       n = *np;
 
-               for ( i = ld->ld_nabandoned; i > pos; i-- ) {
-                       ld->ld_abandoned[ i ] = ld->ld_abandoned[ i - 1 ];
-               }
-               ld->ld_abandoned[ pos ] = msgid;
-               ++ld->ld_nabandoned;
+       v = ber_memrealloc( *vp, sizeof( ber_int_t ) * ( n + 1 ) );
+       if ( v == NULL ) {
+               return -1;
        }
+       *vp = v;
 
-       if ( err != -1 ) {
-               ld->ld_errno = LDAP_SUCCESS;
+       for ( i = n; i > idx; i-- ) {
+               v[ i ] = v[ i - 1 ];
        }
+       v[ idx ] = id;
+       ++(*np);
 
-done:;
-#ifdef LDAP_R_COMPILE
-       ldap_pvt_thread_mutex_unlock( &ld->ld_res_mutex );
-       ldap_pvt_thread_mutex_lock( &ld->ld_req_mutex );
-#endif
-       return( ld->ld_errno );
+       return 0;
+}
+
+/*
+ * ldap_int_bisect_delete
+ *
+ * args:
+ *     vp:     pointer to array of length *np (in/out)
+ *     np:     pointer to length of array *vp (in/out)
+ *     id:     value to delete (in)
+ *     idx:    location of value to delete (as computed by ldap_int_bisect_find())
+ *
+ * return:
+ *     0:      deleted
+ */
+int
+ldap_int_bisect_delete( ber_int_t **vp, ber_len_t *np, int id, int idx )
+{
+       ber_int_t       *v;
+       ber_len_t       n;
+       int             i;
+
+       assert( vp != NULL );
+       assert( np != NULL );
+       assert( *np >= 0 );
+       assert( idx >= 0 );
+       assert( idx < *np );
+
+       v = *vp;
+
+       assert( v[ idx ] == id );
+
+       --(*np);
+       n = *np;
+
+       for ( i = idx; i < n; i++ ) {
+               v[ i ] = v[ i + 1 ];
+       }
+
+       return 0;
 }
+