opCheck.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867
  1. /** BEGIN COPYRIGHT BLOCK
  2. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  3. * Copyright (C) 2006 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. /*
  13. FILE : opCheck.c
  14. AUTHOR : Jean-Luc SCHWING
  15. VERSION : 1.0
  16. DATE : 04 May 1999
  17. DESCRIPTION :
  18. This file contains the functions used to manage and
  19. check the operations performed by the tool.
  20. These functions manages the operation list
  21. "mctx.opListTail", match an entry retrieved from the
  22. server to the attributes memorized for one operation,
  23. etc...
  24. LOCAL : None.
  25. */
  26. #include <pthread.h> /* Posix threads */
  27. #include <errno.h> /* errno, etc... */
  28. #include <stdlib.h> /* exit(), etc... */
  29. #include <unistd.h> /* sleep(), etc... */
  30. #include <stdio.h> /* printf(), etc... */
  31. #include <signal.h> /* sigset(), etc... */
  32. #include <string.h> /* strerror(), etc... */
  33. #include <sys/resource.h> /* setrlimit(), etc... */
  34. #include <lber.h> /* ldap C-API BER decl. */
  35. #include <ldap.h> /* ldap C-API decl. */
  36. #include <sys/poll.h> /* djani : while porting */
  37. #include <sys/socket.h> /* djani : while porting */
  38. #include <sys/types.h> /* djani : while porting */
  39. #include <netdb.h> /* djani : while porting */
  40. #include <netinet/in.h> /* djani : while porting */
  41. #ifdef LDAP_H_FROM_QA_WKA
  42. #include <proto-ldap.h> /* ldap C-API prototypes */
  43. #endif
  44. #include "port.h" /* Portability definitions */ /*JLS 29-11-00*/
  45. #include "ldclt.h" /* This tool's include file */
  46. #include "remote.h" /* Definitions common with the slave */
  47. enum {SINGLE=0,FIRST,MIDDLE,LAST};
  48. /* ****************************************************************************
  49. FUNCTION : opDecOper
  50. PURPOSE : This function decodes an LDAP operation and return a
  51. printable string.
  52. INPUT : op = operation to decode
  53. OUTPUT : None.
  54. RETURN : The decoded string.
  55. DESCRIPTION :
  56. *****************************************************************************/
  57. char *
  58. opDecOper (
  59. int op)
  60. {
  61. switch (op)
  62. {
  63. case LDAP_REQ_MODIFY: return ("modify"); break;
  64. case LDAP_REQ_ADD: return ("add"); break;
  65. case LDAP_REQ_DELETE: return ("delete"); break;
  66. case LDAP_REQ_MODRDN: return ("modrdn"); break;
  67. default: return ("??unknown??"); break;
  68. }
  69. }
  70. /* ****************************************************************************
  71. FUNCTION : LDAPMod2attributes
  72. PURPOSE : Convert a LDAPMod-like array of attributes to the
  73. internal attributes array.
  74. INPUT : mods = LDAPMod array. If NULL, attribs[] is
  75. initiated as an empty array.
  76. OUTPUT : attribs = struct attribute array. This array is of
  77. MAX_ATTRIBS length.
  78. RETURN : -1 if error, 0 else.
  79. DESCRIPTION :
  80. *****************************************************************************/
  81. int
  82. LDAPMod2attributes (
  83. LDAPMod **mods,
  84. attribute *attribs)
  85. {
  86. int i; /* For the loop */
  87. /*
  88. * Maybe there is no mods ?? This occurs for rename operation, for example.
  89. */
  90. if (mods == NULL)
  91. {
  92. attribs[0].type = NULL;
  93. return (0);
  94. }
  95. /*
  96. * Process each entry
  97. */
  98. for (i=0 ; i< MAX_ATTRIBS && mods[i] != NULL ; i++)
  99. {
  100. attribs[i].type = strdup (mods[i]->mod_type);
  101. if (attribs[i].type == NULL) /*JLS 06-03-00*/
  102. { /*JLS 06-03-00*/
  103. printf ("Error: cannot strdup(attribs[%d].type), error=%d (%s)\n",
  104. i, errno, strerror (errno)); /*JLS 06-03-00*/
  105. return (-1); /*JLS 06-03-00*/
  106. } /*JLS 06-03-00*/
  107. /*
  108. * Well, if it is a binary value, it is most likely an image
  109. * that is read by mmap and always available. Thus there is no reason
  110. * to copy it, just modify the pointers.
  111. */
  112. if (mods[i]->mod_op & LDAP_MOD_BVALUES)
  113. {
  114. attribs[i].dontFree = 1;
  115. attribs[i].length = mods[i]->mod_bvalues[0]->bv_len;
  116. attribs[i].value = mods[i]->mod_bvalues[0]->bv_val;
  117. }
  118. else
  119. {
  120. attribs[i].dontFree = 0;
  121. attribs[i].length = strlen (mods[i]->mod_values[0]);
  122. attribs[i].value = strdup (mods[i]->mod_values[0]);
  123. if (attribs[i].value == NULL) /*JLS 06-03-00*/
  124. { /*JLS 06-03-00*/
  125. printf ("Error: cannot strdup(attribs[%d].value), error=%d (%s)\n",
  126. i, errno, strerror (errno)); /*JLS 06-03-00*/
  127. return (-1); /*JLS 06-03-00*/
  128. } /*JLS 06-03-00*/
  129. }
  130. }
  131. /*
  132. * Don't forget to mark the end !
  133. */
  134. if (i<MAX_ATTRIBS)
  135. attribs[i].type = NULL;
  136. return (0);
  137. }
  138. /* ****************************************************************************
  139. FUNCTION : freeAttributesArray
  140. PURPOSE : This function is targeted to free an array of
  141. struct attribute. It does not free the array itself,
  142. but only the types and values memorized in it.
  143. INPUT : attribs = array to free.
  144. OUTPUT : None.
  145. RETURN : -1 if error, 0 else.
  146. DESCRIPTION :
  147. *****************************************************************************/
  148. int
  149. freeAttributesArray (
  150. attribute *attribs)
  151. {
  152. int i; /* For the loop */
  153. for (i=0;i<MAX_ATTRIBS&&attribs[i].type != NULL;i++)
  154. {
  155. free (attribs[i].type);
  156. if (!(attribs[i].dontFree))
  157. free (attribs[i].value);
  158. }
  159. return (0);
  160. }
  161. /* ****************************************************************************
  162. FUNCTION : opAdd
  163. PURPOSE : Add a new operation to the list.
  164. INPUT : tttctx = thread context
  165. type = operation type
  166. dn = target's DN
  167. attribs = operation attributes
  168. newRdn = new rdn (valid for rename only)
  169. newParent = new parent (valid for rename only)
  170. OUTPUT : None.
  171. RETURN : -1 if error, 0 else.
  172. DESCRIPTION : Note that the attributes given in argument are
  173. directly memorized (i.e. no copy), hence they should
  174. *not* be freed by the calling function.
  175. *****************************************************************************/
  176. int
  177. opAdd (
  178. thread_context *tttctx,
  179. int type,
  180. char *dn,
  181. LDAPMod **attribs,
  182. char *newRdn,
  183. char *newParent)
  184. {
  185. int ret; /* Return value */
  186. oper *newOper; /* New operation to memorize */
  187. if (mctx.mode & VERY_VERBOSE)
  188. printf ("T%03d: opAdd (%s, %s)\n", tttctx->thrdNum, opDecOper(type), dn);
  189. /*
  190. * Go to protected section. This will enforce the correct sequencing
  191. * of the operations performed because the whole function is lock
  192. * for the threads.
  193. * Note: Maybe reduce the size of this section ? To be checked.
  194. */
  195. if ((ret = pthread_mutex_lock (&(mctx.opListTail_mutex))) != 0)
  196. {
  197. fprintf (stderr,
  198. "T%03d: cannot pthread_mutex_lock(opListTail), error=%d (%s)\n",
  199. tttctx->thrdNum, ret, strerror (ret));
  200. fflush (stderr);
  201. return (-1);
  202. }
  203. /*
  204. * Create the new cell
  205. */
  206. newOper = (oper *) malloc (sizeof (oper));
  207. if (newOper == NULL) /*JLS 06-03-00*/
  208. { /*JLS 06-03-00*/
  209. printf ("T%03d: cannot malloc(newOper), error=%d (%s)\n", /*JLS 06-03-00*/
  210. tttctx->thrdNum, errno, strerror (errno)); /*JLS 06-03-00*/
  211. return (-1); /*JLS 06-03-00*/
  212. } /*JLS 06-03-00*/
  213. newOper->next = NULL;
  214. newOper->type = type;
  215. newOper->skipped = mctx.slavesNb;
  216. newOper->dn = strdup (dn);
  217. if (newOper->dn == NULL) /*JLS 06-03-00*/
  218. { /*JLS 06-03-00*/
  219. printf("T%03d: cannot strdup(newOper->dn), error=%d (%s)\n",/*JLS 06-03-00*/
  220. tttctx->thrdNum, errno, strerror (errno)); /*JLS 06-03-00*/
  221. return (-1); /*JLS 06-03-00*/
  222. } /*JLS 06-03-00*/
  223. newOper->newRdn = (newRdn == NULL ? NULL : strdup (newRdn));
  224. if (newOper->newRdn == NULL) /*JLS 06-03-00*/
  225. { /*JLS 06-03-00*/
  226. printf ("T%03d: cannot strdup(newOper->newRdn), error=%d (%s)\n",
  227. tttctx->thrdNum, errno, strerror (errno)); /*JLS 06-03-00*/
  228. return (-1); /*JLS 06-03-00*/
  229. } /*JLS 06-03-00*/
  230. newOper->newParent = (newParent == NULL ? NULL : strdup (newParent));
  231. if (newOper->newParent == NULL) /*JLS 06-03-00*/
  232. { /*JLS 06-03-00*/
  233. printf ("T%03d: cannot strdup(newOper->newParent), error=%d (%s)\n",
  234. tttctx->thrdNum, errno, strerror (errno)); /*JLS 06-03-00*/
  235. return (-1); /*JLS 06-03-00*/
  236. } /*JLS 06-03-00*/
  237. if (LDAPMod2attributes (attribs, newOper->attribs) < 0)
  238. return (-1);
  239. /*
  240. * Don't forget to initiate this cell's mutex !
  241. */
  242. if ((ret = pthread_mutex_init(&(newOper->skipped_mutex), NULL)) != 0)
  243. {
  244. fprintf (stderr,
  245. "T%03d: cannot initiate skipped_mutex error=%d (%s)\n",
  246. tttctx->thrdNum, ret, strerror (ret));
  247. fflush (stderr);
  248. return (-1);
  249. }
  250. /*
  251. * Link the cell
  252. */
  253. mctx.opListTail->next = newOper;
  254. mctx.opListTail = newOper;
  255. /*
  256. * Release the mutex
  257. */
  258. if ((ret = pthread_mutex_unlock (&(mctx.opListTail_mutex))) != 0)
  259. {
  260. fprintf (stderr,
  261. "T%03d: cannot pthread_mutex_unlock(opListTail), error=%d (%s)\n",
  262. tttctx->thrdNum, ret, strerror (ret));
  263. fflush (stderr);
  264. return (-1);
  265. }
  266. return (0);
  267. }
  268. /* ****************************************************************************
  269. FUNCTION : opNext
  270. PURPOSE : Return the next available operation. May return NULL
  271. if no operation available.
  272. INPUT : ctctx = thread context
  273. OUTPUT : op = next operation. May be NULL.
  274. RETURN : -1 if error, 0 else.
  275. DESCRIPTION :
  276. *****************************************************************************/
  277. int
  278. opNext (
  279. check_context *ctctx,
  280. oper **op)
  281. {
  282. int ret; /* Return value */
  283. oper *newHead; /* The new head operation */
  284. /*
  285. * Maybe there is no new operation ?
  286. */
  287. if (ctctx->headListOp->next == NULL)
  288. {
  289. *op = NULL;
  290. if (mctx.mode & VERY_VERBOSE)
  291. printf ("C%03d: opNext --> NULL\n", ctctx->thrdNum);
  292. return (0);
  293. }
  294. /*
  295. * Ok, there is one new operation. Let's skip the head and
  296. * go to the new operation...
  297. */
  298. if ((ret = pthread_mutex_lock (&(ctctx->headListOp->skipped_mutex))) != 0)
  299. {
  300. fprintf (stderr,
  301. "C%03d: cannot pthread_mutex_lock(skipped_mutex), error=%d (%s)\n",
  302. ctctx->thrdNum, ret, strerror (ret));
  303. fflush (stderr);
  304. return (-1);
  305. }
  306. newHead = ctctx->headListOp->next;
  307. ctctx->headListOp->skipped--;
  308. /*
  309. * If there is another thread that has not skipped, let's move to the
  310. * next operation and unlock the counter.
  311. */
  312. if (ctctx->headListOp->skipped != 0)
  313. {
  314. if ((ret = pthread_mutex_unlock (&(ctctx->headListOp->skipped_mutex))) != 0)
  315. {
  316. fprintf (stderr,
  317. "C%03d: cannot pthread_mutex_unlock(skipped_mutex), error=%d (%s)\n",
  318. ctctx->thrdNum, ret, strerror (ret));
  319. fflush (stderr);
  320. return (-1);
  321. }
  322. }
  323. else
  324. {
  325. /*
  326. * Well, looks like we are the last thread to skip.... Let's free this
  327. * operation. BTW, there is no reason to unlock/release the mutex because
  328. * it will be destroyed !
  329. * Note: may be NULL when LDAP_REQ_DELETE for example.
  330. */
  331. if (ctctx->headListOp->attribs != NULL)
  332. if (freeAttributesArray (ctctx->headListOp->attribs) < 0)
  333. return (-1);
  334. if (ctctx->headListOp->dn != NULL)
  335. free (ctctx->headListOp->dn);
  336. if (ctctx->headListOp->newRdn != NULL)
  337. free (ctctx->headListOp->newRdn);
  338. if (ctctx->headListOp->newParent != NULL)
  339. free (ctctx->headListOp->newParent);
  340. free (ctctx->headListOp);
  341. }
  342. /*
  343. * End of function
  344. */
  345. *op = ctctx->headListOp = newHead;
  346. if (mctx.mode & VERY_VERBOSE)
  347. printf ("C%03d: opNext --> (%s, %s)\n",
  348. ctctx->thrdNum, opDecOper ((*op)->type), (*op)->dn);
  349. return (0);
  350. }
  351. /* ****************************************************************************
  352. FUNCTION : opRead
  353. PURPOSE : Read the n'th operation from the head.
  354. INPUT : ctctx = thread context
  355. num = number of the operation to retrieve
  356. OUTPUT : op = returned operation. May be NULL.
  357. RETURN : -1 if error, 0 else.
  358. DESCRIPTION :
  359. *****************************************************************************/
  360. int
  361. opRead (
  362. check_context *ctctx,
  363. int num,
  364. oper **op)
  365. {
  366. *op = ctctx->headListOp;
  367. while (num != 0)
  368. {
  369. /*
  370. * Maybe not enough entries in the list ?
  371. */
  372. if (*op == NULL)
  373. return (0);
  374. *op = (*op)->next;
  375. num--;
  376. }
  377. /*
  378. * If there, we got it :-)
  379. */
  380. return (0);
  381. }
  382. /* ****************************************************************************
  383. FUNCTION : thOperAdd
  384. PURPOSE : This function copies an operation to the late
  385. operation list
  386. INPUT : head list and operation to copy
  387. OUTPUT : None.
  388. RETURN : New head
  389. DESCRIPTION :
  390. *****************************************************************************/
  391. thoper *
  392. thOperAdd ( thoper *head, oper *elem, int f)
  393. {
  394. thoper *new,*t=head;
  395. int i;
  396. new=malloc(sizeof(thoper));
  397. if (new == NULL) /*JLS 06-03-00*/
  398. { /*JLS 06-03-00*/
  399. printf ("Txxx: cannot malloc(new), error=%d (%s)\n", /*JLS 06-03-00*/
  400. errno, strerror (errno)); /*JLS 06-03-00*/
  401. ldcltExit (1); /*JLS 18-08-00*/
  402. } /*JLS 06-03-00*/
  403. new->next=NULL;
  404. new->first=f;
  405. new->type=elem->type;
  406. new->dn=strdup(elem->dn);
  407. if (elem->newRdn != NULL)
  408. new->newRdn=strdup(elem->newRdn);
  409. if (elem->newParent != NULL)
  410. new->newParent=strdup(elem->newParent);
  411. for(i=0;i<MAX_ATTRIBS&&elem->attribs[i].type;i++)
  412. {
  413. new->attribs[i].type=strdup(elem->attribs[i].type);
  414. if (new->attribs[i].type == NULL) /*JLS 06-03-00*/
  415. { /*JLS 06-03-00*/
  416. printf ("Txxx: cannot strdup(new->attribs[%d].type), error=%d (%s)\n",
  417. errno, i, strerror (errno)); /*JLS 06-03-00*/
  418. ldcltExit (1); /*JLS 18-08-00*/
  419. } /*JLS 06-03-00*/
  420. new->attribs[i].length = elem->attribs[i].length;
  421. if((new->attribs[i].dontFree=elem->attribs[i].dontFree))
  422. new->attribs[i].value = elem->attribs[i].value;
  423. else
  424. {
  425. new->attribs[i].value = strdup(elem->attribs[i].value);
  426. if (new->attribs[i].value == NULL) /*JLS 06-03-00*/
  427. { /*JLS 06-03-00*/
  428. printf ("Txxx: cannot strdup(new->attribs[%d].value), error=%d (%s)\n",
  429. errno, i, strerror (errno)); /*JLS 06-03-00*/
  430. ldcltExit (1); /*JLS 18-08-00*/
  431. } /*JLS 06-03-00*/
  432. }
  433. }
  434. if(i<MAX_ATTRIBS)
  435. new->attribs[i].type=NULL;
  436. if(head==NULL)
  437. return new;
  438. for(t=head;t->next;)
  439. t=t->next;
  440. t->next=new;
  441. return head;
  442. }
  443. /* ****************************************************************************
  444. FUNCTION : thOperFree
  445. PURPOSE : This function frees memory for a late operation
  446. INPUT : Head of list and operation to delete
  447. OUTPUT : None.
  448. RETURN : new head
  449. DESCRIPTION :
  450. *****************************************************************************/
  451. thoper *
  452. thOperFree (thoper *head, thoper *elem)
  453. {
  454. thoper *t;
  455. freeAttributesArray(elem->attribs);
  456. free (elem->dn);
  457. if (elem->newRdn != NULL)
  458. free (elem->newRdn);
  459. if (elem->newParent != NULL)
  460. free (elem->newParent);
  461. if(head!=elem)
  462. {
  463. for(t=head;t->next!=elem;)
  464. t=t->next;
  465. t->next=t->next->next;
  466. }
  467. else
  468. head = head->next;
  469. free(elem);
  470. return head;
  471. }
  472. /* ****************************************************************************
  473. FUNCTION : opCheckLoop
  474. PURPOSE : This function is the per slave check function
  475. INPUT : arg = this check thread's check_context
  476. OUTPUT : None.
  477. RETURN : None.
  478. DESCRIPTION :
  479. *****************************************************************************/
  480. void *
  481. opCheckLoop ( void* arg)
  482. {
  483. struct check_context *cctx=(struct check_context *)arg;
  484. struct pollfd pfd;
  485. repconfirm *recOper;
  486. oper *myop;
  487. thoper *t;
  488. unsigned char recbuf[1500];
  489. int ret,i,timeout;
  490. int cnt; /* To count loops for timeout purpose */
  491. int fndlt; /* Found late operation */
  492. int nbRead; /* Nb char read() */
  493. int status; /* Thread status */ /*JLS 17-11-00*/
  494. recOper=(repconfirm*)recbuf;
  495. pfd.fd=cctx->sockfd;
  496. pfd.events=(POLLIN|POLLPRI);
  497. pfd.revents=0;
  498. cctx->status=INITIATED;
  499. if((timeout=mctx.timeout)<30)
  500. timeout=30;
  501. /*
  502. * First time in here?
  503. */
  504. if(cctx->calls==1)
  505. cctx->dcOper=NULL;
  506. while((ret=poll(&pfd,1,500))>=0)
  507. {
  508. if(ret)
  509. {
  510. /*
  511. * Exit if read error on the net
  512. */
  513. if ((nbRead = read (pfd.fd,recOper,sizeof(repconfirm)))<0)
  514. break;
  515. if (nbRead != sizeof(repconfirm))
  516. printf ("C%03d(%s): Partial header read %d - expected %d\n",cctx->thrdNum, cctx->slaveName, nbRead, sizeof(repconfirm));
  517. recOper->type=ntohl(recOper->type);
  518. recOper->res=ntohl(recOper->res);
  519. recOper->dnSize=ntohl(recOper->dnSize);
  520. /*
  521. * Beware of structure alignment
  522. */
  523. if((nbRead=read(pfd.fd,recOper->dn+sizeof(recOper->dn),recOper->dnSize))<0)
  524. break;
  525. if (nbRead != recOper->dnSize)
  526. printf ("C%03d(%s): Partial dn read %d - expected %d\n",cctx->thrdNum, cctx->slaveName, nbRead, recOper->dnSize);
  527. if (nbRead > (1500 - sizeof(repconfirm)))
  528. printf ("C%03d(%s): Read too much %d - expected %d\n",cctx->thrdNum, cctx->slaveName, nbRead, 1500 - sizeof(repconfirm));
  529. cnt=0;
  530. cctx->nbOpRecv++;
  531. if(mctx.mode&VERY_VERBOSE)
  532. {
  533. printf("C%03d(%s): Rec %s\n",cctx->thrdNum,cctx->slaveName,recOper->dn);
  534. for(myop=cctx->headListOp->next;myop;myop=myop->next)
  535. printf("C%03d(%s): IN : %s\n",cctx->thrdNum,cctx->slaveName,myop->dn);
  536. for(t=cctx->dcOper;t;t=t->next)
  537. printf("C%03d(%s): LATE : %s\n",cctx->thrdNum,cctx->slaveName,t->dn);
  538. }
  539. /*
  540. * Do not tell me there was an error during replica...
  541. */
  542. if(recOper->res)
  543. {
  544. printf("C%03d(%s): Replica failed, op:%d(%s), dn=\"%s\" res=%d\n",
  545. cctx->thrdNum, cctx->slaveName,
  546. recOper->type, opDecOper(recOper->type),
  547. recOper->dn, recOper->res );
  548. switch (recOper->res)
  549. {
  550. case 32: cctx->nbRepFail32++ ; break;
  551. case 68: cctx->nbRepFail68++ ; break;
  552. default: cctx->nbRepFailX++ ; break;
  553. }
  554. }
  555. /*
  556. * Is this a late operation?
  557. */
  558. fndlt=0;
  559. if(cctx->dcOper)
  560. {
  561. for (i=1,t = cctx->dcOper;t;i++)
  562. if ((recOper->type!=t->type) || strcmp(recOper->dn,t->dn))
  563. t = t->next;
  564. else
  565. {
  566. /*
  567. * if this is a single operation: 132456
  568. */
  569. if(t->first==SINGLE)
  570. {
  571. /*
  572. * error.
  573. */
  574. printf("C%03d(%s): Late replica: op:%d(%s), dn=\"%s\"\n",
  575. cctx->thrdNum, cctx->slaveName,
  576. t->type, opDecOper(t->type), t->dn );
  577. cctx->nbLate++;
  578. } else if (t->first==MIDDLE)
  579. {
  580. /*
  581. * Middle of a series : 23546
  582. */
  583. printf("C%03d(%s): Early (%3d) op:%d(%s), dn=\"%s\"\n",
  584. cctx->thrdNum, cctx->slaveName,i,
  585. t->type, opDecOper(t->type), t->dn );
  586. cctx->nbEarly++;
  587. } else if(t->next)
  588. {
  589. /*
  590. * else maybe we are in a re-corrected situation.
  591. * we should receive the next one, now.
  592. */
  593. if(t->next->first!=LAST)
  594. t->next->first=FIRST;
  595. }
  596. cctx->dcOper = thOperFree (cctx->dcOper, t);
  597. fndlt=1;
  598. break;
  599. }
  600. }
  601. if(!fndlt)
  602. {
  603. /*
  604. * See if the operation we received is the same as the head
  605. */
  606. opRead(cctx,1,&myop);
  607. if (myop != NULL &&
  608. recOper->type==myop->type &&
  609. strcmp(recOper->dn,myop->dn) == 0)
  610. opNext(cctx,&myop);
  611. else
  612. {
  613. /*
  614. * Nope, look for it
  615. */
  616. for(i=2;opRead(cctx,i,&myop)==0;i++)
  617. if(myop)
  618. {
  619. if(recOper->type==myop->type &&
  620. strcmp(recOper->dn,myop->dn) == 0)
  621. {
  622. /*
  623. * Skip all between current head and this one
  624. */
  625. printf("C%03d(%s): Early (%3d) op:%d(%s), dn=\"%s\"\n", cctx->thrdNum,cctx->slaveName, i-1, recOper->type, opDecOper(recOper->type), recOper->dn );
  626. cctx->nbEarly++;
  627. opNext(cctx,&myop);
  628. /*
  629. * mark the first of the series as leader
  630. */
  631. cctx->dcOper=thOperAdd(cctx->dcOper,myop,
  632. i==2?SINGLE:FIRST);
  633. for(;i>2;i--)
  634. {
  635. opNext(cctx,&myop);
  636. /*
  637. * copy up until one before last
  638. */
  639. if(myop)
  640. thOperAdd(cctx->dcOper,myop,
  641. i==3?LAST:MIDDLE);
  642. }
  643. opNext(cctx,&myop);
  644. break;
  645. }
  646. } else break;
  647. if(!myop)
  648. {
  649. printf("C%03d(%s): Not on list op:%d(%s), dn=\"%s\"\n", cctx->thrdNum,cctx->slaveName, recOper->type, opDecOper(recOper->type), recOper->dn );
  650. cctx->nbNotOnList++;
  651. }
  652. }
  653. }
  654. }
  655. pfd.events=(POLLIN|POLLPRI);
  656. pfd.revents=0;
  657. /*
  658. * operations threads still running?
  659. */
  660. for(i=0;i<mctx.nbThreads;i++)
  661. { /*JLS 17-11-00*/
  662. if (getThreadStatus (&(tctx[i]), &status) < 0) /*JLS 17-11-00*/
  663. break; /*JLS 17-11-00*/
  664. if(status != DEAD) /*JLS 17-11-00*/
  665. {
  666. cnt=0;
  667. break;
  668. }
  669. } /*JLS 17-11-00*/
  670. /*
  671. * twice half a second...
  672. */
  673. if(++cnt>timeout*2)
  674. break;
  675. }
  676. if(mctx.mode&VERY_VERBOSE)
  677. printf("C%03d(%s): Exiting\n",cctx->thrdNum,cctx->slaveName);
  678. /*
  679. * Any operation left?
  680. */
  681. for(opNext(cctx,&myop);myop;opNext(cctx,&myop))
  682. {
  683. printf("Operation %d(%s) still on Queue for %s (%s)\n",myop->type,opDecOper(myop->type),cctx->slaveName,myop->dn);
  684. cctx->nbStillOnQ++;
  685. }
  686. for(t=cctx->dcOper;t;t=t->next)
  687. {
  688. printf("Lost op %d(%s) on %s (%s)\n",t->type,opDecOper(t->type),cctx->slaveName,t->dn);
  689. cctx->nbLostOp++;
  690. }
  691. close(cctx->sockfd);
  692. cctx->status=DEAD;
  693. pthread_exit(NULL);
  694. }
  695. /* ****************************************************************************
  696. FUNCTION : opCheckMain
  697. PURPOSE : This function is the main function of the check
  698. operation threads,
  699. INPUT : arg = NULL
  700. OUTPUT : None.
  701. RETURN : None.
  702. DESCRIPTION :
  703. *****************************************************************************/
  704. void *
  705. opCheckMain (
  706. void *arg)
  707. {
  708. struct sockaddr_in srvsaddr,claddr;
  709. struct hostent cltaddr;
  710. #ifdef LINUX
  711. struct hostent *stupidlinux=NULL;
  712. #endif
  713. struct linger lopt;
  714. uint32_t ipaddr;
  715. int newfd,sockfd,ncctx,i,err;
  716. char buffer[128];
  717. int retry; /* To retry on EINTR */
  718. /*
  719. * Initialization
  720. */
  721. srvsaddr.sin_addr.s_addr=htonl(INADDR_ANY);
  722. srvsaddr.sin_family=AF_INET;
  723. srvsaddr.sin_port=htons(masterPort);
  724. /*
  725. * Let's go !!!
  726. */
  727. if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)
  728. {
  729. perror("Socket");
  730. ldcltExit(1); /*JLS 18-08-00*/
  731. }
  732. i=1;
  733. if(setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,(void *)&i,sizeof(int))!=0)
  734. perror("Sockopt");
  735. if(bind(sockfd,(struct sockaddr*)&srvsaddr,sizeof(struct sockaddr))!=0)
  736. {
  737. perror("Bind");
  738. ldcltExit(1); /*JLS 18-08-00*/
  739. }
  740. if(listen(sockfd,1)!=0)
  741. perror("listen");
  742. for(ncctx=0;;)
  743. {
  744. i=sizeof(claddr);
  745. retry = 1;
  746. while (retry)
  747. {
  748. if ((newfd=accept(sockfd,(struct sockaddr *)&claddr,&i))>=0)
  749. retry = 0;
  750. else
  751. if (errno != EINTR)
  752. {
  753. perror("Accept");
  754. ldcltExit(1); /*JLS 18-08-00*/
  755. }
  756. }
  757. /*
  758. * get client's name
  759. */
  760. ipaddr=ntohl(claddr.sin_addr.s_addr);
  761. #ifdef LINUX
  762. gethostbyaddr_r((char*)&ipaddr,sizeof(ipaddr),AF_INET,&cltaddr,
  763. buffer,128, &stupidlinux, &err);
  764. #else
  765. #if defined(HPUX) && defined(__LP64__)
  766. gethostbyaddr((char*)&ipaddr,sizeof(ipaddr),AF_INET);
  767. #else
  768. gethostbyaddr_r((char*)&ipaddr,sizeof(ipaddr),AF_INET,&cltaddr,
  769. buffer,128,&err);
  770. #endif
  771. #endif
  772. i=1;
  773. if(setsockopt(newfd,IPPROTO_TCP, TCP_NODELAY,(void *)&i,sizeof(int))!=0)
  774. perror("Nagle");
  775. /*
  776. * Linger: when connection ends, send an RST instead of a FIN
  777. * This way the client will have a fail on the first write instead of
  778. * the second
  779. */
  780. lopt.l_onoff=1;
  781. lopt.l_linger=0;
  782. if(setsockopt(newfd,SOL_SOCKET,SO_LINGER,(void*)&lopt,sizeof(struct linger))<0)
  783. perror("Linger");
  784. /*
  785. * Search for an empty client slot. If a client reconnects, use the
  786. * same slot
  787. */
  788. for(i=0;i<mctx.slavesNb;i++)
  789. {
  790. if(cctx[i].calls==0)
  791. {
  792. i=ncctx++;
  793. break;
  794. }
  795. if(cctx[i].slaveName&&cctx[i].status==DEAD)
  796. if(strcmp(cctx[i].slaveName,cltaddr.h_name)==0)
  797. break;
  798. }
  799. if(i>=mctx.slavesNb)
  800. {
  801. fprintf (stderr, "ldclt: Too many slaves %s\n",cltaddr.h_name);
  802. close(newfd);
  803. continue;
  804. }
  805. cctx[i].sockfd=newfd;
  806. cctx[i].calls++;
  807. cctx[i].slaveName=strdup(cltaddr.h_name);
  808. if ((err = pthread_create (&(cctx[i].tid), NULL,
  809. opCheckLoop, (void *)&(cctx[i]))) != 0)
  810. {
  811. fprintf (stderr, "ldclt: %s\n", strerror (err));
  812. fprintf (stderr, "Error: cannot create thread opCheck for %s\n",
  813. cltaddr.h_name);
  814. fflush (stderr);
  815. }
  816. else
  817. mctx.slaveConn = 1;
  818. }
  819. close(sockfd);
  820. }