operation.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655
  1. /** BEGIN COPYRIGHT BLOCK
  2. * This Program is free software; you can redistribute it and/or modify it under
  3. * the terms of the GNU General Public License as published by the Free Software
  4. * Foundation; version 2 of the License.
  5. *
  6. * This Program is distributed in the hope that it will be useful, but WITHOUT
  7. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  8. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  9. *
  10. * You should have received a copy of the GNU General Public License along with
  11. * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
  12. * Place, Suite 330, Boston, MA 02111-1307 USA.
  13. *
  14. * In addition, as a special exception, Red Hat, Inc. gives You the additional
  15. * right to link the code of this Program with code not covered under the GNU
  16. * General Public License ("Non-GPL Code") and to distribute linked combinations
  17. * including the two, subject to the limitations in this paragraph. Non-GPL Code
  18. * permitted under this exception must only link to the code of this Program
  19. * through those well defined interfaces identified in the file named EXCEPTION
  20. * found in the source code files (the "Approved Interfaces"). The files of
  21. * Non-GPL Code may instantiate templates or use macros or inline functions from
  22. * the Approved Interfaces without causing the resulting work to be covered by
  23. * the GNU General Public License. Only Red Hat, Inc. may make changes or
  24. * additions to the list of Approved Interfaces. You must obey the GNU General
  25. * Public License in all respects for all of the Program code and other code used
  26. * in conjunction with the Program except the Non-GPL Code covered by this
  27. * exception. If you modify this file, you may extend this exception to your
  28. * version of the file, but you are not obligated to do so. If you do not wish to
  29. * provide this exception without modification, you must delete this exception
  30. * statement from your version and license this file solely under the GPL without
  31. * exception.
  32. *
  33. *
  34. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  35. * Copyright (C) 2005 Red Hat, Inc.
  36. * All rights reserved.
  37. * END COPYRIGHT BLOCK **/
  38. #ifdef HAVE_CONFIG_H
  39. # include <config.h>
  40. #endif
  41. /* operation.c - routines to deal with pending ldap operations */
  42. #include <stdio.h>
  43. #include <string.h>
  44. #include <sys/types.h>
  45. #ifndef _WIN32
  46. #include <sys/socket.h>
  47. #endif
  48. #include "slap.h"
  49. #include "fe.h"
  50. int
  51. slapi_is_operation_abandoned( Slapi_Operation *op )
  52. {
  53. if (op) {
  54. return( op->o_status == SLAPI_OP_STATUS_ABANDONED );
  55. }
  56. return 0;
  57. }
  58. int
  59. slapi_op_abandoned( Slapi_PBlock *pb )
  60. {
  61. int op_status;
  62. if (pb && pb->pb_op) {
  63. op_status = pb->pb_op->o_status;
  64. return( op_status == SLAPI_OP_STATUS_ABANDONED );
  65. }
  66. return 0;
  67. }
  68. int
  69. slapi_op_internal( Slapi_PBlock *pb )
  70. {
  71. if (pb && pb->pb_op) {
  72. return operation_is_flag_set(pb->pb_op, OP_FLAG_INTERNAL);
  73. }
  74. return 0;
  75. }
  76. void
  77. operation_out_of_disk_space()
  78. {
  79. LDAPDebug(LDAP_DEBUG_ANY, "*** DISK FULL ***\n", 0, 0, 0);
  80. LDAPDebug(LDAP_DEBUG_ANY, "Attempting to shut down gracefully.\n", 0, 0, 0);
  81. g_set_shutdown( SLAPI_SHUTDOWN_DISKFULL );
  82. }
  83. /* Setting the flags on the operation allows more control to the plugin
  84. * to disable and enable checks
  85. * Flags that we support for setting in the operation from the plugin are
  86. * SLAPI_OP_FLAG_NO_ACCESS_CHECK - do not check for access control
  87. * This function can be extended to support other flag setting as well
  88. */
  89. void slapi_operation_set_flag(Slapi_Operation *op, unsigned long flag)
  90. {
  91. operation_set_flag(op, flag);
  92. }
  93. void slapi_operation_clear_flag(Slapi_Operation *op, unsigned long flag)
  94. {
  95. operation_clear_flag(op, flag);
  96. }
  97. int slapi_operation_is_flag_set(Slapi_Operation *op, unsigned long flag)
  98. {
  99. return operation_is_flag_set(op, flag);
  100. }
  101. static int operation_type = -1; /* The type number assigned by the Factory for 'Operation' */
  102. int
  103. get_operation_object_type()
  104. {
  105. if(operation_type==-1)
  106. {
  107. /* The factory is given the name of the object type, in
  108. * return for a type handle. Whenever the object is created
  109. * or destroyed the factory is called with the handle so
  110. * that it may call the constructors or destructors registered
  111. * with it.
  112. */
  113. operation_type= factory_register_type(SLAPI_EXT_OPERATION,offsetof(Operation,o_extension));
  114. }
  115. return operation_type;
  116. }
  117. #if defined(USE_OPENLDAP)
  118. /* openldap doesn't have anything like this, nor does it have
  119. a way to portably and without cheating discover the
  120. sizeof BerElement - see lber_pvt.h for the trick used
  121. for BerElementBuffer
  122. so we just allocate everything separately
  123. If we wanted to get fancy, we could use LBER_OPT_MEMORY_FNS
  124. to override the ber malloc, realloc, etc. and use
  125. LBER_OPT_BER_MEMCTX to provide callback data for use
  126. with those functions
  127. */
  128. static void*
  129. ber_special_alloc(size_t size, BerElement **ppBer)
  130. {
  131. void *mem = NULL;
  132. /* starts out with a null buffer - will grow as needed */
  133. *ppBer = ber_alloc_t(0);
  134. /* Make sure mem size requested is aligned */
  135. if (0 != ( size & 0x03 )) {
  136. size += (sizeof(ber_int_t) - (size & 0x03));
  137. }
  138. mem = slapi_ch_malloc(size);
  139. return mem;
  140. }
  141. static void
  142. ber_special_free(void* buf, BerElement *ber)
  143. {
  144. ber_free(ber, 1);
  145. slapi_ch_free(&buf);
  146. }
  147. #endif
  148. void
  149. operation_init(Slapi_Operation *o, int flags)
  150. {
  151. if (NULL != o)
  152. {
  153. BerElement *ber = o->o_ber; /* may have already been set */
  154. memset(o,0,sizeof(Slapi_Operation));
  155. o->o_ber = ber;
  156. o->o_msgid = -1;
  157. o->o_tag = LBER_DEFAULT;
  158. o->o_status = SLAPI_OP_STATUS_PROCESSING;
  159. slapi_sdn_init(&(o->o_sdn));
  160. o->o_authtype = NULL;
  161. o->o_isroot = 0;
  162. o->o_time = current_time();
  163. o->o_opid = 0;
  164. o->o_connid = 0;
  165. o->o_next = NULL;
  166. o->o_flags= flags;
  167. o->o_reverse_search_state = 0;
  168. if ( config_get_accesslog_level() & LDAP_DEBUG_TIMING ) {
  169. o->o_interval = PR_IntervalNow();
  170. } else {
  171. o->o_interval = (PRIntervalTime)0;
  172. }
  173. o->o_pagedresults_sizelimit = -1;
  174. }
  175. }
  176. Slapi_Operation *
  177. slapi_operation_new(int flags)
  178. {
  179. return (operation_new(flags));
  180. }
  181. /*
  182. * Allocate a new Slapi_Operation.
  183. * The flag parameter indicates whether the the operation is
  184. * external (from an LDAP Client), or internal (from a plugin).
  185. */
  186. Slapi_Operation *
  187. operation_new(int flags)
  188. {
  189. /* To improve performance, we allocate the Operation, BerElement and
  190. * ber buffer in one block, instead of a separate malloc() for each.
  191. * Subsequently, ber_special_free() frees them all; we're careful
  192. * not to free the Operation separately, and the ber software knows
  193. * not to free the buffer separately.
  194. */
  195. Slapi_Operation *o;
  196. BerElement *ber = NULL;
  197. if(flags & OP_FLAG_INTERNAL)
  198. {
  199. o = (Slapi_Operation *) slapi_ch_malloc(sizeof(Slapi_Operation));
  200. }
  201. else
  202. {
  203. o= (Slapi_Operation *) ber_special_alloc( sizeof(Slapi_Operation), &ber );
  204. }
  205. if (NULL != o)
  206. {
  207. o->o_ber = ber;
  208. operation_init(o, flags);
  209. }
  210. return o;
  211. }
  212. void
  213. operation_done( Slapi_Operation **op, Connection *conn )
  214. {
  215. if(op!=NULL && *op!=NULL)
  216. {
  217. /* Call the plugin extension destructors */
  218. factory_destroy_extension(get_operation_object_type(),*op,conn,&((*op)->o_extension));
  219. slapi_sdn_done(&(*op)->o_sdn);
  220. slapi_sdn_free(&(*op)->o_target_spec);
  221. slapi_ch_free_string( &(*op)->o_authtype );
  222. if ( (*op)->o_searchattrs != NULL ) {
  223. charray_free( (*op)->o_searchattrs );
  224. (*op)->o_searchattrs = NULL;
  225. }
  226. if ( NULL != (*op)->o_params.request_controls ) {
  227. ldap_controls_free( (*op)->o_params.request_controls );
  228. (*op)->o_params.request_controls = NULL;
  229. }
  230. if ( NULL != (*op)->o_results.result_controls ) {
  231. ldap_controls_free( (*op)->o_results.result_controls );
  232. (*op)->o_results.result_controls = NULL;
  233. }
  234. slapi_ch_free_string(&(*op)->o_results.result_matched);
  235. #if defined(USE_OPENLDAP)
  236. int options = 0;
  237. /* save the old options */
  238. if ((*op)->o_ber) {
  239. ber_get_option((*op)->o_ber, LBER_OPT_BER_OPTIONS, &options);
  240. /* we don't have a way to reuse the BerElement buffer so just free it */
  241. ber_free_buf((*op)->o_ber);
  242. /* clear out the ber for the next operation */
  243. ber_init2((*op)->o_ber, NULL, options);
  244. }
  245. #else
  246. if((*op)->o_ber){
  247. ber_special_free(*op, (*op)->o_ber); /* have to free everything here */
  248. *op = NULL;
  249. }
  250. #endif
  251. }
  252. }
  253. void
  254. operation_free( Slapi_Operation **op, Connection *conn )
  255. {
  256. operation_done(op, conn);
  257. if(op!=NULL && *op!=NULL)
  258. {
  259. if(operation_is_flag_set(*op, OP_FLAG_INTERNAL))
  260. {
  261. slapi_ch_free((void**)op);
  262. }
  263. else
  264. {
  265. ber_special_free( *op , (*op)->o_ber);
  266. }
  267. /* counters_to_errors_log("after operation"); */
  268. }
  269. }
  270. void
  271. slapi_operation_set_csngen_handler ( Slapi_Operation *op, void *callback )
  272. {
  273. op->o_csngen_handler = (csngen_handler) callback;
  274. }
  275. void
  276. slapi_operation_set_replica_attr_handler ( Slapi_Operation *op, void *callback )
  277. {
  278. op->o_replica_attr_handler = (replica_attr_handler) callback;
  279. }
  280. int
  281. slapi_operation_get_replica_attr ( Slapi_PBlock *pb, Slapi_Operation *op, const char *type, void *value )
  282. {
  283. int rc = -1;
  284. if (op->o_replica_attr_handler)
  285. {
  286. rc = op->o_replica_attr_handler ( pb, type, value );
  287. }
  288. return rc;
  289. }
  290. CSN *
  291. operation_get_csn(Slapi_Operation *op)
  292. {
  293. return op->o_params.csn;
  294. }
  295. void
  296. operation_set_csn(Slapi_Operation *op,CSN *csn)
  297. {
  298. op->o_params.csn= csn;
  299. }
  300. unsigned long
  301. slapi_op_get_type(Slapi_Operation *op)
  302. {
  303. return op->o_params.operation_type;
  304. }
  305. char *
  306. slapi_op_type_to_string(unsigned long type)
  307. {
  308. switch (type)
  309. {
  310. case SLAPI_OPERATION_ADD:
  311. return "add";
  312. case SLAPI_OPERATION_DELETE:
  313. return "delete";
  314. case SLAPI_OPERATION_MODIFY:
  315. return "modify";
  316. case SLAPI_OPERATION_MODRDN:
  317. return "modrdn";
  318. case SLAPI_OPERATION_BIND:
  319. return "bind";
  320. case SLAPI_OPERATION_COMPARE:
  321. return "compare";
  322. case SLAPI_OPERATION_SEARCH:
  323. return "search";
  324. default:
  325. return "unknown operation type";
  326. }
  327. }
  328. /* DEPRECATED : USE FUNCTION ABOVE FOR NEW DVLPT */
  329. unsigned long
  330. operation_get_type(Slapi_Operation *op)
  331. {
  332. return op->o_params.operation_type;
  333. }
  334. void
  335. operation_set_type(Slapi_Operation *op, unsigned long type)
  336. {
  337. op->o_params.operation_type= type;
  338. }
  339. void
  340. operation_set_flag(Slapi_Operation *op, int flag)
  341. {
  342. op->o_flags|= flag;
  343. }
  344. void
  345. operation_clear_flag(Slapi_Operation *op, int flag)
  346. {
  347. op->o_flags &= ~flag;
  348. }
  349. int
  350. operation_is_flag_set(Slapi_Operation *op, int flag)
  351. {
  352. return op->o_flags & flag;
  353. }
  354. Slapi_DN*
  355. operation_get_target_spec (Slapi_Operation *op)
  356. {
  357. return op->o_target_spec;
  358. }
  359. void
  360. operation_set_target_spec (Slapi_Operation *op, const Slapi_DN *target_spec)
  361. {
  362. PR_ASSERT (op);
  363. PR_ASSERT (target_spec);
  364. op->o_target_spec = slapi_sdn_dup(target_spec);
  365. }
  366. void
  367. operation_set_target_spec_str (Slapi_Operation *op, const char *target_spec)
  368. {
  369. PR_ASSERT (op);
  370. op->o_target_spec = slapi_sdn_new_dn_byval (target_spec);
  371. }
  372. unsigned long operation_get_abandoned_op (const Slapi_Operation *op)
  373. {
  374. PR_ASSERT (op);
  375. return op->o_abandoned_op;
  376. }
  377. void operation_set_abandoned_op (Slapi_Operation *op, unsigned long abandoned_op)
  378. {
  379. PR_ASSERT (op);
  380. op->o_abandoned_op = abandoned_op;
  381. }
  382. /* slapi_operation_parameters manipulation functions */
  383. struct slapi_operation_parameters *operation_parameters_new()
  384. {
  385. return (slapi_operation_parameters *)slapi_ch_calloc (1, sizeof (slapi_operation_parameters));
  386. }
  387. ber_tag_t
  388. slapi_operation_get_tag(Slapi_Operation *op)
  389. {
  390. return op->o_tag;
  391. }
  392. ber_int_t
  393. slapi_operation_get_msgid(Slapi_Operation *op)
  394. {
  395. return op->o_msgid;
  396. }
  397. void
  398. slapi_operation_set_tag(Slapi_Operation *op, ber_tag_t tag)
  399. {
  400. op->o_tag = tag;
  401. }
  402. void
  403. slapi_operation_set_msgid(Slapi_Operation *op, ber_int_t msgid)
  404. {
  405. op->o_msgid = msgid;
  406. }
  407. LDAPMod **
  408. copy_mods(LDAPMod **orig_mods)
  409. {
  410. LDAPMod **new_mods = NULL;
  411. LDAPMod *mod;
  412. Slapi_Mods smods_old;
  413. Slapi_Mods smods_new;
  414. slapi_mods_init_byref(&smods_old,orig_mods);
  415. slapi_mods_init_passin(&smods_new,new_mods);
  416. mod= slapi_mods_get_first_mod(&smods_old);
  417. while(mod!=NULL)
  418. {
  419. slapi_mods_add_modbvps(&smods_new,mod->mod_op,mod->mod_type,mod->mod_bvalues);
  420. mod= slapi_mods_get_next_mod(&smods_old);
  421. }
  422. new_mods= slapi_mods_get_ldapmods_passout(&smods_new);
  423. slapi_mods_done(&smods_old);
  424. slapi_mods_done(&smods_new);
  425. return new_mods;
  426. }
  427. struct slapi_operation_parameters *
  428. operation_parameters_dup(struct slapi_operation_parameters *sop)
  429. {
  430. struct slapi_operation_parameters *sop_new = (struct slapi_operation_parameters *)
  431. slapi_ch_malloc(sizeof(struct slapi_operation_parameters));
  432. memcpy(sop_new,sop,sizeof(struct slapi_operation_parameters));
  433. if(sop->target_address.uniqueid!=NULL)
  434. {
  435. sop_new->target_address.uniqueid= slapi_ch_strdup(sop->target_address.uniqueid);
  436. }
  437. if(sop->target_address.sdn != NULL)
  438. {
  439. sop_new->target_address.sdn = slapi_sdn_dup(sop->target_address.sdn);
  440. }
  441. sop_new->csn= csn_dup(sop->csn);
  442. switch(sop->operation_type)
  443. {
  444. case SLAPI_OPERATION_ADD:
  445. sop_new->p.p_add.target_entry= slapi_entry_dup(sop->p.p_add.target_entry);
  446. sop_new->p.p_add.parentuniqueid = slapi_ch_strdup(sop->p.p_add.parentuniqueid);
  447. break;
  448. case SLAPI_OPERATION_MODIFY:
  449. sop_new->p.p_modify.modify_mods= NULL;
  450. if (sop->p.p_modify.modify_mods!=NULL)
  451. {
  452. sop_new->p.p_modify.modify_mods = copy_mods(sop->p.p_modify.modify_mods);
  453. }
  454. break;
  455. case SLAPI_OPERATION_MODRDN:
  456. if(sop->p.p_modrdn.modrdn_newrdn!=NULL)
  457. {
  458. sop_new->p.p_modrdn.modrdn_newrdn= slapi_ch_strdup(sop->p.p_modrdn.modrdn_newrdn);
  459. }
  460. if(sop->p.p_modrdn.modrdn_newsuperior_address.sdn!=NULL)
  461. {
  462. sop_new->p.p_modrdn.modrdn_newsuperior_address.sdn =
  463. slapi_sdn_dup(sop->p.p_modrdn.modrdn_newsuperior_address.sdn);
  464. }
  465. if(sop->p.p_modrdn.modrdn_newsuperior_address.uniqueid!=NULL)
  466. {
  467. sop_new->p.p_modrdn.modrdn_newsuperior_address.uniqueid =
  468. slapi_ch_strdup(sop->p.p_modrdn.modrdn_newsuperior_address.uniqueid);
  469. }
  470. sop_new->p.p_modrdn.modrdn_mods= NULL;
  471. if (sop->p.p_modrdn.modrdn_mods!=NULL)
  472. {
  473. sop_new->p.p_modrdn.modrdn_mods = copy_mods(sop->p.p_modrdn.modrdn_mods);
  474. }
  475. break;
  476. case SLAPI_OPERATION_DELETE:
  477. /* Has no extra parameters. */
  478. case SLAPI_OPERATION_BIND:
  479. case SLAPI_OPERATION_COMPARE:
  480. case SLAPI_OPERATION_SEARCH:
  481. default:
  482. /* We are not interested in these. */
  483. break;
  484. }
  485. return sop_new;
  486. }
  487. void
  488. operation_parameters_done (struct slapi_operation_parameters *sop)
  489. {
  490. if(sop!=NULL)
  491. {
  492. slapi_ch_free((void **)&sop->target_address.uniqueid);
  493. slapi_sdn_free(&sop->target_address.sdn);
  494. csn_free(&sop->csn);
  495. switch(sop->operation_type)
  496. {
  497. case SLAPI_OPERATION_ADD:
  498. slapi_entry_free(sop->p.p_add.target_entry);
  499. sop->p.p_add.target_entry= NULL;
  500. slapi_ch_free((void **)&(sop->p.p_add.parentuniqueid));
  501. break;
  502. case SLAPI_OPERATION_MODIFY:
  503. ldap_mods_free(sop->p.p_modify.modify_mods, 1 /* Free the Array and the Elements */);
  504. sop->p.p_modify.modify_mods= NULL;
  505. break;
  506. case SLAPI_OPERATION_MODRDN:
  507. slapi_ch_free((void **)&(sop->p.p_modrdn.modrdn_newrdn));
  508. slapi_ch_free((void **)&(sop->p.p_modrdn.modrdn_newsuperior_address.uniqueid));
  509. slapi_sdn_free(&sop->p.p_modrdn.modrdn_newsuperior_address.sdn);
  510. ldap_mods_free(sop->p.p_modrdn.modrdn_mods, 1 /* Free the Array and the Elements */);
  511. sop->p.p_modrdn.modrdn_mods= NULL;
  512. break;
  513. case SLAPI_OPERATION_DELETE:
  514. /* Has no extra parameters. */
  515. case SLAPI_OPERATION_BIND:
  516. case SLAPI_OPERATION_COMPARE:
  517. case SLAPI_OPERATION_SEARCH:
  518. default:
  519. /* We are not interested in these */
  520. break;
  521. }
  522. }
  523. }
  524. void operation_parameters_free(struct slapi_operation_parameters **sop)
  525. {
  526. if (sop)
  527. {
  528. operation_parameters_done (*sop);
  529. slapi_ch_free ((void**)sop);
  530. }
  531. }
  532. int slapi_connection_acquire(Slapi_Connection *conn)
  533. {
  534. int rc;
  535. PR_Lock(conn->c_mutex);
  536. /* rc = connection_acquire_nolock(conn); */
  537. /* connection in the closing state can't be acquired */
  538. if (conn->c_flags & CONN_FLAG_CLOSING)
  539. {
  540. /* This may happen while other threads are still working on this connection */
  541. slapi_log_error(SLAPI_LOG_FATAL, "connection",
  542. "conn=%" NSPRIu64 " fd=%d Attempt to acquire connection in the closing state\n",
  543. (long long unsigned int)conn->c_connid, conn->c_sd);
  544. rc = -1;
  545. }
  546. else
  547. {
  548. conn->c_refcnt++;
  549. rc = 0;
  550. }
  551. PR_Unlock(conn->c_mutex);
  552. return(rc);
  553. }
  554. int
  555. slapi_connection_remove_operation( Slapi_PBlock *pb, Slapi_Connection *conn, Slapi_Operation *op, int release)
  556. {
  557. int rc = 0;
  558. Slapi_Operation **olist= &conn->c_ops;
  559. Slapi_Operation **tmp;
  560. PR_Lock( conn->c_mutex );
  561. /* connection_remove_operation_ext(pb, conn,op); */
  562. for ( tmp = olist; *tmp != NULL && *tmp != op; tmp = &(*tmp)->o_next )
  563. ; /* NULL */
  564. if ( *tmp == NULL ) {
  565. LDAPDebug( LDAP_DEBUG_ANY, "connection_remove_operation: can't find op %d for conn %" NSPRIu64 "\n",
  566. (int)op->o_msgid, conn->c_connid, 0 );
  567. } else {
  568. *tmp = (*tmp)->o_next;
  569. }
  570. if (release) {
  571. /* connection_release_nolock(conn); */
  572. if (conn->c_refcnt <= 0) {
  573. slapi_log_error(SLAPI_LOG_FATAL, "connection",
  574. "conn=%" NSPRIu64 " fd=%d Attempt to release connection that is not acquired\n",
  575. (long long unsigned int)conn->c_connid, conn->c_sd);
  576. rc = -1;
  577. } else {
  578. conn->c_refcnt--;
  579. rc = 0;
  580. }
  581. }
  582. PR_Unlock( conn->c_mutex );
  583. return (rc);
  584. }