diff options
Diffstat (limited to 'src')
45 files changed, 668 insertions, 530 deletions
diff --git a/src/compiler/cpp_generator.cc b/src/compiler/cpp_generator.cc index 735e7e58a8..a0c9d3d468 100644 --- a/src/compiler/cpp_generator.cc +++ b/src/compiler/cpp_generator.cc @@ -156,50 +156,16 @@ grpc::string GetHeaderIncludes(const grpc::protobuf::FileDescriptor *file, "#include <grpc++/impl/internal_stub.h>\n" "#include <grpc++/impl/rpc_method.h>\n" "#include <grpc++/impl/service_type.h>\n" + "#include <grpc++/async_unary_call.h>\n" "#include <grpc++/status.h>\n" + "#include <grpc++/stream.h>\n" "\n" "namespace grpc {\n" "class CompletionQueue;\n" "class ChannelInterface;\n" "class RpcService;\n" - "class ServerContext;\n"; - if (HasUnaryCalls(file)) { - temp.append( - "template <class OutMessage> class ClientAsyncResponseReader;\n"); - temp.append( - "template <class OutMessage> class ServerAsyncResponseWriter;\n"); - } - if (HasClientOnlyStreaming(file)) { - temp.append("template <class OutMessage> class ClientWriter;\n"); - temp.append("template <class InMessage> class ServerReader;\n"); - temp.append("template <class OutMessage> class ClientAsyncWriter;\n"); - temp.append( - "template <class OutMessage, class InMessage> class " - "ServerAsyncReader;\n"); - } - if (HasServerOnlyStreaming(file)) { - temp.append("template <class InMessage> class ClientReader;\n"); - temp.append("template <class OutMessage> class ServerWriter;\n"); - temp.append("template <class OutMessage> class ClientAsyncReader;\n"); - temp.append("template <class InMessage> class ServerAsyncWriter;\n"); - } - if (HasBidiStreaming(file)) { - temp.append( - "template <class OutMessage, class InMessage>\n" - "class ClientReaderWriter;\n"); - temp.append( - "template <class OutMessage, class InMessage>\n" - "class ServerReaderWriter;\n"); - temp.append( - "template <class OutMessage, class InMessage>\n" - "class ClientAsyncReaderWriter;\n"); - temp.append( - "template <class OutMessage, class InMessage>\n" - "class ServerAsyncReaderWriter;\n"); - } - temp.append("} // namespace grpc\n"); - - temp.append("\n"); + "class ServerContext;\n" + "} // namespace grpc\n\n"; if (!file->package().empty()) { std::vector<grpc::string> parts = @@ -216,54 +182,314 @@ grpc::string GetHeaderIncludes(const grpc::protobuf::FileDescriptor *file, return temp; } +void PrintHeaderClientMethodInterfaces(grpc::protobuf::io::Printer *printer, + const grpc::protobuf::MethodDescriptor *method, + std::map<grpc::string, grpc::string> *vars, + bool is_public) { + (*vars)["Method"] = method->name(); + (*vars)["Request"] = + grpc_cpp_generator::ClassName(method->input_type(), true); + (*vars)["Response"] = + grpc_cpp_generator::ClassName(method->output_type(), true); + + if (is_public) { + if (NoStreaming(method)) { + printer->Print( + *vars, + "virtual ::grpc::Status $Method$(::grpc::ClientContext* context, " + "const $Request$& request, $Response$* response) = 0;\n"); + printer->Print( + *vars, + "std::unique_ptr< " + "::grpc::ClientAsyncResponseReaderInterface< $Response$>> " + "Async$Method$(::grpc::ClientContext* context, " + "const $Request$& request, " + "::grpc::CompletionQueue* cq, void* tag) {\n"); + printer->Indent(); + printer->Print( + *vars, + "return std::unique_ptr< " + "::grpc::ClientAsyncResponseReaderInterface< $Response$>>(" + "Async$Method$Raw(context, request, cq, tag));\n"); + printer->Outdent(); + printer->Print("}\n"); + } else if (ClientOnlyStreaming(method)) { + printer->Print( + *vars, + "std::unique_ptr< ::grpc::ClientWriterInterface< $Request$>>" + " $Method$(" + "::grpc::ClientContext* context, $Response$* response) {\n"); + printer->Indent(); + printer->Print( + *vars, + "return std::unique_ptr< ::grpc::ClientWriterInterface< $Request$>>" + "($Method$Raw(context, response));\n"); + printer->Outdent(); + printer->Print("}\n"); + printer->Print( + *vars, + "std::unique_ptr< ::grpc::ClientAsyncWriterInterface< $Request$>>" + " Async$Method$(::grpc::ClientContext* context, $Response$* response, " + "::grpc::CompletionQueue* cq, void* tag) {\n"); + printer->Indent(); + printer->Print( + *vars, + "return std::unique_ptr< " + "::grpc::ClientAsyncWriterInterface< $Request$>>(" + "Async$Method$Raw(context, response, cq, tag));\n"); + printer->Outdent(); + printer->Print("}\n"); + } else if (ServerOnlyStreaming(method)) { + printer->Print( + *vars, + "std::unique_ptr< ::grpc::ClientReaderInterface< $Response$>>" + " $Method$(::grpc::ClientContext* context, const $Request$& request)" + " {\n"); + printer->Indent(); + printer->Print( + *vars, + "return std::unique_ptr< ::grpc::ClientReaderInterface< $Response$>>" + "($Method$Raw(context, request));\n"); + printer->Outdent(); + printer->Print("}\n"); + printer->Print( + *vars, + "std::unique_ptr< ::grpc::ClientAsyncReaderInterface< $Response$>> " + "Async$Method$(" + "::grpc::ClientContext* context, const $Request$& request, " + "::grpc::CompletionQueue* cq, void* tag) {\n"); + printer->Indent(); + printer->Print( + *vars, + "return std::unique_ptr< " + "::grpc::ClientAsyncReaderInterface< $Response$>>(" + "Async$Method$Raw(context, request, cq, tag));\n"); + printer->Outdent(); + printer->Print("}\n"); + } else if (BidiStreaming(method)) { + printer->Print( + *vars, + "std::unique_ptr< ::grpc::ClientReaderWriterInterface< $Request$, $Response$>> " + "$Method$(::grpc::ClientContext* context) {\n"); + printer->Indent(); + printer->Print( + *vars, + "return std::unique_ptr< " + "::grpc::ClientReaderWriterInterface< $Request$, $Response$>>(" + "$Method$Raw(context));\n"); + printer->Outdent(); + printer->Print("}\n"); + printer->Print( + *vars, + "std::unique_ptr< " + "::grpc::ClientAsyncReaderWriterInterface< $Request$, $Response$>> " + "Async$Method$(::grpc::ClientContext* context, " + "::grpc::CompletionQueue* cq, void* tag) {\n"); + printer->Indent(); + printer->Print( + *vars, + "return std::unique_ptr< " + "::grpc::ClientAsyncReaderWriterInterface< $Request$, $Response$>>(" + "Async$Method$Raw(context, cq, tag));\n"); + printer->Outdent(); + printer->Print("}\n"); + } + } else { + if (NoStreaming(method)) { + printer->Print( + *vars, + "virtual ::grpc::ClientAsyncResponseReaderInterface< $Response$>* " + "Async$Method$Raw(::grpc::ClientContext* context, " + "const $Request$& request, " + "::grpc::CompletionQueue* cq, void* tag) = 0;\n"); + } else if (ClientOnlyStreaming(method)) { + printer->Print( + *vars, + "virtual ::grpc::ClientWriterInterface< $Request$>*" + " $Method$Raw(" + "::grpc::ClientContext* context, $Response$* response) = 0;\n"); + printer->Print( + *vars, + "virtual ::grpc::ClientAsyncWriterInterface< $Request$>*" + " Async$Method$Raw(::grpc::ClientContext* context, " + "$Response$* response, " + "::grpc::CompletionQueue* cq, void* tag) = 0;\n"); + } else if (ServerOnlyStreaming(method)) { + printer->Print( + *vars, + "virtual ::grpc::ClientReaderInterface< $Response$>* $Method$Raw(" + "::grpc::ClientContext* context, const $Request$& request) = 0;\n"); + printer->Print( + *vars, + "virtual ::grpc::ClientAsyncReaderInterface< $Response$>* " + "Async$Method$Raw(" + "::grpc::ClientContext* context, const $Request$& request, " + "::grpc::CompletionQueue* cq, void* tag) = 0;\n"); + } else if (BidiStreaming(method)) { + printer->Print( + *vars, + "virtual ::grpc::ClientReaderWriterInterface< $Request$, $Response$>* " + "$Method$Raw(::grpc::ClientContext* context) = 0;\n"); + printer->Print( + *vars, + "virtual ::grpc::ClientAsyncReaderWriterInterface< " + "$Request$, $Response$>* " + "Async$Method$Raw(::grpc::ClientContext* context, " + "::grpc::CompletionQueue* cq, void* tag) = 0;\n"); + } + } +} + void PrintHeaderClientMethod(grpc::protobuf::io::Printer *printer, const grpc::protobuf::MethodDescriptor *method, - std::map<grpc::string, grpc::string> *vars) { + std::map<grpc::string, grpc::string> *vars, + bool is_public) { (*vars)["Method"] = method->name(); (*vars)["Request"] = grpc_cpp_generator::ClassName(method->input_type(), true); (*vars)["Response"] = grpc_cpp_generator::ClassName(method->output_type(), true); - if (NoStreaming(method)) { - printer->Print(*vars, - "::grpc::Status $Method$(::grpc::ClientContext* context, " - "const $Request$& request, $Response$* response);\n"); - printer->Print( - *vars, - "std::unique_ptr< ::grpc::ClientAsyncResponseReader< $Response$>> " - "Async$Method$(::grpc::ClientContext* context, " - "const $Request$& request, " - "::grpc::CompletionQueue* cq, void* tag);\n"); - } else if (ClientOnlyStreaming(method)) { - printer->Print( - *vars, - "std::unique_ptr< ::grpc::ClientWriter< $Request$>> $Method$(" - "::grpc::ClientContext* context, $Response$* response);\n"); - printer->Print( - *vars, - "std::unique_ptr< ::grpc::ClientAsyncWriter< $Request$>> Async$Method$(" - "::grpc::ClientContext* context, $Response$* response, " - "::grpc::CompletionQueue* cq, void* tag);\n"); - } else if (ServerOnlyStreaming(method)) { - printer->Print( - *vars, - "std::unique_ptr< ::grpc::ClientReader< $Response$>> $Method$(" - "::grpc::ClientContext* context, const $Request$& request);\n"); - printer->Print(*vars, - "std::unique_ptr< ::grpc::ClientAsyncReader< $Response$>> " - "Async$Method$(" - "::grpc::ClientContext* context, const $Request$& request, " - "::grpc::CompletionQueue* cq, void* tag);\n"); - } else if (BidiStreaming(method)) { - printer->Print( - *vars, - "std::unique_ptr< ::grpc::ClientReaderWriter< $Request$, $Response$>> " - "$Method$(::grpc::ClientContext* context);\n"); - printer->Print(*vars, - "std::unique_ptr< ::grpc::ClientAsyncReaderWriter< " - "$Request$, $Response$>> " - "Async$Method$(::grpc::ClientContext* context, " - "::grpc::CompletionQueue* cq, void* tag);\n"); + + if (is_public) { + if (NoStreaming(method)) { + printer->Print( + *vars, + "::grpc::Status $Method$(::grpc::ClientContext* context, " + "const $Request$& request, $Response$* response) GRPC_OVERRIDE;\n"); + printer->Print( + *vars, + "std::unique_ptr< ::grpc::ClientAsyncResponseReader< $Response$>> " + "Async$Method$(::grpc::ClientContext* context, " + "const $Request$& request, " + "::grpc::CompletionQueue* cq, void* tag) {\n"); + printer->Indent(); + printer->Print( + *vars, + "return std::unique_ptr< " + "::grpc::ClientAsyncResponseReader< $Response$>>(" + "Async$Method$Raw(context, request, cq, tag));\n"); + printer->Outdent(); + printer->Print("}\n"); + } else if (ClientOnlyStreaming(method)) { + printer->Print( + *vars, + "std::unique_ptr< ::grpc::ClientWriter< $Request$>>" + " $Method$(" + "::grpc::ClientContext* context, $Response$* response) {\n"); + printer->Indent(); + printer->Print( + *vars, + "return std::unique_ptr< ::grpc::ClientWriter< $Request$>>" + "($Method$Raw(context, response));\n"); + printer->Outdent(); + printer->Print("}\n"); + printer->Print( + *vars, + "std::unique_ptr< ::grpc::ClientAsyncWriter< $Request$>>" + " Async$Method$(::grpc::ClientContext* context, $Response$* response, " + "::grpc::CompletionQueue* cq, void* tag) {\n"); + printer->Indent(); + printer->Print( + *vars, + "return std::unique_ptr< ::grpc::ClientAsyncWriter< $Request$>>(" + "Async$Method$Raw(context, response, cq, tag));\n"); + printer->Outdent(); + printer->Print("}\n"); + } else if (ServerOnlyStreaming(method)) { + printer->Print( + *vars, + "std::unique_ptr< ::grpc::ClientReader< $Response$>>" + " $Method$(::grpc::ClientContext* context, const $Request$& request)" + " {\n"); + printer->Indent(); + printer->Print( + *vars, + "return std::unique_ptr< ::grpc::ClientReader< $Response$>>" + "($Method$Raw(context, request));\n"); + printer->Outdent(); + printer->Print("}\n"); + printer->Print( + *vars, + "std::unique_ptr< ::grpc::ClientAsyncReader< $Response$>> " + "Async$Method$(" + "::grpc::ClientContext* context, const $Request$& request, " + "::grpc::CompletionQueue* cq, void* tag) {\n"); + printer->Indent(); + printer->Print( + *vars, + "return std::unique_ptr< ::grpc::ClientAsyncReader< $Response$>>(" + "Async$Method$Raw(context, request, cq, tag));\n"); + printer->Outdent(); + printer->Print("}\n"); + } else if (BidiStreaming(method)) { + printer->Print( + *vars, + "std::unique_ptr< ::grpc::ClientReaderWriter< $Request$, $Response$>>" + " $Method$(::grpc::ClientContext* context) {\n"); + printer->Indent(); + printer->Print( + *vars, + "return std::unique_ptr< " + "::grpc::ClientReaderWriter< $Request$, $Response$>>(" + "$Method$Raw(context));\n"); + printer->Outdent(); + printer->Print("}\n"); + printer->Print( + *vars, + "std::unique_ptr< ::grpc::ClientAsyncReaderWriter< " + "$Request$, $Response$>> " + "Async$Method$(::grpc::ClientContext* context, " + "::grpc::CompletionQueue* cq, void* tag) {\n"); + printer->Indent(); + printer->Print( + *vars, + "return std::unique_ptr< " + "::grpc::ClientAsyncReaderWriter< $Request$, $Response$>>(" + "Async$Method$Raw(context, cq, tag));\n"); + printer->Outdent(); + printer->Print("}\n"); + } + } else { + if (NoStreaming(method)) { + printer->Print( + *vars, + "::grpc::ClientAsyncResponseReader< $Response$>* " + "Async$Method$Raw(::grpc::ClientContext* context, " + "const $Request$& request, " + "::grpc::CompletionQueue* cq, void* tag) GRPC_OVERRIDE;\n"); + } else if (ClientOnlyStreaming(method)) { + printer->Print( + *vars, + "::grpc::ClientWriter< $Request$>* $Method$Raw(" + "::grpc::ClientContext* context, $Response$* response) " + "GRPC_OVERRIDE;\n"); + printer->Print( + *vars, + "::grpc::ClientAsyncWriter< $Request$>* Async$Method$Raw(" + "::grpc::ClientContext* context, $Response$* response, " + "::grpc::CompletionQueue* cq, void* tag) GRPC_OVERRIDE;\n"); + } else if (ServerOnlyStreaming(method)) { + printer->Print( + *vars, + "::grpc::ClientReader< $Response$>* $Method$Raw(" + "::grpc::ClientContext* context, const $Request$& request)" + " GRPC_OVERRIDE;\n"); + printer->Print( + *vars, + "::grpc::ClientAsyncReader< $Response$>* Async$Method$Raw(" + "::grpc::ClientContext* context, const $Request$& request, " + "::grpc::CompletionQueue* cq, void* tag) GRPC_OVERRIDE;\n"); + } else if (BidiStreaming(method)) { + printer->Print( + *vars, + "::grpc::ClientReaderWriter< $Request$, $Response$>* " + "$Method$Raw(::grpc::ClientContext* context) GRPC_OVERRIDE;\n"); + printer->Print( + *vars, + "::grpc::ClientAsyncReaderWriter< $Request$, $Response$>* " + "Async$Method$Raw(::grpc::ClientContext* context, " + "::grpc::CompletionQueue* cq, void* tag) GRPC_OVERRIDE;\n"); + } } } @@ -357,18 +583,37 @@ void PrintHeaderService(grpc::protobuf::io::Printer *printer, // Client side printer->Print( - "class Stub GRPC_FINAL : public ::grpc::InternalStub {\n" + "class StubInterface {\n" " public:\n"); printer->Indent(); + printer->Print("virtual ~StubInterface() {}\n"); + for (int i = 0; i < service->method_count(); ++i) { + PrintHeaderClientMethodInterfaces(printer, service->method(i), vars, true); + } + printer->Outdent(); + printer->Print("private:\n"); + printer->Indent(); + for (int i = 0; i < service->method_count(); ++i) { + PrintHeaderClientMethodInterfaces(printer, service->method(i), vars, false); + } + printer->Outdent(); + printer->Print("};\n"); + printer->Print( + "class Stub GRPC_FINAL : public StubInterface," + " public ::grpc::InternalStub {\n public:\n"); + printer->Indent(); printer->Print( "Stub(const std::shared_ptr< ::grpc::ChannelInterface>& channel);\n"); for (int i = 0; i < service->method_count(); ++i) { - PrintHeaderClientMethod(printer, service->method(i), vars); + PrintHeaderClientMethod(printer, service->method(i), vars, true); } printer->Outdent(); - printer->Print(" private:\n"); + printer->Print("\n private:\n"); printer->Indent(); for (int i = 0; i < service->method_count(); ++i) { + PrintHeaderClientMethod(printer, service->method(i), vars, false); + } + for (int i = 0; i < service->method_count(); ++i) { PrintHeaderClientMethodData(printer, service->method(i), vars); } printer->Outdent(); @@ -535,93 +780,85 @@ void PrintSourceClientMethod(grpc::protobuf::io::Printer *printer, "}\n\n"); printer->Print( *vars, - "std::unique_ptr< ::grpc::ClientAsyncResponseReader< $Response$>> " - "$ns$$Service$::Stub::Async$Method$(::grpc::ClientContext* context, " + "::grpc::ClientAsyncResponseReader< $Response$>* " + "$ns$$Service$::Stub::Async$Method$Raw(::grpc::ClientContext* context, " "const $Request$& request, " "::grpc::CompletionQueue* cq, void* tag) {\n"); printer->Print(*vars, - " return std::unique_ptr< " - "::grpc::ClientAsyncResponseReader< $Response$>>(new " + " return new " "::grpc::ClientAsyncResponseReader< $Response$>(" "channel(), cq, " "rpcmethod_$Method$_, " - "context, request, tag));\n" + "context, request, tag);\n" "}\n\n"); } else if (ClientOnlyStreaming(method)) { printer->Print(*vars, - "std::unique_ptr< ::grpc::ClientWriter< $Request$>> " - "$ns$$Service$::Stub::$Method$(" + "::grpc::ClientWriter< $Request$>* " + "$ns$$Service$::Stub::$Method$Raw(" "::grpc::ClientContext* context, $Response$* response) {\n"); printer->Print(*vars, - " return std::unique_ptr< ::grpc::ClientWriter< " - "$Request$>>(new ::grpc::ClientWriter< $Request$>(" - "channel()," + " return new ::grpc::ClientWriter< $Request$>(" + "channel(), " "rpcmethod_$Method$_, " - "context, response));\n" + "context, response);\n" "}\n\n"); printer->Print(*vars, - "std::unique_ptr< ::grpc::ClientAsyncWriter< $Request$>> " - "$ns$$Service$::Stub::Async$Method$(" + "::grpc::ClientAsyncWriter< $Request$>* " + "$ns$$Service$::Stub::Async$Method$Raw(" "::grpc::ClientContext* context, $Response$* response, " "::grpc::CompletionQueue* cq, void* tag) {\n"); printer->Print(*vars, - " return std::unique_ptr< ::grpc::ClientAsyncWriter< " - "$Request$>>(new ::grpc::ClientAsyncWriter< $Request$>(" + " return new ::grpc::ClientAsyncWriter< $Request$>(" "channel(), cq, " "rpcmethod_$Method$_, " - "context, response, tag));\n" + "context, response, tag);\n" "}\n\n"); } else if (ServerOnlyStreaming(method)) { printer->Print( *vars, - "std::unique_ptr< ::grpc::ClientReader< $Response$>> " - "$ns$$Service$::Stub::$Method$(" + "::grpc::ClientReader< $Response$>* " + "$ns$$Service$::Stub::$Method$Raw(" "::grpc::ClientContext* context, const $Request$& request) {\n"); printer->Print(*vars, - " return std::unique_ptr< ::grpc::ClientReader< " - "$Response$>>(new ::grpc::ClientReader< $Response$>(" - "channel()," + " return new ::grpc::ClientReader< $Response$>(" + "channel(), " "rpcmethod_$Method$_, " - "context, request));\n" + "context, request);\n" "}\n\n"); printer->Print(*vars, - "std::unique_ptr< ::grpc::ClientAsyncReader< $Response$>> " - "$ns$$Service$::Stub::Async$Method$(" + "::grpc::ClientAsyncReader< $Response$>* " + "$ns$$Service$::Stub::Async$Method$Raw(" "::grpc::ClientContext* context, const $Request$& request, " "::grpc::CompletionQueue* cq, void* tag) {\n"); printer->Print(*vars, - " return std::unique_ptr< ::grpc::ClientAsyncReader< " - "$Response$>>(new ::grpc::ClientAsyncReader< $Response$>(" + " return new ::grpc::ClientAsyncReader< $Response$>(" "channel(), cq, " "rpcmethod_$Method$_, " - "context, request, tag));\n" + "context, request, tag);\n" "}\n\n"); } else if (BidiStreaming(method)) { printer->Print( *vars, - "std::unique_ptr< ::grpc::ClientReaderWriter< $Request$, $Response$>> " - "$ns$$Service$::Stub::$Method$(::grpc::ClientContext* context) {\n"); + "::grpc::ClientReaderWriter< $Request$, $Response$>* " + "$ns$$Service$::Stub::$Method$Raw(::grpc::ClientContext* context) {\n"); printer->Print(*vars, - " return std::unique_ptr< ::grpc::ClientReaderWriter< " - "$Request$, $Response$>>(new ::grpc::ClientReaderWriter< " + " return new ::grpc::ClientReaderWriter< " "$Request$, $Response$>(" - "channel()," + "channel(), " "rpcmethod_$Method$_, " - "context));\n" + "context);\n" "}\n\n"); printer->Print( *vars, - "std::unique_ptr< ::grpc::ClientAsyncReaderWriter< " - "$Request$, $Response$>> " - "$ns$$Service$::Stub::Async$Method$(::grpc::ClientContext* context, " + "::grpc::ClientAsyncReaderWriter< $Request$, $Response$>* " + "$ns$$Service$::Stub::Async$Method$Raw(::grpc::ClientContext* context, " "::grpc::CompletionQueue* cq, void* tag) {\n"); printer->Print(*vars, - " return std::unique_ptr< ::grpc::ClientAsyncReaderWriter< " - "$Request$, $Response$>>(new " + " return new " "::grpc::ClientAsyncReaderWriter< $Request$, $Response$>(" "channel(), cq, " "rpcmethod_$Method$_, " - "context, tag));\n" + "context, tag);\n" "}\n\n"); } } diff --git a/src/core/iomgr/socket_utils_common_posix.c b/src/core/iomgr/socket_utils_common_posix.c index 3c8cafa315..a9af594700 100644 --- a/src/core/iomgr/socket_utils_common_posix.c +++ b/src/core/iomgr/socket_utils_common_posix.c @@ -76,6 +76,19 @@ int grpc_set_socket_nonblocking(int fd, int non_blocking) { return 1; } +int grpc_set_socket_no_sigpipe_if_possible(int fd) { +#ifdef GPR_HAVE_SO_NOSIGPIPE + int val = 1; + int newval; + socklen_t intlen = sizeof(newval); + return 0 == setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &val, sizeof(val)) && + 0 == getsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &newval, &intlen) && + (newval != 0) == val; +#else + return 1; +#endif +} + /* set a socket to close on exec */ int grpc_set_socket_cloexec(int fd, int close_on_exec) { int oldflags = fcntl(fd, F_GETFD, 0); diff --git a/src/core/iomgr/socket_utils_posix.h b/src/core/iomgr/socket_utils_posix.h index c161082afc..d2a315b462 100644 --- a/src/core/iomgr/socket_utils_posix.h +++ b/src/core/iomgr/socket_utils_posix.h @@ -63,6 +63,11 @@ int grpc_set_socket_low_latency(int fd, int low_latency); state to library users, we turn off IPv6 sockets. */ int grpc_ipv6_loopback_available(void); +/* Tries to set SO_NOSIGPIPE if available on this platform. + Returns 1 on success, 0 on failure. + If SO_NO_SIGPIPE is not available, returns 1. */ +int grpc_set_socket_no_sigpipe_if_possible(int fd); + /* An enum to keep track of IPv4/IPv6 socket modes. Currently, this information is only used when a socket is first created, but diff --git a/src/core/iomgr/tcp_client_posix.c b/src/core/iomgr/tcp_client_posix.c index e20cc3d1b2..2401fe00e4 100644 --- a/src/core/iomgr/tcp_client_posix.c +++ b/src/core/iomgr/tcp_client_posix.c @@ -69,7 +69,8 @@ static int prepare_socket(const struct sockaddr *addr, int fd) { } if (!grpc_set_socket_nonblocking(fd, 1) || !grpc_set_socket_cloexec(fd, 1) || - (addr->sa_family != AF_UNIX && !grpc_set_socket_low_latency(fd, 1))) { + (addr->sa_family != AF_UNIX && !grpc_set_socket_low_latency(fd, 1)) || + !grpc_set_socket_no_sigpipe_if_possible(fd)) { gpr_log(GPR_ERROR, "Unable to configure socket %d: %s", fd, strerror(errno)); goto error; diff --git a/src/core/iomgr/tcp_posix.c b/src/core/iomgr/tcp_posix.c index 06725fbc89..f7dae5f86c 100644 --- a/src/core/iomgr/tcp_posix.c +++ b/src/core/iomgr/tcp_posix.c @@ -53,6 +53,12 @@ #include <grpc/support/sync.h> #include <grpc/support/time.h> +#ifdef GPR_HAVE_MSG_NOSIGNAL +#define SENDMSG_FLAGS MSG_NOSIGNAL +#else +#define SENDMSG_FLAGS 0 +#endif + /* Holds a slice array and associated state. */ typedef struct grpc_tcp_slice_state { gpr_slice *slices; /* Array of slices */ @@ -461,7 +467,7 @@ static grpc_endpoint_write_status grpc_tcp_flush(grpc_tcp *tcp) { GRPC_TIMER_BEGIN(GRPC_PTAG_SENDMSG, 0); do { /* TODO(klempner): Cork if this is a partial write */ - sent_length = sendmsg(tcp->fd, &msg, 0); + sent_length = sendmsg(tcp->fd, &msg, SENDMSG_FLAGS); } while (sent_length < 0 && errno == EINTR); GRPC_TIMER_END(GRPC_PTAG_SENDMSG, 0); diff --git a/src/core/iomgr/tcp_server_posix.c b/src/core/iomgr/tcp_server_posix.c index 7e31f2d7a5..d1cd8a769c 100644 --- a/src/core/iomgr/tcp_server_posix.c +++ b/src/core/iomgr/tcp_server_posix.c @@ -235,7 +235,8 @@ static int prepare_socket(int fd, const struct sockaddr *addr, int addr_len) { if (!grpc_set_socket_nonblocking(fd, 1) || !grpc_set_socket_cloexec(fd, 1) || (addr->sa_family != AF_UNIX && (!grpc_set_socket_low_latency(fd, 1) || - !grpc_set_socket_reuse_addr(fd, 1)))) { + !grpc_set_socket_reuse_addr(fd, 1))) || + !grpc_set_socket_no_sigpipe_if_possible(fd)) { gpr_log(GPR_ERROR, "Unable to configure socket %d: %s", fd, strerror(errno)); goto error; @@ -296,6 +297,8 @@ static void on_read(void *arg, int success) { } } + grpc_set_socket_no_sigpipe_if_possible(fd); + sp->server->cb( sp->server->cb_arg, grpc_tcp_create(grpc_fd_create(fd), GRPC_TCP_DEFAULT_READ_SLICE_SIZE)); diff --git a/src/core/surface/call.c b/src/core/surface/call.c index 7ab9142947..9ee91785e8 100644 --- a/src/core/surface/call.c +++ b/src/core/surface/call.c @@ -739,14 +739,9 @@ static void call_on_done_recv(void *pc, int success) { GRPC_TIMER_BEGIN(GRPC_PTAG_CALL_ON_DONE_RECV, 0); } -static grpc_mdelem_list chain_metadata_from_app(grpc_call *call, size_t count, - grpc_metadata *metadata) { +static int prepare_application_metadata(grpc_call *call, size_t count, + grpc_metadata *metadata) { size_t i; - grpc_mdelem_list out; - if (count == 0) { - out.head = out.tail = NULL; - return out; - } for (i = 0; i < count; i++) { grpc_metadata *md = &metadata[i]; grpc_metadata *next_md = (i == count - 1) ? NULL : &metadata[i + 1]; @@ -756,9 +751,27 @@ static grpc_mdelem_list chain_metadata_from_app(grpc_call *call, size_t count, l->md = grpc_mdelem_from_string_and_buffer(call->metadata_context, md->key, (const gpr_uint8 *)md->value, md->value_length); + if (!grpc_mdstr_is_legal_header(l->md->key)) { + gpr_log(GPR_ERROR, "attempt to send invalid metadata key"); + return 0; + } else if (!grpc_mdstr_is_bin_suffixed(l->md->key) && + !grpc_mdstr_is_legal_header(l->md->value)) { + gpr_log(GPR_ERROR, "attempt to send invalid metadata value"); + return 0; + } l->next = next_md ? (grpc_linked_mdelem *)&next_md->internal_data : NULL; l->prev = prev_md ? (grpc_linked_mdelem *)&prev_md->internal_data : NULL; } + return 1; +} + +static grpc_mdelem_list chain_metadata_from_app(grpc_call *call, size_t count, + grpc_metadata *metadata) { + grpc_mdelem_list out; + if (count == 0) { + out.head = out.tail = NULL; + return out; + } out.head = (grpc_linked_mdelem *)&(metadata[0].internal_data); out.tail = (grpc_linked_mdelem *)&(metadata[count - 1].internal_data); return out; @@ -954,8 +967,16 @@ static grpc_call_error start_ioreq(grpc_call *call, const grpc_ioreq *reqs, } else if (call->request_set[op] == REQSET_DONE) { return start_ioreq_error(call, have_ops, GRPC_CALL_ERROR_ALREADY_INVOKED); } - have_ops |= 1u << op; data = reqs[i].data; + if (op == GRPC_IOREQ_SEND_INITIAL_METADATA || + op == GRPC_IOREQ_SEND_TRAILING_METADATA) { + if (!prepare_application_metadata(call, data.send_metadata.count, + data.send_metadata.metadata)) { + return start_ioreq_error(call, have_ops, + GRPC_CALL_ERROR_INVALID_METADATA); + } + } + have_ops |= 1u << op; call->request_data[op] = data; call->request_set[op] = set; diff --git a/src/core/transport/chttp2_transport.c b/src/core/transport/chttp2_transport.c index e536438646..a6f9f782a1 100644 --- a/src/core/transport/chttp2_transport.c +++ b/src/core/transport/chttp2_transport.c @@ -823,24 +823,23 @@ static void unlock(transport *t) { finish_reads(t); /* gather any callbacks that need to be made */ - if (!t->calling_back && cb) { - perform_callbacks = prepare_callbacks(t); - if (perform_callbacks) { - t->calling_back = 1; - } - if (t->error_state == ERROR_STATE_SEEN && !t->writing) { - call_closed = 1; - t->calling_back = 1; - t->cb = NULL; /* no more callbacks */ - t->error_state = ERROR_STATE_NOTIFIED; - } - if (t->num_pending_goaways) { - goaways = t->pending_goaways; - num_goaways = t->num_pending_goaways; - t->pending_goaways = NULL; - t->num_pending_goaways = 0; - t->cap_pending_goaways = 0; - t->calling_back = 1; + if (!t->calling_back) { + t->calling_back = perform_callbacks = prepare_callbacks(t); + if (cb) { + if (t->error_state == ERROR_STATE_SEEN && !t->writing) { + call_closed = 1; + t->calling_back = 1; + t->cb = NULL; /* no more callbacks */ + t->error_state = ERROR_STATE_NOTIFIED; + } + if (t->num_pending_goaways) { + goaways = t->pending_goaways; + num_goaways = t->num_pending_goaways; + t->pending_goaways = NULL; + t->num_pending_goaways = 0; + t->cap_pending_goaways = 0; + t->calling_back = 1; + } } } diff --git a/src/core/transport/metadata.c b/src/core/transport/metadata.c index 74e94b2c24..c80d67823f 100644 --- a/src/core/transport/metadata.c +++ b/src/core/transport/metadata.c @@ -569,3 +569,19 @@ void grpc_mdctx_locked_mdelem_unref(grpc_mdctx *ctx, grpc_mdelem *gmd) { } void grpc_mdctx_unlock(grpc_mdctx *ctx) { unlock(ctx); } + +int grpc_mdstr_is_legal_header(grpc_mdstr *s) { + /* TODO(ctiller): consider caching this, or computing it on construction */ + const gpr_uint8 *p = GPR_SLICE_START_PTR(s->slice); + const gpr_uint8 *e = GPR_SLICE_END_PTR(s->slice); + for (; p != e; p++) { + if (*p < 32 || *p > 126) return 0; + } + return 1; +} + +int grpc_mdstr_is_bin_suffixed(grpc_mdstr *s) { + /* TODO(ctiller): consider caching this */ + return grpc_is_binary_header((const char *)GPR_SLICE_START_PTR(s->slice), + GPR_SLICE_LENGTH(s->slice)); +} diff --git a/src/core/transport/metadata.h b/src/core/transport/metadata.h index 21b8ae2b78..e7508718f5 100644 --- a/src/core/transport/metadata.h +++ b/src/core/transport/metadata.h @@ -135,6 +135,9 @@ void grpc_mdelem_unref(grpc_mdelem *md); Does not promise that the returned string has no embedded nulls however. */ const char *grpc_mdstr_as_c_string(grpc_mdstr *s); +int grpc_mdstr_is_legal_header(grpc_mdstr *s); +int grpc_mdstr_is_bin_suffixed(grpc_mdstr *s); + /* Batch mode metadata functions. These API's have equivalents above, but allow taking the mdctx just once, performing a bunch of work, and then leaving the mdctx. */ diff --git a/src/cpp/server/server.cc b/src/cpp/server/server.cc index 08c956601c..1ff9ff4b32 100644 --- a/src/cpp/server/server.cc +++ b/src/cpp/server/server.cc @@ -446,8 +446,12 @@ void Server::RunRpc() { ScheduleCallback(); if (ok) { SyncRequest::CallData cd(this, mrd); - mrd->Request(server_); - + { + grpc::unique_lock<grpc::mutex> lock(mu_); + if (!shutdown_) { + mrd->Request(server_); + } + } cd.Run(); } } diff --git a/src/csharp/Grpc.Core.Tests/ClientServerTest.cs b/src/csharp/Grpc.Core.Tests/ClientServerTest.cs index caa6220f2c..b69b933aba 100644 --- a/src/csharp/Grpc.Core.Tests/ClientServerTest.cs +++ b/src/csharp/Grpc.Core.Tests/ClientServerTest.cs @@ -84,7 +84,7 @@ namespace Grpc.Core.Tests { server = new Server(); server.AddServiceDefinition(ServiceDefinition); - int port = server.AddListeningPort(Host + ":0"); + int port = server.AddListeningPort(Host, Server.PickUnusedPort); server.Start(); channel = new Channel(Host + ":" + port); } @@ -220,7 +220,7 @@ namespace Grpc.Core.Tests } } - private static async Task<string> EchoHandler(string request) + private static async Task<string> EchoHandler(ServerCallContext context, string request) { if (request == "THROW") { @@ -229,7 +229,7 @@ namespace Grpc.Core.Tests return request; } - private static async Task<string> ConcatAndEchoHandler(IAsyncStreamReader<string> requestStream) + private static async Task<string> ConcatAndEchoHandler(ServerCallContext context, IAsyncStreamReader<string> requestStream) { string result = ""; await requestStream.ForEach(async (request) => diff --git a/src/csharp/Grpc.Core.Tests/ServerTest.cs b/src/csharp/Grpc.Core.Tests/ServerTest.cs index 2a1855da67..02c773c9cc 100644 --- a/src/csharp/Grpc.Core.Tests/ServerTest.cs +++ b/src/csharp/Grpc.Core.Tests/ServerTest.cs @@ -47,7 +47,7 @@ namespace Grpc.Core.Tests GrpcEnvironment.Initialize(); Server server = new Server(); - server.AddListeningPort("localhost:0"); + server.AddListeningPort("localhost", Server.PickUnusedPort); server.Start(); server.ShutdownAsync().Wait(); diff --git a/src/csharp/Grpc.Core/AsyncClientStreamingCall.cs b/src/csharp/Grpc.Core/AsyncClientStreamingCall.cs index e81ce01ebb..b95776f66d 100644 --- a/src/csharp/Grpc.Core/AsyncClientStreamingCall.cs +++ b/src/csharp/Grpc.Core/AsyncClientStreamingCall.cs @@ -40,7 +40,9 @@ namespace Grpc.Core /// <summary> /// Return type for client streaming calls. /// </summary> - public struct AsyncClientStreamingCall<TRequest, TResponse> + public sealed class AsyncClientStreamingCall<TRequest, TResponse> + where TRequest : class + where TResponse : class { readonly IClientStreamWriter<TRequest> requestStream; readonly Task<TResponse> result; diff --git a/src/csharp/Grpc.Core/AsyncDuplexStreamingCall.cs b/src/csharp/Grpc.Core/AsyncDuplexStreamingCall.cs index 1cb30f4779..ee05437416 100644 --- a/src/csharp/Grpc.Core/AsyncDuplexStreamingCall.cs +++ b/src/csharp/Grpc.Core/AsyncDuplexStreamingCall.cs @@ -40,7 +40,9 @@ namespace Grpc.Core /// <summary> /// Return type for bidirectional streaming calls. /// </summary> - public struct AsyncDuplexStreamingCall<TRequest, TResponse> + public sealed class AsyncDuplexStreamingCall<TRequest, TResponse> + where TRequest : class + where TResponse : class { readonly IClientStreamWriter<TRequest> requestStream; readonly IAsyncStreamReader<TResponse> responseStream; diff --git a/src/csharp/Grpc.Core/AsyncServerStreamingCall.cs b/src/csharp/Grpc.Core/AsyncServerStreamingCall.cs index d614916fb7..73b9614985 100644 --- a/src/csharp/Grpc.Core/AsyncServerStreamingCall.cs +++ b/src/csharp/Grpc.Core/AsyncServerStreamingCall.cs @@ -40,7 +40,8 @@ namespace Grpc.Core /// <summary> /// Return type for server streaming calls. /// </summary> - public struct AsyncServerStreamingCall<TResponse> + public sealed class AsyncServerStreamingCall<TResponse> + where TResponse : class { readonly IAsyncStreamReader<TResponse> responseStream; diff --git a/src/csharp/Grpc.Core/Call.cs b/src/csharp/Grpc.Core/Call.cs index 070dfb569d..771cc083da 100644 --- a/src/csharp/Grpc.Core/Call.cs +++ b/src/csharp/Grpc.Core/Call.cs @@ -41,6 +41,8 @@ namespace Grpc.Core /// Abstraction of a call to be invoked on a client. /// </summary> public class Call<TRequest, TResponse> + where TRequest : class + where TResponse : class { readonly string name; readonly Marshaller<TRequest> requestMarshaller; diff --git a/src/csharp/Grpc.Core/Calls.cs b/src/csharp/Grpc.Core/Calls.cs index a8d2b9498e..ba42a2d4f8 100644 --- a/src/csharp/Grpc.Core/Calls.cs +++ b/src/csharp/Grpc.Core/Calls.cs @@ -44,6 +44,8 @@ namespace Grpc.Core public static class Calls { public static TResponse BlockingUnaryCall<TRequest, TResponse>(Call<TRequest, TResponse> call, TRequest req, CancellationToken token) + where TRequest : class + where TResponse : class { var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestMarshaller.Serializer, call.ResponseMarshaller.Deserializer); // TODO(jtattermusch): this gives a race that cancellation can be requested before the call even starts. @@ -52,6 +54,8 @@ namespace Grpc.Core } public static async Task<TResponse> AsyncUnaryCall<TRequest, TResponse>(Call<TRequest, TResponse> call, TRequest req, CancellationToken token) + where TRequest : class + where TResponse : class { var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestMarshaller.Serializer, call.ResponseMarshaller.Deserializer); asyncCall.Initialize(call.Channel, GetCompletionQueue(), call.Name); @@ -61,6 +65,8 @@ namespace Grpc.Core } public static AsyncServerStreamingCall<TResponse> AsyncServerStreamingCall<TRequest, TResponse>(Call<TRequest, TResponse> call, TRequest req, CancellationToken token) + where TRequest : class + where TResponse : class { var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestMarshaller.Serializer, call.ResponseMarshaller.Deserializer); asyncCall.Initialize(call.Channel, GetCompletionQueue(), call.Name); @@ -71,6 +77,8 @@ namespace Grpc.Core } public static AsyncClientStreamingCall<TRequest, TResponse> AsyncClientStreamingCall<TRequest, TResponse>(Call<TRequest, TResponse> call, CancellationToken token) + where TRequest : class + where TResponse : class { var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestMarshaller.Serializer, call.ResponseMarshaller.Deserializer); asyncCall.Initialize(call.Channel, GetCompletionQueue(), call.Name); @@ -81,6 +89,8 @@ namespace Grpc.Core } public static AsyncDuplexStreamingCall<TRequest, TResponse> AsyncDuplexStreamingCall<TRequest, TResponse>(Call<TRequest, TResponse> call, CancellationToken token) + where TRequest : class + where TResponse : class { var asyncCall = new AsyncCall<TRequest, TResponse>(call.RequestMarshaller.Serializer, call.ResponseMarshaller.Deserializer); asyncCall.Initialize(call.Channel, GetCompletionQueue(), call.Name); diff --git a/src/csharp/Grpc.Core/Grpc.Core.csproj b/src/csharp/Grpc.Core/Grpc.Core.csproj index 9c91541d90..f5f2cf5f22 100644 --- a/src/csharp/Grpc.Core/Grpc.Core.csproj +++ b/src/csharp/Grpc.Core/Grpc.Core.csproj @@ -96,6 +96,7 @@ <Compile Include="Internal\ServerResponseStream.cs" /> <Compile Include="Internal\AtomicCounter.cs" /> <Compile Include="Internal\DebugStats.cs" /> + <Compile Include="ServerCallContext.cs" /> </ItemGroup> <ItemGroup> <None Include="packages.config" /> diff --git a/src/csharp/Grpc.Core/IAsyncStreamReader.cs b/src/csharp/Grpc.Core/IAsyncStreamReader.cs index 61cf57f7e0..699741cd05 100644 --- a/src/csharp/Grpc.Core/IAsyncStreamReader.cs +++ b/src/csharp/Grpc.Core/IAsyncStreamReader.cs @@ -44,9 +44,10 @@ namespace Grpc.Core /// </summary> /// <typeparam name="T"></typeparam> public interface IAsyncStreamReader<T> + where T : class { /// <summary> - /// Reads a single message. Returns default(T) if the last message was already read. + /// Reads a single message. Returns null if the last message was already read. /// A following read can only be started when the previous one finishes. /// </summary> Task<T> ReadNext(); diff --git a/src/csharp/Grpc.Core/IAsyncStreamWriter.cs b/src/csharp/Grpc.Core/IAsyncStreamWriter.cs index 724bae8f31..4bd8bfb8df 100644 --- a/src/csharp/Grpc.Core/IAsyncStreamWriter.cs +++ b/src/csharp/Grpc.Core/IAsyncStreamWriter.cs @@ -44,6 +44,7 @@ namespace Grpc.Core /// </summary> /// <typeparam name="T"></typeparam> public interface IAsyncStreamWriter<T> + where T : class { /// <summary> /// Writes a single message. Only one write can be pending at a time. diff --git a/src/csharp/Grpc.Core/IClientStreamWriter.cs b/src/csharp/Grpc.Core/IClientStreamWriter.cs index 6da42e9ccc..0847a928e6 100644 --- a/src/csharp/Grpc.Core/IClientStreamWriter.cs +++ b/src/csharp/Grpc.Core/IClientStreamWriter.cs @@ -44,6 +44,7 @@ namespace Grpc.Core /// </summary> /// <typeparam name="T"></typeparam> public interface IClientStreamWriter<T> : IAsyncStreamWriter<T> + where T : class { /// <summary> /// Closes the stream. Can only be called once there is no pending write. No writes should follow calling this. diff --git a/src/csharp/Grpc.Core/IServerStreamWriter.cs b/src/csharp/Grpc.Core/IServerStreamWriter.cs index e76397d8a0..199a585a3f 100644 --- a/src/csharp/Grpc.Core/IServerStreamWriter.cs +++ b/src/csharp/Grpc.Core/IServerStreamWriter.cs @@ -43,6 +43,7 @@ namespace Grpc.Core /// A writable stream of messages that is used in server-side handlers. /// </summary> public interface IServerStreamWriter<T> : IAsyncStreamWriter<T> + where T : class { } } diff --git a/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs b/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs index 3c66c67dcc..171d0c799d 100644 --- a/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs +++ b/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs @@ -138,9 +138,7 @@ namespace Grpc.Core.Internal ReleaseResourcesIfPossible(); } - // TODO(jtattermusch): check if call was cancelled. - - // TODO: handle error ... + // TODO(jtattermusch): handle error finishedServersideTcs.SetResult(null); } diff --git a/src/csharp/Grpc.Core/Internal/ClientRequestStream.cs b/src/csharp/Grpc.Core/Internal/ClientRequestStream.cs index 6854922a6f..1697058732 100644 --- a/src/csharp/Grpc.Core/Internal/ClientRequestStream.cs +++ b/src/csharp/Grpc.Core/Internal/ClientRequestStream.cs @@ -38,6 +38,8 @@ namespace Grpc.Core.Internal /// Writes requests asynchronously to an underlying AsyncCall object. /// </summary> internal class ClientRequestStream<TRequest, TResponse> : IClientStreamWriter<TRequest> + where TRequest : class + where TResponse : class { readonly AsyncCall<TRequest, TResponse> call; diff --git a/src/csharp/Grpc.Core/Internal/ClientResponseStream.cs b/src/csharp/Grpc.Core/Internal/ClientResponseStream.cs index 7fa511faa8..b2378cade6 100644 --- a/src/csharp/Grpc.Core/Internal/ClientResponseStream.cs +++ b/src/csharp/Grpc.Core/Internal/ClientResponseStream.cs @@ -38,6 +38,8 @@ using System.Threading.Tasks; namespace Grpc.Core.Internal { internal class ClientResponseStream<TRequest, TResponse> : IAsyncStreamReader<TResponse> + where TRequest : class + where TResponse : class { readonly AsyncCall<TRequest, TResponse> call; diff --git a/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs b/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs index 01b2a11369..95d8e97869 100644 --- a/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs +++ b/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs @@ -45,6 +45,8 @@ namespace Grpc.Core.Internal } internal class UnaryServerCallHandler<TRequest, TResponse> : IServerCallHandler + where TRequest : class + where TResponse : class { readonly Method<TRequest, TResponse> method; readonly UnaryServerMethod<TRequest, TResponse> handler; @@ -72,7 +74,8 @@ namespace Grpc.Core.Internal var request = await requestStream.ReadNext(); // TODO(jtattermusch): we need to read the full stream so that native callhandle gets deallocated. Preconditions.CheckArgument(await requestStream.ReadNext() == null); - var result = await handler(request); + var context = new ServerCallContext(); // TODO(jtattermusch): initialize the context + var result = await handler(context, request); await responseStream.Write(result); } catch (Exception e) @@ -93,6 +96,8 @@ namespace Grpc.Core.Internal } internal class ServerStreamingServerCallHandler<TRequest, TResponse> : IServerCallHandler + where TRequest : class + where TResponse : class { readonly Method<TRequest, TResponse> method; readonly ServerStreamingServerMethod<TRequest, TResponse> handler; @@ -121,7 +126,8 @@ namespace Grpc.Core.Internal // TODO(jtattermusch): we need to read the full stream so that native callhandle gets deallocated. Preconditions.CheckArgument(await requestStream.ReadNext() == null); - await handler(request, responseStream); + var context = new ServerCallContext(); // TODO(jtattermusch): initialize the context + await handler(context, request, responseStream); } catch (Exception e) { @@ -142,6 +148,8 @@ namespace Grpc.Core.Internal } internal class ClientStreamingServerCallHandler<TRequest, TResponse> : IServerCallHandler + where TRequest : class + where TResponse : class { readonly Method<TRequest, TResponse> method; readonly ClientStreamingServerMethod<TRequest, TResponse> handler; @@ -162,11 +170,12 @@ namespace Grpc.Core.Internal var finishedTask = asyncCall.ServerSideCallAsync(); var requestStream = new ServerRequestStream<TRequest, TResponse>(asyncCall); var responseStream = new ServerResponseStream<TRequest, TResponse>(asyncCall); + var context = new ServerCallContext(); // TODO(jtattermusch): initialize the context Status status = Status.DefaultSuccess; try { - var result = await handler(requestStream); + var result = await handler(context, requestStream); try { await responseStream.Write(result); @@ -195,6 +204,8 @@ namespace Grpc.Core.Internal } internal class DuplexStreamingServerCallHandler<TRequest, TResponse> : IServerCallHandler + where TRequest : class + where TResponse : class { readonly Method<TRequest, TResponse> method; readonly DuplexStreamingServerMethod<TRequest, TResponse> handler; @@ -215,11 +226,12 @@ namespace Grpc.Core.Internal var finishedTask = asyncCall.ServerSideCallAsync(); var requestStream = new ServerRequestStream<TRequest, TResponse>(asyncCall); var responseStream = new ServerResponseStream<TRequest, TResponse>(asyncCall); + var context = new ServerCallContext(); // TODO(jtattermusch): initialize the context Status status = Status.DefaultSuccess; try { - await handler(requestStream, responseStream); + await handler(context, requestStream, responseStream); } catch (Exception e) { diff --git a/src/csharp/Grpc.Core/Internal/ServerCalls.cs b/src/csharp/Grpc.Core/Internal/ServerCalls.cs index 5c6b335c7f..81279678b9 100644 --- a/src/csharp/Grpc.Core/Internal/ServerCalls.cs +++ b/src/csharp/Grpc.Core/Internal/ServerCalls.cs @@ -41,21 +41,29 @@ namespace Grpc.Core.Internal internal static class ServerCalls { public static IServerCallHandler UnaryCall<TRequest, TResponse>(Method<TRequest, TResponse> method, UnaryServerMethod<TRequest, TResponse> handler) + where TRequest : class + where TResponse : class { return new UnaryServerCallHandler<TRequest, TResponse>(method, handler); } public static IServerCallHandler ClientStreamingCall<TRequest, TResponse>(Method<TRequest, TResponse> method, ClientStreamingServerMethod<TRequest, TResponse> handler) + where TRequest : class + where TResponse : class { return new ClientStreamingServerCallHandler<TRequest, TResponse>(method, handler); } public static IServerCallHandler ServerStreamingCall<TRequest, TResponse>(Method<TRequest, TResponse> method, ServerStreamingServerMethod<TRequest, TResponse> handler) + where TRequest : class + where TResponse : class { return new ServerStreamingServerCallHandler<TRequest, TResponse>(method, handler); } public static IServerCallHandler DuplexStreamingCall<TRequest, TResponse>(Method<TRequest, TResponse> method, DuplexStreamingServerMethod<TRequest, TResponse> handler) + where TRequest : class + where TResponse : class { return new DuplexStreamingServerCallHandler<TRequest, TResponse>(method, handler); } diff --git a/src/csharp/Grpc.Core/Internal/ServerRequestStream.cs b/src/csharp/Grpc.Core/Internal/ServerRequestStream.cs index aa311059c3..d9ee0c815b 100644 --- a/src/csharp/Grpc.Core/Internal/ServerRequestStream.cs +++ b/src/csharp/Grpc.Core/Internal/ServerRequestStream.cs @@ -38,6 +38,8 @@ using System.Threading.Tasks; namespace Grpc.Core.Internal { internal class ServerRequestStream<TRequest, TResponse> : IAsyncStreamReader<TRequest> + where TRequest : class + where TResponse : class { readonly AsyncCallServer<TRequest, TResponse> call; diff --git a/src/csharp/Grpc.Core/Internal/ServerResponseStream.cs b/src/csharp/Grpc.Core/Internal/ServerResponseStream.cs index 686017c048..da688d504f 100644 --- a/src/csharp/Grpc.Core/Internal/ServerResponseStream.cs +++ b/src/csharp/Grpc.Core/Internal/ServerResponseStream.cs @@ -39,6 +39,8 @@ namespace Grpc.Core.Internal /// Writes responses asynchronously to an underlying AsyncCallServer object. /// </summary> internal class ServerResponseStream<TRequest, TResponse> : IServerStreamWriter<TResponse> + where TRequest : class + where TResponse : class { readonly AsyncCallServer<TRequest, TResponse> call; diff --git a/src/csharp/Grpc.Core/Server.cs b/src/csharp/Grpc.Core/Server.cs index a3000cee46..0df46bb25b 100644 --- a/src/csharp/Grpc.Core/Server.cs +++ b/src/csharp/Grpc.Core/Server.cs @@ -47,6 +47,11 @@ namespace Grpc.Core /// </summary> public class Server { + /// <summary> + /// Pass this value as port to have the server choose an unused listening port for you. + /// </summary> + public const int PickUnusedPort = 0; + // TODO(jtattermusch) : make sure the delegate doesn't get garbage collected while // native callbacks are in the completion queue. readonly ServerShutdownCallbackDelegate serverShutdownHandler; @@ -89,29 +94,25 @@ namespace Grpc.Core /// Add a non-secure port on which server should listen. /// Only call this before Start(). /// </summary> - public int AddListeningPort(string addr) + /// <returns>The port on which server will be listening.</returns> + /// <param name="host">the host</param> + /// <param name="port">the port. If zero, an unused port is chosen automatically.</param> + public int AddListeningPort(string host, int port) { - lock (myLock) - { - Preconditions.CheckState(!startRequested); - return handle.AddListeningPort(addr); - } + return AddListeningPortInternal(host, port, null); } /// <summary> - /// Add a secure port on which server should listen. + /// Add a non-secure port on which server should listen. /// Only call this before Start(). /// </summary> - public int AddListeningPort(string addr, ServerCredentials credentials) + /// <returns>The port on which server will be listening.</returns> + /// <param name="host">the host</param> + /// <param name="port">the port. If zero, , an unused port is chosen automatically.</param> + public int AddListeningPort(string host, int port, ServerCredentials credentials) { - lock (myLock) - { - Preconditions.CheckState(!startRequested); - using (var nativeCredentials = credentials.ToNativeCredentials()) - { - return handle.AddListeningPort(addr, nativeCredentials); - } - } + Preconditions.CheckNotNull(credentials); + return AddListeningPortInternal(host, port, credentials); } /// <summary> @@ -164,6 +165,26 @@ namespace Grpc.Core handle.Dispose(); } + private int AddListeningPortInternal(string host, int port, ServerCredentials credentials) + { + lock (myLock) + { + Preconditions.CheckState(!startRequested); + var address = string.Format("{0}:{1}", host, port); + if (credentials != null) + { + using (var nativeCredentials = credentials.ToNativeCredentials()) + { + return handle.AddListeningPort(address, nativeCredentials); + } + } + else + { + return handle.AddListeningPort(address); + } + } + } + /// <summary> /// Allows one new RPC call to be received by server. /// </summary> diff --git a/src/csharp/Grpc.Core/ServerCallContext.cs b/src/csharp/Grpc.Core/ServerCallContext.cs new file mode 100644 index 0000000000..e873b3e88a --- /dev/null +++ b/src/csharp/Grpc.Core/ServerCallContext.cs @@ -0,0 +1,56 @@ +#region Copyright notice and license + +// Copyright 2015, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#endregion + +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; + +namespace Grpc.Core +{ + /// <summary> + /// Context for a server-side call. + /// </summary> + public sealed class ServerCallContext + { + + // TODO(jtattermusch): add cancellationToken + + // TODO(jtattermusch): add deadline info + + // TODO(jtattermusch): expose initial metadata sent by client for reading + + // TODO(jtattermusch): expose method to send initial metadata back to client + + // TODO(jtattermusch): allow setting status and trailing metadata to send after handler completes. + } +} diff --git a/src/csharp/Grpc.Core/ServerMethods.cs b/src/csharp/Grpc.Core/ServerMethods.cs index 6646bb5a89..377b78eb30 100644 --- a/src/csharp/Grpc.Core/ServerMethods.cs +++ b/src/csharp/Grpc.Core/ServerMethods.cs @@ -42,20 +42,28 @@ namespace Grpc.Core /// <summary> /// Server-side handler for unary call. /// </summary> - public delegate Task<TResponse> UnaryServerMethod<TRequest, TResponse>(TRequest request); + public delegate Task<TResponse> UnaryServerMethod<TRequest, TResponse>(ServerCallContext context, TRequest request) + where TRequest : class + where TResponse : class; /// <summary> /// Server-side handler for client streaming call. /// </summary> - public delegate Task<TResponse> ClientStreamingServerMethod<TRequest, TResponse>(IAsyncStreamReader<TRequest> requestStream); + public delegate Task<TResponse> ClientStreamingServerMethod<TRequest, TResponse>(ServerCallContext context, IAsyncStreamReader<TRequest> requestStream) + where TRequest : class + where TResponse : class; /// <summary> /// Server-side handler for server streaming call. /// </summary> - public delegate Task ServerStreamingServerMethod<TRequest, TResponse>(TRequest request, IServerStreamWriter<TResponse> responseStream); + public delegate Task ServerStreamingServerMethod<TRequest, TResponse>(ServerCallContext context, TRequest request, IServerStreamWriter<TResponse> responseStream) + where TRequest : class + where TResponse : class; /// <summary> /// Server-side handler for bidi streaming call. /// </summary> - public delegate Task DuplexStreamingServerMethod<TRequest, TResponse>(IAsyncStreamReader<TRequest> requestStream, IServerStreamWriter<TResponse> responseStream); + public delegate Task DuplexStreamingServerMethod<TRequest, TResponse>(ServerCallContext context, IAsyncStreamReader<TRequest> requestStream, IServerStreamWriter<TResponse> responseStream) + where TRequest : class + where TResponse : class; } diff --git a/src/csharp/Grpc.Core/ServerServiceDefinition.cs b/src/csharp/Grpc.Core/ServerServiceDefinition.cs index 01b1dc8f7b..81846beb2f 100644 --- a/src/csharp/Grpc.Core/ServerServiceDefinition.cs +++ b/src/csharp/Grpc.Core/ServerServiceDefinition.cs @@ -76,6 +76,8 @@ namespace Grpc.Core public Builder AddMethod<TRequest, TResponse>( Method<TRequest, TResponse> method, UnaryServerMethod<TRequest, TResponse> handler) + where TRequest : class + where TResponse : class { callHandlers.Add(GetFullMethodName(serviceName, method.Name), ServerCalls.UnaryCall(method, handler)); return this; @@ -84,6 +86,8 @@ namespace Grpc.Core public Builder AddMethod<TRequest, TResponse>( Method<TRequest, TResponse> method, ClientStreamingServerMethod<TRequest, TResponse> handler) + where TRequest : class + where TResponse : class { callHandlers.Add(GetFullMethodName(serviceName, method.Name), ServerCalls.ClientStreamingCall(method, handler)); return this; @@ -92,6 +96,8 @@ namespace Grpc.Core public Builder AddMethod<TRequest, TResponse>( Method<TRequest, TResponse> method, ServerStreamingServerMethod<TRequest, TResponse> handler) + where TRequest : class + where TResponse : class { callHandlers.Add(GetFullMethodName(serviceName, method.Name), ServerCalls.ServerStreamingCall(method, handler)); return this; @@ -100,6 +106,8 @@ namespace Grpc.Core public Builder AddMethod<TRequest, TResponse>( Method<TRequest, TResponse> method, DuplexStreamingServerMethod<TRequest, TResponse> handler) + where TRequest : class + where TResponse : class { callHandlers.Add(GetFullMethodName(serviceName, method.Name), ServerCalls.DuplexStreamingCall(method, handler)); return this; diff --git a/src/csharp/Grpc.Core/Stub/AbstractStub.cs b/src/csharp/Grpc.Core/Stub/AbstractStub.cs index cf5ab958c5..4a8b254357 100644 --- a/src/csharp/Grpc.Core/Stub/AbstractStub.cs +++ b/src/csharp/Grpc.Core/Stub/AbstractStub.cs @@ -64,6 +64,8 @@ namespace Grpc.Core /// Creates a new call to given method. /// </summary> protected Call<TRequest, TResponse> CreateCall<TRequest, TResponse>(string serviceName, Method<TRequest, TResponse> method) + where TRequest : class + where TResponse : class { var headerBuilder = Metadata.CreateBuilder(); config.HeaderInterceptor(headerBuilder); diff --git a/src/csharp/Grpc.Examples.MathServer/MathServer.cs b/src/csharp/Grpc.Examples.MathServer/MathServer.cs index abc7ef05e4..cfde9b42c7 100644 --- a/src/csharp/Grpc.Examples.MathServer/MathServer.cs +++ b/src/csharp/Grpc.Examples.MathServer/MathServer.cs @@ -46,7 +46,7 @@ namespace math Server server = new Server(); server.AddServiceDefinition(MathGrpc.BindService(new MathServiceImpl())); - int port = server.AddListeningPort(host + ":23456"); + int port = server.AddListeningPort(host, 23456); server.Start(); Console.WriteLine("MathServer listening on port " + port); diff --git a/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs b/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs index 332795e0e5..4ada95edd6 100644 --- a/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs +++ b/src/csharp/Grpc.Examples.Tests/MathClientServerTests.cs @@ -59,7 +59,7 @@ namespace math.Tests server = new Server(); server.AddServiceDefinition(MathGrpc.BindService(new MathServiceImpl())); - int port = server.AddListeningPort(host + ":0"); + int port = server.AddListeningPort(host, Server.PickUnusedPort); server.Start(); channel = new Channel(host + ":" + port); diff --git a/src/csharp/Grpc.Examples/MathGrpc.cs b/src/csharp/Grpc.Examples/MathGrpc.cs index 60408b9018..03f5c31cb7 100644 --- a/src/csharp/Grpc.Examples/MathGrpc.cs +++ b/src/csharp/Grpc.Examples/MathGrpc.cs @@ -133,13 +133,13 @@ namespace math // server-side interface public interface IMathService { - Task<DivReply> Div(DivArgs request); + Task<DivReply> Div(ServerCallContext context, DivArgs request); - Task Fib(FibArgs request, IServerStreamWriter<Num> responseStream); + Task Fib(ServerCallContext context, FibArgs request, IServerStreamWriter<Num> responseStream); - Task<Num> Sum(IAsyncStreamReader<Num> requestStream); + Task<Num> Sum(ServerCallContext context, IAsyncStreamReader<Num> requestStream); - Task DivMany(IAsyncStreamReader<DivArgs> requestStream, IServerStreamWriter<DivReply> responseStream); + Task DivMany(ServerCallContext context, IAsyncStreamReader<DivArgs> requestStream, IServerStreamWriter<DivReply> responseStream); } public static ServerServiceDefinition BindService(IMathService serviceImpl) diff --git a/src/csharp/Grpc.Examples/MathServiceImpl.cs b/src/csharp/Grpc.Examples/MathServiceImpl.cs index 83ec2a8c3d..800dee8735 100644 --- a/src/csharp/Grpc.Examples/MathServiceImpl.cs +++ b/src/csharp/Grpc.Examples/MathServiceImpl.cs @@ -46,12 +46,12 @@ namespace math /// </summary> public class MathServiceImpl : MathGrpc.IMathService { - public Task<DivReply> Div(DivArgs request) + public Task<DivReply> Div(ServerCallContext context, DivArgs request) { return Task.FromResult(DivInternal(request)); } - public async Task Fib(FibArgs request, IServerStreamWriter<Num> responseStream) + public async Task Fib(ServerCallContext context, FibArgs request, IServerStreamWriter<Num> responseStream) { if (request.Limit <= 0) { @@ -68,7 +68,7 @@ namespace math } } - public async Task<Num> Sum(IAsyncStreamReader<Num> requestStream) + public async Task<Num> Sum(ServerCallContext context, IAsyncStreamReader<Num> requestStream) { long sum = 0; await requestStream.ForEach(async num => @@ -78,7 +78,7 @@ namespace math return Num.CreateBuilder().SetNum_(sum).Build(); } - public async Task DivMany(IAsyncStreamReader<DivArgs> requestStream, IServerStreamWriter<DivReply> responseStream) + public async Task DivMany(ServerCallContext context, IAsyncStreamReader<DivArgs> requestStream, IServerStreamWriter<DivReply> responseStream) { await requestStream.ForEach(async divArgs => { diff --git a/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs b/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs index 45380227c2..9e49ce0d17 100644 --- a/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs +++ b/src/csharp/Grpc.IntegrationTesting/InteropClientServerTest.cs @@ -59,7 +59,7 @@ namespace Grpc.IntegrationTesting server = new Server(); server.AddServiceDefinition(TestServiceGrpc.BindService(new TestServiceImpl())); - int port = server.AddListeningPort(host + ":0", TestCredentials.CreateTestServerCredentials()); + int port = server.AddListeningPort(host, Server.PickUnusedPort, TestCredentials.CreateTestServerCredentials()); server.Start(); var channelArgs = ChannelArgs.CreateBuilder() diff --git a/src/csharp/Grpc.IntegrationTesting/InteropServer.cs b/src/csharp/Grpc.IntegrationTesting/InteropServer.cs index ad5200774f..ca54aed041 100644 --- a/src/csharp/Grpc.IntegrationTesting/InteropServer.cs +++ b/src/csharp/Grpc.IntegrationTesting/InteropServer.cs @@ -93,16 +93,17 @@ namespace Grpc.IntegrationTesting var server = new Server(); server.AddServiceDefinition(TestServiceGrpc.BindService(new TestServiceImpl())); - string addr = "0.0.0.0:" + options.port; + string host = "0.0.0.0"; + int port = options.port.Value; if (options.useTls) { - server.AddListeningPort(addr, TestCredentials.CreateTestServerCredentials()); + server.AddListeningPort(host, port, TestCredentials.CreateTestServerCredentials()); } else { - server.AddListeningPort(addr); + server.AddListeningPort(host, options.port.Value); } - Console.WriteLine("Running server on " + addr); + Console.WriteLine("Running server on " + string.Format("{0}:{1}", host, port)); server.Start(); server.ShutdownTask.Wait(); diff --git a/src/csharp/Grpc.IntegrationTesting/TestServiceGrpc.cs b/src/csharp/Grpc.IntegrationTesting/TestServiceGrpc.cs index d1f8aa12c7..9f14dad6c0 100644 --- a/src/csharp/Grpc.IntegrationTesting/TestServiceGrpc.cs +++ b/src/csharp/Grpc.IntegrationTesting/TestServiceGrpc.cs @@ -171,17 +171,17 @@ namespace grpc.testing // server-side interface public interface ITestService { - Task<Empty> EmptyCall(Empty request); + Task<Empty> EmptyCall(ServerCallContext context, Empty request); - Task<SimpleResponse> UnaryCall(SimpleRequest request); + Task<SimpleResponse> UnaryCall(ServerCallContext context, SimpleRequest request); - Task StreamingOutputCall(StreamingOutputCallRequest request, IServerStreamWriter<StreamingOutputCallResponse> responseStream); + Task StreamingOutputCall(ServerCallContext context, StreamingOutputCallRequest request, IServerStreamWriter<StreamingOutputCallResponse> responseStream); - Task<StreamingInputCallResponse> StreamingInputCall(IAsyncStreamReader<StreamingInputCallRequest> requestStream); + Task<StreamingInputCallResponse> StreamingInputCall(ServerCallContext context, IAsyncStreamReader<StreamingInputCallRequest> requestStream); - Task FullDuplexCall(IAsyncStreamReader<StreamingOutputCallRequest> requestStream, IServerStreamWriter<StreamingOutputCallResponse> responseStream); + Task FullDuplexCall(ServerCallContext context, IAsyncStreamReader<StreamingOutputCallRequest> requestStream, IServerStreamWriter<StreamingOutputCallResponse> responseStream); - Task HalfDuplexCall(IAsyncStreamReader<StreamingOutputCallRequest> requestStream, IServerStreamWriter<StreamingOutputCallResponse> responseStream); + Task HalfDuplexCall(ServerCallContext context, IAsyncStreamReader<StreamingOutputCallRequest> requestStream, IServerStreamWriter<StreamingOutputCallResponse> responseStream); } public static ServerServiceDefinition BindService(ITestService serviceImpl) diff --git a/src/csharp/Grpc.IntegrationTesting/TestServiceImpl.cs b/src/csharp/Grpc.IntegrationTesting/TestServiceImpl.cs index 8b0cf3a2d0..40f32b5a88 100644 --- a/src/csharp/Grpc.IntegrationTesting/TestServiceImpl.cs +++ b/src/csharp/Grpc.IntegrationTesting/TestServiceImpl.cs @@ -46,19 +46,19 @@ namespace grpc.testing /// </summary> public class TestServiceImpl : TestServiceGrpc.ITestService { - public Task<Empty> EmptyCall(Empty request) + public Task<Empty> EmptyCall(ServerCallContext context, Empty request) { return Task.FromResult(Empty.DefaultInstance); } - public Task<SimpleResponse> UnaryCall(SimpleRequest request) + public Task<SimpleResponse> UnaryCall(ServerCallContext context, SimpleRequest request) { var response = SimpleResponse.CreateBuilder() .SetPayload(CreateZerosPayload(request.ResponseSize)).Build(); return Task.FromResult(response); } - public async Task StreamingOutputCall(StreamingOutputCallRequest request, IServerStreamWriter<StreamingOutputCallResponse> responseStream) + public async Task StreamingOutputCall(ServerCallContext context, StreamingOutputCallRequest request, IServerStreamWriter<StreamingOutputCallResponse> responseStream) { foreach (var responseParam in request.ResponseParametersList) { @@ -68,7 +68,7 @@ namespace grpc.testing } } - public async Task<StreamingInputCallResponse> StreamingInputCall(IAsyncStreamReader<StreamingInputCallRequest> requestStream) + public async Task<StreamingInputCallResponse> StreamingInputCall(ServerCallContext context, IAsyncStreamReader<StreamingInputCallRequest> requestStream) { int sum = 0; await requestStream.ForEach(async request => @@ -78,7 +78,7 @@ namespace grpc.testing return StreamingInputCallResponse.CreateBuilder().SetAggregatedPayloadSize(sum).Build(); } - public async Task FullDuplexCall(IAsyncStreamReader<StreamingOutputCallRequest> requestStream, IServerStreamWriter<StreamingOutputCallResponse> responseStream) + public async Task FullDuplexCall(ServerCallContext context, IAsyncStreamReader<StreamingOutputCallRequest> requestStream, IServerStreamWriter<StreamingOutputCallResponse> responseStream) { await requestStream.ForEach(async request => { @@ -91,7 +91,7 @@ namespace grpc.testing }); } - public async Task HalfDuplexCall(IAsyncStreamReader<StreamingOutputCallRequest> requestStream, IServerStreamWriter<StreamingOutputCallResponse> responseStream) + public async Task HalfDuplexCall(ServerCallContext context, IAsyncStreamReader<StreamingOutputCallRequest> requestStream, IServerStreamWriter<StreamingOutputCallResponse> responseStream) { throw new NotImplementedException(); } diff --git a/src/php/.gitignore b/src/php/.gitignore index 0bb5f8e956..ecde2ca4c6 100644 --- a/src/php/.gitignore +++ b/src/php/.gitignore @@ -18,4 +18,5 @@ missing mkinstalldirs ext/grpc/ltmain.sh - +composer.lock +vendor/ diff --git a/src/php/composer.lock b/src/php/composer.lock deleted file mode 100644 index c2d723def4..0000000000 --- a/src/php/composer.lock +++ /dev/null @@ -1,315 +0,0 @@ -{ - "_readme": [ - "This file locks the dependencies of your project to a known state", - "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", - "This file is @generated automatically" - ], - "hash": "bb81ea5f72ddea2f594a172ff0f3b44d", - "packages": [ - { - "name": "firebase/php-jwt", - "version": "2.0.0", - "target-dir": "Firebase/PHP-JWT", - "source": { - "type": "git", - "url": "https://github.com/firebase/php-jwt.git", - "reference": "ffcfd888ce1e4f2d70cac2dc9b7301038332fe57" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/firebase/php-jwt/zipball/ffcfd888ce1e4f2d70cac2dc9b7301038332fe57", - "reference": "ffcfd888ce1e4f2d70cac2dc9b7301038332fe57", - "shasum": "" - }, - "require": { - "php": ">=5.2.0" - }, - "type": "library", - "autoload": { - "classmap": [ - "Authentication/", - "Exceptions/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Neuman Vong", - "email": "neuman+pear@twilio.com", - "role": "Developer" - }, - { - "name": "Anant Narayanan", - "email": "anant@php.net", - "role": "Developer" - } - ], - "description": "A simple library to encode and decode JSON Web Tokens (JWT) in PHP. Should conform to the current spec.", - "homepage": "https://github.com/firebase/php-jwt", - "time": "2015-04-01 18:46:38" - }, - { - "name": "google/auth", - "version": "dev-master", - "source": { - "type": "git", - "url": "https://github.com/google/google-auth-library-php.git", - "reference": "35f87159b327fa6416266948c1747c585a4ae3ad" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/google/google-auth-library-php/zipball/35f87159b327fa6416266948c1747c585a4ae3ad", - "reference": "35f87159b327fa6416266948c1747c585a4ae3ad", - "shasum": "" - }, - "require": { - "firebase/php-jwt": "2.0.0", - "guzzlehttp/guzzle": "5.2.*", - "php": ">=5.4" - }, - "require-dev": { - "phplint/phplint": "0.0.1", - "phpunit/phpunit": "3.7.*" - }, - "type": "library", - "autoload": { - "classmap": [ - "src/" - ], - "psr-4": { - "Google\\Auth\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "Apache-2.0" - ], - "description": "Google Auth Library for PHP", - "homepage": "http://github.com/google/google-auth-library-php", - "keywords": [ - "Authentication", - "google", - "oauth2" - ], - "time": "2015-04-30 11:57:19" - }, - { - "name": "guzzlehttp/guzzle", - "version": "5.2.0", - "source": { - "type": "git", - "url": "https://github.com/guzzle/guzzle.git", - "reference": "475b29ccd411f2fa8a408e64576418728c032cfa" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/475b29ccd411f2fa8a408e64576418728c032cfa", - "reference": "475b29ccd411f2fa8a408e64576418728c032cfa", - "shasum": "" - }, - "require": { - "guzzlehttp/ringphp": "~1.0", - "php": ">=5.4.0" - }, - "require-dev": { - "ext-curl": "*", - "phpunit/phpunit": "~4.0", - "psr/log": "~1.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.0-dev" - } - }, - "autoload": { - "psr-4": { - "GuzzleHttp\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - } - ], - "description": "Guzzle is a PHP HTTP client library and framework for building RESTful web service clients", - "homepage": "http://guzzlephp.org/", - "keywords": [ - "client", - "curl", - "framework", - "http", - "http client", - "rest", - "web service" - ], - "time": "2015-01-28 01:03:29" - }, - { - "name": "guzzlehttp/ringphp", - "version": "1.0.7", - "source": { - "type": "git", - "url": "https://github.com/guzzle/RingPHP.git", - "reference": "52d868f13570a9a56e5fce6614e0ec75d0f13ac2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/guzzle/RingPHP/zipball/52d868f13570a9a56e5fce6614e0ec75d0f13ac2", - "reference": "52d868f13570a9a56e5fce6614e0ec75d0f13ac2", - "shasum": "" - }, - "require": { - "guzzlehttp/streams": "~3.0", - "php": ">=5.4.0", - "react/promise": "~2.0" - }, - "require-dev": { - "ext-curl": "*", - "phpunit/phpunit": "~4.0" - }, - "suggest": { - "ext-curl": "Guzzle will use specific adapters if cURL is present" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "psr-4": { - "GuzzleHttp\\Ring\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - } - ], - "description": "Provides a simple API and specification that abstracts away the details of HTTP into a single PHP function.", - "time": "2015-03-30 01:43:20" - }, - { - "name": "guzzlehttp/streams", - "version": "3.0.0", - "source": { - "type": "git", - "url": "https://github.com/guzzle/streams.git", - "reference": "47aaa48e27dae43d39fc1cea0ccf0d84ac1a2ba5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/guzzle/streams/zipball/47aaa48e27dae43d39fc1cea0ccf0d84ac1a2ba5", - "reference": "47aaa48e27dae43d39fc1cea0ccf0d84ac1a2ba5", - "shasum": "" - }, - "require": { - "php": ">=5.4.0" - }, - "require-dev": { - "phpunit/phpunit": "~4.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.0-dev" - } - }, - "autoload": { - "psr-4": { - "GuzzleHttp\\Stream\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - } - ], - "description": "Provides a simple abstraction over streams of data", - "homepage": "http://guzzlephp.org/", - "keywords": [ - "Guzzle", - "stream" - ], - "time": "2014-10-12 19:18:40" - }, - { - "name": "react/promise", - "version": "v2.2.0", - "source": { - "type": "git", - "url": "https://github.com/reactphp/promise.git", - "reference": "365fcee430dfa4ace1fbc75737ca60ceea7eeeef" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/reactphp/promise/zipball/365fcee430dfa4ace1fbc75737ca60ceea7eeeef", - "reference": "365fcee430dfa4ace1fbc75737ca60ceea7eeeef", - "shasum": "" - }, - "require": { - "php": ">=5.4.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0-dev" - } - }, - "autoload": { - "psr-4": { - "React\\Promise\\": "src/" - }, - "files": [ - "src/functions_include.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jan Sorgalla", - "email": "jsorgalla@googlemail.com" - } - ], - "description": "A lightweight implementation of CommonJS Promises/A for PHP", - "time": "2014-12-30 13:32:42" - } - ], - "packages-dev": [], - "aliases": [], - "minimum-stability": "stable", - "stability-flags": { - "google/auth": 20 - }, - "prefer-stable": false, - "prefer-lowest": false, - "platform": { - "php": ">=5.5.0" - }, - "platform-dev": [] -} |