Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

TOPS20 Tcp/Ip API

176 views
Skip to first unread message

PoBe

unread,
Aug 21, 2021, 3:22:07 AM8/21/21
to
I have an interest in writing a TOPS20 program utilising tcp/ip. I do have a (vanilla) Panda distribution (7.01) up and running with a working Internet connection. I can Telnet into the machine etc. so I have the basics in place.

I have not fully understand if tcp/ip is layered product or not? I got the impression it's. If so is it pre-installed on the Panada distribution? After all there are a few programs Telnet and FTP on the distribution that works.

I was looking through the JSYSs but I could not find any obvious entry for tcp/ip (Arpanet) communication.

Any hints?

best regards,
PoBe




gah4

unread,
Aug 21, 2021, 6:24:05 AM8/21/21
to
On Saturday, August 21, 2021 at 12:22:07 AM UTC-7, PoBe wrote:
> I have an interest in writing a TOPS20 program utilising tcp/ip.
> I do have a (vanilla) Panda distribution (7.01) up and running
> with a working Internet connection.
> I can Telnet into the machine etc. so I have the basics in place.

My favorite book series has two versions of vol. 3, on the API for
using TCP/IP. One is BSD/sockets, and the other is TLI.

I hadn't thought about this in terms of TOPS-20 before you asked,
but there are some references that trace BSD/sockets back to TOPS-20.

Since TENEX traces back to ARPAnet days, it isn't surprising that it also
traces back early in the days of IP. One reference is that DoD had BSD
people create the sockets implementation so that they could get IP
onto their Unix systems, along with their TOPS-20 systems.


Lars Brinkhoff

unread,
Aug 21, 2021, 8:56:34 AM8/21/21
to
PoBe wrote:
> I was looking through the JSYSs but I could not find any obvious entry
> for tcp/ip (Arpanet) communication.

I don't know about TOPS-20, but I found some promising text in
<DOCUMENTATION>JSYS_REFERENCE.MEM. Search for TCP.

Lars Brinkhoff

unread,
Aug 21, 2021, 9:09:42 AM8/21/21
to
If someone would like to do TCP/IP programming on ITS, I could be more
helpful.

Dan Cross

unread,
Aug 21, 2021, 9:18:45 AM8/21/21
to
In article <fd4f04dc-4989-4bd1...@googlegroups.com>,
gah4 <ga...@u.washington.edu> wrote:
>On Saturday, August 21, 2021 at 12:22:07 AM UTC-7, PoBe wrote:
>> I have an interest in writing a TOPS20 program utilising tcp/ip.
>> I do have a (vanilla) Panda distribution (7.01) up and running
>> with a working Internet connection.
>> I can Telnet into the machine etc. so I have the basics in place.
>
>My favorite book series has two versions of vol. 3, on the API for
>using TCP/IP. One is BSD/sockets, and the other is TLI.

You're surely referring to W. Richard Stevens's "Unix Network
Programming". The second edition of those books was shipped in
two volumes: one covering BSD sockets and XTI, the other
covering other forms of IPC (pipes, SYSV shared memory, message
passing, a bunch of multithreading topics around critical
sections and mutual exclusion, etc).

It's probably worthwhile pointing out that every extant modern
version of Unix ships with sockets, and almost nothing uses TLI.
Historical versions of System V derivitives might ship with the
latter, however.

Stevens's book is now in its 3rd edition, carried on after
Stevens's untimely death by Bill Fenner and Andrew Rudoff.

>I hadn't thought about this in terms of TOPS-20 before you asked,
>but there are some references that trace BSD/sockets back to TOPS-20.

Not exactly. The idea of "sockets" as an abstraction was around
in the early TCP/IP days, and in those days, a lot of work was
being done on TENEX/TOPS-20, so the idea was floating around.
But the BSD sockets implementation was built from scratch for
Unix. Well, an initial implementation was done at BBN under a
DARPA contract, but it was modified, expanded, and arguably
improved at UC Berkeley for 4BSD.

>Since TENEX traces back to ARPAnet days, it isn't surprising that it also
>traces back early in the days of IP. One reference is that DoD had BSD
>people create the sockets implementation so that they could get IP
>onto their Unix systems, along with their TOPS-20 systems.

Partially correct. The PDP-10 had heavy presence on the ARPANET,
but by the late 70s/early 80s was clearly reaching end of life
as a hardware platform. At the same time, the DoD was looking
for a common software platform for its contractors; the
competition was between VMS on the VAX and Unix. A working
TCP/IP implementation was a prerequisite, but not necessarily
for communications with TOPS-20 specificailly.

Sadly, with respect to the OP's original question, I cannot
provide a useful answer. My thought is that there will be
some set of JSYS targets that implement TCP/IP functionality,
and that one would fill in some well-defined data structures
analogous to sockaddr_in in the BSD sockets world that those
JSYS calls consume. It wouldn't surprise me if the TOPS-20
C compilers have a sockets compatibility library. But to get
started with whatever the "native" JSYS API is, I'd recommend
looking at something simple like the `finger` client.

- Dan C.

Lars Brinkhoff

unread,
Aug 21, 2021, 12:05:59 PM8/21/21
to
Dan Cross wrote:
> Sadly, with respect to the OP's original question, I cannot provide a
> useful answer. My thought is that there will be some set of JSYS
> targets that implement TCP/IP functionality, and that one would fill
> in some well-defined data structures

As far as I can see, you open (GETJFN) a file name starting with "TCP:".
Parameters, including host name and port, follow after TCP:

Douglas Wells

unread,
Aug 21, 2021, 1:28:48 PM8/21/21
to
>On Saturday, August 21, 2021 at 12:22:07 AM UTC-7, PoBe wrote:
>> I have an interest in writing a TOPS20 program utilising tcp/ip.
>> I do have a (vanilla) Panda distribution (7.01) up and running
>> with a working Internet connection.
>> I can Telnet into the machine etc. so I have the basics in place.
>
>I hadn't thought about this in terms of TOPS-20 before you asked,
>but there are some references that trace BSD/sockets back to TOPS-20.
>
>Since TENEX traces back to ARPAnet days, it isn't surprising that it also
>traces back early in the days of IP. One reference is that DoD had BSD
>people create the sockets implementation so that they could get IP
>onto their Unix systems, along with their TOPS-20 systems.

The concept of sockets dates to the first days of ARPAnet (using
NCP(*)). Although there were a myriad of various OSs, each generally
had an I/O model similar to UNIX/POSIX open/read/write/close. This
was generally readily transferable to the ARPAnet NCP by thinking of
the ARPAnet connection as a multiplexed serial link (as was widely
available by the late 60s and early 70s. What was "new" was the huge
number of subdevices (64Ki) as opposed to less than (typically) 100.
This was too many devices for the memory-limited OSs to allocate
(i.e., waste memory space on) at build or boot time. Instead, one had
to make a call to the OS to allocate such a subdevice. These became
known as sockets. (I don't know the actual derivation of the name;
most likely it was simply one of a set of connection-oriented names
that wasn't in use for something else.)

(*) What people generally refer to today as NCP was actually the
ARPAnet Host-to-Host protocol, a name that was rapidly dropped with
the start of TCP development in the mid-1970s.

But the real reason for this post is that I include a sample program
to do TCP/IP communication on various systems, including TOPS-20.
Please excuse the huge number of preprocessor options. The intent was
to make the same source program operate on numerous OSs. There are
also hacks to get around various limitations (including the problem
with the LINKER on TOPS-20 actually being the TOPS-10 program (or
close to it). Also, I apologize for the size of the program.

Note that use of UDP requires elevated privileges on TOPS-20, so no
code for that is available here.

I hope that the program comments will provide sufficient context. This
program was last run on twenex and toad-1, probably in 2013 (and
hasn't been touched since). Also, I haven't bothered to chase down
the necessary additional files to make this run. My purpose is to
show some code that does TCP/IP.

- dmw

----------------- snip here ---------------------------------

/* Adapted from ~/develop/time/nettime/c_getnettime.c (21 Dec 2011) */

/* netday - the object of this program is to display the */
/* time of day, as obtained via the DAYTIME protocol (port 13) */
/* of a specified host. The purpose of writing this program */
/* is to explore the use of low-level JSYS calls on TOPS-20. */
/* A specific goal is to have it run on twenex.org, which does */
/* not have KCC USYS network support. */

/* FIXME: The USE_TCP_OPEN option doesn't work. There is */
/* garbage that looks like a byte pointer and other cruft) in */
/* the receive buffer -- although the receive count is correct. */
/* If we patch things and use a SIN JSYS (instead of a read), */
/* everything looks ok. */

/* BSD sockets work on daisy and toad-1 (and FreeBSD) */
/* JSYS sockets work on toad-1 and on twenex */
/* TCP_OPEN works on twenex, doesn't work on toad-1 (always get timeout) */

#include <stdlib.h>
#include <stdio.h>
/* #if (__STDC_VERSION__ >= 199901L) || (__GNUC__ >= 3) */
/* # include <stdbool.h> */
/* #endif */
#if __STDC__
# include <stdarg.h>
# include <limits.h>
#else
# include <varargs.h>
#endif

#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <signal.h>
#include <string.h>
#include <time.h>

/* #if ! __bool_true_false_are_defined */
/* typedef unsigned int _Bool; */
/* # define bool _Bool */
# define bool int
# define false 0
# define true 1
# define __bool_true_false_are_defined 1
/* #endif */

#if ! defined (__unix__)
# if defined (__unix)
# define __unix__ __unix
# elif defined (unix)
# define __unix__ unix
# elif defined (__APPLE_CC__)
# define __unix__ __APPLE_CC__
# endif
#endif

#if defined (__COMPILER_KCC__)
# if __STDC__ /* this is our indicator */
# define xKCCLIB_VERSION 6
# else
# define xKCCLIB_VERSION 5
# endif
#endif /* defined (__COMPILER_KCC__) */

#if __STDC__
# define CONST const
#else
# define CONST
#endif
/* These characteristics are assumed by default: */
#define HAVE_UDP 1
#define HAVE_TCP 1

#if SYS_T20
# define HAVE_GTHST 1
# undef HAVE_UDP
# define HAVE_UDP 0

# define USE_BSD_SOCKETS 0
# define USE_JSYS_SOCKETS 1
# define USE_TCP_OPEN 0 /* FIXME: this doesn't work yet */
# define USE_JSYS_READ_WITH_TCP_OPEN (USE_TCP_OPEN && 0)

# include <sys/types.h>
# include <sys/time.h>

# if USE_TCP_OPEN
# include <fcntl.h>
# if xKCCLIB_VERSION < 6
# define O_RDWR (02) /* Open for reading and writing */
# define O_BINARY (0100) /* Open in binary mode (sys-dep) */
# define O_BSIZE_8 (020000) /* Bytesize value: 8-bit */
# endif
# endif

# if xKCCLIB_VERSION >= 6
# include <unistd.h>
# endif /* __STDC__ */

typedef int SOCKET;
# define recv(h, b, l, f) read ((h), (b), (l))
# define CLOSESOCKET(s) close (s)
# define INVALID_SOCKET (-1)
# define SOCKET_ERROR (-1)

# define HAVE_GETHOSTBYNAME 1
# define HAVE_INET_FUNCS (xKCCLIB_VERSION >= 6) /* basic inet_... */
#else /* SYS_T20 */
# define SYS_T20 0
#endif /* SYS_T20 */

#if defined (__unix__)
# include <unistd.h>

# include <sys/types.h>
# include <sys/time.h>

typedef int SOCKET;
# define CLOSESOCKET(s) close (s)
# define INVALID_SOCKET (-1)
# define SOCKET_ERROR (-1)

# define USE_BSD_SOCKETS 1
# define HAVE_GETHOSTBYNAME 1
# define HAVE_INET_FUNCS 1 /* orig/basic inet_... */
#endif

#if (USE_BSD_SOCKETS + USE_JSYS_SOCKETS + USE_TCP_OPEN) != 1
# error "Must select exactly one socket mechanism."
#endif

#include "str789.h"

#if USE_JSYS_SOCKETS || HAVE_GTHST || USE_JSYS_READ_WITH_TCP_OPEN
# include <jsys.h>
# include <monsym.h>
# include <macsym.h>

# define dGTHLA monsym (".gthla")
# define dGTHSN monsym (".gthsn")
# define dPRIOU monsym (".priou")
# define dTCMWH monsym (".tcmwh")
/* Some, but not all, of these names */
/* are defined if we simply replace */
/* the percent by an underscore. So, */
/* we use a different convention. */
# define GJ__NEW monsym ("gj%new")
# define GJ__SHT monsym ("gj%sht")
# define GS__EOF monsym ("gs%eof")
# define OF__BSZ monsym ("of%bsz")
# define OF__MOD monsym ("of%mod")
# define OF__PLN monsym ("of%pln")
# define OF__RD monsym ("of%rd")
# define OF__WR monsym ("of%wr")

# define HALFWORDMASK 0777777
#endif
#if USE_BSD_SOCKETS
# include <sys/socket.h>
# include <netinet/in.h>
#endif
#if HAVE_GETHOSTBYNAME
# include <netdb.h>
# if SYS_T20 && (xKCCLIB_VERSION < 6)
struct in_addr
{
unsigned long s_addr;
};
# else /* SYS_T20 && (xKCCLIB_VERSION < 6) */
# include <netinet/in.h> /* struct in_addr is supposed to be in <arpa/inet.h> */
# endif /* SYS_T20 && (xKCCLIB_VERSION < 6) */
#endif /* HAVE_GETHOSTBYNAME */
#if HAVE_INET_FUNCS
# include <arpa/inet.h>
#else
# define NEED_INET_NTOA 1 /* we fabriate this if we need it */
#endif

#if defined (__APPLE_CC__)
# define HAVE_TIMEOUT_SOCKOPT 1
# if (__APPLE_CC__ < 1495) /* prior to Darwin 7.0 */
typedef int socklen_t;
# endif
#elif defined (__FreeBSD__)
# if (__FreeBSD__ < 5)
typedef uint32_t in_addr_t;
typedef uint16_t in_port_t;
# endif
# define HAVE_TIMEOUT_SOCKOPT 1
#elif defined (__linux__)
# if defined (__GNUC__) && (__GNUC__ >= 3)
# define HAVE_TIMEOUT_SOCKOPT 1
# else
typedef uint32_t in_addr_t;
typedef uint16_t in_port_t;
# endif
#elif SYS_T20
# define HAVE_TIMEOUT_SOCKOPT 0
typedef int socklen_t;
typedef unsigned short in_port_t;
typedef unsigned int in_addr_t;
# define INADDR_NONE ((in_addr_t) -1)
# define ntohs(x) (x)
# define ntohl(x) (x)
# define htons(x) (x)
# define htonl(x) (x)
# if xKCCLIB_VERSION < 6
typedef int ssize_t;
# define INADDR_LOOPBACK (unsigned long) 0x7f000001
# endif
#endif

typedef unsigned long hostnum_tp; /* 32-bit host num - in host order */
#define NULL_HOSTNUM 0
typedef unsigned short portnum_tp; /* 16-bit port num - in host order */
#define NULL_PORTNUM 0
typedef struct
{
hostnum_tp hostnum;
portnum_tp portnum;
} conninfo_tp;

#if COMPILER_KCC
# define decode_host_identifier HHdecode_host_identifier
# define poll_remote_tcp TTpoll_remote_tcp
# define poll_remote_udp UUpoll_remote_udp
# define timeout_handler TTtimeout_handler
#endif

#if ! defined (NI_MAXHOST)
# define NI_MAXHOST 1025
#endif

#if ! defined (EXIT_SUCCESS)
# define EXIT_FAILURE 1
# define EXIT_SUCCESS 0
#endif

#define OPTINDCH '-'

#define PROGNAME "netday"

#define NUL '\0'

#define THOUSAND 1000

#define DFLT_DAYTIME_PORT 13
#define MAX_DAYTIME_MSG 256

enum poll_type { unknown_POLL, udp_POLL, tcp_POLL, rtime_POLL };
enum timeout_type { unknown_TIMEOUT, sock_TIMEOUT, alarm_TIMEOUT,
posix_TIMEOUT, inherent_TIMEOUT };

double timeout = 5; /* in seconds */
bool verbose;
bool showraw;
int debug;
/* default poll type is TCP */
#if HAVE_TCP
enum poll_type poll_method = tcp_POLL;
#elif HAVE_UDP
enum poll_type poll_method = udp_POLL;
#elif HAVE_TCP
enum poll_type poll_method = tcp_POLL;
#else
enum poll_type poll_method = unknown_POLL;

#endif
enum timeout_type timout_method = unknown_TIMEOUT;

void
#if __STDC__
abort_program (int errcode, CONST char *fmt, ...)
#else
abort_program (va_alist)
va_dcl
#endif
{
va_list ap;
#if ! __STDC__
int errcode;
CONST char *fmt;
#endif

#if __STDC__
va_start (ap, fmt);
#else
va_start (ap);
errcode = va_arg (ap, int);
fmt = va_arg (ap, char *);
#endif

if (errcode == -1)
errcode = errno;
#if SYS_T20
if (errcode == -2)
errcode = -1; /* get last error from MONITOR */
#endif

fprintf (stderr, "%s: ", PROGNAME);
if (errcode != 0)
fprintf (stderr, "error: (%d) %s, ", errcode,
strerror (errcode));
vfprintf (stderr, fmt, ap);
fprintf (stderr, "\n");

va_end (ap);

exit (EXIT_FAILURE);
/* NOTREACHED */
}

#if NEED_INET_NTOA
# define Q(addr36, offset) (((addr36) >> (9 * ((offset) - 1))) & 0xff)

char *
# if __STDC__
inet_ntoa (struct in_addr in)
# else
inet_ntoa (in)
struct in_addr in;
# endif
{
static char ntoabuff [20];

sprintf (ntoabuff, "%d.%d.%d.%d",
Q (in.s_addr, 4), Q (in.s_addr, 3), Q (in.s_addr, 2), Q (in.s_addr, 1));

return ntoabuff;
}
#endif /* NEED_INET_NTOA */
#if HAVE_TIMEOUT_SOCKOPT
static struct timeval
# if __STDC__
mk_timeval (double tosecs)
# else
mk_timeval (tosecs)
double tosecs;
# endif
{
struct timeval tv;

tv.tv_sec = (time_t) tosecs;
tv.tv_usec = (long) ((tosecs - tv.tv_sec) * 1e6);

if ((tosecs != 0) && (tv.tv_sec == 0) && (tv.tv_usec == 0))
tv.tv_usec = 1;

return tv;
}
#endif

void
#if __STDC__
report_attempt (CONST char *method, CONST conninfo_tp *cip)
#else
report_attempt (method, cip)
CONST char *method;
CONST conninfo_tp *cip;
#endif
{
struct in_addr ina;

if (! verbose) return;

ina.s_addr = htonl (word32to36 (cip->hostnum));
printf ("Fetching time from %s:%d via %s\n",
inet_ntoa (ina), cip->portnum, method);
}

hostnum_tp
#if __STDC__
decode_host_identifier (CONST char *hostid)
#else
decode_host_identifier (hostid)
CONST char *hostid;
#endif
{
hostnum_tp hostnum;

#if HAVE_GTHST
/* TODO: apparently the GTDOM JSYS would do a better job of this */
{
int result, acs [5];

acs [1] = dGTHSN; /* host name to number */
acs [2] = (int) &hostid [-1];

result = jsys (GTHST, acs);
if (debug >= 2)
fprintf (stderr,
"GTHST jsys => %d, acs[01234] = %12lo %12lo %12lo %12lo %12lo\n",
result, acs [0], acs [1], acs [2], acs [3], acs [4]);
if (result == 2)
{
hostnum = acs [3];
if (debug >= 2)
fprintf (stderr,
"GTHST returns hostnum => %12.12lo\n",
(long) hostnum);
return hostnum;
}
if (debug >= 1)
fprintf (stderr, "GTHST returns error: %d => %s\n",
acs [0], strerror (-1));
}
#endif /* HAVE_GTHST */

#if HAVE_GETHOSTBYNAME
{
struct hostent *hp;
hp = gethostbyname (hostid);
if (hp != NULL)
{
in_addr_t in_addr;

assert (hp->h_addrtype == AF_INET);
assert (sizeof in_addr == hp->h_length);
# if SYS_T20
memcpy (&in_addr, hp->h_addr, sizeof in_addr);
# else
memcpy (&in_addr, hp->h_addr_list [0], sizeof in_addr);
# endif
hostnum = ntohl (word36to32 (in_addr));
if (debug >= 2)
{
struct in_addr sin_addr;

sin_addr.s_addr = in_addr;
fprintf (stderr, "GHBN returns hostnum => %s\n",
inet_ntoa (sin_addr));
}
return hostnum;
}
}
#endif /* HAVE_GETHOSTBYNAME */

#if HAVE_INET_FUNCS
{
struct in_addr sin_addr;

sin_addr.s_addr = inet_addr (hostid);
if (sin_addr.s_addr != INADDR_NONE)
{
hostnum = ntohl (word36to32 (sin_addr.s_addr));
if (debug >= 2)
fprintf (stderr, "inet_addr -> %12.12lo\n",
(long) hostnum);
return hostnum;
}
}
#else /* HAVE_INET_FUNCS */
{
int count;
unsigned int h1, h2, h3, h4;

if (sscanf (hostid, "%u.%u.%u.%u", &h1, &h2, &h3, &h4) == 4)
{
hostnum = 0;
hostnum |= h1 << 24;
hostnum |= h2 << 16;
hostnum |= h3 << 8;
hostnum |= h4 << 0;

if (debug >= 2)
fprintf (stderr, "quad decode -> %12.12lo\n",
(long) hostnum);
return hostnum;
}
}
#endif /* HAVE_INET_FUNCS */

if (debug >= 1)
fprintf (stderr, "didn't match any host name\n");

return NULL_HOSTNUM;
}

void
#if __STDC__
timeout_handler (int signum)
#else
timeout_handler (signum)
int signum;
#endif
{
(void) signum;

abort_program (ETIMEDOUT, "Attempt to contact remote host");
}

void
#if __STDC__
set_alarm_timeout (double tout_secs)
#else
set_alarm_timeout (tout_secs)
double tout_secs;
#endif
{
unsigned int alrm_secs = (unsigned int) tout_secs;

if (debug >= 3)
fprintf (stderr, "Setting alarm for %d secs\n", alrm_secs);

assert (tout_secs != 0);

signal (SIGALRM, timeout_handler);

if (alrm_secs == 0)
alrm_secs = 1;
alarm (alrm_secs);
}

#if HAVE_TIMEOUT_SOCKOPT
void
# if __STDC__
set_socktimeout (SOCKET sockfd, double tout_secs)
# else
set_socktimeout (sockfd, tout_secs)
SOCKET sockfd;
double tout_secs;
# endif
{
struct timeval timout;

timout = mk_timeval (tout_secs);

assert (tout_secs != 0);

if (debug >= 2)
fprintf (stderr, "SO_SNDTIMEO: %ld:%06ld\n",
(long) timout.tv_sec, (long) timout.tv_usec);

if (setsockopt (sockfd, SOL_SOCKET, SO_SNDTIMEO,
(CONST void *) &timout, sizeof timout) != 0)
abort_program (-1, "setsockopt SO_SNDTIMEO");

if (setsockopt (sockfd, SOL_SOCKET, SO_RCVTIMEO,
(CONST void *) &timout, sizeof timout) != 0)
abort_program (-1, "setsockopt SO_RCVTIMEO");
}
#endif /* HAVE_TIMEOUT_SOCKOPT */

void
#if __STDC__
set_timeout (SOCKET sockfd, double tout_secs)
#else
set_timeout (sockfd, tout_secs)
SOCKET sockfd;
double tout_secs;
#endif
{
(void) sockfd;

if (timeout == 0)
return; /* no timeout desired */

if (debug >= 1)
fprintf (stderr, "Setting timeout to %f seconds\n", tout_secs);

switch (timout_method)
{
#if HAVE_TIMEOUT_SOCKOPT
case sock_TIMEOUT:
set_socktimeout (sockfd, timeout);
break;
#endif
case alarm_TIMEOUT:
set_alarm_timeout (timeout);
break;
default:
assert (! "No timeout mechanism known");
}
}

void
#if __STDC__
mkopendescriptor (char *buffp, size_t buffsize, CONST conninfo_tp *cip)
#else
mkopendescriptor (buffp, buffsize, cip)
char *buffp;
size_t buffsize;
CONST conninfo_tp *cip;
#endif
{
sprintf (buffp,
"TCP:.%lo-%d;CONNECTION:ACTIVE", cip->hostnum, cip->portnum);
if (timeout != 0)
{
char *sptr = strchr (buffp, NUL);

sprintf (sptr, ";PERSIST:%d;TIMEOUT:%d",
(int) timeout, (int) timeout);
}
if (debug >= 2)
fprintf (stderr, "open descriptor = '%s'\n", buffp);

assert (strlen (buffp) < buffsize);
}

/* Requires that msg have space for a trailing NUL! */
void
#if __STDC__
display_daytime_msg (char *msgp, size_t msglen)
#else
display_daytime_msg (msgp, msglen)
char *msgp;
size_t msglen;
#endif
{
if (showraw)
fwrite (msgp, 1, msglen, stdout);
else
{
size_t indx;

msgp [msglen] = NUL;
while ((msglen > 0) && isspace (msgp [msglen - 1]))
msgp [--msglen] = NUL;

/* Rid the message of vile characters. */
/* Note that we use the length here in */
/* case there is an embedded NUL. */
for (indx = 0 ; indx < msglen ; ++indx)
{
int ch = msgp [indx];

if (! (isgraph (ch) || isspace (ch)))
msgp [indx] = '?';
}
printf ("%s\n", msgp);
}
}

#if HAVE_TCP
ssize_t
# if __STDC__
read_tcp_data (SOCKET sockfd, char *buffp, size_t buffsize)
# else
read_tcp_data (sockfd, buffp, buffsize)
SOCKET sockfd;
char *buffp;
size_t buffsize;
# endif
{
ssize_t numxferred;

if (debug >= 1)
fprintf (stderr, "Waiting for data from remote host.\n");

if (debug >= 3)
fprintf (stderr, "sockfd at read = %d\n", sockfd);

# if (USE_BSD_SOCKETS || USE_TCP_OPEN) && (! USE_JSYS_READ_WITH_TCP_OPEN)
numxferred = recv (sockfd, buffp, buffsize, 0);
# elif USE_JSYS_SOCKETS || USE_JSYS_READ_WITH_TCP_OPEN
{
int result, acs [5];
ssize_t count1, count2;

#if USE_JSYS_READ_WITH_TCP_OPEN
int jfn;
fprintf (stderr, "Using JSYS read w/ TCP open\n");
jfn = fcntl (sockfd, F_GETSYSFD, 0);
fprintf (stderr, "jfn for sockfd %d is %d\n", sockfd, jfn);
sockfd = jfn;
#endif
acs [1] = sockfd;
acs [2] = (int) &buffp [-1];
acs [3] = buffsize;

if (debug >= 3)
fprintf (stderr,
"SIN acs in [123]: %lo, %12.12lo, %lo\n",
acs [1], acs [2], acs [3]);
result = jsys (SIN, acs);
if (debug >= 3)
fprintf (stderr,
"SIN out [0123]: %lo, %lo, %12.12lo, %lo\n",
acs [0], acs [1], acs [2], acs [3]);
if (debug >= 2)
{
int *p = (int *) buffp;
fprintf (stderr, "rcvd msg: %9.9lx, %9.9lx, %9.9lx\n",
p [0], p [1], p [2]);
}
/* save the count value before it goes away */
count1 = (char *) acs [2] - (buffp - 1);
count2 = buffsize - acs [3];
if (debug >= 3)
{
fprintf (stderr, "count1 = %ld\n", (long) count1);
fprintf (stderr, "count2 = %ld\n", (long) count2);
}
if (result != 1)
{
if (debug >= 1)
fprintf (stderr, "SIN JSYS failed: %d - %s\n",
result, strerror (-1));

acs [1] = sockfd;

if (jsys (GTSTS, acs) != 1)
abort_program (-2, "GTSYS failed");
if ((acs [2] & GS__EOF) != GS__EOF)
{
return SOCKET_ERROR;
}
}
assert (count1 == count2);
numxferred = count1;
}
# else /* USE_BSD_SOCKETS || USE_TCP_OPEN */
# error "invalid #if/#else construct"
# endif /* USE_BSD_SOCKETS || USE_TCP_OPEN */
if (debug >= 2)
fprintf (stderr,
"Received %ld bytes from remote host (errno = %d).\n",
(long) numxferred, errno);
if (debug >= 3)
{
const long *p = (const long *) buffp;
fprintf (stderr, "buffp @ %12.12lo\n", (long) buffp);
fprintf (stderr, "buffp => %9.9lx %9.9lx %9.9lx %9.9lx\n",
p [0], p [1], p [2], p [3]);
fprintf (stderr, "buffp => %12.12lo %12.12lo %12.12lo %12.12lo\n",
p[0], p[1], p[2], p[3]);
}
if (numxferred == SOCKET_ERROR)
return SOCKET_ERROR;

return numxferred;
}
#endif /* HAVE_TCP */

#if HAVE_TCP
bool
# if __STDC__
poll_remote_tcp (SOCKET sockfd, CONST conninfo_tp *cip)
# else
poll_remote_tcp (sockfd, cip)
SOCKET sockfd;
CONST conninfo_tp *cip;
# endif
{
ssize_t numxferred;
char netmsg [MAX_DAYTIME_MSG + 1];

# if USE_BSD_SOCKETS
{
struct sockaddr_in sai;

memset (&sai, 0, sizeof sai);

sai.sin_family = AF_INET;
sai.sin_addr.s_addr = htonl (word32to36 (cip->hostnum));
sai.sin_port = htons (cip->portnum);
if (debug >= 2)
{
fprintf (stderr, "hostnum = %lx\n", (long) cip->hostnum);
fprintf (stderr, "sin_addr = %lx\n", (long) sai.sin_addr.s_addr);
}

if (connect (sockfd, (CONST struct sockaddr *) &sai, sizeof sai) != 0)
{
switch (errno)
{
case ECONNREFUSED:
case ETIMEDOUT:
case EADDRNOTAVAIL:
case ENETUNREACH:
return false;
}
abort_program (-1, "connect");
}
}
# elif USE_JSYS_SOCKETS
{
int acs [5];

(void) cip;

acs [1] = sockfd;
acs [2] = FLD (8, OF__BSZ) | FLD (dTCMWH, OF__MOD)
| OF__RD | OF__WR | OF__PLN;
/* 8 bit bytes, high throughput, read/write */

if (jsys (OPENF, acs) != 2)
{
if (debug >= 1)
fprintf (stderr, "OPENF JSYS failed: %s\n",
strerror (-1));
return false;
}
}
# elif USE_TCP_OPEN
/* nothing to do ? */
# else /* USE_BSD_SOCKETS */
# error "Invalid #if/#else"
# endif /* USE_BSD_SOCKETS */

numxferred = 0;
for ( ; ; )
{
ssize_t numread = read_tcp_data (sockfd, netmsg + numxferred,
sizeof netmsg - 1 - numxferred);

if (numread == SOCKET_ERROR)
return false;
if (numread == 0)
break;
numxferred += numread;
}

display_daytime_msg (netmsg, numxferred);

return true;
}
#endif /* HAVE_TCP */

#if HAVE_TCP
bool
# if __STDC__
fetchtcptime (CONST conninfo_tp *cip)
# else
fetchtcptime (cip)
CONST conninfo_tp *cip;
# endif
{
SOCKET sockfd;
bool result;

report_attempt ("TCP", cip);

if (debug >= 1)
fprintf (stderr, "Creating TCP socket\n");

# if USE_BSD_SOCKETS
sockfd = socket (AF_INET, SOCK_STREAM, 0);
# elif USE_JSYS_SOCKETS
{
int acs [5];
char openname [256];

mkopendescriptor (openname, sizeof openname, cip);

acs [1] = GJ__SHT | GJ__NEW;
acs [2] = (int) &openname [-1];

if (jsys (GTJFN, acs) != 2)
{
if (debug >= 1)
fprintf (stderr, "GTJFN JSYS failed: %s\n",
strerror (-1));
return false;
}

sockfd = acs [1];
}
# elif USE_TCP_OPEN
{
char openbuf [256];

mkopendescriptor (openbuf, sizeof openbuf, cip);

sockfd = open (openbuf, O_RDWR | O_BINARY | O_BSIZE_8);
}
# else /* USE_BSD_SOCKETS */
# error "Invalid #if/#else construct"
# endif /* USE_BSD_SOCKETS */
if (debug >= 2)
fprintf (stderr, "sockfd = %d, errno = %d, lasterr = %s\n",
sockfd, errno, strerror (-1));
if (sockfd == INVALID_SOCKET)
abort_program (-1, "opening socket");

# if ! SYS_T20
set_timeout (sockfd, timeout);
# endif

result = poll_remote_tcp (sockfd, cip);

# if USE_BSD_SOCKETS || USE_TCP_OPEN
CLOSESOCKET (sockfd);
# elif USE_JSYS_SOCKETS
{
int result, acs [5];

acs [1] = (sockfd & HALFWORDMASK);
result = jsys (CLOSF, acs);
}
# else /* USE_BSD_SOCKETS || USE_TCP_OPEN */
# error "invalid #if/#else construct"
# endif /* USE_BSD_SOCKETS || USE_TCP_OPEN */

return result;
}
#endif /* HAVE_TCP */

#if HAVE_UDP
bool
# if __STDC__
poll_remote_udp (SOCKET sockfd, CONST struct sockaddr_in *saip, socklen_t salen)
# else
poll_remote_udp (sockfd, saip, salen)
SOCKET sockfd;
CONST struct sockaddr_in *saip;
socklen_t salen;
# endif
{
ssize_t numxferred;
socklen_t addrsize;
char netmsg [MAX_DAYTIME_MSG + 1];
struct sockaddr_in fromsai;

if (debug >= 1)
fprintf (stderr, "Sending data to remote host.\n");

numxferred = sendto (sockfd, (char *) netmsg, 0, 0,
(struct sockaddr *) saip, salen);
if (numxferred == SOCKET_ERROR)
return false;
if (numxferred != 0)
{
errno = EIO;
return false;
}

if (debug >= 1)
fprintf (stderr, "Waiting for data from remote host.\n");

addrsize = sizeof fromsai;
numxferred = recvfrom (sockfd, (char *) netmsg, sizeof netmsg - 1,
0, (struct sockaddr *) &fromsai, &addrsize);
if (debug >= 2)
fprintf (stderr,
"Received %d bytes from remote host (errno = %d)\n",
(int) numxferred, errno);
if (numxferred == SOCKET_ERROR)
{
if (errno == EAGAIN)
errno = ETIMEDOUT;
return false;
}

display_daytime_msg (netmsg, numxferred);

return true;
}
#endif /* HAVE_UDP */

#if HAVE_UDP
bool
# if __STDC__
fetchudptime (CONST conninfo_tp *cip)
# else
fetchudptime (cip)
CONST conninfo_tp *cip;
# endif
{
SOCKET sockfd;
bool result;
struct sockaddr_in sai;

report_attempt ("UDP", cip);

if (debug >= 1)
fprintf (stderr, "Creating UDP socket\n");

memset (&sai, 0, sizeof sai);

sai.sin_family = AF_INET;
sai.sin_addr.s_addr = htonl (word32to36 (cip->hostnum));
sai.sin_port = htons (cip->portnum);

sockfd = socket (sai.sin_family, SOCK_DGRAM, 0);
if (sockfd == INVALID_SOCKET)
abort_program (-1, "opening socket");

set_timeout (sockfd, timeout);

result = poll_remote_udp (sockfd, &sai, sizeof sai);

CLOSESOCKET (sockfd);

return result;
}
#endif /* HAVE_UDP */

bool
#if __STDC__
fetch_nettime (CONST conninfo_tp *cip)
#else
fetch_nettime (cip)
CONST conninfo_tp *cip;
#endif
{
bool result = false;

switch (poll_method)
{
#if HAVE_TCP
case tcp_POLL:
result = fetchtcptime (cip);
if (! result)
return false;

break;
#endif /* HAVE_TCP */
#if HAVE_UDP
case udp_POLL:
result = fetchudptime (cip);
if (! result)
return false;

break;
#endif /* HAVE_UDP */
default:
assert (! "Internal error: invalid switch in getnetime");
}

return result;
}

hostnum_tp
#if __STDC__
get_loopback_id (void) /* this returns a 32-bit number */
#else
get_loopback_id ()
#endif
{
#if SYS_T20
return gethostid ();
#elif HAVE_GTHST /* this won't get selected, but we save the code */
{
int hostnum, result, acs [5];

acs [1] = dGTHLA; /* get all local addresses */
acs [3] = (int) &hostnum;
acs [4] = 1; /* but we really only want one */

result = jsys (GTHST, acs);
if (debug >= 2)
fprintf (stderr,
"GTHST jsys => %d, acs[01234] = %12lo %12lo %12lo %12lo %12lo\n",
result, acs [0], acs [1], acs [2], acs [3], acs [4]);
if (result == 2)
{
if (debug >= 2)
fprintf (stderr,
"GTHST returns local hostnum => %12.12lo\n",
(long) hostnum);
return hostnum;
}
if (debug >= 1)
fprintf (stderr, "GTHST returns error: %d => %s\n",
acs [0], strerror (-1));

}
#endif /* SYS_T20 */

return INADDR_LOOPBACK;
}

bool
#if __STDC__
getnettime (CONST char *hostname, portnum_tp portnum)
#else
getnettime (hostname, portnum)
CONST char *hostname;
portnum_tp portnum;
#endif
{
conninfo_tp conninfo;

#if SYS_T20
if ((hostname == NULL) || (strcmp (hostname, "localhost") == 0))
#else
if (hostname == NULL)
#endif
{
conninfo.hostnum = get_loopback_id ();
if (debug >= 2)
fprintf (stderr, "NULL hostname => %12.12lo\n",
(long) conninfo.hostnum);
}
else
{
hostnum_tp hostnum;

hostnum = decode_host_identifier (hostname);
if (hostnum == NULL_HOSTNUM)
abort_program (-1, "Unable to decode hostname: %s",
hostname);
conninfo.hostnum = hostnum;
}

conninfo.portnum = portnum;

return fetch_nettime (&conninfo);

}

void
#if __STDC__
prusage (void)
#else
prusage ()
#endif
{
fprintf (stderr, "Displays time at a remote host via DAYTIME protocol.\n");
fprintf (stderr, "Usage is:\n");
fprintf (stderr, " %s [ options ] [ hostname [ timeport ]]\n", PROGNAME);
fprintf (stderr, "Options are\n");
# if HAVE_TCP
fprintf (stderr, " %ct use TCP protocol (default)\n", OPTINDCH);
# endif /* HAVE_TCP */
# if HAVE_UDP
fprintf (stderr, " %cu use UDP protocol\n", OPTINDCH);
# endif /* HAVE_UDP */
fprintf (stderr, " %cv be verbose\n", OPTINDCH);
fprintf (stderr, " %cr emit the raw message as received\n", OPTINDCH);
fprintf (stderr, " %cT secs set timeout\n", OPTINDCH);
fprintf (stderr, " %cA use alarm timeout method\n", OPTINDCH);
# if HAVE_TIMEOUT_SOCKOPT
fprintf (stderr, " %cS use socket timeout method\n", OPTINDCH);
# endif

exit (2);
}

#if SYS_T20 && (xKCCLIB_VERSION < 6)
extern int optind;
extern char *optarg;
#endif

void
#if __STDC__
initialize (int argc, char *argv [])
#else
initialize (argc, argv)
int argc;
char *argv [];
#endif
{
bool errflag = false;
int ch;

while ((ch = getopt (argc, argv, "!ArST:tuvZ")) != -1)
{
switch (ch)
{
case '!': case 'Z':
++debug;
break;
case 'A':
timout_method = alarm_TIMEOUT;
break;
case 'r':
showraw = true;
break;
# if HAVE_TIMEOUT_SOCKOPT
case 'S':
timout_method = sock_TIMEOUT;
break;
# endif
case 'T':
timeout = strtod (optarg, NULL);
break;
# if HAVE_TCP
case 't':
poll_method = tcp_POLL;
break;
# endif /* HAVE_TCP */
# if HAVE_UDP
case 'u':
poll_method = udp_POLL;
break;
# endif /* HAVE_UDP */
case 'v':
verbose = true;
break;
case '?':
default:
errflag = true;
break;

}
}

if (timout_method == unknown_TIMEOUT)
{
# if HAVE_TIMEOUT_SOCKOPT
timout_method = sock_TIMEOUT;
# else
timout_method = alarm_TIMEOUT;
# endif
}

if (errflag)
prusage ();

if (debug >= 1)
{
# if USE_BSD_SOCKETS
fprintf (stderr, "Using BSD sockets\n");
# elif USE_JSYS_SOCKETS
fprintf (stderr, "Using JSYS sockets\n");
# elif USE_TCP_OPEN
fprintf (stderr, "Using special TCP open\n");
# else
# error "Invalid #if/#else case"
# endif
}
}

int
#if __STDC__
main (int argc, char *argv [])
#else
main (argc, argv)
int argc;
char *argv [];
#endif
{
CONST char *hostname = NULL, *hostpname = NULL;
portnum_tp portnum = DFLT_DAYTIME_PORT;
bool result;

initialize (argc, argv);

switch (argc - optind)
{
default:
prusage ();

case 2: portnum = atol (argv [optind + 1]);
/* FALLTHROUGH */
case 1: hostname = argv [optind + 0];
/* FALLTHROUGH */
case 0:
break;
}

hostpname = (hostname != NULL) ? hostname : "(localhost)";

result = getnettime (hostname, portnum);
if (! result)
abort_program (-1, "Unable to get time from %s", hostpname);

return result ? EXIT_SUCCESS : EXIT_FAILURE;
}

----------------- snip here ---------------------------------


Alan Frisbie

unread,
Aug 21, 2021, 2:36:33 PM8/21/21
to
On 8/21/21 6:18 AM, Dan Cross wrote:

> You're surely referring to W. Richard Stevens's "Unix Network
> Programming".
> ...
> Stevens's book is now in its 3rd edition, carried on after
> Stevens's untimely death by Bill Fenner and Andrew Rudoff.
I'm sorry, but I must have an extremely sick mind. When I
read this, an alternative meaning sprang forth: that Stevens's
death was *caused* by Fenner and Rudoff. Perhaps I should
seek help. :-) :-) :-)

Alan Frisbie

fishtoprecords

unread,
Aug 21, 2021, 8:11:50 PM8/21/21
to
There was none that I knew of for TOPS-20. DEC (or LCG) sold special Tops20-AN versions. AN was for "Arpanet networking"
which was for sinners, since all true believers thought DEC's OSI/IOS based DECnet was the future. It was impossible to get any information about TOPS20AN from my local DEC salesman.

I have no idea why LCG pushed DECnet so hard, since they delivered pretty braindead and restricted versions of DECnet until post-Jupiter cancellation at which point TOPS-20 was no longer a viable product to market.

gah4

unread,
Aug 22, 2021, 5:01:07 AM8/22/21
to
On Saturday, August 21, 2021 at 6:18:45 AM UTC-7, Dan Cross wrote:
> In article <fd4f04dc-4989-4bd1...@googlegroups.com>,

(snip, I wrote)
> >My favorite book series has two versions of vol. 3, on the API for
> >using TCP/IP. One is BSD/sockets, and the other is TLI.

> You're surely referring to W. Richard Stevens's "Unix Network
> Programming". The second edition of those books was shipped in
> two volumes: one covering BSD sockets and XTI, the other
> covering other forms of IPC (pipes, SYSV shared memory, message
> passing, a bunch of multithreading topics around critical
> sections and mutual exclusion, etc).

Actually, it is the Comer books. I know about Stevens' books, but
started with the Comer books and still like them.

I think I got the TLI book at a thrift store, not completely knowing
what the difference was at the time.

> It's probably worthwhile pointing out that every extant modern
> version of Unix ships with sockets, and almost nothing uses TLI.
> Historical versions of System V derivitives might ship with the
> latter, however.

The unusual part about sockets, or at least ones with BSD heritage,
is that sockets and file descriptors are in the same address space.
One can use either send/recv or read/write with them. I believe some
implementations without Unix heritage don't do that.

Dan Cross

unread,
Aug 22, 2021, 7:58:36 PM8/22/21
to
In article <DYWdnXODAP422rz8...@supernews.com>,
Ha! I can't image Bill Fenner engaging in violence. :-)

- Dan C.

Dan Cross

unread,
Aug 22, 2021, 8:06:38 PM8/22/21
to
In article <e4d3ab65-d384-422c...@googlegroups.com>,
gah4 <ga...@u.washington.edu> wrote:
>On Saturday, August 21, 2021 at 6:18:45 AM UTC-7, Dan Cross wrote:
>> In article <fd4f04dc-4989-4bd1...@googlegroups.com>,
>
>(snip, I wrote)
>> >My favorite book series has two versions of vol. 3, on the API for
>> >using TCP/IP. One is BSD/sockets, and the other is TLI.
>
>> You're surely referring to W. Richard Stevens's "Unix Network
>> Programming". The second edition of those books was shipped in
>> two volumes: one covering BSD sockets and XTI, the other
>> covering other forms of IPC (pipes, SYSV shared memory, message
>> passing, a bunch of multithreading topics around critical
>> sections and mutual exclusion, etc).
>
>Actually, it is the Comer books. I know about Stevens' books, but
>started with the Comer books and still like them.

Ah. Comer's books are quite good, if a little dated at this point.

>I think I got the TLI book at a thrift store, not completely knowing
>what the difference was at the time.

Ha! That's quite a find.

>> It's probably worthwhile pointing out that every extant modern
>> version of Unix ships with sockets, and almost nothing uses TLI.
>> Historical versions of System V derivitives might ship with the
>> latter, however.
>
>The unusual part about sockets, or at least ones with BSD heritage,
>is that sockets and file descriptors are in the same address space.
>One can use either send/recv or read/write with them. I believe some
>implementations without Unix heritage don't do that.

That's not quite true; socket descriptors and file descriptors
provide similar mechanisms for IO using e.g. read/write/close,
but the similarly stops there: one cannot send/recv to/from a
file, for example. Similarly, `select` on a file always returns
immediately, as the file is always "ready" for reading/writing;
the idea of blocking for more data to show up is specific to IPC.

Sockets also exist outside of the filesystem name space, which
is a bit of an unfortunate defect in the design of the mechanism.

- Dan C.

gah4

unread,
Aug 23, 2021, 4:01:56 AM8/23/21
to
On Sunday, August 22, 2021 at 5:06:38 PM UTC-7, Dan Cross wrote:
> In article <e4d3ab65-d384-422c...@googlegroups.com>,

(snip, I wrote)
> >Actually, it is the Comer books. I know about Stevens' books, but
> >started with the Comer books and still like them.

> Ah. Comer's books are quite good, if a little dated at this point.
> >I think I got the TLI book at a thrift store, not completely knowing
> >what the difference was at the time.

> Ha! That's quite a find.

(snip)
> >The unusual part about sockets, or at least ones with BSD heritage,
> >is that sockets and file descriptors are in the same address space.
> >One can use either send/recv or read/write with them. I believe some
> >implementations without Unix heritage don't do that.

> That's not quite true; socket descriptors and file descriptors
> provide similar mechanisms for IO using e.g. read/write/close,
> but the similarly stops there: one cannot send/recv to/from a
> file, for example. Similarly, `select` on a file always returns
> immediately, as the file is always "ready" for reading/writing;
> the idea of blocking for more data to show up is specific to IPC.

I conveniently didn't say that you could send/recv on a file.
Mostly this come into the way that inetd works, where the new
task uses fd/socket 0. (I haven't thought about this for a while,
I believe also fd/socket 1.)

So, a program can read/write stdin/stdout without knowing anything
about sockets. But otherwise, if it can send/recv on socket 0, it is
probably close enough.

Dan Cross

unread,
Aug 23, 2021, 8:15:50 AM8/23/21
to
In article <79829bbf-15bb-486c...@googlegroups.com>,
gah4 <ga...@u.washington.edu> wrote:
>On Sunday, August 22, 2021 at 5:06:38 PM UTC-7, Dan Cross wrote:
>> In article <e4d3ab65-d384-422c...@googlegroups.com>,
>
>(snip, I wrote)
>> >Actually, it is the Comer books. I know about Stevens' books, but
>> >started with the Comer books and still like them.
>
>> Ah. Comer's books are quite good, if a little dated at this point.
>> >I think I got the TLI book at a thrift store, not completely knowing
>> >what the difference was at the time.
>
>> Ha! That's quite a find.
>
>(snip)
>> >The unusual part about sockets, or at least ones with BSD heritage,
>> >is that sockets and file descriptors are in the same address space.
>> >One can use either send/recv or read/write with them. I believe some
>> >implementations without Unix heritage don't do that.
>
>> That's not quite true; socket descriptors and file descriptors
>> provide similar mechanisms for IO using e.g. read/write/close,
>> but the similarly stops there: one cannot send/recv to/from a
>> file, for example. Similarly, `select` on a file always returns
>> immediately, as the file is always "ready" for reading/writing;
>> the idea of blocking for more data to show up is specific to IPC.
>
>I conveniently didn't say that you could send/recv on a file.

Perhaps I misunderstood your comment where you said that,
"One can use either send/recv or read/write with them."

That was in the context of discussing how files and sockets
are were in the same address space. My point is that that is
only true that in a socket descriptor is an index in the
process's local descriptor table and can be the target of a
handful of overlapping IO calls. However, the similarity
stops there.

>Mostly this come into the way that inetd works, where the new
>task uses fd/socket 0. (I haven't thought about this for a while,
> I believe also fd/socket 1.)

No. Read/write/close on a socket descriptor predate the
existance of inetd, and date back to the original `namei`
hacks used in network Unix and the BBN TCP/IP prototype.
It was done that way because that's just how Unix does IO,
but people quickly realized that networking required a
richer API than that used for simple local filesystems,
hence send/recv/sendmsg/recvmsg etc.

Inetd was created in response to the overhead involved in
having multiple independent network daemons running on
overloaded timesharing machines; it was cheaper to have
one program that mux'ed the network listening duties and
spent most of its time blocked on select(2).

You are correct that file descriptor 1 is dup'ed to the
socket by inetd, though. It also dup's the socket to 2
(standard error).

>So, a program can read/write stdin/stdout without knowing anything
>about sockets. But otherwise, if it can send/recv on socket 0, it is
>probably close enough.

A delve into Unix history is always nice, but I'm afraid this
is all rather far-afield from network programming for TOPS-20
at this point. :-)

- Dan C.

Message has been deleted
Message has been deleted

gah4

unread,
Aug 24, 2021, 4:16:33 AM8/24/21
to
On Monday, August 23, 2021 at 5:15:50 AM UTC-7, Dan Cross wrote:

(snip, I wrote)
> >So, a program can read/write stdin/stdout without knowing anything
> >about sockets. But otherwise, if it can send/recv on socket 0, it is
> >probably close enough.

> A delve into Unix history is always nice, but I'm afraid this
> is all rather far-afield from network programming for TOPS-20
> at this point. :-)

I didn't get into network programming until some years after using TOPS-20
(and the system was sold).

But some searches seemed to say that the ideas behind BSD and sockets
originated with TOPS-20. I couldn't find enough detail to see which parts
those were, though.



Dan Cross

unread,
Aug 24, 2021, 1:11:18 PM8/24/21
to
In article <2d0c83ca-7c71-4cd8...@googlegroups.com>,
Doug Wells addressed this in <16295669...@nowhere.invalid>.
The idea of "sockets" as endpoints for network connections has been
floating around since the earliest ARPANET days, but the Unix
implementation is pretty well independent of that for TOPS-20.

- Dan C.

PoBe

unread,
Aug 27, 2021, 2:05:04 AM8/27/21
to
I tried KCC-6 with some success. I got a client and server program working and interacting with Linux host. The client side was fairly straight forward and I was able to use the standard socket interface.
The server side was a bit more interesting since the KCC-6 libs did not contain any support for server side i.e. bind and listening. However the info need for the server part was in JSYS_REFERENCE.MEM (5-28)

https://groups.google.com/g/alt.sys.pdp10/c/ZCX-pM3VM3M/m/gZPrDNRXAgAJ

sample code are found in github https://github.com/hoddmimes/tops20-tcp

Questor

unread,
Aug 28, 2021, 3:38:31 PM8/28/21
to
On Sat, 21 Aug 2021 17:11:49 -0700 (PDT), fishtoprecords <pat2...@gmail.com>
wrote:
>There was none that I knew of for TOPS-20. DEC (or LCG) sold special Tops20-AN
>versions. AN was for "Arpanet networking"

Yes. There was a full suite of TOPS-20 monitors for ARPAnet sites: small,
medium, large, and max, which had support for the appropriate hardware and
software. As noted elsewhere, the usual file JSYSes are used with ARPAnet
specific file specifications. The details should be found in the JSYS manual.
(I can't remember its exact name off the top of my head.) I never played with
the ARPAnet stuff myself; that was Kevin P.'s domain as I recall.


>which was for sinners, since all true believers thought DEC's OSI/IOS based
>DECnet was the future. It was impossible to get any information about TOPS20AN
>from my local DEC salesman.

Proprietary networks were still a thing in the years around 1980, and there was
no clear indication that everything would be connected and everyone would
eventually settle on TCP/IP as a kind of universal standard. I can't explain
your salesman's behavior, but if you were already an Arpanet site then you had
an ARPAnet monitor; if you weren't an ARPAnet site then why would you want one?
I can't recall any demand on the part of TOPS-20 customers to create private
networks using TCP/IP instead of DECnet.


>I have no idea why LCG pushed DECnet so hard, since they delivered pretty
>braindead and restricted versions of DECnet until post-Jupiter cancellation at
>which point TOPS-20 was no longer a viable product to market.

There is hardly even a grease stain left where this expired equus has been
flogged, both in this forum and elsewhere, so I'll try to keep this brief.

While the PDP-10 line was profitable, DEC's bread and butter was the PDP-11,
and then the VAX. The VAX was immensely popular and propelled DEC to being the
second largest computer company in the world. So the VAX and VMS was largely
where the focus, the money, and the resources went.

Of course a follow-on to the KL-10 should have been started in the mid-1970s,
but it wasn't. As the VAX took off, follow-on products both large and small
were quickly approved and started. There was plenty of talk in LCG about
different projects -- a bigger PDP-10, a personal, under-the-desk model, etc. --
but it was just talk. Eventually one project was chosen -- and it was called
Jupiter, a much bigger, faster PDP-10 than the KL-10.

TOPS-20 (and TOPS-10) development then fell prey to an internal version of
a problem that some computer companies face: they announce an improved version
of their product, so customers wait for it and hold off purchasing the existing
products, starving the company of revenue. Similarly, any development on
the existing KL-10 and TOPS-20 essentially ceased, with all the effort going
into the expected new machine. The KL and TOPS-20 were already showing their
limitations by the turn of the decade, but the bigger and faster Jupiter was
going to Fix Everything(tm), and Real Soon Now(tm).

One of the places where TOPS-20 was bulging at the seams was DECnet. The DN20
memory was limited to 128K, and it was already stuffed full just for Phase III
DECnet. There was barely any room for new edits in response to SPRs, and
Phase IV DECnet was out of the question. The Jupiter was going to have bigger,
beefier PDP-11s as front-ends, among other wonders. So TOPS-20 was stuck at
Phase III, limited to just 256 notes, while the VAX was coming out with
Phase IV, with Ethernet support and an expansion to thousands of potential
nodes. Of course LCG promoted DECnet -- apart from being DEC's product, it was
the lingua franca for connecting DEC computers. And the new PDP-10 was going to
have Phase IV Any Day Now(tm).

We know what happened next. The Jupiter hardware project ran into problems, and
there were delays, and eventually it was realized that the chosen design just
couldn't meet the necessary performance levels needed to make the machine fast
enough to be a viable PDP-10 follow-on. The decision was made to pull the plug
on both the Jupiter and the entire PDP-10 product line. DEC pledged to provide
several years of maintenance in order to provide a soft(er) landing and an
eventual migration path away from TOPS-20 and TOPS-10. At that point a full
pivot was made and development focused on what modest improvements could be made
to the existing products. There was no help for the DN20, but with addition of
the Massbus-based Network Interconnect (NI) and new versions of TOPS-20 and
TOPS-10 with Ethernet support, those machines could more fully participate in
DECnet Phase IV networks.

So that's why TOPS-20 DECnet was so limited until after the Jupiter was
cancelled The eventual release of upgraded DECnet support wasn't intended to be
a selling point for TOPS-20 machines, but rather a bone thrown to existing
customers to ease their pain.
.

fishtoprecords

unread,
Aug 30, 2021, 9:53:02 PM8/30/21
to
On Saturday, August 28, 2021 at 3:38:31 PM UTC-4, Questor wrote:
> So that's why TOPS-20 DECnet was so limited until after the Jupiter was
> cancelled The eventual release of upgraded DECnet support wasn't intended to be
> a selling point for TOPS-20 machines, but rather a bone thrown to existing
> customers to ease their pain.

We had 6 KLs and tried to use DECnet to network them seamlessly. That was a loser.
Compuserv clearly had fairly seamless networking, but they had essentially been using their
own home grown networking for ages on their homegrown TOPS-10 hack. CIS used half-duplex with
local echo, for heavens sake. You can't pretend that is proper TOPS-20 usage.

There was no way to use the DECnet that LCG was willing to sell because it woke up the KL for every character
even when you did a "SET HOST" to another KL/PDP-11 20 feet away.

Since LCG would not even talk to us about TOPS-20-AN, we never got far enough to know if it would have been better.
I have ranted about how incompetent and evil LCG was for decades on this usenet group.

Questor

unread,
Aug 31, 2021, 4:55:29 PM8/31/21
to
On Mon, 30 Aug 2021 18:53:01 -0700 (PDT), fishtoprecords <pat2...@gmail.com>
wrote:
>On Saturday, August 28, 2021 at 3:38:31 PM UTC-4, Questor wrote:
>> So that's why TOPS-20 DECnet was so limited until after the Jupiter was
>> cancelled The eventual release of upgraded DECnet support wasn't intended to be
>> a selling point for TOPS-20 machines, but rather a bone thrown to existing
>> customers to ease their pain.
>
>We had 6 KLs and tried to use DECnet to network them seamlessly. That was a loser.
>Compuserv clearly had fairly seamless networking, but they had essentially been using their
>own home grown networking for ages on their homegrown TOPS-10 hack. CIS used half-duplex with
>local echo, for heavens sake. You can't pretend that is proper TOPS-20 usage.

I guess that depends on what you mean by seamless. More specifically, what your
"application load" was. The big three are e-mail, file transfer/manipulation,
and virtual terminals. I'm fuzzy on e-mail, particularly since almost no one
at any of the internal DEC TOPS-20 sites used the vanilla supported version of
e-mail. The two most popular were MS and MM, and beyond that I can't recall
which version, where they came from. or who wrote them.

File transfer was not quite as seamless as with VMS, where all one had to do was
prepend "nodename::" to the file specification in any file command and generally
the right thing happens, perhaps after being prompted for a password. However,
the TOPS-20 Network File Transfer utility (NFT) commands mimicked the EXEC file
commands and it otherwise worked well, although I never concerned myself with
investigating any metrics.


>There was no way to use the DECnet that LCG was willing to sell because it woke
>up the KL for every character even when you did a "SET HOST" to another
>KL/PDP-11 20 feet away.

The ANF-10 network product had many limitations, not the least of which is that
it was for TOPS-10 hosts only. But one thing it did really well was virtual
terminals -- SET HOST. The big difference is that with ANF-10, one did not have
to login to the local host; you were not running an application; it didn't take
up a job slot. All the terminal traffic went to the remote DN87 network front
end. (I can't recall if local terminals were connected to the primary front-end
or the local DN87.)

With DECnet-20, there is no "SET HOST" EXEC command. There is the user level
SETHOST program, which was admittedly a minimal effort. At this remove I'm not
even certain if it was a supported utility or simply DEC-supplied "as is."
In any event, you're running a user mode program with all the overhead that
entails. I suppose a line mode, as opposed to character mode, SETHOST program
could be written, particularly if escape is included as line break character.
That might make using TECO possible, but it still breaks EXEC question mark
help and makes running EMACS impossible, just to name two off the top of my
head.

This is admittedly a deficiency in DECnet-20, and its in large part due to
TOPS-10. There was a lot of mischief one could do on TOPS-10 without a valid
login, and consquently a lot of holes to plug in order thwart it. TOPS-20
greatly limited what one could do without logging in, which certainly included
running a SETHOST application. (VMS essentially eliminated doing anything
without valid login credentials.) In any event, either SETHOST runs, or a SET
HOST command is implemented and an instance of EXEC does the work, but
due to the software architecture of TOPS-20, a user mode program must be run
and a job slot taken. The DN20, DECnet-20's network front end, had no support
for any terminal lines, and there wasn't any room to add the code for them.


>Since LCG would not even talk to us about TOPS-20-AN, we never got far enough to
>know if it would have been better I have ranted about how incompetent and evil
>LCG was for decades on this usenet group.

I was in LCG... I am incompetent and evil? I certainly would not characterize
LCG Engineering as incompetent and evil. However, I was well-insulated from the
usual customer experience, which varied greatly depending on which office
supported you. I can't answer for that, or them. Again, if you were not an
ARPAnet site, why would they talk to you about product meant for a small,
very specific set of customers? I don't have any evidence that there was a plan
or even a thought about TOPS-20 customers setting up private TCP/IP networks.
In retrospect, that may have been a poor decision, but at the time, the ARPAnet
was considered to be a research project and not in any way a commercial
enterprise. TOPS-20AN was not an offering intended to increase company revenue;
DECnet-20 was. In that light, the salesman's response is understandable.

fishtoprecords

unread,
Aug 31, 2021, 6:10:15 PM8/31/21
to
On Tuesday, August 31, 2021 at 4:55:29 PM UTC-4, Questor wrote:
> On Mon, 30 Aug 2021 18:53:01 -0700 (PDT), fishtoprecords <pat2...@gmail.com>
> >Since LCG would not even talk to us about TOPS-20-AN, we never got far enough to
> >know if it would have been better. I have ranted about how incompetent and evil
> >LCG was for decades on this usenet group.
> I was in LCG... I am incompetent and evil? I certainly would not characterize
> LCG Engineering as incompetent and evil.

I used sloppy wording.
The LCG engineers that I worked with were great.
The LCG marketing and sales folks were snakes.
For example, they kept insisting that a Vax 8600 would easily replace several of our KLs.
They were all 2065 with at least a MW of memory, so no, a 8600 would not replace one of them.

> TOPS-20AN was not an offering intended to increase company revenue;
> DECnet-20 was. In that light, the salesman's response is understandable.

By this time, pretty much nothing would increase DEC's revenue from the big commercial
sites. We may have kept buying an occasional RP07, but nothing else. We got the 5th and 6th KLs because
customers showed up and we had to, but they were locked into System 1022, so neither our customers
or us had much in the way of options.

Maybe a Foonley, or XKL...... nah
Commercial timesharing was barely a dead man walking.

Rich Alderson

unread,
Sep 1, 2021, 4:59:37 PM9/1/21
to
use...@only.tnx (Questor) writes:

[ regarding inter-system connectivity via DECnet ]

> I'm fuzzy on e-mail, particularly since almost no one at any of the internal
> DEC TOPS-20 sites used the vanilla supported version of e-mail. The two most
> popular were MS and MM, and beyond that I can't recall which version, where
> they came from. or who wrote them.

MM came first, initially written by (IIRC) McMahon, later taken over by our
late friend Mark Crispin and expanded greatly to allow TCP/IP, DECnet, and
dialup e-mail interchange as well as local delivery; I believe that the TCP/IP
code replaced the NCP/FTP code of earlier versions.

MS was a DEC fork of an early version of MM (I've seen the source, it's
acknowledged right there) which standardized on DECnet and local delivery, and
did not keep any of the ARPANET stuff; the phone-net stuff was much later anyway.

--
Rich Alderson ne...@alderson.users.panix.com
Audendum est, et veritas investiganda; quam etiamsi non assequamur,
omnino tamen proprius, quam nunc sumus, ad eam perveniemus.
--Galen

fishtoprecords

unread,
Sep 1, 2021, 7:57:20 PM9/1/21
to
On Wednesday, September 1, 2021 at 4:59:37 PM UTC-4, Rich Alderson wrote:
> MM came first, initially written by (IIRC) McMahon, later taken over by our
> late friend Mark Crispin and expanded greatly to allow TCP/IP, DECnet, and
> dialup e-mail interchange as well as local delivery; I believe that the TCP/IP
> code replaced the NCP/FTP code of earlier versions.
>
> MS was a DEC fork of an early version of MM (I've seen the source, it's
> acknowledged right there) which standardized on DECnet and local delivery, and
> did not keep any of the ARPANET stuff; the phone-net stuff was much later anyway.

We started with DEC's MS and quickly picked up MM. We put in a moderate number of local hacks
specific to our hacked TOPS-20. We also added "receipt" for delivery (meaning that the addressee
read the message)

I remember the address parser that Mark put in. Even supported dial-up UUCP
I think Mark had a lot of input into RFC822 for proper 10/20 address forms.

Rich Alderson

unread,
Sep 2, 2021, 9:07:50 PM9/2/21
to
It actually wasn't uucp; it was a similar facility which MRC created himself
and called "Cafard" (French for "bug" or "cockroach"; used in soldier's patois
to describe someone who's gone round the bend). I don't know that he saw the
work I had done to add MMDF capability to MM for the University of Chicago, the
project which first acquainted us with each other and led to my move to Stanford.
I think he had a lot of input into both RFC822 and RFC821.
0 new messages