Back to index

openldap  2.4.31
cancel.c
Go to the documentation of this file.
00001 /* cancel.c - LDAP cancel extended operation */
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 
00017 #include "portable.h"
00018 
00019 #include <stdio.h>
00020 
00021 #include <ac/socket.h>
00022 #include <ac/string.h>
00023 #include <ac/unistd.h>
00024 
00025 #include "slap.h"
00026 
00027 #include <lber_pvt.h>
00028 #include <lutil.h>
00029 
00030 const struct berval slap_EXOP_CANCEL = BER_BVC(LDAP_EXOP_CANCEL);
00031 
00032 int cancel_extop( Operation *op, SlapReply *rs )
00033 {
00034        Operation *o;
00035        int rc;
00036        int opid;
00037        BerElement *ber;
00038 
00039        assert( ber_bvcmp( &slap_EXOP_CANCEL, &op->ore_reqoid ) == 0 );
00040 
00041        if ( op->ore_reqdata == NULL ) {
00042               rs->sr_text = "no message ID supplied";
00043               return LDAP_PROTOCOL_ERROR;
00044        }
00045 
00046        ber = ber_init( op->ore_reqdata );
00047        if ( ber == NULL ) {
00048               rs->sr_text = "internal error";
00049               return LDAP_OTHER;
00050        }
00051 
00052        if ( ber_scanf( ber, "{i}", &opid ) == LBER_ERROR ) {
00053               rs->sr_text = "message ID parse failed";
00054               return LDAP_PROTOCOL_ERROR;
00055        }
00056 
00057        (void) ber_free( ber, 1 );
00058 
00059        Statslog( LDAP_DEBUG_STATS, "%s CANCEL msg=%d\n",
00060               op->o_log_prefix, opid, 0, 0, 0 );
00061 
00062        if ( opid < 0 ) {
00063               rs->sr_text = "message ID invalid";
00064               return LDAP_PROTOCOL_ERROR;
00065        }
00066 
00067        ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );
00068 
00069        if ( op->o_abandon ) {
00070               /* FIXME: Should instead reject the cancel/abandon of this op, but
00071                * it seems unsafe to reset op->o_abandon once it is set. ITS#6138.
00072                */
00073               rc = LDAP_OPERATIONS_ERROR;
00074               rs->sr_text = "tried to abandon or cancel this operation";
00075               goto out;
00076        }
00077 
00078        LDAP_STAILQ_FOREACH( o, &op->o_conn->c_pending_ops, o_next ) {
00079               if ( o->o_msgid == opid ) {
00080                      /* TODO: We could instead remove the cancelled operation
00081                       * from c_pending_ops like Abandon does, and send its
00082                       * response here.  Not if it is pending because of a
00083                       * congested connection though.
00084                       */
00085                      rc = LDAP_CANNOT_CANCEL;
00086                      rs->sr_text = "too busy for Cancel, try Abandon instead";
00087                      goto out;
00088               }
00089        }
00090 
00091        LDAP_STAILQ_FOREACH( o, &op->o_conn->c_ops, o_next ) {
00092               if ( o->o_msgid == opid ) {
00093                      break;
00094               }
00095        }
00096 
00097        if ( o == NULL ) {
00098               rc = LDAP_NO_SUCH_OPERATION;
00099               rs->sr_text = "message ID not found";
00100 
00101        } else if ( o->o_tag == LDAP_REQ_BIND
00102                      || o->o_tag == LDAP_REQ_UNBIND
00103                      || o->o_tag == LDAP_REQ_ABANDON ) {
00104               rc = LDAP_CANNOT_CANCEL;
00105 
00106        } else if ( o->o_cancel != SLAP_CANCEL_NONE ) {
00107               rc = LDAP_OPERATIONS_ERROR;
00108               rs->sr_text = "message ID already being cancelled";
00109 
00110 #if 0
00111        } else if ( o->o_abandon ) {
00112               /* TODO: Would this break something when
00113                * o_abandon="suppress response"? (ITS#6138)
00114                */
00115               rc = LDAP_TOO_LATE;
00116 #endif
00117 
00118        } else {
00119               rc = LDAP_SUCCESS;
00120               o->o_cancel = SLAP_CANCEL_REQ;
00121               o->o_abandon = 1;
00122        }
00123 
00124  out:
00125        ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );
00126 
00127        if ( rc == LDAP_SUCCESS ) {
00128               LDAP_STAILQ_FOREACH( op->o_bd, &backendDB, be_next ) {
00129                      if( !op->o_bd->be_cancel ) continue;
00130 
00131                      op->oq_cancel.rs_msgid = opid;
00132                      if ( op->o_bd->be_cancel( op, rs ) == LDAP_SUCCESS ) {
00133                             return LDAP_SUCCESS;
00134                      }
00135               }
00136 
00137               do {
00138                      /* Fake a cond_wait with thread_yield, then
00139                       * verify the result properly mutex-protected.
00140                       */
00141                      while ( o->o_cancel == SLAP_CANCEL_REQ )
00142                             ldap_pvt_thread_yield();
00143                      ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );
00144                      rc = o->o_cancel;
00145                      ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );
00146               } while ( rc == SLAP_CANCEL_REQ );
00147 
00148               if ( rc == SLAP_CANCEL_ACK ) {
00149                      rc = LDAP_SUCCESS;
00150               }
00151 
00152               o->o_cancel = SLAP_CANCEL_DONE;
00153        }
00154 
00155        return rc;
00156 }