diff options
25 files changed, 786 insertions, 306 deletions
diff --git a/examples/cpp/helloworld/greeter_async_client.cc b/examples/cpp/helloworld/greeter_async_client.cc index 605fb7fb3a..923c8ffa74 100644 --- a/examples/cpp/helloworld/greeter_async_client.cc +++ b/examples/cpp/helloworld/greeter_async_client.cc @@ -35,13 +35,8 @@ #include <memory> #include <string> -#include <grpc/grpc.h> -#include <grpc/support/log.h> -#include <grpc++/channel.h> -#include <grpc++/client_context.h> -#include <grpc++/completion_queue.h> -#include <grpc++/create_channel.h> -#include <grpc++/security/credentials.h> +#include <grpc++/grpc++.h> + #include "helloworld.grpc.pb.h" using grpc::Channel; @@ -58,39 +53,72 @@ class GreeterClient { explicit GreeterClient(std::shared_ptr<Channel> channel) : stub_(Greeter::NewStub(channel)) {} + // Assambles the client's payload, sends it and presents the response back + // from the server. std::string SayHello(const std::string& user) { + // Data we are sending to the server. HelloRequest request; request.set_name(user); + + // Container for the data we expect from the server. HelloReply reply; + + // Context for the client. It could be used to convey extra information to + // the server and/or tweak certain RPC behaviors. ClientContext context; + + // The producer-consumer queue we use to communicate asynchronously with the + // gRPC runtime. CompletionQueue cq; + + // Storage for the status of the RPC upon completion. Status status; + // stub_->AsyncSayHello() perform the RPC call, returning an instance we + // store in "rpc". Because we are using the asynchronous API, we need the + // hold on to the "rpc" instance in order to get updates on the ongoig RPC. std::unique_ptr<ClientAsyncResponseReader<HelloReply> > rpc( stub_->AsyncSayHello(&context, request, &cq)); + + // Request that, upon completion of the RPC, "reply" be updated with the + // server's response; "status" with the indication of whether the operation + // was successful. Tag the request with the integer 1. rpc->Finish(&reply, &status, (void*)1); void* got_tag; bool ok = false; + // Block until the next result is available in the completion queue "cq". cq.Next(&got_tag, &ok); - GPR_ASSERT(ok); + + // Verify that the result from "cq" corresponds, by its tag, our previous + // request. GPR_ASSERT(got_tag == (void*)1); + // ... and that the request was completed successfully. Note that "ok" + // corresponds solely to the request for updates introduced by Finish(). + GPR_ASSERT(ok); + // Act upon the status of the actual RPC. if (status.ok()) { return reply.message(); } else { - return "Rpc failed"; + return "RPC failed"; } } private: + // Out of the passed in Channel comes the stub, stored here, our view of the + // server's exposed services. std::unique_ptr<Greeter::Stub> stub_; }; int main(int argc, char** argv) { - GreeterClient greeter(grpc::CreateChannel( - "localhost:50051", grpc::InsecureCredentials())); + // Instantiate the client. It requires a channel, out of which the actual RPCs + // are created. This channel models a connection to an endpoint (in this case, + // localhost at port 50051). We indicate that the channel isn't authenticated + // (use of InsecureCredentials()). + GreeterClient greeter( + grpc::CreateChannel("localhost:50051", grpc::InsecureCredentials())); std::string user("world"); - std::string reply = greeter.SayHello(user); + std::string reply = greeter.SayHello(user); // The actual RPC call! std::cout << "Greeter received: " << reply << std::endl; return 0; diff --git a/examples/cpp/helloworld/greeter_async_server.cc b/examples/cpp/helloworld/greeter_async_server.cc index 189c3afe6d..b2047a8ce5 100644 --- a/examples/cpp/helloworld/greeter_async_server.cc +++ b/examples/cpp/helloworld/greeter_async_server.cc @@ -36,13 +36,8 @@ #include <string> #include <thread> -#include <grpc/grpc.h> -#include <grpc/support/log.h> -#include <grpc++/completion_queue.h> -#include <grpc++/security/server_credentials.h> -#include <grpc++/server.h> -#include <grpc++/server_builder.h> -#include <grpc++/server_context.h> +#include <grpc++/grpc++.h> + #include "helloworld.grpc.pb.h" using grpc::Server; @@ -59,6 +54,7 @@ class ServerImpl final { public: ~ServerImpl() { server_->Shutdown(); + // Always shutdown the completion queue after the server. cq_->Shutdown(); } @@ -67,56 +63,102 @@ class ServerImpl final { std::string server_address("0.0.0.0:50051"); ServerBuilder builder; + // Listen on the given address without any authentication mechanism. builder.AddListeningPort(server_address, grpc::InsecureServerCredentials()); + // Register "service_" as the instance through which we'll communicate with + // clients. In this case it corresponds to an *asynchronous* service. builder.RegisterAsyncService(&service_); + // Get hold of the completion queue used for the asynchronous communication + // with the gRPC runtime. cq_ = builder.AddCompletionQueue(); + // Finally assemble the server. server_ = builder.BuildAndStart(); std::cout << "Server listening on " << server_address << std::endl; + // Proceed to the server's main loop. HandleRpcs(); } private: + // Class encompasing the state and logic needed to serve a request. class CallData { public: + // Take in the "service" instance (in this case representing an asynchronous + // server) and the completion queue "cq" used for asynchronous communication + // with the gRPC runtime. CallData(Greeter::AsyncService* service, ServerCompletionQueue* cq) : service_(service), cq_(cq), responder_(&ctx_), status_(CREATE) { + // Invoke the serving logic right away. Proceed(); } void Proceed() { if (status_ == CREATE) { + // As part of the initial CREATE state, we *request* that the system + // start processing SayHello requests. In this request, "this" acts are + // the tag uniquely identifying the request (so that different CallData + // instances can serve different requests concurrently), in this case + // the memory address of this CallData instance. service_->RequestSayHello(&ctx_, &request_, &responder_, cq_, cq_, this); + // Make this instance progress to the PROCESS state. status_ = PROCESS; } else if (status_ == PROCESS) { + // Spawn a new CallData instance to serve new clients while we process + // the one for this CallData. The instance will deallocate itself as + // part of its FINISH state. new CallData(service_, cq_); + + // The actual processing. std::string prefix("Hello "); reply_.set_message(prefix + request_.name()); + + // And we are done! Let the gRPC runtime know we've finished, using the + // memory address of this instance as the uniquely identifying tag for + // the event. responder_.Finish(reply_, Status::OK, this); status_ = FINISH; } else { + GPR_ASSERT(status_ == FINISH); + // Once in the FINISH state, deallocate ourselves (CallData). delete this; } } private: + // The means of communication with the gRPC runtime for an asynchronous + // server. Greeter::AsyncService* service_; + // The producer-consumer queue where for asynchronous server notifications. ServerCompletionQueue* cq_; + // Context for the rpc, allowing to tweak aspects of it such as the use + // of compression, authentication, as well as to send metadata back to the + // client. ServerContext ctx_; + + // What we get from the client. HelloRequest request_; + // What we send back to the client. HelloReply reply_; + + // The means to get back to the client. ServerAsyncResponseWriter<HelloReply> responder_; + + // Let's implement a tiny state machine with the following states. enum CallStatus { CREATE, PROCESS, FINISH }; - CallStatus status_; + CallStatus status_; // The current serving state. }; // This can be run in multiple threads if needed. void HandleRpcs() { + // Spawn a new CallData instance to serve new clients. new CallData(&service_, cq_.get()); - void* tag; + void* tag; // uniquely identifies a request. bool ok; while (true) { + // Block waiting to read the next event from the completion queue. The + // event is uniquely identified by its tag, which in this case is the + // memory address of a CallData instance. cq_->Next(&tag, &ok); GPR_ASSERT(ok); static_cast<CallData*>(tag)->Proceed(); diff --git a/examples/cpp/helloworld/greeter_client.cc b/examples/cpp/helloworld/greeter_client.cc index bfb7c12724..6cd8353a9f 100644 --- a/examples/cpp/helloworld/greeter_client.cc +++ b/examples/cpp/helloworld/greeter_client.cc @@ -35,11 +35,8 @@ #include <memory> #include <string> -#include <grpc/grpc.h> -#include <grpc++/channel.h> -#include <grpc++/client_context.h> -#include <grpc++/create_channel.h> -#include <grpc++/security/credentials.h> +#include <grpc++/grpc++.h> + #include "helloworld.grpc.pb.h" using grpc::Channel; @@ -54,17 +51,28 @@ class GreeterClient { GreeterClient(std::shared_ptr<Channel> channel) : stub_(Greeter::NewStub(channel)) {} + // Assambles the client's payload, sends it and presents the response back + // from the server. std::string SayHello(const std::string& user) { + // Data we are sending to the server. HelloRequest request; request.set_name(user); + + // Container for the data we expect from the server. HelloReply reply; + + // Context for the client. It could be used to convey extra information to + // the server and/or tweak certain RPC behaviors. ClientContext context; + // The actual RPC. Status status = stub_->SayHello(&context, request, &reply); + + // Act upon its status. if (status.ok()) { return reply.message(); } else { - return "Rpc failed"; + return "RPC failed"; } } @@ -73,6 +81,10 @@ class GreeterClient { }; int main(int argc, char** argv) { + // Instantiate the client. It requires a channel, out of which the actual RPCs + // are created. This channel models a connection to an endpoint (in this case, + // localhost at port 50051). We indicate that the channel isn't authenticated + // (use of InsecureCredentials()). GreeterClient greeter( grpc::CreateChannel("localhost:50051", grpc::InsecureCredentials())); std::string user("world"); diff --git a/examples/cpp/helloworld/greeter_server.cc b/examples/cpp/helloworld/greeter_server.cc index b434752d87..9eab32c62b 100644 --- a/examples/cpp/helloworld/greeter_server.cc +++ b/examples/cpp/helloworld/greeter_server.cc @@ -35,11 +35,8 @@ #include <memory> #include <string> -#include <grpc/grpc.h> -#include <grpc++/security/server_credentials.h> -#include <grpc++/server.h> -#include <grpc++/server_builder.h> -#include <grpc++/server_context.h> +#include <grpc++/grpc++.h> + #include "helloworld.grpc.pb.h" using grpc::Server; @@ -50,6 +47,7 @@ using helloworld::HelloRequest; using helloworld::HelloReply; using helloworld::Greeter; +// Logic and data behind the server's behavior. class GreeterServiceImpl final : public Greeter::Service { Status SayHello(ServerContext* context, const HelloRequest* request, HelloReply* reply) override { @@ -64,10 +62,17 @@ void RunServer() { GreeterServiceImpl service; ServerBuilder builder; + // Listen on the given address without any authentication mechanism. builder.AddListeningPort(server_address, grpc::InsecureServerCredentials()); + // Register "service" as the instance through which we'll communicate with + // clients. In this case it corresponds to an *synchronous* service. builder.RegisterService(&service); + // Finally assemble the server. std::unique_ptr<Server> server(builder.BuildAndStart()); std::cout << "Server listening on " << server_address << std::endl; + + // Wait for the server to shutdown. Note that some other thread must be + // responsible for shutting down the server for this call to ever return. server->Wait(); } diff --git a/include/grpc++/channel.h b/include/grpc++/channel.h index a8af74175b..60c816d58a 100644 --- a/include/grpc++/channel.h +++ b/include/grpc++/channel.h @@ -65,18 +65,19 @@ class ClientAsyncReaderWriter; template <class R> class ClientAsyncResponseReader; +/// Channels represent a connection to an endpoint. Created by \a CreateChannel. class Channel GRPC_FINAL : public GrpcLibrary, public CallHook, public std::enable_shared_from_this<Channel> { public: ~Channel(); - // Get the current channel state. If the channel is in IDLE and try_to_connect - // is set to true, try to connect. + /// Get the current channel state. If the channel is in IDLE and + /// \a try_to_connect is set to true, try to connect. grpc_connectivity_state GetState(bool try_to_connect); - // Return the tag on cq when the channel state is changed or deadline expires. - // GetState needs to called to get the current state. + /// Return the \a tag on \a cq when the channel state is changed or \a + /// deadline expires. \a GetState needs to called to get the current state. template <typename T> void NotifyOnStateChange(grpc_connectivity_state last_observed, T deadline, CompletionQueue* cq, void* tag) { @@ -84,8 +85,8 @@ class Channel GRPC_FINAL : public GrpcLibrary, NotifyOnStateChangeImpl(last_observed, deadline_tp.raw_time(), cq, tag); } - // Blocking wait for channel state change or deadline expiration. - // GetState needs to called to get the current state. + /// Blocking wait for channel state change or \a deadline expiration. + /// \a GetState needs to called to get the current state. template <typename T> bool WaitForStateChange(grpc_connectivity_state last_observed, T deadline) { TimePoint<T> deadline_tp(deadline); diff --git a/include/grpc++/client_context.h b/include/grpc++/client_context.h index 917a1222a8..7046f939e5 100644 --- a/include/grpc++/client_context.h +++ b/include/grpc++/client_context.h @@ -31,6 +31,21 @@ * */ +/// A ClientContext allows the person implementing a service client to: +/// +/// - Add custom metadata key-value pairs that will propagated to the server +/// side. +/// - Control call settings such as compression and authentication. +/// - Initial and trailing metadata coming from the server. +/// - Get performance metrics (ie, census). +/// +/// Context settings are only relevant to the call they are invoked with, that +/// is to say, they aren't sticky. Some of these settings, such as the +/// compression options, can be made persistant at channel construction time +/// (see \a grpc::CreateCustomChannel). +/// +/// \warning ClientContext instances should \em not be reused across rpcs. + #ifndef GRPCXX_CLIENT_CONTEXT_H #define GRPCXX_CLIENT_CONTEXT_H @@ -72,6 +87,11 @@ template <class R> class ClientAsyncResponseReader; class ServerContext; +/// Options for \a ClientContext::FromServerContext specifying which traits from +/// the \a ServerContext to propagate (copy) from it into a new \a +/// ClientContext. +/// +/// \see ClientContext::FromServerContext class PropagationOptions { public: PropagationOptions() : propagate_(GRPC_PROPAGATE_DEFAULTS) {} @@ -131,26 +151,66 @@ class ClientContext { ClientContext(); ~ClientContext(); - /// Create a new ClientContext that propagates some or all of its attributes + /// Create a new \a ClientContext as a child of an incoming server call, + /// according to \a options (\see PropagationOptions). + /// + /// \param server_context The source server context to use as the basis for + /// constructing the client context. + /// \param options The options controlling what to copy from the \a + /// server_context. + /// + /// \return A newly constructed \a ClientContext instance based on \a + /// server_context, with traits propagated (copied) according to \a options. static std::unique_ptr<ClientContext> FromServerContext( const ServerContext& server_context, PropagationOptions options = PropagationOptions()); + /// Add the (\a meta_key, \a meta_value) pair to the metadata associated with + /// a client call. These are made available at the server side by the \a + /// grpc::ServerContext::client_metadata() method. + /// + /// \warning This method should only be called before invoking the rpc. + /// + /// \param meta_key The metadata key. If \a meta_value is binary data, it must + /// end in "-bin". + /// \param meta_value The metadata value. If its value is binary, it must be + /// base64-encoding (see https://tools.ietf.org/html/rfc4648#section-4) and \a + /// meta_key must end in "-bin". void AddMetadata(const grpc::string& meta_key, const grpc::string& meta_value); + /// Return a collection of initial metadata key-value pairs. Note that keys + /// may happen more than once (ie, a \a std::multimap is returned). + /// + /// \warning This method should only be called after initial metadata has been + /// received. For streaming calls, see \a + /// ClientReaderInterface::WaitForInitialMetadata(). + /// + /// \return A multimap of initial metadata key-value pairs from the server. const std::multimap<grpc::string_ref, grpc::string_ref>& GetServerInitialMetadata() { GPR_ASSERT(initial_metadata_received_); return recv_initial_metadata_; } + /// Return a collection of trailing metadata key-value pairs. Note that keys + /// may happen more than once (ie, a \a std::multimap is returned). + /// + /// \warning This method is only callable once the stream has finished. + /// + /// \return A multimap of metadata trailing key-value pairs from the server. const std::multimap<grpc::string_ref, grpc::string_ref>& GetServerTrailingMetadata() { // TODO(yangg) check finished return trailing_metadata_; } + /// Set the deadline for the client call. + /// + /// \warning This method should only be called before invoking the rpc. + /// + /// \param deadline the deadline for the client call. Units are determined by + /// the type used. template <typename T> void set_deadline(const T& deadline) { TimePoint<T> deadline_tp(deadline); @@ -158,40 +218,65 @@ class ClientContext { } #ifndef GRPC_CXX0X_NO_CHRONO + /// Return the deadline for the client call. std::chrono::system_clock::time_point deadline() { return Timespec2Timepoint(deadline_); } #endif // !GRPC_CXX0X_NO_CHRONO + /// Return a \a gpr_timespec representation of the client call's deadline. gpr_timespec raw_deadline() { return deadline_; } + /// Set the per call authority header (see + /// https://tools.ietf.org/html/rfc7540#section-8.1.2.3). void set_authority(const grpc::string& authority) { authority_ = authority; } - // Set credentials for the rpc. + /// Return the authentication context for this client call. + /// + /// \see grpc::AuthContext. + std::shared_ptr<const AuthContext> auth_context() const; + + /// Set credentials for the client call. + /// + /// A credentials object encapsulates all the state needed by a client to + /// authenticate with a server and make various assertions, e.g., about the + /// client’s identity, role, or whether it is authorized to make a particular + /// call. + /// + /// \see https://github.com/grpc/grpc/blob/master/doc/grpc-auth-support.md void set_credentials(const std::shared_ptr<Credentials>& creds) { creds_ = creds; } + /// Return the compression algorithm to be used by the client call. grpc_compression_algorithm compression_algorithm() const { return compression_algorithm_; } + /// Set \a algorithm to be the compression algorithm used for the client call. + /// + /// \param algorith The compression algorithm used for the client call. void set_compression_algorithm(grpc_compression_algorithm algorithm); - std::shared_ptr<const AuthContext> auth_context() const; - - // Return the peer uri in a string. - // WARNING: this value is never authenticated or subject to any security - // related code. It must not be used for any authentication related - // functionality. Instead, use auth_context. + /// Return the peer uri in a string. + /// + /// \warning This value is never authenticated or subject to any security + /// related code. It must not be used for any authentication related + /// functionality. Instead, use auth_context. + /// + /// \return The call's peer URI. grpc::string peer() const; - // Get and set census context + /// Get and set census context void set_census_context(struct census_context* ccp) { census_context_ = ccp; } struct census_context* census_context() const { return census_context_; } + /// Send a best-effort out-of-band cancel. The call could be in any stage. + /// e.g. if it is already finished, it may still return success. + /// + /// There is no guarantee the call will be cancelled. void TryCancel(); private: diff --git a/include/grpc++/completion_queue.h b/include/grpc++/completion_queue.h index d81d2e735d..0ea970417e 100644 --- a/include/grpc++/completion_queue.h +++ b/include/grpc++/completion_queue.h @@ -31,6 +31,8 @@ * */ +/// A completion queue implements a concurrent producer-consumer queue, with two +/// main methods, \a Next and \a AsyncNext. #ifndef GRPCXX_COMPLETION_QUEUE_H #define GRPCXX_COMPLETION_QUEUE_H @@ -67,53 +69,79 @@ class UnknownMethodHandler; class Channel; class ClientContext; +class CompletionQueueTag; class CompletionQueue; class RpcMethod; class Server; class ServerBuilder; class ServerContext; -class CompletionQueueTag { - public: - virtual ~CompletionQueueTag() {} - // Called prior to returning from Next(), return value - // is the status of the operation (return status is the default thing - // to do) - // If this function returns false, the tag is dropped and not returned - // from the completion queue - virtual bool FinalizeResult(void** tag, bool* status) = 0; -}; - -// grpc_completion_queue wrapper class +/// A thin wrapper around \a grpc_completion_queue (see / \a +/// src/core/surface/completion_queue.h). class CompletionQueue : public GrpcLibrary { public: + /// Default constructor. Implicitly creates a \a grpc_completion_queue + /// instance. CompletionQueue(); + + /// Wrap \a take, taking ownership of the instance. + /// + /// \param take The completion queue instance to wrap. Ownership is taken. explicit CompletionQueue(grpc_completion_queue* take); - ~CompletionQueue() GRPC_OVERRIDE; - // Tri-state return for AsyncNext: SHUTDOWN, GOT_EVENT, TIMEOUT - enum NextStatus { SHUTDOWN, GOT_EVENT, TIMEOUT }; + /// Destructor. Destroys the owned wrapped completion queue / instance. + ~CompletionQueue() GRPC_OVERRIDE; - // Nonblocking (until deadline) read from queue. - // Cannot rely on result of tag or ok if return is TIMEOUT + /// Tri-state return for AsyncNext: SHUTDOWN, GOT_EVENT, TIMEOUT. + enum NextStatus { + SHUTDOWN, ///< The completion queue has been shutdown. + GOT_EVENT, ///< Got a new event; \a tag will be filled in with its + ///< associated value; \a ok indicating its success. + TIMEOUT ///< deadline was reached. + }; + + /// Read from the queue, blocking up to \a deadline (or the queue's shutdown). + /// Both \a tag and \a ok are updated upon success (if an event is available + /// within the \a deadline). A \a tag points to an arbitrary location usually + /// employed to uniquely identify an event. + /// + /// \param tag[out] Upon sucess, updated to point to the event's tag. + /// \param ok[out] Upon sucess, true if read a regular event, false otherwise. + /// \param deadline[in] How long to block in wait for an event. + /// + /// \return The type of event read. template <typename T> NextStatus AsyncNext(void** tag, bool* ok, const T& deadline) { TimePoint<T> deadline_tp(deadline); return AsyncNextInternal(tag, ok, deadline_tp.raw_time()); } - // Blocking read from queue. - // Returns false if the queue is ready for destruction, true if event - + /// Read from the queue, blocking until an event is available or the queue is + /// shutting down. + /// + /// \param tag[out] Updated to point to the read event's tag. + /// \param ok[out] true if read a regular event, false otherwise. + /// + /// \return true if read a regular event, false if the queue is shutting down. bool Next(void** tag, bool* ok) { return (AsyncNextInternal(tag, ok, gpr_inf_future(GPR_CLOCK_REALTIME)) != SHUTDOWN); } - // Shutdown has to be called, and the CompletionQueue can only be - // destructed when false is returned from Next(). + /// Request the shutdown of the queue. + /// + /// \warning This method must be called at some point. Once invoked, \a Next + /// will start to return false and \a AsyncNext will return \a + /// NextStatus::SHUTDOWN. Only once either one of these methods does that + /// (that is, once the queue has been \em drained) can an instance of this + /// class be destroyed. void Shutdown(); + /// Returns a \em raw pointer to the underlying \a grpc_completion_queue + /// instance. + /// + /// \warning Remember that the returned instance is owned. No transfer of + /// owership is performed. grpc_completion_queue* cq() { return cq_; } private: @@ -150,16 +178,29 @@ class CompletionQueue : public GrpcLibrary { NextStatus AsyncNextInternal(void** tag, bool* ok, gpr_timespec deadline); - // Wraps grpc_completion_queue_pluck. - // Cannot be mixed with calls to Next(). + /// Wraps \a grpc_completion_queue_pluck. + /// \warning Must not be mixed with calls to \a Next. bool Pluck(CompletionQueueTag* tag); - // Does a single polling pluck on tag + /// Performs a single polling pluck on \a tag. void TryPluck(CompletionQueueTag* tag); grpc_completion_queue* cq_; // owned }; +/// An interface allowing implementors to process and filter event tags. +class CompletionQueueTag { + public: + virtual ~CompletionQueueTag() {} + // Called prior to returning from Next(), return value is the status of the + // operation (return status is the default thing to do). If this function + // returns false, the tag is dropped and not returned from the completion + // queue + virtual bool FinalizeResult(void** tag, bool* status) = 0; +}; + +/// A specific type of completion queue used by the processing of notifications +/// by servers. Instantiated by \a ServerBuilder. class ServerCompletionQueue : public CompletionQueue { private: friend class ServerBuilder; diff --git a/include/grpc++/create_channel.h b/include/grpc++/create_channel.h index 72f05174e1..196d2927a9 100644 --- a/include/grpc++/create_channel.h +++ b/include/grpc++/create_channel.h @@ -42,13 +42,24 @@ namespace grpc { -// If creds does not hold an object or is invalid, a lame channel is returned. +/// Create a new \a Channel pointing to \a target +/// +/// \param target The URI of the endpoint to connect to. +/// \param creds Credentials to use for the created channel. If it does not hold +/// an object or is invalid, a lame channel is returned. +/// \param args Options for channel creation. std::shared_ptr<Channel> CreateChannel( const grpc::string& target, const std::shared_ptr<Credentials>& creds); -// For advanced use and testing ONLY. Override default channel arguments only -// if necessary. -// If creds does not hold an object or is invalid, a lame channel is returned. +/// Create a new \em custom \a Channel pointing to \a target +/// +/// \warning For advanced use and testing ONLY. Override default channel +/// arguments only if necessary. +/// +/// \param target The URI of the endpoint to connect to. +/// \param creds Credentials to use for the created channel. If it does not hold +/// an object or is invalid, a lame channel is returned. +/// \param args Options for channel creation. std::shared_ptr<Channel> CreateCustomChannel( const grpc::string& target, const std::shared_ptr<Credentials>& creds, const ChannelArguments& args); diff --git a/include/grpc++/grpc++.h b/include/grpc++/grpc++.h new file mode 100644 index 0000000000..b7d5fb0bbc --- /dev/null +++ b/include/grpc++/grpc++.h @@ -0,0 +1,64 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +/// \mainpage gRPC C++ API +/// +/// The gRPC C++ API mainly consists of the following classes: +/// - grpc::Channel, which represents the connection to an endpoint. See [the +/// gRPC Concepts page](http://www.grpc.io/docs/guides/concepts.html) for more +/// details. Channels are created by the factory function grpc::CreateChannel. +/// - grpc::CompletionQueue, the producer-consumer queue used for all +/// asynchronous communication with the gRPC runtime. +/// - grpc::ClientContext and grpc::ServerContext, where optional configuration +/// for an RPC can be set, such as setting custom metadata to be conveyed to the +/// peer, compression settings, authentication, etc. +/// - grpc::Server, representing a gRPC server, created by grpc::ServerBuilder. +/// +/// Refer to the +/// [examples](https://github.com/grpc/grpc/blob/master/examples/cpp) +/// for code putting these pieces into play. + +#ifndef GRPCXX_GRPCXX_H +#define GRPCXX_GRPCXX_H + +#include <grpc/grpc.h> + +#include <grpc++/channel.h> +#include <grpc++/client_context.h> +#include <grpc++/completion_queue.h> +#include <grpc++/create_channel.h> +#include <grpc++/server.h> +#include <grpc++/server_builder.h> +#include <grpc++/server_context.h> + +#endif // GRPCXX_GRPCXX_H diff --git a/include/grpc++/security/auth_context.h b/include/grpc++/security/auth_context.h index fc2701e806..4b1bbd85bc 100644 --- a/include/grpc++/security/auth_context.h +++ b/include/grpc++/security/auth_context.h @@ -37,6 +37,7 @@ #include <iterator> #include <vector> +#include <grpc/grpc_security.h> #include <grpc++/support/config.h> #include <grpc++/support/string_ref.h> @@ -73,26 +74,41 @@ class AuthPropertyIterator const char* name_; }; +/// Class encapsulating the Authentication Information. +/// +/// It includes the secure identity of the peer, the type of secure transport +/// used as well as any other properties required by the authorization layer. class AuthContext { public: virtual ~AuthContext() {} - // Returns true if the peer is authenticated. + /// Returns true if the peer is authenticated. virtual bool IsPeerAuthenticated() const = 0; - // A peer identity, in general is one or more properties (in which case they - // have the same name). + /// A peer identity. + /// + /// It is, in general, comprised of one or more properties (in which case they + /// have the same name). virtual std::vector<grpc::string_ref> GetPeerIdentity() const = 0; virtual grpc::string GetPeerIdentityPropertyName() const = 0; - // Returns all the property values with the given name. + /// Returns all the property values with the given name. virtual std::vector<grpc::string_ref> FindPropertyValues( const grpc::string& name) const = 0; - // Iteration over all the properties. + /// Iteration over all the properties. virtual AuthPropertyIterator begin() const = 0; virtual AuthPropertyIterator end() const = 0; + static string transport_security_type_property_name() { + return GRPC_TRANSPORT_SECURITY_TYPE_PROPERTY_NAME; + } + static string ssl_transport_security_type() { + return GRPC_SSL_TRANSPORT_SECURITY_TYPE; + } + static string x509_cn_property_name() { return GRPC_X509_CN_PROPERTY_NAME; } + static string x509_san_property_name() { return GRPC_X509_SAN_PROPERTY_NAME; } + // Mutation functions: should only be used by an AuthMetadataProcessor. virtual void AddProperty(const grpc::string& key, const grpc::string_ref& value) = 0; diff --git a/include/grpc++/security/credentials.h b/include/grpc++/security/credentials.h index ce5a9e0606..e423849714 100644 --- a/include/grpc++/security/credentials.h +++ b/include/grpc++/security/credentials.h @@ -44,9 +44,17 @@ class ChannelArguments; class Channel; class SecureCredentials; +/// A credentials object encapsulates all the state needed by a client to +/// authenticate with a server and make various assertions, e.g., about the +/// client’s identity, role, or whether it is authorized to make a particular +/// call. +/// +/// \see https://github.com/grpc/grpc/blob/master/doc/grpc-auth-support.md class Credentials : public GrpcLibrary { public: ~Credentials() GRPC_OVERRIDE; + + /// Apply this instance's credentials to \a call. virtual bool ApplyToCall(grpc_call* call) = 0; protected: @@ -65,68 +73,96 @@ class Credentials : public GrpcLibrary { const grpc::string& target, const ChannelArguments& args) = 0; }; -// Options used to build SslCredentials -// pem_roots_cert is the buffer containing the PEM encoding of the server root -// certificates. If this parameter is empty, the default roots will be used. -// pem_private_key is the buffer containing the PEM encoding of the client's -// private key. This parameter can be empty if the client does not have a -// private key. -// pem_cert_chain is the buffer containing the PEM encoding of the client's -// certificate chain. This parameter can be empty if the client does not have -// a certificate chain. +/// Options used to build SslCredentials. struct SslCredentialsOptions { + /// The buffer containing the PEM encoding of the server root certificates. If + /// this parameter is empty, the default roots will be used. The default + /// roots can be overridden using the \a GRPC_DEFAULT_SSL_ROOTS_FILE_PATH + /// environment variable pointing to a file on the file system containing the + /// roots. grpc::string pem_root_certs; + + /// The buffer containing the PEM encoding of the client's private key. This + /// parameter can be empty if the client does not have a private key. grpc::string pem_private_key; + + /// The buffer containing the PEM encoding of the client's certificate chain. + /// This parameter can be empty if the client does not have a certificate + /// chain. grpc::string pem_cert_chain; }; -// Factories for building different types of Credentials -// The functions may return empty shared_ptr when credentials cannot be created. -// If a Credentials pointer is returned, it can still be invalid when used to -// create a channel. A lame channel will be created then and all rpcs will -// fail on it. - -// Builds credentials with reasonable defaults. +// Factories for building different types of Credentials The functions may +// return empty shared_ptr when credentials cannot be created. If a +// Credentials pointer is returned, it can still be invalid when used to create +// a channel. A lame channel will be created then and all rpcs will fail on it. + +/// Builds credentials with reasonable defaults. +/// +/// \warning Only use these credentials when connecting to a Google endpoint. +/// Using these credentials to connect to any other service may result in this +/// service being able to impersonate your client for requests to Google +/// services. std::shared_ptr<Credentials> GoogleDefaultCredentials(); -// Builds SSL Credentials given SSL specific options +/// Builds SSL Credentials given SSL specific options std::shared_ptr<Credentials> SslCredentials( const SslCredentialsOptions& options); -// Builds credentials for use when running in GCE +/// Builds credentials for use when running in GCE +/// +/// \warning Only use these credentials when connecting to a Google endpoint. +/// Using these credentials to connect to any other service may result in this +/// service being able to impersonate your client for requests to Google +/// services. std::shared_ptr<Credentials> GoogleComputeEngineCredentials(); -// Builds Service Account JWT Access credentials. -// json_key is the JSON key string containing the client's private key. -// token_lifetime_seconds is the lifetime in seconds of each Json Web Token -// (JWT) created with this credentials. It should not exceed -// grpc_max_auth_token_lifetime or will be cropped to this value. +/// Builds Service Account JWT Access credentials. +/// json_key is the JSON key string containing the client's private key. +/// token_lifetime_seconds is the lifetime in seconds of each Json Web Token +/// (JWT) created with this credentials. It should not exceed +/// grpc_max_auth_token_lifetime or will be cropped to this value. std::shared_ptr<Credentials> ServiceAccountJWTAccessCredentials( const grpc::string& json_key, long token_lifetime_seconds); -// Builds refresh token credentials. -// json_refresh_token is the JSON string containing the refresh token along -// with a client_id and client_secret. +/// Builds refresh token credentials. +/// json_refresh_token is the JSON string containing the refresh token along +/// with a client_id and client_secret. +/// +/// \warning Only use these credentials when connecting to a Google endpoint. +/// Using these credentials to connect to any other service may result in this +/// service being able to impersonate your client for requests to Google +/// services. std::shared_ptr<Credentials> GoogleRefreshTokenCredentials( const grpc::string& json_refresh_token); -// Builds access token credentials. -// access_token is an oauth2 access token that was fetched using an out of band -// mechanism. +/// Builds access token credentials. +/// access_token is an oauth2 access token that was fetched using an out of band +/// mechanism. +/// +/// \warning Only use these credentials when connecting to a Google endpoint. +/// Using these credentials to connect to any other service may result in this +/// service being able to impersonate your client for requests to Google +/// services. std::shared_ptr<Credentials> AccessTokenCredentials( const grpc::string& access_token); -// Builds IAM credentials. +/// Builds IAM credentials. +/// +/// \warning Only use these credentials when connecting to a Google endpoint. +/// Using these credentials to connect to any other service may result in this +/// service being able to impersonate your client for requests to Google +/// services. std::shared_ptr<Credentials> GoogleIAMCredentials( const grpc::string& authorization_token, const grpc::string& authority_selector); -// Combines two credentials objects into a composite credentials +/// Combines two credentials objects into a composite credentials std::shared_ptr<Credentials> CompositeCredentials( const std::shared_ptr<Credentials>& creds1, const std::shared_ptr<Credentials>& creds2); -// Credentials for an unencrypted, unauthenticated channel +/// Credentials for an unencrypted, unauthenticated channel std::shared_ptr<Credentials> InsecureCredentials(); } // namespace grpc diff --git a/include/grpc++/security/server_credentials.h b/include/grpc++/security/server_credentials.h index 2094c7403c..e933825ec3 100644 --- a/include/grpc++/security/server_credentials.h +++ b/include/grpc++/security/server_credentials.h @@ -45,7 +45,7 @@ struct grpc_server; namespace grpc { class Server; -// grpc_server_credentials wrapper class. +// Wrapper around \a grpc_server_credentials, a way to authenticate a server. class ServerCredentials { public: virtual ~ServerCredentials(); @@ -58,11 +58,16 @@ class ServerCredentials { private: friend class ::grpc::Server; + /// Tries to bind \a server to the given \a addr (eg, localhost:1234, + /// 192.168.1.1:31416, [::1]:27182, etc.) + /// + /// \return bound port number on sucess, 0 on failure. + // TODO(dgq): the "port" part seems to be a misnomer. virtual int AddPortToServer(const grpc::string& addr, grpc_server* server) = 0; }; -// Options to create ServerCredentials with SSL +/// Options to create ServerCredentials with SSL struct SslServerCredentialsOptions { SslServerCredentialsOptions() : force_client_auth(false) {} @@ -75,10 +80,11 @@ struct SslServerCredentialsOptions { bool force_client_auth; }; -// Builds SSL ServerCredentials given SSL specific options +/// Builds SSL ServerCredentials given SSL specific options std::shared_ptr<ServerCredentials> SslServerCredentials( const SslServerCredentialsOptions& options); +/// Builds insecure server credentials. std::shared_ptr<ServerCredentials> InsecureServerCredentials(); } // namespace grpc diff --git a/include/grpc++/server.h b/include/grpc++/server.h index 22d14ee652..18a8017880 100644 --- a/include/grpc++/server.h +++ b/include/grpc++/server.h @@ -57,24 +57,30 @@ class RpcServiceMethod; class ServerAsyncStreamingInterface; class ThreadPoolInterface; -// Currently it only supports handling rpcs in a single thread. +/// Models a gRPC server. +/// +/// Servers are configured and started via \a grpc::ServerBuilder. class Server GRPC_FINAL : public GrpcLibrary, private CallHook { public: ~Server(); - // Shutdown the server, block until all rpc processing finishes. - // Forcefully terminate pending calls after deadline expires. + /// Shutdown the server, blocking until all rpc processing finishes. + /// Forcefully terminate pending calls after \a deadline expires. + /// + /// \param deadline How long to wait until pending rpcs are forcefully + /// terminated. template <class T> void Shutdown(const T& deadline) { ShutdownInternal(TimePoint<T>(deadline).raw_time()); } - // Shutdown the server, waiting for all rpc processing to finish. + /// Shutdown the server, waiting for all rpc processing to finish. void Shutdown() { ShutdownInternal(gpr_inf_future(GPR_CLOCK_MONOTONIC)); } - // Block waiting for all work to complete (the server must either - // be shutting down or some other thread must call Shutdown for this - // function to ever return) + /// Block waiting for all work to complete. + /// + /// \warning The server must be either shutting down or some other thread must + /// call \a Shutdown for this function to ever return. void Wait(); private: @@ -86,22 +92,57 @@ class Server GRPC_FINAL : public GrpcLibrary, private CallHook { class AsyncRequest; class ShutdownRequest; - // ServerBuilder use only + /// Server constructors. To be used by \a ServerBuilder only. + /// + /// \param thread_pool The threadpool instance to use for call processing. + /// \param thread_pool_owned Does the server own the \a thread_pool instance? + /// \param max_message_size Maximum message length that the channel can + /// receive. Server(ThreadPoolInterface* thread_pool, bool thread_pool_owned, int max_message_size); - // Register a service. This call does not take ownership of the service. - // The service must exist for the lifetime of the Server instance. + + /// Register a service. This call does not take ownership of the service. + /// The service must exist for the lifetime of the Server instance. bool RegisterService(const grpc::string* host, RpcService* service); + + /// Register an asynchronous service. This call does not take ownership of the + /// service. The service must exist for the lifetime of the Server instance. bool RegisterAsyncService(const grpc::string* host, AsynchronousService* service); + + /// Register a generic service. This call does not take ownership of the + /// service. The service must exist for the lifetime of the Server instance. void RegisterAsyncGenericService(AsyncGenericService* service); - // Add a listening port. Can be called multiple times. + + /// Tries to bind \a server to the given \a addr. + /// + /// It can be invoked multiple times. + /// + /// \param addr The address to try to bind to the server (eg, localhost:1234, + /// 192.168.1.1:31416, [::1]:27182, etc.). + /// \params creds The credentials associated with the server. + /// + /// \return bound port number on sucess, 0 on failure. + /// + /// \warning It's an error to call this method on an already started server. int AddListeningPort(const grpc::string& addr, ServerCredentials* creds); - // Start the server. + + /// Start the server. + /// + /// \param cqs Completion queues for handling asynchronous services. The + /// caller is required to keep all completion queues live until the server is + /// destroyed. + /// \param num_cqs How many completion queues does \a cqs hold. + /// + /// \return true on a successful shutdown. bool Start(ServerCompletionQueue** cqs, size_t num_cqs); void HandleQueueClosed(); + + /// Process one or more incoming calls. void RunRpc(); + + /// Schedule \a RunRpc to run in the threadpool. void ScheduleCallback(); void PerformOpsOnCall(CallOpSetInterface* ops, Call* call) GRPC_OVERRIDE; diff --git a/include/grpc++/server_builder.h b/include/grpc++/server_builder.h index 8cd2048592..496e7862c5 100644 --- a/include/grpc++/server_builder.h +++ b/include/grpc++/server_builder.h @@ -51,57 +51,68 @@ class ServerCredentials; class SynchronousService; class ThreadPoolInterface; +/// A builder class for the creation and startup of \a grpc::Server instances. class ServerBuilder { public: ServerBuilder(); - // Register a service. This call does not take ownership of the service. - // The service must exist for the lifetime of the Server instance returned by - // BuildAndStart(). - // Matches requests with any :authority + /// Register a service. This call does not take ownership of the service. + /// The service must exist for the lifetime of the \a Server instance returned + /// by \a BuildAndStart(). + /// Matches requests with any :authority void RegisterService(SynchronousService* service); - // Register an asynchronous service. - // This call does not take ownership of the service or completion queue. - // The service and completion queuemust exist for the lifetime of the Server - // instance returned by BuildAndStart(). - // Matches requests with any :authority + /// Register an asynchronous service. + /// This call does not take ownership of the service or completion queue. + /// The service and completion queuemust exist for the lifetime of the \a + /// Server instance returned by \a BuildAndStart(). + /// Matches requests with any :authority void RegisterAsyncService(AsynchronousService* service); - // Register a generic service. - // Matches requests with any :authority + /// Register a generic service. + /// Matches requests with any :authority void RegisterAsyncGenericService(AsyncGenericService* service); - // Register a service. This call does not take ownership of the service. - // The service must exist for the lifetime of the Server instance returned by - // BuildAndStart(). - // Only matches requests with :authority \a host + /// Register a service. This call does not take ownership of the service. + /// The service must exist for the lifetime of the \a Server instance returned + /// by BuildAndStart(). + /// Only matches requests with :authority \a host void RegisterService(const grpc::string& host, SynchronousService* service); - // Register an asynchronous service. - // This call does not take ownership of the service or completion queue. - // The service and completion queuemust exist for the lifetime of the Server - // instance returned by BuildAndStart(). - // Only matches requests with :authority \a host + /// Register an asynchronous service. + /// This call does not take ownership of the service or completion queue. + /// The service and completion queuemust exist for the lifetime of the \a + /// Server instance returned by \a BuildAndStart(). + /// Only matches requests with :authority equal to \a host void RegisterAsyncService(const grpc::string& host, AsynchronousService* service); - // Set max message size in bytes. + /// Set max message size in bytes. void SetMaxMessageSize(int max_message_size) { max_message_size_ = max_message_size; } - // Add a listening port. Can be called multiple times. + /// Tries to bind \a server to the given \a addr. + /// + /// It can be invoked multiple times. + /// + /// \param addr The address to try to bind to the server (eg, localhost:1234, + /// 192.168.1.1:31416, [::1]:27182, etc.). + /// \params creds The credentials associated with the server. + /// \param selected_port[out] Upon success, updated to contain the port + /// number. \a nullptr otherwise. + /// + // TODO(dgq): the "port" part seems to be a misnomer. void AddListeningPort(const grpc::string& addr, std::shared_ptr<ServerCredentials> creds, int* selected_port = nullptr); - // Add a completion queue for handling asynchronous services - // Caller is required to keep this completion queue live until - // the server is destroyed. + /// Add a completion queue for handling asynchronous services + /// Caller is required to keep this completion queue live until + /// the server is destroyed. std::unique_ptr<ServerCompletionQueue> AddCompletionQueue(); - // Return a running server which is ready for processing rpcs. + /// Return a running server which is ready for processing calls. std::unique_ptr<Server> BuildAndStart(); private: diff --git a/include/grpc++/support/async_stream.h b/include/grpc++/support/async_stream.h index 4c12fda12f..b4dae30cd5 100644 --- a/include/grpc++/support/async_stream.h +++ b/include/grpc++/support/async_stream.h @@ -45,32 +45,48 @@ namespace grpc { -// Async interfaces -// Common interface for all client side streaming. +/// Common interface for all client side asynchronous streaming. class ClientAsyncStreamingInterface { public: virtual ~ClientAsyncStreamingInterface() {} + /// Request notification of the reading of the initial metadata. Completion + /// will be notified by \a tag on the associated completion queue. + /// + /// \param[in] tag Tag identifying this request. virtual void ReadInitialMetadata(void* tag) = 0; + /// Request notification completion. + /// + /// \param[out] status To be updated with the operation status. + /// \param[in] tag Tag identifying this request. virtual void Finish(Status* status, void* tag) = 0; }; -// An interface that yields a sequence of R messages. +/// An interface that yields a sequence of messages of type \a R. template <class R> class AsyncReaderInterface { public: virtual ~AsyncReaderInterface() {} + /// Read a message of type \a R into \a msg. Completion will be notified by \a + /// tag on the associated completion queue. + /// + /// \param[out] msg Where to eventually store the read message. + /// \param[in] tag The tag identifying the operation. virtual void Read(R* msg, void* tag) = 0; }; -// An interface that can be fed a sequence of W messages. +/// An interface that can be fed a sequence of messages of type \a W. template <class W> class AsyncWriterInterface { public: virtual ~AsyncWriterInterface() {} + /// Request the writing of \a msg with identifying tag \a tag. + /// + /// \param[in] msg The message to be written. + /// \param[in] tag The tag identifying the operation. virtual void Write(const W& msg, void* tag) = 0; }; @@ -81,7 +97,7 @@ class ClientAsyncReaderInterface : public ClientAsyncStreamingInterface, template <class R> class ClientAsyncReader GRPC_FINAL : public ClientAsyncReaderInterface<R> { public: - // Create a stream and write the first request out. + /// Create a stream and write the first request out. template <class W> ClientAsyncReader(Channel* channel, CompletionQueue* cq, const RpcMethod& method, ClientContext* context, @@ -131,10 +147,14 @@ class ClientAsyncReader GRPC_FINAL : public ClientAsyncReaderInterface<R> { CallOpSet<CallOpRecvInitialMetadata, CallOpClientRecvStatus> finish_ops_; }; +/// Common interface for client side asynchronous writing. template <class W> class ClientAsyncWriterInterface : public ClientAsyncStreamingInterface, public AsyncWriterInterface<W> { public: + /// Signal the client is done with the writes. + /// + /// \param[in] tag The tag identifying the operation. virtual void WritesDone(void* tag) = 0; }; @@ -194,12 +214,15 @@ class ClientAsyncWriter GRPC_FINAL : public ClientAsyncWriterInterface<W> { CallOpClientRecvStatus> finish_ops_; }; -// Client-side interface for bi-directional streaming. +/// Client-side interface for asynchronous bi-directional streaming. template <class W, class R> class ClientAsyncReaderWriterInterface : public ClientAsyncStreamingInterface, public AsyncWriterInterface<W>, public AsyncReaderInterface<R> { public: + /// Signal the client is done with the writes. + /// + /// \param[in] tag The tag identifying the operation. virtual void WritesDone(void* tag) = 0; }; @@ -373,7 +396,7 @@ class ServerAsyncWriter GRPC_FINAL : public ServerAsyncStreamingInterface, CallOpSet<CallOpSendInitialMetadata, CallOpServerSendStatus> finish_ops_; }; -// Server-side interface for bi-directional streaming. +/// Server-side interface for asynchronous bi-directional streaming. template <class W, class R> class ServerAsyncReaderWriter GRPC_FINAL : public ServerAsyncStreamingInterface, public AsyncWriterInterface<W>, diff --git a/include/grpc++/support/byte_buffer.h b/include/grpc++/support/byte_buffer.h index 3f8cc25f47..c413703970 100644 --- a/include/grpc++/support/byte_buffer.h +++ b/include/grpc++/support/byte_buffer.h @@ -46,21 +46,24 @@ namespace grpc { +/// A sequence of bytes. class ByteBuffer GRPC_FINAL { public: + /// Constuct an empty buffer. ByteBuffer() : buffer_(nullptr) {} + /// Construct buffer from \a slices, of which there are \a nslices. ByteBuffer(const Slice* slices, size_t nslices); - ~ByteBuffer() { - if (buffer_) { - grpc_byte_buffer_destroy(buffer_); - } - } + ~ByteBuffer(); + /// Dump (read) the buffer contents into \a slices. void Dump(std::vector<Slice>* slices) const; + /// Remove all data. void Clear(); + + /// Buffer size in bytes. size_t Length() const; private: @@ -78,6 +81,7 @@ class ByteBuffer GRPC_FINAL { buffer_ = buf; } + // For \a SerializationTraits's usage. grpc_byte_buffer* buffer() const { return buffer_; } grpc_byte_buffer* buffer_; diff --git a/include/grpc++/support/channel_arguments.h b/include/grpc++/support/channel_arguments.h index cee68467c7..9957712a96 100644 --- a/include/grpc++/support/channel_arguments.h +++ b/include/grpc++/support/channel_arguments.h @@ -46,9 +46,9 @@ namespace testing { class ChannelArgumentsTest; } // namespace testing -// Options for channel creation. The user can use generic setters to pass -// key value pairs down to c channel creation code. For grpc related options, -// concrete setters are provided. +/// Options for channel creation. The user can use generic setters to pass +/// key value pairs down to c channel creation code. For grpc related options, +/// concrete setters are provided. class ChannelArguments { public: ChannelArguments() {} @@ -62,21 +62,26 @@ class ChannelArguments { void Swap(ChannelArguments& other); - // grpc specific channel argument setters - // Set target name override for SSL host name checking. + /// Populates this instance with the arguments from \a channel_args. Does not + /// take ownership of \a channel_args. + /// + /// Note that the underlying arguments are shared. Changes made to either \a + /// channel_args or this instance would be reflected on both. + void SetChannelArgs(grpc_channel_args* channel_args) const; + + // gRPC specific channel argument setters + /// Set target name override for SSL host name checking. void SetSslTargetNameOverride(const grpc::string& name); // TODO(yangg) add flow control options - - // Set the compression algorithm for the channel. + /// Set the compression algorithm for the channel. void SetCompressionAlgorithm(grpc_compression_algorithm algorithm); // Generic channel argument setters. Only for advanced use cases. + /// Set an integer argument \a value under \a key. void SetInt(const grpc::string& key, int value); + /// Set a textual argument \a value under \a key. void SetString(const grpc::string& key, const grpc::string& value); - // Populates given channel_args with args_, does not take ownership. - void SetChannelArgs(grpc_channel_args* channel_args) const; - private: friend class SecureCredentials; friend class testing::ChannelArgumentsTest; diff --git a/include/grpc++/support/slice.h b/include/grpc++/support/slice.h index b2343a7f3d..456379cc5b 100644 --- a/include/grpc++/support/slice.h +++ b/include/grpc++/support/slice.h @@ -39,28 +39,42 @@ namespace grpc { +/// A wrapper around \a grpc_slice. +/// +/// A slice represents a contiguous reference counted array of bytes. +/// It is cheap to take references to a slice, and it is cheap to create a +/// slice pointing to a subset of another slice. class Slice GRPC_FINAL { public: - // construct empty slice + /// Construct an empty slice. Slice(); - // destructor - drops one ref + // Destructor - drops one reference. ~Slice(); - // construct slice from grpc slice, adding a ref + enum AddRef { ADD_REF }; + /// Construct a slice from \a slice, adding a reference. Slice(gpr_slice slice, AddRef); - // construct slice from grpc slice, stealing a ref + enum StealRef { STEAL_REF }; + /// Construct a slice from \a slice, stealing a reference. Slice(gpr_slice slice, StealRef); - // copy constructor - adds a ref + + /// Copy constructor, adds a reference. Slice(const Slice& other); - // assignment - ref count is unchanged + + /// Assignment, reference count is unchanged. Slice& operator=(Slice other) { std::swap(slice_, other.slice_); return *this; } + /// Byte size. size_t size() const { return GPR_SLICE_LENGTH(slice_); } + + /// Raw pointer to the beginning (first element) of the slice. const gpr_uint8* begin() const { return GPR_SLICE_START_PTR(slice_); } + + /// Raw pointer to the end (one byte \em past the last element) of the slice. const gpr_uint8* end() const { return GPR_SLICE_END_PTR(slice_); } private: diff --git a/include/grpc++/support/status.h b/include/grpc++/support/status.h index 05750ff600..e59bac92d1 100644 --- a/include/grpc++/support/status.h +++ b/include/grpc++/support/status.h @@ -39,19 +39,31 @@ namespace grpc { +/// Did it work? If it didn't, why? +/// +/// See \a grpc::StatusCode for details on the available code and their meaning. class Status { public: + /// Construct an OK instance. Status() : code_(StatusCode::OK) {} + + /// Construct an instance with associated \a code and \a details (also + // referred to as "error_message"). Status(StatusCode code, const grpc::string& details) : code_(code), details_(details) {} // Pre-defined special status objects. + /// An OK pre-defined instance. static const Status& OK; + /// A CANCELLED pre-defined instance. static const Status& CANCELLED; + /// Return the instance's error code. StatusCode error_code() const { return code_; } + /// Return the instance's error message. grpc::string error_message() const { return details_; } + /// Is the status OK? bool ok() const { return code_ == StatusCode::OK; } private: diff --git a/include/grpc++/support/status_code_enum.h b/include/grpc++/support/status_code_enum.h index 7cb40452c8..ee05b40b51 100644 --- a/include/grpc++/support/status_code_enum.h +++ b/include/grpc++/support/status_code_enum.h @@ -37,120 +37,113 @@ namespace grpc { enum StatusCode { - /* Not an error; returned on success */ + /// Not an error; returned on success. OK = 0, - /* The operation was cancelled (typically by the caller). */ + /// The operation was cancelled (typically by the caller). CANCELLED = 1, - /* Unknown error. An example of where this error may be returned is - if a Status value received from another address space belongs to - an error-space that is not known in this address space. Also - errors raised by APIs that do not return enough error information - may be converted to this error. */ + /// Unknown error. An example of where this error may be returned is if a + /// Status value received from another address space belongs to an error-space + /// that is not known in this address space. Also errors raised by APIs that + /// do not return enough error information may be converted to this error. UNKNOWN = 2, - /* Client specified an invalid argument. Note that this differs - from FAILED_PRECONDITION. INVALID_ARGUMENT indicates arguments - that are problematic regardless of the state of the system - (e.g., a malformed file name). */ + /// Client specified an invalid argument. Note that this differs from + /// FAILED_PRECONDITION. INVALID_ARGUMENT indicates arguments that are + /// problematic regardless of the state of the system (e.g., a malformed file + /// name). INVALID_ARGUMENT = 3, - /* Deadline expired before operation could complete. For operations - that change the state of the system, this error may be returned - even if the operation has completed successfully. For example, a - successful response from a server could have been delayed long - enough for the deadline to expire. */ + /// Deadline expired before operation could complete. For operations that + /// change the state of the system, this error may be returned even if the + /// operation has completed successfully. For example, a successful response + /// from a server could have been delayed long enough for the deadline to + /// expire. DEADLINE_EXCEEDED = 4, - /* Some requested entity (e.g., file or directory) was not found. */ + /// Some requested entity (e.g., file or directory) was not found. NOT_FOUND = 5, - /* Some entity that we attempted to create (e.g., file or directory) - already exists. */ + /// Some entity that we attempted to create (e.g., file or directory) already + /// exists. ALREADY_EXISTS = 6, - /* The caller does not have permission to execute the specified - operation. PERMISSION_DENIED must not be used for rejections - caused by exhausting some resource (use RESOURCE_EXHAUSTED - instead for those errors). PERMISSION_DENIED must not be - used if the caller can not be identified (use UNAUTHENTICATED - instead for those errors). */ + /// The caller does not have permission to execute the specified operation. + /// PERMISSION_DENIED must not be used for rejections caused by exhausting + /// some resource (use RESOURCE_EXHAUSTED instead for those errors). + /// PERMISSION_DENIED must not be used if the caller can not be identified + /// (use UNAUTHENTICATED instead for those errors). PERMISSION_DENIED = 7, - /* The request does not have valid authentication credentials for the - operation. */ + /// The request does not have valid authentication credentials for the + /// operation. UNAUTHENTICATED = 16, - /* Some resource has been exhausted, perhaps a per-user quota, or - perhaps the entire file system is out of space. */ + /// Some resource has been exhausted, perhaps a per-user quota, or perhaps the + /// entire file system is out of space. RESOURCE_EXHAUSTED = 8, - /* Operation was rejected because the system is not in a state - required for the operation's execution. For example, directory - to be deleted may be non-empty, an rmdir operation is applied to - a non-directory, etc. - - A litmus test that may help a service implementor in deciding - between FAILED_PRECONDITION, ABORTED, and UNAVAILABLE: - (a) Use UNAVAILABLE if the client can retry just the failing call. - (b) Use ABORTED if the client should retry at a higher-level - (e.g., restarting a read-modify-write sequence). - (c) Use FAILED_PRECONDITION if the client should not retry until - the system state has been explicitly fixed. E.g., if an "rmdir" - fails because the directory is non-empty, FAILED_PRECONDITION - should be returned since the client should not retry unless - they have first fixed up the directory by deleting files from it. - (d) Use FAILED_PRECONDITION if the client performs conditional - REST Get/Update/Delete on a resource and the resource on the - server does not match the condition. E.g., conflicting - read-modify-write on the same resource. */ + /// Operation was rejected because the system is not in a state required for + /// the operation's execution. For example, directory to be deleted may be + /// non-empty, an rmdir operation is applied to a non-directory, etc. + /// + /// A litmus test that may help a service implementor in deciding + /// between FAILED_PRECONDITION, ABORTED, and UNAVAILABLE: + /// (a) Use UNAVAILABLE if the client can retry just the failing call. + /// (b) Use ABORTED if the client should retry at a higher-level + /// (e.g., restarting a read-modify-write sequence). + /// (c) Use FAILED_PRECONDITION if the client should not retry until + /// the system state has been explicitly fixed. E.g., if an "rmdir" + /// fails because the directory is non-empty, FAILED_PRECONDITION + /// should be returned since the client should not retry unless + /// they have first fixed up the directory by deleting files from it. + /// (d) Use FAILED_PRECONDITION if the client performs conditional + /// REST Get/Update/Delete on a resource and the resource on the + /// server does not match the condition. E.g., conflicting + /// read-modify-write on the same resource. FAILED_PRECONDITION = 9, - /* The operation was aborted, typically due to a concurrency issue - like sequencer check failures, transaction aborts, etc. - - See litmus test above for deciding between FAILED_PRECONDITION, - ABORTED, and UNAVAILABLE. */ + /// The operation was aborted, typically due to a concurrency issue like + /// sequencer check failures, transaction aborts, etc. + /// + /// See litmus test above for deciding between FAILED_PRECONDITION, ABORTED, + /// and UNAVAILABLE. ABORTED = 10, - /* Operation was attempted past the valid range. E.g., seeking or - reading past end of file. - - Unlike INVALID_ARGUMENT, this error indicates a problem that may - be fixed if the system state changes. For example, a 32-bit file - system will generate INVALID_ARGUMENT if asked to read at an - offset that is not in the range [0,2^32-1], but it will generate - OUT_OF_RANGE if asked to read from an offset past the current - file size. - - There is a fair bit of overlap between FAILED_PRECONDITION and - OUT_OF_RANGE. We recommend using OUT_OF_RANGE (the more specific - error) when it applies so that callers who are iterating through - a space can easily look for an OUT_OF_RANGE error to detect when - they are done. */ + /// Operation was attempted past the valid range. E.g., seeking or reading + /// past end of file. + /// + /// Unlike INVALID_ARGUMENT, this error indicates a problem that may be fixed + /// if the system state changes. For example, a 32-bit file system will + /// generate INVALID_ARGUMENT if asked to read at an offset that is not in the + /// range [0,2^32-1], but it will generate OUT_OF_RANGE if asked to read from + /// an offset past the current file size. + /// + /// There is a fair bit of overlap between FAILED_PRECONDITION and + /// OUT_OF_RANGE. We recommend using OUT_OF_RANGE (the more specific error) + /// when it applies so that callers who are iterating through a space can + /// easily look for an OUT_OF_RANGE error to detect when they are done. OUT_OF_RANGE = 11, - /* Operation is not implemented or not supported/enabled in this service. */ + /// Operation is not implemented or not supported/enabled in this service. UNIMPLEMENTED = 12, - /* Internal errors. Means some invariants expected by underlying - system has been broken. If you see one of these errors, - something is very broken. */ + /// Internal errors. Means some invariants expected by underlying System has + /// been broken. If you see one of these errors, Something is very broken. INTERNAL = 13, - /* The service is currently unavailable. This is a most likely a - transient condition and may be corrected by retrying with - a backoff. - - See litmus test above for deciding between FAILED_PRECONDITION, - ABORTED, and UNAVAILABLE. */ + /// The service is currently unavailable. This is a most likely a transient + /// condition and may be corrected by retrying with a backoff. + /// + /// See litmus test above for deciding between FAILED_PRECONDITION, ABORTED, + /// and UNAVAILABLE. UNAVAILABLE = 14, - /* Unrecoverable data loss or corruption. */ + /// Unrecoverable data loss or corruption. DATA_LOSS = 15, - /* Force users to include a default branch: */ + /// Force users to include a default branch: DO_NOT_USE = -1 }; diff --git a/include/grpc++/support/string_ref.h b/include/grpc++/support/string_ref.h index 2bc1fecefe..a17e167d2b 100644 --- a/include/grpc++/support/string_ref.h +++ b/include/grpc++/support/string_ref.h @@ -41,11 +41,14 @@ namespace grpc { -// This class is a non owning reference to a string. -// It should be a strict subset of the upcoming std::string_ref. See: -// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3442.html -// The constexpr is dropped or replaced with const for legacy compiler -// compatibility. +/// This class is a non owning reference to a string. +/// +/// It should be a strict subset of the upcoming std::string_ref. +/// +/// \see http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3442.html +/// +/// The constexpr is dropped or replaced with const for legacy compiler +/// compatibility. class string_ref { public: // types diff --git a/include/grpc++/support/sync_stream.h b/include/grpc++/support/sync_stream.h index b4bb637ff2..514363338d 100644 --- a/include/grpc++/support/sync_stream.h +++ b/include/grpc++/support/sync_stream.h @@ -45,60 +45,78 @@ namespace grpc { -// Common interface for all client side streaming. +/// Common interface for all synchronous client side streaming. class ClientStreamingInterface { public: virtual ~ClientStreamingInterface() {} - // Wait until the stream finishes, and return the final status. When the - // client side declares it has no more message to send, either implicitly or - // by calling WritesDone, it needs to make sure there is no more message to - // be received from the server, either implicitly or by getting a false from - // a Read(). - // This function will return either: - // - when all incoming messages have been read and the server has returned - // status - // - OR when the server has returned a non-OK status + /// Wait until the stream finishes, and return the final status. When the + /// client side declares it has no more message to send, either implicitly or + /// by calling \a WritesDone(), it needs to make sure there is no more message + /// to be received from the server, either implicitly or by getting a false + /// from a \a Read(). + /// + /// This function will return either: + /// - when all incoming messages have been read and the server has returned + /// status. + /// - OR when the server has returned a non-OK status. virtual Status Finish() = 0; }; -// An interface that yields a sequence of R messages. +/// An interface that yields a sequence of messages of type \a R. template <class R> class ReaderInterface { public: virtual ~ReaderInterface() {} - // Blocking read a message and parse to msg. Returns true on success. - // The method returns false when there will be no more incoming messages, - // either because the other side has called WritesDone or the stream has - // failed (or been cancelled). + /// Blocking read a message and parse to \a msg. Returns \a true on success. + /// + /// \param[out] msg The read message. + /// + /// \return \a false when there will be no more incoming messages, either + /// because the other side has called \a WritesDone() or the stream has failed + /// (or been cancelled). virtual bool Read(R* msg) = 0; }; -// An interface that can be fed a sequence of W messages. +/// An interface that can be fed a sequence of messages of type \a W. template <class W> class WriterInterface { public: virtual ~WriterInterface() {} - // Blocking write msg to the stream. Returns true on success. - // Returns false when the stream has been closed. + /// Blocking write \a msg to the stream with options. + /// + /// \param msg The message to be written to the stream. + /// \param options Options affecting the write operation. + /// + /// \return \a true on success, \a false when the stream has been closed. virtual bool Write(const W& msg, const WriteOptions& options) = 0; + /// Blocking write \a msg to the stream with default options. + /// + /// \param msg The message to be written to the stream. + /// + /// \return \a true on success, \a false when the stream has been closed. inline bool Write(const W& msg) { return Write(msg, WriteOptions()); } }; +/// Client-side interface for streaming reads of message of type \a R. template <class R> class ClientReaderInterface : public ClientStreamingInterface, public ReaderInterface<R> { public: + /// Blocking wait for initial metadata from server. The received metadata + /// can only be accessed after this call returns. Should only be called before + /// the first read. Calling this method is optional, and if it is not called + /// the metadata will be available in ClientContext after the first read. virtual void WaitForInitialMetadata() = 0; }; template <class R> class ClientReader GRPC_FINAL : public ClientReaderInterface<R> { public: - // Blocking create a stream and write the first request out. + /// Blocking create a stream and write the first request out. template <class W> ClientReader(Channel* channel, const RpcMethod& method, ClientContext* context, const W& request) @@ -113,17 +131,13 @@ class ClientReader GRPC_FINAL : public ClientReaderInterface<R> { cq_.Pluck(&ops); } - // Blocking wait for initial metadata from server. The received metadata - // can only be accessed after this call returns. Should only be called before - // the first read. Calling this method is optional, and if it is not called - // the metadata will be available in ClientContext after the first read. void WaitForInitialMetadata() { GPR_ASSERT(!context_->initial_metadata_received_); CallOpSet<CallOpRecvInitialMetadata> ops; ops.RecvInitialMetadata(context_); call_.PerformOps(&ops); - cq_.Pluck(&ops); // status ignored + cq_.Pluck(&ops); /// status ignored } bool Read(R* msg) GRPC_OVERRIDE { @@ -151,17 +165,22 @@ class ClientReader GRPC_FINAL : public ClientReaderInterface<R> { Call call_; }; +/// Client-side interface for streaming writes of message of type \a W. template <class W> class ClientWriterInterface : public ClientStreamingInterface, public WriterInterface<W> { public: + /// Half close writing from the client. + /// Block until writes are completed. + /// + /// \return Whether the writes were successful. virtual bool WritesDone() = 0; }; template <class W> class ClientWriter : public ClientWriterInterface<W> { public: - // Blocking create a stream. + /// Blocking create a stream. template <class R> ClientWriter(Channel* channel, const RpcMethod& method, ClientContext* context, R* response) @@ -191,7 +210,7 @@ class ClientWriter : public ClientWriterInterface<W> { return cq_.Pluck(&ops); } - // Read the final response and wait for the final status. + /// Read the final response and wait for the final status. Status Finish() GRPC_OVERRIDE { Status status; finish_ops_.ClientRecvStatus(context_, &status); @@ -207,20 +226,28 @@ class ClientWriter : public ClientWriterInterface<W> { Call call_; }; -// Client-side interface for bi-directional streaming. +/// Client-side interface for bi-directional streaming. template <class W, class R> class ClientReaderWriterInterface : public ClientStreamingInterface, public WriterInterface<W>, public ReaderInterface<R> { public: + /// Blocking wait for initial metadata from server. The received metadata + /// can only be accessed after this call returns. Should only be called before + /// the first read. Calling this method is optional, and if it is not called + /// the metadata will be available in ClientContext after the first read. virtual void WaitForInitialMetadata() = 0; + + /// Block until writes are completed. + /// + /// \return Whether the writes were successful. virtual bool WritesDone() = 0; }; template <class W, class R> class ClientReaderWriter GRPC_FINAL : public ClientReaderWriterInterface<W, R> { public: - // Blocking create a stream. + /// Blocking create a stream. ClientReaderWriter(Channel* channel, const RpcMethod& method, ClientContext* context) : context_(context), call_(channel->CreateCall(method, context, &cq_)) { @@ -230,10 +257,6 @@ class ClientReaderWriter GRPC_FINAL : public ClientReaderWriterInterface<W, R> { cq_.Pluck(&ops); } - // Blocking wait for initial metadata from server. The received metadata - // can only be accessed after this call returns. Should only be called before - // the first read. Calling this method is optional, and if it is not called - // the metadata will be available in ClientContext after the first read. void WaitForInitialMetadata() { GPR_ASSERT(!context_->initial_metadata_received_); @@ -344,7 +367,7 @@ class ServerWriter GRPC_FINAL : public WriterInterface<W> { ServerContext* const ctx_; }; -// Server-side interface for bi-directional streaming. +/// Server-side interface for bi-directional streaming. template <class W, class R> class ServerReaderWriter GRPC_FINAL : public WriterInterface<W>, public ReaderInterface<R> { diff --git a/include/grpc/grpc.h b/include/grpc/grpc.h index a75f356312..47f3df6605 100644 --- a/include/grpc/grpc.h +++ b/include/grpc/grpc.h @@ -47,11 +47,9 @@ extern "C" { /*! \mainpage GRPC Core * - * \section intro_sec The GRPC Core library is a low-level library designed - * to be wrapped by higher level libraries. - * - * The top-level API is provided in grpc.h. - * Security related functionality lives in grpc_security.h. + * The GRPC Core library is a low-level library designed to be wrapped by higher + * level libraries. The top-level API is provided in grpc.h. Security related + * functionality lives in grpc_security.h. */ /** Completion Queues enable notification of the completion of asynchronous diff --git a/src/core/surface/completion_queue.h b/src/core/surface/completion_queue.h index 8de024aaea..74dc09e36e 100644 --- a/src/core/surface/completion_queue.h +++ b/src/core/surface/completion_queue.h @@ -34,7 +34,7 @@ #ifndef GRPC_INTERNAL_CORE_SURFACE_COMPLETION_QUEUE_H #define GRPC_INTERNAL_CORE_SURFACE_COMPLETION_QUEUE_H -/* Internal API for completion channels */ +/* Internal API for completion queues */ #include "src/core/iomgr/pollset.h" #include <grpc/grpc.h> diff --git a/src/cpp/util/byte_buffer.cc b/src/cpp/util/byte_buffer.cc index e46e656beb..755234d7e8 100644 --- a/src/cpp/util/byte_buffer.cc +++ b/src/cpp/util/byte_buffer.cc @@ -45,6 +45,12 @@ ByteBuffer::ByteBuffer(const Slice* slices, size_t nslices) { buffer_ = grpc_raw_byte_buffer_create(c_slices.data(), nslices); } +ByteBuffer::~ByteBuffer() { + if (buffer_) { + grpc_byte_buffer_destroy(buffer_); + } +} + void ByteBuffer::Clear() { if (buffer_) { grpc_byte_buffer_destroy(buffer_); |