repl5_protocol_util.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615
  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. /* Check if this is a fractional agreement, we need to
  184. * verify that the consumer is read-only */
  185. if (agmt_is_fractional(prp->agmt)) {
  186. crc = conn_replica_is_readonly(conn);
  187. if (CONN_IS_NOT_READONLY == crc) {
  188. /* This is a fatal error */
  189. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  190. "%s: Unable to acquire replica: "
  191. "the agreement is fractional but the replica is not read-only. Fractional agreements must specify a read-only replica "
  192. "Replication is aborting.\n",
  193. agmt_get_long_name(prp->agmt));
  194. return_value = ACQUIRE_FATAL_ERROR;
  195. goto error;
  196. }
  197. }
  198. /* Good to go. Start the protocol. */
  199. /* Obtain a current CSN */
  200. replarea_sdn = agmt_get_replarea(prp->agmt);
  201. current_csn = get_current_csn(replarea_sdn);
  202. if (NULL != current_csn)
  203. {
  204. struct berval *payload = NSDS50StartReplicationRequest_new(
  205. prot_oid, slapi_sdn_get_ndn(replarea_sdn),
  206. NULL /* XXXggood need to provide referral(s) */, current_csn);
  207. /* JCMREPL - Need to extract the referrals from the RUV */
  208. csn_free(&current_csn);
  209. current_csn = NULL;
  210. crc = conn_send_extended_operation(conn,
  211. REPL_START_NSDS50_REPLICATION_REQUEST_OID, payload, NULL /* update control */, NULL /* Message ID */);
  212. if (CONN_OPERATION_SUCCESS != crc)
  213. {
  214. int operation, error;
  215. conn_get_error(conn, &operation, &error);
  216. /* Couldn't send the extended operation */
  217. return_value = ACQUIRE_TRANSIENT_ERROR; /* XXX right return value? */
  218. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  219. "%s: Unable to send a startReplication "
  220. "extended operation to consumer (%s). Will retry later.\n",
  221. agmt_get_long_name(prp->agmt),
  222. error ? ldap_err2string(error) : "unknown error");
  223. }
  224. /* Since the operation request is async, we need to wait for the response here */
  225. crc = conn_read_result_ex(conn,&retoid,&retdata,NULL,NULL,1);
  226. ber_bvfree(payload);
  227. payload = NULL;
  228. /* Look at the response we got. */
  229. if (CONN_OPERATION_SUCCESS == crc)
  230. {
  231. /*
  232. * Extop was processed. Look at extop response to see if we're
  233. * permitted to go ahead.
  234. */
  235. struct berval **ruv_bervals = NULL;
  236. int extop_result;
  237. int extop_rc = decode_repl_ext_response(retdata, &extop_result,
  238. &ruv_bervals);
  239. if (0 == extop_rc)
  240. {
  241. prp->last_acquire_response_code = extop_result;
  242. switch (extop_result)
  243. {
  244. /* XXXggood handle other error codes here */
  245. case NSDS50_REPL_INTERNAL_ERROR:
  246. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  247. "%s: Unable to acquire replica: "
  248. "an internal error occurred on the remote replica. "
  249. "Replication is aborting.\n",
  250. agmt_get_long_name(prp->agmt));
  251. return_value = ACQUIRE_FATAL_ERROR;
  252. break;
  253. case NSDS50_REPL_PERMISSION_DENIED:
  254. /* Not allowed to send updates */
  255. {
  256. char *repl_binddn = agmt_get_binddn(prp->agmt);
  257. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  258. "%s: Unable to acquire replica: permission denied. "
  259. "The bind dn \"%s\" does not have permission to "
  260. "supply replication updates to the replica. "
  261. "Will retry later.\n",
  262. agmt_get_long_name(prp->agmt), repl_binddn);
  263. slapi_ch_free((void **)&repl_binddn);
  264. return_value = ACQUIRE_TRANSIENT_ERROR;
  265. break;
  266. }
  267. case NSDS50_REPL_NO_SUCH_REPLICA:
  268. /* There is no such replica on the consumer */
  269. {
  270. Slapi_DN *repl_root = agmt_get_replarea(prp->agmt);
  271. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  272. "%s: Unable to acquire replica: there is no "
  273. "replicated area \"%s\" on the consumer server. "
  274. "Replication is aborting.\n",
  275. agmt_get_long_name(prp->agmt),
  276. slapi_sdn_get_dn(repl_root));
  277. slapi_sdn_free(&repl_root);
  278. return_value = ACQUIRE_FATAL_ERROR;
  279. break;
  280. }
  281. case NSDS50_REPL_EXCESSIVE_CLOCK_SKEW:
  282. /* Large clock skew between the consumer and the supplier */
  283. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  284. "%s: Unable to acquire replica: "
  285. "Excessive clock skew between the supplier and "
  286. "the consumer. Replication is aborting.\n",
  287. agmt_get_long_name(prp->agmt));
  288. return_value = ACQUIRE_FATAL_ERROR;
  289. break;
  290. case NSDS50_REPL_DECODING_ERROR:
  291. /* We sent something the replica couldn't understand. */
  292. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  293. "%s: Unable to acquire replica: "
  294. "the consumer was unable to decode the "
  295. "startReplicationRequest extended operation sent by the "
  296. "supplier. Replication is aborting.\n",
  297. agmt_get_long_name(prp->agmt));
  298. return_value = ACQUIRE_FATAL_ERROR;
  299. break;
  300. case NSDS50_REPL_REPLICA_BUSY:
  301. /* Someone else is updating the replica. Try later. */
  302. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
  303. "%s: Unable to acquire replica: "
  304. "the replica is currently being updated"
  305. "by another supplier. Will try later\n",
  306. agmt_get_long_name(prp->agmt));
  307. return_value = ACQUIRE_REPLICA_BUSY;
  308. break;
  309. case NSDS50_REPL_LEGACY_CONSUMER:
  310. /* remote replica is a legacy consumer */
  311. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  312. "%s: Unable to acquire replica: the replica "
  313. "is supplied by a legacy supplier. "
  314. "Replication is aborting.\n", agmt_get_long_name(prp->agmt));
  315. return_value = ACQUIRE_FATAL_ERROR;
  316. break;
  317. case NSDS50_REPL_REPLICAID_ERROR:
  318. /* remote replica detected a duplicate ReplicaID */
  319. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  320. "%s: Unable to aquire replica: the replica "
  321. "has the same Replica ID as this one. "
  322. "Replication is aborting.\n",
  323. agmt_get_long_name(prp->agmt));
  324. return_value = ACQUIRE_FATAL_ERROR;
  325. break;
  326. case NSDS50_REPL_REPLICA_READY:
  327. /* We've acquired the replica. */
  328. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
  329. "%s: Replica was successfully acquired.\n",
  330. agmt_get_long_name(prp->agmt));
  331. /* Parse the update vector */
  332. if (NULL != ruv_bervals && NULL != ruv)
  333. {
  334. if (ruv_init_from_bervals(ruv_bervals, ruv) != RUV_SUCCESS)
  335. {
  336. /* Couldn't parse the update vector */
  337. *ruv = NULL;
  338. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  339. "%s: Warning: acquired replica, "
  340. "but could not parse update vector. "
  341. "The replica must be reinitialized.\n",
  342. agmt_get_long_name(prp->agmt));
  343. }
  344. }
  345. /* Save consumer's RUV in the replication agreement.
  346. It is used by the changelog trimming code */
  347. if (ruv && *ruv)
  348. agmt_set_consumer_ruv (prp->agmt, *ruv);
  349. return_value = ACQUIRE_SUCCESS;
  350. break;
  351. default:
  352. return_value = ACQUIRE_FATAL_ERROR;
  353. }
  354. }
  355. else
  356. {
  357. /* Couldn't parse the response */
  358. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  359. "%s: Unable to parse the response to the "
  360. "startReplication extended operation. "
  361. "Replication is aborting.\n",
  362. agmt_get_long_name(prp->agmt));
  363. prp->last_acquire_response_code = NSDS50_REPL_INTERNAL_ERROR;
  364. return_value = ACQUIRE_FATAL_ERROR;
  365. }
  366. if (NULL != ruv_bervals)
  367. ber_bvecfree(ruv_bervals);
  368. }
  369. else
  370. {
  371. int operation, error;
  372. conn_get_error(conn, &operation, &error);
  373. /* Couldn't send the extended operation */
  374. return_value = ACQUIRE_TRANSIENT_ERROR; /* XXX right return value? */
  375. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  376. "%s: Unable to receive the response for a startReplication "
  377. "extended operation to consumer (%s). Will retry later.\n",
  378. agmt_get_long_name(prp->agmt),
  379. error ? ldap_err2string(error) : "unknown error");
  380. }
  381. }
  382. else
  383. {
  384. /* Couldn't get a current CSN */
  385. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  386. "%s: Unable to obtain current CSN. "
  387. "Replication is aborting.\n",
  388. agmt_get_long_name(prp->agmt));
  389. return_value = ACQUIRE_FATAL_ERROR;
  390. }
  391. slapi_sdn_free(&replarea_sdn);
  392. if (NULL != retoid)
  393. ldap_memfree(retoid);
  394. if (NULL != retdata)
  395. ber_bvfree(retdata);
  396. }
  397. }
  398. }
  399. error:
  400. if (ACQUIRE_SUCCESS != return_value)
  401. {
  402. /* could not acquire the replica, so reinstate the linger timer, since this
  403. means we won't call release_replica, which also reinstates the timer */
  404. conn_start_linger(conn);
  405. }
  406. else
  407. {
  408. /* replica successfully acquired */
  409. prp->replica_acquired = PR_TRUE;
  410. }
  411. return return_value;
  412. }
  413. /*
  414. * Release a replica by sending an "end replication" extended request.
  415. */
  416. void
  417. release_replica(Private_Repl_Protocol *prp)
  418. {
  419. int rc;
  420. struct berval *retdata = NULL;
  421. char *retoid = NULL;
  422. struct berval *payload = NULL;
  423. Slapi_DN *replarea_sdn = NULL;
  424. int sent_message_id = 0;
  425. int ret_message_id = 0;
  426. ConnResult conres = 0;
  427. PR_ASSERT(NULL != prp);
  428. PR_ASSERT(NULL != prp->conn);
  429. if (!prp->replica_acquired)
  430. return;
  431. replarea_sdn = agmt_get_replarea(prp->agmt);
  432. payload = NSDS50EndReplicationRequest_new((char *)slapi_sdn_get_dn(replarea_sdn)); /* XXXggood had to cast away const */
  433. slapi_sdn_free(&replarea_sdn);
  434. rc = conn_send_extended_operation(prp->conn,
  435. REPL_END_NSDS50_REPLICATION_REQUEST_OID, payload, NULL /* update control */, &sent_message_id /* Message ID */);
  436. if (0 != rc)
  437. {
  438. int operation, error;
  439. conn_get_error(prp->conn, &operation, &error);
  440. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  441. "%s: Warning: unable to send endReplication extended operation (%s)\n",
  442. agmt_get_long_name(prp->agmt),
  443. error ? ldap_err2string(error) : "unknown error");
  444. goto error;
  445. }
  446. /* Since the operation request is async, we need to wait for the response here */
  447. conres = conn_read_result_ex(prp->conn,&retoid,&retdata,NULL,&ret_message_id,1);
  448. if (CONN_OPERATION_SUCCESS != conres)
  449. {
  450. int operation, error;
  451. conn_get_error(prp->conn, &operation, &error);
  452. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  453. "%s: Warning: unable to receive endReplication extended operation response (%s)\n",
  454. agmt_get_long_name(prp->agmt),
  455. error ? ldap_err2string(error) : "unknown error");
  456. }
  457. else
  458. {
  459. struct berval **ruv_bervals = NULL; /* Shouldn't actually be returned */
  460. int extop_result;
  461. int extop_rc = 0;
  462. /* Check the message id's match */
  463. if (sent_message_id != sent_message_id)
  464. {
  465. int operation, error;
  466. conn_get_error(prp->conn, &operation, &error);
  467. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  468. "%s: Warning: response message id does not match the request (%s)\n",
  469. agmt_get_long_name(prp->agmt),
  470. error ? ldap_err2string(error) : "unknown error");
  471. }
  472. extop_rc = decode_repl_ext_response(retdata, &extop_result,
  473. (struct berval ***)&ruv_bervals);
  474. if (0 == extop_rc)
  475. {
  476. if (NSDS50_REPL_REPLICA_RELEASE_SUCCEEDED == extop_result)
  477. {
  478. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
  479. "%s: Successfully released consumer\n", agmt_get_long_name(prp->agmt));
  480. }
  481. else
  482. {
  483. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  484. "%s: Unable to release consumer: response code %d\n",
  485. agmt_get_long_name(prp->agmt), extop_result);
  486. /* disconnect from the consumer so that it does not stay locked */
  487. conn_disconnect (prp->conn);
  488. }
  489. }
  490. else
  491. {
  492. /* Couldn't parse the response */
  493. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  494. "%s: Warning: Unable to parse the response "
  495. " to the endReplication extended operation.\n",
  496. agmt_get_long_name(prp->agmt));
  497. }
  498. if (NULL != ruv_bervals)
  499. ber_bvecfree(ruv_bervals);
  500. /* XXXggood free ruv_bervals if we got them for some reason */
  501. }
  502. if (NULL != payload)
  503. ber_bvfree(payload);
  504. if (NULL != retoid)
  505. ldap_memfree(retoid);
  506. if (NULL != retdata)
  507. ber_bvfree(retdata);
  508. /* replica is released, start the linger timer on the connection, which
  509. was stopped in acquire_replica */
  510. conn_start_linger(prp->conn);
  511. error:
  512. prp->replica_acquired = PR_FALSE;
  513. }
  514. /* converts consumer's response to a string */
  515. char *
  516. protocol_response2string (int response)
  517. {
  518. switch (response)
  519. {
  520. case NSDS50_REPL_REPLICA_READY: return "replica acquired";
  521. case NSDS50_REPL_REPLICA_BUSY: return "replica busy";
  522. case NSDS50_REPL_EXCESSIVE_CLOCK_SKEW: return "excessive clock skew";
  523. case NSDS50_REPL_PERMISSION_DENIED: return "permission denied";
  524. case NSDS50_REPL_DECODING_ERROR: return "decoding error";
  525. case NSDS50_REPL_UNKNOWN_UPDATE_PROTOCOL: return "unknown update protocol";
  526. case NSDS50_REPL_NO_SUCH_REPLICA: return "no such replica";
  527. case NSDS50_REPL_BELOW_PURGEPOINT: return "csn below purge point";
  528. case NSDS50_REPL_INTERNAL_ERROR: return "internal error";
  529. case NSDS50_REPL_REPLICA_RELEASE_SUCCEEDED: return "replica released";
  530. case NSDS50_REPL_LEGACY_CONSUMER: return "replica is a legacy consumer";
  531. case NSDS50_REPL_REPLICAID_ERROR: return "duplicate replica ID detected";
  532. case NSDS50_REPL_UPTODATE: return "no change to send";
  533. default: return "unknown error";
  534. }
  535. }
  536. int
  537. repl5_strip_fractional_mods(Repl_Agmt *agmt, LDAPMod ** mods)
  538. {
  539. int retval = 0;
  540. int i = 0;
  541. char **a = agmt_get_fractional_attrs(agmt);
  542. if (a) {
  543. /* Iterate through the fractional attr list */
  544. for ( i = 0; a[i] != NULL; i++ )
  545. {
  546. char *this_excluded_attr = a[i];
  547. int j = 0;
  548. for ( j = 0; NULL != mods[ j ]; )
  549. {
  550. /* For each one iterate through the attrs in this mod list */
  551. /* For any that match, remove the mod */
  552. LDAPMod *this_mod = mods[j];
  553. if (0 == slapi_attr_type_cmp(this_mod->mod_type,this_excluded_attr,SLAPI_TYPE_CMP_SUBTYPE))
  554. {
  555. /* Move down all subsequent mods */
  556. int k = 0;
  557. for (k = j; mods[k+1] ; k++)
  558. {
  559. mods[k] = mods[k+1];
  560. }
  561. /* Zero the end of the array */
  562. mods[k] = NULL;
  563. /* Adjust value of j, implicit in not incrementing it */
  564. /* Free this mod */
  565. ber_bvecfree(this_mod->mod_bvalues);
  566. slapi_ch_free((void **)&(this_mod->mod_type));
  567. slapi_ch_free((void **)&this_mod);
  568. } else {
  569. j++;
  570. }
  571. }
  572. }
  573. slapi_ch_array_free(a);
  574. }
  575. return retval;
  576. }