Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members

SRPC.H

Go to the documentation of this file.
00001 // Copyright (C) 2001, Compaq Computer Corporation
00002 // 
00003 // This file is part of Vesta.
00004 // 
00005 // Vesta is free software; you can redistribute it and/or
00006 // modify it under the terms of the GNU Lesser General Public
00007 // License as published by the Free Software Foundation; either
00008 // version 2.1 of the License, or (at your option) any later version.
00009 // 
00010 // Vesta is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013 // Lesser General Public License for more details.
00014 // 
00015 // You should have received a copy of the GNU Lesser General Public
00016 // License along with Vesta; if not, write to the Free Software
00017 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018 
00019 // Last modified on Wed Jun 25 23:22:21 EDT 2003 by ken@xorian.net         
00020 //      modified on Fri Sep  8 13:05:23 PDT 2000 by mann  
00021 //      modified on Tue Mar 31 10:48:58 PST 1998 by heydon
00022 //      modified on Thu Jul 11 09:00:39 PDT 1996 by levin
00023 
00024 
00025 #ifndef _SRPC
00026 #define _SRPC
00027 
00028 //  ****************
00029 //  *  Simple RPC  *
00030 //  ****************
00031 
00032 
00033 // This class provides a simple RPC facility that emphasizes
00034 // convenience rather than generality.  It handles reliable connection
00035 // of caller and callee, but doesn't support general-purpose argument
00036 // marshalling.  The underlying communication protocol is assumed to
00037 // be TCP; this class depends on TCP_sock, although the user of this
00038 // class can largely ignore that fact.
00039 
00040 // A description of the use of this class appears at the end of this file.
00041 
00042 // The implementation depends on the pthreads and reentrant C libraries
00043 // SRPC does not depend upon the garbage collector.
00044 
00045 #include <Basics.H>
00046 #include "TCP_sock.H"
00047 #include "int_seq.H"
00048 #include "chars_seq.H"
00049 #include "bytes_seq.H"
00050 
00051 class SRPC {
00052   friend class SRPC_impl;
00053 public:
00054 
00055   //
00056   // Generic failure type (for exception handling).
00057   //
00058 
00059   enum {
00060     // By convention, negative values represent generic problems.  Particular
00061     // interfaces use positive values to report specific problems if they
00062     // wish, or may use generic values (e.g., "protocol_violation") if they
00063     // prefer.
00064     unknown_host       = -1,
00065     unknown_interface  = -2,       //no exporter or bogus port number
00066     version_skew       = -3,       //start_call/await_call rules violation
00067     protocol_violation = -4,       //mismatch, e.g. send_X with recv_Y
00068     buffer_too_small   = -5,       //see recv_*_seq, recv_chars_here
00069     transport_failure  = -6,       //underlying transport (TCP) problem
00070     internal_trouble   = -7,       //bug in SRPC implementation
00071     invalid_parameter  = -8,       //probable caller bug
00072     partner_went_away  = -9,       //partner's SRPC destructor invoked
00073     not_implemented    = -10,
00074     read_timeout       = -11       // no data from peer for too long
00075     };
00076   struct failure {
00077     int r;
00078     Text msg;
00079     inline failure() { };
00080     inline failure(int r, const Text &msg) {
00081       this->r = r; this->msg = msg; };
00082     inline failure(const failure &f) {
00083       this->r = f.r; this->msg = f.msg; };
00084     inline failure& operator=(const failure &f) {
00085       this->r = f.r; this->msg = f.msg; return *this; };
00086   };
00087 
00088   //
00089   // SRPC creation and destruction
00090   //
00091 
00092   enum which_end { caller, callee };
00093 
00094   SRPC(which_end me, const Text &interface, const Text &hostname = "")
00095     throw(failure);
00096     // If "which_end" is "caller", then the remaining parameters identify
00097     // the callee.  "interface" is a string identifying the exported service
00098     // to be called; "hostname", if present, specifies a particular exporter,
00099     // which may be identified by name or by an explicit IP address.
00100     // If "interface" is a decimal number, it is assumed to be a port number
00101     // on a socket defined by "hostname", which in this case cannot be
00102     // defaulted.
00103     //
00104     // If "which_end" is "callee", then "interface" defines the
00105     // service being exported by the local machine.  If it is a
00106     // decimal number, it is interpreted as a port number.  "hostname"
00107     // is ignored for callees.
00108 
00109   SRPC(which_end me, TCP_sock *sock) throw(failure);
00110     // If "which_end" is "caller", "sock" specifies a connected TCP socket.
00111     // If "which_end" is "callee", "sock" specifies a listener TCP socket.
00112 
00113   ~SRPC() throw(failure);
00114     // The underlying transport layer's connection is shutdown and any
00115     // resources it consumes are released.  If this destructor is invoked
00116     // before send_end(...) has returned "true", "failure" is thrown on the
00117     // remote end.
00118 
00119   static Text this_host() throw(failure);
00120     // Returns a/the name for the local machine.  This is the name
00121     // that is used when the 'hostname' argument in the first
00122     // SRPC constructor, above, has its default value.
00123 
00124   static void split_name(const Text &host_and_port, Text &host, Text &port);
00125     // Divides 'host_and_port', which is expected to be of the form
00126     // <host>:<port>, into two Texts 'host' and 'port'.  If no colon is
00127     // present, the entire Text is returned as 'host' and 'port' is empty.
00128 
00129   //
00130   // Connection establishment (call identification)
00131   //
00132 
00133   enum {default_intf_version = -1};
00134   enum {default_proc_id = -1};
00135   void start_call(int proc_id = default_proc_id,
00136                   int intf_version = default_intf_version) throw(failure);
00137   void await_call(int &proc_id, int &intf_version) throw(failure);
00138 
00139   //
00140   // Connection information
00141   //
00142 
00143   bool previous_failure(SRPC::failure *f = NULL) throw();
00144     // If a failure has previously occurred on the SRPC connection, this
00145     // function returns true and, if 'f' is non-NULL, fills in *f with the
00146     // information associated with the previous failure.  Otherwise, this
00147     // function returns false and the value of 'f' is immaterial (that is,
00148     // *f is unaffected).
00149 
00150   bool alive(SRPC::failure *f = NULL) throw();
00151     // Returns true if previous_failure(f) is false and if, upon inspection,
00152     // the SRPC connection seems to be healthy.  In this case, the value
00153     // of 'f' is immaterial.  Otherwise, alive(f) returns false and, if 'f'
00154     // is non-NULL, *f is filled in with the reason that the connection is
00155     // no longer considered usable.
00156 
00157   TCP_sock *socket() throw(failure);
00158     // Returns the underlying TCP_socket for the SRPC connection.  If no
00159     // connection has yet been established (as is the case for the callee
00160     // side immediately after construction), NULL is returned.
00161 
00162   Text local_socket() throw(failure);
00163     // s.local_socket() is semantically equivalent to:
00164     //   TCP_sock *sock = s.socket();
00165     //   if (sock == NULL) return NULL;
00166     //   sockaddr_in me;
00167     //   sock->get_local_addr(me);
00168     //   char a[22];
00169     //   sprintf(a, "%s:%d", inet_ntoa(me.sin_addr), me.sin_port);
00170     //   return Text(a);
00171 
00172   Text remote_socket() throw(failure);
00173     // s.remote_socket() is semantically equivalent to:
00174     //   TCP_sock *sock = s.socket();
00175     //   if (sock == NULL) return NULL;
00176     //   sockaddr_in him;
00177     //   sock->get_remote_addr(him);
00178     //   char a[22];
00179     //   sprintf(a, "%s:%d", inet_ntoa(him.sin_addr), him.sin_port);
00180     //   return Text(a);
00181 
00182   //
00183   // Configuration
00184   //
00185   
00186   void enable_read_timeout(unsigned int seconds,
00187                            bool use_between_calls = false) throw ();
00188   void disable_read_timeout() throw ();
00189   inline bool get_read_timeout(/*OUT*/ unsigned int &seconds,
00190                                /*OUT*/ bool &use_between_calls) throw();
00191     // Enable, disable, or check the setting of the read timeout
00192     // feature.  This makes it possible to set an upper limit on the
00193     // amount of time spent waiting for data from a peer.  This
00194     // feature can be used by servers to prevent holding a resource
00195     // for an indefinite amount of time due to suspended or
00196     // misbehaving clients.  Normally the timeout is only used during
00197     // each call and is disabled between calls.
00198 
00199   //
00200   // Single argument/result transmission
00201   //
00202 
00203   void send_int32(int i) throw(failure);
00204   int recv_int32(bool *got_end = NULL) throw(failure);
00205 
00206   inline void send_int(int i) throw(failure)
00207   {
00208     send_int32(i);
00209   }
00210   inline int recv_int(bool *got_end = NULL) throw(failure)
00211   {
00212     return recv_int32(got_end);
00213   }
00214 
00215   void send_int16(Basics::int16 i) throw(failure);
00216   Basics::int16 recv_int16(bool *got_end = NULL) throw(failure);
00217 
00218   inline void send_short(Basics::int16 i) throw(failure)
00219   {
00220     send_int16(i);
00221   }
00222   inline Basics::int16 recv_short(bool *got_end = NULL) throw(failure)
00223   {
00224     return recv_int16(got_end);
00225   }
00226 
00227   void send_int64(Basics::int64 i) throw(failure);
00228   Basics::int64 recv_int64(bool *got_end = NULL) throw(failure);
00229 
00230   // Send and receive single precision fp numbers.
00231   // Used for sending load averages around.
00232   // assumes sizeof(float) == sizeof(int),
00233   // which I think is as safe as recv_int32 assuming sizeof(int) == sizeof(int32).
00234   inline void send_float(float f) throw(failure)
00235   {
00236     int *ip = (int *)&f;
00237     send_int32(*ip);
00238   }
00239   inline float recv_float(bool *got_end = NULL) throw(failure)
00240   {
00241     int i;
00242     float *fp = (float *)&i;
00243     i = recv_int32(got_end);
00244     return *fp;
00245   }
00246 
00247   // Send and receive booleans.  Intended for use with optional
00248   // parameters.
00249   void send_bool(bool b) throw (failure);
00250   bool recv_bool(bool *got_end = NULL) throw(failure);
00251 
00252   void send_chars(const char *s) throw(failure);
00253     // The sequence of characters beginning at "s" and terminated by
00254     // a null byte (binary zero) is transmitted.  Passing NULL for "s"
00255     // is equivalent to passing a zero-length string.
00256   char *recv_chars(bool *got_end = NULL) throw(failure);
00257     // The incoming string is stored in dynamic storage; a pointer to it
00258     // is returned.  The client is responsible for deallocating the storage.
00259   char *recv_chars(char *buff, int buff_len, bool *got_end = NULL)
00260     throw(failure);
00261     // If the incoming string (plus its null terminator) is at most "buff_len",
00262     // then the string and its null terminator are read into "buff" and "buff"
00263     // is returned. Otherwise, dynamic storage is allocated to hold the
00264     // incoming string (and its null terminator), and a pointer to that buffer
00265     // is returned. In the latter case, the client is responsible for de-
00266     // allocating the storage.
00267   void recv_chars_here(char *buffer, int &len, bool *got_end = NULL)
00268     throw(failure);
00269     // "buffer" and "len" define a storage area into which the incoming
00270     // string is placed.  If space permits, the string is stored (with a
00271     // null terminator) and "len" is updated to reflect its length (without
00272     // the terminator).  If the string is too long to fit in the space
00273     // provided, "failure(buffer_too_small)" is thrown.
00274 
00275   void send_Text(const Text &t) throw(failure);
00276     // The Text 't' is transmitted.
00277   void recv_Text(/*OUT*/ Text &t, bool *got_end = NULL) throw(failure);
00278     // Set "t" to the incoming text.
00279 
00280   void send_bytes(const char *buffer, int len) throw(failure);
00281     // The sequence of characters beginning at "buffer" and of length "len"
00282     // is transmitted.
00283   char *recv_bytes(int &len, bool *got_end = NULL) throw(failure);
00284     // An incoming sequence of bytes is stored in dynamically allocated
00285     // storage, whose address is returned as the result of this function.
00286     // Additionally, the "len" parameter is set to the length of the
00287     // received sequence.  The client is responsible for deallocating
00288     // the storage used by the sequence.
00289   void recv_bytes_here(char *buffer, int &len, bool *got_end = NULL)
00290     throw(failure);
00291     // "buffer" and "len" define a storage area into which the incoming
00292     // sequence of bytes is placed. If space permits, the bytes are stored
00293     // in a prefix of "buffer" and "len" is set to the number of bytes
00294     // received. If the number of incoming bytes is greater than the initial
00295     // value of "len", then "failure(buffer_too_small)" is thrown.
00296 
00297   void send_socket(sockaddr_in &sock) throw(failure);
00298     // "sock" is an Internet socket address containing an IP address and
00299     // port stored (as is customary in Unix) in network byte order.
00300   sockaddr_in recv_socket(bool *got_end = NULL) throw(failure);
00301     // Returns an Internet socket address containing an IP address and port
00302     // stored in network byte order.  The remaining fields of the resulting
00303     // "sockaddr_in" are initialized appropriately, so that the address can
00304     // be used immediately, e.g., as a parameter to "TCP_sock::connect_to".
00305 
00306   //
00307   // Sequence of argument/result transmission: special cases
00308   //
00309 
00310   void send_int16_array(const Basics::int16 *seq, int len)
00311     throw (SRPC::failure);
00312     // Send the array of 16-bit integers in "seq", which must have
00313     // length "len".
00314   Basics::int16* recv_int16_array(/*OUT*/ int &len) throw (SRPC::failure);
00315     // Receive an array of 16-bit integers into a newly allocated
00316     // array. The new array is returned, and "len" is set to its
00317     // length.
00318 
00319   inline void send_short_array(const Basics::int16 *seq, int len)
00320     throw (SRPC::failure)
00321   {
00322     send_int16_array(seq, len);
00323   }
00324   inline Basics::int16* recv_short_array(/*OUT*/ int &len)
00325     throw (SRPC::failure)
00326   {
00327     return recv_int16_array(len);
00328   }
00329 
00330   void send_int32_array(const Basics::int32 *seq, int len)
00331     throw (SRPC::failure);
00332     // Send the array of 32-bit integers in "seq", which must have
00333     // length "len".
00334   Basics::int32* recv_int32_array(/*OUT*/ int &len) throw (SRPC::failure);
00335     // Receive an array of 32-bit integers into a newly allocated
00336     // array. The new array is returned, and "len" is set to its
00337     // length.
00338 
00339   void send_int64_array(const Basics::int64 *seq, int len)
00340     throw (SRPC::failure);
00341     // Send the array of 64-bit integers in "seq", which must have
00342     // length "len".
00343   Basics::int64* recv_int64_array(/*OUT*/ int &len) throw (SRPC::failure);
00344     // Receive an array of 64-bit integers into a newly allocated
00345     // array. The new array is returned, and "len" is set to its
00346     // length.
00347 
00348   void send_int_seq(int_seq &is) throw(failure);
00349     // "send_int_seq" transmits the sequence of integers specified by "is".
00350     // It is legal to send an integer sequence as a component of a general-case
00351     // sequence (i.e., between calls of "send_seq_start" and "send_seq_end").
00352     // Except for this proviso, the semantics of "send_int_seq" are
00353     // equivalent to:
00354     //   send_seq_start(cs.length());
00355     //   for (int i = 0; i < is.length(); i++) send_int(is[i]);
00356     //   send_seq_end();
00357   void recv_int_seq(int_seq &is) throw (failure);
00358     // "recv_int_seq" receives a sequence of integers into storage defined
00359     // by "is".  It is legal to receive an integer sequence as a component
00360     // of a general-case sequence (i.e., between calls of "recv_seq_start"
00361     // and "recv_seq_end").  Except for this proviso, the semantics of
00362     // "recv_int_seq" are equivalent to:
00363     //   recv_seq_start();
00364     //   while (true) {
00365     //     bool got_end;
00366     //     int i = recv_int(&got_end);
00367     //     if (got_end) break;
00368     //     is.append(i);
00369     //   };
00370     //   recv_seq_end();
00371 
00372   void send_chars_seq(chars_seq &cs) throw(failure);
00373     // "send_chars_seq" transmits a sequence of character strings.  The
00374     // chars_seq class provides various ways to construct such a sequence.
00375     // It is legal to send a string sequence as a component of a general-case
00376     // sequence (i.e., between calls of "send_seq_start" and "send_seq_end").
00377     // Except for this proviso, the semantics of "send_chars_seq" are
00378     // equivalent to:
00379     //   send_seq_start(cs.length());
00380     //   for (int i = 0; i < cs.length(); i++) send_chars(cs[i]);
00381     //   send_seq_end();
00382   void recv_chars_seq(chars_seq &cs) throw(failure);
00383     // "recv_chars_seq" receives a sequence of character strings.  The
00384     // "cs" parameter will generally be a freshly constructed chars_seq;
00385     // see the description of the chars_seq class, below, for various
00386     // construction options.  If "cs" is incapable of accommodating the
00387     // incoming sequence, "failure(buffer_too_small)" is thrown.
00388     // It is legal to receive a character string sequence as a component
00389     // of a general-case sequence (i.e., between calls of "recv_seq_start"
00390     // and "recv_seq_end").  Except for this proviso, the semantics of
00391     // "recv_chars_seq" are equivalent to:
00392     //   recv_seq_start();
00393     //   while (true) {
00394     //     bool got_end;
00395     //     char *s = recv_chars(&got_end);
00396     //     if (got_end) break;
00397     //     cs.append(s);
00398     //   };
00399     //   recv_seq_end();
00400 
00401   void send_bytes_seq(bytes_seq &bs) throw(failure);
00402     // "send_bytes_seq" transmits a sequence of byte strings.  The
00403     // bytes_seq class provides various ways to construct such a sequence.
00404     // It is legal to send a byte-string sequence as a component of a
00405     // general-case sequence (i.e., between calls of "send_seq_start" and
00406     // "send_seq_end").  Except for this proviso, the semantics of
00407     // "send_bytes_seq" are equivalent to:
00408     //   send_seq_start(bs.length());
00409     //   for (int i = 0; i < bs.length(); i++) send_bytes(bs[i]);
00410     //   send_seq_end();
00411   void recv_bytes_seq(bytes_seq &bs) throw(failure);
00412     // "recv_bytes_seq" receives a sequence of byte strings.  The
00413     // "bs" parameter will generally be a freshly constructed bytes_seq;
00414     // see the description of the bytes_seq class, below, for various
00415     // construction options.  If "bs" is incapable of accommodating the
00416     // incoming sequence, "failure(buffer_too_small)" is thrown.
00417     // It is legal to receive a byte-string sequence as a component
00418     // of a general-case sequence (i.e., between calls of "recv_seq_start"
00419     // and "recv_seq_end").  Except for this proviso, the semantics of
00420     // "recv_bytes_seq" are equivalent to:
00421     //   recv_seq_start();
00422     //   while (true) {
00423     //     bool got_end;
00424     //     int len;
00425     //     char *s = recv_bytes(len, &got_end);
00426     //     if (got_end) break;
00427     //     bs.append(byte_str(s, len));
00428     //   };
00429     //   recv_seq_end();
00430 
00431 
00432   //
00433   // Sequence of argument/result transmission: general case
00434   //
00435 
00436   enum {any = -1 };
00437 
00438   void send_seq_start(int len = any, int bytes = any) throw(failure);
00439     // If the "len" parameter is not "any", it specifies the number
00440     // of elements in the sequence.  If the "bytes" parameter is not
00441     // "any", it specifies the total storage required for the sequence.
00442     // Any argument other than another general-case sequence may be
00443     // transmitted as part of the general-case sequence.
00444   void recv_seq_start(int *len = NULL, int *bytes = NULL) throw(failure);
00445     // The "len" and "bytes" parameters supplied by send_seq_start are
00446     // returned (provided the corresponding parameter pointers are non-NULL).
00447     // These can be used by the receiver to allocate appropriate storage for
00448     // the sequence.  It is the responsibility of sender and receiver to
00449     // communicate and use these quantities properly; the SRPC implementation
00450     // neither interprets nor verifies them.
00451     // Any argument other than another general-case sequence may be transmitted
00452     // as part of the general-case sequence.
00453   void send_seq_end() throw(failure);
00454     // This function is called to inform the receiver that all members of
00455     // the sequence have been transmitted.  It is required, even if
00456     // "send_seq_start" was called with an explicit "len" parameter.
00457   void recv_seq_end() throw(failure);
00458     // This function is called by the receiver when it believes it has
00459     // received all elements of the sequence.  That belief may be based
00460     // on interpretation of the "len" value returned by "recv_seq_start", by
00461     // the inherent structure of the sequence (e.g., an agreed-upon marker),
00462     // or by a true value for the "got_end" result parameter to a preceding
00463     // call of "recv_X".
00464 
00465   //
00466   // Argument/result transmission completion
00467   //
00468 
00469   void send_end() throw(failure);
00470     // If send_end returns normally, the invoker is assured that the preceding
00471     // arguments/results were accepted by the other end.
00472   void recv_end() throw(failure);
00473     // If recv_end returns normally, the invoker can assume that the stream
00474     // of arguments/results ended as expected and the other end has been
00475     // informed that all values were properly received.
00476 
00477 
00478   //
00479   // Failure reporting
00480   //
00481 
00482   void send_failure(int r,
00483                     const Text &msg,
00484                     bool remote_only = false) throw(failure);
00485     // The exception "failure" is transmitted to the other end of the
00486     // SRPC connection and thrown at the next opportunity.  This
00487     // function returns normally if and only if "remote_only" is true
00488     // and the (remote) failure notification occurs without trouble;
00489     // otherwise, "failure" is thrown (locally).  Regardless of whether
00490     // "failure" is thrown locally, the SRPC object is useless for
00491     // further operations; a subsequent attempt to use it will throw
00492     // "failure(protocol_violation)".
00493 
00494   static failure convert_TCP_failure(TCP_sock::failure tf);
00495     // This utility function converts a failure reported by the TCP_sock
00496     // machinery to a suitable SRPC::failure.
00497 
00498 private:
00499   SRPC_impl *p;
00500   static pthread_once_t init_block;
00501   static void init() throw (failure);
00502 
00503   // An SRPC object should neither be copied nor assigned.
00504   SRPC(SRPC &);
00505   void operator=(SRPC &);
00506 };
00507 
00508 
00509 //  ***************************
00510 //  *  Use of the SRPC class  *
00511 //  ***************************
00512 
00513 /*
00514 
00515 An SRPC object represents one end of a "connection" that is used for a
00516 remote procedure call.  The actual connection, however, is essentially
00517 invisible to the client (which gives the implementation freedom in
00518 choosing the underlying transport protocol -- today, it's TCP).
00519 Because the connection is being used for a procedure call and not
00520 arbitrary bidirectional communication, the semantics of SRPC member
00521 functions are tuned to this purpose.  This is done to reduce the need
00522 for handshaking between the ends and thereby improve performance.
00523 
00524 The possibility of a remote call begins when a server (who will be the
00525 callee) advertises its availability.  It does so by using one of the
00526 SRPC constructors and specifying the first parameter as "callee".  The
00527 other parameters define the service (e.g., by name or well-known
00528 socket/port).  This produces an SRPC object, but does not block
00529 awaiting a connection from a client.  However, the creation of the
00530 SRPC object by the callee causes the underlying machinery to "listen"
00531 for client requests.  A server may create multiple SRPC objects for
00532 the same service; they would typically be handled subsequently by
00533 separate threads.
00534 
00535 [Aside: Note that the private data of the SRPC class consists of a
00536 single pointer; the actual data storage space is allocated on the heap.
00537 Clients of SRPC therefore should not feel the need to allocate
00538 pointers to SRPC objects; they may be freely passed around without
00539 overhead.]
00540 
00541 A call is actually initiated by a client (the caller), which invokes
00542 one of the SRPC constructors specifying the first parameter as
00543 "caller".  The other parameters specify the callee by naming the
00544 service it provides (e.g., symbolically, or as a well-known
00545 socket/port).  The SRPC implementation verifies that the service is
00546 known to exist (i.e., has been advertised by some server), and
00547 initiates contact, but does not block until an underlying connection
00548 is established.
00549 
00550 The caller then optionally calls start_call, which allows a
00551 specification of the "procedure" to be called and the version of the
00552 "interface" being used.  The callee discovers these specifications by
00553 invoking await_call.  In face, these specifications are simply integer
00554 values whose meanings are agreed upon by the two parties.  To simplify
00555 common cases, however, SRPC performs a few tests that serve to detect
00556 common cases of version skew.  Here are the rules for using start_call and
00557 await_call:
00558 
00559   * If the caller invokes start_call, the callee must invoke await_call.
00560 
00561   * If the caller omits start_call, the callee may omit await_call.
00562     If the callee invokes await_call, the semantics are the same as if
00563     the caller had invoked start_call with default values for its
00564     parameters.  (See below.)
00565 
00566   * If await_call is invoked, SRPC compares the values supplied for
00567     its parameters with the values supplied for the corresponding
00568     parameters in the invocation of start_call.  If await_call
00569     supplies the default value for a parameter, SRPC replaces it with
00570     the value given by start_call (which may or may not be the default
00571     value).  If await_call supplies a non-default value, it must be
00572     equal to the value supplied by start_call.
00573 
00574   * If the preceding requirements are not met, the exception "failure"
00575     is thrown for both caller and callee at the earliest opportunity.
00576 
00577 These rules allow a server (the callee) to accomodate clients
00578 (callers) that expect different versions of an interface.  Each caller
00579 specifies particular values for the interface and/or procedure it
00580 wants to call; the callee specifies the default value and receives the
00581 caller's specification, which it can then act upon.  A strict server
00582 can specify a non-default value, thereby causing SRPC to throw
00583 "failure" for all attempted calls that don't match that value.
00584 
00585 Once caller and callee have agreed on the procedure to be performed,
00586 the caller begins transmitting arguments, using the "send_*"
00587 functions, finishing with a call of send_end.  The callee executes a
00588 corresponding sequence of "recv_*" functions, ending with a call of
00589 "recv_end".  (The consequences of a mismatch in the sequence of "send_*" and
00590 "recv_*" calls are discussed below.)
00591 
00592 SRPC handles only a limited collection of argument types; there is no
00593 general-purpose marshalling facility.  Only simple types are supported
00594 (integers, character and byte strings), as well as homogeneous
00595 sequences of these these simple types.
00596 
00597 The transmission of simple types is straightforward.  The sender
00598 invokes send_X(val), where X is a simple type, and val has type X. The
00599 receiver invokes a correspondingly named recv_X function, receiving a
00600 value of type X as a result.  In the case of recv_chars or recv_bytes,
00601 the storage to hold the string is allocated dynamically; the caller is
00602 responsible for disposing of it.
00603 
00604 There are several ways to transmit sequences:
00605 
00606  1. If the sender knows the length of the sequence, it can invoke
00607     send_X_seq, passing an object that embodies the entire sequence.
00608     The receiver invokes recv_X_seq and obtains an object that embodies
00609     the whole sequence.  Storage management at the receiving end is
00610     established by the way the sequence object is created.  See the
00611     comments for the various constructors in X_seq classes, above.
00612 
00613  2. If the sender does not know the length of the sequence, it invokes
00614     send_seq_start, followed by a series of calls on send_X, and
00615     concluding with a call of send_seq_end.  The receiver invokes
00616     recv_seq_start, followed by a series of calls on recv_X(&got_end),
00617     concluding with a call of recv_seq_end.  The result parameter got_end
00618     informs the receiver when the end of the sequence has been seen; if
00619     it is true, the return value of recv_X is not meaningful.
00620 
00621  3. The sender and receiver may agree to the transmission of a
00622     heterogeneously typed values by observing the above protocol but
00623     varying X in the series of calls of send_X and recv_X.  Of
00624     course, the two ends must vary X consistently to avoid error.
00625 
00626 Once argument transmission is complete (i.e., when the callee's call
00627 of recv_end returns normally), the callee begins execution of the
00628 agreed-upon procedure.  After execution is complete, the callee begins
00629 result transmission by calling a sequence of "send_*" procedures,
00630 ending with "send_end".  The caller executes a corresponding sequence
00631 of "recv_*" procedures, ending with "recv_end".  If the caller's call
00632 of "recv_end" returns normally, the remote call is complete.  (See
00633 below for reuse of the SRPC object.)
00634 
00635 Either side may invoke "send_failure" to cause the other side to
00636 receive a failure notification.  The type "failure" includes an
00637 integer code describing the failure and a character string value.
00638 There are some conventional values for the code included in the
00639 definition of the SRPC class; caller and callee may use other
00640 non-conflicting values as they wish.  For the conventional values, the
00641 accompanying string gives more details on the failure; it is intended
00642 for human consumption.
00643 
00644 Once a failure is thrown for any reason, the SRPC connection is no longer
00645 useful.
00646 
00647 The implementation doesn't guarantee that a failure will be reported
00648 as soon as possible (which would require failure notifications to be
00649 sent out-of-band and significantly complicate the implementation).
00650 Instead, the clients of this interface should surround the entire
00651 sequence of calls to send_X or recv_X in a "try ... catch (failure)".
00652 The implementation does promise to report any prior failure no later
00653 than the return from send_end and recv_end; that is, if these
00654 procedures return normally, the caller can assume that the actions of
00655 all preceding calls were acceptable to the other side of the
00656 connection.  Notice that this implies that the caller may not discover
00657 that a server is not responding until it has transmitted (i.e., called
00658 send_X for) all of its arguments.
00659 
00660 As long as neither side throws "failure", the implicit connection can
00661 be reused for subsequent calls, beginning with the (optional) calls of
00662 start_call and await_call.  That is, following a normal return from
00663 send_end (by the callee) and recv_end (by the caller), a new call may
00664 be initiated without destroying and recreating new SRPC objects.  The
00665 underlying resources of the transport machinery are retained until the
00666 SRPC object is destroyed.
00667 
00668 An SRPC object is an inherently sequential facility.  Multi-threaded use
00669 of an SRPC object by a client must be synchronized by the client.
00670 
00671 */
00672 
00673 #endif  /* _SRPC */

Generated on Mon May 8 00:48:57 2006 for Vesta by  doxygen 1.4.2