|
|
1.1 ! root 1: /* $Header: CHlookup.c,v 2.4 87/03/14 06:41:56 jqj Exp $ */ ! 2: ! 3: /* contains: ! 4: * CH_LookupAddr ! 5: * CH_GetFirstCH ! 6: * CH_GetOtherCH ! 7: */ ! 8: ! 9: /* $Log: CHlookup.c,v $ ! 10: * Revision 2.4 87/03/14 06:41:56 jqj ! 11: * major changes to CH location algorithm. ! 12: * changed LookupAddressDN to use new simpler semantics (can call GetOtherCH ! 13: * many times) ! 14: * ! 15: * Revision 2.3 87/01/05 11:58:47 ed ! 16: * Webster changes ! 17: * ! 18: * Revision 2.3 87/01/05 11:58:47 ed ! 19: * Eliminate hard file name for BFS and use BFS definition instead ! 20: * ! 21: * Revision 2.2 86/06/30 12:23:48 jqj ! 22: * 1/ convert BDT read to dynamically allocate a buffer, and grow it if ! 23: * necessary using realloc(). This should fix problems with support at ! 24: * Xerox, where they have so many CHes that we were running out of space. ! 25: * 2/ convert CH_GetFirstCH() to use /usr/new/xnsbfs if CH.default fails ! 26: * to find a CH. xnsbfs does an expanding ring, or at least a local, ! 27: * broadcast for servers. ! 28: * ! 29: * Revision 2.1 86/06/05 09:12:48 jqj ! 30: * Split out CHdefault.c from this file. The path to the addresses file ! 31: * is now found in that file. ! 32: * ! 33: * Revision 2.0 85/11/21 07:22:32 jqj ! 34: * 4.3BSD standard release ! 35: * ! 36: * Revision 1.3 85/11/21 07:14:19 jqj ! 37: * first try at 4.3BSD standard release ! 38: * ! 39: * Revision 1.2 85/10/21 12:41:55 jqj ! 40: * Gould version: work around a Gould compiler bug. Default to /usr/new ! 41: * for consistency. ! 42: * ! 43: * Revision 1.1 85/10/18 09:14:53 jqj ! 44: * Initial revision ! 45: * ! 46: * Revision 1.1 85/03/26 06:27:00 jqj ! 47: * Initial revision ! 48: * ! 49: */ ! 50: #include <stdio.h> ! 51: #include <sys/types.h> ! 52: #include <netns/ns.h> ! 53: #include <xnscourier/Clearinghouse2.h> ! 54: #include <xnscourier/CHEntries.h> ! 55: #include <xnscourier/except.h> ! 56: #include <sys/file.h> ! 57: ! 58: #ifndef BFS ! 59: #define BFS "/usr/new/xnsbfs" ! 60: #endif ! 61: ! 62: /* data structures for very simple (null) authentication */ ! 63: static Cardinal nullpasswd = 0; ! 64: static Clearinghouse2_Authenticator nullagent = {{0,{0,0}},{1,&nullpasswd}}; ! 65: ! 66: /* ! 67: * This is an entry in the in-core cache of known clearinghouses. ! 68: * chl_name Each entry has a name, which may be null for entries ! 69: * obtained by expanding ring broadcast or initial table lookup. A ! 70: * particular address may appear in the list multiple times with ! 71: * different or null names, but mostly the entries are unique. ! 72: * chl_addr The address is one of the addresses given for this ! 73: * host. For multihomed CHs, no attempt is made to make sure that ! 74: * this address is optimal. ! 75: * chl_status The status of the entry, one of: ! 76: * chunknown address invalid. ! 77: * chdown did not answer when probed. ! 78: * chup address valid, and responds to RetrieveAddresses. ! 79: * chused has been returned to caller of GetCH routines ! 80: * as a valid CH. Hence GetOtherCH will not return it ! 81: * again. Note that GetFirstCH resets chused->chup. ! 82: * chl_next Link to next clearinghouse in database. ! 83: * chl_domains [NOT YET USED] List of domains served, for efficiency ! 84: */ ! 85: struct chlist { ! 86: Clearinghouse2_ObjectName *chl_name; ! 87: struct ns_addr chl_addr; ! 88: enum {chunknown, chup, chdown, chused} chl_status; ! 89: struct Clearinghouse2_TwoPartName *chl_domains; ! 90: struct chlist *chl_next; ! 91: }; ! 92: struct chlist *namelist = NULL; ! 93: ! 94: /* ! 95: * add a clearinghouse name to the ch list if it isn't already there. ! 96: * Initial state is chunknown, since we don't know its address and can't ! 97: * probe it. ! 98: */ ! 99: static struct chlist * ! 100: addtochlist(ch_name) ! 101: Clearinghouse2_ObjectName *ch_name; ! 102: { ! 103: struct chlist *chptr; ! 104: extern char *malloc(); ! 105: ! 106: if (ch_name != NULL) /* don't eliminate duplicate anonymous entries */ ! 107: for (chptr = namelist; chptr != NULL; chptr = chptr->chl_next) { ! 108: if ( chptr->chl_name && ! 109: (strcmp(chptr->chl_name->object,ch_name->object)==0) && ! 110: (strcmp(chptr->chl_name->domain,ch_name->domain)==0) && ! 111: (strcmp(chptr->chl_name->organization, ! 112: ch_name->organization)==0)) { ! 113: clear_Clearinghouse2_ObjectName(ch_name); /* dealloc */ ! 114: return NULL; /* already in list */ ! 115: } ! 116: } ! 117: chptr = (struct chlist *) malloc(sizeof(struct chlist)); ! 118: chptr->chl_name = ch_name; ! 119: chptr->chl_status = chunknown; ! 120: chptr->chl_next = namelist; ! 121: namelist = chptr; ! 122: return chptr; ! 123: } ! 124: ! 125: static ! 126: GetData(conn) ! 127: CourierConnection *conn; ! 128: { ! 129: int count, i; ! 130: int bufused, bufsize; ! 131: Unspecified *buffer, *bp; ! 132: Clearinghouse2_StreamOfObjectName obnames; ! 133: ! 134: bufsize = MAXWORDS*4; /* end of available space */ ! 135: buffer = Allocate(bufsize); ! 136: bufused = 0; /* number of words used */ ! 137: while (count = BDTread(conn, (char*)(buffer+bufused), ! 138: MAXWORDS*sizeof(Unspecified)) ! 139: ) { ! 140: bufused += count/sizeof(Unspecified); ! 141: /* leave room for one last packet */ ! 142: if (bufused+MAXWORDS > bufsize) { ! 143: bufsize += bufsize; /* double our space */ ! 144: buffer = (Unspecified *) realloc((char *) buffer, ! 145: bufsize*sizeof(Unspecified)); ! 146: } ! 147: } ! 148: bp = buffer; ! 149: while (bp-buffer < bufused) { ! 150: bp += internalize_Clearinghouse2_StreamOfObjectName(&obnames,bp); ! 151: if (0 == (int) obnames.designator) { ! 152: for (i = 0; i < obnames.nextSegment_case.segment.length; i++) ! 153: addtochlist( ! 154: &obnames.nextSegment_case.segment.sequence[i]); ! 155: } else { ! 156: for (i = 0; i < obnames.lastSegment_case.length; i++) ! 157: addtochlist( ! 158: &obnames.lastSegment_case.sequence[i]); ! 159: Deallocate(buffer); ! 160: return; ! 161: } ! 162: } ! 163: Deallocate(buffer); ! 164: return; ! 165: } ! 166: ! 167: static struct ns_addr* ! 168: itemtonsaddr(itemptr) ! 169: Clearinghouse2_Item *itemptr; /* i.e. a sequence of Unspecified */ ! 170: { ! 171: static union { ! 172: struct ns_addr addr; ! 173: u_short shrt[6]; ! 174: } result; ! 175: register int i; ! 176: register Unspecified *seq; ! 177: ! 178: if (itemptr->length < 7) ! 179: return(0); ! 180: ! 181: seq = itemptr->sequence +1; ! 182: /* itemptr->sequence[0] == number of addresses */ ! 183: for (i = 0; i < 6; i++, seq++) ! 184: result.shrt[i] = ntohs(*seq); ! 185: return(&result.addr); ! 186: } ! 187: ! 188: /* ! 189: * Open an SPP connection to the address given as chaddr, then ! 190: * check whether the CHS pointed to by conn is up. If not, close ! 191: * conn and return 0. If so, return the connection. ! 192: */ ! 193: static CourierConnection* ! 194: ClearinghouseOpen(chaddr) ! 195: struct ns_addr chaddr; ! 196: { ! 197: CourierConnection *conn; ! 198: Clearinghouse2_RetrieveAddressesResults raresult; ! 199: ! 200: conn.x_port = 0; ! 201: if ((conn = CourierOpen(&chaddr)) == NULL) ! 202: return(conn); ! 203: DURING ! 204: raresult = Clearinghouse2_RetrieveAddresses(conn,NULL); ! 205: HANDLER { ! 206: CourierClose(conn); ! 207: conn = NULL; ! 208: } END_HANDLER; ! 209: clear_Clearinghouse2_RetrieveAddressesResults(&raresult); ! 210: return(conn); ! 211: } ! 212: ! 213: /* ! 214: * path to look for the addresses file on ! 215: * (I wish I'd picked a shorter name, so we could rendezvous in /etc. ! 216: * But long file names in /etc are very unpopular!). ! 217: * This path is defined n CHdefault.c, and used by CH_NameDefault() ! 218: */ ! 219: extern char *chaddrpath[]; ! 220: ! 221: CourierConnection* ! 222: CH_GetFirstCH() ! 223: { ! 224: struct ns_addr chaddr; ! 225: extern struct ns_addr *getXNSaddr(); ! 226: extern struct ns_addr ns_addr(); ! 227: char buf[BUFSIZ]; ! 228: CourierConnection *result; ! 229: FILE *chfile; ! 230: struct chlist *chptr; ! 231: int i; ! 232: ! 233: result = (CourierConnection *) NULL; ! 234: /* first, look in the process cache */ ! 235: for (chptr = namelist; chptr != NULL; chptr = chptr->chl_next) { ! 236: switch (chptr->chl_status) { ! 237: case chunknown: ! 238: case chdown: ! 239: break; ! 240: case chused: ! 241: chptr->chl_status = chup; ! 242: case chup: ! 243: if (result == NULL) ! 244: result = ClearinghouseOpen(chptr->chl_addr); ! 245: } ! 246: } ! 247: if (result) return(result); ! 248: ! 249: /* Now, use hard-coded CH */ ! 250: /* eventually we'll do an expanding-ring or something */ ! 251: for (i = 0; chaddrpath[i] != NULL; i++) { ! 252: if ((chfile = fopen(chaddrpath[i],"r")) == NULL) ! 253: continue; ! 254: flock(fileno(chfile),LOCK_SH); ! 255: while (fgets(buf, BUFSIZ, chfile) != NULL) ! 256: if ((buf[0] != '#') && ! 257: (chaddr = ns_addr(buf), ! 258: result = ClearinghouseOpen((chaddr)))) { ! 259: if ((chptr = addtochlist(NULL))) { ! 260: chptr->chl_addr = chaddr; ! 261: chptr->chl_status = chused; ! 262: } ! 263: flock(fileno(chfile),LOCK_UN); ! 264: fclose(chfile); ! 265: return(result); ! 266: } ! 267: flock(fileno(chfile),LOCK_UN); ! 268: fclose(chfile); ! 269: break; /* don't look for other files */ ! 270: } ! 271: /* try expanding-ring here -- this could be more efficient! */ ! 272: if ((chfile = popen(BFS,"r")) != NULL) { ! 273: while (fgets(buf, BUFSIZ, chfile) != NULL) ! 274: if ((buf[0] != '#') && ! 275: (chaddr=ns_addr(buf), ! 276: result = ClearinghouseOpen(chaddr))) { ! 277: if ((chptr = addtochlist(NULL))) { ! 278: chptr->chl_addr = chaddr; ! 279: chptr->chl_status = chused; ! 280: } ! 281: pclose(chfile); ! 282: return(result); ! 283: } ! 284: pclose(chfile); ! 285: } ! 286: return(result); ! 287: } ! 288: ! 289: CourierConnection * ! 290: CH_GetOtherCH(conn,hint) ! 291: CourierConnection *conn; ! 292: Clearinghouse2_ObjectName hint; ! 293: { ! 294: struct ns_addr *ch2addr; ! 295: CourierConnection *ch2conn, *chresult; ! 296: Clearinghouse2_RetrieveItemResults riresult; ! 297: Clearinghouse2_RetrieveMembersResults rmresult; ! 298: struct chlist *chptr; ! 299: ! 300: Clearinghouse2_Property clearinghouseNames = 3; ! 301: Clearinghouse2_Property clearinghouseAddresses = 4; ! 302: ! 303: if (hint.object != NULL && *hint.object != '\0') { ! 304: DURING ! 305: /* get list of possible other clearinghouses */ ! 306: rmresult = Clearinghouse2_RetrieveMembers(conn, GetData, hint, ! 307: clearinghouseNames, BulkData1_immediateSink, ! 308: nullagent); ! 309: HANDLER { ! 310: /* some race condition */ ! 311: return(NULL); ! 312: } END_HANDLER; ! 313: /* throw away the distinguished name, which we don't need */ ! 314: clear_Clearinghouse2_RetrieveMembersResults(&rmresult); ! 315: } ! 316: /* for each member of potentials list, probe it */ ! 317: ch2conn = chresult = NULL; ! 318: for (chptr = namelist; chptr != NULL; chptr = chptr->chl_next) { ! 319: switch (chptr->chl_status) { ! 320: case chunknown: /* a new entry, presumably */ ! 321: /* get its address */ ! 322: DURING ! 323: riresult = Clearinghouse2_RetrieveItem(conn, NULL, ! 324: *(chptr->chl_name), ! 325: clearinghouseAddresses, nullagent); ! 326: HANDLER ! 327: break; /* try next in namelist */ ! 328: END_HANDLER; ! 329: chptr->chl_addr = *itemtonsaddr(&riresult.value); ! 330: clear_Clearinghouse2_RetrieveItemResults(&riresult); ! 331: chptr->chl_status = chdown; ! 332: /* fall through to: */ ! 333: case chdown: /* check down CH to see if it has revived */ ! 334: /* make sure the second CH is really there */ ! 335: if ((ch2conn = ClearinghouseOpen(chptr->chl_addr))) { ! 336: chptr->chl_status = chup; /* we got it! */ ! 337: if (chresult == NULL) { ! 338: chresult = ch2conn; ! 339: chptr->chl_status = chused; ! 340: } ! 341: else CourierClose(ch2conn); ! 342: ch2conn = NULL; ! 343: } ! 344: break; ! 345: case chup: ! 346: case chused: ! 347: break; ! 348: } /* end of switch */ ! 349: } /* inspect next in list */ ! 350: /* ! 351: * if no new one, return an old one ! 352: */ ! 353: for (chptr= namelist; chptr && (chresult==NULL); chptr= chptr->chl_next) { ! 354: if (chptr->chl_status == chup) { ! 355: chptr->chl_status = ! 356: (chresult=ClearinghouseOpen(chptr->chl_addr)) ! 357: ? chused : chdown; ! 358: } ! 359: } ! 360: return(chresult); ! 361: } ! 362: ! 363: /* ! 364: * Given a Clearinghouse three part name (possibly containing wild cards) ! 365: * and the property number on which a NetworkAddress is expected to occur, ! 366: * returns the ns_addr structure associated with that name. ! 367: * Note that the ns_addr structure is statically allocated! ! 368: * Resets pattern to be the distinguished name of the object found. ! 369: */ ! 370: struct ns_addr * ! 371: CH_LookupAddr(pattern,property) ! 372: Clearinghouse2_ObjectNamePattern pattern; ! 373: Clearinghouse2_Property property; ! 374: { ! 375: struct ns_addr* CH_LookupAddrDN(); ! 376: return(CH_LookupAddrDN(pattern,property,0,0)); ! 377: } ! 378: ! 379: /* ! 380: * Lookup a clearinghouse address, returning the address and the ! 381: * distinguished name of the object found. ! 382: */ ! 383: struct ns_addr * ! 384: CH_LookupAddrDN(pattern,property,distnamep,distnamelen) ! 385: Clearinghouse2_ObjectNamePattern pattern; ! 386: Clearinghouse2_Property property; ! 387: char *distnamep; ! 388: int distnamelen; ! 389: { ! 390: struct ns_addr *chaddr, *resultaddr; ! 391: CourierConnection *conn, *ch2conn; ! 392: Clearinghouse2_ObjectName hint; /* from WrongServer errors */ ! 393: Clearinghouse2_RetrieveItemResults riresult; ! 394: int i; ! 395: ! 396: ! 397: if ((long) property <= 0) /* default to addressList i.e. 4 */ ! 398: property = CHEntries0_addressList; ! 399: if (pattern.object == NULL || ! 400: pattern.domain == NULL || ! 401: pattern.organization == NULL) ! 402: return(NULL); /* can't handle defaults */ ! 403: ! 404: if ((conn = CH_GetFirstCH()) == NULL) { ! 405: fprintf(stderr,"Can't open connection to local Clearinghouse\n"); ! 406: exit(1); ! 407: } ! 408: /* ask our primary clearinghouse for the address of this thing */ ! 409: for (i = 5; i > 0; i--) { ! 410: DURING { ! 411: riresult = Clearinghouse2_RetrieveItem(conn, NULL, ! 412: pattern, property, nullagent); ! 413: i = -1; ! 414: } HANDLER { ! 415: if (Exception.Code == REJECT_ERROR) { ! 416: fprintf(stderr,"Problem with CH.addrs. CH rejected request\n"); ! 417: hint.object = hint.domain = hint.organization = NULL; ! 418: } ! 419: else if (Exception.Code != Clearinghouse2_WrongServer) { ! 420: /* some random error */ ! 421: hint.object = hint.domain = hint.organization = NULL; ! 422: } ! 423: else hint = CourierErrArgs(Clearinghouse2_WrongServerArgs, hint); ! 424: ch2conn = CH_GetOtherCH(conn, hint); ! 425: CourierClose(conn); ! 426: if (ch2conn == NULL) return(0); ! 427: conn = ch2conn; ! 428: } END_HANDLER; ! 429: } ! 430: if (i >= 0) { ! 431: return(0); ! 432: } ! 433: resultaddr = itemtonsaddr(&riresult.value); ! 434: if (distnamep != NULL && ! 435: distnamelen >= (2+strlen(riresult.distinguishedObject.object)+ ! 436: strlen(riresult.distinguishedObject.domain)+ ! 437: strlen(riresult.distinguishedObject.organization))) ! 438: strcpy(distnamep,CH_NameToString(riresult.distinguishedObject)); ! 439: clear_Clearinghouse2_RetrieveItemResults(&riresult); ! 440: CourierClose(conn); ! 441: return(resultaddr); ! 442: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.