xref: /csrg-svn/usr.bin/telnet/network.c (revision 32146)
1*32146Sminshall #include <sys/types.h>
2*32146Sminshall #include <sys/socket.h>
3*32146Sminshall #include <sys/time.h>
4*32146Sminshall 
5*32146Sminshall #include <errno.h>
6*32146Sminshall 
7*32146Sminshall #include <arpa/telnet.h>
8*32146Sminshall 
9*32146Sminshall #include "defines.h"
10*32146Sminshall #include "externs.h"
11*32146Sminshall 
12*32146Sminshall char	netobuf[2*BUFSIZ], *nfrontp, *nbackp;
13*32146Sminshall static char	*neturg;		/* one past last byte of urgent data */
14*32146Sminshall 
15*32146Sminshall /*
16*32146Sminshall  * Initialize internal network data structures.
17*32146Sminshall  */
18*32146Sminshall 
19*32146Sminshall init_network()
20*32146Sminshall {
21*32146Sminshall     nfrontp = nbackp = netobuf;
22*32146Sminshall     NetTrace = stdout;
23*32146Sminshall }
24*32146Sminshall 
25*32146Sminshall 
26*32146Sminshall /*
27*32146Sminshall  * Check to see if any out-of-band data exists on a socket (for
28*32146Sminshall  * Telnet "synch" processing).
29*32146Sminshall  */
30*32146Sminshall 
31*32146Sminshall int
32*32146Sminshall stilloob(s)
33*32146Sminshall int	s;		/* socket number */
34*32146Sminshall {
35*32146Sminshall     static struct timeval timeout = { 0 };
36*32146Sminshall     fd_set	excepts;
37*32146Sminshall     int value;
38*32146Sminshall 
39*32146Sminshall     do {
40*32146Sminshall 	FD_ZERO(&excepts);
41*32146Sminshall 	FD_SET(s, &excepts);
42*32146Sminshall 	value = select(s+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout);
43*32146Sminshall     } while ((value == -1) && (errno == EINTR));
44*32146Sminshall 
45*32146Sminshall     if (value < 0) {
46*32146Sminshall 	perror("select");
47*32146Sminshall 	quit();
48*32146Sminshall     }
49*32146Sminshall     if (FD_ISSET(s, &excepts)) {
50*32146Sminshall 	return 1;
51*32146Sminshall     } else {
52*32146Sminshall 	return 0;
53*32146Sminshall     }
54*32146Sminshall }
55*32146Sminshall 
56*32146Sminshall 
57*32146Sminshall /*
58*32146Sminshall  *  netflush
59*32146Sminshall  *		Send as much data as possible to the network,
60*32146Sminshall  *	handling requests for urgent data.
61*32146Sminshall  *
62*32146Sminshall  *		The return value indicates whether we did any
63*32146Sminshall  *	useful work.
64*32146Sminshall  */
65*32146Sminshall 
66*32146Sminshall 
67*32146Sminshall int
68*32146Sminshall netflush()
69*32146Sminshall {
70*32146Sminshall     int n;
71*32146Sminshall 
72*32146Sminshall     if ((n = nfrontp - nbackp) > 0) {
73*32146Sminshall 	if (!neturg) {
74*32146Sminshall 	    n = send(net, nbackp, n, 0);	/* normal write */
75*32146Sminshall 	} else {
76*32146Sminshall 	    n = neturg - nbackp;
77*32146Sminshall 	    /*
78*32146Sminshall 	     * In 4.2 (and 4.3) systems, there is some question about
79*32146Sminshall 	     * what byte in a sendOOB operation is the "OOB" data.
80*32146Sminshall 	     * To make ourselves compatible, we only send ONE byte
81*32146Sminshall 	     * out of band, the one WE THINK should be OOB (though
82*32146Sminshall 	     * we really have more the TCP philosophy of urgent data
83*32146Sminshall 	     * rather than the Unix philosophy of OOB data).
84*32146Sminshall 	     */
85*32146Sminshall 	    if (n > 1) {
86*32146Sminshall 		n = send(net, nbackp, n-1, 0);	/* send URGENT all by itself */
87*32146Sminshall 	    } else {
88*32146Sminshall 		n = send(net, nbackp, n, MSG_OOB);	/* URGENT data */
89*32146Sminshall 	    }
90*32146Sminshall 	}
91*32146Sminshall     }
92*32146Sminshall     if (n < 0) {
93*32146Sminshall 	if (errno != ENOBUFS && errno != EWOULDBLOCK) {
94*32146Sminshall 	    setcommandmode();
95*32146Sminshall 	    perror(hostname);
96*32146Sminshall 	    NetClose(net);
97*32146Sminshall 	    neturg = 0;
98*32146Sminshall 	    longjmp(peerdied, -1);
99*32146Sminshall 	    /*NOTREACHED*/
100*32146Sminshall 	}
101*32146Sminshall 	n = 0;
102*32146Sminshall     }
103*32146Sminshall     if (netdata && n) {
104*32146Sminshall 	Dump('>', nbackp, n);
105*32146Sminshall     }
106*32146Sminshall     nbackp += n;
107*32146Sminshall     if (nbackp >= neturg) {
108*32146Sminshall 	neturg = 0;
109*32146Sminshall     }
110*32146Sminshall     if (nbackp == nfrontp) {
111*32146Sminshall 	nbackp = nfrontp = netobuf;
112*32146Sminshall     }
113*32146Sminshall     return n > 0;
114*32146Sminshall }
115*32146Sminshall 
116*32146Sminshall /*
117*32146Sminshall  * nextitem()
118*32146Sminshall  *
119*32146Sminshall  *	Return the address of the next "item" in the TELNET data
120*32146Sminshall  * stream.  This will be the address of the next character if
121*32146Sminshall  * the current address is a user data character, or it will
122*32146Sminshall  * be the address of the character following the TELNET command
123*32146Sminshall  * if the current address is a TELNET IAC ("I Am a Command")
124*32146Sminshall  * character.
125*32146Sminshall  */
126*32146Sminshall 
127*32146Sminshall static char *
128*32146Sminshall nextitem(current)
129*32146Sminshall char	*current;
130*32146Sminshall {
131*32146Sminshall     if ((*current&0xff) != IAC) {
132*32146Sminshall 	return current+1;
133*32146Sminshall     }
134*32146Sminshall     switch (*(current+1)&0xff) {
135*32146Sminshall     case DO:
136*32146Sminshall     case DONT:
137*32146Sminshall     case WILL:
138*32146Sminshall     case WONT:
139*32146Sminshall 	return current+3;
140*32146Sminshall     case SB:		/* loop forever looking for the SE */
141*32146Sminshall 	{
142*32146Sminshall 	    register char *look = current+2;
143*32146Sminshall 
144*32146Sminshall 	    for (;;) {
145*32146Sminshall 		if ((*look++&0xff) == IAC) {
146*32146Sminshall 		    if ((*look++&0xff) == SE) {
147*32146Sminshall 			return look;
148*32146Sminshall 		    }
149*32146Sminshall 		}
150*32146Sminshall 	    }
151*32146Sminshall 	}
152*32146Sminshall     default:
153*32146Sminshall 	return current+2;
154*32146Sminshall     }
155*32146Sminshall }
156*32146Sminshall /*
157*32146Sminshall  * netclear()
158*32146Sminshall  *
159*32146Sminshall  *	We are about to do a TELNET SYNCH operation.  Clear
160*32146Sminshall  * the path to the network.
161*32146Sminshall  *
162*32146Sminshall  *	Things are a bit tricky since we may have sent the first
163*32146Sminshall  * byte or so of a previous TELNET command into the network.
164*32146Sminshall  * So, we have to scan the network buffer from the beginning
165*32146Sminshall  * until we are up to where we want to be.
166*32146Sminshall  *
167*32146Sminshall  *	A side effect of what we do, just to keep things
168*32146Sminshall  * simple, is to clear the urgent data pointer.  The principal
169*32146Sminshall  * caller should be setting the urgent data pointer AFTER calling
170*32146Sminshall  * us in any case.
171*32146Sminshall  */
172*32146Sminshall 
173*32146Sminshall static void
174*32146Sminshall netclear()
175*32146Sminshall {
176*32146Sminshall     register char *thisitem, *next;
177*32146Sminshall     char *good;
178*32146Sminshall #define	wewant(p)	((nfrontp > p) && ((*p&0xff) == IAC) && \
179*32146Sminshall 				((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))
180*32146Sminshall 
181*32146Sminshall     thisitem = netobuf;
182*32146Sminshall 
183*32146Sminshall     while ((next = nextitem(thisitem)) <= nbackp) {
184*32146Sminshall 	thisitem = next;
185*32146Sminshall     }
186*32146Sminshall 
187*32146Sminshall     /* Now, thisitem is first before/at boundary. */
188*32146Sminshall 
189*32146Sminshall     good = netobuf;	/* where the good bytes go */
190*32146Sminshall 
191*32146Sminshall     while (nfrontp > thisitem) {
192*32146Sminshall 	if (wewant(thisitem)) {
193*32146Sminshall 	    int length;
194*32146Sminshall 
195*32146Sminshall 	    next = thisitem;
196*32146Sminshall 	    do {
197*32146Sminshall 		next = nextitem(next);
198*32146Sminshall 	    } while (wewant(next) && (nfrontp > next));
199*32146Sminshall 	    length = next-thisitem;
200*32146Sminshall 	    memcpy(good, thisitem, length);
201*32146Sminshall 	    good += length;
202*32146Sminshall 	    thisitem = next;
203*32146Sminshall 	} else {
204*32146Sminshall 	    thisitem = nextitem(thisitem);
205*32146Sminshall 	}
206*32146Sminshall     }
207*32146Sminshall 
208*32146Sminshall     nbackp = netobuf;
209*32146Sminshall     nfrontp = good;		/* next byte to be sent */
210*32146Sminshall     neturg = 0;
211*32146Sminshall }
212*32146Sminshall 
213*32146Sminshall /*
214*32146Sminshall  * These routines add various telnet commands to the data stream.
215*32146Sminshall  */
216*32146Sminshall 
217*32146Sminshall void
218*32146Sminshall xmitAO()
219*32146Sminshall {
220*32146Sminshall     NET2ADD(IAC, AO);
221*32146Sminshall     if (autoflush) {
222*32146Sminshall 	doflush();
223*32146Sminshall     }
224*32146Sminshall }
225*32146Sminshall 
226*32146Sminshall 
227*32146Sminshall void
228*32146Sminshall xmitEL()
229*32146Sminshall {
230*32146Sminshall     NET2ADD(IAC, EL);
231*32146Sminshall }
232*32146Sminshall 
233*32146Sminshall void
234*32146Sminshall xmitEC()
235*32146Sminshall {
236*32146Sminshall     NET2ADD(IAC, EC);
237*32146Sminshall }
238*32146Sminshall 
239*32146Sminshall 
240*32146Sminshall #if	defined(NOT43)
241*32146Sminshall int
242*32146Sminshall #else	/* defined(NOT43) */
243*32146Sminshall void
244*32146Sminshall #endif	/* defined(NOT43) */
245*32146Sminshall dosynch()
246*32146Sminshall {
247*32146Sminshall     netclear();			/* clear the path to the network */
248*32146Sminshall     NET2ADD(IAC, DM);
249*32146Sminshall     neturg = NETLOC()-1;	/* Some systems are off by one XXX */
250*32146Sminshall 
251*32146Sminshall #if	defined(NOT43)
252*32146Sminshall     return 0;
253*32146Sminshall #endif	/* defined(NOT43) */
254*32146Sminshall }
255*32146Sminshall 
256*32146Sminshall void
257*32146Sminshall doflush()
258*32146Sminshall {
259*32146Sminshall     NET2ADD(IAC, DO);
260*32146Sminshall     NETADD(TELOPT_TM);
261*32146Sminshall     flushline = 1;
262*32146Sminshall     flushout = 1;
263*32146Sminshall     ttyflush();
264*32146Sminshall     /* do printoption AFTER flush, otherwise the output gets tossed... */
265*32146Sminshall     printoption("<SENT", doopt, TELOPT_TM, 0);
266*32146Sminshall }
267*32146Sminshall 
268*32146Sminshall void
269*32146Sminshall intp()
270*32146Sminshall {
271*32146Sminshall     NET2ADD(IAC, IP);
272*32146Sminshall     if (autoflush) {
273*32146Sminshall 	doflush();
274*32146Sminshall     }
275*32146Sminshall     if (autosynch) {
276*32146Sminshall 	dosynch();
277*32146Sminshall     }
278*32146Sminshall }
279*32146Sminshall 
280*32146Sminshall void
281*32146Sminshall sendbrk()
282*32146Sminshall {
283*32146Sminshall     NET2ADD(IAC, BREAK);
284*32146Sminshall     if (autoflush) {
285*32146Sminshall 	doflush();
286*32146Sminshall     }
287*32146Sminshall     if (autosynch) {
288*32146Sminshall 	dosynch();
289*32146Sminshall     }
290*32146Sminshall }
291