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