mirror of https://github.com/grpc/grpc.git
Merge pull request #501 from ctiller/c++api
Rebinding of C++ API to the new C core APIpull/366/merge
commit
d3973499ad
74 changed files with 3338 additions and 2115 deletions
@ -1,70 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2014, 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. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef __GRPCPP_ASYNC_SERVER_H__ |
||||
#define __GRPCPP_ASYNC_SERVER_H__ |
||||
|
||||
#include <mutex> |
||||
|
||||
#include <grpc++/config.h> |
||||
|
||||
struct grpc_server; |
||||
|
||||
namespace grpc { |
||||
class CompletionQueue; |
||||
|
||||
class AsyncServer { |
||||
public: |
||||
explicit AsyncServer(CompletionQueue* cc); |
||||
~AsyncServer(); |
||||
|
||||
void AddPort(const grpc::string& addr); |
||||
|
||||
void Start(); |
||||
|
||||
// The user has to call this to get one new rpc on the completion
|
||||
// queue.
|
||||
void RequestOneRpc(); |
||||
|
||||
void Shutdown(); |
||||
|
||||
private: |
||||
bool started_; |
||||
std::mutex shutdown_mu_; |
||||
bool shutdown_; |
||||
grpc_server* server_; |
||||
}; |
||||
|
||||
} // namespace grpc
|
||||
|
||||
#endif // __GRPCPP_ASYNC_SERVER_H__
|
@ -1,95 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2014, 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. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef __GRPCPP_ASYNC_SERVER_CONTEXT_H__ |
||||
#define __GRPCPP_ASYNC_SERVER_CONTEXT_H__ |
||||
|
||||
#include <chrono> |
||||
|
||||
#include <grpc++/config.h> |
||||
|
||||
struct grpc_byte_buffer; |
||||
struct grpc_call; |
||||
struct grpc_completion_queue; |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
class Message; |
||||
} |
||||
} |
||||
|
||||
using std::chrono::system_clock; |
||||
|
||||
namespace grpc { |
||||
class Status; |
||||
|
||||
// TODO(rocking): wrap grpc c structures.
|
||||
class AsyncServerContext { |
||||
public: |
||||
AsyncServerContext(grpc_call* call, const grpc::string& method, |
||||
const grpc::string& host, |
||||
system_clock::time_point absolute_deadline); |
||||
~AsyncServerContext(); |
||||
|
||||
// Accept this rpc, bind it to a completion queue.
|
||||
void Accept(grpc_completion_queue* cq); |
||||
|
||||
// Read and write calls, all async. Return true for success.
|
||||
bool StartRead(google::protobuf::Message* request); |
||||
bool StartWrite(const google::protobuf::Message& response, int flags); |
||||
bool StartWriteStatus(const Status& status); |
||||
|
||||
bool ParseRead(grpc_byte_buffer* read_buffer); |
||||
|
||||
grpc::string method() const { return method_; } |
||||
grpc::string host() const { return host_; } |
||||
system_clock::time_point absolute_deadline() { return absolute_deadline_; } |
||||
|
||||
grpc_call* call() { return call_; } |
||||
|
||||
private: |
||||
AsyncServerContext(const AsyncServerContext&); |
||||
AsyncServerContext& operator=(const AsyncServerContext&); |
||||
|
||||
// These properties may be moved to a ServerContext class.
|
||||
const grpc::string method_; |
||||
const grpc::string host_; |
||||
system_clock::time_point absolute_deadline_; |
||||
|
||||
google::protobuf::Message* request_; // not owned
|
||||
grpc_call* call_; // owned
|
||||
}; |
||||
|
||||
} // namespace grpc
|
||||
|
||||
#endif // __GRPCPP_ASYNC_SERVER_CONTEXT_H__
|
@ -0,0 +1,147 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2014, 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. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef __GRPCPP_CALL_H__ |
||||
#define __GRPCPP_CALL_H__ |
||||
|
||||
#include <grpc/grpc.h> |
||||
#include <grpc++/status.h> |
||||
#include <grpc++/completion_queue.h> |
||||
|
||||
#include <memory> |
||||
#include <map> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
class Message; |
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
struct grpc_call; |
||||
struct grpc_op; |
||||
|
||||
namespace grpc { |
||||
|
||||
class Call; |
||||
|
||||
class CallOpBuffer : public CompletionQueueTag { |
||||
public: |
||||
CallOpBuffer() : return_tag_(this) {} |
||||
~CallOpBuffer(); |
||||
|
||||
void Reset(void *next_return_tag); |
||||
|
||||
// Does not take ownership.
|
||||
void AddSendInitialMetadata( |
||||
std::multimap<grpc::string, grpc::string> *metadata); |
||||
void AddSendInitialMetadata(ClientContext *ctx); |
||||
void AddRecvInitialMetadata( |
||||
std::multimap<grpc::string, grpc::string> *metadata); |
||||
void AddSendMessage(const google::protobuf::Message &message); |
||||
void AddRecvMessage(google::protobuf::Message *message); |
||||
void AddClientSendClose(); |
||||
void AddClientRecvStatus(std::multimap<grpc::string, grpc::string> *metadata, |
||||
Status *status); |
||||
void AddServerSendStatus(std::multimap<grpc::string, grpc::string> *metadata, |
||||
const Status &status); |
||||
void AddServerRecvClose(bool *cancelled); |
||||
|
||||
// INTERNAL API:
|
||||
|
||||
// Convert to an array of grpc_op elements
|
||||
void FillOps(grpc_op *ops, size_t *nops); |
||||
|
||||
// Called by completion queue just prior to returning from Next() or Pluck()
|
||||
void FinalizeResult(void **tag, bool *status) override; |
||||
|
||||
bool got_message = false; |
||||
|
||||
private: |
||||
void *return_tag_ = nullptr; |
||||
// Send initial metadata
|
||||
bool send_initial_metadata_ = false; |
||||
size_t initial_metadata_count_ = 0; |
||||
grpc_metadata *initial_metadata_ = nullptr; |
||||
// Recv initial metadta
|
||||
std::multimap<grpc::string, grpc::string> *recv_initial_metadata_ = nullptr; |
||||
grpc_metadata_array recv_initial_metadata_arr_ = {0, 0, nullptr}; |
||||
// Send message
|
||||
const google::protobuf::Message *send_message_ = nullptr; |
||||
grpc_byte_buffer *send_message_buf_ = nullptr; |
||||
// Recv message
|
||||
google::protobuf::Message *recv_message_ = nullptr; |
||||
grpc_byte_buffer *recv_message_buf_ = nullptr; |
||||
// Client send close
|
||||
bool client_send_close_ = false; |
||||
// Client recv status
|
||||
std::multimap<grpc::string, grpc::string> *recv_trailing_metadata_ = nullptr; |
||||
Status *recv_status_ = nullptr; |
||||
grpc_metadata_array recv_trailing_metadata_arr_ = {0, 0, nullptr}; |
||||
grpc_status_code status_code_ = GRPC_STATUS_OK; |
||||
char *status_details_ = nullptr; |
||||
size_t status_details_capacity_ = 0; |
||||
// Server send status
|
||||
const Status *send_status_ = nullptr; |
||||
size_t trailing_metadata_count_ = 0; |
||||
grpc_metadata *trailing_metadata_ = nullptr; |
||||
int cancelled_buf_; |
||||
bool *recv_closed_ = nullptr; |
||||
}; |
||||
|
||||
// Channel and Server implement this to allow them to hook performing ops
|
||||
class CallHook { |
||||
public: |
||||
virtual ~CallHook() {} |
||||
virtual void PerformOpsOnCall(CallOpBuffer *ops, Call *call) = 0; |
||||
}; |
||||
|
||||
// Straightforward wrapping of the C call object
|
||||
class Call final { |
||||
public: |
||||
/* call is owned by the caller */ |
||||
Call(grpc_call *call, CallHook *call_hook_, CompletionQueue *cq); |
||||
|
||||
void PerformOps(CallOpBuffer *buffer); |
||||
|
||||
grpc_call *call() { return call_; } |
||||
CompletionQueue *cq() { return cq_; } |
||||
|
||||
private: |
||||
CallHook *call_hook_; |
||||
CompletionQueue *cq_; |
||||
grpc_call *call_; |
||||
}; |
||||
|
||||
} // namespace grpc
|
||||
|
||||
#endif // __GRPCPP_CALL_INTERFACE_H__
|
@ -0,0 +1,66 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2014, 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. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef __GRPCPP_CLIENT_UNARY_CALL_H__ |
||||
#define __GRPCPP_CLIENT_UNARY_CALL_H__ |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
class Message; |
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
namespace grpc { |
||||
|
||||
class ChannelInterface; |
||||
class ClientContext; |
||||
class CompletionQueue; |
||||
class RpcMethod; |
||||
class Status; |
||||
|
||||
// Wrapper that begins an asynchronous unary call
|
||||
void AsyncUnaryCall(ChannelInterface *channel, const RpcMethod &method, |
||||
ClientContext *context, |
||||
const google::protobuf::Message &request, |
||||
google::protobuf::Message *result, Status *status, |
||||
CompletionQueue *cq, void *tag); |
||||
|
||||
// Wrapper that performs a blocking unary call
|
||||
Status BlockingUnaryCall(ChannelInterface *channel, const RpcMethod &method, |
||||
ClientContext *context, |
||||
const google::protobuf::Message &request, |
||||
google::protobuf::Message *result); |
||||
|
||||
} // namespace grpc
|
||||
|
||||
#endif |
@ -0,0 +1,127 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2014, 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. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef __GRPCPP_IMPL_SERVICE_TYPE_H__ |
||||
#define __GRPCPP_IMPL_SERVICE_TYPE_H__ |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
class Message; |
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
namespace grpc { |
||||
|
||||
class Call; |
||||
class RpcService; |
||||
class Server; |
||||
class ServerContext; |
||||
class Status; |
||||
|
||||
class SynchronousService { |
||||
public: |
||||
virtual ~SynchronousService() {} |
||||
virtual RpcService* service() = 0; |
||||
}; |
||||
|
||||
class ServerAsyncStreamingInterface { |
||||
public: |
||||
virtual ~ServerAsyncStreamingInterface() {} |
||||
|
||||
virtual void SendInitialMetadata(void* tag) = 0; |
||||
|
||||
private: |
||||
friend class Server; |
||||
virtual void BindCall(Call* call) = 0; |
||||
}; |
||||
|
||||
class AsynchronousService { |
||||
public: |
||||
// this is Server, but in disguise to avoid a link dependency
|
||||
class DispatchImpl { |
||||
public: |
||||
virtual void RequestAsyncCall(void* registered_method, |
||||
ServerContext* context, |
||||
::google::protobuf::Message* request, |
||||
ServerAsyncStreamingInterface* stream, |
||||
CompletionQueue* cq, void* tag) = 0; |
||||
}; |
||||
|
||||
AsynchronousService(CompletionQueue* cq, const char** method_names, |
||||
size_t method_count) |
||||
: cq_(cq), method_names_(method_names), method_count_(method_count) {} |
||||
|
||||
~AsynchronousService() { delete[] request_args_; } |
||||
|
||||
CompletionQueue* completion_queue() const { return cq_; } |
||||
|
||||
protected: |
||||
void RequestAsyncUnary(int index, ServerContext* context, |
||||
::google::protobuf::Message* request, |
||||
ServerAsyncStreamingInterface* stream, |
||||
CompletionQueue* cq, void* tag) { |
||||
dispatch_impl_->RequestAsyncCall(request_args_[index], context, request, |
||||
stream, cq, tag); |
||||
} |
||||
void RequestClientStreaming(int index, ServerContext* context, |
||||
ServerAsyncStreamingInterface* stream, |
||||
CompletionQueue* cq, void* tag) { |
||||
dispatch_impl_->RequestAsyncCall(request_args_[index], context, nullptr, |
||||
stream, cq, tag); |
||||
} |
||||
void RequestServerStreaming(int index, ServerContext* context, |
||||
::google::protobuf::Message* request, |
||||
ServerAsyncStreamingInterface* stream, |
||||
CompletionQueue* cq, void* tag) { |
||||
dispatch_impl_->RequestAsyncCall(request_args_[index], context, request, |
||||
stream, cq, tag); |
||||
} |
||||
void RequestBidiStreaming(int index, ServerContext* context, |
||||
ServerAsyncStreamingInterface* stream, |
||||
CompletionQueue* cq, void* tag) { |
||||
dispatch_impl_->RequestAsyncCall(request_args_[index], context, nullptr, |
||||
stream, cq, tag); |
||||
} |
||||
|
||||
private: |
||||
friend class Server; |
||||
CompletionQueue* const cq_; |
||||
DispatchImpl* dispatch_impl_ = nullptr; |
||||
const char** const method_names_; |
||||
size_t method_count_; |
||||
void** request_args_ = nullptr; |
||||
}; |
||||
|
||||
} // namespace grpc
|
||||
|
||||
#endif // __GRPCPP_IMPL_SERVICE_TYPE_H__
|
@ -1,64 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2014, 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. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef __GRPCPP_STREAM_CONTEXT_INTERFACE_H__ |
||||
#define __GRPCPP_STREAM_CONTEXT_INTERFACE_H__ |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
class Message; |
||||
} |
||||
} |
||||
|
||||
namespace grpc { |
||||
class Status; |
||||
|
||||
// An interface to avoid dependency on internal implementation.
|
||||
class StreamContextInterface { |
||||
public: |
||||
virtual ~StreamContextInterface() {} |
||||
|
||||
virtual void Start(bool buffered) = 0; |
||||
|
||||
virtual bool Read(google::protobuf::Message* msg) = 0; |
||||
virtual bool Write(const google::protobuf::Message* msg, bool is_last) = 0; |
||||
virtual const Status& Wait() = 0; |
||||
virtual void Cancel() = 0; |
||||
|
||||
virtual google::protobuf::Message* request() = 0; |
||||
virtual google::protobuf::Message* response() = 0; |
||||
}; |
||||
|
||||
} // namespace grpc
|
||||
|
||||
#endif // __GRPCPP_STREAM_CONTEXT_INTERFACE_H__
|
@ -0,0 +1 @@ |
||||
/home/craig/grpc-ct/include/grpc |
@ -0,0 +1,89 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2014, 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. |
||||
* |
||||
*/ |
||||
|
||||
#include <grpc++/impl/client_unary_call.h> |
||||
#include <grpc++/impl/call.h> |
||||
#include <grpc++/channel_interface.h> |
||||
#include <grpc++/client_context.h> |
||||
#include <grpc++/completion_queue.h> |
||||
#include <grpc++/status.h> |
||||
#include <grpc/support/log.h> |
||||
|
||||
namespace grpc { |
||||
|
||||
// Wrapper that performs a blocking unary call
|
||||
Status BlockingUnaryCall(ChannelInterface *channel, const RpcMethod &method, |
||||
ClientContext *context, |
||||
const google::protobuf::Message &request, |
||||
google::protobuf::Message *result) { |
||||
CompletionQueue cq; |
||||
Call call(channel->CreateCall(method, context, &cq)); |
||||
CallOpBuffer buf; |
||||
Status status; |
||||
buf.AddSendInitialMetadata(context); |
||||
buf.AddSendMessage(request); |
||||
buf.AddRecvInitialMetadata(&context->recv_initial_metadata_); |
||||
buf.AddRecvMessage(result); |
||||
buf.AddClientSendClose(); |
||||
buf.AddClientRecvStatus(&context->trailing_metadata_, &status); |
||||
call.PerformOps(&buf); |
||||
GPR_ASSERT((cq.Pluck(&buf) && buf.got_message) || !status.IsOk()); |
||||
return status; |
||||
} |
||||
|
||||
class ClientAsyncRequest final : public CallOpBuffer { |
||||
public: |
||||
void FinalizeResult(void **tag, bool *status) override { |
||||
CallOpBuffer::FinalizeResult(tag, status); |
||||
delete this; |
||||
} |
||||
}; |
||||
|
||||
void AsyncUnaryCall(ChannelInterface *channel, const RpcMethod &method, |
||||
ClientContext *context, |
||||
const google::protobuf::Message &request, |
||||
google::protobuf::Message *result, Status *status, |
||||
CompletionQueue *cq, void *tag) { |
||||
ClientAsyncRequest *buf = new ClientAsyncRequest; |
||||
buf->Reset(tag); |
||||
Call call(channel->CreateCall(method, context, cq)); |
||||
buf->AddSendInitialMetadata(context); |
||||
buf->AddSendMessage(request); |
||||
buf->AddRecvInitialMetadata(&context->recv_initial_metadata_); |
||||
buf->AddRecvMessage(result); |
||||
buf->AddClientSendClose(); |
||||
buf->AddClientRecvStatus(&context->trailing_metadata_, status); |
||||
call.PerformOps(buf); |
||||
} |
||||
|
||||
} // namespace grpc
|
@ -0,0 +1,287 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2014, 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. |
||||
* |
||||
*/ |
||||
|
||||
#include <google/protobuf/message.h> |
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc++/impl/call.h> |
||||
#include <grpc++/client_context.h> |
||||
#include <grpc++/channel_interface.h> |
||||
|
||||
#include "src/cpp/proto/proto_utils.h" |
||||
|
||||
namespace grpc { |
||||
|
||||
void CallOpBuffer::Reset(void* next_return_tag) { |
||||
return_tag_ = next_return_tag; |
||||
|
||||
send_initial_metadata_ = false; |
||||
initial_metadata_count_ = 0; |
||||
gpr_free(initial_metadata_); |
||||
|
||||
recv_initial_metadata_ = nullptr; |
||||
recv_initial_metadata_arr_.count = 0; |
||||
|
||||
send_message_ = nullptr; |
||||
if (send_message_buf_) { |
||||
grpc_byte_buffer_destroy(send_message_buf_); |
||||
send_message_buf_ = nullptr; |
||||
} |
||||
|
||||
recv_message_ = nullptr; |
||||
got_message = false; |
||||
if (recv_message_buf_) { |
||||
grpc_byte_buffer_destroy(recv_message_buf_); |
||||
recv_message_buf_ = nullptr; |
||||
} |
||||
|
||||
client_send_close_ = false; |
||||
|
||||
recv_trailing_metadata_ = nullptr; |
||||
recv_status_ = nullptr; |
||||
recv_trailing_metadata_arr_.count = 0; |
||||
|
||||
status_code_ = GRPC_STATUS_OK; |
||||
|
||||
send_status_ = nullptr; |
||||
trailing_metadata_count_ = 0; |
||||
trailing_metadata_ = nullptr; |
||||
|
||||
recv_closed_ = nullptr; |
||||
} |
||||
|
||||
CallOpBuffer::~CallOpBuffer() { |
||||
gpr_free(status_details_); |
||||
gpr_free(recv_initial_metadata_arr_.metadata); |
||||
gpr_free(recv_trailing_metadata_arr_.metadata); |
||||
if (recv_message_buf_) { |
||||
grpc_byte_buffer_destroy(recv_message_buf_); |
||||
} |
||||
if (send_message_buf_) { |
||||
grpc_byte_buffer_destroy(send_message_buf_); |
||||
} |
||||
} |
||||
|
||||
namespace { |
||||
// TODO(yangg) if the map is changed before we send, the pointers will be a
|
||||
// mess. Make sure it does not happen.
|
||||
grpc_metadata* FillMetadataArray( |
||||
std::multimap<grpc::string, grpc::string>* metadata) { |
||||
if (metadata->empty()) { |
||||
return nullptr; |
||||
} |
||||
grpc_metadata* metadata_array = |
||||
(grpc_metadata*)gpr_malloc(metadata->size() * sizeof(grpc_metadata)); |
||||
size_t i = 0; |
||||
for (auto iter = metadata->cbegin(); iter != metadata->cend(); ++iter, ++i) { |
||||
metadata_array[i].key = iter->first.c_str(); |
||||
metadata_array[i].value = iter->second.c_str(); |
||||
metadata_array[i].value_length = iter->second.size(); |
||||
} |
||||
return metadata_array; |
||||
} |
||||
|
||||
void FillMetadataMap(grpc_metadata_array* arr, |
||||
std::multimap<grpc::string, grpc::string>* metadata) { |
||||
for (size_t i = 0; i < arr->count; i++) { |
||||
// TODO(yangg) handle duplicates?
|
||||
metadata->insert(std::pair<grpc::string, grpc::string>( |
||||
arr->metadata[i].key, |
||||
{arr->metadata[i].value, arr->metadata[i].value_length})); |
||||
} |
||||
grpc_metadata_array_destroy(arr); |
||||
grpc_metadata_array_init(arr); |
||||
} |
||||
} // namespace
|
||||
|
||||
void CallOpBuffer::AddSendInitialMetadata( |
||||
std::multimap<grpc::string, grpc::string>* metadata) { |
||||
send_initial_metadata_ = true; |
||||
initial_metadata_count_ = metadata->size(); |
||||
initial_metadata_ = FillMetadataArray(metadata); |
||||
} |
||||
|
||||
void CallOpBuffer::AddRecvInitialMetadata( |
||||
std::multimap<grpc::string, grpc::string>* metadata) { |
||||
recv_initial_metadata_ = metadata; |
||||
} |
||||
|
||||
void CallOpBuffer::AddSendInitialMetadata(ClientContext* ctx) { |
||||
AddSendInitialMetadata(&ctx->send_initial_metadata_); |
||||
} |
||||
|
||||
void CallOpBuffer::AddSendMessage(const google::protobuf::Message& message) { |
||||
send_message_ = &message; |
||||
} |
||||
|
||||
void CallOpBuffer::AddRecvMessage(google::protobuf::Message* message) { |
||||
recv_message_ = message; |
||||
recv_message_->Clear(); |
||||
} |
||||
|
||||
void CallOpBuffer::AddClientSendClose() { client_send_close_ = true; } |
||||
|
||||
void CallOpBuffer::AddServerRecvClose(bool* cancelled) { |
||||
recv_closed_ = cancelled; |
||||
} |
||||
|
||||
void CallOpBuffer::AddClientRecvStatus( |
||||
std::multimap<grpc::string, grpc::string>* metadata, Status* status) { |
||||
recv_trailing_metadata_ = metadata; |
||||
recv_status_ = status; |
||||
} |
||||
|
||||
void CallOpBuffer::AddServerSendStatus( |
||||
std::multimap<grpc::string, grpc::string>* metadata, const Status& status) { |
||||
if (metadata != NULL) { |
||||
trailing_metadata_count_ = metadata->size(); |
||||
trailing_metadata_ = FillMetadataArray(metadata); |
||||
} else { |
||||
trailing_metadata_count_ = 0; |
||||
} |
||||
send_status_ = &status; |
||||
} |
||||
|
||||
void CallOpBuffer::FillOps(grpc_op* ops, size_t* nops) { |
||||
*nops = 0; |
||||
if (send_initial_metadata_) { |
||||
ops[*nops].op = GRPC_OP_SEND_INITIAL_METADATA; |
||||
ops[*nops].data.send_initial_metadata.count = initial_metadata_count_; |
||||
ops[*nops].data.send_initial_metadata.metadata = initial_metadata_; |
||||
(*nops)++; |
||||
} |
||||
if (recv_initial_metadata_) { |
||||
ops[*nops].op = GRPC_OP_RECV_INITIAL_METADATA; |
||||
ops[*nops].data.recv_initial_metadata = &recv_initial_metadata_arr_; |
||||
(*nops)++; |
||||
} |
||||
if (send_message_) { |
||||
bool success = SerializeProto(*send_message_, &send_message_buf_); |
||||
if (!success) { |
||||
abort(); |
||||
// TODO handle parse failure
|
||||
} |
||||
ops[*nops].op = GRPC_OP_SEND_MESSAGE; |
||||
ops[*nops].data.send_message = send_message_buf_; |
||||
(*nops)++; |
||||
} |
||||
if (recv_message_) { |
||||
ops[*nops].op = GRPC_OP_RECV_MESSAGE; |
||||
ops[*nops].data.recv_message = &recv_message_buf_; |
||||
(*nops)++; |
||||
} |
||||
if (client_send_close_) { |
||||
ops[*nops].op = GRPC_OP_SEND_CLOSE_FROM_CLIENT; |
||||
(*nops)++; |
||||
} |
||||
if (recv_status_) { |
||||
ops[*nops].op = GRPC_OP_RECV_STATUS_ON_CLIENT; |
||||
ops[*nops].data.recv_status_on_client.trailing_metadata = |
||||
&recv_trailing_metadata_arr_; |
||||
ops[*nops].data.recv_status_on_client.status = &status_code_; |
||||
ops[*nops].data.recv_status_on_client.status_details = &status_details_; |
||||
ops[*nops].data.recv_status_on_client.status_details_capacity = |
||||
&status_details_capacity_; |
||||
(*nops)++; |
||||
} |
||||
if (send_status_) { |
||||
ops[*nops].op = GRPC_OP_SEND_STATUS_FROM_SERVER; |
||||
ops[*nops].data.send_status_from_server.trailing_metadata_count = |
||||
trailing_metadata_count_; |
||||
ops[*nops].data.send_status_from_server.trailing_metadata = |
||||
trailing_metadata_; |
||||
ops[*nops].data.send_status_from_server.status = |
||||
static_cast<grpc_status_code>(send_status_->code()); |
||||
ops[*nops].data.send_status_from_server.status_details = |
||||
send_status_->details().c_str(); |
||||
(*nops)++; |
||||
} |
||||
if (recv_closed_) { |
||||
ops[*nops].op = GRPC_OP_RECV_CLOSE_ON_SERVER; |
||||
ops[*nops].data.recv_close_on_server.cancelled = &cancelled_buf_; |
||||
(*nops)++; |
||||
} |
||||
} |
||||
|
||||
void CallOpBuffer::FinalizeResult(void** tag, bool* status) { |
||||
// Release send buffers.
|
||||
if (send_message_buf_) { |
||||
grpc_byte_buffer_destroy(send_message_buf_); |
||||
send_message_buf_ = nullptr; |
||||
} |
||||
if (initial_metadata_) { |
||||
gpr_free(initial_metadata_); |
||||
initial_metadata_ = nullptr; |
||||
} |
||||
if (trailing_metadata_count_) { |
||||
gpr_free(trailing_metadata_); |
||||
trailing_metadata_ = nullptr; |
||||
} |
||||
// Set user-facing tag.
|
||||
*tag = return_tag_; |
||||
// Process received initial metadata
|
||||
if (recv_initial_metadata_) { |
||||
FillMetadataMap(&recv_initial_metadata_arr_, recv_initial_metadata_); |
||||
} |
||||
// Parse received message if any.
|
||||
if (recv_message_) { |
||||
if (recv_message_buf_) { |
||||
got_message = *status; |
||||
*status = *status && DeserializeProto(recv_message_buf_, recv_message_); |
||||
grpc_byte_buffer_destroy(recv_message_buf_); |
||||
recv_message_buf_ = nullptr; |
||||
} else { |
||||
// Read failed
|
||||
got_message = false; |
||||
*status = false; |
||||
} |
||||
} |
||||
// Parse received status.
|
||||
if (recv_status_) { |
||||
FillMetadataMap(&recv_trailing_metadata_arr_, recv_trailing_metadata_); |
||||
*recv_status_ = Status( |
||||
static_cast<StatusCode>(status_code_), |
||||
status_details_ ? grpc::string(status_details_) : grpc::string()); |
||||
} |
||||
if (recv_closed_) { |
||||
*recv_closed_ = cancelled_buf_ != 0; |
||||
} |
||||
} |
||||
|
||||
Call::Call(grpc_call* call, CallHook* call_hook, CompletionQueue* cq) |
||||
: call_hook_(call_hook), cq_(cq), call_(call) {} |
||||
|
||||
void Call::PerformOps(CallOpBuffer* buffer) { |
||||
call_hook_->PerformOpsOnCall(buffer, this); |
||||
} |
||||
|
||||
} // namespace grpc
|
@ -1,89 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2014, 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. |
||||
* |
||||
*/ |
||||
|
||||
#include <grpc++/async_server.h> |
||||
|
||||
#include <grpc/grpc.h> |
||||
#include <grpc/support/log.h> |
||||
#include <grpc++/completion_queue.h> |
||||
|
||||
namespace grpc { |
||||
|
||||
AsyncServer::AsyncServer(CompletionQueue *cc) |
||||
: started_(false), shutdown_(false) { |
||||
server_ = grpc_server_create(cc->cq(), nullptr); |
||||
} |
||||
|
||||
AsyncServer::~AsyncServer() { |
||||
std::unique_lock<std::mutex> lock(shutdown_mu_); |
||||
if (started_ && !shutdown_) { |
||||
lock.unlock(); |
||||
Shutdown(); |
||||
} |
||||
grpc_server_destroy(server_); |
||||
} |
||||
|
||||
void AsyncServer::AddPort(const grpc::string &addr) { |
||||
GPR_ASSERT(!started_); |
||||
int success = grpc_server_add_http2_port(server_, addr.c_str()); |
||||
GPR_ASSERT(success); |
||||
} |
||||
|
||||
void AsyncServer::Start() { |
||||
GPR_ASSERT(!started_); |
||||
started_ = true; |
||||
grpc_server_start(server_); |
||||
} |
||||
|
||||
void AsyncServer::RequestOneRpc() { |
||||
GPR_ASSERT(started_); |
||||
std::unique_lock<std::mutex> lock(shutdown_mu_); |
||||
if (shutdown_) { |
||||
return; |
||||
} |
||||
lock.unlock(); |
||||
grpc_call_error err = grpc_server_request_call_old(server_, nullptr); |
||||
GPR_ASSERT(err == GRPC_CALL_OK); |
||||
} |
||||
|
||||
void AsyncServer::Shutdown() { |
||||
std::unique_lock<std::mutex> lock(shutdown_mu_); |
||||
if (started_ && !shutdown_) { |
||||
shutdown_ = true; |
||||
lock.unlock(); |
||||
// TODO(yangg) should we shutdown without start?
|
||||
grpc_server_shutdown(server_); |
||||
} |
||||
} |
||||
|
||||
} // namespace grpc
|
@ -1,36 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2014, 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. |
||||
* |
||||
*/ |
||||
|
||||
#include "src/cpp/server/server_context_impl.h" |
||||
|
||||
namespace grpc {} // namespace grpc
|
@ -1,140 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2014, 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. |
||||
* |
||||
*/ |
||||
|
||||
#include "src/cpp/server/server_rpc_handler.h" |
||||
|
||||
#include <grpc/support/log.h> |
||||
#include "src/cpp/server/server_context_impl.h" |
||||
#include "src/cpp/stream/stream_context.h" |
||||
#include <grpc++/async_server_context.h> |
||||
#include <grpc++/impl/rpc_service_method.h> |
||||
|
||||
namespace grpc { |
||||
|
||||
ServerRpcHandler::ServerRpcHandler(AsyncServerContext *async_server_context, |
||||
RpcServiceMethod *method) |
||||
: async_server_context_(async_server_context), method_(method) {} |
||||
|
||||
void ServerRpcHandler::StartRpc() { |
||||
if (method_ == nullptr) { |
||||
// Method not supported, finish the rpc with error.
|
||||
// TODO(rocking): do we need to call read to consume the request?
|
||||
FinishRpc(Status(StatusCode::UNIMPLEMENTED, "No such method.")); |
||||
return; |
||||
} |
||||
|
||||
ServerContextImpl user_context(async_server_context_->absolute_deadline()); |
||||
|
||||
if (method_->method_type() == RpcMethod::NORMAL_RPC) { |
||||
// Start the rpc on this dedicated completion queue.
|
||||
async_server_context_->Accept(cq_.cq()); |
||||
|
||||
// Allocate request and response.
|
||||
std::unique_ptr<google::protobuf::Message> request( |
||||
method_->AllocateRequestProto()); |
||||
std::unique_ptr<google::protobuf::Message> response( |
||||
method_->AllocateResponseProto()); |
||||
|
||||
// Read request
|
||||
async_server_context_->StartRead(request.get()); |
||||
auto type = WaitForNextEvent(); |
||||
GPR_ASSERT(type == CompletionQueue::SERVER_READ_OK); |
||||
|
||||
// Run the application's rpc handler
|
||||
MethodHandler *handler = method_->handler(); |
||||
Status status = handler->RunHandler(MethodHandler::HandlerParameter( |
||||
&user_context, request.get(), response.get())); |
||||
|
||||
if (status.IsOk()) { |
||||
// Send the response if we get an ok status.
|
||||
async_server_context_->StartWrite(*response, GRPC_WRITE_BUFFER_HINT); |
||||
type = WaitForNextEvent(); |
||||
if (type != CompletionQueue::SERVER_WRITE_OK) { |
||||
status = Status(StatusCode::INTERNAL, "Error writing response."); |
||||
} |
||||
} |
||||
|
||||
FinishRpc(status); |
||||
} else { |
||||
// Allocate request and response.
|
||||
// TODO(yangg) maybe not allocate both when not needed?
|
||||
std::unique_ptr<google::protobuf::Message> request( |
||||
method_->AllocateRequestProto()); |
||||
std::unique_ptr<google::protobuf::Message> response( |
||||
method_->AllocateResponseProto()); |
||||
|
||||
StreamContext stream_context(*method_, async_server_context_->call(), |
||||
cq_.cq(), request.get(), response.get()); |
||||
|
||||
// Run the application's rpc handler
|
||||
MethodHandler *handler = method_->handler(); |
||||
Status status = handler->RunHandler(MethodHandler::HandlerParameter( |
||||
&user_context, request.get(), response.get(), &stream_context)); |
||||
if (status.IsOk() && |
||||
method_->method_type() == RpcMethod::CLIENT_STREAMING) { |
||||
stream_context.Write(response.get(), false); |
||||
} |
||||
// TODO(yangg) Do we need to consider the status in stream_context?
|
||||
FinishRpc(status); |
||||
} |
||||
} |
||||
|
||||
CompletionQueue::CompletionType ServerRpcHandler::WaitForNextEvent() { |
||||
void *tag = nullptr; |
||||
CompletionQueue::CompletionType type = cq_.Next(&tag); |
||||
if (type != CompletionQueue::QUEUE_CLOSED && |
||||
type != CompletionQueue::RPC_END) { |
||||
GPR_ASSERT(static_cast<AsyncServerContext *>(tag) == |
||||
async_server_context_.get()); |
||||
} |
||||
return type; |
||||
} |
||||
|
||||
void ServerRpcHandler::FinishRpc(const Status &status) { |
||||
async_server_context_->StartWriteStatus(status); |
||||
CompletionQueue::CompletionType type; |
||||
|
||||
// HALFCLOSE_OK and RPC_END events come in either order.
|
||||
type = WaitForNextEvent(); |
||||
GPR_ASSERT(type == CompletionQueue::HALFCLOSE_OK || |
||||
type == CompletionQueue::RPC_END); |
||||
type = WaitForNextEvent(); |
||||
GPR_ASSERT(type == CompletionQueue::HALFCLOSE_OK || |
||||
type == CompletionQueue::RPC_END); |
||||
|
||||
cq_.Shutdown(); |
||||
type = WaitForNextEvent(); |
||||
GPR_ASSERT(type == CompletionQueue::QUEUE_CLOSED); |
||||
} |
||||
|
||||
} // namespace grpc
|
@ -1,66 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2014, 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. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef __GRPCPP_INTERNAL_SERVER_SERVER_RPC_HANDLER_H__ |
||||
#define __GRPCPP_INTERNAL_SERVER_SERVER_RPC_HANDLER_H__ |
||||
|
||||
#include <memory> |
||||
|
||||
#include <grpc++/completion_queue.h> |
||||
#include <grpc++/status.h> |
||||
|
||||
namespace grpc { |
||||
|
||||
class AsyncServerContext; |
||||
class RpcServiceMethod; |
||||
|
||||
class ServerRpcHandler { |
||||
public: |
||||
// Takes ownership of async_server_context.
|
||||
ServerRpcHandler(AsyncServerContext *async_server_context, |
||||
RpcServiceMethod *method); |
||||
|
||||
void StartRpc(); |
||||
|
||||
private: |
||||
CompletionQueue::CompletionType WaitForNextEvent(); |
||||
void FinishRpc(const Status &status); |
||||
|
||||
std::unique_ptr<AsyncServerContext> async_server_context_; |
||||
RpcServiceMethod *method_; |
||||
CompletionQueue cq_; |
||||
}; |
||||
|
||||
} // namespace grpc
|
||||
|
||||
#endif // __GRPCPP_INTERNAL_SERVER_SERVER_RPC_HANDLER_H__
|
@ -1,179 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2014, 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. |
||||
* |
||||
*/ |
||||
|
||||
#include "src/cpp/stream/stream_context.h" |
||||
|
||||
#include <grpc/support/log.h> |
||||
#include "src/cpp/proto/proto_utils.h" |
||||
#include "src/cpp/util/time.h" |
||||
#include <grpc++/client_context.h> |
||||
#include <grpc++/config.h> |
||||
#include <grpc++/impl/rpc_method.h> |
||||
#include <google/protobuf/message.h> |
||||
|
||||
namespace grpc { |
||||
|
||||
// Client only ctor
|
||||
StreamContext::StreamContext(const RpcMethod &method, ClientContext *context, |
||||
const google::protobuf::Message *request, |
||||
google::protobuf::Message *result) |
||||
: is_client_(true), |
||||
method_(&method), |
||||
call_(context->call()), |
||||
cq_(context->cq()), |
||||
request_(const_cast<google::protobuf::Message *>(request)), |
||||
result_(result), |
||||
peer_halfclosed_(false), |
||||
self_halfclosed_(false) { |
||||
GPR_ASSERT(method_->method_type() != RpcMethod::RpcType::NORMAL_RPC); |
||||
} |
||||
|
||||
// Server only ctor
|
||||
StreamContext::StreamContext(const RpcMethod &method, grpc_call *call, |
||||
grpc_completion_queue *cq, |
||||
google::protobuf::Message *request, |
||||
google::protobuf::Message *result) |
||||
: is_client_(false), |
||||
method_(&method), |
||||
call_(call), |
||||
cq_(cq), |
||||
request_(request), |
||||
result_(result), |
||||
peer_halfclosed_(false), |
||||
self_halfclosed_(false) { |
||||
GPR_ASSERT(method_->method_type() != RpcMethod::RpcType::NORMAL_RPC); |
||||
} |
||||
|
||||
StreamContext::~StreamContext() {} |
||||
|
||||
void StreamContext::Start(bool buffered) { |
||||
if (is_client_) { |
||||
// TODO(yangg) handle metadata send path
|
||||
int flag = buffered ? GRPC_WRITE_BUFFER_HINT : 0; |
||||
grpc_call_error error = grpc_call_invoke_old( |
||||
call(), cq(), client_metadata_read_tag(), finished_tag(), flag); |
||||
GPR_ASSERT(GRPC_CALL_OK == error); |
||||
} else { |
||||
// TODO(yangg) metadata needs to be added before accept
|
||||
// TODO(yangg) correctly set flag to accept
|
||||
GPR_ASSERT(grpc_call_server_accept_old(call(), cq(), finished_tag()) == |
||||
GRPC_CALL_OK); |
||||
GPR_ASSERT(grpc_call_server_end_initial_metadata_old(call(), 0) == |
||||
GRPC_CALL_OK); |
||||
} |
||||
} |
||||
|
||||
bool StreamContext::Read(google::protobuf::Message *msg) { |
||||
// TODO(yangg) check peer_halfclosed_ here for possible early return.
|
||||
grpc_call_error err = grpc_call_start_read_old(call(), read_tag()); |
||||
GPR_ASSERT(err == GRPC_CALL_OK); |
||||
grpc_event *read_ev = |
||||
grpc_completion_queue_pluck(cq(), read_tag(), gpr_inf_future); |
||||
GPR_ASSERT(read_ev->type == GRPC_READ); |
||||
bool ret = true; |
||||
if (read_ev->data.read) { |
||||
if (!DeserializeProto(read_ev->data.read, msg)) { |
||||
ret = false; |
||||
grpc_call_cancel_with_status(call(), GRPC_STATUS_DATA_LOSS, |
||||
"Failed to parse incoming proto"); |
||||
} |
||||
} else { |
||||
ret = false; |
||||
peer_halfclosed_ = true; |
||||
} |
||||
grpc_event_finish(read_ev); |
||||
return ret; |
||||
} |
||||
|
||||
bool StreamContext::Write(const google::protobuf::Message *msg, bool is_last) { |
||||
// TODO(yangg) check self_halfclosed_ for possible early return.
|
||||
bool ret = true; |
||||
grpc_event *ev = nullptr; |
||||
|
||||
if (msg) { |
||||
grpc_byte_buffer *out_buf = nullptr; |
||||
if (!SerializeProto(*msg, &out_buf)) { |
||||
grpc_call_cancel_with_status(call(), GRPC_STATUS_INVALID_ARGUMENT, |
||||
"Failed to serialize outgoing proto"); |
||||
return false; |
||||
} |
||||
int flag = is_last ? GRPC_WRITE_BUFFER_HINT : 0; |
||||
grpc_call_error err = |
||||
grpc_call_start_write_old(call(), out_buf, write_tag(), flag); |
||||
grpc_byte_buffer_destroy(out_buf); |
||||
GPR_ASSERT(err == GRPC_CALL_OK); |
||||
|
||||
ev = grpc_completion_queue_pluck(cq(), write_tag(), gpr_inf_future); |
||||
GPR_ASSERT(ev->type == GRPC_WRITE_ACCEPTED); |
||||
|
||||
ret = ev->data.write_accepted == GRPC_OP_OK; |
||||
grpc_event_finish(ev); |
||||
} |
||||
if (ret && is_last) { |
||||
grpc_call_error err = grpc_call_writes_done_old(call(), halfclose_tag()); |
||||
GPR_ASSERT(err == GRPC_CALL_OK); |
||||
ev = grpc_completion_queue_pluck(cq(), halfclose_tag(), gpr_inf_future); |
||||
GPR_ASSERT(ev->type == GRPC_FINISH_ACCEPTED); |
||||
grpc_event_finish(ev); |
||||
|
||||
self_halfclosed_ = true; |
||||
} else if (!ret) { // Stream broken
|
||||
self_halfclosed_ = true; |
||||
peer_halfclosed_ = true; |
||||
} |
||||
|
||||
return ret; |
||||
} |
||||
|
||||
const Status &StreamContext::Wait() { |
||||
// TODO(yangg) properly support metadata
|
||||
grpc_event *metadata_ev = grpc_completion_queue_pluck( |
||||
cq(), client_metadata_read_tag(), gpr_inf_future); |
||||
grpc_event_finish(metadata_ev); |
||||
// TODO(yangg) protect states by a mutex, including other places.
|
||||
if (!self_halfclosed_ || !peer_halfclosed_) { |
||||
Cancel(); |
||||
} |
||||
grpc_event *finish_ev = |
||||
grpc_completion_queue_pluck(cq(), finished_tag(), gpr_inf_future); |
||||
GPR_ASSERT(finish_ev->type == GRPC_FINISHED); |
||||
final_status_ = Status( |
||||
static_cast<StatusCode>(finish_ev->data.finished.status), |
||||
finish_ev->data.finished.details ? finish_ev->data.finished.details : ""); |
||||
grpc_event_finish(finish_ev); |
||||
return final_status_; |
||||
} |
||||
|
||||
void StreamContext::Cancel() { grpc_call_cancel(call()); } |
||||
|
||||
} // namespace grpc
|
@ -1,99 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2014, 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. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef __GRPCPP_INTERNAL_STREAM_STREAM_CONTEXT_H__ |
||||
#define __GRPCPP_INTERNAL_STREAM_STREAM_CONTEXT_H__ |
||||
|
||||
#include <grpc/grpc.h> |
||||
#include <grpc++/status.h> |
||||
#include <grpc++/stream_context_interface.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
class Message; |
||||
} |
||||
} |
||||
|
||||
namespace grpc { |
||||
class ClientContext; |
||||
class RpcMethod; |
||||
|
||||
class StreamContext final : public StreamContextInterface { |
||||
public: |
||||
StreamContext(const RpcMethod &method, ClientContext *context, |
||||
const google::protobuf::Message *request, |
||||
google::protobuf::Message *result); |
||||
StreamContext(const RpcMethod &method, grpc_call *call, |
||||
grpc_completion_queue *cq, google::protobuf::Message *request, |
||||
google::protobuf::Message *result); |
||||
~StreamContext(); |
||||
// Start the stream, if there is a final write following immediately, set
|
||||
// buffered so that the messages can be sent in batch.
|
||||
void Start(bool buffered) override; |
||||
bool Read(google::protobuf::Message *msg) override; |
||||
bool Write(const google::protobuf::Message *msg, bool is_last) override; |
||||
const Status &Wait() override; |
||||
void Cancel() override; |
||||
|
||||
google::protobuf::Message *request() override { return request_; } |
||||
google::protobuf::Message *response() override { return result_; } |
||||
|
||||
private: |
||||
// Unique tags for plucking events from the c layer. this pointer is casted
|
||||
// to char* to create single byte step between tags. It implicitly relies on
|
||||
// that StreamContext is large enough to contain all the pointers.
|
||||
void *finished_tag() { return reinterpret_cast<char *>(this); } |
||||
void *read_tag() { return reinterpret_cast<char *>(this) + 1; } |
||||
void *write_tag() { return reinterpret_cast<char *>(this) + 2; } |
||||
void *halfclose_tag() { return reinterpret_cast<char *>(this) + 3; } |
||||
void *client_metadata_read_tag() { |
||||
return reinterpret_cast<char *>(this) + 5; |
||||
} |
||||
grpc_call *call() { return call_; } |
||||
grpc_completion_queue *cq() { return cq_; } |
||||
|
||||
bool is_client_; |
||||
const RpcMethod *method_; // not owned
|
||||
grpc_call *call_; // not owned
|
||||
grpc_completion_queue *cq_; // not owned
|
||||
google::protobuf::Message *request_; // first request, not owned
|
||||
google::protobuf::Message *result_; // last response, not owned
|
||||
|
||||
bool peer_halfclosed_; |
||||
bool self_halfclosed_; |
||||
Status final_status_; |
||||
}; |
||||
|
||||
} // namespace grpc
|
||||
|
||||
#endif // __GRPCPP_INTERNAL_STREAM_STREAM_CONTEXT_H__
|
@ -0,0 +1,379 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2014, 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. |
||||
* |
||||
*/ |
||||
|
||||
#include <chrono> |
||||
#include <thread> |
||||
|
||||
#include "test/core/util/test_config.h" |
||||
#include "test/cpp/util/echo_duplicate.pb.h" |
||||
#include "test/cpp/util/echo.pb.h" |
||||
#include "src/cpp/util/time.h" |
||||
#include <grpc++/channel_arguments.h> |
||||
#include <grpc++/channel_interface.h> |
||||
#include <grpc++/client_context.h> |
||||
#include <grpc++/create_channel.h> |
||||
#include <grpc++/credentials.h> |
||||
#include <grpc++/server.h> |
||||
#include <grpc++/server_builder.h> |
||||
#include <grpc++/server_context.h> |
||||
#include <grpc++/status.h> |
||||
#include <grpc++/stream.h> |
||||
#include "test/core/util/port.h" |
||||
#include <gtest/gtest.h> |
||||
|
||||
#include <grpc/grpc.h> |
||||
#include <grpc/support/thd.h> |
||||
#include <grpc/support/time.h> |
||||
|
||||
using grpc::cpp::test::util::EchoRequest; |
||||
using grpc::cpp::test::util::EchoResponse; |
||||
using std::chrono::system_clock; |
||||
|
||||
namespace grpc { |
||||
namespace testing { |
||||
|
||||
namespace { |
||||
|
||||
void* tag(int i) { |
||||
return (void*)(gpr_intptr)i; |
||||
} |
||||
|
||||
void verify_ok(CompletionQueue* cq, int i, bool expect_ok) { |
||||
bool ok; |
||||
void* got_tag; |
||||
EXPECT_TRUE(cq->Next(&got_tag, &ok)); |
||||
EXPECT_EQ(expect_ok, ok); |
||||
EXPECT_EQ(tag(i), got_tag); |
||||
} |
||||
|
||||
class AsyncEnd2endTest : public ::testing::Test { |
||||
protected: |
||||
AsyncEnd2endTest() : service_(&srv_cq_) {} |
||||
|
||||
void SetUp() override { |
||||
int port = grpc_pick_unused_port_or_die(); |
||||
server_address_ << "localhost:" << port; |
||||
// Setup server
|
||||
ServerBuilder builder; |
||||
builder.AddPort(server_address_.str()); |
||||
builder.RegisterAsyncService(&service_); |
||||
server_ = builder.BuildAndStart(); |
||||
} |
||||
|
||||
void TearDown() override { server_->Shutdown(); } |
||||
|
||||
void ResetStub() { |
||||
std::shared_ptr<ChannelInterface> channel = |
||||
CreateChannel(server_address_.str(), ChannelArguments()); |
||||
stub_.reset(grpc::cpp::test::util::TestService::NewStub(channel)); |
||||
} |
||||
|
||||
void server_ok(int i) { |
||||
verify_ok(&srv_cq_, i, true); |
||||
} |
||||
void client_ok(int i) { |
||||
verify_ok(&cli_cq_, i , true); |
||||
} |
||||
void server_fail(int i) { |
||||
verify_ok(&srv_cq_, i, false); |
||||
} |
||||
void client_fail(int i) { |
||||
verify_ok(&cli_cq_, i, false); |
||||
} |
||||
|
||||
void SendRpc(int num_rpcs) { |
||||
for (int i = 0; i < num_rpcs; i++) { |
||||
EchoRequest send_request; |
||||
EchoRequest recv_request; |
||||
EchoResponse send_response; |
||||
EchoResponse recv_response; |
||||
Status recv_status; |
||||
|
||||
ClientContext cli_ctx; |
||||
ServerContext srv_ctx; |
||||
grpc::ServerAsyncResponseWriter<EchoResponse> response_writer(&srv_ctx); |
||||
|
||||
send_request.set_message("Hello"); |
||||
stub_->Echo( |
||||
&cli_ctx, send_request, &recv_response, &recv_status, &cli_cq_, tag(1)); |
||||
|
||||
service_.RequestEcho( |
||||
&srv_ctx, &recv_request, &response_writer, &srv_cq_, tag(2)); |
||||
|
||||
server_ok(2); |
||||
EXPECT_EQ(send_request.message(), recv_request.message()); |
||||
|
||||
send_response.set_message(recv_request.message()); |
||||
response_writer.Finish(send_response, Status::OK, tag(3)); |
||||
|
||||
server_ok(3); |
||||
|
||||
client_ok(1); |
||||
|
||||
EXPECT_EQ(send_response.message(), recv_response.message()); |
||||
EXPECT_TRUE(recv_status.IsOk()); |
||||
} |
||||
} |
||||
|
||||
CompletionQueue cli_cq_; |
||||
CompletionQueue srv_cq_; |
||||
std::unique_ptr<grpc::cpp::test::util::TestService::Stub> stub_; |
||||
std::unique_ptr<Server> server_; |
||||
grpc::cpp::test::util::TestService::AsyncService service_; |
||||
std::ostringstream server_address_; |
||||
}; |
||||
|
||||
TEST_F(AsyncEnd2endTest, SimpleRpc) { |
||||
ResetStub(); |
||||
SendRpc(1); |
||||
} |
||||
|
||||
TEST_F(AsyncEnd2endTest, SequentialRpcs) { |
||||
ResetStub(); |
||||
SendRpc(10); |
||||
} |
||||
|
||||
// Two pings and a final pong.
|
||||
TEST_F(AsyncEnd2endTest, SimpleClientStreaming) { |
||||
ResetStub(); |
||||
|
||||
EchoRequest send_request; |
||||
EchoRequest recv_request; |
||||
EchoResponse send_response; |
||||
EchoResponse recv_response; |
||||
Status recv_status; |
||||
ClientContext cli_ctx; |
||||
ServerContext srv_ctx; |
||||
ServerAsyncReader<EchoResponse, EchoRequest> srv_stream(&srv_ctx); |
||||
|
||||
send_request.set_message("Hello"); |
||||
ClientAsyncWriter<EchoRequest>* cli_stream = |
||||
stub_->RequestStream(&cli_ctx, &recv_response, &cli_cq_, tag(1)); |
||||
|
||||
service_.RequestRequestStream( |
||||
&srv_ctx, &srv_stream, &srv_cq_, tag(2)); |
||||
|
||||
server_ok(2); |
||||
client_ok(1); |
||||
|
||||
cli_stream->Write(send_request, tag(3)); |
||||
client_ok(3); |
||||
|
||||
srv_stream.Read(&recv_request, tag(4)); |
||||
server_ok(4); |
||||
EXPECT_EQ(send_request.message(), recv_request.message()); |
||||
|
||||
cli_stream->Write(send_request, tag(5)); |
||||
client_ok(5); |
||||
|
||||
srv_stream.Read(&recv_request, tag(6)); |
||||
server_ok(6); |
||||
|
||||
EXPECT_EQ(send_request.message(), recv_request.message()); |
||||
cli_stream->WritesDone(tag(7)); |
||||
client_ok(7); |
||||
|
||||
srv_stream.Read(&recv_request, tag(8)); |
||||
server_fail(8); |
||||
|
||||
send_response.set_message(recv_request.message()); |
||||
srv_stream.Finish(send_response, Status::OK, tag(9)); |
||||
server_ok(9); |
||||
|
||||
cli_stream->Finish(&recv_status, tag(10)); |
||||
client_ok(10); |
||||
|
||||
EXPECT_EQ(send_response.message(), recv_response.message()); |
||||
EXPECT_TRUE(recv_status.IsOk()); |
||||
} |
||||
|
||||
// One ping, two pongs.
|
||||
TEST_F(AsyncEnd2endTest, SimpleServerStreaming) { |
||||
ResetStub(); |
||||
|
||||
EchoRequest send_request; |
||||
EchoRequest recv_request; |
||||
EchoResponse send_response; |
||||
EchoResponse recv_response; |
||||
Status recv_status; |
||||
ClientContext cli_ctx; |
||||
ServerContext srv_ctx; |
||||
ServerAsyncWriter<EchoResponse> srv_stream(&srv_ctx); |
||||
|
||||
send_request.set_message("Hello"); |
||||
ClientAsyncReader<EchoResponse>* cli_stream = |
||||
stub_->ResponseStream(&cli_ctx, send_request, &cli_cq_, tag(1)); |
||||
|
||||
service_.RequestResponseStream( |
||||
&srv_ctx, &recv_request, &srv_stream, &srv_cq_, tag(2)); |
||||
|
||||
server_ok(2); |
||||
client_ok(1); |
||||
EXPECT_EQ(send_request.message(), recv_request.message()); |
||||
|
||||
send_response.set_message(recv_request.message()); |
||||
srv_stream.Write(send_response, tag(3)); |
||||
server_ok(3); |
||||
|
||||
cli_stream->Read(&recv_response, tag(4)); |
||||
client_ok(4); |
||||
EXPECT_EQ(send_response.message(), recv_response.message()); |
||||
|
||||
srv_stream.Write(send_response, tag(5)); |
||||
server_ok(5); |
||||
|
||||
cli_stream->Read(&recv_response, tag(6)); |
||||
client_ok(6); |
||||
EXPECT_EQ(send_response.message(), recv_response.message()); |
||||
|
||||
srv_stream.Finish(Status::OK, tag(7)); |
||||
server_ok(7); |
||||
|
||||
cli_stream->Read(&recv_response, tag(8)); |
||||
client_fail(8); |
||||
|
||||
cli_stream->Finish(&recv_status, tag(9)); |
||||
client_ok(9); |
||||
|
||||
EXPECT_TRUE(recv_status.IsOk()); |
||||
} |
||||
|
||||
// One ping, one pong.
|
||||
TEST_F(AsyncEnd2endTest, SimpleBidiStreaming) { |
||||
ResetStub(); |
||||
|
||||
EchoRequest send_request; |
||||
EchoRequest recv_request; |
||||
EchoResponse send_response; |
||||
EchoResponse recv_response; |
||||
Status recv_status; |
||||
ClientContext cli_ctx; |
||||
ServerContext srv_ctx; |
||||
ServerAsyncReaderWriter<EchoResponse, EchoRequest> srv_stream(&srv_ctx); |
||||
|
||||
send_request.set_message("Hello"); |
||||
ClientAsyncReaderWriter<EchoRequest, EchoResponse>* cli_stream = |
||||
stub_->BidiStream(&cli_ctx, &cli_cq_, tag(1)); |
||||
|
||||
service_.RequestBidiStream( |
||||
&srv_ctx, &srv_stream, &srv_cq_, tag(2)); |
||||
|
||||
server_ok(2); |
||||
client_ok(1); |
||||
|
||||
cli_stream->Write(send_request, tag(3)); |
||||
client_ok(3); |
||||
|
||||
srv_stream.Read(&recv_request, tag(4)); |
||||
server_ok(4); |
||||
EXPECT_EQ(send_request.message(), recv_request.message()); |
||||
|
||||
send_response.set_message(recv_request.message()); |
||||
srv_stream.Write(send_response, tag(5)); |
||||
server_ok(5); |
||||
|
||||
cli_stream->Read(&recv_response, tag(6)); |
||||
client_ok(6); |
||||
EXPECT_EQ(send_response.message(), recv_response.message()); |
||||
|
||||
cli_stream->WritesDone(tag(7)); |
||||
client_ok(7); |
||||
|
||||
srv_stream.Read(&recv_request, tag(8)); |
||||
server_fail(8); |
||||
|
||||
srv_stream.Finish(Status::OK, tag(9)); |
||||
server_ok(9); |
||||
|
||||
cli_stream->Finish(&recv_status, tag(10)); |
||||
client_ok(10); |
||||
|
||||
EXPECT_TRUE(recv_status.IsOk()); |
||||
} |
||||
|
||||
// Metadata tests
|
||||
TEST_F(AsyncEnd2endTest, ClientInitialMetadataRpc) { |
||||
ResetStub(); |
||||
|
||||
EchoRequest send_request; |
||||
EchoRequest recv_request; |
||||
EchoResponse send_response; |
||||
EchoResponse recv_response; |
||||
Status recv_status; |
||||
|
||||
ClientContext cli_ctx; |
||||
ServerContext srv_ctx; |
||||
grpc::ServerAsyncResponseWriter<EchoResponse> response_writer(&srv_ctx); |
||||
|
||||
send_request.set_message("Hello"); |
||||
std::pair<grpc::string, grpc::string> meta1("key1", "val1"); |
||||
std::pair<grpc::string, grpc::string> meta2("key2", "val2"); |
||||
cli_ctx.AddMetadata(meta1.first, meta1.second); |
||||
cli_ctx.AddMetadata(meta2.first, meta2.second); |
||||
|
||||
stub_->Echo( |
||||
&cli_ctx, send_request, &recv_response, &recv_status, &cli_cq_, tag(1)); |
||||
|
||||
service_.RequestEcho( |
||||
&srv_ctx, &recv_request, &response_writer, &srv_cq_, tag(2)); |
||||
server_ok(2); |
||||
EXPECT_EQ(send_request.message(), recv_request.message()); |
||||
auto client_initial_metadata = srv_ctx.client_metadata(); |
||||
EXPECT_EQ(meta1.second, client_initial_metadata.find(meta1.first)->second); |
||||
EXPECT_EQ(meta2.second, client_initial_metadata.find(meta2.first)->second); |
||||
EXPECT_EQ(2, client_initial_metadata.size()); |
||||
|
||||
send_response.set_message(recv_request.message()); |
||||
response_writer.Finish(send_response, Status::OK, tag(3)); |
||||
|
||||
server_ok(3); |
||||
|
||||
client_ok(1); |
||||
|
||||
EXPECT_EQ(send_response.message(), recv_response.message()); |
||||
EXPECT_TRUE(recv_status.IsOk()); |
||||
} |
||||
|
||||
} // namespace
|
||||
} // namespace testing
|
||||
} // namespace grpc
|
||||
|
||||
int main(int argc, char** argv) { |
||||
grpc_test_init(argc, argv); |
||||
grpc_init(); |
||||
::testing::InitGoogleTest(&argc, argv); |
||||
int result = RUN_ALL_TESTS(); |
||||
grpc_shutdown(); |
||||
google::protobuf::ShutdownProtobufLibrary(); |
||||
return result; |
||||
} |
@ -1,154 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2014, 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. |
||||
* |
||||
*/ |
||||
|
||||
#include "test/cpp/end2end/async_test_server.h" |
||||
|
||||
#include <chrono> |
||||
|
||||
#include <grpc/support/log.h> |
||||
#include "src/cpp/proto/proto_utils.h" |
||||
#include "test/cpp/util/echo.pb.h" |
||||
#include <grpc++/async_server.h> |
||||
#include <grpc++/async_server_context.h> |
||||
#include <grpc++/completion_queue.h> |
||||
#include <grpc++/status.h> |
||||
#include <gtest/gtest.h> |
||||
|
||||
using grpc::cpp::test::util::EchoRequest; |
||||
using grpc::cpp::test::util::EchoResponse; |
||||
|
||||
using std::chrono::duration_cast; |
||||
using std::chrono::microseconds; |
||||
using std::chrono::seconds; |
||||
using std::chrono::system_clock; |
||||
|
||||
namespace grpc { |
||||
namespace testing { |
||||
|
||||
AsyncTestServer::AsyncTestServer() : server_(&cq_), cq_drained_(false) {} |
||||
|
||||
AsyncTestServer::~AsyncTestServer() {} |
||||
|
||||
void AsyncTestServer::AddPort(const grpc::string& addr) { |
||||
server_.AddPort(addr); |
||||
} |
||||
|
||||
void AsyncTestServer::Start() { server_.Start(); } |
||||
|
||||
// Return true if deadline actual is within 0.5s from expected.
|
||||
bool DeadlineMatched(const system_clock::time_point& actual, |
||||
const system_clock::time_point& expected) { |
||||
microseconds diff_usecs = duration_cast<microseconds>(expected - actual); |
||||
gpr_log(GPR_INFO, "diff_usecs= %d", diff_usecs.count()); |
||||
return diff_usecs.count() < 500000 && diff_usecs.count() > -500000; |
||||
} |
||||
|
||||
void AsyncTestServer::RequestOneRpc() { server_.RequestOneRpc(); } |
||||
|
||||
void AsyncTestServer::MainLoop() { |
||||
EchoRequest request; |
||||
EchoResponse response; |
||||
void* tag = nullptr; |
||||
|
||||
RequestOneRpc(); |
||||
|
||||
while (true) { |
||||
CompletionQueue::CompletionType t = cq_.Next(&tag); |
||||
AsyncServerContext* server_context = static_cast<AsyncServerContext*>(tag); |
||||
switch (t) { |
||||
case CompletionQueue::SERVER_RPC_NEW: |
||||
gpr_log(GPR_INFO, "SERVER_RPC_NEW %p", server_context); |
||||
if (server_context) { |
||||
EXPECT_EQ(server_context->method(), "/foo"); |
||||
// TODO(ctiller): verify deadline
|
||||
server_context->Accept(cq_.cq()); |
||||
// Handle only one rpc at a time.
|
||||
RequestOneRpc(); |
||||
server_context->StartRead(&request); |
||||
} |
||||
break; |
||||
case CompletionQueue::RPC_END: |
||||
gpr_log(GPR_INFO, "RPC_END %p", server_context); |
||||
delete server_context; |
||||
break; |
||||
case CompletionQueue::SERVER_READ_OK: |
||||
gpr_log(GPR_INFO, "SERVER_READ_OK %p", server_context); |
||||
response.set_message(request.message()); |
||||
server_context->StartWrite(response, 0); |
||||
break; |
||||
case CompletionQueue::SERVER_READ_ERROR: |
||||
gpr_log(GPR_INFO, "SERVER_READ_ERROR %p", server_context); |
||||
server_context->StartWriteStatus(Status::OK); |
||||
break; |
||||
case CompletionQueue::HALFCLOSE_OK: |
||||
gpr_log(GPR_INFO, "HALFCLOSE_OK %p", server_context); |
||||
// Do nothing, just wait for RPC_END.
|
||||
break; |
||||
case CompletionQueue::SERVER_WRITE_OK: |
||||
gpr_log(GPR_INFO, "SERVER_WRITE_OK %p", server_context); |
||||
server_context->StartRead(&request); |
||||
break; |
||||
case CompletionQueue::SERVER_WRITE_ERROR: |
||||
EXPECT_TRUE(0); |
||||
break; |
||||
case CompletionQueue::QUEUE_CLOSED: { |
||||
gpr_log(GPR_INFO, "QUEUE_CLOSED"); |
||||
HandleQueueClosed(); |
||||
return; |
||||
} |
||||
default: |
||||
EXPECT_TRUE(0); |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
|
||||
void AsyncTestServer::HandleQueueClosed() { |
||||
std::unique_lock<std::mutex> lock(cq_drained_mu_); |
||||
cq_drained_ = true; |
||||
cq_drained_cv_.notify_all(); |
||||
} |
||||
|
||||
void AsyncTestServer::Shutdown() { |
||||
// The server need to be shut down before cq_ as grpc_server flushes all
|
||||
// pending requested calls to the completion queue at shutdown.
|
||||
server_.Shutdown(); |
||||
cq_.Shutdown(); |
||||
std::unique_lock<std::mutex> lock(cq_drained_mu_); |
||||
while (!cq_drained_) { |
||||
cq_drained_cv_.wait(lock); |
||||
} |
||||
} |
||||
|
||||
} // namespace testing
|
||||
} // namespace grpc
|
@ -1,75 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2014, 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. |
||||
* |
||||
*/ |
||||
|
||||
#ifndef __GRPCPP_TEST_END2END_ASYNC_TEST_SERVER_H__ |
||||
#define __GRPCPP_TEST_END2END_ASYNC_TEST_SERVER_H__ |
||||
|
||||
#include <condition_variable> |
||||
#include <mutex> |
||||
#include <string> |
||||
|
||||
#include <grpc++/async_server.h> |
||||
#include <grpc++/completion_queue.h> |
||||
|
||||
namespace grpc { |
||||
|
||||
namespace testing { |
||||
|
||||
class AsyncTestServer { |
||||
public: |
||||
AsyncTestServer(); |
||||
virtual ~AsyncTestServer(); |
||||
|
||||
void AddPort(const grpc::string& addr); |
||||
void Start(); |
||||
void RequestOneRpc(); |
||||
virtual void MainLoop(); |
||||
void Shutdown(); |
||||
|
||||
CompletionQueue* completion_queue() { return &cq_; } |
||||
|
||||
protected: |
||||
void HandleQueueClosed(); |
||||
|
||||
private: |
||||
CompletionQueue cq_; |
||||
AsyncServer server_; |
||||
bool cq_drained_; |
||||
std::mutex cq_drained_mu_; |
||||
std::condition_variable cq_drained_cv_; |
||||
}; |
||||
|
||||
} // namespace testing
|
||||
} // namespace grpc
|
||||
|
||||
#endif // __GRPCPP_TEST_END2END_ASYNC_TEST_SERVER_H__
|
@ -1,236 +0,0 @@ |
||||
/*
|
||||
* |
||||
* Copyright 2014, 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. |
||||
* |
||||
*/ |
||||
|
||||
#include <chrono> |
||||
#include <memory> |
||||
#include <sstream> |
||||
#include <string> |
||||
|
||||
#include <grpc/grpc.h> |
||||
#include <grpc/support/thd.h> |
||||
#include "test/cpp/util/echo.pb.h" |
||||
#include <grpc++/channel_arguments.h> |
||||
#include <grpc++/channel_interface.h> |
||||
#include <grpc++/client_context.h> |
||||
#include <grpc++/create_channel.h> |
||||
#include <grpc++/impl/internal_stub.h> |
||||
#include <grpc++/impl/rpc_method.h> |
||||
#include <grpc++/status.h> |
||||
#include <grpc++/stream.h> |
||||
#include "test/cpp/end2end/async_test_server.h" |
||||
#include "test/core/util/port.h" |
||||
#include <gtest/gtest.h> |
||||
|
||||
using grpc::cpp::test::util::EchoRequest; |
||||
using grpc::cpp::test::util::EchoResponse; |
||||
|
||||
using std::chrono::duration_cast; |
||||
using std::chrono::microseconds; |
||||
using std::chrono::seconds; |
||||
using std::chrono::system_clock; |
||||
|
||||
using grpc::testing::AsyncTestServer; |
||||
|
||||
namespace grpc { |
||||
namespace { |
||||
|
||||
void ServerLoop(void* s) { |
||||
AsyncTestServer* server = static_cast<AsyncTestServer*>(s); |
||||
server->MainLoop(); |
||||
} |
||||
|
||||
class End2endTest : public ::testing::Test { |
||||
protected: |
||||
void SetUp() override { |
||||
int port = grpc_pick_unused_port_or_die(); |
||||
// TODO(yangg) protobuf has a StringPrintf, maybe use that
|
||||
std::ostringstream oss; |
||||
oss << "[::]:" << port; |
||||
// Setup server
|
||||
server_.reset(new AsyncTestServer()); |
||||
server_->AddPort(oss.str()); |
||||
server_->Start(); |
||||
|
||||
RunServerThread(); |
||||
|
||||
// Setup client
|
||||
oss.str(""); |
||||
oss << "127.0.0.1:" << port; |
||||
std::shared_ptr<ChannelInterface> channel = |
||||
CreateChannel(oss.str(), ChannelArguments()); |
||||
stub_.set_channel(channel); |
||||
} |
||||
|
||||
void RunServerThread() { |
||||
gpr_thd_id id; |
||||
EXPECT_TRUE(gpr_thd_new(&id, ServerLoop, server_.get(), NULL)); |
||||
} |
||||
|
||||
void TearDown() override { server_->Shutdown(); } |
||||
|
||||
std::unique_ptr<AsyncTestServer> server_; |
||||
InternalStub stub_; |
||||
}; |
||||
|
||||
TEST_F(End2endTest, NoOpTest) { EXPECT_TRUE(stub_.channel() != nullptr); } |
||||
|
||||
TEST_F(End2endTest, SimpleRpc) { |
||||
EchoRequest request; |
||||
request.set_message("hello"); |
||||
EchoResponse result; |
||||
ClientContext context; |
||||
RpcMethod method("/foo"); |
||||
std::chrono::system_clock::time_point deadline = |
||||
std::chrono::system_clock::now() + std::chrono::seconds(10); |
||||
context.set_absolute_deadline(deadline); |
||||
Status s = |
||||
stub_.channel()->StartBlockingRpc(method, &context, request, &result); |
||||
EXPECT_EQ(result.message(), request.message()); |
||||
EXPECT_TRUE(s.IsOk()); |
||||
} |
||||
|
||||
TEST_F(End2endTest, KSequentialSimpleRpcs) { |
||||
int k = 3; |
||||
for (int i = 0; i < k; i++) { |
||||
EchoRequest request; |
||||
request.set_message("hello"); |
||||
EchoResponse result; |
||||
ClientContext context; |
||||
RpcMethod method("/foo"); |
||||
std::chrono::system_clock::time_point deadline = |
||||
std::chrono::system_clock::now() + std::chrono::seconds(10); |
||||
context.set_absolute_deadline(deadline); |
||||
Status s = |
||||
stub_.channel()->StartBlockingRpc(method, &context, request, &result); |
||||
EXPECT_EQ(result.message(), request.message()); |
||||
EXPECT_TRUE(s.IsOk()); |
||||
} |
||||
} |
||||
|
||||
TEST_F(End2endTest, OnePingpongBidiStream) { |
||||
EchoRequest request; |
||||
request.set_message("hello"); |
||||
EchoResponse result; |
||||
ClientContext context; |
||||
RpcMethod method("/foo", RpcMethod::RpcType::BIDI_STREAMING); |
||||
std::chrono::system_clock::time_point deadline = |
||||
std::chrono::system_clock::now() + std::chrono::seconds(10); |
||||
context.set_absolute_deadline(deadline); |
||||
StreamContextInterface* stream_interface = |
||||
stub_.channel()->CreateStream(method, &context, nullptr, nullptr); |
||||
std::unique_ptr<ClientReaderWriter<EchoRequest, EchoResponse>> stream( |
||||
new ClientReaderWriter<EchoRequest, EchoResponse>(stream_interface)); |
||||
EXPECT_TRUE(stream->Write(request)); |
||||
EXPECT_TRUE(stream->Read(&result)); |
||||
stream->WritesDone(); |
||||
EXPECT_FALSE(stream->Read(&result)); |
||||
Status s = stream->Wait(); |
||||
EXPECT_EQ(result.message(), request.message()); |
||||
EXPECT_TRUE(s.IsOk()); |
||||
} |
||||
|
||||
TEST_F(End2endTest, TwoPingpongBidiStream) { |
||||
EchoRequest request; |
||||
request.set_message("hello"); |
||||
EchoResponse result; |
||||
ClientContext context; |
||||
RpcMethod method("/foo", RpcMethod::RpcType::BIDI_STREAMING); |
||||
std::chrono::system_clock::time_point deadline = |
||||
std::chrono::system_clock::now() + std::chrono::seconds(10); |
||||
context.set_absolute_deadline(deadline); |
||||
StreamContextInterface* stream_interface = |
||||
stub_.channel()->CreateStream(method, &context, nullptr, nullptr); |
||||
std::unique_ptr<ClientReaderWriter<EchoRequest, EchoResponse>> stream( |
||||
new ClientReaderWriter<EchoRequest, EchoResponse>(stream_interface)); |
||||
EXPECT_TRUE(stream->Write(request)); |
||||
EXPECT_TRUE(stream->Read(&result)); |
||||
EXPECT_EQ(result.message(), request.message()); |
||||
EXPECT_TRUE(stream->Write(request)); |
||||
EXPECT_TRUE(stream->Read(&result)); |
||||
EXPECT_EQ(result.message(), request.message()); |
||||
stream->WritesDone(); |
||||
EXPECT_FALSE(stream->Read(&result)); |
||||
Status s = stream->Wait(); |
||||
EXPECT_TRUE(s.IsOk()); |
||||
} |
||||
|
||||
TEST_F(End2endTest, OnePingpongClientStream) { |
||||
EchoRequest request; |
||||
request.set_message("hello"); |
||||
EchoResponse result; |
||||
ClientContext context; |
||||
RpcMethod method("/foo", RpcMethod::RpcType::CLIENT_STREAMING); |
||||
std::chrono::system_clock::time_point deadline = |
||||
std::chrono::system_clock::now() + std::chrono::seconds(10); |
||||
context.set_absolute_deadline(deadline); |
||||
StreamContextInterface* stream_interface = |
||||
stub_.channel()->CreateStream(method, &context, nullptr, &result); |
||||
std::unique_ptr<ClientWriter<EchoRequest>> stream( |
||||
new ClientWriter<EchoRequest>(stream_interface)); |
||||
EXPECT_TRUE(stream->Write(request)); |
||||
stream->WritesDone(); |
||||
Status s = stream->Wait(); |
||||
EXPECT_EQ(result.message(), request.message()); |
||||
EXPECT_TRUE(s.IsOk()); |
||||
} |
||||
|
||||
TEST_F(End2endTest, OnePingpongServerStream) { |
||||
EchoRequest request; |
||||
request.set_message("hello"); |
||||
EchoResponse result; |
||||
ClientContext context; |
||||
RpcMethod method("/foo", RpcMethod::RpcType::SERVER_STREAMING); |
||||
std::chrono::system_clock::time_point deadline = |
||||
std::chrono::system_clock::now() + std::chrono::seconds(10); |
||||
context.set_absolute_deadline(deadline); |
||||
StreamContextInterface* stream_interface = |
||||
stub_.channel()->CreateStream(method, &context, &request, nullptr); |
||||
std::unique_ptr<ClientReader<EchoResponse>> stream( |
||||
new ClientReader<EchoResponse>(stream_interface)); |
||||
EXPECT_TRUE(stream->Read(&result)); |
||||
EXPECT_FALSE(stream->Read(nullptr)); |
||||
Status s = stream->Wait(); |
||||
EXPECT_EQ(result.message(), request.message()); |
||||
EXPECT_TRUE(s.IsOk()); |
||||
} |
||||
|
||||
} // namespace
|
||||
} // namespace grpc
|
||||
|
||||
int main(int argc, char** argv) { |
||||
grpc_init(); |
||||
::testing::InitGoogleTest(&argc, argv); |
||||
int result = RUN_ALL_TESTS(); |
||||
grpc_shutdown(); |
||||
return result; |
||||
} |
Loading…
Reference in new issue