Newsgroups: comp.sources.unix From: bcr@physics.purdue.edu (Bill C. Riemers) Subject: v28i167: term-2.2.5 - SLIP-like functionality between two *IX hosts (REPOST), Part04/09 References: <1.784237938.15304@gw.home.vix.com> Sender: unix-sources-moderator@gw.home.vix.com Approved: vixie@gw.home.vix.com Submitted-By: bcr@physics.purdue.edu (Bill C. Riemers) Posting-Number: Volume 28, Issue 167 Archive-Name: term-2.2.5/part04 #!/bin/sh # This is `part04' (part 4 of a multipart archive). # Do not concatenate these parts, unpack them in order with `/bin/sh'. # File `term-2.2.5/configure' is being continued... # touch -am 1231235999 $$.touch >/dev/null 2>&1 if test ! -f 1231235999 && test -f $$.touch; then shar_touch=touch else shar_touch=: echo echo 'WARNING: not restoring timestamps. Consider getting and' echo "installing GNU \`touch', distributed in GNU File Utilities..." echo fi rm -f 1231235999 $$.touch # if test ! -r _sharseq.tmp; then echo 'Please unpack part 1 first!' exit 1 fi shar_sequence=`cat _sharseq.tmp` if test "$shar_sequence" != 4; then echo "Please unpack part $shar_sequence next!" exit 1 fi if test ! -f _sharnew.tmp; then echo 'x - still skipping term-2.2.5/configure' else echo 'x - continuing file term-2.2.5/configure' sed 's/^X//' << 'SHAR_EOF' >> 'term-2.2.5/configure' && Xif [ x$bindir = xunknown ] ; then bindir=$prefix/bin ; fi Xif [ x$mandir = xunknown ] ; then mandir=$prefix/man/man1 ; fi Xif [ x$incdir = xunknown ] ; then incdir=$prefix/include ; fi X XCC='gcc -Wall' XCPP='$(CC) -E' XDEBUGFLAGS='-O' Xif [ -f /usr/bin/ranlib -o -f /bin/ranlib -o -f /usr/ucb/ranlib ]; then X AR='ar rc' X RANLIB='ranlib' Xelse X AR='ar rcs' X RANLIB='echo' Xfi X X# If no OS type provided yet, try to guess X X# Probably the best thing to check is uname, so we try that first. Xif [ "x$OS" = x -a \( -f /bin/uname -o -f /usr/bin/uname \) ]; then X OS=`uname` Xfi X# Next we will try arch. Xif [ "x$OS" = x -a \( -f /bin/arch -o -f /usr/bin/arch \) ]; then X OS=`arch` Xfi X# What about bash, if we're running it? Xif [ "x$OS" = x -a x$HOSTTYPE != x ]; then X OS=$HOSTTYPE Xfi X# Or running bash, if we're not running it? Xif [ "x$OS" = x -a \( -f /bin/bash -o -f /usr/bin/bash \) ]; then X OS=`bash -c 'echo $HOSTTYPE'` Xfi X# Finally we can try "tcsh". Xif [ "x$OS" = x -a \( -f /bin/tcsh -o -f /usr/bin/tcsh \) ]; then X OS=`tcsh -c 'echo $HOSTTYPE'` Xfi X# OK, try filesystem-specific things. Xif [ "x$OS" = x -a -d /NextApps ]; then X OS=next Xelif [ "x$UNIX_SV" != x ]; then X OS=unixsv Xfi X# Give up Xif [ "x$OS" = x ]; then X echo "Can't guess OS; use 'configure os-name'" >&2 X exit 1 Xfi X X# Normalize the OS type X# Xcase "$OS" in XLinux | i386-linux) OS=linux ;; XTitanOS) OS=titan ;; XNetBSD) OS=netbsd ;; XSunOS) case `uname -r` in X 4.*) OS=sun ;; X 5.*) OS=sol2 ;; X *) echo "Unknown Sun OS release!" >&2; exit 1 ;; X esac ;; Xsol21) OS=sol2 ;; # compatibility with older term releases Xcd4680fs | epix) OS=epix ;; XULTRIX) OS=ultrix ;; XIRIX) OS=irix ;; XNeXT) OS=next ;; XCX/UX) OS=hcx ;; Xaix370 | aixESA | rtpc | AIX) OS=aix ;; Xbsd386) OS=bsdi ;; Xdgux) OS=dgux ;; Xsco386) OS=sco ;; Xvistra800) OS=svr4 ;; Xptx) OS=dynixptx ;; Xiris3d | iris4d) OS=sgi ;; XOSF1) OS=osf1 ;; Xm68k) if [ "x$MACHTEN" != x ]; then OS=machten; fi ;; XConvexOS) OS=convex ;; XHP-UX) OS=hpux ;; XISC) OS=isc ;; XUNIX_SV) OS=unixsv ;; X Xesac X X# set OS specific options X# Xcase $OS in X Xsgi | convex | mips) ;; X Xosf1) CC="gcc -Wall -Wno-implicit" ;; X Xlinux) if [ x$shlib = xunknown ]; then shlib=$is_root; fi X if [ x$shlib = xyes ]; then X if [ -x /usr/bin/jumpas ]; then X DLLAS=jumpas X DLLBIN= X elif [ -x /usr/dll/jump/as ]; then X DLLAS=/usr/dll/jump/as X DLLBIN=/usr/dll/bin/ X else X echo "You need dll tools 2.11 or greater for" X echo "dynamic libraries. Using static instead." X shlib=no X fi X fi X if [ $shlib = yes ]; then X ARCH_VARS="-e 's,@dllas@,$DLLAS,' -e 's,@dllbin@,$DLLBIN,'" X fi ;; X Xmachten) CC="gcc" ;; X Xbsdi) CPP="cc -E" CC=cc X OSFLAGS="-funsigned-char -DBSDI" ;; X Xepix) CPP="cc -E" CC=cc X OSFLAGS="-systype bsd43 -DEPIX" ;; X Xtitan) CC="cc -43" ;; X Xaix) OSFLAGS="-D_BSD" LIBS="-lbsd" CC="xlc -D_ALL_SOURCE" ;; X Xnetbsd) if [ x$shlib = xunknown ]; then shlib=yes; fi ;; X Xsun) CC="gcc -Wall -Wno-implicit" X if [ x$shlib = xunknown ]; then shlib=yes; fi ;; X Xunixsv) OSFLAGS="-DSVR4 -DUNIX_SV" LIBS="-lsocket -lnsl" ;; X Xsol2) OSFLAGS="-DSVR4" LIBS="-lsocket -lnsl" ;; X Xultrix) CC="gcc -Wall -Wno-implicit -Wno-comment -Dultrix" X OSLINK=" -s" STRIP="echo" ;; X Xirix) OSFLAGS="-DIRIX" ;; X Xnext) CPP="cc -E" CC=cc OSFLAGS="-funsigned-char" ;; X X# if this doesn't work try c89 instead of cc. X# use only if you don't have gcc; at least hpux 8.x cc is broken. X# Or better, get gcc from hpux.ask.uni-karlsruhe.de:/hpux9/Gnu/ Xhpux-cc) CC="cc -Aa" OSLINK=" -s" OSFLAGS="-D_HPUX_SOURCE" X STRIP="echo" ;; X Xhpux) CC="gcc" OSLINK=" -s" OSFLAGS="-D_HPUX_SOURCE" STRIP="echo" ;; X Xisc) CC="gcc -posix" DEBUGFLAGS="-g" OSFLAGS="-DISC -DNO_UNIX_DOMAIN -DSVR3 -D_SYSV3" X LIBS="-linet -lpt -lcposix " ;; X Xsvr4) OSFLAGS="-funsigned-char -m486 -DSVR4" LIBS="-lsocket -lnsl" ;; X Xdgux) OSFLAGS="-DDGUX -DSVR3" X CC=cc DEBUGFLAGS=-g ;; X Xsco) OSFLAGS="-DSCO -DSVR3 -DNO_UNIX_DOMAIN" X LIBS="-lsocket -lpt" CC=cc DEBUGFLAGS=-g ;; X Xdynixptx) CC="cc -DDYNIXPTX" CPP="cc -E" X LIBS="-lsocket -linet -lnsl -lseq" ;; X X# The HCX/UX 5.1 cc does not understand ANSI C. To convert the term source X# to K&R on the fly, "unproto" must be compiled and the generated "cpp" X# binary placed in some directory, specified below with UNPROTO. This lets the X# hcx cc be passed de-ANSIfied C code. "unproto" can be found in archives X# for comp.sources.misc, volume 27, issue 85. X# Xhcx) if [ "x$UNPROTO" = x ]; then X UNPROTO=/path/to/unproto/dir X fi X if [ ! -f "$UNPROTO"/cpp ]; then X echo "hcx: can't find $UNPROTO/cpp. Please either edit" >&2 X echo " configure or setenv UNPROTO before running it." >&2 X exit 1 X fi X CC="cc -B$UNPROTO/ -tp" X CPP=$UNPROTO/cpp ;; X X*) echo "Couldn't find rules for $OS; try 'configure os-name'" X exit 1 ;; X Xesac X Xif [ $is_root = no ] ; then X who_prefix='!root' Xelse X who_prefix='root' Xfi X Xif [ $shlib = yes ]; then X lib_prefix='shlib' X install_shlib=install.shlib X if [ -f /usr/sbin/ldconfig ]; then X ldconfig=/usr/sbin/ldconfig X elif [ -f /usr/etc/ldconfig ]; then X ldconfig=/usr/etc/ldconfig X elif [ -f /usr/bin/ldconfig ]; then X ldconfig=/usr/bin/ldconfig X elif [ -f /sbin/ldconfig ]; then X ldconfig=/sbin/ldconfig X elif [ -f /etc/ldconfig ]; then X ldconfig=/etc/ldconfig X elif [ -f /bin/ldconfig ]; then X ldconfig=/bin/ldconfig X else X echo "Can't find ldconfig." X echo "ldconfig must be in root's PATH at install time." X ldconfig=ldconfig X fi Xelse X lib_prefix='static' X install_shlib= X ldconfig=this_should_never_be_used X if [ x$is_root = xno ] ; then X CC="$CC -DONE_CLIENT" X if [ x$one_client = xunknown ]; then X one_client=yes; X fi X fi Xfi X Xif [ x$one_client = xyes ]; then X one_client_prefix="one_client"; Xelse X one_client_prefix="!one_client"; Xfi X Xif [ x$jump_lib = xlibc ] ; then X OSFLAGS="$OSFLAGS -D_LIBC" Xfi X Xrm -f config.status Xecho "#!/bin/sh" > config.status Xcat >> config.status << FOO Xrm -f $Makefile Xif [ ! -f $srcdir/Makefile.in ] ; then X co $srcdir/Makefile.in Xfi X Xeval \`sed -n -e 's/ *//g' -e '/^VERSION_MAJOR=/p' -e '/^VERSION_MINOR=/p' \\ X -e '/^PATCH_LEVEL=/p' $srcdir/Makefile.in\` XVERSION_MINOR=\`expr \( \$VERSION_MINOR + 100 \) : '.\(..\)'\` XPATCH_LEVEL=\`expr \( \$PATCH_LEVEL + 100 \) : '.\(..\)'\` XVERSION_NUM=\$VERSION_MAJOR\$VERSION_MINOR\$PATCH_LEVEL X Xsed -e "s,@version_num@,\$VERSION_NUM,g" \\ X -e 's,@srcdir@,$srcdir,g' \\ X -e 's,@abs_srcdir@,$abs_srcdir,g' \\ X -e 's,@jump_dir@,$jump_dir,g' \\ X -e 's,@jump_lib@,$jump_lib,g' \\ X -e 's,@cc@,$CC,g' \\ X -e 's,@cpp@,$CPP,g' \\ X -e 's,@ar@,$AR,g' \\ X -e 's,@OS@,$OS,g' \\ X -e 's,@ranlib@,$RANLIB,g' \\ X -e 's,@strip@,$STRIP,g' \\ X -e 's,@setid@,$setid,g' \\ X -e 's,@libs@,$LIBS,g' \\ X -e 's,@osflags@,$OSFLAGS,g' \\ X -e 's,@incdir@,$incdir,g' \\ X -e 's,@libdir@,$libdir,g' \\ X -e 's,@debugflags@,$DEBUGFLAGS,g' \\ X -e 's,@oslink@,$OSLINK,g' \\ X -e 's,@bindir@,$bindir,g' \\ X -e 's,@mandir@,$mandir,g' \\ X -e 's,@sharedir@,$sharedir,g' \\ X -e 's,@ldconfig@,$ldconfig,g' \\ X -e 's,@install_shlib@,$install_shlib,g' \\ X -e 's,^# *if *$one_client_prefix *,,g' \\ X -e 's,^# *if *$who_prefix *,,g' \\ X -e 's,^# *if *$lib_prefix=$OS *,,g' \\ X -e 's,^# *if *$lib_prefix=any *,,g' \\ X -e 's,^# *if *$who_prefix *,,g' \\ X $ARCH_VARS \\ X -e 's,^ *$,,g' \\ X -e '/^# *if /d' \\ X < $srcdir/Makefile.in > $Makefile XFOO Xchmod +x config.status X./config.status X Xecho "term configured to build on $OS and install in $prefix" X Xif [ $shlib = no ]; then X echo "use of dynamic term libraries suppressed" Xfi X Xif [ $shlib = yes ]; then X cat << FOO X X Note that if you want to test the binaries before doing a full X install, you may need to run "make install-shlib" first as root X so that they are able to find the correct dynamic libraries. X XFOO X X if [ $OS = linux ]; then X cat << FOO X X You can test the binaries by linking them with the static library X instead: make static.bin will create them. make clean.bin removes X them for re-linking. X XFOO X fi Xfi SHAR_EOF echo 'File term-2.2.5/configure is complete' && $shar_touch -am 1028144694 'term-2.2.5/configure' && chmod 0755 'term-2.2.5/configure' || echo 'restore of term-2.2.5/configure failed' shar_count="`wc -c < 'term-2.2.5/configure'`" test 13521 -eq "$shar_count" || echo "term-2.2.5/configure: original size 13521, current size $shar_count" rm -f _sharnew.tmp fi # ============= term-2.2.5/debug.h ============== if test -f 'term-2.2.5/debug.h' && test X"$1" != X"-c"; then echo 'x - skipping term-2.2.5/debug.h (file already exists)' rm -f _sharnew.tmp else > _sharnew.tmp echo 'x - extracting term-2.2.5/debug.h (text)' sed 's/^X//' << 'SHAR_EOF' > 'term-2.2.5/debug.h' && X#define NOTIFY \ X (write_noise < 2) ? 0 : fprintf X X#define WARNING \ X (!(write_noise)) ? 0 : fprintf X X#define DEBUG_STATE \ X (!(term_debug & 1)) ? 0 : fprintf X X#define DEBUG_MAIN \ X (!(term_debug & 2)) ? 0 : fprintf X X#define DEBUG_SER \ X (!(term_debug &8)) ? 0 :fprintf X X X#define DEBUG_CHECK \ X (!(term_debug & 16)) ? 0 : fprintf X X#define DEBUG_PED \ X (!(term_debug & 32)) ? 0 : fprintf X X#define DEBUG_FP (!(term_debug & 64)) ? 0 : fprintf X X#define DEBUG_LINK \ X (!(term_debug & 128)) ? 0 : fprintf X X#define DEBUG_LL \ X (!(term_debug & 256)) ? 0 : fprintf X X#define DEBUG_C \ X (!(term_debug & 512)) ? 0 : fprintf X X#define DEBUG_SEV \ X (!(term_debug & 1024)) ? 0 : fprintf X X#define DEBUG_UDP \ X (!(term_debug & 2048)) ? 0 : fprintf X SHAR_EOF $shar_touch -am 1028144694 'term-2.2.5/debug.h' && chmod 0644 'term-2.2.5/debug.h' || echo 'restore of term-2.2.5/debug.h failed' shar_count="`wc -c < 'term-2.2.5/debug.h'`" test 780 -eq "$shar_count" || echo "term-2.2.5/debug.h: original size 780, current size $shar_count" rm -f _sharnew.tmp fi # ============= term-2.2.5/do_connect.c ============== if test -f 'term-2.2.5/do_connect.c' && test X"$1" != X"-c"; then echo 'x - skipping term-2.2.5/do_connect.c (file already exists)' rm -f _sharnew.tmp else > _sharnew.tmp echo 'x - extracting term-2.2.5/do_connect.c (text)' sed 's/^X//' << 'SHAR_EOF' > 'term-2.2.5/do_connect.c' && X#define I_ERRNO X#define I_SYS X#define I_IOCTL X#define I_STRING X#define I_SIGNAL X#include "includes.h" X Xtypedef struct { X int client; X int server; X struct Buffer from; X struct Buffer to; X} Con; X Xstatic void sig_ignore(int dummy) { X signal(SIGPIPE, sig_ignore); X} X Xvoid do_connect(int num, int *svs, int (*get_server)(int,struct sockaddr *)) { X int max, num_cons = 0; X int serv, j; X#if defined(STREAMS_PIPE) || defined(X_STREAMS_PIPE) X int dumb; X#endif X Con *cons = 0; X X serv = connect_server(term_server); X if (serv < 0) { X fprintf(stderr, "Couldn't contact term server.\n"); X exit(1); X } X X if ((j=fork()) < 0) X exit(1); X else if (j) X exit(0); X X signal(SIGPIPE, sig_ignore); X X close(0); X close(1); X close(2); X lose_ctty(); X chdir("/"); X X for (max = 0; max < num;++max) X set_nonblock(svs[max]); X X while (1) { X fd_set in, out, except; X Con *c; X int i, ret, loop; X X FD_ZERO(&in); X FD_ZERO(&out); X FD_ZERO(&except); X max = -1; X for (i = 0; i < num;++i) { X FD_SET(svs[i], &in); X if (max < svs[i]) max = svs[i]; X } X X FD_SET(serv, &except); X FD_SET(serv, &in); X if (serv > max) max = serv; X X /* Ok. Build a list of all the sockets */ X /* we want to look at.. */ X for (i = 0, c = cons; i < num_cons;++i, ++c) { X if (c->client >= 0) { /* If this socket can we read and */ X /* written.. */ X if (c->to.size) { /* If there is something to go to it */ X /* then select for writing. */ X FD_SET(c->client, &out); X if (c->client > max) max = c->client; X } else if (c->server >=0) { /* Else select for more data if we can. */ X FD_SET(c->server, &in); X if (c->server > max) max = c->server; X } else { /* ok there was nothing in the buffer, */ X /* and we couldn't get anymore , so */ X /* just close. */ X close(c->client); X c->client = -1; X } X } X if (c->server >= 0) { X if (c->from.size) { X FD_SET(c->server, &out); X if (c->server > max) max = c->server; X } else if (c->client >=0) { X FD_SET(c->client, &in); X if (c->client > max) max = c->client; X } else { X close(c->server); X c->server = -1; X } X } /* if if server >=0 */ X } /* Of for() */ X X select(max+1, &in, &out, &except, 0); X X /* Check for term going away... */ X if (FD_ISSET(serv, &except) || FD_ISSET(serv, &in)) { X /* Ok. Critical . Close every thing.*/ X exit(0); X } X for (loop = 0; loop < num;++loop) X if (FD_ISSET(svs[loop], &in)) { /* new connection */ X struct sockaddr addr; X int saddr = sizeof(addr),i ; X for (i = 0; i < num_cons;i ++) X if (cons[i].server < 0 && cons[i].client < 0) break; X if(i>MAX_CLIENTS) continue; X X if (i >= num_cons) { X if (!cons) X cons = (Con *) malloc(sizeof(Con)); X else X cons = (Con *) realloc((char *) cons, (num_cons + 1) * X sizeof(Con)); X memset(&cons[(i = num_cons++)],0,sizeof(Con)); X } X c = &cons[i]; X#if defined(STREAMS_PIPE) || defined(X_STREAMS_PIPE) X c->client = CheckClientConnection(svs[loop]); X if (c->client != -2) { /* we have a streams pipe */ X if (c->client == -1) { X fprintf(stderr, "can't add client\n"); X continue; X } /* fall through to after "accept" */ X } else /* not a streams pipe */ X#endif X c->client = accept(svs[loop], (struct sockaddr *) &addr, &saddr); X X if ((c->server = get_server(loop,&addr)) <0) { X perror("Couldn't open term"); X close(c->client); X continue; X } X X set_nonblock(c->server); X set_nonblock(c->client); X X X c->to.size = c->to.start = c->to.end = 0; X c->from.size = c->from.start = c->from.end = 0; X X add_to_buffer(&c->to, 0); X get_from_buffer(&c->to); X add_to_buffer(&c->from, 0); X get_from_buffer(&c->from); X X } X X for (i = 0, c = cons; i < num_cons;++i, ++c) { X if (c->client < 0) continue; X if (FD_ISSET(c->client,&in)) X ret = read_into_buff(c->client, &c->from, 0); X else if (FD_ISSET(c->client, &out)) X ret = write_from_buff(c->client, &c->to, 0); X else continue; X /* Handle possible error condition */ X if (ret <=0 && termerrno) { X /* an error has occurred or a stream */ X /* has closed. Close connection. NYF*/ X close(c->client); X c->client = -1; X continue; X } X } X X for (i = 0, c = cons; i < num_cons;++i, ++c) { X if (c->server < 0) continue; X if (FD_ISSET(c->server, &out)) X ret = write_from_buff(c->server, &c->from, 0); X else if (FD_ISSET(c->server, &in)) X ret = read_into_buff(c->server, &c->to, 0); X else continue; X /* Handle possible error condition */ X if (ret<=0 && termerrno) { X close(c->server); X c->server = -1; X } X } X } X} X SHAR_EOF $shar_touch -am 1028144694 'term-2.2.5/do_connect.c' && chmod 0644 'term-2.2.5/do_connect.c' || echo 'restore of term-2.2.5/do_connect.c failed' shar_count="`wc -c < 'term-2.2.5/do_connect.c'`" test 4594 -eq "$shar_count" || echo "term-2.2.5/do_connect.c: original size 4594, current size $shar_count" rm -f _sharnew.tmp fi # ============= term-2.2.5/do_link.c ============== if test -f 'term-2.2.5/do_link.c' && test X"$1" != X"-c"; then echo 'x - skipping term-2.2.5/do_link.c (file already exists)' rm -f _sharnew.tmp else > _sharnew.tmp echo 'x - extracting term-2.2.5/do_link.c (text)' sed 's/^X//' << 'SHAR_EOF' > 'term-2.2.5/do_link.c' && X#define I_SYS X#define I_ERRNO X#define I_IOCTL X#define I_STRING X#define I_STAT X#define I_INET X#define I_CTYPE X#define I_TIME X#define I_UTIME X#include "includes.h" X X#include "debug.h" X X#define FATAL 1 X Xvoid get_term_localaddr(unsigned long); Xchar *sockaddr_to_str(struct sockaddr *,int trans); Xstruct sockaddr *str_to_sockaddr(char *,unsigned long); Xstruct sockaddr *make_sockaddr(unsigned int port, char *host, X unsigned long defaulthost); Xchar *term_strherror(int err); X X#ifdef X_DEBUG Xstatic int x_debug = 0; X#endif X Xextern do_stats(un_char *, int, struct Client *); X X/* X * This modules handles multiplexing the clients onto the serial stream. X * X * do_link_in() is called when there are in packets waiting, and X * do_link_out() is called when there is something in the link_out buffer and X * the serial out buffer is empty. X */ X X/*-----------------------------------------------------------------------*/ X/* Local function prototypes */ Xint get_data(un_char *, int); Xvoid put_data(un_char *, int); Xint get_client_data(struct Client *); Xvoid put_client_data(struct Client *, int); Xvoid init_client(struct Client *cl); X/*-----------------------------------------------------------------------*/ X/* Data */ X Xint curr_in_stream = -1, X curr_out_stream = -1 ; X/* we have this in the open to peek to see if compression is X * wanted... croutons X */ Xstatic struct Client *curr_client = 0; Xint new_packet = 0; X X/* Convert an address to a string */ X Xstatic char *hostent_to_str(struct hostent *addr) { X static char hostname[300]; X struct in_addr *addr_in; X X if(addr->h_addrtype==AF_INET){ X addr_in = (struct in_addr *) addr->h_addr; X sprintf(hostname,"%lx %s",(long)ntohl(addr_in->s_addr),addr->h_name); X }else{ X sprintf(hostname,"0 %s",addr->h_name); X }; X return hostname; X} X X X/* To complicate matters, I require the first client then transmit version */ X/* # and later go back and transmit the first real packet */ X/*-----------------------------------------------------------------------*/ Xvoid do_link_out(void) { X int len; X static int sent_version = 0, old_len = 0; X X /* Add another packet to the out packet list */ X X if (p_out_num >= window_size ) { X /* naff off. The packet window is full. */ X /* This is actually normal, so don't */ X /* print a message. */ X#if 0 X DEBUG_LINK(stderr, "Tried to do link_out with p_out_num == %d\n", X p_out_num); X#endif X return; X } X X /* put some data in the packet. Get up to 'max' bytes. */ X /* returns the length. If the length is -ve then it has been compressed */ X X new_packet = 1; X X if (!old_len){ X if (remote_term_version >= 20000) X len = get_data(p_out[(sent_version) ? p_out_s : ((p_out_s+1)%N_PACKETS)].data, X packet_len); X else X len = get_data(p_out[(sent_version) ? p_out_s : ((p_out_s+1)%N_PACKETS)].data, X (packet_len <= out_mask) ? packet_len : out_mask); X SANITY(packet_len <= out_mask+1); X }else { X len = old_len; X old_len = 0; X } X X if (! len) { X /* All the data waiting was control data for local daemon */ X /* We can handle this. */ X return; X } X X if (! sent_version) { X sprintf((char *)p_out[p_out_s].data, "VERSION %lu %lx %s", X (unsigned long)VERSION, term_localaddr, term_localhost); X old_len = len; X len = strlen((char *)p_out[p_out_s].data) + 1; X } X X p_out[p_out_s].timeout = 0; /* Transmit right away */ X p_out[p_out_s].queue = &curr_client->queue; X p_out[p_out_s].trans = 0; X p_out[p_out_s].len = (len > 0) ? len : -len; X p_out[p_out_s].type = (sent_version) ? ((len > 0) ? (seven_bit_out ? 2 : 0) : 1) : 0; X DEBUG_LINK(stderr, "%s:Added pack %d to out Q %d\n", term_server, p_out_s, X curr_client->number); X p_out_s = (p_out_s + 1) % N_PACKETS; X X sent_version = 1; X curr_client->queue++; X p_out_num ++; X} X X X /* Here is where I handle client priorities. */ X /* Basically I run a little lottery with each client having a # of */ X /* tickets based on priorities. I don't use a random # because */ X /* gambling is illegal in most states. :-) */ X Xint do_lottery(void) { X int count=0, i, j, high = -10000, low=10000, high_min, h; X int tickets[MAX_CLIENTS], winner; X static int next=0; X X /* Find the lowest priority, and initialize */ X X high_min = packet_len; X for(i=0;i high) { X high_min = clients[i].in_buff.size; X high = j; X }else if (j == high || high_min > clients[i].in_buff.size) { X high_min = clients[i].in_buff.size; X } X low = (low < j) ? j : low; X } X tickets[i] = 0; X }; X if (high == -10000) return -1; X X#if 0 X /* This is more unix like... I'm not really sure this is well suited */ X /* For term, since it might be preferable to have processes suspend */ X /* or nearly so when running trsh or such... */ X if (high > 20) high = 20; X if (low < -20) low = -20; X for(h=high, count = 0; h > -20 ;--h) X#else X /* The less we have queued the fairer I am. If there is only one slot */ X /* left we should give it to the most deserving... */ X for(h=high, count = 0; count < window_size_max - p_out_num;--h) X#endif X for(i=0;i= h && X (high_min > packet_len - 40 || clients[i].in_buff.size <= X high_min + clients[i].priority + 20) ) { X tickets[i]++; X count++; X } X if (! count) return -1; X X winner = (next++ % count); X X /* OK, lets search for the winning ticket */ X X while (winner >= 0) X for (i=0;i 0) { X if (! winner--) break; X tickets[i]--; X } X X /* And the winner is client i */ X X return i; X} X X Xvoid do_link_in(void) { X /* Takes packet of the in packet list and feeds it to clients. */ X static un_char uncomp_buff[2049]; X int l; X while (p_in[p_in_e].type >= 0) { X /* feed data out */ X DEBUG_LINK(stderr, "%s: Handling p %d off in Q\n", term_server, p_in_e); X if (p_in[p_in_e].type == 1) { /* compressed data */ X extern int stat_uncomp_in, stat_uncomp_out; X l =uncompress(p_in[p_in_e].data , p_in[p_in_e].len, X uncomp_buff); X stat_uncomp_in += p_in[p_in_e].len; X stat_uncomp_out += l; X put_data(uncomp_buff, l); X } else if (p_in[p_in_e].type == 0) { /* uncompressed 8 bit data */ X if (! remote_term_version) { X memset(term_remotehost,0,sizeof(term_remotehost)); X if(sscanf((char *)p_in[p_in_e].data, "VERSION %lu %lx %s", X &remote_term_version, &term_remoteaddr, term_remotehost) < 1) { X remote_term_version = 10800; X put_data(p_in[p_in_e].data, p_in[p_in_e].len); X } X if(! remote_term_version) X remote_term_version = 10800; X if (! term_remoteaddr || term_remoteaddr == ntohl(inet_addr("127.0.0.1"))) X term_remoteaddr = htonl(inet_addr("127.0.0.254")); X if (! term_remotehost[0] || !strcmp(term_remotehost,"localhost")) X strcpy(term_remotehost,"remotehost"); X } else X put_data(p_in[p_in_e].data, p_in[p_in_e].len); X } else { /* seven bit data */ X l = s_2_e_buff(p_in[p_in_e].data, uncomp_buff, X p_in[p_in_e].len); X put_data(uncomp_buff, l); X } X X p_in[p_in_e].type = -1; X p_in_e = (p_in_e + 1) % N_PACKETS; X p_in_num --; X } X} X X/*---------------------------------------------------------------------------*/ X X/* This is where compression will eventually get done */ X/* For now , we just get some bytes */ X/* we are compressing now. */ Xint get_data(un_char *b, int len) { X extern int tok_byte_width_out; X int i, j, k; X /* this is a horrible kludge, but without major reorganization, X * this is the simplest way. we need to know if the current X * packet for the current client should be compressed, so we X * need to know the client. we get the first byte (which forces X * which client we are getting data from) and then peek and X * see what that client wants. we then pass along the byte X * that we read.. (this is the REAL kludge). X * croutons. X */ X /* Get a byte, so we we have a client. */ X k = get_client_byte(); X if ( k < 0 ) /* no data */ X return 0; X /* Now that we have a client, we can */ X /* check to see whether we want to */ X /* compress the data or not. */ X /* The idea is if compression failed, we */ X /* don't compress again for a while. */ X switch (curr_client->compress) { X case 48: X curr_client->compress = 32; X case 1: X case 2: X case 4: X case 8: X case 16: X case 32: X if ((j = compress(b, len-1, k)) != 0) { X DEBUG_SER(stderr,"%s:compressing packet\n",term_server); X if (j < 0 ) { X ++curr_client->compress; X j = ( -j + tok_byte_width_out - 1) / tok_byte_width_out; X }else { X if (curr_client->compress > 1) X curr_client->compress -= curr_client->compress / 2; X j = ( j + tok_byte_width_out - 1) / tok_byte_width_out; X } X return -j; X } X break; X default: X ++curr_client->compress; X break; X } X /* If we only have a seven bit output */ X /* line, then we want to pack 8 bytes */ X /* to 7 seven bit bytes. */ X if (seven_bit_out) { X DEBUG_SER(stderr,"%s:sevenbit packet\n",term_server); X len = (len * 7) / 8; X b[0] = 0; X j = e_2_s_put(b, (unsigned) k, 0); X while ((j>>3) < len) { X if ((i = get_client_byte()) < 0) X break; X j = e_2_s_put(b, (unsigned) i, j); X } X return (j>>3) + 1; X } else { /* Else, just dump the data, we can */ X /* handle it. */ X b[0] = k; /* put the first byte in the array */ X j = 1; X X while (j < len) { X i = get_client_byte(); X if (i < 0) break; X b[j ++ ] = i; X } X } X return j; X} X/*---------------------------------------------------------------------------*/ X Xvoid ADD_BUFF(struct Client *clt, un_char c) X{ X add_to_buffer( &((clt)->out_buff), c); X} X Xvoid ADD_IN_BUFF(struct Client *clt, un_char c) X{ X add_to_buffer( &((clt)->in_buff), c); X} X Xvoid clear_buffers(struct Client *cl) { X cl->in_buff.size = cl->in_buff.start = cl->in_buff.end = 0; X cl->out_buff.size = cl->out_buff.start = cl->out_buff.end = 0; X X add_to_buffer (& (cl->in_buff), 0); X get_from_buffer (& (cl->in_buff ) ); X X add_to_buffer (& (cl->out_buff), 0); X get_from_buffer (& (cl->out_buff ) ); X} X Xvoid add_ret_buff(struct Client *cl, int which, int byte) { X if (!which) X ADD_IN_BUFF(cl, (un_char) byte); X else X put_client_data(cl, byte); X} X Xvoid add_ret_buff_str(struct Client *cl, int which, char *s) { X int i; X for (i = 0; s[i];++i) X add_ret_buff(cl, which, (int) s[i]); X} X X/* The following return an error. The return should only be fatal X if normally the command would put the socket in DUMB mode. X */ X Xvoid ret_hfail(struct Client *cl, int which, int fatal, char *p) { X int olderrno; X extern int h_errno; X X olderrno = errno; X add_ret_buff(cl, which, SWITCH); X add_ret_buff(cl, which, SWITCH-3); X add_ret_buff(cl, which, I_FAIL); X if (p) { X add_ret_buff_str(cl, which, p); X add_ret_buff_str(cl, which, ": "); X } X add_ret_buff_str(cl, which, term_strherror(h_errno)); X add_ret_buff(cl, which, 0); X if(!fatal){ X errno = olderrno; X return; X } X X add_ret_buff(cl, which, SWITCH); X add_ret_buff(cl, which, SWITCH-2); X add_ret_buff(cl, which, C_CLOSE); X add_ret_buff(cl, which, 0); X errno = olderrno; X} X X X/* The following return an error. The return should only be fatal X if normally the command would put the socket in DUMB mode. X */ X Xvoid ret_fail(struct Client *cl, int which, int fatal, char *p) { X int olderrno; X X olderrno = errno; X add_ret_buff(cl, which, SWITCH); X add_ret_buff(cl, which, SWITCH-3); X add_ret_buff(cl, which, I_FAIL); X if (p) { X add_ret_buff_str(cl, which, p); X add_ret_buff_str(cl, which, ": "); X } X add_ret_buff_str(cl, which, strerror(olderrno)); X add_ret_buff(cl, which, 0); X if(!fatal){ X errno = olderrno; X return; X } X X add_ret_buff(cl, which, SWITCH); X add_ret_buff(cl, which, SWITCH-2); X add_ret_buff(cl, which, C_CLOSE); X add_ret_buff(cl, which, 0); X errno = olderrno; X} X Xvoid ret_ok(struct Client *cl, int which) { X add_ret_buff(cl, which, SWITCH); X add_ret_buff(cl, which, SWITCH-3); X add_ret_buff(cl, which, I_OK); X add_ret_buff(cl, which, 0); X} X Xvoid do_control(int local , struct Client *cl, un_char *c) { X#if defined(SYSV) && !defined(DYNIXPTX) X struct utsname unam; X#endif X DEBUG_FP(stderr, "%s:do_control %s on client %d:%s:\n", X term_server, (local) ? "local" : "remote", cl->number, c); X X switch(c[0]) { X case C_NAME: X DEBUG_FP(stderr, "%s:c_name\n", term_server); X sprintf(cl->name, "%s", (char *)(c+1)); X break; X case C_PUTENV: X DEBUG_FP(stderr, "%s:c_putenv\n", term_server); X if (strchr((char *)(c+1),'=')) term_putenv((char *)(c+1)); X break; X case C_CLOSE: /* Close the file descriptor and the client */ X DEBUG_FP(stderr, "%s:c_close\n", term_server); X if (!isdigit((char) c[1])) { X if (cl->state == 1) X cl->state = 3; /* Go to flush buffers and close. */ X }else { X int k; X k = atoi((char *)c + 1); X if (k < 0 || k >= MAX_CLIENTS) break; X if (clients[k].state == 1) X clients[k].state = 3; X } X break; X case C_CLCLOSE: /* Just close the file descriptor */ X DEBUG_FP(stderr, "%s:c_clclose %s\n", term_server,(char *)c+1); X if (!isdigit((char) c[1])) { X if (cl->state == 1) X cl->state = 4; /* This closes the file descriptor, */ X /* but leaves the client active... */ X }else { X int k; X k = atoi((char *)c + 1); X if (k < 0 || k >= MAX_CLIENTS) { X break; X } X if (clients[k].state == 1) X clients[k].state = 4; X } X break; X case C_DUMB: X DEBUG_FP(stderr, "%s:c_dumb\n", term_server); X cl->type &= ~T_SMART; X cl->dump_count = 0; X break; X case C_DUMP: X case C_DUMP_OLD: X DEBUG_FP(stderr, "%s: c_dump %d\n", term_server, atoi((char *) (c+1))); X if (c[0] == C_DUMP_OLD) ret_ok(cl, local); X cl->type &= ~T_SMART; X cl->dump_count = atol((char *)c+1)+1; X break; X case C_CHMOD: /* There is no return value, so we can speed things up */ X DEBUG_FP(stderr,"%s: c_chmod %s\n",term_server, (char *)c+1); X { X int k; X long atime, mtime; X char *a; X X atime = 0; X mtime = 0; X a = strchr((char *)c+1,'\n'); X if (a != NULL && sscanf((char *)c+1,"%o %ld %ld", &k, &atime, X &mtime) < 1) { X DEBUG_FP(stderr,"%s: c_chmod invalid arguments\n",term_server); X break; X } X if (chmod(++a,k) < 0) { X DEBUG_FP(stderr, "%s: chmod %s failed: %s\n",term_server, a, X strerror(errno)); X break; X } X X { X long now; X struct utimbuf utb; X X now = (long)time(NULL); X utb.actime = (time_t) (atime + now); X utb.modtime = (time_t) (mtime + now); X if (utime(a,&utb) < 0) { X DEBUG_FP(stderr, "%s: utimes failed: %s\n",term_server, X strerror(errno)); X break; X } X } X } X break; X case C_SETPEERNAME: X DEBUG_FP(stderr, "%s: c_setpeername %s\n", term_server, (char *)c+1); X { X memcpy((struct sockaddr *)&cl->peername, X str_to_sockaddr((char *)c+1,inet_addr("127.0.0.1")), X sizeof(struct sockaddr)); X } X break; X case C_OPEN: X DEBUG_FP(stderr,"%s:got c_open %s\n", term_server, (char *)c+1); X case C_UPLOAD: X if (c[0] == C_UPLOAD) X DEBUG_FP(stderr,"%s:got c_upload %s\n", term_server, (char *)c+1); X case C_DOWNLOAD: X if (c[0] == C_DOWNLOAD) X DEBUG_FP(stderr,"%s:got c_download %s\n", term_server, (char *)c+1); X { X long l = 0; X int mode = 0666; X char *a; X X a = strchr((char *)c+1,'\n'); X if (a != NULL) { X if (sscanf((char *)c+1,"%ld %o", &l, &mode) < 1) { X ret_fail(cl,local,FATAL, "open() invalid options"); X DEBUG_FP(stderr,"%s: c_open invalid options\n", term_server); X break; X } X }else a = (char *)c; X X if (cl->fd >=0) close(cl->fd); X X if (c[0] == C_OPEN) { X chmod(++a,0600); X cl->fd = open(a, O_RDWR | O_CREAT, mode); X if (cl->fd > 0) chmod(a,mode); X }else if (c[0] == C_UPLOAD) { X unlink(++a); X cl->fd = open(a, O_WRONLY | O_CREAT | O_TRUNC, mode); X if (cl->fd > 0) chmod(a,mode); /* This probably isn't necessary. */ X }else { X cl->fd = open(++a, O_RDONLY); X } X X if (cl->fd < 0) { X ret_fail(cl,local,FATAL, "open() failed"); X DEBUG_FP(stderr, "%s: open failed: %s\n",term_server,strerror(errno)); X break; X } X if (l != 0 && lseek(cl->fd, (off_t)l, 0) == -1) { X ret_fail(cl,local, FATAL, "lseek failed"); X DEBUG_FP(stderr, "%s: lseek failed: %s\n",term_server, X strerror(errno)); X close(cl->fd); X cl->fd = -1; X break; X } X X } X cl->state = 1; X if (c[0] != C_DOWNLOAD) { X cl->type= T_WRFILE; X cl->cl_type = CL_FILE; X ret_ok(cl,local); X break; X } X /* We allow C_DOWNLOAD to fall through to C_STAT */ X X case C_STAT: X if (c[0] == C_STAT) X DEBUG_FP(stderr, "%s: c_stat %s\n", term_server, (char *)(c+1)); X { X struct stat st; X int type, permissions; X unsigned short cksum=0; X long now, cklen = -1; X char *a, *b, buff[128]; X X a = strchr((char *)c+1,'\n'); X if (a == NULL) X a = (char *)c; X else if ((b = strchr(a+1,'\n'))) { X sscanf(a+1, "%ld", &cklen); X a = b; X } X now = (long)time(NULL); X if (stat(++a, &st)< 0) { X ret_fail(cl, local, ! FATAL, "stat() failed"); X DEBUG_FP(stderr, "%s: stat() failed\n", term_server); X if(c[0] == C_DOWNLOAD) { X close(cl->fd); X cl->fd = -1; X } X break; X } X add_ret_buff(cl, local,SWITCH); X add_ret_buff(cl, local,SWITCH-3); X add_ret_buff(cl, local,I_OK); X /* Get type */ X if (S_ISREG(st.st_mode)) type = 0; X else if (S_ISDIR(st.st_mode)) type = 1; X else type = 2; X /* Now get permissions. */ X permissions = (int) (st.st_mode & 511); X if (getuid() == st.st_uid) X permissions >>= 6; X else if (getgid() == st.st_gid) X permissions >>= 3; X permissions &= 07; X X /* Get checksum if desired. */ X if (cklen >= 0) cksum = file_crc(a, cklen ? cklen : st.st_size); X X sprintf(buff, "%ld %d %d %ld %ld %o %u", X (long)st.st_size, type, permissions, X (long)st.st_atime - now, (long)st.st_mtime - now, X (int)st.st_mode, cksum); X add_ret_buff_str(cl, local, buff); X add_ret_buff(cl, local,0); X X if (c[0] == C_DOWNLOAD) { X cl->type= T_RDFILE; X cl->cl_type = CL_FILE; X cl->dump_count = (long)st.st_size + cl->in_buff.size; X } X break; X } X X case C_UNLINK: X DEBUG_FP(stderr, "%s:c_unlink\n", term_server); X if (unlink(c+1)) { X ret_fail(cl, local, ! FATAL, "unlink failed"); X DEBUG_FP(stderr, "%s: unlink failed: %s\n", term_server, X strerror(errno)); X } else X ret_ok(cl, local); X break; X X case C_PTYEXEC: X case C_EXEC: X if (cl->fd>=0) close(cl->fd); X DEBUG_FP(stderr, "%s: %s on client %d (%s) \n", term_server, X c[0]==C_PTYEXEC?"C_PTYEXEC":"C_EXEC", cl->number, c+1); X if (rshtype > 0) cl->fd = -5; X else { X#ifndef NO_PTYEXEC X if (c[0] == C_PTYEXEC) X cl->fd = open_pty((char *)(c + 1)); X else X#endif X cl->fd = open_socket((char *)(c + 1)); X } X if (cl->fd < 0) { X char *p; X DEBUG_FP(stderr, "%s: failed to open client: error: %d\n", X term_server, cl->fd); X X switch (cl->fd) { X case -1: p = "Couldn't get pty"; break; X case -2: p = "fchmod() failed"; break; X case -3: p = "fork() failed"; break; X case -4: p = "S_Pipe() failed"; break; X case -5: p = "Permission denied"; break; X default: p = "Unknown failure"; break; X } X errno = 0; X ret_fail(cl, local, FATAL, p); X break; X } X DEBUG_FP(stderr, "%s: opened client\n", term_server); X cl->type = T_WRFILE | T_RDFILE; X cl->cl_type = CL_CHILD; X cl->state = 1; X cl->pid = pty_pid; X DEBUG_FP(stderr, "%s: got pid %d\n", term_server, pty_pid); X ret_ok(cl, local); X break; X X case C_BIND: X DEBUG_FP(stderr, "%s: c_bind %s\n", term_server, (char *)(c+1)); X { X unsigned int port=0; X int s,backlog=5; X X sscanf((char *)c+1, "%u %d", &port, &backlog); X DEBUG_FP(stderr, "%s: c_bind %u %d\n", term_server, port, backlog); X X if ((s = bind_tcp_listen(port,backlog)) < 0) { X errno = 0; X ret_fail(cl, local , FATAL, "bind_tcp_listen() failed"); X DEBUG_FP(stderr, "%s:bind_tcp_listen failed (%d): %s\n", term_server, port, X strerror(errno)); X } X if (! port) { X struct sockaddr_in addr_in; X int k=sizeof(addr_in); X X if (getsockname(s, (struct sockaddr *)&addr_in, &k) < 0) { X DEBUG_FP(stderr, "%s:getsockname failed: %s\n", term_server, X strerror(errno)); X }else { X DEBUG_FP(stderr, "%s:sockname returned %s\n", term_server, X sockaddr_to_str((struct sockaddr *)&addr_in, 0)); X port = ntohs(addr_in.sin_port); X } X } X set_nonblock(s); X if (cl->fd>=0) close(cl->fd); X cl->fd = s; X cl->cl_type = CL_BOUND; X cl->type = T_RDFILE | T_WRFILE; X cl->state = 1; X add_ret_buff(cl, local,SWITCH); X add_ret_buff(cl, local,SWITCH-3); X add_ret_buff(cl, local,I_OK); X { X char cport[10]; X sprintf(cport,"%u",port); X add_ret_buff_str(cl,local,cport); X } X add_ret_buff(cl, local,0); X } X break; X case C_ACCEPT: X { X struct sockaddr_in addr_in; X X int ain = sizeof(addr_in); X int s; X X cl->type |= T_RDFILE; X X DEBUG_FP(stderr, "%s: c_accept %s\n", term_server, (char *)(c+1)); X /* Get the socket to try and accept() */ X /* on. */ X s = atoi((char *) (c+1)); X /* Error checking.. */ X if (s < 0 || s >= MAX_CLIENTS || clients[s].fd < 0 || X clients[s].cl_type != CL_BOUND) { X errno = 0; X ret_fail(cl, local, FATAL, "Client out of range"); X DEBUG_FP(stderr,"Client out of range\n"); X break; X }else /* The bound port can accept more connections... */ X clients[s].type |= T_RDFILE | T_WRFILE; X X /* try the actual accept(). */ X s = accept(clients[s].fd , (struct sockaddr *) &addr_in, &ain); X if (s < 0) { X ret_fail(cl, local, FATAL, "Accept failed"); X DEBUG_FP(stderr, "%s: accept failed: %s\n", term_server, strerror(errno)); X break; X } X X memcpy(&cl->peername,&addr_in,sizeof(cl->peername)); X X set_nonblock(s); X add_ret_buff(cl, local,SWITCH); X add_ret_buff(cl, local,SWITCH-3); X add_ret_buff(cl, local,I_OK); X add_ret_buff_str(cl,local,sockaddr_to_str((struct sockaddr *)&addr_in,1)); X add_ret_buff(cl, local,0); X X DEBUG_FP(stderr,"%s:got c_accept\n", term_server); X if (cl->fd>=0) close(cl->fd); X cl->fd = s; X cl->cl_type = CL_SOCKET; X DEBUG_FP(stderr, "%s:name is %s\n", term_server, (char *)(c+1)); X cl->type = T_RDFILE | T_WRFILE; X cl->state = 1; X } X break; X#ifndef X_STREAMS_PIPE X case C_X_SERVER: X#ifdef SVR3 X { X int s; X struct hostent *hostaddr; X char *display; X char host[80]; X int screen = 0; X struct sockaddr_in sock_in; X int i; X X /* X * This code will use the environment variable DISPLAY that was in X * effect at the time "term" was started to direct all X connections X * to. It only works for INET domain sockets X */ X display = getenv("DISPLAY"); X if (display == NULL) X display = (char *)(c+1); X for (i = 0; display[i] && display[i] != ':'; i++) { X host[i] = display[i]; X } X host[i] = '\000'; X if (host[i] == ':') X screen = atoi(&host[i+1]); X X hostaddr = host_lookup(host,0,AF_INET,0,NULL); X X if (hostaddr == NULL) { X ret_fail(cl, local, FATAL, "Failed to find DISPLAY host"); X break; X } X X if ((s = socket(AF_INET, SOCK_STREAM, PF_INET)) < 0) { X perror("Failed to allocate socket for X display"); X ret_fail(cl, local, FATAL, "socket allocation failed"); X break; X } X X sock_in.sin_family = AF_INET; X bcopy((char *) hostaddr->h_addr_list[0], (char *) &sock_in.sin_addr, X hostaddr->h_length); X sock_in.sin_port = htons(6000+screen); X X fprintf(stderr, "Attempting connection to host %d.%d.%d.%d\n", X sock_in.sin_addr.s_addr & 0xff, X (sock_in.sin_addr.s_addr >> 8) & 0xff, X (sock_in.sin_addr.s_addr >> 16) & 0xff, X (sock_in.sin_addr.s_addr >> 24) & 0xff); X if (connect(s, &sock_in, sizeof(sock_in))) { X perror("Connection attempt to X server failed"); X ret_fail(cl, local, FATAL, "Failed to connect to display"); X break; X } X fprintf(stderr, "Connection was successful\n"); X X set_nonblock(s); X DEBUG_FP(stderr, "%s:got c_x_socket\n", term_server); X if (cl->fd>=0) close(cl->fd); X cl->fd = s; X cl->cl_type = CL_SOCKET; X DEBUG_FP(stderr, "%s:name is %s\n", term_server, (char *)(c+1)); X cl->type = T_RDFILE | T_WRFILE; X cl->state = 1; X ret_ok(cl, local); X } X break; X#endif X#endif X case C_SOCKET: X DEBUG_FP(stderr, "%s: c_socket %s\n", term_server, (char *)(c+1)); X { X X int s; X X s = open_unix((char *)(c+1)); X if (s < 0) { X ret_fail(cl, local, FATAL, "open_unix() failed"); X DEBUG_FP(stderr, "%s:open_unix failed: %s\n", term_server, X strerror(errno)); X break; X } X X set_nonblock(s); X DEBUG_FP(stderr,"%s:got c_socket\n", term_server); X if (cl->fd>=0) close(cl->fd); X cl->fd = s; X cl->cl_type = CL_SOCKET; X DEBUG_FP(stderr, "%s:name is %s\n", term_server, (char *)(c+1)); X cl->type = T_RDFILE | T_WRFILE; X cl->state = 1; X ret_ok(cl, local); X } X break; X#ifdef X_STREAMS_PIPE X case C_X_SERVER: X DEBUG_FP(stderr, "%s: c_x_server %s\n", term_server, (char *)(c+1)); X { X X int s; X int display_num; X char *display, *screen; X X /* check DISPLAY variable for screen number */ X X display = getenv("DISPLAY"); X if (display == 0) X display = ":0"; X X screen = strchr(display, ':'); X if (screen != 0) X display_num = atoi((char *)(screen + 1)); X else X display_num = 0; X X s = MakeStreamPipeConnection(display_num); X if (s < 0) { X ret_fail(cl, local, FATAL, "X connection failed"); X DEBUG_FP(stderr, "%s: x connection failed: %s\n", term_server, X strerror(errno)); X break; X } X X set_nonblock(s); X DEBUG_FP(stderr,"%s:got c_x_server\n", term_server); X if (cl->fd>=0) close(cl->fd); X cl->fd = s; X cl->cl_type = CL_SPIPE; X DEBUG_FP(stderr, "%s:name is %s\n", term_server, (char *)(c+1)); X cl->type = T_RDFILE | T_WRFILE; X cl->state = 1; X ret_ok(cl, local); X } X break; X#endif X case C_PORT: X DEBUG_FP(stderr, "%s: c_port %s\n", term_server, (char *)(c+1)); X { X struct sockaddr *addr; X char *hostname = NULL; X int s, old=0; X unsigned int port; X char *colon; X X colon = strchr((char *)c+1,':'); X sscanf((colon) ? (colon+1) : (char *)c+1,"%u %d",&port,&old); X hostname=(colon) ? ((char *)c+1) : NULL; X X if (old && cl->fd >= 0) { X s = cl->fd; X }else if ((s = socket(AF_INET, SOCK_STREAM, 0 )) < 0) { X ret_fail(cl, local, FATAL, "Socket() failed"); X DEBUG_FP(stderr, "%s: Socket() failed: %s\n", term_server, X strerror(errno)); X break; X } X X if (!(addr=make_sockaddr(port,hostname,inet_addr("127.0.0.1")))) { X errno = 0; X ret_fail(cl, local, FATAL, "Can't get local address"); X DEBUG_FP(stderr,"%s: Can't get local address\n", term_server); X close(s); X break; X } X X#ifndef USE_CONNBLOCK X /* Set nonblock mode before connecting so connect() returns right away */ X set_nonblock(s); X#endif X X DEBUG_FP(stderr, "%s: connecting to to %s\n", term_server, X sockaddr_to_str(addr,INADDR_ANY)); X if (connect(s,addr,sizeof(struct sockaddr))<0) { X#ifndef USE_CONNBLOCK X if (errno != EINPROGRESS && errno != ERR_BLOCK) { X#endif X ret_fail(cl,local, FATAL, "connect() failed"); X DEBUG_FP(stderr, "%s: connect() failed: %s\n", term_server, X strerror(errno)); X close(s); X break; X#ifndef USE_CONNBLOCK X } X#endif X } X X#ifdef USE_CONNBLOCK X set_nonblock(s); X#endif X X DEBUG_FP(stderr,"%s:got c_port\n", term_server); X if (cl->fd>=0 && ! old) close(cl->fd); X cl->fd = s; X cl->cl_type = CL_SOCKET; X cl->type = T_RDFILE | T_WRFILE; X#ifndef USE_CONNBLOCK X cl->state = 5; X cl->timeout = current_time + term_inc*30; X /* 30-second connect timeout */ X#else X cl->state = 1; X ret_ok(cl, local); X#endif X } X break; X case C_LISTEN: X DEBUG_FP(stderr, "%s: c_listen %s\n", term_server, (char *)(c+1)); X { X int k, queue; X X if(sscanf((char *)c+1,"%d %d",&k,&queue) < 2) { X errno = 0; X#if 0 X ret_fail(cl, local, ! FATAL, "Insufficient argc"); X#endif X DEBUG_UDP(stderr, "%s:insufficient argc\n", term_server); X break; X } X if (k < 0 || k >= MAX_CLIENTS || clients[k].fd < 0 || X clients[k].cl_type != CL_BOUND) { X errno = 0; X#if 0 X ret_fail(cl, local, FATAL, "Client out of range"); X#endif X DEBUG_FP(stderr,"%s: Client out of range\n",term_server); X break; X } X if (listen(clients[k].fd, queue) < 0) { /* If we can't listen... */ X#if 0 X ret_fail(cl, local, ! FATAL, "listen() failed"); X#endif X DEBUG_FP(stderr,"%s: listen() failed: %s\n", term_server, X strerror(errno)); X close(clients[k].fd); X clients[k].fd = -1; X break; X } X#if 0 X ret_ok(cl, local); X#endif X } X break; X case C_PRIORITY_OLD: X case C_PRIORITY: X DEBUG_FP(stderr, "%s: c_priority %d\n", term_server, X atoi((char *) (c+1))); X cl->priority = atoi((char *) (c+1)); X if (c[0] == C_PRIORITY_OLD) ret_ok(cl, local); X break; X case C_COMPRESS: X DEBUG_FP(stderr, "%s: c_compress %c\n", term_server, c[1]); X X switch(c[1]) { X case 'y': /* yes */ X case 'c': /* compress */ X case 'Y': /* caps too */ X case 'C': X case 1: /* true */ X case '1': /* in ascii */ X cl->compress = 1; X ret_ok(cl, local); X break; X case 'n': /* no */ X case 'u': /* uncompress */ X case 'r': /* raw */ X case 'N': /* caps too */ X case 'U': X case 'R': X case 0: /* false */ X case '0': /* in ascii */ X cl->compress = 0; X ret_ok(cl, local); X break; X default: X errno = 0; X ret_fail(cl, local, ! FATAL, "Invalid argument"); X DEBUG_FP(stderr,"%s: invalid argument\n", term_server); X break; X } X break; X X case C_STATS: X { X int opt; X un_char ret[2000]; X/* extern do_stats(un_char *, int, struct Client *); */ X X DEBUG_FP(stderr, "%s:c_stats\n", term_server); X opt = atoi((char *) (c+1)); X add_ret_buff(cl, local, SWITCH); X add_ret_buff(cl, local, SWITCH-3); X add_ret_buff(cl, local, I_OK); X X do_stats(ret, opt, cl); X X add_ret_buff_str(cl, local, (char *)ret); X add_ret_buff(cl, local, 0); X break; X } X case C_SEEK: X { X long l; X DEBUG_FP(stderr, "%s:c_seek %s\n", term_server, c+1); X if(sscanf((char *)(c+1),"%ld",&l)<1) l=0; X if (lseek(cl->fd, (off_t)l, 0) < (off_t)0) { X ret_fail(cl, local, ! FATAL, "lseek() failed"); X DEBUG_FP(stderr, "%s:c_seek failed\n",term_server); X break; X } X ret_ok(cl, local); X break; X } X case C_RESIZE_OLD: X case C_RESIZE: X DEBUG_FP(stderr, "%s:c_resize %s\n", term_server, c+1); X { X#ifdef USE_SIGWINCH X void do_resize(int number, int rows, int cols, int ypixels, int xpixels); X int number; X int rows, cols, ypixels, xpixels; X sscanf((char *) (c+1), "%d %d %d %d %d", X &number, &rows, &cols, &ypixels, &xpixels); X do_resize(number, rows, cols, ypixels, xpixels); X#endif /* USE_SIGWINCH */ X } X if (c[0] == C_RESIZE_OLD) ret_ok(cl, local); X break; X X case C_BINDN: /* ftp special -ot */ X DEBUG_FP(stderr, "%s: c_bindn %s\n", term_server,c+1); X { X int s, k; X struct sockaddr_in addr_in; X X s = bind_tcp_listen((unsigned int) atoi((char *)(c+1)),5); X if (s < 0) { X errno = 0; X ret_fail(cl, local , FATAL, "bind_tcp_listen() failed"); X DEBUG_FP(stderr, "%s:bind_tcp_listen failed\n", term_server); X break; X } X k=sizeof(addr_in); X if (getsockname(s, (struct sockaddr *)&addr_in, &k) < 0) { X ret_fail(cl, local, FATAL, "getsockname() failed"); X DEBUG_FP(stderr, "%s:getsockname failed: %s\n", term_server, X strerror(errno)); X break; X } X X DEBUG_FP(stderr, "%s:sockname returned %lx %x\n", term_server, X (long)ntohl(addr_in.sin_addr.s_addr), ntohs(addr_in.sin_port)); X ret_ok(cl, local); X X add_ret_buff_str(cl,local,sockaddr_to_str((struct sockaddr *)&addr_in,1)); X add_ret_buff(cl, local,0); X X set_nonblock(s); X if (cl->fd>=0) close(cl->fd); X cl->fd = s; X cl->cl_type = CL_BOUND; X cl->type = T_RDFILE | T_WRFILE; X cl->state = 1; X } X break; X X case C_GETSOCKNAME: /* Return the local sockname -warlord */ X DEBUG_FP(stderr, "%s: c_getsockname %s\n", term_server,(c+1)); X { X int s, k, kt; X struct sockaddr addr; X X if(! *(c+1)){ X s = cl->fd; X kt= cl->cl_type; X } else { X k = atoi((char *)c+1); X if (k < 0 || k >= MAX_CLIENTS) { X errno = 0; X ret_fail(cl, local, ! FATAL, "Client out of range"); X DEBUG_FP(stderr, "%s: client out of range\n", term_server); X break; X }; X s=clients[k].fd; X kt=clients[k].cl_type; X }; X X if ( s < 0 ) { X errno = 0; X ret_fail(cl, local, ! FATAL, "Client closed"); X DEBUG_FP(stderr, "%s:client closed\n", term_server); X break; X } X /* Error checking.. */ X if (kt != CL_BOUND && kt != CL_SOCKET) { X errno = 0; X ret_fail(cl, local, ! FATAL, "Invalid client type"); X DEBUG_FP(stderr, "%s:invalid client type\n", term_server); X break; X } X X k=sizeof(addr); X if (getsockname(s, &addr, &k) < 0) { X ret_fail(cl, local, ! FATAL, "getsockname() failed"); X DEBUG_FP(stderr, "%s:getsockname failed: %s\n", term_server, X strerror(errno)); X break; X } X X /* Convert this to a string */ X X /* Set up the return buffer */ X add_ret_buff(cl, local, SWITCH); X add_ret_buff(cl, local, SWITCH-3); X add_ret_buff(cl, local, I_OK); X add_ret_buff_str(cl, local, sockaddr_to_str(&addr,1)); X add_ret_buff(cl, local,0); X X DEBUG_FP(stderr, "%s:sockname returned\n", term_server); X } X break; X X case C_GETPEERNAME: /* Return the peername -warlord */ X DEBUG_FP(stderr, "%s: c_getpeername %s\n", term_server,(c+1)); X { X int s, k, kt; X struct sockaddr addr; X struct sockaddr_in *addr_in; X X if(! *(c+1)){ X s = cl->fd; X kt = cl->cl_type; X addr_in = &cl->peername; X } else { X k = atoi((char *)c+1); X if (k < 0 || k >= MAX_CLIENTS) { X errno = 0; X ret_fail(cl, local, ! FATAL, "Client out of range"); X DEBUG_FP(stderr, "%s: client out of range\n", term_server); X break; X }; X s=clients[k].fd; X kt=clients[k].cl_type; X addr_in = &clients[k].peername; X } X X if ( s < 0 ) { X errno = 0; X ret_fail(cl, local, ! FATAL, "Client closed"); X DEBUG_FP(stderr, "%s:client closed\n", term_server); X break; X } X X if (kt != CL_SOCKET) { X errno = 0; X ret_fail(cl, local, ! FATAL, "Invalid client type"); X DEBUG_FP(stderr, "%s:invalid client type\n", term_server); X break; X } X X k=sizeof(addr); X if (addr_in->sin_family != ~0) { X if (k > sizeof(struct sockaddr_in)) k = sizeof(struct sockaddr_in); X memcpy((struct sockaddr_in *)&addr, addr_in, k); X }else if (getpeername(s, &addr, &k) < 0) { X ret_fail(cl, local, ! FATAL, "getpeername() failed"); X DEBUG_FP(stderr, "%s: getpeername failed: %s\n", term_server, X strerror(errno)); X break; X } X X /* Set up the return buffer */ X add_ret_buff(cl, local, SWITCH); X add_ret_buff(cl, local, SWITCH-3); X add_ret_buff(cl, local, I_OK); X add_ret_buff_str(cl, local, sockaddr_to_str(&addr,1)); X add_ret_buff(cl, local,0); X X DEBUG_FP(stderr, "%s:peername returned\n", term_server); X } X break; X X case C_GETHOSTNAME: /* Canonical hostname */ X DEBUG_FP(stderr, "%s: c_gethostname %s\n", term_server, X ((*(c+1)) ? (char *) (c+1) : "")); X { X struct hostent *hp=NULL; X char hostname[259]; X X if (*(c+1)) { X strcpy(hostname, (char *) (c+1)); X } else { X#if defined(SYSV) && !defined(DYNIXPTX) X uname(&unam); X strcpy(hostname, unam.nodename); X#else X gethostname(hostname, sizeof(hostname)); X#endif /* SYSV */ X } X X if (isdigit(*hostname)) { X unsigned long k; X k=inet_addr(hostname); X hp=host_lookup((char *)&k, sizeof(k), AF_INET, 0, NULL); X } X if (!hp) { X hp=host_lookup(hostname,0,AF_INET,0,NULL); X } X if (!hp) { X extern int h_errno; X ret_hfail(cl, local, ! FATAL, "gethostbyname() failed"); X DEBUG_FP(stderr, "Term: gethostbyname() failed: %s\n", X term_strherror(h_errno)); X break; X } X X add_ret_buff(cl, local, SWITCH); X add_ret_buff(cl, local, SWITCH-3); X add_ret_buff(cl, local, I_OK); X add_ret_buff_str(cl, local, hostent_to_str(hp)); X add_ret_buff(cl, local,0); X } X break; X X case C_BINDS: /* One time tcp term socket */ X DEBUG_FP(stderr, "%s: c_binds\n", term_server); X { X int j,k; X struct sockaddr_in addr_in; X char port[10]; X X for (j=0;j= MAX_CLIENTS){ X errno = 0; X ret_fail(cl, local, ! FATAL, "Client out of range"); X DEBUG_FP(stderr,"client out of range\n"); X break; X }else if( (s = socket(AF_INET,SOCK_DGRAM,0)) < 0) { X ret_fail(cl,local,! FATAL,"dgram socket() failed"); /* 0 ? is it fatal? */ X DEBUG_UDP(stderr, "%s: dgram socket failed: %s\n", term_server, X strerror(errno)); X break; X } X X if( clients[k].fd >= 0) close(clients[k].fd); X X clients[k].fd = s; X clients[k].type = T_WRFILE | T_RDFILE | T_UDP; X clients[k].cl_type = CL_SOCKET; X clients[k].state = 1; X clients[k].udp_type = udp_type; X clients[k].udp_size = 0; X X set_nonblock(clients[k].fd); X X clients[k].udp_host = 0; X clients[k].udp_port = 0; X clients[k].parent = cl->number; X ret_ok(cl,local); X } X break; X X case C_UBIND: X DEBUG_FP(stderr, "%s: c_ubind %s\n", term_server, (char *)c+1); X { X int k; X unsigned int port=0; X struct sockaddr *addr; X X sscanf((char *)c+1,"%d %u",&k,&port); X X DEBUG_FP(stderr,"%s:- client %d, port %u.\n", term_server, k, port); X X/* hmmm.. maybe do some more sanity checks? is T_UDP? */ X/* Naa, leave it general so people can use if for other things. */ X X if (k < 0 || k >= MAX_CLIENTS || clients[k].fd < 0) { X errno = 0; X ret_fail(cl, local, ! FATAL, "Client out of range"); X DEBUG_FP(stderr,"client out of range\n"); X break; X } X X if (!(addr=make_sockaddr(port,NULL,INADDR_ANY))) { X errno = 0; X ret_fail(cl, local, ! FATAL, "Can't get local address"); X DEBUG_FP(stderr,"can't get local address\n"); X break; X } X X if( bind(clients[k].fd,addr,sizeof(struct sockaddr)) < 0) { X ret_fail(cl,local, ! FATAL,"bind() failed"); X DEBUG_FP(stderr,"term: bind() failed: %s: %s\n", (char *)c+1, X strerror(errno)); X break; X } X ret_ok(cl,local); X } X break; X X case C_UDPSET: X DEBUG_FP(stderr, "%s: c_udpset %s\n", term_server, (char *) c+1); X { X int k; X char *ptr; X struct sockaddr_in *addr_in; X X k = atoi((char *)c+1); X if (k < 0 || k >= MAX_CLIENTS) { X errno = 0; X ret_fail(cl,local,! FATAL,"client out of range"); X DEBUG_FP(stderr,"client out of range\n"); X break; X } X X ptr = strchr((char *)c+1,':'); X if (ptr == NULL) { X errno = 0; X ret_fail(cl,local,! FATAL,"No address specified"); X DEBUG_FP(stderr,"no address specified\n"); X break; X } X X addr_in = (struct sockaddr_in *) str_to_sockaddr(++ptr, X inet_addr("127.0.0.1")); X X if (addr_in == NULL) { X ret_fail(cl,local,! FATAL,"Address not recognized"); X DEBUG_FP(stderr,"address not recognized\n"); X break; X } X X clients[k].udp_host = ntohl(addr_in->sin_addr.s_addr); X clients[k].udp_port = ntohs(addr_in->sin_port); X X DEBUG_FP(stderr, "c_udpset %lx %x\n",clients[k].udp_host,clients[k].udp_port); X X ret_ok(cl,local); X } X break; X X case C_QUIT: X DEBUG_FP(stderr, "%s: c_quit %s\n", term_server, (char *)c+1); X if (c[1] == '\0') X do_shutdown = -1; X else { X do_shutdown = atoi((char *)c+1); /* 1 == no hangup, 2 == force hangup */ X if (do_shutdown < 1) X do_shutdown = -1; /* -1 == take the default action */ X } X break; X X default: X break; X } /* switch */ X} /* function */ X Xvoid init_client(struct Client *cl) { X extern int compressing; /* the default from main */ X cl->type = T_RDFILE | T_WRFILE; X cl->udp_type = 0; X cl->udp_size = 0; X cl->dump_count = 0; X cl->cl_type = CL_SOCKET; X cl->state = 1; X cl->compress = compressing; X cl->c_state = 0; X cl->number = (cl - &clients[0]); X cl->priority = 0; /* default priority. Higher is better. */ X cl->queue = 0; X cl->name[0] = 0; X cl->parent = -1; X cl->peername.sin_port = ~0; X cl->peername.sin_addr.s_addr = term_localaddr; X cl->peername.sin_family = ~0; X if (cl->fd > 0) { X close(cl->fd); X cl->fd = -1; X } X clear_buffers(cl); X DEBUG_LINK(stderr, "Init client %d\n", cl->number); X} X X/*---------------------------------------------------------------------------*/ X/* Returns next client to read. Will be beefed up later to support priorities*/ X/* A client with a priority of n will get n/(sum) of the packets available */ X/* maybe :) */ X Xstruct Client * get_next_client(void) { X int i, j=0; X /* Check to see if any of the clients */ X /* are closing. This gets priority. */ X for (i = 0; i < MAX_CLIENTS;++i) X if (clients[i].state == 2) { X DEBUG_STATE(stderr, "get_n_c ret cl %d\n", i); X return &clients[i]; X } X X if ((j = do_lottery()) < 0) return 0; /* Nobody was ready */ X X return &clients[j]; X} X Xint get_client_data(struct Client *cl) { X int i; /* If nothing ready, signal that. */ X SANITY(cl); X if (!cl->in_buff.size) X return -1; X SANITY(cl->in_buff.end <= cl->in_buff.alloced); X SANITY(cl->in_buff.end >= 0); X SANITY(cl->in_buff.size >= 0); X SANITY(cl->in_buff.size <= cl->in_buff.alloced); X X /* get the next byte from the buffer.*/ X X X i = cl->in_buff.data[cl->in_buff.end++]; X if (cl->in_buff.end == cl->in_buff.alloced) /* Wrap the buffer */ X /* round if we have */ X /* hit the end. */ X cl->in_buff.end = 0; X cl->in_buff.size --; /* Update count of bytes left in buffer. */ X X SANITY(cl->dump_count >= 0); X if (cl->dump_count) { /* If we are currently dumping, update */ X /* the dump count, and go smart if we */ X /* have finished. */ X if (!--cl->dump_count && cl->cl_type != CL_FILE) X cl->type |= T_SMART; X } X X DEBUG_STATE(stderr, "\tgcd:%d\n", i); X return i; X} X Xvoid put_client_data(struct Client *cl, int i) { X while (1) { X DEBUG_STATE(stderr, "p_c_d: %d: state %d i %d c_len %d\n", X cl->number, cl->c_state, i, cl->c_len); X switch (cl->c_state) { X case 0: X if (i == SWITCH) { X cl->c_state = 1; X return; X } X X ADD_BUFF(cl, (un_char) i); X return; X case 1: X if (i == SWITCH) { X ADD_BUFF(cl, (un_char) i); X cl->c_state = 0; X return ; X } X cl->c_len = 0; /* yes. We do want to throw this byte away */ X /* It is just a remote control message flag */ X if (i == SWITCH - 3) { /* It is a result message. */ X if (cl->type & T_SMART) { X ADD_BUFF(cl, (un_char) SWITCH); X ADD_BUFF(cl, SWITCH-3); X } X cl->c_state = 3; X }else { X cl->c_state = 2; X } X return; X case 2: X /* XXX Skip commands that are too long. This is not very elegant. */ X if (cl->c_len < sizeof(cl->control)-1) X cl->control[cl->c_len++] = i; X if (i) return; X if (cl->c_len >= sizeof(cl->control)-1) { X WARNING(stderr, "%s:command skipped, too long: \"%.30s...\"\n", X term_server, cl->control); X errno = E2BIG; X ret_fail(cl, 0, 1, "command skipped"); X }else { X do_control(0, cl , cl->control); X } X cl->c_state = 0; X return; X case 3: X if (cl->type & T_SMART) ADD_BUFF(cl, (un_char) i); X if (i) return; X cl->c_state = 0; X return; X default: X cl->c_state = 0; X break; X } X } X} X X X X/* Return the next byte that should go down the serial link */ X/* Another bloody finite state machine. ;) */ X/* This was a bitch to write. Sigh. More things than I thought needed */ X/* to be handled. And it still isn't perfect. :( */ X Xint get_client_byte() { X static int state = 0, X next, max; X X static char control[1024]; X struct Client *cl; X int i; X X while (1) { X DEBUG_STATE(stderr, "get_c_b: state %d next %d max %d cl %d\n", state, X next, max, !curr_client ? -1 : curr_client->number); X X switch(state) { X case 0: /* looking for new client */ X new_packet = 0; X cl = get_next_client(); X if (cl == 0) X return -1; X X if (!cl->in_buff.size && cl->state == 2) { /* closing down */ X /* We have emptied the buffers, so */ X /* just tell the remote end that , and */ X /* finish off. */ X DEBUG_FP(stderr, "%s:sending c_close\n", term_server); X /* ++kay: should be state 3, not -1 */ X cl->state = 3; X state = 4; X sprintf(control, "%c%c%c%c%c%c", SWITCH, cl->number + SWITCH + 1, X SWITCH, SWITCH - 2, C_CLOSE, 0); X curr_client = cl; X next = 0; X max = 6; X break; X } X X if (cl != curr_client) { X curr_client = cl; X state = 1; X return SWITCH; X } X state = 2; X break; X case 1: X state = 2; X return curr_client->number + SWITCH + 1; X break; X case 2: X /* If we are a new packet, then check */ X /* to see if there is a new client */ X /* with a greater probability. */ X if (new_packet) { X new_packet = 0; X state = 0; X break; X } X X i = get_client_data(curr_client); X if (i == SWITCH) { X if (!(curr_client->type & T_SMART)) { X state = 4; X max = 1; next = 0; X control[0] = SWITCH; X return SWITCH; X } X state = 3; X break; X } else if (i < 0) { X state = 0; X break; X } X { X extern int stat_cooked_out; X ++stat_cooked_out; X } X return i; X break; X case 3: X i = get_client_data(curr_client); X if (i < 0) X return -1; X X if (i == SWITCH) { X /* It is an escaped escape code */ X state = 4; X X max = 1; next = 0; X return SWITCH; X } X /* ok. We have some sort of control message */ X if ( i > SWITCH ) { X /* Hmm. It is trying to switch streams on its own. welllll. ok. */ X /* we'll let it. Note that is can only reliably insert 1 byte at */ X /* a time */ X control[0] = (i-SWITCH-1 1023) { X if (curr_client->fd >= 0) close(curr_client->fd); X }else { X control[next++] = i; X } X X /* If this isn't the end of the */ X /* message, keep going.. */ X if (i) X break; X X if (next > 1023) { X WARNING(stderr, "%s:local command skipped, too long: \"%.30s...\"\n", X term_server, control); X }else { X do_control(1, curr_client, (un_char *) control); X } X X state = 2; X break; X } /* switch */ X } /* while */ X} X X/*----------------------------------------------------------------------*/ X/* Transfers the next 'len' bytes from the link, to clients. Note that */ X/* we handle control information here. */ Xvoid put_data(un_char *b, int len) { X static struct Client *curr_client = 0; X static int state = 0; X int i, d; X X i = 0; X while (i < len) { X DEBUG_STATE(stderr, "%s:put_d: s %d, cl %d d %d\n", term_server, state, X !curr_client ? 0 : curr_client->number, b[i]); X switch(state) { X case 0: X d = b[i++]; X if (d == SWITCH) { X state = 1; X break; X } X /* ok. Just put data to current client */ X if (!curr_client) X break; X put_client_data(curr_client, d); X break; X case 1: X d = b[i++]; X /* checked for escaped escape */ X if (d == SWITCH) { X if (curr_client) { X put_client_data(curr_client, d); X put_client_data(curr_client, d); X } X state = 0; X break; X } X /* check for stream switch */ X if (d > SWITCH && d - SWITCH - 1 < MAX_CLIENTS ) { X curr_client = &clients[d - SWITCH - 1]; X if (curr_client->state < 0) X init_client(curr_client); X DEBUG_LINK(stderr, "%s:stream switch to %d\n", term_server, X d - SWITCH - 1); X state = 0; X break; X } X if (curr_client) { X put_client_data(curr_client, SWITCH); X put_client_data(curr_client, d); X } X state = 0; X break; X default: X state = 0; X break; X } /* switch */ X } /* while */ X} /* function */ X SHAR_EOF $shar_touch -am 1028144694 'term-2.2.5/do_link.c' && chmod 0644 'term-2.2.5/do_link.c' || echo 'restore of term-2.2.5/do_link.c failed' shar_count="`wc -c < 'term-2.2.5/do_link.c'`" test 52519 -eq "$shar_count" || echo "term-2.2.5/do_link.c: original size 52519, current size $shar_count" rm -f _sharnew.tmp fi # ============= term-2.2.5/do_select.c ============== if test -f 'term-2.2.5/do_select.c' && test X"$1" != X"-c"; then echo 'x - skipping term-2.2.5/do_select.c (file already exists)' rm -f _sharnew.tmp else > _sharnew.tmp echo 'x - extracting term-2.2.5/do_select.c (text)' sed 's/^X//' << 'SHAR_EOF' > 'term-2.2.5/do_select.c' && X#define I_SYS X#define I_ERRNO X#define I_STRING X#define I_STRING X#include "includes.h" X Xvoid do_select_loop(int sock, int in_f, int out_f) { X struct Buffer in, out; X int i; X X X in.start = in.end = in.size = in.alloced = 0; X in.data = (un_char*) 0; X out.start = out.end = out.size = out.alloced = 0; X out.data = (un_char*) 0; X X add_to_buffer (&in, 0); X get_from_buffer (&in ); X X add_to_buffer (&out, 0); X get_from_buffer (&out); X X while (sock >= 0 || (out_f >=0 && out.size)) { X fd_set rd, wr; X int max; X max = 0; X FD_ZERO(&rd); X FD_ZERO(&wr); X X if (sock >= 0 && in_f < 0 && ! in.size) { X close(sock); X sock = -1; X } X if (sock < 0) { X if (in_f >= 0) { X in_f = -1; X in.start = in.end = in.size = 0; X } X if (! out.size) out_f = -1; X if (out_f < 0) break; X } X X if (in.size) { X FD_SET(sock, &wr); X if (sock > max) max = sock; X } else if (in_f >= 0) { X FD_SET(in_f, &rd); X if (in_f > max) max = in_f; X } X X if (out.size) { X if (out_f >= 0) { X FD_SET(out_f, &wr); X if (out_f > max) max = out_f; X }else { X out.start = out.end = out.size = 0; X } X } else if (sock >= 0) { X FD_SET(sock, &rd); X if(sock > max) max = sock; X } X X if (select(max+1, &rd, &wr, 0, 0) < 0 && errno == EINTR) continue; X X if (sock >= 0 && FD_ISSET(sock, &rd)) { X i = read_into_buff(sock, &out, 0); X if (i<1 && termerrno) { X close(sock); X sock = -1; X } X } X if (sock >= 0 && FD_ISSET(sock, &wr)) { X i = write_from_buff(sock, &in, 0); X if (i<1 && termerrno) { X close(sock); X sock = -1; X } X } X if (in_f >= 0 && sock >= 0 && FD_ISSET(in_f, &rd)) { X i = read_into_buff(in_f, &in, 0); X if (i<1 && termerrno) in_f = -1; X } X if (out_f >= 0 && FD_ISSET(out_f, &wr)) { X i = write_from_buff(out_f, &out, 0); X if (i <1 && termerrno) { X out_f = -1; X out.start = out.end = out.size = 0; X } X } X } X if (sock >= 0) close(sock); X} X X X SHAR_EOF $shar_touch -am 1028144694 'term-2.2.5/do_select.c' && chmod 0644 'term-2.2.5/do_select.c' || echo 'restore of term-2.2.5/do_select.c failed' shar_count="`wc -c < 'term-2.2.5/do_select.c'`" test 2076 -eq "$shar_count" || echo "term-2.2.5/do_select.c: original size 2076, current size $shar_count" rm -f _sharnew.tmp fi # ============= term-2.2.5/download.c ============== if test -f 'term-2.2.5/download.c' && test X"$1" != X"-c"; then echo 'x - skipping term-2.2.5/download.c (file already exists)' rm -f _sharnew.tmp else > _sharnew.tmp echo 'x - extracting term-2.2.5/download.c (text)' sed 's/^X//' << 'SHAR_EOF' > 'term-2.2.5/download.c' && X/* X * A client for term. Taken from upload.c sources by Chris Metcalf X * (metcalf@lcs.mit.edu). X * Hacked up for checksums by ot X */ X X/* If the remote file exists, tupload tries to checks if it can resume X * with the following conditions: X * X * - Either the remote file is read only or it is the same size as the X * local X * - The remote file is not larger than the local file. X * - The local file has not been edited, touched, or otherwise modified. X * - The remote and local checksums match. X * (bcr@physics.purdue.edu) X */ X X#define I_IOCTL X#define I_STRING X#define I_STAT X#define I_TIME X#define I_UTIME X#define I_TYPES X#define DEBUG X X#include "includes.h" X#include "client.h" X X#ifdef ONE_CLIENT X# define main tdownload X#else Xint term_debug = 0; X#endif Xint download_force = 0; X Xint download_unlinkmode = 0; Xint download_literal_filename = 0; X Xstruct stat st; X X/*---------------------------------------------------------------------------*/ X Xstatic int local_options ( char opt, char *optarg ) X{ X switch(opt) X { X case 'f' : X download_force = 1; X break; X case 'q' : X verbose = 0; X break; X case 'u': X download_unlinkmode = 1; X break; X case 'l': X download_literal_filename = 1; X break; X default: X return -1; X } X return 0; X} X/*---------------------------------------------------------------------------*/ X X#define CPS_WINDOW 10 /* about ten seconds */ X Xdouble download_delta_timeval(struct timeval *a, struct timeval *b) X{ X return (a->tv_sec + a->tv_usec/1000000.0) - X (b->tv_sec + b->tv_usec/1000000.0); X} X Xint main(int argc, char *argv[]) X{ X /* From client.c */ X /* locals for upload. */ X struct Buffer buffer; X char *cutpath, *file, *local, path[255], filename[255]; X int term, fd, first, type, perms, i; X unsigned int lcksum, rcksum; X int filesent, j=0, fullperms=0; X long ret, remote_size, local_size; X long bytesrecvd, total_bytesrecvd; X long atime, mtime, rmtime; X double cps = 0; X struct timeval total_starttime, total_stoptime, starttime, lasttime, nowtime; X double etime, total_etime = 0; X double recent_cpsbytes[CPS_WINDOW], recent_etime[CPS_WINDOW]; X int cps_count, read_size; X int bufsiz = BUFSIZ; X struct utimbuf utb; X char *remote_unlink = NULL; X X term = -1; X fd = -1; X first = -1; X priority = -5; /* The scale is -20 to 20 with higher being better */ X verbose = 1; X bytesrecvd = 0; X total_bytesrecvd = 0; X gettime(&total_starttime); X filesent = 0; X path[0] = '\0'; X buffer.start = buffer.end = buffer.size = buffer.alloced = 0; X buffer.data = NULL; X X /* Handle the options. We use the standard client argument handling */ X /* to do this. Options peculiar to upload are 'f' for force, q for */ X /* quiet, and v for verbose, u for unlink */ X if ( ((first = client_options(argc,argv,"fquvl",local_options)) == -1) X || (first >= argc) ) { X fprintf(stderr, X "Usage: download [-f] [-q] [-u] [-v] [-r] [-c] [-p ] " X " [... ] [local dir]\n"); X exit(1); X } X X use_term_command(PRIVILEGED); X X /* Make sure the buffer is non-zero in */ X /* size. */ X add_to_buffer(&buffer, 0); X get_from_buffer(&buffer); X if ((term = socket_connect_server(-1, term_server)) < 0) { X fprintf(stderr,"Term: %s\n", command_result); X exit(1); X } X X /* check the last arg to see if it's a dir, and if so, */ X /* that's where we put the received files. */ X if (first < argc && stat(argv[argc-1], &st) == 0 && S_ISDIR(st.st_mode)) { X strcpy(path, argv[--argc]); X if ( ! (i = strlen(path))) { X fprintf(stderr, "\tFatal. Zero length path passed.\n"); X exit(1); X } X if ( path[i - 1] != '/' ) { X path[i] = '/'; X path[i+1] = '\0'; X } X } X X /* should check here for a file to send. enforce command line. */ X /* or, maybe no args should mean take from stdin. */ X /* but then, what's the output file name? -q */ X X while ( first < argc ) { X X /* close the output file if it was left open (it shouldn't be) */ X if (fd > 0) { X close(fd); X fd = -1; X } X X /* get the filename to receive.*/ X file = argv[first++]; X X if ( (first+1 < argc) && X (! strcmp(argv[first],"-as") || ! strcmp(argv[first],"--as")) ) { X local = argv[first+1]; X first += 2; X } X else { X /* leave the filename alone */ X local = file; X X /* remove the pathname for the outgoing file */ X if (!download_literal_filename) { X for ( cutpath = local; *cutpath; cutpath++ ) X if ( ( *cutpath == '/' ) && ( *(cutpath+1) ) ) X local = cutpath + 1; X } X } X X /* prepend the specified path, if there is one. */ X if ( *path ) { X strcpy(filename, path); X strcat(filename, local); X local = filename; X } X X if ( verbose > 0 ) { X if ( file == local ) X fprintf(stderr, "receiving %s\n",file); X else X fprintf(stderr, "receiving %s as %s\n", file, local ); X } X /* use stdout if requested */ X fd = -1; X if ( !strcmp(local, "-") ) X fd = 1; X X /* get some info on the remote file. We need to know the file */ X /* size at the very least. */ X remote_size = 0; X if (fd != 1 && remote_term_version >= 20164 && stat(local, &st) == 0) X i=send_command(term, C_STAT, 0, "\n%ld\n%s", st.st_size, file); X else X i=send_command(term, C_STAT, 0, "%s", file); X X rmtime = 0; fullperms = 0; rcksum = 0; X if (i >= 0) { X gettime(&nowtime); X if (sscanf(command_result,"%ld %d %*d %*d %ld %o %u", X &remote_size, &type, &rmtime, &fullperms, &rcksum) < 2) { X fprintf(stderr, "\tSkipped : can't stat %s: %s\n", file, X command_result); X j=1; X continue; X } X if (type != 0) { X fprintf(stderr, "\tSkipped : %s is not a regular file\n", file); X j=1; X continue; X } X }else { X fprintf(stderr, "\tSkipped : can't open remote file\n"); X j=1; X continue; X } X X /* see if the file exists to be resumed (but don't resume to stdout, X even if it's pointing to a file). */ X local_size = 0; X if (fd != 1) { X if (stat(local, &st) == 0) { X local_size = st.st_size; X /* Local file has been changed since last download. Warn */ X if (download_force && remote_term_version < 20164) { X local_size = 0; X }else { X if (rmtime && (rmtime+nowtime.tv_sec > st.st_mtime)) { X if (download_force) { X local_size = 0; X }else { X fprintf(stderr,"\tSkipping, the remote file has been modified\n"); X j = 1; X continue; X } X } X if ((local_size || ! download_force) && (st.st_mode & 0333)) { X if (download_force) { X local_size = (local_size != remote_size) ? 0 : local_size; X }else { X fprintf(stderr, "\tSkipping, local file has write/exec permission\n"); X j=1; X continue; X } X } X else if ((local_size || ! download_force) && chmod(local, 0600)) { X if (download_force) { X local_size = 0; X }else { X fprintf(stderr, "\tSkipping, can't change file mode to 0600\n"); X j=1; X continue; X } X } X /* Ok. The local file exists. lets check a few things here.. */ X X /* local file is larger than remote file. Skip this.*/ X if (local_size && local_size > remote_size) { X if (download_force) { X local_size = 0; X }else { X fprintf(stderr,"\tSkipping, local file is larger than remote\n"); X j=1; X continue; X } X } X X /* remote file is same size. Skip it. */ X if ((local_size || ! download_force) && local_size == remote_size) { X if (! download_force) X fprintf(stderr,"\tLocal file is same size as remote"); X if (remote_term_version >= 20164 && i >= 0) { X fullperms = 0; rcksum = 0; X sscanf(command_result,"%*d %*d %*d %ld %ld %o %u", X &atime, &mtime, &perms, &rcksum); X if (rcksum) { X lcksum = file_crc(local, (long)st.st_size); X if (lcksum) { X if (lcksum==rcksum) { X long now; X now = time(NULL); X if(download_force && verbose > 1) X fprintf(stderr,"\tSame size local and remote file"); X if(verbose > 1 || ! download_force) X fprintf(stderr, ", checksums do match, setting mode"); X utb.actime = atime + now; X utb.modtime = mtime + now; X if(verbose > 1 || ! download_force) { X if (utime(local, &utb)) X fprintf(stderr, " (time failed)"); X if (perms != -1 && chmod(local, perms)) X fprintf(stderr, " (perms failed)"); X fprintf(stderr,"\n"); X } X if (! download_force) j=1; X continue; X }else if(download_force) { X local_size = 0; X }else { X fprintf(stderr, ", checksums do not match, skipping"); X } X } X }else if (download_force) { X local_size = 0; X }else if (! download_force) { X fprintf(stderr, ", skipping"); X } X }else if (download_force) { X local_size = 0; X }else if (! download_force) { X fprintf(stderr, ", skipping"); X } X if (! download_force) { X fprintf(stderr, "\n"); X j=1; X continue; X } X } X X /* Local file is smaller than remote. Perform additional checks */ X if (local_size && (remote_term_version >= 20164) && i >= 0) { X if (rcksum) { X /* Local is a different shorter file. Skip */ X lcksum = file_crc(local, local_size); X if ((lcksum) && (rcksum!=lcksum)) { X if (download_force) { X local_size = 0; X }else { X fprintf(stderr, "\tSkipping, local file differs from beginning of remote\n"); X j=1; X continue; X } X } X } X } X if (local_size || ! download_force ) { X fprintf(stderr, "\tAttempting to restart download from %ld\n", X local_size); X } X } X } X X if (local_size == 0) { X if (download_force) { X /* Try to make sure we can download to the file. If we can */ X /* chmod it, we are certain to succeed. If not, perhaps we have */ X /* write access as group or other; try to truncate. If that */ X /* fails too, unlink it, and hope we can create a new file below. */ X if (chmod(local, 0666) < 0) { X if ((fd = open(local, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0) { X (void) unlink(local); X fd = open(local, O_WRONLY|O_CREAT|O_TRUNC, 0666); X } X }else { X fd = open(local, O_WRONLY|O_CREAT|O_TRUNC, 0666); X } X }else { X fd = open(local, O_WRONLY|O_CREAT|O_TRUNC, 0666); X } X }else { X fd = open(local, O_WRONLY|O_APPEND, 0666); X } X chmod(local, 0444); X } X X if (send_command(term, C_DOWNLOAD, 0, "%ld\n%s", local_size, file) < 0) { X fprintf(stderr,"\tSkipped : Couldn't open remote file, %s\n", X command_result); X j=1; X continue; X }else { X long now; X now = time(NULL); X atime = mtime = 0; X perms = -1; X if (sscanf(command_result, "%*d %d %*d %ld %ld %o", X &type, &atime, &mtime, &perms) < 2) { X fprintf(stderr, "\tSkipped : can't stat %s: %s\n", file, X command_result); X j=1; X send_command(term, C_CLOSE, 0, 0); X continue; X } X atime += (long)now; X mtime += (long)now; X } X X /* receive the file over the socket. */ X if (verbose > 1) { X gettime(&starttime); X lasttime = starttime; X } X bytesrecvd = 0; X cps_count = 0; X for (i = 0; i < CPS_WINDOW; ++i) { X recent_cpsbytes[i] = 0; X recent_etime[i] = 0; X } X filesent++; X if (verbose > 2) { X if (remote_size) X fprintf(stderr, "\r\t%ld of %ld (0%%) ", local_size, remote_size); X else X fprintf(stderr, "\r\t%ld ", local_size); X } X do { X read_size = bufsiz; X if (verbose > 2 && (local_size%bufsiz)) /* after restarting download */ X read_size = bufsiz - (local_size%bufsiz); X if (read_size > remote_size-local_size) /* at end of file */ X read_size = remote_size-local_size; X if (buffer.size < read_size) { X ret = (long)(read_into_buff(term, &buffer, read_size-buffer.size)); X if (ret < 0) break; X if (ret > 0 && buffer.size < read_size) continue; X } X if (buffer.size == 0) X break; X else { X ret = (long) write_from_buff(fd, &buffer, 0); X if (ret <= 0 && termerrno) { X fprintf(stderr, "\tError writing to file. Aborting..\n"); X break; X } X X bytesrecvd += ret; X total_bytesrecvd += ret; X local_size += ret; X } X X if ( (verbose > 2)) { X X /* Each CPS value is placed in a X CPS_WINDOW-sized buffer and the average of the buffer is X used as the CPS value. */ X X gettime(&nowtime); X etime = download_delta_timeval(&nowtime, &lasttime); X X lasttime = nowtime; X recent_cpsbytes[cps_count] = ret; X recent_etime[cps_count] = etime; X if (++cps_count >= CPS_WINDOW) X cps_count = 0; X for (i = 0, cps = 0, etime = 0; i < CPS_WINDOW; ++i) { X cps += recent_cpsbytes[i]; X etime += recent_etime[i]; X } X if (etime > 0) X cps /= etime; X else X cps = 0; X X /* Adjust bufsiz so we see about one report per second */ X while (bufsiz < cps/2 && local_size%(2*bufsiz) == 0) X bufsiz *= 2; X while (bufsiz > cps*2) X bufsiz /= 2; X X if (remote_size) { X long perc; X X perc = (local_size*100) / remote_size; X if (cps) X fprintf(stderr, "\r\t%ld of %ld (%ld%%), current CPS %.0f. ETA: %.1f TT: %.1f ", X local_size, remote_size, perc, X cps, (remote_size-local_size)/cps, X remote_size/cps); X else X fprintf(stderr, "\r\t%ld of %ld (%ld%%) ", X local_size, remote_size, perc); X } X else { X if (cps) X fprintf(stderr, "\r\t%ld, current CPS %.0f. ", local_size, cps ); X else X fprintf(stderr, "\r\t%ld ", local_size); X } X } X } while (local_size < remote_size); X X /* Reopen the term connection */ X if (term >= 0) X close(term); X if ((term = socket_connect_server(-1, term_server)) < 0) { X fprintf(stderr,"Term: %s\n", command_result); X exit(1); X } X X /* give them cps ratings */ X if (verbose > 1) { X gettime(&nowtime); X etime = download_delta_timeval(&nowtime, &starttime); X if (etime == 0) X etime = 0.1; X fprintf(stderr, "\r\t%ld bytes received in %.1f seconds;" X " CPS = %.0f ", X bytesrecvd, etime, bytesrecvd/etime ); X total_etime += etime; X } X X /* check the local file after send */ X if (fd == 1) { X if (bytesrecvd == remote_size) { X if (download_unlinkmode) X remote_unlink = file; X } else { X fprintf(stderr, X "\n\tCount of bytes received is different from initial remote size!\n"); X j=1; X } X } X else { X int err = 0; X close(fd); X fd = -1; X if (stat(local, &st)) { X fprintf(stderr, "\n\tCan't stat local file after download!\n"); X err=j=1; X } X if (st.st_size != remote_size) { X fprintf(stderr, "\n\tLocal file is a different size from initial " X "remote size!\n"); X err=j=1; X } X utb.actime = atime; X utb.modtime = mtime; X if (utime(local, &utb)) { X fprintf(stderr, "\n\tCan't set correct times on file after download!\n"); X err=j=1; X } X if (perms != -1 && chmod(local, perms)) { X fprintf(stderr, "\n\tCan't set permission on file after download!\n"); X err=j=1; X } X X if (remote_term_version>=20164) { X i = send_command(term, C_STAT, 0, "\n%ld\n%s", remote_size, file); X fprintf(stderr, "CRC "); X if (i >= 0) { X rcksum = 0; X sscanf(command_result,"%*d %*d %*d %*d %*d %*o %u", &rcksum); X if (rcksum) { X lcksum = file_crc(local, (long)st.st_size); SHAR_EOF : || echo 'restore of term-2.2.5/download.c failed' fi echo 'End of archive part 4' echo 'File term-2.2.5/download.c is continued in part 5' echo 5 > _sharseq.tmp exit 0