|
|
1.1 ! root 1: /* di_block.c - routines to handle operation activity blocks */ ! 2: ! 3: #ifndef lint ! 4: static char *rcsid = "$Header: /f/osi/quipu/RCS/di_block.c,v 7.2 90/07/09 14:45:34 mrose Exp $"; ! 5: #endif ! 6: ! 7: /* ! 8: * $Header: /f/osi/quipu/RCS/di_block.c,v 7.2 90/07/09 14:45:34 mrose Exp $ ! 9: * ! 10: * ! 11: * $Log: di_block.c,v $ ! 12: * Revision 7.2 90/07/09 14:45:34 mrose ! 13: * sync ! 14: * ! 15: * Revision 7.1 89/12/19 16:20:09 mrose ! 16: * sync ! 17: * ! 18: * Revision 7.0 89/11/23 22:17:00 mrose ! 19: * Release 6.0 ! 20: * ! 21: */ ! 22: ! 23: /* ! 24: * NOTICE ! 25: * ! 26: * Acquisition, use, and distribution of this module and related ! 27: * materials are subject to the restrictions of a license agreement. ! 28: * Consult the Preface in the User's Manual for the full terms of ! 29: * this agreement. ! 30: * ! 31: */ ! 32: ! 33: ! 34: #include "quipu/util.h" ! 35: #include "quipu/connection.h" ! 36: #include "tsap.h" ! 37: #include "tailor.h" ! 38: ! 39: extern LLog * log_dsap; ! 40: ! 41: extern time_t timenow; ! 42: ! 43: struct di_block *di_alloc() ! 44: { ! 45: struct di_block * di_ret; ! 46: ! 47: di_ret = (struct di_block *) calloc(1,sizeof(struct di_block)); ! 48: ! 49: return(di_ret); ! 50: } ! 51: ! 52: di_free(di) ! 53: struct di_block *di; ! 54: { ! 55: DLOG(log_dsap, LLOG_TRACE, ("di_free()")); ! 56: ! 57: switch (di->di_state) { ! 58: case DI_GLOBAL: break; ! 59: case DI_TASK: break; ! 60: case DI_OPERATION: break; ! 61: default: ! 62: DLOG(log_dsap, LLOG_TRACE, ("di_free() of unknown type %d",di->di_state)); ! 63: return; ! 64: } ! 65: ! 66: dn_free(di->di_dn); ! 67: ! 68: dn_free(di->di_target); ! 69: ! 70: if(di->di_accesspoints != NULLACCESSPOINT) ! 71: aps_free(di->di_accesspoints); ! 72: ! 73: di->di_state = -1; ! 74: ! 75: free((char *)di); ! 76: } ! 77: ! 78: di_extract(old_di) ! 79: struct di_block * old_di; ! 80: { ! 81: struct di_block * di; ! 82: struct di_block **next_di; ! 83: ! 84: LLOG(log_dsap, LLOG_TRACE, ("di_extract")); ! 85: #ifdef DEBUG ! 86: di_log(old_di); ! 87: #endif ! 88: ! 89: switch(old_di->di_type) ! 90: { ! 91: case DI_GLOBAL: ! 92: next_di = &(deferred_dis); ! 93: for(di=deferred_dis; di!=NULL_DI_BLOCK; di=di->di_next) ! 94: { ! 95: if(di == old_di) ! 96: break; ! 97: ! 98: next_di = &(di->di_next); ! 99: } ! 100: if(di == NULL_DI_BLOCK) ! 101: { ! 102: LLOG(log_dsap, LLOG_EXCEPTIONS, ("di_block has escaped from global list")); ! 103: } ! 104: else ! 105: { ! 106: (*next_di) = di->di_next; ! 107: } ! 108: break; ! 109: case DI_OPERATION: ! 110: break; ! 111: case DI_TASK: ! 112: break; ! 113: default: ! 114: break; ! 115: } ! 116: ! 117: di_free(old_di); ! 118: } ! 119: ! 120: di_desist(di) ! 121: struct di_block * di; ! 122: { ! 123: struct di_block * di_tmp1; ! 124: struct di_block * di_tmp1_next; ! 125: struct di_block * di_tmp2; ! 126: struct di_block **di_p2; ! 127: ! 128: DLOG(log_dsap, LLOG_TRACE, ("di_desist()")); ! 129: ! 130: for(di_tmp1=di; di_tmp1 != NULL_DI_BLOCK; di_tmp1 = di_tmp1_next) ! 131: { ! 132: di_tmp1_next = di_tmp1->di_next; ! 133: ! 134: switch(di->di_state) ! 135: { ! 136: case DI_ACCESSPOINT: ! 137: case DI_COMPLETE: ! 138: break; ! 139: case DI_DEFERRED: ! 140: di_p2 = &(di_tmp1->di_perform->on_wake_list); ! 141: for(di_tmp2=di_tmp1->di_perform->on_wake_list; di_tmp2!=NULL_DI_BLOCK; di_tmp2=di_tmp2->di_wake_next) ! 142: { ! 143: if(di_tmp2 == di_tmp1) ! 144: break; ! 145: ! 146: di_p2 = &(di_tmp2->di_wake_next); ! 147: } ! 148: if(di_tmp2 == NULL_DI_BLOCK) ! 149: { ! 150: LLOG(log_dsap, LLOG_EXCEPTIONS, ("di_desist - di_block lost from performing operations wake up list")); ! 151: } ! 152: else ! 153: { ! 154: (*di_p2) = di_tmp2->di_wake_next; ! 155: } ! 156: break; ! 157: } ! 158: di_free(di_tmp1); ! 159: } ! 160: } ! 161: ! 162: di_log(di) ! 163: struct di_block * di; ! 164: { ! 165: DLOG (log_dsap,LLOG_DEBUG, ("di_block [%x] , state = %d, type = %d", ! 166: di, di->di_state, di->di_type)); ! 167: } ! 168: ! 169: di_list_log(di) ! 170: struct di_block *di; ! 171: { ! 172: struct di_block * di_tmp; ! 173: ! 174: DLOG(log_dsap, LLOG_DEBUG, ("di_list:")); ! 175: #ifdef DEBUG ! 176: for(di_tmp = di; di_tmp!=NULL_DI_BLOCK; di_tmp=di_tmp->di_next) ! 177: { ! 178: di_log(di_tmp); ! 179: } ! 180: #endif ! 181: DLOG(log_dsap, LLOG_DEBUG, ("di_list ends.")); ! 182: } ! 183: ! 184: ! 185: ! 186: static struct dn_seq * prefer_dsa_list = NULLDNSEQ; ! 187: ! 188: prefer_dsa (str) ! 189: char * str; ! 190: { ! 191: struct dn_seq * dsa, *loop; ! 192: ! 193: if (( dsa=str2dnseq(str)) == NULLDNSEQ) { ! 194: LLOG (log_dsap,LLOG_EXCEPTIONS,("Invalid prefered DSA name %s",str)); ! 195: return; ! 196: } ! 197: ! 198: if (prefer_dsa_list == NULLDNSEQ) ! 199: prefer_dsa_list = dsa; ! 200: else { ! 201: for (loop = prefer_dsa_list; loop->dns_next != NULLDNSEQ; loop=loop->dns_next) ! 202: ; ! 203: loop->dns_next = dsa; ! 204: } ! 205: } ! 206: ! 207: static di_prefer_dsa (a,b) ! 208: DN a,b; ! 209: { ! 210: int x,y; ! 211: ! 212: if (prefer_dsa_list == NULLDNSEQ) { ! 213: DLOG (log_dsap,LLOG_TRACE,("NO DSAs to chose from")); ! 214: return 0; /* not fussy !!! */ ! 215: } ! 216: ! 217: if ((b == NULLDN) || (a == NULLDN)) { ! 218: DLOG (log_dsap,LLOG_NOTICE,("di_pref DNs NULL")); ! 219: return 0; /* safty catch - don't think it can happen */ ! 220: } ! 221: ! 222: if ((x = dn_in_dnseq (a,prefer_dsa_list)) == 0) ! 223: if ((y = dn_in_dnseq (b,prefer_dsa_list)) == 0) ! 224: return 0; ! 225: else { ! 226: DLOG (log_dsap,LLOG_TRACE,("DSA selected on preference")); ! 227: return -1; ! 228: } ! 229: ! 230: if ((y = dn_in_dnseq (b,prefer_dsa_list)) == 0) { ! 231: DLOG (log_dsap,LLOG_TRACE,("DSA selected on preference")); ! 232: return 1; ! 233: } ! 234: ! 235: if ( x != y ) { ! 236: DLOG (log_dsap,LLOG_TRACE,("DSA selected on preference")); ! 237: return ( x > y ? -1 : 1 ); ! 238: } ! 239: ! 240: return 0; ! 241: ! 242: } ! 243: ! 244: static di_ap2comp (di) ! 245: struct di_block **di; ! 246: { ! 247: struct di_block *loop; ! 248: Entry eptr; ! 249: ! 250: /* replace DI_ACCESSPOINT with DI_COMPLETE if possible... */ ! 251: /* (data may have been cached since creating DI_ACCESSPOINT) */ ! 252: ! 253: for (loop= *di; loop!=NULL_DI_BLOCK; loop=loop->di_next) { ! 254: if (loop->di_state != DI_ACCESSPOINT) ! 255: continue; ! 256: ! 257: if (loop->di_reftype == RT_NONSPECIFICSUBORDINATE) ! 258: continue; /* can't split these - all must be followed... */ ! 259: ! 260: if (loop->di_accesspoints->ap_next == NULLACCESSPOINT) { ! 261: if ((eptr=local_find_entry (loop->di_accesspoints->ap_name,FALSE)) != NULLENTRY) ! 262: if (eptr->e_dsainfo != NULLDSA) { ! 263: loop->di_entry = eptr; ! 264: loop->di_state = DI_COMPLETE; ! 265: aps_free (loop->di_accesspoints); ! 266: loop->di_accesspoints = NULLACCESSPOINT; ! 267: } ! 268: } else ! 269: LLOG (log_dsap,LLOG_EXCEPTIONS,("Many access points, but not a RT_NONSPECIFICSUBORDINATE")); ! 270: } ! 271: ! 272: } ! 273: ! 274: dsa_reliable (cn,good,when) ! 275: struct connection * cn; ! 276: char good; ! 277: time_t when; ! 278: { ! 279: Entry ptr; ! 280: ! 281: if ( (ptr=local_find_entry(cn->cn_dn,FALSE)) == NULLENTRY) ! 282: return; ! 283: ! 284: if (ptr->e_dsainfo == NULLDSA) ! 285: return; ! 286: ! 287: ptr->e_dsainfo->dsa_last_attempt = when; ! 288: if (good) { ! 289: ptr->e_dsainfo->dsa_last_success = when; ! 290: ptr->e_dsainfo->dsa_failures = 0; ! 291: } else ! 292: ptr->e_dsainfo->dsa_failures++; ! 293: } ! 294: ! 295: static di_cmp_reliability (a,b) ! 296: struct di_block *a, *b; ! 297: { ! 298: extern time_t retry_timeout; ! 299: struct dsa_info *da, *db; ! 300: ! 301: /* If we have used a DSA recently, with no failures - use it again */ ! 302: ! 303: if ((da = a->di_entry->e_dsainfo) == NULLDSA) ! 304: return 0; ! 305: if ((db = b->di_entry->e_dsainfo) == NULLDSA) ! 306: return 0; ! 307: ! 308: if (da->dsa_last_attempt == (time_t)0) { ! 309: if (db->dsa_failures == 0) { ! 310: if ((db->dsa_last_success != (time_t)0) ! 311: && (timenow - db->dsa_last_attempt < retry_timeout)) ! 312: return -1; /* b worked recently */ ! 313: } else if (timenow - db->dsa_last_attempt < retry_timeout) ! 314: return 1; /* b failed recently */ ! 315: return 0; /* have not tried either recently */ ! 316: ! 317: } else if (db->dsa_last_attempt == (time_t)0) { ! 318: if (da->dsa_failures == 0) { ! 319: if ((da->dsa_last_success != (time_t)0) ! 320: && (timenow - da->dsa_last_attempt < retry_timeout)) ! 321: return 1; /* a worked recentdlry */ ! 322: } else if (timenow - da->dsa_last_attempt < retry_timeout) ! 323: return -1; /* a failed recently */ ! 324: return 0; /* have not tried either recently */ ! 325: } ! 326: ! 327: if (da->dsa_failures == 0) { ! 328: if (db->dsa_failures == 0) ! 329: return 0; /* both OK */ ! 330: return 1; /* a worked last time, b failed - use a */ ! 331: } ! 332: ! 333: if (db->dsa_failures == 0) ! 334: return -1; /* b worked last time, a failed - use b */ ! 335: ! 336: /* both failed last time - see if either have suceeded recently */ ! 337: ! 338: if ((timenow - da->dsa_last_success) > retry_timeout ) { ! 339: if ((timenow - db->dsa_last_success) > retry_timeout) ! 340: return 0; /* too long ago to tell */ ! 341: return -1; /* use b it worked not that long ago... */ ! 342: } ! 343: if ((timenow - db->dsa_last_success) > retry_timeout) ! 344: return 1; /* use a it worked not that long ago... */ ! 345: ! 346: /* neither has worked recently chose some other way */ ! 347: return 0; ! 348: } ! 349: ! 350: static di_cmp_address (a,b) ! 351: struct di_block *a, *b; ! 352: { ! 353: struct NSAPaddr *na; ! 354: struct NSAPaddr *nb; ! 355: struct NSAPaddr nas; ! 356: struct TSAPaddr *ta2norm(); ! 357: struct TSAPaddr *ta; ! 358: struct TSAPaddr *tb; ! 359: int *ip; ! 360: extern DN mydsadn; ! 361: DN dnptr, mydnptr, dna,dnb; ! 362: int ma,mb; ! 363: ! 364: /* select DSA with best looking address !!! */ ! 365: ! 366: if (a->di_state == DI_COMPLETE) { ! 367: ta = &(a->di_entry->e_dsainfo->dsa_addr->pa_addr.sa_addr); ! 368: tb = &(b->di_entry->e_dsainfo->dsa_addr->pa_addr.sa_addr); ! 369: dna = a->di_dn; ! 370: dnb = b->di_dn; ! 371: } else { ! 372: /* Use 1 access point only */ ! 373: ta = &(a->di_accesspoints->ap_address->pa_addr.sa_addr); ! 374: tb = &(b->di_accesspoints->ap_address->pa_addr.sa_addr); ! 375: } ! 376: ! 377: /* ta2norm return a static buffer */ ! 378: ta = ta2norm (ta); ! 379: nas = *(ta->ta_addrs); /* struct copy */ ! 380: na = &nas; ! 381: tb = ta2norm (tb); ! 382: nb = tb->ta_addrs; ! 383: ! 384: /* normalised, so look for first "na" match with ts_communities */ ! 385: for (ip = ts_communities; *ip; ip++) { ! 386: if (*ip == na->na_community) { ! 387: if (*ip == nb->na_community) ! 388: break; /* same primary community */ ! 389: return 1; /* 'a' preferred */ ! 390: } ! 391: if (*ip == nb->na_community) ! 392: return -1; /* 'b' preferred */ ! 393: } ! 394: ! 395: /* Look at the DSA name to detect locality */ ! 396: ma=0; ! 397: for (dnptr=dna, mydnptr=mydsadn ; ! 398: (dnptr!=NULLDN) && (mydnptr!=NULLDN) ; ! 399: dnptr=dnptr->dn_parent, mydnptr=mydnptr->dn_parent) { ! 400: if (rdn_cmp(dnptr->dn_rdn,mydnptr->dn_rdn) == 0) ! 401: ma++; ! 402: } ! 403: ! 404: mb=0; ! 405: for (dnptr=dnb, mydnptr=mydsadn ; ! 406: (dnptr!=NULLDN) && (mydnptr!=NULLDN) ; ! 407: dnptr=dnptr->dn_parent, mydnptr=mydnptr->dn_parent) { ! 408: if (rdn_cmp(dnptr->dn_rdn,mydnptr->dn_rdn) == 0) ! 409: mb++; ! 410: } ! 411: ! 412: if (ma != mb) ! 413: return (ma > mb ? 1 : -1); ! 414: ! 415: /* check the DMD - NYI */ ! 416: return 0; ! 417: } ! 418: ! 419: static di_cmp (a,b) ! 420: struct di_block *a, *b; ! 421: /* ! 422: * Select best di_block ! 423: * rule 1: deferred dsa infos have lowest preference, ! 424: * complete have highest. ! 425: * ! 426: * If two block have same state, select using ! 427: * preference 1: quipu DSAs with quipu context ! 428: * preference 2: quipu DSAs ! 429: * preference 3: reliable DSAs ! 430: * preference 4: local DSAs ! 431: */ ! 432: { ! 433: int x,y; ! 434: ! 435: if (a->di_state != b->di_state) ! 436: return (a->di_state > b->di_state ? -1 : 1); /* rule 1 */ ! 437: ! 438: switch (a->di_state) { ! 439: case DI_DEFERRED: ! 440: break; ! 441: case DI_ACCESSPOINT: ! 442: if ((x = di_cmp_address(a,b)) != 0) { ! 443: DLOG (log_dsap,LLOG_TRACE,("AP selected on address")); ! 444: return x; /* preference 4 - no info to asses 1,2 or 3 */ ! 445: } ! 446: break; ! 447: case DI_COMPLETE: ! 448: x = quipu_ctx_supported (a->di_entry); ! 449: y = quipu_ctx_supported (b->di_entry); ! 450: if ( x != y ) { ! 451: DLOG (log_dsap,LLOG_TRACE,("DSA selected on context")); ! 452: return ( x > y ? 1 : -1); /* preference 1 or 2 */ ! 453: } ! 454: ! 455: if ((x=di_cmp_reliability (a,b)) != 0) { ! 456: DLOG (log_dsap,LLOG_TRACE,("DSA selected on relibility")); ! 457: return x; /* preference 3 */ ! 458: } ! 459: ! 460: if ((x=di_cmp_address(a,b)) != 0) { ! 461: DLOG (log_dsap,LLOG_TRACE,("DSA selected on address")); ! 462: return x; /* preference 4 */ ! 463: } ! 464: ! 465: break; ! 466: } ! 467: ! 468: return (di_prefer_dsa(a->di_dn, b->di_dn)); ! 469: } ! 470: ! 471: ! 472: sort_dsa_list (dsas) ! 473: struct di_block **dsas; ! 474: { ! 475: struct di_block *trail; ! 476: struct di_block *old_di, *new_di; ! 477: struct di_block *result; ! 478: char changed = FALSE; ! 479: ! 480: /* turn access point into complete references if possible */ ! 481: di_ap2comp (dsas); ! 482: ! 483: result = *dsas; ! 484: if ((old_di = result->di_next) == NULL_DI_BLOCK) ! 485: return; /* only 1 - must be sorted !!! */ ! 486: ! 487: result->di_next = NULL_DI_BLOCK; ! 488: ! 489: for(; old_di != NULL_DI_BLOCK; ) { ! 490: trail = NULL_DI_BLOCK; ! 491: for(new_di = result; new_di != NULL_DI_BLOCK; new_di= new_di->di_next) { ! 492: if ( di_cmp (old_di,new_di) > 0 ) { ! 493: if (trail == NULL_DI_BLOCK) { ! 494: result = old_di; ! 495: old_di = old_di->di_next; ! 496: result->di_next = new_di; ! 497: } else { ! 498: trail->di_next = old_di; ! 499: old_di = old_di->di_next; ! 500: trail->di_next->di_next = new_di; ! 501: } ! 502: changed = TRUE; ! 503: break; ! 504: } ! 505: trail = new_di; ! 506: } ! 507: if (new_di == NULL_DI_BLOCK) { ! 508: trail->di_next = old_di; ! 509: old_di = old_di->di_next; ! 510: trail->di_next->di_next = NULL_DI_BLOCK; ! 511: } ! 512: } ! 513: *dsas = result; ! 514: ! 515: if (changed) { ! 516: LLOG (log_dsap,LLOG_TRACE,("DSA order changed")); ! 517: #ifdef DEBUG ! 518: di_list_log (result); ! 519: #endif ! 520: } else ! 521: DLOG (log_dsap,LLOG_TRACE,("DSA order not changed")); ! 522: ! 523: } ! 524: ! 525: static int common_address (a,tb) ! 526: struct di_block *a; ! 527: struct TSAPaddr *tb; ! 528: { ! 529: struct TSAPaddr *ta; ! 530: struct NSAPaddr *na; ! 531: struct NSAPaddr *nb; ! 532: int x,y; ! 533: ! 534: /* select DSA with best looking address !!! */ ! 535: ! 536: if (a->di_state == DI_DEFERRED) ! 537: return FALSE; ! 538: ! 539: if (a->di_state == DI_COMPLETE) ! 540: ta = &(a->di_entry->e_dsainfo->dsa_addr->pa_addr.sa_addr); ! 541: else ! 542: /* Use 1 access point only */ ! 543: ta = &(a->di_accesspoints->ap_address->pa_addr.sa_addr); ! 544: ! 545: /* compare ta and tb to see if they have a network in common */ ! 546: for (na=ta->ta_addrs , x = ta->ta_naddr - 1 ; ! 547: x >= 0; ! 548: na++, x-- ) { ! 549: for (nb=tb->ta_addrs , y = tb->ta_naddr - 1 ; ! 550: y >= 0; ! 551: nb++, y-- ) { ! 552: if (na->na_community == nb->na_community) ! 553: return TRUE; ! 554: } ! 555: } ! 556: return FALSE; ! 557: } ! 558: ! 559: ! 560: struct di_block * select_refer_dsa(di,tk) ! 561: struct di_block *di; ! 562: struct task_act *tk; ! 563: { ! 564: struct di_block *best; ! 565: struct di_block *loop; ! 566: Entry eptr; ! 567: struct TSAPaddr *ta; ! 568: DN rdsa; ! 569: ! 570: /* return the di block of the best DSA the other end should be ! 571: to contact... ! 572: If it can't contact any - return NULL ! 573: */ ! 574: ! 575: if (di != NULL_DI_BLOCK) ! 576: best = di; ! 577: else ! 578: best = NULL_DI_BLOCK; ! 579: ! 580: /* First set - find out who the remote end is... */ ! 581: if (tk->tk_conn->cn_ctx == DS_CTX_X500_DAP) ! 582: return best; /* we will chain anyway - unless prevented by service control... */ ! 583: ! 584: rdsa = tk->tk_conn->cn_dn; ! 585: if ((eptr=local_find_entry (rdsa,FALSE)) == NULLENTRY) ! 586: return best; /* no way of knowing */ ! 587: ! 588: if (eptr->e_dsainfo == NULLDSA) ! 589: return best; /* no way of knowing */ ! 590: ! 591: ta = &(eptr->e_dsainfo->dsa_addr->pa_addr.sa_addr); ! 592: ta = ta2norm (ta); /* calculate subnets... */ ! 593: ! 594: for (loop=di; loop!=NULL_DI_BLOCK; loop=loop->di_next) ! 595: if (common_address (loop,ta)) ! 596: return loop; ! 597: ! 598: /* nothing on the same network - chain if possible !!! */ ! 599: return NULL_DI_BLOCK; ! 600: } ! 601:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.