TCP networking in Oberon Workstation 1.3.0

The TCPNet.Mod module and TCPNet Device in Oberon Workstation provide client and server internet connectivity to Oberon programs. Each of the (max 32) connections works with 2 regular Oberon files. One file receives TCP data; the other supplies data to be transmitted.

Both files appear as normal files to the modules (programs) in the Oberon system, but have extended behaviour. If an Oberon module writes data to the ouput file of the connection, this data is sent out on the internet connection. Incoming data from the connection is appended to the input file. If you want to keep the in- and out- streams, you can normally register the file(s).

The TCPNet Device works concurrently with RISC5 execution. During regular Oberon command execution however, a program does not perceive any network activity. The program may freely append new output data to the connection output file, and/or it may read data from the input file. Interaction with the TCPNet Device occurs via a Service Request task in the TCPNet.Mod module. The task is periodically called to "synchronize" your in/out files with the TCPNet Device. The service request task performs 3 actions:

Using TCPNet.Mod

To create a connection to a server

PROCEDURE Open* (conn: TCPConn; in, out: Files.File;
		address: ARRAY OF CHAR; port: INTEGER; 
		handler: Handler; VAR res: INTEGER);

This procedure requests the establishment of a connection conform the given parameters. The action occurs asynchronously by macOS system calls to its sockets library. When the requested connection succeeds, streaming is potentially immediately started if either local or remote sides have data to send. The establishment of the connection (among other events) is reported via status calls to your handler procedure.

a NEW-created TCPNet.TCPConn record. to hold the connection parameters.
in, out
the receive (in), and transmit (out) files for the connection. The files do not need to be empty, and are not required to be registered. Transmission of the out file always starts at position 0. Received bytes are always appended at the end of the in-file. The files are assigned to the connection for its entire lifetime (i.e. till the connection is closed). Each in- or out file must not be attached to more than 1 connection.
The server address. As DNS lookup is provided in the TCPNet Device, this parameter may be in domain name- or IPv4 form, e.g.:
The address string is max. 63 chars (excluding trailing null)
Port number at the server. This integer is in normal Oberon integer endianness (i.e. not in big-endian network form). Max. port number is 0FFFFH (16 bits).
Client PROCEDURE of type TCPNet.Handler , This procedure will be called if the Network Device has any status changes to report since the previous handler call, which may require a client action. see below for details on handler calls
Result. 0: success (connection requested); <0: failed request (no free handles, or direct parameter error)

Responding to handler calls

Handler* = PROCEDURE (conn: TCPConn; stat:SET): INTEGER;
The unique connection that this status call relates to. Each connection may have its own unique handler procedure, or a handler procedure may be shared by multiple connections.
Status. A set of flags that report events that occured on the connection. Multiple flags may be set.
hostc IN stat
The connection was successfully established. This flag is only reported once for a connection.

In case of a directly requested connection, if needed, you may use the TCPConn.raddr and TCPConn.lport fields of the connection record to inspect resolved remote address and the (automatically) assigned local port respectively.

In case of a served connection (see Listening connection), if needed, you may use the TCPConn.raddr field to inspect the remote client address, and TCPConn.rport to look up the remote port of the visitor.

newrx IN stat
Some data was received and appended to the in-file since the previous handler call. The length of the in-file has increased correspondingly.
newtx IN stat, spacetx IN stat
newtx: some data was transmitted from the output file since the previous handler call. spacetx: the local transmission mechanism reached the end of the output file, and will only resume if you write more data.
These flags have little value for use in programs. You do not have to wait for spacetx in order to append more data to the output file. The flags do not guarantee the remote host has received anything yet.
endrx IN stat
The server has closed its transmission stream. Therefore, we will not receive any more data in the in-file from this connection. Modern protocols typically do not rely on this feature, as to-be-expected amounts of data back and forth are determined by parsing the content of the streams.
limrx IN stat, error IN stat, discon IN stat
Typically fatal errors, that render the connection stale. The proper response is to close the connection. limrx: input stream has reached the max. file size limit; error: an error in sockets/streaming; discon: disconnected by server, this flag has not yet been implemented.
return value of the handler
In the INTEGER return value of handler you can specify a timeout value to force a next handler call within a maximum time period.
This is not yet implemented.

To close a connection

PROCEDURE Close*(conn: TCPConn);

Closing a connection from the local site is useful when a protocol "cycle" has ended, and no new actions are planned, or an error occured. This saves resources on server and client sides. The Close procedure may be called from within the body of the handler or as part of a normal Oberon command. After closing, any references to the connection record and files in the TCPNet module and TCPNet Device are erased.

The connection record is subject to normal Oberon garbage collection. Since closing the connection has no impact on the in- and out files, these files have kept their content as it existed when closing the connection. The files may be re-used on new connections, or analyzed to study communication behaviour.

Set up a listening connection

PROCEDURE Listen* (conn: TCPConn; in, out: Files.File; 
	port: INTEGER; handler: Handler; VAR res: INTEGER);

This procedure reserves a serving connection slot where potentially a single remote client can connect to. If multiple of such listening slots are created with the same port number, effectively a "server" is created on that port with a fixed maximum number or simultaneous connections. These connections, once established, behave essentially the same as directly requested connections. Whereas directly requested connections specify a definite peer address and start contacting the peer immediately, these serving connection slots wait to be contacted by any remote computer.

The same type of handler procedure applies to a listening connection as to a directly created connection. A single handler for listening connections with a given port number would typically be implemented for that port number.

The TCPNet Device allows a maximum of 4 different serving ports to be in use, supporting 4 servers to be working at once.

This call is still being validated/tested: it may not yet work reliably.

Local port number of this server. This integer is in normal Oberon integer endianness (i.e. not in big-endian network form). Max. port number is 0FFFFH (16 bits). Make sure that no server port is used that is already in use by other sever software on your computer. Port numbers 1024-49151 are recommended for your own server(s) or protocols. For a web server, typically use 80.