xref: /csrg-svn/contrib/xns/examples/gap/gap2d.c (revision 34456)
134455Sbostic #ifndef lint
234455Sbostic static char RCSid[] = "$Header: gap2d.c,v 2.0 85/11/21 07:23:00 jqj Exp $";
334455Sbostic #endif
434455Sbostic /*
534455Sbostic  * server for GAP-style (TransportObject=server,teletype) telnet connections
634455Sbostic  * Note that we support only GAP version 2, although a server for version 3
734455Sbostic  * exists.  The version 2 server has not been tested as thoroughly as has the
834455Sbostic  * version 3; it does NOT support RESERVE functionality.
934455Sbostic  */
1034455Sbostic 
1134455Sbostic /* $Log:	gap2d.c,v $
1234455Sbostic  * Revision 2.0  85/11/21  07:23:00  jqj
1334455Sbostic  * 4.3BSD standard release
1434455Sbostic  *
1534455Sbostic  * Revision 1.2  85/05/23  06:22:18  jqj
1634455Sbostic  * *** empty log message ***
1734455Sbostic  *
1834455Sbostic  * Revision 1.2  85/05/23  06:22:18  jqj
1934455Sbostic  * *** empty log message ***
2034455Sbostic  *
2134455Sbostic  * Revision 1.1  85/05/22  09:46:52  jqj
2234455Sbostic  * Initial revision
2334455Sbostic  */
2434455Sbostic #include <stdio.h>
2534455Sbostic #include <signal.h>
2634455Sbostic #include <sgtty.h>
2734455Sbostic #include <sys/types.h>
2834455Sbostic #include <sys/time.h>
2934455Sbostic #include <sys/uio.h>
3034455Sbostic #include <sys/socket.h>
3134455Sbostic #include <netns/ns.h>
3234455Sbostic #include <netns/idp.h>
3334455Sbostic #include <netns/sp.h>
3434455Sbostic #include <sys/wait.h>
3534455Sbostic #include <xnscourier/realcourierconnection.h>
3634455Sbostic #include "GAP2.h"
3734455Sbostic #include "gapcontrols.h"
3834455Sbostic #include <xnscourier/except.h>
3934455Sbostic #include <errno.h>
4034455Sbostic 
4134455Sbostic #define	BELL	'\07'
4234455Sbostic #define BANNER	"\r\n\r\n4.3 BSD UNIX (%s)\r\n\r\r\n\r%s"
4334455Sbostic 
4434455Sbostic int pty, net;
4534455Sbostic extern CourierConnection *_serverConnection;
4634455Sbostic char buf[sizeof(struct sphdr)+SPPMAXDATA];
4734455Sbostic struct sphdr our_sphdr;
4834455Sbostic struct iovec our_iovec[2] = {{((caddr_t)&our_sphdr), sizeof(our_sphdr)}};
4934455Sbostic /*
5034455Sbostic  * I/O data buffers, pointers, and counters.
5134455Sbostic  */
5234455Sbostic char	ptyibuf[512], *ptyip = ptyibuf;
5334455Sbostic char	ptyobuf[BUFSIZ], *pfrontp = ptyobuf, *pbackp = ptyobuf;
5434455Sbostic char	*netip = buf;
5534455Sbostic char	netobuf[512], *nfrontp = netobuf, *nbackp = netobuf;
5634455Sbostic int	pcc, ncc;
5734455Sbostic char	line[12];
5834455Sbostic extern	char **environ;
5934455Sbostic extern	int errno;
6034455Sbostic 
6134455Sbostic char *envinit[3];
6234455Sbostic char wsenv[50];
6334455Sbostic 
6434455Sbostic /*
6534455Sbostic  * session parameters
6634455Sbostic  */
6734455Sbostic Cardinal frametimeout;		/* 0 or time in seconds to wait */
6834455Sbostic 
6934455Sbostic 
7034455Sbostic /*
7134455Sbostic  * This modified version of the server is necessary since GAP specifies
7234455Sbostic  * that the telnet data-transfer session occurs after the RPC to create
7334455Sbostic  * it has returned!
7434455Sbostic  */
Server(skipcount,skippedwords)7534455Sbostic Server(skipcount,skippedwords)
7634455Sbostic 	int skipcount;
7734455Sbostic 	Unspecified skippedwords[];
7834455Sbostic {
7934455Sbostic 	Cardinal _procedure;
8034455Sbostic 	register Unspecified *_buf;
8134455Sbostic 	LongCardinal programnum;
8234455Sbostic 	Cardinal versionnum;
8334455Sbostic 	Cardinal _n;
8434455Sbostic 
8534455Sbostic #ifdef DEBUG
8634455Sbostic 	BUGOUT("Server: %d %d",skipcount,skippedwords);
8734455Sbostic #endif
8834455Sbostic 	for (;;) {
8934455Sbostic 		_buf = ReceiveCallMessage(&_procedure, skipcount, skippedwords);
9034455Sbostic 		DURING switch (_procedure) {
9134455Sbostic 		case 3:
9234455Sbostic 			server_GAP2_Delete(_buf);
9334455Sbostic 			break;
9434455Sbostic 		case 2:
9534455Sbostic 			server_GAP2_Create(_buf);
9634455Sbostic 			net = _serverConnection->fd;
9734455Sbostic 			gaptelnet(); /* returns on connection close */
9834455Sbostic 			break;
9934455Sbostic 		case 0:
10034455Sbostic 			server_GAP2_Reset(_buf);
10134455Sbostic 			break;
10234455Sbostic 		default:
10334455Sbostic 			NoSuchProcedureValue("GAP", _procedure);
10434455Sbostic 			break;
10534455Sbostic 		} HANDLER {
10634455Sbostic 		    Deallocate(_buf);
10734455Sbostic 		    switch (Exception.Code) {
10834455Sbostic 		    case GAP2_terminalAddressInvalid:
10934455Sbostic 		    case GAP2_terminalAddressInUse:
11034455Sbostic 		    case GAP2_controllerDoesNotExist:
11134455Sbostic 		    case GAP2_controllerAlreadyExists:
11234455Sbostic 		    case GAP2_gapCommunicationError:
11334455Sbostic 		    case GAP2_gapNotExported:
11434455Sbostic 		    case GAP2_bugInGAPCode:
11534455Sbostic 		    case GAP2_tooManyGateStreams:
11634455Sbostic 		    case GAP2_inconsistentParams:
11734455Sbostic 		    case GAP2_transmissionMediumUnavailable:
11834455Sbostic 		    case GAP2_dialingHardwareProblem:
11934455Sbostic 		    case GAP2_noDialingHardware:
12034455Sbostic 		    case GAP2_badAddressFormat:
12134455Sbostic 		    case GAP2_mediumConnectFailed:
12234455Sbostic 		    case GAP2_illegalTransport:
12334455Sbostic 		    case GAP2_noCommunicationHardware:
12434455Sbostic 		    case GAP2_unimplemented:
12534455Sbostic 			_buf = Allocate(0);
12634455Sbostic 			SendAbortMessage(Exception.Code-ERROR_OFFSET, 0, _buf);
12734455Sbostic 			break;
12834455Sbostic 		    default:
12934455Sbostic 			_buf = Allocate(0);
13034455Sbostic 			SendRejectMessage(unspecifiedError, 0, _buf);
13134455Sbostic 			break;
13234455Sbostic 		    }
13334455Sbostic 		} END_HANDLER;
13434455Sbostic 		Deallocate(_buf);
13534455Sbostic 		for (;;) {
13634455Sbostic 			skipcount = LookAheadCallMsg(&programnum, &versionnum,
13734455Sbostic 					skippedwords);
13834455Sbostic 			if (skipcount < 0) return(0);	/* timed out */
13934455Sbostic 			if (programnum != 3 || versionnum != 2)
14034455Sbostic 				ExecCourierProgram(programnum, versionnum,
14134455Sbostic 						skipcount, skippedwords);
14234455Sbostic 		}  /* loop if can't exec that program */
14334455Sbostic 	}
14434455Sbostic }
14534455Sbostic 
14634455Sbostic void
GAP2_Delete(session)14734455Sbostic GAP2_Delete(session)
14834455Sbostic 	GAP2_SessionHandle session;
14934455Sbostic {
15034455Sbostic }
15134455Sbostic 
15234455Sbostic void
GAP2_Reset()15334455Sbostic GAP2_Reset()
15434455Sbostic {
15534455Sbostic }
15634455Sbostic 
15734455Sbostic GAP2_CreateResults
GAP2_Create(conn,BDTproc,sessionparams,transports,createTimeout)15834455Sbostic GAP2_Create(conn, BDTproc, sessionparams, transports,
15934455Sbostic 	    createTimeout)
16034455Sbostic 	CourierConnection *conn;
16134455Sbostic 	int BDTproc;
16234455Sbostic 	GAP2_SessionParameterObject sessionparams;
16334455Sbostic 	struct {Cardinal length;
16434455Sbostic 		GAP2_TransportObject *sequence;
16534455Sbostic 	} transports;
16634455Sbostic 	GAP2_WaitTime createTimeout;
16734455Sbostic {
16834455Sbostic 	GAP2_CreateResults result;
16934455Sbostic 	char *c1, *c2, *host;
17034455Sbostic 	int t, pid;
17134455Sbostic 	struct sgttyb b;
17234455Sbostic 	char *xntoa(), *wsname();
17334455Sbostic 	struct sockaddr_ns who;
17434455Sbostic 	int whosize = sizeof(who);
17534455Sbostic 	LongCardinal servicetype;
17634455Sbostic 	GAP2_CommParamObject *cp;
17734455Sbostic 	GAP2_Duplexity duplexity;	/* fullDuplex, halfDuplex */
17834455Sbostic 
17934455Sbostic #ifdef DEBUG
18034455Sbostic 	BUGOUT("CREATE");
18134455Sbostic #endif
18234455Sbostic 	switch (sessionparams.designator) {
18334455Sbostic 	case ttyHost:
18434455Sbostic 		frametimeout = sessionparams.ttyHost_case.frameTimeout/1000;
18534455Sbostic 		/* could set other parameters here */
18634455Sbostic 		break;
18734455Sbostic 	default:
18834455Sbostic 		raise(GAP2_unimplemented, 0);
18934455Sbostic 		/*NOTREACHED*/
19034455Sbostic 	}
19134455Sbostic 	if (transports.length != 2) {
19234455Sbostic 		raise(GAP2_illegalTransport);
19334455Sbostic 		/*NOTREACHED*/
19434455Sbostic 	}
19534455Sbostic 	switch (transports.sequence[0].designator) {
19634455Sbostic 	case rs232c:	/* maybe some day */
19734455Sbostic 		cp = &transports.sequence[0].rs232c_case.commParams;
19834455Sbostic 		if (cp->accessDetail.designator == directConn) {
19934455Sbostic 			duplexity = cp->duplex;
20034455Sbostic 			servicetype = 0; /* fake it */
20134455Sbostic 			break;
20234455Sbostic 		}
20334455Sbostic 		raise(GAP2_noCommunicationHardware, 0);
20434455Sbostic 		/*NOTREACHED*/
20534455Sbostic 	default:
20634455Sbostic 		raise(GAP2_illegalTransport, 0);
20734455Sbostic 		/*NOTREACHED*/
20834455Sbostic 	}
20934455Sbostic 	if (transports.sequence[1].designator != teletype)
21034455Sbostic 	  raise(GAP2_illegalTransport, 0);
21134455Sbostic 	/* ignore createTimeout */
21234455Sbostic 	/* ignore credentials and verifier */
21334455Sbostic 
21434455Sbostic 	for (c1 = "pq"; *c1 != 0; c1++)
21534455Sbostic 	  for (c2 = "0123456789abcdef"; *c2 != 0; c2++) {
21634455Sbostic 		  sprintf(line, "/dev/pty%c%c", *c1, *c2);
21734455Sbostic 		  pty = open(line, 2);
21834455Sbostic 		  if (pty < 0) continue;
21934455Sbostic 		  line[strlen("/dev/")] = 't';
22034455Sbostic 		  t = open(line, 2);
22134455Sbostic 		  if (t > 0) goto gotpty;
22234455Sbostic 		  close(pty);
22334455Sbostic 	  }
22434455Sbostic 	raise(GAP2_tooManyGateStreams, 0);
22534455Sbostic 	/*NOTREACHED*/
22634455Sbostic  gotpty:
22734455Sbostic 	getpeername(_serverConnection->fd, &who, &whosize);
22834455Sbostic 	host = wsname(who.sns_addr);
22934455Sbostic #ifdef DEBUG
23034455Sbostic 	BUGOUT("gotpty <%s> %d <%s>",line, pty, host);
23134455Sbostic #endif
23234455Sbostic 	ioctl(t, TIOCGETP, &b);
23334455Sbostic 	b.sg_flags = CRMOD|XTABS|ANYP;
23434455Sbostic 	ioctl(t, TIOCSETP, &b);
23534455Sbostic 	ioctl(pty, TIOCGETP, &b);
23634455Sbostic 	if (duplexity == fullduplex)
23734455Sbostic 	  b.sg_flags |= ECHO;
23834455Sbostic 	else
23934455Sbostic 	  b.sg_flags &= ~ECHO;
24034455Sbostic 	ioctl(pty, TIOCSETP, &b);
24134455Sbostic 	/* we do the fork now so we can return failures as REPORTS */
24234455Sbostic 	pid = fork();
24334455Sbostic 	if (pid < 0) {
24434455Sbostic 		close(pty); close(t);
24534455Sbostic 		raise(GAP2_tooManyGateStreams, 0);
24634455Sbostic 		/*NOTREACHED*/
24734455Sbostic 	}
24834455Sbostic 	else if (pid == 0) {	/* in the execed fork */
24934455Sbostic 		sleep(1);	/* let parent get ready for us */
25034455Sbostic 		close(_serverConnection->fd); /* close net */
25134455Sbostic 		close(pty);
25234455Sbostic 		dup2(t, 0);
25334455Sbostic 		dup2(t, 1);
25434455Sbostic 		dup2(t, 2);
25534455Sbostic 		if (t > 2) close(t);
25634455Sbostic 		envinit[0] = "TERM=network";
257*34456Sbostic 		(void)sprintf(wsenv, "WORKSTATION=%s", xntoa(who.sns_addr));
258*34456Sbostic 		envinit[1] = wsenv;
25934455Sbostic 		envinit[2] = (char*) 0;
26034455Sbostic #ifdef DEBUG
26134455Sbostic 		BUGOUT("about to exec /bin/login");
26234455Sbostic #endif
26334455Sbostic 		execl("/bin/login","login", "-h", host, 0);
26434455Sbostic #ifdef DEBUG
26534455Sbostic 		BUGOUT("exec of /bin/login failed");
26634455Sbostic #endif
26734455Sbostic 		perror("/bin/login");
26834455Sbostic 		exit(1);
26934455Sbostic 		/*NOTREACHED*/
27034455Sbostic 	}
27134455Sbostic 	close(t);
27234455Sbostic #ifdef DEBUG
27334455Sbostic 	BUGOUT("fork successful");
27434455Sbostic #endif
27534455Sbostic 	result.session[0] = pid;
27634455Sbostic 	return(result);
27734455Sbostic }
27834455Sbostic 
27934455Sbostic jmp_buf childdiedbuf;
28034455Sbostic 
28134455Sbostic /*
28234455Sbostic  * Main loop.  Select from pty and network, and
28334455Sbostic  * hand data to telnet receiver finite state machine.
28434455Sbostic  * Returns 0 on orderly shutdown, 1 on abnormal shutdown.
28534455Sbostic  */
gaptelnet()28634455Sbostic gaptelnet()
28734455Sbostic {
28834455Sbostic 	int on = 1;
28934455Sbostic 	char hostname[32];
29034455Sbostic 	int childdied();
29134455Sbostic 	int ibits = 0, obits = 0;
29234455Sbostic 	register int c;
29334455Sbostic 	struct sphdr *si = (struct sphdr *)buf;
29434455Sbostic 	static struct timeval timeout = {600,0};
29534455Sbostic 	int keepalives = 0;
29634455Sbostic 	int i;
29734455Sbostic 
29834455Sbostic #ifdef DEBUG
29934455Sbostic 	BUGOUT("gaptelnet net=%d,pty=%d",net,pty);
30034455Sbostic #endif
30134455Sbostic 	if (setjmp(childdiedbuf) != 0)
30234455Sbostic 	  return(0);		/* child died */
30334455Sbostic 	signal(SIGCHLD, childdied);
30434455Sbostic 	signal(SIGTSTP, SIG_IGN);
30534455Sbostic 	ioctl(net, FIONBIO, &on);
30634455Sbostic 	ioctl(pty, FIONBIO, &on);
30734455Sbostic 
30834455Sbostic 
30934455Sbostic 	/*
31034455Sbostic 	 * Show banner that getty never gave.
31134455Sbostic 	 */
31234455Sbostic 	gethostname(hostname, sizeof (hostname));
31334455Sbostic 	sprintf(nfrontp, BANNER, hostname, "");
31434455Sbostic 	nfrontp += strlen(nfrontp);
31534455Sbostic 	/*
31634455Sbostic 	 * Send status message indicating we're ready to go
31734455Sbostic 	 */
31834455Sbostic 	changeSPPopts(net, GAPCTLnone, 1);
31934455Sbostic 	sendoobdata(GAPCTLmediumUp);
32034455Sbostic 	for (;;) {
32134455Sbostic #ifdef DEBUG
32234455Sbostic 		BUGOUT("looping in gaptelnet");
32334455Sbostic #endif
32434455Sbostic 		ibits = obits = 0;
32534455Sbostic 		/*
32634455Sbostic 		 * Never look for input if there's still
32734455Sbostic 		 * stuff in the corresponding output buffer
32834455Sbostic 		 */
32934455Sbostic 		if (nfrontp - nbackp || pcc > 0)
33034455Sbostic 			obits |= (1 << net);
33134455Sbostic 		else
33234455Sbostic 			ibits |= (1 << pty);
33334455Sbostic 		if (pfrontp - pbackp || ncc > 0)
33434455Sbostic 			obits |= (1 << pty);
33534455Sbostic 		else
33634455Sbostic 			ibits |= (1 << net);
33734455Sbostic 		if (ncc < 0 && pcc < 0)
33834455Sbostic 			break;
33934455Sbostic 		timeout.tv_sec = 600;
34034455Sbostic 		timeout.tv_usec = 0;
34134455Sbostic 		select(16, &ibits, &obits, 0, &timeout);
34234455Sbostic 		if (ibits == 0 && obits == 0) {
34334455Sbostic 			/* timeout means no activity for a long time */
34434455Sbostic #ifdef DEBUG
34534455Sbostic 			BUGOUT("timeout from select");
34634455Sbostic #endif
34734455Sbostic 			if (keepalives++ < 2) {
34834455Sbostic 			  /* first 2 times through send warning */
34934455Sbostic 				if (nfrontp == nbackp && pcc == 0) {
35034455Sbostic 					/* but only if not blocked on output */
35134455Sbostic #define WARNING "\r\nYou've been idle much too long.  Respond or log off.\r\n"
35234455Sbostic 					strcpy(nfrontp, WARNING);
35334455Sbostic 					nfrontp += sizeof(WARNING);
35434455Sbostic 				}
35534455Sbostic 				sleep(5);
35634455Sbostic 				continue;
35734455Sbostic 			}
35834455Sbostic #ifdef DEBUG
35934455Sbostic 			BUGOUT("keepalive expired -- calling cleanup");
36034455Sbostic #endif
36134455Sbostic 			/* keepalive count has expired */
36234455Sbostic 			cleanup();
36334455Sbostic 			return(1);
36434455Sbostic 		}
36534455Sbostic 
36634455Sbostic 		/*
36734455Sbostic 		 * Something to read from the network...
36834455Sbostic 		 */
36934455Sbostic 		if (ibits & (1 << net)) {
37034455Sbostic 			ncc = read(net, buf, sizeof(buf));
37134455Sbostic #ifdef DEBUG
37234455Sbostic 			BUGOUT("read from net %d",ncc);
37334455Sbostic #endif
37434455Sbostic 			if (ncc < 0 && errno == EWOULDBLOCK)
37534455Sbostic 				ncc = 0;
37634455Sbostic 			else if (ncc < sizeof(struct sphdr)) {
37734455Sbostic #ifdef DEBUG
37834455Sbostic 				BUGOUT("short read, %d.  calling cleanup",ncc);
37934455Sbostic #endif
38034455Sbostic 				cleanup(); /* will probably fail or block */
38134455Sbostic 				return(1);
38234455Sbostic 			}
38334455Sbostic 			else if (si->sp_cc & SP_OB) {
38434455Sbostic 				/* a status or OOB control */
38534455Sbostic 				switch (buf[sizeof(struct sphdr)]) {
38634455Sbostic 				case GAPCTLinterrupt:
38734455Sbostic 					/* shove interrupt char in buffer */
38834455Sbostic 					interrupt();
38934455Sbostic 					break; /* from switch */
39034455Sbostic 				case GAPCTLareYouThere:
39134455Sbostic 					sendoobdata(GAPCTLiAmHere);
39234455Sbostic 					break; /* from switch */
39334455Sbostic 				default:
39434455Sbostic 					/* Ignore other controls instead of:
39534455Sbostic 					 * sendoobdata(
39634455Sbostic 					 *     GAPCTLunexpectedRemoteBehavior);
39734455Sbostic 					 */
39834455Sbostic 					break; /* from switch */
39934455Sbostic 				}
40034455Sbostic 				ncc = 0; /* no chars here */
40134455Sbostic 			}
40234455Sbostic 			else if (si->sp_dt==GAPCTLnone) {
40334455Sbostic 				/* the normal case */
40434455Sbostic 				ncc -= sizeof(struct sphdr);
40534455Sbostic 				netip = buf + sizeof(struct sphdr);
40634455Sbostic 				keepalives = 0;
40734455Sbostic 			}
40834455Sbostic 			else if(si->sp_dt==GAPCTLcleanup) {
40934455Sbostic #ifdef DEBUG
41034455Sbostic 				BUGOUT("got CLEANUP packet.  Done");
41134455Sbostic #endif
41234455Sbostic 				cleanup(); /* normal termination */
41334455Sbostic 				return(0);
41434455Sbostic 			}
41534455Sbostic 			else if (si->sp_dt==SPPSST_END) {
41634455Sbostic 				/* got premature termination */
41734455Sbostic 				quitquit(net, pty);
41834455Sbostic 				return(1);
41934455Sbostic 			}
42034455Sbostic 		}
42134455Sbostic 
42234455Sbostic 		/*
42334455Sbostic 		 * Something to read from the pty...
42434455Sbostic 		 */
42534455Sbostic 		if (ibits & (1 << pty)) {
42634455Sbostic 			if (frametimeout > 0) sleep(frametimeout);
42734455Sbostic 			pcc = read(pty, ptyibuf, sizeof(ptyibuf));
42834455Sbostic #ifdef DEBUG
42934455Sbostic 			BUGOUT("read from pty %d",pcc);
43034455Sbostic #endif
43134455Sbostic 			if (pcc < 0 && errno == EWOULDBLOCK)
43234455Sbostic 				pcc = 0;
43334455Sbostic 			else if (pcc <= 0) {
43434455Sbostic #ifdef DEBUG
43534455Sbostic 				BUGOUT("short read from pty. Calling cleanup");
43634455Sbostic #endif
43734455Sbostic 				cleanup();
43834455Sbostic 				return(1); /* ?? abnormal termination */
43934455Sbostic 			}
44034455Sbostic 			ptyip = ptyibuf;
44134455Sbostic 		}
44234455Sbostic 
44334455Sbostic 		while (pcc > 0) {
44434455Sbostic 			if ((&netobuf[sizeof(netobuf)] - nfrontp) < 2)
44534455Sbostic 				break;
44634455Sbostic 			*nfrontp++ = *ptyip++ & 0377; pcc--;
44734455Sbostic 		}
44834455Sbostic 		if ((obits & (1 << net)) && (nfrontp - nbackp) > 0)
44934455Sbostic 			netflush();
45034455Sbostic 		while (ncc > 0) {
45134455Sbostic 			if ((&ptyobuf[sizeof(ptyobuf)] - pfrontp) < 2) break;
45234455Sbostic 			*pfrontp++ = *netip++ & 0377;
45334455Sbostic 			ncc--;
45434455Sbostic 		}
45534455Sbostic 		if ((obits & (1 << pty)) && (pfrontp - pbackp) > 0)
45634455Sbostic 			ptyflush();
45734455Sbostic 	}
45834455Sbostic 	/* we should never get to here */
45934455Sbostic #ifdef DEBUG
46034455Sbostic 	BUGOUT("broke out of for(;;) somehow.  calling cleanup");
46134455Sbostic #endif
46234455Sbostic 	cleanup();
46334455Sbostic 	return(0);
46434455Sbostic }
46534455Sbostic 
46634455Sbostic /*
46734455Sbostic  * Send out of band data to other end of network
46834455Sbostic  */
sendoobdata(value)46934455Sbostic sendoobdata(value)
47034455Sbostic 	u_char value;
47134455Sbostic {
47234455Sbostic 	struct {
47334455Sbostic 		struct sphdr hdr;
47434455Sbostic 		char val;
47534455Sbostic 	} oob;
47634455Sbostic 	oob.hdr = our_sphdr;
47734455Sbostic 	oob.val = value;
47834455Sbostic #ifdef DEBUG
47934455Sbostic 	BUGOUT("sendoobdata 0%o",value);
48034455Sbostic #endif
48134455Sbostic 	send(net, &oob, sizeof(oob), MSG_OOB);
48234455Sbostic }
48334455Sbostic 
48434455Sbostic /*
48534455Sbostic  * Send interrupt to process on other side of pty.
48634455Sbostic  * If it is in raw mode, just write NULL;
48734455Sbostic  * otherwise, write intr char.
48834455Sbostic  */
interrupt()48934455Sbostic interrupt()
49034455Sbostic {
49134455Sbostic 	struct sgttyb b;
49234455Sbostic 	struct tchars tchars;
49334455Sbostic 
49434455Sbostic 	ptyflush();	/* half-hearted */
49534455Sbostic 	ioctl(pty, TIOCGETP, &b);
49634455Sbostic 	if (b.sg_flags & RAW) {
49734455Sbostic 		*pfrontp++ = '\0';
49834455Sbostic 		return;
49934455Sbostic 	}
50034455Sbostic 	*pfrontp++ = ioctl(pty, TIOCGETC, &tchars) < 0 ?
50134455Sbostic 		'\177' : tchars.t_intrc;
50234455Sbostic }
50334455Sbostic 
ptyflush()50434455Sbostic ptyflush()
50534455Sbostic {
50634455Sbostic 	register int n;
50734455Sbostic 
50834455Sbostic 	if ((n = pfrontp - pbackp) > 0)
50934455Sbostic 		n = write(pty, pbackp, n);
51034455Sbostic #ifdef DEBUG
51134455Sbostic 	BUGOUT("ptyflush wrote %d",n);
51234455Sbostic #endif
51334455Sbostic 	if (n < 0)
51434455Sbostic 		return;
51534455Sbostic 	pbackp += n;
51634455Sbostic 	if (pbackp >= pfrontp)	/* actually, > is an error */
51734455Sbostic 		pbackp = pfrontp = ptyobuf;
51834455Sbostic }
51934455Sbostic 
netflush()52034455Sbostic netflush()
52134455Sbostic {
52234455Sbostic 	register int n;
52334455Sbostic 
52434455Sbostic 	if ((n = nfrontp - nbackp) > 0) {
52534455Sbostic 		our_iovec[1].iov_len = ((n > SPPMAXDATA) ? SPPMAXDATA : n);
52634455Sbostic 		our_iovec[1].iov_base = nbackp;
52734455Sbostic 		n = writev(net, our_iovec, 2) - sizeof(struct sphdr);
52834455Sbostic 	}
52934455Sbostic #ifdef DEBUG
53034455Sbostic 	BUGOUT("netflush wrote %d",n);
53134455Sbostic 	if (our_iovec[0].iov_base != (char*)&our_sphdr)
53234455Sbostic 		BUGOUT("Oops:  our_iovec clobbered");
53334455Sbostic 	BUGOUT("header: %d %d, %d %d %d %d %d %d",
53434455Sbostic 		our_sphdr.sp_cc, our_sphdr.sp_dt,
53534455Sbostic 		our_sphdr.sp_sid, our_sphdr.sp_did, our_sphdr.sp_seq,
53634455Sbostic 		our_sphdr.sp_ack, our_sphdr.sp_alo);
53734455Sbostic #endif
53834455Sbostic 	if (n < 0) {
53934455Sbostic 		if (errno == EWOULDBLOCK)
54034455Sbostic 			return;
54134455Sbostic 		/* should blow this guy away... */
54234455Sbostic 		return;
54334455Sbostic 	}
54434455Sbostic 	nbackp += n;
54534455Sbostic 	if (nbackp >= nfrontp)	/* actually , > is an error */
54634455Sbostic 		nbackp = nfrontp = netobuf;
54734455Sbostic }
54834455Sbostic 
54934455Sbostic /*
55034455Sbostic  * handle receipt of an SPPSST_END packet
55134455Sbostic  * This is currently an error, since client didn't send "cleanup" first
55234455Sbostic  */
quitquit()55334455Sbostic quitquit()
55434455Sbostic {
55534455Sbostic 	changeSPPopts(net, SPPSST_ENDREPLY, 1);
55634455Sbostic 	write(net, &our_sphdr, sizeof(our_sphdr));
55734455Sbostic 	sleep(3);
55834455Sbostic 
55934455Sbostic 	rmut();
56034455Sbostic 	vhangup();	/* XXX */
56134455Sbostic 	shutdown(net, 1);
56234455Sbostic 	close(net);
56334455Sbostic }
56434455Sbostic 
56534455Sbostic /*
56634455Sbostic  * shut down the data connection for one reason or another
56734455Sbostic  */
cleanup()56834455Sbostic cleanup()
56934455Sbostic {
57034455Sbostic 	int fdmask;
57134455Sbostic 	struct timeval timeout;
57234455Sbostic 	struct sphdr *si = (struct sphdr *)buf;
57334455Sbostic 	int off = 0;
57434455Sbostic 
57534455Sbostic 	signal(SIGCHLD, SIG_IGN);
57634455Sbostic 	sendoobdata(GAPCTLcleanup);
57734455Sbostic 	changeSPPopts(net, SPPSST_END, 1);
57834455Sbostic 	if (write(net, &our_sphdr, sizeof(our_sphdr)) < 0) {
57934455Sbostic 		fdmask = 1<<net;
58034455Sbostic 		timeout.tv_sec = 10;
58134455Sbostic 		while (select(net+1,&fdmask,(int*)0, (int*)0, &timeout) > 0 &&
58234455Sbostic 		       read(net,buf,sizeof(buf)) >= sizeof(struct sphdr)) {
58334455Sbostic #ifdef DEBUG
58434455Sbostic 			BUGOUT("cleanup -- got packet");
58534455Sbostic #endif
58634455Sbostic 			if ((si->sp_cc & SP_OB)
58734455Sbostic 			    && si->sp_dt == SPPSST_ENDREPLY) {
58834455Sbostic 				changeSPPopts(net, SPPSST_ENDREPLY, 1);
58934455Sbostic 				write(net, &our_sphdr, sizeof(our_sphdr));
59034455Sbostic #ifdef DEBUG
59134455Sbostic 				BUGOUT("cleanup -- wrote ENDREPLY");
59234455Sbostic #endif
59334455Sbostic 				sleep(1);
59434455Sbostic 				changeSPPopts(net,0,0);
59534455Sbostic 				ioctl(net, FIONBIO, &off);
59634455Sbostic 				rmut();
59734455Sbostic 				vhangup();	/* XXX */
59834455Sbostic 				return;
59934455Sbostic 			}
60034455Sbostic 			/* loop: ignore everything except ENDREPLY */
60134455Sbostic 			fdmask = 1<<net;
60234455Sbostic 			timeout.tv_sec = 10;
60334455Sbostic 		}
60434455Sbostic 		/* timed out or read failed */
60534455Sbostic 		changeSPPopts(net, SPPSST_ENDREPLY, 1);
60634455Sbostic 		write(net, &our_sphdr, sizeof(our_sphdr));
60734455Sbostic 		sleep(1);
60834455Sbostic 	}
60934455Sbostic 	shutdown(net, 1);
61034455Sbostic 	close(net);
61134455Sbostic 	rmut();
61234455Sbostic 	vhangup();	/* XXX */
61334455Sbostic }
61434455Sbostic 
61534455Sbostic /*
61634455Sbostic  * SIGCHLD interrupt handler
61734455Sbostic  */
childdied()61834455Sbostic childdied()
61934455Sbostic {
62034455Sbostic #ifdef DEBUG
62134455Sbostic 	BUGOUT("child died");
62234455Sbostic #endif
62334455Sbostic 	cleanup();
62434455Sbostic 	longjmp(childdiedbuf, -1);
62534455Sbostic }
62634455Sbostic 
changeSPPopts(s,stream,eom)62734455Sbostic changeSPPopts(s, stream, eom)
62834455Sbostic 	int s;			/* SPP socket */
62934455Sbostic 	u_char stream;		/* datastream type */
63034455Sbostic 	char eom;		/* Boolean EOM */
63134455Sbostic {
63234455Sbostic 	our_sphdr.sp_dt = stream;
63334455Sbostic 	our_sphdr.sp_cc = (eom ? SP_EM : 0);
63434455Sbostic }
63534455Sbostic 
63634455Sbostic 
63734455Sbostic #include <utmp.h>
63834455Sbostic 
63934455Sbostic struct	utmp wtmp;
64034455Sbostic char	wtmpf[]	= "/usr/adm/wtmp";
64134455Sbostic char	utmp[] = "/etc/utmp";
64234455Sbostic #define SCPYN(a, b)	strncpy(a, b, sizeof (a))
64334455Sbostic #define SCMPN(a, b)	strncmp(a, b, sizeof (a))
64434455Sbostic 
rmut()64534455Sbostic rmut()
64634455Sbostic {
64734455Sbostic 	register f;
64834455Sbostic 	int found = 0;
64934455Sbostic 
65034455Sbostic 	f = open(utmp, 2);
65134455Sbostic 	if (f >= 0) {
65234455Sbostic 		while(read(f, (char *)&wtmp, sizeof (wtmp)) == sizeof (wtmp)) {
65334455Sbostic 			if (SCMPN(wtmp.ut_line, line+5) || wtmp.ut_name[0]==0)
65434455Sbostic 				continue;
65534455Sbostic 			lseek(f, -(long)sizeof (wtmp), 1);
65634455Sbostic 			SCPYN(wtmp.ut_name, "");
65734455Sbostic 			SCPYN(wtmp.ut_host, "");
65834455Sbostic 			time(&wtmp.ut_time);
65934455Sbostic 			write(f, (char *)&wtmp, sizeof (wtmp));
66034455Sbostic 			found++;
66134455Sbostic 		}
66234455Sbostic 		close(f);
66334455Sbostic 	}
66434455Sbostic 	if (found) {
66534455Sbostic 		f = open(wtmpf, 1);
66634455Sbostic 		if (f >= 0) {
66734455Sbostic 			SCPYN(wtmp.ut_line, line+5);
66834455Sbostic 			SCPYN(wtmp.ut_name, "");
66934455Sbostic 			SCPYN(wtmp.ut_host, "");
67034455Sbostic 			time(&wtmp.ut_time);
67134455Sbostic 			lseek(f, (long)0, 2);
67234455Sbostic 			write(f, (char *)&wtmp, sizeof (wtmp));
67334455Sbostic 			close(f);
67434455Sbostic 		}
67534455Sbostic 	}
67634455Sbostic 	chmod(line, 0666);
67734455Sbostic 	chown(line, 0, 0);
67834455Sbostic 	line[strlen("/dev/")] = 'p';
67934455Sbostic 	chmod(line, 0666);
68034455Sbostic 	chown(line, 0, 0);
68134455Sbostic }
68234455Sbostic 
68334455Sbostic /*
68434455Sbostic  * Convert network-format xns address
68534455Sbostic  * to ascii
68634455Sbostic  * --Replace this with a clearinghouse name lookup someday.
68734455Sbostic  */
68834455Sbostic char *
wsname(addr)68934455Sbostic wsname(addr)
69034455Sbostic 	struct ns_addr addr;
69134455Sbostic {
69234455Sbostic 	static char b[50];
69334455Sbostic 	char temp[10];
69434455Sbostic 	int i;
69534455Sbostic 
69634455Sbostic 	/* net */
69734455Sbostic 	sprintf(b, "%D.", ntohl(ns_netof(addr)));
69834455Sbostic 	/* skip leading zeros */
69934455Sbostic 	for(i=0; (addr.x_host.c_host[i] == (char) 0); i++) ;
70034455Sbostic 	/* print the rest */
70134455Sbostic 	for(; i < 6; i++) {
70234455Sbostic 		sprintf(temp,"%x", addr.x_host.c_host[i]);
70334455Sbostic 		strcat(b, temp);
70434455Sbostic 		if(i != 5) strcat(b, ":");
70534455Sbostic 	}
70634455Sbostic 	return (b);
70734455Sbostic }
70834455Sbostic 
70934455Sbostic /*
71034455Sbostic   * generate an xns address that "DE" can parse.
71134455Sbostic   * This goes in the environment.  Should be the same as above
71234455Sbostic   */
71334455Sbostic char *
xntoa(addr)71434455Sbostic xntoa(addr)
71534455Sbostic 	struct ns_addr addr;
71634455Sbostic {
71734455Sbostic 	static char b[50];
71834455Sbostic 	char temp[10];
71934455Sbostic 	int i;
72034455Sbostic 
72134455Sbostic 	/* net */
72234455Sbostic 	sprintf(b, "%X#", ntohl(ns_netof(addr)));
72334455Sbostic 	/* print the rest */
72434455Sbostic 	for(i=0; i < 6; i++) {
72534455Sbostic 		sprintf(temp,"%x", addr.x_host.c_host[i]);
72634455Sbostic 		strcat(b, temp);
72734455Sbostic 		if(i != 5) strcat(b, ".");
72834455Sbostic 	}
72934455Sbostic 	return (b);
73034455Sbostic }
73134455Sbostic 
73234455Sbostic #ifdef DEBUG
BUGOUT(str,a,b,c,d,e,f,g,h)73334455Sbostic BUGOUT(str,a,b,c,d,e,f,g,h)
73434455Sbostic 	char *str;
73534455Sbostic {
73634455Sbostic 	FILE *fd;
73734455Sbostic 	fd = fopen("/tmp/GAP2d.log","a");
73834455Sbostic 	fprintf(fd,str,a,b,c,d,e,f,g,h);
73934455Sbostic 	putc('\n',fd);
74034455Sbostic 	fclose(fd);
74134455Sbostic }
74234455Sbostic #endif
743