欢迎来到虫虫下载站 | 资源下载 资源专辑 关于我们
虫虫下载站

state.c

早期freebsd实现
C
第 1 页 / 共 3 页
字号:
/* * Copyright (c) 1989, 1993 *	The Regents of the University of California.  All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software *    must display the following acknowledgement: *	This product includes software developed by the University of *	California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors *    may be used to endorse or promote products derived from this software *    without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#ifndef lintstatic char sccsid[] = "@(#)state.c	8.2 (Berkeley) 12/15/93";#endif /* not lint */#include "telnetd.h"#if	defined(AUTHENTICATION)#include <libtelnet/auth.h>#endifunsigned char	doopt[] = { IAC, DO, '%', 'c', 0 };unsigned char	dont[] = { IAC, DONT, '%', 'c', 0 };unsigned char	will[] = { IAC, WILL, '%', 'c', 0 };unsigned char	wont[] = { IAC, WONT, '%', 'c', 0 };int	not42 = 1;/* * Buffer for sub-options, and macros * for suboptions buffer manipulations */unsigned char subbuffer[512], *subpointer= subbuffer, *subend= subbuffer;#define	SB_CLEAR()	subpointer = subbuffer#define	SB_TERM()	{ subend = subpointer; SB_CLEAR(); }#define	SB_ACCUM(c)	if (subpointer < (subbuffer+sizeof subbuffer)) { \				*subpointer++ = (c); \			}#define	SB_GET()	((*subpointer++)&0xff)#define	SB_EOF()	(subpointer >= subend)#define	SB_LEN()	(subend - subpointer)#ifdef	ENV_HACKunsigned char *subsave;#define SB_SAVE()	subsave = subpointer;#define	SB_RESTORE()	subpointer = subsave;#endif/* * State for recv fsm */#define	TS_DATA		0	/* base state */#define	TS_IAC		1	/* look for double IAC's */#define	TS_CR		2	/* CR-LF ->'s CR */#define	TS_SB		3	/* throw away begin's... */#define	TS_SE		4	/* ...end's (suboption negotiation) */#define	TS_WILL		5	/* will option negotiation */#define	TS_WONT		6	/* wont " */#define	TS_DO		7	/* do " */#define	TS_DONT		8	/* dont " */	voidtelrcv(){	register int c;	static int state = TS_DATA;#if	defined(CRAY2) && defined(UNICOS5)	char *opfrontp = pfrontp;#endif	while (ncc > 0) {		if ((&ptyobuf[BUFSIZ] - pfrontp) < 2)			break;		c = *netip++ & 0377, ncc--;#ifdef	ENCRYPTION		if (decrypt_input)			c = (*decrypt_input)(c);#endif	/* ENCRYPTION */		switch (state) {		case TS_CR:			state = TS_DATA;			/* Strip off \n or \0 after a \r */			if ((c == 0) || (c == '\n')) {				break;			}			/* FALL THROUGH */		case TS_DATA:			if (c == IAC) {				state = TS_IAC;				break;			}			/*			 * We now map \r\n ==> \r for pragmatic reasons.			 * Many client implementations send \r\n when			 * the user hits the CarriageReturn key.			 *			 * We USED to map \r\n ==> \n, since \r\n says			 * that we want to be in column 1 of the next			 * printable line, and \n is the standard			 * unix way of saying that (\r is only good			 * if CRMOD is set, which it normally is).			 */			if ((c == '\r') && his_state_is_wont(TELOPT_BINARY)) {				int nc = *netip;#ifdef	ENCRYPTION				if (decrypt_input)					nc = (*decrypt_input)(nc & 0xff);#endif	/* ENCRYPTION */#ifdef	LINEMODE				/*				 * If we are operating in linemode,				 * convert to local end-of-line.				 */				if (linemode && (ncc > 0) && (('\n' == nc) ||					 ((0 == nc) && tty_iscrnl())) ) {					netip++; ncc--;					c = '\n';				} else#endif				{#ifdef	ENCRYPTION					if (decrypt_input)						(void)(*decrypt_input)(-1);#endif	/* ENCRYPTION */					state = TS_CR;				}			}			*pfrontp++ = c;			break;		case TS_IAC:gotiac:			switch (c) {			/*			 * Send the process on the pty side an			 * interrupt.  Do this with a NULL or			 * interrupt char; depending on the tty mode.			 */			case IP:				DIAG(TD_OPTIONS,					printoption("td: recv IAC", c));				interrupt();				break;			case BREAK:				DIAG(TD_OPTIONS,					printoption("td: recv IAC", c));				sendbrk();				break;			/*			 * Are You There?			 */			case AYT:				DIAG(TD_OPTIONS,					printoption("td: recv IAC", c));				recv_ayt();				break;			/*			 * Abort Output			 */			case AO:			    {				DIAG(TD_OPTIONS,					printoption("td: recv IAC", c));				ptyflush();	/* half-hearted */				init_termbuf();				if (slctab[SLC_AO].sptr &&				    *slctab[SLC_AO].sptr != (cc_t)(_POSIX_VDISABLE)) {				    *pfrontp++ =					(unsigned char)*slctab[SLC_AO].sptr;				}				netclear();	/* clear buffer back */				*nfrontp++ = IAC;				*nfrontp++ = DM;				neturg = nfrontp-1; /* off by one XXX */				DIAG(TD_OPTIONS,					printoption("td: send IAC", DM));				break;			    }			/*			 * Erase Character and			 * Erase Line			 */			case EC:			case EL:			    {				cc_t ch;				DIAG(TD_OPTIONS,					printoption("td: recv IAC", c));				ptyflush();	/* half-hearted */				init_termbuf();				if (c == EC)					ch = *slctab[SLC_EC].sptr;				else					ch = *slctab[SLC_EL].sptr;				if (ch != (cc_t)(_POSIX_VDISABLE))					*pfrontp++ = (unsigned char)ch;				break;			    }			/*			 * Check for urgent data...			 */			case DM:				DIAG(TD_OPTIONS,					printoption("td: recv IAC", c));				SYNCHing = stilloob(net);				settimer(gotDM);				break;			/*			 * Begin option subnegotiation...			 */			case SB:				state = TS_SB;				SB_CLEAR();				continue;			case WILL:				state = TS_WILL;				continue;			case WONT:				state = TS_WONT;				continue;			case DO:				state = TS_DO;				continue;			case DONT:				state = TS_DONT;				continue;			case EOR:				if (his_state_is_will(TELOPT_EOR))					doeof();				break;			/*			 * Handle RFC 10xx Telnet linemode option additions			 * to command stream (EOF, SUSP, ABORT).			 */			case xEOF:				doeof();				break;			case SUSP:				sendsusp();				break;			case ABORT:				sendbrk();				break;			case IAC:				*pfrontp++ = c;				break;			}			state = TS_DATA;			break;		case TS_SB:			if (c == IAC) {				state = TS_SE;			} else {				SB_ACCUM(c);			}			break;		case TS_SE:			if (c != SE) {				if (c != IAC) {					/*					 * bad form of suboption negotiation.					 * handle it in such a way as to avoid					 * damage to local state.  Parse					 * suboption buffer found so far,					 * then treat remaining stream as					 * another command sequence.					 */					/* for DIAGNOSTICS */					SB_ACCUM(IAC);					SB_ACCUM(c);					subpointer -= 2;					SB_TERM();					suboption();					state = TS_IAC;					goto gotiac;				}				SB_ACCUM(c);				state = TS_SB;			} else {				/* for DIAGNOSTICS */				SB_ACCUM(IAC);				SB_ACCUM(SE);				subpointer -= 2;				SB_TERM();				suboption();	/* handle sub-option */				state = TS_DATA;			}			break;		case TS_WILL:			willoption(c);			state = TS_DATA;			continue;		case TS_WONT:			wontoption(c);			state = TS_DATA;			continue;		case TS_DO:			dooption(c);			state = TS_DATA;			continue;		case TS_DONT:			dontoption(c);			state = TS_DATA;			continue;		default:			syslog(LOG_ERR, "telnetd: panic state=%d\n", state);			printf("telnetd: panic state=%d\n", state);			exit(1);		}	}#if	defined(CRAY2) && defined(UNICOS5)	if (!linemode) {		char	xptyobuf[BUFSIZ+NETSLOP];		char	xbuf2[BUFSIZ];		register char *cp;		int n = pfrontp - opfrontp, oc;		bcopy(opfrontp, xptyobuf, n);		pfrontp = opfrontp;		pfrontp += term_input(xptyobuf, pfrontp, n, BUFSIZ+NETSLOP,					xbuf2, &oc, BUFSIZ);		for (cp = xbuf2; oc > 0; --oc)			if ((*nfrontp++ = *cp++) == IAC)				*nfrontp++ = IAC;	}#endif	/* defined(CRAY2) && defined(UNICOS5) */}  /* end of telrcv *//* * The will/wont/do/dont state machines are based on Dave Borman's * Telnet option processing state machine. * * These correspond to the following states: *	my_state = the last negotiated state *	want_state = what I want the state to go to *	want_resp = how many requests I have sent * All state defaults are negative, and resp defaults to 0. * * When initiating a request to change state to new_state: *  * if ((want_resp == 0 && new_state == my_state) || want_state == new_state) { *	do nothing; * } else { *	want_state = new_state; *	send new_state; *	want_resp++; * } * * When receiving new_state: * * if (want_resp) { *	want_resp--; *	if (want_resp && (new_state == my_state)) *		want_resp--; * } * if ((want_resp == 0) && (new_state != want_state)) { *	if (ok_to_switch_to new_state) *		want_state = new_state; *	else *		want_resp++; *	send want_state; * } * my_state = new_state; * * Note that new_state is implied in these functions by the function itself. * will and do imply positive new_state, wont and dont imply negative. * * Finally, there is one catch.  If we send a negative response to a * positive request, my_state will be the positive while want_state will * remain negative.  my_state will revert to negative when the negative * acknowlegment arrives from the peer.  Thus, my_state generally tells * us not only the last negotiated state, but also tells us what the peer * wants to be doing as well.  It is important to understand this difference * as we may wish to be processing data streams based on our desired state * (want_state) or based on what the peer thinks the state is (my_state). * * This all works fine because if the peer sends a positive request, the data * that we receive prior to negative acknowlegment will probably be affected * by the positive state, and we can process it as such (if we can; if we * can't then it really doesn't matter).  If it is that important, then the * peer probably should be buffering until this option state negotiation * is complete. * */	voidsend_do(option, init)	int option, init;{	if (init) {		if ((do_dont_resp[option] == 0 && his_state_is_will(option)) ||		    his_want_state_is_will(option))			return;		/*		 * Special case for TELOPT_TM:  We send a DO, but pretend		 * that we sent a DONT, so that we can send more DOs if		 * we want to.		 */		if (option == TELOPT_TM)			set_his_want_state_wont(option);		else			set_his_want_state_will(option);		do_dont_resp[option]++;	}	(void) sprintf(nfrontp, (char *)doopt, option);	nfrontp += sizeof (dont) - 2;	DIAG(TD_OPTIONS, printoption("td: send do", option));}#ifdef	AUTHENTICATIONextern void auth_request();#endif#ifdef	LINEMODEextern void doclientstat();#endif#ifdef	ENCRYPTIONextern void encrypt_send_support();#endif	/* ENCRYPTION */	voidwilloption(option)	int option;{	int changeok = 0;	void (*func)() = 0;	/*	 * process input from peer.	 */	DIAG(TD_OPTIONS, printoption("td: recv will", option));	if (do_dont_resp[option]) {		do_dont_resp[option]--;		if (do_dont_resp[option] && his_state_is_will(option))			do_dont_resp[option]--;	}	if (do_dont_resp[option] == 0) {	    if (his_want_state_is_wont(option)) {		switch (option) {		case TELOPT_BINARY:			init_termbuf();			tty_binaryin(1);			set_termbuf();			changeok++;			break;		case TELOPT_ECHO:			/*			 * See comments below for more info.			 */			not42 = 0;	/* looks like a 4.2 system */			break;		case TELOPT_TM:#if	defined(LINEMODE) && defined(KLUDGELINEMODE)			/*			 * This telnetd implementation does not really			 * support timing marks, it just uses them to			 * support the kludge linemode stuff.  If we			 * receive a will or wont TM in response to our			 * do TM request that may have been sent to			 * determine kludge linemode support, process			 * it, otherwise TM should get a negative			 * response back.			 */			/*			 * Handle the linemode kludge stuff.			 * If we are not currently supporting any			 * linemode at all, then we assume that this			 * is the client telling us to use kludge			 * linemode in response to our query.  Set the			 * linemode type that is to be supported, note			 * that the client wishes to use linemode, and			 * eat the will TM as though it never arrived.			 */			if (lmodetype < KLUDGE_LINEMODE) {				lmodetype = KLUDGE_LINEMODE;				clientstat(TELOPT_LINEMODE, WILL, 0);				send_wont(TELOPT_SGA, 1);			} else if (lmodetype == NO_AUTOKLUDGE) {				lmodetype = KLUDGE_OK;			}#endif	/* defined(LINEMODE) && defined(KLUDGELINEMODE) */			/*			 * We never respond to a WILL TM, and			 * we leave the state WONT.			 */			return;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -