xref: /csrg-svn/usr.bin/telnet/network.c (revision 32531)
132146Sminshall #include <sys/types.h>
232146Sminshall #include <sys/socket.h>
332146Sminshall #include <sys/time.h>
432146Sminshall 
532146Sminshall #include <errno.h>
632146Sminshall 
732146Sminshall #include <arpa/telnet.h>
832146Sminshall 
932381Sminshall #include "ring.h"
1032381Sminshall 
1132146Sminshall #include "defines.h"
1232146Sminshall #include "externs.h"
1332146Sminshall 
14*32531Sminshall Ring	netoring, netiring;
15*32531Sminshall char	netobuf[2*BUFSIZ], netibuf[BUFSIZ];
1632146Sminshall 
1732146Sminshall /*
1832146Sminshall  * Initialize internal network data structures.
1932146Sminshall  */
2032146Sminshall 
2132146Sminshall init_network()
2232146Sminshall {
2332381Sminshall     ring_init(&netoring, netobuf, sizeof netobuf);
24*32531Sminshall     ring_init(&netiring, netibuf, sizeof netibuf);
2532146Sminshall     NetTrace = stdout;
2632146Sminshall }
2732146Sminshall 
2832146Sminshall 
2932146Sminshall /*
3032146Sminshall  * Check to see if any out-of-band data exists on a socket (for
3132146Sminshall  * Telnet "synch" processing).
3232146Sminshall  */
3332146Sminshall 
3432146Sminshall int
3532146Sminshall stilloob(s)
3632146Sminshall int	s;		/* socket number */
3732146Sminshall {
3832146Sminshall     static struct timeval timeout = { 0 };
3932146Sminshall     fd_set	excepts;
4032146Sminshall     int value;
4132146Sminshall 
4232146Sminshall     do {
4332146Sminshall 	FD_ZERO(&excepts);
4432146Sminshall 	FD_SET(s, &excepts);
4532146Sminshall 	value = select(s+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout);
4632146Sminshall     } while ((value == -1) && (errno == EINTR));
4732146Sminshall 
4832146Sminshall     if (value < 0) {
4932146Sminshall 	perror("select");
5032146Sminshall 	quit();
5132146Sminshall     }
5232146Sminshall     if (FD_ISSET(s, &excepts)) {
5332146Sminshall 	return 1;
5432146Sminshall     } else {
5532146Sminshall 	return 0;
5632146Sminshall     }
5732146Sminshall }
5832146Sminshall 
5932146Sminshall 
6032146Sminshall /*
6132257Sminshall  *  setneturg()
6232257Sminshall  *
6332257Sminshall  *	Sets "neturg" to the current location.
6432257Sminshall  */
6532257Sminshall 
6632257Sminshall void
6732257Sminshall setneturg()
6832257Sminshall {
6932381Sminshall     ring_mark(&netoring);
7032257Sminshall }
7132257Sminshall 
7232257Sminshall 
7332257Sminshall /*
7432146Sminshall  *  netflush
7532146Sminshall  *		Send as much data as possible to the network,
7632146Sminshall  *	handling requests for urgent data.
7732146Sminshall  *
7832146Sminshall  *		The return value indicates whether we did any
7932146Sminshall  *	useful work.
8032146Sminshall  */
8132146Sminshall 
8232146Sminshall 
8332146Sminshall int
8432146Sminshall netflush()
8532146Sminshall {
8632146Sminshall     int n;
8732146Sminshall 
8832528Sminshall     if ((n = ring_full_consecutive(&netoring)) > 0) {
8932381Sminshall 	if (!ring_at_mark(&netoring)) {
9032528Sminshall 	    n = send(net, netoring.consume, n, 0);	/* normal write */
9132146Sminshall 	} else {
9232146Sminshall 	    /*
9332146Sminshall 	     * In 4.2 (and 4.3) systems, there is some question about
9432146Sminshall 	     * what byte in a sendOOB operation is the "OOB" data.
9532146Sminshall 	     * To make ourselves compatible, we only send ONE byte
9632146Sminshall 	     * out of band, the one WE THINK should be OOB (though
9732146Sminshall 	     * we really have more the TCP philosophy of urgent data
9832146Sminshall 	     * rather than the Unix philosophy of OOB data).
9932146Sminshall 	     */
10032528Sminshall 	    n = send(net, netoring.consume, 1, MSG_OOB);/* URGENT data */
10132146Sminshall 	}
10232146Sminshall     }
10332146Sminshall     if (n < 0) {
10432146Sminshall 	if (errno != ENOBUFS && errno != EWOULDBLOCK) {
10532146Sminshall 	    setcommandmode();
10632146Sminshall 	    perror(hostname);
10732146Sminshall 	    NetClose(net);
10832381Sminshall 	    ring_clear_mark(&netoring);
10932146Sminshall 	    longjmp(peerdied, -1);
11032146Sminshall 	    /*NOTREACHED*/
11132146Sminshall 	}
11232146Sminshall 	n = 0;
11332146Sminshall     }
11432146Sminshall     if (netdata && n) {
11532528Sminshall 	Dump('>', netoring.consume, n);
11632146Sminshall     }
11732528Sminshall     ring_consumed(&netoring, n);
11832146Sminshall     return n > 0;
11932146Sminshall }
12032146Sminshall 
12132146Sminshall /*
12232146Sminshall  * nextitem()
12332146Sminshall  *
12432146Sminshall  *	Return the address of the next "item" in the TELNET data
12532146Sminshall  * stream.  This will be the address of the next character if
12632146Sminshall  * the current address is a user data character, or it will
12732146Sminshall  * be the address of the character following the TELNET command
12832146Sminshall  * if the current address is a TELNET IAC ("I Am a Command")
12932146Sminshall  * character.
13032146Sminshall  */
13132146Sminshall 
13232146Sminshall static char *
13332146Sminshall nextitem(current)
13432146Sminshall char	*current;
13532146Sminshall {
13632146Sminshall     if ((*current&0xff) != IAC) {
13732146Sminshall 	return current+1;
13832146Sminshall     }
13932146Sminshall     switch (*(current+1)&0xff) {
14032146Sminshall     case DO:
14132146Sminshall     case DONT:
14232146Sminshall     case WILL:
14332146Sminshall     case WONT:
14432146Sminshall 	return current+3;
14532146Sminshall     case SB:		/* loop forever looking for the SE */
14632146Sminshall 	{
14732146Sminshall 	    register char *look = current+2;
14832146Sminshall 
14932146Sminshall 	    for (;;) {
15032146Sminshall 		if ((*look++&0xff) == IAC) {
15132146Sminshall 		    if ((*look++&0xff) == SE) {
15232146Sminshall 			return look;
15332146Sminshall 		    }
15432146Sminshall 		}
15532146Sminshall 	    }
15632146Sminshall 	}
15732146Sminshall     default:
15832146Sminshall 	return current+2;
15932146Sminshall     }
16032146Sminshall }
16132381Sminshall 
16232146Sminshall /*
16332146Sminshall  * netclear()
16432146Sminshall  *
16532146Sminshall  *	We are about to do a TELNET SYNCH operation.  Clear
16632146Sminshall  * the path to the network.
16732146Sminshall  *
16832146Sminshall  *	Things are a bit tricky since we may have sent the first
16932146Sminshall  * byte or so of a previous TELNET command into the network.
17032146Sminshall  * So, we have to scan the network buffer from the beginning
17132146Sminshall  * until we are up to where we want to be.
17232146Sminshall  *
17332146Sminshall  *	A side effect of what we do, just to keep things
17432146Sminshall  * simple, is to clear the urgent data pointer.  The principal
17532146Sminshall  * caller should be setting the urgent data pointer AFTER calling
17632146Sminshall  * us in any case.
17732146Sminshall  */
17832146Sminshall 
17932257Sminshall void
18032146Sminshall netclear()
18132146Sminshall {
18232381Sminshall #if	0	/* XXX */
18332146Sminshall     register char *thisitem, *next;
18432146Sminshall     char *good;
18532146Sminshall #define	wewant(p)	((nfrontp > p) && ((*p&0xff) == IAC) && \
18632146Sminshall 				((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))
18732146Sminshall 
18832146Sminshall     thisitem = netobuf;
18932146Sminshall 
19032381Sminshall     while ((next = nextitem(thisitem)) <= netobuf.send) {
19132146Sminshall 	thisitem = next;
19232146Sminshall     }
19332146Sminshall 
19432146Sminshall     /* Now, thisitem is first before/at boundary. */
19532146Sminshall 
19632146Sminshall     good = netobuf;	/* where the good bytes go */
19732146Sminshall 
19832381Sminshall     while (netoring.add > thisitem) {
19932146Sminshall 	if (wewant(thisitem)) {
20032146Sminshall 	    int length;
20132146Sminshall 
20232146Sminshall 	    next = thisitem;
20332146Sminshall 	    do {
20432146Sminshall 		next = nextitem(next);
20532146Sminshall 	    } while (wewant(next) && (nfrontp > next));
20632146Sminshall 	    length = next-thisitem;
20732146Sminshall 	    memcpy(good, thisitem, length);
20832146Sminshall 	    good += length;
20932146Sminshall 	    thisitem = next;
21032146Sminshall 	} else {
21132146Sminshall 	    thisitem = nextitem(thisitem);
21232146Sminshall 	}
21332146Sminshall     }
21432146Sminshall 
21532381Sminshall #endif	/* 0 */
21632381Sminshall     ring_init(&netoring, netobuf, sizeof netobuf);
21732146Sminshall }
21832381Sminshall 
21932381Sminshall #include <varargs.h>
22032381Sminshall 
22132381Sminshall void
22232381Sminshall netoprint(va_alist)
22332381Sminshall va_dcl
22432381Sminshall {
22532381Sminshall     va_list ap;
22632381Sminshall     char buffer[100];		/* where things go */
22732382Sminshall     char *ptr;
22832381Sminshall     char *format;
22932382Sminshall     char *string;
23032381Sminshall     int i;
23132381Sminshall 
23232381Sminshall     va_start(ap);
23332381Sminshall 
23432381Sminshall     format = va_arg(ap, char *);
23532382Sminshall     ptr = buffer;
23632381Sminshall 
23732381Sminshall     while ((i = *format++) != 0) {
23832381Sminshall 	if (i == '%') {
23932381Sminshall 	    i = *format++;
24032381Sminshall 	    switch (i) {
24132381Sminshall 	    case 'c':
24232382Sminshall 		*ptr++ = va_arg(ap, int);
24332381Sminshall 		break;
24432382Sminshall 	    case 's':
24532382Sminshall 		string = va_arg(ap, char *);
24632528Sminshall 		ring_supply_data(&netoring, buffer, ptr-buffer);
24732528Sminshall 		ring_supply_data(&netoring, string, strlen(string));
24832382Sminshall 		ptr = buffer;
24932382Sminshall 		break;
25032381Sminshall 	    case 0:
25132382Sminshall 		ExitString("netoprint: trailing %%.\n", 1);
25232381Sminshall 		/*NOTREACHED*/
25332381Sminshall 	    default:
25432381Sminshall 		ExitString("netoprint: unknown format character.\n", 1);
25532381Sminshall 		/*NOTREACHED*/
25632381Sminshall 	    }
25732381Sminshall 	} else {
25832381Sminshall 	    *ptr++ = i;
25932381Sminshall 	}
26032381Sminshall     }
26132528Sminshall     ring_supply_data(&netoring, buffer, ptr-buffer);
26232381Sminshall }
263