distGapLib.c
上传用户:nvosite88
上传日期:2007-01-17
资源大小:4983k
文件大小:35k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* distGapLib.c - distributed group agreement protocol library */
  2. /* Copyright 1999 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01i,24may99,drm  added vxfusion prefix to VxFusion related includes
  8. 01h,11feb99,drm  fixed endian bugs in GAP protocol - added htons() / ntohs()
  9. 01g,11sep98,drm  changed #include "distStatLib.h" to "private/distLibP.h"
  10. 01f,20may98,drm  removed local variable distNodeLclState which was no longer
  11.                  being used.
  12. 01e,13may98,ur   review of some comments
  13. 01d,15apr98,ur   replaced misleading comments
  14. 01c,13mar98,ur   fixed crash detection
  15. 01b,07jan98,ur   fixed "group id already in use"
  16. 01a,15jul97,ur   written
  17. */
  18. /*
  19. DESCRIPTION
  20. This library contains the "group agreement protocol" (GAP).
  21. */
  22. #include "vxWorks.h"
  23. #if defined (DIST_GAP_REPORT) || defined (DIST_DIAGNOSTIC)
  24. #include "stdio.h"
  25. #endif
  26. #include "stdlib.h"
  27. #include "string.h"
  28. #include "sllLib.h"
  29. #include "dllLib.h"
  30. #include "msgQLib.h"
  31. #include "taskLib.h"
  32. #include "netinet/in.h"
  33. #include "private/semLibP.h"
  34. #include "vxfusion/msgQDistGrpLib.h"
  35. #include "vxfusion/distIfLib.h"
  36. #include "vxfusion/private/distLibP.h"
  37. #include "vxfusion/private/distNameLibP.h"
  38. #include "vxfusion/private/msgQDistGrpLibP.h"
  39. #include "vxfusion/private/distNetLibP.h"
  40. #include "vxfusion/private/distNodeLibP.h"
  41. LOCAL DL_LIST gapInProgress;
  42. LOCAL SEMAPHORE distGapSemaphore;
  43. /* local prototypes */
  44. LOCAL void distGapCatchCrashed (DIST_NODE_ID nodeId);
  45. LOCAL void distGapPh1Done (DIST_GRP_DB_NODE *pDistGrp);
  46. LOCAL STATUS distGapTry (DIST_NODE_ID distNodeId,
  47. DIST_GRP_DB_NODE *pDbNode);
  48. LOCAL BOOL distGapOutstandConc (DIST_NODE_DB_NODE *pDistNodeDbNode,
  49. SL_LIST *pOutstand);
  50. LOCAL BOOL distGapOutstandOk (DIST_GAP_NODE *pDistGapNode,
  51. DIST_NODE_ID distNodeIdOk);
  52. LOCAL void distGapOutstandDel (DIST_GAP_NODE *pDistGapNode,
  53. DIST_GAP_RESPONSE *pDistGapResponse,
  54. DIST_GAP_RESPONSE *pDistGapResponsePrev);
  55. LOCAL DIST_STATUS distGapInput (DIST_NODE_ID nodeIdSrc,
  56. DIST_TBUF_HDR *pTBufHdr);
  57. #ifdef DIST_GAP_TASK
  58. LOCAL void distGapTimerTask (void);
  59. LOCAL void distGapTimer (void);
  60. #endif
  61. /*******************************************************************************
  62. *
  63. * distGapLibInit - 
  64. *
  65. * NOMANUAL
  66. */
  67. STATUS distGapLibInit()
  68. {
  69. #ifdef DIST_GAP_TASK
  70. int tid;
  71. #endif
  72. dllInit (&gapInProgress);
  73. #ifdef DIST_GAP_TASK
  74. tid = taskSpawn ("tDistGAP",
  75. DIST_GAP_MGR_PRIO,
  76. VX_SUPERVISOR_MODE | VX_UNBREAKABLE,
  77. DIST_GAP_MGR_STACK_SZ,
  78. (FUNCPTR) distGapTimerTask,
  79. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  80. if (tid == ERROR)
  81. return (ERROR);
  82. #endif
  83. distCtl (DIST_CTL_CRASHED_HOOK, (int) distGapCatchCrashed);
  84. /*
  85.  * Add GAP input function to table of services.
  86.  */
  87. return (distNetServAdd (DIST_PKT_TYPE_GAP, distGapInput,
  88. DIST_GAP_SERV_NAME, DIST_GAP_SERV_NET_PRIO,
  89. DIST_GAP_SERV_TASK_PRIO, DIST_GAP_SERV_TASK_STACK_SZ));
  90. }
  91. /*******************************************************************************
  92. *
  93. * distGapCatchCrashed - get notified by a node crash
  94. *
  95. * NOMANUAL
  96. */
  97. LOCAL void distGapCatchCrashed
  98. (
  99. DIST_NODE_ID crashedId
  100. )
  101. {
  102. DIST_GRP_DB_NODE *pGrpDone;
  103. DIST_GAP_NODE *pGapNode;
  104. BOOL more;
  105. #ifdef DIST_GAP_REPORT
  106. printf ("distGapCatchCrashed: node %ld crashedn", crashedId);
  107. #endif
  108. pGapNode = (DIST_GAP_NODE *) DLL_FIRST (&gapInProgress);
  109. while (pGapNode != NULL)
  110. {
  111. msgQDistGrpDbLock();
  112. pGrpDone = pGapNode->pGapGrp;
  113. distGapLock();
  114. more = distGapOutstandOk (pGapNode, crashedId);
  115. distGapUnlock();
  116. pGapNode = (DIST_GAP_NODE *) DLL_NEXT (pGapNode);
  117. if (more == FALSE) /* this was the last node we waited for */
  118. {
  119. msgQDistGrpLclSetState (pGrpDone, DIST_GRP_STATE_GLOBAL);
  120. msgQDistGrpLclSetCreator (pGrpDone, distNodeLocalGetId());
  121. msgQDistGrpDbUnlock();
  122. distGapPh1Done (pGrpDone);
  123. }
  124. else
  125. msgQDistGrpDbUnlock();
  126. }
  127. }
  128. /*******************************************************************************
  129. *
  130. * distGapOutstandLink - link all operational nodes to GAP structure
  131. *
  132. * NOMANUAL
  133. */
  134. void distGapOutstandLink
  135. (
  136. DIST_GAP_NODE *distGapNode
  137. )
  138. {
  139. sllInit (&distGapNode->gapOutstand);
  140. distNodeEach (distGapOutstandConc, (int) &distGapNode->gapOutstand);
  141. }
  142. /*******************************************************************************
  143. *
  144. * distGapOutstandConc - called by distGapOutstandLink()
  145. *
  146. * NOMANUAL
  147. */
  148. LOCAL BOOL distGapOutstandConc
  149. (
  150. DIST_NODE_DB_NODE *pDistNodeDbNode,
  151. SL_LIST *pOutstand
  152. )
  153. {
  154. DIST_GAP_RESPONSE *pDistGapResp;
  155. if (pDistNodeDbNode->nodeState == DIST_NODE_STATE_OPERATIONAL &&
  156. pDistNodeDbNode->nodeId != DIST_IF_BROADCAST_ADDR)
  157. {
  158. pDistGapResp =
  159. (DIST_GAP_RESPONSE *) malloc (sizeof (DIST_GAP_RESPONSE));
  160. if (pDistGapResp == NULL)
  161. return (ERROR);
  162. pDistGapResp->pGapResponseNode = pDistNodeDbNode;
  163. sllPutAtHead (pOutstand, (SL_NODE *) pDistGapResp);
  164. }
  165. return (TRUE); /* continue */
  166. }
  167. /*******************************************************************************
  168. *
  169. * distGapOutstandUnlink - Free all nodes linked to the GAP structure
  170. *
  171. * NOMANUAL
  172. */
  173. void distGapOutstandUnlink
  174. (
  175. DIST_GAP_NODE *distGapNode
  176. )
  177. {
  178. DIST_GAP_RESPONSE *pDistGapResponse;
  179. DIST_GAP_RESPONSE *pDistGapResponsePrev = NULL;
  180. if (distGapNode == NULL)
  181. return;
  182. pDistGapResponse = (DIST_GAP_RESPONSE *)
  183. SLL_FIRST (&distGapNode->gapOutstand);
  184. while (pDistGapResponse != NULL)
  185. {
  186. sllRemove (&distGapNode->gapOutstand, (SL_NODE *) pDistGapResponse,
  187. (SL_NODE *) pDistGapResponsePrev);
  188. pDistGapResponsePrev = pDistGapResponse;
  189. pDistGapResponse = (DIST_GAP_RESPONSE *) SLL_NEXT (pDistGapResponse);
  190. free (pDistGapResponsePrev);
  191. }
  192. }
  193. /*******************************************************************************
  194. *
  195. * distGapOutstandOk - Delete a single node from the GAP structure's node list
  196. *
  197. * RETURNS: TRUE if there are more outstanding responses, or FALSE if the
  198. * job is done.
  199. *
  200. * NOMANUAL
  201. */
  202. LOCAL BOOL distGapOutstandOk
  203. (
  204. DIST_GAP_NODE *pDistGapNode,
  205. DIST_NODE_ID distNodeIdOk
  206. )
  207. {
  208. DIST_GAP_RESPONSE *pDistGapResp;
  209. DIST_GAP_RESPONSE *pDistGapRespPrev;
  210. pDistGapResp = (DIST_GAP_RESPONSE *)
  211. SLL_FIRST (&pDistGapNode->gapOutstand);
  212. pDistGapRespPrev = NULL;
  213. while (pDistGapResp != NULL &&
  214.    pDistGapResp->pGapResponseNode->nodeId != distNodeIdOk)
  215. {
  216. pDistGapRespPrev = pDistGapResp;
  217. pDistGapResp = (DIST_GAP_RESPONSE *) SLL_NEXT (pDistGapResp);
  218. }
  219. if (pDistGapResp != NULL)
  220. {
  221. distGapOutstandDel (pDistGapNode, pDistGapResp, pDistGapRespPrev);
  222. if (SLL_FIRST (&pDistGapNode->gapOutstand) == NULL)
  223. return (FALSE);
  224. }
  225. return (TRUE);
  226. }
  227. /*******************************************************************************
  228. *
  229. * distGapOutstandDel - Delete a single node 
  230. *
  231. * NOMANUAL
  232. */
  233. LOCAL void distGapOutstandDel
  234. (
  235. DIST_GAP_NODE *pDistGapNode,
  236. DIST_GAP_RESPONSE *pDistGapResponse,
  237. DIST_GAP_RESPONSE *pDistGapResponsePrev
  238. )
  239. {
  240. sllRemove ((SL_LIST *) &pDistGapNode->gapOutstand,
  241. (SL_NODE *) pDistGapResponse, (SL_NODE *) pDistGapResponsePrev);
  242. free (pDistGapResponse);
  243. #ifdef DIST_GAP_REPORT
  244. {
  245. SL_NODE *pNode = SLL_FIRST (&pDistGapNode->gapOutstand);
  246. int i;
  247. for (i=0; pNode; i++)
  248. pNode = SLL_NEXT (pNode);
  249. printf ("distGapOutstandDel: %d nodes outstandingn", i);
  250. }
  251. #endif
  252. }
  253. /*******************************************************************************
  254. *
  255. * distGapPh1Done - phase 1 is done
  256. *
  257. * NOMANUAL
  258. */
  259. LOCAL void distGapPh1Done
  260. (
  261. DIST_GRP_DB_NODE *pDistGrp
  262. )
  263. {
  264. /*
  265.  * List of outstanding responses is empty now. We are done.
  266.  * Send SET telegram and wakeup sleeping task.
  267.  */
  268. DIST_PKT_GAP_SET distPktGapSet;
  269. #ifdef DIST_GAP_REPORT
  270. printf ("distGapInput/OK: GAP phase 1 done.n");
  271. #endif
  272. /*
  273.  * Build SET telegram and broadcast it.
  274.  */
  275. distPktGapSet.setHdr.pktType = DIST_PKT_TYPE_GAP;
  276. distPktGapSet.setHdr.pktSubType = DIST_PKT_TYPE_GAP_SET;
  277. distPktGapSet.setId = htons (pDistGrp->grpDbId);
  278. strcpy ((char *) &distPktGapSet.setName,
  279. (char *) &pDistGrp->grpDbName);
  280. #ifdef DIST_GAP_REPORT
  281. printf ("distGapInput/OK: GAP phase 2 -- broadcast SET `%s'/%d.n",
  282. distPktGapSet.setName, distPktGapSet.setId);
  283. #endif
  284. distNetSend (DIST_IF_BROADCAST_ADDR, (DIST_PKT *) &distPktGapSet,
  285. sizeof (distPktGapSet), WAIT_FOREVER, DIST_GAP_PRIO);
  286. /*
  287.  * Wakeup initiator.
  288.  */
  289. semGive (&pDistGrp->pGrpDbGapNode->gapWaitFor);
  290. }
  291. /*******************************************************************************
  292. *
  293. * distGapNodeInit - Initialize a GAP node
  294. *
  295. * NOMANUAL
  296. */
  297. void distGapNodeInit
  298. (
  299. DIST_GAP_NODE *pDistGapNode,
  300. DIST_GRP_DB_NODE *pDistGrpDbNode,
  301. BOOL link
  302. )
  303. {
  304. if (link)
  305. distGapOutstandLink(pDistGapNode);
  306. semBInit (&(pDistGapNode->gapWaitFor), SEM_Q_FIFO, SEM_EMPTY);
  307. pDistGapNode->pGapGrp = pDistGrpDbNode;
  308. pDistGapNode->gapTimeout = DIST_GAP_TRY_TIMO;
  309. pDistGapNode->gapRetries = 1;
  310. distGapLock();
  311. dllInsert (&gapInProgress, NULL, &(pDistGapNode->gapLink));
  312. distGapUnlock();
  313. }
  314. /*******************************************************************************
  315. *
  316. * distGapNodeDelete - Delete a GAP node
  317. *
  318. * NOMANUAL
  319. */
  320. void distGapNodeDelete
  321. (
  322. DIST_GAP_NODE *pDistGapNode
  323. )
  324. {
  325. distGapLock();
  326. dllRemove (&gapInProgress, (DL_NODE *) &(pDistGapNode->gapLink));
  327. distGapUnlock();
  328. }
  329. /*******************************************************************************
  330. *
  331. * distGapStart - Start GAP (group agreement protocol)
  332. *
  333. * Do a TRY in order to create a new group.
  334. *
  335. * NOMANUAL
  336. */
  337. DIST_MSG_Q_GRP_ID distGapStart
  338. (
  339. DIST_GRP_DB_NODE *pDistGrpDbNode
  340. )
  341. {
  342. DIST_GAP_NODE distGapNode;
  343. DIST_MSG_Q_GRP_ID uniqGrpId;
  344. if (distNodeGetNumNodes(DIST_NODE_NUM_NODES_ALIVE) == 1)
  345. {
  346. /* we are alone */
  347. msgQDistGrpLclSetState (pDistGrpDbNode, DIST_GRP_STATE_GLOBAL);
  348. msgQDistGrpLclSetCreator (pDistGrpDbNode, distNodeLocalGetId());
  349. return (pDistGrpDbNode->grpDbId);
  350. }
  351. /*
  352.  * Init GAP Node and link it to the group database node and
  353.  * the list of active GAPs.
  354.  * GAP initialization includes the linking of all nodes,
  355.  * currently known in the system. When a response comes in,
  356.  * the linked list is updated (the node is removed from the
  357.  * list).
  358.  */
  359. distGapNodeInit(&distGapNode, pDistGrpDbNode, TRUE);
  360. pDistGrpDbNode->pGrpDbGapNode = &distGapNode;
  361. /*
  362.  * Send TRY.
  363.  */
  364. distGapTry (DIST_IF_BROADCAST_ADDR, pDistGrpDbNode);
  365. /*
  366.  * Wait on GAP Node.
  367.  */
  368. semTake (&distGapNode.gapWaitFor, WAIT_FOREVER);
  369. /*
  370.  * Cleanup
  371.  */
  372. if (pDistGrpDbNode->pGrpDbGapNode)
  373. {
  374. DIST_GAP_NODE *pGapNode = pDistGrpDbNode->pGrpDbGapNode;
  375. pDistGrpDbNode->pGrpDbGapNode = NULL;
  376. distGapNodeDelete (pGapNode);
  377. }
  378. #ifdef DIST_DIAGNOSTIC
  379. if (pDistGrpDbNode->grpDbState != DIST_GRP_STATE_GLOBAL)
  380. distLog ("distGapStart: group has no global staten");
  381. #endif
  382. /*
  383.  * Ask for group id.
  384.  */
  385. msgQDistGrpDbLock();
  386. uniqGrpId = msgQDistGrpLclGetId (pDistGrpDbNode);
  387. msgQDistGrpDbUnlock();
  388. return (uniqGrpId);
  389. }
  390. /*******************************************************************************
  391. *
  392. * distGapTry - Send a TRY, for a specified group
  393. *
  394. * NOMANUAL
  395. */
  396. LOCAL STATUS distGapTry
  397. (
  398. DIST_NODE_ID distNodeId, /* node address */
  399. DIST_GRP_DB_NODE *pDistGrpDbNode /* group to try */
  400. )
  401. {
  402. DIST_PKT_GAP_TRY distPktGapTry;
  403. STATUS status;
  404. /*
  405.  * Build TRY telegram and send it.
  406.  */
  407. distPktGapTry.tryHdr.pktType = DIST_PKT_TYPE_GAP;
  408. distPktGapTry.tryHdr.pktSubType = DIST_PKT_TYPE_GAP_TRY;
  409. distPktGapTry.tryId = htons (pDistGrpDbNode->grpDbId);  /* uint16 */
  410. strcpy ((char *) &distPktGapTry.tryName,
  411. (char *) &pDistGrpDbNode->grpDbName);
  412. #ifdef DIST_GAP_REPORT
  413. printf ("distGapTry: send a TRY for `%s'/%d to node %ldn",
  414. (char *) &pDistGrpDbNode->grpDbName,
  415. pDistGrpDbNode->grpDbId, distNodeId);
  416. #endif
  417. status = distNetSend (distNodeId, (DIST_PKT *) &distPktGapTry,
  418. sizeof (distPktGapTry), WAIT_FOREVER, DIST_GAP_PRIO);
  419. return (status);
  420. }
  421. /*******************************************************************************
  422. *
  423. * distGapInput - GAP incoming message dispatcher
  424. *
  425. * NOMANUAL
  426. */
  427. LOCAL DIST_STATUS distGapInput
  428. (
  429. DIST_NODE_ID distNodeIdSrc,
  430. DIST_TBUF_HDR *pTBufHdr
  431. )
  432. {
  433. char distPktGap[DIST_PKT_GAP_MAX_LEN];
  434. distTBufCopy (DIST_TBUF_GET_NEXT (pTBufHdr), 0, (char *) &distPktGap,
  435. DIST_PKT_GAP_MAX_LEN);
  436. switch (((DIST_PKT *) &distPktGap)->pktSubType)
  437. {
  438. /*
  439.  * We have received a TRY. Look if there are conflicts. If not,
  440.  * respond with OK, else compare the node ids (buddy algorithm)
  441.  * and send either OK or REJECT.
  442.  */
  443. case DIST_PKT_TYPE_GAP_TRY:
  444. {
  445. DIST_PKT_GAP_TRY *pDistPktGapTry = (DIST_PKT_GAP_TRY *) &distPktGap;
  446. DIST_GRP_DB_NODE *pGrpFoundById;
  447. DIST_GRP_DB_NODE *pGrpFoundByName;
  448. DIST_GRP_STATE grpState;
  449. /* Convert tryId (uint16) to host order */
  450. pDistPktGapTry->tryId = ntohs (pDistPktGapTry->tryId);
  451. /*
  452.  * What can we read out form the TRY-id?
  453.  *
  454.  * If we receive a TRY for an id that is greater the one
  455.  * we would try, we have missed a TRY.
  456.  * This can happen, if some node sent a TRY, which is correctly
  457.  * received by some other node, but not by us--retransmission
  458.  * is enforced, but takes some time. The other node immediately
  459.  * starts sendind a TRY of its own, which in turn is received by us
  460.  * correctly. As you can see, it seams for us that we have
  461.  * missed a TRY--in fact the missing TRY is just delayed.
  462.  *
  463.  * If we receive a TRY for an id that is lower the one
  464.  * we would try, it is *NOT* for sure, that the remote
  465.  * node has missed a TRY. This can happen if an outgoing
  466.  * TRY is delayed at the remote node.
  467.  */
  468. #ifdef DIST_GAP_REPORT
  469. printf ("distGapInput: received TRY for `%s'/%d from node %ldn",
  470. pDistPktGapTry->tryName, pDistPktGapTry->tryId, distNodeIdSrc);
  471. #endif
  472. msgQDistGrpDbLock();
  473. /*
  474.  * Test for conflicts. Try to find id and name in local database.
  475.  * If found, ask for GLOBAL state.
  476.  */
  477. pGrpFoundById = msgQDistGrpLclFindById (pDistPktGapTry->tryId);
  478. if (pGrpFoundById)
  479. {
  480. grpState = msgQDistGrpLclGetState (pGrpFoundById);
  481. #ifdef DIST_GAP_REPORT
  482. printf ("distGapInput/TRY: group id %d already in %s usen",
  483. pDistPktGapTry->tryId,
  484. (grpState == DIST_GRP_STATE_GLOBAL) ? "global" : "local");
  485. #endif
  486. if (grpState == DIST_GRP_STATE_GLOBAL)
  487. {
  488. /*
  489.  * Someone sends a TRY for an id, already confirmed
  490.  * by GAP. Give him a reject.
  491.  */
  492. DIST_PKT_GAP_REJECT *pDistPktGapReject;
  493. msgQDistGrpDbUnlock();
  494. #ifdef DIST_GAP_REPORT
  495. printf ("distGapInput:TRY: group id already in use; rejectn");
  496. #endif
  497. pDistPktGapReject = (DIST_PKT_GAP_REJECT *) &distPktGap;
  498. pDistPktGapReject->rejectHdr.pktSubType =
  499. DIST_PKT_TYPE_GAP_REJECT;
  500. pDistPktGapReject->rejectId = htons (pDistPktGapReject->rejectId);
  501. distNetSend(distNodeIdSrc, (DIST_PKT *) pDistPktGapReject,
  502. sizeof (*pDistPktGapReject), WAIT_FOREVER,
  503. DIST_GAP_PRIO);
  504. break;
  505. }
  506. }
  507. pGrpFoundByName = msgQDistGrpLclFindByName (pDistPktGapTry->tryName);
  508. if (pGrpFoundByName)
  509. {
  510. grpState = msgQDistGrpLclGetState (pGrpFoundByName);
  511. #ifdef DIST_GAP_REPORT
  512. printf ("distGapInput/TRY: group name `%s' already in %s usen",
  513. pDistPktGapTry->tryName,
  514. (grpState == DIST_GRP_STATE_GLOBAL) ? "global" : "local");
  515. #endif
  516. if (grpState == DIST_GRP_STATE_GLOBAL)
  517. {
  518. DIST_PKT_GAP_SET *pDistPktGapSet;
  519. /*
  520.  * Someone sends a TRY for a group that is in GLOBAL
  521.  * state here.
  522.  * This can happen, if
  523.  * 1) someone did a TRY before receiving our
  524.  *    SET (remote TRYs do not force creation of a
  525.  *    database entry).
  526.  * 2) a WAIT timed out and the state shifts to
  527.  *    WAIT_TRY. In this case the remote node has
  528.  *    missed the SET. Directly respond with SET.
  529.  */
  530. /*
  531.  * Respond with SET.
  532.  */
  533. pDistPktGapSet = (DIST_PKT_GAP_SET *) &distPktGap;
  534. pDistPktGapSet->setHdr.pktSubType = DIST_PKT_TYPE_GAP_SET;
  535. pDistPktGapSet->setId = msgQDistGrpLclGetId (pGrpFoundByName);
  536. msgQDistGrpDbUnlock();
  537. #ifdef DIST_GAP_REPORT
  538. printf ("distGapInput/TRY: respond with SET `%s'/%dn",
  539. pDistPktGapSet->setName, pDistPktGapSet->setId);
  540. #endif
  541. /* Convert setId (uint16) to network byte order */
  542. pDistPktGapSet->setId = htons (pDistPktGapSet->setId);
  543. distNetSend(distNodeIdSrc, (DIST_PKT *) pDistPktGapSet,
  544. sizeof (*pDistPktGapSet), WAIT_FOREVER,
  545. DIST_GAP_PRIO);
  546. break;
  547. }
  548. }
  549. else
  550. {
  551. DIST_GRP_DB_NODE *pDistGrp;
  552. /*
  553.  * Create DB entry for new group.
  554.  */
  555. pDistGrp = msgQDistGrpLclCreate (pDistPktGapTry->tryName,
  556. pDistPktGapTry->tryId, DIST_GRP_STATE_REMOTE_TRY);
  557. if (pDistGrp == NULL)
  558. {
  559. /*
  560.  * We cannot create a new node in the group database.
  561.  * This is a fatal error.
  562.  */
  563. distPanic ("distGapInput:TRY: creation of new node failedn");
  564. }
  565. /* only temporary, creator may change */
  566. msgQDistGrpLclSetCreator (pDistGrp, distNodeIdSrc);
  567. pDistGrp->pGrpDbGapNode = NULL;
  568. }
  569. /*
  570.  * If there is a local group with the same name as currently
  571.  * tried, it is not in GLOBAL state. We have checked this
  572.  * before.
  573.  */
  574. if (pGrpFoundById == NULL && pGrpFoundByName == NULL)
  575. {
  576. DIST_PKT_GAP_OK *pDistPktGapOk;
  577. /*
  578.  * No conflicts. Neither group id nor group name
  579.  * are used in the local database.
  580.  */
  581. distGrpIdNext++;
  582. msgQDistGrpDbUnlock();
  583. /*
  584.  * Respond with OK.
  585.  */
  586. #ifdef DIST_GAP_REPORT
  587. printf ("distGapInput/TRY: neither id nor name used; respond OKn");
  588. #endif
  589. pDistPktGapOk = (DIST_PKT_GAP_OK *) &distPktGap;
  590. pDistPktGapOk->okHdr.pktSubType = DIST_PKT_TYPE_GAP_OK;
  591. /* Convert okId (uint16) to network byte order */
  592. pDistPktGapOk->okId = htons (pDistPktGapOk->okId);
  593. distNetSend(distNodeIdSrc, (DIST_PKT *) pDistPktGapOk,
  594. sizeof (*pDistPktGapOk), WAIT_FOREVER, DIST_GAP_PRIO);
  595. break;
  596. }
  597. if (pGrpFoundById == pGrpFoundByName)
  598. {
  599. /*
  600.  * No conflict. There is already an object that
  601.  * exactly matches the remote one.
  602.  */
  603. DIST_PKT_GAP_OK *pDistPktGapOk = (DIST_PKT_GAP_OK *) &distPktGap;
  604. msgQDistGrpDbUnlock();
  605. /*
  606.  * Respond with OK.
  607.  */
  608. #ifdef DIST_GAP_REPORT
  609. printf ("distGapInput/TRY: id and name match; respond OKn");
  610. #endif
  611. pDistPktGapOk->okHdr.pktSubType = DIST_PKT_TYPE_GAP_OK;
  612. /* Convert okId (uint16) to network byte order */
  613.             pDistPktGapOk->okId = htons (pDistPktGapOk->okId);
  614. distNetSend(distNodeIdSrc, (DIST_PKT *) pDistPktGapOk,
  615. sizeof (*pDistPktGapOk), WAIT_FOREVER, DIST_GAP_PRIO);
  616. break;
  617. }
  618. /*
  619.  * There is a conflict. Compare node ids to solve the conflict.
  620.  * This is kind of a game: the one with the higher node id wins.
  621.  */
  622. if (distNodeLocalGetId() < distNodeIdSrc)
  623. {
  624. DIST_PKT_GAP_OK *pDistPktGapOk;
  625. /*
  626.  * We have lost. Do a local cleanup and send OK.
  627.  */
  628. distGrpIdNext++;
  629. #ifdef DIST_GAP_REPORT
  630. printf ("distGapInput/TRY: we have lost, trying %dn",
  631. pDistPktGapTry->tryId);
  632. #endif
  633. if (pGrpFoundByName)
  634. {
  635. /*
  636.  * Someone else is trying to create the same group, but has
  637.  * a different group id. We have lost, so let us wait until
  638.  * we receive a SET.
  639.  */
  640. /*
  641.  * Remove linked list of outstanding responses.
  642.  */
  643. distGapOutstandUnlink (pGrpFoundByName->pGrpDbGapNode);
  644. /*
  645.  * Set WAIT state.
  646.  */
  647. msgQDistGrpLclSetState (pGrpFoundByName, DIST_GRP_STATE_WAIT);
  648. pGrpFoundByName->pGrpDbGapNode->gapTimeout = DIST_GAP_WAIT_TIMO;
  649. msgQDistGrpDbUnlock ();
  650. }
  651. else
  652. {
  653. /*
  654.  * Someone else is trying to create a group with an
  655.  * id, that was also proposed by us. We have lost,
  656.  * so forget about the id and try another one.
  657.  */
  658. /*
  659.  * Cleanup and reinitialize the GAP structure.
  660.  */
  661. distGapOutstandUnlink (pGrpFoundById->pGrpDbGapNode);
  662. distGapOutstandLink (pGrpFoundById->pGrpDbGapNode);
  663. pGrpFoundById->pGrpDbGapNode->gapTimeout = DIST_GAP_TRY_TIMO;
  664. pGrpFoundById->pGrpDbGapNode->gapRetries = 1;
  665. /*
  666.  * Get a new id and reset state.
  667.  */
  668. msgQDistGrpLclSetId (pGrpFoundByName, distGrpIdNext++);
  669. msgQDistGrpLclSetState (pGrpFoundByName,
  670. DIST_GRP_STATE_LOCAL_TRY);
  671. msgQDistGrpDbUnlock();
  672. /*
  673.  * Have a different TRY.
  674.  */
  675. distGapTry (DIST_IF_BROADCAST_ADDR, pGrpFoundByName);
  676. }
  677. #ifdef DIST_GAP_REPORT
  678. printf ("distGapInput/TRY: respond with OKn");
  679. #endif
  680. pDistPktGapOk = (DIST_PKT_GAP_OK *) &distPktGap;
  681. pDistPktGapOk->okHdr.pktSubType = DIST_PKT_TYPE_GAP_OK;
  682. /* Convert okId (uint16) to network byte order */
  683.             pDistPktGapOk->okId = htons (pDistPktGapOk->okId);
  684. distNetSend(distNodeIdSrc, (DIST_PKT *) pDistPktGapOk,
  685. sizeof (*pDistPktGapOk), WAIT_FOREVER, DIST_GAP_PRIO);
  686. }
  687. else
  688. {
  689. /*
  690.  * We won.
  691.  */
  692. #ifdef DIST_GAP_REPORT
  693. printf ("distGapInput/TRY: we have won, trying %dn",
  694. pDistPktGapTry->tryId);
  695. #endif
  696. msgQDistGrpDbUnlock();
  697. if (pGrpFoundByName)
  698. {
  699. /*
  700.  * Someone is trying to create the same group, we
  701.  * are trying, with a different group id. We won
  702.  * the game, ask him to wait (ASK_WAIT).
  703.  */
  704. DIST_PKT_GAP_ASK_WAIT *pDistPktGapAskWait;
  705. #ifdef DIST_GAP_REPORT
  706. printf ("distGapInput/TRY: respond with ASK_WAITn");
  707. #endif
  708. pDistPktGapAskWait = (DIST_PKT_GAP_ASK_WAIT *) &distPktGap;
  709. pDistPktGapAskWait->askWaitHdr.pktSubType =
  710. DIST_PKT_TYPE_GAP_ASK_WAIT;
  711. /* Convert askWaitId (uint16) to network byte order */
  712.              pDistPktGapAskWait->askWaitId = htons (pDistPktGapAskWait->askWaitId);
  713. distNetSend(distNodeIdSrc, (DIST_PKT *) pDistPktGapAskWait,
  714. sizeof (*pDistPktGapAskWait), WAIT_FOREVER,
  715. DIST_GAP_PRIO);
  716. }
  717. else
  718. {
  719. /*
  720.  * Someone is trying to create a group with an
  721.  * id, already in use by us. We won the game, so
  722.  * give him a REJECT.
  723.  */
  724. DIST_PKT_GAP_REJECT *pDistPktGapReject;
  725. #ifdef DIST_GAP_REPORT
  726. printf ("distGapInput/TRY: respond with REJECTn");
  727. #endif
  728. pDistPktGapReject = (DIST_PKT_GAP_REJECT *) &distPktGap;
  729. pDistPktGapReject->rejectHdr.pktSubType =
  730. DIST_PKT_TYPE_GAP_REJECT;
  731. /* Convert rejectId (uint16) to network byte order */
  732.                 pDistPktGapReject->rejectId = htons (pDistPktGapReject->rejectId);
  733. distNetSend(distNodeIdSrc, (DIST_PKT *) pDistPktGapReject,
  734. sizeof (*pDistPktGapReject), WAIT_FOREVER,
  735. DIST_GAP_PRIO);
  736. }
  737. }
  738. break;
  739. }
  740. /*
  741.  * We have received an OK in response to an earlier TRY.
  742.  */
  743. case DIST_PKT_TYPE_GAP_OK:
  744. {
  745. DIST_PKT_GAP_OK *pDistPktGapOk = (DIST_PKT_GAP_OK *) &distPktGap;
  746. DIST_GRP_DB_NODE *pDistGrp;
  747. BOOL more;
  748. /* Convert okId (uint16) to host order */
  749. pDistPktGapOk->okId = ntohs (pDistPktGapOk->okId);
  750. #ifdef DIST_GAP_REPORT
  751. printf ("distGapInput: received OK for `%s'/%d from node %ldn",
  752. pDistPktGapOk->okName, pDistPktGapOk->okId, distNodeIdSrc);
  753. #endif
  754. msgQDistGrpDbLock();
  755. /*
  756.  * Try to find the confirmed id.
  757.  */
  758. pDistGrp = msgQDistGrpLclFindById (pDistPktGapOk->okId);
  759. if (pDistGrp == NULL ||
  760. msgQDistGrpLclGetState (pDistGrp) == DIST_GRP_STATE_GLOBAL)
  761. {
  762. /*
  763.  * This is an OK for an id, that
  764.  * 1) does not exist anymore (due to earlier REJECTs):
  765.  *    This means, someone sent us a REJECT. As a
  766.  *    consequence of this, we destoyed the local entry
  767.  *    for this group and tried again with a new id.
  768.  * 2) was confirmed by GAP earlier (group is in GLOBAL state).
  769.  *
  770.  * All responses to the old group id go here and will be ignored.
  771.  */
  772. msgQDistGrpDbUnlock();
  773. break;
  774. }
  775. distGapLock();
  776. /*
  777.  * Update list of outstanding responses.
  778.  */
  779. more = distGapOutstandOk(pDistGrp->pGrpDbGapNode, distNodeIdSrc);
  780. distGapUnlock();
  781. if (more == FALSE)
  782. {
  783. msgQDistGrpLclSetState (pDistGrp, DIST_GRP_STATE_GLOBAL);
  784. msgQDistGrpLclSetCreator (pDistGrp, distNodeLocalGetId());
  785. msgQDistGrpDbUnlock();
  786. distGapPh1Done (pDistGrp);
  787. break;
  788. }
  789. msgQDistGrpDbUnlock();
  790. break;
  791. }
  792. /*
  793.  * We have received a REJECT.
  794.  * Someone else is trying to create another group with an
  795.  * id, that was also proposed by us. It seams, we have
  796.  * lost a remote comparison, so forget about the old group
  797.  * id and try a new one.
  798.  */
  799. case DIST_PKT_TYPE_GAP_REJECT:
  800. {
  801. DIST_PKT_GAP_REJECT *pDistPktGapReject;
  802. DIST_GRP_DB_NODE *pDistGrp;
  803. pDistPktGapReject = (DIST_PKT_GAP_REJECT *) &distPktGap;
  804. /* Convert rejectId (uint16) to host order */
  805. pDistPktGapReject->rejectId = ntohs (pDistPktGapReject->rejectId);
  806. #ifdef DIST_GAP_REPORT
  807. printf ("distGapInput: received REJECT for `%s'/%d from node %ldn",
  808. pDistPktGapReject->rejectName, pDistPktGapReject->rejectId,
  809. distNodeIdSrc);
  810. #endif
  811. msgQDistGrpDbLock();
  812. pDistGrp = msgQDistGrpLclFindById (pDistPktGapReject->rejectId);
  813. if (pDistGrp == NULL ||
  814. msgQDistGrpLclGetState (pDistGrp) == DIST_GRP_STATE_GLOBAL)
  815. {
  816. /*
  817.  * This is a REJECT for an id, that
  818.  * 1) does not exist anymore (due to earlier REJECTs):
  819.  *    This means, someone sent us a REJECT. As a
  820.  *    consequence of this, we destoyed the local entry
  821.  *    for this group and tried again with a new id.
  822.  * 2) was confirmed by GAP earlier (group is in GLOBAL state).
  823.  *
  824.  * All responses to the old group id go here and will be ignored.
  825.  */
  826. msgQDistGrpDbUnlock();
  827. break;
  828. }
  829. /*
  830.  * Cleanup and reinitialize the GAP structure.
  831.  */
  832. distGapOutstandUnlink (pDistGrp->pGrpDbGapNode);
  833. distGapOutstandLink (pDistGrp->pGrpDbGapNode);
  834. pDistGrp->pGrpDbGapNode->gapTimeout = DIST_GAP_TRY_TIMO;
  835. pDistGrp->pGrpDbGapNode->gapRetries = 1;
  836. /*
  837.  * Get a new id and reset state.
  838.  */
  839. msgQDistGrpLclSetId (pDistGrp, distGrpIdNext++);
  840. msgQDistGrpLclSetState (pDistGrp, DIST_GRP_STATE_LOCAL_TRY);
  841. msgQDistGrpDbUnlock();
  842. /*
  843.  * Have a different TRY.
  844.  */
  845. distGapTry (DIST_IF_BROADCAST_ADDR, pDistGrp);
  846. break;
  847. }
  848. /*
  849.  * We received an ASK_WAIT. We have send a TRY before. Someone else
  850.  * found a conflict, where it is trying to create the same group, but
  851.  * with an alternate id. Since the other node has a higher node id
  852.  * it asks us to wait for a SET.
  853.  */
  854. case DIST_PKT_TYPE_GAP_ASK_WAIT:
  855. {
  856. DIST_PKT_GAP_ASK_WAIT *pDistPktGapAskWait;
  857. DIST_GRP_DB_NODE *pDistGrp;
  858. pDistPktGapAskWait = (DIST_PKT_GAP_ASK_WAIT *) &distPktGap;
  859. /* Convert askWaitId (uint16) to host byte order */
  860. pDistPktGapAskWait->askWaitId = ntohs (pDistPktGapAskWait->askWaitId);
  861. #ifdef DIST_GAP_REPORT
  862. printf ("distGapInput: received ASK_WAIT for `%s'/%d from node %ldn",
  863. pDistPktGapAskWait->askWaitName, pDistPktGapAskWait->askWaitId,
  864. distNodeIdSrc);
  865. #endif
  866. msgQDistGrpDbLock();
  867. pDistGrp = msgQDistGrpLclFindByName (pDistPktGapAskWait->askWaitName);
  868. if (pDistGrp == NULL ||
  869. msgQDistGrpLclGetState (pDistGrp) == DIST_GRP_STATE_GLOBAL)
  870. {
  871. /*
  872.  * This is an ASK_WAIT for an id, that
  873.  * 1) does not exist anymore (due to earlier REJECTs):
  874.  *    This means, someone sent us a REJECT. As a
  875.  *    consequence of this, we destoyed the local entry
  876.  *    for this group and tried again with a new id.
  877.  * 2) was confirmed by GAP earlier (group is in GLOBAL state).
  878.  *
  879.  * All responses to the old group id go here and will be ignored.
  880.  */
  881. msgQDistGrpDbUnlock();
  882. break;
  883. }
  884. if (msgQDistGrpLclGetState (pDistGrp) != DIST_GRP_STATE_WAIT)
  885. {
  886. /*
  887.  * Remove the list of outstanding responses. Do *NOT*
  888.  * remove the GAP structure.
  889.  */
  890. distGapOutstandUnlink (pDistGrp->pGrpDbGapNode);
  891. msgQDistGrpLclSetState (pDistGrp, DIST_GRP_STATE_WAIT);
  892. pDistGrp->pGrpDbGapNode->gapTimeout = DIST_GAP_WAIT_TIMO;
  893. }
  894. msgQDistGrpDbUnlock();
  895. break;
  896. }
  897. /*
  898.  * We have received a SET. When receiving a SET, we already should
  899.  * have received a TRY and responded to it with OK.
  900.  */
  901. case DIST_PKT_TYPE_GAP_SET:
  902. {
  903. DIST_PKT_GAP_SET *pDistPktGapSet;
  904. DIST_GRP_DB_NODE *pGrpFoundById;
  905. DIST_GRP_DB_NODE *pGrpFoundByName;
  906. DIST_GRP_DB_NODE *pDistGrp;
  907. pDistPktGapSet = (DIST_PKT_GAP_SET *) &distPktGap;
  908. /* Convert setId (uint16) to host byte order */
  909. pDistPktGapSet->setId = ntohs (pDistPktGapSet->setId);
  910. #ifdef DIST_GAP_REPORT
  911. printf ("distGapInput: received SET for `%s'/%d from node %ldn",
  912. pDistPktGapSet->setName, pDistPktGapSet->setId, distNodeIdSrc);
  913. #endif
  914. /*
  915.  * Sanity check: Is this a SET from future?
  916.  */
  917. if (pDistPktGapSet->setId >= distGrpIdNext)
  918. {
  919. /*
  920.  * There was no TRY for this SET! Just ignore this.
  921.  */
  922. #ifdef DIST_DIAGNOSTIC
  923. distLog ("distGapInput/SET: no TRY for SETn");
  924. #endif
  925. break;
  926. }
  927. msgQDistGrpDbLock();
  928. pGrpFoundById = msgQDistGrpLclFindById (pDistPktGapSet->setId);
  929. pGrpFoundByName = msgQDistGrpLclFindByName (pDistPktGapSet->setName);
  930. if (pGrpFoundByName &&
  931. (!pGrpFoundById || pGrpFoundById == pGrpFoundByName) &&
  932. (msgQDistGrpLclGetState (pGrpFoundByName) != DIST_GRP_STATE_GLOBAL))
  933. {
  934. /*
  935.  * When do we get here?
  936.  * We were waiting for this one. An earlier TRY asked us to
  937.  * wait. Here is the SET we waited for.
  938.  */
  939. #ifdef DIST_GAP_REPORT
  940. printf ("distGapInput/SET: got SET for existing nonglobal group");
  941. #endif
  942. msgQDistGrpLclSetId (pGrpFoundByName, pDistPktGapSet->setId);
  943. msgQDistGrpLclSetState (pGrpFoundByName, DIST_GRP_STATE_GLOBAL);
  944. msgQDistGrpLclSetCreator (pGrpFoundByName, distNodeIdSrc);
  945. if (pGrpFoundByName->pGrpDbGapNode)
  946. {
  947. distGapOutstandUnlink (pGrpFoundByName->pGrpDbGapNode);
  948. semFlush (&pGrpFoundByName->pGrpDbGapNode->gapWaitFor);
  949. }
  950. msgQDistGrpDbUnlock();
  951. break;
  952. }
  953. if (pGrpFoundById != pGrpFoundByName)
  954. {
  955. /*
  956.  * Id or name are already in database but do not point
  957.  * to the same object. This can happen, if we receive
  958.  * multiple SETs.
  959.  */
  960. msgQDistGrpDbUnlock();
  961. #ifdef DIST_GAP_REPORT
  962. printf ("distGapInput/SET: id or name already in databasen");
  963. #endif
  964. break;
  965. }
  966. if (pGrpFoundById && pGrpFoundById == pGrpFoundByName)
  967. {
  968. /*
  969.  * An exact copy of this object is already in the database.
  970.  * Ignore state.
  971.  */
  972. #ifdef DIST_GAP_REPORT
  973. printf ("distGapInput/SET: `%s' (0x%lx) is already in databasen",
  974. pDistPktGapSet->setName, (u_long) pDistPktGapSet->setId);
  975. #endif
  976. msgQDistGrpLclSetState (pGrpFoundByName, DIST_GRP_STATE_GLOBAL);
  977. msgQDistGrpLclSetCreator (pGrpFoundByName, distNodeIdSrc);
  978. if (pGrpFoundByName->pGrpDbGapNode != NULL)
  979. semFlush (&pGrpFoundByName->pGrpDbGapNode->gapWaitFor);
  980. msgQDistGrpDbUnlock();
  981. break;
  982. }
  983. /*
  984.  * Neither id nor name are found in the database.
  985.  * Create node in group database.
  986.  */
  987. #ifdef DIST_GAP_REPORT
  988. printf ("distGapInput/SET: creating local db entry `%s' (0x%lx)n",
  989. pDistPktGapSet->setName, (u_long) pDistPktGapSet->setId);
  990. #endif
  991. pDistGrp = msgQDistGrpLclCreate (pDistPktGapSet->setName,
  992. pDistPktGapSet->setId, DIST_GRP_STATE_GLOBAL);
  993. msgQDistGrpLclSetCreator (pDistGrp, distNodeLocalGetId ());
  994. if (pDistGrp == NULL)
  995. {
  996. /*
  997.  * We have a SET from remote and cannot create a new
  998.  * node in the group database. This is a fatal error.
  999.  */
  1000. distPanic ("distGapInput:SET: creation of new node failedn");
  1001. }
  1002. msgQDistGrpLclSetCreator (pDistGrp, distNodeIdSrc);
  1003. msgQDistGrpDbUnlock();
  1004. break;
  1005. }
  1006. /*
  1007.  * This type of telegram is unknown.
  1008.  */
  1009. default:
  1010. {
  1011. /*
  1012.  * When we get here, the packet is already acknowledged.
  1013.  * But this makes no difference since an unknown type of
  1014.  * telegram is a fatal error. Let's panic!
  1015.  */
  1016. #ifdef DIST_DIAGNOSTIC
  1017. distPanic ("distGapInput: unknown type of telegramn");
  1018. #endif
  1019. }
  1020. }
  1021. return (DIST_GAP_STATUS_OK);
  1022. }
  1023. #ifdef DIST_GAP_TASK
  1024. /*******************************************************************************
  1025. *
  1026. * distGapTimerTask - Timeout management task
  1027. *
  1028. *
  1029. * NOMANUAL
  1030. */
  1031. LOCAL void distGapTimerTask ()
  1032. {
  1033. while (1)
  1034. {
  1035. distGapTimer ();
  1036. taskDelay (DIST_GAP_MGR_WAKEUP_TICKS);
  1037. }
  1038. }
  1039. /*******************************************************************************
  1040. *
  1041. * distGapTimer - Timeout management
  1042. *
  1043. * The job of the distGapTimer() is to go through the list of active
  1044. * GAPs to see if a GAP has timed out.
  1045. *
  1046. * NOMANUAL
  1047. */
  1048. LOCAL void distGapTimer ()
  1049. {
  1050. DIST_GAP_NODE *pGapNode;
  1051. distGapLock();
  1052. /*
  1053.  * Run through list of open GAPs.
  1054.  */
  1055. pGapNode = (DIST_GAP_NODE *) DLL_FIRST (&gapInProgress);
  1056. while (pGapNode != NULL)
  1057. {
  1058. DIST_GAP_RESPONSE *pDistGapResponse =
  1059. (DIST_GAP_RESPONSE *) SLL_FIRST (&pGapNode->gapOutstand);
  1060. switch (msgQDistGrpLclGetState (pGapNode->pGapGrp))
  1061. {
  1062. case DIST_GRP_STATE_LOCAL_TRY: /* try initiated by us */
  1063. case DIST_GRP_STATE_WAIT_TRY: /* retry after wait */
  1064. {
  1065. /*
  1066.  * This GAP is open and we are still trying.
  1067.  */
  1068. if (pGapNode->gapTimeout == 0)
  1069. {
  1070. /*
  1071.  * GAP has timed out. Lookup the missing nodes.
  1072.  */
  1073. DIST_GAP_RESPONSE *pDistGapResponsePrev;
  1074. while (pDistGapResponse != NULL)
  1075. {
  1076. if (distNodeGetState (pDistGapResponse->pGapResponseNode) ==
  1077. DIST_NODE_STATE_OPERATIONAL)
  1078. {
  1079. /*
  1080.  * According to our local database the node is OPERATIONAL.
  1081.  * Check the number of retries.
  1082.  */
  1083. DIST_NODE_ID distNodeIdMissing =
  1084. pDistGapResponse->pGapResponseNode->nodeId;
  1085. if (pGapNode->gapRetries++ > DIST_GAP_MAX_RETRIES)
  1086. {
  1087. /*
  1088.  * The number of retries is within the limit.
  1089.  * Send a unicast TRY with a higher timeout to the
  1090.  * missing node.
  1091.  */
  1092. pGapNode->gapTimeout =
  1093. pGapNode->gapRetries * DIST_GAP_TRY_TIMO;
  1094. distGapTry (distNodeIdMissing, pGapNode->pGapGrp);
  1095. }
  1096. else
  1097. {
  1098. /*
  1099.  * We have exceeded the limit of max retries.
  1100.  * The remote node seams to be dead. Tell the node
  1101.  * database about our assumption.
  1102.  */
  1103. (void) distNodeCrashed (distNodeIdMissing);
  1104. distGapOutstandDel (pGapNode, pDistGapResponse,
  1105. pDistGapResponsePrev);
  1106. }
  1107. }
  1108. else
  1109. {
  1110. /*
  1111.  * Node has died, while we were waiting for a response.
  1112.  * Dying is something like agreeing.
  1113.  */
  1114. distGapOutstandDel (pGapNode, pDistGapResponse,
  1115. pDistGapResponsePrev);
  1116. }
  1117. pDistGapResponsePrev = pDistGapResponse;
  1118. pDistGapResponse = (DIST_GAP_RESPONSE *)
  1119. SLL_NEXT (pDistGapResponse);
  1120. } /* while (pDistGapResponse != NULL) */
  1121. }
  1122. pGapNode->gapTimeout--;
  1123. break;
  1124. }
  1125. case DIST_GRP_STATE_WAIT:
  1126. {
  1127. /*
  1128.  * Someone told us to wait.
  1129.  */
  1130. if (pGapNode->gapTimeout == 0)
  1131. {
  1132. /*
  1133.  * GAP timed out and we are still waiting for a SET. We will
  1134.  * return to try again, but we must not forget the WAITing
  1135.  * state we were in, since the missing SET might come in at
  1136.  * any time.
  1137.  */
  1138. DIST_GRP_DB_NODE *pDistGrp;
  1139. /*
  1140.  * Reinitialize the GAP structure. Cleanup was done,
  1141.  * before entering WAITing state.
  1142.  */
  1143. distGapOutstandLink (pGapNode);
  1144. pDistGrp->pGrpDbGapNode->gapTimeout = DIST_GAP_TRY_TIMO;
  1145. pDistGrp->pGrpDbGapNode->gapRetries = 1;
  1146. /*
  1147.  * Get a new id and reset state.
  1148.  */
  1149. pDistGrp = pGapNode->pGapGrp;
  1150. msgQDistGrpLclSetId (pDistGrp, distGrpIdNext++);
  1151. msgQDistGrpLclSetState (pDistGrp, DIST_GRP_STATE_WAIT_TRY);
  1152. /*
  1153.  * Have another TRY with a different id.
  1154.  */
  1155. distGapTry (DIST_IF_BROADCAST_ADDR, pDistGrp);
  1156. }
  1157. pGapNode->gapTimeout--;
  1158. break;
  1159. }
  1160. default:
  1161. {
  1162. #ifdef DIST_DIAGNOSTIC
  1163. distLog ("distGapTimer: `%s' in unknown or unexpected state %dn",
  1164. &pGapNode->pGapGrp->grpDbName,
  1165. pGapNode->pGapGrp->grpDbState);
  1166. #endif
  1167. }
  1168. } /* switch (state) */
  1169. pGapNode = (DIST_GAP_NODE *) DLL_NEXT (pGapNode);
  1170. } /* while (pGapNode != NULL) */
  1171. distGapUnlock();
  1172. }
  1173. #endif