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 */