LogCabin
RPC/ClientRPC.h
Go to the documentation of this file.
00001 /* Copyright (c) 2012 Stanford University
00002  * Copyright (c) 2014 Diego Ongaro
00003  *
00004  * Permission to use, copy, modify, and distribute this software for any
00005  * purpose with or without fee is hereby granted, provided that the above
00006  * copyright notice and this permission notice appear in all copies.
00007  *
00008  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR(S) DISCLAIM ALL WARRANTIES
00009  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
00010  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHORS BE LIABLE FOR
00011  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00012  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
00013  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
00014  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00015  */
00016 
00017 #include <cinttypes>
00018 #include <google/protobuf/message.h>
00019 #include <iostream>
00020 #include <memory>
00021 #include <string>
00022 
00023 #include "RPC/OpaqueClientRPC.h"
00024 
00025 #ifndef LOGCABIN_RPC_CLIENTRPC_H
00026 #define LOGCABIN_RPC_CLIENTRPC_H
00027 
00028 namespace LogCabin {
00029 namespace RPC {
00030 
00031 class ClientSession; // forward declaration
00032 
00033 /**
00034  * This class represents an asynchronous remote procedure call. Unlike
00035  * OpaqueClientRPC, this executes a particular method on a particular service.
00036  *
00037  * TODO(ongaro): This abstraction should ideally contain protocol version
00038  * negotiation for the higher layer. To do so, we'd want to be able to
00039  * associate a small amount of state with the session.
00040  */
00041 class ClientRPC {
00042   public:
00043     /// Clock used for timeouts.
00044     typedef OpaqueClientRPC::Clock Clock;
00045     /// Type for absolute time values used for timeouts.
00046     typedef OpaqueClientRPC::TimePoint TimePoint;
00047 
00048     /**
00049      * Issue an RPC to a remote service.
00050      * \param session
00051      *      A connection to the remote server.
00052      * \param service
00053      *      Identifies the service running on the server.
00054      *      See Protocol::Common::ServiceId.
00055      * \param serviceSpecificErrorVersion
00056      *      This tells the Service what service-specific errors the client
00057      *      understands. Clients can expect services to not send
00058      *      service-specific errors introduced in newer versions, but they
00059      *      should remain compatible with older versions.
00060      * \param opCode
00061      *      Identifies the remote procedure within the Service to execute.
00062      * \param request
00063      *      The arguments to the remote procedure.
00064      */
00065     ClientRPC(std::shared_ptr<RPC::ClientSession> session,
00066               uint16_t service,
00067               uint8_t serviceSpecificErrorVersion,
00068               uint16_t opCode,
00069               const google::protobuf::Message& request);
00070 
00071     /**
00072      * Default constructor. This doesn't create a valid RPC, but it is useful
00073      * as a placeholder.
00074      */
00075     ClientRPC();
00076 
00077     /**
00078      * Move constructor.
00079      */
00080     ClientRPC(ClientRPC&&);
00081 
00082     /**
00083      * Destructor.
00084      */
00085     ~ClientRPC();
00086 
00087     /**
00088      * Move assignment.
00089      */
00090     ClientRPC& operator=(ClientRPC&&);
00091 
00092     /**
00093      * Abort the RPC.
00094      * The caller is no longer interested in its reply.
00095      */
00096     void cancel();
00097 
00098     /**
00099      * Indicate whether a response or error has been received for
00100      * the RPC.
00101      * \return
00102      *      True means the reply is ready or an error has occurred; false
00103      *      otherwise.
00104      */
00105     bool isReady();
00106 
00107     /**
00108      * The return type of waitForReply().
00109      */
00110     enum class Status {
00111         /**
00112          * The service returned a normal response. This is available in
00113          * 'response'.
00114          */
00115         OK,
00116         /**
00117          * The service threw an error (but at the transport level, the RPC
00118          * succeeded). Service-specific details may be available in
00119          * 'serviceSpecificError'.
00120          */
00121         SERVICE_SPECIFIC_ERROR,
00122         /**
00123          * The server could not be contacted or did not reply. It is unknown
00124          * whether or not the server executed the RPC. More information is
00125          * available with getErrorMessage().
00126          */
00127         RPC_FAILED,
00128         /**
00129          * The RPC was aborted using #cancel(). It is unknown whether the
00130          * server executed or will execute the RPC.
00131          */
00132         RPC_CANCELED,
00133         /**
00134          * The RPC did not complete before the given timeout elapsed. It is
00135          * unknown whether or not the server executed the RPC (yet).
00136          */
00137         TIMEOUT,
00138         /**
00139          * The server is not running the requested service.
00140          */
00141         INVALID_SERVICE,
00142         /**
00143          * The server rejected the request, probably because it doesn't support
00144          * the opcode, or maybe the request arguments were invalid.
00145          */
00146         INVALID_REQUEST,
00147     };
00148 
00149     /**
00150      * Wait for a reply to the RPC or an error.
00151      * Panics if the server responds but is not running the same protocol.
00152      *
00153      * \param[out] response
00154      *      If not NULL, this will be filled in if this method returns OK.
00155      * \param[out] serviceSpecificError
00156      *      If not NULL, this will be filled in if this method returns
00157      *      SERVICE_SPECIFIC_ERROR.
00158      * \param[in] timeout
00159      *      After this time has elapsed, stop waiting and return TIMEOUT.
00160      *      In this case, response and serviceSpecificError will be left
00161      *      unmodified.
00162      * \return
00163      *      See the individual values of #Status.
00164      */
00165     Status waitForReply(google::protobuf::Message* response,
00166                         google::protobuf::Message* serviceSpecificError,
00167                         TimePoint timeout);
00168 
00169     /**
00170      * If an RPC failure occurred, return a message describing that error.
00171      *
00172      * All errors indicate that it is unknown whether or not the server
00173      * executed the RPC. Unless the RPC was canceled with #cancel(), the
00174      * ClientSession has been disconnected and is no longer useful for
00175      * initiating new RPCs.
00176      *
00177      * \return
00178      *      If an RPC failure has occurred, a message describing that error.
00179      *      Otherwise, an empty string.
00180      */
00181     std::string getErrorMessage() const;
00182 
00183   private:
00184     /**
00185      * Identifies the service running on the server.
00186      * See Protocol::Common::ServiceId.
00187      */
00188     uint16_t service;
00189 
00190     /**
00191      * Identifies the remote procedure within the Service to execute.
00192      */
00193     uint16_t opCode;
00194 
00195     OpaqueClientRPC opaqueRPC;
00196 
00197     // ClientRPC is non-copyable.
00198     ClientRPC(const ClientRPC&) = delete;
00199     ClientRPC& operator=(const ClientRPC&) = delete;
00200 
00201 }; // class ClientRPC
00202 
00203 /**
00204  * Output a ClientRPC::Status to a stream.
00205  * This is helpful for google test output.
00206  */
00207 ::std::ostream&
00208 operator<<(::std::ostream& os, ClientRPC::Status status);
00209 
00210 } // namespace LogCabin::RPC
00211 } // namespace LogCabin
00212 
00213 #endif /* LOGCABIN_RPC_CLIENTRPC_H */
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines