text: // Licensed to the Apache Software Foundation (ASF) under one
  // or more contributor license agreements.  See the NOTICE file
  // distributed with this work for additional information
  // regarding copyright ownership.  The ASF licenses this file
  // to you under the Apache License, Version 2.0 (the
  // "License"); you may not use this file except in compliance
  // with the License.  You may obtain a copy of the License at
  //
  //   http://www.apache.org/licenses/LICENSE-2.0
  //
  // Unless required by applicable law or agreed to in writing,
  // software distributed under the License is distributed on an
  // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  // KIND, either express or implied.  See the License for the
  // specific language governing permissions and limitations
  // under the License.
  #ifndef KUDU_RPC_RPC_CONTEXT_H
  #define KUDU_RPC_RPC_CONTEXT_H
  
  #include <stddef.h>
  #include <string>
  
  #include "kudu/gutil/gscoped_ptr.h"
  #include "kudu/rpc/rpc_header.pb.h"
  #include "kudu/rpc/service_if.h"
  #include "kudu/util/status.h"
  
  namespace google {
  namespace protobuf {
  class Message;
  } // namespace protobuf
  } // namespace google
  
  namespace kudu {
  
  class Sockaddr;
  class Trace;
  
  namespace rpc {
  
  class InboundCall;
  class RemoteUser;
  class ResultTracker;
  class RpcSidecar;
  
  #define PANIC_RPC(rpc_context, message) \
    do { \
      if (rpc_context) {                              \
        rpc_context->Panic(__FILE__, __LINE__, (message));  \
      } else { \
        LOG(FATAL) << message; \
      } \
    } while (0)
  
  // The context provided to a generated ServiceIf. This provides
  // methods to respond to the RPC. In the future, this will also
  // include methods to access information about the caller: e.g
  // authentication info, tracing info, and cancellation status.
  //
  // This is the server-side analogue to the RpcController class.
  class RpcContext {
   public:
    // Create an RpcContext. This is called only from generated code
    // and is not a public API.
    RpcContext(InboundCall *call,
               const google::protobuf::Message *request_pb,
               google::protobuf::Message *response_pb,
               const scoped_refptr<ResultTracker>& result_tracker);
  
    ~RpcContext();
  
    // Return the trace buffer for this call.
    Trace* trace();
  
    // Send a response to the call. The service may call this method
    // before or after returning from the original handler method,
    // and it may call this method from a different thread.
    //
    // The response should be prepared already in the response PB pointer
    // which was passed to the handler method.
    //
    // After this method returns, this RpcContext object is destroyed. The request
    // and response protobufs are also destroyed.
    void RespondSuccess();
  
    // Like the above, but doesn't store the results of the service call, if results
    // are being tracked.
    // Used in cases where a call specific error was set on the response protobuf,
    // the call should be considered failed, thus results shouldn't be cached.
    void RespondNoCache();
  
    // Respond with an error to the client. This sends back an error with the code
    // ERROR_APPLICATION. Because there is no more specific error code passed back
    // to the client, most applications should create a custom error PB extension
    // and use RespondApplicationError(...) below. This method should only be used
    // for unexpected errors where the server doesn't expect the client to do any
    // more advanced handling.
    //
    // After this method returns, this RpcContext object is destroyed. The request
    // and response protobufs are also destroyed.
    void RespondFailure(const Status &status);
  
    // Respond with an RPC-level error. This typically manifests to the client as
    // a remote error, one whose handling is agnostic to the particulars of the
    // sent RPC. For example, both ERROR_SERVER_TOO_BUSY and ERROR_UNAVAILABLE
    // usually cause the client to retry the RPC at a later time.
    //
    // After this method returns, this RpcContext object is destroyed. The request
    // and response protobufs are also destroyed.
    void RespondRpcFailure(ErrorStatusPB_RpcErrorCodePB err, const Status& status);
  
    // Respond with an application-level error. This causes the caller to get a
    // RemoteError status with the provided string message. Additionally, a
    // service-specific error extension is passed back to the client. The
    // extension must be registered with the ErrorStatusPB protobuf. For
    // example:
    //
    //   message MyServiceError {
    //     extend kudu.rpc.ErrorStatusPB {
    //       optional MyServiceError my_service_error_ext = 101;
    //     }
    //     // Add any extra fields or status codes you want to pass back to
    //     // the client here.
    //     required string extra_error_data = 1;
    //   }
    //
    // NOTE: the numeric '101' above must be an integer greater than 101
    // and must be unique across your code base.
    //
    // Given the above definition in your service protobuf file, you would
    // use this method like:
    //
    //   MyServiceError err;
    //   err.set_extra_error_data("foo bar");
    //   ctx->RespondApplicationError(MyServiceError::my_service_error_ext.number(),
    //                                "Some error occurred", err);
    //
    // The client side may then retreieve the error by calling:
    //   const MyServiceError& err_details =
    //     controller->error_response()->GetExtension(MyServiceError::my_service_error_ext);
    //
    // After this method returns, this RpcContext object is destroyed. The request
    // and response protobufs are also destroyed.
    void RespondApplicationError(int error_ext_id, const std::string& message,
                                 const google::protobuf::Message& app_error_pb);
  
  
    // Adds an RpcSidecar to the response. This is the preferred method for
    // transferring large amounts of binary data, because this avoids additional
    // copies made by serializing the protobuf.
    //
    // Assumes no changes to the sidecar's data are made after insertion.
    //
    // Upon success, writes the index of the sidecar (necessary to be retrieved
    // later) to 'idx'. Call may fail if all sidecars have already been used
    // by the RPC response.
    Status AddOutboundSidecar(std::unique_ptr<RpcSidecar> car, int* idx);
  
    // Fills 'sidecar' with a sidecar sent by the client. Returns an error if 'idx' is out
    // of bounds.
    Status GetInboundSidecar(int idx, Slice* slice);
  
    // Return the identity of remote user who made this call.
    const RemoteUser& remote_user() const;
  
    // Discards the memory associated with the inbound call's payload. All previously
    // obtained sidecar slices will be invalidated by this call. It is an error to call
    // GetInboundSidecar() after this method. request_pb() remains valid.
    // This is useful in the case where the server wishes to delay responding to an RPC
    // (perhaps to control the rate of RPC requests), but knows that the RPC payload itself
    // won't be processed any further.
    void DiscardTransfer();
  
    // Return the remote IP address and port which sent the current RPC call.
    const Sockaddr& remote_address() const;
  
    // A string identifying the requestor -- both the user info and the IP address.
    // Suitable for use in log messages.
    std::string requestor_string() const;
  
    // Return the name of the RPC service method being called.
    std::string method_name() const;
  
    // Return the name of the RPC service being called.
    std::string service_name() const;
  
    const google::protobuf::Message *request_pb() const { return request_pb_.get(); }
    google::protobuf::Message *response_pb() const { return response_pb_.get(); }
  
    // Return an upper bound on the client timeout deadline. This does not
    // account for transmission delays between the client and the server.
    // If the client did not specify a deadline, returns MonoTime::Max().
    MonoTime GetClientDeadline() const;
  
    // Return the time when the inbound call was received.
    MonoTime GetTimeReceived() const;
  
    // Whether the results of this RPC are tracked with a ResultTracker.
    // If this returns true, both result_tracker() and request_id() should return non-null results.
    bool AreResultsTracked() const { return result_tracker_.get() != nullptr; }
  
    // Returns this call's result tracker, if it is set.
    const scoped_refptr<ResultTracker>& result_tracker() const {
      return result_tracker_;
    }
  
    // Returns this call's request id, if it is set.
    const rpc::RequestIdPB* request_id() const;
  
    // Returns the size of the transfer buffer that backs 'call_'. If the
    // transfer buffer no longer exists (e.g. GetTransferSize() is called after
    // DiscardTransfer()), returns 0.
    size_t GetTransferSize() const;
  
    // Panic the server. This logs a fatal error with the given message, and
    // also includes the current RPC request, requestor, trace information, etc,
    // to make it easier to debug.
    //
    // Call this via the PANIC_RPC() macro.
    void Panic(const char* filepath, int line_number, const std::string& message)
      __attribute__((noreturn));
  
   private:
    friend class ResultTracker;
    InboundCall* const call_;
    const gscoped_ptr<const google::protobuf::Message> request_pb_;
    const gscoped_ptr<google::protobuf::Message> response_pb_;
    scoped_refptr<ResultTracker> result_tracker_;
  };
  
  } // namespace rpc
  } // namespace kudu
  #endif
  