Skip to main content

VI. Informal Description of Network Operations

We present here narratives describing the operation conducted during the three major phases of network usage: opening, flow control, and closing.

A. Opening​

In order to establish a connection for data transmission, a pair of RFC's must be exchanged. An RTS must go from the receive-side to the send-side, and an STR must be issued by the send-side to the receive-side. In addition, the receive-side, in its RTS, must specify a link number. These RFC's (RFC is a generic term encompassing RTS and STR) may be issued in any time sequence. A provision must also be made for queuing pending calls (i.e., RFC's which have not been dealt with by the user program). Thus, when a user is finished with a connection, he may choose to examine the next pending call from another process and decide to either accept or refuse the request for connection. A problem develops because the user may not choose to examine his pending calls; thus they will merely serve to occupy queue space in the NCP. Several alternative solutions to this problem will be mentioned later.

Utilizing the framework of the prototype system calls described above, we envision at least four temporal sequences for obtaining a successfully opened connection:

  1. The user may issue a LISTEN, indicating he is willing to consider connecting to anyone who sends him an RFC. When an RFC comes in the user is notified. The user then decides whether he wishes to connect to this socket and issues an ACCEPT or a CLOSE on the basis of that decision. A CLOSE ' refuses' the connection, as discussed under "Closing." An ACCEPT indicates he is willing to connect; an RFC is issued, and the connection becomes fully opened.
  2. Upon processing a user request for a LISTEN, the NCP discovers that a pending call exists for that local socket. The user is immediately notified, and he may ACCEPT or CLOSE, as above.
  3. The user issues a CONNECT, specifying a particular foreign socket that he would like to connect to. An RFC is issued. If the foreign process accepts the request, it answers by returning an RFC. When this acknowledging RFC is received, the connection is opened.
  4. When presented with a CONNECT, the NCP may discover that a pending call exists from the specified foreign socket to the local socket in question. An acknowledging RFC is issued and the connection is opened.

In all of the above cases the user is notified when the connection is opened, but data flow cannot begin until buffer space is allocated and an ALL command is transmitted.

Any of these connection scenarios will be interrupted if a CLS comes in, as discussed under "Closing."

1. Pending Call Queues​

It is essential that some form of queuing for pending RFC's be implemented. A simple way to see this is to examine a typical LISTEN-CONNECT sequence. One side issues a LISTEN, the other a CONNECT. If the LISTEN is issued before the RFC coming from the remote CONNECT arrives, all is fine. However, due to the asynchronous nature of the net, we can never guarantee that this sequence of events will occur. If calls are not queued, and the RFC comes in before the LISTEN is issued, it will be refused; if it arrives later, it will be accepted. Thus we have an extremely ambiguous situation.

Unless one has infinite queue space, it is desirable that some mechanism for purging the queues of old RFC's which the user never bothered to examine. An obvious but informal method is to note the time when each RFC is entered into the queue, and then periodically refuse all RFC's which have exceeded some arbitrary time limit. Another thought, which probably should be included within the context of any scheme, is for the NCP to send a CLS on all outstanding connections or pending calls when a user logs out or blows up.

The scheme which is utilized in this description may seem at first blush to be non-intuitive; but we feel it is more realistic than other proposals. Basically, when a CONNECT is issued, the NCP assumes that this socket wishes to talk to the specified foreign socket and to that socket only. It therefore purges from the pending call queue all non-matching RFC's by sending back CLS's. Similarly, when the connection is in the RFC-SEND state (a CONNECT has been issued), all non-matching RFC's are refused. If a LISTEN-ACCEPT or LISTEN- CLOSE sequence is executed, the remainder of the pending calls are not removed from the queue, in the expectation that the user may wish to accept these requests in the future.

Although the latter method may seem to be arbitrary and/or unnecessarily restrictive, we have not yet concocted a scenario which would be prohibited by this method, assuming that we are dealing with a competent programmer (i.e., one who is wary of race conditions and the asynchronous nature of the net). Of course whatever scheme or schemes a particular site chooses is highly implementation dependent; we suggest that some provision for the queuing of RFC's be provided for a period of time at least of the order of magnitude that they are retained in the CONNECT-clear scheme mentioned above.

B. Flow Control​

Meaningful data can only flow on a connection when it is fully opened (i.e., two RFC's have been exchanged and closing has not begun). We assume that the NCP's have a buffer for receiving incoming data and that there is some meaningful quantity which they can advertise (on a per connection basis) indicating the size message they can handle. We further assume that the sending side regulates its transmission according to the advertisements of that size.

When a connection is opened, a cell (called 'Their Size') is set to zero. The receive-side will decide how much space it can allocate and send an ALL message specifying that space. The send-side will increment 'Their Size' by the allocated space and will then be able to send messages of length less than or equal to 'Their Size' When messages are transmitted, the length of the message is subtracted from 'Their Size'. When the receive-side allocates more buffer space (e.g. when a message is taken by the user, thus freeing some system buffer space), the number of bits released is sent to the send-side via an ALL message.

Thus, 'Their Size' is never allowed to become negative and no transmission can take place if 'Their Size' equals zero.

Notice that the lengths specified in ALL messages are increments not the absolute size of the receiving buffer. This is necessitated by the full duplex nature of the flow control protocol. The length field of the ALL message can be 32 bits long (note: this is an unsigned integer), thus providing the facility for essentially an infinite "bit sink", if that may ever be desired.

C. Closing​

Just as two RFC's are required to open a connection, two CLS's are required to close a connection. Closing occurs under various circumstances and serves several purposes. To simplify the analysis of race conditions, we distinguish four cases: aborting, refusing, termination by receiver, termination by sender.

A user "aborts" a connection when he issues a CONNECT and then a CLOSE before the CONNECT is acknowledged. Typically a user will abort following an extended wait for the acknowledgment; his system may also abort for him if he blows up.

A user "refuses" a connection when he issues a LISTEN and, after being notified of a prospective caller, issues a CLOSE. Any requests for connection to a socket which is expecting a call from a particular socket are also refused.

After a connection is established, either side may terminate. The required sequence of events suggests that attempts to CLOSE by the receive-side should be viewed as "requests" which are always honored as soon as possible by the send-side. Any data which has not yet been passed to the user, or which continues over the network, is discarded. Requests to CLOSE by the send-side are honored as soon as all data transmission is complete.

1. Aborting​

We may distinguish three cases:

  • a) In the simplest case, we send an RFC followed later by a CLS. The other side responds with a CLS and the attempt to connect ends.
  • b) The foreign process may accept the connection concurrently with the local process aborting it. In this case, the foreign process will believe the local process is terminating an open connection.
  • c) The foreign process may refuse the connection concurrently with the local process aborting it. In this case, the foreign process will believe the local process is acknowledging its refusal.

2. Refusing​

After an RFC is received, the local host may respond with an RFC or a CLS, or it may fail to respond. (The local host may have already sent its own RFC, etc.) If the local host sends a CLS, the local host is said to be "refusing" the request for connection.

We require that CLS commands be exchanged to close a connection, so it is necessary for the local host to maintain the rendezvous table entry until an acknowledging CLS is returned.

3. Terminating by the Sender​

When the user on the send side issues a CLOSE system call, his NCP must accept it immediately, but may not send out a CLS command until all the data in the local buffers has been passed to the foreign host. It is thus necessary to test for both 'buffer-empty' and 'RFNM-received' before sending the CLS command. As usual, the CLS must be acknowledged before the entry may be deleted.

4. Terminating by the Receiver​

When the user on the receive side issues a CLOSE system call, his NCP accepts and sends the CLS command immediately. Data may still arrive, however, and this data should be discarded. The send side, upon receiving the CLS, should immediately terminate the data flow.