repl5_protocol_util.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620
  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. /* repl5_protocol_util.c */
  39. /*
  40. Code common to both incremental and total protocols.
  41. */
  42. #include "repl5.h"
  43. #include "repl5_prot_private.h"
  44. /*
  45. * Obtain a current CSN (e.g. one that would have been
  46. * generated for an operation occurring at this time)
  47. * for a given replica.
  48. */
  49. CSN *
  50. get_current_csn(Slapi_DN *replarea_sdn)
  51. {
  52. Object *replica_obj;
  53. Replica *replica;
  54. Object *gen_obj;
  55. CSNGen *gen;
  56. CSN *current_csn = NULL;
  57. if (NULL != replarea_sdn)
  58. {
  59. replica_obj = replica_get_replica_from_dn(replarea_sdn);
  60. if (NULL != replica_obj)
  61. {
  62. replica = object_get_data(replica_obj);
  63. if (NULL != replica)
  64. {
  65. gen_obj = replica_get_csngen(replica);
  66. if (NULL != gen_obj)
  67. {
  68. gen = (CSNGen *)object_get_data(gen_obj);
  69. if (NULL != gen)
  70. {
  71. if (csngen_new_csn(gen, &current_csn,
  72. PR_FALSE /* notify */) != CSN_SUCCESS)
  73. {
  74. current_csn = NULL;
  75. }
  76. object_release(gen_obj);
  77. }
  78. }
  79. }
  80. }
  81. }
  82. return current_csn;
  83. }
  84. /*
  85. * Acquire exclusive access to a replica. Send a start replication extended
  86. * operation to the replica. The response will contain a success code, and
  87. * optionally the replica's update vector if acquisition is successful.
  88. * This function returns one of the following:
  89. * ACQUIRE_SUCCESS - the replica was acquired, and we have exclusive update access
  90. * ACQUIRE_REPLICA_BUSY - another master was updating the replica
  91. * ACQUIRE_FATAL_ERROR - something bad happened, and it's not likely to improve
  92. * if we wait.
  93. * ACQUIRE_TRANSIENT_ERROR - something bad happened, but it's probably worth
  94. * another try after waiting a while.
  95. * If ACQUIRE_SUCCESS is returned, then ruv will point to the replica's update
  96. * vector. It's possible that the replica does something goofy and doesn't
  97. * return us an update vector, so be prepared for ruv to be NULL (but this is
  98. * an error).
  99. */
  100. int
  101. acquire_replica(Private_Repl_Protocol *prp, char *prot_oid, RUV **ruv)
  102. {
  103. int return_value;
  104. ConnResult crc;
  105. Repl_Connection *conn;
  106. PR_ASSERT(prp && prot_oid);
  107. if (prp->replica_acquired) /* we already acquire replica */
  108. {
  109. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  110. "%s: Remote replica already acquired\n",
  111. agmt_get_long_name(prp->agmt));
  112. return_value = ACQUIRE_FATAL_ERROR;
  113. return ACQUIRE_SUCCESS;
  114. }
  115. if (NULL != ruv)
  116. {
  117. ruv_destroy ( ruv );
  118. }
  119. if (strcmp(prot_oid, REPL_NSDS50_INCREMENTAL_PROTOCOL_OID) == 0)
  120. {
  121. Replica *replica;
  122. Object *supl_ruv_obj, *cons_ruv_obj;
  123. PRBool is_newer = PR_FALSE;
  124. object_acquire(prp->replica_object);
  125. replica = object_get_data(prp->replica_object);
  126. supl_ruv_obj = replica_get_ruv ( replica );
  127. cons_ruv_obj = agmt_get_consumer_ruv ( prp->agmt );
  128. is_newer = ruv_is_newer ( supl_ruv_obj, cons_ruv_obj );
  129. if ( supl_ruv_obj ) object_release ( supl_ruv_obj );
  130. if ( cons_ruv_obj ) object_release ( cons_ruv_obj );
  131. object_release (prp->replica_object);
  132. replica = NULL;
  133. if (is_newer == PR_FALSE) {
  134. prp->last_acquire_response_code = NSDS50_REPL_UPTODATE;
  135. return ACQUIRE_CONSUMER_WAS_UPTODATE;
  136. }
  137. }
  138. prp->last_acquire_response_code = NSDS50_REPL_REPLICA_NO_RESPONSE;
  139. /* Get the connection */
  140. conn = prp->conn;
  141. crc = conn_connect(conn);
  142. if (CONN_OPERATION_FAILED == crc)
  143. {
  144. return_value = ACQUIRE_TRANSIENT_ERROR;
  145. }
  146. else if (CONN_SSL_NOT_ENABLED == crc)
  147. {
  148. return_value = ACQUIRE_FATAL_ERROR;
  149. }
  150. else
  151. {
  152. /* we don't want the timer to go off in the middle of an operation */
  153. conn_cancel_linger(conn);
  154. /* Does the remote replica support the 5.0 protocol? */
  155. crc = conn_replica_supports_ds5_repl(conn);
  156. if (CONN_DOES_NOT_SUPPORT_DS5_REPL == crc)
  157. {
  158. return_value = ACQUIRE_FATAL_ERROR;
  159. }
  160. else if (CONN_NOT_CONNECTED == crc || CONN_OPERATION_FAILED == crc)
  161. {
  162. /* We don't know anything about the remote replica. Try again later. */
  163. return_value = ACQUIRE_TRANSIENT_ERROR;
  164. }
  165. else
  166. {
  167. /* Does the remote replica support the 7.1 protocol? */
  168. crc = conn_replica_supports_ds71_repl(conn);
  169. if (CONN_DOES_NOT_SUPPORT_DS71_REPL == crc)
  170. {
  171. prp->repl50consumer = 1;
  172. }
  173. if (CONN_NOT_CONNECTED == crc || CONN_OPERATION_FAILED == crc)
  174. {
  175. /* We don't know anything about the remote replica. Try again later. */
  176. return_value = ACQUIRE_TRANSIENT_ERROR;
  177. } else
  178. {
  179. CSN *current_csn = NULL;
  180. struct berval *retdata = NULL;
  181. char *retoid = NULL;
  182. Slapi_DN *replarea_sdn;
  183. /* Good to go. Start the protocol. */
  184. /* Obtain a current CSN */
  185. replarea_sdn = agmt_get_replarea(prp->agmt);
  186. current_csn = get_current_csn(replarea_sdn);
  187. if (NULL != current_csn)
  188. {
  189. struct berval *payload = NSDS50StartReplicationRequest_new(
  190. prot_oid, slapi_sdn_get_ndn(replarea_sdn),
  191. NULL /* XXXggood need to provide referral(s) */, current_csn);
  192. /* JCMREPL - Need to extract the referrals from the RUV */
  193. csn_free(&current_csn);
  194. current_csn = NULL;
  195. crc = conn_send_extended_operation(conn,
  196. REPL_START_NSDS50_REPLICATION_REQUEST_OID, payload, NULL /* update control */, NULL /* Message ID */);
  197. if (CONN_OPERATION_SUCCESS != crc)
  198. {
  199. int operation, error;
  200. conn_get_error(conn, &operation, &error);
  201. /* Couldn't send the extended operation */
  202. return_value = ACQUIRE_TRANSIENT_ERROR; /* XXX right return value? */
  203. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  204. "%s: Unable to send a startReplication "
  205. "extended operation to consumer (%s). Will retry later.\n",
  206. agmt_get_long_name(prp->agmt),
  207. error ? ldap_err2string(error) : "unknown error");
  208. }
  209. /* Since the operation request is async, we need to wait for the response here */
  210. crc = conn_read_result_ex(conn,&retoid,&retdata,NULL,NULL,1);
  211. ber_bvfree(payload);
  212. payload = NULL;
  213. /* Look at the response we got. */
  214. if (CONN_OPERATION_SUCCESS == crc)
  215. {
  216. /*
  217. * Extop was processed. Look at extop response to see if we're
  218. * permitted to go ahead.
  219. */
  220. struct berval **ruv_bervals = NULL;
  221. int extop_result;
  222. int extop_rc = decode_repl_ext_response(retdata, &extop_result,
  223. &ruv_bervals);
  224. if (0 == extop_rc)
  225. {
  226. prp->last_acquire_response_code = extop_result;
  227. switch (extop_result)
  228. {
  229. /* XXXggood handle other error codes here */
  230. case NSDS50_REPL_INTERNAL_ERROR:
  231. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  232. "%s: Unable to acquire replica: "
  233. "an internal error occurred on the remote replica. "
  234. "Replication is aborting.\n",
  235. agmt_get_long_name(prp->agmt));
  236. return_value = ACQUIRE_FATAL_ERROR;
  237. break;
  238. case NSDS50_REPL_PERMISSION_DENIED:
  239. /* Not allowed to send updates */
  240. {
  241. char *repl_binddn = agmt_get_binddn(prp->agmt);
  242. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  243. "%s: Unable to acquire replica: permission denied. "
  244. "The bind dn \"%s\" does not have permission to "
  245. "supply replication updates to the replica. "
  246. "Will retry later.\n",
  247. agmt_get_long_name(prp->agmt), repl_binddn);
  248. slapi_ch_free((void **)&repl_binddn);
  249. return_value = ACQUIRE_TRANSIENT_ERROR;
  250. break;
  251. }
  252. case NSDS50_REPL_NO_SUCH_REPLICA:
  253. /* There is no such replica on the consumer */
  254. {
  255. Slapi_DN *repl_root = agmt_get_replarea(prp->agmt);
  256. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  257. "%s: Unable to acquire replica: there is no "
  258. "replicated area \"%s\" on the consumer server. "
  259. "Replication is aborting.\n",
  260. agmt_get_long_name(prp->agmt),
  261. slapi_sdn_get_dn(repl_root));
  262. slapi_sdn_free(&repl_root);
  263. return_value = ACQUIRE_FATAL_ERROR;
  264. break;
  265. }
  266. case NSDS50_REPL_EXCESSIVE_CLOCK_SKEW:
  267. /* Large clock skew between the consumer and the supplier */
  268. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  269. "%s: Unable to acquire replica: "
  270. "Excessive clock skew between the supplier and "
  271. "the consumer. Replication is aborting.\n",
  272. agmt_get_long_name(prp->agmt));
  273. return_value = ACQUIRE_FATAL_ERROR;
  274. break;
  275. case NSDS50_REPL_DECODING_ERROR:
  276. /* We sent something the replica couldn't understand. */
  277. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  278. "%s: Unable to acquire replica: "
  279. "the consumer was unable to decode the "
  280. "startReplicationRequest extended operation sent by the "
  281. "supplier. Replication is aborting.\n",
  282. agmt_get_long_name(prp->agmt));
  283. return_value = ACQUIRE_FATAL_ERROR;
  284. break;
  285. case NSDS50_REPL_REPLICA_BUSY:
  286. /* Someone else is updating the replica. Try later. */
  287. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
  288. "%s: Unable to acquire replica: "
  289. "the replica is currently being updated"
  290. "by another supplier. Will try later\n",
  291. agmt_get_long_name(prp->agmt));
  292. return_value = ACQUIRE_REPLICA_BUSY;
  293. break;
  294. case NSDS50_REPL_LEGACY_CONSUMER:
  295. /* remote replica is a legacy consumer */
  296. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  297. "%s: Unable to acquire replica: the replica "
  298. "is supplied by a legacy supplier. "
  299. "Replication is aborting.\n", agmt_get_long_name(prp->agmt));
  300. return_value = ACQUIRE_FATAL_ERROR;
  301. break;
  302. case NSDS50_REPL_REPLICAID_ERROR:
  303. /* remote replica detected a duplicate ReplicaID */
  304. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  305. "%s: Unable to aquire replica: the replica "
  306. "has the same Replica ID as this one. "
  307. "Replication is aborting.\n",
  308. agmt_get_long_name(prp->agmt));
  309. return_value = ACQUIRE_FATAL_ERROR;
  310. break;
  311. case NSDS50_REPL_REPLICA_READY:
  312. /* We've acquired the replica. */
  313. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
  314. "%s: Replica was successfully acquired.\n",
  315. agmt_get_long_name(prp->agmt));
  316. /* Parse the update vector */
  317. if (NULL != ruv_bervals && NULL != ruv)
  318. {
  319. if (ruv_init_from_bervals(ruv_bervals, ruv) != RUV_SUCCESS)
  320. {
  321. /* Couldn't parse the update vector */
  322. *ruv = NULL;
  323. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  324. "%s: Warning: acquired replica, "
  325. "but could not parse update vector. "
  326. "The replica must be reinitialized.\n",
  327. agmt_get_long_name(prp->agmt));
  328. }
  329. }
  330. /* Save consumer's RUV in the replication agreement.
  331. It is used by the changelog trimming code */
  332. if (ruv && *ruv)
  333. agmt_set_consumer_ruv (prp->agmt, *ruv);
  334. return_value = ACQUIRE_SUCCESS;
  335. break;
  336. default:
  337. return_value = ACQUIRE_FATAL_ERROR;
  338. }
  339. /* Now check for fractional compatibility with the replica
  340. * We need to do the check now because prior to acquiring the
  341. * replica we do not have sufficient access rights to read the replica id
  342. */
  343. /* Check if this is a fractional agreement, we need to
  344. * verify that the consumer is read-only */
  345. if ((return_value == ACQUIRE_SUCCESS) &&
  346. agmt_is_fractional(prp->agmt)) {
  347. crc = conn_replica_is_readonly(conn);
  348. if (CONN_IS_NOT_READONLY == crc) {
  349. /* This is a fatal error */
  350. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  351. "%s: Unable to acquire replica: "
  352. "the agreement is fractional but the replica is not read-only. Fractional agreements must specify a read-only replica "
  353. "Replication is aborting.\n",
  354. agmt_get_long_name(prp->agmt));
  355. prp->last_acquire_response_code = NSDS50_REPL_INTERNAL_ERROR;
  356. return_value = ACQUIRE_FATAL_ERROR;
  357. goto error;
  358. }
  359. }
  360. }
  361. else
  362. {
  363. /* Couldn't parse the response */
  364. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  365. "%s: Unable to parse the response to the "
  366. "startReplication extended operation. "
  367. "Replication is aborting.\n",
  368. agmt_get_long_name(prp->agmt));
  369. prp->last_acquire_response_code = NSDS50_REPL_INTERNAL_ERROR;
  370. return_value = ACQUIRE_FATAL_ERROR;
  371. }
  372. if (NULL != ruv_bervals)
  373. ber_bvecfree(ruv_bervals);
  374. }
  375. else
  376. {
  377. int operation, error;
  378. conn_get_error(conn, &operation, &error);
  379. /* Couldn't send the extended operation */
  380. return_value = ACQUIRE_TRANSIENT_ERROR; /* XXX right return value? */
  381. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  382. "%s: Unable to receive the response for a startReplication "
  383. "extended operation to consumer (%s). Will retry later.\n",
  384. agmt_get_long_name(prp->agmt),
  385. error ? ldap_err2string(error) : "unknown error");
  386. }
  387. }
  388. else
  389. {
  390. /* Couldn't get a current CSN */
  391. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  392. "%s: Unable to obtain current CSN. "
  393. "Replication is aborting.\n",
  394. agmt_get_long_name(prp->agmt));
  395. return_value = ACQUIRE_FATAL_ERROR;
  396. }
  397. slapi_sdn_free(&replarea_sdn);
  398. if (NULL != retoid)
  399. ldap_memfree(retoid);
  400. if (NULL != retdata)
  401. ber_bvfree(retdata);
  402. }
  403. }
  404. }
  405. error:
  406. if (ACQUIRE_SUCCESS != return_value)
  407. {
  408. /* could not acquire the replica, so reinstate the linger timer, since this
  409. means we won't call release_replica, which also reinstates the timer */
  410. conn_start_linger(conn);
  411. }
  412. else
  413. {
  414. /* replica successfully acquired */
  415. prp->replica_acquired = PR_TRUE;
  416. }
  417. return return_value;
  418. }
  419. /*
  420. * Release a replica by sending an "end replication" extended request.
  421. */
  422. void
  423. release_replica(Private_Repl_Protocol *prp)
  424. {
  425. int rc;
  426. struct berval *retdata = NULL;
  427. char *retoid = NULL;
  428. struct berval *payload = NULL;
  429. Slapi_DN *replarea_sdn = NULL;
  430. int sent_message_id = 0;
  431. int ret_message_id = 0;
  432. ConnResult conres = 0;
  433. PR_ASSERT(NULL != prp);
  434. PR_ASSERT(NULL != prp->conn);
  435. if (!prp->replica_acquired)
  436. return;
  437. replarea_sdn = agmt_get_replarea(prp->agmt);
  438. payload = NSDS50EndReplicationRequest_new((char *)slapi_sdn_get_dn(replarea_sdn)); /* XXXggood had to cast away const */
  439. slapi_sdn_free(&replarea_sdn);
  440. rc = conn_send_extended_operation(prp->conn,
  441. REPL_END_NSDS50_REPLICATION_REQUEST_OID, payload, NULL /* update control */, &sent_message_id /* Message ID */);
  442. if (0 != rc)
  443. {
  444. int operation, error;
  445. conn_get_error(prp->conn, &operation, &error);
  446. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  447. "%s: Warning: unable to send endReplication extended operation (%s)\n",
  448. agmt_get_long_name(prp->agmt),
  449. error ? ldap_err2string(error) : "unknown error");
  450. goto error;
  451. }
  452. /* Since the operation request is async, we need to wait for the response here */
  453. conres = conn_read_result_ex(prp->conn,&retoid,&retdata,NULL,&ret_message_id,1);
  454. if (CONN_OPERATION_SUCCESS != conres)
  455. {
  456. int operation, error;
  457. conn_get_error(prp->conn, &operation, &error);
  458. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  459. "%s: Warning: unable to receive endReplication extended operation response (%s)\n",
  460. agmt_get_long_name(prp->agmt),
  461. error ? ldap_err2string(error) : "unknown error");
  462. }
  463. else
  464. {
  465. struct berval **ruv_bervals = NULL; /* Shouldn't actually be returned */
  466. int extop_result;
  467. int extop_rc = 0;
  468. /* Check the message id's match */
  469. if (sent_message_id != sent_message_id)
  470. {
  471. int operation, error;
  472. conn_get_error(prp->conn, &operation, &error);
  473. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  474. "%s: Warning: response message id does not match the request (%s)\n",
  475. agmt_get_long_name(prp->agmt),
  476. error ? ldap_err2string(error) : "unknown error");
  477. }
  478. extop_rc = decode_repl_ext_response(retdata, &extop_result,
  479. (struct berval ***)&ruv_bervals);
  480. if (0 == extop_rc)
  481. {
  482. if (NSDS50_REPL_REPLICA_RELEASE_SUCCEEDED == extop_result)
  483. {
  484. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
  485. "%s: Successfully released consumer\n", agmt_get_long_name(prp->agmt));
  486. }
  487. else
  488. {
  489. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  490. "%s: Unable to release consumer: response code %d\n",
  491. agmt_get_long_name(prp->agmt), extop_result);
  492. /* disconnect from the consumer so that it does not stay locked */
  493. conn_disconnect (prp->conn);
  494. }
  495. }
  496. else
  497. {
  498. /* Couldn't parse the response */
  499. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  500. "%s: Warning: Unable to parse the response "
  501. " to the endReplication extended operation.\n",
  502. agmt_get_long_name(prp->agmt));
  503. }
  504. if (NULL != ruv_bervals)
  505. ber_bvecfree(ruv_bervals);
  506. /* XXXggood free ruv_bervals if we got them for some reason */
  507. }
  508. if (NULL != payload)
  509. ber_bvfree(payload);
  510. if (NULL != retoid)
  511. ldap_memfree(retoid);
  512. if (NULL != retdata)
  513. ber_bvfree(retdata);
  514. /* replica is released, start the linger timer on the connection, which
  515. was stopped in acquire_replica */
  516. conn_start_linger(prp->conn);
  517. error:
  518. prp->replica_acquired = PR_FALSE;
  519. }
  520. /* converts consumer's response to a string */
  521. char *
  522. protocol_response2string (int response)
  523. {
  524. switch (response)
  525. {
  526. case NSDS50_REPL_REPLICA_READY: return "replica acquired";
  527. case NSDS50_REPL_REPLICA_BUSY: return "replica busy";
  528. case NSDS50_REPL_EXCESSIVE_CLOCK_SKEW: return "excessive clock skew";
  529. case NSDS50_REPL_PERMISSION_DENIED: return "permission denied";
  530. case NSDS50_REPL_DECODING_ERROR: return "decoding error";
  531. case NSDS50_REPL_UNKNOWN_UPDATE_PROTOCOL: return "unknown update protocol";
  532. case NSDS50_REPL_NO_SUCH_REPLICA: return "no such replica";
  533. case NSDS50_REPL_BELOW_PURGEPOINT: return "csn below purge point";
  534. case NSDS50_REPL_INTERNAL_ERROR: return "internal error";
  535. case NSDS50_REPL_REPLICA_RELEASE_SUCCEEDED: return "replica released";
  536. case NSDS50_REPL_LEGACY_CONSUMER: return "replica is a legacy consumer";
  537. case NSDS50_REPL_REPLICAID_ERROR: return "duplicate replica ID detected";
  538. case NSDS50_REPL_UPTODATE: return "no change to send";
  539. default: return "unknown error";
  540. }
  541. }
  542. int
  543. repl5_strip_fractional_mods(Repl_Agmt *agmt, LDAPMod ** mods)
  544. {
  545. int retval = 0;
  546. int i = 0;
  547. char **a = agmt_get_fractional_attrs(agmt);
  548. if (a) {
  549. /* Iterate through the fractional attr list */
  550. for ( i = 0; a[i] != NULL; i++ )
  551. {
  552. char *this_excluded_attr = a[i];
  553. int j = 0;
  554. for ( j = 0; NULL != mods[ j ]; )
  555. {
  556. /* For each one iterate through the attrs in this mod list */
  557. /* For any that match, remove the mod */
  558. LDAPMod *this_mod = mods[j];
  559. if (0 == slapi_attr_type_cmp(this_mod->mod_type,this_excluded_attr,SLAPI_TYPE_CMP_SUBTYPE))
  560. {
  561. /* Move down all subsequent mods */
  562. int k = 0;
  563. for (k = j; mods[k+1] ; k++)
  564. {
  565. mods[k] = mods[k+1];
  566. }
  567. /* Zero the end of the array */
  568. mods[k] = NULL;
  569. /* Adjust value of j, implicit in not incrementing it */
  570. /* Free this mod */
  571. ber_bvecfree(this_mod->mod_bvalues);
  572. slapi_ch_free((void **)&(this_mod->mod_type));
  573. slapi_ch_free((void **)&this_mod);
  574. } else {
  575. j++;
  576. }
  577. }
  578. }
  579. slapi_ch_array_free(a);
  580. }
  581. return retval;
  582. }