repl5_protocol_util.c 23 KB

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