#!/usr/local/bin/tops -i -s /usr/local/tops/sys -u /opt/mytops/usr/
/* GNU General Public License

Program Tops - a stack-based computing environment
Copyright (C) 1999-2005  Dale R. Williamson

Author: Dale R. Williamson <dale.williamson@prodigy.net>

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

----------------------------------------------------------------------*/

# File: telserver  September 2005
# Copyright (C) 2005  D. R. Williamson

# Start a tops telnetd server.  After running this script, script 
# telclient or ordinary telnet can be run to connect clients to a 
# real telnet server through the tops telnetd server.  

# Listening PORT is 9890 if not set by command line switch -port:
   (PORT,f) = (9890,number(argv("-port")));

# Vector output to a log file in user /home named telserver_PID.log:
   set_sysout("/tmp/telserver_" + runid1 + ".log");
 # set_sysout(env("HOME") + "/telserver_" + intstr(getpid) + ".log");

# Write the first lines in the log file:
   nl(dot(nl,cats("-",72)));
   nl(dot("PID " + spaced(intstr(getpid)) + date));

# Command line switch -ntrace can be set to also obtain network trace 
# output; the log file will grow very rapidly:
   if(argv("-ntrace") != "") ntrace();

# Allow a specific IP address to connect with switch -allow:
   if((IP=argv("-allow")) != "") ALLOW(IP);

# Show the IP addresses that are allowed to connect:
   nl(dot("Clients allowed to connect:"),nl,dot(CLIENT_ALLOW.clients));

# Source the server words in file term.v:
   msource(catmsg(no),"term.v","Server Words");

# Function CONN() created next will connect this run to an instance of 
# tops listening on port 9877.  Then from that server we can later re-
# moteprompt to this telserver and run interactive commands for main-
# tenance or debugging (the notes below show an interactive session):
   function CONN() { 
      if(port_listening((P=9877))) // if 9877 is a listening port, then
         CLIENT(IPloop,P);         // connect as a tops client
   }

# An alarm is used to run CONN() because TELNETD() never returns, but 
# we cannot run CONN() until after the daemon is started by TELNETD():
if(PORT != 9877)
   ALARM(5,"CONN"); // delay connecting until after TELNETD() starts

# Start the tops telnetd daemon listening on PORT:
   TELNETD(PORT);

/*----------------------------------------------------------------------

Notes on running interactive commands on telserver.

Why bother with an ALARM and its function CONN()?  Why not just connect
a tops CLIENT to the telserver listening port and then run remoteprompt
through that socket?  

Connecting with remoteprompt will not work because telserver has been 
set up by TELNETD() especially for clients connecting to run telnet. 

The instant a client connects, telserver starts the Unix telnet nego-
tiation for login, which makes any dialog from remoteprompt useless.

So the connection is turned around, and CONN() connects telserver as a
client to a normal tops server listening on port 9877.  Since this con-
nection does not go through the telserver listening port, remoteprompt 
will work.

Here is starting an ordinary server listening on port 9877, prior to 
running this script: 

   [dale@clacker] /home/dale > tops
            Tops 3.0.1
   Sun Sep 18 22:22:39 PDT 2005
   [tops@clacker] ready > "*" 9877 SERVER

   [tops@clacker] ready > clients
    Server local is listening on port 9877
    No clients

   [tops@clacker] ready > 

Below we see telserver function CONN() connecting telserver to this 
server a few seconds after the telserver script is run:

   [tops@clacker] ready > 
   Sun Sep 18 22:23:47 PDT 2005 SERVER: connection from 127.0.0.1

Telserver is running as a daemon with no sysin or sysout.  But this 
connection made by CONN() will allow us to "remoteprompt" to telserver
and run interactive commands right on its stack.  

First, word clients is used to learn that telserver is connected on 
socket 6:

   [tops@clacker] ready > clients
    Server local is listening on port 9877
    Clients:
     socket 6, port 33003, conn S<C, 127.0.0.1 LOGIN dale clacker

Command remoteprompt run next will take us to a prompt on socket 6, 
which is telserver, where keyed commands will run telserver:

   [tops@clacker] ready > 6 remoteprompt

On telserver, here is running word clients to see its connections (the
new prompt, tops@socket6, indicates we are now running interactively on
telserver):

   tops@socket6 > clients
    Server local is listening on port 9890
    Clients:
     socket 2, port  9877, conn C>S, 127.0.0.1 dale clacker
     socket 3, port 33004, conn S<F, 127.0.0.1 TERM Sun Sep 18 22:24:45 PDT 2005
     socket 4, port  9923, conn C>F, 127.0.0.1 dale clacker
     socket 6, port 33006, conn S<F, 127.0.0.1 TERM Sun Sep 18 22:25:38 PDT 2005
     socket 7, port  9924, conn C>F, 127.0.0.1 dale clacker
   tops@socket6 > 

The lines above show telserver is listening on port 9890 (the default
port for TELNETD()--see above), and the clients are as follows:

   socket 2 - us from the tops server listening on port 9877

   socket 3 - a telnet client logged in (type TERM, login time shown)
   socket 4 - a telnetd daemon on port 9923 used by socket 3

   socket 6 - another telnet client logged in
   socket 7 - a telnetd daemon on port 9924 used by socket 6

Symbol C>S for socket 2 indicates that telserver is a client connected 
to the server on port 9877 (this is where we just came from).

S<F for sockets 3 and 6 indicates telnet foreign clients connected to 
the server here, being run by telserver on port 9890.  The system has 
assigned them to ports 330004 and 330006, respectively.

C>F for sockets 4 and 7 indicates that telserver is a client connected
to a foreign server on ports 9923 and 9924, respectively.  The foreign 
server is the Unix telnetd server that TELNETD() starts, and connects 
to, for each telnet client. 

Once a connection is made to a Unix telnetd server, listening on its
port is turned off, so each Unix telnetd server (on ports 9923 and
9924) is serving only one client.

----------------------------------------------------------------------*/
