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/>.
5 * Copyright 1998-2008 The OpenLDAP Foundation.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
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>.
21 #include <ac/socket.h>
22 #include <ac/string.h>
23 #include <ac/unistd.h>
31 const struct berval slap_EXOP_TXN_START
= BER_BVC(LDAP_EXOP_X_TXN_START
);
32 const struct berval slap_EXOP_TXN_END
= BER_BVC(LDAP_EXOP_X_TXN_END
);
35 Operation
*op
, SlapReply
*rs
)
40 Statslog( LDAP_DEBUG_STATS
, "%s TXN START\n",
41 op
->o_log_prefix
, 0, 0, 0, 0 );
43 if( op
->ore_reqdata
!= NULL
) {
44 rs
->sr_text
= "no request data expected";
45 return LDAP_PROTOCOL_ERROR
;
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
)
55 /* acquire connection lock */
56 ldap_pvt_thread_mutex_lock( &op
->o_conn
->c_mutex
);
58 if( op
->o_conn
->c_txn
!= CONN_TXN_INACTIVE
) {
59 rs
->sr_text
= "Too many transactions";
64 assert( op
->o_conn
->c_txn_backend
== NULL
);
65 op
->o_conn
->c_txn
= CONN_TXN_SPECIFY
;
67 bv
= (struct berval
*) ch_malloc( sizeof (struct berval
) );
75 /* release connection lock */
76 ldap_pvt_thread_mutex_unlock( &op
->o_conn
->c_mutex
);
81 Operation
*op
, SlapReply
*rs
, LDAPControl
*ctrl
)
83 if ( !ctrl
->ldctl_iscritical
) {
84 rs
->sr_text
= "txnSpec control must be marked critical";
85 return LDAP_PROTOCOL_ERROR
;
88 rs
->sr_text
= "txnSpec control provided multiple times";
89 return LDAP_PROTOCOL_ERROR
;
92 if ( ctrl
->ldctl_value
.bv_val
== NULL
) {
93 rs
->sr_text
= "no transaction identifier provided";
94 return LDAP_PROTOCOL_ERROR
;
96 if ( ctrl
->ldctl_value
.bv_len
!= 0 ) {
97 rs
->sr_text
= "invalid transaction identifier";
98 return LDAP_X_TXN_ID_INVALID
;
101 if ( op
->o_preread
) { /* temporary limitation */
102 rs
->sr_text
= "cannot perform pre-read in transaction";
103 return LDAP_UNWILLING_TO_PERFORM
;
105 if ( op
->o_postread
) { /* temporary limitation */
106 rs
->sr_text
= "cannot perform post-read in transaction";
107 return LDAP_UNWILLING_TO_PERFORM
;
110 op
->o_txnSpec
= SLAP_CONTROL_CRITICAL
;
115 Operation
*op
, SlapReply
*rs
)
118 BerElementBuffer berbuf
;
119 BerElement
*ber
= (BerElement
*)&berbuf
;
125 Statslog( LDAP_DEBUG_STATS
, "%s TXN END\n",
126 op
->o_log_prefix
, 0, 0, 0, 0 );
128 if( op
->ore_reqdata
== NULL
) {
129 rs
->sr_text
= "request data expected";
130 return LDAP_PROTOCOL_ERROR
;
132 if( op
->ore_reqdata
->bv_len
== 0 ) {
133 rs
->sr_text
= "empty request data";
134 return LDAP_PROTOCOL_ERROR
;
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
)
144 ber_init2( ber
, op
->ore_reqdata
, 0 );
146 tag
= ber_scanf( ber
, "{" /*}*/ );
147 if( tag
== LBER_ERROR
) {
148 rs
->sr_text
= "request data decoding error";
149 return LDAP_PROTOCOL_ERROR
;
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
;
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
;
168 rs
->sr_text
= "invalid transaction identifier";
169 return LDAP_X_TXN_ID_INVALID
;
172 /* acquire connection lock */
173 ldap_pvt_thread_mutex_lock( &op
->o_conn
->c_mutex
);
175 if( op
->o_conn
->c_txn
!= CONN_TXN_SPECIFY
) {
176 rs
->sr_text
= "invalid transaction identifier";
177 rc
= LDAP_X_TXN_ID_INVALID
;
180 op
->o_conn
->c_txn
= CONN_TXN_SETTLE
;
183 if ( op
->o_abandon
) {
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
;
193 rs
->sr_text
= "not yet implemented";
194 rc
= LDAP_UNWILLING_TO_PERFORM
;
197 rs
->sr_text
= "transaction aborted";
202 /* drain txn ops list */
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
;
211 /* release connection lock */
212 ldap_pvt_thread_mutex_unlock( &op
->o_conn
->c_mutex
);
217 #endif /* LDAP_X_TXN */