Back to index

openldap  2.4.31
txn.c
Go to the documentation of this file.
00001 /* txn.c - LDAP Transactions */
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 #ifdef LDAP_X_TXN
00031 const struct berval slap_EXOP_TXN_START = BER_BVC(LDAP_EXOP_X_TXN_START);
00032 const struct berval slap_EXOP_TXN_END = BER_BVC(LDAP_EXOP_X_TXN_END);
00033 
00034 int txn_start_extop(
00035        Operation *op, SlapReply *rs )
00036 {
00037        int rc;
00038        struct berval *bv;
00039 
00040        Statslog( LDAP_DEBUG_STATS, "%s TXN START\n",
00041               op->o_log_prefix, 0, 0, 0, 0 );
00042 
00043        if( op->ore_reqdata != NULL ) {
00044               rs->sr_text = "no request data expected";
00045               return LDAP_PROTOCOL_ERROR;
00046        }
00047 
00048        op->o_bd = op->o_conn->c_authz_backend;
00049        if( backend_check_restrictions( op, rs,
00050               (struct berval *)&slap_EXOP_TXN_START ) != LDAP_SUCCESS )
00051        {
00052               return rs->sr_err;
00053        }
00054 
00055        /* acquire connection lock */
00056        ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );
00057 
00058        if( op->o_conn->c_txn != CONN_TXN_INACTIVE ) {
00059               rs->sr_text = "Too many transactions";
00060               rc = LDAP_BUSY;
00061               goto done;
00062        }
00063 
00064        assert( op->o_conn->c_txn_backend == NULL );
00065        op->o_conn->c_txn = CONN_TXN_SPECIFY;
00066 
00067        bv = (struct berval *) ch_malloc( sizeof (struct berval) );
00068        bv->bv_len = 0;
00069        bv->bv_val = NULL;
00070 
00071        rs->sr_rspdata = bv;
00072        rc = LDAP_SUCCESS;
00073 
00074 done:
00075        /* release connection lock */
00076        ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );
00077        return rc;
00078 }
00079 
00080 int txn_spec_ctrl(
00081        Operation *op, SlapReply *rs, LDAPControl *ctrl )
00082 {
00083        if ( !ctrl->ldctl_iscritical ) {
00084               rs->sr_text = "txnSpec control must be marked critical";
00085               return LDAP_PROTOCOL_ERROR;
00086        }
00087        if( op->o_txnSpec ) {
00088               rs->sr_text = "txnSpec control provided multiple times";
00089               return LDAP_PROTOCOL_ERROR;
00090        }
00091 
00092        if ( ctrl->ldctl_value.bv_val == NULL ) {
00093               rs->sr_text = "no transaction identifier provided";
00094               return LDAP_PROTOCOL_ERROR;
00095        }
00096        if ( ctrl->ldctl_value.bv_len != 0 ) {
00097               rs->sr_text = "invalid transaction identifier";
00098               return LDAP_X_TXN_ID_INVALID;
00099        }
00100 
00101        if ( op->o_preread ) { /* temporary limitation */
00102               rs->sr_text = "cannot perform pre-read in transaction";
00103               return LDAP_UNWILLING_TO_PERFORM;
00104        } 
00105        if ( op->o_postread ) { /* temporary limitation */
00106               rs->sr_text = "cannot perform post-read in transaction";
00107               return LDAP_UNWILLING_TO_PERFORM;
00108        }
00109 
00110        op->o_txnSpec = SLAP_CONTROL_CRITICAL;
00111        return LDAP_SUCCESS;
00112 }
00113 
00114 int txn_end_extop(
00115        Operation *op, SlapReply *rs )
00116 {
00117        int rc;
00118        BerElementBuffer berbuf;
00119        BerElement *ber = (BerElement *)&berbuf;
00120        ber_tag_t tag;
00121        ber_len_t len;
00122        ber_int_t commit=1;
00123        struct berval txnid;
00124 
00125        Statslog( LDAP_DEBUG_STATS, "%s TXN END\n",
00126               op->o_log_prefix, 0, 0, 0, 0 );
00127 
00128        if( op->ore_reqdata == NULL ) {
00129               rs->sr_text = "request data expected";
00130               return LDAP_PROTOCOL_ERROR;
00131        }
00132        if( op->ore_reqdata->bv_len == 0 ) {
00133               rs->sr_text = "empty request data";
00134               return LDAP_PROTOCOL_ERROR;
00135        }
00136 
00137        op->o_bd = op->o_conn->c_authz_backend;
00138        if( backend_check_restrictions( op, rs,
00139               (struct berval *)&slap_EXOP_TXN_END ) != LDAP_SUCCESS )
00140        {
00141               return rs->sr_err;
00142        }
00143 
00144        ber_init2( ber, op->ore_reqdata, 0 );
00145 
00146        tag = ber_scanf( ber, "{" /*}*/ );
00147        if( tag == LBER_ERROR ) {
00148               rs->sr_text = "request data decoding error";
00149               return LDAP_PROTOCOL_ERROR;
00150        }
00151 
00152        tag = ber_peek_tag( ber, &len );
00153        if( tag == LBER_BOOLEAN ) {
00154               tag = ber_scanf( ber, "b", &commit );
00155               if( tag == LBER_ERROR ) {
00156                      rs->sr_text = "request data decoding error";
00157                      return LDAP_PROTOCOL_ERROR;
00158               }
00159        }
00160 
00161        tag = ber_scanf( ber, /*{*/ "m}", &txnid );
00162        if( tag == LBER_ERROR ) {
00163               rs->sr_text = "request data decoding error";
00164               return LDAP_PROTOCOL_ERROR;
00165        }
00166 
00167        if( txnid.bv_len ) {
00168               rs->sr_text = "invalid transaction identifier";
00169               return LDAP_X_TXN_ID_INVALID;
00170        }
00171 
00172        /* acquire connection lock */
00173        ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );
00174 
00175        if( op->o_conn->c_txn != CONN_TXN_SPECIFY ) {
00176               rs->sr_text = "invalid transaction identifier";
00177               rc = LDAP_X_TXN_ID_INVALID;
00178               goto done;
00179        }
00180        op->o_conn->c_txn = CONN_TXN_SETTLE;
00181 
00182        if( commit ) {
00183               if ( op->o_abandon ) {
00184               }
00185 
00186               if( LDAP_STAILQ_EMPTY(&op->o_conn->c_txn_ops) ) {
00187                      /* no updates to commit */
00188                      rs->sr_text = "no updates to commit";
00189                      rc = LDAP_OPERATIONS_ERROR;
00190                      goto settled;
00191               }
00192 
00193               rs->sr_text = "not yet implemented";
00194               rc = LDAP_UNWILLING_TO_PERFORM;
00195 
00196        } else {
00197               rs->sr_text = "transaction aborted";
00198               rc = LDAP_SUCCESS;;
00199        }
00200 
00201 drain:
00202        /* drain txn ops list */
00203 
00204 settled:
00205        assert( LDAP_STAILQ_EMPTY(&op->o_conn->c_txn_ops) );
00206        assert( op->o_conn->c_txn == CONN_TXN_SETTLE );
00207        op->o_conn->c_txn = CONN_TXN_INACTIVE;
00208        op->o_conn->c_txn_backend = NULL;
00209 
00210 done:
00211        /* release connection lock */
00212        ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );
00213 
00214        return rc;
00215 }
00216 
00217 #endif /* LDAP_X_TXN */