repl5_protocol_util.c 22 KB

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