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