[comp.protocols.appletalk] TCP specificattion

saf@CITI.UMICH.EDU (10/06/87)

					TCP DRIVER INTERFACE SPECIFICATION (final draft 10/6/87)



ABOUT THE TCP DRIVER
--------------------

The TCP driver layer, one of the CITI MacIP drivers, implements the Transmission 
Control Protocol [RFCJ793].  This document describes the interface to TCP.


TCP DATA STRUCTURES
-------------------

The reader should be familiar with the common C derived types, such as those described in 
<sys/types.h>, <sys/time.h>, MPW C, and Inside Macintosh.

Version information on the TCP driver is returned in the following structure:

	typedef struct tcp_version {
		unsigned char	version[32];	/* Version number */
		unsigned char	specdesc[32];	/* Specification description */
		unsigned char	site[32];		/* Originating site */
	} tcp_version_t, *tcp_version_p;


If TCP is configured to collect statistics, that information is returned in the following 
structure  (NOTE: this structure is not finalized!):

	typedef struct tcp_stats {	/* Not yet defined */
		} tcp_stats_t, *tcp_stats_p;


TCP FUNCTIONS
-------------

The following functions provide a program interface to the TCP driver layer.  Each 
function returns success (0) or an error code.  Error code identifiers are defined in 
net_errno.h.  The return type for all functions is long.

TCP may notify clients of asynchronous events by executing a client-supplied notification 
routine.  Execution of the notification routine is called delivery of notification.  Clients are 
notified of an event if and only if they have specifically requested notification of that event.  
Clients request  and cancel notification of events by setting a mask and passing it to 
tcp_request and tcp_cancel, respectively.

Some functions accept io_timeout as a parameter.  For these routines, if io_timeout is 
NULL, the function blocks forever, or until the call can be completed.  If io_timeout is 
not NULL, the function blocks until the timeout value expires or the call can be completed.  
Implementation-dependent restrictions may apply as to when a client can block.  If it is 
illegal for a call to block, the error E_CANTBLOCK is returned.

Certain functions can operate synchronously or asynchronously.  For these routines, if the 
TCP_FLAG_ASYNC bit in io_flags is cleared, the routine operates synchronously, either 
completing the operation within the timeout period or giving up.  If the TCP_FLAG_ASYNC 
bit is set, the function returns immediately and performs the operation asynchronously.

Some functions accept (and in certain cases return) io_flags as a parameter.  io_flags is 
a long-word bitmask of control flags.  A list of all flags is given in "TCPJCONSTANTS."

Right and left arrows indicate values passed to and from the driver functions, respectively.

tcp_create (io_stream, io_lport, io_snd_buffer, io_snd_buflen, io_rcv_buffer, 
			io_rcv_buflen)
	<-	Ptr				*io_stream		TCP stream descriptor
	->	unsigned short	io_lport		Local TCP port
	->	Ptr				io_snd_buffer	Pointer to send buffer
	->	long			io_snd_buflen	Length of send buffer
	->	Ptr				io_rcv_buffer	Pointer to receive buffer
	->	long			io_rcv_buflen	Length of receive buffer

tcp_create creates a TCP stream.  If io_lport is non-zero, the local port is set for 
io_stream, otherwise, a subsequent call to tcp_setport must set the local port.

TCP clients may specify send/receive buffer pointers io_snd_buffer/ io_rcv_buffer.  
They must be non-relocatable blocks of size io_snd_buflen/ io_rcv_buflen, 
respectively, that remain fixed while this stream is open.  If io_snd_buffer/ 
io_rcv_buffer is NULL, or if io_snd_buflen/ io_rcv_buflen is zero, TCP will 
internally allocate a send/receive buffer.

Errors returned are:
	E_NOMEM


tcp_delete (io_stream)
	->	Ptr	io_stream	TCP stream descriptor

tcp_delete deletes a TCP stream.  If the stream is connected tcp_delete aborts the 
connection.  If the client supplied send and/or receive buffers when the stream was created, 
the client may now free them; buffer memory allocated by TCP is deallocated by TCP.  
This call will fail if called from a notification routine, but only if notifying on the same 
stream.

Errors returned are:
	E_BADSTREAM
	E_NOTIFYING


tcp_request (io_stream, io_nclass, io_notify, io_userdata, io_flags)
	->	Ptr				io_stream	TCP stream descriptor
	->	unsigned long	io_nclass	Set of events to notify on
	->	ProcPtr			io_notify	Notification routine
	->	unsigned long	io_userdata	Passed to notification routine
	->	unsigned long	io_flags	Control flags

tcp_request sets up notification for a stream.  io_notify is a pointer to the client's 
notification routine.  io_userdata is passed to the client's notification routine.

io_nclass is the bitwise or of the notification identifiers to notify on.  So that clients may 
request to add to current notifications, io_nclass is bitwise ored to the existing bits.  
Values for io_nclass are defined in the section "TCPJNOTIFICATION."  When a TCP 
stream is created, the default value for io_nclass is TCP_NT_NONE (i.e., no notification).

Special behavior can be specified with io_flags.  The following flags are defined:

TCP_FLAG_NEWNOTIFY	io_notify should replace the previous io_notify.  Clients 
may disable notification by passing NULL for io_notify 
and setting this flag.  Notification may be re-enabled later by 
setting IP_FLAG_NEWNOTIFY and io_notify.

	TCP_FLAG_NEWUDATA	io_userdata should replace the previous io_userdata.

Errors returned are:
	E_BADSTREAM
	E_BADNOTIFICATION
	E_BADFLAG


tcp_cancel (io_stream, io_nclass)
	->	Ptr				io_stream	TCP stream descriptor
	->	unsigned long	io_nclass	Events not to notify on

tcp_cancel subtracts from the set of events for which the client accepts notification.

Errors returned are:
	E_BADSTREAM


tcp_setport (io_stream, io_lport)
	->	Ptr				io_stream	TCP stream descriptor
	<>	unsigned short	*io_lport	Local TCP port

tcp_setport binds a port to a TCP stream.  If io_lport is zero TCP will assign an 
unused port number.

Errors returned are:
	E_BADSTREAM
	E_STREAMCONNECTED


tcp_connect (io_stream, io_timeout, io_fhost, io_fport, io_flags)
	->	Ptr				io_stream	TCP stream descriptor
	->	unsigned long	io_fhost	Foreign IP address
	->	unsigned short	io_fport	Foreign TCP port
	->	struct timeval	*io_timeout	Timeout value
	->	unsigned long	io_flags	Control flags

tcp_connect attempts to connect to io_fport on io_fhost.

If the TCP_FLAG_ASYNC bit in io_flags is clear tcp_connect operates synchronously.  If 
the connection cannot be established in io_timeout, TCP gives up, returning the stream to 
its initial state.  This is an illegal operation if called from a notification routine.

If the TCP_FLAG_ASYNC bit in io_flags is set tcp_connect operates asynchronously.  
The client is notified when the connection is established.  If the connection cannot be 
established in io_timeout TCP gives up and delivers a TCP_NT_ERROR notification.  As 
with the synchronous case, the stream is returned to its initial state.

Errors returned are:
	E_BADSTREAM
	E_TIMEDOUT
	E_NOTIFYING
	E_CANTBLOCK
	E_STREAMCONNECTED
	E_REMOTEABORT
	E_SERVICEFAIL


tcp_listen (io_stream, io_timeout, io_fhost, io_fport, io_flags)
	->	Ptr				io_stream	TCP stream descriptor
	<>	unsigned long	*io_fhost	Foreign IP address
	<>	unsigned short	*io_fport	Foreign TCP port
	->	struct timeval	*io_timeout	Timeout value
	->	unsigned long	io_flags	Control flags

tcp_listen listens for connection requests on io_stream.

If io_fport(io_fhost) is non-zero, connection requests are accepted only if they originate 
at the specified port(host).

If the TCP_FLAG_ASYNC bit in io_flags is clear, tcp_listen blocks until a connection 
request arrives.  When a connection is established, the foreign host and port are returned in 
io_fhost and io_fport.  If no request arrives within io_timeout, tcp_listen returns 
an error, and the stream is returned to its initial state.  This is an illegal operation if called 
from a notification routine.

If the TCP_FLAG_ASYNC bit in io_flags is set, the TCP stream enters a listening state and 
tcp_listen returns immediately.  When TCP accepts a connection request for 
io_stream, TCP notifies the client by delivering a TCP_NT_CONNECT notification. If a 
connection cannot be established in io_timeout TCP gives up and delivers a 
TCP_NT_ERROR notification.  As with the synchronous case, the stream is returned to its 
initial state.

Errors returned are:
	E_BADSTREAM
	E_TIMEDOUT
	E_NOTIFYING
	E_CANTBLOCK
	E_STREAMCONNECTED
	E_REMOTEABORT
	E_SERVICEFAIL


tcp_close (io_stream, io_timeout, io_flags)
	->	Ptr				io_stream	TCP stream descriptor
	->	struct timeval	*io_timeout	Timeout value
	->	unsigned long	io_flags	Control flags

tcp_close negotiates the termination of a connection.  All outstanding data is delivered 
(i.e., clients may continue to call tcp_get until all input buffers are read.

If the TCP_FLAG_ASYNC bit in io_flags is clear,TCP  operates synchronously.  If TCP 
cannot negotiate the close within io_timeout, an error is returned and the connection is 
aborted. This is an illegal operation if called from a notification routine.

If the TCP_FLAG_ASYNC bit in io_flags is set, TCP operates asynchronously.  When the 
connection is closed or the timeout expires the client is notified with TCP_NT_CLOSED or 
TCP_NT_ERROR, respectively.  If the connection was not closed within the timeout the 
connection is aborted.

Errors returned are:
	E_BADSTREAM
	E_TIMEDOUT
	E_NOTIFYING
	E_CANTBLOCK
	E_STREAMCLOSING
	E_STREAMCLOSED
	E_REMOTEABORT
	E_SERVICEFAIL


tcp_abort (io_stream)
	->	Ptr	io_stream	TCP stream descriptor

tcp_abort aborts a connection.  Any data in transit is lost.  The stream returns to the 
closed state.

Errors returned are:
	E_BADSTREAM
	E_STREAMCLOSED


tcp_put (io_stream, io_buffer, io_buflen, io_flags)
	->	Ptr				io_stream	TCP stream descriptor
	->	Ptr				io_buffer	Pointer to data
	->	unsigned long	io_buflen	Length of data (bytes)
	->	unsigned long	io_flags	Control flags

tcp_put sends io_buflen bytes of io_buffer on io_stream.

The TCP_FLAG_PUSH and TCP_FLAG_URG bits in io_flags correspond to the "data stream 
push" and "urgent data signalling" facilities of TCP (e.g., setting TCP_FLAG_URG marks the 
data as urgent).

tcp_put returns immediately; the TCP driver schedules actual data delivery.

Errors returned are:
	E_BADSTREAM
	E_BADFLAG
	E_NOMEM
	E_STREAMCLOSING
	E_STREAMCLOSED


tcp_get (io_stream, io_timeout, io_buffer, io_buflen, io_flags)
	->	Ptr				io_stream	TCP stream descriptor
	->	Ptr				io_buffer	Pointer to data
	<>	unsigned long	*io_buflen	Length of data (bytes)
	->	struct timeval	*io_timeout	Timeout value
	<>	unsigned long	*io_flags	Control flags

tcp_get requests data on a TCP stream.  io_buffer points to a client-supplied buffer.  
io_rcv_buflen specifies the length of that buffer in bytes.

tcp_get blocks until one of the following conditions occurs:
	-	io_timeout expires.
	-	urgent data is outstanding.
	-	push data arrives.
	-	io_buflen bytes are available.
When tcp_get returns it passes back all available data.  io_buflen indicates how much 
data was actually read.

On return, if the TCP_FLAG_URG bit of io_flags is set, there is outstanding urgent data on 
io_stream.  The client should "urgently" read data from TCP until all urgent data has been 
read.  tcp_get sets the TCP_FLAG_MARK bit of io_flags when the last of the urgent data is 
delivered.  TCP will not deliver both urgent and non-urgent data in the same buffer.  
Similarly, if pushed data exists, only data up to the push marker is delivered; more non-
pushed data may be available.

Errors returned are:
	E_BADSTREAM
	E_TIMEDOUT
	E_CANTBLOCK
	E_STREAMCLOSING
	E_STREAMCLOSED


tcp_control (io_stream, io_buffer, io_buflen, io_control)
	->	Ptr				io_stream	TCP stream descriptor
	<>	Ptr				io_buffer	Data used by control call
	<>	long			*io_buflen	Size of io_buffer (bytes)
	->	unsigned long	io_control	Specifies control operation

tcp_control performs various operations for a TCP stream.  io_control selects an 
operation and is the only mandatory parameter.  Parameters that are not required by 
individual control operations may be passed as NULL.

General errors returned by tcp_control are:
	E_BADSTREAM
	E_BADCONTROL

Currently defined control operations are:

	TCP_CTL_VERSION
		->	io_stream	TCP stream descriptor
		<>	io_buffer	Pointer to tcp_version_t structure
		->	io_control	Control operation

	Returns version information.  Clients pass a pointer to a structure of type 
	tcp_version_t, as defined in the section "TCPJDATAJSTRUCTURES."

	No specific errors are returned for this control.


	TCP_CTL_STATS
		->	io_stream	TCP stream descriptor
		<>	io_buffer	Pointer to tcp_stats_t structure
		->	io_control	Control operation

	No specific errors are returned for this control.


	TCP_CTL_PERM_STREAM
		->	io_stream	TCP stream descriptor
		->	io_control	Control operation

	This stream should never be deallocated by the system.

	No specific errors are returned for this control.


tcp_task ()

tcp_task allots time to TCP for asynchronous processing.

Errors returned are:
	E_CANTBLOCK


TCP NOTIFICATION
----------------

Clients may request and cancel notification of asynchronous events by calling 
tcp_request and tcp_cancel, respectively.  As asynchronous events occur, the 
notification routine io_notify is called with the following parameters:

(*io_notify)(io_stream, io_fhost, io_fport, io_lhost, io_lport, io_flags, 
			 io_nclass, io_ndata, io_userdata)
	->	Ptr				io_stream	TCP stream descriptor
	->	unsigned long	io_fhost	Foreign IP address
	->	unsigned short	io_fport	Foreign TCP port
	->	unsigned long	io_lhost	Local IP address
	->	unsigned short	io_lport	Local TCP port
	->	unsigned long	io_flags	TCP flags
	->	unsigned long	io_nclass	Class of async notification
	->	unsigned long	io_ndata	Notification data
	->	unsigned long	io_userdata	User-data field

io_nclass is the type of event that caused this notification.  io_userdata was passed to 
tcp_request by the client.  io_ndata contains additional specification for the event.

The following describes the valid notification classes (io_nclass):

	TCP_NT_CONNECT:  Connection Notification
		->	io_stream
		->	io_fhost
		->	io_fport
		->	io_lhost
		->	io_lport
		->	io_nclass
		->	io_userdata

	Connection notification is delivered when a connection is established with io_fport on 
	io_fhost.  To receive connection notification, the client must be listening for connections 
	(see tcp_listen).

	TCP_NT_DATA:  Data Arrival Notification
		->	io_stream
		->	io_fhost
		->	io_fport
		->	io_lhost
		->	io_lport
		->	io_flags
		->	io_nclass
		->	io_ndata
		->	io_userdata

	Data arrival notification is delivered when a data segment arrives from io_fport on 
	io_fhost.  io_ndata is the number of bytes currently available in the steam's input 
	buffers.  The TCP_FLAG_PUSH and TCP_FLAG_URG bits in io_flags will be set if there is 
	push data or urgent data in the stream.  If a client is accepting TCP_NT_DATA they will not 
	receive TCP_NT_URG.


	TCP_NT_URGENT:  Urgent Data Notification
		->	io_stream
		->	io_fhost
		->	io_fport
		->	io_lhost
		->	io_lport
		->	io_nclass
		->	io_ndata
		->	io_userdata

	Urgent data notification is delivered when there is outstanding urgent data somewhere in 
	the stream.  io_ndata indicates the number of bytes available in the input buffers.  The 
	notification is delivered just once, when the foreign host first puts urgent data  in the 
	stream.  Once all urgent data has been read, TCP will again be ready to deliver urgent data 
	notification.

	TCP_NT_RETRANS:  Retransmit Notification
		->	io_stream
		->	io_fhost
		->	io_fport
		->	io_lhost
		->	io_lport
		->	io_nclass
		->	io_userdata

	The client is notified when TCP retransmits data destined for io_fport on io_fhost.

	TCP_NT_CLOSING:  Closing Notification
		->	io_stream
		->	io_fhost
		->	io_fport
		->	io_lhost
		->	io_lport
		->	io_nclass
		->	io_userdata

	The client is notified when the foreign host begins negotiating closing a connection with 
	io_fport on io_fhost.

	TCP_NT_CLOSED:  Closed Notification
		->	io_stream
		->	io_fhost
		->	io_fport
		->	io_lhost
		->	io_lport
		->	io_nclass
		->	io_userdata

	The client is notified when the connection with io_fport on io_fhost has been gracefully 
	closed.

	TCP_NT_ERROR:  Error Notification
		->	io_stream
		->	io_buffer
		->	io_buflen
		->	io_fhost
		->	io_fport
		->	io_lhost
		->	io_lport
		->	io_nclass
		->	io_ndata
		->	io_userdata

	The client is notified when an asynchronous error occurs, (e.g., destination unreachable 
	messages, connection resets).  io_ndata identifies the error.  For some errors, an ICMP 
	destination unreachable datagram is returned in io_buffer.  io_buflen is the length of 
	that datagram.  For more information on ICMP, refer to [RFCJ792].  If the error is not 
	based on an ICMP message, io_buffer is NULL.

Errors delivered are:
	E_NETUN
	E_HOSTUN
	E_PROTOUN
	E_PORTUN
	E_REMOTEABORT
	E_SERVICEFAIL
	E_OPENFAIL
	E_TIMEDOUT


TCP ERROR CODES
---------------

Following is a description of all possible error codes returned by TCP:

	E_NOMEM
		Not enough memory to perform operation.
	E_BADSTREAM
		Stream descriptor was not found in this driver's list of streams.
	E_BADNOTIFICATION
		Invalid notification class.
	E_BADFLAG
		Invalid control flag bit is set in io_flags.
	E_BADCONTROL
		Invalid control identifier.
	E_BADWDS
		Invalid WDS structure or pointer.
	E_CANTRESOLVEADDR
		Unable to determine the next destination IP address that leads to the 
		requested destination IP address.
	E_HWWRITEERR
		Hardware failed in writing datagram to network.
	E_CANTBLOCK
		Current context does not allow a blocking call.
	E_NOTIFYING
		Cannot perform operation on stream while notifying on same stream.
	E_STREAMCONNECTED
		Invalid operation; stream is already connected or synchronizing to connect.
	E_STREAMCLOSING
		Invalid operation; stream is already synchronizing to close.
	E_STREAMCLOSED
		Invalid operation; stream is already closed.
	E_TIMEDOUT
		Could not perform operation within requested timeout period.
	E_REMOTEABORT
		Foreign host has aborted connection.
	E_SERVICEFAIL
		Invalid data from foreign host.
	E_OPENEFAIL
		Could not open connection to foreign host.


OUTSTANDING ISSUES
------------------

Synchronous routines that take timeout values should decrement the timeout structure by 
the elapsed time so the client can determine how much of the timeout period was used and 
how much remains.  This would not work for asynchronous operations because the routine 
does not hold on to the timeval structure.  Perhaps the time remaining could be passed as 
part of the notification.