The session layer resides above the transport layer, and provides ``value added'' services to the underlying transport layer services. The session layer (along with the presentation layer) add services to the transport layer that are likely to be of use to applications, so that each application doesn't have to provide its own implementation.
It is the thinnest layer in the OSI model. At the time the model was formulated, it was not clear that a session layer was needed.
The session layer provides the following services:
In the ISO protocols, dialog management is implemented through the use of a data token. The token is sent back and forth, and a user may transmit only when it possesses the token.
The transport layer handles only communication errors, synchronization deals with upper layer errors. In a file transfer, for instance, the transport layer might deliver data correctly, but the application layer might be unable to write the file because the file system is full.
Users can split the data stream into pages, inserting synchronization points between each page. When an error occurs, the receiver can resynchronize the state of the session to a previous synchronization point. This requires that the sender hold data as long as may be needed.
Synchronization is achieved through the use of sequence numbers. The ISO protocols provide both major and minor synchronization points. When resynchronizing, one can only go back as far as the previous major synchronization point. In addition, major synchronization points are acknowledged through explicit messages (making their use expensive). In contrast, minor synchronization points are just markers.
Activities might be used to delimit files of a multi-file transfer.
Activities are also used for quarantining, collecting all the messages of a multi-message exchange together before processing them. The receiving application would begin processing messages only after all the messages had arrived. This provides a way of helping insure that all or none of a set of operations are performed.
For example, a bank transaction may consist of locking a record, updating a value, and then unlocking the record. If an application processed the first operation, but never received the remaining operations (due to client or network failures), the record would remain locked forever. Quarantining addresses this problem.
Note: The TCP/IP protocols do not include a session layer at all.
Remote Procedure Call (RPC) provides a different paradigm for accessing network services. Instead of accessing remote services by sending and receiving messages, a client invokes services by making a local procedure call. The local procedure hides the details of the network communication.
When making a remote procedure call:
The main goal of RPC is to hide the existence of the network from a program. As a result, RPC doesn't quite fit into the OSI model:
RPC is especially well suited for client-server (e.g., query-response) interaction in which the flow of control alternates between the caller and callee. Conceptually, the client and server do not both execute at the same time. Instead, the thread of execution jumps from the caller to the callee and then back again.
The following steps take place during an RPC:
Issues that must be addressed:
Parameters consist of simple types (e.g., integers) and compound types (e.g., C structures or Pascal records). Moreover, because each type has its own representation, the types of the various parameters must be known to the modules that actually do the conversion. For example, 4 bytes of characters would be uninterpreted, while a 4-byte integer may need to the order of its bytes reversed.
One approach is to simulate call-by-reference using copy-restore. In copy-restore, call-by-reference parameters are handled by sending a copy of the referenced data structure to the server, and on return replacing the client's copy with that modified by the server.
However, copy-restore doesn't work in all cases. For instance, if the same argument is passed twice, two copies will be made, and references through one parameter only changes one of the copies.
The most flexible solution is to use dynamic binding and find the server at run time when the RPC is first made. The first time the client stub is invoked, it contacts a name server to determine the transport address at which the server resides.
We'll examine one solution to the above issues by considering the approach taken by Birrell and Nelson []. Binding consists of two parts:
In B&N, remote procedures are named through interfaces. An interface uniquely identifies a particular service, describing the types and numbers of its arguments. It is similar in purpose to a type definition in programming languauges.
For example, a ``phone'' service interface might specify a single string argument that returns a character string phone number.
In B&N's system, a server having a service to offer exports an interface for it. Exporting an interface registers it with the system so that clients can use it.
A client must import an (exported) interface before communication can begin. The export and import operations are analogous to those found in object-oriented systems.
Interface names consists of two parts:
B&N's RPC system was developed as part of a distributed system called Grapevine. Grapevine was developed at Xerox by the same research group the developed the Ethernet.
Among other things, Grapevine provides a distributed, replicated database, implemented by servers residing at various locations around the internet.
Clients can query, add new entries or modify existing entries in the database.
The Grapevine database maps character string keys to entries called RNames. There are two types of entries:
For example, if wpi and bigboote both offered file access, the group entry ``file access'' would consists of two individual RNames, one for wpi and bigboote's servers.
When a server wishes to export an interface:
In B&N, there is one export table per machine, containing entries for all currently exported interfaces. This table is used to map incoming RPC request messages to their corresponding server procedure.
a unique identifier that identifies that interface, and
a pointer to the server stub that should be called to invoke the interface service. The unique identifier is never reused. If the server crashes and restarts, new identifiers are used.
The client binds to an exported service as follows:
Otherwise call the server stub procedure.
Note: The unique identifiers in the export table change whenever a server crashes and restarts, allowing the client to detect server restarts between calls. In those cases where a client doesn't care if the server has restarted, it simply rebinds to another instance of the interface and restarts the remote call.
Note: Identifiers are managed by the server and are not stored in the Grapevine database. Storing them in the Grapevine database would reduce the number of messages exchanged during the binding phase. However, the current approach greatly reduces the load on the Grapevine servers. In most cases, when a server exports an interface to Grapevine, the entry will have been registered previously, and no updates to the database are required (updates are expensive because the database is distributed).
Using Grapevine's database provides late binding. Binding callers to specific servers at runtime makes it possible to move the server to another machine without requiring changes to client software.
Finally, the separate registering of types and instances provides great flexibility. Rather than binding to a specific instance, a client asks for a specific type. Because all instances of a type implement the same interface, the RPC support routines would take the list of instances returned by Grapevine and chose the one that is closest to the client.
How is binding done on other systems?
Unlike normal procedure calls, many things can go wrong with RPC. Normally, a client will send a request, the server will execute the request and then return a response to the client. What are appropriate semantics for server or network failures? Possibilities:
While the last possibility seems the most reasonable, it may lead to problems. Suppose that:
Operations that can safely be executed twice are called idempotent. For example, fetching the current time and date, or retrieving a particular page of a file.
Is deducting $10,000 from an account idempotent? No. One can only deduct the money once. Likewise, deleting a file is not idempotent. If the delete request is executed twice, the first attempt will be successful, while the second attempt produces a ``nonexistent file'' error.
While implementing RPC, B&N determined that the semantics of RPCs could be categorized in various ways:
Can we implement RPC on top of an existing transport protocol such as TCP? Yes. However, reliable stream protocols are designed for a different purpose: high throughput. The cost of setting up and terminating a connection is insignificant in comparison to the amount of data exchanged. Most of the elapsed time is spent sending data.
With RPC, low latency is more important than high throughput. If applications are going to use RPC much like they use regular procedures (e.g., over and over again), performance is crucial.
RPC can be characterized as a specific instance of transaction-oriented communication, where:
How many TCP packets would be required for a single request-response transaction? A minimum of 5 packets: 3 for the initial handshake, plus 2 for the FIN and FIN ACK (assuming that we can piggy back data and a FIN on the third packet of the 3-way handshake).
A transaction-oriented transport protocol should efficiently handle the following cases: