1/* operation.c - routines to deal with pending ldap operations */ 2/* $OpenLDAP$ */ 3/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 4 * 5 * Copyright 1998-2011 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/* Portions Copyright (c) 1995 Regents of the University of Michigan. 17 * All rights reserved. 18 * 19 * Redistribution and use in source and binary forms are permitted 20 * provided that this notice is preserved and that due credit is given 21 * to the University of Michigan at Ann Arbor. The name of the University 22 * may not be used to endorse or promote products derived from this 23 * software without specific prior written permission. This software 24 * is provided ``as is'' without express or implied warranty. 25 */ 26 27#include "portable.h" 28 29#include <stdio.h> 30 31#include <ac/string.h> 32#include <ac/socket.h> 33 34#include "slap.h" 35 36#ifdef LDAP_SLAPI 37#include "slapi/slapi.h" 38#endif 39 40static ldap_pvt_thread_mutex_t slap_op_mutex; 41static time_t last_time; 42static int last_incr; 43 44void slap_op_init(void) 45{ 46 ldap_pvt_thread_mutex_init( &slap_op_mutex ); 47} 48 49void slap_op_destroy(void) 50{ 51 ldap_pvt_thread_mutex_destroy( &slap_op_mutex ); 52} 53 54static void 55slap_op_q_destroy( void *key, void *data ) 56{ 57 Operation *op, *op2; 58 for ( op = data; op; op = op2 ) { 59 op2 = LDAP_STAILQ_NEXT( op, o_next ); 60 ber_memfree_x( op, NULL ); 61 } 62} 63 64void 65slap_op_groups_free( Operation *op ) 66{ 67 GroupAssertion *g, *n; 68 for ( g = op->o_groups; g; g = n ) { 69 n = g->ga_next; 70 slap_sl_free( g, op->o_tmpmemctx ); 71 } 72 op->o_groups = NULL; 73} 74 75void 76slap_op_free( Operation *op, void *ctx ) 77{ 78 OperationBuffer *opbuf; 79 80 assert( LDAP_STAILQ_NEXT(op, o_next) == NULL ); 81 82 /* paranoia */ 83 op->o_abandon = 1; 84 85 if ( op->o_ber != NULL ) { 86 ber_free( op->o_ber, 1 ); 87 } 88 if ( !BER_BVISNULL( &op->o_dn ) ) { 89 ch_free( op->o_dn.bv_val ); 90 op->o_dn.bv_val = NULL; 91 } 92 if ( !BER_BVISNULL( &op->o_ndn ) ) { 93 ch_free( op->o_ndn.bv_val ); 94 op->o_ndn.bv_val = NULL; 95 } 96 if ( !BER_BVISNULL( &op->o_authmech ) ) { 97 ch_free( op->o_authmech.bv_val ); 98 op->o_authmech.bv_val = NULL; 99 } 100 if ( op->o_ctrls != NULL ) { 101 slap_free_ctrls( op, op->o_ctrls ); 102 } 103 104#ifdef LDAP_CONNECTIONLESS 105 if ( op->o_res_ber != NULL ) { 106 ber_free( op->o_res_ber, 1 ); 107 } 108#endif 109 110 if ( op->o_groups ) { 111 slap_op_groups_free( op ); 112 } 113 114#if defined( LDAP_SLAPI ) 115 if ( slapi_plugins_used ) { 116 slapi_int_free_object_extensions( SLAPI_X_EXT_OPERATION, op ); 117 } 118#endif /* defined( LDAP_SLAPI ) */ 119 120 if ( !BER_BVISNULL( &op->o_csn ) ) { 121 op->o_tmpfree( op->o_csn.bv_val, op->o_tmpmemctx ); 122 } 123 124 if ( op->o_pagedresults_state != NULL ) { 125 op->o_tmpfree( op->o_pagedresults_state, op->o_tmpmemctx ); 126 } 127 128 /* Selectively zero out the struct. Ignore fields that will 129 * get explicitly initialized later anyway. Keep o_abandon intact. 130 */ 131 opbuf = (OperationBuffer *) op; 132 op->o_bd = NULL; 133 BER_BVZERO( &op->o_req_dn ); 134 BER_BVZERO( &op->o_req_ndn ); 135 memset( &op->o_request, 0, sizeof( op->o_request )); 136 memset( &op->o_do_not_cache, 0, sizeof( Operation ) - offsetof( Operation, o_do_not_cache )); 137 memset( opbuf->ob_controls, 0, sizeof( opbuf->ob_controls )); 138 op->o_controls = opbuf->ob_controls; 139 140 if ( ctx ) { 141 Operation *op2 = NULL; 142 ldap_pvt_thread_pool_setkey( ctx, (void *)slap_op_free, 143 op, slap_op_q_destroy, (void **)&op2, NULL ); 144 LDAP_STAILQ_NEXT( op, o_next ) = op2; 145 if ( op2 ) { 146 op->o_tincr = op2->o_tincr + 1; 147 /* No more than 10 ops on per-thread free list */ 148 if ( op->o_tincr > 10 ) { 149 ldap_pvt_thread_pool_setkey( ctx, (void *)slap_op_free, 150 op2, slap_op_q_destroy, NULL, NULL ); 151 ber_memfree_x( op, NULL ); 152 } 153 } else { 154 op->o_tincr = 1; 155 } 156 } else { 157 ber_memfree_x( op, NULL ); 158 } 159} 160 161void 162slap_op_time(time_t *t, int *nop) 163{ 164 ldap_pvt_thread_mutex_lock( &slap_op_mutex ); 165 *t = slap_get_time(); 166 if ( *t == last_time ) { 167 *nop = ++last_incr; 168 } else { 169 last_time = *t; 170 last_incr = 0; 171 *nop = 0; 172 } 173 ldap_pvt_thread_mutex_unlock( &slap_op_mutex ); 174} 175 176Operation * 177slap_op_alloc( 178 BerElement *ber, 179 ber_int_t msgid, 180 ber_tag_t tag, 181 ber_int_t id, 182 void *ctx ) 183{ 184 Operation *op = NULL; 185 186 if ( ctx ) { 187 void *otmp = NULL; 188 ldap_pvt_thread_pool_getkey( ctx, (void *)slap_op_free, &otmp, NULL ); 189 if ( otmp ) { 190 op = otmp; 191 otmp = LDAP_STAILQ_NEXT( op, o_next ); 192 ldap_pvt_thread_pool_setkey( ctx, (void *)slap_op_free, 193 otmp, slap_op_q_destroy, NULL, NULL ); 194 op->o_abandon = 0; 195 op->o_cancel = 0; 196 } 197 } 198 if (!op) { 199 op = (Operation *) ch_calloc( 1, sizeof(OperationBuffer) ); 200 op->o_hdr = &((OperationBuffer *) op)->ob_hdr; 201 op->o_controls = ((OperationBuffer *) op)->ob_controls; 202 } 203 204 op->o_ber = ber; 205 op->o_msgid = msgid; 206 op->o_tag = tag; 207 208 slap_op_time( &op->o_time, &op->o_tincr ); 209 op->o_opid = id; 210 211#if defined( LDAP_SLAPI ) 212 if ( slapi_plugins_used ) { 213 slapi_int_create_object_extensions( SLAPI_X_EXT_OPERATION, op ); 214 } 215#endif /* defined( LDAP_SLAPI ) */ 216 217 return( op ); 218} 219 220slap_op_t 221slap_req2op( ber_tag_t tag ) 222{ 223 switch ( tag ) { 224 case LDAP_REQ_BIND: 225 return SLAP_OP_BIND; 226 case LDAP_REQ_UNBIND: 227 return SLAP_OP_UNBIND; 228 case LDAP_REQ_ADD: 229 return SLAP_OP_ADD; 230 case LDAP_REQ_DELETE: 231 return SLAP_OP_DELETE; 232 case LDAP_REQ_MODRDN: 233 return SLAP_OP_MODRDN; 234 case LDAP_REQ_MODIFY: 235 return SLAP_OP_MODIFY; 236 case LDAP_REQ_COMPARE: 237 return SLAP_OP_COMPARE; 238 case LDAP_REQ_SEARCH: 239 return SLAP_OP_SEARCH; 240 case LDAP_REQ_ABANDON: 241 return SLAP_OP_ABANDON; 242 case LDAP_REQ_EXTENDED: 243 return SLAP_OP_EXTENDED; 244 } 245 246 return SLAP_OP_LAST; 247} 248