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