v01i004: xtclient: use a 3b1 as a layers terminal, Part01/04

Merlin J Mathesius merlinm at i88.isc.com
Fri Feb 15 13:09:51 AEST 1991


Submitted-by: merlinm at i88.isc.com (Merlin J Mathesius)
Posting-number: Volume 1, Issue 4
Archive-name: xtclient/part01

---- Cut Here and feed the following to sh ----
#!/bin/sh
# This is xtclient, a shell archive (shar 3.44)
# made 01/26/1991 20:35 UTC by merlinm at justus
# Source directory /u/merlinm/src/xtclient
#
# existing files will NOT be overwritten unless -c is specified
#
# This shar contains:
# length  mode       name
# ------ ---------- ------------------------------------------
#   4214 -rw-r--r-- README
#   3410 -rw-r--r-- xtclient.1
#   3937 -rw-r--r-- mgrxtclient.1
#   1879 -rw-r--r-- xtclient/Makefile
#  10705 -rw-r--r-- xtclient/appl.c
#    284 -rw-r--r-- xtclient/appl.h
#    671 -rw-r--r-- xtclient/command.h
#  10936 -rw-r--r-- xtclient/datalink.c
#   2043 -rw-r--r-- xtclient/datalink.h
#  14169 -rw-r--r-- xtclient/dlutil.c
#   3437 -rw-r--r-- xtclient/dumplog.c
#   2260 -rw-r--r-- xtclient/frame.h
#  22004 -rw-r--r-- xtclient/mgrwindow.c
#   2168 -rw-r--r-- xtclient/network.c
#    197 -rw-r--r-- xtclient/network.h
#  10054 -rw-r--r-- xtclient/phone.c
#    208 -rw-r--r-- xtclient/phone.h
#   9682 -rw-r--r-- xtclient/phys.c
#    190 -rw-r--r-- xtclient/phys.h
#    755 -rw-r--r-- xtclient/select.h
#  13449 -rw-r--r-- xtclient/session.c
#    239 -rw-r--r-- xtclient/session.h
#  19471 -rw-r--r-- xtclient/window.c
#    536 -rw-r--r-- xtclient/window.h
#   6728 -rw-r--r-- xtclient/xtclient.c
#    304 -rw-r--r-- xtclient/xtclient.h
#    118 -rw-r--r-- pty/Files
#    699 -rwxr-xr-x pty/Install
#    120 -rwxr-xr-x pty/MKflop
#    905 -rwxr-xr-x pty/Makedev
#    570 -rw-r--r-- pty/Makefile
#     24 -rw-r--r-- pty/Name
#   5891 -rw-r--r-- pty/README.3b1
#   1624 -rw-r--r-- pty/READ_ME
#   1042 -rwxr-xr-x pty/Reinstall
#   1065 -rw-r--r-- pty/Remove
#   1055 -rw-r--r-- pty/Remove.orig
#      3 -rw-r--r-- pty/Size
#      4 -rw-r--r-- pty/Version
#   3028 -rw-r--r-- pty/interface.c
#    894 -rw-r--r-- pty/linesw.c
#    176 -rw-r--r-- pty/number-ptys.h
#  11612 -rw-r--r-- pty/pty.c
#   1777 -rw-r--r-- pty/pty.h
#   9262 -rw-r--r-- pty/select.c
#    755 -rw-r--r-- pty/select.h
#    510 -rw-r--r-- pty/sysent.h
#     78 -rw-r--r-- font/Makefile
#  16814 -rw-r--r-- font/xtclient.ft
#
# ============= README ==============
if test -f 'README' -a X"$1" != X"-c"; then
	echo 'x - skipping README (File already exists)'
else
echo 'x - extracting README (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'README' &&
If you would like to use the AT&T 3B1 as a layers terminal, keep
reading!
X
I call this program "xtclient" (since it supports the client side of
the "xt/layers" protocol).  I originally wrote it as a project for a
computer networking class I was taking last winter (I got an "A" for
it!), so please excuse my attempt to model it after the layers in the
ISO network model! :-) The program originally only supported dial-out
communication using the on-board modem and windowing using TAM (ie.,
the 3B1 native windows) but a good friend and co-worker, Brad Bosch,
added support for other serial communication devices, windowing using
MGR, and other miscellaneous bug fixes.  With these enhancements, Brad
also uses "xtclient" on SUNs running MGR to get windows connected to
his 3B1 at home via an external modem.  We have both been using if for
many months under both TAM and MGR, and it works very well.  I even
have testimony from a former co-worker (Hi, Leo!) who has been using
it "almost daily" on his 3B1!
X
Under TAM, "xtclient" allows use of up to 7 normal text windows with
shells, etc. on the remote host.  Under MGR, it emulates up to 7 MGR
data streams with full MGR abilities for graphics, etc.  It does *not*
allow downloading of 5620 or 630 code.
X
Please note that you can't dial *into* a 3B1 using the on-board modem
and run layers (neither using "xtclient" nor a 5620/630 connected to a
modem).  There is something in the "xt" device driver that prevents
this from working on a /dev/ph* line, but a /dev/tty* device (with an
Xexternal modem) works fine.  If somebody finds a fix for this, please
let me know!
X
"xtclient" uses the select() system call which is included in the pty
driver that MGR uses.  If you don't have MGR, the pty driver must be
loaded.  There are even man pages provided for both versions!
X
All standard disclaimers and lack of warranties apply, but please let
me know of any problems that you may encounter...  If you make any
interesting enhancements, I would like to know about those too!
X
Enjoy.
X
Merlin J Mathesius
Internet: merlinm at i88.isc.com
UUCP: ...!laidbak!merlinm
X
================================================================
To compile "xtclient" for use under TAM:
X
X  1. Type "make" in each of the directories "pty" and "font".
X  2. Decide where you want to place the font for xtclient and put it
X     there!  The source is configured to find the font in
X     "/usr/local/lib/xtclient.f".  The file to copy is "font/xtclient.f"
X  3. If you chose someplace other than "/usr/local/lib/xtclient.f" to
X     put the font file in step 2, edit the #define for "DEFAULT_FONT" in
X     file "xtclient/window.c" (currently at line 44) and provide the
X     full path name to wherever you placed it.
X  4. Type "make xtclient" in the directory "xtclient" (you may want to
X     remove the -DEBUG flag from the Makefile).  The executable file is
X     called "xtclient".
X  5. Install "xtclient" in whatever directory you wish.
X  6. Install the "pty" (ie., pseudo tty) device driver.  See the files
X     in the directory "pty"...  This is needed for the "select()" system
X     call that it provides.  NOTE: If you have MGR installed and working
X     on your machine, you already have this driver installed.
X  7. Read the "xtclient" man page.
X  8. Use it!
X
To compile "xtclient" for use under MGR:
X
X  1. Edit "xtclient/Makefile" to make sure the paths to the MGR
X     include files and library are correct.
X  2. Type "make mgrxtclient" in the directory "xtclient" (you may want to
X     remove the -DEBUG flag from the Makefile).  The executable file is
X     called "mgrxtclient".  NOTE:  There may be a loader warning about
X     symbol "menu" being redefined.
X  3. Install "mgrxtclient" in whatever directory you wish.
X  4. Read the "mgrxtclient" man page.
X  5. Use it!
X
================================================================
X
There is also a program called "dumplog" included in the directory
"xtclient".  It was used during the countless hours of development and
debugging to dump the "xt/layers" protocol packets in a readable
format.  If you encounter protocol problems with your machine or wish
to add some sort of enhancements to "xtclient", you will wish to use
it!
SHAR_EOF
chmod 0644 README ||
echo 'restore of README failed'
Wc_c="`wc -c < 'README'`"
test 4214 -eq "$Wc_c" ||
	echo 'README: original size 4214, current size' "$Wc_c"
fi
# ============= xtclient.1 ==============
if test -f 'xtclient.1' -a X"$1" != X"-c"; then
	echo 'x - skipping xtclient.1 (File already exists)'
else
echo 'x - extracting xtclient.1 (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'xtclient.1' &&
.po +4
.TH XTCLIENT 1
.SH NAME
xtclient - multiplexed terminal emulator
.SH SYNOPSIS
.B xtclient
[ -x ] [ -l <line> ] [ -s <speed> ] phone-number
.SH DESCRIPTION
.I Xtclient
is a client end of the "xt/layers" system for the AT&T 3B1 Personal Computer.
.sp
When invoked, a single window is opened at a
default location and a telephone connection
is established to a remote computer using the
device, baud rate, and telephone number specified.  
The default line is /dev/ph0 (ie., the built in modem on line 1)
at the default speed of 1200 baud.
The user is informed when a data path has been established,
a full-duplex connection is established,
and the program will function as a standard (single window) terminal emulator.
If the remote computer has the "xt/layers" package, however,
the "layers" command may be invoked on the host and multiplexed mode
will be entered.
Additional windows (up to a total of 7) may be opened by clicking the
RIGHT button of the mouse while the mouse pointer is inside the currently
active window.
.sp
When in multiplexed mode, the 3B1 will emulate an AT&T 630 MTG terminal
(accepting ANSI X.64 escape sequences),
and full screen visual editors such as
.I vi
and
.I "GNU emacs"
can be successfully used.
.sp 
While multiplexed, the LEFT button of the mouse
will select a window to bring it to the top of
the screen and make it active by clicking anywhere
within the window or its border.
'\"
XSelecting the RESIZE icon
(in the lower right corner of a window border)
with the left mouse button
can be used to shape the window to the desired size.
'\"
XSelecting the MOVE icon
(in the upper left corner of a window border)
may be used to move the window to another location on the screen.
'\"
XSelecting the CLOSE icon
(in the lower left corner of a window border)
will close the window and terminate the host process associated with
this window.
Please note that the primary window does not have a CLOSE icon and can
not be deleted.
'\"
Keyboard input is only accepted in the currently active (ie., highlighted)
window, although output may occur to any window at any time.
.sp
To exit the multiplexed window protocol,
the "Shift-EXIT" key must be depressed,
and non-multiplexed communication will resume.
When non-multiplexed, the "Shift-EXIT" key
will cause
.I xtclient
to terminate and hang
up the phone connection.
.sp
If the
.I -x
argument is specified on the command line,
.I xtclient
will generate log files of all data sent and received over the telephone
connection.  This is a byte-for-byte dump of the data (including protocol
headers, escape sequences, and the likes) and is of little use except for
debugging.  The input and output log files are ".input_log" and ".output_log"
in the current directory.
.SH EXAMPLES
Establish a connection with a remote computer
.sp
X	xtclient 5552935
.SH SEE ALSO
cu(1), layers(1).
.SH DIAGNOSTICS
There are currently several messages of a debugging and informational nature 
written to standard error (which is normally directed to the primary window).
.SH WARNINGS
Although quite functional,
.I xtclient
is not guaranteed to be exceptionally robust or efficient.
.sp
The telephone line must be configured for DATA mode before invoking
.I xtclient.
No diagnostics are reported if it is configured for VOICE,
but it just won't work at all!
.SH AUTHORS
Merlin J. Mathesius - merlinm at i88.isc.com
.br
Brad Bosch          - brad at i88.isc.com
SHAR_EOF
chmod 0644 xtclient.1 ||
echo 'restore of xtclient.1 failed'
Wc_c="`wc -c < 'xtclient.1'`"
test 3410 -eq "$Wc_c" ||
	echo 'xtclient.1: original size 3410, current size' "$Wc_c"
fi
# ============= mgrxtclient.1 ==============
if test -f 'mgrxtclient.1' -a X"$1" != X"-c"; then
	echo 'x - skipping mgrxtclient.1 (File already exists)'
else
echo 'x - extracting mgrxtclient.1 (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'mgrxtclient.1' &&
.po +4
.TH MGRXTCLIENT 1
.SH NAME
mgrxtclient - multiplexed terminal emulator
.SH SYNOPSIS
.B mgrxtclient
[ -x ] [ -l <line> ] [ -s <speed> ] phone-number
.SH DESCRIPTION
.I Mgrxtclient
is a client end of the "xt/layers" system for the AT&T 3B1 Personal
Computer under the MGR window manager.
.sp
When invoked, the originating window is changed to an icon of a terminal
and a second window with the same size and font as the originating window
is opened at a
default location and a telephone connection
is established to a remote computer using the
device, baud rate, and telephone number specified.  
The default line is /dev/ph0 (ie., the built in modem on line 1)
at the default speed of 1200 baud.
The user is informed when a data path has been established,
a full-duplex connection is established,
and the program will function as a standard (single window) terminal emulator.
If the remote computer has the "xt/layers" package, however,
the "layers" command may be invoked on the host and multiplexed mode
will be entered.
Additional windows (up to a total of 7) may be opened by selecting the
icon window and using the MIDDLE button of the mouse to select the
"create window" menu entry.  The "c" key may be typed into the icon window as
an alternative to the "create window" menu entry.  New windows created this
way have the same size and font as the initial window.
.sp
When in multiplexed mode, each window is a full MGR data stream and any MGR
application may be run in each window.
.sp
XSelecting the "send break" item from the icon window
menu or typing "b" to this window will send a break signal if possible to the
remote host.
.sp 
Each window may also be manipulated with the mouse via the normal MGR mouse
operations.  Window resize events are not reported to the remote layers
process.  New windows are reported as size 0 X 0 when created.  Use the normal
MGR methods to communicate the window size to the remote OS and applications.
.sp
Keyboard input is only accepted in the currently active (ie., highlighted)
window, although output may occur to any window at any time.  MGR internaly 
generated input is also accepted in any window and will be transmitted to
the appropriate remote data stream.
.sp
To exit the multiplexed window protocol,
use the MIDDLE mouse button with the the icon window's menu to select
the "quit" option.
When the host agrees, non-multiplexed communication will resume.
When non-multiplexed, the "quit" option of the icon window's menu
will cause
.I mgrxtclient
to terminate and hang
up the phone connection.
The "q" key may be typed into the icon window as a short hand for the "quit"
menu item.
.sp
If the
.I -x
argument is specified on the command line,
.I mgrxtclient
will generate log files of all data sent and received over the telephone
connection.  This is a byte-for-byte dump of the data (including protocol
headers, escape sequences, and the likes) and is of little use except for
debugging.  The input and output log files are ".input_log" and ".output_log"
in the current directory.
.sp
If the phone-number is the null string (""), no number is dialed.  This should
allow you to dial by hand with external modems when required.
.SH EXAMPLES
Establish a connection with a remote computer
.sp
X	mgrxtclient 5552935
.SH SEE ALSO
cu(1), layers(1).
.SH DIAGNOSTICS
There are currently several messages of a debugging and informational nature 
written to standard error (which is normally directed to the primary window).
.SH WARNINGS
Although quite functional,
.I mgrxtclient
is not guaranteed to be exceptionally robust or efficient.
.sp
The telephone line must be configured for DATA mode before invoking
.I mgrxtclient.
No diagnostics are reported if it is configured for VOICE,
but it just won't work at all!
.SH AUTHORS
Merlin J. Mathesius - merlinm at i88.isc.com
.br
Brad Bosch          - brad at i88.isc.com
------------------------------Cut here------------------------------
X
X
SHAR_EOF
chmod 0644 mgrxtclient.1 ||
echo 'restore of mgrxtclient.1 failed'
Wc_c="`wc -c < 'mgrxtclient.1'`"
test 3937 -eq "$Wc_c" ||
	echo 'mgrxtclient.1: original size 3937, current size' "$Wc_c"
fi
# ============= xtclient/Makefile ==============
if test ! -d 'xtclient'; then
    echo 'x - creating directory xtclient'
    mkdir 'xtclient'
fi
if test -f 'xtclient/Makefile' -a X"$1" != X"-c"; then
	echo 'x - skipping xtclient/Makefile (File already exists)'
else
echo 'x - extracting xtclient/Makefile (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'xtclient/Makefile' &&
# this section for sun
#CFLAGS=-g -DEBUG -I. -I/u/brad/src/mgr.os4/lib
#LIBMGR= -L/u/brad/src/mgr.os4/lib -lmgr
#CC=/usr/5bin/cc
# end sun section
# this section for 3b1
CFLAGS=-g -DEBUG -I. -I/usr/local/mgr/include
LIBMGR=/lib/crt0s.o /lib/shlib.ifile /usr/local/mgr/lib/libmgr.a
LIBTAM=/lib/crt0s.o /lib/shlib.ifile
# end 3b1 section
OBJS=xtclient.o phone.o phys.o datalink.o dlutil.o network.o \
X	session.o appl.o
XSRCS=xtclient.c phone.c phys.c datalink.c dlutil.c network.c \
X	session.c appl.c window.c mgrwindow.c
HDRS=xtclient.h phone.h phys.h datalink.h network.h session.h \
X	appl.h window.h command.h frame.h
MISC=Makefile dumplog.c
X
default: mgrxtclient xtclient
X
xtclient: $(OBJS) window.o
X	$(LD) -o xtclient $(OBJS) window.o $(LIBTAM)
X
mgrxtclient: $(OBJS) mgrwindow.o
X	$(LD) -o mgrxtclient $(OBJS) mgrwindow.o $(LIBMGR)
X
lint:
X	sh -c "lint -DEBUG -I. $(SRCS)" > lint.out
X
dumplog: dumplog.o
X	$(LD) -o dumplog dumplog.o $(LIBTAM)
X
dumplog.o: frame.h
X
phone.o: phone.c phone.h
phys.o: phys.c phys.h
phys.o: xtclient.h datalink.h frame.h phone.h
datalink.o: datalink.c datalink.h
datalink.o: frame.h
dlutil.o: dlutil.c
dlutil.o: datalink.h frame.h phone.h window.h appl.h session.h xtclient.h
network.o: network.c network.h
network.o: frame.h session.h
session.o: session.c session.h
session.o: appl.h command.h xtclient.h
appl.o: appl.c appl.h
appl.o: window.h xtclient.h command.h
window.o: window.c window.h
window.o: xtclient.h appl.h command.h
mgrwindow.o: window.c window.h
mgrwindow.o: xtclient.h appl.h command.h
xtclient.o: xtclient.c xtclient.h
xtclient.o: phone.h phys.h datalink.h network.h session.h appl.h window.h
X
backup:
X	ls $(SRCS) $(HDRS) $(MISC) | cpio -oBcv > /dev/rfp021
X
archive:
X	ls $(SRCS) $(HDRS) $(MISC) | cpio -ocv > /tmp/xt.cpio
X
shar:
X	shar -n xtclient -a -c -o /tmp/xt -l 50 $(SRCS) $(HDRS) $(MISC)
X
list:
X	@echo Makefile $(HDRS) $(SRCS)
SHAR_EOF
chmod 0644 xtclient/Makefile ||
echo 'restore of xtclient/Makefile failed'
Wc_c="`wc -c < 'xtclient/Makefile'`"
test 1879 -eq "$Wc_c" ||
	echo 'xtclient/Makefile: original size 1879, current size' "$Wc_c"
fi
# ============= xtclient/appl.c ==============
if test -f 'xtclient/appl.c' -a X"$1" != X"-c"; then
	echo 'x - skipping xtclient/appl.c (File already exists)'
else
echo 'x - extracting xtclient/appl.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'xtclient/appl.c' &&
/*
X * File name:	appl.c
X *
X * Description:	The application layer for the "xt/layers" client system
X *		for the UNIX-PC
X *
X *		This layer is responsible for interfacing with the windowing
X *		system.  The interface is kept as generic as possible to allow
X *		porting the system to use other windowing packages.
X *
X *		This layer is used in both multiplexed and unmultiplexed
X *		modes of operation, so it is initialized once when the client
X *		process is started, and when it is terminated the process is
X *		also terminated.
X *
X * Author:	Merlin J. Mathesius
X *
X * Contents:	APinit()	initialize the application layer
X *		APterm()	terminate the application layer
X *		APreq()		reqest for data from the application layer
X *		APind()		indication there is data for the appl layer
X *		APmpx()		indication that multiplexed mode is starting
X *		APunmpx()	indication that multiplexed mode is complete
X *		APinform()	indication that user has executed a control cmd
X *		APexec()	host request to execute a remote command
X *
X * Data:	APreply_cnt	indicator that reply is to be returned
X */
X
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <memory.h>
X
#include "appl.h"
#include "window.h"
#include "xtclient.h"
#include "command.h"
X
#define ESC '\033'
X
typedef struct {
X	/* counter and buffer to capture escape sequences */
X	int	esc_cnt;
X	char	esc_buf[80];
} W_Info;
X
/* buffer to intercept escape codes */
static W_Info w_info;
X
/* provides for one outstanding reply to host from application layer */
static char reply_buf[32];	/* buffer with a reply to send back */
static int  reply_addr;		/* address providing the reply */
X
/* count of characters in reply - this is global so "Wait()" can check it */
int APreply_cnt;
X
/*
X * Function name:	APinit()
X *
X * Description:		Initialize the application layer.
X *
X * Parameters:		None
X *
X * Return values:	None
X */
void
APinit()
{
X	int	i;
X
X	/* initialize our windowing system */
X	Winit();
X
X	/* initialize the escape character count */
X	w_info.esc_cnt = 0;
X
X	/* no pending reply */
X	APreply_cnt = 0;
}
X
/*
X * Function name:	APterm()
X *
X * Description:		Terminate the application layer.  Windowing system
X *			is also terminated.
X *
X * Parameters:		None
X *
X * Return values:	Never returns!!!
X */
void
APterm()
{
X	/* shutdown the window system -- this will exit and never return */
X	Wshutdown();
}
X
/*
X * Function name:	APreq(addr, data, size)
X *
X * Description:		A request has been made from "below" to return any
X *			available data from the application layer.  The number
X *			of bytes and window providing the data is also
X *			returned.
X *
X *			If there is some sort of "reply" queued up it
X *			will be returned, otherwise the windowing routines
X *			will be called to try for some keyboard input.
X *
X * Parameters:		addr	pointer to location to return window number
X *			data	pointer to data buffer
X *			size	maximum number of bytes of data to return
X *
X * Return values:	0	no data available
X *			else	number of bytes of data actually returned
X */
int
APreq(addr, data, size)
int	*addr;	/* returned channel (ie., window number) with data */
char	*data;	/* data buffer in which to placed returned data */
int	size;	/* maximum number of bytes of data to be returned */
{
X	/* if there is a reply queued up, send it back */
X	if (APreply_cnt)
X	{
X		*addr = reply_addr;
X		/* Incoming "size" is NOT checked, it is assumed to fit! */
X		size = APreply_cnt;
X		(void)memcpy(data, reply_buf, size);
X		/* clear the reply indicator */
X		APreply_cnt = 0;
X		return(size);
X	}
X
X	/* pass request for data to windowing interface function */
X	return(Winput(addr, data, size));
}
X
/*
X * Function name:	APind(addr, data, size)
X *
X * Description:		A indication has been made from "below" that
X *			there is data for the application layer.
X *
X *			This function must capture (and process) ANSI escape
X *			sequences to complete the host/client information
X *			exchange that occurs during "xt/layers" startup. 
X *			Unwanted sequences are passed on to the windowing
X *			output routines.
X *
X * Parameters:		addr	window to which data should be written.
X *				If -1, write to window 1.
X *			data	pointer to data buffer
X *			size	number of bytes of data to send.
X *				If -1, assume that "data" is a null terminated
X *				string and compute the size.
X *
X * Return values:	-1	error
X *			0	success
X */
int
APind(addr, data, size)
int	addr;	/* channel (ie., window number) to receive data */
char	*data;	/* data to be output */
int	size;	/* number of bytes of data available */
{
X	register W_Info *w;	/* pointer to window information */
X	register char *dp;	/* pointer to next data character */
X	register int bufcnt;	/* count of characters in output buffer */
X	register int i;		/* loop index */
X	register int j;		/* secondary loop index */
X	enum {
X		KeepGoing,	/* keep capturing chars in escape sequence */
X		PassItOn,	/* pass this sequence on to window */
X		Process		/* this sequence is for us, process it! */
X	} esc_opr;
X	char buf[128];		/* output buffer */
X
X	/* if size is -1, we have a NULL terminated string so find length */
X	if (size == -1)
X		size = strlen(data);
X
X
X	if (addr < 1 || addr > MAXW)
X		/* invalid address */
X		return(-1);
X
X	w = &w_info;
X
X	/* initialize count of buffered characters and pointer to data buf */
X	bufcnt = 0;
X	dp = data;
X	/* loop through all data characters */
X	for (i = size; i > 0; i--, dp++)
X	{
X		/* if we are in the middle of capturing an escape sequence... */
X		if (w->esc_cnt > 0)
X		{
X			/* capture this char */
X			w->esc_buf[w->esc_cnt++] = *dp;
X
X			if (w->esc_cnt == 2)
X			{
X				if(*dp == '[')
X					/* start of multi-char escape seq */
X					esc_opr = KeepGoing;
X				else
X					/* end of a 2-char escape seq, */
X					/* we don't want this, give it back */
X					esc_opr = PassItOn;
X			}
X			/* is this the end of a many-char escape seq? */
X			else if(isalpha(*dp) || *dp == '|' || *dp == '@')
X			{
X				switch (*dp)
X				{
X				case 'c':
X				case 'F':
X				case 'v':
X					/* we want this one! */
X					esc_opr = Process;
X					break;
X				default:
X					/* we don't want this, give it back */
X					esc_opr = PassItOn;
X					break;
X				}
X			}
X			else
X			{
X				/* in middle of many-char escape seq */
X				esc_opr = KeepGoing;
X			}
X
X			switch (esc_opr)
X			{
X			case KeepGoing:
X				/* nothing to do */
X				break;
X
X			case Process:
X				if (bufcnt > 0)
X				{
X					/* flush the output buffer */
X					(void)Woutput(addr, buf, bufcnt);
X					bufcnt = 0;
X				}
X				/* now, process our code */
X				switch (*dp)
X				{
X				case 'c':
X					/* reply with a ROM version number */
#ifdef EBUG
X	if (APreply_cnt != 0)
X		(void)fprintf(stderr, "APind: a reply has been lost\n");
#endif
X					(void)strcpy(reply_buf, "\033[?8;7;5c");
X					APreply_cnt = strlen(reply_buf);
X					reply_addr = addr;
X					break;
X				case 'F':
X					/* reply that "encoding" is off */
#ifdef EBUG
X	if (APreply_cnt != 0)
X		(void)fprintf(stderr, "APind: a reply has been lost\n");
#endif
X					(void)strcpy(reply_buf, "\033[0F");
X					APreply_cnt = strlen(reply_buf);
X					reply_addr = addr;
X					break;
X				case 'v':
X					/* should we enter mpx mode? */
X					if (w->esc_buf[2] == '2')
X						mpx_flag = 1;
X					break;
X				}
X				/* reset the escape counter */
X				w->esc_cnt = 0;
X				break;
X
X			case PassItOn:
X			default:	/* don't know what happened... */
X
X				/* place contents of the escape buffer in */
X				/* the output buffer */
X				for (j = 0; j < w->esc_cnt; j++)
X					buf[bufcnt++] = w->esc_buf[j];
X				w->esc_cnt = 0;
X				break;
X			}
X		}
X		/* this is the start of an escape sequence */
X		else if (*dp == ESC && !mpx_flag)
X		{
X			w->esc_buf[w->esc_cnt++] = *dp;
X		}
X		/* this is just another character to send to the output */
X		else
X		{
X			buf[bufcnt++] = *dp;
X		}
X		
X	}
X
X	/* nothing in buffer, return successfully */
X	if (bufcnt == 0)
X		return(0);
X
X	/* send data to window */
X	return(Woutput(addr, buf, bufcnt) < 0 ? -1 : 0);
}
X
/*
X * Function name:	APmpx()
X *
X * Description:		Indication that multiplexed mode is starting.
X *
X * Parameters:		None
X *
X * Return values:	None
X */
void
APmpx()
{
X	/* simply inform windowing system that we are multiplexed */
X	Wmpx();
}
X
/*
X * Function name:	APunmpx()
X *
X * Description:		Indication that multiplexed mode is ending.
X *
X * Parameters:		None
X *
X * Return values:	None
X */
void
APunmpx()
{
X	/* simply inform windowing system that we are unmultiplexed */
X	Wunmpx();
}
X
/*
X * Function name:	APinform()
X *
X * Description:		Called by a window routine to inform us that
X *			user has executed an "xt/layers" control command.
X *
X * Parameters:		command	user command
X *			addr	window on which command was executed
X *			p1	extra parameter when needed
X *			p2	extra parameter when needed
X *			p3	extra parameter when needed
X *			p4	extra parameter when needed
X *
X * Return values:	0	command accepted
X *			-1	error
X */
int
APinform(command, addr, p1, p2, p3, p4)
XXtCommand	command;	/* user command */
int		addr;		/* address on which command was executed */
long		p1, p2, p3, p4;	/* extra parameters when needed */
{
X	return(SESinform(command, addr, p1, p2, p3, p4));
}
X
/*
X * Function name:	APexec()
X *
X * Description:		Called by session layer to request execution
X *			of a windowing command by the host.
X *
X * Parameters:		command	host command
X *			addr	window on which command is to be executed
X *			p1	extra parameter when needed
X *			p2	extra parameter when needed
X *			p3	extra parameter when needed
X *			p4	extra parameter when needed
X *
X * Return values:	0	command accepted
X *			-1	error
X *			else	address of window created (if XtCreate command)
X */
int
APexec(command, addr, p1, p2, p3, p4)
XXtCommand	command;	/* host command */
int		addr;		/* address on which command is to be executed */
long		p1, p2, p3, p4;	/* extra parameters when needed */
{
X
X	switch (command)
X	{
X	case XtCreate:		/* Create a new window */
X	case XtXcreate:		/* Create a new window, but don't inform host */
X
X		/* create the new window */
X		addr = Wcreate(-1, p1, p2, p3, p4, (command == XtCreate), 1);
X		if (addr < 0)
X			return(-1);
X		
X		return(addr);
X
X	case XtDelete:		/* Delete an existing window */
X		return(Wdestroy(addr));
X
X	case XtReshape:		/* Reshape an existing window */
X		return(Wshape(addr, p1, p2, p3, p4));
X
X	case XtCurrent:		/* Select current input window */
X		return(Wselect(addr));
X
X	case XtTop:		/* Pop existing window to top of display */
X		return(Wtop(addr));
X
X	case XtBottom:		/* Push existing window to bottom of display */
X		return(Wbottom(addr));
X
X	case XtMove:		/* Move an existing window to a new location */
X		return(Wshape(addr, p1, p2, -1, -1));
X
X	case XtExit:		/* Exit layers */
X		/* hand this request back to the session layer! */
X		return(SESinform(XtExit, addr, 0L, 0L, 0L, 0L));
X
X	case XtUnknown:		/* Unknown command */
X	default:
X		return(-1);
X	}
}
SHAR_EOF
chmod 0644 xtclient/appl.c ||
echo 'restore of xtclient/appl.c failed'
Wc_c="`wc -c < 'xtclient/appl.c'`"
test 10705 -eq "$Wc_c" ||
	echo 'xtclient/appl.c: original size 10705, current size' "$Wc_c"
fi
# ============= xtclient/appl.h ==============
if test -f 'xtclient/appl.h' -a X"$1" != X"-c"; then
	echo 'x - skipping xtclient/appl.h (File already exists)'
else
echo 'x - extracting xtclient/appl.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'xtclient/appl.h' &&
/*
X * File name:	appl.h
X *
X * Description:	External function and data declarations for appl.c
X *
X * Author:	Merlin J. Mathesius
X */
X
Xextern void	APinit(), APterm();
Xextern int	APreq(), APind();
Xextern void	APmpx(), APunmpx();
Xextern int	APinform(), APexec();
X
Xextern int	APreply_cnt;
SHAR_EOF
chmod 0644 xtclient/appl.h ||
echo 'restore of xtclient/appl.h failed'
Wc_c="`wc -c < 'xtclient/appl.h'`"
test 284 -eq "$Wc_c" ||
	echo 'xtclient/appl.h: original size 284, current size' "$Wc_c"
fi
# ============= xtclient/command.h ==============
if test -f 'xtclient/command.h' -a X"$1" != X"-c"; then
	echo 'x - skipping xtclient/command.h (File already exists)'
else
echo 'x - extracting xtclient/command.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'xtclient/command.h' &&
/*
X * File name:	command.h
X *
X * Description:	Enumeration of user requested "xt/layers" control commands.
X *
X * Author:	Merlin J. Mathesius
X */
X
typedef enum {
X	XtUnknown,	/* Unknown command */
X	XtCreate,	/* Create a new window */
X	XtDelete,	/* Delete an existing window */
X	XtReshape,	/* Reshape an existing window */
X	XtCurrent,	/* Select current input window */
X	XtTop,		/* Pop existing window to top of display */
X	XtBottom,	/* Push existing window to bottom of display */
X	XtMove,		/* Move an existing window to a new location */
X	XtXcreate,	/* Create a new window, but don't inform host */
X	XtExit		/* Exit layers, destroying all but primary window */
} XtCommand;
SHAR_EOF
chmod 0644 xtclient/command.h ||
echo 'restore of xtclient/command.h failed'
Wc_c="`wc -c < 'xtclient/command.h'`"
test 671 -eq "$Wc_c" ||
	echo 'xtclient/command.h: original size 671, current size' "$Wc_c"
fi
# ============= xtclient/datalink.c ==============
if test -f 'xtclient/datalink.c' -a X"$1" != X"-c"; then
	echo 'x - skipping xtclient/datalink.c (File already exists)'
else
echo 'x - extracting xtclient/datalink.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'xtclient/datalink.c' &&
/*
X * File name:	datalink.c
X *
X * Description:	Main routine and interface functions for the data link layer
X *		of the UNIX-PC "xt/layers" system.
X *
X * Author:	Merlin J. Mathesius
X *
X * Contents:	DLinit()	Initialize the data link layer.
X *		DLfromPH()	Retrieve a frame from the physical layer
X *		DLtoPH()	Send a frame to the physical layer
X *		DLfromNET()	Retrieve a packet from the network layer
X *		DLtoNET()	Send a packet from the network layer
X *		DataLinkLayer()	"THE" data link layer control function
X *		CntlFrm()	Process an incoming control frame <local>
X *
X * Data:	DestInfo[]	protcol control information - per destination
X *		o_buffer[]	output frame buffers with acknowledgement info
X *		nbuffered	number of output buffers in use
X */
X
#include <stdio.h>
#include "datalink.h"
X
static void	CntlFrm();
X
/*
X * Function name:	DLinit()
X *
X * Description:		Initialize the data link layer.
X *
X * Parameters:		None
X *
X * Return values:	None
X */
void
DLinit()
{
X	/* all initialization is done upon entering DataLinkLayer() */
}
X
/*
X * Function name:	DLfromPH(f)
X *
X * Description:		Retrieves a frame from the physical layer.
X *
X *			Note:  This function will only return a valid frame
X *			when it is known that a complete frame has arrived
X *			(ie., after a "FrameArrival" event)
X *
X * Parameters:		f	pointer to buffer in which to store frame
X *
X * Return values:	0	returned frame is valid
X *			-1	no frame returned
X */
int
DLfromPH(f)
Frame *f;
{
X	/* call physical layer interface function */
X	return(PHtoDL(f));
}
X
/*
X * Function name:	DLtoPH(f)
X *
X * Description:		Gives a frame to the physical layer.
X *
X * Parameters:		f	pointer to frame to send
X *
X * Return value:	total number of bytes in frame
X */
int
DLtoPH(f)
Frame *f;
{
X	/* call physical layer interface function */
X	return(PHfromDL(f));
}
X
/*
X * Function name:	DLfromNET(p)
X *
X * Description:		Retrieves a packet from the network layer.
X *
X * Parameters:		p	pointer to buffer in which to store packet
X *
X * Return values:	0	packet successfully retreived (with data)
X *			-1	no data, or error
X */
int
DLfromNET(p)
Packet *p;
{
X	/* call network layer interface function */
X	return(NETtoDL(p));
}
X
/*
X * Function name:	DLtoNET(p)
X *
X * Description:		Sends a packet to the network layer.
X *
X * Parameters:		p	pointer to packet to send
X *
X * Return values:	-1	error
X *			0	OK, packet successfully accepted
X */
int
DLtoNET(p)
Packet *p;
{
X	/* call network layer interface function */
X	return(NETfromDL(p));
}
X
/* destination information - one structure per destination */
DestInfo destinfo[MaxAddr+1];
X
/* buffer area for outgoing Frames */
FrmInfo	o_buffer[NumBuf];
int	nbuffered;	    /* how many buffer slots currently in use */
X
/*
X * Function name:	DataLinkLayer()
X *
X * Description:		THE data link layer.
X *
X *			Variation of sliding windows, go back N protocol.
X *			Loosely based upon protocol 5 in "Computer Networks,
X *			2nd edition" by Andrew S. Tanenbaum
X *
X *			This is the main control function for the UNIX-PC
X *			"xt/layers" client system, and does not return until
X *			multiplexed mode is exited and the protocol terminates.
X *
X * Parameters:		None
X *
X * Return values:	None
X */
X
void
DataLinkLayer()
{
X	DestInfo   *Dest;	    /* scratch pointer to destination info */
X	FrmInfo	   *bufp;	    /* pointer to frame info */
X	Frame	   f;		    /* scratch frame variable */
X	Packet	   p;		    /* scratch packet variable */
X	SequenceNr i;		    /* used to index into buffer */
X	EvType	   event;	    /* arriving event */
X	int	   doomsday;	    /* flag to indicate when to quit */
X	int	   rc;		    /* return code storage */
X	int	   j;		    /* loop index */
X
X	/* clear and reset all destination control information */
X	for (j = 0; j <= MaxAddr; j++)
X	{
X		Dest = &destinfo[j];
X		Dest->Addr            = j;
X		Dest->NextFrameToSend = 0;
X		Dest->AckExpected     = 0;
X		Dest->FrameExpected   = 0;
X	}
X
X	/* set indication that all output buffers are empty */
X	/* and with no timeout */
X	nbuffered = 0;
X	for (j = 0; j < NumBuf; j++)
X	{
X		o_buffer[j].frame.mark = 0;
X		o_buffer[j].timeout = 0;
X	}
X
X	/* setup timer data (nothing yet!) */
X	CheckTimers();
X
X	/* enable the network layer */
X	EnableNetworkLayer();
X
X	/* it is not Dooms Day... yet! */
X	doomsday  = 0;
X
X	do {
X		/* wait for some event to occur */
X		event = Wait();
X
X		switch (event)
X		{
X
X		/* the network layer has a packet to send */
X		case NetworkLayerReady:
X
X
X			/* accept the packet from the network layer */
X			rc = FromNetworkLayer(&p);
X			if (rc != 0) break; /* false alarm */
X
X			/* locate buffer to assemble outgoing frame */
X			bufp = FindBuf(-1, 0);
X
#ifdef EBUG
X	/* this event should not occur unless there are */
X	/* available buffers!!!! */
X	if (bufp == NULL)
X	{
X		(void)fprintf(stderr, "FindBuf(), no buffer!\n");
X		break;
X	}
#endif
X
X			/* one more buffered */
X			nbuffered++;
X
X			/* map packet to frame */
X			PktToFrm(&bufp->frame, &p);
X
X			/* chose appropriate destination stream */
X			Dest = &destinfo[bufp->frame.addr];
X
X			/* set sequence number of frame */
X			bufp->frame.seq = Dest->NextFrameToSend;
X
X			/* transmit the frame */
X			SendData(bufp);
X
X			/* expand the senders window */
X			inc(&Dest->NextFrameToSend);
X			break;
X
X		case FrameArrival:
X
X			/* fetch the frame from the physical layer */
X			rc = FromPhysicalLayer(&f);
X			if (rc != 0) break; /* false alarm */
X
X			/* chose appropriate destination stream */
X			Dest = &destinfo[f.addr];
X
X			/* if a control frame... */
X			if (f.ctl)
X			{
X				/* process the control frame */
X				CntlFrm(Dest, &f);
X			}
X			else
X			{
X				/* process the data frame */
X
X				/* frames are accepted only in proper order, */
X				/* out-of-sequence frames are discarded */
X				if (f.seq == Dest->FrameExpected)
X				{
X
X					/* acknowledge the frame's arrival */
X					SendAck((int)f.addr,(SequenceNr)f.seq);
X
X					/* map frame to packet */
X					FrmToPkt(&p, &f);
X
X					/* pass packet to network layer */
X					(void)ToNetworkLayer(&p);
X
X					/* advance receiving window */
X					inc(&Dest->FrameExpected);
X				}
X				/* if we already saw this packet, then the */
X				/* ack got lost.  Ack it again. */
X				else if (between ((Dest->FrameExpected + 6) & 7
X					,f.seq, Dest->FrameExpected))
X				{
X					/* acknowledge the frame's arrival */
X					SendAck((int)f.addr,(SequenceNr)f.seq);
#ifdef EBUG
X					(void)fprintf(stderr,
X					   "datalink: remote lost ACK, stream %d seq %d\n",
X					    (int)f.addr,(SequenceNr)f.seq);
#endif
X				}
X				/* else we must have missed one */
X				else
X				{
X					/* Request previus packets */
X					SendNak((int)f.addr,(SequenceNr)f.seq);
X				}
X			}
X			break;
X
X		case CksumErr:
X
#ifdef EBUG
X	(void)fprintf(stderr, "Checksum error on arriving frame\n");
#endif
X
X			/* ignore bad frames, other end will retransmit */
X			
X			break;
X
X		case TimeOut:
X
#ifdef EBUG
X	(void)fprintf(stderr, "TimeOut on stream %d (%d)\n",
X		      last_timeout->frame.addr, last_timeout->frame.seq);
#endif
X			/* trouble; retransmit all outstanding frames for */
X			/* stream that timed out */
X
X			Dest = &destinfo[last_timeout->frame.addr];
X
X			/* start retransmitting with next expected ACK */
X			i = Dest->AckExpected;
X			while (between(Dest->AckExpected, i, Dest->NextFrameToSend))
X			{
X				/* find the buffered frame to retransmit */
X				bufp = FindBuf(Dest->Addr, i);
#ifdef EBUG
X	if (bufp == NULL)
X	{
X		(void)fprintf(stderr, "TimeOut: can't find outgoing buffer!\n");
X		inc(&i);
X		continue;
X	}
X	else
X	{
X		(void)fprintf(stderr, "Retransmitting addr %d seq %d\n",
X			      bufp->frame.addr, bufp->frame.seq);
X	}
#endif
X
X				/* re-send the frame */
X				SendData(bufp);
X
X				/* increment to the next sequence number */
X				inc(&i);
X			}
X
X			break;
X
X		case DoomsDay:
X
X			/* we have received orders to shut down */
X
X			doomsday = 1;
X
X			break;
X
X		default:
X			/* something we can't handle, ignore */
X			break;
X		}
X
X		/* if we are out of output buffers, disable the network */
X		/* layer.  otherwise, enable it */
X		if (nbuffered < NumBuf)
X			EnableNetworkLayer();
X		else
X			DisableNetworkLayer();
X
X	} while ( !doomsday );
}
X
/*
X * Function name:	CntlFrm(dest, f)
X *
X * Description:		Process a control frame.
X *
X *			It is necessary to examine the data portion of the
X *			frame here since there is only a single control bit
X *			available in the header, and the control command is
X *			stored in the data area.
X *
X * Parameters:		dest	pointer to destination info of stream
X *				receiving this frame
X *			f	pointer to control frame
X *
X * Return values:	None
X */
static void
CntlFrm(dest, f)
DestInfo *dest;	/* pointer to destination info */
Frame	*f;	/* the control frame */
{
X	FrmInfo		*of;	/* scratch pointer to frame info for ACKs */
X	SequenceNr	i;	/* sequence counter */
X
X	enum {		/* enumeration of control frame types */
X		ack,
X		nak,
X		unknown
X	} frame_type;
X
X	/* a control frame with no data is an ACK */
X	if(f->size == 0)
X		frame_type = ack;
X
X	/* look for ASCII ACK character in data section */
X	else if (f->data[0] == '\006')
X		frame_type = ack;
X
X	/* look for ASCII NAK character in data section */
X	else if (f->data[0] == '\025')
X		frame_type = nak;
X
X	/* don't know what we got... */
X	else
X		frame_type = unknown;
X
X	switch (frame_type)
X	{
X	case ack:
X		/* ack "n" implies "n-1", "n-2", etc.; check for this */
X		while (between(dest->AckExpected,
X			       (SequenceNr)f->seq,
X			       dest->NextFrameToSend))
X		{
X			/* find the buffered frame being acknowledged */
X			of = FindBuf(dest->Addr, dest->AckExpected);
X
#ifdef EBUG
X	if (of == NULL)
X	{
X		(void)fprintf(stderr, "CntlFrm, ACK: can't find outgoing buffer!\n");
X
X		/* contract sending window */
X		inc(&dest->AckExpected);
X		continue;
X	}
#endif
X			/* mark this buffer as available! */
X			of->frame.mark = 0;
X
X			/* stop timer for this frame */
X			StopTimer(of);
X
X			/* one less frame buffered */
X			nbuffered--;
X
X			/* contract sending window */
X			inc(&dest->AckExpected);
X		}
X		break;
X
X	case nak:
#ifdef EBUG
X		(void)fprintf(stderr, "CntlFrm: NAK for stream %d\n", dest->Addr);
#endif
X		/* retransmit this and all previously sequenced frames */
X
X		/* first, the previous frames */
X		i = dest->AckExpected;
X		while (between(dest->AckExpected, i, (SequenceNr)f->seq))
X		{
X			/* find the buffered frame to retransmit */
X			of = FindBuf(dest->Addr, i);
#ifdef EBUG
X			if (of == NULL)
X			{
X				(void)fprintf(stderr, "CntlFrm, NAK1: can't find outgoing buffer!\n");
X				/* increment to the next sequence number */
X				inc(&i);
X				continue;
X			}
#endif
X			/* re-send the frame */
X			SendData(of);
X
X			/* increment to the next sequence number */
X			inc(&i);
X		}
X
X		/* find the final buffered frame to retransmit */
X		of = FindBuf(dest->Addr, (SequenceNr)f->seq);
#ifdef EBUG
X		if (of == NULL)
X		{
X			(void)fprintf(stderr, "CntlFrm, NAK2: can't find outgoing buffer!\n");
X			break;
X		}
#endif
X
X		/* re-send the final frame */
X		SendData(of);
X
X		break;
X
X	default:
X		/* don't know what to do... discard the frame */
#ifdef EBUG
X	(void)fprintf(stderr, "CntlFrm: unknown control frame\n");
#endif
X		break;
X	}
}
SHAR_EOF
chmod 0644 xtclient/datalink.c ||
echo 'restore of xtclient/datalink.c failed'
Wc_c="`wc -c < 'xtclient/datalink.c'`"
test 10936 -eq "$Wc_c" ||
	echo 'xtclient/datalink.c: original size 10936, current size' "$Wc_c"
fi
# ============= xtclient/datalink.h ==============
if test -f 'xtclient/datalink.h' -a X"$1" != X"-c"; then
	echo 'x - skipping xtclient/datalink.h (File already exists)'
else
echo 'x - extracting xtclient/datalink.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'xtclient/datalink.h' &&
/*
X * File name:	datalink.h
X *
X * Description:	External function and data declarations for datalink.c and
X *		dlutil.c
X *
X * Author:	Merlin J. Mathesius
X */
X
#include "frame.h"
#include <sys/types.h>
#include <memory.h>
X
/* Event types */
typedef enum {
X	FrameArrival,		/* a frame has arrived */
X	CksumErr,		/* a frame arrived damaged and was discarded */
X	TimeOut,		/* a transmitted frame was not acknowledged */
X	NetworkLayerReady,	/* network layer has data ready */
X	DoomsDay,		/* shutdown data link layer */
X	UnknownEvent		/* something funny happened */
} EvType;
X
#define MaxAddr		7	/* maximum stream (address) number */
#define MaxSeq		7	/* maximum sequence number */
X
typedef int SequenceNr;
X
/* each destination (ie., window) has it's own logical stream */
typedef struct {
X	int	   Addr;	    /* address of this destination */
X	SequenceNr NextFrameToSend; /* used for outbound frame stream */
X	SequenceNr AckExpected;	    /* oldest frame as yet unacknowledged */
X	SequenceNr FrameExpected;   /* next frame expected on inbound stream */
} DestInfo;
X
#define NumBuf		7	/* total number of outgoing frame buffers. */
X				/* One less that number of addresses to avoid */
X				/* circularity problems. */
X
/* buffered frame structure */
typedef struct {
X	Frame	frame;		/* buffered frame */
X	long	timeout;	/* system time at which ACK timer expires */
} FrmInfo;
X
X
/* datalink.c */
Xextern void	DLinit();
Xextern int	DLfromPH(), DLtoPH(), DLfromNET(), DLtoNET();
Xextern void	DataLinkLayer();
X
/* dlutil.c */
Xextern int	between();
Xextern void	SendData(), SendAck();
Xextern void	EnableNetworkLayer(), DisableNetworkLayer();
Xextern int	ToPhysicalLayer(), FromPhysicalLayer();
Xextern int	ToNetworkLayer(), FromNetworkLayer();
Xextern void	StartTimer(), StopTimer(), CheckTimers();
Xextern void	inc();
Xextern EvType	Wait();
Xextern FrmInfo	*FindBuf();
X
/* buffer area for outgoing frames */
Xextern FrmInfo o_buffer[];
X
/* destination information */
Xextern DestInfo destinfo[];
X
/* pointer to most recent frame to time out */
Xextern FrmInfo *last_timeout;
SHAR_EOF
chmod 0644 xtclient/datalink.h ||
echo 'restore of xtclient/datalink.h failed'
Wc_c="`wc -c < 'xtclient/datalink.h'`"
test 2043 -eq "$Wc_c" ||
	echo 'xtclient/datalink.h: original size 2043, current size' "$Wc_c"
fi
# ============= xtclient/dlutil.c ==============
if test -f 'xtclient/dlutil.c' -a X"$1" != X"-c"; then
	echo 'x - skipping xtclient/dlutil.c (File already exists)'
else
echo 'x - extracting xtclient/dlutil.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'xtclient/dlutil.c' &&
/*
X * File name:	dlutil.c
X *
X * Description:	Utility functions for data link layer of UNIX-PC "xt/layers"
X *		system.
X *
X * Author:	Merlin J. Mathesius
X *
X * Contents:	between()		circular comparison of sequence numbers
X *		SendAck()		sends acknowledgement for a frame
X *		SendData()		sends data frame
X *		Wait()			waits for an control even to occur
X *		FromNetworkLayer()	retrieves a packet from the net layer
X *		ToNetworkLayer()	sends a packet to the network layer
X *		FromPhysicalLayer()	retrieves a frame from the phys layer
X *		ToPhysicalLayer()	sends a frame to the physical layer
X *		StartTimer()		starts a timer on an outgoing frame
X *		StopTimer()		stops a timer on an outgoing frame
X *		CheckTimers()		checks for next timer to expire
X *		EnableNetworkLayer()	enables events from the network layer
X *		DisableNetworkLayer()	disables events from the network layer
X *		inc()			circular increment of sequence number
X *		FindBuf()		finds a frame buffer
X *
X * Data:	readfds			bit map of readable file descriptors
X */
X
#include <stdio.h>
#ifdef sun
#include <sys/types.h>
#endif
#include <sys/times.h>
#include <sys/param.h>
#include <select.h>
X
#include "datalink.h"
#include "phone.h"
#include "window.h"
#include "appl.h"
#include "session.h"
#include "xtclient.h"
X
int		readfds;	/* bit map of readable file descriptors */
X
Xextern long	times();	/* not declared in any header file */
X
/*
X * Function name:	between(a, b, c)
X *
X * Description:		Return true if a <= b < c circularly, false otherwise.
X *
X * Parameters:		a	lower bound (inclusive) for check
X *			b	sequence number to check
X *			c	upper bound (non-inclusive) for check
X *
X * Return values:	1	a <= b < c (circularly)
X *			0	otherwise
X */
int
between(a, b, c)
XSequenceNr	a, b, c;
{
X	if ( a <= b && b < c
X	  || c < a && a <= b
X	  || b < c && c < a )
X		return(1);
X	else
X		return(0);
}
X
/*
X * Function name:	SendAck(addr, seq)
X *
X * Description:		Send an acknowledgement frame for given stream and
X *			sequence number
X *
X * Parameters:		addr	stream receiving frame
X *			seq	sequence number of received frame
X *
X * Return values:	None
X *			
X */
void
XSendAck(addr, seq)
int		addr;
XSequenceNr	seq;
{
X	Frame	f;
X
X	/* construct an acknowledgement frame */
X	f.mark = 1;
X	f.ctl  = 1;
X	f.addr = addr;
X	f.seq  = seq;
X	f.size = 2;
X	f.data[0] = '\006';	/* ASCII ACK character */
X	f.data[1] = 003;	/* indication to "xt/layers" that it is OK */
X				/* to send more data */
X
X	/* transmit the acknowledgement */
X	(void)ToPhysicalLayer(&f);
}
X
/*
X * Function name:	SendNak(addr, seq)
X *
X * Description:		Send a negative acknowledgement frame for given stream
X *			and sequence number
X *
X * Parameters:		addr	stream receiving frame
X *			seq	sequence number of received frame
X *
X * Return values:	None
X *			
X */
void
XSendNak(addr, seq)
int		addr;
XSequenceNr	seq;
{
X	Frame	f;
X
#ifdef EBUG
X	(void)fprintf(stderr, "dlutil: sent NAK, stream %d seq %d\n",addr,seq);
#endif
X	/* construct an acknowledgement frame */
X	f.mark = 1;
X	f.ctl  = 1;
X	f.addr = addr;
X	f.seq  = seq;
X	f.size = 1;
X	f.data[0] = '\025';	/* ASCII NAK character */
X
X	/* transmit the negative acknowledgement */
X	(void)ToPhysicalLayer(&f);
}
X
/*
X * Function name:	SendData(fi)
X *
X * Description:		Construct and send an outgoing frame.
X *
X *			Acknowledgement timer is also started for frame.
X *
X * Parameters:		fi	frame information pointer for frame to send
X *
X * Return values:	None
X */
void
XSendData(fi)
FrmInfo	*fi;	/* pointer to frame info of frame to send */
{
X	/* send frame to physical layer */
X	(void)ToPhysicalLayer(&fi->frame);
X
X	/* start time for this frame */
X	StartTimer(fi);
}
X
static int net_layer_enabled;	/* 1 = network layer enabled, 0 = disabled */
X
static FrmInfo *next_timeout = NULL;	/* pointer to next frame to time out */
X
FrmInfo *last_timeout = NULL;	/* pointer to most recent frame to time out */
X
/*
X * Function name:	Wait()
X *
X * Description:		Wait for an event to happen; return its type.
X *
X *			This function uses hooks into the other layers (and the
X *			UNIX operation system) to detect when an event occurs.
X *
X *			If there is reply information waiting from the
X *			application or session layers (and the network layer
X *			is enabled), a "NetworkLayerReady" event is returned
X *			immediately.
X *
X *			If we are no longer multiplexed, a "DoomsDay" event
X *			is returned.
X *
X *			If neither of the above two conditions have occurred,
X *			the next frame to timeout is located and then select()
X *			is called to wait until input is available from the
X *			phone line or keyboard, or a timeout occurs.  If no
X *			output frame is pending, an occasional timeout is set
X *			anyhow so the status of the phone connection can be
X *			checked.
X *
X *			When select() returns, if there is any input ready
X *			from the phone, it is processed and a "FrameArrival"
X *			or "ChksumErr" event will be returned if appropriate.
X *
X *			If there is keyboard input ready (and the network layer
X *			is enabled), a "NetworkLayerReady" event is returned.
X *
X *			If no input is ready, timers are checked and if one has
X *			expired a "TimeOut" event is returned.
X *
X *			Finally, the status of the phone line is checked and
X *			if it has been disconnected a "DoomsDay" event is
X *			returned.
X *
X *			Wait() will loop and continue looping until one of the
X *			above events occurs.
X *
X * Parameters:		None
X *
X * Return values:	FrameArrival	a frame has arrived
X *			CksumErr	a damaged frame arrived (discarded)
X *			TimeOut		a transmitted frame was not acknowledged
X *			NetworkLayerReady	network layer has data ready
X *			DoomsDay	shutdown data link layer
X *			UnknownEvent	unknown event
X */
EvType
Wait()
{
X	int	nfds;		/* returned number of ready file descriptors */
X	int	physbit, netbit; /* bit mask for physical and network files */
X	long	systime;	/* system time (in HZ) */
X	struct timeval to;	/* timeout structure */
X	struct tms dummy;	/* dummy system times structure */
X
KeepWaiting:
X
X	/* if we have a reply queued from the application layer, or some */
X	/* control information from the session layer, dispatch immediately */
X	if (net_layer_enabled && (Wready || APreply_cnt || SESready))
X		return(NetworkLayerReady);
X
X	/* if we are no longer multiplexed, exit */
X	if (!mpx_flag)
X	{
X		return(DoomsDay);
X	}
X
X	/* set up bit map for phone line file descriptor */
X
X	physbit = 1 << phone_fd;
X
X	/* network indicator will only be set if it is enabled */
X
X	netbit = net_layer_enabled * wind_fds;
X
X	/* merge the two maps */
X
X	readfds = physbit | netbit;
X
X	/* clear the timeout structure */
X	timerclear(&to);
X
X	if (next_timeout == NULL)
X	{
X		/* no timeouts are pending, but timeout every once in a */
X		/* while to check the status of the phone connection */
X		to.tv_sec = 5;
X	}
X	else
X	{
X		/* get current system time (in HZ) */
X		systime = times(&dummy);
X
X		/* how long until timeout occurs? */
X		if (next_timeout->timeout > systime)
X		{
X			/* convert timeout from HZ to microseconds */
X			to.tv_usec = (next_timeout->timeout-systime)*1000000/HZ;
X		}
X		/* else: timeout will remain 0 (immediate)! */
X	}
X
X	/* pass the read bit masks and timeout structure to */
X	/* select().  this system call will return if any */
X	/* of the file descriptors in the bit mask have data */
X	/* available for reading, or if the timeout occurs */
#ifdef sun
X	if (to.tv_usec >= 1000000)
X	{
X		to.tv_sec = to.tv_usec / 1000000;
X		to.tv_usec = to.tv_usec - to.tv_sec * 1000000;
X	}
#endif sun
X	nfds = select(32, &readfds, 0, 0, &to);
X
X	/* at this point, the bit mask has been modified by select() */
X	/* to contain only those file descriptors that have data */
X	/* ready for reading */
X
X	if (nfds < 0)
X		/* select() caught a signal and was interrupted, continue */
X		goto KeepWaiting;
X
X	/* if no data ready, check if it's a timeout */
X	if (nfds == 0)
X	{
X		/* are any timeouts pending? */
X		if (next_timeout != NULL)
X		{
X			/* get the current system time */
X			systime = times(&dummy);
X
X			/* has the timer expired? */
X			if (next_timeout->timeout <= systime)
X			{
X				/* It was a timeout, save the timer that */
X				/* expired, stop the timer, and return */
X				last_timeout = next_timeout;
X				StopTimer(next_timeout);
X				return(TimeOut);
X			}
X		}
X	}
X	else /* there should be some data ready */
X	{
X		/* check network layer */
X		if (readfds & netbit)
X		{
X			/* network layer has data ready */
X			return(NetworkLayerReady);
X		}
X
X		/* first, check the physical line */
X		if (readfds & physbit)
X		{
X			/* check for status of arriving frame */
X			switch (PHquery())
X			{
X			case 1:     /* a frame has arrived and is waiting */
X				return(FrameArrival);
X			case -1:    /* a checksum error occured */
X				return(CksumErr);
X			case 0:     /* frame not ready yet */
X				break;
X			default:    /* unknown... */
X				return(UnknownEvent);
X			}
X		}
X	}
X
X	/* if the phone connection has failed, exit */
X	if (!isconnected())
X	{
X		return(DoomsDay);
X	}
X
X	/* nothing to do, keep waiting */
X	goto KeepWaiting;
}
X
/*
X * Function name:	FromNetworkLayer(p)
X *
X * Description:		Fetch information from the the network layer for
X *			transmission on the channel.
X *
X * Parameters:		p	pointer to buffer in which to store packet
X *
X * Return values:	0	packet successfully retreived (with data)
X *			-1	no data, or error
X */
int
FromNetworkLayer(p)
Packet	*p;
{
X	/* call data link layer interface function */
X	return(DLfromNET(p));
}
X
/*
X * Function name:	ToNetworkLayer(p)
X *
X * Description:		Deliver information from an inbound frame to the
X *			network layer.
X *
X * Parameters:		p	pointer to packet to send
X *
X * Return values:	-1	error
X *			0	OK, packet successfully accepted
X */
int
ToNetworkLayer(p)
Packet	*p;
{
X	/* call data link layer interface function */
X	return(DLtoNET(p));
}
X
/*
X * Function name:	FromPhysicalLayer(r)
X *
X * Description:		Go get an inbound frame from the physical layer.
X *
X *			Note:  This function will only return a valid frame
X *			when it is known that a complete frame has arrived
X *			(ie., after a "FrameArrival" event)
X *
X * Parameters:		r	pointer to buffer in which to store frame
X *
X * Return values:	0	returned frame is valid
X *			-1	no frame returned
X */
int
FromPhysicalLayer(r)
Frame	*r;
{
X	/* call data link layer interface function */
X	return(DLfromPH(r));
}
X
/*
X * Function name:	ToPhysicalLayer(s)
X *
X * Description:		Pass the frame to the physical layer for transmission.
X *
X * Parameters:		s	pointer to frame to send
X *
X * Return value:	total number of bytes in frame
X */
int
ToPhysicalLayer(s)
Frame	*s;
{
X	/* call data link layer interface function */
X	return(DLtoPH(s));
}
X
/*
X * Function name:	StartTimer(fi)
X *
X * Description:		Start the clock running and enable "TimeOut" event.
X *
X * Parameters:		fi	pointer to frame information of outgoing frame
X *
X * Return values:	None
X */
void
XStartTimer(fi)
FrmInfo *fi;
{
X	struct tms dummy;	/* system times structure */
X
X	/* allow 2 seconds for acknowledgement */
X
X	fi->timeout = times(&dummy) + 2*HZ;
X
X	/* check for next expiring timer */
X	CheckTimers();
}
X
/*
X * Function name:	StopTimer()
X *
X * Description:		Stop the clock and disable "TimeOut" event.
X *
X * Parameters:		fi	pointer to frame information of ACKed frame
X *
X * Return values:	None
X */
void
XStopTimer(fi)
FrmInfo *fi;
{
X	/* disable timeout for this frame */
X
X	fi->timeout = 0;
X
X	/* check for next expiring timer */
X	CheckTimers();
}
X
/*
X * Function name:	CheckTimers()
X *
X * Description:		Locate next timeout alarm to go off.  Store the
X *			frame info pointer in "next_timeout" global variable.
X *
X * Parameters:		None
X *
X * Return values:	None
X */
void
CheckTimers()
{
X	register int i;		/* loop index */
X	register long t, min_t;	/* time values */
X
X	/* start out by clearing the pointer */
X	next_timeout = NULL;
X
X	/* no minimum time yet */
X	min_t = 0;
X
X	/* check all outgoing buffers */
X	for (i = 0; i < NumBuf; i++)
X	{
X		t = o_buffer[i].timeout;
X		/* if a timeout value is set and this is the first timeout */
X		/* found, or less than the current minimum, save it */
X		if (t != 0 && (next_timeout == NULL || t < min_t))
X		{
X			min_t = t;
X			next_timeout = &o_buffer[i];
X		}
X	}
X
X	/* "next_timeout" has been set appropriately */
X	return;
}
X
/*
X * Function name:	EnableNetworkLayer()
X *
X * Description:		Allow the network layer to cause a "NetworkLayerReady"
X *			event.
X *
X * Parameters:		None
X *
X * Return values:	None
X */
void
EnableNetworkLayer()
{
#ifdef EBUG
X	/* if we are transitioning from disabled to enabled... */
X	if (net_layer_enabled == 0)
X		(void)fprintf(stderr, "Network layer enabled...\n");
#endif
X	/* set indicator for network layer */
X	net_layer_enabled = 1;
}
X
/*
X * Function name:	DisableNetworkLayer()
X *
X * Description:		Forbid the network layer from causing a
X *			"NetworkLayerReady" event.
X *
X * Parameters:		None
X *
X * Return values:	None
X */
void
DisableNetworkLayer()
{
#ifdef EBUG
X	/* if we are transitioning from enabled to disabled... */
X	if (net_layer_enabled == 1)
X		(void)fprintf(stderr, "Network layer disabled...\n");
#endif
X	/* clear indicator for network layer */
X	net_layer_enabled = 0;
}
X
/*
X * Function name:	inc(k)
X *
X * Description:		Increment "k" circularly.
X *
X * Parameters:		k	pointer to sequence number to increment
X *
X * Return values:	None
X */
void
inc(k)
XSequenceNr *k;
{
X	if (*k < MaxSeq)
X		(*k)++;
X	else
X		*k = 0;
}
X
/*
X * Function name:	FindBuf(addr, seq)
X *
X * Description:		Finds a frame output buffer:
X *			if "addr" is -1, finds an open buffer
X *			otherwise, finds the buffer for "addr" and "seq"
X *
X * Parameters:		addr	address of frame to find (or -1)
X *			seq	sequence number of frame to find
X *
X * Return values:	NULL	- buffer not found
X *			ptr	- pointer to frame info buffer requested
X */
FrmInfo *
FindBuf(addr, seq)
int		addr;
XSequenceNr	seq;
{
X	register int i;
X	register FrmInfo *f;
X
X	/* set pointer to first buffer */
X	f = o_buffer;
X
X	if (addr == -1)
X	{
X		/* find any unoccupied buffer slot */
X
X		for (i = 0; i < NumBuf; i++, f++)
X			if (f->frame.mark == 0)		/* empty slot */
X				return(f);
X	}
X	else
X	{
X		for (i = 0; i < NumBuf; i++, f++)
X			if (f->frame.mark == 1		/* slot occupied */
X			 && f->frame.addr == addr	/* address matches */
X			 && f->frame.seq  == seq)	/* sequence matches */
X				return(f);
X	}
X
X	/* didn't find what we were looking for */
X	return(NULL);
}
SHAR_EOF
chmod 0644 xtclient/dlutil.c ||
echo 'restore of xtclient/dlutil.c failed'
Wc_c="`wc -c < 'xtclient/dlutil.c'`"
test 14169 -eq "$Wc_c" ||
	echo 'xtclient/dlutil.c: original size 14169, current size' "$Wc_c"
fi
# ============= xtclient/dumplog.c ==============
if test -f 'xtclient/dumplog.c' -a X"$1" != X"-c"; then
	echo 'x - skipping xtclient/dumplog.c (File already exists)'
else
echo 'x - extracting xtclient/dumplog.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'xtclient/dumplog.c' &&
#include <ctype.h>
#include "frame.h"
X
Xenum FrmState {
X	FrmNull,	/* awaiting arrival of start of frame */
X	FrmHeader,	/* awaiting arrival of 2nd byte of header */
X	FrmData,	/* awaiting arrival of remaining data */
X	FrmCRC,		/* awaiting arrival of CRC */
X	FrmDone		/* frame arrived, awaiting acceptance of frame */
X			/*  by data link layer */
};
X
static	Frame		frame;		/* current arriving frame */
static	enum FrmState	frame_state;	/* state of current arriving frame */
static	char		*fp;		/* pointer to next byte to receive */
static	unsigned	count;		/* count of remaining bytes in state */
X
int
reset()
{
X	frame_state = FrmNull;
X	fp = (char *)&frame;
}
X
int
main(argc, argv)
int	argc;
char	*argv[];
{
X    register int rc;
X    int fd;
X
X    fd = 0;
X
X    dump_header();
X
X    reset();
X
X    for(;;)
X    {
X	switch (frame_state)
X	{
X	case FrmNull:	/* awaiting arrival of start of frame */
X
X		/* try to read first byte of header */
X		rc = read(fd, fp, (unsigned)1);
X		if (rc <= 0)
X			goto finish;
X
X		/* The type first byte of a valid frame will have the */
X		/* "mark" bit set to 1.  Ignore if it is not set. */
XSyncStart:	if (frame.mark != 1)
X			continue;
X
X		/* first byte OK, move to next state... */
X		frame_state = FrmHeader; fp++;
X
X		/* FALLTHROUGH */
X
X	case FrmHeader:	/* awaiting arrival of 2nd byte of header */
X
X		/* try to read remaining byte of header */
X		rc = read(fd, fp, (unsigned)1);
X		if (rc <= 0)
X			goto finish;
X
X		/* Size of the data portion of the frame must be in */
X		/* range.  We are out of sync if it is out of range, */
X		/* so retry to see if it is the first byte of the frame. */
X		if (frame.size > DAT_SZ) {
X			reset();
X			goto SyncStart;
X		}
X
X		/* header is OK, we are expecting "size" bytes in the */
X		/* data section of the frame. */
X
X		frame_state = FrmData; fp++; count = frame.size;
X
X		/* FALLTHROUGH */
X
X	case FrmData:	/* awaiting arrival of remaining data */
X
X		if (count != 0)
X		{
X			rc = read(fd, fp, count);
X			if (rc <= 0)
X				goto finish;
X
X			/* got some data, figure out what's left */
X			count -= rc;
X			fp += rc;
X
X			/* still need more data */
X			if (count != 0)
X				goto finish;
X		}
X
X		/* got all the data we need, move on to next state */
X
X		frame_state = FrmCRC;
X		fp = (char *)&frame.crc; count = sizeof(frame.crc);
X
X		/* FALLTHROUGH */
X
X	case FrmCRC:	/* awaiting arrival of CRC */
X
X		rc = read(fd, fp, count);
X		if (rc <= 0)
X			goto finish;
X
X		count -= rc;
X		fp += rc;
X
X		/* still need remaining byte(s) of CRC */
X		if (count != 0)
X			goto finish;
X
X		/* We now have a complete frame!  Don't check the CRC. */
X
X		/* We have a happy, healty frame! */
X
X		frame_state = FrmDone;
X
X		/* FALLTHROUGH */
X
X	case FrmDone:	/* frame arrived, awaiting acceptance of frame */
X
X		dump_frame();
X		reset();
X		continue;
X
X	default:
X
X		/* Don't know how we got here, reset to know state */
X		reset();
X		continue;
X	}
X    }
X
finish:
X
X	if (count != 0) printf("Incomplete frame!\n");
X
X	exit(1);
X
}
X
dump_header()
{
X	printf("m   a   s\n");
X	printf("a c d s i\n");
X	printf("r t d e z\n");
X	printf("k l r q e  crc  data\n");
X	printf("- - - - -- ---- ----\n");
}
X
dump_frame()
{
X	int i;
X
X	printf("%d %d %d %d %-2d %02x%02x",
X		frame.mark, frame.ctl, frame.addr, frame.seq, frame.size,
X		*((Byte *)&frame.crc), *(((Byte *)&frame.crc)+1) );
X	for (i = 0; i < frame.size; i++)
X		if (isascii(frame.data[i])&&isgraph(frame.data[i]))
X			printf(" %c", frame.data[i]);
X		else
X			printf(" <%02x>", frame.data[i]);
X	printf("\n");
}
SHAR_EOF
chmod 0644 xtclient/dumplog.c ||
echo 'restore of xtclient/dumplog.c failed'
Wc_c="`wc -c < 'xtclient/dumplog.c'`"
test 3437 -eq "$Wc_c" ||
	echo 'xtclient/dumplog.c: original size 3437, current size' "$Wc_c"
fi
true || echo 'restore of xtclient/frame.h failed'
echo End of part 1, continue with part 2
exit 0



More information about the Comp.sources.3b1 mailing list