|
|
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: if ((conn = CourierOpen(&chaddr)) == NULL)
201: return(conn);
202: DURING
203: raresult = Clearinghouse2_RetrieveAddresses(conn,NULL);
204: HANDLER {
205: CourierClose(conn);
206: conn = NULL;
207: } END_HANDLER;
208: clear_Clearinghouse2_RetrieveAddressesResults(&raresult);
209: return(conn);
210: }
211:
212: /*
213: * path to look for the addresses file on
214: * (I wish I'd picked a shorter name, so we could rendezvous in /etc.
215: * But long file names in /etc are very unpopular!).
216: * This path is defined n CHdefault.c, and used by CH_NameDefault()
217: */
218: extern char *chaddrpath[];
219:
220: CourierConnection*
221: CH_GetFirstCH()
222: {
223: struct ns_addr chaddr;
224: extern struct ns_addr *getXNSaddr();
225: extern struct ns_addr ns_addr();
226: char buf[BUFSIZ];
227: CourierConnection *result;
228: FILE *chfile;
229: struct chlist *chptr;
230: int i;
231:
232: result = (CourierConnection *) NULL;
233: /* first, look in the process cache */
234: for (chptr = namelist; chptr != NULL; chptr = chptr->chl_next) {
235: switch (chptr->chl_status) {
236: case chunknown:
237: case chdown:
238: break;
239: case chused:
240: chptr->chl_status = chup;
241: case chup:
242: if (result == NULL)
243: result = ClearinghouseOpen(chptr->chl_addr);
244: }
245: }
246: if (result) return(result);
247:
248: /* Now, use hard-coded CH */
249: /* eventually we'll do an expanding-ring or something */
250: for (i = 0; chaddrpath[i] != NULL; i++) {
251: if ((chfile = fopen(chaddrpath[i],"r")) == NULL)
252: continue;
253: flock(fileno(chfile),LOCK_SH);
254: while (fgets(buf, BUFSIZ, chfile) != NULL)
255: if ((buf[0] != '#') &&
256: (chaddr = ns_addr(buf),
257: result = ClearinghouseOpen((chaddr)))) {
258: if ((chptr = addtochlist(NULL))) {
259: chptr->chl_addr = chaddr;
260: chptr->chl_status = chused;
261: }
262: flock(fileno(chfile),LOCK_UN);
263: fclose(chfile);
264: return(result);
265: }
266: flock(fileno(chfile),LOCK_UN);
267: fclose(chfile);
268: break; /* don't look for other files */
269: }
270: /* try expanding-ring here -- this could be more efficient! */
271: if ((chfile = popen(BFS,"r")) != NULL) {
272: while (fgets(buf, BUFSIZ, chfile) != NULL)
273: if ((buf[0] != '#') &&
274: (chaddr=ns_addr(buf),
275: result = ClearinghouseOpen(chaddr))) {
276: if ((chptr = addtochlist(NULL))) {
277: chptr->chl_addr = chaddr;
278: chptr->chl_status = chused;
279: }
280: pclose(chfile);
281: return(result);
282: }
283: pclose(chfile);
284: }
285: return(result);
286: }
287:
288: CourierConnection *
289: CH_GetOtherCH(conn,hint)
290: CourierConnection *conn;
291: Clearinghouse2_ObjectName hint;
292: {
293: struct ns_addr *ch2addr;
294: CourierConnection *ch2conn, *chresult;
295: Clearinghouse2_RetrieveItemResults riresult;
296: Clearinghouse2_RetrieveMembersResults rmresult;
297: struct chlist *chptr;
298:
299: Clearinghouse2_Property clearinghouseNames = 3;
300: Clearinghouse2_Property clearinghouseAddresses = 4;
301:
302: if (hint.object != NULL && *hint.object != '\0') {
303: DURING
304: /* get list of possible other clearinghouses */
305: rmresult = Clearinghouse2_RetrieveMembers(conn, GetData, hint,
306: clearinghouseNames, BulkData1_immediateSink,
307: nullagent);
308: HANDLER {
309: /* some race condition */
310: return(NULL);
311: } END_HANDLER;
312: /* throw away the distinguished name, which we don't need */
313: clear_Clearinghouse2_RetrieveMembersResults(&rmresult);
314: }
315: /* for each member of potentials list, probe it */
316: ch2conn = chresult = NULL;
317: for (chptr = namelist; chptr != NULL; chptr = chptr->chl_next) {
318: switch (chptr->chl_status) {
319: case chunknown: /* a new entry, presumably */
320: /* get its address */
321: DURING
322: riresult = Clearinghouse2_RetrieveItem(conn, NULL,
323: *(chptr->chl_name),
324: clearinghouseAddresses, nullagent);
325: HANDLER
326: break; /* try next in namelist */
327: END_HANDLER;
328: chptr->chl_addr = *itemtonsaddr(&riresult.value);
329: clear_Clearinghouse2_RetrieveItemResults(&riresult);
330: chptr->chl_status = chdown;
331: /* fall through to: */
332: case chdown: /* check down CH to see if it has revived */
333: /* make sure the second CH is really there */
334: if ((ch2conn = ClearinghouseOpen(chptr->chl_addr))) {
335: chptr->chl_status = chup; /* we got it! */
336: if (chresult == NULL) {
337: chresult = ch2conn;
338: chptr->chl_status = chused;
339: }
340: else CourierClose(ch2conn);
341: ch2conn = NULL;
342: }
343: break;
344: case chup:
345: case chused:
346: break;
347: } /* end of switch */
348: } /* inspect next in list */
349: /*
350: * if no new one, return an old one
351: */
352: for (chptr= namelist; chptr && (chresult==NULL); chptr= chptr->chl_next) {
353: if (chptr->chl_status == chup) {
354: chptr->chl_status =
355: (chresult=ClearinghouseOpen(chptr->chl_addr))
356: ? chused : chdown;
357: }
358: }
359: return(chresult);
360: }
361:
362: /*
363: * Given a Clearinghouse three part name (possibly containing wild cards)
364: * and the property number on which a NetworkAddress is expected to occur,
365: * returns the ns_addr structure associated with that name.
366: * Note that the ns_addr structure is statically allocated!
367: * Resets pattern to be the distinguished name of the object found.
368: */
369: struct ns_addr *
370: CH_LookupAddr(pattern,property)
371: Clearinghouse2_ObjectNamePattern pattern;
372: Clearinghouse2_Property property;
373: {
374: struct ns_addr* CH_LookupAddrDN();
375: return(CH_LookupAddrDN(pattern,property,0,0));
376: }
377:
378: /*
379: * Lookup a clearinghouse address, returning the address and the
380: * distinguished name of the object found.
381: */
382: struct ns_addr *
383: CH_LookupAddrDN(pattern,property,distnamep,distnamelen)
384: Clearinghouse2_ObjectNamePattern pattern;
385: Clearinghouse2_Property property;
386: char *distnamep;
387: int distnamelen;
388: {
389: struct ns_addr *chaddr, *resultaddr;
390: CourierConnection *conn, *ch2conn;
391: Clearinghouse2_ObjectName hint; /* from WrongServer errors */
392: Clearinghouse2_RetrieveItemResults riresult;
393: int i;
394:
395:
396: if ((long) property <= 0) /* default to addressList i.e. 4 */
397: property = CHEntries0_addressList;
398: if (pattern.object == NULL ||
399: pattern.domain == NULL ||
400: pattern.organization == NULL)
401: return(NULL); /* can't handle defaults */
402:
403: if ((conn = CH_GetFirstCH()) == NULL) {
404: fprintf(stderr,"Can't open connection to local Clearinghouse\n");
405: exit(1);
406: }
407: /* ask our primary clearinghouse for the address of this thing */
408: for (i = 5; i > 0; i--) {
409: DURING {
410: riresult = Clearinghouse2_RetrieveItem(conn, NULL,
411: pattern, property, nullagent);
412: i = -1;
413: } HANDLER {
414: if (Exception.Code == REJECT_ERROR) {
415: fprintf(stderr,"Problem with CH.addrs. CH rejected request\n");
416: hint.object = hint.domain = hint.organization = NULL;
417: }
418: else if (Exception.Code != Clearinghouse2_WrongServer) {
419: /* some random error */
420: hint.object = hint.domain = hint.organization = NULL;
421: }
422: else hint = CourierErrArgs(Clearinghouse2_WrongServerArgs, hint);
423: ch2conn = CH_GetOtherCH(conn, hint);
424: CourierClose(conn);
425: if (ch2conn == NULL) return(0);
426: conn = ch2conn;
427: } END_HANDLER;
428: }
429: if (i >= 0) {
430: return(0);
431: }
432: resultaddr = itemtonsaddr(&riresult.value);
433: if (distnamep != NULL &&
434: distnamelen >= (2+strlen(riresult.distinguishedObject.object)+
435: strlen(riresult.distinguishedObject.domain)+
436: strlen(riresult.distinguishedObject.organization)))
437: strcpy(distnamep,CH_NameToString(riresult.distinguishedObject));
438: clear_Clearinghouse2_RetrieveItemResults(&riresult);
439: CourierClose(conn);
440: return(resultaddr);
441: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.