xref: /original-bsd/contrib/xns/examples/gap/gap2d.c (revision 6d9336ba)
1 #ifndef lint
2 static char RCSid[] = "$Header: gap2d.c,v 2.0 85/11/21 07:23:00 jqj Exp $";
3 #endif
4 /*
5  * server for GAP-style (TransportObject=server,teletype) telnet connections
6  * Note that we support only GAP version 2, although a server for version 3
7  * exists.  The version 2 server has not been tested as thoroughly as has the
8  * version 3; it does NOT support RESERVE functionality.
9  */
10 
11 /* $Log:	gap2d.c,v $
12  * Revision 2.0  85/11/21  07:23:00  jqj
13  * 4.3BSD standard release
14  *
15  * Revision 1.2  85/05/23  06:22:18  jqj
16  * *** empty log message ***
17  *
18  * Revision 1.2  85/05/23  06:22:18  jqj
19  * *** empty log message ***
20  *
21  * Revision 1.1  85/05/22  09:46:52  jqj
22  * Initial revision
23  */
24 #include <stdio.h>
25 #include <signal.h>
26 #include <sgtty.h>
27 #include <sys/types.h>
28 #include <sys/time.h>
29 #include <sys/uio.h>
30 #include <sys/socket.h>
31 #include <netns/ns.h>
32 #include <netns/idp.h>
33 #include <netns/sp.h>
34 #include <sys/wait.h>
35 #include <xnscourier/realcourierconnection.h>
36 #include "GAP2.h"
37 #include "gapcontrols.h"
38 #include <xnscourier/except.h>
39 #include <errno.h>
40 
41 #define	BELL	'\07'
42 #define BANNER	"\r\n\r\n4.3 BSD UNIX (%s)\r\n\r\r\n\r%s"
43 
44 int pty, net;
45 extern CourierConnection *_serverConnection;
46 char buf[sizeof(struct sphdr)+SPPMAXDATA];
47 struct sphdr our_sphdr;
48 struct iovec our_iovec[2] = {{((caddr_t)&our_sphdr), sizeof(our_sphdr)}};
49 /*
50  * I/O data buffers, pointers, and counters.
51  */
52 char	ptyibuf[512], *ptyip = ptyibuf;
53 char	ptyobuf[BUFSIZ], *pfrontp = ptyobuf, *pbackp = ptyobuf;
54 char	*netip = buf;
55 char	netobuf[512], *nfrontp = netobuf, *nbackp = netobuf;
56 int	pcc, ncc;
57 char	line[12];
58 extern	char **environ;
59 extern	int errno;
60 
61 char *envinit[3];
62 char wsenv[50];
63 
64 /*
65  * session parameters
66  */
67 Cardinal frametimeout;		/* 0 or time in seconds to wait */
68 
69 
70 /*
71  * This modified version of the server is necessary since GAP specifies
72  * that the telnet data-transfer session occurs after the RPC to create
73  * it has returned!
74  */
Server(skipcount,skippedwords)75 Server(skipcount,skippedwords)
76 	int skipcount;
77 	Unspecified skippedwords[];
78 {
79 	Cardinal _procedure;
80 	register Unspecified *_buf;
81 	LongCardinal programnum;
82 	Cardinal versionnum;
83 	Cardinal _n;
84 
85 #ifdef DEBUG
86 	BUGOUT("Server: %d %d",skipcount,skippedwords);
87 #endif
88 	for (;;) {
89 		_buf = ReceiveCallMessage(&_procedure, skipcount, skippedwords);
90 		DURING switch (_procedure) {
91 		case 3:
92 			server_GAP2_Delete(_buf);
93 			break;
94 		case 2:
95 			server_GAP2_Create(_buf);
96 			net = _serverConnection->fd;
97 			gaptelnet(); /* returns on connection close */
98 			break;
99 		case 0:
100 			server_GAP2_Reset(_buf);
101 			break;
102 		default:
103 			NoSuchProcedureValue("GAP", _procedure);
104 			break;
105 		} HANDLER {
106 		    Deallocate(_buf);
107 		    switch (Exception.Code) {
108 		    case GAP2_terminalAddressInvalid:
109 		    case GAP2_terminalAddressInUse:
110 		    case GAP2_controllerDoesNotExist:
111 		    case GAP2_controllerAlreadyExists:
112 		    case GAP2_gapCommunicationError:
113 		    case GAP2_gapNotExported:
114 		    case GAP2_bugInGAPCode:
115 		    case GAP2_tooManyGateStreams:
116 		    case GAP2_inconsistentParams:
117 		    case GAP2_transmissionMediumUnavailable:
118 		    case GAP2_dialingHardwareProblem:
119 		    case GAP2_noDialingHardware:
120 		    case GAP2_badAddressFormat:
121 		    case GAP2_mediumConnectFailed:
122 		    case GAP2_illegalTransport:
123 		    case GAP2_noCommunicationHardware:
124 		    case GAP2_unimplemented:
125 			_buf = Allocate(0);
126 			SendAbortMessage(Exception.Code-ERROR_OFFSET, 0, _buf);
127 			break;
128 		    default:
129 			_buf = Allocate(0);
130 			SendRejectMessage(unspecifiedError, 0, _buf);
131 			break;
132 		    }
133 		} END_HANDLER;
134 		Deallocate(_buf);
135 		for (;;) {
136 			skipcount = LookAheadCallMsg(&programnum, &versionnum,
137 					skippedwords);
138 			if (skipcount < 0) return(0);	/* timed out */
139 			if (programnum != 3 || versionnum != 2)
140 				ExecCourierProgram(programnum, versionnum,
141 						skipcount, skippedwords);
142 		}  /* loop if can't exec that program */
143 	}
144 }
145 
146 void
GAP2_Delete(session)147 GAP2_Delete(session)
148 	GAP2_SessionHandle session;
149 {
150 }
151 
152 void
GAP2_Reset()153 GAP2_Reset()
154 {
155 }
156 
157 GAP2_CreateResults
GAP2_Create(conn,BDTproc,sessionparams,transports,createTimeout)158 GAP2_Create(conn, BDTproc, sessionparams, transports,
159 	    createTimeout)
160 	CourierConnection *conn;
161 	int BDTproc;
162 	GAP2_SessionParameterObject sessionparams;
163 	struct {Cardinal length;
164 		GAP2_TransportObject *sequence;
165 	} transports;
166 	GAP2_WaitTime createTimeout;
167 {
168 	GAP2_CreateResults result;
169 	char *c1, *c2, *host;
170 	int t, pid;
171 	struct sgttyb b;
172 	char *xntoa(), *wsname();
173 	struct sockaddr_ns who;
174 	int whosize = sizeof(who);
175 	LongCardinal servicetype;
176 	GAP2_CommParamObject *cp;
177 	GAP2_Duplexity duplexity;	/* fullDuplex, halfDuplex */
178 
179 #ifdef DEBUG
180 	BUGOUT("CREATE");
181 #endif
182 	switch (sessionparams.designator) {
183 	case ttyHost:
184 		frametimeout = sessionparams.ttyHost_case.frameTimeout/1000;
185 		/* could set other parameters here */
186 		break;
187 	default:
188 		raise(GAP2_unimplemented, 0);
189 		/*NOTREACHED*/
190 	}
191 	if (transports.length != 2) {
192 		raise(GAP2_illegalTransport);
193 		/*NOTREACHED*/
194 	}
195 	switch (transports.sequence[0].designator) {
196 	case rs232c:	/* maybe some day */
197 		cp = &transports.sequence[0].rs232c_case.commParams;
198 		if (cp->accessDetail.designator == directConn) {
199 			duplexity = cp->duplex;
200 			servicetype = 0; /* fake it */
201 			break;
202 		}
203 		raise(GAP2_noCommunicationHardware, 0);
204 		/*NOTREACHED*/
205 	default:
206 		raise(GAP2_illegalTransport, 0);
207 		/*NOTREACHED*/
208 	}
209 	if (transports.sequence[1].designator != teletype)
210 	  raise(GAP2_illegalTransport, 0);
211 	/* ignore createTimeout */
212 	/* ignore credentials and verifier */
213 
214 	for (c1 = "pq"; *c1 != 0; c1++)
215 	  for (c2 = "0123456789abcdef"; *c2 != 0; c2++) {
216 		  sprintf(line, "/dev/pty%c%c", *c1, *c2);
217 		  pty = open(line, 2);
218 		  if (pty < 0) continue;
219 		  line[strlen("/dev/")] = 't';
220 		  t = open(line, 2);
221 		  if (t > 0) goto gotpty;
222 		  close(pty);
223 	  }
224 	raise(GAP2_tooManyGateStreams, 0);
225 	/*NOTREACHED*/
226  gotpty:
227 	getpeername(_serverConnection->fd, &who, &whosize);
228 	host = wsname(who.sns_addr);
229 #ifdef DEBUG
230 	BUGOUT("gotpty <%s> %d <%s>",line, pty, host);
231 #endif
232 	ioctl(t, TIOCGETP, &b);
233 	b.sg_flags = CRMOD|XTABS|ANYP;
234 	ioctl(t, TIOCSETP, &b);
235 	ioctl(pty, TIOCGETP, &b);
236 	if (duplexity == fullduplex)
237 	  b.sg_flags |= ECHO;
238 	else
239 	  b.sg_flags &= ~ECHO;
240 	ioctl(pty, TIOCSETP, &b);
241 	/* we do the fork now so we can return failures as REPORTS */
242 	pid = fork();
243 	if (pid < 0) {
244 		close(pty); close(t);
245 		raise(GAP2_tooManyGateStreams, 0);
246 		/*NOTREACHED*/
247 	}
248 	else if (pid == 0) {	/* in the execed fork */
249 		sleep(1);	/* let parent get ready for us */
250 		close(_serverConnection->fd); /* close net */
251 		close(pty);
252 		dup2(t, 0);
253 		dup2(t, 1);
254 		dup2(t, 2);
255 		if (t > 2) close(t);
256 		envinit[0] = "TERM=network";
257 		(void)sprintf(wsenv, "WORKSTATION=%s", xntoa(who.sns_addr));
258 		envinit[1] = wsenv;
259 		envinit[2] = (char*) 0;
260 #ifdef DEBUG
261 		BUGOUT("about to exec /bin/login");
262 #endif
263 		execl("/bin/login","login", "-h", host, 0);
264 #ifdef DEBUG
265 		BUGOUT("exec of /bin/login failed");
266 #endif
267 		perror("/bin/login");
268 		exit(1);
269 		/*NOTREACHED*/
270 	}
271 	close(t);
272 #ifdef DEBUG
273 	BUGOUT("fork successful");
274 #endif
275 	result.session[0] = pid;
276 	return(result);
277 }
278 
279 jmp_buf childdiedbuf;
280 
281 /*
282  * Main loop.  Select from pty and network, and
283  * hand data to telnet receiver finite state machine.
284  * Returns 0 on orderly shutdown, 1 on abnormal shutdown.
285  */
gaptelnet()286 gaptelnet()
287 {
288 	int on = 1;
289 	char hostname[32];
290 	int childdied();
291 	int ibits = 0, obits = 0;
292 	register int c;
293 	struct sphdr *si = (struct sphdr *)buf;
294 	static struct timeval timeout = {600,0};
295 	int keepalives = 0;
296 	int i;
297 
298 #ifdef DEBUG
299 	BUGOUT("gaptelnet net=%d,pty=%d",net,pty);
300 #endif
301 	if (setjmp(childdiedbuf) != 0)
302 	  return(0);		/* child died */
303 	signal(SIGCHLD, childdied);
304 	signal(SIGTSTP, SIG_IGN);
305 	ioctl(net, FIONBIO, &on);
306 	ioctl(pty, FIONBIO, &on);
307 
308 
309 	/*
310 	 * Show banner that getty never gave.
311 	 */
312 	gethostname(hostname, sizeof (hostname));
313 	sprintf(nfrontp, BANNER, hostname, "");
314 	nfrontp += strlen(nfrontp);
315 	/*
316 	 * Send status message indicating we're ready to go
317 	 */
318 	changeSPPopts(net, GAPCTLnone, 1);
319 	sendoobdata(GAPCTLmediumUp);
320 	for (;;) {
321 #ifdef DEBUG
322 		BUGOUT("looping in gaptelnet");
323 #endif
324 		ibits = obits = 0;
325 		/*
326 		 * Never look for input if there's still
327 		 * stuff in the corresponding output buffer
328 		 */
329 		if (nfrontp - nbackp || pcc > 0)
330 			obits |= (1 << net);
331 		else
332 			ibits |= (1 << pty);
333 		if (pfrontp - pbackp || ncc > 0)
334 			obits |= (1 << pty);
335 		else
336 			ibits |= (1 << net);
337 		if (ncc < 0 && pcc < 0)
338 			break;
339 		timeout.tv_sec = 600;
340 		timeout.tv_usec = 0;
341 		select(16, &ibits, &obits, 0, &timeout);
342 		if (ibits == 0 && obits == 0) {
343 			/* timeout means no activity for a long time */
344 #ifdef DEBUG
345 			BUGOUT("timeout from select");
346 #endif
347 			if (keepalives++ < 2) {
348 			  /* first 2 times through send warning */
349 				if (nfrontp == nbackp && pcc == 0) {
350 					/* but only if not blocked on output */
351 #define WARNING "\r\nYou've been idle much too long.  Respond or log off.\r\n"
352 					strcpy(nfrontp, WARNING);
353 					nfrontp += sizeof(WARNING);
354 				}
355 				sleep(5);
356 				continue;
357 			}
358 #ifdef DEBUG
359 			BUGOUT("keepalive expired -- calling cleanup");
360 #endif
361 			/* keepalive count has expired */
362 			cleanup();
363 			return(1);
364 		}
365 
366 		/*
367 		 * Something to read from the network...
368 		 */
369 		if (ibits & (1 << net)) {
370 			ncc = read(net, buf, sizeof(buf));
371 #ifdef DEBUG
372 			BUGOUT("read from net %d",ncc);
373 #endif
374 			if (ncc < 0 && errno == EWOULDBLOCK)
375 				ncc = 0;
376 			else if (ncc < sizeof(struct sphdr)) {
377 #ifdef DEBUG
378 				BUGOUT("short read, %d.  calling cleanup",ncc);
379 #endif
380 				cleanup(); /* will probably fail or block */
381 				return(1);
382 			}
383 			else if (si->sp_cc & SP_OB) {
384 				/* a status or OOB control */
385 				switch (buf[sizeof(struct sphdr)]) {
386 				case GAPCTLinterrupt:
387 					/* shove interrupt char in buffer */
388 					interrupt();
389 					break; /* from switch */
390 				case GAPCTLareYouThere:
391 					sendoobdata(GAPCTLiAmHere);
392 					break; /* from switch */
393 				default:
394 					/* Ignore other controls instead of:
395 					 * sendoobdata(
396 					 *     GAPCTLunexpectedRemoteBehavior);
397 					 */
398 					break; /* from switch */
399 				}
400 				ncc = 0; /* no chars here */
401 			}
402 			else if (si->sp_dt==GAPCTLnone) {
403 				/* the normal case */
404 				ncc -= sizeof(struct sphdr);
405 				netip = buf + sizeof(struct sphdr);
406 				keepalives = 0;
407 			}
408 			else if(si->sp_dt==GAPCTLcleanup) {
409 #ifdef DEBUG
410 				BUGOUT("got CLEANUP packet.  Done");
411 #endif
412 				cleanup(); /* normal termination */
413 				return(0);
414 			}
415 			else if (si->sp_dt==SPPSST_END) {
416 				/* got premature termination */
417 				quitquit(net, pty);
418 				return(1);
419 			}
420 		}
421 
422 		/*
423 		 * Something to read from the pty...
424 		 */
425 		if (ibits & (1 << pty)) {
426 			if (frametimeout > 0) sleep(frametimeout);
427 			pcc = read(pty, ptyibuf, sizeof(ptyibuf));
428 #ifdef DEBUG
429 			BUGOUT("read from pty %d",pcc);
430 #endif
431 			if (pcc < 0 && errno == EWOULDBLOCK)
432 				pcc = 0;
433 			else if (pcc <= 0) {
434 #ifdef DEBUG
435 				BUGOUT("short read from pty. Calling cleanup");
436 #endif
437 				cleanup();
438 				return(1); /* ?? abnormal termination */
439 			}
440 			ptyip = ptyibuf;
441 		}
442 
443 		while (pcc > 0) {
444 			if ((&netobuf[sizeof(netobuf)] - nfrontp) < 2)
445 				break;
446 			*nfrontp++ = *ptyip++ & 0377; pcc--;
447 		}
448 		if ((obits & (1 << net)) && (nfrontp - nbackp) > 0)
449 			netflush();
450 		while (ncc > 0) {
451 			if ((&ptyobuf[sizeof(ptyobuf)] - pfrontp) < 2) break;
452 			*pfrontp++ = *netip++ & 0377;
453 			ncc--;
454 		}
455 		if ((obits & (1 << pty)) && (pfrontp - pbackp) > 0)
456 			ptyflush();
457 	}
458 	/* we should never get to here */
459 #ifdef DEBUG
460 	BUGOUT("broke out of for(;;) somehow.  calling cleanup");
461 #endif
462 	cleanup();
463 	return(0);
464 }
465 
466 /*
467  * Send out of band data to other end of network
468  */
sendoobdata(value)469 sendoobdata(value)
470 	u_char value;
471 {
472 	struct {
473 		struct sphdr hdr;
474 		char val;
475 	} oob;
476 	oob.hdr = our_sphdr;
477 	oob.val = value;
478 #ifdef DEBUG
479 	BUGOUT("sendoobdata 0%o",value);
480 #endif
481 	send(net, &oob, sizeof(oob), MSG_OOB);
482 }
483 
484 /*
485  * Send interrupt to process on other side of pty.
486  * If it is in raw mode, just write NULL;
487  * otherwise, write intr char.
488  */
interrupt()489 interrupt()
490 {
491 	struct sgttyb b;
492 	struct tchars tchars;
493 
494 	ptyflush();	/* half-hearted */
495 	ioctl(pty, TIOCGETP, &b);
496 	if (b.sg_flags & RAW) {
497 		*pfrontp++ = '\0';
498 		return;
499 	}
500 	*pfrontp++ = ioctl(pty, TIOCGETC, &tchars) < 0 ?
501 		'\177' : tchars.t_intrc;
502 }
503 
ptyflush()504 ptyflush()
505 {
506 	register int n;
507 
508 	if ((n = pfrontp - pbackp) > 0)
509 		n = write(pty, pbackp, n);
510 #ifdef DEBUG
511 	BUGOUT("ptyflush wrote %d",n);
512 #endif
513 	if (n < 0)
514 		return;
515 	pbackp += n;
516 	if (pbackp >= pfrontp)	/* actually, > is an error */
517 		pbackp = pfrontp = ptyobuf;
518 }
519 
netflush()520 netflush()
521 {
522 	register int n;
523 
524 	if ((n = nfrontp - nbackp) > 0) {
525 		our_iovec[1].iov_len = ((n > SPPMAXDATA) ? SPPMAXDATA : n);
526 		our_iovec[1].iov_base = nbackp;
527 		n = writev(net, our_iovec, 2) - sizeof(struct sphdr);
528 	}
529 #ifdef DEBUG
530 	BUGOUT("netflush wrote %d",n);
531 	if (our_iovec[0].iov_base != (char*)&our_sphdr)
532 		BUGOUT("Oops:  our_iovec clobbered");
533 	BUGOUT("header: %d %d, %d %d %d %d %d %d",
534 		our_sphdr.sp_cc, our_sphdr.sp_dt,
535 		our_sphdr.sp_sid, our_sphdr.sp_did, our_sphdr.sp_seq,
536 		our_sphdr.sp_ack, our_sphdr.sp_alo);
537 #endif
538 	if (n < 0) {
539 		if (errno == EWOULDBLOCK)
540 			return;
541 		/* should blow this guy away... */
542 		return;
543 	}
544 	nbackp += n;
545 	if (nbackp >= nfrontp)	/* actually , > is an error */
546 		nbackp = nfrontp = netobuf;
547 }
548 
549 /*
550  * handle receipt of an SPPSST_END packet
551  * This is currently an error, since client didn't send "cleanup" first
552  */
quitquit()553 quitquit()
554 {
555 	changeSPPopts(net, SPPSST_ENDREPLY, 1);
556 	write(net, &our_sphdr, sizeof(our_sphdr));
557 	sleep(3);
558 
559 	rmut();
560 	vhangup();	/* XXX */
561 	shutdown(net, 1);
562 	close(net);
563 }
564 
565 /*
566  * shut down the data connection for one reason or another
567  */
cleanup()568 cleanup()
569 {
570 	int fdmask;
571 	struct timeval timeout;
572 	struct sphdr *si = (struct sphdr *)buf;
573 	int off = 0;
574 
575 	signal(SIGCHLD, SIG_IGN);
576 	sendoobdata(GAPCTLcleanup);
577 	changeSPPopts(net, SPPSST_END, 1);
578 	if (write(net, &our_sphdr, sizeof(our_sphdr)) < 0) {
579 		fdmask = 1<<net;
580 		timeout.tv_sec = 10;
581 		while (select(net+1,&fdmask,(int*)0, (int*)0, &timeout) > 0 &&
582 		       read(net,buf,sizeof(buf)) >= sizeof(struct sphdr)) {
583 #ifdef DEBUG
584 			BUGOUT("cleanup -- got packet");
585 #endif
586 			if ((si->sp_cc & SP_OB)
587 			    && si->sp_dt == SPPSST_ENDREPLY) {
588 				changeSPPopts(net, SPPSST_ENDREPLY, 1);
589 				write(net, &our_sphdr, sizeof(our_sphdr));
590 #ifdef DEBUG
591 				BUGOUT("cleanup -- wrote ENDREPLY");
592 #endif
593 				sleep(1);
594 				changeSPPopts(net,0,0);
595 				ioctl(net, FIONBIO, &off);
596 				rmut();
597 				vhangup();	/* XXX */
598 				return;
599 			}
600 			/* loop: ignore everything except ENDREPLY */
601 			fdmask = 1<<net;
602 			timeout.tv_sec = 10;
603 		}
604 		/* timed out or read failed */
605 		changeSPPopts(net, SPPSST_ENDREPLY, 1);
606 		write(net, &our_sphdr, sizeof(our_sphdr));
607 		sleep(1);
608 	}
609 	shutdown(net, 1);
610 	close(net);
611 	rmut();
612 	vhangup();	/* XXX */
613 }
614 
615 /*
616  * SIGCHLD interrupt handler
617  */
childdied()618 childdied()
619 {
620 #ifdef DEBUG
621 	BUGOUT("child died");
622 #endif
623 	cleanup();
624 	longjmp(childdiedbuf, -1);
625 }
626 
changeSPPopts(s,stream,eom)627 changeSPPopts(s, stream, eom)
628 	int s;			/* SPP socket */
629 	u_char stream;		/* datastream type */
630 	char eom;		/* Boolean EOM */
631 {
632 	our_sphdr.sp_dt = stream;
633 	our_sphdr.sp_cc = (eom ? SP_EM : 0);
634 }
635 
636 
637 #include <utmp.h>
638 
639 struct	utmp wtmp;
640 char	wtmpf[]	= "/usr/adm/wtmp";
641 char	utmp[] = "/etc/utmp";
642 #define SCPYN(a, b)	strncpy(a, b, sizeof (a))
643 #define SCMPN(a, b)	strncmp(a, b, sizeof (a))
644 
rmut()645 rmut()
646 {
647 	register f;
648 	int found = 0;
649 
650 	f = open(utmp, 2);
651 	if (f >= 0) {
652 		while(read(f, (char *)&wtmp, sizeof (wtmp)) == sizeof (wtmp)) {
653 			if (SCMPN(wtmp.ut_line, line+5) || wtmp.ut_name[0]==0)
654 				continue;
655 			lseek(f, -(long)sizeof (wtmp), 1);
656 			SCPYN(wtmp.ut_name, "");
657 			SCPYN(wtmp.ut_host, "");
658 			time(&wtmp.ut_time);
659 			write(f, (char *)&wtmp, sizeof (wtmp));
660 			found++;
661 		}
662 		close(f);
663 	}
664 	if (found) {
665 		f = open(wtmpf, 1);
666 		if (f >= 0) {
667 			SCPYN(wtmp.ut_line, line+5);
668 			SCPYN(wtmp.ut_name, "");
669 			SCPYN(wtmp.ut_host, "");
670 			time(&wtmp.ut_time);
671 			lseek(f, (long)0, 2);
672 			write(f, (char *)&wtmp, sizeof (wtmp));
673 			close(f);
674 		}
675 	}
676 	chmod(line, 0666);
677 	chown(line, 0, 0);
678 	line[strlen("/dev/")] = 'p';
679 	chmod(line, 0666);
680 	chown(line, 0, 0);
681 }
682 
683 /*
684  * Convert network-format xns address
685  * to ascii
686  * --Replace this with a clearinghouse name lookup someday.
687  */
688 char *
wsname(addr)689 wsname(addr)
690 	struct ns_addr addr;
691 {
692 	static char b[50];
693 	char temp[10];
694 	int i;
695 
696 	/* net */
697 	sprintf(b, "%D.", ntohl(ns_netof(addr)));
698 	/* skip leading zeros */
699 	for(i=0; (addr.x_host.c_host[i] == (char) 0); i++) ;
700 	/* print the rest */
701 	for(; i < 6; i++) {
702 		sprintf(temp,"%x", addr.x_host.c_host[i]);
703 		strcat(b, temp);
704 		if(i != 5) strcat(b, ":");
705 	}
706 	return (b);
707 }
708 
709 /*
710   * generate an xns address that "DE" can parse.
711   * This goes in the environment.  Should be the same as above
712   */
713 char *
xntoa(addr)714 xntoa(addr)
715 	struct ns_addr addr;
716 {
717 	static char b[50];
718 	char temp[10];
719 	int i;
720 
721 	/* net */
722 	sprintf(b, "%X#", ntohl(ns_netof(addr)));
723 	/* print the rest */
724 	for(i=0; i < 6; i++) {
725 		sprintf(temp,"%x", addr.x_host.c_host[i]);
726 		strcat(b, temp);
727 		if(i != 5) strcat(b, ".");
728 	}
729 	return (b);
730 }
731 
732 #ifdef DEBUG
BUGOUT(str,a,b,c,d,e,f,g,h)733 BUGOUT(str,a,b,c,d,e,f,g,h)
734 	char *str;
735 {
736 	FILE *fd;
737 	fd = fopen("/tmp/GAP2d.log","a");
738 	fprintf(fd,str,a,b,c,d,e,f,g,h);
739 	putc('\n',fd);
740 	fclose(fd);
741 }
742 #endif
743