Programmer's Manual to Napier88/RPC 2.2 Miguel Mira da Silva
[email protected]
Dept of Computing Science University of Glasgow Glasgow G12 8QQ Scotland Abstract A remote procedure call mechanism (RPC) is a facility which enables a process to call a procedure in another, remote process. RPC hides the complexity of communicating across a network. Perhaps due to this apparent simplicity, RPC is a popular mechanism for building distributed applications. This document explains how to use an RPC mechanism built for (and in) Napier88. Contrary to most reference manuals, where the interface to the facility is described in terms of procedure descriptions, this programmer's manual shows its use by listing complete examples. We hope this approach will make it easier, even for novice Napier88 programmers, to quickly start using it successfully.
Contents
1 Introduction 2 First Things First
2.1 Installation 2.2 Fundamental Concepts 2.3 Typical Usage Pattern
1 2
: : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :
3 Registering a Service 3.1 At the Client Side 3.2 At the Server Side
5
: : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :
4 Registering Remote Procedures 4.1 At the Client Side 4.2 At the Server Side
: : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :
5 Making Remote Calls 5.1 At the Client Side 5.2 At the Server Side
5 6
6 6 7
8
: : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :
6 Advanced Use
6.1 At the Client Side 6.2 At the Server Side
2 3 4
8 10
10 : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :
7 Limitations and Future Work 8 Troubleshooting Acknowledgements References A Interface Types B List of Errors
11 12
13 14 15 15 16 17
1 Introduction A remote procedure call mechanism, or RPC for short, extends the traditional notion of calling a procedure to an environment where the procedure being called may reside in another process [BN84]. Thus RPC is a particular interprocess communication mechanism. Based on this simple idea, an RPC can then be used in a variety of ways to build distributed applications:
Client/Server Applications. In these applications several instances of the
same program share the same set of data. The data resides in one server (a Napier88 store) and is accessed by a number of clients (each one also running in a Napier88 store) using the RPC. Many applications have been implemented with this architecture. Uniformly Distributed Applications. In these applications a number of programs co-operate to achieve a common goal, and the application as a whole is constructed by using the services oered by those programs. This is an extension to the previous category where every client may also act as a server. Some multi-user applications fall in this category because some programs may prefer to store their own data instead of using a central database (for privacy, autonomy, reliability or even historical reasons). Co-operating Applications. In these applications a number of previously independent applications are extended to exchange (restricted and well de ned) data between them. This is a sub-set of the distributed model above where the applications may not have been originally designed to co-operate, or when a high level of autonomy is desired.
This manual describes how to use an RPC mechanism developed for Napier88. The current type-safe, type-complete Napier88/RPC implementation has been developed from an earlier type-safe RPC for Napier88 [MdS95]. Type-safety means that the RPC prevents invalid remote calls from happening, while type-complete says that (at least in theory) the arguments and result have no restrictions on their type. This new release, apart from type-completeness, also includes failure detection and report, a exible programmer interface, improved performance and increased reliability. This release is also compatible with the \remote scan and copy" facility of the Napier88 standard library [KBC+94], meaning that both mechanisms can operate at the same time. In order to use this RPC facility, the Napier88/RPC library will have to be installed in each store involved in RPC communication. Also, it will be needed to compile all programs using that library in the context of the RPC declaration set. 1
The next section describes the Napier88 requirements for using the RPC, terminology and an introduction to its use. Sections 3, 4 and 5 show how to register a service, declare a remote procedure, and nally how to call a remote procedure. Section 6 describes how to use the RPC with complex (i.e., non-primitive) types. Limitations and future work are brie y described in section 7, and troubleshooting in section 8.
2 First Things First Before starting with the examples, it is important to install the RPC mechanism, and to understand the terminology. An overview of the ways in which Napier88/RPC is used is then given.
2.1 Installation This release of the Napier88/RPC is compatible with \Napier88 2.2". Napier88 2.2 adds some functionality to the /Library/Distribution environment not found in [KBC+94], even though the language de nition is the same as that of Napier88 2.0 described in [MBC+94]. Part of this new functionality is implemented by a new abstract machine and interpreter. The Napier88/RPC library belongs to the Distribution section of Glasgow Libraries [WWP+95]. This library will need to be installed in each store involved in RPC communication. The procedures used in the examples below can be found in the environment: /GlasgowLibraries/Distribution/RPC
which contains the following procedures: clientService
serverService
Returns a ClientPack data structure (see appendix A) which can then be used to register and call remote procedures. Returns a ServerPack data structure (see appendix A) which can then be used to register remote procedures to be called remotely. 2
In the same environment there is also a procedure called implementation which (given a password, see section 8) returns an environment containing the Napier88/RPC internal procedures and data structures, together with procedures to list their current status. The declaration set RPC should be included in the list of declaration sets when compiling the examples given in this manual or using the Napier88/RPC library in other programs. For example, if a le called client.N contains the code for registering a procedure as remote in some distributed application, then the UNIX command line for compiling this le will be something like: npc client.N -t userTypes -t RPC
2.2 Fundamental Concepts An RPC library permits to call procedures in a remote process. The program which calls a remote procedure is the client, and the server is one which oers a procedure which may be called remotely. Behind this simple interface, an RPC provides two fundamental facilities for building distributed applications: 1. Data Transfer. Data is transferred between processes in the actual parameters of a remote procedure call from the client to the server, and from server to client in the result. 2. Synchronisation. Synchronisation is provided as the client (or strictly, the thread of the client which made the call) waits until it receives a response from the server. Similarly, the server is waiting for requests from the clients. In order to better understand the Napier88/RPC interface and operation, a list of the main concepts needed to achieve the above facilities is given next:
Signature. The name of the remote procedure and the types of the arguments
Registering a Service. When a programmer decides to oer a certain proce-
and result.
dure to be called remotely at a server, he/she does so by rst creating a service which will contain that procedure and others which together comprise the service. Clients must connect to that service before they call the intended procedure. Registering a Remote Procedure. Before calling a remote procedure, both programmers at the client and the server must have arranged for the RPC package to generate the code to support type-safe communication for that procedure. 3
The code for the client is generated automatically from the signature, then conveniently wrapped as a procedure called a client stub. The client stubs main functionality is to convert between programming language values and network messages. At the server side an equivalent server stub is generated from the same information to achieve the complementary operation. Making a Remote Call. The client program then uses a client stub which calls its counter-part server stub in the remote program. The return value of the remote call is always a variant, either a value of the type expected or a failure. A failure includes an error code intended to be used by the program itself to determine the nature of the error and a message which can be used to explain the error. Capabilities. When the client stub rst calls a server stub, it sends the signature registered with the client to be validated against the signature registered with the server. Because sending the procedure signature is an expensive operation, the server stub returns a capability (very much like a dicult to forge password) which then enables the client to make further calls without the need to re-send the signature.
2.3 Typical Usage Pattern Now that the concepts have been introduced, we describe next a typical sequence of events needed to perform a remote call: 1. The server rst registers a service with a name. 2. Then the server registers a procedure with that service by supplying its signature and its implementation. 3. Later, a client registers the same service, specifying a server believed to oer that service. 4. Then the client supplies a procedure signature, which must eventually type check as equivalent to the procedure signature registered at the server. 5. The client then calls the remote procedure as if it was a similar local one and receives the return value, which may be either of the expected type or an error code. 6. Typically steps 2 and 4 are applied to set up several RPC stubs, while step 5 is repeated for a sequence of calls to these remote procedures. 4
The address of the server where the service is supported is given alongside the service name when this is registered with the client. But services can move from one server to another server, or the client may wish to try other servers oering the same service. Thus Napier88/RPC permits a service to be re-registered and the client to \point" to another server. This means that the same stubs can be used to call equivalent remote procedures in a dierent server (see section 3). Also, when a server stub is re-registered with the same signature (for example, to provide a new implementation for the remote procedure), Napier88/RPC keeps the old capability because the signature is still the same. This functionality enables the client to still call the \same" remote procedure, even though it is now provided by a dierent implementation.
3 Registering a Service A service has a name and comprises a number of procedures to be called by a remote program. The service must be registered with both the client and the server. A number of clients can use the same service at a server, and each client may use a sub-set of the procedures supported. This section shows how this can be achieved at both the client and the server, with code examples. The next section describes how to create stubs, again at the client and the server.
3.1 At the Client Side An example follows on how to register a new service at the client, called PingService. Spaces, commas and other separators are not supported as part of service names, so do not use Ping Service, Ping.Service or the like. let server := RemoteStore( "alderney", "/local/fide/users/mms/stores/target" ) in User let clientPing := clientService( "PingService", server )
After these statements, a service called PingService has been registered as (potentially) existing in the machine alderney at the store with UNIX directory as speci ed. The directory path is needed because there can be multiple stores on a machine. 5
If a service with the same name is already registered, then the existing service is \re-directed" to the new server maintaining all its old stubs. The new behaviour applies to all users of the same service. This decision may generate some unexpected failures if the new server does not support all the remote procedures of the previous server. It is, however, necessary if services have to be \re-directed" towards new servers dynamically. A remote call will always return a failure if the service is not registered at the remote server, or it is but it does not support this particular remote procedure (see appendix B).
3.2 At the Server Side The code needed at the server side is even simpler because the server does not need to know store addresses as it accepts remote calls from any client store. in User let serverPing := serverService( "PingService" )
As already stated before, the name of the service should be the same at both the client and the server.
4 Registering Remote Procedures After the service has been registered, the server can tell the RPC which procedures will be available to be called remotely. Similarly, the client should tell the RPC the signatures of the remote procedures it may use later.
4.1 At the Client Side A procedure signature consists of its name and the types of the arguments and the result. In order to facilitate error reporting, there can be only one argument. Multiple arguments can easily be simulated by creating a new structured type. use User with clientPing:ClientPack in begin clientPing(importProc)( "pingIntStub", "proc( int -> int )" ) clientPing(importProc)( "pingStringStub", "proc( string -> string )" ) end
6
Type ClientPack used in the example above is described in the appendix A. The name of the remote procedure, pingIntStub or pingStringStub in the example above, should be unique for all services. If the procedure name already exists, the existing one is replaced by the new one, eventually with a new signature. The use of complex types (i.e., those other than int, real, string, null, etc.) is described in section 6. Napier88/RPC generates code to implement these client stubs, compiles them and puts them in the store for later use. The client stubs include calls to the RPC runtime to transform the argument into messages to the server, and interpret messages back from the server representing the result.
4.2 At the Server Side At the server side the RPC needs not only the signature of the remote procedure, but also its implementation. This is achieved by passing the name of the procedure and its implementation, as in Napier88 the signature of a procedure can be discovered at execution time by the RPC mechanism (except its name). This signature should match the signature registered at the client. use User with serverPing:ServerPack in begin !*** it may be a procedure built from scratch let pingIntImpl := proc( anInt:int -> int ) { writeString( iformat(anInt) ++ "'n" ); anInt } serverPing(exportProc)( "pingIntStub", any(pingIntImpl) ) !*** or it can be a procedure already existing elsewhere use use use use use
GlasgowLibraries with Distribution: env in Distribution with RPC: env in RPC with implementation: proc (string -> env) in implementation ("friend") with Utilities: env in Utilities with getVar: proc( string -> string ) in serverPing(exportProc)( "pingStringStub", any(getVar) )
end
7
Type ServerPack is described in the appendix A. Server stubs are then generated, compiled and stored in a database of server stubs in the server store. These server stubs will be called automatically by the RPC run-time at the server side when an incoming call arrives for these remote procedures. In order to support evolution at the server, the RPC mechanism also provides these functionalities:
Initially, the procedure called by the RPC is pingIntImpl as de ned in the example above. If the procedure implementation is later changed, this has no eect on the RPC, which continues to use the old implementation. However, the remote implementation of pingIntImpl can be changed by re-registering the new implementation with the same name and signature by a further call to serverPing(exportProc). If the new server stub is registered under the same name but with a dierent signature, then Napier88/RPC deletes the old server stub and creates a new one with a new capability. If the client attempts to use the old remote procedure which is no longer supported, a failure is returned to the client program which invoked the (now invalid) remote procedure.
There is no functionality in the current release to stop supporting a particular remote procedure. We suggest the procedure no longer supported should be replaced by a dummy implementation returning an application-level error value (such as an empty string), which also detects and records whether clients are still using a procedure no longer supported.
5 Making Remote Calls We are now in a position to show how to make remote procedure calls. However, the reader should note that it is only the client which makes these calls, the server is just listening to the network waiting for incoming requests.
5.1 At the Client Side The return value of the remote call is a variant of type CallResult (see appendixes A and B) which can be found in the declaration set RPC. A value of type CallResult can be either an indication of an error which has occurred or the return value. If it is 8
an error, it contains an error code and an error message. If it is not an error, than it is an any which should be projected onto the type expected. The following example uses pingStringStub registered above: let testStringPing := proc( aString:string -> string ) use User with clientPing:ClientPack in begin let res := clientPing(callRemProc)( "pingStringStub", any(aString) ) project res as res onto ok: project res as str onto string: str default: "should not happen" error: "remote call failed (" ++ res(msg) ++ ")" default: "should not happen" end let str := testStringPing( "NPRSTORE" ) writeString( "String returned is: " ++ str ++ "'n" )
We expect most RPC programmers to encapsulate the code above in a procedure as we did, perhaps including a more elaborate error treatment. This procedure can then be conveniently called by other parts of the client program. When an error occurs, res'error(kind) is a variant which can be checked for a number of error kinds (see appendix B). An error message is also returned; for example, if the server is not executing at the time of the remote call, the following message will be printed: String returned is: remote call failed (server not responding)
9
If everything proceeds without further complications, the message printed in the screen for the above example will be the value of the UNIX environment variable called NPRSTORE at the server: String returned is: /local/fide/users/mms/stores/target
5.2 At the Server Side In order to be able to accept incoming client calls for remote procedures, the server needs to be listening to the network. This in turn means that a Napier88 process must be executing for that store and the RPC mechanism accepting calls at that moment. The programmer turns the listening active by calling the following server procedure: use User with serverPing:ServerPack in serverPing(acceptCalls)(true)
The programmer may also switch the RPC listener o. This is achieved by: use User with serverPing:ServerPack in serverPing(acceptCalls)(false)
In order to listen to the network the RPC mechanism uses (and so is compatible with) the standard facility for \remote scan and copy" described in the Napier88 standard library manual [KBC+94]. A word of caution. In order for the server store to be able to accept calls it must be running. However, if the programmer does nothing, Napier88 executes the above statement and quits. In many practical situations, the server program is executing a graphical application, and WIN prevents the program from quiting. In other situations, an in nite loop can be used to prevent this from happening, such as: while true do {}
6 Advanced Use The examples above use primitive types such as int or string. Napier88/RPC is said to be type-complete and in theory any type can be used as argument or result, 10
including procedures. In practice, however, types are limited by the current Napier88 implementation and other practical considerations (see next section). Suppose one wish to call a remote procedure which accepts a number as an integer, and returns a structure containing the same number and its string representation, i.e., a value of the following type: type NumberRep is structure ( number: int; representation: string )
An example follows for registering a remote procedure, called getNumberRep, which uses NumberRep as the return type. For simplicity, the example uses the same service as the examples above.
6.1 At the Client Side First the client needs to install the complex type being used as argument or result in a declaration set in order for it to be recognised when the client stub is compiled. Because the complex type NumberRep appears as a result to getNumberRep, this means that values of type NumberRep are being \imported" into the client store. Thus, before registering getNumberRep itself, the client program needs to register NumberRep as an \imported type". The type NumberRep should exist beforehand in a declaration set. Normally it will already exist in the declaration set for the application, because one can expect types to be sent remotely to be manipulated locally as well. If not, then it should be compiled by the types compiler into a declaration set. The RPC just uses the rst type called NumberRep it nds, by alphabetical order of declaration sets. If the same type name appears in multiple declaration sets, the problem may be solved by creating an alias to the right (i.e., the intended) one. use User with clientPing:ClientPack in begin clientPing(importType)( "NumberRep" ) clientPing(importProc)( "getNumberRep", "proc( int -> NumberRep )" ) end
The consequence of calling clientPing(importType)( "NumberRep" ) is to copy the type NumberRep from the declaration set in which it is declared to a declaration set 11
called PingService.imp. The copy is needed because this new declaration set will be used by the RPC to compile the client stub, avoiding any confusion with any other type with the same name which could exist in other declaration set. If the type NumberRep is not imported, an error message is printed. In order to call the remote procedure getNumberRep, the programmer writes: let testGetNumberRep := proc( nb:int -> string ) use User with clientPing:ClientPack in begin let res := clientPing(callRemProc)( "getNumberRep", any(nb) ) project res as res onto ok: project res as nbrep onto NumberRep: nbrep(representation) default: "should never happen" error: "remote call failed (" ++ res(msg) ++ ")" default: "should never happen" end let str := testGetNumberRep( 1000 ) writeString( "NumberRep returned is: " ++ str ++ "'n" )
The program will then print the following in the screen: NumberRep returned is: 1000
6.2 At the Server Side At the server side what is required from the programmer is almost the same as at the client side, the main dierence being that now NumberRep is an \exported type" because it appears as a result in the server. 12
The following example shows how to register getNumberRep at the server: use User with serverPing:ServerPack in begin let getNumberRep := proc( nb:int -> NumberRep ) NumberRep( nb, iformat(nb) ) serverPing(exportType)( "NumberRep" ) serverPing(exportProc)( "getNumberRep", any(getNumberRep) ) end
In this simple example, the procedure getNumberRep just builds a new instance of NumberRep using iformat, a standard procedure in the store which accepts an integer and returns its string representation.
7 Limitations and Future Work Although the current release of Napier88/RPC can be considered quite reliable, ecient and easy-to-use, there are a number of known limitations and problems which can be improved or solved in the near future:
Every remote procedure should have exactly one argument (which, however, may be a structure with several elds) and a return value. Remote procedures will in a future release accept as argument a vector, a list or an environment to overcome this limitation. Although the performance of the RPC has not been shown to be a major obstacle in some initial experiments with the client/server version of the library explorer, we recognise that it can still be greatly improved. The reliability can be considered good, but it could be even further improved if a low-level procedure which the RPC relies on returned an error code.
We are currently working to reduce the inconvenience caused by these limitations. In addition to the problems listed above, the following list attempts to describe those which we think are more dicult to tackle, or even impossible to solve completely. They are listed for completeness, and also to warn programmers of potential hazardous RPC usage. 13
The programmer should not use types found in the declaration set RPC as argument or result because they have special meaning for Napier88/RPC. Also, parametric types and the type any are not supported in this release. The current name representation of types (i.e., nding the rst type in the list of declaration sets) can lead to ill-de ned behaviour. Threads in the current release of Napier88 are non-preemptive, meaning that while one is blocked by the operating system (for example, waiting for keyboard input) all other threads are suspended as well. As a consequence, if the client sends the argument and the server (for any obscure reason, such as being suspended) does not send the result, all threads at the client simply stop executing. A very particular instantiation of this problem occurs when a program is acting as both client and server to another program, which is both its client and server; this situation creates conditions for a potential deadlock. Both the argument and result are copied across the network by transitive closure, so great care should be given to the use of recursive types as argument or result. As the current Napier88 implementation makes the transitive closure of most procedures the entire store, especial care should be taken with data structures which include procedures in their closure. For example, maps from Glasgow Libraries [WWP+ 95] cannot be chosen as argument or result, while lists can (and should be used instead of maps for this release). When in doubt contact the author.
We are also working towards reducing or solving these, especially the problems associated with the transitive closure.
8 Troubleshooting The procedure implementation of type proc( string -> env ) which can be found in the environment /GlasgowLibraries/Distribution/RPC returns an environment containing internal RPC environments, and also procedures to list the RPC internal data structures. The password is \friend", use with care. The RPC uses a procedure called debug of type proc( string ) which prints debug messages to the screen. This procedure can be turned on and o by setting the variable debugon found in the environment Utilities (which may be found in the implementation environment, see previous paragraph) to true or false. Any bugs or problems found when using Napier88/RPC should be reported to the author. Suggestions and criticisms for improving Napier88/RPC or this programmer's manual are very welcome. 14
Acknowledgements Malcolm Atkinson, for his permanent support and criticism. The following people in Glasgow should also be acknowledged: Peter Dickman, Paul Philbrow, Stewart Macneill, Darryn Lavery and Tor Faegri; Ron Morrison, Graham Kirby, Quintin Cutts and Dave Munro in St. Andrews; and Benrd Mathiske in Hamburg.
References [BN84]
A.D. Birrel and B.J. Nelson. Implementing remote procedure calls. ACM Transactions on Computer Systems, 2(1):39{59, February 1984. [KBC+94] G.N.C. Kirby, A.L. Brown, R.C.H. Connor, Q.I. Cutts, A. Dearle, V.S. Moore, R. Morrison, and D.S. Munro. The Napier88 standard library reference manual version 2.2. Technical Report FIDE/94/105, ESPRIT Basic Research Action, Project Number 6309|FIDE2 , 1994. [MBC+94] R. Morrison, A.L. Brown, R.C.H. Connor, Q.I. Cutts, A. Dearle, G.N.C. Kirby, and D.S. Munro. The Napier88 reference manual release 2.0. Technical Report FIDE/94/104, ESPRIT Basic Research Action, Project Number 6309|FIDE2 , 1994. [MdS95] M. Mira da Silva. Automating type-safe RPC. In Omran Bukhres, Tamer O zsu, and Ming-Chien Shan, editors, Proceedings of The Fifth International Workshop on Research Issues on Data Engineering: Distributed Object Management (Taipei, Taiwan, 6th{7th March 1995), pages 100{ 107. IEEE Computer Society Press, 1995. [WWP+95] C.A. Waite, R.C. Welland, T. Printezis, A. Pirmohamed, P.C. Philbrow, G. Montgomery, M. Mira da Silva, S.D. Macneill, D.O. Lavery, C. Hertzig, A. Froggatt, R.L. Cooper, and M.P. Atkinson. Glasgow libraries for orthogonally persistent systems|philosophy, organisation and contents. Technical Report FIDE/95/132, ESPRIT Basic Research Action, Project Number 6309|FIDE2 , 1995.
15
A Interface Types The type ClientPack, returned when registering a service with the client side of the RPC, is a structure containing the following elds: Registers a non-primitive type by name with the service, to be used as a result in a remote procedure. exportType: proc( string ). Registers a non-primitive type by name with the service, to be used as an argument in a remote procedure. importProc: proc( string, string ). Registers a remote procedure by name and signature (given as a string) with the service. callRemProc: proc( string, any -> CallResult ). Calls a remote procedure previously registered. Accepts the procedure name and its argument, and returns a variant which is either a value of the expected type or a failure as described below.
importType: proc( string ).
The type CallResult, returned by callRemProc above, is a variant which can have one of the following labels: The remote return value of the expected type if the remote call has been correctly executed. error: CallError. An error code which is a structure with two elds: kind, a variant which can have one of the values described in appendix A; and msg, a string which explains the error which has occurred.
ok: any.
The type ServerPack, returned when registering a service with the server side of the RPC, is a structure containing the following elds: Registers a non-primitive type by name with the service, to be used as an argument in a remote procedure. exportType: proc( string ). Registers a non-primitive type by name with the service, to be used as a result in a remote procedure. exportProc: proc( string, any ). Registers a remote procedure by name and implementation (given as an any) with the service. acceptCalls: proc( bool ). Starts (if argument is true) or stops (if argument is false) accepting incoming remote calls for procedures registered with this service.
importType: proc( string ).
16
B List of Errors Errors found when registering services, client and server stubs simply print an error message and abort the current execution, but these should not be usual if the programmer follows the guidelines in this manual. In addition to the error message in res'error(msg), the errors listed below are returned as res'error(kind) when calling a remote procedure: clientStub.
The remote procedure is not registered with the client program. wrongArgsType. The type of the argument passed to the client stub is not as registered for that stub. connectIgnored. The server is not responding to the client attempts to establish a socket connection. The error message does not specify the reason, but typical ones include:
{ invalid machine name and/or path of the server store when registering the
service name (check and correct if necessary). { server not executing (start the server); { a le called /tmp/.napier88/port.info at the server machine has multiple instances of the server store (remove all but the last one);
ServiceRPC. The
work.
server is executing but the service is not listening to the net-
serverStub.
The remote procedure is not registered with the server program. messageReceived. The network message received from the server representing the return value was corrupted. wrongReturnType. The network message received from the server representing the return value was not of the expected type. errorOnError. This error should never happen as it means an internal RPC error.
Other failures can be detected and reported back to the client program in future releases of Napier88/RPC, but only if programmers can prove they really need and can understand them.
17