|
|
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.