repl_extop.c 50 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720
  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. #include "slapi-plugin.h"
  42. #include "repl.h"
  43. #include "repl5.h"
  44. #include "repl5_prot_private.h"
  45. #include "cl5_api.h"
  46. /*
  47. * repl_extop.c - there are two types of functions in this file:
  48. * - Code that implements an extended operation plugin.
  49. * The replication DLL arranges for this code to
  50. * be called when a StartNSDS50ReplicationRequest
  51. * or an EndNSDS50ReplicationRequest extended operation
  52. * is received.
  53. * - Code that sends extended operations on an already-
  54. * established client connection.
  55. *
  56. * The requestValue portion of the StartNSDS50ReplicationRequest
  57. * looks like this:
  58. *
  59. * requestValue ::= SEQUENCE {
  60. * replProtocolOID LDAPOID,
  61. * replicatedTree LDAPDN,
  62. supplierRUV OCTET STRING
  63. * referralURLs SET of LDAPURL OPTIONAL
  64. * csn OCTET STRING OPTIONAL
  65. * }
  66. *
  67. */
  68. static int check_replica_id_uniqueness(Replica *replica, RUV *supplier_ruv);
  69. static multimaster_mtnode_extension *replica_config_get_mtnode_by_dn(const char *dn);
  70. static int
  71. encode_ruv (BerElement *ber, const RUV *ruv)
  72. {
  73. int rc = LDAP_SUCCESS;
  74. struct berval **bvals = NULL;
  75. PR_ASSERT (ber);
  76. PR_ASSERT (ruv);
  77. if (ruv_to_bervals(ruv, &bvals) != 0)
  78. {
  79. rc = LDAP_OPERATIONS_ERROR;
  80. goto done;
  81. }
  82. if (ber_printf(ber, "[V]", bvals) == -1)
  83. {
  84. rc = LDAP_ENCODING_ERROR;
  85. goto done;
  86. }
  87. rc = LDAP_SUCCESS;
  88. done:
  89. if (bvals)
  90. ber_bvecfree (bvals);
  91. return rc;
  92. }
  93. /* The data_guid and data parameters should only be set if we
  94. * are talking with a 9.0 replica. */
  95. static struct berval *
  96. create_ReplicationExtopPayload(const char *protocol_oid,
  97. const char *repl_root, char **extra_referrals, CSN *csn,
  98. int send_end, const char *data_guid, const struct berval *data)
  99. {
  100. struct berval *req_data = NULL;
  101. BerElement *tmp_bere = NULL;
  102. int rc = 0;
  103. Object *repl_obj = NULL, *ruv_obj = NULL;
  104. Replica *repl;
  105. RUV *ruv;
  106. Slapi_DN *sdn = NULL;
  107. PR_ASSERT(protocol_oid != NULL || send_end);
  108. PR_ASSERT(repl_root != NULL);
  109. /* Create the request data */
  110. if ((tmp_bere = der_alloc()) == NULL)
  111. {
  112. rc = LDAP_ENCODING_ERROR;
  113. goto loser;
  114. }
  115. if (!send_end)
  116. {
  117. if (ber_printf(tmp_bere, "{ss", protocol_oid, repl_root) == -1)
  118. {
  119. rc = LDAP_ENCODING_ERROR;
  120. goto loser;
  121. }
  122. }
  123. else
  124. {
  125. if (ber_printf(tmp_bere, "{s", repl_root) == -1)
  126. {
  127. rc = LDAP_ENCODING_ERROR;
  128. goto loser;
  129. }
  130. }
  131. sdn = slapi_sdn_new_dn_byref(repl_root);
  132. repl_obj = replica_get_replica_from_dn (sdn);
  133. if (repl_obj == NULL)
  134. {
  135. rc = LDAP_OPERATIONS_ERROR;
  136. goto loser;
  137. }
  138. repl = (Replica*)object_get_data (repl_obj);
  139. PR_ASSERT (repl);
  140. ruv_obj = replica_get_ruv (repl);
  141. if (ruv_obj == NULL)
  142. {
  143. rc = LDAP_OPERATIONS_ERROR;
  144. goto loser;
  145. }
  146. ruv = object_get_data(ruv_obj);
  147. PR_ASSERT(ruv);
  148. /* send supplier's ruv so that consumer can build its own referrals.
  149. In case of total protocol, it is also used as consumer's ruv once
  150. protocol successfully completes */
  151. /* We need to encode and send each time the local ruv in case we have changed it */
  152. rc = encode_ruv (tmp_bere, ruv);
  153. if (rc != 0)
  154. {
  155. goto loser;
  156. }
  157. if (!send_end)
  158. {
  159. char s[CSN_STRSIZE];
  160. ReplicaId rid;
  161. char *local_replica_referral[2] = {0};
  162. char **referrals_to_send = NULL;
  163. /* Add the referral URL(s), if present */
  164. rid = replica_get_rid(repl);
  165. if (!ruv_contains_replica(ruv, rid))
  166. {
  167. /*
  168. * In the event that there is no RUV component for this replica (e.g.
  169. * if the database was just loaded from LDIF and no local CSNs have been
  170. * generated), then we need to explicitly add this server to the list
  171. * of referrals, since it wouldn't have been sent with the RUV.
  172. */
  173. local_replica_referral[0] = (char *)multimaster_get_local_purl(); /* XXXggood had to cast away const */
  174. }
  175. charray_merge(&referrals_to_send, extra_referrals, 0);
  176. charray_merge(&referrals_to_send, local_replica_referral, 0);
  177. if (NULL != referrals_to_send)
  178. {
  179. if (ber_printf(tmp_bere, "[v]", referrals_to_send) == -1)
  180. {
  181. rc = LDAP_ENCODING_ERROR;
  182. goto loser;
  183. }
  184. slapi_ch_free((void **)&referrals_to_send);
  185. }
  186. /* Add the CSN */
  187. PR_ASSERT(NULL != csn);
  188. if (ber_printf(tmp_bere, "s", csn_as_string(csn,PR_FALSE,s)) == -1)
  189. {
  190. rc = LDAP_ENCODING_ERROR;
  191. goto loser;
  192. }
  193. }
  194. /* If we have data to send to a 9.0 style replica, set it here. */
  195. if (data_guid && data) {
  196. if (ber_printf(tmp_bere, "sO", data_guid, data) == -1)
  197. {
  198. rc = LDAP_ENCODING_ERROR;
  199. goto loser;
  200. }
  201. }
  202. if (ber_printf(tmp_bere, "}") == -1)
  203. {
  204. rc = LDAP_ENCODING_ERROR;
  205. goto loser;
  206. }
  207. if (ber_flatten(tmp_bere, &req_data) == -1)
  208. {
  209. rc = LDAP_LOCAL_ERROR;
  210. goto loser;
  211. }
  212. /* Success */
  213. goto done;
  214. loser:
  215. /* Free stuff we allocated */
  216. if (NULL != req_data)
  217. {
  218. ber_bvfree(req_data); req_data = NULL;
  219. }
  220. done:
  221. if (NULL != tmp_bere)
  222. {
  223. ber_free(tmp_bere, 1); tmp_bere = NULL;
  224. }
  225. if (NULL != sdn)
  226. {
  227. slapi_sdn_free (&sdn); /* Put on stack instead of allocating? */
  228. }
  229. if (NULL != repl_obj)
  230. {
  231. object_release (repl_obj);
  232. }
  233. if (NULL != ruv_obj)
  234. {
  235. object_release (ruv_obj);
  236. }
  237. return req_data;
  238. }
  239. struct berval *
  240. NSDS50StartReplicationRequest_new(const char *protocol_oid,
  241. const char *repl_root, char **extra_referrals, CSN *csn)
  242. {
  243. return(create_ReplicationExtopPayload(protocol_oid,
  244. repl_root, extra_referrals, csn, 0, 0, 0));
  245. }
  246. struct berval *
  247. NSDS90StartReplicationRequest_new(const char *protocol_oid,
  248. const char *repl_root, char **extra_referrals, CSN *csn,
  249. const char *data_guid, const struct berval *data)
  250. {
  251. return(create_ReplicationExtopPayload(protocol_oid,
  252. repl_root, extra_referrals, csn, 0, data_guid, data));
  253. }
  254. struct berval *
  255. NSDS50EndReplicationRequest_new(char *repl_root)
  256. {
  257. return(create_ReplicationExtopPayload(NULL, repl_root, NULL, NULL, 1, 0, 0));
  258. }
  259. static int
  260. decode_ruv (BerElement *ber, RUV **ruv)
  261. {
  262. int rc = -1;
  263. struct berval **bvals = NULL;
  264. PR_ASSERT (ber && ruv);
  265. if (ber_scanf(ber, "[V]", &bvals) == LBER_DEFAULT)
  266. {
  267. goto done;
  268. }
  269. if (ruv_init_from_bervals(bvals, ruv) != 0)
  270. {
  271. goto done;
  272. }
  273. rc = 0;
  274. done:
  275. if (bvals)
  276. ber_bvecfree (bvals);
  277. return rc;
  278. }
  279. /*
  280. * Decode an NSDS50 or NSDS90 Start Replication Request extended
  281. * operation. Returns 0 on success, -1 on decoding error.
  282. * The caller is responsible for freeing protocol_oid,
  283. * repl_root, referrals, csn, data_guid, and data.
  284. */
  285. static int
  286. decode_startrepl_extop(Slapi_PBlock *pb, char **protocol_oid, char **repl_root,
  287. RUV **supplier_ruv, char ***extra_referrals, char **csnstr,
  288. char **data_guid, struct berval **data, int *is90)
  289. {
  290. char *extop_oid = NULL;
  291. struct berval *extop_value = NULL;
  292. BerElement *tmp_bere = NULL;
  293. ber_len_t len;
  294. int rc = 0;
  295. PR_ASSERT (pb && protocol_oid && repl_root && supplier_ruv && extra_referrals && csnstr && data_guid && data);
  296. *protocol_oid = NULL;
  297. *repl_root = NULL;
  298. *supplier_ruv = NULL;
  299. *extra_referrals = NULL;
  300. *csnstr = NULL;
  301. slapi_pblock_get(pb, SLAPI_EXT_OP_REQ_OID, &extop_oid);
  302. slapi_pblock_get(pb, SLAPI_EXT_OP_REQ_VALUE, &extop_value);
  303. if (NULL == extop_oid ||
  304. ((strcmp(extop_oid, REPL_START_NSDS50_REPLICATION_REQUEST_OID) != 0) &&
  305. (strcmp(extop_oid, REPL_START_NSDS90_REPLICATION_REQUEST_OID) != 0)) ||
  306. NULL == extop_value || NULL == extop_value->bv_val)
  307. {
  308. /* bogus */
  309. rc = -1;
  310. goto free_and_return;
  311. }
  312. /* Set a flag to let the caller know if this is a 9.0 style start extop */
  313. if (strcmp(extop_oid, REPL_START_NSDS90_REPLICATION_REQUEST_OID) == 0)
  314. {
  315. *is90 = 1;
  316. }
  317. else
  318. {
  319. *is90 = 0;
  320. }
  321. if ((tmp_bere = ber_init(extop_value)) == NULL)
  322. {
  323. rc = -1;
  324. goto free_and_return;
  325. }
  326. if (ber_scanf(tmp_bere, "{") == LBER_ERROR)
  327. {
  328. rc = -1;
  329. goto free_and_return;
  330. }
  331. /* Get the required protocol OID and root of replicated subtree */
  332. if (ber_get_stringa(tmp_bere, protocol_oid) == LBER_DEFAULT)
  333. {
  334. rc = -1;
  335. goto free_and_return;
  336. }
  337. if (ber_get_stringa(tmp_bere, repl_root) == LBER_DEFAULT)
  338. {
  339. rc = -1;
  340. goto free_and_return;
  341. }
  342. /* get supplier's ruv */
  343. if (decode_ruv (tmp_bere, supplier_ruv) == -1)
  344. {
  345. rc = -1;
  346. goto free_and_return;
  347. }
  348. /* Get the optional set of referral URLs */
  349. if (ber_peek_tag(tmp_bere, &len) == LBER_SET)
  350. {
  351. if (ber_scanf(tmp_bere, "[v]", extra_referrals) == LBER_ERROR)
  352. {
  353. rc = -1;
  354. goto free_and_return;
  355. }
  356. }
  357. /* Get the CSN */
  358. if (ber_get_stringa(tmp_bere, csnstr) == LBER_ERROR)
  359. {
  360. rc = -1;
  361. goto free_and_return;
  362. }
  363. /* Get the optional replication session callback data. */
  364. if (ber_peek_tag(tmp_bere, &len) == LBER_OCTETSTRING)
  365. {
  366. if (ber_get_stringa(tmp_bere, data_guid) == LBER_ERROR)
  367. {
  368. rc = -1;
  369. goto free_and_return;
  370. }
  371. /* If a data_guid was specified, data must be specified as well. */
  372. if (ber_peek_tag(tmp_bere, &len) == LBER_OCTETSTRING)
  373. {
  374. if (ber_get_stringal(tmp_bere, data) == LBER_ERROR)
  375. {
  376. rc = -1;
  377. goto free_and_return;
  378. }
  379. }
  380. else
  381. {
  382. rc = -1;
  383. goto free_and_return;
  384. }
  385. }
  386. if (ber_scanf(tmp_bere, "}") == LBER_ERROR)
  387. {
  388. rc = -1;
  389. goto free_and_return;
  390. }
  391. free_and_return:
  392. if (-1 == rc)
  393. {
  394. /* Free everything when error encountered */
  395. /* slapi_ch_free accepts NULL pointer */
  396. slapi_ch_free ((void**)protocol_oid);
  397. slapi_ch_free ((void**)repl_root);
  398. slapi_ch_array_free (*extra_referrals);
  399. *extra_referrals = NULL;
  400. slapi_ch_free ((void**)csnstr);
  401. if (*supplier_ruv)
  402. {
  403. ruv_destroy (supplier_ruv);
  404. }
  405. }
  406. if (NULL != tmp_bere)
  407. {
  408. ber_free(tmp_bere, 1);
  409. tmp_bere = NULL;
  410. }
  411. return rc;
  412. }
  413. /*
  414. * Decode an NSDS50 End Replication Request extended
  415. * operation. Returns 0 on success, -1 on decoding error.
  416. * The caller is responsible for freeing repl_root.
  417. */
  418. static int
  419. decode_endrepl_extop(Slapi_PBlock *pb, char **repl_root)
  420. {
  421. char *extop_oid = NULL;
  422. struct berval *extop_value = NULL;
  423. BerElement *tmp_bere = NULL;
  424. int rc = 0;
  425. slapi_pblock_get(pb, SLAPI_EXT_OP_REQ_OID, &extop_oid);
  426. slapi_pblock_get(pb, SLAPI_EXT_OP_REQ_VALUE, &extop_value);
  427. if (NULL == extop_oid ||
  428. strcmp(extop_oid, REPL_END_NSDS50_REPLICATION_REQUEST_OID) != 0 ||
  429. NULL == extop_value || NULL == extop_value->bv_val)
  430. {
  431. /* bogus */
  432. rc = -1;
  433. goto free_and_return;
  434. }
  435. if ((tmp_bere = ber_init(extop_value)) == NULL)
  436. {
  437. rc = -1;
  438. goto free_and_return;
  439. }
  440. if (ber_scanf(tmp_bere, "{") == LBER_DEFAULT)
  441. {
  442. rc = -1;
  443. goto free_and_return;
  444. }
  445. /* Get the required root of replicated subtree */
  446. if (ber_get_stringa(tmp_bere, repl_root) == LBER_DEFAULT)
  447. {
  448. rc = -1;
  449. goto free_and_return;
  450. }
  451. if (ber_scanf(tmp_bere, "}") == LBER_DEFAULT)
  452. {
  453. rc = -1;
  454. goto free_and_return;
  455. }
  456. free_and_return:
  457. if (NULL != tmp_bere)
  458. {
  459. ber_free(tmp_bere, 1);
  460. tmp_bere = NULL;
  461. }
  462. return rc;
  463. }
  464. /*
  465. * Decode an NSDS50ReplicationResponse or NSDS90ReplicationResponse
  466. * extended response. The extended response just contains a sequence
  467. * that contains:
  468. * 1) An integer response code
  469. * 2) An optional array of bervals representing the consumer
  470. * replica's update vector
  471. * 3) An optional data guid and data string if this is a 9.0
  472. * style response
  473. * Returns 0 on success, or -1 if the response could not be parsed.
  474. */
  475. int
  476. decode_repl_ext_response(struct berval *bvdata, int *response_code,
  477. struct berval ***ruv_bervals, char **data_guid, struct berval **data)
  478. {
  479. BerElement *tmp_bere = NULL;
  480. int return_value = 0;
  481. PR_ASSERT(NULL != response_code);
  482. PR_ASSERT(NULL != ruv_bervals);
  483. if (NULL == bvdata || NULL == response_code || NULL == ruv_bervals ||
  484. NULL == data_guid || NULL == data || NULL == bvdata->bv_val)
  485. {
  486. return_value = -1;
  487. }
  488. else
  489. {
  490. ber_len_t len;
  491. ber_int_t temp_response_code = 0;
  492. *ruv_bervals = NULL;
  493. if ((tmp_bere = ber_init(bvdata)) == NULL)
  494. {
  495. return_value = -1;
  496. }
  497. else if (ber_scanf(tmp_bere, "{e", &temp_response_code) == LBER_ERROR)
  498. {
  499. return_value = -1;
  500. }
  501. else if (ber_peek_tag(tmp_bere, &len) == LBER_SEQUENCE)
  502. {
  503. if (ber_scanf(tmp_bere, "{V}", ruv_bervals) == LBER_ERROR)
  504. {
  505. return_value = -1;
  506. }
  507. }
  508. /* Check for optional data from replication session callback */
  509. if (ber_peek_tag(tmp_bere, &len) == LBER_OCTETSTRING)
  510. {
  511. if (ber_scanf(tmp_bere, "aO}", data_guid, data) == LBER_ERROR)
  512. {
  513. return_value = -1;
  514. }
  515. }
  516. else if (ber_scanf(tmp_bere, "}") == LBER_ERROR)
  517. {
  518. return_value = -1;
  519. }
  520. *response_code = (int)temp_response_code;
  521. }
  522. if (0 != return_value)
  523. {
  524. if (NULL != ruv_bervals && NULL != *ruv_bervals)
  525. {
  526. ber_bvecfree(*ruv_bervals);
  527. }
  528. }
  529. if (NULL != tmp_bere)
  530. {
  531. ber_free(tmp_bere, 1); tmp_bere = NULL;
  532. }
  533. return return_value;
  534. }
  535. /*
  536. * This plugin entry point is called whenever a
  537. * StartNSDS50ReplicationRequest is received.
  538. */
  539. int
  540. multimaster_extop_StartNSDS50ReplicationRequest(Slapi_PBlock *pb)
  541. {
  542. int return_value = SLAPI_PLUGIN_EXTENDED_NOT_HANDLED;
  543. ber_int_t response = 0;
  544. int rc = 0;
  545. BerElement *resp_bere = NULL;
  546. struct berval *resp_bval = NULL;
  547. char *protocol_oid = NULL;
  548. char *repl_root = NULL;
  549. Slapi_DN *repl_root_sdn = NULL;
  550. char **referrals = NULL;
  551. Object *replica_object = NULL;
  552. Replica *replica = NULL;
  553. void *conn;
  554. consumer_connection_extension *connext = NULL;
  555. char *replicacsnstr = NULL;
  556. CSN *replicacsn = NULL;
  557. int zero = 0;
  558. int one = 1;
  559. RUV *ruv = NULL;
  560. struct berval **ruv_bervals = NULL;
  561. CSNGen *gen = NULL;
  562. Object *gen_obj = NULL;
  563. Slapi_DN *bind_sdn = NULL;
  564. char *bind_dn = NULL;
  565. Object *ruv_object = NULL;
  566. RUV *supplier_ruv = NULL;
  567. PRUint64 connid = 0;
  568. int opid = 0;
  569. PRBool isInc = PR_FALSE; /* true if incremental update */
  570. char *locking_purl = NULL; /* the supplier contacting us */
  571. char *current_purl = NULL; /* the supplier which already has exclusive access */
  572. char locking_session[24];
  573. char *data_guid = NULL;
  574. struct berval *data = NULL;
  575. int is90 = 0;
  576. /* Decode the extended operation */
  577. if (decode_startrepl_extop(pb, &protocol_oid, &repl_root, &supplier_ruv,
  578. &referrals, &replicacsnstr, &data_guid, &data, &is90) == -1)
  579. {
  580. response = NSDS50_REPL_DECODING_ERROR;
  581. goto send_response;
  582. }
  583. if (NULL == protocol_oid || NULL == repl_root || NULL == replicacsnstr)
  584. {
  585. response = NSDS50_REPL_DECODING_ERROR;
  586. goto send_response;
  587. }
  588. slapi_pblock_get(pb, SLAPI_CONN_ID, &connid);
  589. slapi_pblock_get(pb, SLAPI_OPERATION_ID, &opid);
  590. /*
  591. * Get a hold of the connection extension object and
  592. * make sure it's there.
  593. */
  594. slapi_pblock_get(pb, SLAPI_CONNECTION, &conn);
  595. connext = (consumer_connection_extension *)repl_con_get_ext(
  596. REPL_CON_EXT_CONN, conn);
  597. if (NULL == connext)
  598. {
  599. /* Something bad happened. Don't go any further */
  600. response = NSDS50_REPL_INTERNAL_ERROR;
  601. goto send_response;
  602. }
  603. /* Verify that we know about this replication protocol OID */
  604. if (strcmp(protocol_oid, REPL_NSDS50_INCREMENTAL_PROTOCOL_OID) == 0)
  605. {
  606. if (repl_session_plugin_call_recv_acquire_cb(repl_root, 0 /* is_total == FALSE */,
  607. data_guid, data))
  608. {
  609. slapi_ch_free_string(&data_guid);
  610. ber_bvfree(data);
  611. data = NULL;
  612. response = NSDS50_REPL_BACKOFF;
  613. goto send_response;
  614. } else {
  615. slapi_ch_free_string(&data_guid);
  616. ber_bvfree(data);
  617. data = NULL;
  618. }
  619. /* Stash info that this is an incremental update session */
  620. connext->repl_protocol_version = REPL_PROTOCOL_50_INCREMENTAL;
  621. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
  622. "conn=%" NSPRIu64 " op=%d repl=\"%s\": Begin incremental protocol\n",
  623. connid, opid, repl_root);
  624. isInc = PR_TRUE;
  625. }
  626. else if (strcmp(protocol_oid, REPL_NSDS50_TOTAL_PROTOCOL_OID) == 0)
  627. {
  628. if (repl_session_plugin_call_recv_acquire_cb(repl_root, 1 /* is_total == TRUE */,
  629. data_guid, data))
  630. {
  631. slapi_ch_free_string(&data_guid);
  632. ber_bvfree(data);
  633. data = NULL;
  634. response = NSDS50_REPL_DISABLED;
  635. goto send_response;
  636. } else {
  637. slapi_ch_free_string(&data_guid);
  638. ber_bvfree(data);
  639. data = NULL;
  640. }
  641. /* Stash info that this is a total update session */
  642. if (NULL != connext)
  643. {
  644. connext->repl_protocol_version = REPL_PROTOCOL_50_TOTALUPDATE;
  645. }
  646. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
  647. "conn=%" NSPRIu64 " op=%d repl=\"%s\": Begin total protocol\n",
  648. connid, opid, repl_root);
  649. isInc = PR_FALSE;
  650. }
  651. else if (strcmp(protocol_oid, REPL_NSDS71_INCREMENTAL_PROTOCOL_OID) == 0)
  652. {
  653. /* Stash info that this is an incremental update session */
  654. connext->repl_protocol_version = REPL_PROTOCOL_50_INCREMENTAL;
  655. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
  656. "conn=%" NSPRIu64 " op=%d repl=\"%s\": Begin 7.1 incremental protocol\n",
  657. connid, opid, repl_root);
  658. isInc = PR_TRUE;
  659. }
  660. else if (strcmp(protocol_oid, REPL_NSDS71_TOTAL_PROTOCOL_OID) == 0)
  661. {
  662. /* Stash info that this is a total update session */
  663. if (NULL != connext)
  664. {
  665. connext->repl_protocol_version = REPL_PROTOCOL_71_TOTALUPDATE;
  666. }
  667. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
  668. "conn=%" NSPRIu64 " op=%d repl=\"%s\": Begin 7.1 total protocol\n",
  669. connid, opid, repl_root);
  670. isInc = PR_FALSE;
  671. }
  672. else
  673. {
  674. /* Unknown replication protocol */
  675. response = NSDS50_REPL_UNKNOWN_UPDATE_PROTOCOL;
  676. goto send_response;
  677. }
  678. /* Verify that repl_root names a valid replicated area */
  679. if ((repl_root_sdn = slapi_sdn_new_dn_byval(repl_root)) == NULL)
  680. {
  681. response = NSDS50_REPL_INTERNAL_ERROR;
  682. goto send_response;
  683. }
  684. /* see if this replica is being configured and wait for it */
  685. if (replica_is_being_configured(repl_root))
  686. {
  687. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
  688. "conn=%" NSPRIu64 " op=%d replica=\"%s\": "
  689. "Replica is being configured: try again later\n",
  690. connid, opid, repl_root);
  691. response = NSDS50_REPL_REPLICA_BUSY;
  692. goto send_response;
  693. }
  694. replica_object = replica_get_replica_from_dn(repl_root_sdn);
  695. if (NULL != replica_object)
  696. {
  697. replica = object_get_data(replica_object);
  698. }
  699. if (NULL == replica)
  700. {
  701. response = NSDS50_REPL_NO_SUCH_REPLICA;
  702. goto send_response;
  703. }
  704. if (REPL_PROTOCOL_50_TOTALUPDATE == connext->repl_protocol_version)
  705. {
  706. /* If total update has been initiated against other replicas or
  707. * this replica is already being initialized, we should return
  708. * an error immediately. */
  709. if (replica_is_state_flag_set(replica,
  710. REPLICA_TOTAL_EXCL_SEND|REPLICA_TOTAL_EXCL_RECV))
  711. {
  712. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  713. "%s: total update on is initiated on the replica. Cannot execute the total update from other master.\n", repl_root);
  714. response = NSDS50_REPL_REPLICA_BUSY;
  715. goto send_response;
  716. }
  717. else
  718. {
  719. replica_set_state_flag (replica, REPLICA_TOTAL_EXCL_RECV, 0);
  720. }
  721. }
  722. /* check that this replica is not a 4.0 consumer */
  723. if (replica_is_legacy_consumer (replica))
  724. {
  725. response = NSDS50_REPL_LEGACY_CONSUMER;
  726. goto send_response;
  727. }
  728. /* Check that bind dn is authorized to supply replication updates */
  729. slapi_pblock_get(pb, SLAPI_CONN_DN, &bind_dn); /* bind_dn is allocated */
  730. bind_sdn = slapi_sdn_new_dn_passin(bind_dn);
  731. if (replica_is_updatedn(replica, bind_sdn) == PR_FALSE)
  732. {
  733. response = NSDS50_REPL_PERMISSION_DENIED;
  734. goto send_response;
  735. }
  736. /* Check received CSN for clock skew */
  737. gen_obj = replica_get_csngen(replica);
  738. if (NULL != gen_obj)
  739. {
  740. gen = object_get_data(gen_obj);
  741. if (NULL != gen)
  742. {
  743. replicacsn = csn_new_by_string(replicacsnstr);
  744. if (NULL != replicacsn)
  745. {
  746. /* ONREPL - we used to manage clock skew here. However, csn generator
  747. code already does it. The csngen also manages local skew caused by
  748. system clock reset, so to keep it consistent, I removed code from here */
  749. /* update the state of the csn generator */
  750. rc = replica_update_csngen_state_ext (replica, supplier_ruv, replicacsn); /* too much skew */
  751. if (rc == CSN_LIMIT_EXCEEDED)
  752. {
  753. response = NSDS50_REPL_EXCESSIVE_CLOCK_SKEW;
  754. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
  755. "conn=%" NSPRIu64 " op=%d repl=\"%s\": "
  756. "Excessive clock skew from supplier RUV\n",
  757. connid, opid, repl_root);
  758. goto send_response;
  759. }
  760. else if (rc != 0)
  761. {
  762. /* Oops, problem csn or ruv format, or memory, or .... */
  763. response = NSDS50_REPL_INTERNAL_ERROR;
  764. goto send_response;
  765. }
  766. }
  767. else
  768. {
  769. /* Oops, csnstr couldn't be converted */
  770. response = NSDS50_REPL_INTERNAL_ERROR;
  771. goto send_response;
  772. }
  773. }
  774. else
  775. {
  776. /* Oops, no csn generator */
  777. response = NSDS50_REPL_INTERNAL_ERROR;
  778. goto send_response;
  779. }
  780. }
  781. else
  782. {
  783. /* Oops, no csn generator object */
  784. response = NSDS50_REPL_INTERNAL_ERROR;
  785. goto send_response;
  786. }
  787. if (check_replica_id_uniqueness(replica, supplier_ruv) != 0){
  788. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
  789. "conn=%" NSPRIu64 " op=%d repl=\"%s\": "
  790. "Replica has same replicaID %d as supplier\n",
  791. connid, opid, repl_root, replica_get_rid(replica));
  792. response = NSDS50_REPL_REPLICAID_ERROR;
  793. goto send_response;
  794. }
  795. /* Attempt to acquire exclusive access to the replicated area */
  796. /* Since partial URL is always the master, this locking_purl does not
  797. * help us to know the true locker when it is a hub. Change to use
  798. * the session's conn id and op id to identify the the supplier.
  799. */
  800. /* junkrc = ruv_get_first_id_and_purl(supplier_ruv, &junkrid, &locking_purl); */
  801. PR_snprintf(locking_session, sizeof(locking_session), "conn=%" NSPRIu64 " id=%d", connid, opid);
  802. locking_purl = &locking_session[0];
  803. if (replica_get_exclusive_access(replica, &isInc, connid, opid,
  804. locking_purl,
  805. &current_purl) == PR_FALSE)
  806. {
  807. locking_purl = NULL; /* no dangling pointers */
  808. response = NSDS50_REPL_REPLICA_BUSY;
  809. goto send_response;
  810. }
  811. else
  812. {
  813. locking_purl = NULL; /* no dangling pointers */
  814. /* Stick the replica object pointer in the connection extension */
  815. connext->replica_acquired = (void *)replica_object;
  816. replica_object = NULL;
  817. }
  818. /* If this is incremental protocol get replica's ruv to return to the supplier */
  819. if (connext->repl_protocol_version == REPL_PROTOCOL_50_INCREMENTAL)
  820. {
  821. ruv_object = replica_get_ruv(replica);
  822. if (NULL != ruv_object)
  823. {
  824. ruv = object_get_data(ruv_object);
  825. (void)ruv_to_bervals(ruv, &ruv_bervals);
  826. object_release(ruv_object);
  827. }
  828. }
  829. /*
  830. * Save the supplier ruv in the connection extension so it can
  831. * either (a) be installed upon successful initialization (if this
  832. * is a total update session) or used to update referral information
  833. * for new replicas that show up in the supplier's RUV.
  834. */
  835. /*
  836. * the supplier_ruv may have been set before, so free it here
  837. * (in ruv_copy_and_destroy)
  838. */
  839. ruv_copy_and_destroy(&supplier_ruv, (RUV **)&connext->supplier_ruv);
  840. if (connext->repl_protocol_version == REPL_PROTOCOL_50_INCREMENTAL)
  841. {
  842. /* The supplier ruv may have changed, so let's update the referrals */
  843. consumer5_set_mapping_tree_state_for_replica(replica, connext->supplier_ruv);
  844. }
  845. else /* full protocol */
  846. {
  847. char *mtnstate = slapi_mtn_get_state(repl_root_sdn);
  848. char **mtnreferral = slapi_mtn_get_referral(repl_root_sdn);
  849. /* richm 20041118 - we do not want to reap tombstones while there is
  850. a total update in progress, so shut it down */
  851. replica_set_tombstone_reap_stop(replica, PR_TRUE);
  852. /* richm 20010831 - set the mapping tree to the referral state *before*
  853. we invoke slapi_start_bulk_import - see bug 556992 -
  854. slapi_start_bulk_import sets the database offline, if an operation comes
  855. in while the database is offline but the mapping tree is not referring yet,
  856. the server gets confused
  857. */
  858. /* During a total update we refer *all* operations */
  859. repl_set_mtn_state_and_referrals(repl_root_sdn, STATE_REFERRAL,
  860. connext->supplier_ruv, NULL, referrals);
  861. /* LPREPL - check the return code.
  862. * But what do we do if mapping tree could not be updated ? */
  863. /* start the bulk import */
  864. slapi_pblock_set (pb, SLAPI_TARGET_SDN, repl_root_sdn);
  865. rc = slapi_start_bulk_import (pb);
  866. if (rc != LDAP_SUCCESS)
  867. {
  868. response = NSDS50_REPL_INTERNAL_ERROR;
  869. /* reset the mapping tree state to what it was before
  870. we tried to do the bulk import if mtnstate exists */
  871. if (mtnstate) {
  872. repl_set_mtn_state_and_referrals(repl_root_sdn, mtnstate,
  873. NULL, NULL, mtnreferral);
  874. slapi_ch_free_string(&mtnstate);
  875. }
  876. charray_free(mtnreferral);
  877. mtnreferral = NULL;
  878. goto send_response;
  879. }
  880. slapi_ch_free_string(&mtnstate);
  881. charray_free(mtnreferral);
  882. mtnreferral = NULL;
  883. }
  884. response = NSDS50_REPL_REPLICA_READY;
  885. /* Set the "is replication session" flag in the connection extension */
  886. slapi_pblock_set( pb, SLAPI_CONN_IS_REPLICATION_SESSION, &one );
  887. connext->isreplicationsession = 1;
  888. /* Save away the connection */
  889. slapi_pblock_get(pb, SLAPI_CONNECTION, &connext->connection);
  890. send_response:
  891. if (connext && replica &&
  892. (REPL_PROTOCOL_50_TOTALUPDATE == connext->repl_protocol_version))
  893. {
  894. replica_set_state_flag (replica, REPLICA_TOTAL_EXCL_RECV, 1);
  895. }
  896. if (response != NSDS50_REPL_REPLICA_READY)
  897. {
  898. int resp_log_level = SLAPI_LOG_FATAL;
  899. char purlstr[1024] = {0};
  900. if (current_purl)
  901. PR_snprintf(purlstr, sizeof(purlstr), " locked by %s for %s update", current_purl,
  902. isInc ? "incremental" : "total");
  903. /* Don't log replica busy as errors - these are almost always not
  904. errors - use the replication monitoring tools to determine if
  905. a replica is not converging, then look for pathological replica
  906. busy errors by turning on the replication log level. We also
  907. don't want to log replica backoff as an error, as that response
  908. is only used when a replication session hook wants a master to
  909. go into incremental backoff mode. */
  910. if ((response == NSDS50_REPL_REPLICA_BUSY) || (response == NSDS50_REPL_BACKOFF)) {
  911. resp_log_level = SLAPI_LOG_REPL;
  912. }
  913. slapi_log_error (resp_log_level, repl_plugin_name,
  914. "conn=%" NSPRIu64 " op=%d replica=\"%s\": "
  915. "Unable to acquire replica: error: %s%s\n",
  916. connid, opid,
  917. (replica ? slapi_sdn_get_dn(replica_get_root(replica)) : "unknown"),
  918. protocol_response2string (response), purlstr);
  919. /* enable tombstone reap again since the total update failed */
  920. replica_set_tombstone_reap_stop(replica, PR_FALSE);
  921. }
  922. /* Call any registered replica session reply callback. We
  923. * want to reject the updates if the return value is non-0. */
  924. if (repl_session_plugin_call_reply_acquire_cb(replica ?
  925. slapi_sdn_get_ndn(replica_get_root(replica)) : "",
  926. ((isInc == PR_TRUE) ? 0 : 1), &data_guid, &data))
  927. {
  928. slapi_ch_free_string(&data_guid);
  929. ber_bvfree(data);
  930. data = NULL;
  931. response = NSDS50_REPL_BACKOFF;
  932. }
  933. /* Send the response */
  934. if ((resp_bere = der_alloc()) == NULL)
  935. {
  936. /* ONREPL - not sure what we suppose to do here */
  937. }
  938. ber_printf(resp_bere, "{e", response);
  939. if (NULL != ruv_bervals)
  940. {
  941. ber_printf(resp_bere, "{V}", ruv_bervals);
  942. }
  943. /* Add extra data from replication session callback if necessary */
  944. if (is90 && data_guid && data)
  945. {
  946. ber_printf(resp_bere, "sO", data_guid, data);
  947. }
  948. ber_printf(resp_bere, "}");
  949. ber_flatten(resp_bere, &resp_bval);
  950. if (is90)
  951. {
  952. slapi_pblock_set(pb, SLAPI_EXT_OP_RET_OID, REPL_NSDS90_REPLICATION_RESPONSE_OID);
  953. }
  954. else
  955. {
  956. slapi_pblock_set(pb, SLAPI_EXT_OP_RET_OID, REPL_NSDS50_REPLICATION_RESPONSE_OID);
  957. }
  958. slapi_pblock_set(pb, SLAPI_EXT_OP_RET_VALUE, resp_bval);
  959. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
  960. "conn=%" NSPRIu64 " op=%d repl=\"%s\": "
  961. "%s: response=%d rc=%d\n",
  962. connid, opid, repl_root,
  963. is90 ? "StartNSDS90ReplicationRequest" :
  964. "StartNSDS50ReplicationRequest", response, rc);
  965. slapi_send_ldap_result(pb, LDAP_SUCCESS, NULL, NULL, 0, NULL);
  966. return_value = SLAPI_PLUGIN_EXTENDED_SENT_RESULT;
  967. /* Free any data allocated by the replication
  968. * session reply callback. */
  969. slapi_ch_free_string(&data_guid);
  970. ber_bvfree(data);
  971. data = NULL;
  972. slapi_ch_free_string(&current_purl);
  973. /* protocol_oid */
  974. /* slapi_ch_free accepts NULL pointer */
  975. slapi_ch_free((void **)&protocol_oid);
  976. /* repl_root */
  977. slapi_ch_free((void **)&repl_root);
  978. /* supplier's ruv */
  979. if (supplier_ruv)
  980. {
  981. ruv_destroy (&supplier_ruv);
  982. }
  983. /* referrals (char **) */
  984. slapi_ch_array_free(referrals);
  985. /* replicacsnstr */
  986. slapi_ch_free((void **)&replicacsnstr);
  987. /* repl_root_sdn */
  988. slapi_sdn_free(&repl_root_sdn);
  989. if (NSDS50_REPL_REPLICA_READY != response)
  990. {
  991. /*
  992. * Something went wrong, and we never told the other end that the
  993. * replica had been acquired, so we'd better release it.
  994. */
  995. if (NULL != connext && NULL != connext->replica_acquired)
  996. {
  997. Object *r_obj = (Object*)connext->replica_acquired;
  998. replica_relinquish_exclusive_access((Replica*)object_get_data (r_obj),
  999. connid, opid);
  1000. }
  1001. /* Remove any flags that would indicate repl session in progress */
  1002. if (NULL != connext)
  1003. {
  1004. connext->repl_protocol_version = REPL_PROTOCOL_UNKNOWN;
  1005. connext->isreplicationsession = 0;
  1006. }
  1007. slapi_pblock_set( pb, SLAPI_CONN_IS_REPLICATION_SESSION, &zero );
  1008. }
  1009. /* Release reference to replica_object */
  1010. if (NULL != replica_object)
  1011. {
  1012. object_release(replica_object);
  1013. }
  1014. /* bind_sdn */
  1015. if (NULL != bind_sdn)
  1016. {
  1017. slapi_sdn_free(&bind_sdn);
  1018. }
  1019. /* Release reference to gen_obj */
  1020. if (NULL != gen_obj)
  1021. {
  1022. object_release(gen_obj);
  1023. }
  1024. /* replicacsn */
  1025. if (NULL != replicacsn)
  1026. {
  1027. csn_free(&replicacsn);
  1028. }
  1029. /* resp_bere */
  1030. if (NULL != resp_bere)
  1031. {
  1032. ber_free(resp_bere, 1);
  1033. }
  1034. /* resp_bval */
  1035. if (NULL != resp_bval)
  1036. {
  1037. ber_bvfree(resp_bval);
  1038. }
  1039. /* ruv_bervals */
  1040. if (NULL != ruv_bervals)
  1041. {
  1042. ber_bvecfree(ruv_bervals);
  1043. }
  1044. return return_value;
  1045. }
  1046. /*
  1047. * This plugin entry point is called whenever an
  1048. * EndNSDS50ReplicationRequest is received.
  1049. * XXXggood this code is not finished.
  1050. */
  1051. int
  1052. multimaster_extop_EndNSDS50ReplicationRequest(Slapi_PBlock *pb)
  1053. {
  1054. int return_value = SLAPI_PLUGIN_EXTENDED_NOT_HANDLED;
  1055. char *repl_root = NULL;
  1056. Slapi_DN *repl_root_sdn = NULL;
  1057. BerElement *resp_bere = NULL;
  1058. struct berval *resp_bval = NULL;
  1059. ber_int_t response;
  1060. void *conn;
  1061. consumer_connection_extension *connext = NULL;
  1062. PRUint64 connid = 0;
  1063. int opid=-1;
  1064. /* Decode the extended operation */
  1065. if (decode_endrepl_extop(pb, &repl_root) == -1)
  1066. {
  1067. response = NSDS50_REPL_DECODING_ERROR;
  1068. }
  1069. else
  1070. {
  1071. /* First, verify that the current connection is a replication session */
  1072. /* XXXggood - do we need to wait around for any pending updates to complete?
  1073. I suppose it's possible that the end request may arrive asynchronously, before
  1074. we're really done processing all the updates.
  1075. */
  1076. /* Get a hold of the connection extension object */
  1077. slapi_pblock_get(pb, SLAPI_CONNECTION, &conn);
  1078. connext = (consumer_connection_extension *)repl_con_get_ext(
  1079. REPL_CON_EXT_CONN, conn);
  1080. if (NULL != connext && NULL != connext->replica_acquired)
  1081. {
  1082. int zero= 0;
  1083. Replica *r = (Replica*)object_get_data ((Object*)connext->replica_acquired);
  1084. /* if this is total protocol we need to install suppliers ruv for the replica */
  1085. if (connext->repl_protocol_version == REPL_PROTOCOL_50_TOTALUPDATE)
  1086. {
  1087. /* We no longer need to refer all operations...
  1088. * and update the referrals on the mapping tree node
  1089. */
  1090. consumer5_set_mapping_tree_state_for_replica(r, NULL);
  1091. /* LPREPL - First we clear the total in progress flag
  1092. Like this we know it's a normal termination of import. This is required by
  1093. the replication function that responds to backend state change.
  1094. If the flag is not clear, the callback knows that replication should not be
  1095. enabled again */
  1096. replica_set_state_flag(r, REPLICA_TOTAL_IN_PROGRESS, PR_TRUE /* clear flag */);
  1097. /* slapi_pblock_set (pb, SLAPI_TARGET_DN, repl_root); */
  1098. /* Verify that repl_root names a valid replicated area */
  1099. if ((repl_root_sdn = slapi_sdn_new_dn_byref(repl_root)) == NULL)
  1100. {
  1101. response = NSDS50_REPL_INTERNAL_ERROR;
  1102. goto send_response;
  1103. }
  1104. slapi_pblock_set (pb, SLAPI_TARGET_SDN, repl_root_sdn);
  1105. slapi_stop_bulk_import (pb);
  1106. /* ONREPL - this is a bit of a hack. Once bulk import is finished,
  1107. the replication function that responds to backend state change
  1108. will be called. That function normally do all ruv and changelog
  1109. processing. However, in the case of replica initalization, it
  1110. will not do the right thing because supplier does not send its
  1111. ruv tombstone to the consumer. So that's why we need to do the
  1112. second processing here.
  1113. The supplier does not send its RUV entry because it could be
  1114. more up to date then the data send to the consumer.
  1115. The best solution I think, would be to "fake" on the supplier
  1116. an entry that corresponds to the ruv sent to the consumer and then
  1117. send it as part of the data */
  1118. if (cl5GetState () == CL5_STATE_OPEN)
  1119. {
  1120. cl5DeleteDBSync (connext->replica_acquired);
  1121. }
  1122. replica_set_ruv (r, connext->supplier_ruv);
  1123. connext->supplier_ruv = NULL;
  1124. /* if changelog is enabled, we need to log a dummy change for the
  1125. smallest csn in the new ruv, so that this replica ca supply
  1126. other servers.
  1127. */
  1128. if (cl5GetState () == CL5_STATE_OPEN)
  1129. {
  1130. replica_log_ruv_elements (r);
  1131. }
  1132. /* ONREPL code that dealt with new RUV, etc was moved into the code
  1133. that enables replication when a backend comes back online. This
  1134. code is called once the bulk import is finished */
  1135. /* allow reaping again */
  1136. replica_set_tombstone_reap_stop(r, PR_FALSE);
  1137. }
  1138. else if (connext->repl_protocol_version == REPL_PROTOCOL_50_INCREMENTAL)
  1139. {
  1140. /* The ruv from the supplier may have changed. Report the change on the
  1141. consumer side */
  1142. replica_update_ruv_consumer(r, connext->supplier_ruv);
  1143. }
  1144. /* Relinquish control of the replica */
  1145. slapi_pblock_get (pb, SLAPI_OPERATION_ID, &opid);
  1146. if (opid) slapi_pblock_get (pb, SLAPI_CONN_ID, &connid);
  1147. replica_relinquish_exclusive_access(r, connid, opid);
  1148. object_release ((Object*)connext->replica_acquired);
  1149. connext->replica_acquired = NULL;
  1150. connext->isreplicationsession= 0;
  1151. slapi_pblock_set( pb, SLAPI_CONN_IS_REPLICATION_SESSION, &zero );
  1152. response = NSDS50_REPL_REPLICA_RELEASE_SUCCEEDED;
  1153. /* Outbound replication agreements need to all be restarted now */
  1154. /* XXXGGOOD RESTART REEPL AGREEMENTS */
  1155. } else {
  1156. /* Unless bail out, we return uninitialized response */
  1157. goto free_and_return;
  1158. }
  1159. }
  1160. send_response:
  1161. /* Send the response code */
  1162. if ((resp_bere = der_alloc()) == NULL)
  1163. {
  1164. goto free_and_return;
  1165. }
  1166. ber_printf(resp_bere, "{e}", response);
  1167. ber_flatten(resp_bere, &resp_bval);
  1168. slapi_pblock_set(pb, SLAPI_EXT_OP_RET_OID, REPL_NSDS50_REPLICATION_RESPONSE_OID);
  1169. slapi_pblock_set(pb, SLAPI_EXT_OP_RET_VALUE, resp_bval);
  1170. slapi_send_ldap_result(pb, LDAP_SUCCESS, NULL, NULL, 0, NULL);
  1171. return_value = SLAPI_PLUGIN_EXTENDED_SENT_RESULT;
  1172. free_and_return:
  1173. /* repl_root */
  1174. slapi_ch_free((void **)&repl_root);
  1175. slapi_sdn_free(&repl_root_sdn);
  1176. /* BerElement */
  1177. if (NULL != resp_bere)
  1178. {
  1179. ber_free(resp_bere, 1);
  1180. }
  1181. /* response */
  1182. if (NULL != resp_bval)
  1183. {
  1184. ber_bvfree(resp_bval);
  1185. }
  1186. return return_value;
  1187. }
  1188. /*
  1189. * Return the mtnode extension of the dn
  1190. */
  1191. static multimaster_mtnode_extension *
  1192. replica_config_get_mtnode_by_dn(const char *dn)
  1193. {
  1194. Slapi_DN *sdn;
  1195. mapping_tree_node *mtnode;
  1196. multimaster_mtnode_extension *ext = NULL;
  1197. sdn = slapi_sdn_new_dn_byval(dn);
  1198. mtnode = slapi_get_mapping_tree_node_by_dn (sdn);
  1199. if (mtnode) {
  1200. /* check if the replica object already exists in the subtree */
  1201. ext = (multimaster_mtnode_extension *)repl_con_get_ext (REPL_CON_EXT_MTNODE, mtnode);
  1202. }
  1203. slapi_sdn_free (&sdn);
  1204. return ext;
  1205. }
  1206. /*
  1207. * Decode the ber element passed to us by the cleanAllRUV task
  1208. */
  1209. static int
  1210. decode_cleanruv_payload(struct berval *extop_value, char **payload)
  1211. {
  1212. BerElement *tmp_bere = NULL;
  1213. int rc = 0;
  1214. if ((tmp_bere = ber_init(extop_value)) == NULL){
  1215. rc = -1;
  1216. goto free_and_return;
  1217. }
  1218. if (ber_scanf(tmp_bere, "{") == LBER_ERROR){
  1219. rc = -1;
  1220. goto free_and_return;
  1221. }
  1222. if (ber_get_stringa(tmp_bere, payload) == LBER_DEFAULT){
  1223. rc = -1;
  1224. goto free_and_return;
  1225. }
  1226. if (ber_scanf(tmp_bere, "}") == LBER_ERROR){
  1227. rc = -1;
  1228. goto free_and_return;
  1229. }
  1230. free_and_return:
  1231. if (-1 == rc){
  1232. slapi_ch_free_string(payload);
  1233. }
  1234. if (NULL != tmp_bere){
  1235. ber_free(tmp_bere, 1);
  1236. tmp_bere = NULL;
  1237. }
  1238. return rc;
  1239. }
  1240. /*
  1241. * Process the REPL_CLEANRUV_OID extended operation.
  1242. *
  1243. * The payload consists of the replica ID, and the repl root dn. Since this is
  1244. * basically a replication operation, it could of originated here and bounced
  1245. * back from another master. So check the rid against the "cleaned_rid". If
  1246. * it's a match, then we were already here, and we can just return success.
  1247. *
  1248. * Otherwise, we the set the cleaned_rid from the payload, fire off extended ops
  1249. * to all the replica agreements on this replica. Then perform the actual
  1250. * cleanruv_task on this replica.
  1251. */
  1252. int
  1253. multimaster_extop_cleanruv(Slapi_PBlock *pb){
  1254. multimaster_mtnode_extension *mtnode_ext;
  1255. PRThread *thread = NULL;
  1256. Repl_Connection *conn;
  1257. const Slapi_DN *dn;
  1258. Replica *r = NULL;
  1259. Object *agmt_obj;
  1260. Repl_Agmt *agmt;
  1261. ConnResult crc;
  1262. cleanruv_data *data = NULL;
  1263. struct berval *extop_value;
  1264. char *extop_oid;
  1265. char *repl_root;
  1266. char *payload = NULL;
  1267. char *iter;
  1268. int send_msgid = 0;
  1269. int agmt_count = 0;
  1270. int rid = 0;
  1271. int rc = 0;
  1272. slapi_pblock_get(pb, SLAPI_EXT_OP_REQ_OID, &extop_oid);
  1273. slapi_pblock_get(pb, SLAPI_EXT_OP_REQ_VALUE, &extop_value);
  1274. if (NULL == extop_oid || strcmp(extop_oid, REPL_CLEANRUV_OID) != 0 ||
  1275. NULL == extop_value || NULL == extop_value->bv_val){
  1276. /* something is wrong, error out */
  1277. return -1;
  1278. }
  1279. /*
  1280. * Extract the rid and repl_root from the payload
  1281. */
  1282. if(decode_cleanruv_payload(extop_value, &payload)){
  1283. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_extop: failed to decode payload. Aborting ext op\n");
  1284. return -1;
  1285. }
  1286. rid = atoi(ldap_utf8strtok_r(payload, ":", &iter));
  1287. repl_root = ldap_utf8strtok_r(iter, ":", &iter);
  1288. /*
  1289. * If we already cleaned this server, just return success
  1290. */
  1291. if(is_cleaned_rid(rid)){
  1292. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "cleanAllRUV_extop: rid (%d) has already been cleaned, skipping\n",rid);
  1293. return rc;
  1294. } else {
  1295. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_extop: cleaning rid (%d)...\n", rid);
  1296. set_cleaned_rid(rid);
  1297. }
  1298. /*
  1299. * Get the node, so we can get the replica and its agreements
  1300. */
  1301. if((mtnode_ext = replica_config_get_mtnode_by_dn(repl_root)) == NULL){
  1302. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_extop: failed to get replication node "
  1303. "from (%s), aborting operation\n", repl_root);
  1304. return -1;
  1305. }
  1306. if (mtnode_ext->replica)
  1307. object_acquire (mtnode_ext->replica);
  1308. if (mtnode_ext->replica == NULL){
  1309. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_extop: replica is missing from (%s), "
  1310. "aborting operation\n",repl_root);
  1311. rc = LDAP_OPERATIONS_ERROR;
  1312. goto free_and_return;
  1313. }
  1314. r = (Replica*)object_get_data (mtnode_ext->replica);
  1315. /*
  1316. * Send out extended ops to each repl agreement
  1317. */
  1318. agmt_obj = agmtlist_get_first_agreement_for_replica (r);
  1319. while (agmt_obj)
  1320. {
  1321. agmt = (Repl_Agmt*)object_get_data (agmt_obj);
  1322. if(!agmt_is_enabled(agmt)){
  1323. agmt_obj = agmtlist_get_next_agreement_for_replica (r, agmt_obj);
  1324. continue;
  1325. }
  1326. dn = agmt_get_dn_byref(agmt);
  1327. conn = (Repl_Connection *)agmt_get_connection(agmt);
  1328. if(conn == NULL){
  1329. /* no connection for this agreement, move on to the next agmt */
  1330. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_extop: the replica (%s), is "
  1331. "missing the connection. This replica will not be cleaned.\n", slapi_sdn_get_dn(dn));
  1332. agmt_obj = agmtlist_get_next_agreement_for_replica (r, agmt_obj);
  1333. continue;
  1334. }
  1335. crc = conn_connect(conn);
  1336. if (CONN_OPERATION_FAILED == crc ){
  1337. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_extop: failed to connect "
  1338. "to repl agreement connection (%s), error %d\n",slapi_sdn_get_dn(dn), ACQUIRE_TRANSIENT_ERROR);
  1339. rc = LDAP_OPERATIONS_ERROR;
  1340. } else if (CONN_SSL_NOT_ENABLED == crc){
  1341. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_extop: failed to acquire "
  1342. "repl agmt connection (%s), error %d\n",slapi_sdn_get_dn(dn), ACQUIRE_FATAL_ERROR);
  1343. rc = LDAP_OPERATIONS_ERROR;
  1344. } else {
  1345. conn_cancel_linger(conn);
  1346. crc = conn_send_extended_operation(conn, REPL_CLEANRUV_OID, extop_value, NULL, &send_msgid);
  1347. if (CONN_OPERATION_SUCCESS != crc){
  1348. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_extop: failed to send "
  1349. "clean_ruv extended op to repl agmt (%s), error %d\n", slapi_sdn_get_dn(dn), crc);
  1350. rc = LDAP_OPERATIONS_ERROR;
  1351. } else {
  1352. /* success */
  1353. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_extop: successfully sent "
  1354. "extended op to (%s)\n",slapi_sdn_get_dn(dn) );
  1355. agmt_count++;
  1356. }
  1357. conn_start_linger(conn);
  1358. }
  1359. if(crc != CONN_OPERATION_SUCCESS){
  1360. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_extop: replica (%s) has not "
  1361. "been cleaned. You will need to rerun the CLEANALLRUV task on this replica\n",
  1362. slapi_sdn_get_dn(dn) );
  1363. rc = LDAP_OPERATIONS_ERROR;
  1364. }
  1365. agmt_obj = agmtlist_get_next_agreement_for_replica (r, agmt_obj);
  1366. }
  1367. /* now clean the ruv */
  1368. replica_execute_cleanruv_task_ext(mtnode_ext->replica, rid);
  1369. free_and_return:
  1370. if(rc == 0 && agmt_count > 0){
  1371. /*
  1372. * Launch the cleanruv monitoring thread. Once all the replicas are cleaned it will release the rid
  1373. */
  1374. data = (cleanruv_data*)slapi_ch_calloc(1, sizeof(cleanruv_data));
  1375. if (data == NULL) {
  1376. slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_extop: failed to allocate "
  1377. "cleanruv_Data\n");
  1378. return -1;
  1379. }
  1380. data->repl_obj = mtnode_ext->replica;
  1381. data->rid = rid;
  1382. thread = PR_CreateThread(PR_USER_THREAD, replica_cleanallruv_monitor_thread,
  1383. (void *)data, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
  1384. PR_UNJOINABLE_THREAD, SLAPD_DEFAULT_THREAD_STACKSIZE);
  1385. if (thread == NULL) {
  1386. slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_extop: unable to create cleanAllRUV "
  1387. "monitoring thread. Aborting task.\n");
  1388. }
  1389. } else if (rc == 0){
  1390. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_extop: Successfully Finished.\n");
  1391. } else {
  1392. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanALLRUV_extop: failed to clean rid (%d), error (%d)\n",rid, rc);
  1393. }
  1394. if (mtnode_ext->replica)
  1395. object_release (mtnode_ext->replica);
  1396. return rc;
  1397. }
  1398. /*
  1399. * Process the REPL_RELEASERUV_OID extended operation
  1400. *
  1401. * Once, all the replicas in the replication farm have been cleaned, then
  1402. * we need to "release" the cleaned_rid, or else we will reject all updates
  1403. * that come from that rid until we restart the server.
  1404. *
  1405. * We set the cleaned_ruv to zero(invalid rid), and then fire off extended
  1406. * operations to all of the replicas
  1407. */
  1408. int
  1409. multimaster_extop_releaseruv(Slapi_PBlock *pb){
  1410. multimaster_mtnode_extension *mtnode_ext;
  1411. Repl_Connection *conn;
  1412. const Slapi_DN *dn;
  1413. Replica *r = NULL;
  1414. Object *agmt_obj;
  1415. Repl_Agmt *agmt;
  1416. ConnResult crc;
  1417. struct berval *extop_value;
  1418. char *payload = NULL;
  1419. char *extop_oid;
  1420. char *repl_root;
  1421. char *iter;
  1422. int send_msgid = 0;
  1423. int rid = 0;
  1424. int rc = 0;
  1425. slapi_pblock_get(pb, SLAPI_EXT_OP_REQ_OID, &extop_oid);
  1426. slapi_pblock_get(pb, SLAPI_EXT_OP_REQ_VALUE, &extop_value);
  1427. if (NULL == extop_oid || strcmp(extop_oid, REPL_RELEASERUV_OID) != 0 ||
  1428. NULL == extop_value || NULL == extop_value->bv_val){
  1429. /* something is wrong, error out */
  1430. return -1;
  1431. }
  1432. if(decode_cleanruv_payload(extop_value, &payload)){
  1433. slapi_log_error(SLAPI_LOG_FATAL,repl_plugin_name, "releaseRUV_extop: failed to decode payload, aborting ext op.\n");
  1434. return -1;
  1435. }
  1436. rid = atoi(ldap_utf8strtok_r(payload, ":", &iter));
  1437. repl_root = ldap_utf8strtok_r(iter, ":", &iter);
  1438. /*
  1439. * If we already released this ruv, just return.
  1440. */
  1441. if(is_released_rid(rid) || is_already_released_rid()){
  1442. slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "cleanAllRUV_extop: rid (%d) has already been released, skipping.\n",rid);
  1443. return 0;
  1444. } else {
  1445. /* set the released rid, and trigger trimming */
  1446. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_extop: releasing rid (%d)...\n", rid);
  1447. set_released_rid((int)rid);
  1448. trigger_cl_trimming();
  1449. }
  1450. if((mtnode_ext = replica_config_get_mtnode_by_dn(repl_root)) == NULL){
  1451. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "releaseRUV_extop: failed to get node "
  1452. "from replication root dn(%s), aborting operation.\n", repl_root);
  1453. return -1;
  1454. }
  1455. if (mtnode_ext->replica)
  1456. object_acquire (mtnode_ext->replica);
  1457. if (mtnode_ext->replica == NULL){
  1458. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "releaseRUV_extop: replica is missing from (%s), "
  1459. "aborting operation.\n", repl_root);
  1460. rc = LDAP_OPERATIONS_ERROR;
  1461. goto free_and_return;
  1462. }
  1463. r = (Replica*)object_get_data (mtnode_ext->replica);
  1464. /*
  1465. * Loop over the agreements, and send out extended ops
  1466. */
  1467. agmt_obj = agmtlist_get_first_agreement_for_replica (r);
  1468. while (agmt_obj)
  1469. {
  1470. agmt = (Repl_Agmt*)object_get_data (agmt_obj);
  1471. if(!agmt_is_enabled(agmt)){
  1472. agmt_obj = agmtlist_get_next_agreement_for_replica (r, agmt_obj);
  1473. continue;
  1474. }
  1475. dn = agmt_get_dn_byref(agmt);
  1476. conn = (Repl_Connection *)agmt_get_connection(agmt);
  1477. if(conn == NULL){
  1478. /* no connection for this agreement, log error, and move on */
  1479. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_extop: the replica (%s), is "
  1480. "missing the connection. This replica will not be released.\n", slapi_sdn_get_dn(dn));
  1481. agmt_obj = agmtlist_get_next_agreement_for_replica (r, agmt_obj);
  1482. continue;
  1483. }
  1484. crc = conn_connect(conn);
  1485. if (CONN_OPERATION_FAILED == crc ){
  1486. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "releaseRUV_extop: failed to connect "
  1487. "to repl agreement connection (%s), error %d\n",slapi_sdn_get_dn(dn), ACQUIRE_TRANSIENT_ERROR);
  1488. rc = LDAP_OPERATIONS_ERROR;
  1489. } else if (CONN_SSL_NOT_ENABLED == crc){
  1490. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "releaseRUV_extop: failed to acquire "
  1491. "repl agmt connection (%s), error %d\n",slapi_sdn_get_dn(dn), ACQUIRE_FATAL_ERROR);
  1492. rc = LDAP_OPERATIONS_ERROR;
  1493. } else {
  1494. conn_cancel_linger(conn);
  1495. crc = conn_send_extended_operation(conn, REPL_RELEASERUV_OID, extop_value, NULL, &send_msgid);
  1496. if (CONN_OPERATION_SUCCESS != crc){
  1497. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_extop: failed to send "
  1498. "releaseRUV extended op to repl agmt (%s), error %d\n", slapi_sdn_get_dn(dn), crc);
  1499. rc = LDAP_OPERATIONS_ERROR;
  1500. } else {
  1501. /* success */
  1502. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_extop: successfully sent "
  1503. "releaseRUV extended op to (%s)\n",slapi_sdn_get_dn(dn) );
  1504. rc = 0;
  1505. }
  1506. conn_start_linger(conn);
  1507. }
  1508. if(crc){
  1509. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_extop: replica (%s) has not "
  1510. "been released. You will need to rerun the task.\n",
  1511. slapi_sdn_get_dn(dn) );
  1512. }
  1513. agmt_obj = agmtlist_get_next_agreement_for_replica (r, agmt_obj);
  1514. }
  1515. free_and_return:
  1516. /*
  1517. * Set the rid as "ALREADY_RELEASED, and remove the cleaned ruv
  1518. */
  1519. if(rc == 0){
  1520. set_released_rid(ALREADY_RELEASED);
  1521. delete_cleaned_rid();
  1522. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_extop: Successfully released rid (%d)\n", rid);
  1523. } else {
  1524. slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanAllRUV_extop: Failed to release rid(%d), error (%d), "
  1525. "please retry the task.\n",rid, rc);
  1526. }
  1527. if(mtnode_ext->replica)
  1528. object_release (mtnode_ext->replica);
  1529. return rc;
  1530. }
  1531. /*
  1532. * This plugin entry point is a noop entry
  1533. * point. It's used when registering extops that
  1534. * are only used as responses. We'll never receive
  1535. * one of those, unsolicited, but we still want to
  1536. * register them so they appear in the
  1537. * supportedextension attribute in the root DSE.
  1538. */
  1539. int
  1540. extop_noop(Slapi_PBlock *pb)
  1541. {
  1542. return SLAPI_PLUGIN_EXTENDED_NOT_HANDLED;
  1543. }
  1544. static int
  1545. check_replica_id_uniqueness(Replica *replica, RUV *supplier_ruv)
  1546. {
  1547. ReplicaId local_rid = replica_get_rid(replica);
  1548. ReplicaId sup_rid = 0;
  1549. char *sup_purl = NULL;
  1550. if (ruv_get_first_id_and_purl(supplier_ruv, &sup_rid, &sup_purl) == RUV_SUCCESS) {
  1551. /* ReplicaID Uniqueness is checked only on Masters */
  1552. if ((replica_get_type(replica) == REPLICA_TYPE_UPDATABLE) &&
  1553. (sup_rid == local_rid)) {
  1554. return 1;
  1555. }
  1556. }
  1557. return 0;
  1558. }