txn.c revision 1.1
1/* txn.c - LDAP Transactions */ 2/* $OpenLDAP: pkg/ldap/servers/slapd/txn.c,v 1.6.2.3 2008/02/11 23:26:45 kurt Exp $ */ 3/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 4 * 5 * Copyright 1998-2008 The OpenLDAP Foundation. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted only as authorized by the OpenLDAP 10 * Public License. 11 * 12 * A copy of this license is available in the file LICENSE in the 13 * top-level directory of the distribution or, alternatively, at 14 * <http://www.OpenLDAP.org/license.html>. 15 */ 16 17#include "portable.h" 18 19#include <stdio.h> 20 21#include <ac/socket.h> 22#include <ac/string.h> 23#include <ac/unistd.h> 24 25#include "slap.h" 26 27#include <lber_pvt.h> 28#include <lutil.h> 29 30#ifdef LDAP_X_TXN 31const struct berval slap_EXOP_TXN_START = BER_BVC(LDAP_EXOP_X_TXN_START); 32const struct berval slap_EXOP_TXN_END = BER_BVC(LDAP_EXOP_X_TXN_END); 33 34int txn_start_extop( 35 Operation *op, SlapReply *rs ) 36{ 37 int rc; 38 struct berval *bv; 39 40 Statslog( LDAP_DEBUG_STATS, "%s TXN START\n", 41 op->o_log_prefix, 0, 0, 0, 0 ); 42 43 if( op->ore_reqdata != NULL ) { 44 rs->sr_text = "no request data expected"; 45 return LDAP_PROTOCOL_ERROR; 46 } 47 48 op->o_bd = op->o_conn->c_authz_backend; 49 if( backend_check_restrictions( op, rs, 50 (struct berval *)&slap_EXOP_TXN_START ) != LDAP_SUCCESS ) 51 { 52 return rs->sr_err; 53 } 54 55 /* acquire connection lock */ 56 ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex ); 57 58 if( op->o_conn->c_txn != CONN_TXN_INACTIVE ) { 59 rs->sr_text = "Too many transactions"; 60 rc = LDAP_BUSY; 61 goto done; 62 } 63 64 assert( op->o_conn->c_txn_backend == NULL ); 65 op->o_conn->c_txn = CONN_TXN_SPECIFY; 66 67 bv = (struct berval *) ch_malloc( sizeof (struct berval) ); 68 bv->bv_len = 0; 69 bv->bv_val = NULL; 70 71 rs->sr_rspdata = bv; 72 rc = LDAP_SUCCESS; 73 74done: 75 /* release connection lock */ 76 ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex ); 77 return rc; 78} 79 80int txn_spec_ctrl( 81 Operation *op, SlapReply *rs, LDAPControl *ctrl ) 82{ 83 if ( !ctrl->ldctl_iscritical ) { 84 rs->sr_text = "txnSpec control must be marked critical"; 85 return LDAP_PROTOCOL_ERROR; 86 } 87 if( op->o_txnSpec ) { 88 rs->sr_text = "txnSpec control provided multiple times"; 89 return LDAP_PROTOCOL_ERROR; 90 } 91 92 if ( ctrl->ldctl_value.bv_val == NULL ) { 93 rs->sr_text = "no transaction identifier provided"; 94 return LDAP_PROTOCOL_ERROR; 95 } 96 if ( ctrl->ldctl_value.bv_len != 0 ) { 97 rs->sr_text = "invalid transaction identifier"; 98 return LDAP_X_TXN_ID_INVALID; 99 } 100 101 if ( op->o_preread ) { /* temporary limitation */ 102 rs->sr_text = "cannot perform pre-read in transaction"; 103 return LDAP_UNWILLING_TO_PERFORM; 104 } 105 if ( op->o_postread ) { /* temporary limitation */ 106 rs->sr_text = "cannot perform post-read in transaction"; 107 return LDAP_UNWILLING_TO_PERFORM; 108 } 109 110 op->o_txnSpec = SLAP_CONTROL_CRITICAL; 111 return LDAP_SUCCESS; 112} 113 114int txn_end_extop( 115 Operation *op, SlapReply *rs ) 116{ 117 int rc; 118 BerElementBuffer berbuf; 119 BerElement *ber = (BerElement *)&berbuf; 120 ber_tag_t tag; 121 ber_len_t len; 122 ber_int_t commit=1; 123 struct berval txnid; 124 125 Statslog( LDAP_DEBUG_STATS, "%s TXN END\n", 126 op->o_log_prefix, 0, 0, 0, 0 ); 127 128 if( op->ore_reqdata == NULL ) { 129 rs->sr_text = "request data expected"; 130 return LDAP_PROTOCOL_ERROR; 131 } 132 if( op->ore_reqdata->bv_len == 0 ) { 133 rs->sr_text = "empty request data"; 134 return LDAP_PROTOCOL_ERROR; 135 } 136 137 op->o_bd = op->o_conn->c_authz_backend; 138 if( backend_check_restrictions( op, rs, 139 (struct berval *)&slap_EXOP_TXN_END ) != LDAP_SUCCESS ) 140 { 141 return rs->sr_err; 142 } 143 144 ber_init2( ber, op->ore_reqdata, 0 ); 145 146 tag = ber_scanf( ber, "{" /*}*/ ); 147 if( tag == LBER_ERROR ) { 148 rs->sr_text = "request data decoding error"; 149 return LDAP_PROTOCOL_ERROR; 150 } 151 152 tag = ber_peek_tag( ber, &len ); 153 if( tag == LBER_BOOLEAN ) { 154 tag = ber_scanf( ber, "b", &commit ); 155 if( tag == LBER_ERROR ) { 156 rs->sr_text = "request data decoding error"; 157 return LDAP_PROTOCOL_ERROR; 158 } 159 } 160 161 tag = ber_scanf( ber, /*{*/ "m}", &txnid ); 162 if( tag == LBER_ERROR ) { 163 rs->sr_text = "request data decoding error"; 164 return LDAP_PROTOCOL_ERROR; 165 } 166 167 if( txnid.bv_len ) { 168 rs->sr_text = "invalid transaction identifier"; 169 return LDAP_X_TXN_ID_INVALID; 170 } 171 172 /* acquire connection lock */ 173 ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex ); 174 175 if( op->o_conn->c_txn != CONN_TXN_SPECIFY ) { 176 rs->sr_text = "invalid transaction identifier"; 177 rc = LDAP_X_TXN_ID_INVALID; 178 goto done; 179 } 180 op->o_conn->c_txn = CONN_TXN_SETTLE; 181 182 if( commit ) { 183 if ( op->o_abandon ) { 184 } 185 186 if( LDAP_STAILQ_EMPTY(&op->o_conn->c_txn_ops) ) { 187 /* no updates to commit */ 188 rs->sr_text = "no updates to commit"; 189 rc = LDAP_OPERATIONS_ERROR; 190 goto settled; 191 } 192 193 rs->sr_text = "not yet implemented"; 194 rc = LDAP_UNWILLING_TO_PERFORM; 195 196 } else { 197 rs->sr_text = "transaction aborted"; 198 rc = LDAP_SUCCESS;; 199 } 200 201drain: 202 /* drain txn ops list */ 203 204settled: 205 assert( LDAP_STAILQ_EMPTY(&op->o_conn->c_txn_ops) ); 206 assert( op->o_conn->c_txn == CONN_TXN_SETTLE ); 207 op->o_conn->c_txn = CONN_TXN_INACTIVE; 208 op->o_conn->c_txn_backend = NULL; 209 210done: 211 /* release connection lock */ 212 ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex ); 213 214 return rc; 215} 216 217#endif /* LDAP_X_TXN */ 218