This unit was written by Rob
Morewood (morewood@planeteer.com)
for classroom use at Burnaby South Secondary School (south.sd41.bc.ca)
with Turbo Pascal for Windows 1.5
The purpose of this unit is to simplify the programming of internet
interfaces (TCP/IP). A single command, OpenTCP, sets up a
connection
with a remote application. Two commands, WriteTCP and ReadTCP,
send and receive data. The command, CloseTCP, closes the
connection.
One additional command, CheckTCP, helps maintain synchronicity.
This unit uses the WinSock library, which means that (on most systems?)
the internet connection (dialer?) software must be run before any
programs which use this unit.
Background information
----------------------
TCP/IP stand for Transport Control Protocol and Internet Protocal.
The Internet Protocal assigns a 32-bit address to every computer
in a
an extended network (or the Internet) and provides a mechanism
for
transporting message packets from one machine to another.
The TCP
adds 16-bit port numbers to allow multiple connections onto a single
machine. (It also adds error checking and correction as well
as confirmation
of receipt services.) A "TCP Connection" is defined by the
the IP addresses
of both machines as well a port number for each machine and provides
a reliable
two-way communication channel. It is worth noting that a
single port
on a single machine may serve multiple TCP connections, just so
long as all
the remote addresses or ports are different. The TCP also
provides for an
'urgent' communication channel. This unit does not support
sending data
in this mode. When urgent data is received it will be read
by the ReadTCP
function ahead of any normal data waiting to be read. Urgent
data will
not be mixed with normal data in the same ReadTCP but will not
otherwise
be distinguished.
TCP_Handle
----------
A variable of type `TCP_Handle` is required for each TCP connection
opened
by this unit. This variable is a pointer to a record with
fields containing
information about the connection. The LocalPort and LocalAddress
fields
may be useful in discovering what port as been assigned to a connection.
An FTP client requires this information to establish the Data connection.
The RemotePort, RemoteAddress, and RemoteName fields may be useful
in
discovering the source of an incoming connection. The WinSockData
pointer
points to an additional record with information about your particular
WinSock library. For most applications, none of these fields
will need
to be accessed. Just pass the TCP_Handle for the appropriate
connection
to each TCP function. See the TCP.PAS source file for details.
OpenTCP
-------
Function OpenTCP( Var Connection:TCP_Handle; Port:Word; Address:String):Boolean
The OpenTCP function requires a TCP_Handle type variable into which
it
will place a pointer to a record holding details about the connection.
Every TCP connection has two ends, one of which must initiate the
connection while the other accepts it. Therefore OpenTCP
operates in two
modes. To initiate a connection to a remote machine:
Address = IP_address string for the remote machine.
(eg. 'south.sd41.bc.ca' or '206.108.205.100')
Port = port number on which the remote application will be listening.
This is the port number on the remote machine. A local port
number
will be assigned automatically. If there is need to refer
to this number
it is available in Connecton^.LocalPort.
To prepare to accept a connection from a remote machine:
Address = An empty string.
Port = Local port to assign to the local application.
This must be done before the remote machine attempts to connect.
The actual acceptance of a connection is handled automatically
whenever
the connection is accessed by ReadTCP, WriteTCP, or CheckTCP.
To find out who has connected you can check Connection^.RemotePort,
Connection^.RemoteAddress, and Connection^.RemoteName.
The return value is TRUE if the connectoin is succesful (or a listening
port is successfully set up). If the return value is FALSE,
there was
an error somewhere. OpenTCP will still have attempted to
allocate memory
and return as much information as possible. If Connection
is not NIL,
then Connection^.WinSockError should contain a WinSock library
error
which may be informative.
EVERY call to OpenTCP, successful or not, should be followed by
a call
to CloseTCP to deallocate memory and close any sockets which were
opened.
CloseTCP
--------
Function CloseTCP( Var Connection:TCP_Handle ):Integer;
Attempts to deallocate all memory associated with the connection
and
close any open connections. Return value is Zero of all goes
well,
otherwise a WinSock library error code will be returned.
This must be called for every OpenTCP, successful or not.
Otherwise
the application will lose memory. Worse, most WinSock implimentations
only support a small number of connections (often 5). Connections
left
open when your application finishes will reduce that already small
number!
ReadTCP
-------
Function ReadTCP( Var Connection:TCP_Handle; Var Data:String);
This function checks the connection, accepting incoming connections
if there is no active connection, and returns up to 255 characters
of data in the supplied string. Like a keyboard Read, this
function
will wait until data is received or the connection is closed.
BEWARE: This opens the possibility for deadlocks where both
applications
are waiting for the other to say something. Use CheckTCP.
If an empty string is returned then the connection was closed.
The function returns TRUE unless the WinSocket library generates
an
error. In that case, the error code will be found in Connection^.WinSockError.
Possible Future Change: I am considering adding a timeout
to
eliminate the possibility of deadlocks.
CheckTCP
--------
Function CheckTCP( Var Connection:TCP_Handle ):TCP_Status
This functions checks the connection and returns the status.
If there is no active connection, but their is an incoming connection
pending, then it will be accepted. the possible return values are:
TCP_Error = Something went wrong at the WinSock level.
The WinSock Error code is in Connection^.WinSockError}
TCP_Ready = Data from a remote application is ready to be read,
TCP_Active = Connected to a remote application, but no data is
waiting.
TCP_Listening = Waiting for a remote application to connect.
TCP_Closed = The remote application closed the connection.
A connection which was started in Listening mode will return to
listening mode (or accept the next imcoming connection) when the
current active connection is closed.
WriteTCP
--------
Function WriteTCP( Var Connection:TCP_Handle; Data:String[254]
):Boolean
The characters in the supplied string are sent to the remote application.
Only a single string is sent, no other data types are supported.
Note the limitation to a maximum of 254 characters at a time.
(It seems like more trouble than it is worth to raise the limit
to 255.)
WARNING: If an empty string is sent on a connection which
was initially
listening.then the active connection will be closed and the connection
will revert to listening for new connections.
Another WARNING: Many protocols which use TCP expect a Carriage
Return and
Linefeed at the end of every command or reply. WriteTCP does
not add these,
so you must add them if required. (Put +#13+#10 after the
string.)
Limitations
-----------
This unit was created for my high school programming class.
It functioned properly in an isolated school lab running under
OS/2 Warp (version 3).
It has been rewritten to correct known bugs and provide better
documentation before public release. Please let me know if
it
works or not on your setup. If you find/fix any bugs, or
make
any improvements please let me know at morewood@planeteer.com
so that I can incorporate any improvements before the start of
the next school year.
Extensions
----------
Those wishing to do Event-Oriented internet programming in Pascal
should get the full Winsock unit package from:
ftp://ftp.simtel.net/pub/simtelnet/win3/inet/pasock10.zip
(Simtel has rearranged their directory structures and most of
the pre-existing links to that file are broken. The
above
address IS good as of July 10, 1998.)