aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/compiler/cpp_generator.cc68
-rw-r--r--src/compiler/cpp_generator_helpers.h3
-rw-r--r--src/compiler/cpp_plugin.cc7
-rw-r--r--src/compiler/go_generator.cc530
-rw-r--r--src/compiler/go_generator.h (renamed from src/cpp/rpc_method.h)40
-rw-r--r--src/compiler/go_plugin.cc83
-rw-r--r--src/compiler/ruby_generator.cc13
-rw-r--r--src/compiler/ruby_generator_helpers-inl.h8
-rw-r--r--src/compiler/ruby_generator_map-inl.h6
-rw-r--r--src/compiler/ruby_generator_string-inl.h6
-rw-r--r--src/core/channel/channel_args.h2
-rw-r--r--src/core/channel/channel_stack.c11
-rw-r--r--src/core/channel/channel_stack.h2
-rw-r--r--src/core/channel/client_channel.h2
-rw-r--r--src/core/channel/client_setup.h2
-rw-r--r--src/core/channel/connected_channel.c49
-rw-r--r--src/core/channel/connected_channel.h2
-rw-r--r--src/core/channel/http_server_filter.c108
-rw-r--r--src/core/channel/metadata_buffer.c2
-rw-r--r--src/core/channel/metadata_buffer.h2
-rw-r--r--src/core/channel/noop_filter.c4
-rw-r--r--src/core/channel/noop_filter.h2
-rw-r--r--src/core/compression/algorithm.h2
-rw-r--r--src/core/compression/message_compress.h2
-rw-r--r--src/core/httpcli/format_request.h2
-rw-r--r--src/core/httpcli/httpcli.h2
-rw-r--r--src/core/httpcli/httpcli_security_context.h2
-rw-r--r--src/core/httpcli/parser.h2
-rw-r--r--src/core/iomgr/pollset.h1
-rw-r--r--src/core/iomgr/sockaddr_utils.c28
-rw-r--r--src/core/iomgr/sockaddr_utils.h6
-rw-r--r--src/core/iomgr/tcp_server.h5
-rw-r--r--src/core/iomgr/tcp_server_posix.c87
-rw-r--r--src/core/security/auth.c5
-rw-r--r--src/core/security/auth.h2
-rw-r--r--src/core/security/credentials.c21
-rw-r--r--src/core/security/credentials.h12
-rw-r--r--src/core/security/factories.c80
-rw-r--r--src/core/security/google_root_certs.h2
-rw-r--r--src/core/security/secure_endpoint.h2
-rw-r--r--src/core/security/secure_transport_setup.h2
-rw-r--r--src/core/security/security_context.c131
-rw-r--r--src/core/security/security_context.h36
-rw-r--r--src/core/security/server_secure_chttp2.c3
-rw-r--r--src/core/statistics/census_interface.h2
-rw-r--r--src/core/statistics/census_rpc_stats.h2
-rw-r--r--src/core/statistics/census_tracing.c30
-rw-r--r--src/core/statistics/hash_table.c6
-rw-r--r--src/core/support/alloc.c4
-rw-r--r--src/core/support/cpu.h2
-rw-r--r--src/core/support/cpu_linux.c24
-rw-r--r--src/core/support/log.c23
-rw-r--r--src/core/support/log_android.c24
-rw-r--r--src/core/support/log_linux.c31
-rw-r--r--src/core/support/log_posix.c41
-rw-r--r--src/core/support/log_win32.c40
-rw-r--r--src/core/support/murmur_hash.h2
-rw-r--r--src/core/support/thd_internal.h2
-rw-r--r--src/core/surface/call.c2
-rw-r--r--src/core/surface/call.h2
-rw-r--r--src/core/surface/channel.c2
-rw-r--r--src/core/surface/channel.h2
-rw-r--r--src/core/surface/client.c7
-rw-r--r--src/core/surface/client.h2
-rw-r--r--src/core/surface/completion_queue.h2
-rw-r--r--src/core/surface/event_string.h2
-rw-r--r--src/core/surface/lame_client.c29
-rw-r--r--src/core/surface/server.c4
-rw-r--r--src/core/surface/server.h2
-rw-r--r--src/core/surface/server_chttp2.c16
-rw-r--r--src/core/surface/surface_trace.h2
-rw-r--r--src/core/transport/chttp2/frame.h2
-rw-r--r--src/core/transport/chttp2/frame_data.c1
-rw-r--r--src/core/transport/chttp2/frame_data.h2
-rw-r--r--src/core/transport/chttp2/frame_ping.h2
-rw-r--r--src/core/transport/chttp2/frame_rst_stream.h2
-rw-r--r--src/core/transport/chttp2/frame_settings.h2
-rw-r--r--src/core/transport/chttp2/frame_window_update.h2
-rw-r--r--src/core/transport/chttp2/hpack_parser.h2
-rw-r--r--src/core/transport/chttp2/hpack_table.c124
-rw-r--r--src/core/transport/chttp2/hpack_table.h2
-rw-r--r--src/core/transport/chttp2/http2_errors.h2
-rw-r--r--src/core/transport/chttp2/status_conversion.h2
-rw-r--r--src/core/transport/chttp2/stream_encoder.c130
-rw-r--r--src/core/transport/chttp2/stream_encoder.h17
-rw-r--r--src/core/transport/chttp2/stream_map.h2
-rw-r--r--src/core/transport/chttp2/varint.h2
-rw-r--r--src/core/transport/chttp2_transport.c246
-rw-r--r--src/core/transport/chttp2_transport.h2
-rw-r--r--src/core/transport/metadata.h2
-rw-r--r--src/core/transport/stream_op.h2
-rw-r--r--src/core/transport/transport.h2
-rw-r--r--src/core/transport/transport_impl.h2
-rw-r--r--src/core/tsi/fake_transport_security.c24
-rw-r--r--src/core/tsi/fake_transport_security.h3
-rw-r--r--src/core/tsi/fake_transport_security_test.cc151
-rw-r--r--src/core/tsi/ssl_transport_security.c78
-rw-r--r--src/core/tsi/ssl_transport_security.h14
-rw-r--r--src/core/tsi/ssl_transport_security_test.cc534
-rw-r--r--src/core/tsi/transport_security.c35
-rw-r--r--src/core/tsi/transport_security.h4
-rw-r--r--src/core/tsi/transport_security_interface.h48
-rw-r--r--src/core/tsi/transport_security_test_lib.cc363
-rw-r--r--src/core/tsi/transport_security_test_lib.h154
-rw-r--r--src/cpp/client/channel.cc20
-rw-r--r--src/cpp/client/channel.h8
-rw-r--r--src/cpp/client/credentials.cc37
-rw-r--r--src/cpp/client/internal_stub.cc2
-rw-r--r--src/cpp/common/rpc_method.cc (renamed from src/cpp/rpc_method.cc)2
-rw-r--r--src/cpp/proto/proto_utils.cc6
-rw-r--r--src/cpp/proto/proto_utils.h3
-rw-r--r--src/cpp/server/async_server_context.cc3
-rw-r--r--src/cpp/server/rpc_service_method.h214
-rw-r--r--src/cpp/server/server.cc2
-rw-r--r--src/cpp/server/server_context_impl.cc4
-rw-r--r--src/cpp/server/server_credentials.cc1
-rw-r--r--src/cpp/server/server_rpc_handler.cc14
-rw-r--r--src/cpp/stream/stream_context.cc9
-rw-r--r--src/cpp/stream/stream_context.h13
-rw-r--r--src/cpp/util/status.cc1
-rw-r--r--src/node/README.md12
-rw-r--r--src/node/binding.gyp46
-rw-r--r--src/node/byte_buffer.cc79
-rw-r--r--src/node/byte_buffer.h56
-rw-r--r--src/node/call.cc392
-rw-r--r--src/node/call.h82
-rw-r--r--src/node/channel.cc182
-rw-r--r--src/node/channel.h79
-rw-r--r--src/node/client.js209
-rw-r--r--src/node/common.js62
-rw-r--r--src/node/completion_queue_async_worker.cc89
-rw-r--r--src/node/completion_queue_async_worker.h79
-rw-r--r--src/node/credentials.cc209
-rw-r--r--src/node/credentials.h81
-rw-r--r--src/node/event.cc164
-rw-r--r--src/node/event.h (renamed from src/cpp/client/internal_stub.h)28
-rw-r--r--src/node/examples/math.proto25
-rw-r--r--src/node/examples/math_server.js201
-rw-r--r--src/node/node_grpc.cc182
-rw-r--r--src/node/package.json18
-rw-r--r--src/node/port_picker.js52
-rw-r--r--src/node/server.cc236
-rw-r--r--src/node/server.h79
-rw-r--r--src/node/server.js261
-rw-r--r--src/node/server_credentials.cc161
-rw-r--r--src/node/server_credentials.h77
-rw-r--r--src/node/surface_client.js339
-rw-r--r--src/node/surface_server.js358
-rw-r--r--src/node/tag.cc101
-rw-r--r--src/node/tag.h59
-rw-r--r--src/node/test/call_test.js202
-rw-r--r--src/node/test/channel_test.js88
-rw-r--r--src/node/test/client_server_test.js183
-rw-r--r--src/node/test/constant_test.js130
-rw-r--r--src/node/test/data/README1
-rw-r--r--src/node/test/data/ca.pem15
-rw-r--r--src/node/test/data/server1.key16
-rw-r--r--src/node/test/data/server1.pem16
-rw-r--r--src/node/test/end_to_end_test.js201
-rw-r--r--src/node/test/math_client_test.js209
-rw-r--r--src/node/test/server_test.js121
-rw-r--r--src/node/timeval.cc66
-rw-r--r--src/node/timeval.h48
-rw-r--r--[-rwxr-xr-x]src/php/ext/grpc/byte_buffer.c9
-rw-r--r--[-rwxr-xr-x]src/php/ext/grpc/byte_buffer.h3
-rw-r--r--[-rwxr-xr-x]src/php/ext/grpc/call.c293
-rw-r--r--[-rwxr-xr-x]src/php/ext/grpc/call.h17
-rw-r--r--[-rwxr-xr-x]src/php/ext/grpc/channel.c89
-rw-r--r--[-rwxr-xr-x]src/php/ext/grpc/completion_queue.c76
-rwxr-xr-xsrc/php/ext/grpc/config.m43
-rw-r--r--[-rwxr-xr-x]src/php/ext/grpc/credentials.c86
-rw-r--r--[-rwxr-xr-x]src/php/ext/grpc/event.c63
-rw-r--r--[-rwxr-xr-x]src/php/ext/grpc/php_grpc.c266
-rw-r--r--[-rwxr-xr-x]src/php/ext/grpc/php_grpc.h23
-rw-r--r--[-rwxr-xr-x]src/php/ext/grpc/server.c107
-rw-r--r--[-rwxr-xr-x]src/php/ext/grpc/server_credentials.c56
-rw-r--r--[-rwxr-xr-x]src/php/ext/grpc/timeval.c151
-rwxr-xr-x[-rw-r--r--]src/ruby/bin/interop/interop_client.rb3
-rwxr-xr-x[-rw-r--r--]src/ruby/bin/interop/interop_server.rb4
-rwxr-xr-x[-rw-r--r--]src/ruby/bin/math_client.rb5
-rwxr-xr-x[-rw-r--r--]src/ruby/bin/math_server.rb4
-rwxr-xr-x[-rw-r--r--]src/ruby/bin/noproto_client.rb3
-rwxr-xr-x[-rw-r--r--]src/ruby/bin/noproto_server.rb3
-rw-r--r--src/ruby/ext/grpc/rb_byte_buffer.c10
-rw-r--r--src/ruby/ext/grpc/rb_byte_buffer.h2
-rw-r--r--src/ruby/ext/grpc/rb_call.c38
-rw-r--r--src/ruby/ext/grpc/rb_call.h2
-rw-r--r--src/ruby/ext/grpc/rb_channel.c4
-rw-r--r--src/ruby/ext/grpc/rb_channel.h2
-rw-r--r--src/ruby/ext/grpc/rb_channel_args.c11
-rw-r--r--src/ruby/ext/grpc/rb_channel_args.h3
-rw-r--r--src/ruby/ext/grpc/rb_completion_queue.c43
-rw-r--r--src/ruby/ext/grpc/rb_completion_queue.h2
-rw-r--r--src/ruby/ext/grpc/rb_credentials.c22
-rw-r--r--src/ruby/ext/grpc/rb_credentials.h2
-rw-r--r--src/ruby/ext/grpc/rb_event.c67
-rw-r--r--src/ruby/ext/grpc/rb_event.h2
-rw-r--r--src/ruby/ext/grpc/rb_grpc.c43
-rw-r--r--src/ruby/ext/grpc/rb_grpc.h2
-rw-r--r--src/ruby/ext/grpc/rb_metadata.c9
-rw-r--r--src/ruby/ext/grpc/rb_metadata.h4
-rw-r--r--src/ruby/ext/grpc/rb_server.c8
-rw-r--r--src/ruby/ext/grpc/rb_server.h2
-rw-r--r--src/ruby/ext/grpc/rb_server_credentials.c15
-rw-r--r--src/ruby/ext/grpc/rb_server_credentials.h2
205 files changed, 7761 insertions, 3085 deletions
diff --git a/src/compiler/cpp_generator.cc b/src/compiler/cpp_generator.cc
index 14d5005dc0..1116049806 100644
--- a/src/compiler/cpp_generator.cc
+++ b/src/compiler/cpp_generator.cc
@@ -43,23 +43,19 @@ namespace grpc_cpp_generator {
namespace {
bool NoStreaming(const google::protobuf::MethodDescriptor* method) {
- return !method->client_streaming() &&
- !method->server_streaming();
+ return !method->client_streaming() && !method->server_streaming();
}
bool ClientOnlyStreaming(const google::protobuf::MethodDescriptor* method) {
- return method->client_streaming() &&
- !method->server_streaming();
+ return method->client_streaming() && !method->server_streaming();
}
bool ServerOnlyStreaming(const google::protobuf::MethodDescriptor* method) {
- return !method->client_streaming() &&
- method->server_streaming();
+ return !method->client_streaming() && method->server_streaming();
}
bool BidiStreaming(const google::protobuf::MethodDescriptor* method) {
- return method->client_streaming() &&
- method->server_streaming();
+ return method->client_streaming() && method->server_streaming();
}
bool HasClientOnlyStreaming(const google::protobuf::FileDescriptor* file) {
@@ -98,7 +94,7 @@ bool HasBidiStreaming(const google::protobuf::FileDescriptor* file) {
string GetHeaderIncludes(const google::protobuf::FileDescriptor* file) {
string temp =
- "#include \"src/cpp/client/internal_stub.h\"\n"
+ "#include \"grpc++/impl/internal_stub.h\"\n"
"#include \"grpc++/status.h\"\n"
"\n"
"namespace grpc {\n"
@@ -126,15 +122,15 @@ string GetHeaderIncludes(const google::protobuf::FileDescriptor* file) {
}
string GetSourceIncludes() {
- return "#include \"src/cpp/rpc_method.h\"\n"
- "#include \"src/cpp/server/rpc_service_method.h\"\n"
- "#include \"grpc++/channel_interface.h\"\n"
+ return "#include \"grpc++/channel_interface.h\"\n"
+ "#include \"grpc++/impl/rpc_method.h\"\n"
+ "#include \"grpc++/impl/rpc_service_method.h\"\n"
"#include \"grpc++/stream.h\"\n";
}
void PrintHeaderClientMethod(google::protobuf::io::Printer* printer,
- const google::protobuf::MethodDescriptor* method,
- map<string, string>* vars) {
+ const google::protobuf::MethodDescriptor* method,
+ map<string, string>* vars) {
(*vars)["Method"] = method->name();
(*vars)["Request"] =
grpc_cpp_generator::ClassName(method->input_type(), true);
@@ -205,8 +201,9 @@ void PrintHeaderService(google::protobuf::io::Printer* printer,
printer->Indent();
// Client side
- printer->Print("class Stub : public ::grpc::InternalStub {\n"
- " public:\n");
+ printer->Print(
+ "class Stub : public ::grpc::InternalStub {\n"
+ " public:\n");
printer->Indent();
for (int i = 0; i < service->method_count(); ++i) {
PrintHeaderClientMethod(printer, service->method(i), vars);
@@ -220,8 +217,9 @@ void PrintHeaderService(google::protobuf::io::Printer* printer,
printer->Print("\n");
// Server side
- printer->Print("class Service {\n"
- " public:\n");
+ printer->Print(
+ "class Service {\n"
+ " public:\n");
printer->Indent();
printer->Print("Service() : service_(nullptr) {}\n");
printer->Print("virtual ~Service();\n");
@@ -230,8 +228,9 @@ void PrintHeaderService(google::protobuf::io::Printer* printer,
}
printer->Print("::grpc::RpcService* service();\n");
printer->Outdent();
- printer->Print(" private:\n"
- " ::grpc::RpcService* service_;\n");
+ printer->Print(
+ " private:\n"
+ " ::grpc::RpcService* service_;\n");
printer->Print("};\n");
printer->Outdent();
@@ -252,8 +251,8 @@ string GetHeaderServices(const google::protobuf::FileDescriptor* file) {
}
void PrintSourceClientMethod(google::protobuf::io::Printer* printer,
- const google::protobuf::MethodDescriptor* method,
- map<string, string>* vars) {
+ const google::protobuf::MethodDescriptor* method,
+ map<string, string>* vars) {
(*vars)["Method"] = method->name();
(*vars)["Request"] =
grpc_cpp_generator::ClassName(method->input_type(), true);
@@ -309,8 +308,8 @@ void PrintSourceClientMethod(google::protobuf::io::Printer* printer,
}
void PrintSourceServerMethod(google::protobuf::io::Printer* printer,
- const google::protobuf::MethodDescriptor* method,
- map<string, string>* vars) {
+ const google::protobuf::MethodDescriptor* method,
+ map<string, string>* vars) {
(*vars)["Method"] = method->name();
(*vars)["Request"] =
grpc_cpp_generator::ClassName(method->input_type(), true);
@@ -363,12 +362,12 @@ void PrintSourceService(google::protobuf::io::Printer* printer,
map<string, string>* vars) {
(*vars)["Service"] = service->name();
printer->Print(*vars,
- "$Service$::Stub* $Service$::NewStub("
- "const std::shared_ptr<::grpc::ChannelInterface>& channel) {\n"
- " $Service$::Stub* stub = new $Service$::Stub();\n"
- " stub->set_channel(channel);\n"
- " return stub;\n"
- "};\n\n");
+ "$Service$::Stub* $Service$::NewStub("
+ "const std::shared_ptr<::grpc::ChannelInterface>& channel) {\n"
+ " $Service$::Stub* stub = new $Service$::Stub();\n"
+ " stub->set_channel(channel);\n"
+ " return stub;\n"
+ "};\n\n");
for (int i = 0; i < service->method_count(); ++i) {
PrintSourceClientMethod(printer, service->method(i), vars);
}
@@ -381,11 +380,12 @@ void PrintSourceService(google::protobuf::io::Printer* printer,
PrintSourceServerMethod(printer, service->method(i), vars);
}
printer->Print(*vars,
- "::grpc::RpcService* $Service$::Service::service() {\n");
+ "::grpc::RpcService* $Service$::Service::service() {\n");
printer->Indent();
- printer->Print("if (service_ != nullptr) {\n"
- " return service_;\n"
- "}\n");
+ printer->Print(
+ "if (service_ != nullptr) {\n"
+ " return service_;\n"
+ "}\n");
printer->Print("service_ = new ::grpc::RpcService();\n");
for (int i = 0; i < service->method_count(); ++i) {
const google::protobuf::MethodDescriptor* method = service->method(i);
diff --git a/src/compiler/cpp_generator_helpers.h b/src/compiler/cpp_generator_helpers.h
index 8d8b03ea43..ba251faf29 100644
--- a/src/compiler/cpp_generator_helpers.h
+++ b/src/compiler/cpp_generator_helpers.h
@@ -85,7 +85,8 @@ inline string DotsToUnderscores(const string& name) {
return StringReplace(name, ".", "_");
}
-inline string ClassName(const google::protobuf::Descriptor* descriptor, bool qualified) {
+inline string ClassName(const google::protobuf::Descriptor* descriptor,
+ bool qualified) {
// Find "outer", the descriptor of the top-level message in which
// "descriptor" is embedded.
const google::protobuf::Descriptor* outer = descriptor;
diff --git a/src/compiler/cpp_plugin.cc b/src/compiler/cpp_plugin.cc
index 7aa745a4f1..17836b1612 100644
--- a/src/compiler/cpp_plugin.cc
+++ b/src/compiler/cpp_plugin.cc
@@ -54,9 +54,10 @@ class CppGrpcGenerator : public google::protobuf::compiler::CodeGenerator {
google::protobuf::compiler::GeneratorContext* context,
string* error) const {
if (file->options().cc_generic_services()) {
- *error = "cpp grpc proto compiler plugin does not work with generic "
- "services. To generate cpp grpc APIs, please set \""
- "cc_generic_service = false\".";
+ *error =
+ "cpp grpc proto compiler plugin does not work with generic "
+ "services. To generate cpp grpc APIs, please set \""
+ "cc_generic_service = false\".";
return false;
}
diff --git a/src/compiler/go_generator.cc b/src/compiler/go_generator.cc
new file mode 100644
index 0000000000..84aa27668e
--- /dev/null
+++ b/src/compiler/go_generator.cc
@@ -0,0 +1,530 @@
+/*
+ *
+ * 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/compiler/go_generator.h"
+
+#include <cctype>
+
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/descriptor.h>
+
+using namespace std;
+
+namespace grpc_go_generator {
+
+bool NoStreaming(const google::protobuf::MethodDescriptor* method) {
+ return !method->client_streaming() && !method->server_streaming();
+}
+
+bool ClientOnlyStreaming(const google::protobuf::MethodDescriptor* method) {
+ return method->client_streaming() && !method->server_streaming();
+}
+
+bool ServerOnlyStreaming(const google::protobuf::MethodDescriptor* method) {
+ return !method->client_streaming() && method->server_streaming();
+}
+
+bool BidiStreaming(const google::protobuf::MethodDescriptor* method) {
+ return method->client_streaming() && method->server_streaming();
+}
+
+bool HasClientOnlyStreaming(const google::protobuf::FileDescriptor* file) {
+ for (int i = 0; i < file->service_count(); i++) {
+ for (int j = 0; j < file->service(i)->method_count(); j++) {
+ if (ClientOnlyStreaming(file->service(i)->method(j))) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+string LowerCaseService(const string& service) {
+ string ret = service;
+ if (!ret.empty() && ret[0] >= 'A' && ret[0] <= 'Z') {
+ ret[0] = ret[0] - 'A' + 'a';
+ }
+ return ret;
+}
+
+void PrintClientMethodDef(google::protobuf::io::Printer* printer,
+ const google::protobuf::MethodDescriptor* method,
+ map<string, string>* vars) {
+ (*vars)["Method"] = method->name();
+ (*vars)["Request"] = method->input_type()->name();
+ (*vars)["Response"] = method->output_type()->name();
+ if (NoStreaming(method)) {
+ printer->Print(*vars,
+ "\t$Method$(ctx context.Context, in *$Request$, opts "
+ "...rpc.CallOption) "
+ "(*$Response$, error)\n");
+ } else if (BidiStreaming(method)) {
+ printer->Print(*vars,
+ "\t$Method$(ctx context.Context, opts ...rpc.CallOption) "
+ "($Service$_$Method$Client, error)\n");
+ } else if (ServerOnlyStreaming(method)) {
+ printer->Print(
+ *vars,
+ "\t$Method$(ctx context.Context, m *$Request$, opts ...rpc.CallOption) "
+ "($Service$_$Method$Client, error)\n");
+ } else if (ClientOnlyStreaming(method)) {
+ printer->Print(*vars,
+ "\t$Method$(ctx context.Context, opts ...rpc.CallOption) "
+ "($Service$_$Method$Client, error)\n");
+ }
+}
+
+void PrintClientMethodImpl(google::protobuf::io::Printer* printer,
+ const google::protobuf::MethodDescriptor* method,
+ map<string, string>* vars) {
+ (*vars)["Method"] = method->name();
+ (*vars)["Request"] = method->input_type()->name();
+ (*vars)["Response"] = method->output_type()->name();
+
+ if (NoStreaming(method)) {
+ printer->Print(
+ *vars,
+ "func (c *$ServiceStruct$Client) $Method$(ctx context.Context, "
+ "in *$Request$, opts ...rpc.CallOption) (*$Response$, error) {\n");
+ printer->Print(*vars, "\tout := new($Response$)\n");
+ printer->Print(*vars,
+ "\terr := rpc.Invoke(ctx, \"/$Package$$Service$/$Method$\", "
+ "in, out, c.cc, opts...)\n");
+ printer->Print("\tif err != nil {\n");
+ printer->Print("\t\treturn nil, err\n");
+ printer->Print("\t}\n");
+ printer->Print("\treturn out, nil\n");
+ printer->Print("}\n\n");
+ } else if (BidiStreaming(method)) {
+ printer->Print(
+ *vars,
+ "func (c *$ServiceStruct$Client) $Method$(ctx context.Context, opts "
+ "...rpc.CallOption) ($Service$_$Method$Client, error) {\n"
+ "\tstream, err := rpc.NewClientStream(ctx, c.cc, "
+ "\"/$Package$$Service$/$Method$\", opts...)\n"
+ "\tif err != nil {\n"
+ "\t\treturn nil, err\n"
+ "\t}\n"
+ "\treturn &$ServiceStruct$$Method$Client{stream}, nil\n"
+ "}\n\n");
+ printer->Print(*vars,
+ "type $Service$_$Method$Client interface {\n"
+ "\tSend(*$Request$) error\n"
+ "\tRecv() (*$Response$, error)\n"
+ "\trpc.ClientStream\n"
+ "}\n\n");
+ printer->Print(*vars,
+ "type $ServiceStruct$$Method$Client struct {\n"
+ "\trpc.ClientStream\n"
+ "}\n\n");
+ printer->Print(
+ *vars,
+ "func (x *$ServiceStruct$$Method$Client) Send(m *$Request$) error {\n"
+ "\treturn x.ClientStream.SendProto(m)\n"
+ "}\n\n");
+ printer->Print(
+ *vars,
+ "func (x *$ServiceStruct$$Method$Client) Recv() (*$Response$, error) "
+ "{\n"
+ "\tm := new($Response$)\n"
+ "\tif err := x.ClientStream.RecvProto(m); err != nil {\n"
+ "\t\treturn nil, err\n"
+ "\t}\n"
+ "\treturn m, nil\n"
+ "}\n\n");
+ } else if (ServerOnlyStreaming(method)) {
+ printer->Print(
+ *vars,
+ "func (c *$ServiceStruct$Client) $Method$(ctx context.Context, m "
+ "*$Request$, "
+ "opts ...rpc.CallOption) ($Service$_$Method$Client, error) {\n"
+ "\tstream, err := rpc.NewClientStream(ctx, c.cc, "
+ "\"/$Package$$Service$/$Method$\", opts...)\n"
+ "\tif err != nil {\n"
+ "\t\treturn nil, err\n"
+ "\t}\n"
+ "\tx := &$ServiceStruct$$Method$Client{stream}\n"
+ "\tif err := x.ClientStream.SendProto(m); err != nil {\n"
+ "\t\treturn nil, err\n"
+ "\t}\n"
+ "\tif err := x.ClientStream.CloseSend(); err != nil {\n"
+ "\t\treturn nil, err\n"
+ "\t}\n"
+ "\treturn x, nil\n"
+ "}\n\n");
+ printer->Print(*vars,
+ "type $Service$_$Method$Client interface {\n"
+ "\tRecv() (*$Response$, error)\n"
+ "\trpc.ClientStream\n"
+ "}\n\n");
+ printer->Print(*vars,
+ "type $ServiceStruct$$Method$Client struct {\n"
+ "\trpc.ClientStream\n"
+ "}\n\n");
+ printer->Print(
+ *vars,
+ "func (x *$ServiceStruct$$Method$Client) Recv() (*$Response$, error) "
+ "{\n"
+ "\tm := new($Response$)\n"
+ "\tif err := x.ClientStream.RecvProto(m); err != nil {\n"
+ "\t\treturn nil, err\n"
+ "\t}\n"
+ "\treturn m, nil\n"
+ "}\n\n");
+ } else if (ClientOnlyStreaming(method)) {
+ printer->Print(
+ *vars,
+ "func (c *$ServiceStruct$Client) $Method$(ctx context.Context, opts "
+ "...rpc.CallOption) ($Service$_$Method$Client, error) {\n"
+ "\tstream, err := rpc.NewClientStream(ctx, c.cc, "
+ "\"/$Package$$Service$/$Method$\", opts...)\n"
+ "\tif err != nil {\n"
+ "\t\treturn nil, err\n"
+ "\t}\n"
+ "\treturn &$ServiceStruct$$Method$Client{stream}, nil\n"
+ "}\n\n");
+ printer->Print(*vars,
+ "type $Service$_$Method$Client interface {\n"
+ "\tSend(*$Request$) error\n"
+ "\tCloseAndRecv() (*$Response$, error)\n"
+ "\trpc.ClientStream\n"
+ "}\n\n");
+ printer->Print(*vars,
+ "type $ServiceStruct$$Method$Client struct {\n"
+ "\trpc.ClientStream\n"
+ "}\n\n");
+ printer->Print(
+ *vars,
+ "func (x *$ServiceStruct$$Method$Client) Send(m *$Request$) error {\n"
+ "\treturn x.ClientStream.SendProto(m)\n"
+ "}\n\n");
+ printer->Print(
+ *vars,
+ "func (x *$ServiceStruct$$Method$Client) CloseAndRecv() (*$Response$, "
+ "error) {\n"
+ "\tif err := x.ClientStream.CloseSend(); err != nil {\n"
+ "\t\treturn nil, err\n"
+ "\t}\n"
+ "\tm := new($Response$)\n"
+ "\tif err := x.ClientStream.RecvProto(m); err != nil {\n"
+ "\t\treturn nil, err\n"
+ "\t}\n"
+ "\t// Read EOF.\n"
+ "\tif err := x.ClientStream.RecvProto(m); err == io.EOF {\n"
+ "\t\treturn m, io.EOF\n"
+ "\t}\n"
+ "\t// gRPC protocol violation.\n"
+ "\treturn m, fmt.Errorf(\"Violate gRPC client streaming protocol: no "
+ "EOF after the response.\")\n"
+ "}\n\n");
+ }
+}
+
+void PrintClient(google::protobuf::io::Printer* printer,
+ const google::protobuf::ServiceDescriptor* service,
+ map<string, string>* vars) {
+ (*vars)["Service"] = service->name();
+ (*vars)["ServiceStruct"] = LowerCaseService(service->name());
+ printer->Print(*vars, "type $Service$Client interface {\n");
+ for (int i = 0; i < service->method_count(); ++i) {
+ PrintClientMethodDef(printer, service->method(i), vars);
+ }
+ printer->Print("}\n\n");
+
+ printer->Print(*vars,
+ "type $ServiceStruct$Client struct {\n"
+ "\tcc *rpc.ClientConn\n"
+ "}\n\n");
+ printer->Print(
+ *vars,
+ "func New$Service$Client(cc *rpc.ClientConn) $Service$Client {\n"
+ "\treturn &$ServiceStruct$Client{cc}\n"
+ "}\n\n");
+ for (int i = 0; i < service->method_count(); ++i) {
+ PrintClientMethodImpl(printer, service->method(i), vars);
+ }
+}
+
+void PrintServerMethodDef(google::protobuf::io::Printer* printer,
+ const google::protobuf::MethodDescriptor* method,
+ map<string, string>* vars) {
+ (*vars)["Method"] = method->name();
+ (*vars)["Request"] = method->input_type()->name();
+ (*vars)["Response"] = method->output_type()->name();
+ if (NoStreaming(method)) {
+ printer->Print(
+ *vars,
+ "\t$Method$(context.Context, *$Request$) (*$Response$, error)\n");
+ } else if (BidiStreaming(method)) {
+ printer->Print(*vars, "\t$Method$($Service$_$Method$Server) error\n");
+ } else if (ServerOnlyStreaming(method)) {
+ printer->Print(*vars,
+ "\t$Method$(*$Request$, $Service$_$Method$Server) error\n");
+ } else if (ClientOnlyStreaming(method)) {
+ printer->Print(*vars, "\t$Method$($Service$_$Method$Server) error\n");
+ }
+}
+
+void PrintServerHandler(google::protobuf::io::Printer* printer,
+ const google::protobuf::MethodDescriptor* method,
+ map<string, string>* vars) {
+ (*vars)["Method"] = method->name();
+ (*vars)["Request"] = method->input_type()->name();
+ (*vars)["Response"] = method->output_type()->name();
+ if (NoStreaming(method)) {
+ printer->Print(
+ *vars,
+ "func _$Service$_$Method$_Handler(srv interface{}, ctx context.Context,"
+ " buf []byte) (proto.Message, error) {\n");
+ printer->Print(*vars, "\tin := new($Request$)\n");
+ printer->Print("\tif err := proto.Unmarshal(buf, in); err != nil {\n");
+ printer->Print("\t\treturn nil, err\n");
+ printer->Print("\t}\n");
+ printer->Print(*vars,
+ "\tout, err := srv.($Service$Server).$Method$(ctx, in)\n");
+ printer->Print("\tif err != nil {\n");
+ printer->Print("\t\treturn nil, err\n");
+ printer->Print("\t}\n");
+ printer->Print("\treturn out, nil\n");
+ printer->Print("}\n\n");
+ } else if (BidiStreaming(method)) {
+ printer->Print(
+ *vars,
+ "func _$Service$_$Method$_Handler(srv interface{}, stream rpc.Stream) "
+ "error {\n"
+ "\treturn srv.($Service$Server).$Method$(&$ServiceStruct$$Method$Server"
+ "{stream})\n"
+ "}\n\n");
+ printer->Print(*vars,
+ "type $Service$_$Method$Server interface {\n"
+ "\tSend(*$Response$) error\n"
+ "\tRecv() (*$Request$, error)\n"
+ "\trpc.Stream\n"
+ "}\n\n");
+ printer->Print(*vars,
+ "type $ServiceStruct$$Method$Server struct {\n"
+ "\trpc.Stream\n"
+ "}\n\n");
+ printer->Print(
+ *vars,
+ "func (x *$ServiceStruct$$Method$Server) Send(m *$Response$) error {\n"
+ "\treturn x.Stream.SendProto(m)\n"
+ "}\n\n");
+ printer->Print(
+ *vars,
+ "func (x *$ServiceStruct$$Method$Server) Recv() (*$Request$, error) "
+ "{\n"
+ "\tm := new($Request$)\n"
+ "\tif err := x.Stream.RecvProto(m); err != nil {\n"
+ "\t\treturn nil, err\n"
+ "\t}\n"
+ "\treturn m, nil\n"
+ "}\n\n");
+ } else if (ServerOnlyStreaming(method)) {
+ printer->Print(
+ *vars,
+ "func _$Service$_$Method$_Handler(srv interface{}, stream rpc.Stream) "
+ "error {\n"
+ "\tm := new($Request$)\n"
+ "\tif err := stream.RecvProto(m); err != nil {\n"
+ "\t\treturn err\n"
+ "\t}\n"
+ "\treturn srv.($Service$Server).$Method$(m, "
+ "&$ServiceStruct$$Method$Server{stream})\n"
+ "}\n\n");
+ printer->Print(*vars,
+ "type $Service$_$Method$Server interface {\n"
+ "\tSend(*$Response$) error\n"
+ "\trpc.Stream\n"
+ "}\n\n");
+ printer->Print(*vars,
+ "type $ServiceStruct$$Method$Server struct {\n"
+ "\trpc.Stream\n"
+ "}\n\n");
+ printer->Print(
+ *vars,
+ "func (x *$ServiceStruct$$Method$Server) Send(m *$Response$) error {\n"
+ "\treturn x.Stream.SendProto(m)\n"
+ "}\n\n");
+ } else if (ClientOnlyStreaming(method)) {
+ printer->Print(
+ *vars,
+ "func _$Service$_$Method$_Handler(srv interface{}, stream rpc.Stream) "
+ "error {\n"
+ "\treturn srv.($Service$Server).$Method$(&$ServiceStruct$$Method$Server"
+ "{stream})\n"
+ "}\n\n");
+ printer->Print(*vars,
+ "type $Service$_$Method$Server interface {\n"
+ "\tSendAndClose(*$Response$) error\n"
+ "\tRecv() (*$Request$, error)\n"
+ "\trpc.Stream\n"
+ "}\n\n");
+ printer->Print(*vars,
+ "type $ServiceStruct$$Method$Server struct {\n"
+ "\trpc.Stream\n"
+ "}\n\n");
+ printer->Print(
+ *vars,
+ "func (x *$ServiceStruct$$Method$Server) SendAndClose(m *$Response$) "
+ "error {\n"
+ "\tif err := x.Stream.SendProto(m); err != nil {\n"
+ "\t\treturn err\n"
+ "\t}\n"
+ "\treturn nil\n"
+ "}\n\n");
+ printer->Print(
+ *vars,
+ "func (x *$ServiceStruct$$Method$Server) Recv() (*$Request$, error) {\n"
+ "\tm := new($Request$)\n"
+ "\tif err := x.Stream.RecvProto(m); err != nil {\n"
+ "\t\treturn nil, err\n"
+ "\t}\n"
+ "\treturn m, nil\n"
+ "}\n\n");
+ }
+}
+
+void PrintServerMethodDesc(google::protobuf::io::Printer* printer,
+ const google::protobuf::MethodDescriptor* method,
+ map<string, string>* vars) {
+ (*vars)["Method"] = method->name();
+ printer->Print("\t\t{\n");
+ printer->Print(*vars, "\t\t\tMethodName:\t\"$Method$\",\n");
+ printer->Print(*vars, "\t\t\tHandler:\t_$Service$_$Method$_Handler,\n");
+ printer->Print("\t\t},\n");
+}
+
+void PrintServerStreamingMethodDesc(
+ google::protobuf::io::Printer* printer,
+ const google::protobuf::MethodDescriptor* method,
+ map<string, string>* vars) {
+ (*vars)["Method"] = method->name();
+ printer->Print("\t\t{\n");
+ printer->Print(*vars, "\t\t\tStreamName:\t\"$Method$\",\n");
+ printer->Print(*vars, "\t\t\tHandler:\t_$Service$_$Method$_Handler,\n");
+ printer->Print("\t\t},\n");
+}
+
+void PrintServer(google::protobuf::io::Printer* printer,
+ const google::protobuf::ServiceDescriptor* service,
+ map<string, string>* vars) {
+ (*vars)["Service"] = service->name();
+ printer->Print(*vars, "type $Service$Server interface {\n");
+ for (int i = 0; i < service->method_count(); ++i) {
+ PrintServerMethodDef(printer, service->method(i), vars);
+ }
+ printer->Print("}\n\n");
+
+ printer->Print(*vars,
+ "func RegisterService(s *rpc.Server, srv $Service$Server) {\n"
+ "\ts.RegisterService(&_$Service$_serviceDesc, srv)\n"
+ "}\n\n");
+
+ for (int i = 0; i < service->method_count(); ++i) {
+ PrintServerHandler(printer, service->method(i), vars);
+ }
+
+ printer->Print(*vars,
+ "var _$Service$_serviceDesc = rpc.ServiceDesc{\n"
+ "\tServiceName: \"$Package$$Service$\",\n"
+ "\tHandlerType: (*$Service$Server)(nil),\n"
+ "\tMethods: []rpc.MethodDesc{\n");
+ for (int i = 0; i < service->method_count(); ++i) {
+ if (NoStreaming(service->method(i))) {
+ PrintServerMethodDesc(printer, service->method(i), vars);
+ }
+ }
+ printer->Print("\t},\n");
+
+ printer->Print("\tStreams: []rpc.StreamDesc{\n");
+ for (int i = 0; i < service->method_count(); ++i) {
+ if (!NoStreaming(service->method(i))) {
+ PrintServerStreamingMethodDesc(printer, service->method(i), vars);
+ }
+ }
+ printer->Print(
+ "\t},\n"
+ "}\n\n");
+}
+
+std::string BadToUnderscore(std::string str) {
+ for (unsigned i = 0; i < str.size(); ++i) {
+ if (!std::isalnum(str[i])) {
+ str[i] = '_';
+ }
+ }
+ return str;
+}
+
+string GetServices(const google::protobuf::FileDescriptor* file) {
+ string output;
+ google::protobuf::io::StringOutputStream output_stream(&output);
+ google::protobuf::io::Printer printer(&output_stream, '$');
+ map<string, string> vars;
+
+ string package_name = !file->options().go_package().empty()
+ ? file->options().go_package()
+ : file->package();
+ vars["PackageName"] = BadToUnderscore(package_name);
+ printer.Print(vars, "package $PackageName$\n\n");
+ printer.Print("import (\n");
+ if (HasClientOnlyStreaming(file)) {
+ printer.Print(
+ "\t\"fmt\"\n"
+ "\t\"io\"\n");
+ }
+ printer.Print(
+ "\t\"google/net/grpc/go/rpc\"\n"
+ "\tcontext \"google/third_party/golang/go_net/context/context\"\n"
+ "\tproto \"google/net/proto2/go/proto\"\n"
+ ")\n\n");
+
+ // $Package$ is used to fully qualify method names.
+ vars["Package"] = file->package();
+ if (!file->package().empty()) {
+ vars["Package"].append(".");
+ }
+
+ for (int i = 0; i < file->service_count(); ++i) {
+ PrintClient(&printer, file->service(0), &vars);
+ printer.Print("\n");
+ PrintServer(&printer, file->service(0), &vars);
+ printer.Print("\n");
+ }
+ return output;
+}
+
+} // namespace grpc_go_generator
diff --git a/src/cpp/rpc_method.h b/src/compiler/go_generator.h
index 24a34bed89..5744345b56 100644
--- a/src/cpp/rpc_method.h
+++ b/src/compiler/go_generator.h
@@ -31,39 +31,21 @@
*
*/
-#ifndef __GRPCPP_INTERNAL_RPC_METHOD_H__
-#define __GRPCPP_INTERNAL_RPC_METHOD_H__
+#ifndef NET_GRPC_COMPILER_GO_GENERATOR_H_
+#define NET_GRPC_COMPILER_GO_GENERATOR_H_
+
+#include <string>
namespace google {
namespace protobuf {
-class Message;
-}
-}
-
-namespace grpc {
-
-class RpcMethod {
- public:
- enum RpcType {
- NORMAL_RPC = 0,
- CLIENT_STREAMING, // request streaming
- SERVER_STREAMING, // response streaming
- BIDI_STREAMING
- };
-
- explicit RpcMethod(const char* name)
- : name_(name), method_type_(NORMAL_RPC) {}
- RpcMethod(const char* name, RpcType type) : name_(name), method_type_(type) {}
-
- const char *name() const { return name_; }
+class FileDescriptor;
+} // namespace protobuf
+} // namespace google
- RpcType method_type() const { return method_type_; }
+namespace grpc_go_generator {
- private:
- const char *name_;
- const RpcType method_type_;
-};
+std::string GetServices(const google::protobuf::FileDescriptor* file);
-} // namespace grpc
+} // namespace grpc_go_generator
-#endif // __GRPCPP_INTERNAL_RPC_METHOD_H__
+#endif // NET_GRPC_COMPILER_GO_GENERATOR_H_
diff --git a/src/compiler/go_plugin.cc b/src/compiler/go_plugin.cc
new file mode 100644
index 0000000000..c81612c0ab
--- /dev/null
+++ b/src/compiler/go_plugin.cc
@@ -0,0 +1,83 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+// Generates go gRPC service interface out of Protobuf IDL.
+//
+// This is a Proto2 compiler plugin. See net/proto2/compiler/proto/plugin.proto
+// and net/proto2/compiler/public/plugin.h for more information on plugins.
+
+#include <fstream>
+#include <memory>
+
+using namespace std;
+
+#include "src/compiler/go_generator.h"
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/plugin.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/descriptor.h>
+
+class GoGrpcGenerator : public google::protobuf::compiler::CodeGenerator {
+ public:
+ GoGrpcGenerator() {}
+ virtual ~GoGrpcGenerator() {}
+
+ virtual bool Generate(const google::protobuf::FileDescriptor* file,
+ const string& parameter,
+ google::protobuf::compiler::GeneratorContext* context,
+ string* error) const {
+ // Get output file name.
+ string file_name;
+ if (file->name().size() > 6 &&
+ file->name().find_last_of(".proto") == file->name().size() - 1) {
+ file_name =
+ file->name().substr(0, file->name().size() - 6) + "_grpc.pb.go";
+ } else {
+ *error = "Invalid proto file name. Proto file must end with .proto";
+ return false;
+ }
+
+ std::unique_ptr<google::protobuf::io::ZeroCopyOutputStream> output(
+ context->Open(file_name));
+ google::protobuf::io::CodedOutputStream coded_out(output.get());
+ string code = grpc_go_generator::GetServices(file);
+ coded_out.WriteRaw(code.data(), code.size());
+ return true;
+ }
+};
+
+int main(int argc, char* argv[]) {
+ GoGrpcGenerator generator;
+ return google::protobuf::compiler::PluginMain(argc, argv, &generator);
+}
diff --git a/src/compiler/ruby_generator.cc b/src/compiler/ruby_generator.cc
index 20485b47a5..fae8858ff7 100644
--- a/src/compiler/ruby_generator.cc
+++ b/src/compiler/ruby_generator.cc
@@ -67,9 +67,8 @@ void PrintMethod(const MethodDescriptor* method, const string& package,
output_type = "stream(" + output_type + ")";
}
map<string, string> method_vars = ListToDict({
- "mth.name", method->name(),
- "input.type", input_type,
- "output.type", output_type,
+ "mth.name", method->name(), "input.type", input_type, "output.type",
+ output_type,
});
out->Print(method_vars, "rpc :$mth.name$, $input.type$, $output.type$\n");
}
@@ -105,8 +104,7 @@ void PrintService(const ServiceDescriptor* service, const string& package,
out->Print("self.marshal_class_method = :encode\n");
out->Print("self.unmarshal_class_method = :decode\n");
map<string, string> pkg_vars = ListToDict({
- "service.name", service->name(),
- "pkg.name", package,
+ "service.name", service->name(), "pkg.name", package,
});
out->Print(pkg_vars, "self.service_name = '$pkg.name$.$service.name$'\n");
out->Print("\n");
@@ -139,9 +137,8 @@ string GetServices(const FileDescriptor* file) {
// Write out a file header.
map<string, string> header_comment_vars = ListToDict({
- "file.name", file->name(),
- "file.package", file->package(),
- });
+ "file.name", file->name(), "file.package", file->package(),
+ });
out.Print("# Generated by the protocol buffer compiler. DO NOT EDIT!\n");
out.Print(header_comment_vars,
"# Source: $file.name$ for package '$file.package$'\n");
diff --git a/src/compiler/ruby_generator_helpers-inl.h b/src/compiler/ruby_generator_helpers-inl.h
index 67a5eedd09..8263e353b2 100644
--- a/src/compiler/ruby_generator_helpers-inl.h
+++ b/src/compiler/ruby_generator_helpers-inl.h
@@ -47,8 +47,9 @@ inline bool ServicesFilename(const google::protobuf::FileDescriptor* file,
static const unsigned proto_suffix_length = 6; // length of ".proto"
if (file->name().size() > proto_suffix_length &&
file->name().find_last_of(".proto") == file->name().size() - 1) {
- *file_name_or_error = file->name().substr(
- 0, file->name().size() - proto_suffix_length) + "_services.rb";
+ *file_name_or_error =
+ file->name().substr(0, file->name().size() - proto_suffix_length) +
+ "_services.rb";
return true;
} else {
*file_name_or_error = "Invalid proto file name: must end with .proto";
@@ -56,7 +57,8 @@ inline bool ServicesFilename(const google::protobuf::FileDescriptor* file,
}
}
-inline string MessagesRequireName(const google::protobuf::FileDescriptor* file) {
+inline string MessagesRequireName(
+ const google::protobuf::FileDescriptor* file) {
return Replace(file->name(), ".proto", "");
}
diff --git a/src/compiler/ruby_generator_map-inl.h b/src/compiler/ruby_generator_map-inl.h
index ea5050652b..fa86fbb956 100644
--- a/src/compiler/ruby_generator_map-inl.h
+++ b/src/compiler/ruby_generator_map-inl.h
@@ -40,7 +40,6 @@
#include <string>
#include <vector>
-
using std::initializer_list;
using std::map;
using std::vector;
@@ -51,11 +50,12 @@ namespace grpc_ruby_generator {
// into a map of key* to value*. Is merely a readability helper for later code.
inline map<string, string> ListToDict(const initializer_list<string>& values) {
if (values.size() % 2 != 0) {
- // MOE: insert std::cerr << "Not every 'key' has a value in `values`." << std::endl;
+ // MOE: insert std::cerr << "Not every 'key' has a value in `values`."
+ // << std::endl;
}
map<string, string> value_map;
auto value_iter = values.begin();
- for (unsigned i = 0; i < values.size()/2; ++i) {
+ for (unsigned i = 0; i < values.size() / 2; ++i) {
string key = *value_iter;
++value_iter;
string value = *value_iter;
diff --git a/src/compiler/ruby_generator_string-inl.h b/src/compiler/ruby_generator_string-inl.h
index 85a76fa421..44e17a202a 100644
--- a/src/compiler/ruby_generator_string-inl.h
+++ b/src/compiler/ruby_generator_string-inl.h
@@ -45,7 +45,7 @@ using std::transform;
namespace grpc_ruby_generator {
// Split splits a string using char into elems.
-inline vector<string> &Split(const string &s, char delim,
+inline vector<string>& Split(const string& s, char delim,
vector<string>* elems) {
stringstream ss(s);
string item;
@@ -56,7 +56,7 @@ inline vector<string> &Split(const string &s, char delim,
}
// Split splits a string using char, returning the result in a vector.
-inline vector<string> Split(const string &s, char delim) {
+inline vector<string> Split(const string& s, char delim) {
vector<string> elems;
Split(s, delim, &elems);
return elems;
@@ -106,7 +106,7 @@ inline string CapitalizeFirst(string s) {
inline string RubyTypeOf(const string& a_type, const string& package) {
string res(a_type);
ReplacePrefix(&res, package, ""); // remove the leading package if present
- ReplacePrefix(&res, ".", ""); // remove the leading . (no package)
+ ReplacePrefix(&res, ".", ""); // remove the leading . (no package)
if (res.find('.') == string::npos) {
return res;
} else {
diff --git a/src/core/channel/channel_args.h b/src/core/channel/channel_args.h
index cf38d5d01f..92280450a1 100644
--- a/src/core/channel/channel_args.h
+++ b/src/core/channel/channel_args.h
@@ -51,4 +51,4 @@ void grpc_channel_args_destroy(grpc_channel_args *a);
is specified in channel args, otherwise returns 0. */
int grpc_channel_args_is_census_enabled(const grpc_channel_args *a);
-#endif /* __GRPC_INTERNAL_CHANNEL_CHANNEL_ARGS_H__ */
+#endif /* __GRPC_INTERNAL_CHANNEL_CHANNEL_ARGS_H__ */
diff --git a/src/core/channel/channel_stack.c b/src/core/channel/channel_stack.c
index 5ee412bf7d..14fc800778 100644
--- a/src/core/channel/channel_stack.c
+++ b/src/core/channel/channel_stack.c
@@ -54,7 +54,7 @@
/* Given a size, round up to the next multiple of sizeof(void*) */
#define ROUND_UP_TO_ALIGNMENT_SIZE(x) \
- (((x)+GPR_MAX_ALIGNMENT - 1) & ~(GPR_MAX_ALIGNMENT - 1))
+ (((x) + GPR_MAX_ALIGNMENT - 1) & ~(GPR_MAX_ALIGNMENT - 1))
size_t grpc_channel_stack_size(const grpc_channel_filter **filters,
size_t filter_count) {
@@ -190,14 +190,13 @@ void grpc_channel_next_op(grpc_channel_element *elem, grpc_channel_op *op) {
grpc_channel_stack *grpc_channel_stack_from_top_element(
grpc_channel_element *elem) {
- return (grpc_channel_stack *)((char *)(elem) -
- ROUND_UP_TO_ALIGNMENT_SIZE(
- sizeof(grpc_channel_stack)));
+ return (grpc_channel_stack *)((char *)(elem)-ROUND_UP_TO_ALIGNMENT_SIZE(
+ sizeof(grpc_channel_stack)));
}
grpc_call_stack *grpc_call_stack_from_top_element(grpc_call_element *elem) {
- return (grpc_call_stack *)((char *)(elem) - ROUND_UP_TO_ALIGNMENT_SIZE(
- sizeof(grpc_call_stack)));
+ return (grpc_call_stack *)((char *)(elem)-ROUND_UP_TO_ALIGNMENT_SIZE(
+ sizeof(grpc_call_stack)));
}
static void do_nothing(void *user_data, grpc_op_error error) {}
diff --git a/src/core/channel/channel_stack.h b/src/core/channel/channel_stack.h
index 14e972f539..eb68102b43 100644
--- a/src/core/channel/channel_stack.h
+++ b/src/core/channel/channel_stack.h
@@ -302,4 +302,4 @@ void grpc_call_element_send_cancel(grpc_call_element *cur_elem);
} while (0)
#endif
-#endif /* __GRPC_INTERNAL_CHANNEL_CHANNEL_STACK_H__ */
+#endif /* __GRPC_INTERNAL_CHANNEL_CHANNEL_STACK_H__ */
diff --git a/src/core/channel/client_channel.h b/src/core/channel/client_channel.h
index 576af64ec7..6b8a7d95a8 100644
--- a/src/core/channel/client_channel.h
+++ b/src/core/channel/client_channel.h
@@ -59,4 +59,4 @@ grpc_transport_setup_result grpc_client_channel_transport_setup_complete(
grpc_channel_filter const **channel_filters, size_t num_channel_filters,
grpc_mdctx *mdctx);
-#endif /* __GRPC_INTERNAL_CHANNEL_CLIENT_CHANNEL_H__ */
+#endif /* __GRPC_INTERNAL_CHANNEL_CLIENT_CHANNEL_H__ */
diff --git a/src/core/channel/client_setup.h b/src/core/channel/client_setup.h
index a508785e60..155a9a5b1a 100644
--- a/src/core/channel/client_setup.h
+++ b/src/core/channel/client_setup.h
@@ -64,4 +64,4 @@ gpr_timespec grpc_client_setup_request_deadline(grpc_client_setup_request *r);
grpc_mdctx *grpc_client_setup_get_mdctx(grpc_client_setup_request *r);
-#endif /* __GRPC_INTERNAL_CHANNEL_CLIENT_SETUP_H__ */
+#endif /* __GRPC_INTERNAL_CHANNEL_CLIENT_SETUP_H__ */
diff --git a/src/core/channel/connected_channel.c b/src/core/channel/connected_channel.c
index 5faa03c2f4..30de10905c 100644
--- a/src/core/channel/connected_channel.c
+++ b/src/core/channel/connected_channel.c
@@ -69,7 +69,7 @@ typedef struct {
/* We perform a small hack to locate transport data alongside the connected
channel data in call allocations, to allow everything to be pulled in minimal
cache line requests */
-#define TRANSPORT_STREAM_FROM_CALL_DATA(calld) ((grpc_stream *)((calld)+1))
+#define TRANSPORT_STREAM_FROM_CALL_DATA(calld) ((grpc_stream *)((calld) + 1))
#define CALL_DATA_FROM_TRANSPORT_STREAM(transport_stream) \
(((call_data *)(transport_stream)) - 1)
@@ -257,9 +257,9 @@ static void destroy_channel_elem(grpc_channel_element *elem) {
}
const grpc_channel_filter grpc_connected_channel_filter = {
- call_op, channel_op,
+ call_op, channel_op,
- sizeof(call_data), init_call_elem, destroy_call_elem,
+ sizeof(call_data), init_call_elem, destroy_call_elem,
sizeof(channel_data), init_channel_elem, destroy_channel_elem,
@@ -289,12 +289,8 @@ static void accept_stream(void *user_data, grpc_transport *transport,
}
static void recv_error(channel_data *chand, call_data *calld, int line,
- const char *fmt, ...) {
- va_list a;
-
- va_start(a, fmt);
- gpr_vlog(__FILE__, line, GPR_LOG_SEVERITY_ERROR, fmt, a);
- va_end(a);
+ const char *message) {
+ gpr_log_message(__FILE__, line, GPR_LOG_SEVERITY_ERROR, message);
if (chand->transport) {
grpc_transport_abort_stream(chand->transport,
@@ -388,19 +384,23 @@ static void recv_batch(void *user_data, grpc_transport *transport,
case GRPC_OP_BEGIN_MESSAGE:
/* can't begin a message when we're still reading a message */
if (calld->reading_message) {
- recv_error(chand, calld, __LINE__,
- "Message terminated early; read %d bytes, expected %d",
- calld->incoming_message.length,
- calld->incoming_message_length);
+ char message[128];
+ sprintf(message,
+ "Message terminated early; read %d bytes, expected %d",
+ (int)calld->incoming_message.length,
+ (int)calld->incoming_message_length);
+ recv_error(chand, calld, __LINE__, message);
return;
}
/* stash away parameters, and prepare for incoming slices */
length = stream_op->data.begin_message.length;
if (length > calld->max_message_length) {
- recv_error(
- chand, calld, __LINE__,
+ char message[128];
+ sprintf(
+ message,
"Maximum message length of %d exceeded by a message of length %d",
calld->max_message_length, length);
+ recv_error(chand, calld, __LINE__, message);
} else if (length > 0) {
calld->reading_message = 1;
calld->incoming_message_length = length;
@@ -423,10 +423,12 @@ static void recv_batch(void *user_data, grpc_transport *transport,
gpr_slice_buffer_add(&calld->incoming_message, stream_op->data.slice);
if (calld->incoming_message.length > calld->incoming_message_length) {
/* if we got too many bytes, complain */
- recv_error(chand, calld, __LINE__,
- "Receiving message overflow; read %d bytes, expected %d",
- calld->incoming_message.length,
- calld->incoming_message_length);
+ char message[128];
+ sprintf(message,
+ "Receiving message overflow; read %d bytes, expected %d",
+ (int)calld->incoming_message.length,
+ (int)calld->incoming_message_length);
+ recv_error(chand, calld, __LINE__, message);
return;
} else if (calld->incoming_message.length ==
calld->incoming_message_length) {
@@ -439,10 +441,11 @@ static void recv_batch(void *user_data, grpc_transport *transport,
final_state == GRPC_STREAM_CLOSED)) {
calld->got_read_close = 1;
if (calld->reading_message) {
- recv_error(chand, calld, __LINE__,
- "Last message truncated; read %d bytes, expected %d",
- calld->incoming_message.length,
- calld->incoming_message_length);
+ char message[128];
+ sprintf(message, "Last message truncated; read %d bytes, expected %d",
+ (int)calld->incoming_message.length,
+ (int)calld->incoming_message_length);
+ recv_error(chand, calld, __LINE__, message);
}
call_op.type = GRPC_RECV_HALF_CLOSE;
call_op.dir = GRPC_CALL_UP;
diff --git a/src/core/channel/connected_channel.h b/src/core/channel/connected_channel.h
index 660ea7ad89..9d143fc135 100644
--- a/src/core/channel/connected_channel.h
+++ b/src/core/channel/connected_channel.h
@@ -46,4 +46,4 @@ extern const grpc_channel_filter grpc_connected_channel_filter;
grpc_transport_setup_result grpc_connected_channel_bind_transport(
grpc_channel_stack *channel_stack, grpc_transport *transport);
-#endif /* __GRPC_INTERNAL_CHANNEL_CONNECTED_CHANNEL_H__ */
+#endif /* __GRPC_INTERNAL_CHANNEL_CONNECTED_CHANNEL_H__ */
diff --git a/src/core/channel/http_server_filter.c b/src/core/channel/http_server_filter.c
index 9a20d79c61..44eab43f09 100644
--- a/src/core/channel/http_server_filter.c
+++ b/src/core/channel/http_server_filter.c
@@ -32,13 +32,26 @@
*/
#include "src/core/channel/http_server_filter.h"
+
+#include <string.h>
#include <grpc/support/log.h>
-typedef struct call_data { int sent_status; } call_data;
+typedef struct call_data {
+ int sent_status;
+ int seen_scheme;
+ int seen_method;
+ int seen_te_trailers;
+} call_data;
typedef struct channel_data {
grpc_mdelem *te_trailers;
- grpc_mdelem *status_md;
+ grpc_mdelem *method;
+ grpc_mdelem *http_scheme;
+ grpc_mdelem *https_scheme;
+ /* TODO(klempner): Remove this once we stop using it */
+ grpc_mdelem *grpc_scheme;
+ grpc_mdelem *content_type;
+ grpc_mdelem *status;
} channel_data;
/* used to silence 'variable not used' warnings */
@@ -56,20 +69,54 @@ static void call_op(grpc_call_element *elem, grpc_call_element *from_elem,
channel_data *channeld = elem->channel_data;
GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
- ignore_unused(calld);
- ignore_unused(channeld);
-
switch (op->type) {
case GRPC_RECV_METADATA:
- /* check if it's a te: trailers header */
- if (op->data.metadata == channeld->te_trailers) {
+ /* Check if it is one of the headers we care about. */
+ if (op->data.metadata == channeld->te_trailers ||
+ op->data.metadata == channeld->method ||
+ op->data.metadata == channeld->http_scheme ||
+ op->data.metadata == channeld->https_scheme ||
+ op->data.metadata == channeld->grpc_scheme ||
+ op->data.metadata == channeld->content_type) {
/* swallow it */
+ if (op->data.metadata == channeld->method) {
+ calld->seen_method = 1;
+ } else if (op->data.metadata->key == channeld->http_scheme->key) {
+ calld->seen_scheme = 1;
+ } else if (op->data.metadata == channeld->te_trailers) {
+ calld->seen_te_trailers = 1;
+ }
+ /* TODO(klempner): Track that we've seen all the headers we should
+ require */
grpc_mdelem_unref(op->data.metadata);
op->done_cb(op->user_data, GRPC_OP_OK);
- } else if (op->data.metadata->key == channeld->te_trailers->key) {
- gpr_log(GPR_ERROR, "Invalid te: header: '%s'",
+ } else if (op->data.metadata->key == channeld->content_type->key) {
+ if (strncmp(grpc_mdstr_as_c_string(op->data.metadata->value),
+ "application/grpc+", 17) == 0) {
+ /* Although the C implementation doesn't (currently) generate them,
+ any
+ custom +-suffix is explicitly valid. */
+ /* TODO(klempner): We should consider preallocating common values such
+ as +proto or +json, or at least stashing them if we see them. */
+ /* TODO(klempner): Should we be surfacing this to application code? */
+ } else {
+ /* TODO(klempner): We're currently allowing this, but we shouldn't
+ see it without a proxy so log for now. */
+ gpr_log(GPR_INFO, "Unexpected content-type %s",
+ channeld->content_type->key);
+ }
+ grpc_mdelem_unref(op->data.metadata);
+ op->done_cb(op->user_data, GRPC_OP_OK);
+ } else if (op->data.metadata->key == channeld->te_trailers->key ||
+ op->data.metadata->key == channeld->method->key ||
+ op->data.metadata->key == channeld->http_scheme->key ||
+ op->data.metadata->key == channeld->content_type->key) {
+ gpr_log(GPR_ERROR, "Invalid %s: header: '%s'",
+ grpc_mdstr_as_c_string(op->data.metadata->key),
grpc_mdstr_as_c_string(op->data.metadata->value));
- /* swallow it */
+ /* swallow it and error everything out. */
+ /* TODO(klempner): We ought to generate more descriptive error messages
+ on the wire here. */
grpc_mdelem_unref(op->data.metadata);
op->done_cb(op->user_data, GRPC_OP_OK);
grpc_call_element_send_cancel(elem);
@@ -78,14 +125,33 @@ static void call_op(grpc_call_element *elem, grpc_call_element *from_elem,
grpc_call_next_op(elem, op);
}
break;
+ case GRPC_RECV_END_OF_INITIAL_METADATA:
+ /* Have we seen the required http2 transport headers?
+ (:method, :scheme, content-type, with :path and :authority covered
+ at the channel level right now) */
+ if (calld->seen_method && calld->seen_scheme && calld->seen_te_trailers) {
+ grpc_call_next_op(elem, op);
+ } else {
+ if (!calld->seen_method) {
+ gpr_log(GPR_ERROR, "Missing :method header");
+ } else if (!calld->seen_scheme) {
+ gpr_log(GPR_ERROR, "Missing :scheme header");
+ } else if (!calld->seen_te_trailers) {
+ gpr_log(GPR_ERROR, "Missing te trailers header");
+ }
+ /* Error this call out */
+ op->done_cb(op->user_data, GRPC_OP_OK);
+ grpc_call_element_send_cancel(elem);
+ }
+ break;
case GRPC_SEND_START:
case GRPC_SEND_METADATA:
/* If we haven't sent status 200 yet, we need to so so because it needs to
come before any non : prefixed metadata. */
if (!calld->sent_status) {
calld->sent_status = 1;
- /* status_md is reffed by grpc_call_element_send_metadata */
- grpc_call_element_send_metadata(elem, channeld->status_md);
+ /* status is reffed by grpc_call_element_send_metadata */
+ grpc_call_element_send_metadata(elem, channeld->status);
}
grpc_call_next_op(elem, op);
break;
@@ -124,6 +190,9 @@ static void init_call_elem(grpc_call_element *elem,
/* initialize members */
calld->sent_status = 0;
+ calld->seen_scheme = 0;
+ calld->seen_method = 0;
+ calld->seen_te_trailers = 0;
}
/* Destructor for call_data */
@@ -151,7 +220,13 @@ static void init_channel_elem(grpc_channel_element *elem,
/* initialize members */
channeld->te_trailers = grpc_mdelem_from_strings(mdctx, "te", "trailers");
- channeld->status_md = grpc_mdelem_from_strings(mdctx, ":status", "200");
+ channeld->status = grpc_mdelem_from_strings(mdctx, ":status", "200");
+ channeld->method = grpc_mdelem_from_strings(mdctx, ":method", "POST");
+ channeld->http_scheme = grpc_mdelem_from_strings(mdctx, ":scheme", "http");
+ channeld->https_scheme = grpc_mdelem_from_strings(mdctx, ":scheme", "https");
+ channeld->grpc_scheme = grpc_mdelem_from_strings(mdctx, ":scheme", "grpc");
+ channeld->content_type =
+ grpc_mdelem_from_strings(mdctx, "content-type", "application/grpc");
}
/* Destructor for channel data */
@@ -160,7 +235,12 @@ static void destroy_channel_elem(grpc_channel_element *elem) {
channel_data *channeld = elem->channel_data;
grpc_mdelem_unref(channeld->te_trailers);
- grpc_mdelem_unref(channeld->status_md);
+ grpc_mdelem_unref(channeld->status);
+ grpc_mdelem_unref(channeld->method);
+ grpc_mdelem_unref(channeld->http_scheme);
+ grpc_mdelem_unref(channeld->https_scheme);
+ grpc_mdelem_unref(channeld->grpc_scheme);
+ grpc_mdelem_unref(channeld->content_type);
}
const grpc_channel_filter grpc_http_server_filter = {
diff --git a/src/core/channel/metadata_buffer.c b/src/core/channel/metadata_buffer.c
index 75fd90b707..d4de4ba576 100644
--- a/src/core/channel/metadata_buffer.c
+++ b/src/core/channel/metadata_buffer.c
@@ -61,7 +61,7 @@ struct grpc_metadata_buffer_impl {
size_t elem_cap;
};
-#define ELEMS(buffer) ((qelem *)((buffer)+1))
+#define ELEMS(buffer) ((qelem *)((buffer) + 1))
void grpc_metadata_buffer_init(grpc_metadata_buffer *buffer) {
/* start buffer as NULL, indicating no elements */
diff --git a/src/core/channel/metadata_buffer.h b/src/core/channel/metadata_buffer.h
index 818b290ce2..011dabed1b 100644
--- a/src/core/channel/metadata_buffer.h
+++ b/src/core/channel/metadata_buffer.h
@@ -67,4 +67,4 @@ grpc_metadata *grpc_metadata_buffer_extract_elements(
grpc_metadata_buffer *buffer);
void grpc_metadata_buffer_cleanup_elements(void *elements, grpc_op_error error);
-#endif /* __GRPC_INTERNAL_CHANNEL_METADATA_BUFFER_H__ */
+#endif /* __GRPC_INTERNAL_CHANNEL_METADATA_BUFFER_H__ */
diff --git a/src/core/channel/noop_filter.c b/src/core/channel/noop_filter.c
index b6b3f661f7..6f854a2b87 100644
--- a/src/core/channel/noop_filter.c
+++ b/src/core/channel/noop_filter.c
@@ -131,9 +131,9 @@ static void destroy_channel_elem(grpc_channel_element *elem) {
}
const grpc_channel_filter grpc_no_op_filter = {
- call_op, channel_op,
+ call_op, channel_op,
- sizeof(call_data), init_call_elem, destroy_call_elem,
+ sizeof(call_data), init_call_elem, destroy_call_elem,
sizeof(channel_data), init_channel_elem, destroy_channel_elem,
diff --git a/src/core/channel/noop_filter.h b/src/core/channel/noop_filter.h
index 4057ff7ac9..269214f893 100644
--- a/src/core/channel/noop_filter.h
+++ b/src/core/channel/noop_filter.h
@@ -41,4 +41,4 @@
customize for their own filters */
extern const grpc_channel_filter grpc_no_op_filter;
-#endif /* __GRPC_INTERNAL_CHANNEL_NOOP_FILTER_H__ */
+#endif /* __GRPC_INTERNAL_CHANNEL_NOOP_FILTER_H__ */
diff --git a/src/core/compression/algorithm.h b/src/core/compression/algorithm.h
index 05895a889e..c5ec6d21b6 100644
--- a/src/core/compression/algorithm.h
+++ b/src/core/compression/algorithm.h
@@ -46,4 +46,4 @@ typedef enum {
const char *grpc_compression_algorithm_name(
grpc_compression_algorithm algorithm);
-#endif /* __GRPC_INTERNAL_COMPRESSION_ALGORITHM_H__ */
+#endif /* __GRPC_INTERNAL_COMPRESSION_ALGORITHM_H__ */
diff --git a/src/core/compression/message_compress.h b/src/core/compression/message_compress.h
index af8a0a5d75..564ca69a87 100644
--- a/src/core/compression/message_compress.h
+++ b/src/core/compression/message_compress.h
@@ -49,4 +49,4 @@ int grpc_msg_compress(grpc_compression_algorithm algorithm,
int grpc_msg_decompress(grpc_compression_algorithm algorithm,
gpr_slice_buffer *input, gpr_slice_buffer *output);
-#endif /* __GRPC_INTERNAL_COMPRESSION_MESSAGE_COMPRESS_H__ */
+#endif /* __GRPC_INTERNAL_COMPRESSION_MESSAGE_COMPRESS_H__ */
diff --git a/src/core/httpcli/format_request.h b/src/core/httpcli/format_request.h
index 988f872563..a82130cb93 100644
--- a/src/core/httpcli/format_request.h
+++ b/src/core/httpcli/format_request.h
@@ -42,4 +42,4 @@ gpr_slice grpc_httpcli_format_post_request(const grpc_httpcli_request *request,
const char *body_bytes,
size_t body_size);
-#endif /* __GRPC_INTERNAL_HTTPCLI_FORMAT_REQUEST_H__ */
+#endif /* __GRPC_INTERNAL_HTTPCLI_FORMAT_REQUEST_H__ */
diff --git a/src/core/httpcli/httpcli.h b/src/core/httpcli/httpcli.h
index ef8031354c..90f89a9366 100644
--- a/src/core/httpcli/httpcli.h
+++ b/src/core/httpcli/httpcli.h
@@ -115,4 +115,4 @@ typedef int (*grpc_httpcli_post_override)(const grpc_httpcli_request *request,
void grpc_httpcli_set_override(grpc_httpcli_get_override get,
grpc_httpcli_post_override post);
-#endif /* __GRPC_INTERNAL_HTTPCLI_HTTPCLI_H__ */
+#endif /* __GRPC_INTERNAL_HTTPCLI_HTTPCLI_H__ */
diff --git a/src/core/httpcli/httpcli_security_context.h b/src/core/httpcli/httpcli_security_context.h
index c267622e60..a73ecca0b3 100644
--- a/src/core/httpcli/httpcli_security_context.h
+++ b/src/core/httpcli/httpcli_security_context.h
@@ -40,4 +40,4 @@ grpc_security_status grpc_httpcli_ssl_channel_security_context_create(
const unsigned char *pem_root_certs, size_t pem_root_certs_size,
const char *secure_peer_name, grpc_channel_security_context **ctx);
-#endif /* __GRPC_INTERNAL_HTTPCLI_HTTPCLI_SECURITY_CONTEXT_H__ */
+#endif /* __GRPC_INTERNAL_HTTPCLI_HTTPCLI_SECURITY_CONTEXT_H__ */
diff --git a/src/core/httpcli/parser.h b/src/core/httpcli/parser.h
index e2c24a9993..520b16fd02 100644
--- a/src/core/httpcli/parser.h
+++ b/src/core/httpcli/parser.h
@@ -61,4 +61,4 @@ void grpc_httpcli_parser_destroy(grpc_httpcli_parser *parser);
int grpc_httpcli_parser_parse(grpc_httpcli_parser *parser, gpr_slice slice);
int grpc_httpcli_parser_eof(grpc_httpcli_parser *parser);
-#endif /* __GRPC_INTERNAL_HTTPCLI_PARSER_H__ */
+#endif /* __GRPC_INTERNAL_HTTPCLI_PARSER_H__ */
diff --git a/src/core/iomgr/pollset.h b/src/core/iomgr/pollset.h
index 7374a4ec13..36d80d5c29 100644
--- a/src/core/iomgr/pollset.h
+++ b/src/core/iomgr/pollset.h
@@ -35,6 +35,7 @@
#define __GRPC_INTERNAL_IOMGR_POLLSET_H_
#include <grpc/support/port_platform.h>
+#include <grpc/support/time.h>
/* A grpc_pollset is a set of file descriptors that a higher level item is
interested in. For example:
diff --git a/src/core/iomgr/sockaddr_utils.c b/src/core/iomgr/sockaddr_utils.c
index f709d35162..eca14a4f39 100644
--- a/src/core/iomgr/sockaddr_utils.c
+++ b/src/core/iomgr/sockaddr_utils.c
@@ -153,3 +153,31 @@ int grpc_sockaddr_to_string(char **out, const struct sockaddr *addr,
errno = save_errno;
return ret;
}
+
+int grpc_sockaddr_get_port(const struct sockaddr *addr) {
+ switch (addr->sa_family) {
+ case AF_INET:
+ return ntohs(((struct sockaddr_in *)addr)->sin_port);
+ case AF_INET6:
+ return ntohs(((struct sockaddr_in6 *)addr)->sin6_port);
+ default:
+ gpr_log(GPR_ERROR, "Unknown socket family %d in %s", addr->sa_family,
+ __FUNCTION__);
+ return 0;
+ }
+}
+
+int grpc_sockaddr_set_port(const struct sockaddr *addr, int port) {
+ switch (addr->sa_family) {
+ case AF_INET:
+ ((struct sockaddr_in *)addr)->sin_port = htons(port);
+ return 1;
+ case AF_INET6:
+ ((struct sockaddr_in6 *)addr)->sin6_port = htons(port);
+ return 1;
+ default:
+ gpr_log(GPR_ERROR, "Unknown socket family %d in %s", addr->sa_family,
+ __FUNCTION__);
+ return 0;
+ }
+}
diff --git a/src/core/iomgr/sockaddr_utils.h b/src/core/iomgr/sockaddr_utils.h
index 753d0c824a..3f5b770e86 100644
--- a/src/core/iomgr/sockaddr_utils.h
+++ b/src/core/iomgr/sockaddr_utils.h
@@ -57,6 +57,12 @@ int grpc_sockaddr_is_wildcard(const struct sockaddr *addr, int *port_out);
void grpc_sockaddr_make_wildcards(int port, struct sockaddr_in *wild4_out,
struct sockaddr_in6 *wild6_out);
+/* Return the IP port number of a sockaddr */
+int grpc_sockaddr_get_port(const struct sockaddr *addr);
+
+/* Set IP port number of a sockaddr */
+int grpc_sockaddr_set_port(const struct sockaddr *addr, int port);
+
/* Converts a sockaddr into a newly-allocated human-readable string.
Currently, only the AF_INET and AF_INET6 families are recognized.
diff --git a/src/core/iomgr/tcp_server.h b/src/core/iomgr/tcp_server.h
index 1968246b75..d881e146b9 100644
--- a/src/core/iomgr/tcp_server.h
+++ b/src/core/iomgr/tcp_server.h
@@ -52,7 +52,8 @@ grpc_tcp_server *grpc_tcp_server_create();
void grpc_tcp_server_start(grpc_tcp_server *server, grpc_pollset *pollset,
grpc_tcp_server_cb cb, void *cb_arg);
-/* Add a port to the server, returning true on success, or false otherwise.
+/* Add a port to the server, returning port number on success, or negative
+ on failure.
The :: and 0.0.0.0 wildcard addresses are treated identically, accepting
both IPv4 and IPv6 connections, but :: is the preferred style. This usually
@@ -60,6 +61,8 @@ void grpc_tcp_server_start(grpc_tcp_server *server, grpc_pollset *pollset,
but not dualstack sockets.
For raw access to the underlying sockets, see grpc_tcp_server_get_fd(). */
+/* TODO(ctiller): deprecate this, and make grpc_tcp_server_add_ports to handle
+ all of the multiple socket port matching logic in one place */
int grpc_tcp_server_add_port(grpc_tcp_server *s, const struct sockaddr *addr,
int addr_len);
diff --git a/src/core/iomgr/tcp_server_posix.c b/src/core/iomgr/tcp_server_posix.c
index 5ed517748a..753e24c38e 100644
--- a/src/core/iomgr/tcp_server_posix.c
+++ b/src/core/iomgr/tcp_server_posix.c
@@ -154,6 +154,9 @@ static int get_max_accept_queue_size() {
/* Prepare a recently-created socket for listening. */
static int prepare_socket(int fd, const struct sockaddr *addr, int addr_len) {
+ struct sockaddr_storage sockname_temp;
+ socklen_t sockname_len;
+
if (fd < 0) {
goto error;
}
@@ -179,13 +182,18 @@ static int prepare_socket(int fd, const struct sockaddr *addr, int addr_len) {
goto error;
}
- return 1;
+ sockname_len = sizeof(sockname_temp);
+ if (getsockname(fd, (struct sockaddr *)&sockname_temp, &sockname_len) < 0) {
+ goto error;
+ }
+
+ return grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp);
error:
if (fd >= 0) {
close(fd);
}
- return 0;
+ return -1;
}
/* event manager callback when reads are ready */
@@ -234,39 +242,64 @@ error:
static int add_socket_to_server(grpc_tcp_server *s, int fd,
const struct sockaddr *addr, int addr_len) {
server_port *sp;
+ int port;
- if (!prepare_socket(fd, addr, addr_len)) {
- return 0;
- }
-
- gpr_mu_lock(&s->mu);
- GPR_ASSERT(!s->cb && "must add ports before starting server");
- /* append it to the list under a lock */
- if (s->nports == s->port_capacity) {
- s->port_capacity *= 2;
- s->ports = gpr_realloc(s->ports, sizeof(server_port *) * s->port_capacity);
+ port = prepare_socket(fd, addr, addr_len);
+ if (port >= 0) {
+ gpr_mu_lock(&s->mu);
+ GPR_ASSERT(!s->cb && "must add ports before starting server");
+ /* append it to the list under a lock */
+ if (s->nports == s->port_capacity) {
+ s->port_capacity *= 2;
+ s->ports =
+ gpr_realloc(s->ports, sizeof(server_port *) * s->port_capacity);
+ }
+ sp = &s->ports[s->nports++];
+ sp->server = s;
+ sp->fd = fd;
+ sp->emfd = grpc_fd_create(fd);
+ GPR_ASSERT(sp->emfd);
+ gpr_mu_unlock(&s->mu);
}
- sp = &s->ports[s->nports++];
- sp->server = s;
- sp->fd = fd;
- sp->emfd = grpc_fd_create(fd);
- GPR_ASSERT(sp->emfd);
- gpr_mu_unlock(&s->mu);
- return 1;
+ return port;
}
int grpc_tcp_server_add_port(grpc_tcp_server *s, const struct sockaddr *addr,
int addr_len) {
- int ok = 0;
+ int allocated_port1 = -1;
+ int allocated_port2 = -1;
+ int i;
int fd;
grpc_dualstack_mode dsmode;
struct sockaddr_in6 addr6_v4mapped;
struct sockaddr_in wild4;
struct sockaddr_in6 wild6;
struct sockaddr_in addr4_copy;
+ struct sockaddr *allocated_addr = NULL;
+ struct sockaddr_storage sockname_temp;
+ socklen_t sockname_len;
int port;
+ /* Check if this is a wildcard port, and if so, try to keep the port the same
+ as some previously created listener. */
+ if (grpc_sockaddr_get_port(addr) == 0) {
+ for (i = 0; i < s->nports; i++) {
+ sockname_len = sizeof(sockname_temp);
+ if (0 == getsockname(s->ports[i].fd, (struct sockaddr *)&sockname_temp,
+ &sockname_len)) {
+ port = grpc_sockaddr_get_port((struct sockaddr *)&sockname_temp);
+ if (port > 0) {
+ allocated_addr = malloc(addr_len);
+ memcpy(allocated_addr, addr, addr_len);
+ grpc_sockaddr_set_port(allocated_addr, port);
+ addr = allocated_addr;
+ break;
+ }
+ }
+ }
+ }
+
if (grpc_sockaddr_to_v4mapped(addr, &addr6_v4mapped)) {
addr = (const struct sockaddr *)&addr6_v4mapped;
addr_len = sizeof(addr6_v4mapped);
@@ -280,12 +313,15 @@ int grpc_tcp_server_add_port(grpc_tcp_server *s, const struct sockaddr *addr,
addr = (struct sockaddr *)&wild6;
addr_len = sizeof(wild6);
fd = grpc_create_dualstack_socket(addr, SOCK_STREAM, 0, &dsmode);
- ok |= add_socket_to_server(s, fd, addr, addr_len);
+ allocated_port1 = add_socket_to_server(s, fd, addr, addr_len);
if (fd >= 0 && dsmode == GRPC_DSMODE_DUALSTACK) {
- return ok;
+ goto done;
}
/* If we didn't get a dualstack socket, also listen on 0.0.0.0. */
+ if (port == 0 && allocated_port1 > 0) {
+ grpc_sockaddr_set_port((struct sockaddr *)&wild4, allocated_port1);
+ }
addr = (struct sockaddr *)&wild4;
addr_len = sizeof(wild4);
}
@@ -299,8 +335,11 @@ int grpc_tcp_server_add_port(grpc_tcp_server *s, const struct sockaddr *addr,
addr = (struct sockaddr *)&addr4_copy;
addr_len = sizeof(addr4_copy);
}
- ok |= add_socket_to_server(s, fd, addr, addr_len);
- return ok;
+ allocated_port2 = add_socket_to_server(s, fd, addr, addr_len);
+
+done:
+ gpr_free(allocated_addr);
+ return allocated_port1 >= 0 ? allocated_port1 : allocated_port2;
}
int grpc_tcp_server_get_fd(grpc_tcp_server *s, int index) {
diff --git a/src/core/security/auth.c b/src/core/security/auth.c
index f743b25838..e36bf2382f 100644
--- a/src/core/security/auth.c
+++ b/src/core/security/auth.c
@@ -157,6 +157,5 @@ static void destroy_channel_elem(grpc_channel_element *elem) {
}
const grpc_channel_filter grpc_client_auth_filter = {
- call_op, channel_op, sizeof(call_data),
- init_call_elem, destroy_call_elem, sizeof(channel_data),
- init_channel_elem, destroy_channel_elem, "auth"};
+ call_op, channel_op, sizeof(call_data), init_call_elem, destroy_call_elem,
+ sizeof(channel_data), init_channel_elem, destroy_channel_elem, "auth"};
diff --git a/src/core/security/auth.h b/src/core/security/auth.h
index 0b279f8740..94fa2aba7d 100644
--- a/src/core/security/auth.h
+++ b/src/core/security/auth.h
@@ -38,4 +38,4 @@
extern const grpc_channel_filter grpc_client_auth_filter;
-#endif /* __GRPC_INTERNAL_SECURITY_AUTH_H__ */
+#endif /* __GRPC_INTERNAL_SECURITY_AUTH_H__ */
diff --git a/src/core/security/credentials.c b/src/core/security/credentials.c
index c99ac8021d..d3bba0fb1f 100644
--- a/src/core/security/credentials.c
+++ b/src/core/security/credentials.c
@@ -819,6 +819,26 @@ const grpc_credentials_array *grpc_composite_credentials_get_credentials(
return &c->inner;
}
+grpc_credentials *grpc_credentials_contains_type(
+ grpc_credentials *creds, const char *type,
+ grpc_credentials **composite_creds) {
+ size_t i;
+ if (!strcmp(creds->type, type)) {
+ if (composite_creds != NULL) *composite_creds = NULL;
+ return creds;
+ } else if (!strcmp(creds->type, GRPC_CREDENTIALS_TYPE_COMPOSITE)) {
+ const grpc_credentials_array *inner_creds_array =
+ grpc_composite_credentials_get_credentials(creds);
+ for (i = 0; i < inner_creds_array->num_creds; i++) {
+ if (!strcmp(type, inner_creds_array->creds_array[i]->type)) {
+ if (composite_creds != NULL) *composite_creds = creds;
+ return inner_creds_array->creds_array[i];
+ }
+ }
+ }
+ return NULL;
+}
+
/* -- IAM credentials. -- */
typedef struct {
@@ -877,4 +897,3 @@ grpc_credentials *grpc_iam_credentials_create(const char *token,
/* -- Default credentials TODO(jboeuf). -- */
grpc_credentials *grpc_default_credentials_create(void) { return NULL; }
-
diff --git a/src/core/security/credentials.h b/src/core/security/credentials.h
index 036a44493e..4a2532d7c4 100644
--- a/src/core/security/credentials.h
+++ b/src/core/security/credentials.h
@@ -108,6 +108,14 @@ typedef struct {
const grpc_credentials_array *grpc_composite_credentials_get_credentials(
grpc_credentials *composite_creds);
+/* Returns creds if creds is of the specified type or the inner creds of the
+ specified type (if found), if the creds is of type COMPOSITE.
+ If composite_creds is not NULL, *composite_creds will point to creds if of
+ type COMPOSITE in case of success. */
+grpc_credentials *grpc_credentials_contains_type(
+ grpc_credentials *creds, const char *type,
+ grpc_credentials **composite_creds);
+
/* Exposed for testing only. */
grpc_credentials_status
grpc_oauth2_token_fetcher_credentials_parse_server_response(
@@ -118,7 +126,6 @@ grpc_oauth2_token_fetcher_credentials_parse_server_response(
grpc_credentials *grpc_fake_oauth2_credentials_create(
const char *token_md_value, int is_async);
-
/* --- grpc_server_credentials. --- */
typedef struct {
@@ -136,5 +143,4 @@ struct grpc_server_credentials {
const grpc_ssl_config *grpc_ssl_server_credentials_get_config(
const grpc_server_credentials *ssl_creds);
-
-#endif /* __GRPC_INTERNAL_SECURITY_CREDENTIALS_H__ */
+#endif /* __GRPC_INTERNAL_SECURITY_CREDENTIALS_H__ */
diff --git a/src/core/security/factories.c b/src/core/security/factories.c
new file mode 100644
index 0000000000..d89c692989
--- /dev/null
+++ b/src/core/security/factories.c
@@ -0,0 +1,80 @@
+/*
+ *
+ * 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 <string.h>
+
+#include "src/core/security/credentials.h"
+#include "src/core/security/security_context.h"
+#include "src/core/surface/lame_client.h"
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/useful.h>
+
+grpc_channel *grpc_secure_channel_create(grpc_credentials *creds,
+ const char *target,
+ const grpc_channel_args *args) {
+ grpc_secure_channel_factory factories[] = {
+ {GRPC_CREDENTIALS_TYPE_SSL, grpc_ssl_channel_create},
+ {GRPC_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY,
+ grpc_fake_transport_security_channel_create}};
+ return grpc_secure_channel_create_with_factories(
+ factories, GPR_ARRAY_SIZE(factories), creds, target, args);
+}
+
+grpc_server *grpc_secure_server_create(grpc_server_credentials *creds,
+ grpc_completion_queue *cq,
+ const grpc_channel_args *args) {
+ grpc_security_status status = GRPC_SECURITY_ERROR;
+ grpc_security_context *ctx = NULL;
+ grpc_server *server = NULL;
+ if (creds == NULL) return NULL; /* TODO(ctiller): Return lame server. */
+
+ if (!strcmp(creds->type, GRPC_CREDENTIALS_TYPE_SSL)) {
+ status = grpc_ssl_server_security_context_create(
+ grpc_ssl_server_credentials_get_config(creds), &ctx);
+ } else if (!strcmp(creds->type,
+ GRPC_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY)) {
+ ctx = grpc_fake_server_security_context_create();
+ status = GRPC_SECURITY_OK;
+ }
+
+ if (status != GRPC_SECURITY_OK) {
+ gpr_log(GPR_ERROR,
+ "Unable to create secure server with credentials of type %s.",
+ creds->type);
+ return NULL; /* TODO(ctiller): Return lame server. */
+ }
+ server = grpc_secure_server_create_internal(cq, args, ctx);
+ grpc_security_context_unref(ctx);
+ return server;
+}
diff --git a/src/core/security/google_root_certs.h b/src/core/security/google_root_certs.h
index 4bcfaddcdb..30ed16c03b 100644
--- a/src/core/security/google_root_certs.h
+++ b/src/core/security/google_root_certs.h
@@ -37,4 +37,4 @@
extern unsigned char grpc_google_root_certs[];
extern unsigned int grpc_google_root_certs_size;
-#endif /* __GRPC_INTERNAL_SECURITY_GOOGLE_ROOT_CERTS_H__ */
+#endif /* __GRPC_INTERNAL_SECURITY_GOOGLE_ROOT_CERTS_H__ */
diff --git a/src/core/security/secure_endpoint.h b/src/core/security/secure_endpoint.h
index d0f0fa7d5b..20143150e0 100644
--- a/src/core/security/secure_endpoint.h
+++ b/src/core/security/secure_endpoint.h
@@ -44,4 +44,4 @@ grpc_endpoint *grpc_secure_endpoint_create(
struct tsi_frame_protector *protector, grpc_endpoint *to_wrap,
gpr_slice *leftover_slices, size_t leftover_nslices);
-#endif /* __GRPC_INTERNAL_ENDPOINT_SECURE_ENDPOINT_H__ */
+#endif /* __GRPC_INTERNAL_ENDPOINT_SECURE_ENDPOINT_H__ */
diff --git a/src/core/security/secure_transport_setup.h b/src/core/security/secure_transport_setup.h
index 50f2b08529..b13d065fbf 100644
--- a/src/core/security/secure_transport_setup.h
+++ b/src/core/security/secure_transport_setup.h
@@ -50,4 +50,4 @@ void grpc_setup_secure_transport(grpc_security_context *ctx,
grpc_secure_transport_setup_done_cb cb,
void *user_data);
-#endif /* __GRPC_INTERNAL_SECURITY_SECURE_TRANSPORT_SETUP_H__ */
+#endif /* __GRPC_INTERNAL_SECURITY_SECURE_TRANSPORT_SETUP_H__ */
diff --git a/src/core/security/security_context.c b/src/core/security/security_context.c
index 13b9a847ee..d519ecab87 100644
--- a/src/core/security/security_context.c
+++ b/src/core/security/security_context.c
@@ -100,8 +100,7 @@ grpc_arg grpc_security_context_to_arg(grpc_security_context *ctx) {
return result;
}
-grpc_security_context *grpc_security_context_from_arg(
- const grpc_arg *arg) {
+grpc_security_context *grpc_security_context_from_arg(const grpc_arg *arg) {
if (strcmp(arg->key, GRPC_SECURITY_CONTEXT_ARG)) return NULL;
if (arg->type != GRPC_ARG_POINTER) {
gpr_log(GPR_ERROR, "Invalid type %d for arg %s", arg->type,
@@ -140,9 +139,7 @@ static void fake_channel_destroy(grpc_security_context *ctx) {
gpr_free(ctx);
}
-static void fake_server_destroy(grpc_security_context *ctx) {
- gpr_free(ctx);
-}
+static void fake_server_destroy(grpc_security_context *ctx) { gpr_free(ctx); }
static grpc_security_status fake_channel_create_handshaker(
grpc_security_context *ctx, tsi_handshaker **handshaker) {
@@ -234,8 +231,7 @@ static void ssl_channel_destroy(grpc_security_context *ctx) {
}
static void ssl_server_destroy(grpc_security_context *ctx) {
- grpc_ssl_server_security_context *c =
- (grpc_ssl_server_security_context *)ctx;
+ grpc_ssl_server_security_context *c = (grpc_ssl_server_security_context *)ctx;
if (c->handshaker_factory != NULL) {
tsi_ssl_handshaker_factory_destroy(c->handshaker_factory);
}
@@ -267,8 +263,7 @@ static grpc_security_status ssl_channel_create_handshaker(
static grpc_security_status ssl_server_create_handshaker(
grpc_security_context *ctx, tsi_handshaker **handshaker) {
- grpc_ssl_server_security_context *c =
- (grpc_ssl_server_security_context *)ctx;
+ grpc_ssl_server_security_context *c = (grpc_ssl_server_security_context *)ctx;
return ssl_create_handshaker(c->handshaker_factory, 0, NULL, handshaker);
}
@@ -438,20 +433,19 @@ error:
return GRPC_SECURITY_ERROR;
}
-
-
/* -- High level objects. -- */
-static grpc_channel *grpc_ssl_channel_create(grpc_credentials *creds,
- const grpc_ssl_config *config,
- const char *target,
- const grpc_channel_args *args) {
+grpc_channel *grpc_ssl_channel_create(grpc_credentials *ssl_creds,
+ grpc_credentials *request_metadata_creds,
+ const char *target,
+ const grpc_channel_args *args) {
grpc_channel_security_context *ctx = NULL;
grpc_channel *channel = NULL;
grpc_security_status status = GRPC_SECURITY_OK;
size_t i = 0;
const char *secure_peer_name = target;
- for (i = 0; i < args->num_args; i++) {
+
+ for (i = 0; args && i < args->num_args; i++) {
grpc_arg *arg = &args->args[i];
if (!strcmp(arg->key, GRPC_SSL_TARGET_NAME_OVERRIDE_ARG) &&
arg->type == GRPC_ARG_STRING) {
@@ -459,8 +453,9 @@ static grpc_channel *grpc_ssl_channel_create(grpc_credentials *creds,
break;
}
}
- status = grpc_ssl_channel_security_context_create(creds, config,
- secure_peer_name, &ctx);
+ status = grpc_ssl_channel_security_context_create(
+ request_metadata_creds, grpc_ssl_credentials_get_config(ssl_creds),
+ secure_peer_name, &ctx);
if (status != GRPC_SECURITY_OK) {
return grpc_lame_client_channel_create();
}
@@ -469,58 +464,47 @@ static grpc_channel *grpc_ssl_channel_create(grpc_credentials *creds,
return channel;
}
-
-static grpc_credentials *get_creds_from_composite(
- grpc_credentials *composite_creds, const char *type) {
- size_t i;
- const grpc_credentials_array *inner_creds_array =
- grpc_composite_credentials_get_credentials(composite_creds);
- for (i = 0; i < inner_creds_array->num_creds; i++) {
- if (!strcmp(type, inner_creds_array->creds_array[i]->type)) {
- return inner_creds_array->creds_array[i];
- }
- }
- return NULL;
+grpc_channel *grpc_fake_transport_security_channel_create(
+ grpc_credentials *fake_creds, grpc_credentials *request_metadata_creds,
+ const char *target, const grpc_channel_args *args) {
+ grpc_channel_security_context *ctx =
+ grpc_fake_channel_security_context_create(request_metadata_creds);
+ grpc_channel *channel =
+ grpc_secure_channel_create_internal(target, args, ctx);
+ grpc_security_context_unref(&ctx->base);
+ return channel;
}
-static grpc_channel *grpc_channel_create_from_composite_creds(
- grpc_credentials *composite_creds, const char *target,
+grpc_channel *grpc_secure_channel_create_with_factories(
+ const grpc_secure_channel_factory *factories, size_t num_factories,
+ grpc_credentials *creds, const char *target,
const grpc_channel_args *args) {
- grpc_credentials *creds =
- get_creds_from_composite(composite_creds, GRPC_CREDENTIALS_TYPE_SSL);
- if (creds != NULL) {
- return grpc_ssl_channel_create(
- composite_creds, grpc_ssl_credentials_get_config(creds), target, args);
+ size_t i;
+ if (creds == NULL) {
+ gpr_log(GPR_ERROR, "No credentials to create a secure channel.");
+ return grpc_lame_client_channel_create();
}
- return NULL; /* TODO(ctiller): return lame channel. */
-}
-
-grpc_channel *grpc_secure_channel_create(grpc_credentials *creds,
- const char *target,
- const grpc_channel_args *args) {
if (grpc_credentials_has_request_metadata_only(creds)) {
gpr_log(GPR_ERROR,
"Credentials is insufficient to create a secure channel.");
return grpc_lame_client_channel_create();
}
- if (!strcmp(creds->type, GRPC_CREDENTIALS_TYPE_SSL)) {
- return grpc_ssl_channel_create(NULL, grpc_ssl_credentials_get_config(creds),
- target, args);
- } else if (!strcmp(creds->type,
- GRPC_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY)) {
- grpc_channel_security_context *ctx =
- grpc_fake_channel_security_context_create(NULL);
- grpc_channel *channel =
- grpc_secure_channel_create_internal(target, args, ctx);
- grpc_security_context_unref(&ctx->base);
- return channel;
- } else if (!strcmp(creds->type, GRPC_CREDENTIALS_TYPE_COMPOSITE)) {
- return grpc_channel_create_from_composite_creds(creds, target, args);
- } else {
- gpr_log(GPR_ERROR,
- "Unknown credentials type %s for creating a secure channel.");
- return grpc_lame_client_channel_create();
+
+ for (i = 0; i < num_factories; i++) {
+ grpc_credentials *composite_creds = NULL;
+ grpc_credentials *transport_security_creds = NULL;
+ transport_security_creds = grpc_credentials_contains_type(
+ creds, factories[i].creds_type, &composite_creds);
+ if (transport_security_creds != NULL) {
+ return factories[i].factory(transport_security_creds, composite_creds,
+ target, args);
+ }
}
+
+ gpr_log(GPR_ERROR,
+ "Unknown credentials type %s for creating a secure channel.",
+ creds->type);
+ return grpc_lame_client_channel_create();
}
grpc_channel *grpc_default_secure_channel_create(
@@ -528,30 +512,3 @@ grpc_channel *grpc_default_secure_channel_create(
return grpc_secure_channel_create(grpc_default_credentials_create(), target,
args);
}
-
-grpc_server *grpc_secure_server_create(grpc_server_credentials *creds,
- grpc_completion_queue *cq,
- const grpc_channel_args *args) {
- grpc_security_status status = GRPC_SECURITY_ERROR;
- grpc_security_context *ctx = NULL;
- grpc_server *server = NULL;
- if (creds == NULL) return NULL; /* TODO(ctiller): Return lame server. */
- if (!strcmp(creds->type, GRPC_CREDENTIALS_TYPE_SSL)) {
- status = grpc_ssl_server_security_context_create(
- grpc_ssl_server_credentials_get_config(creds), &ctx);
- } else if (!strcmp(creds->type,
- GRPC_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY)) {
- ctx = grpc_fake_server_security_context_create();
- status = GRPC_SECURITY_OK;
- } else {
- gpr_log(GPR_ERROR,
- "Unable to create secure server with credentials of type %s.",
- creds->type);
- }
- if (status != GRPC_SECURITY_OK) {
- return NULL; /* TODO(ctiller): Return lame server. */
- }
- server = grpc_secure_server_create_internal(cq, args, ctx);
- grpc_security_context_unref(ctx);
- return server;
-}
diff --git a/src/core/security/security_context.h b/src/core/security/security_context.h
index bbd7ff3b1a..9ace7f1ccb 100644
--- a/src/core/security/security_context.h
+++ b/src/core/security/security_context.h
@@ -118,7 +118,7 @@ grpc_security_context *grpc_find_security_context_in_args(
typedef struct grpc_channel_security_context grpc_channel_security_context;
struct grpc_channel_security_context {
- grpc_security_context base; /* requires is_client_side to be non 0. */
+ grpc_security_context base; /* requires is_client_side to be non 0. */
grpc_credentials *request_metadata_creds;
};
@@ -159,17 +159,41 @@ grpc_security_status grpc_ssl_channel_security_context_create(
grpc_security_status grpc_ssl_server_security_context_create(
const grpc_ssl_config *config, grpc_security_context **ctx);
-
/* --- Creation of high level objects. --- */
/* Secure client channel creation. */
+
+grpc_channel *grpc_ssl_channel_create(grpc_credentials *ssl_creds,
+ grpc_credentials *request_metadata_creds,
+ const char *target,
+ const grpc_channel_args *args);
+
+grpc_channel *grpc_fake_transport_security_channel_create(
+ grpc_credentials *fake_creds, grpc_credentials *request_metadata_creds,
+ const char *target, const grpc_channel_args *args);
+
grpc_channel *grpc_secure_channel_create_internal(
const char *target, const grpc_channel_args *args,
grpc_channel_security_context *ctx);
+typedef grpc_channel *(*grpc_secure_channel_factory_func)(
+ grpc_credentials *transport_security_creds,
+ grpc_credentials *request_metadata_creds, const char *target,
+ const grpc_channel_args *args);
+
+typedef struct {
+ const char *creds_type;
+ grpc_secure_channel_factory_func factory;
+} grpc_secure_channel_factory;
+
+grpc_channel *grpc_secure_channel_create_with_factories(
+ const grpc_secure_channel_factory *factories, size_t num_factories,
+ grpc_credentials *creds, const char *target, const grpc_channel_args *args);
+
/* Secure server creation. */
-grpc_server *grpc_secure_server_create_internal(
- grpc_completion_queue *cq, const grpc_channel_args *args,
- grpc_security_context *ctx);
-#endif /* __GRPC_INTERNAL_SECURITY_SECURITY_CONTEXT_H__ */
+grpc_server *grpc_secure_server_create_internal(grpc_completion_queue *cq,
+ const grpc_channel_args *args,
+ grpc_security_context *ctx);
+
+#endif /* __GRPC_INTERNAL_SECURITY_SECURITY_CONTEXT_H__ */
diff --git a/src/core/security/server_secure_chttp2.c b/src/core/security/server_secure_chttp2.c
index 9d7c0e5e5a..931fa95651 100644
--- a/src/core/security/server_secure_chttp2.c
+++ b/src/core/security/server_secure_chttp2.c
@@ -70,8 +70,7 @@ static void on_accept(void *server, grpc_endpoint *tcp) {
const grpc_channel_args *args = grpc_server_get_channel_args(server);
grpc_security_context *ctx = grpc_find_security_context_in_args(args);
GPR_ASSERT(ctx);
- grpc_setup_secure_transport(ctx, tcp, on_secure_transport_setup_done,
- server);
+ grpc_setup_secure_transport(ctx, tcp, on_secure_transport_setup_done, server);
}
/* Note: the following code is the same with server_chttp2.c */
diff --git a/src/core/statistics/census_interface.h b/src/core/statistics/census_interface.h
index 7618387ee2..af9c70c4fb 100644
--- a/src/core/statistics/census_interface.h
+++ b/src/core/statistics/census_interface.h
@@ -73,4 +73,4 @@ census_op_id census_tracing_start_op();
/* Ends tracing. Calling this function will invalidate the input op_id. */
void census_tracing_end_op(census_op_id op_id);
-#endif /* __GRPC_INTERNAL_STATISTICS_CENSUS_INTERFACE_H__ */
+#endif /* __GRPC_INTERNAL_STATISTICS_CENSUS_INTERFACE_H__ */
diff --git a/src/core/statistics/census_rpc_stats.h b/src/core/statistics/census_rpc_stats.h
index e1ff3ac31b..a9c999aa5c 100644
--- a/src/core/statistics/census_rpc_stats.h
+++ b/src/core/statistics/census_rpc_stats.h
@@ -98,4 +98,4 @@ void census_stats_store_shutdown();
}
#endif
-#endif /* __GRPC_INTERNAL_STATISTICS_CENSUS_RPC_STATS_H__ */
+#endif /* __GRPC_INTERNAL_STATISTICS_CENSUS_RPC_STATS_H__ */
diff --git a/src/core/statistics/census_tracing.c b/src/core/statistics/census_tracing.c
index d37c427c5b..45302cd6ab 100644
--- a/src/core/statistics/census_tracing.c
+++ b/src/core/statistics/census_tracing.c
@@ -47,8 +47,8 @@
/* Struct for a trace annotation. */
typedef struct annotation {
- gpr_uint64 ts; /* timestamp of the annotation */
- char txt[CENSUS_MAX_ANNOTATION_LENGTH]; /* actual txt annotation */
+ gpr_timespec ts; /* timestamp of the annotation */
+ char txt[CENSUS_MAX_ANNOTATION_LENGTH + 1]; /* actual txt annotation */
struct annotation* next;
} annotation;
@@ -107,8 +107,8 @@ census_op_id census_tracing_start_op() {
ret->rpc_stats.cnt = 1;
ret->ts = gpr_now();
census_ht_insert(g_trace_store, op_id_as_key(&ret->id), (void*)ret);
+ gpr_log(GPR_DEBUG, "Start tracing for id %lu", g_id);
gpr_mu_unlock(&g_mu);
- gpr_log(GPR_DEBUG, "Start tracing for id %lu\n", g_id);
return ret->id;
}
}
@@ -127,7 +127,27 @@ int census_add_method_tag(census_op_id op_id, const char* method) {
return ret;
}
-void census_tracing_print(census_op_id op_id, const char* annotation) {}
+void census_tracing_print(census_op_id op_id, const char* anno_txt) {
+ trace_obj* trace = NULL;
+ gpr_mu_lock(&g_mu);
+ trace = census_ht_find(g_trace_store, op_id_as_key(&op_id));
+ if (trace != NULL) {
+ annotation* anno = gpr_malloc(sizeof(annotation));
+ anno->ts = gpr_now();
+ {
+ char* d = anno->txt;
+ const char* s = anno_txt;
+ int n = 0;
+ for (; n < CENSUS_MAX_ANNOTATION_LENGTH && *s != '\0'; ++n) {
+ *d++ = *s++;
+ }
+ *d = '\0';
+ }
+ anno->next = trace->annotations;
+ trace->annotations = anno;
+ }
+ gpr_mu_unlock(&g_mu);
+}
void census_tracing_end_op(census_op_id op_id) {
trace_obj* trace = NULL;
@@ -136,7 +156,7 @@ void census_tracing_end_op(census_op_id op_id) {
if (trace != NULL) {
trace->rpc_stats.elapsed_time_ms =
gpr_timespec_to_micros(gpr_time_sub(gpr_now(), trace->ts));
- gpr_log(GPR_DEBUG, "End tracing for id %lu, method %s, latency %f us\n",
+ gpr_log(GPR_DEBUG, "End tracing for id %lu, method %s, latency %f us",
op_id_2_uint64(&op_id), trace->method,
trace->rpc_stats.elapsed_time_ms);
census_ht_erase(g_trace_store, op_id_as_key(&op_id));
diff --git a/src/core/statistics/hash_table.c b/src/core/statistics/hash_table.c
index f0105ee683..1aee86d3a4 100644
--- a/src/core/statistics/hash_table.c
+++ b/src/core/statistics/hash_table.c
@@ -141,10 +141,10 @@ static gpr_int32 find_bucket_idx(const census_ht* ht, census_ht_key key) {
static int keys_match(const census_ht_option* opt, const ht_entry* p,
const census_ht_key key) {
+ GPR_ASSERT(opt->key_type == CENSUS_HT_UINT64 ||
+ opt->key_type == CENSUS_HT_POINTER);
if (opt->key_type == CENSUS_HT_UINT64) return p->key.val == key.val;
- if (opt->key_type == CENSUS_HT_POINTER)
- return !opt->compare_keys((p->key).ptr, key.ptr);
- return 0;
+ return !opt->compare_keys((p->key).ptr, key.ptr);
}
static entry_locator ht_find(const census_ht* ht, census_ht_key key) {
diff --git a/src/core/support/alloc.c b/src/core/support/alloc.c
index 658408f334..ddf6789773 100644
--- a/src/core/support/alloc.c
+++ b/src/core/support/alloc.c
@@ -62,6 +62,4 @@ void *gpr_malloc_aligned(size_t size, size_t alignment) {
return (void *)ret;
}
-void gpr_free_aligned(void *ptr) {
- free(((void **)ptr)[-1]);
-}
+void gpr_free_aligned(void *ptr) { free(((void **)ptr)[-1]); }
diff --git a/src/core/support/cpu.h b/src/core/support/cpu.h
index 6ac0db35e5..2435ec0353 100644
--- a/src/core/support/cpu.h
+++ b/src/core/support/cpu.h
@@ -46,4 +46,4 @@ int gpr_cpu_num_cores();
[0, gpr_cpu_num_cores() - 1] */
int gpr_cpu_current_cpu();
-#endif /* __GRPC_INTERNAL_SUPPORT_CPU_H__ */
+#endif /* __GRPC_INTERNAL_SUPPORT_CPU_H__ */
diff --git a/src/core/support/cpu_linux.c b/src/core/support/cpu_linux.c
index 4d538a5b1b..922b61c3c5 100644
--- a/src/core/support/cpu_linux.c
+++ b/src/core/support/cpu_linux.c
@@ -37,13 +37,37 @@
#include "src/core/support/cpu.h"
+#ifndef _GNU_SOURCE
#define _GNU_SOURCE
+#define GRPC_GNU_SOURCE
+#endif
+
+#ifndef __USE_GNU
#define __USE_GNU
+#define GRPC_USE_GNU
+#endif
+
+#ifndef __USE_MISC
#define __USE_MISC
+#define GRPC_USE_MISC
+#endif
+
#include <sched.h>
+
+#ifdef GRPC_GNU_SOURCE
#undef _GNU_SOURCE
+#undef GRPC_GNU_SOURCE
+#endif
+
+#ifdef GRPC_USE_GNU
#undef __USE_GNU
+#undef GRPC_USE_GNU
+#endif
+
+#ifdef GRPC_USE_MISC
#undef __USE_MISC
+#undef GRPC_USE_MISC
+#endif
#include <errno.h>
#include <unistd.h>
diff --git a/src/core/support/log.c b/src/core/support/log.c
index b9e2897efc..7f102efea8 100644
--- a/src/core/support/log.c
+++ b/src/core/support/log.c
@@ -34,6 +34,10 @@
#include <grpc/support/log.h>
#include <stdio.h>
+#include <string.h>
+
+extern void gpr_default_log(gpr_log_func_args *args);
+static gpr_log_func g_log_func = gpr_default_log;
const char *gpr_log_severity_string(gpr_log_severity severity) {
switch (severity) {
@@ -47,12 +51,15 @@ const char *gpr_log_severity_string(gpr_log_severity severity) {
return "UNKNOWN";
}
-void gpr_log(const char *file, int line, gpr_log_severity severity,
- const char *format, ...) {
- va_list args;
- va_start(args, format);
-
- gpr_vlog(file, line, severity, format, args);
-
- va_end(args);
+void gpr_log_message(const char *file, int line, gpr_log_severity severity,
+ const char *message) {
+ gpr_log_func_args lfargs;
+ memset(&lfargs, 0, sizeof(lfargs));
+ lfargs.file = file;
+ lfargs.line = line;
+ lfargs.severity = severity;
+ lfargs.message = message;
+ g_log_func(&lfargs);
}
+
+void gpr_set_log_function(gpr_log_func f) { g_log_func = f; }
diff --git a/src/core/support/log_android.c b/src/core/support/log_android.c
index 4c83e09914..11129e3e06 100644
--- a/src/core/support/log_android.c
+++ b/src/core/support/log_android.c
@@ -54,25 +54,31 @@ static android_LogPriority severity_to_log_priority(gpr_log_severity severity) {
return ANDROID_LOG_DEFAULT;
}
-void gpr_vlog(const char *file, int line, gpr_log_severity severity,
- const char *format, va_list args) {
+void gpr_log(const char *file, int line, gpr_log_severity severity,
+ const char *format, ...) {
+ char *message = NULL;
+ va_list args;
+ va_start(args, format);
+ vasprintf(&message, format, args);
+ va_end(args);
+ gpr_log_message(file, line, severity, message);
+ free(message);
+}
+
+void gpr_default_log(gpr_log_func_args *args) {
char *final_slash;
const char *display_file;
- char *prefix = NULL;
- char *suffix = NULL;
char *output = NULL;
- final_slash = strrchr(file, '/');
+ final_slash = strrchr(args->file, '/');
if (final_slash == NULL)
display_file = file;
else
display_file = final_slash + 1;
- asprintf(&prefix, "%s:%d] ", display_file, line);
- vasprintf(&suffix, format, args);
- asprintf(&output, "%s%s", prefix, suffix);
+ asprintf(&prefix, "%s:%d] %s", display_file, args->line, args->message);
- __android_log_write(severity_to_log_priority(severity), "GRPC", output);
+ __android_log_write(severity_to_log_priority(args->severity), "GRPC", output);
/* allocated by asprintf => use free, not gpr_free */
free(prefix);
diff --git a/src/core/support/log_linux.c b/src/core/support/log_linux.c
index 322ff07dd9..36fb4b5051 100644
--- a/src/core/support/log_linux.c
+++ b/src/core/support/log_linux.c
@@ -49,17 +49,30 @@
static long gettid() { return syscall(__NR_gettid); }
-void gpr_vlog(const char *file, int line, gpr_log_severity severity,
- const char *format, va_list args) {
+void gpr_log(const char *file, int line, gpr_log_severity severity,
+ const char *format, ...) {
+ char *message = NULL;
+ va_list args;
+ va_start(args, format);
+ if (vasprintf(&message, format, args) == -1) {
+ va_end(args);
+ return;
+ }
+ va_end(args);
+ gpr_log_message(file, line, severity, message);
+ free(message);
+}
+
+void gpr_default_log(gpr_log_func_args *args) {
char *final_slash;
const char *display_file;
char time_buffer[64];
gpr_timespec now = gpr_now();
struct tm tm;
- final_slash = strrchr(file, '/');
+ final_slash = strrchr(args->file, '/');
if (final_slash == NULL)
- display_file = file;
+ display_file = args->file;
else
display_file = final_slash + 1;
@@ -70,12 +83,10 @@ void gpr_vlog(const char *file, int line, gpr_log_severity severity,
strcpy(time_buffer, "error:strftime");
}
- flockfile(stderr);
- fprintf(stderr, "%s%s.%09d %7ld %s:%d] ", gpr_log_severity_string(severity),
- time_buffer, (int)(now.tv_nsec), gettid(), display_file, line);
- vfprintf(stderr, format, args);
- fputc('\n', stderr);
- funlockfile(stderr);
+ fprintf(stderr, "%s%s.%09d %7ld %s:%d] %s\n",
+ gpr_log_severity_string(args->severity), time_buffer,
+ (int)(now.tv_nsec), gettid(), display_file, args->line,
+ args->message);
}
#endif
diff --git a/src/core/support/log_posix.c b/src/core/support/log_posix.c
index b47c433cd7..0420570a3e 100644
--- a/src/core/support/log_posix.c
+++ b/src/core/support/log_posix.c
@@ -47,17 +47,40 @@
static long gettid() { return pthread_self(); }
-void gpr_vlog(const char *file, int line, gpr_log_severity severity,
- const char *format, va_list args) {
+void gpr_log(const char *file, int line, gpr_log_severity severity,
+ const char *format, ...) {
+ char buf[64];
+ char *allocated = NULL;
+ char *message = NULL;
+ int ret;
+ va_list args;
+ va_start(args, format);
+ ret = vsnprintf(buf, format, args);
+ va_end(args);
+ if (ret < 0) {
+ message = NULL;
+ } else if (ret <= sizeof(buf) - 1) {
+ message = buf;
+ } else {
+ message = allocated = gpr_malloc(ret + 1);
+ va_start(args, format);
+ vsnprintf(message, format, args);
+ va_end(args);
+ }
+ gpr_log_message(file, line, severity, message);
+ gpr_free(allocated);
+}
+
+void gpr_default_log(gpr_log_func_args *args) {
char *final_slash;
const char *display_file;
char time_buffer[64];
gpr_timespec now = gpr_now();
struct tm tm;
- final_slash = strrchr(file, '/');
+ final_slash = strrchr(args->file, '/');
if (final_slash == NULL)
- display_file = file;
+ display_file = args->file;
else
display_file = final_slash + 1;
@@ -68,12 +91,10 @@ void gpr_vlog(const char *file, int line, gpr_log_severity severity,
strcpy(time_buffer, "error:strftime");
}
- flockfile(stderr);
- fprintf(stderr, "%s%s.%09d %7ld %s:%d] ", gpr_log_severity_string(severity),
- time_buffer, (int)(now.tv_nsec), gettid(), display_file, line);
- vfprintf(stderr, format, args);
- fputc('\n', stderr);
- funlockfile(stderr);
+ fprintf(stderr, "%s%s.%09d %7ld %s:%d] %s\n",
+ gpr_log_severity_string(args->severity), time_buffer,
+ (int)(now.tv_nsec), gettid(), display_file, args->line,
+ args->message);
}
#endif /* defined(GPR_POSIX_LOG) */
diff --git a/src/core/support/log_win32.c b/src/core/support/log_win32.c
index e6567dca7e..ae5f23a90d 100644
--- a/src/core/support/log_win32.c
+++ b/src/core/support/log_win32.c
@@ -39,12 +39,42 @@
#include <stdio.h>
#include <stdarg.h>
+void gpr_log(const char *file, int line, gpr_log_severity severity,
+ const char *message) {
+ const char *message = NULL;
+ va_list args;
+ int ret;
+
+ /* Determine the length. */
+ va_start(args, format);
+ ret = _vscprintf(format, args);
+ va_end(args);
+ if (!(0 <= ret && ret < ~(size_t)0)) {
+ message = NULL;
+ } else {
+ /* Allocate a new buffer, with space for the NUL terminator. */
+ strp_buflen = (size_t)ret + 1;
+ message = gpr_malloc(strp_buflen);
+
+ /* Print to the buffer. */
+ va_start(args, format);
+ ret = vsnprintf_s(message, strp_buflen, _TRUNCATE, format, args);
+ va_end(args);
+ if (ret != strp_buflen - 1) {
+ /* This should never happen. */
+ gpr_free(message);
+ message = NULL;
+ }
+ }
+
+ gpr_log_message(file, line, severity, message);
+ gpr_free(message);
+}
+
/* Simple starter implementation */
-void gpr_vlog(const char *file, int line, gpr_log_severity severity,
- const char *format, va_list args) {
- fprintf(stderr, "%s %s:%d: ", gpr_log_severity_string(severity), file, line);
- vfprintf(stderr, format, args);
- fputc('\n', stderr);
+void gpr_default_log(gpr_log_func_args *args) {
+ fprintf(stderr, "%s %s:%d: %s\n", gpr_log_severity_string(severity),
+ args->file, args->line, args->message);
}
#endif
diff --git a/src/core/support/murmur_hash.h b/src/core/support/murmur_hash.h
index 5643717cd2..2ebf3e57b1 100644
--- a/src/core/support/murmur_hash.h
+++ b/src/core/support/murmur_hash.h
@@ -41,4 +41,4 @@
/* compute the hash of key (length len) */
gpr_uint32 gpr_murmur_hash3(const void *key, size_t len, gpr_uint32 seed);
-#endif /* __GRPC_INTERNAL_SUPPORT_MURMUR_HASH_H__ */
+#endif /* __GRPC_INTERNAL_SUPPORT_MURMUR_HASH_H__ */
diff --git a/src/core/support/thd_internal.h b/src/core/support/thd_internal.h
index 519177a555..190d4e3668 100644
--- a/src/core/support/thd_internal.h
+++ b/src/core/support/thd_internal.h
@@ -36,4 +36,4 @@
/* Internal interfaces between modules within the gpr support library. */
-#endif /* __GRPC_INTERNAL_SUPPORT_THD_INTERNAL_H__ */
+#endif /* __GRPC_INTERNAL_SUPPORT_THD_INTERNAL_H__ */
diff --git a/src/core/surface/call.c b/src/core/surface/call.c
index f6d93bd957..297d9587eb 100644
--- a/src/core/surface/call.c
+++ b/src/core/surface/call.c
@@ -202,7 +202,7 @@ struct grpc_call {
gpr_refcount internal_refcount;
};
-#define CALL_STACK_FROM_CALL(call) ((grpc_call_stack *)((call)+1))
+#define CALL_STACK_FROM_CALL(call) ((grpc_call_stack *)((call) + 1))
#define CALL_FROM_CALL_STACK(call_stack) (((grpc_call *)(call_stack)) - 1)
#define CALL_ELEM_FROM_CALL(call, idx) \
grpc_call_stack_element(CALL_STACK_FROM_CALL(call), idx)
diff --git a/src/core/surface/call.h b/src/core/surface/call.h
index 5c2ef3be18..01605bb38a 100644
--- a/src/core/surface/call.h
+++ b/src/core/surface/call.h
@@ -73,4 +73,4 @@ grpc_metadata_buffer *grpc_call_get_metadata_buffer(grpc_call *call);
void grpc_call_add_mdelem(grpc_call *call, grpc_mdelem *mdelem,
gpr_uint32 flags);
-#endif /* __GRPC_INTERNAL_SURFACE_CALL_H__ */
+#endif /* __GRPC_INTERNAL_SURFACE_CALL_H__ */
diff --git a/src/core/surface/channel.c b/src/core/surface/channel.c
index 8ef13675fe..a1bcea58dd 100644
--- a/src/core/surface/channel.c
+++ b/src/core/surface/channel.c
@@ -51,7 +51,7 @@ struct grpc_channel {
grpc_mdstr *authority_string;
};
-#define CHANNEL_STACK_FROM_CHANNEL(c) ((grpc_channel_stack *)((c)+1))
+#define CHANNEL_STACK_FROM_CHANNEL(c) ((grpc_channel_stack *)((c) + 1))
grpc_channel *grpc_channel_create_from_filters(
const grpc_channel_filter **filters, size_t num_filters,
diff --git a/src/core/surface/channel.h b/src/core/surface/channel.h
index 11d4939916..b3ea2ede40 100644
--- a/src/core/surface/channel.h
+++ b/src/core/surface/channel.h
@@ -48,4 +48,4 @@ grpc_mdstr *grpc_channel_get_message_string(grpc_channel *channel);
void grpc_channel_internal_ref(grpc_channel *channel);
void grpc_channel_internal_unref(grpc_channel *channel);
-#endif /* __GRPC_INTERNAL_SURFACE_CHANNEL_H__ */
+#endif /* __GRPC_INTERNAL_SURFACE_CHANNEL_H__ */
diff --git a/src/core/surface/client.c b/src/core/surface/client.c
index 98cb460d63..524b0718a9 100644
--- a/src/core/surface/client.c
+++ b/src/core/surface/client.c
@@ -106,13 +106,12 @@ static void init_channel_elem(grpc_channel_element *elem,
GPR_ASSERT(!is_last);
}
-static void destroy_channel_elem(grpc_channel_element *elem) {
-}
+static void destroy_channel_elem(grpc_channel_element *elem) {}
const grpc_channel_filter grpc_client_surface_filter = {
- call_op, channel_op,
+ call_op, channel_op,
- sizeof(call_data), init_call_elem, destroy_call_elem,
+ sizeof(call_data), init_call_elem, destroy_call_elem,
sizeof(channel_data), init_channel_elem, destroy_channel_elem,
diff --git a/src/core/surface/client.h b/src/core/surface/client.h
index eb567276e2..cff3d401d9 100644
--- a/src/core/surface/client.h
+++ b/src/core/surface/client.h
@@ -38,4 +38,4 @@
extern const grpc_channel_filter grpc_client_surface_filter;
-#endif /* __GRPC_INTERNAL_SURFACE_CLIENT_H__ */
+#endif /* __GRPC_INTERNAL_SURFACE_CLIENT_H__ */
diff --git a/src/core/surface/completion_queue.h b/src/core/surface/completion_queue.h
index 2e752a3fe0..5e45749396 100644
--- a/src/core/surface/completion_queue.h
+++ b/src/core/surface/completion_queue.h
@@ -104,4 +104,4 @@ void grpc_cq_dump_pending_ops(grpc_completion_queue *cc);
grpc_pollset *grpc_cq_pollset(grpc_completion_queue *cc);
-#endif /* __GRPC_INTERNAL_SURFACE_COMPLETION_QUEUE_H__ */
+#endif /* __GRPC_INTERNAL_SURFACE_COMPLETION_QUEUE_H__ */
diff --git a/src/core/surface/event_string.h b/src/core/surface/event_string.h
index 30b693e95c..b34e2d152b 100644
--- a/src/core/surface/event_string.h
+++ b/src/core/surface/event_string.h
@@ -39,4 +39,4 @@
/* Returns a string describing an event. Must be later freed with gpr_free() */
char *grpc_event_string(grpc_event *ev);
-#endif /* __GRPC_INTERNAL_SURFACE_EVENT_STRING_H__ */
+#endif /* __GRPC_INTERNAL_SURFACE_EVENT_STRING_H__ */
diff --git a/src/core/surface/lame_client.c b/src/core/surface/lame_client.c
index 6a832436ca..5fa3e42362 100644
--- a/src/core/surface/lame_client.c
+++ b/src/core/surface/lame_client.c
@@ -33,6 +33,8 @@
#include "src/core/surface/lame_client.h"
+#include <string.h>
+
#include "src/core/channel/channel_stack.h"
#include "src/core/surface/channel.h"
#include "src/core/surface/call.h"
@@ -42,16 +44,28 @@
typedef struct { void *unused; } call_data;
-typedef struct { void *unused; } channel_data;
+typedef struct { grpc_mdelem *message; } channel_data;
+
+static void do_nothing(void *data, grpc_op_error error) {}
static void call_op(grpc_call_element *elem, grpc_call_element *from_elem,
grpc_call_op *op) {
+ channel_data *channeld = elem->channel_data;
GRPC_CALL_LOG_OP(GPR_INFO, elem, op);
switch (op->type) {
- case GRPC_SEND_START:
+ case GRPC_SEND_START: {
+ grpc_call_op set_status_op;
+ grpc_mdelem_ref(channeld->message);
+ memset(&set_status_op, 0, sizeof(grpc_call_op));
+ set_status_op.dir = GRPC_CALL_UP;
+ set_status_op.type = GRPC_RECV_METADATA;
+ set_status_op.done_cb = do_nothing;
+ set_status_op.data.metadata = channeld->message;
+ grpc_call_recv_metadata(elem, &set_status_op);
grpc_call_recv_finish(elem, 1);
break;
+ }
case GRPC_SEND_METADATA:
grpc_mdelem_unref(op->data.metadata);
break;
@@ -81,11 +95,20 @@ static void destroy_call_elem(grpc_call_element *elem) {}
static void init_channel_elem(grpc_channel_element *elem,
const grpc_channel_args *args, grpc_mdctx *mdctx,
int is_first, int is_last) {
+ channel_data *channeld = elem->channel_data;
+
GPR_ASSERT(is_first);
GPR_ASSERT(is_last);
+
+ channeld->message = grpc_mdelem_from_strings(mdctx, "grpc-message",
+ "Rpc sent on a lame channel.");
}
-static void destroy_channel_elem(grpc_channel_element *elem) {}
+static void destroy_channel_elem(grpc_channel_element *elem) {
+ channel_data *channeld = elem->channel_data;
+
+ grpc_mdelem_unref(channeld->message);
+}
static const grpc_channel_filter lame_filter = {
call_op, channel_op,
diff --git a/src/core/surface/server.c b/src/core/surface/server.c
index aa544a97f2..167bfe97d1 100644
--- a/src/core/surface/server.c
+++ b/src/core/surface/server.c
@@ -405,9 +405,9 @@ static void destroy_channel_elem(grpc_channel_element *elem) {
}
static const grpc_channel_filter server_surface_filter = {
- call_op, channel_op,
+ call_op, channel_op,
- sizeof(call_data), init_call_elem, destroy_call_elem,
+ sizeof(call_data), init_call_elem, destroy_call_elem,
sizeof(channel_data), init_channel_elem, destroy_channel_elem,
diff --git a/src/core/surface/server.h b/src/core/surface/server.h
index 61292ebe4e..50574d66a4 100644
--- a/src/core/surface/server.h
+++ b/src/core/surface/server.h
@@ -60,4 +60,4 @@ grpc_transport_setup_result grpc_server_setup_transport(
const grpc_channel_args *grpc_server_get_channel_args(grpc_server *server);
-#endif /* __GRPC_INTERNAL_SURFACE_SERVER_H__ */
+#endif /* __GRPC_INTERNAL_SURFACE_SERVER_H__ */
diff --git a/src/core/surface/server_chttp2.c b/src/core/surface/server_chttp2.c
index a0961bd449..47fca827f3 100644
--- a/src/core/surface/server_chttp2.c
+++ b/src/core/surface/server_chttp2.c
@@ -76,6 +76,8 @@ int grpc_server_add_http2_port(grpc_server *server, const char *addr) {
grpc_tcp_server *tcp = NULL;
size_t i;
int count = 0;
+ int port_num = -1;
+ int port_temp;
resolved = grpc_blocking_resolve_address(addr, "http");
if (!resolved) {
@@ -88,9 +90,15 @@ int grpc_server_add_http2_port(grpc_server *server, const char *addr) {
}
for (i = 0; i < resolved->naddrs; i++) {
- if (grpc_tcp_server_add_port(tcp,
- (struct sockaddr *)&resolved->addrs[i].addr,
- resolved->addrs[i].len)) {
+ port_temp = grpc_tcp_server_add_port(
+ tcp, (struct sockaddr *)&resolved->addrs[i].addr,
+ resolved->addrs[i].len);
+ if (port_temp >= 0) {
+ if (port_num == -1) {
+ port_num = port_temp;
+ } else {
+ GPR_ASSERT(port_num == port_temp);
+ }
count++;
}
}
@@ -108,7 +116,7 @@ int grpc_server_add_http2_port(grpc_server *server, const char *addr) {
/* Register with the server only upon success */
grpc_server_add_listener(server, tcp, start, destroy);
- return 1;
+ return port_num;
/* Error path: cleanup and return */
error:
diff --git a/src/core/surface/surface_trace.h b/src/core/surface/surface_trace.h
index f6f9acfd9c..df1aea9669 100644
--- a/src/core/surface/surface_trace.h
+++ b/src/core/surface/surface_trace.h
@@ -51,4 +51,4 @@
} while (0)
#endif
-#endif /* __GRPC_INTERNAL_SURFACE_SURFACE_TRACE_H__ */
+#endif /* __GRPC_INTERNAL_SURFACE_SURFACE_TRACE_H__ */
diff --git a/src/core/transport/chttp2/frame.h b/src/core/transport/chttp2/frame.h
index a04e442ed6..6d28638309 100644
--- a/src/core/transport/chttp2/frame.h
+++ b/src/core/transport/chttp2/frame.h
@@ -77,4 +77,4 @@ typedef struct {
#define GRPC_CHTTP2_DATA_FLAG_PADDED 8
#define GRPC_CHTTP2_FLAG_HAS_PRIORITY 0x20
-#endif /* __GRPC_INTERNAL_TRANSPORT_CHTTP2_FRAME_H__ */
+#endif /* __GRPC_INTERNAL_TRANSPORT_CHTTP2_FRAME_H__ */
diff --git a/src/core/transport/chttp2/frame_data.c b/src/core/transport/chttp2/frame_data.c
index fbd3b6cabf..c22a223737 100644
--- a/src/core/transport/chttp2/frame_data.c
+++ b/src/core/transport/chttp2/frame_data.c
@@ -161,4 +161,3 @@ grpc_chttp2_parse_error grpc_chttp2_data_parser_parse(
abort();
return GRPC_CHTTP2_CONNECTION_ERROR;
}
-
diff --git a/src/core/transport/chttp2/frame_data.h b/src/core/transport/chttp2/frame_data.h
index abe26dab76..c260059e8b 100644
--- a/src/core/transport/chttp2/frame_data.h
+++ b/src/core/transport/chttp2/frame_data.h
@@ -77,4 +77,4 @@ grpc_chttp2_parse_error grpc_chttp2_data_parser_parse(
/* create a slice with an empty data frame and is_last set */
gpr_slice grpc_chttp2_data_frame_create_empty_close(gpr_uint32 id);
-#endif /* __GRPC_INTERNAL_TRANSPORT_CHTTP2_FRAME_DATA_H__ */
+#endif /* __GRPC_INTERNAL_TRANSPORT_CHTTP2_FRAME_DATA_H__ */
diff --git a/src/core/transport/chttp2/frame_ping.h b/src/core/transport/chttp2/frame_ping.h
index a64d53644b..fa778c51b2 100644
--- a/src/core/transport/chttp2/frame_ping.h
+++ b/src/core/transport/chttp2/frame_ping.h
@@ -50,4 +50,4 @@ grpc_chttp2_parse_error grpc_chttp2_ping_parser_begin_frame(
grpc_chttp2_parse_error grpc_chttp2_ping_parser_parse(
void *parser, grpc_chttp2_parse_state *state, gpr_slice slice, int is_last);
-#endif /* __GRPC_INTERNAL_TRANSPORT_CHTTP2_FRAME_PING_H__ */
+#endif /* __GRPC_INTERNAL_TRANSPORT_CHTTP2_FRAME_PING_H__ */
diff --git a/src/core/transport/chttp2/frame_rst_stream.h b/src/core/transport/chttp2/frame_rst_stream.h
index 78aea0f26a..dbb262971b 100644
--- a/src/core/transport/chttp2/frame_rst_stream.h
+++ b/src/core/transport/chttp2/frame_rst_stream.h
@@ -38,4 +38,4 @@
gpr_slice grpc_chttp2_rst_stream_create(gpr_uint32 stream_id, gpr_uint32 code);
-#endif /* __GRPC_INTERNAL_TRANSPORT_CHTTP2_FRAME_RST_STREAM_H__ */
+#endif /* __GRPC_INTERNAL_TRANSPORT_CHTTP2_FRAME_RST_STREAM_H__ */
diff --git a/src/core/transport/chttp2/frame_settings.h b/src/core/transport/chttp2/frame_settings.h
index dcb8b00ca1..855f9636bb 100644
--- a/src/core/transport/chttp2/frame_settings.h
+++ b/src/core/transport/chttp2/frame_settings.h
@@ -96,4 +96,4 @@ grpc_chttp2_parse_error grpc_chttp2_settings_parser_begin_frame(
grpc_chttp2_parse_error grpc_chttp2_settings_parser_parse(
void *parser, grpc_chttp2_parse_state *state, gpr_slice slice, int is_last);
-#endif /* __GRPC_INTERNAL_TRANSPORT_CHTTP2_FRAME_SETTINGS_H__ */
+#endif /* __GRPC_INTERNAL_TRANSPORT_CHTTP2_FRAME_SETTINGS_H__ */
diff --git a/src/core/transport/chttp2/frame_window_update.h b/src/core/transport/chttp2/frame_window_update.h
index 4b789fcc4a..2d9e6c4dcb 100644
--- a/src/core/transport/chttp2/frame_window_update.h
+++ b/src/core/transport/chttp2/frame_window_update.h
@@ -52,4 +52,4 @@ grpc_chttp2_parse_error grpc_chttp2_window_update_parser_begin_frame(
grpc_chttp2_parse_error grpc_chttp2_window_update_parser_parse(
void *parser, grpc_chttp2_parse_state *state, gpr_slice slice, int is_last);
-#endif /* __GRPC_INTERNAL_TRANSPORT_CHTTP2_FRAME_WINDOW_UPDATE_H__ */
+#endif /* __GRPC_INTERNAL_TRANSPORT_CHTTP2_FRAME_WINDOW_UPDATE_H__ */
diff --git a/src/core/transport/chttp2/hpack_parser.h b/src/core/transport/chttp2/hpack_parser.h
index 799513e7ff..b0a0d76713 100644
--- a/src/core/transport/chttp2/hpack_parser.h
+++ b/src/core/transport/chttp2/hpack_parser.h
@@ -108,4 +108,4 @@ grpc_chttp2_parse_error grpc_chttp2_header_parser_parse(
void *hpack_parser, grpc_chttp2_parse_state *state, gpr_slice slice,
int is_last);
-#endif /* __GRPC_INTERNAL_TRANSPORT_CHTTP2_HPACK_PARSER_H__ */
+#endif /* __GRPC_INTERNAL_TRANSPORT_CHTTP2_HPACK_PARSER_H__ */
diff --git a/src/core/transport/chttp2/hpack_table.c b/src/core/transport/chttp2/hpack_table.c
index 8f2ebecfeb..ae8bfa8009 100644
--- a/src/core/transport/chttp2/hpack_table.c
+++ b/src/core/transport/chttp2/hpack_table.c
@@ -43,68 +43,68 @@ static struct {
const char *key;
const char *value;
} static_table[] = {
- /* 0: */ {NULL, NULL},
- /* 1: */ {":authority", ""},
- /* 2: */ {":method", "GET"},
- /* 3: */ {":method", "POST"},
- /* 4: */ {":path", "/"},
- /* 5: */ {":path", "/index.html"},
- /* 6: */ {":scheme", "http"},
- /* 7: */ {":scheme", "https"},
- /* 8: */ {":status", "200"},
- /* 9: */ {":status", "204"},
- /* 10: */ {":status", "206"},
- /* 11: */ {":status", "304"},
- /* 12: */ {":status", "400"},
- /* 13: */ {":status", "404"},
- /* 14: */ {":status", "500"},
- /* 15: */ {"accept-charset", ""},
- /* 16: */ {"accept-encoding", "gzip, deflate"},
- /* 17: */ {"accept-language", ""},
- /* 18: */ {"accept-ranges", ""},
- /* 19: */ {"accept", ""},
- /* 20: */ {"access-control-allow-origin", ""},
- /* 21: */ {"age", ""},
- /* 22: */ {"allow", ""},
- /* 23: */ {"authorization", ""},
- /* 24: */ {"cache-control", ""},
- /* 25: */ {"content-disposition", ""},
- /* 26: */ {"content-encoding", ""},
- /* 27: */ {"content-language", ""},
- /* 28: */ {"content-length", ""},
- /* 29: */ {"content-location", ""},
- /* 30: */ {"content-range", ""},
- /* 31: */ {"content-type", ""},
- /* 32: */ {"cookie", ""},
- /* 33: */ {"date", ""},
- /* 34: */ {"etag", ""},
- /* 35: */ {"expect", ""},
- /* 36: */ {"expires", ""},
- /* 37: */ {"from", ""},
- /* 38: */ {"host", ""},
- /* 39: */ {"if-match", ""},
- /* 40: */ {"if-modified-since", ""},
- /* 41: */ {"if-none-match", ""},
- /* 42: */ {"if-range", ""},
- /* 43: */ {"if-unmodified-since", ""},
- /* 44: */ {"last-modified", ""},
- /* 45: */ {"link", ""},
- /* 46: */ {"location", ""},
- /* 47: */ {"max-forwards", ""},
- /* 48: */ {"proxy-authenticate", ""},
- /* 49: */ {"proxy-authorization", ""},
- /* 50: */ {"range", ""},
- /* 51: */ {"referer", ""},
- /* 52: */ {"refresh", ""},
- /* 53: */ {"retry-after", ""},
- /* 54: */ {"server", ""},
- /* 55: */ {"set-cookie", ""},
- /* 56: */ {"strict-transport-security", ""},
- /* 57: */ {"transfer-encoding", ""},
- /* 58: */ {"user-agent", ""},
- /* 59: */ {"vary", ""},
- /* 60: */ {"via", ""},
- /* 61: */ {"www-authenticate", ""},
+ /* 0: */ {NULL, NULL},
+ /* 1: */ {":authority", ""},
+ /* 2: */ {":method", "GET"},
+ /* 3: */ {":method", "POST"},
+ /* 4: */ {":path", "/"},
+ /* 5: */ {":path", "/index.html"},
+ /* 6: */ {":scheme", "http"},
+ /* 7: */ {":scheme", "https"},
+ /* 8: */ {":status", "200"},
+ /* 9: */ {":status", "204"},
+ /* 10: */ {":status", "206"},
+ /* 11: */ {":status", "304"},
+ /* 12: */ {":status", "400"},
+ /* 13: */ {":status", "404"},
+ /* 14: */ {":status", "500"},
+ /* 15: */ {"accept-charset", ""},
+ /* 16: */ {"accept-encoding", "gzip, deflate"},
+ /* 17: */ {"accept-language", ""},
+ /* 18: */ {"accept-ranges", ""},
+ /* 19: */ {"accept", ""},
+ /* 20: */ {"access-control-allow-origin", ""},
+ /* 21: */ {"age", ""},
+ /* 22: */ {"allow", ""},
+ /* 23: */ {"authorization", ""},
+ /* 24: */ {"cache-control", ""},
+ /* 25: */ {"content-disposition", ""},
+ /* 26: */ {"content-encoding", ""},
+ /* 27: */ {"content-language", ""},
+ /* 28: */ {"content-length", ""},
+ /* 29: */ {"content-location", ""},
+ /* 30: */ {"content-range", ""},
+ /* 31: */ {"content-type", ""},
+ /* 32: */ {"cookie", ""},
+ /* 33: */ {"date", ""},
+ /* 34: */ {"etag", ""},
+ /* 35: */ {"expect", ""},
+ /* 36: */ {"expires", ""},
+ /* 37: */ {"from", ""},
+ /* 38: */ {"host", ""},
+ /* 39: */ {"if-match", ""},
+ /* 40: */ {"if-modified-since", ""},
+ /* 41: */ {"if-none-match", ""},
+ /* 42: */ {"if-range", ""},
+ /* 43: */ {"if-unmodified-since", ""},
+ /* 44: */ {"last-modified", ""},
+ /* 45: */ {"link", ""},
+ /* 46: */ {"location", ""},
+ /* 47: */ {"max-forwards", ""},
+ /* 48: */ {"proxy-authenticate", ""},
+ /* 49: */ {"proxy-authorization", ""},
+ /* 50: */ {"range", ""},
+ /* 51: */ {"referer", ""},
+ /* 52: */ {"refresh", ""},
+ /* 53: */ {"retry-after", ""},
+ /* 54: */ {"server", ""},
+ /* 55: */ {"set-cookie", ""},
+ /* 56: */ {"strict-transport-security", ""},
+ /* 57: */ {"transfer-encoding", ""},
+ /* 58: */ {"user-agent", ""},
+ /* 59: */ {"vary", ""},
+ /* 60: */ {"via", ""},
+ /* 61: */ {"www-authenticate", ""},
};
void grpc_chttp2_hptbl_init(grpc_chttp2_hptbl *tbl, grpc_mdctx *mdctx) {
diff --git a/src/core/transport/chttp2/hpack_table.h b/src/core/transport/chttp2/hpack_table.h
index a3a07ad014..84a8e2d1e0 100644
--- a/src/core/transport/chttp2/hpack_table.h
+++ b/src/core/transport/chttp2/hpack_table.h
@@ -94,4 +94,4 @@ typedef struct {
grpc_chttp2_hptbl_find_result grpc_chttp2_hptbl_find(
const grpc_chttp2_hptbl *tbl, grpc_mdelem *md);
-#endif /* __GRPC_INTERNAL_TRANSPORT_CHTTP2_HPACK_TABLE_H__ */
+#endif /* __GRPC_INTERNAL_TRANSPORT_CHTTP2_HPACK_TABLE_H__ */
diff --git a/src/core/transport/chttp2/http2_errors.h b/src/core/transport/chttp2/http2_errors.h
index d065422c6f..7791da6d5a 100644
--- a/src/core/transport/chttp2/http2_errors.h
+++ b/src/core/transport/chttp2/http2_errors.h
@@ -53,4 +53,4 @@ typedef enum {
GRPC_CHTTP2__ERROR_DO_NOT_USE = -1
} grpc_chttp2_error_code;
-#endif /* __GRPC_INTERNAL_TRANSPORT_CHTTP2_HTTP2_ERRORS_H__ */
+#endif /* __GRPC_INTERNAL_TRANSPORT_CHTTP2_HTTP2_ERRORS_H__ */
diff --git a/src/core/transport/chttp2/status_conversion.h b/src/core/transport/chttp2/status_conversion.h
index ae9e7f2ca3..f78d81e0aa 100644
--- a/src/core/transport/chttp2/status_conversion.h
+++ b/src/core/transport/chttp2/status_conversion.h
@@ -47,4 +47,4 @@ grpc_status_code grpc_chttp2_http2_error_to_grpc_status(
grpc_status_code grpc_chttp2_http2_status_to_grpc_status(int status);
int grpc_chttp2_grpc_status_to_http2_status(grpc_status_code status);
-#endif /* __GRPC_INTERNAL_TRANSPORT_CHTTP2_STATUS_CONVERSION_H__ */
+#endif /* __GRPC_INTERNAL_TRANSPORT_CHTTP2_STATUS_CONVERSION_H__ */
diff --git a/src/core/transport/chttp2/stream_encoder.c b/src/core/transport/chttp2/stream_encoder.c
index 8595a59879..92a36d0c16 100644
--- a/src/core/transport/chttp2/stream_encoder.c
+++ b/src/core/transport/chttp2/stream_encoder.c
@@ -68,8 +68,6 @@ typedef struct {
gpr_uint8 last_was_header;
/* output stream id */
gpr_uint32 stream_id;
- /* number of flow controlled bytes written */
- gpr_uint32 output_size;
gpr_slice_buffer *output;
} framer_state;
@@ -464,49 +462,31 @@ void grpc_chttp2_hpack_compressor_destroy(grpc_chttp2_hpack_compressor *c) {
grpc_mdstr_unref(c->timeout_key_str);
}
-gpr_uint32 grpc_chttp2_encode_some(grpc_stream_op *ops, size_t *ops_count,
- int eof, gpr_slice_buffer *output,
- gpr_uint32 max_bytes, gpr_uint32 stream_id,
- grpc_chttp2_hpack_compressor *compressor) {
- framer_state st;
+gpr_uint32 grpc_chttp2_preencode(grpc_stream_op *inops, size_t *inops_count,
+ gpr_uint32 max_flow_controlled_bytes,
+ grpc_stream_op_buffer *outops) {
gpr_slice slice;
grpc_stream_op *op;
gpr_uint32 max_take_size;
+ gpr_uint32 flow_controlled_bytes_taken = 0;
gpr_uint32 curop = 0;
- gpr_uint32 nops = *ops_count;
gpr_uint8 *p;
- GPR_ASSERT(stream_id != 0);
-
- st.cur_frame_type = NONE;
- st.last_was_header = 0;
- st.stream_id = stream_id;
- st.output = output;
- st.output_size = 0;
-
- while (curop < nops) {
- GPR_ASSERT(st.output_size <= max_bytes);
- op = &ops[curop];
+ while (curop < *inops_count) {
+ GPR_ASSERT(flow_controlled_bytes_taken <= max_flow_controlled_bytes);
+ op = &inops[curop];
switch (op->type) {
case GRPC_NO_OP:
+ /* skip */
curop++;
break;
case GRPC_OP_FLOW_CTL_CB:
- op->data.flow_ctl_cb.cb(op->data.flow_ctl_cb.arg, GRPC_OP_OK);
- curop++;
- break;
- case GRPC_OP_METADATA:
- hpack_enc(compressor, op->data.metadata, &st);
- curop++;
- break;
case GRPC_OP_DEADLINE:
- deadline_enc(compressor, op->data.deadline, &st);
- curop++;
- break;
+ case GRPC_OP_METADATA:
case GRPC_OP_METADATA_BOUNDARY:
- ensure_frame_type(&st, HEADER, 0);
- finish_frame(&st, 1, 0);
- st.last_was_header = 0; /* force a new header frame */
+ /* these just get copied as they don't impact the number of flow
+ controlled bytes */
+ grpc_sopb_append(outops, op, 1);
curop++;
break;
case GRPC_OP_BEGIN_MESSAGE:
@@ -525,42 +505,100 @@ gpr_uint32 grpc_chttp2_encode_some(grpc_stream_op *ops, size_t *ops_count,
case GRPC_OP_SLICE:
slice = op->data.slice;
if (!GPR_SLICE_LENGTH(slice)) {
+ /* skip zero length slices */
+ gpr_slice_unref(slice);
curop++;
break;
}
- if (st.output_size == max_bytes) {
+ max_take_size = max_flow_controlled_bytes - flow_controlled_bytes_taken;
+ if (max_take_size == 0) {
goto exit_loop;
}
+ if (GPR_SLICE_LENGTH(slice) > max_take_size) {
+ slice = gpr_slice_split_head(&op->data.slice, max_take_size);
+ grpc_sopb_add_slice(outops, slice);
+ } else {
+ /* consume this op immediately */
+ grpc_sopb_append(outops, op, 1);
+ curop++;
+ }
+ flow_controlled_bytes_taken += GPR_SLICE_LENGTH(slice);
+ break;
+ }
+ }
+exit_loop:
+ *inops_count -= curop;
+ memmove(inops, inops + curop, *inops_count * sizeof(grpc_stream_op));
+
+ return flow_controlled_bytes_taken;
+}
+
+void grpc_chttp2_encode(grpc_stream_op *ops, size_t ops_count, int eof,
+ gpr_uint32 stream_id,
+ grpc_chttp2_hpack_compressor *compressor,
+ gpr_slice_buffer *output) {
+ framer_state st;
+ gpr_slice slice;
+ grpc_stream_op *op;
+ gpr_uint32 max_take_size;
+ gpr_uint32 curop = 0;
+
+ GPR_ASSERT(stream_id != 0);
+
+ st.cur_frame_type = NONE;
+ st.last_was_header = 0;
+ st.stream_id = stream_id;
+ st.output = output;
+
+ while (curop < ops_count) {
+ op = &ops[curop];
+ switch (op->type) {
+ case GRPC_NO_OP:
+ case GRPC_OP_BEGIN_MESSAGE:
+ gpr_log(
+ GPR_ERROR,
+ "These stream ops should be filtered out by grpc_chttp2_preencode");
+ abort();
+ case GRPC_OP_FLOW_CTL_CB:
+ op->data.flow_ctl_cb.cb(op->data.flow_ctl_cb.arg, GRPC_OP_OK);
+ curop++;
+ break;
+ case GRPC_OP_METADATA:
+ hpack_enc(compressor, op->data.metadata, &st);
+ curop++;
+ break;
+ case GRPC_OP_DEADLINE:
+ deadline_enc(compressor, op->data.deadline, &st);
+ curop++;
+ break;
+ case GRPC_OP_METADATA_BOUNDARY:
+ ensure_frame_type(&st, HEADER, 0);
+ finish_frame(&st, 1, 0);
+ st.last_was_header = 0; /* force a new header frame */
+ curop++;
+ break;
+ case GRPC_OP_SLICE:
+ slice = op->data.slice;
if (st.cur_frame_type == DATA &&
st.output->length - st.output_length_at_start_of_frame ==
GRPC_CHTTP2_MAX_PAYLOAD_LENGTH) {
finish_frame(&st, 0, 0);
}
ensure_frame_type(&st, DATA, 1);
- max_take_size =
- GPR_MIN(max_bytes - st.output_size,
- GRPC_CHTTP2_MAX_PAYLOAD_LENGTH +
- st.output_length_at_start_of_frame - st.output->length);
+ max_take_size = GRPC_CHTTP2_MAX_PAYLOAD_LENGTH +
+ st.output_length_at_start_of_frame - st.output->length;
if (GPR_SLICE_LENGTH(slice) > max_take_size) {
slice = gpr_slice_split_head(&op->data.slice, max_take_size);
} else {
/* consume this op immediately */
curop++;
}
- st.output_size += GPR_SLICE_LENGTH(slice);
gpr_slice_buffer_add(output, slice);
break;
}
}
-exit_loop:
if (eof && st.cur_frame_type == NONE) {
begin_frame(&st, DATA);
}
- finish_frame(&st, 1, eof && curop == nops);
-
- nops -= curop;
- *ops_count = nops;
- memmove(ops, ops + curop, nops * sizeof(grpc_stream_op));
-
- return st.output_size;
+ finish_frame(&st, 1, eof);
}
diff --git a/src/core/transport/chttp2/stream_encoder.h b/src/core/transport/chttp2/stream_encoder.h
index dad64697a5..147b1d31ff 100644
--- a/src/core/transport/chttp2/stream_encoder.h
+++ b/src/core/transport/chttp2/stream_encoder.h
@@ -78,9 +78,16 @@ void grpc_chttp2_hpack_compressor_init(grpc_chttp2_hpack_compressor *c,
grpc_mdctx *mdctx);
void grpc_chttp2_hpack_compressor_destroy(grpc_chttp2_hpack_compressor *c);
-gpr_uint32 grpc_chttp2_encode_some(grpc_stream_op *ops, size_t *ops_count,
- int eof, gpr_slice_buffer *output,
- gpr_uint32 max_bytes, gpr_uint32 stream_id,
- grpc_chttp2_hpack_compressor *compressor);
+/* select stream ops to be encoded, moving them from inops to outops, and
+ moving subsequent ops in inops forward in the queue */
+gpr_uint32 grpc_chttp2_preencode(grpc_stream_op *inops, size_t *inops_count,
+ gpr_uint32 max_flow_controlled_bytes,
+ grpc_stream_op_buffer *outops);
-#endif /* __GRPC_INTERNAL_TRANSPORT_CHTTP2_STREAM_ENCODER_H__ */
+/* encode stream ops to output */
+void grpc_chttp2_encode(grpc_stream_op *ops, size_t ops_count, int eof,
+ gpr_uint32 stream_id,
+ grpc_chttp2_hpack_compressor *compressor,
+ gpr_slice_buffer *output);
+
+#endif /* __GRPC_INTERNAL_TRANSPORT_CHTTP2_STREAM_ENCODER_H__ */
diff --git a/src/core/transport/chttp2/stream_map.h b/src/core/transport/chttp2/stream_map.h
index caaee30676..03bf719f37 100644
--- a/src/core/transport/chttp2/stream_map.h
+++ b/src/core/transport/chttp2/stream_map.h
@@ -78,4 +78,4 @@ void grpc_chttp2_stream_map_for_each(grpc_chttp2_stream_map *map,
void *value),
void *user_data);
-#endif /* __GRPC_INTERNAL_TRANSPORT_CHTTP2_STREAM_MAP_H__ */
+#endif /* __GRPC_INTERNAL_TRANSPORT_CHTTP2_STREAM_MAP_H__ */
diff --git a/src/core/transport/chttp2/varint.h b/src/core/transport/chttp2/varint.h
index 780390238f..940df00a99 100644
--- a/src/core/transport/chttp2/varint.h
+++ b/src/core/transport/chttp2/varint.h
@@ -70,4 +70,4 @@ void grpc_chttp2_hpack_write_varint_tail(gpr_uint32 tail_value,
} \
} while (0)
-#endif /* __GRPC_INTERNAL_TRANSPORT_CHTTP2_VARINT_H__ */
+#endif /* __GRPC_INTERNAL_TRANSPORT_CHTTP2_VARINT_H__ */
diff --git a/src/core/transport/chttp2_transport.c b/src/core/transport/chttp2_transport.c
index 5bf763e76f..1b90d4715b 100644
--- a/src/core/transport/chttp2_transport.c
+++ b/src/core/transport/chttp2_transport.c
@@ -71,6 +71,13 @@ typedef struct stream stream;
typedef enum {
/* streams that have pending writes */
WRITABLE = 0,
+ /* streams that have been selected to be written */
+ WRITING,
+ /* streams that have just been written, and included a close */
+ WRITTEN_CLOSED,
+ /* streams that have been cancelled and have some pending state updates
+ to perform */
+ CANCELLED,
/* streams that want to send window updates */
WINDOW_UPDATE,
/* streams that are waiting to start because there are too many concurrent
@@ -258,7 +265,12 @@ struct stream {
gpr_uint32 outgoing_window;
gpr_uint32 incoming_window;
- gpr_uint8 write_closed;
+ /* when the application requests writes be closed, the write_closed is
+ 'queued'; when the close is flow controlled into the send path, we are
+ 'sending' it; when the write has been performed it is 'sent' */
+ gpr_uint8 queued_write_closed;
+ gpr_uint8 sending_write_closed;
+ gpr_uint8 sent_write_closed;
gpr_uint8 read_closed;
gpr_uint8 cancelled;
gpr_uint8 allow_window_updates;
@@ -267,7 +279,10 @@ struct stream {
stream_link links[STREAM_LIST_COUNT];
gpr_uint8 included[STREAM_LIST_COUNT];
+ /* sops from application */
grpc_stream_op_buffer outgoing_sopb;
+ /* sops that have passed flow control to be written */
+ grpc_stream_op_buffer writing_sopb;
grpc_chttp2_data_parser parser;
@@ -284,7 +299,7 @@ static int prepare_callbacks(transport *t);
static void run_callbacks(transport *t);
static int prepare_write(transport *t);
-static void finish_write(void *t, grpc_endpoint_cb_status status);
+static void perform_write(transport *t, grpc_endpoint *ep);
static void lock(transport *t);
static void unlock(transport *t);
@@ -303,6 +318,7 @@ static void cancel_stream_id(transport *t, gpr_uint32 id,
static void cancel_stream(transport *t, stream *s,
grpc_status_code local_status,
grpc_chttp2_error_code error_code, int send_rst);
+static void finalize_cancellations(transport *t);
static stream *lookup_stream(transport *t, gpr_uint32 id);
static void remove_from_stream_map(transport *t, stream *s);
static void maybe_start_some_streams(transport *t);
@@ -518,7 +534,9 @@ static int init_stream(grpc_transport *gt, grpc_stream *gs,
t->settings[PEER_SETTINGS][GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
s->incoming_window =
t->settings[SENT_SETTINGS][GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE];
- s->write_closed = 0;
+ s->queued_write_closed = 0;
+ s->sending_write_closed = 0;
+ s->sent_write_closed = 0;
s->read_closed = 0;
s->cancelled = 0;
s->allow_window_updates = 0;
@@ -526,8 +544,9 @@ static int init_stream(grpc_transport *gt, grpc_stream *gs,
memset(&s->links, 0, sizeof(s->links));
memset(&s->included, 0, sizeof(s->included));
grpc_sopb_init(&s->outgoing_sopb);
- grpc_chttp2_data_parser_init(&s->parser);
+ grpc_sopb_init(&s->writing_sopb);
grpc_sopb_init(&s->callback_sopb);
+ grpc_chttp2_data_parser_init(&s->parser);
if (!server_data) {
unlock(t);
@@ -565,8 +584,9 @@ static void destroy_stream(grpc_transport *gt, grpc_stream *gs) {
gpr_mu_unlock(&t->mu);
grpc_sopb_destroy(&s->outgoing_sopb);
- grpc_chttp2_data_parser_destroy(&s->parser);
+ grpc_sopb_destroy(&s->writing_sopb);
grpc_sopb_destroy(&s->callback_sopb);
+ grpc_chttp2_data_parser_destroy(&s->parser);
unref_transport(t);
}
@@ -575,6 +595,10 @@ static void destroy_stream(grpc_transport *gt, grpc_stream *gs) {
* LIST MANAGEMENT
*/
+static int stream_list_empty(transport *t, stream_list_id id) {
+ return t->lists[id].head == NULL;
+}
+
static stream *stream_list_remove_head(transport *t, stream_list_id id) {
stream *s = t->lists[id].head;
if (s) {
@@ -666,6 +690,10 @@ static void unlock(transport *t) {
}
}
+ if (!t->writing) {
+ finalize_cancellations(t);
+ }
+
/* gather any callbacks that need to be made */
if (!t->calling_back && t->cb) {
perform_callbacks = prepare_callbacks(t);
@@ -709,53 +737,9 @@ static void unlock(transport *t) {
}
/* write some bytes if necessary */
- while (start_write) {
- switch (grpc_endpoint_write(ep, t->outbuf.slices, t->outbuf.count,
- finish_write, t)) {
- case GRPC_ENDPOINT_WRITE_DONE:
- /* grab the lock directly without wrappers since we just want to
- continue writes if we loop: no need to check read callbacks again */
- gpr_mu_lock(&t->mu);
- t->outbuf.count = 0;
- t->outbuf.length = 0;
- t->writing = start_write = prepare_write(t);
- if (!start_write) {
- if (!t->reading) {
- grpc_endpoint_destroy(t->ep);
- t->ep = NULL;
- gpr_cv_broadcast(&t->cv);
- /* endpoint ref: safe because we'll still have the ref for write */
- unref_transport(t);
- }
- }
- gpr_mu_unlock(&t->mu);
- if (!start_write) {
- unref_transport(t);
- }
- break;
- case GRPC_ENDPOINT_WRITE_ERROR:
- start_write = 0;
- /* use the wrapper lock/unlock here as we drop_connection, causing
- read callbacks to be queued (which will be cleared during unlock) */
- lock(t);
- t->outbuf.count = 0;
- t->outbuf.length = 0;
- t->writing = 0;
- drop_connection(t);
- if (!t->reading) {
- grpc_endpoint_destroy(t->ep);
- t->ep = NULL;
- gpr_cv_broadcast(&t->cv);
- /* endpoint ref: safe because we'll still have the ref for write */
- unref_transport(t);
- }
- unlock(t);
- unref_transport(t);
- break;
- case GRPC_ENDPOINT_WRITE_PENDING:
- start_write = 0;
- break;
- }
+ if (start_write) {
+ /* ultimately calls unref_transport(t); and clears t->writing */
+ perform_write(t, ep);
}
if (perform_callbacks || call_closed || num_goaways) {
@@ -788,32 +772,10 @@ static void push_setting(transport *t, grpc_chttp2_setting_id id,
}
}
-static void finish_write(void *tp, grpc_endpoint_cb_status error) {
- transport *t = tp;
-
- lock(t);
- if (error != GRPC_ENDPOINT_CB_OK) {
- drop_connection(t);
- }
- t->outbuf.count = 0;
- t->outbuf.length = 0;
- /* leave the writing flag up on shutdown to prevent further writes in unlock()
- from starting */
- t->writing = 0;
- if (!t->reading) {
- grpc_endpoint_destroy(t->ep);
- t->ep = NULL;
- gpr_cv_broadcast(&t->cv);
- unref_transport(t); /* safe because we'll still have the ref for write */
- }
- unlock(t);
-
- unref_transport(t);
-}
-
static int prepare_write(transport *t) {
stream *s;
gpr_slice_buffer tempbuf;
+ gpr_uint32 window_delta;
/* simple writes are queued to qbuf, and flushed here */
tempbuf = t->qbuf;
@@ -834,17 +796,16 @@ static int prepare_write(transport *t) {
/* for each stream that's become writable, frame it's data (according to
available window sizes) and add to the output buffer */
while (t->outgoing_window && (s = stream_list_remove_head(t, WRITABLE))) {
- gpr_uint32 written = grpc_chttp2_encode_some(
- s->outgoing_sopb.ops, &s->outgoing_sopb.nops, s->write_closed,
- &t->outbuf, GPR_MIN(t->outgoing_window, s->outgoing_window), s->id,
- &t->hpack_compressor);
- t->outgoing_window -= written;
- s->outgoing_window -= written;
-
- /* if there are no more writes to do and writes are closed, we need to
- queue a callback to let the application know */
- if (s->write_closed && s->outgoing_sopb.nops == 0) {
- stream_list_join(t, s, PENDING_CALLBACKS);
+ window_delta = grpc_chttp2_preencode(
+ s->outgoing_sopb.ops, &s->outgoing_sopb.nops,
+ GPR_MIN(t->outgoing_window, s->outgoing_window), &s->writing_sopb);
+ t->outgoing_window -= window_delta;
+ s->outgoing_window -= window_delta;
+
+ s->sending_write_closed =
+ s->queued_write_closed && s->outgoing_sopb.nops == 0;
+ if (s->writing_sopb.nops > 0 || s->sending_write_closed) {
+ stream_list_join(t, s, WRITING);
}
/* if there are still writes to do and the stream still has window
@@ -857,25 +818,89 @@ static int prepare_write(transport *t) {
/* for each stream that wants to update its window, add that window here */
while ((s = stream_list_remove_head(t, WINDOW_UPDATE))) {
- gpr_uint32 window_add =
+ window_delta =
t->settings[LOCAL_SETTINGS][GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE] -
s->incoming_window;
- if (!s->read_closed && window_add) {
- gpr_slice_buffer_add(&t->outbuf,
- grpc_chttp2_window_update_create(s->id, window_add));
- s->incoming_window += window_add;
+ if (!s->read_closed && window_delta) {
+ gpr_slice_buffer_add(
+ &t->outbuf, grpc_chttp2_window_update_create(s->id, window_delta));
+ s->incoming_window += window_delta;
}
}
/* if the transport is ready to send a window update, do so here also */
if (t->incoming_window < t->connection_window_target * 3 / 4) {
- gpr_uint32 window_add = t->connection_window_target - t->incoming_window;
+ window_delta = t->connection_window_target - t->incoming_window;
gpr_slice_buffer_add(&t->outbuf,
- grpc_chttp2_window_update_create(0, window_add));
- t->incoming_window += window_add;
+ grpc_chttp2_window_update_create(0, window_delta));
+ t->incoming_window += window_delta;
}
- return t->outbuf.length > 0;
+ return t->outbuf.length > 0 || !stream_list_empty(t, WRITING);
+}
+
+static void finalize_outbuf(transport *t) {
+ stream *s;
+
+ while ((s = stream_list_remove_head(t, WRITING))) {
+ grpc_chttp2_encode(s->writing_sopb.ops, s->writing_sopb.nops,
+ s->sending_write_closed, s->id, &t->hpack_compressor,
+ &t->outbuf);
+ s->writing_sopb.nops = 0;
+ if (s->sending_write_closed) {
+ stream_list_join(t, s, WRITTEN_CLOSED);
+ }
+ }
+}
+
+static void finish_write_common(transport *t, int success) {
+ stream *s;
+
+ lock(t);
+ if (!success) {
+ drop_connection(t);
+ }
+ while ((s = stream_list_remove_head(t, WRITTEN_CLOSED))) {
+ s->sent_write_closed = 1;
+ stream_list_join(t, s, PENDING_CALLBACKS);
+ }
+ t->outbuf.count = 0;
+ t->outbuf.length = 0;
+ /* leave the writing flag up on shutdown to prevent further writes in unlock()
+ from starting */
+ t->writing = 0;
+ if (!t->reading) {
+ grpc_endpoint_destroy(t->ep);
+ t->ep = NULL;
+ gpr_cv_broadcast(&t->cv);
+ unref_transport(t); /* safe because we'll still have the ref for write */
+ }
+ unlock(t);
+
+ unref_transport(t);
+}
+
+static void finish_write(void *tp, grpc_endpoint_cb_status error) {
+ transport *t = tp;
+ finish_write_common(t, error == GRPC_ENDPOINT_CB_OK);
+}
+
+static void perform_write(transport *t, grpc_endpoint *ep) {
+ finalize_outbuf(t);
+
+ GPR_ASSERT(t->outbuf.count > 0);
+
+ switch (grpc_endpoint_write(ep, t->outbuf.slices, t->outbuf.count,
+ finish_write, t)) {
+ case GRPC_ENDPOINT_WRITE_DONE:
+ finish_write_common(t, 1);
+ break;
+ case GRPC_ENDPOINT_WRITE_ERROR:
+ finish_write_common(t, 0);
+ break;
+ case GRPC_ENDPOINT_WRITE_PENDING:
+ break;
+ }
}
static void maybe_start_some_streams(transport *t) {
@@ -901,19 +926,14 @@ static void send_batch(grpc_transport *gt, grpc_stream *gs, grpc_stream_op *ops,
lock(t);
if (is_last) {
- s->write_closed = 1;
+ s->queued_write_closed = 1;
}
if (!s->cancelled) {
grpc_sopb_append(&s->outgoing_sopb, ops, ops_count);
- if (is_last && s->outgoing_sopb.nops == 0) {
- if (s->id != 0) {
- gpr_slice_buffer_add(&t->qbuf,
- grpc_chttp2_data_frame_create_empty_close(s->id));
- }
- } else if (s->id == 0) {
+ if (s->id == 0) {
stream_list_join(t, s, WAITING_FOR_CONCURRENCY);
maybe_start_some_streams(t);
- } else if (s->outgoing_window) {
+ } else {
stream_list_join(t, s, WRITABLE);
}
} else {
@@ -967,12 +987,22 @@ static void send_ping(grpc_transport *gt, void (*cb)(void *user_data),
* INPUT PROCESSING
*/
+static void finalize_cancellations(transport *t) {
+ stream *s;
+
+ while ((s = stream_list_remove_head(t, CANCELLED))) {
+ s->read_closed = 1;
+ s->sent_write_closed = 1;
+ stream_list_join(t, s, PENDING_CALLBACKS);
+ }
+}
+
static void cancel_stream_inner(transport *t, stream *s, gpr_uint32 id,
grpc_status_code local_status,
grpc_chttp2_error_code error_code,
int send_rst) {
- char buffer[32];
int had_outgoing;
+ char buffer[32];
if (s) {
/* clear out any unreported input & output: nobody cares anymore */
@@ -981,10 +1011,9 @@ static void cancel_stream_inner(transport *t, stream *s, gpr_uint32 id,
grpc_sopb_reset(&s->outgoing_sopb);
if (s->cancelled) {
send_rst = 0;
- } else if (!s->read_closed || !s->write_closed || had_outgoing) {
+ } else if (!s->read_closed || !s->sent_write_closed || had_outgoing) {
s->cancelled = 1;
- s->read_closed = 1;
- s->write_closed = 1;
+ stream_list_join(t, s, CANCELLED);
sprintf(buffer, "%d", local_status);
grpc_sopb_add_metadata(
@@ -1667,8 +1696,7 @@ static int prepare_callbacks(transport *t) {
s->parser.incoming_sopb = s->callback_sopb;
s->callback_sopb = temp_sopb;
- s->callback_state = compute_state(
- s->write_closed && s->outgoing_sopb.nops == 0, s->read_closed);
+ s->callback_state = compute_state(s->sent_write_closed, s->read_closed);
if (s->callback_state == GRPC_STREAM_CLOSED) {
remove_from_stream_map(t, s);
if (s->published_close) {
diff --git a/src/core/transport/chttp2_transport.h b/src/core/transport/chttp2_transport.h
index dd4419b98d..e12357ff5e 100644
--- a/src/core/transport/chttp2_transport.h
+++ b/src/core/transport/chttp2_transport.h
@@ -44,4 +44,4 @@ void grpc_create_chttp2_transport(grpc_transport_setup_callback setup,
size_t nslices, grpc_mdctx *metadata_context,
int is_client);
-#endif /* __GRPC_INTERNAL_TRANSPORT_CHTTP2_TRANSPORT_H__ */
+#endif /* __GRPC_INTERNAL_TRANSPORT_CHTTP2_TRANSPORT_H__ */
diff --git a/src/core/transport/metadata.h b/src/core/transport/metadata.h
index 6c6dee5efd..943e65a981 100644
--- a/src/core/transport/metadata.h
+++ b/src/core/transport/metadata.h
@@ -136,4 +136,4 @@ const char *grpc_mdstr_as_c_string(grpc_mdstr *s);
#define GRPC_MDSTR_KV_HASH(k_hash, v_hash) (GPR_ROTL((k_hash), 2) ^ (v_hash))
-#endif /* __GRPC_INTERNAL_TRANSPORT_METADATA_H__ */
+#endif /* __GRPC_INTERNAL_TRANSPORT_METADATA_H__ */
diff --git a/src/core/transport/stream_op.h b/src/core/transport/stream_op.h
index be60bc2da6..20d609133f 100644
--- a/src/core/transport/stream_op.h
+++ b/src/core/transport/stream_op.h
@@ -125,4 +125,4 @@ void grpc_sopb_add_flow_ctl_cb(grpc_stream_op_buffer *sopb,
void grpc_sopb_append(grpc_stream_op_buffer *sopb, grpc_stream_op *ops,
size_t nops);
-#endif /* __GRPC_INTERNAL_TRANSPORT_STREAM_OP_H__ */
+#endif /* __GRPC_INTERNAL_TRANSPORT_STREAM_OP_H__ */
diff --git a/src/core/transport/transport.h b/src/core/transport/transport.h
index 00dacbf5b9..af12f4e700 100644
--- a/src/core/transport/transport.h
+++ b/src/core/transport/transport.h
@@ -254,4 +254,4 @@ void grpc_transport_setup_initiate(grpc_transport_setup *setup);
used as a destruction call by setup). */
void grpc_transport_setup_cancel(grpc_transport_setup *setup);
-#endif /* __GRPC_INTERNAL_TRANSPORT_TRANSPORT_H__ */
+#endif /* __GRPC_INTERNAL_TRANSPORT_TRANSPORT_H__ */
diff --git a/src/core/transport/transport_impl.h b/src/core/transport/transport_impl.h
index 9f497b9cba..31e80d36ed 100644
--- a/src/core/transport/transport_impl.h
+++ b/src/core/transport/transport_impl.h
@@ -84,4 +84,4 @@ struct grpc_transport {
const grpc_transport_vtable *vtable;
};
-#endif /* __GRPC_INTERNAL_TRANSPORT_TRANSPORT_IMPL_H__ */
+#endif /* __GRPC_INTERNAL_TRANSPORT_TRANSPORT_IMPL_H__ */
diff --git a/src/core/tsi/fake_transport_security.c b/src/core/tsi/fake_transport_security.c
index 7807e71949..63d0e1f788 100644
--- a/src/core/tsi/fake_transport_security.c
+++ b/src/core/tsi/fake_transport_security.c
@@ -83,7 +83,6 @@ typedef struct {
uint32_t max_frame_size;
} tsi_fake_frame_protector;
-
/* --- Utils. ---*/
static const char* tsi_fake_handshake_message_strings[] = {
@@ -120,7 +119,7 @@ static void store32_little_endian(uint32_t value, unsigned char* buf) {
buf[3] = (unsigned char)(value >> 24) & 0xFF;
buf[2] = (unsigned char)(value >> 16) & 0xFF;
buf[1] = (unsigned char)(value >> 8) & 0xFF;
- buf[0] = (unsigned char)(value) & 0xFF;
+ buf[0] = (unsigned char)(value)&0xFF;
}
static void tsi_fake_frame_reset(tsi_fake_frame* frame, int needs_draining) {
@@ -246,8 +245,8 @@ static tsi_result fake_protector_protect(
/* Try to drain first. */
if (frame->needs_draining) {
drained_size = saved_output_size - *num_bytes_written;
- result = drain_frame_to_bytes(protected_output_frames,
- &drained_size, frame);
+ result =
+ drain_frame_to_bytes(protected_output_frames, &drained_size, frame);
*num_bytes_written += drained_size;
protected_output_frames += drained_size;
if (result != TSI_OK) {
@@ -273,8 +272,8 @@ static tsi_result fake_protector_protect(
return result;
}
}
- result = fill_frame_from_bytes(unprotected_bytes, unprotected_bytes_size,
- frame);
+ result =
+ fill_frame_from_bytes(unprotected_bytes, unprotected_bytes_size, frame);
if (result != TSI_OK) {
if (result == TSI_INCOMPLETE_DATA) result = TSI_OK;
return result;
@@ -301,7 +300,7 @@ static tsi_result fake_protector_protect_flush(
frame->size = frame->offset;
frame->offset = 0;
frame->needs_draining = 1;
- store32_little_endian(frame->size, frame->data); /* Overwrite header. */
+ store32_little_endian(frame->size, frame->data); /* Overwrite header. */
}
result = drain_frame_to_bytes(protected_output_frames,
protected_output_frames_size, frame);
@@ -327,8 +326,7 @@ static tsi_result fake_protector_unprotect(
/* Go past the header if needed. */
if (frame->offset == 0) frame->offset = TSI_FAKE_FRAME_HEADER_SIZE;
drained_size = saved_output_size - *num_bytes_written;
- result = drain_frame_to_bytes(unprotected_bytes, &drained_size,
- frame);
+ result = drain_frame_to_bytes(unprotected_bytes, &drained_size, frame);
unprotected_bytes += drained_size;
*num_bytes_written += drained_size;
if (result != TSI_OK) {
@@ -352,7 +350,7 @@ static tsi_result fake_protector_unprotect(
/* Try to drain again. */
if (!frame->needs_draining) return TSI_INTERNAL_ERROR;
if (frame->offset != 0) return TSI_INTERNAL_ERROR;
- frame->offset = TSI_FAKE_FRAME_HEADER_SIZE; /* Go past the header. */
+ frame->offset = TSI_FAKE_FRAME_HEADER_SIZE; /* Go past the header. */
drained_size = saved_output_size - *num_bytes_written;
result = drain_frame_to_bytes(unprotected_bytes, &drained_size, frame);
*num_bytes_written += drained_size;
@@ -481,10 +479,8 @@ static void fake_handshaker_destroy(tsi_handshaker* self) {
static const tsi_handshaker_vtable handshaker_vtable = {
fake_handshaker_get_bytes_to_send_to_peer,
- fake_handshaker_process_bytes_from_peer,
- fake_handshaker_get_result,
- fake_handshaker_extract_peer,
- fake_handshaker_create_frame_protector,
+ fake_handshaker_process_bytes_from_peer, fake_handshaker_get_result,
+ fake_handshaker_extract_peer, fake_handshaker_create_frame_protector,
fake_handshaker_destroy,
};
diff --git a/src/core/tsi/fake_transport_security.h b/src/core/tsi/fake_transport_security.h
index 075d51871b..a62fe81c09 100644
--- a/src/core/tsi/fake_transport_security.h
+++ b/src/core/tsi/fake_transport_security.h
@@ -50,7 +50,6 @@ extern "C" {
cleartext data for the protector. */
tsi_handshaker* tsi_create_fake_handshaker(int is_client);
-
/* Creates a protector directly without going through the handshake phase. */
tsi_frame_protector* tsi_create_fake_protector(
uint32_t* max_protected_frame_size);
@@ -59,4 +58,4 @@ tsi_frame_protector* tsi_create_fake_protector(
}
#endif
-#endif /* __FAKE_TRANSPORT_SECURITY_H_ */
+#endif /* __FAKE_TRANSPORT_SECURITY_H_ */
diff --git a/src/core/tsi/fake_transport_security_test.cc b/src/core/tsi/fake_transport_security_test.cc
deleted file mode 100644
index 0ae88e0c9a..0000000000
--- a/src/core/tsi/fake_transport_security_test.cc
+++ /dev/null
@@ -1,151 +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/core/tsi/fake_transport_security.h"
-
-#include "src/core/tsi/transport_security_test_lib.h"
-#include <gtest/gtest.h>
-#include "util/random/permute-inl.h"
-
-namespace {
-
-void CheckStringPeerProperty(const tsi_peer& peer, int property_index,
- const char* expected_name,
- const char* expected_value) {
- EXPECT_LT(property_index, peer.property_count);
- const tsi_peer_property* property = &peer.properties[property_index];
- EXPECT_EQ(TSI_PEER_PROPERTY_TYPE_STRING, property->type);
- EXPECT_EQ(string(expected_name), string(property->name));
- EXPECT_EQ(string(expected_value),
- string(property->value.string.data, property->value.string.length));
-}
-
-class FakeTransportSecurityTest : public tsi::test::TransportSecurityTest {
- protected:
- void SetupHandshakers() override {
- client_handshaker_.reset(tsi_create_fake_handshaker(1));
- server_handshaker_.reset(tsi_create_fake_handshaker(0));
- }
-
- void CheckPeer(tsi_handshaker* handshaker) {
- tsi_peer peer;
- EXPECT_EQ(TSI_OK, tsi_handshaker_extract_peer(handshaker, &peer));
- EXPECT_EQ(1, peer.property_count);
- CheckStringPeerProperty(peer, 0, TSI_CERTIFICATE_TYPE_PEER_PROPERTY,
- TSI_FAKE_CERTIFICATE_TYPE);
- tsi_peer_destruct(&peer);
- }
-
- void CheckHandshakeResults() override {
- CheckPeer(client_handshaker_.get());
- CheckPeer(server_handshaker_.get());
- }
-
- const tsi::test::TestConfig* config() {
- return &config_;
- }
-
- tsi::test::TestConfig config_;
-};
-
-TEST_F(FakeTransportSecurityTest, Handshake) {
- PerformHandshake();
-}
-
-TEST_F(FakeTransportSecurityTest, HandshakeSmallBuffer) {
- config_.handshake_buffer_size = 3;
- PerformHandshake();
-}
-TEST_F(FakeTransportSecurityTest, PingPong) {
- PingPong();
-}
-
-TEST_F(FakeTransportSecurityTest, RoundTrip) {
- config_.client_message = big_message_;
- config_.server_message = small_message_;
- DoRoundTrip();
-}
-
-TEST_F(FakeTransportSecurityTest, RoundTripSmallMessageBuffer) {
- config_.message_buffer_allocated_size = 42;
- config_.client_message = big_message_;
- config_.server_message = small_message_;
- DoRoundTrip();
-}
-
-TEST_F(FakeTransportSecurityTest, RoundTripSmallProtectedBufferSize) {
- config_.protected_buffer_size = 37;
- config_.client_message = big_message_;
- config_.server_message = small_message_;
- DoRoundTrip();
-}
-
-TEST_F(FakeTransportSecurityTest, RoundTripSmallReadBufferSize) {
- config_.read_buffer_allocated_size = 41;
- config_.client_message = big_message_;
- config_.server_message = small_message_;
- DoRoundTrip();
-}
-
-TEST_F(FakeTransportSecurityTest, RoundTripSmallClientFrames) {
- config_.set_client_max_output_protected_frame_size(39);
- config_.client_message = big_message_;
- config_.server_message = small_message_;
- DoRoundTrip();
-}
-
-TEST_F(FakeTransportSecurityTest, RoundTripSmallServerFrames) {
- config_.set_server_max_output_protected_frame_size(43);
- config_.client_message = small_message_;
- config_.server_message = big_message_;
- DoRoundTrip();
-}
-
-TEST_F(FakeTransportSecurityTest, RoundTripOddBufferSizes) {
- int odd_sizes[] = {33, 67, 135, 271, 523};
- RandomPermutation<int> permute(odd_sizes, arraysize(odd_sizes),
- random_.get());
- permute.Permute();
- LOG(ERROR) << odd_sizes[0] << "\t" << odd_sizes[1] << "\t" << odd_sizes[2]
- << "\t" << odd_sizes[3] << "\t" << odd_sizes[4];
- config_.message_buffer_allocated_size = odd_sizes[0];
- config_.protected_buffer_size = odd_sizes[1];
- config_.read_buffer_allocated_size = odd_sizes[2];
- config_.set_client_max_output_protected_frame_size(odd_sizes[3]);
- config_.set_server_max_output_protected_frame_size(odd_sizes[4]);
- config_.client_message = big_message_;
- config_.server_message = small_message_;
- DoRoundTrip();
-}
-
-} // namespace
diff --git a/src/core/tsi/ssl_transport_security.c b/src/core/tsi/ssl_transport_security.c
index b9e48e7373..c98071a937 100644
--- a/src/core/tsi/ssl_transport_security.c
+++ b/src/core/tsi/ssl_transport_security.c
@@ -54,7 +54,6 @@
* SSL structure. This is what we would ultimately want though... */
#define TSI_SSL_MAX_PROTECTION_OVERHEAD 100
-
/* --- Structure definitions. ---*/
struct tsi_ssl_handshaker_factory {
@@ -100,7 +99,6 @@ typedef struct {
uint32_t buffer_offset;
} tsi_ssl_frame_protector;
-
/* --- Library Initialization. ---*/
static gpr_once init_openssl_once = GPR_ONCE_INIT;
@@ -269,7 +267,7 @@ static tsi_result peer_from_x509(X509* cert, int include_certificate_type,
tsi_peer* peer) {
/* TODO(jboeuf): Maybe add more properties. */
uint32_t property_count = include_certificate_type ? 3 : 2;
- tsi_result result = tsi_construct_peer(property_count, peer);
+ tsi_result result = tsi_construct_peer(property_count, peer);
if (result != TSI_OK) return result;
do {
result = peer_property_from_x509_common_name(cert, &peer->properties[0]);
@@ -299,12 +297,10 @@ static void log_ssl_error_stack(void) {
}
}
-
/* Performs an SSL_read and handle errors. */
static tsi_result do_ssl_read(SSL* ssl, unsigned char* unprotected_bytes,
uint32_t* unprotected_bytes_size) {
- int read_from_ssl = SSL_read(ssl, unprotected_bytes,
- *unprotected_bytes_size);
+ int read_from_ssl = SSL_read(ssl, unprotected_bytes, *unprotected_bytes_size);
if (read_from_ssl == 0) {
gpr_log(GPR_ERROR, "SSL_read returned 0 unexpectedly.");
return TSI_INTERNAL_ERROR;
@@ -378,7 +374,7 @@ static tsi_result ssl_ctx_use_certificate_chain(
X509* certificate_authority = PEM_read_bio_X509(pem, NULL, NULL, "");
if (certificate_authority == NULL) {
ERR_clear_error();
- break; /* Done reading. */
+ break; /* Done reading. */
}
if (!SSL_CTX_add_extra_chain_cert(context, certificate_authority)) {
X509_free(certificate_authority);
@@ -423,8 +419,8 @@ static tsi_result ssl_ctx_use_private_key(SSL_CTX* context,
/* Loads in-memory PEM verification certs into the SSL context and optionally
returns the verification cert names (root_names can be NULL). */
static tsi_result ssl_ctx_load_verification_certs(
- SSL_CTX* context, const unsigned char* pem_roots,
- uint32_t pem_roots_size, STACK_OF(X509_NAME)** root_names) {
+ SSL_CTX* context, const unsigned char* pem_roots, uint32_t pem_roots_size,
+ STACK_OF(X509_NAME) * *root_names) {
tsi_result result = TSI_OK;
uint32_t num_roots = 0;
X509* root = NULL;
@@ -442,7 +438,7 @@ static tsi_result ssl_ctx_load_verification_certs(
root = PEM_read_bio_X509_AUX(pem, NULL, NULL, "");
if (root == NULL) {
ERR_clear_error();
- break; /* We're at the end of stream. */
+ break; /* We're at the end of stream. */
}
if (root_names != NULL) {
root_name = X509_get_subject_name(root);
@@ -485,13 +481,11 @@ static tsi_result ssl_ctx_load_verification_certs(
return result;
}
-
/* Populates the SSL context with a private key and a cert chain, and sets the
cipher list and the ephemeral ECDH key. */
static tsi_result populate_ssl_context(
SSL_CTX* context, const unsigned char* pem_private_key,
- uint32_t pem_private_key_size,
- const unsigned char* pem_certificate_chain,
+ uint32_t pem_private_key_size, const unsigned char* pem_certificate_chain,
uint32_t pem_certificate_chain_size, const char* cipher_list) {
tsi_result result = TSI_OK;
if (pem_certificate_chain != NULL) {
@@ -532,12 +526,12 @@ static tsi_result extract_x509_subject_names_from_pem_cert(
tsi_result result = TSI_OK;
X509* cert = NULL;
BIO* pem = BIO_new_mem_buf((void*)pem_cert, pem_cert_size);
- if (pem == NULL) return TSI_OUT_OF_RESOURCES;
+ if (pem == NULL) return TSI_OUT_OF_RESOURCES;
cert = PEM_read_bio_X509(pem, NULL, NULL, "");
if (cert == NULL) {
- gpr_log(GPR_ERROR, "Invalid certificate");
- result = TSI_INVALID_ARGUMENT;
+ gpr_log(GPR_ERROR, "Invalid certificate");
+ result = TSI_INVALID_ARGUMENT;
} else {
result = peer_from_x509(cert, 0, peer);
}
@@ -581,8 +575,7 @@ static tsi_result build_alpn_protocol_name_list(
static tsi_result ssl_protector_protect(
tsi_frame_protector* self, const unsigned char* unprotected_bytes,
- uint32_t* unprotected_bytes_size,
- unsigned char* protected_output_frames,
+ uint32_t* unprotected_bytes_size, unsigned char* protected_output_frames,
uint32_t* protected_output_frames_size) {
tsi_ssl_frame_protector* impl = (tsi_ssl_frame_protector*)self;
int read_from_ssl;
@@ -634,8 +627,7 @@ static tsi_result ssl_protector_protect(
static tsi_result ssl_protector_protect_flush(
tsi_frame_protector* self, unsigned char* protected_output_frames,
- uint32_t* protected_output_frames_size,
- uint32_t* still_pending_size) {
+ uint32_t* protected_output_frames_size, uint32_t* still_pending_size) {
tsi_result result = TSI_OK;
tsi_ssl_frame_protector* impl = (tsi_ssl_frame_protector*)self;
int read_from_ssl = 0;
@@ -662,8 +654,7 @@ static tsi_result ssl_protector_protect_flush(
static tsi_result ssl_protector_unprotect(
tsi_frame_protector* self, const unsigned char* protected_frames_bytes,
- uint32_t* protected_frames_bytes_size,
- unsigned char* unprotected_bytes,
+ uint32_t* protected_frames_bytes_size, unsigned char* unprotected_bytes,
uint32_t* unprotected_bytes_size) {
tsi_result result = TSI_OK;
int written_into_ssl = 0;
@@ -673,7 +664,7 @@ static tsi_result ssl_protector_unprotect(
/* First, try to read remaining data from ssl. */
result = do_ssl_read(impl->ssl, unprotected_bytes, unprotected_bytes_size);
- if (result != TSI_OK) return result;
+ if (result != TSI_OK) return result;
if (*unprotected_bytes_size == output_bytes_size) {
/* We have read everything we could and cannot process any more input. */
*protected_frames_bytes_size = 0;
@@ -684,8 +675,8 @@ static tsi_result ssl_protector_unprotect(
*unprotected_bytes_size = output_bytes_size - output_bytes_offset;
/* Then, try to write some data to ssl. */
- written_into_ssl = BIO_write(
- impl->into_ssl, protected_frames_bytes, *protected_frames_bytes_size);
+ written_into_ssl = BIO_write(impl->into_ssl, protected_frames_bytes,
+ *protected_frames_bytes_size);
if (written_into_ssl < 0) {
gpr_log(GPR_ERROR, "Sending protected frame to ssl failed with %d",
written_into_ssl);
@@ -710,13 +701,10 @@ static void ssl_protector_destroy(tsi_frame_protector* self) {
}
static const tsi_frame_protector_vtable frame_protector_vtable = {
- ssl_protector_protect,
- ssl_protector_protect_flush,
- ssl_protector_unprotect,
+ ssl_protector_protect, ssl_protector_protect_flush, ssl_protector_unprotect,
ssl_protector_destroy,
};
-
/* --- tsi_handshaker methods implementation. ---*/
static tsi_result ssl_handshaker_get_bytes_to_send_to_peer(
@@ -751,8 +739,7 @@ static tsi_result ssl_handshaker_get_result(tsi_handshaker* self) {
}
static tsi_result ssl_handshaker_process_bytes_from_peer(
- tsi_handshaker* self, const unsigned char* bytes,
- uint32_t* bytes_size) {
+ tsi_handshaker* self, const unsigned char* bytes, uint32_t* bytes_size) {
tsi_ssl_handshaker* impl = (tsi_ssl_handshaker*)self;
int bytes_written_into_ssl_size = 0;
if (bytes == NULL || bytes_size == 0 || *bytes_size > INT_MAX) {
@@ -884,14 +871,11 @@ static void ssl_handshaker_destroy(tsi_handshaker* self) {
static const tsi_handshaker_vtable handshaker_vtable = {
ssl_handshaker_get_bytes_to_send_to_peer,
- ssl_handshaker_process_bytes_from_peer,
- ssl_handshaker_get_result,
- ssl_handshaker_extract_peer,
- ssl_handshaker_create_frame_protector,
+ ssl_handshaker_process_bytes_from_peer, ssl_handshaker_get_result,
+ ssl_handshaker_extract_peer, ssl_handshaker_create_frame_protector,
ssl_handshaker_destroy,
};
-
/* --- tsi_ssl_handshaker_factory common methods. --- */
tsi_result tsi_ssl_handshaker_factory_create_handshaker(
@@ -971,7 +955,6 @@ static tsi_result create_tsi_ssl_handshaker(SSL_CTX* ctx, int is_client,
return TSI_OK;
}
-
/* --- tsi_ssl__client_handshaker_factory methods implementation. --- */
static tsi_result ssl_client_handshaker_factory_create_handshaker(
@@ -991,7 +974,6 @@ static void ssl_client_handshaker_factory_destroy(
free(impl);
}
-
/* --- tsi_ssl_server_handshaker_factory methods implementation. --- */
static tsi_result ssl_server_handshaker_factory_create_handshaker(
@@ -1031,19 +1013,19 @@ static int does_entry_match_name(const char* entry, uint32_t entry_length,
const char* name_subdomain = NULL;
if (entry_length == 0) return 0;
if (!strncmp(name, entry, entry_length) && (strlen(name) == entry_length)) {
- return 1; /* Perfect match. */
+ return 1; /* Perfect match. */
}
if (entry[0] != '*') return 0;
/* Wildchar subdomain matching. */
- if (entry_length < 3 || entry[1] != '.') { /* At least *.x */
+ if (entry_length < 3 || entry[1] != '.') { /* At least *.x */
gpr_log(GPR_ERROR, "Invalid wildchar entry.");
return 0;
}
name_subdomain = strchr(name, '.');
if (name_subdomain == NULL || strlen(name_subdomain) < 2) return 0;
- name_subdomain++; /* Starts after the dot. */
- entry += 2; /* Remove *. */
+ name_subdomain++; /* Starts after the dot. */
+ entry += 2; /* Remove *. */
entry_length -= 2;
return (!strncmp(entry, name_subdomain, entry_length) &&
(strlen(name_subdomain) == entry_length));
@@ -1095,7 +1077,6 @@ static int server_handshaker_factory_alpn_callback(
return SSL_TLSEXT_ERR_NOACK;
}
-
/* --- tsi_ssl_handshaker_factory constructors. --- */
tsi_result tsi_create_ssl_client_handshaker_factory(
@@ -1277,10 +1258,8 @@ int tsi_ssl_peer_matches_name(const tsi_peer* peer, const char* name) {
uint32_t i = 0;
const tsi_peer_property* property = tsi_peer_get_property_by_name(
peer, TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY);
- if (property == NULL ||
- property->type != TSI_PEER_PROPERTY_TYPE_STRING) {
- gpr_log(GPR_ERROR,
- "Invalid x509 subject common name property.");
+ if (property == NULL || property->type != TSI_PEER_PROPERTY_TYPE_STRING) {
+ gpr_log(GPR_ERROR, "Invalid x509 subject common name property.");
return 0;
}
if (does_entry_match_name(property->value.string.data,
@@ -1291,8 +1270,7 @@ int tsi_ssl_peer_matches_name(const tsi_peer* peer, const char* name) {
property = tsi_peer_get_property_by_name(
peer, TSI_X509_SUBJECT_ALTERNATIVE_NAMES_PEER_PROPERTY);
if (property == NULL || property->type != TSI_PEER_PROPERTY_TYPE_LIST) {
- gpr_log(GPR_ERROR,
- "Invalid x509 subject alternative names property.");
+ gpr_log(GPR_ERROR, "Invalid x509 subject alternative names property.");
return 0;
}
@@ -1308,5 +1286,5 @@ int tsi_ssl_peer_matches_name(const tsi_peer* peer, const char* name) {
return 1;
}
}
- return 0; /* Not found. */
+ return 0; /* Not found. */
}
diff --git a/src/core/tsi/ssl_transport_security.h b/src/core/tsi/ssl_transport_security.h
index 2ed3ed861b..de2b1df7bf 100644
--- a/src/core/tsi/ssl_transport_security.h
+++ b/src/core/tsi/ssl_transport_security.h
@@ -43,6 +43,17 @@ extern "C" {
/* Value for the TSI_CERTIFICATE_TYPE_PEER_PROPERTY property for X509 certs. */
#define TSI_X509_CERTIFICATE_TYPE "X509"
+/* This property is of type TSI_PEER_PROPERTY_STRING. */
+#define TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY "x509_subject_common_name"
+
+/* This property is of type TSI_PEER_PROPERTY_LIST and the children contain
+ unnamed (name == NULL) properties of type TSI_PEER_PROPERTY_STRING. */
+#define TSI_X509_SUBJECT_ALTERNATIVE_NAMES_PEER_PROPERTY \
+ "x509_subject_alternative_names"
+
+/* This property is of type TSI_PEER_PROPERTY_STRING. */
+#define TSI_SSL_ALPN_SELECTED_PROTOCOL "ssl_alpn_selected_protocol"
+
/* --- tsi_ssl_handshaker_factory object ---
This object creates tsi_handshaker objects implemented in terms of the
@@ -151,9 +162,8 @@ void tsi_ssl_handshaker_factory_destroy(tsi_ssl_handshaker_factory* self);
/* Util that checks that an ssl peer matches a specific name. */
int tsi_ssl_peer_matches_name(const tsi_peer* peer, const char* name);
-
#ifdef __cplusplus
}
#endif
-#endif /* __SSL_TRANSPORT_SECURITY_H_ */
+#endif /* __SSL_TRANSPORT_SECURITY_H_ */
diff --git a/src/core/tsi/ssl_transport_security_test.cc b/src/core/tsi/ssl_transport_security_test.cc
deleted file mode 100644
index a759403126..0000000000
--- a/src/core/tsi/ssl_transport_security_test.cc
+++ /dev/null
@@ -1,534 +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 <memory>
-
-#include "base/commandlineflags.h"
-#include "file/base/helpers.h"
-#include "file/base/options.pb.h"
-#include "file/base/path.h"
-#include "src/core/tsi/transport_security_test_lib.h"
-#include "src/core/tsi/ssl_transport_security.h"
-#include "util/random/permute-inl.h"
-
-namespace {
-
-const char kTestCredsDir[] =
- "/internal/tsi/test_creds/";
-
-enum AlpnMode {
- NO_ALPN,
- ALPN_CLIENT_NO_SERVER,
- ALPN_SERVER_NO_CLIENT,
- ALPN_CLIENT_SERVER_OK,
- ALPN_CLIENT_SERVER_MISMATCH
-};
-
-class SslTestConfig : public tsi::test::TestConfig {
- public:
- SslTestConfig()
- : do_client_authentication(false),
- subject_name_indication(nullptr),
- use_bad_client_cert(false),
- use_bad_server_cert(false),
- alpn_mode(NO_ALPN) {}
- bool do_client_authentication;
- const char* subject_name_indication;
- bool use_bad_client_cert;
- bool use_bad_server_cert;
- AlpnMode alpn_mode;
-};
-
-struct TsiSslHandshakerFactoryDeleter {
- inline void operator()(tsi_ssl_handshaker_factory* ptr) {
- tsi_ssl_handshaker_factory_destroy(ptr);
- }
-};
-typedef std::unique_ptr<tsi_ssl_handshaker_factory,
- TsiSslHandshakerFactoryDeleter>
- TsiSslHandshakerFactoryUniquePtr;
-
-class SslTransportSecurityTest : public tsi::test::TransportSecurityTest {
- protected:
- void CheckSubjectAltName(const tsi_peer_property& property,
- const string& expected_subject_alt_name) {
- EXPECT_EQ(property.type, TSI_PEER_PROPERTY_TYPE_STRING);
- EXPECT_EQ(property.name, nullptr);
- EXPECT_EQ(
- string(property.value.string.data, property.value.string.length),
- expected_subject_alt_name);
- }
-
- const tsi_peer_property* CheckBasicAuthenticatedPeerAndGetCommonName(
- const tsi_peer* peer) {
- const tsi_peer_property* property =
- tsi_peer_get_property_by_name(peer, TSI_CERTIFICATE_TYPE_PEER_PROPERTY);
- EXPECT_NE(property, nullptr);
- EXPECT_EQ(property->type, TSI_PEER_PROPERTY_TYPE_STRING);
- EXPECT_EQ(
- string(property->value.string.data, property->value.string.length),
- string(TSI_X509_CERTIFICATE_TYPE));
- property = tsi_peer_get_property_by_name(
- peer, TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY);
- EXPECT_EQ(property->type, TSI_PEER_PROPERTY_TYPE_STRING);
- return property;
- }
-
- void CheckServer0Peer(tsi_peer* peer) {
- const tsi_peer_property* property =
- CheckBasicAuthenticatedPeerAndGetCommonName(peer);
- EXPECT_EQ(
- string(property->value.string.data, property->value.string.length),
- string("*.test.google.com.au"));
- property = tsi_peer_get_property_by_name(
- peer, TSI_X509_SUBJECT_ALTERNATIVE_NAMES_PEER_PROPERTY);
- EXPECT_EQ(property->type, TSI_PEER_PROPERTY_TYPE_LIST);
- EXPECT_EQ(property->value.list.child_count, 0);
- EXPECT_EQ(1, tsi_ssl_peer_matches_name(peer, "foo.test.google.com.au"));
- EXPECT_EQ(1, tsi_ssl_peer_matches_name(peer, "bar.test.google.com.au"));
- EXPECT_EQ(0, tsi_ssl_peer_matches_name(peer, "bar.test.google.blah"));
- EXPECT_EQ(0, tsi_ssl_peer_matches_name(peer, "foo.bar.test.google.com.au"));
- EXPECT_EQ(0, tsi_ssl_peer_matches_name(peer, "test.google.com.au"));
- tsi_peer_destruct(peer);
- }
-
- void CheckServer1Peer(tsi_peer* peer) {
- const tsi_peer_property* property =
- CheckBasicAuthenticatedPeerAndGetCommonName(peer);
- EXPECT_EQ(
- string(property->value.string.data, property->value.string.length),
- string("*.test.google.com"));
- property = tsi_peer_get_property_by_name(
- peer, TSI_X509_SUBJECT_ALTERNATIVE_NAMES_PEER_PROPERTY);
- EXPECT_EQ(property->type, TSI_PEER_PROPERTY_TYPE_LIST);
- EXPECT_EQ(property->value.list.child_count, 3);
- CheckSubjectAltName(property->value.list.children[0], "*.test.google.fr");
- CheckSubjectAltName(property->value.list.children[1],
- "waterzooi.test.google.be");
- CheckSubjectAltName(property->value.list.children[2], "*.test.youtube.com");
- EXPECT_EQ(1, tsi_ssl_peer_matches_name(peer, "foo.test.google.com"));
- EXPECT_EQ(1, tsi_ssl_peer_matches_name(peer, "bar.test.google.fr"));
- EXPECT_EQ(1, tsi_ssl_peer_matches_name(peer, "waterzooi.test.google.be"));
- EXPECT_EQ(1, tsi_ssl_peer_matches_name(peer, "foo.test.youtube.com"));
- EXPECT_EQ(0, tsi_ssl_peer_matches_name(peer, "bar.foo.test.google.com"));
- EXPECT_EQ(0, tsi_ssl_peer_matches_name(peer, "test.google.fr"));
- EXPECT_EQ(0, tsi_ssl_peer_matches_name(peer, "tartines.test.google.be"));
- EXPECT_EQ(0, tsi_ssl_peer_matches_name(peer, "tartines.youtube.com"));
- tsi_peer_destruct(peer);
- }
-
- void CheckClientPeer(tsi_peer* peer, bool is_authenticated) {
- if (!is_authenticated) {
- EXPECT_EQ(peer->property_count,
- config_.alpn_mode == ALPN_CLIENT_SERVER_OK ? 1 : 0);
- } else {
- const tsi_peer_property* property =
- CheckBasicAuthenticatedPeerAndGetCommonName(peer);
- EXPECT_EQ(
- string(property->value.string.data, property->value.string.length),
- string("testclient"));
- }
- tsi_peer_destruct(peer);
- }
-
- void SetupHandshakers() override {
- tsi_ssl_handshaker_factory* client_handshaker_factory;
- const unsigned char* client_cert = NULL;
- unsigned int client_cert_size = 0;
- const unsigned char* client_key = NULL;
- unsigned int client_key_size = 0;
- if (config_.do_client_authentication) {
- if (config_.use_bad_client_cert) {
- client_cert =
- reinterpret_cast<const unsigned char*>(badclient_cert_.data());
- client_cert_size = badclient_cert_.size();
- client_key =
- reinterpret_cast<const unsigned char*>(badclient_key_.data());
- client_key_size = badclient_key_.size();
- } else {
- client_cert =
- reinterpret_cast<const unsigned char*>(client_cert_.data());
- client_cert_size = client_cert_.size();
- client_key = reinterpret_cast<const unsigned char*>(client_key_.data());
- client_key_size = client_key_.size();
- }
- }
- const unsigned char** client_alpn_protocols(nullptr);
- const unsigned char* client_alpn_protocols_lengths(nullptr);
- uint16_t num_client_alpn_protocols = 0;
- if (config_.alpn_mode == ALPN_CLIENT_NO_SERVER ||
- config_.alpn_mode == ALPN_CLIENT_SERVER_OK ||
- config_.alpn_mode == ALPN_CLIENT_SERVER_MISMATCH) {
- client_alpn_protocols =
- reinterpret_cast<const unsigned char**>(&client_alpn_protocols_[0]);
- client_alpn_protocols_lengths = &client_alpn_protocols_lengths_[0];
- num_client_alpn_protocols = client_alpn_protocols_.size();
- }
-
- EXPECT_EQ(tsi_create_ssl_client_handshaker_factory(
- client_key, client_key_size, client_cert, client_cert_size,
- reinterpret_cast<const unsigned char*>(root_certs_.data()),
- root_certs_.size(), NULL, client_alpn_protocols,
- client_alpn_protocols_lengths, num_client_alpn_protocols,
- &client_handshaker_factory),
- TSI_OK);
- client_handshaker_factory_.reset(client_handshaker_factory);
-
- const unsigned char** server_alpn_protocols(nullptr);
- const unsigned char* server_alpn_protocols_lengths(nullptr);
- uint16_t num_server_alpn_protocols = 0;
- if (config_.alpn_mode == ALPN_SERVER_NO_CLIENT ||
- config_.alpn_mode == ALPN_CLIENT_SERVER_OK ||
- config_.alpn_mode == ALPN_CLIENT_SERVER_MISMATCH) {
- server_alpn_protocols =
- reinterpret_cast<const unsigned char**>(&server_alpn_protocols_[0]);
- server_alpn_protocols_lengths = &server_alpn_protocols_lengths_[0];
- num_server_alpn_protocols = server_alpn_protocols_.size();
- if (config_.alpn_mode == ALPN_CLIENT_SERVER_MISMATCH) {
- // Remove the last element that is common.
- num_server_alpn_protocols--;
- }
- }
- tsi_ssl_handshaker_factory* server_handshaker_factory;
- EXPECT_EQ(
- tsi_create_ssl_server_handshaker_factory(
- config_.use_bad_server_cert ? &badserver_keys_[0]
- : &server_keys_[0],
- config_.use_bad_server_cert ? &badserver_keys_sizes_[0]
- : &server_keys_sizes_[0],
- config_.use_bad_server_cert ? &badserver_certs_[0]
- : &server_certs_[0],
- config_.use_bad_server_cert ? &badserver_certs_sizes_[0]
- : &server_certs_sizes_[0],
- config_.use_bad_server_cert ? badserver_keys_.size()
- : server_keys_.size(),
- config_.do_client_authentication
- ? reinterpret_cast<const unsigned char*>(root_certs_.data())
- : NULL,
- config_.do_client_authentication ? root_certs_.size() : 0, NULL,
- server_alpn_protocols, server_alpn_protocols_lengths,
- num_server_alpn_protocols, &server_handshaker_factory),
- TSI_OK);
- server_handshaker_factory_.reset(server_handshaker_factory);
-
- tsi_handshaker* client_handshaker;
- EXPECT_EQ(tsi_ssl_handshaker_factory_create_handshaker(
- client_handshaker_factory, config_.subject_name_indication,
- &client_handshaker),
- TSI_OK);
- client_handshaker_.reset(client_handshaker);
-
- tsi_handshaker* server_handshaker;
- EXPECT_EQ(tsi_ssl_handshaker_factory_create_handshaker(
- server_handshaker_factory, NULL, &server_handshaker),
- TSI_OK);
- server_handshaker_.reset(server_handshaker);
- }
-
- void CheckAlpn(const tsi_peer* peer) {
- const tsi_peer_property* alpn_property =
- tsi_peer_get_property_by_name(peer, TSI_SSL_ALPN_SELECTED_PROTOCOL);
- if (config_.alpn_mode != ALPN_CLIENT_SERVER_OK) {
- EXPECT_EQ(nullptr, alpn_property);
- } else {
- EXPECT_NE(nullptr, alpn_property);
- EXPECT_EQ(TSI_PEER_PROPERTY_TYPE_STRING, alpn_property->type);
- string expected_match("baz");
- EXPECT_EQ(expected_match, string(alpn_property->value.string.data,
- alpn_property->value.string.length));
- }
- }
-
- void CheckHandshakeResults() override {
- tsi_peer peer;
-
- bool expect_success =
- !(config_.use_bad_server_cert ||
- (config_.use_bad_client_cert && config_.do_client_authentication));
- tsi_result result = tsi_handshaker_get_result(client_handshaker_.get());
- EXPECT_NE(result, TSI_HANDSHAKE_IN_PROGRESS);
- if (expect_success) {
- EXPECT_EQ(result, TSI_OK);
- EXPECT_EQ(tsi_handshaker_extract_peer(client_handshaker_.get(), &peer),
- TSI_OK);
- CheckAlpn(&peer);
- // TODO(jboeuf): This is a bit fragile. Maybe revisit.
- if (config_.subject_name_indication != nullptr) {
- CheckServer1Peer(&peer);
- } else {
- CheckServer0Peer(&peer);
- }
- } else {
- EXPECT_NE(result, TSI_OK);
- EXPECT_NE(tsi_handshaker_extract_peer(client_handshaker_.get(), &peer),
- TSI_OK);
- }
-
- result = tsi_handshaker_get_result(server_handshaker_.get());
- EXPECT_NE(result, TSI_HANDSHAKE_IN_PROGRESS);
- if (expect_success) {
- EXPECT_EQ(result, TSI_OK);
- EXPECT_EQ(tsi_handshaker_extract_peer(server_handshaker_.get(), &peer),
- TSI_OK);
- CheckAlpn(&peer);
- CheckClientPeer(&peer, config_.do_client_authentication);
- } else {
- EXPECT_NE(result, TSI_OK);
- EXPECT_NE(tsi_handshaker_extract_peer(server_handshaker_.get(), &peer),
- TSI_OK);
- }
- }
-
- const tsi::test::TestConfig* config() override {
- return &config_;
- }
-
- SslTransportSecurityTest()
- : client_alpn_protocols_({"foo", "toto", "baz"}),
- server_alpn_protocols_({"boooo", "far", "baz"}),
- client_alpn_protocols_lengths_({3, 4, 3}),
- server_alpn_protocols_lengths_({5, 3, 3}) {
- CHECK_OK(file::GetContents(
- file::JoinPath(FLAGS_test_srcdir, kTestCredsDir, "badserver.key"),
- &badserver_key_, file::Options()));
- CHECK_OK(file::GetContents(
- file::JoinPath(FLAGS_test_srcdir, kTestCredsDir, "badserver.pem"),
- &badserver_cert_, file::Options()));
- CHECK_OK(file::GetContents(
- file::JoinPath(FLAGS_test_srcdir, kTestCredsDir, "badclient.key"),
- &badclient_key_, file::Options()));
- CHECK_OK(file::GetContents(
- file::JoinPath(FLAGS_test_srcdir, kTestCredsDir, "badclient.pem"),
- &badclient_cert_, file::Options()));
- CHECK_OK(file::GetContents(
- file::JoinPath(FLAGS_test_srcdir, kTestCredsDir, "server0.key"),
- &server0_key_, file::Options()));
- CHECK_OK(file::GetContents(
- file::JoinPath(FLAGS_test_srcdir, kTestCredsDir, "server0.pem"),
- &server0_cert_, file::Options()));
- CHECK_OK(file::GetContents(
- file::JoinPath(FLAGS_test_srcdir, kTestCredsDir, "server1.key"),
- &server1_key_, file::Options()));
- CHECK_OK(file::GetContents(
- file::JoinPath(FLAGS_test_srcdir, kTestCredsDir, "server1.pem"),
- &server1_cert_, file::Options()));
- CHECK_OK(file::GetContents(
- file::JoinPath(FLAGS_test_srcdir, kTestCredsDir, "client.key"),
- &client_key_, file::Options()));
- CHECK_OK(file::GetContents(
- file::JoinPath(FLAGS_test_srcdir, kTestCredsDir, "client.pem"),
- &client_cert_, file::Options()));
- CHECK_OK(file::GetContents(
- file::JoinPath(FLAGS_test_srcdir, kTestCredsDir, "ca.pem"),
- &root_certs_, file::Options()));
- badserver_keys_.push_back(
- reinterpret_cast<const unsigned char*>(badserver_key_.data()));
- badserver_certs_.push_back(
- reinterpret_cast<const unsigned char*>(badserver_cert_.data()));
- server_keys_.push_back(
- reinterpret_cast<const unsigned char*>(server0_key_.data()));
- server_keys_.push_back(
- reinterpret_cast<const unsigned char*>(server1_key_.data()));
- server_certs_.push_back(
- reinterpret_cast<const unsigned char*>(server0_cert_.data()));
- server_certs_.push_back(
- reinterpret_cast<const unsigned char*>(server1_cert_.data()));
- badserver_keys_sizes_.push_back(badserver_key_.size());
- badserver_certs_sizes_.push_back(badserver_cert_.size());
- server_keys_sizes_.push_back(server0_key_.size());
- server_keys_sizes_.push_back(server1_key_.size());
- server_certs_sizes_.push_back(server0_cert_.size());
- server_certs_sizes_.push_back(server1_cert_.size());
- }
-
- string badserver_key_;
- string badserver_cert_;
- string badclient_key_;
- string badclient_cert_;
- string server0_key_;
- string server0_cert_;
- string server1_key_;
- string server1_cert_;
- string client_key_;
- string client_cert_;
- string root_certs_;
- std::vector<const unsigned char*> badserver_keys_;
- std::vector<const unsigned char*> badserver_certs_;
- std::vector<const unsigned char*> server_keys_;
- std::vector<const unsigned char*> server_certs_;
- std::vector<unsigned int> badserver_keys_sizes_;
- std::vector<unsigned int> badserver_certs_sizes_;
- std::vector<unsigned int> server_keys_sizes_;
- std::vector<unsigned int> server_certs_sizes_;
- TsiSslHandshakerFactoryUniquePtr client_handshaker_factory_;
- TsiSslHandshakerFactoryUniquePtr server_handshaker_factory_;
- std::vector<const char*> client_alpn_protocols_;
- std::vector<const char*> server_alpn_protocols_;
- std::vector<unsigned char> client_alpn_protocols_lengths_;
- std::vector<unsigned char> server_alpn_protocols_lengths_;
- string matched_alpn_;
- SslTestConfig config_;
-};
-
-
-TEST_F(SslTransportSecurityTest, LoadInvalidRoots) {
- tsi_ssl_handshaker_factory* client_handshaker_factory;
- string invalid_roots("Invalid roots!");
- EXPECT_EQ(
- TSI_INVALID_ARGUMENT,
- tsi_create_ssl_client_handshaker_factory(
- NULL, 0, NULL, 0,
- reinterpret_cast<const unsigned char*>(invalid_roots.data()),
- invalid_roots.size(), NULL, NULL, 0, 0, &client_handshaker_factory));
-}
-
-TEST_F(SslTransportSecurityTest, Handshake) {
- PerformHandshake();
-}
-
-TEST_F(SslTransportSecurityTest, HandshakeClientAuthentication) {
- config_.do_client_authentication = true;
- PerformHandshake();
-}
-
-TEST_F(SslTransportSecurityTest, HandshakeSmallBuffer) {
- config_.handshake_buffer_size = 128;
- PerformHandshake();
-}
-
-TEST_F(SslTransportSecurityTest, HandshakeSNIExactDomain) {
- // server1 cert contains waterzooi.test.google.be in SAN.
- config_.subject_name_indication = "waterzooi.test.google.be";
- PerformHandshake();
-}
-
-TEST_F(SslTransportSecurityTest, HandshakeSNIWildstarDomain) {
- // server1 cert contains *.test.google.fr in SAN.
- config_.subject_name_indication = "juju.test.google.fr";
- PerformHandshake();
-}
-
-TEST_F(SslTransportSecurityTest, BadServerCertFailure) {
- config_.use_bad_server_cert = true;
- PerformHandshake();
-}
-
-TEST_F(SslTransportSecurityTest, BadClientCertFailure) {
- config_.use_bad_client_cert = true;
- config_.do_client_authentication = true;
- PerformHandshake();
-}
-
-TEST_F(SslTransportSecurityTest, AlpnClientNoServer) {
- config_.alpn_mode = ALPN_CLIENT_NO_SERVER;
- PerformHandshake();
-}
-
-TEST_F(SslTransportSecurityTest, AlpnServerNoClient) {
- config_.alpn_mode = ALPN_SERVER_NO_CLIENT;
- PerformHandshake();
-}
-
-TEST_F(SslTransportSecurityTest, AlpnClientServeMismatch) {
- config_.alpn_mode = ALPN_CLIENT_SERVER_MISMATCH;
- PerformHandshake();
-}
-
-TEST_F(SslTransportSecurityTest, AlpnClientServerOk) {
- config_.alpn_mode = ALPN_CLIENT_SERVER_OK;
- PerformHandshake();
-}
-
-TEST_F(SslTransportSecurityTest, PingPong) {
- PingPong();
-}
-
-TEST_F(SslTransportSecurityTest, RoundTrip) {
- config_.client_message = big_message_;
- config_.server_message = small_message_;
- DoRoundTrip();
-}
-
-TEST_F(SslTransportSecurityTest, RoundTripSmallMessageBuffer) {
- config_.message_buffer_allocated_size = 42;
- config_.client_message = big_message_;
- config_.server_message = small_message_;
- DoRoundTrip();
-}
-
-TEST_F(SslTransportSecurityTest, RoundTripSmallProtectedBufferSize) {
- config_.protected_buffer_size = 37;
- config_.client_message = big_message_;
- config_.server_message = small_message_;
- DoRoundTrip();
-}
-
-TEST_F(SslTransportSecurityTest, RoundTripSmallReadBufferSize) {
- config_.read_buffer_allocated_size = 41;
- config_.client_message = big_message_;
- config_.server_message = small_message_;
- DoRoundTrip();
-}
-
-TEST_F(SslTransportSecurityTest, RoundTripSmallClientFrames) {
- config_.set_client_max_output_protected_frame_size(39);
- config_.client_message = big_message_;
- config_.server_message = small_message_;
- DoRoundTrip();
-}
-
-TEST_F(SslTransportSecurityTest, RoundTripSmallServerFrames) {
- config_.set_server_max_output_protected_frame_size(43);
- config_.client_message = small_message_;
- config_.server_message = big_message_;
- DoRoundTrip();
-}
-
-TEST_F(SslTransportSecurityTest, RoundTripOddBufferSizes) {
- int odd_sizes[] = {33, 67, 135, 271, 523};
- RandomPermutation<int> permute(odd_sizes, arraysize(odd_sizes),
- random_.get());
- permute.Permute();
- LOG(ERROR) << odd_sizes[0] << "\t" << odd_sizes[1] << "\t" << odd_sizes[2]
- << "\t" << odd_sizes[3] << "\t" << odd_sizes[4];
- config_.message_buffer_allocated_size = odd_sizes[0];
- config_.protected_buffer_size = odd_sizes[1];
- config_.read_buffer_allocated_size = odd_sizes[2];
- config_.set_client_max_output_protected_frame_size(odd_sizes[3]);
- config_.set_server_max_output_protected_frame_size(odd_sizes[4]);
- config_.client_message = big_message_;
- config_.server_message = small_message_;
- DoRoundTrip();
-}
-
-} // namespace
diff --git a/src/core/tsi/transport_security.c b/src/core/tsi/transport_security.c
index 94252e36d0..5a42f03f5f 100644
--- a/src/core/tsi/transport_security.c
+++ b/src/core/tsi/transport_security.c
@@ -44,7 +44,7 @@ char* tsi_strdup(const char* src) {
if (!src) return NULL;
len = strlen(src) + 1;
dst = malloc(len);
- if (!dst) return NULL;
+ if (!dst) return NULL;
memcpy(dst, src, len);
return dst;
}
@@ -84,17 +84,15 @@ const char* tsi_result_to_string(tsi_result result) {
}
}
-
/* --- tsi_frame_protector common implementation. ---
Calls specific implementation after state/input validation. */
-tsi_result tsi_frame_protector_protect(
- tsi_frame_protector* self,
- const unsigned char* unprotected_bytes,
- uint32_t* unprotected_bytes_size,
- unsigned char* protected_output_frames,
- uint32_t* protected_output_frames_size) {
+tsi_result tsi_frame_protector_protect(tsi_frame_protector* self,
+ const unsigned char* unprotected_bytes,
+ uint32_t* unprotected_bytes_size,
+ unsigned char* protected_output_frames,
+ uint32_t* protected_output_frames_size) {
if (self == NULL || unprotected_bytes == NULL ||
unprotected_bytes_size == NULL || protected_output_frames == NULL ||
protected_output_frames_size == NULL) {
@@ -106,10 +104,8 @@ tsi_result tsi_frame_protector_protect(
}
tsi_result tsi_frame_protector_protect_flush(
- tsi_frame_protector* self,
- unsigned char* protected_output_frames,
- uint32_t* protected_output_frames_size,
- uint32_t* still_pending_size) {
+ tsi_frame_protector* self, unsigned char* protected_output_frames,
+ uint32_t* protected_output_frames_size, uint32_t* still_pending_size) {
if (self == NULL || protected_output_frames == NULL ||
protected_output_frames == NULL || still_pending_size == NULL) {
return TSI_INVALID_ARGUMENT;
@@ -120,10 +116,8 @@ tsi_result tsi_frame_protector_protect_flush(
}
tsi_result tsi_frame_protector_unprotect(
- tsi_frame_protector* self,
- const unsigned char* protected_frames_bytes,
- uint32_t* protected_frames_bytes_size,
- unsigned char* unprotected_bytes,
+ tsi_frame_protector* self, const unsigned char* protected_frames_bytes,
+ uint32_t* protected_frames_bytes_size, unsigned char* unprotected_bytes,
uint32_t* unprotected_bytes_size) {
if (self == NULL || protected_frames_bytes == NULL ||
protected_frames_bytes_size == NULL || unprotected_bytes == NULL ||
@@ -140,7 +134,6 @@ void tsi_frame_protector_destroy(tsi_frame_protector* self) {
self->vtable->destroy(self);
}
-
/* --- tsi_handshaker common implementation. ---
Calls specific implementation after state/input validation. */
@@ -153,7 +146,6 @@ tsi_result tsi_handshaker_get_bytes_to_send_to_peer(tsi_handshaker* self,
return self->vtable->get_bytes_to_send_to_peer(self, bytes, bytes_size);
}
-
tsi_result tsi_handshaker_process_bytes_from_peer(tsi_handshaker* self,
const unsigned char* bytes,
uint32_t* bytes_size) {
@@ -179,8 +171,7 @@ tsi_result tsi_handshaker_extract_peer(tsi_handshaker* self, tsi_peer* peer) {
}
tsi_result tsi_handshaker_create_frame_protector(
- tsi_handshaker* self,
- uint32_t* max_protected_frame_size,
+ tsi_handshaker* self, uint32_t* max_protected_frame_size,
tsi_frame_protector** protector) {
tsi_result result;
if (self == NULL || protector == NULL) return TSI_INVALID_ARGUMENT;
@@ -201,7 +192,6 @@ void tsi_handshaker_destroy(tsi_handshaker* self) {
self->vtable->destroy(self);
}
-
/* --- tsi_peer implementation. --- */
const tsi_peer_property* tsi_peer_get_property_by_name(const tsi_peer* self,
@@ -227,7 +217,6 @@ tsi_peer_property tsi_init_peer_property(void) {
return property;
}
-
static void tsi_peer_destroy_list_property(tsi_peer_property* children,
uint32_t child_count) {
uint32_t i;
@@ -254,7 +243,7 @@ void tsi_peer_property_destruct(tsi_peer_property* property) {
/* Nothing to free. */
break;
}
- *property = tsi_init_peer_property(); /* Reset everything to 0. */
+ *property = tsi_init_peer_property(); /* Reset everything to 0. */
}
void tsi_peer_destruct(tsi_peer* self) {
diff --git a/src/core/tsi/transport_security.h b/src/core/tsi/transport_security.h
index cf9a2b0195..9a20fa83a5 100644
--- a/src/core/tsi/transport_security.h
+++ b/src/core/tsi/transport_security.h
@@ -109,10 +109,10 @@ tsi_result tsi_construct_list_peer_property(const char* name,
tsi_peer_property* property);
/* Utils. */
-char* tsi_strdup(const char* src); /* Sadly, no strdup in C89. */
+char* tsi_strdup(const char* src); /* Sadly, no strdup in C89. */
#ifdef __cplusplus
}
#endif
-#endif /* __TRANSPORT_SECURITY_H_ */
+#endif /* __TRANSPORT_SECURITY_H_ */
diff --git a/src/core/tsi/transport_security_interface.h b/src/core/tsi/transport_security_interface.h
index 6be72c753a..76746a4b20 100644
--- a/src/core/tsi/transport_security_interface.h
+++ b/src/core/tsi/transport_security_interface.h
@@ -60,7 +60,6 @@ typedef enum {
const char* tsi_result_to_string(tsi_result result);
-
/* --- tsi_frame_protector object ---
This object protects and unprotects buffers once the handshake is done.
@@ -121,12 +120,11 @@ typedef struct tsi_frame_protector tsi_frame_protector;
if (result != TSI_OK) HandleError(result);
------------------------------------------------------------------------ */
-tsi_result tsi_frame_protector_protect(
- tsi_frame_protector* self,
- const unsigned char* unprotected_bytes,
- uint32_t* unprotected_bytes_size,
- unsigned char* protected_output_frames,
- uint32_t* protected_output_frames_size);
+tsi_result tsi_frame_protector_protect(tsi_frame_protector* self,
+ const unsigned char* unprotected_bytes,
+ uint32_t* unprotected_bytes_size,
+ unsigned char* protected_output_frames,
+ uint32_t* protected_output_frames_size);
/* Indicates that we need to flush the bytes buffered in the protector and get
the resulting frame.
@@ -137,10 +135,8 @@ tsi_result tsi_frame_protector_protect(
- still_pending_bytes is an output parameter indicating the number of bytes
that still need to be flushed from the protector.*/
tsi_result tsi_frame_protector_protect_flush(
- tsi_frame_protector* self,
- unsigned char* protected_output_frames,
- uint32_t* protected_output_frames_size,
- uint32_t* still_pending_size);
+ tsi_frame_protector* self, unsigned char* protected_output_frames,
+ uint32_t* protected_output_frames_size, uint32_t* still_pending_size);
/* Outputs unprotected bytes.
- protected_frames_bytes is an input only parameter and points to the
@@ -163,16 +159,13 @@ tsi_result tsi_frame_protector_protect_flush(
needs to be read before new protected data can be processed in which case
protected_frames_size will be set to 0. */
tsi_result tsi_frame_protector_unprotect(
- tsi_frame_protector* self,
- const unsigned char* protected_frames_bytes,
- uint32_t* protected_frames_bytes_size,
- unsigned char* unprotected_bytes,
+ tsi_frame_protector* self, const unsigned char* protected_frames_bytes,
+ uint32_t* protected_frames_bytes_size, unsigned char* unprotected_bytes,
uint32_t* unprotected_bytes_size);
/* Destroys the tsi_frame_protector object. */
void tsi_frame_protector_destroy(tsi_frame_protector* self);
-
/* --- tsi_peer objects ---
tsi_peer objects are a set of properties. The peer owns the properties. */
@@ -180,23 +173,6 @@ void tsi_frame_protector_destroy(tsi_frame_protector* self);
/* This property is of type TSI_PEER_PROPERTY_STRING. */
#define TSI_CERTIFICATE_TYPE_PEER_PROPERTY "certificate_type"
-/* This property is of type TSI_PEER_PROPERTY_STRING. */
-#define TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY "x509_subject_common_name"
-
-/* This property is of type TSI_PEER_PROPERTY_LIST and the children contain
- unnamed (name == NULL) properties of type TSI_PEER_PROPERTY_STRING. */
-#define TSI_X509_SUBJECT_ALTERNATIVE_NAMES_PEER_PROPERTY \
- "x509_subject_alternative_names"
-
-/* This property is of type TSI_PEER_PROPERTY_STRING. */
-#define TSI_SSL_ALPN_SELECTED_PROTOCOL "ssl_alpn_selected_protocol"
-
-/* This property is of type TSI_PEER_PROPERTY_STRING. */
-#define TSI_MDB_USER_NAME_PEER_PROPERTY "mdb_user_name"
-
-/* This property is of type TSI_PEER_PROPERTY_SIGNED_INTEGER. */
-#define TSI_MDB_GAIA_ID_PEER_PROPERTY "mdb_gaia_id"
-
/* Properties of type TSI_PEER_PROPERTY_TYPE_STRING may contain NULL characters
just like C++ strings. The length field gives the length of the string. */
typedef enum {
@@ -350,7 +326,6 @@ tsi_result tsi_handshaker_get_result(tsi_handshaker* self);
#define tsi_handshaker_is_in_progress(h) \
(tsi_handshaker_get_result((h)) == TSI_HANDSHAKE_IN_PROGRESS)
-
/* This method may return TSI_FAILED_PRECONDITION if
tsi_handshaker_is_in_progress returns 1, it returns TSI_OK otherwise
assuming the handshaker is not in a fatal error state.
@@ -374,8 +349,7 @@ tsi_result tsi_handshaker_extract_peer(tsi_handshaker* self, tsi_peer* peer);
the handshaker is not in a fatal error state.
The caller is responsible for destroying the protector. */
tsi_result tsi_handshaker_create_frame_protector(
- tsi_handshaker* self,
- uint32_t* max_output_protected_frame_size,
+ tsi_handshaker* self, uint32_t* max_output_protected_frame_size,
tsi_frame_protector** protector);
/* This method releases the tsi_handshaker object. After this method is called,
@@ -386,4 +360,4 @@ void tsi_handshaker_destroy(tsi_handshaker* self);
}
#endif
-#endif /* __TRANSPORT_SECURITY_INTERFACE_H_ */
+#endif /* __TRANSPORT_SECURITY_INTERFACE_H_ */
diff --git a/src/core/tsi/transport_security_test_lib.cc b/src/core/tsi/transport_security_test_lib.cc
deleted file mode 100644
index 1b630c9578..0000000000
--- a/src/core/tsi/transport_security_test_lib.cc
+++ /dev/null
@@ -1,363 +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/core/tsi/transport_security_test_lib.h"
-
-#include <memory>
-
-#include "base/commandlineflags.h"
-#include "src/core/tsi/transport_security_interface.h"
-#include "strings/escaping.h"
-#include "strings/strcat.h"
-#include <gtest/gtest.h>
-#include "util/random/mt_random.h"
-
-namespace {
-
-const char kPingRequest[] = "Ping";
-const char kPongResponse[] = "Pong";
-const int kBigMessageSize = 17000;
-
-} // namespace
-
-namespace tsi {
-namespace test {
-
-TransportSecurityTest::TransportSecurityTest() : random_(new MTRandom()) {
- small_message_ = "Chapi Chapo";
- big_message_ = RandomString(kBigMessageSize);
-}
-
-string TransportSecurityTest::RandomString(int size) {
- std::unique_ptr<char[]> buffer(new char[size]);
- for (int i = 0; i < size; i++) {
- buffer[i] = random_->Rand8();
- }
- return string(buffer.get(), size);
-}
-
-void TransportSecurityTest::SendBytesToPeer(bool is_client, unsigned char* buf,
- unsigned int buf_size) {
- string& channel = is_client ? to_server_channel_ : to_client_channel_;
- LOG(INFO) << (is_client ? "Client:" : "Server") << " sending " << buf_size
- << " bytes to peer.";
- channel.append(reinterpret_cast<const char*>(buf), buf_size);
-}
-
-void TransportSecurityTest::ReadBytesFromPeer(bool is_client,
- unsigned char* buf,
- unsigned int* buf_size) {
- string& channel = is_client ? to_client_channel_ : to_server_channel_;
- unsigned int to_read =
- *buf_size < channel.size() ? *buf_size : channel.size();
- memcpy(buf, channel.data(), to_read);
- *buf_size = to_read;
- channel.erase(0, to_read);
- LOG(INFO) << (is_client ? "Client:" : "Server") << " read " << to_read
- << " bytes from peer.";
-}
-
-void TransportSecurityTest::DoHandshakeStep(bool is_client,
- unsigned int buf_allocated_size,
- tsi_handshaker* handshaker,
- string* remaining_bytes) {
- tsi_result result = TSI_OK;
- std::unique_ptr<unsigned char[]> buf(new unsigned char[buf_allocated_size]);
- unsigned int buf_offset;
- unsigned int buf_size;
- // See if we need to send some bytes to the peer.
- do {
- unsigned int buf_size_to_send = buf_allocated_size;
- result = tsi_handshaker_get_bytes_to_send_to_peer(handshaker, buf.get(),
- &buf_size_to_send);
- if (buf_size_to_send > 0) {
- SendBytesToPeer(is_client, buf.get(), buf_size_to_send);
- }
- } while (result == TSI_INCOMPLETE_DATA);
- if (!tsi_handshaker_is_in_progress(handshaker)) return;
-
- do {
- // Read bytes from the peer.
- buf_size = buf_allocated_size;
- buf_offset = 0;
- ReadBytesFromPeer(is_client, buf.get(), &buf_size);
- if (buf_size == 0) break;
-
- // Process the bytes from the peer. We have to be careful as these bytes
- // may contain non-handshake data (protected data). If this is the case,
- // we will exit from the loop with buf_size > 0.
- unsigned int consumed_by_handshaker = buf_size;
- result = tsi_handshaker_process_bytes_from_peer(handshaker, buf.get(),
- &consumed_by_handshaker);
- buf_size -= consumed_by_handshaker;
- buf_offset += consumed_by_handshaker;
- } while (result == TSI_INCOMPLETE_DATA);
-
- if (!tsi_handshaker_is_in_progress(handshaker)) {
- remaining_bytes->assign(
- reinterpret_cast<const char*>(buf.get()) + buf_offset, buf_size);
- }
-}
-
-void TransportSecurityTest::PerformHandshake() {
- SetupHandshakers();
- string remaining_bytes;
- do {
- DoHandshakeStep(true, config()->handshake_buffer_size,
- client_handshaker_.get(), &remaining_bytes);
- EXPECT_EQ(0, remaining_bytes.size());
- DoHandshakeStep(false, config()->handshake_buffer_size,
- server_handshaker_.get(), &remaining_bytes);
- EXPECT_EQ(0, remaining_bytes.size());
- } while (tsi_handshaker_is_in_progress(client_handshaker_.get()) ||
- tsi_handshaker_is_in_progress(server_handshaker_.get()));
- CheckHandshakeResults();
-}
-
-void TransportSecurityTest::SendMessageToPeer(
- bool is_client, tsi_frame_protector* protector, const string& message,
- unsigned int protected_buffer_size) {
- std::unique_ptr<unsigned char[]> protected_buffer(
- new unsigned char[protected_buffer_size]);
- unsigned int message_size = message.size();
- const unsigned char* message_bytes =
- reinterpret_cast<const unsigned char*>(message.data());
- tsi_result result = TSI_OK;
- while (message_size > 0 && result == TSI_OK) {
- unsigned int protected_buffer_size_to_send = protected_buffer_size;
- unsigned int processed_message_size = message_size;
- result = tsi_frame_protector_protect(
- protector, message_bytes, &processed_message_size,
- protected_buffer.get(), &protected_buffer_size_to_send);
- EXPECT_EQ(TSI_OK, result);
- SendBytesToPeer(is_client, protected_buffer.get(),
- protected_buffer_size_to_send);
- message_bytes += processed_message_size;
- message_size -= processed_message_size;
-
- // Flush if we're done.
- if (message_size == 0) {
- unsigned int still_pending_size;
- do {
- protected_buffer_size_to_send = protected_buffer_size;
- result = tsi_frame_protector_protect_flush(
- protector, protected_buffer.get(), &protected_buffer_size_to_send,
- &still_pending_size);
- EXPECT_EQ(TSI_OK, result);
- SendBytesToPeer(is_client, protected_buffer.get(),
- protected_buffer_size_to_send);
- } while (still_pending_size > 0 && result == TSI_OK);
- EXPECT_EQ(TSI_OK, result);
- }
- }
- EXPECT_EQ(TSI_OK, result);
-}
-
-void TransportSecurityTest::ReceiveMessageFromPeer(
- bool is_client, tsi_frame_protector* protector,
- unsigned int read_buf_allocated_size,
- unsigned int message_buf_allocated_size, string* message) {
- std::unique_ptr<unsigned char[]> read_buffer(
- new unsigned char[read_buf_allocated_size]);
- unsigned int read_offset = 0;
- unsigned int read_from_peer_size = 0;
- std::unique_ptr<unsigned char[]> message_buffer(
- new unsigned char[message_buf_allocated_size]);
- tsi_result result = TSI_OK;
- bool done = false;
- while (!done && result == TSI_OK) {
- if (read_from_peer_size == 0) {
- read_from_peer_size = read_buf_allocated_size;
- ReadBytesFromPeer(is_client, read_buffer.get(), &read_from_peer_size);
- read_offset = 0;
- }
- if (read_from_peer_size == 0) done = true;
- unsigned int message_buffer_size;
- do {
- message_buffer_size = message_buf_allocated_size;
- unsigned int processed_size = read_from_peer_size;
- result = tsi_frame_protector_unprotect(
- protector, read_buffer.get() + read_offset, &processed_size,
- message_buffer.get(), &message_buffer_size);
- EXPECT_EQ(TSI_OK, result);
- if (message_buffer_size > 0) {
- LOG(INFO) << "Wrote " << message_buffer_size << " bytes to message.";
- message->append(reinterpret_cast<const char*>(message_buffer.get()),
- message_buffer_size);
- }
- read_offset += processed_size;
- read_from_peer_size -= processed_size;
- } while ((read_from_peer_size > 0 || message_buffer_size > 0) &&
- result == TSI_OK);
- EXPECT_EQ(TSI_OK, result);
- }
- EXPECT_EQ(TSI_OK, result);
-}
-
-void TransportSecurityTest::DoRoundTrip(const string& request,
- const string& response) {
- PerformHandshake();
-
- tsi_frame_protector* client_frame_protector;
- tsi_frame_protector* server_frame_protector;
- unsigned int client_max_output_protected_frame_size =
- config()->client_max_output_protected_frame_size();
- EXPECT_EQ(TSI_OK,
- tsi_handshaker_create_frame_protector(
- client_handshaker_.get(),
- config()->use_client_default_max_output_protected_frame_size()
- ? nullptr
- : &client_max_output_protected_frame_size,
- &client_frame_protector));
-
- unsigned int server_max_output_protected_frame_size =
- config()->server_max_output_protected_frame_size();
- EXPECT_EQ(TSI_OK,
- tsi_handshaker_create_frame_protector(
- server_handshaker_.get(),
- config()->use_server_default_max_output_protected_frame_size()
- ? nullptr
- : &server_max_output_protected_frame_size,
- &server_frame_protector));
-
- SendMessageToPeer(true, client_frame_protector, request,
- config()->protected_buffer_size);
- string retrieved_request;
- ReceiveMessageFromPeer(
- false, server_frame_protector, config()->read_buffer_allocated_size,
- config()->message_buffer_allocated_size, &retrieved_request);
- EXPECT_EQ(request.size(), retrieved_request.size());
- EXPECT_EQ(strings::b2a_hex(request), strings::b2a_hex(retrieved_request));
-
- SendMessageToPeer(false, server_frame_protector, response,
- config()->protected_buffer_size);
- string retrieved_response;
- ReceiveMessageFromPeer(
- true, client_frame_protector, config()->read_buffer_allocated_size,
- config()->message_buffer_allocated_size, &retrieved_response);
- EXPECT_EQ(response.size(), retrieved_response.size());
- EXPECT_EQ(strings::b2a_hex(response), strings::b2a_hex(retrieved_response));
-
- tsi_frame_protector_destroy(client_frame_protector);
- tsi_frame_protector_destroy(server_frame_protector);
-}
-
-void TransportSecurityTest::DoRoundTrip() {
- DoRoundTrip(config()->client_message, config()->server_message);
-}
-void TransportSecurityTest::PingPong() {
- PerformHandshake();
-
- unsigned char to_server[4096];
- unsigned char to_client[4096];
- unsigned int max_frame_size = sizeof(to_client);
- tsi_frame_protector* client_frame_protector;
- tsi_frame_protector* server_frame_protector;
- EXPECT_EQ(
- tsi_handshaker_create_frame_protector(
- client_handshaker_.get(), &max_frame_size, &client_frame_protector),
- TSI_OK);
- EXPECT_EQ(max_frame_size, sizeof(to_client));
- EXPECT_EQ(
- tsi_handshaker_create_frame_protector(
- server_handshaker_.get(), &max_frame_size, &server_frame_protector),
- TSI_OK);
- EXPECT_EQ(max_frame_size, sizeof(to_client));
-
- // Send Ping.
- unsigned int ping_length = strlen(kPingRequest);
- unsigned int protected_size = sizeof(to_server);
- EXPECT_EQ(tsi_frame_protector_protect(
- client_frame_protector,
- reinterpret_cast<const unsigned char*>(kPingRequest),
- &ping_length, to_server, &protected_size),
- TSI_OK);
- EXPECT_EQ(ping_length, strlen(kPingRequest));
- EXPECT_EQ(protected_size, 0);
- protected_size = sizeof(to_server);
- unsigned int still_pending_size;
- EXPECT_EQ(
- tsi_frame_protector_protect_flush(client_frame_protector, to_server,
- &protected_size, &still_pending_size),
- TSI_OK);
- EXPECT_EQ(still_pending_size, 0);
- EXPECT_GT(protected_size, strlen(kPingRequest));
-
- // Receive Ping.
- unsigned int unprotected_size = sizeof(to_server);
- unsigned int saved_protected_size = protected_size;
- EXPECT_EQ(tsi_frame_protector_unprotect(server_frame_protector, to_server,
- &protected_size, to_server,
- &unprotected_size),
- TSI_OK);
- EXPECT_EQ(saved_protected_size, protected_size);
- EXPECT_EQ(ping_length, unprotected_size);
- EXPECT_EQ(string(kPingRequest),
- string(reinterpret_cast<const char*>(to_server), unprotected_size));
-
- // Send back Pong.
- unsigned int pong_length = strlen(kPongResponse);
- protected_size = sizeof(to_client);
- EXPECT_EQ(tsi_frame_protector_protect(
- server_frame_protector,
- reinterpret_cast<const unsigned char*>(kPongResponse),
- &pong_length, to_client, &protected_size),
- TSI_OK);
- EXPECT_EQ(pong_length, strlen(kPongResponse));
- EXPECT_EQ(protected_size, 0);
- protected_size = sizeof(to_client);
- EXPECT_EQ(
- tsi_frame_protector_protect_flush(server_frame_protector, to_client,
- &protected_size, &still_pending_size),
- TSI_OK);
- EXPECT_EQ(still_pending_size, 0);
- EXPECT_GT(protected_size, strlen(kPongResponse));
-
- // Receive Pong.
- unprotected_size = sizeof(to_server);
- saved_protected_size = protected_size;
- EXPECT_EQ(tsi_frame_protector_unprotect(client_frame_protector, to_client,
- &protected_size, to_client,
- &unprotected_size),
- TSI_OK);
- EXPECT_EQ(saved_protected_size, protected_size);
- EXPECT_EQ(pong_length, unprotected_size);
- EXPECT_EQ(string(kPongResponse),
- string(reinterpret_cast<const char*>(to_client), unprotected_size));
-
- tsi_frame_protector_destroy(client_frame_protector);
- tsi_frame_protector_destroy(server_frame_protector);
-}
-
-} // namespace test
-} // namespace tsi
diff --git a/src/core/tsi/transport_security_test_lib.h b/src/core/tsi/transport_security_test_lib.h
deleted file mode 100644
index 8c9c764c91..0000000000
--- a/src/core/tsi/transport_security_test_lib.h
+++ /dev/null
@@ -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.
- *
- */
-
-#ifndef __TRANSPORT_SECURITY_TEST_LIB_H_
-#define __TRANSPORT_SECURITY_TEST_LIB_H_
-
-#include <memory>
-
-#include "base/commandlineflags.h"
-#include "src/core/tsi/transport_security_interface.h"
-#include "strings/strcat.h"
-#include <gtest/gtest.h>
-#include "util/random/mt_random.h"
-
-namespace tsi {
-namespace test {
-
-class TestConfig {
- public:
- TestConfig()
- : client_message("Chapi Chapo"),
- server_message("Chapi Chapo"),
- handshake_buffer_size(4096),
- read_buffer_allocated_size(4096),
- message_buffer_allocated_size(4096),
- protected_buffer_size(16384),
- use_client_default_max_output_protected_frame_size_(true),
- use_server_default_max_output_protected_frame_size_(true),
- client_max_output_protected_frame_size_(0),
- server_max_output_protected_frame_size_(0) {}
-
- void set_client_max_output_protected_frame_size(unsigned int size) {
- use_client_default_max_output_protected_frame_size_ = false;
- client_max_output_protected_frame_size_ = size;
- }
- void set_server_max_output_protected_frame_size(unsigned int size) {
- use_server_default_max_output_protected_frame_size_ = false;
- server_max_output_protected_frame_size_ = size;
- }
- bool use_client_default_max_output_protected_frame_size() const {
- return use_client_default_max_output_protected_frame_size_;
- }
- bool use_server_default_max_output_protected_frame_size() const {
- return use_server_default_max_output_protected_frame_size_;
- }
- unsigned int client_max_output_protected_frame_size() const {
- return client_max_output_protected_frame_size_;
- }
- unsigned int server_max_output_protected_frame_size() const {
- return server_max_output_protected_frame_size_;
- }
-
- string client_message;
- string server_message;
- unsigned int handshake_buffer_size;
- unsigned int read_buffer_allocated_size;
- unsigned int message_buffer_allocated_size;
- unsigned int protected_buffer_size;
-
- private:
- bool use_client_default_max_output_protected_frame_size_;
- bool use_server_default_max_output_protected_frame_size_;
- unsigned int client_max_output_protected_frame_size_;
- unsigned int server_max_output_protected_frame_size_;
-};
-
-
-struct TsiHandshakerDeleter {
- inline void operator()(tsi_handshaker* ptr) { tsi_handshaker_destroy(ptr); }
-};
-typedef std::unique_ptr<tsi_handshaker, TsiHandshakerDeleter>
- TsiHandshakerUniquePtr;
-
-class TransportSecurityTest : public ::testing::Test {
- protected:
- TransportSecurityTest();
- virtual ~TransportSecurityTest() {}
- virtual const TestConfig* config() = 0;
- string RandomString(int size);
- virtual void SetupHandshakers() = 0;
- // An implementation-specific verification of the validity of the handshake.
- virtual void CheckHandshakeResults() = 0;
- // Do a full handshake.
- void PerformHandshake();
- // Send a protected message between the client and server.
- void SendMessageToPeer(bool is_client, tsi_frame_protector* protector,
- const string& message,
- unsigned int protected_buffer_size);
- void ReceiveMessageFromPeer(bool is_client, tsi_frame_protector* protector,
- unsigned int read_buf_allocated_size,
- unsigned int message_buf_allocated_size,
- string* message);
-
- // A simple test that does a handshake and sends a message back and forth
- void PingPong();
- // A complicated test that can be configured by modifying config().
- void DoRoundTrip();
-
- TsiHandshakerUniquePtr client_handshaker_;
- TsiHandshakerUniquePtr server_handshaker_;
-
- string small_message_;
- string big_message_;
- std::unique_ptr<RandomBase> random_;
-
- private:
- // Functions to send raw bytes between the client and server.
- void SendBytesToPeer(bool is_client, unsigned char* buf,
- unsigned int buf_size);
- void ReadBytesFromPeer(bool is_client, unsigned char* buf,
- unsigned int* buf_size);
- // Do a single step of the handshake.
- void DoHandshakeStep(bool is_client, unsigned int buf_allocated_size,
- tsi_handshaker* handshaker, string* remaining_bytes);
- void DoRoundTrip(const string& request, const string& response);
-
- string to_server_channel_;
- string to_client_channel_;
-};
-
-} // namespace test
-} // namespace tsi
-
-#endif // __TRANSPORT_SECURITY_TEST_LIB_H_
diff --git a/src/cpp/client/channel.cc b/src/cpp/client/channel.cc
index 7d95518631..ddda8c22d6 100644
--- a/src/cpp/client/channel.cc
+++ b/src/cpp/client/channel.cc
@@ -41,13 +41,13 @@
#include <grpc/support/log.h>
#include <grpc/support/slice.h>
-#include "src/cpp/rpc_method.h"
#include "src/cpp/proto/proto_utils.h"
#include "src/cpp/stream/stream_context.h"
#include <grpc++/channel_arguments.h>
#include <grpc++/client_context.h>
#include <grpc++/config.h>
#include <grpc++/credentials.h>
+#include <grpc++/impl/rpc_method.h>
#include <grpc++/status.h>
#include <google/protobuf/message.h>
@@ -69,8 +69,9 @@ Channel::Channel(const grpc::string& target,
: args.GetSslTargetNameOverride()) {
grpc_channel_args channel_args;
args.SetChannelArgs(&channel_args);
+ grpc_credentials* c_creds = creds ? creds->GetRawCreds() : nullptr;
c_channel_ = grpc_secure_channel_create(
- creds->GetRawCreds(), target.c_str(),
+ c_creds, target.c_str(),
channel_args.num_args > 0 ? &channel_args : nullptr);
}
@@ -118,10 +119,15 @@ Status Channel::StartBlockingRpc(const RpcMethod& method,
finished_tag,
GRPC_WRITE_BUFFER_HINT) == GRPC_CALL_OK);
ev = grpc_completion_queue_pluck(cq, invoke_tag, gpr_inf_future);
+ bool success = ev->data.invoke_accepted == GRPC_OP_OK;
grpc_event_finish(ev);
+ if (!success) {
+ GetFinalStatus(cq, finished_tag, &status);
+ return status;
+ }
// write request
grpc_byte_buffer* write_buffer = nullptr;
- bool success = SerializeProto(request, &write_buffer);
+ success = SerializeProto(request, &write_buffer);
if (!success) {
grpc_call_cancel(call);
status =
@@ -166,10 +172,10 @@ Status Channel::StartBlockingRpc(const RpcMethod& method,
return status;
}
-StreamContextInterface* Channel::CreateStream(const RpcMethod& method,
- ClientContext* context,
- const google::protobuf::Message* request,
- google::protobuf::Message* result) {
+StreamContextInterface* Channel::CreateStream(
+ const RpcMethod& method, ClientContext* context,
+ const google::protobuf::Message* request,
+ google::protobuf::Message* result) {
grpc_call* call = grpc_channel_create_call(
c_channel_, method.name(), target_.c_str(), context->RawDeadline());
context->set_call(call);
diff --git a/src/cpp/client/channel.h b/src/cpp/client/channel.h
index 621e58539b..8de1180ac2 100644
--- a/src/cpp/client/channel.h
+++ b/src/cpp/client/channel.h
@@ -58,10 +58,10 @@ class Channel : public ChannelInterface {
const google::protobuf::Message& request,
google::protobuf::Message* result) override;
- StreamContextInterface* CreateStream(const RpcMethod& method,
- ClientContext* context,
- const google::protobuf::Message* request,
- google::protobuf::Message* result) override;
+ StreamContextInterface* CreateStream(
+ const RpcMethod& method, ClientContext* context,
+ const google::protobuf::Message* request,
+ google::protobuf::Message* result) override;
private:
const grpc::string target_;
diff --git a/src/cpp/client/credentials.cc b/src/cpp/client/credentials.cc
index 986008f7bb..d81cf9f4d0 100644
--- a/src/cpp/client/credentials.cc
+++ b/src/cpp/client/credentials.cc
@@ -31,10 +31,10 @@
*
*/
-
#include <string>
#include <grpc/grpc_security.h>
+#include <grpc/support/log.h>
#include <grpc++/credentials.h>
@@ -58,6 +58,9 @@ std::unique_ptr<Credentials> CredentialsFactory::SslCredentials(
options.pem_root_certs.empty() ? nullptr
: reinterpret_cast<const unsigned char*>(
options.pem_root_certs.c_str());
+ if (pem_root_certs == nullptr) {
+ return std::unique_ptr<Credentials>();
+ }
const unsigned char* pem_private_key =
options.pem_private_key.empty() ? nullptr
: reinterpret_cast<const unsigned char*>(
@@ -71,17 +74,42 @@ std::unique_ptr<Credentials> CredentialsFactory::SslCredentials(
pem_root_certs, options.pem_root_certs.size(), pem_private_key,
options.pem_private_key.size(), pem_cert_chain,
options.pem_cert_chain.size());
- std::unique_ptr<Credentials> cpp_creds(new Credentials(c_creds));
+ std::unique_ptr<Credentials> cpp_creds(
+ c_creds == nullptr ? nullptr : new Credentials(c_creds));
return cpp_creds;
}
// Builds credentials for use when running in GCE
std::unique_ptr<Credentials> CredentialsFactory::ComputeEngineCredentials() {
grpc_credentials* c_creds = grpc_compute_engine_credentials_create();
- std::unique_ptr<Credentials> cpp_creds(new Credentials(c_creds));
+ std::unique_ptr<Credentials> cpp_creds(
+ c_creds == nullptr ? nullptr : new Credentials(c_creds));
return cpp_creds;
}
+// Builds service account credentials.
+std::unique_ptr<Credentials> CredentialsFactory::ServiceAccountCredentials(
+ const grpc::string& json_key, const grpc::string& scope,
+ std::chrono::seconds token_lifetime) {
+ gpr_timespec lifetime = gpr_time_from_seconds(
+ token_lifetime.count() > 0 ? token_lifetime.count() : 0);
+ grpc_credentials* c_creds = grpc_service_account_credentials_create(
+ json_key.c_str(), scope.c_str(), lifetime);
+ std::unique_ptr<Credentials> cpp_creds(
+ c_creds == nullptr ? nullptr : new Credentials(c_creds));
+ return cpp_creds;
+}
+
+// Builds IAM credentials.
+std::unique_ptr<Credentials> CredentialsFactory::IAMCredentials(
+ const grpc::string& authorization_token,
+ const grpc::string& authority_selector) {
+ grpc_credentials* c_creds = grpc_iam_credentials_create(
+ authorization_token.c_str(), authority_selector.c_str());
+ std::unique_ptr<Credentials> cpp_creds(
+ c_creds == nullptr ? nullptr : new Credentials(c_creds));
+ return cpp_creds;
+}
// Combines two credentials objects into a composite credentials.
std::unique_ptr<Credentials> CredentialsFactory::ComposeCredentials(
@@ -93,7 +121,8 @@ std::unique_ptr<Credentials> CredentialsFactory::ComposeCredentials(
// refcounts incremented.
grpc_credentials* c_creds = grpc_composite_credentials_create(
creds1->GetRawCreds(), creds2->GetRawCreds());
- std::unique_ptr<Credentials> cpp_creds(new Credentials(c_creds));
+ std::unique_ptr<Credentials> cpp_creds(
+ c_creds == nullptr ? nullptr : new Credentials(c_creds));
return cpp_creds;
}
diff --git a/src/cpp/client/internal_stub.cc b/src/cpp/client/internal_stub.cc
index ec88ba5e7e..51cb99d1b4 100644
--- a/src/cpp/client/internal_stub.cc
+++ b/src/cpp/client/internal_stub.cc
@@ -31,6 +31,6 @@
*
*/
-#include "src/cpp/client/internal_stub.h"
+#include <grpc++/impl/internal_stub.h>
namespace grpc {} // namespace grpc
diff --git a/src/cpp/rpc_method.cc b/src/cpp/common/rpc_method.cc
index 8067f42f85..c8b2ccb10e 100644
--- a/src/cpp/rpc_method.cc
+++ b/src/cpp/common/rpc_method.cc
@@ -31,6 +31,6 @@
*
*/
-#include "src/cpp/rpc_method.h"
+#include <grpc++/impl/rpc_method.h>
namespace grpc {} // namespace grpc
diff --git a/src/cpp/proto/proto_utils.cc b/src/cpp/proto/proto_utils.cc
index 255d1461a9..3b94dc3c07 100644
--- a/src/cpp/proto/proto_utils.cc
+++ b/src/cpp/proto/proto_utils.cc
@@ -40,7 +40,8 @@
namespace grpc {
-bool SerializeProto(const google::protobuf::Message& msg, grpc_byte_buffer** bp) {
+bool SerializeProto(const google::protobuf::Message& msg,
+ grpc_byte_buffer** bp) {
grpc::string msg_str;
bool success = msg.SerializeToString(&msg_str);
if (success) {
@@ -52,7 +53,8 @@ bool SerializeProto(const google::protobuf::Message& msg, grpc_byte_buffer** bp)
return success;
}
-bool DeserializeProto(grpc_byte_buffer* buffer, google::protobuf::Message* msg) {
+bool DeserializeProto(grpc_byte_buffer* buffer,
+ google::protobuf::Message* msg) {
grpc::string msg_string;
grpc_byte_buffer_reader* reader = grpc_byte_buffer_reader_create(buffer);
gpr_slice slice;
diff --git a/src/cpp/proto/proto_utils.h b/src/cpp/proto/proto_utils.h
index 11471f1acb..ea472f9c51 100644
--- a/src/cpp/proto/proto_utils.h
+++ b/src/cpp/proto/proto_utils.h
@@ -46,7 +46,8 @@ namespace grpc {
// Serialize the msg into a buffer created inside the function. The caller
// should destroy the returned buffer when done with it. If serialization fails,
// false is returned and buffer is left unchanged.
-bool SerializeProto(const google::protobuf::Message& msg, grpc_byte_buffer** buffer);
+bool SerializeProto(const google::protobuf::Message& msg,
+ grpc_byte_buffer** buffer);
// The caller keeps ownership of buffer and msg.
bool DeserializeProto(grpc_byte_buffer* buffer, google::protobuf::Message* msg);
diff --git a/src/cpp/server/async_server_context.cc b/src/cpp/server/async_server_context.cc
index f44678b569..298936dec9 100644
--- a/src/cpp/server/async_server_context.cc
+++ b/src/cpp/server/async_server_context.cc
@@ -48,8 +48,7 @@ AsyncServerContext::AsyncServerContext(
host_(host),
absolute_deadline_(absolute_deadline),
request_(nullptr),
- call_(call) {
-}
+ call_(call) {}
AsyncServerContext::~AsyncServerContext() { grpc_call_destroy(call_); }
diff --git a/src/cpp/server/rpc_service_method.h b/src/cpp/server/rpc_service_method.h
deleted file mode 100644
index f4fe01c06b..0000000000
--- a/src/cpp/server/rpc_service_method.h
+++ /dev/null
@@ -1,214 +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_RPC_SERVICE_METHOD_H__
-#define __GRPCPP_INTERNAL_SERVER_RPC_SERVICE_METHOD_H__
-
-#include <functional>
-#include <map>
-#include <memory>
-#include <vector>
-
-#include "src/cpp/rpc_method.h"
-#include <google/protobuf/message.h>
-#include <grpc++/status.h>
-#include <grpc++/stream.h>
-
-namespace grpc {
-class ServerContext;
-class StreamContextInterface;
-
-// TODO(rocking): we might need to split this file into multiple ones.
-
-// Base class for running an RPC handler.
-class MethodHandler {
- public:
- virtual ~MethodHandler() {}
- struct HandlerParameter {
- HandlerParameter(ServerContext* context, const google::protobuf::Message* req,
- google::protobuf::Message* resp)
- : server_context(context),
- request(req),
- response(resp),
- stream_context(nullptr) {}
- HandlerParameter(ServerContext* context, const google::protobuf::Message* req,
- google::protobuf::Message* resp, StreamContextInterface* stream)
- : server_context(context),
- request(req),
- response(resp),
- stream_context(stream) {}
- ServerContext* server_context;
- const google::protobuf::Message* request;
- google::protobuf::Message* response;
- StreamContextInterface* stream_context;
- };
- virtual Status RunHandler(const HandlerParameter& param) = 0;
-};
-
-// A wrapper class of an application provided rpc method handler.
-template <class ServiceType, class RequestType, class ResponseType>
-class RpcMethodHandler : public MethodHandler {
- public:
- RpcMethodHandler(
- std::function<Status(ServiceType*, ServerContext*, const RequestType*,
- ResponseType*)> func,
- ServiceType* service)
- : func_(func), service_(service) {}
-
- Status RunHandler(const HandlerParameter& param) final {
- // Invoke application function, cast proto messages to their actual types.
- return func_(service_, param.server_context,
- dynamic_cast<const RequestType*>(param.request),
- dynamic_cast<ResponseType*>(param.response));
- }
-
- private:
- // Application provided rpc handler function.
- std::function<Status(ServiceType*, ServerContext*, const RequestType*,
- ResponseType*)> func_;
- // The class the above handler function lives in.
- ServiceType* service_;
-};
-
-// A wrapper class of an application provided client streaming handler.
-template <class ServiceType, class RequestType, class ResponseType>
-class ClientStreamingHandler : public MethodHandler {
- public:
- ClientStreamingHandler(
- std::function<Status(ServiceType*, ServerContext*,
- ServerReader<RequestType>*, ResponseType*)> func,
- ServiceType* service)
- : func_(func), service_(service) {}
-
- Status RunHandler(const HandlerParameter& param) final {
- ServerReader<RequestType> reader(param.stream_context);
- return func_(service_, param.server_context, &reader,
- dynamic_cast<ResponseType*>(param.response));
- }
-
- private:
- std::function<Status(ServiceType*, ServerContext*, ServerReader<RequestType>*,
- ResponseType*)> func_;
- ServiceType* service_;
-};
-
-// A wrapper class of an application provided server streaming handler.
-template <class ServiceType, class RequestType, class ResponseType>
-class ServerStreamingHandler : public MethodHandler {
- public:
- ServerStreamingHandler(
- std::function<Status(ServiceType*, ServerContext*, const RequestType*,
- ServerWriter<ResponseType>*)> func,
- ServiceType* service)
- : func_(func), service_(service) {}
-
- Status RunHandler(const HandlerParameter& param) final {
- ServerWriter<ResponseType> writer(param.stream_context);
- return func_(service_, param.server_context,
- dynamic_cast<const RequestType*>(param.request), &writer);
- }
-
- private:
- std::function<Status(ServiceType*, ServerContext*, const RequestType*,
- ServerWriter<ResponseType>*)> func_;
- ServiceType* service_;
-};
-
-// A wrapper class of an application provided bidi-streaming handler.
-template <class ServiceType, class RequestType, class ResponseType>
-class BidiStreamingHandler : public MethodHandler {
- public:
- BidiStreamingHandler(
- std::function<Status(ServiceType*, ServerContext*,
- ServerReaderWriter<ResponseType, RequestType>*)>
- func,
- ServiceType* service)
- : func_(func), service_(service) {}
-
- Status RunHandler(const HandlerParameter& param) final {
- ServerReaderWriter<ResponseType, RequestType> stream(param.stream_context);
- return func_(service_, param.server_context, &stream);
- }
-
- private:
- std::function<Status(ServiceType*, ServerContext*,
- ServerReaderWriter<ResponseType, RequestType>*)> func_;
- ServiceType* service_;
-};
-
-// Server side rpc method class
-class RpcServiceMethod : public RpcMethod {
- public:
- // Takes ownership of the handler and two prototype objects.
- RpcServiceMethod(const char* name, RpcMethod::RpcType type,
- MethodHandler* handler, google::protobuf::Message* request_prototype,
- google::protobuf::Message* response_prototype)
- : RpcMethod(name, type),
- handler_(handler),
- request_prototype_(request_prototype),
- response_prototype_(response_prototype) {}
-
- MethodHandler* handler() { return handler_.get(); }
-
- google::protobuf::Message* AllocateRequestProto() { return request_prototype_->New(); }
- google::protobuf::Message* AllocateResponseProto() {
- return response_prototype_->New();
- }
-
- private:
- std::unique_ptr<MethodHandler> handler_;
- std::unique_ptr<google::protobuf::Message> request_prototype_;
- std::unique_ptr<google::protobuf::Message> response_prototype_;
-};
-
-// This class contains all the method information for an rpc service. It is
-// used for registering a service on a grpc server.
-class RpcService {
- public:
- // Takes ownership.
- void AddMethod(RpcServiceMethod* method) {
- methods_.push_back(std::unique_ptr<RpcServiceMethod>(method));
- }
-
- RpcServiceMethod* GetMethod(int i) {
- return methods_[i].get();
- }
- int GetMethodCount() const { return methods_.size(); }
-
- private:
- std::vector<std::unique_ptr<RpcServiceMethod>> methods_;
-};
-
-} // namespace grpc
-
-#endif // __GRPCPP_INTERNAL_SERVER_RPC_SERVICE_METHOD_H__
diff --git a/src/cpp/server/server.cc b/src/cpp/server/server.cc
index 2130befa7d..d85748eea4 100644
--- a/src/cpp/server/server.cc
+++ b/src/cpp/server/server.cc
@@ -37,11 +37,11 @@
#include <grpc/grpc.h>
#include <grpc/grpc_security.h>
#include <grpc/support/log.h>
-#include "src/cpp/server/rpc_service_method.h"
#include "src/cpp/server/server_rpc_handler.h"
#include "src/cpp/server/thread_pool.h"
#include <grpc++/async_server_context.h>
#include <grpc++/completion_queue.h>
+#include <grpc++/impl/rpc_service_method.h>
#include <grpc++/server_credentials.h>
namespace grpc {
diff --git a/src/cpp/server/server_context_impl.cc b/src/cpp/server/server_context_impl.cc
index 13f2a3ae1a..467cc80e05 100644
--- a/src/cpp/server/server_context_impl.cc
+++ b/src/cpp/server/server_context_impl.cc
@@ -33,6 +33,4 @@
#include "src/cpp/server/server_context_impl.h"
-namespace grpc {
-
-} // namespace grpc
+namespace grpc {} // namespace grpc
diff --git a/src/cpp/server/server_credentials.cc b/src/cpp/server/server_credentials.cc
index f9ca1622ba..5d899b1cd9 100644
--- a/src/cpp/server/server_credentials.cc
+++ b/src/cpp/server/server_credentials.cc
@@ -31,7 +31,6 @@
*
*/
-
#include <grpc/grpc_security.h>
#include <grpc++/server_credentials.h>
diff --git a/src/cpp/server/server_rpc_handler.cc b/src/cpp/server/server_rpc_handler.cc
index 3954f04f97..42f8b755b6 100644
--- a/src/cpp/server/server_rpc_handler.cc
+++ b/src/cpp/server/server_rpc_handler.cc
@@ -34,10 +34,10 @@
#include "src/cpp/server/server_rpc_handler.h"
#include <grpc/support/log.h>
-#include "src/cpp/server/rpc_service_method.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 {
@@ -60,8 +60,10 @@ void ServerRpcHandler::StartRpc() {
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());
+ 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());
@@ -86,8 +88,10 @@ void ServerRpcHandler::StartRpc() {
} 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());
+ 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());
diff --git a/src/cpp/stream/stream_context.cc b/src/cpp/stream/stream_context.cc
index 22b7e7d494..7936a30dfd 100644
--- a/src/cpp/stream/stream_context.cc
+++ b/src/cpp/stream/stream_context.cc
@@ -34,11 +34,11 @@
#include "src/cpp/stream/stream_context.h"
#include <grpc/support/log.h>
-#include "src/cpp/rpc_method.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 {
@@ -61,7 +61,8 @@ StreamContext::StreamContext(const RpcMethod& method, ClientContext* context,
// Server only ctor
StreamContext::StreamContext(const RpcMethod& method, grpc_call* call,
grpc_completion_queue* cq,
- google::protobuf::Message* request, google::protobuf::Message* result)
+ google::protobuf::Message* request,
+ google::protobuf::Message* result)
: is_client_(false),
method_(&method),
call_(call),
@@ -85,6 +86,10 @@ void StreamContext::Start(bool buffered) {
GPR_ASSERT(GRPC_CALL_OK == error);
grpc_event* invoke_ev =
grpc_completion_queue_pluck(cq(), invoke_tag(), gpr_inf_future);
+ if (invoke_ev->data.invoke_accepted != GRPC_OP_OK) {
+ peer_halfclosed_ = true;
+ self_halfclosed_ = true;
+ }
grpc_event_finish(invoke_ev);
} else {
// TODO(yangg) metadata needs to be added before accept
diff --git a/src/cpp/stream/stream_context.h b/src/cpp/stream/stream_context.h
index 6c31095042..f70fe6daa3 100644
--- a/src/cpp/stream/stream_context.h
+++ b/src/cpp/stream/stream_context.h
@@ -51,7 +51,8 @@ class RpcMethod;
class StreamContext : public StreamContextInterface {
public:
StreamContext(const RpcMethod& method, ClientContext* context,
- const google::protobuf::Message* request, google::protobuf::Message* result);
+ 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);
@@ -81,11 +82,11 @@ class StreamContext : public StreamContextInterface {
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
+ 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_;
diff --git a/src/cpp/util/status.cc b/src/cpp/util/status.cc
index 66be26da07..e7ca41b752 100644
--- a/src/cpp/util/status.cc
+++ b/src/cpp/util/status.cc
@@ -31,7 +31,6 @@
*
*/
-
#include <grpc++/status.h>
namespace grpc {
diff --git a/src/node/README.md b/src/node/README.md
new file mode 100644
index 0000000000..55329d8cb2
--- /dev/null
+++ b/src/node/README.md
@@ -0,0 +1,12 @@
+# Node.js GRPC extension
+
+The package is built with
+
+ node-gyp configure
+ node-gyp build
+
+or, for brevity
+
+ node-gyp configure build
+
+The tests can be run with `npm test` on a dev install. \ No newline at end of file
diff --git a/src/node/binding.gyp b/src/node/binding.gyp
new file mode 100644
index 0000000000..4a1fd7aaf0
--- /dev/null
+++ b/src/node/binding.gyp
@@ -0,0 +1,46 @@
+{
+ "targets" : [
+ {
+ 'include_dirs': [
+ "<!(node -e \"require('nan')\")"
+ ],
+ 'cxxflags': [
+ '-Wall',
+ '-pthread',
+ '-pedantic',
+ '-g',
+ '-zdefs'
+ '-Werror',
+ ],
+ 'ldflags': [
+ '-g',
+ '-L/usr/local/google/home/mlumish/grpc_dev/lib'
+ ],
+ 'link_settings': {
+ 'libraries': [
+ '-lgrpc',
+ '-levent',
+ '-levent_pthreads',
+ '-levent_core',
+ '-lrt',
+ '-lgpr',
+ '-lpthread'
+ ],
+ },
+ "target_name": "grpc",
+ "sources": [
+ "byte_buffer.cc",
+ "call.cc",
+ "channel.cc",
+ "completion_queue_async_worker.cc",
+ "credentials.cc",
+ "event.cc",
+ "node_grpc.cc",
+ "server.cc",
+ "server_credentials.cc",
+ "tag.cc",
+ "timeval.cc"
+ ]
+ }
+ ]
+}
diff --git a/src/node/byte_buffer.cc b/src/node/byte_buffer.cc
new file mode 100644
index 0000000000..142951475a
--- /dev/null
+++ b/src/node/byte_buffer.cc
@@ -0,0 +1,79 @@
+/*
+ *
+ * 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 <string.h>
+#include <malloc.h>
+
+#include <node.h>
+#include <nan.h>
+#include "grpc/grpc.h"
+#include "grpc/support/slice.h"
+
+namespace grpc {
+namespace node {
+
+#include "byte_buffer.h"
+
+using ::node::Buffer;
+using v8::Handle;
+using v8::Value;
+
+grpc_byte_buffer *BufferToByteBuffer(Handle<Value> buffer) {
+ NanScope();
+ int length = Buffer::Length(buffer);
+ char *data = Buffer::Data(buffer);
+ gpr_slice slice = gpr_slice_malloc(length);
+ memcpy(GPR_SLICE_START_PTR(slice), data, length);
+ grpc_byte_buffer *byte_buffer(grpc_byte_buffer_create(&slice, 1));
+ gpr_slice_unref(slice);
+ return byte_buffer;
+}
+
+Handle<Value> ByteBufferToBuffer(grpc_byte_buffer *buffer) {
+ NanEscapableScope();
+ if (buffer == NULL) {
+ NanReturnNull();
+ }
+ size_t length = grpc_byte_buffer_length(buffer);
+ char *result = reinterpret_cast<char *>(calloc(length, sizeof(char)));
+ size_t offset = 0;
+ grpc_byte_buffer_reader *reader = grpc_byte_buffer_reader_create(buffer);
+ gpr_slice next;
+ while (grpc_byte_buffer_reader_next(reader, &next) != 0) {
+ memcpy(result + offset, GPR_SLICE_START_PTR(next), GPR_SLICE_LENGTH(next));
+ offset += GPR_SLICE_LENGTH(next);
+ }
+ return NanEscapeScope(NanNewBufferHandle(result, length));
+}
+} // namespace node
+} // namespace grpc
diff --git a/src/node/byte_buffer.h b/src/node/byte_buffer.h
new file mode 100644
index 0000000000..ee2b4c0d15
--- /dev/null
+++ b/src/node/byte_buffer.h
@@ -0,0 +1,56 @@
+/*
+ *
+ * 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 NET_GRPC_NODE_BYTE_BUFFER_H_
+#define NET_GRPC_NODE_BYTE_BUFFER_H_
+
+#include <string.h>
+
+#include <node.h>
+#include <nan.h>
+#include "grpc/grpc.h"
+
+namespace grpc {
+namespace node {
+
+/* Convert a Node.js Buffer to grpc_byte_buffer. Requires that
+ ::node::Buffer::HasInstance(buffer) */
+grpc_byte_buffer *BufferToByteBuffer(v8::Handle<v8::Value> buffer);
+
+/* Convert a grpc_byte_buffer to a Node.js Buffer */
+v8::Handle<v8::Value> ByteBufferToBuffer(grpc_byte_buffer *buffer);
+
+} // namespace node
+} // namespace grpc
+
+#endif // NET_GRPC_NODE_BYTE_BUFFER_H_
diff --git a/src/node/call.cc b/src/node/call.cc
new file mode 100644
index 0000000000..b8ee1786a6
--- /dev/null
+++ b/src/node/call.cc
@@ -0,0 +1,392 @@
+/*
+ *
+ * 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 <node.h>
+
+#include "grpc/grpc.h"
+#include "grpc/support/time.h"
+#include "byte_buffer.h"
+#include "call.h"
+#include "channel.h"
+#include "completion_queue_async_worker.h"
+#include "timeval.h"
+#include "tag.h"
+
+namespace grpc {
+namespace node {
+
+using ::node::Buffer;
+using v8::Arguments;
+using v8::Array;
+using v8::Exception;
+using v8::External;
+using v8::Function;
+using v8::FunctionTemplate;
+using v8::Handle;
+using v8::HandleScope;
+using v8::Integer;
+using v8::Local;
+using v8::Number;
+using v8::Object;
+using v8::ObjectTemplate;
+using v8::Persistent;
+using v8::Uint32;
+using v8::String;
+using v8::Value;
+
+Persistent<Function> Call::constructor;
+Persistent<FunctionTemplate> Call::fun_tpl;
+
+Call::Call(grpc_call *call) : wrapped_call(call) {}
+
+Call::~Call() { grpc_call_destroy(wrapped_call); }
+
+void Call::Init(Handle<Object> exports) {
+ NanScope();
+ Local<FunctionTemplate> tpl = FunctionTemplate::New(New);
+ tpl->SetClassName(NanNew("Call"));
+ tpl->InstanceTemplate()->SetInternalFieldCount(1);
+ NanSetPrototypeTemplate(tpl, "addMetadata",
+ FunctionTemplate::New(AddMetadata)->GetFunction());
+ NanSetPrototypeTemplate(tpl, "startInvoke",
+ FunctionTemplate::New(StartInvoke)->GetFunction());
+ NanSetPrototypeTemplate(tpl, "serverAccept",
+ FunctionTemplate::New(ServerAccept)->GetFunction());
+ NanSetPrototypeTemplate(
+ tpl, "serverEndInitialMetadata",
+ FunctionTemplate::New(ServerEndInitialMetadata)->GetFunction());
+ NanSetPrototypeTemplate(tpl, "cancel",
+ FunctionTemplate::New(Cancel)->GetFunction());
+ NanSetPrototypeTemplate(tpl, "startWrite",
+ FunctionTemplate::New(StartWrite)->GetFunction());
+ NanSetPrototypeTemplate(
+ tpl, "startWriteStatus",
+ FunctionTemplate::New(StartWriteStatus)->GetFunction());
+ NanSetPrototypeTemplate(tpl, "writesDone",
+ FunctionTemplate::New(WritesDone)->GetFunction());
+ NanSetPrototypeTemplate(tpl, "startReadMetadata",
+ FunctionTemplate::New(WritesDone)->GetFunction());
+ NanSetPrototypeTemplate(tpl, "startRead",
+ FunctionTemplate::New(StartRead)->GetFunction());
+ NanAssignPersistent(fun_tpl, tpl);
+ NanAssignPersistent(constructor, tpl->GetFunction());
+ constructor->Set(NanNew("WRITE_BUFFER_HINT"),
+ NanNew<Uint32, uint32_t>(GRPC_WRITE_BUFFER_HINT));
+ constructor->Set(NanNew("WRITE_NO_COMPRESS"),
+ NanNew<Uint32, uint32_t>(GRPC_WRITE_NO_COMPRESS));
+ exports->Set(String::NewSymbol("Call"), constructor);
+}
+
+bool Call::HasInstance(Handle<Value> val) {
+ NanScope();
+ return NanHasInstance(fun_tpl, val);
+}
+
+Handle<Value> Call::WrapStruct(grpc_call *call) {
+ NanEscapableScope();
+ if (call == NULL) {
+ return NanEscapeScope(NanNull());
+ }
+ const int argc = 1;
+ Handle<Value> argv[argc] = {External::New(reinterpret_cast<void *>(call))};
+ return NanEscapeScope(constructor->NewInstance(argc, argv));
+}
+
+NAN_METHOD(Call::New) {
+ NanScope();
+
+ if (args.IsConstructCall()) {
+ Call *call;
+ if (args[0]->IsExternal()) {
+ // This option is used for wrapping an existing call
+ grpc_call *call_value =
+ reinterpret_cast<grpc_call *>(External::Unwrap(args[0]));
+ call = new Call(call_value);
+ } else {
+ if (!Channel::HasInstance(args[0])) {
+ return NanThrowTypeError("Call's first argument must be a Channel");
+ }
+ if (!args[1]->IsString()) {
+ return NanThrowTypeError("Call's second argument must be a string");
+ }
+ if (!(args[2]->IsNumber() || args[2]->IsDate())) {
+ return NanThrowTypeError(
+ "Call's third argument must be a date or a number");
+ }
+ Handle<Object> channel_object = args[0]->ToObject();
+ Channel *channel = ObjectWrap::Unwrap<Channel>(channel_object);
+ if (channel->GetWrappedChannel() == NULL) {
+ return NanThrowError("Call cannot be created from a closed channel");
+ }
+ NanUtf8String method(args[1]);
+ double deadline = args[2]->NumberValue();
+ grpc_channel *wrapped_channel = channel->GetWrappedChannel();
+ grpc_call *wrapped_call =
+ grpc_channel_create_call(wrapped_channel, *method, channel->GetHost(),
+ MillisecondsToTimespec(deadline));
+ call = new Call(wrapped_call);
+ args.This()->SetHiddenValue(String::NewSymbol("channel_"),
+ channel_object);
+ }
+ call->Wrap(args.This());
+ NanReturnValue(args.This());
+ } else {
+ const int argc = 4;
+ Local<Value> argv[argc] = {args[0], args[1], args[2], args[3]};
+ NanReturnValue(constructor->NewInstance(argc, argv));
+ }
+}
+
+NAN_METHOD(Call::AddMetadata) {
+ NanScope();
+ if (!HasInstance(args.This())) {
+ return NanThrowTypeError("addMetadata can only be called on Call objects");
+ }
+ Call *call = ObjectWrap::Unwrap<Call>(args.This());
+ for (int i = 0; !args[i]->IsUndefined(); i++) {
+ if (!args[i]->IsObject()) {
+ return NanThrowTypeError(
+ "addMetadata arguments must be objects with key and value");
+ }
+ Handle<Object> item = args[i]->ToObject();
+ Handle<Value> key = item->Get(NanNew("key"));
+ if (!key->IsString()) {
+ return NanThrowTypeError(
+ "objects passed to addMetadata must have key->string");
+ }
+ Handle<Value> value = item->Get(NanNew("value"));
+ if (!Buffer::HasInstance(value)) {
+ return NanThrowTypeError(
+ "objects passed to addMetadata must have value->Buffer");
+ }
+ grpc_metadata metadata;
+ NanUtf8String utf8_key(key);
+ metadata.key = *utf8_key;
+ metadata.value = Buffer::Data(value);
+ metadata.value_length = Buffer::Length(value);
+ grpc_call_error error =
+ grpc_call_add_metadata(call->wrapped_call, &metadata, 0);
+ if (error != GRPC_CALL_OK) {
+ return NanThrowError("addMetadata failed", error);
+ }
+ }
+ NanReturnUndefined();
+}
+
+NAN_METHOD(Call::StartInvoke) {
+ NanScope();
+ if (!HasInstance(args.This())) {
+ return NanThrowTypeError("startInvoke can only be called on Call objects");
+ }
+ if (!args[0]->IsFunction()) {
+ return NanThrowTypeError("StartInvoke's first argument must be a function");
+ }
+ if (!args[1]->IsFunction()) {
+ return NanThrowTypeError(
+ "StartInvoke's second argument must be a function");
+ }
+ if (!args[2]->IsFunction()) {
+ return NanThrowTypeError("StartInvoke's third argument must be a function");
+ }
+ if (!args[3]->IsUint32()) {
+ return NanThrowTypeError(
+ "StartInvoke's fourth argument must be integer flags");
+ }
+ Call *call = ObjectWrap::Unwrap<Call>(args.This());
+ unsigned int flags = args[3]->Uint32Value();
+ grpc_call_error error = grpc_call_start_invoke(
+ call->wrapped_call, CompletionQueueAsyncWorker::GetQueue(),
+ CreateTag(args[0], args.This()), CreateTag(args[1], args.This()),
+ CreateTag(args[2], args.This()), flags);
+ if (error == GRPC_CALL_OK) {
+ CompletionQueueAsyncWorker::Next();
+ CompletionQueueAsyncWorker::Next();
+ CompletionQueueAsyncWorker::Next();
+ } else {
+ return NanThrowError("startInvoke failed", error);
+ }
+ NanReturnUndefined();
+}
+
+NAN_METHOD(Call::ServerAccept) {
+ NanScope();
+ if (!HasInstance(args.This())) {
+ return NanThrowTypeError("accept can only be called on Call objects");
+ }
+ if (!args[0]->IsFunction()) {
+ return NanThrowTypeError("accept's first argument must be a function");
+ }
+ Call *call = ObjectWrap::Unwrap<Call>(args.This());
+ grpc_call_error error = grpc_call_server_accept(
+ call->wrapped_call, CompletionQueueAsyncWorker::GetQueue(),
+ CreateTag(args[0], args.This()));
+ if (error == GRPC_CALL_OK) {
+ CompletionQueueAsyncWorker::Next();
+ } else {
+ return NanThrowError("serverAccept failed", error);
+ }
+ NanReturnUndefined();
+}
+
+NAN_METHOD(Call::ServerEndInitialMetadata) {
+ NanScope();
+ if (!HasInstance(args.This())) {
+ return NanThrowTypeError(
+ "serverEndInitialMetadata can only be called on Call objects");
+ }
+ if (!args[0]->IsUint32()) {
+ return NanThrowTypeError(
+ "serverEndInitialMetadata's second argument must be integer flags");
+ }
+ Call *call = ObjectWrap::Unwrap<Call>(args.This());
+ unsigned int flags = args[1]->Uint32Value();
+ grpc_call_error error =
+ grpc_call_server_end_initial_metadata(call->wrapped_call, flags);
+ if (error != GRPC_CALL_OK) {
+ return NanThrowError("serverEndInitialMetadata failed", error);
+ }
+ NanReturnUndefined();
+}
+
+NAN_METHOD(Call::Cancel) {
+ NanScope();
+ if (!HasInstance(args.This())) {
+ return NanThrowTypeError("startInvoke can only be called on Call objects");
+ }
+ Call *call = ObjectWrap::Unwrap<Call>(args.This());
+ grpc_call_error error = grpc_call_cancel(call->wrapped_call);
+ if (error != GRPC_CALL_OK) {
+ return NanThrowError("cancel failed", error);
+ }
+ NanReturnUndefined();
+}
+
+NAN_METHOD(Call::StartWrite) {
+ NanScope();
+ if (!HasInstance(args.This())) {
+ return NanThrowTypeError("startWrite can only be called on Call objects");
+ }
+ if (!Buffer::HasInstance(args[0])) {
+ return NanThrowTypeError("startWrite's first argument must be a Buffer");
+ }
+ if (!args[1]->IsFunction()) {
+ return NanThrowTypeError("startWrite's second argument must be a function");
+ }
+ if (!args[2]->IsUint32()) {
+ return NanThrowTypeError(
+ "startWrite's third argument must be integer flags");
+ }
+ Call *call = ObjectWrap::Unwrap<Call>(args.This());
+ grpc_byte_buffer *buffer = BufferToByteBuffer(args[0]);
+ unsigned int flags = args[2]->Uint32Value();
+ grpc_call_error error = grpc_call_start_write(
+ call->wrapped_call, buffer, CreateTag(args[1], args.This()), flags);
+ if (error == GRPC_CALL_OK) {
+ CompletionQueueAsyncWorker::Next();
+ } else {
+ return NanThrowError("startWrite failed", error);
+ }
+ NanReturnUndefined();
+}
+
+NAN_METHOD(Call::StartWriteStatus) {
+ NanScope();
+ if (!HasInstance(args.This())) {
+ return NanThrowTypeError(
+ "startWriteStatus can only be called on Call objects");
+ }
+ if (!args[0]->IsUint32()) {
+ return NanThrowTypeError(
+ "startWriteStatus's first argument must be a status code");
+ }
+ if (!args[1]->IsString()) {
+ return NanThrowTypeError(
+ "startWriteStatus's second argument must be a string");
+ }
+ if (!args[2]->IsFunction()) {
+ return NanThrowTypeError(
+ "startWriteStatus's third argument must be a function");
+ }
+ Call *call = ObjectWrap::Unwrap<Call>(args.This());
+ NanUtf8String details(args[1]);
+ grpc_call_error error = grpc_call_start_write_status(
+ call->wrapped_call, (grpc_status_code)args[0]->Uint32Value(), *details,
+ CreateTag(args[2], args.This()));
+ if (error == GRPC_CALL_OK) {
+ CompletionQueueAsyncWorker::Next();
+ } else {
+ return NanThrowError("startWriteStatus failed", error);
+ }
+ NanReturnUndefined();
+}
+
+NAN_METHOD(Call::WritesDone) {
+ NanScope();
+ if (!HasInstance(args.This())) {
+ return NanThrowTypeError("writesDone can only be called on Call objects");
+ }
+ if (!args[0]->IsFunction()) {
+ return NanThrowTypeError("writesDone's first argument must be a function");
+ }
+ Call *call = ObjectWrap::Unwrap<Call>(args.This());
+ grpc_call_error error = grpc_call_writes_done(
+ call->wrapped_call, CreateTag(args[0], args.This()));
+ if (error == GRPC_CALL_OK) {
+ CompletionQueueAsyncWorker::Next();
+ } else {
+ return NanThrowError("writesDone failed", error);
+ }
+ NanReturnUndefined();
+}
+
+NAN_METHOD(Call::StartRead) {
+ NanScope();
+ if (!HasInstance(args.This())) {
+ return NanThrowTypeError("startRead can only be called on Call objects");
+ }
+ if (!args[0]->IsFunction()) {
+ return NanThrowTypeError("startRead's first argument must be a function");
+ }
+ Call *call = ObjectWrap::Unwrap<Call>(args.This());
+ grpc_call_error error =
+ grpc_call_start_read(call->wrapped_call, CreateTag(args[0], args.This()));
+ if (error == GRPC_CALL_OK) {
+ CompletionQueueAsyncWorker::Next();
+ } else {
+ return NanThrowError("startRead failed", error);
+ }
+ NanReturnUndefined();
+}
+
+} // namespace node
+} // namespace grpc
diff --git a/src/node/call.h b/src/node/call.h
new file mode 100644
index 0000000000..55a6fc65b8
--- /dev/null
+++ b/src/node/call.h
@@ -0,0 +1,82 @@
+/*
+ *
+ * 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 NET_GRPC_NODE_CALL_H_
+#define NET_GRPC_NODE_CALL_H_
+
+#include <node.h>
+#include <nan.h>
+#include "grpc/grpc.h"
+
+#include "channel.h"
+
+namespace grpc {
+namespace node {
+
+/* Wrapper class for grpc_call structs. */
+class Call : public ::node::ObjectWrap {
+ public:
+ static void Init(v8::Handle<v8::Object> exports);
+ static bool HasInstance(v8::Handle<v8::Value> val);
+ /* Wrap a grpc_call struct in a javascript object */
+ static v8::Handle<v8::Value> WrapStruct(grpc_call *call);
+
+ private:
+ explicit Call(grpc_call *call);
+ ~Call();
+
+ // Prevent copying
+ Call(const Call &);
+ Call &operator=(const Call &);
+
+ static NAN_METHOD(New);
+ static NAN_METHOD(AddMetadata);
+ static NAN_METHOD(StartInvoke);
+ static NAN_METHOD(ServerAccept);
+ static NAN_METHOD(ServerEndInitialMetadata);
+ static NAN_METHOD(Cancel);
+ static NAN_METHOD(StartWrite);
+ static NAN_METHOD(StartWriteStatus);
+ static NAN_METHOD(WritesDone);
+ static NAN_METHOD(StartRead);
+ static v8::Persistent<v8::Function> constructor;
+ // Used for typechecking instances of this javascript class
+ static v8::Persistent<v8::FunctionTemplate> fun_tpl;
+
+ grpc_call *wrapped_call;
+};
+
+} // namespace node
+} // namespace grpc
+
+#endif // NET_GRPC_NODE_CALL_H_
diff --git a/src/node/channel.cc b/src/node/channel.cc
new file mode 100644
index 0000000000..9087d6f919
--- /dev/null
+++ b/src/node/channel.cc
@@ -0,0 +1,182 @@
+/*
+ *
+ * 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 <malloc.h>
+
+#include <vector>
+
+#include <node.h>
+#include <nan.h>
+#include "grpc/grpc.h"
+#include "grpc/grpc_security.h"
+#include "channel.h"
+#include "credentials.h"
+
+namespace grpc {
+namespace node {
+
+using v8::Arguments;
+using v8::Array;
+using v8::Exception;
+using v8::Function;
+using v8::FunctionTemplate;
+using v8::Handle;
+using v8::HandleScope;
+using v8::Integer;
+using v8::Local;
+using v8::Object;
+using v8::Persistent;
+using v8::String;
+using v8::Value;
+
+Persistent<Function> Channel::constructor;
+Persistent<FunctionTemplate> Channel::fun_tpl;
+
+Channel::Channel(grpc_channel *channel, NanUtf8String *host)
+ : wrapped_channel(channel), host(host) {}
+
+Channel::~Channel() {
+ if (wrapped_channel != NULL) {
+ grpc_channel_destroy(wrapped_channel);
+ }
+ delete host;
+}
+
+void Channel::Init(Handle<Object> exports) {
+ NanScope();
+ Local<FunctionTemplate> tpl = FunctionTemplate::New(New);
+ tpl->SetClassName(NanNew("Channel"));
+ tpl->InstanceTemplate()->SetInternalFieldCount(1);
+ NanSetPrototypeTemplate(tpl, "close",
+ FunctionTemplate::New(Close)->GetFunction());
+ NanAssignPersistent(fun_tpl, tpl);
+ NanAssignPersistent(constructor, tpl->GetFunction());
+ exports->Set(NanNew("Channel"), constructor);
+}
+
+bool Channel::HasInstance(Handle<Value> val) {
+ NanScope();
+ return NanHasInstance(fun_tpl, val);
+}
+
+grpc_channel *Channel::GetWrappedChannel() { return this->wrapped_channel; }
+
+char *Channel::GetHost() { return **this->host; }
+
+NAN_METHOD(Channel::New) {
+ NanScope();
+
+ if (args.IsConstructCall()) {
+ if (!args[0]->IsString()) {
+ return NanThrowTypeError("Channel expects a string and an object");
+ }
+ grpc_channel *wrapped_channel;
+ // Owned by the Channel object
+ NanUtf8String *host = new NanUtf8String(args[0]);
+ if (args[1]->IsUndefined()) {
+ wrapped_channel = grpc_channel_create(**host, NULL);
+ } else if (args[1]->IsObject()) {
+ grpc_credentials *creds = NULL;
+ Handle<Object> args_hash(args[1]->ToObject()->Clone());
+ if (args_hash->HasOwnProperty(NanNew("credentials"))) {
+ Handle<Value> creds_value = args_hash->Get(NanNew("credentials"));
+ if (!Credentials::HasInstance(creds_value)) {
+ return NanThrowTypeError(
+ "credentials arg must be a Credentials object");
+ }
+ Credentials *creds_object =
+ ObjectWrap::Unwrap<Credentials>(creds_value->ToObject());
+ creds = creds_object->GetWrappedCredentials();
+ args_hash->Delete(NanNew("credentials"));
+ }
+ Handle<Array> keys(args_hash->GetOwnPropertyNames());
+ grpc_channel_args channel_args;
+ channel_args.num_args = keys->Length();
+ channel_args.args = reinterpret_cast<grpc_arg *>(
+ calloc(channel_args.num_args, sizeof(grpc_arg)));
+ /* These are used to keep all strings until then end of the block, then
+ destroy them */
+ std::vector<NanUtf8String *> key_strings(keys->Length());
+ std::vector<NanUtf8String *> value_strings(keys->Length());
+ for (unsigned int i = 0; i < channel_args.num_args; i++) {
+ Handle<String> current_key(keys->Get(i)->ToString());
+ Handle<Value> current_value(args_hash->Get(current_key));
+ key_strings[i] = new NanUtf8String(current_key);
+ channel_args.args[i].key = **key_strings[i];
+ if (current_value->IsInt32()) {
+ channel_args.args[i].type = GRPC_ARG_INTEGER;
+ channel_args.args[i].value.integer = current_value->Int32Value();
+ } else if (current_value->IsString()) {
+ channel_args.args[i].type = GRPC_ARG_STRING;
+ value_strings[i] = new NanUtf8String(current_value);
+ channel_args.args[i].value.string = **value_strings[i];
+ } else {
+ free(channel_args.args);
+ return NanThrowTypeError("Arg values must be strings");
+ }
+ }
+ if (creds == NULL) {
+ wrapped_channel = grpc_channel_create(**host, &channel_args);
+ } else {
+ wrapped_channel =
+ grpc_secure_channel_create(creds, **host, &channel_args);
+ }
+ free(channel_args.args);
+ } else {
+ return NanThrowTypeError("Channel expects a string and an object");
+ }
+ Channel *channel = new Channel(wrapped_channel, host);
+ channel->Wrap(args.This());
+ NanReturnValue(args.This());
+ } else {
+ const int argc = 2;
+ Local<Value> argv[argc] = {args[0], args[1]};
+ NanReturnValue(constructor->NewInstance(argc, argv));
+ }
+}
+
+NAN_METHOD(Channel::Close) {
+ NanScope();
+ if (!HasInstance(args.This())) {
+ return NanThrowTypeError("close can only be called on Channel objects");
+ }
+ Channel *channel = ObjectWrap::Unwrap<Channel>(args.This());
+ if (channel->wrapped_channel != NULL) {
+ grpc_channel_destroy(channel->wrapped_channel);
+ channel->wrapped_channel = NULL;
+ }
+ NanReturnUndefined();
+}
+
+} // namespace node
+} // namespace grpc
diff --git a/src/node/channel.h b/src/node/channel.h
new file mode 100644
index 0000000000..140cbf201a
--- /dev/null
+++ b/src/node/channel.h
@@ -0,0 +1,79 @@
+/*
+ *
+ * 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 NET_GRPC_NODE_CHANNEL_H_
+#define NET_GRPC_NODE_CHANNEL_H_
+
+#include <node.h>
+#include <nan.h>
+#include "grpc/grpc.h"
+
+namespace grpc {
+namespace node {
+
+/* Wrapper class for grpc_channel structs */
+class Channel : public ::node::ObjectWrap {
+ public:
+ static void Init(v8::Handle<v8::Object> exports);
+ static bool HasInstance(v8::Handle<v8::Value> val);
+ /* This is used to typecheck javascript objects before converting them to
+ this type */
+ static v8::Persistent<v8::Value> prototype;
+
+ /* Returns the grpc_channel struct that this object wraps */
+ grpc_channel *GetWrappedChannel();
+
+ /* Return the hostname that this channel connects to */
+ char *GetHost();
+
+ private:
+ explicit Channel(grpc_channel *channel, NanUtf8String *host);
+ ~Channel();
+
+ // Prevent copying
+ Channel(const Channel &);
+ Channel &operator=(const Channel &);
+
+ static NAN_METHOD(New);
+ static NAN_METHOD(Close);
+ static v8::Persistent<v8::Function> constructor;
+ static v8::Persistent<v8::FunctionTemplate> fun_tpl;
+
+ grpc_channel *wrapped_channel;
+ NanUtf8String *host;
+};
+
+} // namespace node
+} // namespace grpc
+
+#endif // NET_GRPC_NODE_CHANNEL_H_
diff --git a/src/node/client.js b/src/node/client.js
new file mode 100644
index 0000000000..edaa115d0f
--- /dev/null
+++ b/src/node/client.js
@@ -0,0 +1,209 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+var grpc = require('bindings')('grpc.node');
+
+var common = require('./common');
+
+var Duplex = require('stream').Duplex;
+var util = require('util');
+
+util.inherits(GrpcClientStream, Duplex);
+
+/**
+ * Class for representing a gRPC client side stream as a Node stream. Extends
+ * from stream.Duplex.
+ * @constructor
+ * @param {grpc.Call} call Call object to proxy
+ * @param {object} options Stream options
+ */
+function GrpcClientStream(call, options) {
+ Duplex.call(this, options);
+ var self = this;
+ // Indicates that we can start reading and have not received a null read
+ var can_read = false;
+ // Indicates that a read is currently pending
+ var reading = false;
+ // Indicates that we can call startWrite
+ var can_write = false;
+ // Indicates that a write is currently pending
+ var writing = false;
+ this._call = call;
+ /**
+ * Callback to handle receiving a READ event. Pushes the data from that event
+ * onto the read queue and starts reading again if applicable.
+ * @param {grpc.Event} event The READ event object
+ */
+ function readCallback(event) {
+ var data = event.data;
+ if (self.push(data)) {
+ if (data == null) {
+ // Disable starting to read after null read was received
+ can_read = false;
+ reading = false;
+ } else {
+ call.startRead(readCallback);
+ }
+ } else {
+ // Indicate that reading can be resumed by calling startReading
+ reading = false;
+ }
+ };
+ /**
+ * Initiate a read, which continues until self.push returns false (indicating
+ * that reading should be paused) or data is null (indicating that there is no
+ * more data to read).
+ */
+ function startReading() {
+ call.startRead(readCallback);
+ }
+ // TODO(mlumish): possibly change queue implementation due to shift slowness
+ var write_queue = [];
+ /**
+ * Write the next chunk of data in the write queue if there is one. Otherwise
+ * indicate that there is no pending write. When the write succeeds, this
+ * function is called again.
+ */
+ function writeNext() {
+ if (write_queue.length > 0) {
+ writing = true;
+ var next = write_queue.shift();
+ var writeCallback = function(event) {
+ next.callback();
+ writeNext();
+ };
+ call.startWrite(next.chunk, writeCallback, 0);
+ } else {
+ writing = false;
+ }
+ }
+ call.startInvoke(function(event) {
+ can_read = true;
+ can_write = true;
+ startReading();
+ writeNext();
+ }, function(event) {
+ self.emit('metadata', event.data);
+ }, function(event) {
+ self.emit('status', event.data);
+ }, 0);
+ this.on('finish', function() {
+ call.writesDone(function() {});
+ });
+ /**
+ * Indicate that reads should start, and start them if the INVOKE_ACCEPTED
+ * event has been received.
+ */
+ this._enableRead = function() {
+ if (!reading) {
+ reading = true;
+ if (can_read) {
+ startReading();
+ }
+ }
+ };
+ /**
+ * Push the chunk onto the write queue, and write from the write queue if
+ * there is not a pending write
+ * @param {Buffer} chunk The chunk of data to write
+ * @param {function(Error=)} callback The callback to call when the write
+ * completes
+ */
+ this._tryWrite = function(chunk, callback) {
+ write_queue.push({chunk: chunk, callback: callback});
+ if (can_write && !writing) {
+ writeNext();
+ }
+ };
+}
+
+/**
+ * Start reading. This is an implementation of a method needed for implementing
+ * stream.Readable.
+ * @param {number} size Ignored
+ */
+GrpcClientStream.prototype._read = function(size) {
+ this._enableRead();
+};
+
+/**
+ * Attempt to write the given chunk. Calls the callback when done. This is an
+ * implementation of a method needed for implementing stream.Writable.
+ * @param {Buffer} chunk The chunk to write
+ * @param {string} encoding Ignored
+ * @param {function(Error=)} callback Ignored
+ */
+GrpcClientStream.prototype._write = function(chunk, encoding, callback) {
+ this._tryWrite(chunk, callback);
+};
+
+/**
+ * Make a request on the channel to the given method with the given arguments
+ * @param {grpc.Channel} channel The channel on which to make the request
+ * @param {string} method The method to request
+ * @param {array=} metadata Array of metadata key/value pairs to add to the call
+ * @param {(number|Date)=} deadline The deadline for processing this request.
+ * Defaults to infinite future.
+ * @return {stream=} The stream of responses
+ */
+function makeRequest(channel,
+ method,
+ metadata,
+ deadline) {
+ if (deadline === undefined) {
+ deadline = Infinity;
+ }
+ var call = new grpc.Call(channel, method, deadline);
+ if (metadata) {
+ call.addMetadata(metadata);
+ }
+ return new GrpcClientStream(call);
+}
+
+/**
+ * See documentation for makeRequest above
+ */
+exports.makeRequest = makeRequest;
+
+/**
+ * Represents a client side gRPC channel associated with a single host.
+ */
+exports.Channel = grpc.Channel;
+/**
+ * Status name to code number mapping
+ */
+exports.status = grpc.status;
+/**
+ * Call error name to code number mapping
+ */
+exports.callError = grpc.callError;
diff --git a/src/node/common.js b/src/node/common.js
new file mode 100644
index 0000000000..c2dc276608
--- /dev/null
+++ b/src/node/common.js
@@ -0,0 +1,62 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+var _ = require('highland');
+
+/**
+ * When the given stream finishes without error, call the callback once. This
+ * will not be called until something begins to consume the stream.
+ * @param {function} callback The callback to call at stream end
+ * @param {stream} source The stream to watch
+ * @return {stream} The stream with the callback attached
+ */
+function onSuccessfulStreamEnd(callback, source) {
+ var error = false;
+ return source.consume(function(err, x, push, next) {
+ if (x === _.nil) {
+ if (!error) {
+ callback();
+ }
+ push(null, x);
+ } else if (err) {
+ error = true;
+ push(err);
+ next();
+ } else {
+ push(err, x);
+ next();
+ }
+ });
+}
+
+exports.onSuccessfulStreamEnd = onSuccessfulStreamEnd;
diff --git a/src/node/completion_queue_async_worker.cc b/src/node/completion_queue_async_worker.cc
new file mode 100644
index 0000000000..8de7db66d5
--- /dev/null
+++ b/src/node/completion_queue_async_worker.cc
@@ -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 <node.h>
+#include <nan.h>
+
+#include "grpc/grpc.h"
+#include "grpc/support/time.h"
+#include "completion_queue_async_worker.h"
+#include "event.h"
+#include "tag.h"
+
+namespace grpc {
+namespace node {
+
+using v8::Function;
+using v8::Handle;
+using v8::Object;
+using v8::Persistent;
+using v8::Value;
+
+grpc_completion_queue *CompletionQueueAsyncWorker::queue;
+
+CompletionQueueAsyncWorker::CompletionQueueAsyncWorker()
+ : NanAsyncWorker(NULL) {}
+
+CompletionQueueAsyncWorker::~CompletionQueueAsyncWorker() {}
+
+void CompletionQueueAsyncWorker::Execute() {
+ result = grpc_completion_queue_next(queue, gpr_inf_future);
+}
+
+grpc_completion_queue *CompletionQueueAsyncWorker::GetQueue() { return queue; }
+
+void CompletionQueueAsyncWorker::Next() {
+ NanScope();
+ CompletionQueueAsyncWorker *worker = new CompletionQueueAsyncWorker();
+ NanAsyncQueueWorker(worker);
+}
+
+void CompletionQueueAsyncWorker::Init(Handle<Object> exports) {
+ NanScope();
+ queue = grpc_completion_queue_create();
+}
+
+void CompletionQueueAsyncWorker::HandleOKCallback() {
+ NanScope();
+ NanCallback event_callback(GetTagHandle(result->tag).As<Function>());
+ Handle<Value> argv[] = {CreateEventObject(result)};
+
+ DestroyTag(result->tag);
+ grpc_event_finish(result);
+ result = NULL;
+
+ event_callback.Call(1, argv);
+}
+
+} // namespace node
+} // namespace grpc
diff --git a/src/node/completion_queue_async_worker.h b/src/node/completion_queue_async_worker.h
new file mode 100644
index 0000000000..2c928b7024
--- /dev/null
+++ b/src/node/completion_queue_async_worker.h
@@ -0,0 +1,79 @@
+/*
+ *
+ * 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 NET_GRPC_NODE_COMPLETION_QUEUE_ASYNC_WORKER_H_
+#define NET_GRPC_NODE_COMPLETION_QUEUE_ASYNC_WORKER_H_
+#include <nan.h>
+
+#include "grpc/grpc.h"
+
+namespace grpc {
+namespace node {
+
+/* A worker that asynchronously calls completion_queue_next, and queues onto the
+ node event loop a call to the function stored in the event's tag. */
+class CompletionQueueAsyncWorker : public NanAsyncWorker {
+ public:
+ CompletionQueueAsyncWorker();
+
+ ~CompletionQueueAsyncWorker();
+ /* Calls completion_queue_next with the provided deadline, and stores the
+ event if there was one or sets an error message if there was not */
+ void Execute();
+
+ /* Returns the completion queue attached to this class */
+ static grpc_completion_queue *GetQueue();
+
+ /* Convenience function to create a worker with the given arguments and queue
+ it to run asynchronously */
+ static void Next();
+
+ /* Initialize the CompletionQueueAsyncWorker class */
+ static void Init(v8::Handle<v8::Object> exports);
+
+ protected:
+ /* Called when Execute has succeeded (completed without setting an error
+ message). Calls the saved callback with the event that came from
+ completion_queue_next */
+ void HandleOKCallback();
+
+ private:
+ grpc_event *result;
+
+ static grpc_completion_queue *queue;
+};
+
+} // namespace node
+} // namespace grpc
+
+#endif // NET_GRPC_NODE_COMPLETION_QUEUE_ASYNC_WORKER_H_
diff --git a/src/node/credentials.cc b/src/node/credentials.cc
new file mode 100644
index 0000000000..d58b7eda89
--- /dev/null
+++ b/src/node/credentials.cc
@@ -0,0 +1,209 @@
+/*
+ *
+ * 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 <node.h>
+
+#include "grpc/grpc.h"
+#include "grpc/grpc_security.h"
+#include "grpc/support/log.h"
+#include "credentials.h"
+
+namespace grpc {
+namespace node {
+
+using ::node::Buffer;
+using v8::Arguments;
+using v8::Exception;
+using v8::External;
+using v8::Function;
+using v8::FunctionTemplate;
+using v8::Handle;
+using v8::HandleScope;
+using v8::Integer;
+using v8::Local;
+using v8::Object;
+using v8::ObjectTemplate;
+using v8::Persistent;
+using v8::Value;
+
+Persistent<Function> Credentials::constructor;
+Persistent<FunctionTemplate> Credentials::fun_tpl;
+
+Credentials::Credentials(grpc_credentials *credentials)
+ : wrapped_credentials(credentials) {}
+
+Credentials::~Credentials() {
+ gpr_log(GPR_DEBUG, "Destroying credentials object");
+ grpc_credentials_release(wrapped_credentials);
+}
+
+void Credentials::Init(Handle<Object> exports) {
+ NanScope();
+ Local<FunctionTemplate> tpl = FunctionTemplate::New(New);
+ tpl->SetClassName(NanNew("Credentials"));
+ tpl->InstanceTemplate()->SetInternalFieldCount(1);
+ NanAssignPersistent(fun_tpl, tpl);
+ NanAssignPersistent(constructor, tpl->GetFunction());
+ constructor->Set(NanNew("createDefault"),
+ FunctionTemplate::New(CreateDefault)->GetFunction());
+ constructor->Set(NanNew("createSsl"),
+ FunctionTemplate::New(CreateSsl)->GetFunction());
+ constructor->Set(NanNew("createComposite"),
+ FunctionTemplate::New(CreateComposite)->GetFunction());
+ constructor->Set(NanNew("createGce"),
+ FunctionTemplate::New(CreateGce)->GetFunction());
+ constructor->Set(NanNew("createFake"),
+ FunctionTemplate::New(CreateFake)->GetFunction());
+ constructor->Set(NanNew("createIam"),
+ FunctionTemplate::New(CreateIam)->GetFunction());
+ exports->Set(NanNew("Credentials"), constructor);
+}
+
+bool Credentials::HasInstance(Handle<Value> val) {
+ NanScope();
+ return NanHasInstance(fun_tpl, val);
+}
+
+Handle<Value> Credentials::WrapStruct(grpc_credentials *credentials) {
+ NanEscapableScope();
+ if (credentials == NULL) {
+ return NanEscapeScope(NanNull());
+ }
+ const int argc = 1;
+ Handle<Value> argv[argc] = {
+ External::New(reinterpret_cast<void *>(credentials))};
+ return NanEscapeScope(constructor->NewInstance(argc, argv));
+}
+
+grpc_credentials *Credentials::GetWrappedCredentials() {
+ return wrapped_credentials;
+}
+
+NAN_METHOD(Credentials::New) {
+ NanScope();
+
+ if (args.IsConstructCall()) {
+ if (!args[0]->IsExternal()) {
+ return NanThrowTypeError(
+ "Credentials can only be created with the provided functions");
+ }
+ grpc_credentials *creds_value =
+ reinterpret_cast<grpc_credentials *>(External::Unwrap(args[0]));
+ Credentials *credentials = new Credentials(creds_value);
+ credentials->Wrap(args.This());
+ NanReturnValue(args.This());
+ } else {
+ const int argc = 1;
+ Local<Value> argv[argc] = {args[0]};
+ NanReturnValue(constructor->NewInstance(argc, argv));
+ }
+}
+
+NAN_METHOD(Credentials::CreateDefault) {
+ NanScope();
+ NanReturnValue(WrapStruct(grpc_default_credentials_create()));
+}
+
+NAN_METHOD(Credentials::CreateSsl) {
+ NanScope();
+ char *root_certs;
+ char *private_key = NULL;
+ char *cert_chain = NULL;
+ int root_certs_length, private_key_length = 0, cert_chain_length = 0;
+ if (!Buffer::HasInstance(args[0])) {
+ return NanThrowTypeError("createSsl's first argument must be a Buffer");
+ }
+ root_certs = Buffer::Data(args[0]);
+ root_certs_length = Buffer::Length(args[0]);
+ if (Buffer::HasInstance(args[1])) {
+ private_key = Buffer::Data(args[1]);
+ private_key_length = Buffer::Length(args[1]);
+ } else if (!(args[1]->IsNull() || args[1]->IsUndefined())) {
+ return NanThrowTypeError(
+ "createSSl's second argument must be a Buffer if provided");
+ }
+ if (Buffer::HasInstance(args[2])) {
+ cert_chain = Buffer::Data(args[2]);
+ cert_chain_length = Buffer::Length(args[2]);
+ } else if (!(args[2]->IsNull() || args[2]->IsUndefined())) {
+ return NanThrowTypeError(
+ "createSSl's third argument must be a Buffer if provided");
+ }
+ NanReturnValue(WrapStruct(grpc_ssl_credentials_create(
+ reinterpret_cast<unsigned char *>(root_certs), root_certs_length,
+ reinterpret_cast<unsigned char *>(private_key), private_key_length,
+ reinterpret_cast<unsigned char *>(cert_chain), cert_chain_length)));
+}
+
+NAN_METHOD(Credentials::CreateComposite) {
+ NanScope();
+ if (!HasInstance(args[0])) {
+ return NanThrowTypeError(
+ "createComposite's first argument must be a Credentials object");
+ }
+ if (!HasInstance(args[1])) {
+ return NanThrowTypeError(
+ "createComposite's second argument must be a Credentials object");
+ }
+ Credentials *creds1 = ObjectWrap::Unwrap<Credentials>(args[0]->ToObject());
+ Credentials *creds2 = ObjectWrap::Unwrap<Credentials>(args[1]->ToObject());
+ NanReturnValue(WrapStruct(grpc_composite_credentials_create(
+ creds1->wrapped_credentials, creds2->wrapped_credentials)));
+}
+
+NAN_METHOD(Credentials::CreateGce) {
+ NanScope();
+ NanReturnValue(WrapStruct(grpc_compute_engine_credentials_create()));
+}
+
+NAN_METHOD(Credentials::CreateFake) {
+ NanScope();
+ NanReturnValue(WrapStruct(grpc_fake_transport_security_credentials_create()));
+}
+
+NAN_METHOD(Credentials::CreateIam) {
+ NanScope();
+ if (!args[0]->IsString()) {
+ return NanThrowTypeError("createIam's first argument must be a string");
+ }
+ if (!args[1]->IsString()) {
+ return NanThrowTypeError("createIam's second argument must be a string");
+ }
+ NanUtf8String auth_token(args[0]);
+ NanUtf8String auth_selector(args[1]);
+ NanReturnValue(
+ WrapStruct(grpc_iam_credentials_create(*auth_token, *auth_selector)));
+}
+
+} // namespace node
+} // namespace grpc
diff --git a/src/node/credentials.h b/src/node/credentials.h
new file mode 100644
index 0000000000..981e5a99bc
--- /dev/null
+++ b/src/node/credentials.h
@@ -0,0 +1,81 @@
+/*
+ *
+ * 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 NET_GRPC_NODE_CREDENTIALS_H_
+#define NET_GRPC_NODE_CREDENTIALS_H_
+
+#include <node.h>
+#include <nan.h>
+#include "grpc/grpc.h"
+#include "grpc/grpc_security.h"
+
+namespace grpc {
+namespace node {
+
+/* Wrapper class for grpc_credentials structs */
+class Credentials : public ::node::ObjectWrap {
+ public:
+ static void Init(v8::Handle<v8::Object> exports);
+ static bool HasInstance(v8::Handle<v8::Value> val);
+ /* Wrap a grpc_credentials struct in a javascript object */
+ static v8::Handle<v8::Value> WrapStruct(grpc_credentials *credentials);
+
+ /* Returns the grpc_credentials struct that this object wraps */
+ grpc_credentials *GetWrappedCredentials();
+
+ private:
+ explicit Credentials(grpc_credentials *credentials);
+ ~Credentials();
+
+ // Prevent copying
+ Credentials(const Credentials &);
+ Credentials &operator=(const Credentials &);
+
+ static NAN_METHOD(New);
+ static NAN_METHOD(CreateDefault);
+ static NAN_METHOD(CreateSsl);
+ static NAN_METHOD(CreateComposite);
+ static NAN_METHOD(CreateGce);
+ static NAN_METHOD(CreateFake);
+ static NAN_METHOD(CreateIam);
+ static v8::Persistent<v8::Function> constructor;
+ // Used for typechecking instances of this javascript class
+ static v8::Persistent<v8::FunctionTemplate> fun_tpl;
+
+ grpc_credentials *wrapped_credentials;
+};
+
+} // namespace node
+} // namespace grpc
+
+#endif // NET_GRPC_NODE_CREDENTIALS_H_
diff --git a/src/node/event.cc b/src/node/event.cc
new file mode 100644
index 0000000000..2ca38b7448
--- /dev/null
+++ b/src/node/event.cc
@@ -0,0 +1,164 @@
+/*
+ *
+ * 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 <node.h>
+#include <nan.h>
+#include "grpc/grpc.h"
+#include "byte_buffer.h"
+#include "call.h"
+#include "event.h"
+#include "tag.h"
+#include "timeval.h"
+
+namespace grpc {
+namespace node {
+
+using v8::Array;
+using v8::Date;
+using v8::Handle;
+using v8::HandleScope;
+using v8::Number;
+using v8::Object;
+using v8::Persistent;
+using v8::String;
+using v8::Value;
+
+Handle<Value> GetEventData(grpc_event *event) {
+ NanEscapableScope();
+ size_t count;
+ grpc_metadata *items;
+ Handle<Array> metadata;
+ Handle<Object> status;
+ Handle<Object> rpc_new;
+ switch (event->type) {
+ case GRPC_READ:
+ return NanEscapeScope(ByteBufferToBuffer(event->data.read));
+ case GRPC_INVOKE_ACCEPTED:
+ return NanEscapeScope(NanNew<Number>(event->data.invoke_accepted));
+ case GRPC_WRITE_ACCEPTED:
+ return NanEscapeScope(NanNew<Number>(event->data.write_accepted));
+ case GRPC_FINISH_ACCEPTED:
+ return NanEscapeScope(NanNew<Number>(event->data.finish_accepted));
+ case GRPC_CLIENT_METADATA_READ:
+ count = event->data.client_metadata_read.count;
+ items = event->data.client_metadata_read.elements;
+ metadata = NanNew<Array>(static_cast<int>(count));
+ for (unsigned int i = 0; i < count; i++) {
+ Handle<Object> item_obj = NanNew<Object>();
+ item_obj->Set(NanNew<String, const char *>("key"),
+ NanNew<String, char *>(items[i].key));
+ item_obj->Set(
+ NanNew<String, const char *>("value"),
+ NanNew<String, char *>(items[i].value,
+ static_cast<int>(items[i].value_length)));
+ metadata->Set(i, item_obj);
+ }
+ return NanEscapeScope(metadata);
+ case GRPC_FINISHED:
+ status = NanNew<Object>();
+ status->Set(NanNew("code"), NanNew<Number>(event->data.finished.status));
+ if (event->data.finished.details != NULL) {
+ status->Set(NanNew("details"),
+ String::New(event->data.finished.details));
+ }
+ count = event->data.finished.metadata_count;
+ items = event->data.finished.metadata_elements;
+ metadata = NanNew<Array>(static_cast<int>(count));
+ for (unsigned int i = 0; i < count; i++) {
+ Handle<Object> item_obj = NanNew<Object>();
+ item_obj->Set(NanNew<String, const char *>("key"),
+ NanNew<String, char *>(items[i].key));
+ item_obj->Set(
+ NanNew<String, const char *>("value"),
+ NanNew<String, char *>(items[i].value,
+ static_cast<int>(items[i].value_length)));
+ metadata->Set(i, item_obj);
+ }
+ status->Set(NanNew("metadata"), metadata);
+ return NanEscapeScope(status);
+ case GRPC_SERVER_RPC_NEW:
+ rpc_new = NanNew<Object>();
+ if (event->data.server_rpc_new.method == NULL) {
+ return NanEscapeScope(NanNull());
+ }
+ rpc_new->Set(
+ NanNew<String, const char *>("method"),
+ NanNew<String, const char *>(event->data.server_rpc_new.method));
+ rpc_new->Set(
+ NanNew<String, const char *>("host"),
+ NanNew<String, const char *>(event->data.server_rpc_new.host));
+ rpc_new->Set(NanNew<String, const char *>("absolute_deadline"),
+ NanNew<Date>(TimespecToMilliseconds(
+ event->data.server_rpc_new.deadline)));
+ count = event->data.server_rpc_new.metadata_count;
+ items = event->data.server_rpc_new.metadata_elements;
+ metadata = NanNew<Array>(static_cast<int>(count));
+ for (unsigned int i = 0; i < count; i++) {
+ Handle<Object> item_obj = Object::New();
+ item_obj->Set(NanNew<String, const char *>("key"),
+ NanNew<String, char *>(items[i].key));
+ item_obj->Set(
+ NanNew<String, const char *>("value"),
+ NanNew<String, char *>(items[i].value,
+ static_cast<int>(items[i].value_length)));
+ metadata->Set(i, item_obj);
+ }
+ rpc_new->Set(NanNew<String, const char *>("metadata"), metadata);
+ return NanEscapeScope(rpc_new);
+ default:
+ return NanEscapeScope(NanNull());
+ }
+}
+
+Handle<Value> CreateEventObject(grpc_event *event) {
+ NanEscapableScope();
+ if (event == NULL) {
+ return NanEscapeScope(NanNull());
+ }
+ Handle<Object> event_obj = NanNew<Object>();
+ Handle<Value> call;
+ if (TagHasCall(event->tag)) {
+ call = TagGetCall(event->tag);
+ } else {
+ call = Call::WrapStruct(event->call);
+ }
+ event_obj->Set(NanNew<String, const char *>("call"), call);
+ event_obj->Set(NanNew<String, const char *>("type"),
+ NanNew<Number>(event->type));
+ event_obj->Set(NanNew<String, const char *>("data"), GetEventData(event));
+
+ return NanEscapeScope(event_obj);
+}
+
+} // namespace node
+} // namespace grpc
diff --git a/src/cpp/client/internal_stub.h b/src/node/event.h
index 0eaa717d0b..e06d8f0168 100644
--- a/src/cpp/client/internal_stub.h
+++ b/src/node/event.h
@@ -31,30 +31,18 @@
*
*/
-#ifndef __GRPCPP_INTERNAL_CLIENT_INTERNAL_STUB_H__
-#define __GRPCPP_INTERNAL_CLIENT_INTERNAL_STUB_H__
+#ifndef NET_GRPC_NODE_EVENT_H_
+#define NET_GRPC_NODE_EVENT_H_
-#include <memory>
-
-#include <grpc++/channel_interface.h>
+#include <node.h>
+#include "grpc/grpc.h"
namespace grpc {
+namespace node {
-class InternalStub {
- public:
- InternalStub() {}
- virtual ~InternalStub() {}
-
- void set_channel(const std::shared_ptr<ChannelInterface>& channel) {
- channel_ = channel;
- }
-
- ChannelInterface* channel() { return channel_.get(); }
-
- private:
- std::shared_ptr<ChannelInterface> channel_;
-};
+v8::Handle<v8::Value> CreateEventObject(grpc_event *event);
+} // namespace node
} // namespace grpc
-#endif // __GRPCPP_INTERNAL_CLIENT_INTERNAL_STUB_H__
+#endif // NET_GRPC_NODE_EVENT_H_
diff --git a/src/node/examples/math.proto b/src/node/examples/math.proto
new file mode 100644
index 0000000000..14eff5daaf
--- /dev/null
+++ b/src/node/examples/math.proto
@@ -0,0 +1,25 @@
+syntax = "proto2";
+
+package math;
+
+message DivArgs {
+ required int64 dividend = 1;
+ required int64 divisor = 2;
+}
+
+message DivReply {
+ required int64 quotient = 1;
+ required int64 remainder = 2;
+}
+
+message FibArgs {
+ optional int64 limit = 1;
+}
+
+message Num {
+ required int64 num = 1;
+}
+
+message FibReply {
+ required int64 count = 1;
+} \ No newline at end of file
diff --git a/src/node/examples/math_server.js b/src/node/examples/math_server.js
new file mode 100644
index 0000000000..87336b61e5
--- /dev/null
+++ b/src/node/examples/math_server.js
@@ -0,0 +1,201 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+var _ = require('underscore');
+var ProtoBuf = require('protobufjs');
+var fs = require('fs');
+var util = require('util');
+
+var Transform = require('stream').Transform;
+
+var builder = ProtoBuf.loadProtoFile(__dirname + '/math.proto');
+var math = builder.build('math');
+
+var makeConstructor = require('../surface_server.js').makeServerConstructor;
+
+/**
+ * Get a function that deserializes a specific type of protobuf.
+ * @param {function()} cls The constructor of the message type to deserialize
+ * @return {function(Buffer):cls} The deserialization function
+ */
+function deserializeCls(cls) {
+ /**
+ * Deserialize a buffer to a message object
+ * @param {Buffer} arg_buf The buffer to deserialize
+ * @return {cls} The resulting object
+ */
+ return function deserialize(arg_buf) {
+ return cls.decode(arg_buf);
+ };
+}
+
+/**
+ * Get a function that serializes objects to a buffer by protobuf class.
+ * @param {function()} Cls The constructor of the message type to serialize
+ * @return {function(Cls):Buffer} The serialization function
+ */
+function serializeCls(Cls) {
+ /**
+ * Serialize an object to a Buffer
+ * @param {Object} arg The object to serialize
+ * @return {Buffer} The serialized object
+ */
+ return function serialize(arg) {
+ return new Buffer(new Cls(arg).encode().toBuffer());
+ };
+}
+
+/* This function call creates a server constructor for servers that that expose
+ * the four specified methods. This specifies how to serialize messages that the
+ * server sends and deserialize messages that the client sends, and whether the
+ * client or the server will send a stream of messages, for each method. This
+ * also specifies a prefix that will be added to method names when sending them
+ * on the wire. This function call and all of the preceding code in this file
+ * are intended to approximate what the generated code will look like for the
+ * math service */
+var Server = makeConstructor({
+ Div: {
+ serialize: serializeCls(math.DivReply),
+ deserialize: deserializeCls(math.DivArgs),
+ client_stream: false,
+ server_stream: false
+ },
+ Fib: {
+ serialize: serializeCls(math.Num),
+ deserialize: deserializeCls(math.FibArgs),
+ client_stream: false,
+ server_stream: true
+ },
+ Sum: {
+ serialize: serializeCls(math.Num),
+ deserialize: deserializeCls(math.Num),
+ client_stream: true,
+ server_stream: false
+ },
+ DivMany: {
+ serialize: serializeCls(math.DivReply),
+ deserialize: deserializeCls(math.DivArgs),
+ client_stream: true,
+ server_stream: true
+ }
+}, '/Math/');
+
+/**
+ * Server function for division. Provides the /Math/DivMany and /Math/Div
+ * functions (Div is just DivMany with only one stream element). For each
+ * DivArgs parameter, responds with a DivReply with the results of the division
+ * @param {Object} call The object containing request and cancellation info
+ * @param {function(Error, *)} cb Response callback
+ */
+function mathDiv(call, cb) {
+ var req = call.request;
+ if (req.divisor == 0) {
+ cb(new Error('cannot divide by zero'));
+ }
+ cb(null, {
+ quotient: req.dividend / req.divisor,
+ remainder: req.dividend % req.divisor
+ });
+}
+
+/**
+ * Server function for Fibonacci numbers. Provides the /Math/Fib function. Reads
+ * a single parameter that indicates the number of responses, and then responds
+ * with a stream of that many Fibonacci numbers.
+ * @param {stream} stream The stream for sending responses.
+ */
+function mathFib(stream) {
+ // Here, call is a standard writable Node object Stream
+ var previous = 0, current = 1;
+ for (var i = 0; i < stream.request.limit; i++) {
+ stream.write({num: current});
+ var temp = current;
+ current += previous;
+ previous = temp;
+ }
+ stream.end();
+}
+
+/**
+ * Server function for summation. Provides the /Math/Sum function. Reads a
+ * stream of number parameters, then responds with their sum.
+ * @param {stream} call The stream of arguments.
+ * @param {function(Error, *)} cb Response callback
+ */
+function mathSum(call, cb) {
+ // Here, call is a standard readable Node object Stream
+ var sum = 0;
+ call.on('data', function(data) {
+ sum += data.num | 0;
+ });
+ call.on('end', function() {
+ cb(null, {num: sum});
+ });
+}
+
+function mathDivMany(stream) {
+ // Here, call is a standard duplex Node object Stream
+ util.inherits(DivTransform, Transform);
+ function DivTransform() {
+ var options = {objectMode: true};
+ Transform.call(this, options);
+ }
+ DivTransform.prototype._transform = function(div_args, encoding, callback) {
+ if (div_args.divisor == 0) {
+ callback(new Error('cannot divide by zero'));
+ }
+ callback(null, {
+ quotient: div_args.dividend / div_args.divisor,
+ remainder: div_args.dividend % div_args.divisor
+ });
+ };
+ var transform = new DivTransform();
+ stream.pipe(transform);
+ transform.pipe(stream);
+}
+
+var server = new Server({
+ Div: mathDiv,
+ Fib: mathFib,
+ Sum: mathSum,
+ DivMany: mathDivMany
+});
+
+if (require.main === module) {
+ server.bind('localhost:7070').listen();
+}
+
+/**
+ * See docs for server
+ */
+module.exports = server;
diff --git a/src/node/node_grpc.cc b/src/node/node_grpc.cc
new file mode 100644
index 0000000000..acee0386d2
--- /dev/null
+++ b/src/node/node_grpc.cc
@@ -0,0 +1,182 @@
+/*
+ *
+ * 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 <node.h>
+#include <nan.h>
+#include <v8.h>
+#include "grpc/grpc.h"
+
+#include "call.h"
+#include "channel.h"
+#include "event.h"
+#include "server.h"
+#include "completion_queue_async_worker.h"
+#include "credentials.h"
+#include "server_credentials.h"
+
+using v8::Handle;
+using v8::Value;
+using v8::Object;
+using v8::Uint32;
+using v8::String;
+
+void InitStatusConstants(Handle<Object> exports) {
+ NanScope();
+ Handle<Object> status = Object::New();
+ exports->Set(NanNew("status"), status);
+ Handle<Value> OK(NanNew<Uint32, uint32_t>(GRPC_STATUS_OK));
+ status->Set(NanNew("OK"), OK);
+ Handle<Value> CANCELLED(NanNew<Uint32, uint32_t>(GRPC_STATUS_CANCELLED));
+ status->Set(NanNew("CANCELLED"), CANCELLED);
+ Handle<Value> UNKNOWN(NanNew<Uint32, uint32_t>(GRPC_STATUS_UNKNOWN));
+ status->Set(NanNew("UNKNOWN"), UNKNOWN);
+ Handle<Value> INVALID_ARGUMENT(
+ NanNew<Uint32, uint32_t>(GRPC_STATUS_INVALID_ARGUMENT));
+ status->Set(NanNew("INVALID_ARGUMENT"), INVALID_ARGUMENT);
+ Handle<Value> DEADLINE_EXCEEDED(
+ NanNew<Uint32, uint32_t>(GRPC_STATUS_DEADLINE_EXCEEDED));
+ status->Set(NanNew("DEADLINE_EXCEEDED"), DEADLINE_EXCEEDED);
+ Handle<Value> NOT_FOUND(NanNew<Uint32, uint32_t>(GRPC_STATUS_NOT_FOUND));
+ status->Set(NanNew("NOT_FOUND"), NOT_FOUND);
+ Handle<Value> ALREADY_EXISTS(
+ NanNew<Uint32, uint32_t>(GRPC_STATUS_ALREADY_EXISTS));
+ status->Set(NanNew("ALREADY_EXISTS"), ALREADY_EXISTS);
+ Handle<Value> PERMISSION_DENIED(
+ NanNew<Uint32, uint32_t>(GRPC_STATUS_PERMISSION_DENIED));
+ status->Set(NanNew("PERMISSION_DENIED"), PERMISSION_DENIED);
+ Handle<Value> UNAUTHENTICATED(
+ NanNew<Uint32, uint32_t>(GRPC_STATUS_UNAUTHENTICATED));
+ status->Set(NanNew("UNAUTHENTICATED"), UNAUTHENTICATED);
+ Handle<Value> RESOURCE_EXHAUSTED(
+ NanNew<Uint32, uint32_t>(GRPC_STATUS_RESOURCE_EXHAUSTED));
+ status->Set(NanNew("RESOURCE_EXHAUSTED"), RESOURCE_EXHAUSTED);
+ Handle<Value> FAILED_PRECONDITION(
+ NanNew<Uint32, uint32_t>(GRPC_STATUS_FAILED_PRECONDITION));
+ status->Set(NanNew("FAILED_PRECONDITION"), FAILED_PRECONDITION);
+ Handle<Value> ABORTED(NanNew<Uint32, uint32_t>(GRPC_STATUS_ABORTED));
+ status->Set(NanNew("ABORTED"), ABORTED);
+ Handle<Value> OUT_OF_RANGE(
+ NanNew<Uint32, uint32_t>(GRPC_STATUS_OUT_OF_RANGE));
+ status->Set(NanNew("OUT_OF_RANGE"), OUT_OF_RANGE);
+ Handle<Value> UNIMPLEMENTED(
+ NanNew<Uint32, uint32_t>(GRPC_STATUS_UNIMPLEMENTED));
+ status->Set(NanNew("UNIMPLEMENTED"), UNIMPLEMENTED);
+ Handle<Value> INTERNAL(NanNew<Uint32, uint32_t>(GRPC_STATUS_INTERNAL));
+ status->Set(NanNew("INTERNAL"), INTERNAL);
+ Handle<Value> UNAVAILABLE(NanNew<Uint32, uint32_t>(GRPC_STATUS_UNAVAILABLE));
+ status->Set(NanNew("UNAVAILABLE"), UNAVAILABLE);
+ Handle<Value> DATA_LOSS(NanNew<Uint32, uint32_t>(GRPC_STATUS_DATA_LOSS));
+ status->Set(NanNew("DATA_LOSS"), DATA_LOSS);
+}
+
+void InitCallErrorConstants(Handle<Object> exports) {
+ NanScope();
+ Handle<Object> call_error = Object::New();
+ exports->Set(NanNew("callError"), call_error);
+ Handle<Value> OK(NanNew<Uint32, uint32_t>(GRPC_CALL_OK));
+ call_error->Set(NanNew("OK"), OK);
+ Handle<Value> ERROR(NanNew<Uint32, uint32_t>(GRPC_CALL_ERROR));
+ call_error->Set(NanNew("ERROR"), ERROR);
+ Handle<Value> NOT_ON_SERVER(
+ NanNew<Uint32, uint32_t>(GRPC_CALL_ERROR_NOT_ON_SERVER));
+ call_error->Set(NanNew("NOT_ON_SERVER"), NOT_ON_SERVER);
+ Handle<Value> NOT_ON_CLIENT(
+ NanNew<Uint32, uint32_t>(GRPC_CALL_ERROR_NOT_ON_CLIENT));
+ call_error->Set(NanNew("NOT_ON_CLIENT"), NOT_ON_CLIENT);
+ Handle<Value> ALREADY_INVOKED(
+ NanNew<Uint32, uint32_t>(GRPC_CALL_ERROR_ALREADY_INVOKED));
+ call_error->Set(NanNew("ALREADY_INVOKED"), ALREADY_INVOKED);
+ Handle<Value> NOT_INVOKED(
+ NanNew<Uint32, uint32_t>(GRPC_CALL_ERROR_NOT_INVOKED));
+ call_error->Set(NanNew("NOT_INVOKED"), NOT_INVOKED);
+ Handle<Value> ALREADY_FINISHED(
+ NanNew<Uint32, uint32_t>(GRPC_CALL_ERROR_ALREADY_FINISHED));
+ call_error->Set(NanNew("ALREADY_FINISHED"), ALREADY_FINISHED);
+ Handle<Value> TOO_MANY_OPERATIONS(
+ NanNew<Uint32, uint32_t>(GRPC_CALL_ERROR_TOO_MANY_OPERATIONS));
+ call_error->Set(NanNew("TOO_MANY_OPERATIONS"), TOO_MANY_OPERATIONS);
+ Handle<Value> INVALID_FLAGS(
+ NanNew<Uint32, uint32_t>(GRPC_CALL_ERROR_INVALID_FLAGS));
+ call_error->Set(NanNew("INVALID_FLAGS"), INVALID_FLAGS);
+}
+
+void InitOpErrorConstants(Handle<Object> exports) {
+ NanScope();
+ Handle<Object> op_error = Object::New();
+ exports->Set(NanNew("opError"), op_error);
+ Handle<Value> OK(NanNew<Uint32, uint32_t>(GRPC_OP_OK));
+ op_error->Set(NanNew("OK"), OK);
+ Handle<Value> ERROR(NanNew<Uint32, uint32_t>(GRPC_OP_ERROR));
+ op_error->Set(NanNew("ERROR"), ERROR);
+}
+
+void InitCompletionTypeConstants(Handle<Object> exports) {
+ NanScope();
+ Handle<Object> completion_type = Object::New();
+ exports->Set(NanNew("completionType"), completion_type);
+ Handle<Value> QUEUE_SHUTDOWN(NanNew<Uint32, uint32_t>(GRPC_QUEUE_SHUTDOWN));
+ completion_type->Set(NanNew("QUEUE_SHUTDOWN"), QUEUE_SHUTDOWN);
+ Handle<Value> READ(NanNew<Uint32, uint32_t>(GRPC_READ));
+ completion_type->Set(NanNew("READ"), READ);
+ Handle<Value> INVOKE_ACCEPTED(NanNew<Uint32, uint32_t>(GRPC_INVOKE_ACCEPTED));
+ completion_type->Set(NanNew("INVOKE_ACCEPTED"), INVOKE_ACCEPTED);
+ Handle<Value> WRITE_ACCEPTED(NanNew<Uint32, uint32_t>(GRPC_WRITE_ACCEPTED));
+ completion_type->Set(NanNew("WRITE_ACCEPTED"), WRITE_ACCEPTED);
+ Handle<Value> FINISH_ACCEPTED(NanNew<Uint32, uint32_t>(GRPC_FINISH_ACCEPTED));
+ completion_type->Set(NanNew("FINISH_ACCEPTED"), FINISH_ACCEPTED);
+ Handle<Value> CLIENT_METADATA_READ(
+ NanNew<Uint32, uint32_t>(GRPC_CLIENT_METADATA_READ));
+ completion_type->Set(NanNew("CLIENT_METADATA_READ"), CLIENT_METADATA_READ);
+ Handle<Value> FINISHED(NanNew<Uint32, uint32_t>(GRPC_FINISHED));
+ completion_type->Set(NanNew("FINISHED"), FINISHED);
+ Handle<Value> SERVER_RPC_NEW(NanNew<Uint32, uint32_t>(GRPC_SERVER_RPC_NEW));
+ completion_type->Set(NanNew("SERVER_RPC_NEW"), SERVER_RPC_NEW);
+}
+
+void init(Handle<Object> exports) {
+ NanScope();
+ grpc_init();
+ InitStatusConstants(exports);
+ InitCallErrorConstants(exports);
+ InitOpErrorConstants(exports);
+ InitCompletionTypeConstants(exports);
+
+ grpc::node::Call::Init(exports);
+ grpc::node::Channel::Init(exports);
+ grpc::node::Server::Init(exports);
+ grpc::node::CompletionQueueAsyncWorker::Init(exports);
+ grpc::node::Credentials::Init(exports);
+ grpc::node::ServerCredentials::Init(exports);
+}
+
+NODE_MODULE(grpc, init)
diff --git a/src/node/package.json b/src/node/package.json
new file mode 100644
index 0000000000..a2940b29bb
--- /dev/null
+++ b/src/node/package.json
@@ -0,0 +1,18 @@
+{
+ "name": "grpc",
+ "version": "0.1.0",
+ "description": "gRPC Library for Node",
+ "scripts": {
+ "test": "./node_modules/mocha/bin/mocha"
+ },
+ "dependencies": {
+ "bindings": "^1.2.1",
+ "nan": "~1.3.0",
+ "underscore": "^1.7.0"
+ },
+ "devDependencies": {
+ "mocha": "~1.21.0",
+ "highland": "~2.0.0",
+ "protobufjs": "~3.8.0"
+ }
+}
diff --git a/src/node/port_picker.js b/src/node/port_picker.js
new file mode 100644
index 0000000000..ad82f2a7f8
--- /dev/null
+++ b/src/node/port_picker.js
@@ -0,0 +1,52 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+var net = require('net');
+
+/**
+ * Finds a free port that a server can bind to, in the format
+ * "address:port"
+ * @param {function(string)} cb The callback that should execute when the port
+ * is available
+ */
+function nextAvailablePort(cb) {
+ var server = net.createServer();
+ server.listen(function() {
+ var address = server.address();
+ server.close(function() {
+ cb(address.address + ':' + address.port.toString());
+ });
+ });
+}
+
+exports.nextAvailablePort = nextAvailablePort;
diff --git a/src/node/server.cc b/src/node/server.cc
new file mode 100644
index 0000000000..64826897cd
--- /dev/null
+++ b/src/node/server.cc
@@ -0,0 +1,236 @@
+/*
+ *
+ * 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 "server.h"
+
+#include <node.h>
+#include <nan.h>
+
+#include <malloc.h>
+
+#include <vector>
+#include "grpc/grpc.h"
+#include "grpc/grpc_security.h"
+#include "call.h"
+#include "completion_queue_async_worker.h"
+#include "tag.h"
+#include "server_credentials.h"
+
+namespace grpc {
+namespace node {
+
+using v8::Arguments;
+using v8::Array;
+using v8::Boolean;
+using v8::Exception;
+using v8::Function;
+using v8::FunctionTemplate;
+using v8::Handle;
+using v8::HandleScope;
+using v8::Local;
+using v8::Number;
+using v8::Object;
+using v8::Persistent;
+using v8::String;
+using v8::Value;
+
+Persistent<Function> Server::constructor;
+Persistent<FunctionTemplate> Server::fun_tpl;
+
+Server::Server(grpc_server *server) : wrapped_server(server) {}
+
+Server::~Server() { grpc_server_destroy(wrapped_server); }
+
+void Server::Init(Handle<Object> exports) {
+ NanScope();
+ Local<FunctionTemplate> tpl = FunctionTemplate::New(New);
+ tpl->SetClassName(String::NewSymbol("Server"));
+ tpl->InstanceTemplate()->SetInternalFieldCount(1);
+ NanSetPrototypeTemplate(tpl, "requestCall",
+ FunctionTemplate::New(RequestCall)->GetFunction());
+
+ NanSetPrototypeTemplate(tpl, "addHttp2Port",
+ FunctionTemplate::New(AddHttp2Port)->GetFunction());
+
+ NanSetPrototypeTemplate(
+ tpl, "addSecureHttp2Port",
+ FunctionTemplate::New(AddSecureHttp2Port)->GetFunction());
+
+ NanSetPrototypeTemplate(tpl, "start",
+ FunctionTemplate::New(Start)->GetFunction());
+
+ NanSetPrototypeTemplate(tpl, "shutdown",
+ FunctionTemplate::New(Shutdown)->GetFunction());
+
+ NanAssignPersistent(fun_tpl, tpl);
+ NanAssignPersistent(constructor, tpl->GetFunction());
+ exports->Set(String::NewSymbol("Server"), constructor);
+}
+
+bool Server::HasInstance(Handle<Value> val) {
+ return NanHasInstance(fun_tpl, val);
+}
+
+NAN_METHOD(Server::New) {
+ NanScope();
+
+ /* If this is not a constructor call, make a constructor call and return
+ the result */
+ if (!args.IsConstructCall()) {
+ const int argc = 1;
+ Local<Value> argv[argc] = {args[0]};
+ NanReturnValue(constructor->NewInstance(argc, argv));
+ }
+ grpc_server *wrapped_server;
+ grpc_completion_queue *queue = CompletionQueueAsyncWorker::GetQueue();
+ if (args[0]->IsUndefined()) {
+ wrapped_server = grpc_server_create(queue, NULL);
+ } else if (args[0]->IsObject()) {
+ grpc_server_credentials *creds = NULL;
+ Handle<Object> args_hash(args[0]->ToObject()->Clone());
+ if (args_hash->HasOwnProperty(NanNew("credentials"))) {
+ Handle<Value> creds_value = args_hash->Get(NanNew("credentials"));
+ if (!ServerCredentials::HasInstance(creds_value)) {
+ return NanThrowTypeError(
+ "credentials arg must be a ServerCredentials object");
+ }
+ ServerCredentials *creds_object =
+ ObjectWrap::Unwrap<ServerCredentials>(creds_value->ToObject());
+ creds = creds_object->GetWrappedServerCredentials();
+ args_hash->Delete(NanNew("credentials"));
+ }
+ Handle<Array> keys(args_hash->GetOwnPropertyNames());
+ grpc_channel_args channel_args;
+ channel_args.num_args = keys->Length();
+ channel_args.args = reinterpret_cast<grpc_arg *>(
+ calloc(channel_args.num_args, sizeof(grpc_arg)));
+ /* These are used to keep all strings until then end of the block, then
+ destroy them */
+ std::vector<NanUtf8String *> key_strings(keys->Length());
+ std::vector<NanUtf8String *> value_strings(keys->Length());
+ for (unsigned int i = 0; i < channel_args.num_args; i++) {
+ Handle<String> current_key(keys->Get(i)->ToString());
+ Handle<Value> current_value(args_hash->Get(current_key));
+ key_strings[i] = new NanUtf8String(current_key);
+ channel_args.args[i].key = **key_strings[i];
+ if (current_value->IsInt32()) {
+ channel_args.args[i].type = GRPC_ARG_INTEGER;
+ channel_args.args[i].value.integer = current_value->Int32Value();
+ } else if (current_value->IsString()) {
+ channel_args.args[i].type = GRPC_ARG_STRING;
+ value_strings[i] = new NanUtf8String(current_value);
+ channel_args.args[i].value.string = **value_strings[i];
+ } else {
+ free(channel_args.args);
+ return NanThrowTypeError("Arg values must be strings");
+ }
+ }
+ if (creds == NULL) {
+ wrapped_server = grpc_server_create(queue, &channel_args);
+ } else {
+ wrapped_server = grpc_secure_server_create(creds, queue, &channel_args);
+ }
+ free(channel_args.args);
+ } else {
+ return NanThrowTypeError("Server expects an object");
+ }
+ Server *server = new Server(wrapped_server);
+ server->Wrap(args.This());
+ NanReturnValue(args.This());
+}
+
+NAN_METHOD(Server::RequestCall) {
+ NanScope();
+ if (!HasInstance(args.This())) {
+ return NanThrowTypeError("requestCall can only be called on a Server");
+ }
+ Server *server = ObjectWrap::Unwrap<Server>(args.This());
+ grpc_call_error error = grpc_server_request_call(
+ server->wrapped_server, CreateTag(args[0], NanNull()));
+ if (error == GRPC_CALL_OK) {
+ CompletionQueueAsyncWorker::Next();
+ } else {
+ return NanThrowError("requestCall failed", error);
+ }
+ NanReturnUndefined();
+}
+
+NAN_METHOD(Server::AddHttp2Port) {
+ NanScope();
+ if (!HasInstance(args.This())) {
+ return NanThrowTypeError("addHttp2Port can only be called on a Server");
+ }
+ if (!args[0]->IsString()) {
+ return NanThrowTypeError("addHttp2Port's argument must be a String");
+ }
+ Server *server = ObjectWrap::Unwrap<Server>(args.This());
+ NanReturnValue(NanNew<Boolean>(grpc_server_add_http2_port(
+ server->wrapped_server, *NanUtf8String(args[0]))));
+}
+
+NAN_METHOD(Server::AddSecureHttp2Port) {
+ NanScope();
+ if (!HasInstance(args.This())) {
+ return NanThrowTypeError(
+ "addSecureHttp2Port can only be called on a Server");
+ }
+ if (!args[0]->IsString()) {
+ return NanThrowTypeError("addSecureHttp2Port's argument must be a String");
+ }
+ Server *server = ObjectWrap::Unwrap<Server>(args.This());
+ NanReturnValue(NanNew<Boolean>(grpc_server_add_secure_http2_port(
+ server->wrapped_server, *NanUtf8String(args[0]))));
+}
+
+NAN_METHOD(Server::Start) {
+ NanScope();
+ if (!HasInstance(args.This())) {
+ return NanThrowTypeError("start can only be called on a Server");
+ }
+ Server *server = ObjectWrap::Unwrap<Server>(args.This());
+ grpc_server_start(server->wrapped_server);
+ NanReturnUndefined();
+}
+
+NAN_METHOD(Server::Shutdown) {
+ NanScope();
+ if (!HasInstance(args.This())) {
+ return NanThrowTypeError("shutdown can only be called on a Server");
+ }
+ Server *server = ObjectWrap::Unwrap<Server>(args.This());
+ grpc_server_shutdown(server->wrapped_server);
+ NanReturnUndefined();
+}
+
+} // namespace node
+} // namespace grpc
diff --git a/src/node/server.h b/src/node/server.h
new file mode 100644
index 0000000000..d50f1fb6c5
--- /dev/null
+++ b/src/node/server.h
@@ -0,0 +1,79 @@
+/*
+ *
+ * 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 NET_GRPC_NODE_SERVER_H_
+#define NET_GRPC_NODE_SERVER_H_
+
+#include <node.h>
+#include <nan.h>
+#include "grpc/grpc.h"
+
+namespace grpc {
+namespace node {
+
+/* Wraps grpc_server as a JavaScript object. Provides a constructor
+ and wrapper methods for grpc_server_create, grpc_server_request_call,
+ grpc_server_add_http2_port, and grpc_server_start. */
+class Server : public ::node::ObjectWrap {
+ public:
+ /* Initializes the Server class and exposes the constructor and
+ wrapper methods to JavaScript */
+ static void Init(v8::Handle<v8::Object> exports);
+ /* Tests whether the given value was constructed by this class's
+ JavaScript constructor */
+ static bool HasInstance(v8::Handle<v8::Value> val);
+
+ private:
+ explicit Server(grpc_server *server);
+ ~Server();
+
+ // Prevent copying
+ Server(const Server &);
+ Server &operator=(const Server &);
+
+ static NAN_METHOD(New);
+ static NAN_METHOD(RequestCall);
+ static NAN_METHOD(AddHttp2Port);
+ static NAN_METHOD(AddSecureHttp2Port);
+ static NAN_METHOD(Start);
+ static NAN_METHOD(Shutdown);
+ static v8::Persistent<v8::Function> constructor;
+ static v8::Persistent<v8::FunctionTemplate> fun_tpl;
+
+ grpc_server *wrapped_server;
+};
+
+} // namespace node
+} // namespace grpc
+
+#endif // NET_GRPC_NODE_SERVER_H_
diff --git a/src/node/server.js b/src/node/server.js
new file mode 100644
index 0000000000..7f3e0259a0
--- /dev/null
+++ b/src/node/server.js
@@ -0,0 +1,261 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+var grpc = require('bindings')('grpc.node');
+
+var common = require('./common');
+
+var Duplex = require('stream').Duplex;
+var util = require('util');
+
+util.inherits(GrpcServerStream, Duplex);
+
+/**
+ * Class for representing a gRPC server side stream as a Node stream. Extends
+ * from stream.Duplex.
+ * @constructor
+ * @param {grpc.Call} call Call object to proxy
+ * @param {object} options Stream options
+ */
+function GrpcServerStream(call, options) {
+ Duplex.call(this, options);
+ this._call = call;
+ // Indicate that a status has been sent
+ var finished = false;
+ var self = this;
+ var status = {
+ 'code' : grpc.status.OK,
+ 'details' : 'OK'
+ };
+ /**
+ * Send the pending status
+ */
+ function sendStatus() {
+ call.startWriteStatus(status.code, status.details, function() {
+ });
+ finished = true;
+ }
+ this.on('finish', sendStatus);
+ /**
+ * Set the pending status to a given error status. If the error does not have
+ * code or details properties, the code will be set to grpc.status.INTERNAL
+ * and the details will be set to 'Unknown Error'.
+ * @param {Error} err The error object
+ */
+ function setStatus(err) {
+ var code = grpc.status.INTERNAL;
+ var details = 'Unknown Error';
+
+ if (err.hasOwnProperty('code')) {
+ code = err.code;
+ if (err.hasOwnProperty('details')) {
+ details = err.details;
+ }
+ }
+ status = {'code': code, 'details': details};
+ }
+ /**
+ * Terminate the call. This includes indicating that reads are done, draining
+ * all pending writes, and sending the given error as a status
+ * @param {Error} err The error object
+ * @this GrpcServerStream
+ */
+ function terminateCall(err) {
+ // Drain readable data
+ this.on('data', function() {});
+ setStatus(err);
+ this.end();
+ }
+ this.on('error', terminateCall);
+ // Indicates that a read is pending
+ var reading = false;
+ /**
+ * Callback to be called when a READ event is received. Pushes the data onto
+ * the read queue and starts reading again if applicable
+ * @param {grpc.Event} event READ event object
+ */
+ function readCallback(event) {
+ if (finished) {
+ self.push(null);
+ return;
+ }
+ var data = event.data;
+ if (self.push(data) && data != null) {
+ self._call.startRead(readCallback);
+ } else {
+ reading = false;
+ }
+ }
+ /**
+ * Start reading if there is not already a pending read. Reading will
+ * continue until self.push returns false (indicating reads should slow
+ * down) or the read data is null (indicating that there is no more data).
+ */
+ this.startReading = function() {
+ if (finished) {
+ self.push(null);
+ } else {
+ if (!reading) {
+ reading = true;
+ self._call.startRead(readCallback);
+ }
+ }
+ };
+}
+
+/**
+ * Start reading from the gRPC data source. This is an implementation of a
+ * method required for implementing stream.Readable
+ * @param {number} size Ignored
+ */
+GrpcServerStream.prototype._read = function(size) {
+ this.startReading();
+};
+
+/**
+ * Start writing a chunk of data. This is an implementation of a method required
+ * for implementing stream.Writable.
+ * @param {Buffer} chunk The chunk of data to write
+ * @param {string} encoding Ignored
+ * @param {function(Error=)} callback Callback to indicate that the write is
+ * complete
+ */
+GrpcServerStream.prototype._write = function(chunk, encoding, callback) {
+ var self = this;
+ self._call.startWrite(chunk, function(event) {
+ callback();
+ }, 0);
+};
+
+/**
+ * Constructs a server object that stores request handlers and delegates
+ * incoming requests to those handlers
+ * @constructor
+ * @param {Array} options Options that should be passed to the internal server
+ * implementation
+ */
+function Server(options) {
+ this.handlers = {};
+ var handlers = this.handlers;
+ var server = new grpc.Server(options);
+ this._server = server;
+ var started = false;
+ /**
+ * Start the server and begin handling requests
+ * @this Server
+ */
+ this.start = function() {
+ if (this.started) {
+ throw 'Server is already running';
+ }
+ server.start();
+ /**
+ * Handles the SERVER_RPC_NEW event. If there is a handler associated with
+ * the requested method, use that handler to respond to the request. Then
+ * wait for the next request
+ * @param {grpc.Event} event The event to handle with tag SERVER_RPC_NEW
+ */
+ function handleNewCall(event) {
+ var call = event.call;
+ var data = event.data;
+ if (data == null) {
+ return;
+ }
+ server.requestCall(handleNewCall);
+ var handler = undefined;
+ var deadline = data.absolute_deadline;
+ var cancelled = false;
+ if (handlers.hasOwnProperty(data.method)) {
+ handler = handlers[data.method];
+ }
+ call.serverAccept(function(event) {
+ if (event.data.code === grpc.status.CANCELLED) {
+ cancelled = true;
+ }
+ }, 0);
+ call.serverEndInitialMetadata(0);
+ var stream = new GrpcServerStream(call);
+ Object.defineProperty(stream, 'cancelled', {
+ get: function() { return cancelled;}
+ });
+ try {
+ handler(stream, data.metadata);
+ } catch (e) {
+ stream.emit('error', e);
+ }
+ }
+ server.requestCall(handleNewCall);
+ };
+ /** Shuts down the server.
+ */
+ this.shutdown = function() {
+ server.shutdown();
+ };
+}
+
+/**
+ * Registers a handler to handle the named method. Fails if there already is
+ * a handler for the given method. Returns true on success
+ * @param {string} name The name of the method that the provided function should
+ * handle/respond to.
+ * @param {function} handler Function that takes a stream of request values and
+ * returns a stream of response values
+ * @return {boolean} True if the handler was set. False if a handler was already
+ * set for that name.
+ */
+Server.prototype.register = function(name, handler) {
+ if (this.handlers.hasOwnProperty(name)) {
+ return false;
+ }
+ this.handlers[name] = handler;
+ return true;
+};
+
+/**
+ * Binds the server to the given port, with SSL enabled if secure is specified
+ * @param {string} port The port that the server should bind on, in the format
+ * "address:port"
+ * @param {boolean=} secure Whether the server should open a secure port
+ */
+Server.prototype.bind = function(port, secure) {
+ if (secure) {
+ this._server.addSecureHttp2Port(port);
+ } else {
+ this._server.addHttp2Port(port);
+ }
+};
+
+/**
+ * See documentation for Server
+ */
+module.exports = Server;
diff --git a/src/node/server_credentials.cc b/src/node/server_credentials.cc
new file mode 100644
index 0000000000..38df547527
--- /dev/null
+++ b/src/node/server_credentials.cc
@@ -0,0 +1,161 @@
+/*
+ *
+ * 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 <node.h>
+
+#include "grpc/grpc.h"
+#include "grpc/grpc_security.h"
+#include "grpc/support/log.h"
+#include "server_credentials.h"
+
+namespace grpc {
+namespace node {
+
+using ::node::Buffer;
+using v8::Arguments;
+using v8::Exception;
+using v8::External;
+using v8::Function;
+using v8::FunctionTemplate;
+using v8::Handle;
+using v8::HandleScope;
+using v8::Integer;
+using v8::Local;
+using v8::Object;
+using v8::ObjectTemplate;
+using v8::Persistent;
+using v8::Value;
+
+Persistent<Function> ServerCredentials::constructor;
+Persistent<FunctionTemplate> ServerCredentials::fun_tpl;
+
+ServerCredentials::ServerCredentials(grpc_server_credentials *credentials)
+ : wrapped_credentials(credentials) {}
+
+ServerCredentials::~ServerCredentials() {
+ gpr_log(GPR_DEBUG, "Destroying server credentials object");
+ grpc_server_credentials_release(wrapped_credentials);
+}
+
+void ServerCredentials::Init(Handle<Object> exports) {
+ NanScope();
+ Local<FunctionTemplate> tpl = FunctionTemplate::New(New);
+ tpl->SetClassName(NanNew("ServerCredentials"));
+ tpl->InstanceTemplate()->SetInternalFieldCount(1);
+ NanAssignPersistent(fun_tpl, tpl);
+ NanAssignPersistent(constructor, tpl->GetFunction());
+ constructor->Set(NanNew("createSsl"),
+ FunctionTemplate::New(CreateSsl)->GetFunction());
+ constructor->Set(NanNew("createFake"),
+ FunctionTemplate::New(CreateFake)->GetFunction());
+ exports->Set(NanNew("ServerCredentials"), constructor);
+}
+
+bool ServerCredentials::HasInstance(Handle<Value> val) {
+ NanScope();
+ return NanHasInstance(fun_tpl, val);
+}
+
+Handle<Value> ServerCredentials::WrapStruct(
+ grpc_server_credentials *credentials) {
+ NanEscapableScope();
+ if (credentials == NULL) {
+ return NanEscapeScope(NanNull());
+ }
+ const int argc = 1;
+ Handle<Value> argv[argc] = {
+ External::New(reinterpret_cast<void *>(credentials))};
+ return NanEscapeScope(constructor->NewInstance(argc, argv));
+}
+
+grpc_server_credentials *ServerCredentials::GetWrappedServerCredentials() {
+ return wrapped_credentials;
+}
+
+NAN_METHOD(ServerCredentials::New) {
+ NanScope();
+
+ if (args.IsConstructCall()) {
+ if (!args[0]->IsExternal()) {
+ return NanThrowTypeError(
+ "ServerCredentials can only be created with the provide functions");
+ }
+ grpc_server_credentials *creds_value =
+ reinterpret_cast<grpc_server_credentials *>(External::Unwrap(args[0]));
+ ServerCredentials *credentials = new ServerCredentials(creds_value);
+ credentials->Wrap(args.This());
+ NanReturnValue(args.This());
+ } else {
+ const int argc = 1;
+ Local<Value> argv[argc] = {args[0]};
+ NanReturnValue(constructor->NewInstance(argc, argv));
+ }
+}
+
+NAN_METHOD(ServerCredentials::CreateSsl) {
+ NanScope();
+ char *root_certs = NULL;
+ char *private_key;
+ char *cert_chain;
+ int root_certs_length = 0, private_key_length, cert_chain_length;
+ if (Buffer::HasInstance(args[0])) {
+ root_certs = Buffer::Data(args[0]);
+ root_certs_length = Buffer::Length(args[0]);
+ } else if (!(args[0]->IsNull() || args[0]->IsUndefined())) {
+ return NanThrowTypeError(
+ "createSSl's first argument must be a Buffer if provided");
+ }
+ if (!Buffer::HasInstance(args[1])) {
+ return NanThrowTypeError("createSsl's second argument must be a Buffer");
+ }
+ private_key = Buffer::Data(args[1]);
+ private_key_length = Buffer::Length(args[1]);
+ if (!Buffer::HasInstance(args[2])) {
+ return NanThrowTypeError("createSsl's third argument must be a Buffer");
+ }
+ cert_chain = Buffer::Data(args[2]);
+ cert_chain_length = Buffer::Length(args[2]);
+ NanReturnValue(WrapStruct(grpc_ssl_server_credentials_create(
+ reinterpret_cast<unsigned char *>(root_certs), root_certs_length,
+ reinterpret_cast<unsigned char *>(private_key), private_key_length,
+ reinterpret_cast<unsigned char *>(cert_chain), cert_chain_length)));
+}
+
+NAN_METHOD(ServerCredentials::CreateFake) {
+ NanScope();
+ NanReturnValue(
+ WrapStruct(grpc_fake_transport_security_server_credentials_create()));
+}
+
+} // namespace node
+} // namespace grpc
diff --git a/src/node/server_credentials.h b/src/node/server_credentials.h
new file mode 100644
index 0000000000..8baae3f185
--- /dev/null
+++ b/src/node/server_credentials.h
@@ -0,0 +1,77 @@
+/*
+ *
+ * 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 NET_GRPC_NODE_SERVER_CREDENTIALS_H_
+#define NET_GRPC_NODE_SERVER_CREDENTIALS_H_
+
+#include <node.h>
+#include <nan.h>
+#include "grpc/grpc.h"
+#include "grpc/grpc_security.h"
+
+namespace grpc {
+namespace node {
+
+/* Wrapper class for grpc_server_credentials structs */
+class ServerCredentials : public ::node::ObjectWrap {
+ public:
+ static void Init(v8::Handle<v8::Object> exports);
+ static bool HasInstance(v8::Handle<v8::Value> val);
+ /* Wrap a grpc_server_credentials struct in a javascript object */
+ static v8::Handle<v8::Value> WrapStruct(grpc_server_credentials *credentials);
+
+ /* Returns the grpc_server_credentials struct that this object wraps */
+ grpc_server_credentials *GetWrappedServerCredentials();
+
+ private:
+ explicit ServerCredentials(grpc_server_credentials *credentials);
+ ~ServerCredentials();
+
+ // Prevent copying
+ ServerCredentials(const ServerCredentials &);
+ ServerCredentials &operator=(const ServerCredentials &);
+
+ static NAN_METHOD(New);
+ static NAN_METHOD(CreateSsl);
+ static NAN_METHOD(CreateFake);
+ static v8::Persistent<v8::Function> constructor;
+ // Used for typechecking instances of this javascript class
+ static v8::Persistent<v8::FunctionTemplate> fun_tpl;
+
+ grpc_server_credentials *wrapped_credentials;
+};
+
+} // namespace node
+} // namespace grpc
+
+#endif // NET_GRPC_NODE_SERVER_CREDENTIALS_H_
diff --git a/src/node/surface_client.js b/src/node/surface_client.js
new file mode 100644
index 0000000000..9c40b0a3a0
--- /dev/null
+++ b/src/node/surface_client.js
@@ -0,0 +1,339 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+var _ = require('underscore');
+
+var client = require('./client.js');
+
+var EventEmitter = require('events').EventEmitter;
+
+var stream = require('stream');
+
+var Readable = stream.Readable;
+var Writable = stream.Writable;
+var Duplex = stream.Duplex;
+var util = require('util');
+
+function forwardEvent(fromEmitter, toEmitter, event) {
+ fromEmitter.on(event, function forward() {
+ _.partial(toEmitter.emit, event).apply(toEmitter, arguments);
+ });
+}
+
+util.inherits(ClientReadableObjectStream, Readable);
+
+/**
+ * Class for representing a gRPC server streaming call as a Node stream on the
+ * client side. Extends from stream.Readable.
+ * @constructor
+ * @param {stream} stream Underlying binary Duplex stream for the call
+ * @param {function(Buffer)} deserialize Function for deserializing binary data
+ * @param {object} options Stream options
+ */
+function ClientReadableObjectStream(stream, deserialize, options) {
+ options = _.extend(options, {objectMode: true});
+ Readable.call(this, options);
+ this._stream = stream;
+ var self = this;
+ forwardEvent(stream, this, 'status');
+ forwardEvent(stream, this, 'metadata');
+ this._stream.on('data', function forwardData(chunk) {
+ if (!self.push(deserialize(chunk))) {
+ self._stream.pause();
+ }
+ });
+ this._stream.pause();
+}
+
+util.inherits(ClientWritableObjectStream, Writable);
+
+/**
+ * Class for representing a gRPC client streaming call as a Node stream on the
+ * client side. Extends from stream.Writable.
+ * @constructor
+ * @param {stream} stream Underlying binary Duplex stream for the call
+ * @param {function(*):Buffer} serialize Function for serializing objects
+ * @param {object} options Stream options
+ */
+function ClientWritableObjectStream(stream, serialize, options) {
+ options = _.extend(options, {objectMode: true});
+ Writable.call(this, options);
+ this._stream = stream;
+ this._serialize = serialize;
+ forwardEvent(stream, this, 'status');
+ forwardEvent(stream, this, 'metadata');
+ this.on('finish', function() {
+ this._stream.end();
+ });
+}
+
+
+util.inherits(ClientBidiObjectStream, Duplex);
+
+/**
+ * Class for representing a gRPC bidi streaming call as a Node stream on the
+ * client side. Extends from stream.Duplex.
+ * @constructor
+ * @param {stream} stream Underlying binary Duplex stream for the call
+ * @param {function(*):Buffer} serialize Function for serializing objects
+ * @param {function(Buffer)} deserialize Function for deserializing binary data
+ * @param {object} options Stream options
+ */
+function ClientBidiObjectStream(stream, serialize, deserialize, options) {
+ options = _.extend(options, {objectMode: true});
+ Duplex.call(this, options);
+ this._stream = stream;
+ this._serialize = serialize;
+ var self = this;
+ forwardEvent(stream, this, 'status');
+ forwardEvent(stream, this, 'metadata');
+ this._stream.on('data', function forwardData(chunk) {
+ if (!self.push(deserialize(chunk))) {
+ self._stream.pause();
+ }
+ });
+ this._stream.pause();
+ this.on('finish', function() {
+ this._stream.end();
+ });
+}
+
+/**
+ * _read implementation for both types of streams that allow reading.
+ * @this {ClientReadableObjectStream|ClientBidiObjectStream}
+ * @param {number} size Ignored
+ */
+function _read(size) {
+ this._stream.resume();
+}
+
+/**
+ * See docs for _read
+ */
+ClientReadableObjectStream.prototype._read = _read;
+/**
+ * See docs for _read
+ */
+ClientBidiObjectStream.prototype._read = _read;
+
+/**
+ * _write implementation for both types of streams that allow writing
+ * @this {ClientWritableObjectStream|ClientBidiObjectStream}
+ * @param {*} chunk The value to write to the stream
+ * @param {string} encoding Ignored
+ * @param {function(Error)} callback Callback to call when finished writing
+ */
+function _write(chunk, encoding, callback) {
+ this._stream.write(this._serialize(chunk), encoding, callback);
+}
+
+/**
+ * See docs for _write
+ */
+ClientWritableObjectStream.prototype._write = _write;
+/**
+ * See docs for _write
+ */
+ClientBidiObjectStream.prototype._write = _write;
+
+/**
+ * Get a function that can make unary requests to the specified method.
+ * @param {string} method The name of the method to request
+ * @param {function(*):Buffer} serialize The serialization function for inputs
+ * @param {function(Buffer)} deserialize The deserialization function for
+ * outputs
+ * @return {Function} makeUnaryRequest
+ */
+function makeUnaryRequestFunction(method, serialize, deserialize) {
+ /**
+ * Make a unary request with this method on the given channel with the given
+ * argument, callback, etc.
+ * @param {client.Channel} channel The channel on which to make the request
+ * @param {*} argument The argument to the call. Should be serializable with
+ * serialize
+ * @param {function(?Error, value=)} callback The callback to for when the
+ * response is received
+ * @param {array=} metadata Array of metadata key/value pairs to add to the
+ * call
+ * @param {(number|Date)=} deadline The deadline for processing this request.
+ * Defaults to infinite future
+ * @return {EventEmitter} An event emitter for stream related events
+ */
+ function makeUnaryRequest(channel, argument, callback, metadata, deadline) {
+ var stream = client.makeRequest(channel, method, metadata, deadline);
+ var emitter = new EventEmitter();
+ forwardEvent(stream, emitter, 'status');
+ forwardEvent(stream, emitter, 'metadata');
+ stream.write(serialize(argument));
+ stream.end();
+ stream.on('data', function forwardData(chunk) {
+ try {
+ callback(null, deserialize(chunk));
+ } catch (e) {
+ callback(e);
+ }
+ });
+ return emitter;
+ }
+ return makeUnaryRequest;
+}
+
+/**
+ * Get a function that can make client stream requests to the specified method.
+ * @param {string} method The name of the method to request
+ * @param {function(*):Buffer} serialize The serialization function for inputs
+ * @param {function(Buffer)} deserialize The deserialization function for
+ * outputs
+ * @return {Function} makeClientStreamRequest
+ */
+function makeClientStreamRequestFunction(method, serialize, deserialize) {
+ /**
+ * Make a client stream request with this method on the given channel with the
+ * given callback, etc.
+ * @param {client.Channel} channel The channel on which to make the request
+ * @param {function(?Error, value=)} callback The callback to for when the
+ * response is received
+ * @param {array=} metadata Array of metadata key/value pairs to add to the
+ * call
+ * @param {(number|Date)=} deadline The deadline for processing this request.
+ * Defaults to infinite future
+ * @return {EventEmitter} An event emitter for stream related events
+ */
+ function makeClientStreamRequest(channel, callback, metadata, deadline) {
+ var stream = client.makeRequest(channel, method, metadata, deadline);
+ var obj_stream = new ClientWritableObjectStream(stream, serialize, {});
+ stream.on('data', function forwardData(chunk) {
+ try {
+ callback(null, deserialize(chunk));
+ } catch (e) {
+ callback(e);
+ }
+ });
+ return obj_stream;
+ }
+ return makeClientStreamRequest;
+}
+
+/**
+ * Get a function that can make server stream requests to the specified method.
+ * @param {string} method The name of the method to request
+ * @param {function(*):Buffer} serialize The serialization function for inputs
+ * @param {function(Buffer)} deserialize The deserialization function for
+ * outputs
+ * @return {Function} makeServerStreamRequest
+ */
+function makeServerStreamRequestFunction(method, serialize, deserialize) {
+ /**
+ * Make a server stream request with this method on the given channel with the
+ * given argument, etc.
+ * @param {client.Channel} channel The channel on which to make the request
+ * @param {*} argument The argument to the call. Should be serializable with
+ * serialize
+ * @param {array=} metadata Array of metadata key/value pairs to add to the
+ * call
+ * @param {(number|Date)=} deadline The deadline for processing this request.
+ * Defaults to infinite future
+ * @return {EventEmitter} An event emitter for stream related events
+ */
+ function makeServerStreamRequest(channel, argument, metadata, deadline) {
+ var stream = client.makeRequest(channel, method, metadata, deadline);
+ var obj_stream = new ClientReadableObjectStream(stream, deserialize, {});
+ stream.write(serialize(argument));
+ stream.end();
+ return obj_stream;
+ }
+ return makeServerStreamRequest;
+}
+
+/**
+ * Get a function that can make bidirectional stream requests to the specified
+ * method.
+ * @param {string} method The name of the method to request
+ * @param {function(*):Buffer} serialize The serialization function for inputs
+ * @param {function(Buffer)} deserialize The deserialization function for
+ * outputs
+ * @return {Function} makeBidiStreamRequest
+ */
+function makeBidiStreamRequestFunction(method, serialize, deserialize) {
+ /**
+ * Make a bidirectional stream request with this method on the given channel.
+ * @param {client.Channel} channel The channel on which to make the request
+ * @param {array=} metadata Array of metadata key/value pairs to add to the
+ * call
+ * @param {(number|Date)=} deadline The deadline for processing this request.
+ * Defaults to infinite future
+ * @return {EventEmitter} An event emitter for stream related events
+ */
+ function makeBidiStreamRequest(channel, metadata, deadline) {
+ var stream = client.makeRequest(channel, method, metadata, deadline);
+ var obj_stream = new ClientBidiObjectStream(stream,
+ serialize,
+ deserialize,
+ {});
+ return obj_stream;
+ }
+ return makeBidiStreamRequest;
+}
+
+/**
+ * See docs for makeUnaryRequestFunction
+ */
+exports.makeUnaryRequestFunction = makeUnaryRequestFunction;
+
+/**
+ * See docs for makeClientStreamRequestFunction
+ */
+exports.makeClientStreamRequestFunction = makeClientStreamRequestFunction;
+
+/**
+ * See docs for makeServerStreamRequestFunction
+ */
+exports.makeServerStreamRequestFunction = makeServerStreamRequestFunction;
+
+/**
+ * See docs for makeBidiStreamRequestFunction
+ */
+exports.makeBidiStreamRequestFunction = makeBidiStreamRequestFunction;
+
+/**
+ * See docs for client.Channel
+ */
+exports.Channel = client.Channel;
+/**
+ * See docs for client.status
+ */
+exports.status = client.status;
+/**
+ * See docs for client.callError
+ */
+exports.callError = client.callError;
diff --git a/src/node/surface_server.js b/src/node/surface_server.js
new file mode 100644
index 0000000000..295c1ccaff
--- /dev/null
+++ b/src/node/surface_server.js
@@ -0,0 +1,358 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+var _ = require('underscore');
+
+var Server = require('./server.js');
+
+var stream = require('stream');
+
+var Readable = stream.Readable;
+var Writable = stream.Writable;
+var Duplex = stream.Duplex;
+var util = require('util');
+
+util.inherits(ServerReadableObjectStream, Readable);
+
+/**
+ * Class for representing a gRPC client streaming call as a Node stream on the
+ * server side. Extends from stream.Readable.
+ * @constructor
+ * @param {stream} stream Underlying binary Duplex stream for the call
+ * @param {function(Buffer)} deserialize Function for deserializing binary data
+ * @param {object} options Stream options
+ */
+function ServerReadableObjectStream(stream, deserialize, options) {
+ options = _.extend(options, {objectMode: true});
+ Readable.call(this, options);
+ this._stream = stream;
+ Object.defineProperty(this, 'cancelled', {
+ get: function() { return stream.cancelled; }
+ });
+ var self = this;
+ this._stream.on('data', function forwardData(chunk) {
+ if (!self.push(deserialize(chunk))) {
+ self._stream.pause();
+ }
+ });
+ this._stream.on('end', function forwardEnd() {
+ self.push(null);
+ });
+ this._stream.pause();
+}
+
+util.inherits(ServerWritableObjectStream, Writable);
+
+/**
+ * Class for representing a gRPC server streaming call as a Node stream on the
+ * server side. Extends from stream.Writable.
+ * @constructor
+ * @param {stream} stream Underlying binary Duplex stream for the call
+ * @param {function(*):Buffer} serialize Function for serializing objects
+ * @param {object} options Stream options
+ */
+function ServerWritableObjectStream(stream, serialize, options) {
+ options = _.extend(options, {objectMode: true});
+ Writable.call(this, options);
+ this._stream = stream;
+ this._serialize = serialize;
+ this.on('finish', function() {
+ this._stream.end();
+ });
+}
+
+util.inherits(ServerBidiObjectStream, Duplex);
+
+/**
+ * Class for representing a gRPC bidi streaming call as a Node stream on the
+ * server side. Extends from stream.Duplex.
+ * @constructor
+ * @param {stream} stream Underlying binary Duplex stream for the call
+ * @param {function(*):Buffer} serialize Function for serializing objects
+ * @param {function(Buffer)} deserialize Function for deserializing binary data
+ * @param {object} options Stream options
+ */
+function ServerBidiObjectStream(stream, serialize, deserialize, options) {
+ options = _.extend(options, {objectMode: true});
+ Duplex.call(this, options);
+ this._stream = stream;
+ this._serialize = serialize;
+ var self = this;
+ this._stream.on('data', function forwardData(chunk) {
+ if (!self.push(deserialize(chunk))) {
+ self._stream.pause();
+ }
+ });
+ this._stream.on('end', function forwardEnd() {
+ self.push(null);
+ });
+ this._stream.pause();
+ this.on('finish', function() {
+ this._stream.end();
+ });
+}
+
+/**
+ * _read implementation for both types of streams that allow reading.
+ * @this {ServerReadableObjectStream|ServerBidiObjectStream}
+ * @param {number} size Ignored
+ */
+function _read(size) {
+ this._stream.resume();
+}
+
+/**
+ * See docs for _read
+ */
+ServerReadableObjectStream.prototype._read = _read;
+/**
+ * See docs for _read
+ */
+ServerBidiObjectStream.prototype._read = _read;
+
+/**
+ * _write implementation for both types of streams that allow writing
+ * @this {ServerWritableObjectStream|ServerBidiObjectStream}
+ * @param {*} chunk The value to write to the stream
+ * @param {string} encoding Ignored
+ * @param {function(Error)} callback Callback to call when finished writing
+ */
+function _write(chunk, encoding, callback) {
+ this._stream.write(this._serialize(chunk), encoding, callback);
+}
+
+/**
+ * See docs for _write
+ */
+ServerWritableObjectStream.prototype._write = _write;
+/**
+ * See docs for _write
+ */
+ServerBidiObjectStream.prototype._write = _write;
+
+/**
+ * Creates a binary stream handler function from a unary handler function
+ * @param {function(Object, function(Error, *))} handler Unary call handler
+ * @param {function(*):Buffer} serialize Serialization function
+ * @param {function(Buffer):*} deserialize Deserialization function
+ * @return {function(stream)} Binary stream handler
+ */
+function makeUnaryHandler(handler, serialize, deserialize) {
+ /**
+ * Handles a stream by reading a single data value, passing it to the handler,
+ * and writing the response back to the stream.
+ * @param {stream} stream Binary data stream
+ */
+ return function handleUnaryCall(stream) {
+ stream.on('data', function handleUnaryData(value) {
+ var call = {request: deserialize(value)};
+ Object.defineProperty(call, 'cancelled', {
+ get: function() { return stream.cancelled;}
+ });
+ handler(call, function sendUnaryData(err, value) {
+ if (err) {
+ stream.emit('error', err);
+ } else {
+ stream.write(serialize(value));
+ stream.end();
+ }
+ });
+ });
+ };
+}
+
+/**
+ * Creates a binary stream handler function from a client stream handler
+ * function
+ * @param {function(Readable, function(Error, *))} handler Client stream call
+ * handler
+ * @param {function(*):Buffer} serialize Serialization function
+ * @param {function(Buffer):*} deserialize Deserialization function
+ * @return {function(stream)} Binary stream handler
+ */
+function makeClientStreamHandler(handler, serialize, deserialize) {
+ /**
+ * Handles a stream by passing a deserializing stream to the handler and
+ * writing the response back to the stream.
+ * @param {stream} stream Binary data stream
+ */
+ return function handleClientStreamCall(stream) {
+ var object_stream = new ServerReadableObjectStream(stream, deserialize, {});
+ handler(object_stream, function sendClientStreamData(err, value) {
+ if (err) {
+ stream.emit('error', err);
+ } else {
+ stream.write(serialize(value));
+ stream.end();
+ }
+ });
+ };
+}
+
+/**
+ * Creates a binary stream handler function from a server stream handler
+ * function
+ * @param {function(Writable)} handler Server stream call handler
+ * @param {function(*):Buffer} serialize Serialization function
+ * @param {function(Buffer):*} deserialize Deserialization function
+ * @return {function(stream)} Binary stream handler
+ */
+function makeServerStreamHandler(handler, serialize, deserialize) {
+ /**
+ * Handles a stream by attaching it to a serializing stream, and passing it to
+ * the handler.
+ * @param {stream} stream Binary data stream
+ */
+ return function handleServerStreamCall(stream) {
+ stream.on('data', function handleClientData(value) {
+ var object_stream = new ServerWritableObjectStream(stream,
+ serialize,
+ {});
+ object_stream.request = deserialize(value);
+ handler(object_stream);
+ });
+ };
+}
+
+/**
+ * Creates a binary stream handler function from a bidi stream handler function
+ * @param {function(Duplex)} handler Unary call handler
+ * @param {function(*):Buffer} serialize Serialization function
+ * @param {function(Buffer):*} deserialize Deserialization function
+ * @return {function(stream)} Binary stream handler
+ */
+function makeBidiStreamHandler(handler, serialize, deserialize) {
+ /**
+ * Handles a stream by wrapping it in a serializing and deserializing object
+ * stream, and passing it to the handler.
+ * @param {stream} stream Binary data stream
+ */
+ return function handleBidiStreamCall(stream) {
+ var object_stream = new ServerBidiObjectStream(stream,
+ serialize,
+ deserialize,
+ {});
+ handler(object_stream);
+ };
+}
+
+/**
+ * Map with short names for each of the handler maker functions. Used in
+ * makeServerConstructor
+ */
+var handler_makers = {
+ unary: makeUnaryHandler,
+ server_stream: makeServerStreamHandler,
+ client_stream: makeClientStreamHandler,
+ bidi: makeBidiStreamHandler
+};
+
+/**
+ * Creates a constructor for servers with a service defined by the methods
+ * object. The methods object has string keys and values of this form:
+ * {serialize: function, deserialize: function, client_stream: bool,
+ * server_stream: bool}
+ * @param {Object} methods Method descriptor for each method the server should
+ * expose
+ * @param {string} prefix The prefex to prepend to each method name
+ * @return {function(Object, Object)} New server constructor
+ */
+function makeServerConstructor(methods, prefix) {
+ /**
+ * Create a server with the given handlers for all of the methods.
+ * @constructor
+ * @param {Object} handlers Map from method names to method handlers.
+ * @param {Object} options Options to pass to the underlying server
+ */
+ function SurfaceServer(handlers, options) {
+ var server = new Server(options);
+ this.inner_server = server;
+ _.each(handlers, function(handler, name) {
+ var method = methods[name];
+ var method_type;
+ if (method.client_stream) {
+ if (method.server_stream) {
+ method_type = 'bidi';
+ } else {
+ method_type = 'client_stream';
+ }
+ } else {
+ if (method.server_stream) {
+ method_type = 'server_stream';
+ } else {
+ method_type = 'unary';
+ }
+ }
+ var binary_handler = handler_makers[method_type](handler,
+ method.serialize,
+ method.deserialize);
+ server.register('' + prefix + name, binary_handler);
+ }, this);
+ }
+
+ /**
+ * Binds the server to the given port, with SSL enabled if secure is specified
+ * @param {string} port The port that the server should bind on, in the format
+ * "address:port"
+ * @param {boolean=} secure Whether the server should open a secure port
+ * @return {SurfaceServer} this
+ */
+ SurfaceServer.prototype.bind = function(port, secure) {
+ this.inner_server.bind(port, secure);
+ return this;
+ };
+
+ /**
+ * Starts the server listening on any bound ports
+ * @return {SurfaceServer} this
+ */
+ SurfaceServer.prototype.listen = function() {
+ this.inner_server.start();
+ return this;
+ };
+
+ /**
+ * Shuts the server down; tells it to stop listening for new requests and to
+ * kill old requests.
+ */
+ SurfaceServer.prototype.shutdown = function() {
+ this.inner_server.shutdown();
+ };
+
+ return SurfaceServer;
+}
+
+/**
+ * See documentation for makeServerConstructor
+ */
+exports.makeServerConstructor = makeServerConstructor;
diff --git a/src/node/tag.cc b/src/node/tag.cc
new file mode 100644
index 0000000000..dc8e523e12
--- /dev/null
+++ b/src/node/tag.cc
@@ -0,0 +1,101 @@
+/*
+ *
+ * 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 <stdlib.h>
+#include <node.h>
+#include <nan.h>
+#include "tag.h"
+
+namespace grpc {
+namespace node {
+
+using v8::Handle;
+using v8::HandleScope;
+using v8::Persistent;
+using v8::Value;
+
+struct tag {
+ tag(Persistent<Value> *tag, Persistent<Value> *call)
+ : persist_tag(tag), persist_call(call) {}
+
+ ~tag() {
+ persist_tag->Dispose();
+ if (persist_call != NULL) {
+ persist_call->Dispose();
+ }
+ }
+ Persistent<Value> *persist_tag;
+ Persistent<Value> *persist_call;
+};
+
+void *CreateTag(Handle<Value> tag, Handle<Value> call) {
+ NanScope();
+ Persistent<Value> *persist_tag = new Persistent<Value>();
+ NanAssignPersistent(*persist_tag, tag);
+ Persistent<Value> *persist_call;
+ if (call->IsNull() || call->IsUndefined()) {
+ persist_call = NULL;
+ } else {
+ persist_call = new Persistent<Value>();
+ NanAssignPersistent(*persist_call, call);
+ }
+ struct tag *tag_struct = new struct tag(persist_tag, persist_call);
+ return reinterpret_cast<void *>(tag_struct);
+}
+
+Handle<Value> GetTagHandle(void *tag) {
+ NanEscapableScope();
+ struct tag *tag_struct = reinterpret_cast<struct tag *>(tag);
+ Handle<Value> tag_value = NanNew<Value>(*tag_struct->persist_tag);
+ return NanEscapeScope(tag_value);
+}
+
+bool TagHasCall(void *tag) {
+ struct tag *tag_struct = reinterpret_cast<struct tag *>(tag);
+ return tag_struct->persist_call != NULL;
+}
+
+Handle<Value> TagGetCall(void *tag) {
+ NanEscapableScope();
+ struct tag *tag_struct = reinterpret_cast<struct tag *>(tag);
+ if (tag_struct->persist_call == NULL) {
+ return NanEscapeScope(NanNull());
+ }
+ Handle<Value> call_value = NanNew<Value>(*tag_struct->persist_call);
+ return NanEscapeScope(call_value);
+}
+
+void DestroyTag(void *tag) { delete reinterpret_cast<struct tag *>(tag); }
+
+} // namespace node
+} // namespace grpc
diff --git a/src/node/tag.h b/src/node/tag.h
new file mode 100644
index 0000000000..bdb09252d9
--- /dev/null
+++ b/src/node/tag.h
@@ -0,0 +1,59 @@
+/*
+ *
+ * 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 NET_GRPC_NODE_TAG_H_
+#define NET_GRPC_NODE_TAG_H_
+
+#include <node.h>
+
+namespace grpc {
+namespace node {
+
+/* Create a void* tag that can be passed to various grpc_call functions from
+ a javascript value and the javascript wrapper for the call. The call can be
+ null. */
+void *CreateTag(v8::Handle<v8::Value> tag, v8::Handle<v8::Value> call);
+/* Return the javascript value stored in the tag */
+v8::Handle<v8::Value> GetTagHandle(void *tag);
+/* Returns true if the call was set (non-null) when the tag was created */
+bool TagHasCall(void *tag);
+/* Returns the javascript wrapper for the call associated with this tag */
+v8::Handle<v8::Value> TagGetCall(void *call);
+/* Destroy the tag and all resources it is holding. It is illegal to call any
+ of these other functions on a tag after it has been destroyed. */
+void DestroyTag(void *tag);
+
+} // namespace node
+} // namespace grpc
+
+#endif // NET_GRPC_NODE_TAG_H_
diff --git a/src/node/test/call_test.js b/src/node/test/call_test.js
new file mode 100644
index 0000000000..e6dc9664f1
--- /dev/null
+++ b/src/node/test/call_test.js
@@ -0,0 +1,202 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+var assert = require('assert');
+var grpc = require('bindings')('grpc.node');
+
+var channel = new grpc.Channel('localhost:7070');
+
+/**
+ * Helper function to return an absolute deadline given a relative timeout in
+ * seconds.
+ * @param {number} timeout_secs The number of seconds to wait before timing out
+ * @return {Date} A date timeout_secs in the future
+ */
+function getDeadline(timeout_secs) {
+ var deadline = new Date();
+ deadline.setSeconds(deadline.getSeconds() + timeout_secs);
+ return deadline;
+}
+
+describe('call', function() {
+ describe('constructor', function() {
+ it('should reject anything less than 3 arguments', function() {
+ assert.throws(function() {
+ new grpc.Call();
+ }, TypeError);
+ assert.throws(function() {
+ new grpc.Call(channel);
+ }, TypeError);
+ assert.throws(function() {
+ new grpc.Call(channel, 'method');
+ }, TypeError);
+ });
+ it('should succeed with a Channel, a string, and a date or number',
+ function() {
+ assert.doesNotThrow(function() {
+ new grpc.Call(channel, 'method', new Date());
+ });
+ assert.doesNotThrow(function() {
+ new grpc.Call(channel, 'method', 0);
+ });
+ });
+ it('should fail with a closed channel', function() {
+ var local_channel = new grpc.Channel('hostname');
+ local_channel.close();
+ assert.throws(function() {
+ new grpc.Call(channel, 'method');
+ });
+ });
+ it('should fail with other types', function() {
+ assert.throws(function() {
+ new grpc.Call({}, 'method', 0);
+ }, TypeError);
+ assert.throws(function() {
+ new grpc.Call(channel, null, 0);
+ }, TypeError);
+ assert.throws(function() {
+ new grpc.Call(channel, 'method', 'now');
+ }, TypeError);
+ });
+ });
+ describe('addMetadata', function() {
+ it('should succeed with objects containing keys and values', function() {
+ var call = new grpc.Call(channel, 'method', getDeadline(1));
+ assert.doesNotThrow(function() {
+ call.addMetadata();
+ });
+ assert.doesNotThrow(function() {
+ call.addMetadata({'key' : 'key',
+ 'value' : new Buffer('value')});
+ });
+ assert.doesNotThrow(function() {
+ call.addMetadata({'key' : 'key1',
+ 'value' : new Buffer('value1')},
+ {'key' : 'key2',
+ 'value' : new Buffer('value2')});
+ });
+ });
+ it('should fail with other parameter types', function() {
+ var call = new grpc.Call(channel, 'method', getDeadline(1));
+ assert.throws(function() {
+ call.addMetadata(null);
+ }, TypeError);
+ assert.throws(function() {
+ call.addMetadata('value');
+ }, TypeError);
+ assert.throws(function() {
+ call.addMetadata(5);
+ }, TypeError);
+ });
+ it('should fail if startInvoke was already called', function(done) {
+ var call = new grpc.Call(channel, 'method', getDeadline(1));
+ call.startInvoke(function() {},
+ function() {},
+ function() {done();},
+ 0);
+ assert.throws(function() {
+ call.addMetadata({'key' : 'key', 'value' : new Buffer('value') });
+ }, function(err) {
+ return err.code === grpc.callError.ALREADY_INVOKED;
+ });
+ // Cancel to speed up the test
+ call.cancel();
+ });
+ });
+ describe('startInvoke', function() {
+ it('should fail with fewer than 4 arguments', function() {
+ var call = new grpc.Call(channel, 'method', getDeadline(1));
+ assert.throws(function() {
+ call.startInvoke();
+ }, TypeError);
+ assert.throws(function() {
+ call.startInvoke(function() {});
+ }, TypeError);
+ assert.throws(function() {
+ call.startInvoke(function() {},
+ function() {});
+ }, TypeError);
+ assert.throws(function() {
+ call.startInvoke(function() {},
+ function() {},
+ function() {});
+ }, TypeError);
+ });
+ it('should work with 3 args and an int', function(done) {
+ assert.doesNotThrow(function() {
+ var call = new grpc.Call(channel, 'method', getDeadline(1));
+ call.startInvoke(function() {},
+ function() {},
+ function() {done();},
+ 0);
+ // Cancel to speed up the test
+ call.cancel();
+ });
+ });
+ it('should reject incorrectly typed arguments', function() {
+ var call = new grpc.Call(channel, 'method', getDeadline(1));
+ assert.throws(function() {
+ call.startInvoke(0, 0, 0, 0);
+ }, TypeError);
+ assert.throws(function() {
+ call.startInvoke(function() {},
+ function() {},
+ function() {}, 'test');
+ });
+ });
+ });
+ describe('serverAccept', function() {
+ it('should fail with fewer than 1 argument1', function() {
+ var call = new grpc.Call(channel, 'method', getDeadline(1));
+ assert.throws(function() {
+ call.serverAccept();
+ }, TypeError);
+ });
+ it('should return an error when called on a client Call', function() {
+ var call = new grpc.Call(channel, 'method', getDeadline(1));
+ assert.throws(function() {
+ call.serverAccept(function() {});
+ }, function(err) {
+ return err.code === grpc.callError.NOT_ON_CLIENT;
+ });
+ });
+ });
+ describe('cancel', function() {
+ it('should succeed', function() {
+ var call = new grpc.Call(channel, 'method', getDeadline(1));
+ assert.doesNotThrow(function() {
+ call.cancel();
+ });
+ });
+ });
+});
diff --git a/src/node/test/channel_test.js b/src/node/test/channel_test.js
new file mode 100644
index 0000000000..4d8cfc4d89
--- /dev/null
+++ b/src/node/test/channel_test.js
@@ -0,0 +1,88 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+var assert = require('assert');
+var grpc = require('bindings')('grpc.node');
+
+describe('channel', function() {
+ describe('constructor', function() {
+ it('should require a string for the first argument', function() {
+ assert.doesNotThrow(function() {
+ new grpc.Channel('hostname');
+ });
+ assert.throws(function() {
+ new grpc.Channel();
+ }, TypeError);
+ assert.throws(function() {
+ new grpc.Channel(5);
+ });
+ });
+ it('should accept an object for the second parameter', function() {
+ assert.doesNotThrow(function() {
+ new grpc.Channel('hostname', {});
+ });
+ assert.throws(function() {
+ new grpc.Channel('hostname', 5);
+ });
+ });
+ it('should only accept objects with string or int values', function() {
+ assert.doesNotThrow(function() {
+ new grpc.Channel('hostname', {'key' : 'value'});
+ });
+ assert.doesNotThrow(function() {
+ new grpc.Channel('hostname', {'key' : 5});
+ });
+ assert.throws(function() {
+ new grpc.Channel('hostname', {'key' : null});
+ });
+ assert.throws(function() {
+ new grpc.Channel('hostname', {'key' : new Date()});
+ });
+ });
+ });
+ describe('close', function() {
+ it('should succeed silently', function() {
+ var channel = new grpc.Channel('hostname', {});
+ assert.doesNotThrow(function() {
+ channel.close();
+ });
+ });
+ it('should be idempotent', function() {
+ var channel = new grpc.Channel('hostname', {});
+ assert.doesNotThrow(function() {
+ channel.close();
+ channel.close();
+ });
+ });
+ });
+});
diff --git a/src/node/test/client_server_test.js b/src/node/test/client_server_test.js
new file mode 100644
index 0000000000..534a5c464f
--- /dev/null
+++ b/src/node/test/client_server_test.js
@@ -0,0 +1,183 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+var assert = require('assert');
+var fs = require('fs');
+var path = require('path');
+var grpc = require('bindings')('grpc.node');
+var Server = require('../server');
+var client = require('../client');
+var port_picker = require('../port_picker');
+var common = require('../common');
+var _ = require('highland');
+
+var ca_path = path.join(__dirname, 'data/ca.pem');
+
+var key_path = path.join(__dirname, 'data/server1.key');
+
+var pem_path = path.join(__dirname, 'data/server1.pem');
+
+/**
+ * Helper function to return an absolute deadline given a relative timeout in
+ * seconds.
+ * @param {number} timeout_secs The number of seconds to wait before timing out
+ * @return {Date} A date timeout_secs in the future
+ */
+function getDeadline(timeout_secs) {
+ var deadline = new Date();
+ deadline.setSeconds(deadline.getSeconds() + timeout_secs);
+ return deadline;
+}
+
+/**
+ * Responds to every request with the same data as a response
+ * @param {Stream} stream
+ */
+function echoHandler(stream) {
+ stream.pipe(stream);
+}
+
+/**
+ * Responds to every request with an error status
+ * @param {Stream} stream
+ */
+function errorHandler(stream) {
+ throw {
+ 'code' : grpc.status.UNIMPLEMENTED,
+ 'details' : 'error details'
+ };
+}
+
+describe('echo client', function() {
+ it('should receive echo responses', function(done) {
+ port_picker.nextAvailablePort(function(port) {
+ var server = new Server();
+ server.bind(port);
+ server.register('echo', echoHandler);
+ server.start();
+
+ var messages = ['echo1', 'echo2', 'echo3', 'echo4'];
+ var channel = new grpc.Channel(port);
+ var stream = client.makeRequest(
+ channel,
+ 'echo');
+ _(messages).map(function(val) {
+ return new Buffer(val);
+ }).pipe(stream);
+ var index = 0;
+ stream.on('data', function(chunk) {
+ assert.equal(messages[index], chunk.toString());
+ index += 1;
+ });
+ stream.on('end', function() {
+ server.shutdown();
+ done();
+ });
+ });
+ });
+ it('should get an error status that the server throws', function(done) {
+ port_picker.nextAvailablePort(function(port) {
+ var server = new Server();
+ server.bind(port);
+ server.register('error', errorHandler);
+ server.start();
+
+ var channel = new grpc.Channel(port);
+ var stream = client.makeRequest(
+ channel,
+ 'error',
+ null,
+ getDeadline(1));
+
+ stream.on('data', function() {});
+ stream.write(new Buffer('test'));
+ stream.end();
+ stream.on('status', function(status) {
+ assert.equal(status.code, grpc.status.UNIMPLEMENTED);
+ assert.equal(status.details, 'error details');
+ server.shutdown();
+ done();
+ });
+
+ });
+ });
+});
+/* TODO(mlumish): explore options for reducing duplication between this test
+ * and the insecure echo client test */
+describe('secure echo client', function() {
+ it('should recieve echo responses', function(done) {
+ port_picker.nextAvailablePort(function(port) {
+ fs.readFile(ca_path, function(err, ca_data) {
+ assert.ifError(err);
+ fs.readFile(key_path, function(err, key_data) {
+ assert.ifError(err);
+ fs.readFile(pem_path, function(err, pem_data) {
+ assert.ifError(err);
+ var creds = grpc.Credentials.createSsl(ca_data);
+ var server_creds = grpc.ServerCredentials.createSsl(null,
+ key_data,
+ pem_data);
+
+ var server = new Server({'credentials' : server_creds});
+ server.bind(port, true);
+ server.register('echo', echoHandler);
+ server.start();
+
+ var messages = ['echo1', 'echo2', 'echo3', 'echo4'];
+ var channel = new grpc.Channel(port, {
+ 'grpc.ssl_target_name_override' : 'foo.test.google.com',
+ 'credentials' : creds
+ });
+ var stream = client.makeRequest(
+ channel,
+ 'echo');
+
+ _(messages).map(function(val) {
+ return new Buffer(val);
+ }).pipe(stream);
+ var index = 0;
+ stream.on('data', function(chunk) {
+ assert.equal(messages[index], chunk.toString());
+ index += 1;
+ });
+ stream.on('end', function() {
+ server.shutdown();
+ done();
+ });
+ });
+
+ });
+ });
+ });
+ });
+});
diff --git a/src/node/test/constant_test.js b/src/node/test/constant_test.js
new file mode 100644
index 0000000000..f65eea3cff
--- /dev/null
+++ b/src/node/test/constant_test.js
@@ -0,0 +1,130 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+var assert = require('assert');
+var grpc = require('bindings')('grpc.node');
+
+/**
+ * List of all status names
+ * @const
+ * @type {Array.<string>}
+ */
+var statusNames = [
+ 'OK',
+ 'CANCELLED',
+ 'UNKNOWN',
+ 'INVALID_ARGUMENT',
+ 'DEADLINE_EXCEEDED',
+ 'NOT_FOUND',
+ 'ALREADY_EXISTS',
+ 'PERMISSION_DENIED',
+ 'UNAUTHENTICATED',
+ 'RESOURCE_EXHAUSTED',
+ 'FAILED_PRECONDITION',
+ 'ABORTED',
+ 'OUT_OF_RANGE',
+ 'UNIMPLEMENTED',
+ 'INTERNAL',
+ 'UNAVAILABLE',
+ 'DATA_LOSS'
+];
+
+/**
+ * List of all call error names
+ * @const
+ * @type {Array.<string>}
+ */
+var callErrorNames = [
+ 'OK',
+ 'ERROR',
+ 'NOT_ON_SERVER',
+ 'NOT_ON_CLIENT',
+ 'ALREADY_INVOKED',
+ 'NOT_INVOKED',
+ 'ALREADY_FINISHED',
+ 'TOO_MANY_OPERATIONS',
+ 'INVALID_FLAGS'
+];
+
+/**
+ * List of all op error names
+ * @const
+ * @type {Array.<string>}
+ */
+var opErrorNames = [
+ 'OK',
+ 'ERROR'
+];
+
+/**
+ * List of all completion type names
+ * @const
+ * @type {Array.<string>}
+ */
+var completionTypeNames = [
+ 'QUEUE_SHUTDOWN',
+ 'READ',
+ 'INVOKE_ACCEPTED',
+ 'WRITE_ACCEPTED',
+ 'FINISH_ACCEPTED',
+ 'CLIENT_METADATA_READ',
+ 'FINISHED',
+ 'SERVER_RPC_NEW'
+];
+
+describe('constants', function() {
+ it('should have all of the status constants', function() {
+ for (var i = 0; i < statusNames.length; i++) {
+ assert(grpc.status.hasOwnProperty(statusNames[i]),
+ 'status missing: ' + statusNames[i]);
+ }
+ });
+ it('should have all of the call errors', function() {
+ for (var i = 0; i < callErrorNames.length; i++) {
+ assert(grpc.callError.hasOwnProperty(callErrorNames[i]),
+ 'call error missing: ' + callErrorNames[i]);
+ }
+ });
+ it('should have all of the op errors', function() {
+ for (var i = 0; i < opErrorNames.length; i++) {
+ assert(grpc.opError.hasOwnProperty(opErrorNames[i]),
+ 'op error missing: ' + opErrorNames[i]);
+ }
+ });
+ it('should have all of the completion types', function() {
+ for (var i = 0; i < completionTypeNames.length; i++) {
+ assert(grpc.completionType.hasOwnProperty(completionTypeNames[i]),
+ 'completion type missing: ' + completionTypeNames[i]);
+ }
+ });
+});
diff --git a/src/node/test/data/README b/src/node/test/data/README
new file mode 100644
index 0000000000..888d95b900
--- /dev/null
+++ b/src/node/test/data/README
@@ -0,0 +1 @@
+CONFIRMEDTESTKEY
diff --git a/src/node/test/data/ca.pem b/src/node/test/data/ca.pem
new file mode 100644
index 0000000000..6c8511a73c
--- /dev/null
+++ b/src/node/test/data/ca.pem
@@ -0,0 +1,15 @@
+-----BEGIN CERTIFICATE-----
+MIICSjCCAbOgAwIBAgIJAJHGGR4dGioHMA0GCSqGSIb3DQEBCwUAMFYxCzAJBgNV
+BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX
+aWRnaXRzIFB0eSBMdGQxDzANBgNVBAMTBnRlc3RjYTAeFw0xNDExMTEyMjMxMjla
+Fw0yNDExMDgyMjMxMjlaMFYxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0
+YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxDzANBgNVBAMT
+BnRlc3RjYTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwEDfBV5MYdlHVHJ7
++L4nxrZy7mBfAVXpOc5vMYztssUI7mL2/iYujiIXM+weZYNTEpLdjyJdu7R5gGUu
+g1jSVK/EPHfc74O7AyZU34PNIP4Sh33N+/A5YexrNgJlPY+E3GdVYi4ldWJjgkAd
+Qah2PH5ACLrIIC6tRka9hcaBlIECAwEAAaMgMB4wDAYDVR0TBAUwAwEB/zAOBgNV
+HQ8BAf8EBAMCAgQwDQYJKoZIhvcNAQELBQADgYEAHzC7jdYlzAVmddi/gdAeKPau
+sPBG/C2HCWqHzpCUHcKuvMzDVkY/MP2o6JIW2DBbY64bO/FceExhjcykgaYtCH/m
+oIU63+CFOTtR7otyQAWHqXa7q4SbCDlG7DyRFxqG0txPtGvy12lgldA2+RgcigQG
+Dfcog5wrJytaQ6UA0wE=
+-----END CERTIFICATE-----
diff --git a/src/node/test/data/server1.key b/src/node/test/data/server1.key
new file mode 100644
index 0000000000..143a5b8765
--- /dev/null
+++ b/src/node/test/data/server1.key
@@ -0,0 +1,16 @@
+-----BEGIN PRIVATE KEY-----
+MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAOHDFScoLCVJpYDD
+M4HYtIdV6Ake/sMNaaKdODjDMsux/4tDydlumN+fm+AjPEK5GHhGn1BgzkWF+slf
+3BxhrA/8dNsnunstVA7ZBgA/5qQxMfGAq4wHNVX77fBZOgp9VlSMVfyd9N8YwbBY
+AckOeUQadTi2X1S6OgJXgQ0m3MWhAgMBAAECgYAn7qGnM2vbjJNBm0VZCkOkTIWm
+V10okw7EPJrdL2mkre9NasghNXbE1y5zDshx5Nt3KsazKOxTT8d0Jwh/3KbaN+YY
+tTCbKGW0pXDRBhwUHRcuRzScjli8Rih5UOCiZkhefUTcRb6xIhZJuQy71tjaSy0p
+dHZRmYyBYO2YEQ8xoQJBAPrJPhMBkzmEYFtyIEqAxQ/o/A6E+E4w8i+KM7nQCK7q
+K4JXzyXVAjLfyBZWHGM2uro/fjqPggGD6QH1qXCkI4MCQQDmdKeb2TrKRh5BY1LR
+81aJGKcJ2XbcDu6wMZK4oqWbTX2KiYn9GB0woM6nSr/Y6iy1u145YzYxEV/iMwff
+DJULAkB8B2MnyzOg0pNFJqBJuH29bKCcHa8gHJzqXhNO5lAlEbMK95p/P2Wi+4Hd
+aiEIAF1BF326QJcvYKmwSmrORp85AkAlSNxRJ50OWrfMZnBgzVjDx3xG6KsFQVk2
+ol6VhqL6dFgKUORFUWBvnKSyhjJxurlPEahV6oo6+A+mPhFY8eUvAkAZQyTdupP3
+XEFQKctGz+9+gKkemDp7LBBMEMBXrGTLPhpEfcjv/7KPdnFHYmhYeBTBnuVmTVWe
+F98XJ7tIFfJq
+-----END PRIVATE KEY-----
diff --git a/src/node/test/data/server1.pem b/src/node/test/data/server1.pem
new file mode 100644
index 0000000000..8e582e571f
--- /dev/null
+++ b/src/node/test/data/server1.pem
@@ -0,0 +1,16 @@
+-----BEGIN CERTIFICATE-----
+MIICmzCCAgSgAwIBAgIBAzANBgkqhkiG9w0BAQUFADBWMQswCQYDVQQGEwJBVTET
+MBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQ
+dHkgTHRkMQ8wDQYDVQQDDAZ0ZXN0Y2EwHhcNMTQwNzIyMDYwMDU3WhcNMjQwNzE5
+MDYwMDU3WjBkMQswCQYDVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNV
+BAcTB0NoaWNhZ28xFDASBgNVBAoTC0dvb2dsZSBJbmMuMRowGAYDVQQDFBEqLnRl
+c3QuZ29vZ2xlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA4cMVJygs
+JUmlgMMzgdi0h1XoCR7+ww1pop04OMMyy7H/i0PJ2W6Y35+b4CM8QrkYeEafUGDO
+RYX6yV/cHGGsD/x02ye6ey1UDtkGAD/mpDEx8YCrjAc1Vfvt8Fk6Cn1WVIxV/J30
+3xjBsFgByQ55RBp1OLZfVLo6AleBDSbcxaECAwEAAaNrMGkwCQYDVR0TBAIwADAL
+BgNVHQ8EBAMCBeAwTwYDVR0RBEgwRoIQKi50ZXN0Lmdvb2dsZS5mcoIYd2F0ZXJ6
+b29pLnRlc3QuZ29vZ2xlLmJlghIqLnRlc3QueW91dHViZS5jb22HBMCoAQMwDQYJ
+KoZIhvcNAQEFBQADgYEAM2Ii0LgTGbJ1j4oqX9bxVcxm+/R5Yf8oi0aZqTJlnLYS
+wXcBykxTx181s7WyfJ49WwrYXo78zTDAnf1ma0fPq3e4mpspvyndLh1a+OarHa1e
+aT0DIIYk7qeEa1YcVljx2KyLd0r1BBAfrwyGaEPVeJQVYWaOJRU2we/KD4ojf9s=
+-----END CERTIFICATE-----
diff --git a/src/node/test/end_to_end_test.js b/src/node/test/end_to_end_test.js
new file mode 100644
index 0000000000..40bb5f3bbd
--- /dev/null
+++ b/src/node/test/end_to_end_test.js
@@ -0,0 +1,201 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+var assert = require('assert');
+var grpc = require('bindings')('grpc.node');
+var port_picker = require('../port_picker');
+
+/**
+ * This is used for testing functions with multiple asynchronous calls that
+ * can happen in different orders. This should be passed the number of async
+ * function invocations that can occur last, and each of those should call this
+ * function's return value
+ * @param {function()} done The function that should be called when a test is
+ * complete.
+ * @param {number} count The number of calls to the resulting function if the
+ * test passes.
+ * @return {function()} The function that should be called at the end of each
+ * sequence of asynchronous functions.
+ */
+function multiDone(done, count) {
+ return function() {
+ count -= 1;
+ if (count <= 0) {
+ done();
+ }
+ };
+}
+
+describe('end-to-end', function() {
+ it('should start and end a request without error', function(complete) {
+ port_picker.nextAvailablePort(function(port) {
+ var server = new grpc.Server();
+ var done = multiDone(function() {
+ complete();
+ server.shutdown();
+ }, 2);
+ server.addHttp2Port(port);
+ var channel = new grpc.Channel(port);
+ var deadline = new Date();
+ deadline.setSeconds(deadline.getSeconds() + 3);
+ var status_text = 'xyz';
+ var call = new grpc.Call(channel,
+ 'dummy_method',
+ deadline);
+ call.startInvoke(function(event) {
+ assert.strictEqual(event.type,
+ grpc.completionType.INVOKE_ACCEPTED);
+
+ call.writesDone(function(event) {
+ assert.strictEqual(event.type,
+ grpc.completionType.FINISH_ACCEPTED);
+ assert.strictEqual(event.data, grpc.opError.OK);
+ });
+ },function(event) {
+ assert.strictEqual(event.type,
+ grpc.completionType.CLIENT_METADATA_READ);
+ },function(event) {
+ assert.strictEqual(event.type, grpc.completionType.FINISHED);
+ var status = event.data;
+ assert.strictEqual(status.code, grpc.status.OK);
+ assert.strictEqual(status.details, status_text);
+ done();
+ }, 0);
+
+ server.start();
+ server.requestCall(function(event) {
+ assert.strictEqual(event.type, grpc.completionType.SERVER_RPC_NEW);
+ var server_call = event.call;
+ assert.notEqual(server_call, null);
+ server_call.serverAccept(function(event) {
+ assert.strictEqual(event.type, grpc.completionType.FINISHED);
+ }, 0);
+ server_call.serverEndInitialMetadata(0);
+ server_call.startWriteStatus(
+ grpc.status.OK,
+ status_text,
+ function(event) {
+ assert.strictEqual(event.type,
+ grpc.completionType.FINISH_ACCEPTED);
+ assert.strictEqual(event.data, grpc.opError.OK);
+ done();
+ });
+ });
+ });
+ });
+
+ it('should send and receive data without error', function(complete) {
+ port_picker.nextAvailablePort(function(port) {
+ var req_text = 'client_request';
+ var reply_text = 'server_response';
+ var server = new grpc.Server();
+ var done = multiDone(function() {
+ complete();
+ server.shutdown();
+ }, 6);
+ server.addHttp2Port(port);
+ var channel = new grpc.Channel(port);
+ var deadline = new Date();
+ deadline.setSeconds(deadline.getSeconds() + 3);
+ var status_text = 'success';
+ var call = new grpc.Call(channel,
+ 'dummy_method',
+ deadline);
+ call.startInvoke(function(event) {
+ assert.strictEqual(event.type,
+ grpc.completionType.INVOKE_ACCEPTED);
+ call.startWrite(
+ new Buffer(req_text),
+ function(event) {
+ assert.strictEqual(event.type,
+ grpc.completionType.WRITE_ACCEPTED);
+ assert.strictEqual(event.data, grpc.opError.OK);
+ call.writesDone(function(event) {
+ assert.strictEqual(event.type,
+ grpc.completionType.FINISH_ACCEPTED);
+ assert.strictEqual(event.data, grpc.opError.OK);
+ done();
+ });
+ }, 0);
+ call.startRead(function(event) {
+ assert.strictEqual(event.type, grpc.completionType.READ);
+ assert.strictEqual(event.data.toString(), reply_text);
+ done();
+ });
+ },function(event) {
+ assert.strictEqual(event.type,
+ grpc.completionType.CLIENT_METADATA_READ);
+ done();
+ },function(event) {
+ assert.strictEqual(event.type, grpc.completionType.FINISHED);
+ var status = event.data;
+ assert.strictEqual(status.code, grpc.status.OK);
+ assert.strictEqual(status.details, status_text);
+ done();
+ }, 0);
+
+ server.start();
+ server.requestCall(function(event) {
+ assert.strictEqual(event.type, grpc.completionType.SERVER_RPC_NEW);
+ var server_call = event.call;
+ assert.notEqual(server_call, null);
+ server_call.serverAccept(function(event) {
+ assert.strictEqual(event.type, grpc.completionType.FINISHED);
+ done();
+ });
+ server_call.serverEndInitialMetadata(0);
+ server_call.startRead(function(event) {
+ assert.strictEqual(event.type, grpc.completionType.READ);
+ assert.strictEqual(event.data.toString(), req_text);
+ server_call.startWrite(
+ new Buffer(reply_text),
+ function(event) {
+ assert.strictEqual(event.type,
+ grpc.completionType.WRITE_ACCEPTED);
+ assert.strictEqual(event.data,
+ grpc.opError.OK);
+ server_call.startWriteStatus(
+ grpc.status.OK,
+ status_text,
+ function(event) {
+ assert.strictEqual(event.type,
+ grpc.completionType.FINISH_ACCEPTED);
+ assert.strictEqual(event.data, grpc.opError.OK);
+ done();
+ });
+ }, 0);
+ });
+ });
+ });
+ });
+});
diff --git a/src/node/test/math_client_test.js b/src/node/test/math_client_test.js
new file mode 100644
index 0000000000..f3697aca98
--- /dev/null
+++ b/src/node/test/math_client_test.js
@@ -0,0 +1,209 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+var assert = require('assert');
+var client = require('../surface_client.js');
+var ProtoBuf = require('protobufjs');
+var port_picker = require('../port_picker');
+
+var builder = ProtoBuf.loadProtoFile(__dirname + '/../examples/math.proto');
+var math = builder.build('math');
+
+/**
+ * Get a function that deserializes a specific type of protobuf.
+ * @param {function()} cls The constructor of the message type to deserialize
+ * @return {function(Buffer):cls} The deserialization function
+ */
+function deserializeCls(cls) {
+ /**
+ * Deserialize a buffer to a message object
+ * @param {Buffer} arg_buf The buffer to deserialize
+ * @return {cls} The resulting object
+ */
+ return function deserialize(arg_buf) {
+ return cls.decode(arg_buf);
+ };
+}
+
+/**
+ * Serialize an object to a buffer
+ * @param {*} arg The object to serialize
+ * @return {Buffer} The serialized object
+ */
+function serialize(arg) {
+ return new Buffer(arg.encode().toBuffer());
+}
+
+/**
+ * Sends a Div request on the channel.
+ * @param {client.Channel} channel The channel on which to make the request
+ * @param {DivArg} argument The argument to the call. Should be serializable
+ * with serialize
+ * @param {function(?Error, value=)} The callback to for when the response is
+ * received
+ * @param {array=} Array of metadata key/value pairs to add to the call
+ * @param {(number|Date)=} deadline The deadline for processing this request.
+ * Defaults to infinite future
+ * @return {EventEmitter} An event emitter for stream related events
+ */
+var div = client.makeUnaryRequestFunction(
+ '/Math/Div',
+ serialize,
+ deserializeCls(math.DivReply));
+
+/**
+ * Sends a Fib request on the channel.
+ * @param {client.Channel} channel The channel on which to make the request
+ * @param {*} argument The argument to the call. Should be serializable with
+ * serialize
+ * @param {array=} Array of metadata key/value pairs to add to the call
+ * @param {(number|Date)=} deadline The deadline for processing this request.
+ * Defaults to infinite future
+ * @return {EventEmitter} An event emitter for stream related events
+ */
+var fib = client.makeServerStreamRequestFunction(
+ '/Math/Fib',
+ serialize,
+ deserializeCls(math.Num));
+
+/**
+ * Sends a Sum request on the channel.
+ * @param {client.Channel} channel The channel on which to make the request
+ * @param {function(?Error, value=)} The callback to for when the response is
+ * received
+ * @param {array=} Array of metadata key/value pairs to add to the call
+ * @param {(number|Date)=} deadline The deadline for processing this request.
+ * Defaults to infinite future
+ * @return {EventEmitter} An event emitter for stream related events
+ */
+var sum = client.makeClientStreamRequestFunction(
+ '/Math/Sum',
+ serialize,
+ deserializeCls(math.Num));
+
+/**
+ * Sends a DivMany request on the channel.
+ * @param {client.Channel} channel The channel on which to make the request
+ * @param {array=} Array of metadata key/value pairs to add to the call
+ * @param {(number|Date)=} deadline The deadline for processing this request.
+ * Defaults to infinite future
+ * @return {EventEmitter} An event emitter for stream related events
+ */
+var divMany = client.makeBidiStreamRequestFunction(
+ '/Math/DivMany',
+ serialize,
+ deserializeCls(math.DivReply));
+
+/**
+ * Channel to use to make requests to a running server.
+ */
+var channel;
+
+/**
+ * Server to test against
+ */
+var server = require('../examples/math_server.js');
+
+
+describe('Math client', function() {
+ before(function(done) {
+ port_picker.nextAvailablePort(function(port) {
+ server.bind(port).listen();
+ channel = new client.Channel(port);
+ done();
+ });
+ });
+ after(function() {
+ server.shutdown();
+ });
+ it('should handle a single request', function(done) {
+ var arg = new math.DivArgs({dividend: 7, divisor: 4});
+ var call = div(channel, arg, function handleDivResult(err, value) {
+ assert.ifError(err);
+ assert.equal(value.get('quotient'), 1);
+ assert.equal(value.get('remainder'), 3);
+ });
+ call.on('status', function checkStatus(status) {
+ assert.strictEqual(status.code, client.status.OK);
+ done();
+ });
+ });
+ it('should handle a server streaming request', function(done) {
+ var arg = new math.FibArgs({limit: 7});
+ var call = fib(channel, arg);
+ var expected_results = [1, 1, 2, 3, 5, 8, 13];
+ var next_expected = 0;
+ call.on('data', function checkResponse(value) {
+ assert.equal(value.get('num'), expected_results[next_expected]);
+ next_expected += 1;
+ });
+ call.on('status', function checkStatus(status) {
+ assert.strictEqual(status.code, client.status.OK);
+ done();
+ });
+ });
+ it('should handle a client streaming request', function(done) {
+ var call = sum(channel, function handleSumResult(err, value) {
+ assert.ifError(err);
+ assert.equal(value.get('num'), 21);
+ });
+ for (var i = 0; i < 7; i++) {
+ call.write(new math.Num({'num': i}));
+ }
+ call.end();
+ call.on('status', function checkStatus(status) {
+ assert.strictEqual(status.code, client.status.OK);
+ done();
+ });
+ });
+ it('should handle a bidirectional streaming request', function(done) {
+ function checkResponse(index, value) {
+ assert.equal(value.get('quotient'), index);
+ assert.equal(value.get('remainder'), 1);
+ }
+ var call = divMany(channel);
+ var response_index = 0;
+ call.on('data', function(value) {
+ checkResponse(response_index, value);
+ response_index += 1;
+ });
+ for (var i = 0; i < 7; i++) {
+ call.write(new math.DivArgs({dividend: 2 * i + 1, divisor: 2}));
+ }
+ call.end();
+ call.on('status', function checkStatus(status) {
+ assert.strictEqual(status.code, client.status.OK);
+ done();
+ });
+ });
+});
diff --git a/src/node/test/server_test.js b/src/node/test/server_test.js
new file mode 100644
index 0000000000..79f7b32948
--- /dev/null
+++ b/src/node/test/server_test.js
@@ -0,0 +1,121 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+var assert = require('assert');
+var grpc = require('bindings')('grpc.node');
+var Server = require('../server');
+var port_picker = require('../port_picker');
+
+/**
+ * This is used for testing functions with multiple asynchronous calls that
+ * can happen in different orders. This should be passed the number of async
+ * function invocations that can occur last, and each of those should call this
+ * function's return value
+ * @param {function()} done The function that should be called when a test is
+ * complete.
+ * @param {number} count The number of calls to the resulting function if the
+ * test passes.
+ * @return {function()} The function that should be called at the end of each
+ * sequence of asynchronous functions.
+ */
+function multiDone(done, count) {
+ return function() {
+ count -= 1;
+ if (count <= 0) {
+ done();
+ }
+ };
+}
+
+/**
+ * Responds to every request with the same data as a response
+ * @param {Stream} stream
+ */
+function echoHandler(stream) {
+ stream.pipe(stream);
+}
+
+describe('echo server', function() {
+ it('should echo inputs as responses', function(done) {
+ done = multiDone(done, 4);
+ port_picker.nextAvailablePort(function(port) {
+ var server = new Server();
+ server.bind(port);
+ server.register('echo', echoHandler);
+ server.start();
+
+ var req_text = 'echo test string';
+ var status_text = 'OK';
+
+ var channel = new grpc.Channel(port);
+ var deadline = new Date();
+ deadline.setSeconds(deadline.getSeconds() + 3);
+ var call = new grpc.Call(channel,
+ 'echo',
+ deadline);
+ call.startInvoke(function(event) {
+ assert.strictEqual(event.type,
+ grpc.completionType.INVOKE_ACCEPTED);
+ call.startWrite(
+ new Buffer(req_text),
+ function(event) {
+ assert.strictEqual(event.type,
+ grpc.completionType.WRITE_ACCEPTED);
+ assert.strictEqual(event.data, grpc.opError.OK);
+ call.writesDone(function(event) {
+ assert.strictEqual(event.type,
+ grpc.completionType.FINISH_ACCEPTED);
+ assert.strictEqual(event.data, grpc.opError.OK);
+ done();
+ });
+ }, 0);
+ call.startRead(function(event) {
+ assert.strictEqual(event.type, grpc.completionType.READ);
+ assert.strictEqual(event.data.toString(), req_text);
+ done();
+ });
+ },function(event) {
+ assert.strictEqual(event.type,
+ grpc.completionType.CLIENT_METADATA_READ);
+ done();
+ },function(event) {
+ assert.strictEqual(event.type, grpc.completionType.FINISHED);
+ var status = event.data;
+ assert.strictEqual(status.code, grpc.status.OK);
+ assert.strictEqual(status.details, status_text);
+ server.shutdown();
+ done();
+ }, 0);
+ });
+ });
+});
diff --git a/src/node/timeval.cc b/src/node/timeval.cc
new file mode 100644
index 0000000000..687e33576b
--- /dev/null
+++ b/src/node/timeval.cc
@@ -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.
+ *
+ */
+
+#include <limits>
+
+#include "grpc/grpc.h"
+#include "grpc/support/time.h"
+#include "timeval.h"
+
+namespace grpc {
+namespace node {
+
+gpr_timespec MillisecondsToTimespec(double millis) {
+ if (millis == std::numeric_limits<double>::infinity()) {
+ return gpr_inf_future;
+ } else if (millis == -std::numeric_limits<double>::infinity()) {
+ return gpr_inf_past;
+ } else {
+ return gpr_time_from_micros(static_cast<int64_t>(millis * 1000));
+ }
+}
+
+double TimespecToMilliseconds(gpr_timespec timespec) {
+ if (gpr_time_cmp(timespec, gpr_inf_future) == 0) {
+ return std::numeric_limits<double>::infinity();
+ } else if (gpr_time_cmp(timespec, gpr_inf_past) == 0) {
+ return -std::numeric_limits<double>::infinity();
+ } else {
+ struct timeval time = gpr_timeval_from_timespec(timespec);
+ return (static_cast<double>(time.tv_sec) * 1000 +
+ static_cast<double>(time.tv_usec) / 1000);
+ }
+}
+
+} // namespace node
+} // namespace grpc
diff --git a/src/node/timeval.h b/src/node/timeval.h
new file mode 100644
index 0000000000..1fb0f2c690
--- /dev/null
+++ b/src/node/timeval.h
@@ -0,0 +1,48 @@
+/*
+ *
+ * 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 NET_GRPC_NODE_TIMEVAL_H_
+#define NET_GRPC_NODE_TIMEVAL_H_
+
+#include "grpc/support/time.h"
+
+namespace grpc {
+namespace node {
+
+double TimespecToMilliseconds(gpr_timespec time);
+gpr_timespec MillisecondsToTimespec(double millis);
+
+} // namespace node
+} // namespace grpc
+
+#endif // NET_GRPC_NODE_TIMEVAL_H_
diff --git a/src/php/ext/grpc/byte_buffer.c b/src/php/ext/grpc/byte_buffer.c
index db018313a7..e2f63e3413 100755..100644
--- a/src/php/ext/grpc/byte_buffer.c
+++ b/src/php/ext/grpc/byte_buffer.c
@@ -21,16 +21,15 @@ grpc_byte_buffer *string_to_byte_buffer(char *string, size_t length) {
return grpc_byte_buffer_create(&slice, 1);
}
-void byte_buffer_to_string(grpc_byte_buffer *buffer,
- char **out_string,
+void byte_buffer_to_string(grpc_byte_buffer *buffer, char **out_string,
size_t *out_length) {
size_t length = grpc_byte_buffer_length(buffer);
- char *string = ecalloc(length+1, sizeof(char));
+ char *string = ecalloc(length + 1, sizeof(char));
size_t offset = 0;
grpc_byte_buffer_reader *reader = grpc_byte_buffer_reader_create(buffer);
gpr_slice next;
- while(grpc_byte_buffer_reader_next(reader, &next) != 0) {
- memcpy(string+offset, GPR_SLICE_START_PTR(next), GPR_SLICE_LENGTH(next));
+ while (grpc_byte_buffer_reader_next(reader, &next) != 0) {
+ memcpy(string + offset, GPR_SLICE_START_PTR(next), GPR_SLICE_LENGTH(next));
offset += GPR_SLICE_LENGTH(next);
}
*out_string = string;
diff --git a/src/php/ext/grpc/byte_buffer.h b/src/php/ext/grpc/byte_buffer.h
index 1dd4769de2..b83f734caf 100755..100644
--- a/src/php/ext/grpc/byte_buffer.h
+++ b/src/php/ext/grpc/byte_buffer.h
@@ -5,8 +5,7 @@
grpc_byte_buffer *string_to_byte_buffer(char *string, size_t length);
-void byte_buffer_to_string(grpc_byte_buffer *buffer,
- char **out_string,
+void byte_buffer_to_string(grpc_byte_buffer *buffer, char **out_string,
size_t *out_length);
#endif /* NET_GRPC_PHP_GRPC_BYTE_BUFFER_H_ */
diff --git a/src/php/ext/grpc/call.c b/src/php/ext/grpc/call.c
index 7f4f221caa..c01af34e95 100755..100644
--- a/src/php/ext/grpc/call.c
+++ b/src/php/ext/grpc/call.c
@@ -24,9 +24,9 @@
#include "byte_buffer.h"
/* Frees and destroys an instance of wrapped_grpc_call */
-void free_wrapped_grpc_call(void *object TSRMLS_DC){
- wrapped_grpc_call *call = (wrapped_grpc_call*)object;
- if(call->owned && call->wrapped != NULL){
+void free_wrapped_grpc_call(void *object TSRMLS_DC) {
+ wrapped_grpc_call *call = (wrapped_grpc_call *)object;
+ if (call->owned && call->wrapped != NULL) {
grpc_call_destroy(call->wrapped);
}
efree(call);
@@ -34,38 +34,36 @@ void free_wrapped_grpc_call(void *object TSRMLS_DC){
/* Initializes an instance of wrapped_grpc_call to be associated with an object
* of a class specified by class_type */
-zend_object_value create_wrapped_grpc_call(
- zend_class_entry *class_type TSRMLS_DC){
+zend_object_value create_wrapped_grpc_call(zend_class_entry *class_type
+ TSRMLS_DC) {
zend_object_value retval;
wrapped_grpc_call *intern;
- intern = (wrapped_grpc_call*)emalloc(sizeof(wrapped_grpc_call));
+ intern = (wrapped_grpc_call *)emalloc(sizeof(wrapped_grpc_call));
memset(intern, 0, sizeof(wrapped_grpc_call));
zend_object_std_init(&intern->std, class_type TSRMLS_CC);
object_properties_init(&intern->std, class_type);
retval.handle = zend_objects_store_put(
- intern,
- (zend_objects_store_dtor_t) zend_objects_destroy_object,
- free_wrapped_grpc_call,
- NULL TSRMLS_CC);
+ intern, (zend_objects_store_dtor_t)zend_objects_destroy_object,
+ free_wrapped_grpc_call, NULL TSRMLS_CC);
retval.handlers = zend_get_std_object_handlers();
return retval;
}
/* Wraps a grpc_call struct in a PHP object. Owned indicates whether the struct
should be destroyed at the end of the object's lifecycle */
-zval *grpc_php_wrap_call(grpc_call *wrapped, bool owned){
+zval *grpc_php_wrap_call(grpc_call *wrapped, bool owned) {
zval *call_object;
MAKE_STD_ZVAL(call_object);
object_init_ex(call_object, grpc_ce_call);
- wrapped_grpc_call *call = (wrapped_grpc_call*)zend_object_store_get_object(
- call_object TSRMLS_CC);
+ wrapped_grpc_call *call =
+ (wrapped_grpc_call *)zend_object_store_get_object(call_object TSRMLS_CC);
call->wrapped = wrapped;
return call_object;
}
-zval *grpc_call_create_metadata_array(int count, grpc_metadata *elements){
+zval *grpc_call_create_metadata_array(int count, grpc_metadata *elements) {
int i;
zval *array;
zval **data = NULL;
@@ -78,18 +76,16 @@ zval *grpc_call_create_metadata_array(int count, grpc_metadata *elements){
array_init(array);
array_hash = Z_ARRVAL_P(array);
grpc_metadata *elem;
- for(i=0; i<count; i++){
+ for (i = 0; i < count; i++) {
elem = &elements[i];
key_len = strlen(elem->key);
- str_key = ecalloc(key_len+1, sizeof(char));
+ str_key = ecalloc(key_len + 1, sizeof(char));
memcpy(str_key, elem->key, key_len);
- str_val = ecalloc(elem->value_length+1, sizeof(char));
+ str_val = ecalloc(elem->value_length + 1, sizeof(char));
memcpy(str_val, elem->value, elem->value_length);
- if(zend_hash_find(array_hash,
- str_key,
- key_len,
- (void**)data) == SUCCESS){
- switch(Z_TYPE_P(*data)){
+ if (zend_hash_find(array_hash, str_key, key_len, (void **)data) ==
+ SUCCESS) {
+ switch (Z_TYPE_P(*data)) {
case IS_STRING:
MAKE_STD_ZVAL(inner_array);
array_init(inner_array);
@@ -107,44 +103,36 @@ zval *grpc_call_create_metadata_array(int count, grpc_metadata *elements){
efree(str_val);
return NULL;
}
- add_next_index_stringl(inner_array,
- str_val,
- elem->value_length,
- false);
+ add_next_index_stringl(inner_array, str_val, elem->value_length, false);
} else {
- add_assoc_stringl(array,
- str_key,
- str_val,
- elem->value_length,
- false);
+ add_assoc_stringl(array, str_key, str_val, elem->value_length, false);
}
}
return array;
}
-int php_grpc_call_add_metadata_array_walk(void *elem TSRMLS_DC,
- int num_args,
+int php_grpc_call_add_metadata_array_walk(void *elem TSRMLS_DC, int num_args,
va_list args,
- zend_hash_key *hash_key){
+ zend_hash_key *hash_key) {
grpc_call_error error_code;
- zval **data = (zval**)elem;
+ zval **data = (zval **)elem;
grpc_metadata metadata;
- grpc_call *call = va_arg(args, grpc_call*);
+ grpc_call *call = va_arg(args, grpc_call *);
gpr_uint32 flags = va_arg(args, gpr_uint32);
const char *key;
HashTable *inner_hash;
/* We assume that either two args were passed, and we are in the recursive
case (and the second argument is the key), or one arg was passed and
hash_key is the string key. */
- if(num_args > 2){
- key = va_arg(args, const char*);
+ if (num_args > 2) {
+ key = va_arg(args, const char *);
} else {
/* TODO(mlumish): If possible, check that hash_key is a string */
key = hash_key->arKey;
}
- switch(Z_TYPE_P(*data)){
+ switch (Z_TYPE_P(*data)) {
case IS_STRING:
- metadata.key = (char*)key;
+ metadata.key = (char *)key;
metadata.value = Z_STRVAL_P(*data);
metadata.value_length = Z_STRLEN_P(*data);
error_code = grpc_call_add_metadata(call, &metadata, 0u);
@@ -153,11 +141,8 @@ int php_grpc_call_add_metadata_array_walk(void *elem TSRMLS_DC,
case IS_ARRAY:
inner_hash = Z_ARRVAL_P(*data);
zend_hash_apply_with_arguments(inner_hash TSRMLS_CC,
- php_grpc_call_add_metadata_array_walk,
- 3,
- call,
- flags,
- key);
+ php_grpc_call_add_metadata_array_walk, 3,
+ call, flags, key);
break;
default:
zend_throw_exception(zend_exception_get_default(),
@@ -174,27 +159,26 @@ int php_grpc_call_add_metadata_array_walk(void *elem TSRMLS_DC,
* @param string $method The method to call
* @param Timeval $absolute_deadline The deadline for completing the call
*/
-PHP_METHOD(Call, __construct){
- wrapped_grpc_call *call = (wrapped_grpc_call*)zend_object_store_get_object(
- getThis() TSRMLS_CC);
+PHP_METHOD(Call, __construct) {
+ wrapped_grpc_call *call =
+ (wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC);
zval *channel_obj;
char *method;
int method_len;
zval *deadline_obj;
/* "OsO" == 1 Object, 1 string, 1 Object */
- if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
- "OsO",
- &channel_obj, grpc_ce_channel,
- &method, &method_len,
- &deadline_obj, grpc_ce_timeval) == FAILURE){
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "OsO", &channel_obj,
+ grpc_ce_channel, &method, &method_len,
+ &deadline_obj, grpc_ce_timeval) == FAILURE) {
zend_throw_exception(spl_ce_InvalidArgumentException,
"Call expects a Channel, a String, and a Timeval",
1 TSRMLS_CC);
return;
}
wrapped_grpc_channel *channel =
- (wrapped_grpc_channel*)zend_object_store_get_object(channel_obj TSRMLS_CC);
- if(channel->wrapped == NULL) {
+ (wrapped_grpc_channel *)zend_object_store_get_object(
+ channel_obj TSRMLS_CC);
+ if (channel->wrapped == NULL) {
zend_throw_exception(spl_ce_InvalidArgumentException,
"Call cannot be constructed from a closed Channel",
1 TSRMLS_CC);
@@ -202,11 +186,10 @@ PHP_METHOD(Call, __construct){
}
add_property_zval(getThis(), "channel", channel_obj);
wrapped_grpc_timeval *deadline =
- (wrapped_grpc_timeval*)zend_object_store_get_object(deadline_obj TSRMLS_CC);
- call->wrapped = grpc_channel_create_call(channel->wrapped,
- method,
- channel->target,
- deadline->wrapped);
+ (wrapped_grpc_timeval *)zend_object_store_get_object(
+ deadline_obj TSRMLS_CC);
+ call->wrapped = grpc_channel_create_call(channel->wrapped, method,
+ channel->target, deadline->wrapped);
}
/**
@@ -218,17 +201,15 @@ PHP_METHOD(Call, __construct){
* (optional)
* @return Void
*/
-PHP_METHOD(Call, add_metadata){
- wrapped_grpc_call *call = (wrapped_grpc_call*)zend_object_store_get_object(
- getThis() TSRMLS_CC);
+PHP_METHOD(Call, add_metadata) {
+ wrapped_grpc_call *call =
+ (wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC);
zval *array;
HashTable *array_hash;
long flags = 0;
/* "a|l" == 1 array, 1 optional long */
- if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
- "a|l",
- &array,
- &flags) == FAILURE){
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|l", &array, &flags) ==
+ FAILURE) {
zend_throw_exception(spl_ce_InvalidArgumentException,
"add_metadata expects an array and an optional long",
1 TSRMLS_CC);
@@ -236,10 +217,8 @@ PHP_METHOD(Call, add_metadata){
}
array_hash = Z_ARRVAL_P(array);
zend_hash_apply_with_arguments(array_hash TSRMLS_CC,
- php_grpc_call_add_metadata_array_walk,
- 2,
- call->wrapped,
- (gpr_uint32)flags);
+ php_grpc_call_add_metadata_array_walk, 2,
+ call->wrapped, (gpr_uint32)flags);
}
/**
@@ -252,7 +231,7 @@ PHP_METHOD(Call, add_metadata){
* (optional)
* @return Void
*/
-PHP_METHOD(Call, start_invoke){
+PHP_METHOD(Call, start_invoke) {
grpc_call_error error_code;
long tag1;
long tag2;
@@ -260,31 +239,24 @@ PHP_METHOD(Call, start_invoke){
zval *queue_obj;
long flags = 0;
/* "Olll|l" == 1 Object, 3 mandatory longs, 1 optional long */
- if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
- "Olll|l",
- &queue_obj, grpc_ce_completion_queue,
- &tag1,
- &tag2,
- &tag3,
- &flags) == FAILURE){
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Olll|l", &queue_obj,
+ grpc_ce_completion_queue, &tag1, &tag2, &tag3,
+ &flags) == FAILURE) {
zend_throw_exception(
spl_ce_InvalidArgumentException,
"start_invoke needs a CompletionQueue, 3 longs, and an optional long",
- 1 TSRMLS_CC);
+ 1 TSRMLS_CC);
return;
}
add_property_zval(getThis(), "completion_queue", queue_obj);
- wrapped_grpc_call *call = (wrapped_grpc_call*)zend_object_store_get_object(
- getThis() TSRMLS_CC);
+ wrapped_grpc_call *call =
+ (wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC);
wrapped_grpc_completion_queue *queue =
- (wrapped_grpc_completion_queue*)zend_object_store_get_object(
- queue_obj TSRMLS_CC);
- error_code = grpc_call_start_invoke(call->wrapped,
- queue->wrapped,
- (void*)tag1,
- (void*)tag2,
- (void*)tag3,
- (gpr_uint32)flags);
+ (wrapped_grpc_completion_queue *)zend_object_store_get_object(
+ queue_obj TSRMLS_CC);
+ error_code =
+ grpc_call_start_invoke(call->wrapped, queue->wrapped, (void *)tag1,
+ (void *)tag2, (void *)tag3, (gpr_uint32)flags);
MAYBE_THROW_CALL_ERROR(start_invoke, error_code);
}
@@ -298,15 +270,13 @@ PHP_METHOD(Call, start_invoke){
* (optional)
* @return Void
*/
-PHP_METHOD(Call, server_accept){
+PHP_METHOD(Call, server_accept) {
long tag;
zval *queue_obj;
grpc_call_error error_code;
/* "Ol|l" == 1 Object, 1 long */
- if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
- "Ol",
- &queue_obj, grpc_ce_completion_queue,
- &tag) == FAILURE){
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Ol", &queue_obj,
+ grpc_ce_completion_queue, &tag) == FAILURE) {
zend_throw_exception(
spl_ce_InvalidArgumentException,
"server_accept expects a CompletionQueue, a long, and an optional long",
@@ -314,14 +284,13 @@ PHP_METHOD(Call, server_accept){
return;
}
add_property_zval(getThis(), "completion_queue", queue_obj);
- wrapped_grpc_call *call = (wrapped_grpc_call*)zend_object_store_get_object(
- getThis() TSRMLS_CC);
+ wrapped_grpc_call *call =
+ (wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC);
wrapped_grpc_completion_queue *queue =
- (wrapped_grpc_completion_queue*)zend_object_store_get_object(
- queue_obj TSRMLS_CC);
- error_code = grpc_call_server_accept(call->wrapped,
- queue->wrapped,
- (void*)tag);
+ (wrapped_grpc_completion_queue *)zend_object_store_get_object(
+ queue_obj TSRMLS_CC);
+ error_code =
+ grpc_call_server_accept(call->wrapped, queue->wrapped, (void *)tag);
MAYBE_THROW_CALL_ERROR(server_accept, error_code);
}
@@ -329,16 +298,14 @@ PHP_METHOD(Call, server_end_initial_metadata) {
grpc_call_error error_code;
long flags = 0;
/* "|l" == 1 optional long */
- if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
- "|l",
- &flags) == FAILURE) {
- zend_throw_exception(
- spl_ce_InvalidArgumentException,
- "server_end_initial_metadata expects an optional long",
- 1 TSRMLS_CC);
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &flags) ==
+ FAILURE) {
+ zend_throw_exception(spl_ce_InvalidArgumentException,
+ "server_end_initial_metadata expects an optional long",
+ 1 TSRMLS_CC);
}
- wrapped_grpc_call *call = (wrapped_grpc_call*)zend_object_store_get_object(
- getThis() TSRMLS_CC);
+ wrapped_grpc_call *call =
+ (wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC);
error_code = grpc_call_server_end_initial_metadata(call->wrapped, flags);
MAYBE_THROW_CALL_ERROR(server_end_initial_metadata, error_code);
}
@@ -347,9 +314,9 @@ PHP_METHOD(Call, server_end_initial_metadata) {
* Called by clients to cancel an RPC on the server.
* @return Void
*/
-PHP_METHOD(Call, cancel){
- wrapped_grpc_call *call = (wrapped_grpc_call*)zend_object_store_get_object(
- getThis() TSRMLS_CC);
+PHP_METHOD(Call, cancel) {
+ wrapped_grpc_call *call =
+ (wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC);
grpc_call_error error_code = grpc_call_cancel(call->wrapped);
MAYBE_THROW_CALL_ERROR(cancel, error_code);
}
@@ -362,30 +329,25 @@ PHP_METHOD(Call, cancel){
* (optional)
* @return Void
*/
-PHP_METHOD(Call, start_write){
+PHP_METHOD(Call, start_write) {
grpc_call_error error_code;
- wrapped_grpc_call *call = (wrapped_grpc_call*)zend_object_store_get_object(
- getThis() TSRMLS_CC);
+ wrapped_grpc_call *call =
+ (wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC);
char *buffer;
int buffer_len;
long tag;
long flags = 0;
/* "Ol|l" == 1 Object, 1 mandatory long, 1 optional long */
- if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
- "sl|l",
- &buffer, &buffer_len,
- &tag,
- &flags) == FAILURE){
- zend_throw_exception(
- spl_ce_InvalidArgumentException,
- "start_write expects a string and an optional long",
- 1 TSRMLS_CC);
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl|l", &buffer,
+ &buffer_len, &tag, &flags) == FAILURE) {
+ zend_throw_exception(spl_ce_InvalidArgumentException,
+ "start_write expects a string and an optional long",
+ 1 TSRMLS_CC);
return;
}
error_code = grpc_call_start_write(call->wrapped,
string_to_byte_buffer(buffer, buffer_len),
- (void*)tag,
- (gpr_uint32)flags);
+ (void *)tag, (gpr_uint32)flags);
MAYBE_THROW_CALL_ERROR(start_write, error_code);
}
@@ -396,30 +358,26 @@ PHP_METHOD(Call, start_write){
* @param long $tag The tag to associate with this status
* @return Void
*/
-PHP_METHOD(Call, start_write_status){
+PHP_METHOD(Call, start_write_status) {
grpc_call_error error_code;
- wrapped_grpc_call *call = (wrapped_grpc_call*)zend_object_store_get_object(
- getThis() TSRMLS_CC);
+ wrapped_grpc_call *call =
+ (wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC);
long status_code;
int status_details_length;
long tag;
char *status_details;
/* "lsl" == 1 long, 1 string, 1 long */
- if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
- "lsl",
- &status_code,
- &status_details, &status_details_length,
- &tag) == FAILURE){
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lsl", &status_code,
+ &status_details, &status_details_length,
+ &tag) == FAILURE) {
zend_throw_exception(
spl_ce_InvalidArgumentException,
- "start_write_status expects a long, a string, and a long",
- 1 TSRMLS_CC);
+ "start_write_status expects a long, a string, and a long", 1 TSRMLS_CC);
return;
}
- error_code = grpc_call_start_write_status(call->wrapped,
- (grpc_status_code)status_code,
- status_details,
- (void*)tag);
+ error_code =
+ grpc_call_start_write_status(call->wrapped, (grpc_status_code)status_code,
+ status_details, (void *)tag);
MAYBE_THROW_CALL_ERROR(start_write_status, error_code);
}
@@ -427,19 +385,18 @@ PHP_METHOD(Call, start_write_status){
* Indicate that there are no more messages to send
* @return Void
*/
-PHP_METHOD(Call, writes_done){
+PHP_METHOD(Call, writes_done) {
grpc_call_error error_code;
- wrapped_grpc_call *call = (wrapped_grpc_call*)zend_object_store_get_object(
- getThis() TSRMLS_CC);
+ wrapped_grpc_call *call =
+ (wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC);
long tag;
/* "l" == 1 long */
- if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &tag) == FAILURE){
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &tag) == FAILURE) {
zend_throw_exception(spl_ce_InvalidArgumentException,
- "writes_done expects a long",
- 1 TSRMLS_CC);
+ "writes_done expects a long", 1 TSRMLS_CC);
return;
}
- error_code = grpc_call_writes_done(call->wrapped, (void*)tag);
+ error_code = grpc_call_writes_done(call->wrapped, (void *)tag);
MAYBE_THROW_CALL_ERROR(writes_done, error_code);
}
@@ -449,37 +406,35 @@ PHP_METHOD(Call, writes_done){
* @param long $tag The tag to associate with this read
* @return Void
*/
-PHP_METHOD(Call, start_read){
+PHP_METHOD(Call, start_read) {
grpc_call_error error_code;
- wrapped_grpc_call *call = (wrapped_grpc_call*)zend_object_store_get_object(
- getThis() TSRMLS_CC);
+ wrapped_grpc_call *call =
+ (wrapped_grpc_call *)zend_object_store_get_object(getThis() TSRMLS_CC);
long tag;
/* "l" == 1 long */
- if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &tag) == FAILURE){
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &tag) == FAILURE) {
zend_throw_exception(spl_ce_InvalidArgumentException,
- "start_read expects a long",
- 1 TSRMLS_CC);
+ "start_read expects a long", 1 TSRMLS_CC);
return;
}
- error_code = grpc_call_start_read(call->wrapped, (void*)tag);
+ error_code = grpc_call_start_read(call->wrapped, (void *)tag);
MAYBE_THROW_CALL_ERROR(start_read, error_code);
}
static zend_function_entry call_methods[] = {
- PHP_ME(Call, __construct, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
- PHP_ME(Call, server_accept, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(Call, server_end_initial_metadata, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(Call, add_metadata, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(Call, cancel, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(Call, start_invoke, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(Call, start_read, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(Call, start_write, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(Call, start_write_status, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(Call, writes_done, NULL, ZEND_ACC_PUBLIC)
- PHP_FE_END
-};
+ PHP_ME(Call, __construct, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
+ PHP_ME(Call, server_accept, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(Call, server_end_initial_metadata, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(Call, add_metadata, NULL, ZEND_ACC_PUBLIC) PHP_ME(
+ Call, cancel, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(Call, start_invoke, NULL, ZEND_ACC_PUBLIC) PHP_ME(
+ Call, start_read, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(Call, start_write, NULL, ZEND_ACC_PUBLIC) PHP_ME(
+ Call, start_write_status, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(Call, writes_done, NULL, ZEND_ACC_PUBLIC)
+ PHP_FE_END};
-void grpc_init_call(TSRMLS_D){
+void grpc_init_call(TSRMLS_D) {
zend_class_entry ce;
INIT_CLASS_ENTRY(ce, "Grpc\\Call", call_methods);
ce.create_object = create_wrapped_grpc_call;
diff --git a/src/php/ext/grpc/call.h b/src/php/ext/grpc/call.h
index c3b18d66cb..232c5d7cf2 100755..100644
--- a/src/php/ext/grpc/call.h
+++ b/src/php/ext/grpc/call.h
@@ -13,15 +13,14 @@
#include "grpc/grpc.h"
// Throw an exception if error_code is not OK
-#define MAYBE_THROW_CALL_ERROR(func_name, error_code) \
- do{ \
- if(error_code != GRPC_CALL_OK) { \
- zend_throw_exception(spl_ce_LogicException, \
- #func_name " was called incorrectly", \
- (long)error_code TSRMLS_CC); \
- } \
- } while(0)
-
+#define MAYBE_THROW_CALL_ERROR(func_name, error_code) \
+ do { \
+ if (error_code != GRPC_CALL_OK) { \
+ zend_throw_exception(spl_ce_LogicException, \
+ #func_name " was called incorrectly", \
+ (long)error_code TSRMLS_CC); \
+ } \
+ } while (0)
/* Class entry for the Call PHP class */
zend_class_entry *grpc_ce_call;
diff --git a/src/php/ext/grpc/channel.c b/src/php/ext/grpc/channel.c
index c2847b99f1..f0e4153b22 100755..100644
--- a/src/php/ext/grpc/channel.c
+++ b/src/php/ext/grpc/channel.c
@@ -23,9 +23,9 @@
#include "credentials.h"
/* Frees and destroys an instance of wrapped_grpc_channel */
-void free_wrapped_grpc_channel(void *object TSRMLS_DC){
- wrapped_grpc_channel *channel = (wrapped_grpc_channel*)object;
- if(channel->wrapped != NULL){
+void free_wrapped_grpc_channel(void *object TSRMLS_DC) {
+ wrapped_grpc_channel *channel = (wrapped_grpc_channel *)object;
+ if (channel->wrapped != NULL) {
grpc_channel_destroy(channel->wrapped);
}
efree(channel);
@@ -33,24 +33,22 @@ void free_wrapped_grpc_channel(void *object TSRMLS_DC){
/* Initializes an instance of wrapped_grpc_channel to be associated with an
* object of a class specified by class_type */
-zend_object_value create_wrapped_grpc_channel(
- zend_class_entry *class_type TSRMLS_DC){
+zend_object_value create_wrapped_grpc_channel(zend_class_entry *class_type
+ TSRMLS_DC) {
zend_object_value retval;
wrapped_grpc_channel *intern;
- intern = (wrapped_grpc_channel*)emalloc(sizeof(wrapped_grpc_channel));
+ intern = (wrapped_grpc_channel *)emalloc(sizeof(wrapped_grpc_channel));
memset(intern, 0, sizeof(wrapped_grpc_channel));
zend_object_std_init(&intern->std, class_type TSRMLS_CC);
object_properties_init(&intern->std, class_type);
retval.handle = zend_objects_store_put(
- intern,
- (zend_objects_store_dtor_t)zend_objects_destroy_object,
- free_wrapped_grpc_channel,
- NULL TSRMLS_CC);
+ intern, (zend_objects_store_dtor_t)zend_objects_destroy_object,
+ free_wrapped_grpc_channel, NULL TSRMLS_CC);
retval.handlers = zend_get_std_object_handlers();
return retval;
}
-void php_grpc_read_args_array(zval *args_array, grpc_channel_args *args){
+void php_grpc_read_args_array(zval *args_array, grpc_channel_args *args) {
HashTable *array_hash;
HashPosition array_pointer;
int args_index;
@@ -62,24 +60,18 @@ void php_grpc_read_args_array(zval *args_array, grpc_channel_args *args){
args->num_args = zend_hash_num_elements(array_hash);
args->args = ecalloc(args->num_args, sizeof(grpc_arg));
args_index = 0;
- for(zend_hash_internal_pointer_reset_ex(array_hash, &array_pointer);
- zend_hash_get_current_data_ex(array_hash,
- (void**)&data,
- &array_pointer) == SUCCESS;
- zend_hash_move_forward_ex(array_hash, &array_pointer)){
- if(zend_hash_get_current_key_ex(array_hash,
- &key,
- &key_len,
- &index,
- 0,
- &array_pointer) != HASH_KEY_IS_STRING){
+ for (zend_hash_internal_pointer_reset_ex(array_hash, &array_pointer);
+ zend_hash_get_current_data_ex(array_hash, (void **)&data,
+ &array_pointer) == SUCCESS;
+ zend_hash_move_forward_ex(array_hash, &array_pointer)) {
+ if (zend_hash_get_current_key_ex(array_hash, &key, &key_len, &index, 0,
+ &array_pointer) != HASH_KEY_IS_STRING) {
zend_throw_exception(spl_ce_InvalidArgumentException,
- "args keys must be strings",
- 1 TSRMLS_CC);
+ "args keys must be strings", 1 TSRMLS_CC);
return;
}
args->args[args_index].key = key;
- switch(Z_TYPE_P(*data)){
+ switch (Z_TYPE_P(*data)) {
case IS_LONG:
args->args[args_index].value.integer = (int)Z_LVAL_P(*data);
break;
@@ -88,8 +80,7 @@ void php_grpc_read_args_array(zval *args_array, grpc_channel_args *args){
break;
default:
zend_throw_exception(spl_ce_InvalidArgumentException,
- "args values must be int or string",
- 1 TSRMLS_CC);
+ "args values must be int or string", 1 TSRMLS_CC);
return;
}
args_index++;
@@ -103,9 +94,9 @@ void php_grpc_read_args_array(zval *args_array, grpc_channel_args *args){
* @param string $target The hostname to associate with this channel
* @param array $args The arguments to pass to the Channel (optional)
*/
-PHP_METHOD(Channel, __construct){
+PHP_METHOD(Channel, __construct) {
wrapped_grpc_channel *channel =
- (wrapped_grpc_channel*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ (wrapped_grpc_channel *)zend_object_store_get_object(getThis() TSRMLS_CC);
char *target;
int target_length;
zval *args_array = NULL;
@@ -114,30 +105,25 @@ PHP_METHOD(Channel, __construct){
zval **creds_obj = NULL;
wrapped_grpc_credentials *creds = NULL;
/* "s|a" == 1 string, 1 optional array */
- if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
- "s|a",
- &target, &target_length,
- &args_array) == FAILURE){
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|a", &target,
+ &target_length, &args_array) == FAILURE) {
zend_throw_exception(spl_ce_InvalidArgumentException,
- "Channel expects a string and an array",
- 1 TSRMLS_CC);
+ "Channel expects a string and an array", 1 TSRMLS_CC);
return;
}
if (args_array == NULL) {
channel->wrapped = grpc_channel_create(target, NULL);
} else {
array_hash = Z_ARRVAL_P(args_array);
- if(zend_hash_find(array_hash,
- "credentials",
- sizeof("credentials"),
- (void**)&creds_obj) == SUCCESS) {
- if(zend_get_class_entry(*creds_obj TSRMLS_CC) != grpc_ce_credentials) {
+ if (zend_hash_find(array_hash, "credentials", sizeof("credentials"),
+ (void **)&creds_obj) == SUCCESS) {
+ if (zend_get_class_entry(*creds_obj TSRMLS_CC) != grpc_ce_credentials) {
zend_throw_exception(spl_ce_InvalidArgumentException,
"credentials must be a Credentials object",
1 TSRMLS_CC);
return;
}
- creds = (wrapped_grpc_credentials*)zend_object_store_get_object(
+ creds = (wrapped_grpc_credentials *)zend_object_store_get_object(
*creds_obj TSRMLS_CC);
zend_hash_del(array_hash, "credentials", 12);
}
@@ -146,35 +132,32 @@ PHP_METHOD(Channel, __construct){
channel->wrapped = grpc_channel_create(target, &args);
} else {
gpr_log(GPR_DEBUG, "Initialized secure channel");
- channel->wrapped = grpc_secure_channel_create(creds->wrapped,
- target,
- &args);
+ channel->wrapped =
+ grpc_secure_channel_create(creds->wrapped, target, &args);
}
efree(args.args);
}
- channel->target = ecalloc(target_length+1, sizeof(char));
+ channel->target = ecalloc(target_length + 1, sizeof(char));
memcpy(channel->target, target, target_length);
}
/**
* Close the channel
*/
-PHP_METHOD(Channel, close){
+PHP_METHOD(Channel, close) {
wrapped_grpc_channel *channel =
- (wrapped_grpc_channel*)zend_object_store_get_object(getThis() TSRMLS_CC);
- if(channel->wrapped != NULL) {
+ (wrapped_grpc_channel *)zend_object_store_get_object(getThis() TSRMLS_CC);
+ if (channel->wrapped != NULL) {
grpc_channel_destroy(channel->wrapped);
channel->wrapped = NULL;
}
}
static zend_function_entry channel_methods[] = {
- PHP_ME(Channel, __construct, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
- PHP_ME(Channel, close, NULL, ZEND_ACC_PUBLIC)
- PHP_FE_END
-};
+ PHP_ME(Channel, __construct, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
+ PHP_ME(Channel, close, NULL, ZEND_ACC_PUBLIC) PHP_FE_END};
-void grpc_init_channel(TSRMLS_D){
+void grpc_init_channel(TSRMLS_D) {
zend_class_entry ce;
INIT_CLASS_ENTRY(ce, "Grpc\\Channel", channel_methods);
ce.create_object = create_wrapped_grpc_channel;
diff --git a/src/php/ext/grpc/completion_queue.c b/src/php/ext/grpc/completion_queue.c
index 0570bd5029..9785eab8cc 100755..100644
--- a/src/php/ext/grpc/completion_queue.c
+++ b/src/php/ext/grpc/completion_queue.c
@@ -20,15 +20,15 @@
#include "timeval.h"
/* Frees and destroys a wrapped instance of grpc_completion_queue */
-void free_wrapped_grpc_completion_queue(void *object TSRMLS_DC){
+void free_wrapped_grpc_completion_queue(void *object TSRMLS_DC) {
wrapped_grpc_completion_queue *queue = NULL;
grpc_event *event;
- queue = (wrapped_grpc_completion_queue*)object;
- if(queue->wrapped != NULL){
+ queue = (wrapped_grpc_completion_queue *)object;
+ if (queue->wrapped != NULL) {
grpc_completion_queue_shutdown(queue->wrapped);
event = grpc_completion_queue_next(queue->wrapped, gpr_inf_future);
- while(event != NULL){
- if(event->type == GRPC_QUEUE_SHUTDOWN){
+ while (event != NULL) {
+ if (event->type == GRPC_QUEUE_SHUTDOWN) {
break;
}
event = grpc_completion_queue_next(queue->wrapped, gpr_inf_future);
@@ -41,21 +41,19 @@ void free_wrapped_grpc_completion_queue(void *object TSRMLS_DC){
/* Initializes an instance of wrapped_grpc_channel to be associated with an
* object of a class specified by class_type */
zend_object_value create_wrapped_grpc_completion_queue(
- zend_class_entry *class_type TSRMLS_DC){
+ zend_class_entry *class_type TSRMLS_DC) {
zend_object_value retval;
wrapped_grpc_completion_queue *intern;
- intern = (wrapped_grpc_completion_queue*)emalloc(
+ intern = (wrapped_grpc_completion_queue *)emalloc(
sizeof(wrapped_grpc_completion_queue));
memset(intern, 0, sizeof(wrapped_grpc_completion_queue));
zend_object_std_init(&intern->std, class_type TSRMLS_CC);
object_properties_init(&intern->std, class_type);
retval.handle = zend_objects_store_put(
- intern,
- (zend_objects_store_dtor_t) zend_objects_destroy_object,
- free_wrapped_grpc_completion_queue,
- NULL TSRMLS_CC);
+ intern, (zend_objects_store_dtor_t)zend_objects_destroy_object,
+ free_wrapped_grpc_completion_queue, NULL TSRMLS_CC);
retval.handlers = zend_get_std_object_handlers();
return retval;
}
@@ -63,10 +61,10 @@ zend_object_value create_wrapped_grpc_completion_queue(
/**
* Construct an instance of CompletionQueue
*/
-PHP_METHOD(CompletionQueue, __construct){
+PHP_METHOD(CompletionQueue, __construct) {
wrapped_grpc_completion_queue *queue =
- (wrapped_grpc_completion_queue*)zend_object_store_get_object(
- getThis() TSRMLS_CC);
+ (wrapped_grpc_completion_queue *)zend_object_store_get_object(
+ getThis() TSRMLS_CC);
queue->wrapped = grpc_completion_queue_create();
}
@@ -78,52 +76,46 @@ PHP_METHOD(CompletionQueue, __construct){
* @param Timeval $timeout The timeout for the event
* @return Event The event that occurred
*/
-PHP_METHOD(CompletionQueue, next){
+PHP_METHOD(CompletionQueue, next) {
zval *timeout;
/* "O" == 1 Object */
- if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
- "O",
- &timeout, grpc_ce_timeval)==FAILURE){
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &timeout,
+ grpc_ce_timeval) == FAILURE) {
zend_throw_exception(spl_ce_InvalidArgumentException,
- "next needs a Timeval",
- 1 TSRMLS_CC);
+ "next needs a Timeval", 1 TSRMLS_CC);
return;
}
wrapped_grpc_completion_queue *completion_queue =
- (wrapped_grpc_completion_queue*)zend_object_store_get_object(
- getThis() TSRMLS_CC);
+ (wrapped_grpc_completion_queue *)zend_object_store_get_object(
+ getThis() TSRMLS_CC);
wrapped_grpc_timeval *wrapped_timeout =
- (wrapped_grpc_timeval*)zend_object_store_get_object(timeout TSRMLS_CC);
+ (wrapped_grpc_timeval *)zend_object_store_get_object(timeout TSRMLS_CC);
grpc_event *event = grpc_completion_queue_next(completion_queue->wrapped,
wrapped_timeout->wrapped);
- if(event == NULL){
+ if (event == NULL) {
RETURN_NULL();
}
zval *wrapped_event = grpc_php_convert_event(event);
RETURN_DESTROY_ZVAL(wrapped_event);
}
-PHP_METHOD(CompletionQueue, pluck){
+PHP_METHOD(CompletionQueue, pluck) {
long tag;
zval *timeout;
/* "lO" == 1 long, 1 Object */
- if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
- "lO",
- &tag,
- &timeout, grpc_ce_timeval)==FAILURE){
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lO", &tag, &timeout,
+ grpc_ce_timeval) == FAILURE) {
zend_throw_exception(spl_ce_InvalidArgumentException,
- "pluck needs a long and a Timeval",
- 1 TSRMLS_CC);
+ "pluck needs a long and a Timeval", 1 TSRMLS_CC);
}
wrapped_grpc_completion_queue *completion_queue =
- (wrapped_grpc_completion_queue*)zend_object_store_get_object(
+ (wrapped_grpc_completion_queue *)zend_object_store_get_object(
getThis() TSRMLS_CC);
wrapped_grpc_timeval *wrapped_timeout =
- (wrapped_grpc_timeval*)zend_object_store_get_object(timeout TSRMLS_CC);
- grpc_event *event = grpc_completion_queue_pluck(completion_queue->wrapped,
- (void*)tag,
- wrapped_timeout->wrapped);
- if(event == NULL){
+ (wrapped_grpc_timeval *)zend_object_store_get_object(timeout TSRMLS_CC);
+ grpc_event *event = grpc_completion_queue_pluck(
+ completion_queue->wrapped, (void *)tag, wrapped_timeout->wrapped);
+ if (event == NULL) {
RETURN_NULL();
}
zval *wrapped_event = grpc_php_convert_event(event);
@@ -131,13 +123,11 @@ PHP_METHOD(CompletionQueue, pluck){
}
static zend_function_entry completion_queue_methods[] = {
- PHP_ME(CompletionQueue, __construct, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
- PHP_ME(CompletionQueue, next, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(CompletionQueue, pluck, NULL, ZEND_ACC_PUBLIC)
- PHP_FE_END
-};
+ PHP_ME(CompletionQueue, __construct, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
+ PHP_ME(CompletionQueue, next, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(CompletionQueue, pluck, NULL, ZEND_ACC_PUBLIC) PHP_FE_END};
-void grpc_init_completion_queue(TSRMLS_D){
+void grpc_init_completion_queue(TSRMLS_D) {
zend_class_entry ce;
INIT_CLASS_ENTRY(ce, "Grpc\\CompletionQueue", completion_queue_methods);
ce.create_object = create_wrapped_grpc_completion_queue;
diff --git a/src/php/ext/grpc/config.m4 b/src/php/ext/grpc/config.m4
index 40e4dd3379..d7d13f413e 100755
--- a/src/php/ext/grpc/config.m4
+++ b/src/php/ext/grpc/config.m4
@@ -32,6 +32,9 @@ if test "$PHP_GRPC" != "no"; then
GRPC_SHARED_LIBADD="-lpthread $GRPC_SHARED_LIBADD"
PHP_ADD_LIBRARY(pthread)
+ PHP_ADD_LIBRARY(dl,,GRPC_SHARED_LIBADD)
+ PHP_ADD_LIBRARY(dl)
+
PHP_ADD_LIBRARY(rt,,GRPC_SHARED_LIBADD)
PHP_ADD_LIBRARY(rt)
diff --git a/src/php/ext/grpc/credentials.c b/src/php/ext/grpc/credentials.c
index ffafddae5f..f486272531 100755..100644
--- a/src/php/ext/grpc/credentials.c
+++ b/src/php/ext/grpc/credentials.c
@@ -17,9 +17,9 @@
#include "grpc/grpc_security.h"
/* Frees and destroys an instance of wrapped_grpc_credentials */
-void free_wrapped_grpc_credentials(void *object TSRMLS_DC){
- wrapped_grpc_credentials *creds = (wrapped_grpc_credentials*)object;
- if(creds->wrapped != NULL) {
+void free_wrapped_grpc_credentials(void *object TSRMLS_DC) {
+ wrapped_grpc_credentials *creds = (wrapped_grpc_credentials *)object;
+ if (creds->wrapped != NULL) {
grpc_credentials_release(creds->wrapped);
}
efree(creds);
@@ -27,32 +27,31 @@ void free_wrapped_grpc_credentials(void *object TSRMLS_DC){
/* Initializes an instance of wrapped_grpc_credentials to be associated with an
* object of a class specified by class_type */
-zend_object_value create_wrapped_grpc_credentials(
- zend_class_entry *class_type TSRMLS_DC){
+zend_object_value create_wrapped_grpc_credentials(zend_class_entry *class_type
+ TSRMLS_DC) {
zend_object_value retval;
wrapped_grpc_credentials *intern;
- intern = (wrapped_grpc_credentials*)emalloc(sizeof(wrapped_grpc_credentials));
+ intern =
+ (wrapped_grpc_credentials *)emalloc(sizeof(wrapped_grpc_credentials));
memset(intern, 0, sizeof(wrapped_grpc_credentials));
zend_object_std_init(&intern->std, class_type TSRMLS_CC);
object_properties_init(&intern->std, class_type);
retval.handle = zend_objects_store_put(
- intern,
- (zend_objects_store_dtor_t) zend_objects_destroy_object,
- free_wrapped_grpc_credentials,
- NULL TSRMLS_CC);
+ intern, (zend_objects_store_dtor_t)zend_objects_destroy_object,
+ free_wrapped_grpc_credentials, NULL TSRMLS_CC);
retval.handlers = zend_get_std_object_handlers();
return retval;
}
-zval *grpc_php_wrap_credentials(grpc_credentials *wrapped){
+zval *grpc_php_wrap_credentials(grpc_credentials *wrapped) {
zval *credentials_object;
MAKE_STD_ZVAL(credentials_object);
object_init_ex(credentials_object, grpc_ce_credentials);
wrapped_grpc_credentials *credentials =
- (wrapped_grpc_credentials*)zend_object_store_get_object(
- credentials_object TSRMLS_CC);
+ (wrapped_grpc_credentials *)zend_object_store_get_object(
+ credentials_object TSRMLS_CC);
credentials->wrapped = wrapped;
return credentials_object;
}
@@ -61,7 +60,7 @@ zval *grpc_php_wrap_credentials(grpc_credentials *wrapped){
* Create a default credentials object.
* @return Credentials The new default credentials object
*/
-PHP_METHOD(Credentials, createDefault){
+PHP_METHOD(Credentials, createDefault) {
grpc_credentials *creds = grpc_default_credentials_create();
zval *creds_object = grpc_php_wrap_credentials(creds);
RETURN_DESTROY_ZVAL(creds_object);
@@ -76,7 +75,7 @@ PHP_METHOD(Credentials, createDefault){
* (optional)
* @return Credentials The new SSL credentials object
*/
-PHP_METHOD(Credentials, createSsl){
+PHP_METHOD(Credentials, createSsl) {
char *pem_root_certs;
char *pem_private_key = NULL;
char *pem_cert_chain = NULL;
@@ -84,20 +83,18 @@ PHP_METHOD(Credentials, createSsl){
int root_certs_length, private_key_length = 0, cert_chain_length = 0;
/* "s|s!s! == 1 string, 2 optional nullable strings */
- if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
- "s|s!s!",
- &pem_root_certs, &root_certs_length,
- &pem_private_key, &private_key_length,
- &pem_cert_chain, &cert_chain_length) == FAILURE) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s!s!",
+ &pem_root_certs, &root_certs_length,
+ &pem_private_key, &private_key_length,
+ &pem_cert_chain, &cert_chain_length) == FAILURE) {
zend_throw_exception(spl_ce_InvalidArgumentException,
- "createSsl expects 1 to 3 strings",
- 1 TSRMLS_CC);
+ "createSsl expects 1 to 3 strings", 1 TSRMLS_CC);
return;
}
grpc_credentials *creds = grpc_ssl_credentials_create(
- (unsigned char*)pem_root_certs, (size_t)root_certs_length,
- (unsigned char*)pem_private_key, (size_t)private_key_length,
- (unsigned char*)pem_cert_chain, (size_t)cert_chain_length);
+ (unsigned char *)pem_root_certs, (size_t)root_certs_length,
+ (unsigned char *)pem_private_key, (size_t)private_key_length,
+ (unsigned char *)pem_cert_chain, (size_t)cert_chain_length);
zval *creds_object = grpc_php_wrap_credentials(creds);
RETURN_DESTROY_ZVAL(creds_object);
}
@@ -108,28 +105,26 @@ PHP_METHOD(Credentials, createSsl){
* @param Credentials cred2 The second credential
* @return Credentials The new composite credentials object
*/
-PHP_METHOD(Credentials, createComposite){
+PHP_METHOD(Credentials, createComposite) {
zval *cred1_obj;
zval *cred2_obj;
/* "OO" == 3 Objects */
- if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
- "OO",
- &cred1_obj, grpc_ce_credentials,
- &cred2_obj, grpc_ce_credentials) == FAILURE) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "OO", &cred1_obj,
+ grpc_ce_credentials, &cred2_obj,
+ grpc_ce_credentials) == FAILURE) {
zend_throw_exception(spl_ce_InvalidArgumentException,
- "createComposite expects 2 Credentials",
- 1 TSRMLS_CC);
+ "createComposite expects 2 Credentials", 1 TSRMLS_CC);
return;
}
wrapped_grpc_credentials *cred1 =
- (wrapped_grpc_credentials*)zend_object_store_get_object(
+ (wrapped_grpc_credentials *)zend_object_store_get_object(
cred1_obj TSRMLS_CC);
wrapped_grpc_credentials *cred2 =
- (wrapped_grpc_credentials*)zend_object_store_get_object(
+ (wrapped_grpc_credentials *)zend_object_store_get_object(
cred2_obj TSRMLS_CC);
- grpc_credentials *creds = grpc_composite_credentials_create(cred1->wrapped,
- cred2->wrapped);
+ grpc_credentials *creds =
+ grpc_composite_credentials_create(cred1->wrapped, cred2->wrapped);
zval *creds_object = grpc_php_wrap_credentials(creds);
RETURN_DESTROY_ZVAL(creds_object);
}
@@ -155,15 +150,16 @@ PHP_METHOD(Credentials, createFake) {
}
static zend_function_entry credentials_methods[] = {
- PHP_ME(Credentials, createDefault, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
- PHP_ME(Credentials, createSsl, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
- PHP_ME(Credentials, createComposite, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
- PHP_ME(Credentials, createGce, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
- PHP_ME(Credentials, createFake, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
- PHP_FE_END
-};
-
-void grpc_init_credentials(TSRMLS_D){
+ PHP_ME(Credentials, createDefault, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+ PHP_ME(Credentials, createSsl, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+ PHP_ME(Credentials, createComposite, NULL,
+ ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+ PHP_ME(Credentials, createGce, NULL,
+ ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+ PHP_ME(Credentials, createFake, NULL,
+ ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) PHP_FE_END};
+
+void grpc_init_credentials(TSRMLS_D) {
zend_class_entry ce;
INIT_CLASS_ENTRY(ce, "Grpc\\Credentials", credentials_methods);
ce.create_object = create_wrapped_grpc_credentials;
diff --git a/src/php/ext/grpc/event.c b/src/php/ext/grpc/event.c
index c15f479448..b4069f72f0 100755..100644
--- a/src/php/ext/grpc/event.c
+++ b/src/php/ext/grpc/event.c
@@ -32,24 +32,25 @@ zval *grpc_php_convert_event(grpc_event *event) {
zval *event_object;
- if(event == NULL) {
+ if (event == NULL) {
return NULL;
}
MAKE_STD_ZVAL(event_object);
object_init(event_object);
- add_property_zval(event_object,
- "call",
- grpc_php_wrap_call(event->call,
- event->type==GRPC_SERVER_RPC_NEW));
+ add_property_zval(
+ event_object, "call",
+ grpc_php_wrap_call(event->call, event->type == GRPC_SERVER_RPC_NEW));
add_property_long(event_object, "type", event->type);
add_property_long(event_object, "tag", (long)event->tag);
- switch(event->type){
- case GRPC_QUEUE_SHUTDOWN: add_property_null(event_object, "data"); break;
+ switch (event->type) {
+ case GRPC_QUEUE_SHUTDOWN:
+ add_property_null(event_object, "data");
+ break;
case GRPC_READ:
- if(event->data.read == NULL){
+ if (event->data.read == NULL) {
add_property_null(event_object, "data");
} else {
byte_buffer_to_string(event->data.read, &read_string, &read_len);
@@ -57,16 +58,14 @@ zval *grpc_php_convert_event(grpc_event *event) {
}
break;
case GRPC_INVOKE_ACCEPTED:
- add_property_long(event_object,
- "data",
+ add_property_long(event_object, "data",
(long)event->data.invoke_accepted);
break;
case GRPC_WRITE_ACCEPTED:
add_property_long(event_object, "data", (long)event->data.write_accepted);
break;
case GRPC_FINISH_ACCEPTED:
- add_property_long(event_object,
- "data",
+ add_property_long(event_object, "data",
(long)event->data.finish_accepted);
break;
case GRPC_CLIENT_METADATA_READ:
@@ -79,19 +78,15 @@ zval *grpc_php_convert_event(grpc_event *event) {
MAKE_STD_ZVAL(data_object);
object_init(data_object);
add_property_long(data_object, "code", event->data.finished.status);
- if(event->data.finished.details == NULL){
+ if (event->data.finished.details == NULL) {
add_property_null(data_object, "details");
} else {
detail_len = strlen(event->data.finished.details);
- detail_string = ecalloc(detail_len+1, sizeof(char));
+ detail_string = ecalloc(detail_len + 1, sizeof(char));
memcpy(detail_string, event->data.finished.details, detail_len);
- add_property_string(data_object,
- "details",
- detail_string,
- true);
+ add_property_string(data_object, "details", detail_string, true);
}
- add_property_zval(data_object,
- "metadata",
+ add_property_zval(data_object, "metadata",
grpc_call_create_metadata_array(
event->data.finished.metadata_count,
event->data.finished.metadata_elements));
@@ -101,31 +96,25 @@ zval *grpc_php_convert_event(grpc_event *event) {
MAKE_STD_ZVAL(data_object);
object_init(data_object);
method_len = strlen(event->data.server_rpc_new.method);
- method_string = ecalloc(method_len+1, sizeof(char));
+ method_string = ecalloc(method_len + 1, sizeof(char));
memcpy(method_string, event->data.server_rpc_new.method, method_len);
- add_property_string(data_object,
- "method",
- method_string,
- false);
+ add_property_string(data_object, "method", method_string, false);
host_len = strlen(event->data.server_rpc_new.host);
- host_string = ecalloc(host_len+1, sizeof(char));
+ host_string = ecalloc(host_len + 1, sizeof(char));
memcpy(host_string, event->data.server_rpc_new.host, host_len);
- add_property_string(data_object,
- "host",
- host_string,
- false);
- add_property_zval(data_object,
- "absolute_timeout",
- grpc_php_wrap_timeval(
- event->data.server_rpc_new.deadline));
- add_property_zval(data_object,
- "metadata",
+ add_property_string(data_object, "host", host_string, false);
+ add_property_zval(
+ data_object, "absolute_timeout",
+ grpc_php_wrap_timeval(event->data.server_rpc_new.deadline));
+ add_property_zval(data_object, "metadata",
grpc_call_create_metadata_array(
event->data.server_rpc_new.metadata_count,
event->data.server_rpc_new.metadata_elements));
add_property_zval(event_object, "data", data_object);
break;
- default: add_property_null(event_object, "data"); break;
+ default:
+ add_property_null(event_object, "data");
+ break;
}
grpc_event_finish(event);
return event_object;
diff --git a/src/php/ext/grpc/php_grpc.c b/src/php/ext/grpc/php_grpc.c
index 71449bfd06..c1042293aa 100755..100644
--- a/src/php/ext/grpc/php_grpc.c
+++ b/src/php/ext/grpc/php_grpc.c
@@ -16,14 +16,14 @@
#include "ext/standard/info.h"
#include "php_grpc.h"
-//ZEND_DECLARE_MODULE_GLOBALS(grpc)
+// ZEND_DECLARE_MODULE_GLOBALS(grpc)
/* {{{ grpc_functions[]
*
* Every user visible function must have an entry in grpc_functions[].
*/
const zend_function_entry grpc_functions[] = {
- PHP_FE_END /* Must be the last line in grpc_functions[] */
+ PHP_FE_END /* Must be the last line in grpc_functions[] */
};
/* }}} */
@@ -33,18 +33,12 @@ zend_module_entry grpc_module_entry = {
#if ZEND_MODULE_API_NO >= 20010901
STANDARD_MODULE_HEADER,
#endif
- "grpc",
- grpc_functions,
- PHP_MINIT(grpc),
- PHP_MSHUTDOWN(grpc),
- NULL,
- NULL,
+ "grpc", grpc_functions, PHP_MINIT(grpc), PHP_MSHUTDOWN(grpc), NULL, NULL,
PHP_MINFO(grpc),
#if ZEND_MODULE_API_NO >= 20010901
PHP_GRPC_VERSION,
#endif
- STANDARD_MODULE_PROPERTIES
-};
+ STANDARD_MODULE_PROPERTIES};
/* }}} */
#ifdef COMPILE_DL_GRPC
@@ -55,8 +49,10 @@ ZEND_GET_MODULE(grpc)
*/
/* Remove comments and fill if you need to have entries in php.ini
PHP_INI_BEGIN()
- STD_PHP_INI_ENTRY("grpc.global_value", "42", PHP_INI_ALL, OnUpdateLong, global_value, zend_grpc_globals, grpc_globals)
- STD_PHP_INI_ENTRY("grpc.global_string", "foobar", PHP_INI_ALL, OnUpdateString, global_string, zend_grpc_globals, grpc_globals)
+ STD_PHP_INI_ENTRY("grpc.global_value", "42", PHP_INI_ALL, OnUpdateLong,
+global_value, zend_grpc_globals, grpc_globals)
+ STD_PHP_INI_ENTRY("grpc.global_string", "foobar", PHP_INI_ALL,
+OnUpdateString, global_string, zend_grpc_globals, grpc_globals)
PHP_INI_END()
*/
/* }}} */
@@ -74,159 +70,118 @@ static void php_grpc_init_globals(zend_grpc_globals *grpc_globals)
/* {{{ PHP_MINIT_FUNCTION
*/
-PHP_MINIT_FUNCTION(grpc)
-{
- /* If you have INI entries, uncomment these lines
- REGISTER_INI_ENTRIES();
- */
- /* Register call error constants */
- grpc_init();
- REGISTER_LONG_CONSTANT("Grpc\\CALL_OK", GRPC_CALL_OK, CONST_CS);
- REGISTER_LONG_CONSTANT("Grpc\\CALL_ERROR", GRPC_CALL_ERROR, CONST_CS);
- REGISTER_LONG_CONSTANT("Grpc\\CALL_ERROR_NOT_ON_SERVER",
- GRPC_CALL_ERROR_NOT_ON_SERVER,
- CONST_CS);
- REGISTER_LONG_CONSTANT("Grpc\\CALL_ERROR_NOT_ON_CLIENT",
- GRPC_CALL_ERROR_NOT_ON_CLIENT,
- CONST_CS);
- REGISTER_LONG_CONSTANT("Grpc\\CALL_ERROR_ALREADY_INVOKED",
- GRPC_CALL_ERROR_ALREADY_INVOKED,
- CONST_CS);
- REGISTER_LONG_CONSTANT("Grpc\\CALL_ERROR_NOT_INVOKED",
- GRPC_CALL_ERROR_NOT_INVOKED,
- CONST_CS);
- REGISTER_LONG_CONSTANT("Grpc\\CALL_ERROR_ALREADY_FINISHED",
- GRPC_CALL_ERROR_ALREADY_FINISHED,
- CONST_CS);
- REGISTER_LONG_CONSTANT("Grpc\\CALL_ERROR_TOO_MANY_OPERATIONS",
- GRPC_CALL_ERROR_TOO_MANY_OPERATIONS,
- CONST_CS);
- REGISTER_LONG_CONSTANT("Grpc\\CALL_ERROR_INVALID_FLAGS",
- GRPC_CALL_ERROR_INVALID_FLAGS,
- CONST_CS);
-
- /* Register op error constants */
- REGISTER_LONG_CONSTANT("Grpc\\OP_OK", GRPC_OP_OK, CONST_CS);
- REGISTER_LONG_CONSTANT("Grpc\\OP_ERROR", GRPC_OP_ERROR, CONST_CS);
-
- /* Register flag constants */
- REGISTER_LONG_CONSTANT("Grpc\\WRITE_BUFFER_HINT",
- GRPC_WRITE_BUFFER_HINT,
- CONST_CS);
- REGISTER_LONG_CONSTANT("Grpc\\WRITE_NO_COMPRESS",
- GRPC_WRITE_NO_COMPRESS,
- CONST_CS);
-
- /* Register completion type constants */
- REGISTER_LONG_CONSTANT("Grpc\\QUEUE_SHUTDOWN",
- GRPC_QUEUE_SHUTDOWN,
- CONST_CS);
- REGISTER_LONG_CONSTANT("Grpc\\READ", GRPC_READ, CONST_CS);
- REGISTER_LONG_CONSTANT("Grpc\\INVOKE_ACCEPTED",
- GRPC_INVOKE_ACCEPTED,
- CONST_CS);
- REGISTER_LONG_CONSTANT("Grpc\\WRITE_ACCEPTED",
- GRPC_WRITE_ACCEPTED,
- CONST_CS);
- REGISTER_LONG_CONSTANT("Grpc\\FINISH_ACCEPTED",
- GRPC_FINISH_ACCEPTED,
- CONST_CS);
- REGISTER_LONG_CONSTANT("Grpc\\CLIENT_METADATA_READ",
- GRPC_CLIENT_METADATA_READ,
- CONST_CS);
- REGISTER_LONG_CONSTANT("Grpc\\FINISHED", GRPC_FINISHED, CONST_CS);
- REGISTER_LONG_CONSTANT("Grpc\\SERVER_RPC_NEW",
- GRPC_SERVER_RPC_NEW,
- CONST_CS);
-
- /* Register status constants */
- REGISTER_LONG_CONSTANT("Grpc\\STATUS_OK",
- GRPC_STATUS_OK,
- CONST_CS);
- REGISTER_LONG_CONSTANT("Grpc\\STATUS_CANCELLED",
- GRPC_STATUS_CANCELLED,
- CONST_CS);
- REGISTER_LONG_CONSTANT("Grpc\\STATUS_UNKNOWN",
- GRPC_STATUS_UNKNOWN,
- CONST_CS);
- REGISTER_LONG_CONSTANT("Grpc\\STATUS_INVALID_ARGUMENT",
- GRPC_STATUS_INVALID_ARGUMENT,
- CONST_CS);
- REGISTER_LONG_CONSTANT("Grpc\\STATUS_DEADLINE_EXCEEDED",
- GRPC_STATUS_DEADLINE_EXCEEDED,
- CONST_CS);
- REGISTER_LONG_CONSTANT("Grpc\\STATUS_NOT_FOUND",
- GRPC_STATUS_NOT_FOUND,
- CONST_CS);
- REGISTER_LONG_CONSTANT("Grpc\\STATUS_ALREADY_EXISTS",
- GRPC_STATUS_ALREADY_EXISTS,
- CONST_CS);
- REGISTER_LONG_CONSTANT("Grpc\\STATUS_PERMISSION_DENIED",
- GRPC_STATUS_PERMISSION_DENIED,
- CONST_CS);
- REGISTER_LONG_CONSTANT("Grpc\\STATUS_UNAUTHENTICATED",
- GRPC_STATUS_UNAUTHENTICATED,
- CONST_CS);
- REGISTER_LONG_CONSTANT("Grpc\\STATUS_RESOURCE_EXHAUSTED",
- GRPC_STATUS_RESOURCE_EXHAUSTED,
- CONST_CS);
- REGISTER_LONG_CONSTANT("Grpc\\STATUS_FAILED_PRECONDITION",
- GRPC_STATUS_FAILED_PRECONDITION,
- CONST_CS);
- REGISTER_LONG_CONSTANT("Grpc\\STATUS_ABORTED",
- GRPC_STATUS_ABORTED,
- CONST_CS);
- REGISTER_LONG_CONSTANT("Grpc\\STATUS_OUT_OF_RANGE",
- GRPC_STATUS_OUT_OF_RANGE,
- CONST_CS);
- REGISTER_LONG_CONSTANT("Grpc\\STATUS_UNIMPLEMENTED",
- GRPC_STATUS_UNIMPLEMENTED,
- CONST_CS);
- REGISTER_LONG_CONSTANT("Grpc\\STATUS_INTERNAL",
- GRPC_STATUS_INTERNAL,
- CONST_CS);
- REGISTER_LONG_CONSTANT("Grpc\\STATUS_UNAVAILABLE",
- GRPC_STATUS_UNAVAILABLE,
- CONST_CS);
- REGISTER_LONG_CONSTANT("Grpc\\STATUS_DATA_LOSS",
- GRPC_STATUS_DATA_LOSS,
- CONST_CS);
-
- grpc_init_call(TSRMLS_C);
- grpc_init_channel(TSRMLS_C);
- grpc_init_server(TSRMLS_C);
- grpc_init_completion_queue(TSRMLS_C);
- grpc_init_timeval(TSRMLS_C);
- grpc_init_credentials(TSRMLS_C);
- grpc_init_server_credentials(TSRMLS_C);
- return SUCCESS;
+PHP_MINIT_FUNCTION(grpc) {
+ /* If you have INI entries, uncomment these lines
+ REGISTER_INI_ENTRIES();
+ */
+ /* Register call error constants */
+ grpc_init();
+ REGISTER_LONG_CONSTANT("Grpc\\CALL_OK", GRPC_CALL_OK, CONST_CS);
+ REGISTER_LONG_CONSTANT("Grpc\\CALL_ERROR", GRPC_CALL_ERROR, CONST_CS);
+ REGISTER_LONG_CONSTANT("Grpc\\CALL_ERROR_NOT_ON_SERVER",
+ GRPC_CALL_ERROR_NOT_ON_SERVER, CONST_CS);
+ REGISTER_LONG_CONSTANT("Grpc\\CALL_ERROR_NOT_ON_CLIENT",
+ GRPC_CALL_ERROR_NOT_ON_CLIENT, CONST_CS);
+ REGISTER_LONG_CONSTANT("Grpc\\CALL_ERROR_ALREADY_INVOKED",
+ GRPC_CALL_ERROR_ALREADY_INVOKED, CONST_CS);
+ REGISTER_LONG_CONSTANT("Grpc\\CALL_ERROR_NOT_INVOKED",
+ GRPC_CALL_ERROR_NOT_INVOKED, CONST_CS);
+ REGISTER_LONG_CONSTANT("Grpc\\CALL_ERROR_ALREADY_FINISHED",
+ GRPC_CALL_ERROR_ALREADY_FINISHED, CONST_CS);
+ REGISTER_LONG_CONSTANT("Grpc\\CALL_ERROR_TOO_MANY_OPERATIONS",
+ GRPC_CALL_ERROR_TOO_MANY_OPERATIONS, CONST_CS);
+ REGISTER_LONG_CONSTANT("Grpc\\CALL_ERROR_INVALID_FLAGS",
+ GRPC_CALL_ERROR_INVALID_FLAGS, CONST_CS);
+
+ /* Register op error constants */
+ REGISTER_LONG_CONSTANT("Grpc\\OP_OK", GRPC_OP_OK, CONST_CS);
+ REGISTER_LONG_CONSTANT("Grpc\\OP_ERROR", GRPC_OP_ERROR, CONST_CS);
+
+ /* Register flag constants */
+ REGISTER_LONG_CONSTANT("Grpc\\WRITE_BUFFER_HINT", GRPC_WRITE_BUFFER_HINT,
+ CONST_CS);
+ REGISTER_LONG_CONSTANT("Grpc\\WRITE_NO_COMPRESS", GRPC_WRITE_NO_COMPRESS,
+ CONST_CS);
+
+ /* Register completion type constants */
+ REGISTER_LONG_CONSTANT("Grpc\\QUEUE_SHUTDOWN", GRPC_QUEUE_SHUTDOWN, CONST_CS);
+ REGISTER_LONG_CONSTANT("Grpc\\READ", GRPC_READ, CONST_CS);
+ REGISTER_LONG_CONSTANT("Grpc\\INVOKE_ACCEPTED", GRPC_INVOKE_ACCEPTED,
+ CONST_CS);
+ REGISTER_LONG_CONSTANT("Grpc\\WRITE_ACCEPTED", GRPC_WRITE_ACCEPTED, CONST_CS);
+ REGISTER_LONG_CONSTANT("Grpc\\FINISH_ACCEPTED", GRPC_FINISH_ACCEPTED,
+ CONST_CS);
+ REGISTER_LONG_CONSTANT("Grpc\\CLIENT_METADATA_READ",
+ GRPC_CLIENT_METADATA_READ, CONST_CS);
+ REGISTER_LONG_CONSTANT("Grpc\\FINISHED", GRPC_FINISHED, CONST_CS);
+ REGISTER_LONG_CONSTANT("Grpc\\SERVER_RPC_NEW", GRPC_SERVER_RPC_NEW, CONST_CS);
+
+ /* Register status constants */
+ REGISTER_LONG_CONSTANT("Grpc\\STATUS_OK", GRPC_STATUS_OK, CONST_CS);
+ REGISTER_LONG_CONSTANT("Grpc\\STATUS_CANCELLED", GRPC_STATUS_CANCELLED,
+ CONST_CS);
+ REGISTER_LONG_CONSTANT("Grpc\\STATUS_UNKNOWN", GRPC_STATUS_UNKNOWN, CONST_CS);
+ REGISTER_LONG_CONSTANT("Grpc\\STATUS_INVALID_ARGUMENT",
+ GRPC_STATUS_INVALID_ARGUMENT, CONST_CS);
+ REGISTER_LONG_CONSTANT("Grpc\\STATUS_DEADLINE_EXCEEDED",
+ GRPC_STATUS_DEADLINE_EXCEEDED, CONST_CS);
+ REGISTER_LONG_CONSTANT("Grpc\\STATUS_NOT_FOUND", GRPC_STATUS_NOT_FOUND,
+ CONST_CS);
+ REGISTER_LONG_CONSTANT("Grpc\\STATUS_ALREADY_EXISTS",
+ GRPC_STATUS_ALREADY_EXISTS, CONST_CS);
+ REGISTER_LONG_CONSTANT("Grpc\\STATUS_PERMISSION_DENIED",
+ GRPC_STATUS_PERMISSION_DENIED, CONST_CS);
+ REGISTER_LONG_CONSTANT("Grpc\\STATUS_UNAUTHENTICATED",
+ GRPC_STATUS_UNAUTHENTICATED, CONST_CS);
+ REGISTER_LONG_CONSTANT("Grpc\\STATUS_RESOURCE_EXHAUSTED",
+ GRPC_STATUS_RESOURCE_EXHAUSTED, CONST_CS);
+ REGISTER_LONG_CONSTANT("Grpc\\STATUS_FAILED_PRECONDITION",
+ GRPC_STATUS_FAILED_PRECONDITION, CONST_CS);
+ REGISTER_LONG_CONSTANT("Grpc\\STATUS_ABORTED", GRPC_STATUS_ABORTED, CONST_CS);
+ REGISTER_LONG_CONSTANT("Grpc\\STATUS_OUT_OF_RANGE", GRPC_STATUS_OUT_OF_RANGE,
+ CONST_CS);
+ REGISTER_LONG_CONSTANT("Grpc\\STATUS_UNIMPLEMENTED",
+ GRPC_STATUS_UNIMPLEMENTED, CONST_CS);
+ REGISTER_LONG_CONSTANT("Grpc\\STATUS_INTERNAL", GRPC_STATUS_INTERNAL,
+ CONST_CS);
+ REGISTER_LONG_CONSTANT("Grpc\\STATUS_UNAVAILABLE", GRPC_STATUS_UNAVAILABLE,
+ CONST_CS);
+ REGISTER_LONG_CONSTANT("Grpc\\STATUS_DATA_LOSS", GRPC_STATUS_DATA_LOSS,
+ CONST_CS);
+
+ grpc_init_call(TSRMLS_C);
+ grpc_init_channel(TSRMLS_C);
+ grpc_init_server(TSRMLS_C);
+ grpc_init_completion_queue(TSRMLS_C);
+ grpc_init_timeval(TSRMLS_C);
+ grpc_init_credentials(TSRMLS_C);
+ grpc_init_server_credentials(TSRMLS_C);
+ return SUCCESS;
}
/* }}} */
/* {{{ PHP_MSHUTDOWN_FUNCTION
*/
-PHP_MSHUTDOWN_FUNCTION(grpc)
-{
- /* uncomment this line if you have INI entries
- UNREGISTER_INI_ENTRIES();
- */
- grpc_shutdown_timeval(TSRMLS_C);
- grpc_shutdown();
- return SUCCESS;
+PHP_MSHUTDOWN_FUNCTION(grpc) {
+ /* uncomment this line if you have INI entries
+ UNREGISTER_INI_ENTRIES();
+ */
+ grpc_shutdown_timeval(TSRMLS_C);
+ grpc_shutdown();
+ return SUCCESS;
}
/* }}} */
/* {{{ PHP_MINFO_FUNCTION
*/
-PHP_MINFO_FUNCTION(grpc)
-{
- php_info_print_table_start();
- php_info_print_table_header(2, "grpc support", "enabled");
- php_info_print_table_end();
-
- /* Remove comments if you have entries in php.ini
- DISPLAY_INI_ENTRIES();
- */
+PHP_MINFO_FUNCTION(grpc) {
+ php_info_print_table_start();
+ php_info_print_table_header(2, "grpc support", "enabled");
+ php_info_print_table_end();
+
+ /* Remove comments if you have entries in php.ini
+ DISPLAY_INI_ENTRIES();
+ */
}
/* }}} */
/* The previous line is meant for vim and emacs, so it can correctly fold and
@@ -235,7 +190,6 @@ PHP_MINFO_FUNCTION(grpc)
follow this convention for the convenience of others editing your code.
*/
-
/*
* Local variables:
* tab-width: 4
diff --git a/src/php/ext/grpc/php_grpc.h b/src/php/ext/grpc/php_grpc.h
index 777e0c4368..53cc5dcf6e 100755..100644
--- a/src/php/ext/grpc/php_grpc.h
+++ b/src/php/ext/grpc/php_grpc.h
@@ -7,14 +7,15 @@
extern zend_module_entry grpc_module_entry;
#define phpext_grpc_ptr &grpc_module_entry
-#define PHP_GRPC_VERSION "0.1.0" /* Replace with version number for your extension */
+#define PHP_GRPC_VERSION \
+ "0.1.0" /* Replace with version number for your extension */
#ifdef PHP_WIN32
-# define PHP_GRPC_API __declspec(dllexport)
+#define PHP_GRPC_API __declspec(dllexport)
#elif defined(__GNUC__) && __GNUC__ >= 4
-# define PHP_GRPC_API __attribute__ ((visibility("default")))
+#define PHP_GRPC_API __attribute__((visibility("default")))
#else
-# define PHP_GRPC_API
+#define PHP_GRPC_API
#endif
#ifdef ZTS
@@ -25,11 +26,9 @@ extern zend_module_entry grpc_module_entry;
#include "grpc/grpc.h"
-#define RETURN_DESTROY_ZVAL(val) \
- RETURN_ZVAL( \
- val, \
- false /* Don't execute copy constructor */, \
- true /* Dealloc original before returning */)
+#define RETURN_DESTROY_ZVAL(val) \
+ RETURN_ZVAL(val, false /* Don't execute copy constructor */, \
+ true /* Dealloc original before returning */)
/* These are all function declarations */
/* Code that runs at module initialization */
@@ -40,8 +39,8 @@ PHP_MSHUTDOWN_FUNCTION(grpc);
PHP_MINFO_FUNCTION(grpc);
/*
- Declare any global variables you may need between the BEGIN
- and END macros here:
+ Declare any global variables you may need between the BEGIN
+ and END macros here:
ZEND_BEGIN_MODULE_GLOBALS(grpc)
ZEND_END_MODULE_GLOBALS(grpc)
@@ -63,4 +62,4 @@ ZEND_END_MODULE_GLOBALS(grpc)
#define GRPC_G(v) (grpc_globals.v)
#endif
-#endif /* PHP_GRPC_H */
+#endif /* PHP_GRPC_H */
diff --git a/src/php/ext/grpc/server.c b/src/php/ext/grpc/server.c
index 5af42f76ee..f484375712 100755..100644
--- a/src/php/ext/grpc/server.c
+++ b/src/php/ext/grpc/server.c
@@ -24,9 +24,9 @@
#include "server_credentials.h"
/* Frees and destroys an instance of wrapped_grpc_server */
-void free_wrapped_grpc_server(void *object TSRMLS_DC){
- wrapped_grpc_server *server = (wrapped_grpc_server*)object;
- if(server->wrapped != NULL){
+void free_wrapped_grpc_server(void *object TSRMLS_DC) {
+ wrapped_grpc_server *server = (wrapped_grpc_server *)object;
+ if (server->wrapped != NULL) {
grpc_server_shutdown(server->wrapped);
grpc_server_destroy(server->wrapped);
}
@@ -35,21 +35,19 @@ void free_wrapped_grpc_server(void *object TSRMLS_DC){
/* Initializes an instance of wrapped_grpc_call to be associated with an object
* of a class specified by class_type */
-zend_object_value create_wrapped_grpc_server(
- zend_class_entry *class_type TSRMLS_DC){
+zend_object_value create_wrapped_grpc_server(zend_class_entry *class_type
+ TSRMLS_DC) {
zend_object_value retval;
wrapped_grpc_server *intern;
- intern = (wrapped_grpc_server*)emalloc(sizeof(wrapped_grpc_server));
+ intern = (wrapped_grpc_server *)emalloc(sizeof(wrapped_grpc_server));
memset(intern, 0, sizeof(wrapped_grpc_server));
zend_object_std_init(&intern->std, class_type TSRMLS_CC);
object_properties_init(&intern->std, class_type);
retval.handle = zend_objects_store_put(
- intern,
- (zend_objects_store_dtor_t) zend_objects_destroy_object,
- free_wrapped_grpc_server,
- NULL TSRMLS_CC);
+ intern, (zend_objects_store_dtor_t)zend_objects_destroy_object,
+ free_wrapped_grpc_server, NULL TSRMLS_CC);
retval.handlers = zend_get_std_object_handlers();
return retval;
}
@@ -59,9 +57,9 @@ zend_object_value create_wrapped_grpc_server(
* @param CompletionQueue $queue The completion queue to use with the server
* @param array $args The arguments to pass to the server (optional)
*/
-PHP_METHOD(Server, __construct){
+PHP_METHOD(Server, __construct) {
wrapped_grpc_server *server =
- (wrapped_grpc_server*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ (wrapped_grpc_server *)zend_object_store_get_object(getThis() TSRMLS_CC);
zval *queue_obj;
zval *args_array = NULL;
grpc_channel_args args;
@@ -69,10 +67,8 @@ PHP_METHOD(Server, __construct){
zval **creds_obj = NULL;
wrapped_grpc_server_credentials *creds = NULL;
/* "O|a" == 1 Object, 1 optional array */
- if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
- "O|a",
- &queue_obj, grpc_ce_completion_queue,
- &args_array) == FAILURE){
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|a", &queue_obj,
+ grpc_ce_completion_queue, &args_array) == FAILURE) {
zend_throw_exception(spl_ce_InvalidArgumentException,
"Server expects a CompletionQueue and an array",
1 TSRMLS_CC);
@@ -80,24 +76,22 @@ PHP_METHOD(Server, __construct){
}
add_property_zval(getThis(), "completion_queue", queue_obj);
wrapped_grpc_completion_queue *queue =
- (wrapped_grpc_completion_queue*)zend_object_store_get_object(
- queue_obj TSRMLS_CC);
+ (wrapped_grpc_completion_queue *)zend_object_store_get_object(
+ queue_obj TSRMLS_CC);
if (args_array == NULL) {
server->wrapped = grpc_server_create(queue->wrapped, NULL);
} else {
array_hash = Z_ARRVAL_P(args_array);
- if(zend_hash_find(array_hash,
- "credentials",
- sizeof("credentials"),
- (void**)&creds_obj) == SUCCESS) {
- if(zend_get_class_entry(*creds_obj TSRMLS_CC) !=
- grpc_ce_server_credentials) {
+ if (zend_hash_find(array_hash, "credentials", sizeof("credentials"),
+ (void **)&creds_obj) == SUCCESS) {
+ if (zend_get_class_entry(*creds_obj TSRMLS_CC) !=
+ grpc_ce_server_credentials) {
zend_throw_exception(spl_ce_InvalidArgumentException,
"credentials must be a ServerCredentials object",
1 TSRMLS_CC);
return;
}
- creds = (wrapped_grpc_server_credentials*)zend_object_store_get_object(
+ creds = (wrapped_grpc_server_credentials *)zend_object_store_get_object(
*creds_obj TSRMLS_CC);
zend_hash_del(array_hash, "credentials", sizeof("credentials"));
}
@@ -106,9 +100,8 @@ PHP_METHOD(Server, __construct){
server->wrapped = grpc_server_create(queue->wrapped, &args);
} else {
gpr_log(GPR_DEBUG, "Initialized secure server");
- server->wrapped = grpc_secure_server_create(creds->wrapped,
- queue->wrapped,
- &args);
+ server->wrapped =
+ grpc_secure_server_create(creds->wrapped, queue->wrapped, &args);
}
efree(args.args);
}
@@ -120,21 +113,19 @@ PHP_METHOD(Server, __construct){
* @param long $tag_cancel The tag to use if the call is cancelled
* @return Void
*/
-PHP_METHOD(Server, request_call){
+PHP_METHOD(Server, request_call) {
grpc_call_error error_code;
wrapped_grpc_server *server =
- (wrapped_grpc_server*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ (wrapped_grpc_server *)zend_object_store_get_object(getThis() TSRMLS_CC);
long tag_new;
/* "l" == 1 long */
- if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
- "l",
- &tag_new) == FAILURE){
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &tag_new) ==
+ FAILURE) {
zend_throw_exception(spl_ce_InvalidArgumentException,
- "request_call expects a long",
- 1 TSRMLS_CC);
+ "request_call expects a long", 1 TSRMLS_CC);
return;
}
- error_code = grpc_server_request_call(server->wrapped, (void*)tag_new);
+ error_code = grpc_server_request_call(server->wrapped, (void *)tag_new);
MAYBE_THROW_CALL_ERROR(request_call, error_code);
}
@@ -143,35 +134,31 @@ PHP_METHOD(Server, request_call){
* @param string $addr The address to add
* @return true on success, false on failure
*/
-PHP_METHOD(Server, add_http2_port){
+PHP_METHOD(Server, add_http2_port) {
wrapped_grpc_server *server =
- (wrapped_grpc_server*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ (wrapped_grpc_server *)zend_object_store_get_object(getThis() TSRMLS_CC);
const char *addr;
int addr_len;
/* "s" == 1 string */
- if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
- "s",
- &addr, &addr_len) == FAILURE){
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &addr, &addr_len) ==
+ FAILURE) {
zend_throw_exception(spl_ce_InvalidArgumentException,
- "add_http2_port expects a string",
- 1 TSRMLS_CC);
+ "add_http2_port expects a string", 1 TSRMLS_CC);
return;
}
RETURN_BOOL(grpc_server_add_http2_port(server->wrapped, addr));
}
-PHP_METHOD(Server, add_secure_http2_port){
+PHP_METHOD(Server, add_secure_http2_port) {
wrapped_grpc_server *server =
- (wrapped_grpc_server*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ (wrapped_grpc_server *)zend_object_store_get_object(getThis() TSRMLS_CC);
const char *addr;
int addr_len;
/* "s" == 1 string */
- if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
- "s",
- &addr, &addr_len) == FAILURE){
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &addr, &addr_len) ==
+ FAILURE) {
zend_throw_exception(spl_ce_InvalidArgumentException,
- "add_http2_port expects a string",
- 1 TSRMLS_CC);
+ "add_http2_port expects a string", 1 TSRMLS_CC);
return;
}
RETURN_BOOL(grpc_server_add_secure_http2_port(server->wrapped, addr));
@@ -181,22 +168,20 @@ PHP_METHOD(Server, add_secure_http2_port){
* Start a server - tells all listeners to start listening
* @return Void
*/
-PHP_METHOD(Server, start){
+PHP_METHOD(Server, start) {
wrapped_grpc_server *server =
- (wrapped_grpc_server*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ (wrapped_grpc_server *)zend_object_store_get_object(getThis() TSRMLS_CC);
grpc_server_start(server->wrapped);
}
static zend_function_entry server_methods[] = {
- PHP_ME(Server, __construct, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
- PHP_ME(Server, request_call, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(Server, add_http2_port, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(Server, add_secure_http2_port, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(Server, start, NULL, ZEND_ACC_PUBLIC)
- PHP_FE_END
-};
-
-void grpc_init_server(TSRMLS_D){
+ PHP_ME(Server, __construct, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
+ PHP_ME(Server, request_call, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(Server, add_http2_port, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(Server, add_secure_http2_port, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(Server, start, NULL, ZEND_ACC_PUBLIC) PHP_FE_END};
+
+void grpc_init_server(TSRMLS_D) {
zend_class_entry ce;
INIT_CLASS_ENTRY(ce, "Grpc\\Server", server_methods);
ce.create_object = create_wrapped_grpc_server;
diff --git a/src/php/ext/grpc/server_credentials.c b/src/php/ext/grpc/server_credentials.c
index b07790b4be..5b9ab3390d 100755..100644
--- a/src/php/ext/grpc/server_credentials.c
+++ b/src/php/ext/grpc/server_credentials.c
@@ -17,10 +17,10 @@
#include "grpc/grpc_security.h"
/* Frees and destroys an instace of wrapped_grpc_server_credentials */
-void free_wrapped_grpc_server_credentials(void *object TSRMLS_DC){
+void free_wrapped_grpc_server_credentials(void *object TSRMLS_DC) {
wrapped_grpc_server_credentials *creds =
- (wrapped_grpc_server_credentials*)object;
- if(creds->wrapped != NULL) {
+ (wrapped_grpc_server_credentials *)object;
+ if (creds->wrapped != NULL) {
grpc_server_credentials_release(creds->wrapped);
}
efree(creds);
@@ -29,32 +29,30 @@ void free_wrapped_grpc_server_credentials(void *object TSRMLS_DC){
/* Initializes an instace of wrapped_grpc_server_credentials to be associated
* with an object of a class specified by class_type */
zend_object_value create_wrapped_grpc_server_credentials(
- zend_class_entry *class_type TSRMLS_DC){
+ zend_class_entry *class_type TSRMLS_DC) {
zend_object_value retval;
wrapped_grpc_server_credentials *intern;
- intern = (wrapped_grpc_server_credentials*)emalloc(sizeof(
- wrapped_grpc_server_credentials));
+ intern = (wrapped_grpc_server_credentials *)emalloc(
+ sizeof(wrapped_grpc_server_credentials));
memset(intern, 0, sizeof(wrapped_grpc_server_credentials));
zend_object_std_init(&intern->std, class_type TSRMLS_CC);
object_properties_init(&intern->std, class_type);
retval.handle = zend_objects_store_put(
- intern,
- (zend_objects_store_dtor_t) zend_objects_destroy_object,
- free_wrapped_grpc_server_credentials,
- NULL TSRMLS_CC);
+ intern, (zend_objects_store_dtor_t)zend_objects_destroy_object,
+ free_wrapped_grpc_server_credentials, NULL TSRMLS_CC);
retval.handlers = zend_get_std_object_handlers();
return retval;
}
-zval *grpc_php_wrap_server_credentials(grpc_server_credentials *wrapped){
+zval *grpc_php_wrap_server_credentials(grpc_server_credentials *wrapped) {
zval *server_credentials_object;
MAKE_STD_ZVAL(server_credentials_object);
object_init_ex(server_credentials_object, grpc_ce_server_credentials);
wrapped_grpc_server_credentials *server_credentials =
- (wrapped_grpc_server_credentials*)zend_object_store_get_object(
- server_credentials_object TSRMLS_CC);
+ (wrapped_grpc_server_credentials *)zend_object_store_get_object(
+ server_credentials_object TSRMLS_CC);
server_credentials->wrapped = wrapped;
return server_credentials_object;
}
@@ -66,7 +64,7 @@ zval *grpc_php_wrap_server_credentials(grpc_server_credentials *wrapped){
* @param string pem_cert_chain PEM encoding of the client's certificate chain
* @return Credentials The new SSL credentials object
*/
-PHP_METHOD(ServerCredentials, createSsl){
+PHP_METHOD(ServerCredentials, createSsl) {
char *pem_root_certs = 0;
char *pem_private_key;
char *pem_cert_chain;
@@ -74,20 +72,18 @@ PHP_METHOD(ServerCredentials, createSsl){
int root_certs_length = 0, private_key_length, cert_chain_length;
/* "s!ss" == 1 nullable string, 2 strings */
- if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
- "s!ss",
- &pem_root_certs, &root_certs_length,
- &pem_private_key, &private_key_length,
- &pem_cert_chain, &cert_chain_length) == FAILURE) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s!ss", &pem_root_certs,
+ &root_certs_length, &pem_private_key,
+ &private_key_length, &pem_cert_chain,
+ &cert_chain_length) == FAILURE) {
zend_throw_exception(spl_ce_InvalidArgumentException,
- "createSsl expects 3 strings",
- 1 TSRMLS_CC);
+ "createSsl expects 3 strings", 1 TSRMLS_CC);
return;
}
grpc_server_credentials *creds = grpc_ssl_server_credentials_create(
- (unsigned char*)pem_root_certs, (size_t)root_certs_length,
- (unsigned char*)pem_private_key, (size_t)private_key_length,
- (unsigned char*)pem_cert_chain, (size_t)cert_chain_length);
+ (unsigned char *)pem_root_certs, (size_t)root_certs_length,
+ (unsigned char *)pem_private_key, (size_t)private_key_length,
+ (unsigned char *)pem_cert_chain, (size_t)cert_chain_length);
zval *creds_object = grpc_php_wrap_server_credentials(creds);
RETURN_DESTROY_ZVAL(creds_object);
}
@@ -96,7 +92,7 @@ PHP_METHOD(ServerCredentials, createSsl){
* Create fake credentials. Only to be used for testing.
* @return ServerCredentials The new fake credentials object
*/
-PHP_METHOD(ServerCredentials, createFake){
+PHP_METHOD(ServerCredentials, createFake) {
grpc_server_credentials *creds =
grpc_fake_transport_security_server_credentials_create();
zval *creds_object = grpc_php_wrap_server_credentials(creds);
@@ -104,12 +100,12 @@ PHP_METHOD(ServerCredentials, createFake){
}
static zend_function_entry server_credentials_methods[] = {
- PHP_ME(ServerCredentials, createSsl, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
- PHP_ME(ServerCredentials, createFake, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
- PHP_FE_END
-};
+ PHP_ME(ServerCredentials, createSsl, NULL,
+ ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+ PHP_ME(ServerCredentials, createFake, NULL,
+ ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) PHP_FE_END};
-void grpc_init_server_credentials(TSRMLS_D){
+void grpc_init_server_credentials(TSRMLS_D) {
zend_class_entry ce;
INIT_CLASS_ENTRY(ce, "Grpc\\ServerCredentials", server_credentials_methods);
ce.create_object = create_wrapped_grpc_server_credentials;
diff --git a/src/php/ext/grpc/timeval.c b/src/php/ext/grpc/timeval.c
index 7b7e0e6443..a5508115e4 100755..100644
--- a/src/php/ext/grpc/timeval.c
+++ b/src/php/ext/grpc/timeval.c
@@ -18,36 +18,32 @@
#include "grpc/support/time.h"
/* Frees and destroys an instance of wrapped_grpc_call */
-void free_wrapped_grpc_timeval(void *object TSRMLS_DC){
- efree(object);
-}
+void free_wrapped_grpc_timeval(void *object TSRMLS_DC) { efree(object); }
/* Initializes an instance of wrapped_grpc_timeval to be associated with an
* object of a class specified by class_type */
-zend_object_value create_wrapped_grpc_timeval(
- zend_class_entry *class_type TSRMLS_DC){
+zend_object_value create_wrapped_grpc_timeval(zend_class_entry *class_type
+ TSRMLS_DC) {
zend_object_value retval;
wrapped_grpc_timeval *intern;
- intern = (wrapped_grpc_timeval*)emalloc(sizeof(wrapped_grpc_timeval));
+ intern = (wrapped_grpc_timeval *)emalloc(sizeof(wrapped_grpc_timeval));
memset(intern, 0, sizeof(wrapped_grpc_timeval));
zend_object_std_init(&intern->std, class_type TSRMLS_CC);
object_properties_init(&intern->std, class_type);
retval.handle = zend_objects_store_put(
- intern,
- (zend_objects_store_dtor_t)zend_objects_destroy_object,
- free_wrapped_grpc_timeval,
- NULL TSRMLS_CC);
+ intern, (zend_objects_store_dtor_t)zend_objects_destroy_object,
+ free_wrapped_grpc_timeval, NULL TSRMLS_CC);
retval.handlers = zend_get_std_object_handlers();
return retval;
}
-zval *grpc_php_wrap_timeval(gpr_timespec wrapped){
+zval *grpc_php_wrap_timeval(gpr_timespec wrapped) {
zval *timeval_object;
MAKE_STD_ZVAL(timeval_object);
object_init_ex(timeval_object, grpc_ce_timeval);
wrapped_grpc_timeval *timeval =
- (wrapped_grpc_timeval*)zend_object_store_get_object(
- timeval_object TSRMLS_CC);
+ (wrapped_grpc_timeval *)zend_object_store_get_object(
+ timeval_object TSRMLS_CC);
memcpy(&timeval->wrapped, &wrapped, sizeof(gpr_timespec));
return timeval_object;
}
@@ -56,17 +52,15 @@ zval *grpc_php_wrap_timeval(gpr_timespec wrapped){
* Constructs a new instance of the Timeval class
* @param long $usec The number of microseconds in the interval
*/
-PHP_METHOD(Timeval, __construct){
+PHP_METHOD(Timeval, __construct) {
wrapped_grpc_timeval *timeval =
- (wrapped_grpc_timeval*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ (wrapped_grpc_timeval *)zend_object_store_get_object(getThis() TSRMLS_CC);
long microseconds;
/* "l" == 1 long */
- if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
- "l",
- &microseconds) == FAILURE){
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &microseconds) ==
+ FAILURE) {
zend_throw_exception(spl_ce_InvalidArgumentException,
- "Timeval expects a long",
- 1 TSRMLS_CC);
+ "Timeval expects a long", 1 TSRMLS_CC);
return;
}
gpr_timespec time = gpr_time_from_micros(microseconds);
@@ -79,23 +73,21 @@ PHP_METHOD(Timeval, __construct){
* @param Timeval $other The other Timeval object to add
* @return Timeval A new Timeval object containing the sum
*/
-PHP_METHOD(Timeval, add){
+PHP_METHOD(Timeval, add) {
zval *other_obj;
/* "O" == 1 Object */
- if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
- "O",
- &other_obj, grpc_ce_timeval) == FAILURE){
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &other_obj,
+ grpc_ce_timeval) == FAILURE) {
zend_throw_exception(spl_ce_InvalidArgumentException,
- "add expects a Timeval",
- 1 TSRMLS_CC);
+ "add expects a Timeval", 1 TSRMLS_CC);
return;
}
wrapped_grpc_timeval *self =
- (wrapped_grpc_timeval*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ (wrapped_grpc_timeval *)zend_object_store_get_object(getThis() TSRMLS_CC);
wrapped_grpc_timeval *other =
- (wrapped_grpc_timeval*)zend_object_store_get_object(other_obj TSRMLS_CC);
- zval *sum = grpc_php_wrap_timeval(gpr_time_add(self->wrapped,
- other->wrapped));
+ (wrapped_grpc_timeval *)zend_object_store_get_object(other_obj TSRMLS_CC);
+ zval *sum =
+ grpc_php_wrap_timeval(gpr_time_add(self->wrapped, other->wrapped));
RETURN_DESTROY_ZVAL(sum);
}
@@ -105,23 +97,21 @@ PHP_METHOD(Timeval, add){
* @param Timeval $other The other Timeval object to subtract
* @param Timeval A new Timeval object containing the sum
*/
-PHP_METHOD(Timeval, subtract){
+PHP_METHOD(Timeval, subtract) {
zval *other_obj;
/* "O" == 1 Object */
- if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
- "O",
- &other_obj, grpc_ce_timeval) == FAILURE){
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &other_obj,
+ grpc_ce_timeval) == FAILURE) {
zend_throw_exception(spl_ce_InvalidArgumentException,
- "subtract expects a Timeval",
- 1 TSRMLS_CC);
+ "subtract expects a Timeval", 1 TSRMLS_CC);
return;
}
wrapped_grpc_timeval *self =
- (wrapped_grpc_timeval*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ (wrapped_grpc_timeval *)zend_object_store_get_object(getThis() TSRMLS_CC);
wrapped_grpc_timeval *other =
- (wrapped_grpc_timeval*)zend_object_store_get_object(other_obj TSRMLS_CC);
- zval *diff = grpc_php_wrap_timeval(gpr_time_sub(self->wrapped,
- other->wrapped));
+ (wrapped_grpc_timeval *)zend_object_store_get_object(other_obj TSRMLS_CC);
+ zval *diff =
+ grpc_php_wrap_timeval(gpr_time_sub(self->wrapped, other->wrapped));
RETURN_DESTROY_ZVAL(diff);
}
@@ -132,22 +122,20 @@ PHP_METHOD(Timeval, subtract){
* @param Timeval $b The second time to compare
* @return long
*/
-PHP_METHOD(Timeval, compare){
+PHP_METHOD(Timeval, compare) {
zval *a_obj, *b_obj;
/* "OO" == 2 Objects */
- if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
- "OO",
- &a_obj, grpc_ce_timeval,
- &b_obj, grpc_ce_timeval) == FAILURE){
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "OO", &a_obj,
+ grpc_ce_timeval, &b_obj,
+ grpc_ce_timeval) == FAILURE) {
zend_throw_exception(spl_ce_InvalidArgumentException,
- "compare expects two Timevals",
- 1 TSRMLS_CC);
+ "compare expects two Timevals", 1 TSRMLS_CC);
return;
}
wrapped_grpc_timeval *a =
- (wrapped_grpc_timeval*)zend_object_store_get_object(a_obj TSRMLS_CC);
+ (wrapped_grpc_timeval *)zend_object_store_get_object(a_obj TSRMLS_CC);
wrapped_grpc_timeval *b =
- (wrapped_grpc_timeval*)zend_object_store_get_object(b_obj TSRMLS_CC);
+ (wrapped_grpc_timeval *)zend_object_store_get_object(b_obj TSRMLS_CC);
long result = gpr_time_cmp(a->wrapped, b->wrapped);
RETURN_LONG(result);
}
@@ -159,25 +147,23 @@ PHP_METHOD(Timeval, compare){
* @param Timeval $threshold The threshold to check against
* @return bool True if $a and $b are within $threshold, False otherwise
*/
-PHP_METHOD(Timeval, similar){
+PHP_METHOD(Timeval, similar) {
zval *a_obj, *b_obj, *thresh_obj;
/* "OOO" == 3 Objects */
- if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
- "OOO",
- &a_obj, grpc_ce_timeval,
- &b_obj, grpc_ce_timeval,
- &thresh_obj, grpc_ce_timeval) == FAILURE){
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "OOO", &a_obj,
+ grpc_ce_timeval, &b_obj, grpc_ce_timeval,
+ &thresh_obj, grpc_ce_timeval) == FAILURE) {
zend_throw_exception(spl_ce_InvalidArgumentException,
- "compare expects three Timevals",
- 1 TSRMLS_CC);
+ "compare expects three Timevals", 1 TSRMLS_CC);
return;
}
wrapped_grpc_timeval *a =
- (wrapped_grpc_timeval*)zend_object_store_get_object(a_obj TSRMLS_CC);
+ (wrapped_grpc_timeval *)zend_object_store_get_object(a_obj TSRMLS_CC);
wrapped_grpc_timeval *b =
- (wrapped_grpc_timeval*)zend_object_store_get_object(b_obj TSRMLS_CC);
+ (wrapped_grpc_timeval *)zend_object_store_get_object(b_obj TSRMLS_CC);
wrapped_grpc_timeval *thresh =
- (wrapped_grpc_timeval*)zend_object_store_get_object(thresh_obj TSRMLS_CC);
+ (wrapped_grpc_timeval *)zend_object_store_get_object(
+ thresh_obj TSRMLS_CC);
int result = gpr_time_similar(a->wrapped, b->wrapped, thresh->wrapped);
RETURN_BOOL(result);
}
@@ -186,7 +172,7 @@ PHP_METHOD(Timeval, similar){
* Returns the current time as a timeval object
* @return Timeval The current time
*/
-PHP_METHOD(Timeval, now){
+PHP_METHOD(Timeval, now) {
zval *now = grpc_php_wrap_timeval(gpr_now());
RETURN_DESTROY_ZVAL(now);
}
@@ -195,7 +181,7 @@ PHP_METHOD(Timeval, now){
* Returns the zero time interval as a timeval object
* @return Timeval Zero length time interval
*/
-PHP_METHOD(Timeval, zero){
+PHP_METHOD(Timeval, zero) {
zval *grpc_php_timeval_zero = grpc_php_wrap_timeval(gpr_time_0);
RETURN_ZVAL(grpc_php_timeval_zero,
false, /* Copy original before returning? */
@@ -206,7 +192,7 @@ PHP_METHOD(Timeval, zero){
* Returns the infinite future time value as a timeval object
* @return Timeval Infinite future time value
*/
-PHP_METHOD(Timeval, inf_future){
+PHP_METHOD(Timeval, inf_future) {
zval *grpc_php_timeval_inf_future = grpc_php_wrap_timeval(gpr_inf_future);
RETURN_DESTROY_ZVAL(grpc_php_timeval_inf_future);
}
@@ -215,7 +201,7 @@ PHP_METHOD(Timeval, inf_future){
* Returns the infinite past time value as a timeval object
* @return Timeval Infinite past time value
*/
-PHP_METHOD(Timeval, inf_past){
+PHP_METHOD(Timeval, inf_past) {
zval *grpc_php_timeval_inf_past = grpc_php_wrap_timeval(gpr_inf_past);
RETURN_DESTROY_ZVAL(grpc_php_timeval_inf_past);
}
@@ -224,32 +210,33 @@ PHP_METHOD(Timeval, inf_past){
* Sleep until this time, interpreted as an absolute timeout
* @return void
*/
-PHP_METHOD(Timeval, sleep_until){
+PHP_METHOD(Timeval, sleep_until) {
wrapped_grpc_timeval *this =
- (wrapped_grpc_timeval*)zend_object_store_get_object(getThis() TSRMLS_CC);
+ (wrapped_grpc_timeval *)zend_object_store_get_object(getThis() TSRMLS_CC);
gpr_sleep_until(this->wrapped);
}
static zend_function_entry timeval_methods[] = {
- PHP_ME(Timeval, __construct, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
- PHP_ME(Timeval, add, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(Timeval, compare, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
- PHP_ME(Timeval, inf_future, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
- PHP_ME(Timeval, inf_past, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
- PHP_ME(Timeval, now, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
- PHP_ME(Timeval, similar, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
- PHP_ME(Timeval, sleep_until, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(Timeval, subtract, NULL, ZEND_ACC_PUBLIC)
- PHP_ME(Timeval, zero, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
- PHP_FE_END
-};
-
-void grpc_init_timeval(TSRMLS_D){
+ PHP_ME(Timeval, __construct, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) PHP_ME(
+ Timeval, add, NULL,
+ ZEND_ACC_PUBLIC) PHP_ME(Timeval, compare, NULL,
+ ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+ PHP_ME(Timeval, inf_future, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+ PHP_ME(Timeval, inf_past, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+ PHP_ME(Timeval, now, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+ PHP_ME(Timeval, similar, NULL,
+ ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+ PHP_ME(Timeval, sleep_until, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(Timeval, subtract, NULL, ZEND_ACC_PUBLIC)
+ PHP_ME(Timeval, zero, NULL,
+ ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+ PHP_FE_END};
+
+void grpc_init_timeval(TSRMLS_D) {
zend_class_entry ce;
INIT_CLASS_ENTRY(ce, "Grpc\\Timeval", timeval_methods);
ce.create_object = create_wrapped_grpc_timeval;
grpc_ce_timeval = zend_register_internal_class(&ce TSRMLS_CC);
}
-void grpc_shutdown_timeval(TSRMLS_D){
-}
+void grpc_shutdown_timeval(TSRMLS_D) {}
diff --git a/src/ruby/bin/interop/interop_client.rb b/src/ruby/bin/interop/interop_client.rb
index d0478bb4d1..718b0fdb83 100644..100755
--- a/src/ruby/bin/interop/interop_client.rb
+++ b/src/ruby/bin/interop/interop_client.rb
@@ -1,3 +1,5 @@
+#!/usr/bin/env ruby
+
# Copyright 2014, Google Inc.
# All rights reserved.
#
@@ -27,7 +29,6 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#!/usr/bin/env ruby
# interop_client is a testing tool that accesses a gRPC interop testing
# server and runs a test on it.
#
diff --git a/src/ruby/bin/interop/interop_server.rb b/src/ruby/bin/interop/interop_server.rb
index 53e271e80d..63071f3ec2 100644..100755
--- a/src/ruby/bin/interop/interop_server.rb
+++ b/src/ruby/bin/interop/interop_server.rb
@@ -1,3 +1,5 @@
+#!/usr/bin/env ruby
+
# Copyright 2014, Google Inc.
# All rights reserved.
#
@@ -27,8 +29,6 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#!/usr/bin/env ruby
-#
# interop_server is a Testing app that runs a gRPC interop testing server.
#
# It helps validate interoperation b/w gRPC in different environments
diff --git a/src/ruby/bin/math_client.rb b/src/ruby/bin/math_client.rb
index 5cba9317f4..4df333d085 100644..100755
--- a/src/ruby/bin/math_client.rb
+++ b/src/ruby/bin/math_client.rb
@@ -1,3 +1,5 @@
+#!/usr/bin/env ruby
+
# Copyright 2014, Google Inc.
# All rights reserved.
#
@@ -27,8 +29,7 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#!/usr/bin/env ruby
-#
+
# Sample app that accesses a Calc service running on a Ruby gRPC server and
# helps validate RpcServer as a gRPC server using proto2 serialization.
#
diff --git a/src/ruby/bin/math_server.rb b/src/ruby/bin/math_server.rb
index a0f301c3e7..0e47f71e66 100644..100755
--- a/src/ruby/bin/math_server.rb
+++ b/src/ruby/bin/math_server.rb
@@ -1,3 +1,5 @@
+#!/usr/bin/env ruby
+
# Copyright 2014, Google Inc.
# All rights reserved.
#
@@ -27,8 +29,6 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#!/usr/bin/env ruby
-#
# Sample gRPC Ruby server that implements the Math::Calc service and helps
# validate GRPC::RpcServer as GRPC implementation using proto2 serialization.
#
diff --git a/src/ruby/bin/noproto_client.rb b/src/ruby/bin/noproto_client.rb
index 50ae9fb68f..34bdf545ee 100644..100755
--- a/src/ruby/bin/noproto_client.rb
+++ b/src/ruby/bin/noproto_client.rb
@@ -1,3 +1,5 @@
+#!/usr/bin/env ruby
+
# Copyright 2014, Google Inc.
# All rights reserved.
#
@@ -27,7 +29,6 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#!/usr/bin/env ruby
# Sample app that helps validate RpcServer without protobuf serialization.
#
# Usage: $ ruby -S path/to/noproto_client.rb
diff --git a/src/ruby/bin/noproto_server.rb b/src/ruby/bin/noproto_server.rb
index d410827b22..1bdc192f02 100644..100755
--- a/src/ruby/bin/noproto_server.rb
+++ b/src/ruby/bin/noproto_server.rb
@@ -1,3 +1,5 @@
+#!/usr/bin/env ruby
+
# Copyright 2014, Google Inc.
# All rights reserved.
#
@@ -27,7 +29,6 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#!/usr/bin/env ruby
# Sample app that helps validate RpcServer without protobuf serialization.
#
# Usage: $ path/to/noproto_server.rb
diff --git a/src/ruby/ext/grpc/rb_byte_buffer.c b/src/ruby/ext/grpc/rb_byte_buffer.c
index b75e853d6b..f73b12c417 100644
--- a/src/ruby/ext/grpc/rb_byte_buffer.c
+++ b/src/ruby/ext/grpc/rb_byte_buffer.c
@@ -49,7 +49,6 @@ typedef struct grpc_rb_byte_buffer {
grpc_byte_buffer *wrapped;
} grpc_rb_byte_buffer;
-
/* Destroys ByteBuffer instances. */
static void grpc_rb_byte_buffer_free(void *p) {
grpc_rb_byte_buffer *bb = NULL;
@@ -169,7 +168,6 @@ static VALUE grpc_rb_byte_buffer_to_s(VALUE self) {
return output_obj;
}
-
/* Initializes ByteBuffer instances. */
static VALUE grpc_rb_byte_buffer_init(VALUE self, VALUE src) {
gpr_slice a_slice;
@@ -205,8 +203,8 @@ static VALUE grpc_rb_byte_buffer_init(VALUE self, VALUE src) {
VALUE rb_cByteBuffer = Qnil;
void Init_google_rpc_byte_buffer() {
- rb_cByteBuffer = rb_define_class_under(rb_mGoogleRpcCore, "ByteBuffer",
- rb_cObject);
+ rb_cByteBuffer =
+ rb_define_class_under(rb_mGoogleRpcCore, "ByteBuffer", rb_cObject);
/* Allocates an object managed by the ruby runtime */
rb_define_alloc_func(rb_cByteBuffer, grpc_rb_byte_buffer_alloc);
@@ -223,7 +221,7 @@ void Init_google_rpc_byte_buffer() {
id_empty = rb_intern("");
}
-VALUE grpc_rb_byte_buffer_create_with_mark(VALUE mark, grpc_byte_buffer* bb) {
+VALUE grpc_rb_byte_buffer_create_with_mark(VALUE mark, grpc_byte_buffer *bb) {
grpc_rb_byte_buffer *byte_buffer = NULL;
if (bb == NULL) {
return Qnil;
@@ -236,7 +234,7 @@ VALUE grpc_rb_byte_buffer_create_with_mark(VALUE mark, grpc_byte_buffer* bb) {
}
/* Gets the wrapped byte_buffer from the ruby wrapper */
-grpc_byte_buffer* grpc_rb_get_wrapped_byte_buffer(VALUE v) {
+grpc_byte_buffer *grpc_rb_get_wrapped_byte_buffer(VALUE v) {
grpc_rb_byte_buffer *wrapper = NULL;
Data_Get_Struct(v, grpc_rb_byte_buffer, wrapper);
return wrapper->wrapped;
diff --git a/src/ruby/ext/grpc/rb_byte_buffer.h b/src/ruby/ext/grpc/rb_byte_buffer.h
index 1bdcfe4019..322c268f37 100644
--- a/src/ruby/ext/grpc/rb_byte_buffer.h
+++ b/src/ruby/ext/grpc/rb_byte_buffer.h
@@ -51,4 +51,4 @@ VALUE grpc_rb_byte_buffer_create_with_mark(VALUE mark, grpc_byte_buffer* bb);
/* Gets the wrapped byte_buffer from its ruby object. */
grpc_byte_buffer* grpc_rb_get_wrapped_byte_buffer(VALUE v);
-#endif /* GRPC_RB_BYTE_BUFFER_H_ */
+#endif /* GRPC_RB_BYTE_BUFFER_H_ */
diff --git a/src/ruby/ext/grpc/rb_call.c b/src/ruby/ext/grpc/rb_call.c
index bf292fac75..76b80bcaa1 100644
--- a/src/ruby/ext/grpc/rb_call.c
+++ b/src/ruby/ext/grpc/rb_call.c
@@ -78,7 +78,7 @@ void grpc_rb_call_destroy(void *p) {
ref_count = rb_hash_aref(hash_all_calls, OFFT2NUM((VALUE)call));
if (ref_count == Qnil) {
- return; /* No longer in the hash, so already deleted */
+ return; /* No longer in the hash, so already deleted */
} else if (NUM2UINT(ref_count) == 1) {
rb_hash_delete(hash_all_calls, OFFT2NUM((VALUE)call));
grpc_call_destroy(call);
@@ -92,9 +92,9 @@ void grpc_rb_call_destroy(void *p) {
VALUE rb_error_code_details;
/* Obtains the error detail string for given error code */
-const char* grpc_call_error_detail_of(grpc_call_error err) {
+const char *grpc_call_error_detail_of(grpc_call_error err) {
VALUE detail_ref = rb_hash_aref(rb_error_code_details, UINT2NUM(err));
- const char* detail = "unknown error code!";
+ const char *detail = "unknown error code!";
if (detail_ref != Qnil) {
detail = StringValueCStr(detail_ref);
}
@@ -164,7 +164,7 @@ static VALUE grpc_rb_call_add_metadata(int argc, VALUE *argv, VALUE self) {
/* "11" == 1 mandatory args, 1 (flags) is optional */
rb_scan_args(argc, argv, "11", &metadata, &flags);
if (NIL_P(flags)) {
- flags = UINT2NUM(0); /* Default to no flags */
+ flags = UINT2NUM(0); /* Default to no flags */
}
if (TYPE(metadata) != T_HASH) {
rb_raise(rb_eTypeError, "add metadata failed: metadata should be a hash");
@@ -217,14 +217,13 @@ static VALUE grpc_rb_call_start_invoke(int argc, VALUE *argv, VALUE self) {
rb_scan_args(argc, argv, "41", &cqueue, &invoke_accepted_tag,
&metadata_read_tag, &finished_tag, &flags);
if (NIL_P(flags)) {
- flags = UINT2NUM(0); /* Default to no flags */
+ flags = UINT2NUM(0); /* Default to no flags */
}
cq = grpc_rb_get_wrapped_completion_queue(cqueue);
Data_Get_Struct(self, grpc_call, call);
err = grpc_call_start_invoke(call, cq, ROBJECT(invoke_accepted_tag),
ROBJECT(metadata_read_tag),
- ROBJECT(finished_tag),
- NUM2UINT(flags));
+ ROBJECT(finished_tag), NUM2UINT(flags));
if (err != GRPC_CALL_OK) {
rb_raise(rb_eCallError, "invoke failed: %s (code=%d)",
grpc_call_error_detail_of(err), err);
@@ -329,7 +328,7 @@ static VALUE grpc_rb_call_start_write(int argc, VALUE *argv, VALUE self) {
/* "21" == 2 mandatory args, 1 (flags) is optional */
rb_scan_args(argc, argv, "21", &byte_buffer, &tag, &flags);
if (NIL_P(flags)) {
- flags = UINT2NUM(0); /* Default to no flags */
+ flags = UINT2NUM(0); /* Default to no flags */
}
bfr = grpc_rb_get_wrapped_byte_buffer(byte_buffer);
Data_Get_Struct(self, grpc_call, call);
@@ -405,7 +404,7 @@ static VALUE grpc_rb_call_server_end_initial_metadata(int argc, VALUE *argv,
/* "01" == 1 (flags) is optional */
rb_scan_args(argc, argv, "01", &flags);
if (NIL_P(flags)) {
- flags = UINT2NUM(0); /* Default to no flags */
+ flags = UINT2NUM(0); /* Default to no flags */
}
Data_Get_Struct(self, grpc_call, call);
err = grpc_call_server_end_initial_metadata(call, NUM2UINT(flags));
@@ -445,7 +444,6 @@ static VALUE grpc_rb_call_server_accept(VALUE self, VALUE cqueue,
return Qnil;
}
-
/* rb_cCall is the ruby class that proxies grpc_call. */
VALUE rb_cCall = Qnil;
@@ -477,8 +475,8 @@ void Init_google_rpc_error_codes() {
/* Add the detail strings to a Hash */
rb_error_code_details = rb_hash_new();
- rb_hash_aset(rb_error_code_details,
- UINT2NUM(GRPC_CALL_OK), rb_str_new2("ok"));
+ rb_hash_aset(rb_error_code_details, UINT2NUM(GRPC_CALL_OK),
+ rb_str_new2("ok"));
rb_hash_aset(rb_error_code_details, UINT2NUM(GRPC_CALL_ERROR),
rb_str_new2("unknown error"));
rb_hash_aset(rb_error_code_details, UINT2NUM(GRPC_CALL_ERROR_NOT_ON_SERVER),
@@ -506,8 +504,8 @@ void Init_google_rpc_error_codes() {
void Init_google_rpc_call() {
/* CallError inherits from Exception to signal that it is non-recoverable */
- rb_eCallError = rb_define_class_under(rb_mGoogleRpcCore, "CallError",
- rb_eException);
+ rb_eCallError =
+ rb_define_class_under(rb_mGoogleRpcCore, "CallError", rb_eException);
rb_cCall = rb_define_class_under(rb_mGoogleRpcCore, "Call", rb_cObject);
/* Prevent allocation or inialization of the Call class */
@@ -519,8 +517,7 @@ void Init_google_rpc_call() {
rb_define_method(rb_cCall, "server_accept", grpc_rb_call_server_accept, 2);
rb_define_method(rb_cCall, "server_end_initial_metadata",
grpc_rb_call_server_end_initial_metadata, -1);
- rb_define_method(rb_cCall, "add_metadata", grpc_rb_call_add_metadata,
- -1);
+ rb_define_method(rb_cCall, "add_metadata", grpc_rb_call_add_metadata, -1);
rb_define_method(rb_cCall, "cancel", grpc_rb_call_cancel, 0);
rb_define_method(rb_cCall, "start_invoke", grpc_rb_call_start_invoke, -1);
rb_define_method(rb_cCall, "start_read", grpc_rb_call_start_read, 1);
@@ -551,25 +548,24 @@ void Init_google_rpc_call() {
}
/* Gets the call from the ruby object */
-grpc_call* grpc_rb_get_wrapped_call(VALUE v) {
+grpc_call *grpc_rb_get_wrapped_call(VALUE v) {
grpc_call *c = NULL;
Data_Get_Struct(v, grpc_call, c);
return c;
}
/* Obtains the wrapped object for a given call */
-VALUE grpc_rb_wrap_call(grpc_call* c) {
+VALUE grpc_rb_wrap_call(grpc_call *c) {
VALUE obj = Qnil;
if (c == NULL) {
return Qnil;
}
obj = rb_hash_aref(hash_all_calls, OFFT2NUM((VALUE)c));
- if (obj == Qnil) { /* Not in the hash add it */
+ if (obj == Qnil) { /* Not in the hash add it */
rb_hash_aset(hash_all_calls, OFFT2NUM((VALUE)c), UINT2NUM(1));
} else {
rb_hash_aset(hash_all_calls, OFFT2NUM((VALUE)c),
UINT2NUM(NUM2UINT(obj) + 1));
}
- return Data_Wrap_Struct(rb_cCall, GC_NOT_MARKED, grpc_rb_call_destroy,
- c);
+ return Data_Wrap_Struct(rb_cCall, GC_NOT_MARKED, grpc_rb_call_destroy, c);
}
diff --git a/src/ruby/ext/grpc/rb_call.h b/src/ruby/ext/grpc/rb_call.h
index 422e7e7a6c..965e9eef40 100644
--- a/src/ruby/ext/grpc/rb_call.h
+++ b/src/ruby/ext/grpc/rb_call.h
@@ -56,4 +56,4 @@ extern VALUE rb_eCallError;
/* Initializes the Call class. */
void Init_google_rpc_call();
-#endif /* GRPC_RB_CALL_H_ */
+#endif /* GRPC_RB_CALL_H_ */
diff --git a/src/ruby/ext/grpc/rb_channel.c b/src/ruby/ext/grpc/rb_channel.c
index d951847662..c0187d2d11 100644
--- a/src/ruby/ext/grpc/rb_channel.c
+++ b/src/ruby/ext/grpc/rb_channel.c
@@ -137,7 +137,7 @@ static VALUE grpc_rb_channel_init(int argc, VALUE *argv, VALUE self) {
ch = grpc_secure_channel_create(creds, target_chars, &args);
}
if (args.args != NULL) {
- xfree(args.args); /* Allocated by grpc_rb_hash_convert_to_channel_args */
+ xfree(args.args); /* Allocated by grpc_rb_hash_convert_to_channel_args */
}
if (ch == NULL) {
rb_raise(rb_eRuntimeError, "could not create an rpc channel to target:%s",
@@ -256,7 +256,7 @@ void Init_google_rpc_channel() {
}
/* Gets the wrapped channel from the ruby wrapper */
-grpc_channel* grpc_rb_get_wrapped_channel(VALUE v) {
+grpc_channel *grpc_rb_get_wrapped_channel(VALUE v) {
grpc_rb_channel *wrapper = NULL;
Data_Get_Struct(v, grpc_rb_channel, wrapper);
return wrapper->wrapped;
diff --git a/src/ruby/ext/grpc/rb_channel.h b/src/ruby/ext/grpc/rb_channel.h
index b0a3634474..6c1210e812 100644
--- a/src/ruby/ext/grpc/rb_channel.h
+++ b/src/ruby/ext/grpc/rb_channel.h
@@ -46,4 +46,4 @@ void Init_google_rpc_channel();
/* Gets the wrapped channel from the ruby wrapper */
grpc_channel* grpc_rb_get_wrapped_channel(VALUE v);
-#endif /* GRPC_RB_CHANNEL_H_ */
+#endif /* GRPC_RB_CHANNEL_H_ */
diff --git a/src/ruby/ext/grpc/rb_channel_args.c b/src/ruby/ext/grpc/rb_channel_args.c
index eebced0bd8..b918e1264e 100644
--- a/src/ruby/ext/grpc/rb_channel_args.c
+++ b/src/ruby/ext/grpc/rb_channel_args.c
@@ -46,7 +46,6 @@ static int grpc_rb_channel_create_in_process_add_args_hash_cb(VALUE key,
grpc_channel_args* args;
switch (TYPE(key)) {
-
case T_STRING:
the_key = StringValuePtr(key);
break;
@@ -68,13 +67,12 @@ static int grpc_rb_channel_create_in_process_add_args_hash_cb(VALUE key,
return ST_STOP;
}
- args->args[args->num_args - 1].key = (char *)the_key;
+ args->args[args->num_args - 1].key = (char*)the_key;
switch (TYPE(val)) {
-
case T_SYMBOL:
args->args[args->num_args - 1].type = GRPC_ARG_STRING;
args->args[args->num_args - 1].value.string =
- (char *)rb_id2name(SYM2ID(val));
+ (char*)rb_id2name(SYM2ID(val));
--args->num_args;
return ST_CONTINUE;
@@ -109,11 +107,10 @@ typedef struct channel_convert_params {
grpc_channel_args* dst;
} channel_convert_params;
-
static VALUE grpc_rb_hash_convert_to_channel_args0(VALUE as_value) {
ID id_size = rb_intern("size");
VALUE rb_cChannelArgs = rb_define_class("TmpChannelArgs", rb_cObject);
- channel_convert_params* params = (channel_convert_params *)as_value;
+ channel_convert_params* params = (channel_convert_params*)as_value;
size_t num_args = 0;
if (!NIL_P(params->src_hash) && TYPE(params->src_hash) != T_HASH) {
@@ -146,7 +143,7 @@ void grpc_rb_hash_convert_to_channel_args(VALUE src_hash,
/* Make a protected call to grpc_rb_hash_convert_channel_args */
params.src_hash = src_hash;
params.dst = dst;
- rb_protect(grpc_rb_hash_convert_to_channel_args0, (VALUE) &params, &status);
+ rb_protect(grpc_rb_hash_convert_to_channel_args0, (VALUE)&params, &status);
if (status != 0) {
if (dst->args != NULL) {
/* Free any allocated memory before propagating the error */
diff --git a/src/ruby/ext/grpc/rb_channel_args.h b/src/ruby/ext/grpc/rb_channel_args.h
index bbff017c1e..07be662793 100644
--- a/src/ruby/ext/grpc/rb_channel_args.h
+++ b/src/ruby/ext/grpc/rb_channel_args.h
@@ -49,5 +49,4 @@
void grpc_rb_hash_convert_to_channel_args(VALUE src_hash,
grpc_channel_args* dst);
-
-#endif /* GRPC_RB_CHANNEL_ARGS_H_ */
+#endif /* GRPC_RB_CHANNEL_ARGS_H_ */
diff --git a/src/ruby/ext/grpc/rb_completion_queue.c b/src/ruby/ext/grpc/rb_completion_queue.c
index dc95838ef5..c1b74e2606 100644
--- a/src/ruby/ext/grpc/rb_completion_queue.c
+++ b/src/ruby/ext/grpc/rb_completion_queue.c
@@ -45,33 +45,28 @@ typedef struct next_call_stack {
grpc_completion_queue *cq;
grpc_event *event;
gpr_timespec timeout;
- void* tag;
+ void *tag;
} next_call_stack;
/* Calls grpc_completion_queue_next without holding the ruby GIL */
-static void *grpc_rb_completion_queue_next_no_gil(
- next_call_stack *next_call) {
- next_call->event = grpc_completion_queue_next(next_call->cq,
- next_call->timeout);
+static void *grpc_rb_completion_queue_next_no_gil(next_call_stack *next_call) {
+ next_call->event =
+ grpc_completion_queue_next(next_call->cq, next_call->timeout);
return NULL;
}
/* Calls grpc_completion_queue_pluck without holding the ruby GIL */
-static void *grpc_rb_completion_queue_pluck_no_gil(
- next_call_stack *next_call) {
- next_call->event = grpc_completion_queue_pluck(next_call->cq,
- next_call->tag,
+static void *grpc_rb_completion_queue_pluck_no_gil(next_call_stack *next_call) {
+ next_call->event = grpc_completion_queue_pluck(next_call->cq, next_call->tag,
next_call->timeout);
return NULL;
}
-
/* Shuts down and drains the completion queue if necessary.
*
* This is done when the ruby completion queue object is about to be GCed.
*/
-static void grpc_rb_completion_queue_shutdown_drain(
- grpc_completion_queue* cq) {
+static void grpc_rb_completion_queue_shutdown_drain(grpc_completion_queue *cq) {
next_call_stack next_call;
grpc_completion_type type;
int drained = 0;
@@ -120,13 +115,12 @@ static void grpc_rb_completion_queue_destroy(void *p) {
/* Allocates a completion queue. */
static VALUE grpc_rb_completion_queue_alloc(VALUE cls) {
- grpc_completion_queue* cq = grpc_completion_queue_create();
+ grpc_completion_queue *cq = grpc_completion_queue_create();
if (cq == NULL) {
- rb_raise(rb_eArgError,
- "could not create a completion queue: not sure why");
+ rb_raise(rb_eArgError, "could not create a completion queue: not sure why");
}
- return Data_Wrap_Struct(cls, GC_NOT_MARKED,
- grpc_rb_completion_queue_destroy, cq);
+ return Data_Wrap_Struct(cls, GC_NOT_MARKED, grpc_rb_completion_queue_destroy,
+ cq);
}
/* Blocks until the next event is available, and returns the event. */
@@ -166,9 +160,8 @@ static VALUE grpc_rb_completion_queue_pluck(VALUE self, VALUE tag,
VALUE rb_cCompletionQueue = Qnil;
void Init_google_rpc_completion_queue() {
- rb_cCompletionQueue = rb_define_class_under(rb_mGoogleRpcCore,
- "CompletionQueue",
- rb_cObject);
+ rb_cCompletionQueue =
+ rb_define_class_under(rb_mGoogleRpcCore, "CompletionQueue", rb_cObject);
/* constructor: uses an alloc func without an initializer. Using a simple
alloc func works here as the grpc header does not specify any args for
@@ -176,16 +169,16 @@ void Init_google_rpc_completion_queue() {
rb_define_alloc_func(rb_cCompletionQueue, grpc_rb_completion_queue_alloc);
/* Add the next method that waits for the next event. */
- rb_define_method(rb_cCompletionQueue, "next",
- grpc_rb_completion_queue_next, 1);
+ rb_define_method(rb_cCompletionQueue, "next", grpc_rb_completion_queue_next,
+ 1);
/* Add the pluck method that waits for the next event of given tag */
- rb_define_method(rb_cCompletionQueue, "pluck",
- grpc_rb_completion_queue_pluck, 2);
+ rb_define_method(rb_cCompletionQueue, "pluck", grpc_rb_completion_queue_pluck,
+ 2);
}
/* Gets the wrapped completion queue from the ruby wrapper */
-grpc_completion_queue* grpc_rb_get_wrapped_completion_queue(VALUE v) {
+grpc_completion_queue *grpc_rb_get_wrapped_completion_queue(VALUE v) {
grpc_completion_queue *cq = NULL;
Data_Get_Struct(v, grpc_completion_queue, cq);
return cq;
diff --git a/src/ruby/ext/grpc/rb_completion_queue.h b/src/ruby/ext/grpc/rb_completion_queue.h
index 1ec2718ed4..c563662c2d 100644
--- a/src/ruby/ext/grpc/rb_completion_queue.h
+++ b/src/ruby/ext/grpc/rb_completion_queue.h
@@ -47,4 +47,4 @@ extern VALUE rb_cCompletionQueue;
/* Initializes the CompletionQueue class. */
void Init_google_rpc_completion_queue();
-#endif /* GRPC_RB_COMPLETION_QUEUE_H_ */
+#endif /* GRPC_RB_COMPLETION_QUEUE_H_ */
diff --git a/src/ruby/ext/grpc/rb_credentials.c b/src/ruby/ext/grpc/rb_credentials.c
index 658adacc06..5dec51824d 100644
--- a/src/ruby/ext/grpc/rb_credentials.c
+++ b/src/ruby/ext/grpc/rb_credentials.c
@@ -40,7 +40,6 @@
#include "rb_grpc.h"
-
/* grpc_rb_credentials wraps a grpc_credentials. It provides a
* peer ruby object, 'mark' to minimize copying when a credential is
* created from ruby. */
@@ -92,8 +91,7 @@ static VALUE grpc_rb_credentials_alloc(VALUE cls) {
wrapper->wrapped = NULL;
wrapper->mark = Qnil;
return Data_Wrap_Struct(cls, grpc_rb_credentials_mark,
- grpc_rb_credentials_free,
- wrapper);
+ grpc_rb_credentials_free, wrapper);
}
/* Clones Credentials instances.
@@ -111,8 +109,7 @@ static VALUE grpc_rb_credentials_init_copy(VALUE copy, VALUE orig) {
/* Raise an error if orig is not a credentials object or a subclass. */
if (TYPE(orig) != T_DATA ||
RDATA(orig)->dfree != (RUBY_DATA_FUNC)grpc_rb_credentials_free) {
- rb_raise(rb_eTypeError, "not a %s",
- rb_obj_classname(rb_cCredentials));
+ rb_raise(rb_eTypeError, "not a %s", rb_obj_classname(rb_cCredentials));
}
Data_Get_Struct(orig, grpc_rb_credentials, orig_cred);
@@ -238,14 +235,12 @@ static VALUE grpc_rb_credentials_init(int argc, VALUE *argv, VALUE self) {
RSTRING_PTR(pem_cert_chain), RSTRING_LEN(pem_cert_chain));
} else if (pem_private_key == Qnil) {
creds = grpc_ssl_credentials_create(
- RSTRING_PTR(pem_root_certs), RSTRING_LEN(pem_root_certs),
- NULL, 0,
+ RSTRING_PTR(pem_root_certs), RSTRING_LEN(pem_root_certs), NULL, 0,
RSTRING_PTR(pem_cert_chain), RSTRING_LEN(pem_cert_chain));
} else {
creds = grpc_ssl_credentials_create(
RSTRING_PTR(pem_root_certs), RSTRING_LEN(pem_root_certs),
- RSTRING_PTR(pem_private_key), RSTRING_LEN(pem_private_key),
- NULL, 0);
+ RSTRING_PTR(pem_private_key), RSTRING_LEN(pem_private_key), NULL, 0);
}
if (creds == NULL) {
rb_raise(rb_eRuntimeError, "could not create a credentials, not sure why");
@@ -265,15 +260,14 @@ static VALUE grpc_rb_credentials_init(int argc, VALUE *argv, VALUE self) {
VALUE rb_cCredentials = Qnil;
void Init_google_rpc_credentials() {
- rb_cCredentials = rb_define_class_under(rb_mGoogleRpcCore, "Credentials",
- rb_cObject);
+ rb_cCredentials =
+ rb_define_class_under(rb_mGoogleRpcCore, "Credentials", rb_cObject);
/* Allocates an object managed by the ruby runtime */
rb_define_alloc_func(rb_cCredentials, grpc_rb_credentials_alloc);
/* Provides a ruby constructor and support for dup/clone. */
- rb_define_method(rb_cCredentials, "initialize",
- grpc_rb_credentials_init, -1);
+ rb_define_method(rb_cCredentials, "initialize", grpc_rb_credentials_init, -1);
rb_define_method(rb_cCredentials, "initialize_copy",
grpc_rb_credentials_init_copy, 1);
@@ -294,7 +288,7 @@ void Init_google_rpc_credentials() {
}
/* Gets the wrapped grpc_credentials from the ruby wrapper */
-grpc_credentials* grpc_rb_get_wrapped_credentials(VALUE v) {
+grpc_credentials *grpc_rb_get_wrapped_credentials(VALUE v) {
grpc_rb_credentials *wrapper = NULL;
Data_Get_Struct(v, grpc_rb_credentials, wrapper);
return wrapper->wrapped;
diff --git a/src/ruby/ext/grpc/rb_credentials.h b/src/ruby/ext/grpc/rb_credentials.h
index d18c88ac34..fada3639d5 100644
--- a/src/ruby/ext/grpc/rb_credentials.h
+++ b/src/ruby/ext/grpc/rb_credentials.h
@@ -47,4 +47,4 @@ void Init_google_rpc_credentials();
/* Gets the wrapped credentials from the ruby wrapper */
grpc_credentials* grpc_rb_get_wrapped_credentials(VALUE v);
-#endif /* GRPC_RB_CREDENTIALS_H_ */
+#endif /* GRPC_RB_CREDENTIALS_H_ */
diff --git a/src/ruby/ext/grpc/rb_event.c b/src/ruby/ext/grpc/rb_event.c
index 9200f923cc..0fae9502c3 100644
--- a/src/ruby/ext/grpc/rb_event.c
+++ b/src/ruby/ext/grpc/rb_event.c
@@ -50,7 +50,6 @@ typedef struct grpc_rb_event {
grpc_event *wrapped;
} grpc_rb_event;
-
/* rb_mCompletionType is a ruby module that holds the completion type values */
VALUE rb_mCompletionType = Qnil;
@@ -107,15 +106,15 @@ static VALUE grpc_rb_event_type(VALUE self) {
return rb_const_get(rb_mCompletionType, rb_intern("READ"));
case GRPC_INVOKE_ACCEPTED:
- grpc_rb_event_result(self); /* validates the result */
+ grpc_rb_event_result(self); /* validates the result */
return rb_const_get(rb_mCompletionType, rb_intern("INVOKE_ACCEPTED"));
case GRPC_WRITE_ACCEPTED:
- grpc_rb_event_result(self); /* validates the result */
+ grpc_rb_event_result(self); /* validates the result */
return rb_const_get(rb_mCompletionType, rb_intern("WRITE_ACCEPTED"));
case GRPC_FINISH_ACCEPTED:
- grpc_rb_event_result(self); /* validates the result */
+ grpc_rb_event_result(self); /* validates the result */
return rb_const_get(rb_mCompletionType, rb_intern("FINISH_ACCEPTED"));
case GRPC_CLIENT_METADATA_READ:
@@ -129,8 +128,8 @@ static VALUE grpc_rb_event_type(VALUE self) {
return rb_const_get(rb_mCompletionType, rb_intern("SERVER_RPC_NEW"));
default:
- rb_raise(rb_eRuntimeError,
- "unrecognized event code for an rpc event:%d", event->type);
+ rb_raise(rb_eRuntimeError, "unrecognized event code for an rpc event:%d",
+ event->type);
}
return Qnil; /* should not be reached */
}
@@ -189,7 +188,6 @@ static VALUE grpc_rb_event_metadata(VALUE self) {
/* Figure out which metadata to read. */
event = wrapper->wrapped;
switch (event->type) {
-
case GRPC_CLIENT_METADATA_READ:
count = event->data.client_metadata_read.count;
metadata = event->data.client_metadata_read.elements;
@@ -218,22 +216,18 @@ static VALUE grpc_rb_event_metadata(VALUE self) {
key = rb_str_new2(metadata[i].key);
value = rb_hash_aref(result, key);
if (value == Qnil) {
- value = rb_str_new(
- metadata[i].value,
- metadata[i].value_length);
+ value = rb_str_new(metadata[i].value, metadata[i].value_length);
rb_hash_aset(result, key, value);
} else if (TYPE(value) == T_ARRAY) {
/* Add the string to the returned array */
- rb_ary_push(value, rb_str_new(
- metadata[i].value,
- metadata[i].value_length));
+ rb_ary_push(value,
+ rb_str_new(metadata[i].value, metadata[i].value_length));
} else {
/* Add the current value with this key and the new one to an array */
new_ary = rb_ary_new();
rb_ary_push(new_ary, value);
- rb_ary_push(new_ary, rb_str_new(
- metadata[i].value,
- metadata[i].value_length));
+ rb_ary_push(new_ary,
+ rb_str_new(metadata[i].value, metadata[i].value_length));
rb_hash_aset(result, key, new_ary);
}
}
@@ -252,7 +246,6 @@ static VALUE grpc_rb_event_result(VALUE self) {
event = wrapper->wrapped;
switch (event->type) {
-
case GRPC_QUEUE_SHUTDOWN:
return Qnil;
@@ -287,29 +280,24 @@ static VALUE grpc_rb_event_result(VALUE self) {
return grpc_rb_event_metadata(self);
case GRPC_FINISHED:
- return rb_struct_new(
- rb_sStatus,
- UINT2NUM(event->data.finished.status),
- (event->data.finished.details == NULL ?
- Qnil : rb_str_new2(event->data.finished.details)),
- grpc_rb_event_metadata(self),
- NULL);
+ return rb_struct_new(rb_sStatus, UINT2NUM(event->data.finished.status),
+ (event->data.finished.details == NULL
+ ? Qnil
+ : rb_str_new2(event->data.finished.details)),
+ grpc_rb_event_metadata(self), NULL);
break;
case GRPC_SERVER_RPC_NEW:
return rb_struct_new(
- rb_sNewServerRpc,
- rb_str_new2(event->data.server_rpc_new.method),
+ rb_sNewServerRpc, rb_str_new2(event->data.server_rpc_new.method),
rb_str_new2(event->data.server_rpc_new.host),
- Data_Wrap_Struct(
- rb_cTimeVal, GC_NOT_MARKED, GC_DONT_FREE,
- (void *)&event->data.server_rpc_new.deadline),
- grpc_rb_event_metadata(self),
- NULL);
+ Data_Wrap_Struct(rb_cTimeVal, GC_NOT_MARKED, GC_DONT_FREE,
+ (void *)&event->data.server_rpc_new.deadline),
+ grpc_rb_event_metadata(self), NULL);
default:
- rb_raise(rb_eRuntimeError,
- "unrecognized event code for an rpc event:%d", event->type);
+ rb_raise(rb_eRuntimeError, "unrecognized event code for an rpc event:%d",
+ event->type);
}
return Qfalse;
@@ -319,7 +307,7 @@ static VALUE grpc_rb_event_finish(VALUE self) {
grpc_event *event = NULL;
grpc_rb_event *wrapper = NULL;
Data_Get_Struct(self, grpc_rb_event, wrapper);
- if (wrapper->wrapped == NULL) { /* already closed */
+ if (wrapper->wrapped == NULL) { /* already closed */
return Qnil;
}
event = wrapper->wrapped;
@@ -337,8 +325,8 @@ VALUE rb_cEvent = Qnil;
VALUE rb_eEventError = Qnil;
void Init_google_rpc_event() {
- rb_eEventError = rb_define_class_under(rb_mGoogleRpcCore, "EventError",
- rb_eStandardError);
+ rb_eEventError =
+ rb_define_class_under(rb_mGoogleRpcCore, "EventError", rb_eStandardError);
rb_cEvent = rb_define_class_under(rb_mGoogleRpcCore, "Event", rb_cObject);
/* Prevent allocation or inialization from ruby. */
@@ -355,8 +343,8 @@ void Init_google_rpc_event() {
rb_define_alias(rb_cEvent, "close", "finish");
/* Constants representing the completion types */
- rb_mCompletionType = rb_define_module_under(rb_mGoogleRpcCore,
- "CompletionType");
+ rb_mCompletionType =
+ rb_define_module_under(rb_mGoogleRpcCore, "CompletionType");
rb_define_const(rb_mCompletionType, "QUEUE_SHUTDOWN",
INT2NUM(GRPC_QUEUE_SHUTDOWN));
rb_define_const(rb_mCompletionType, "READ", INT2NUM(GRPC_READ));
@@ -368,8 +356,7 @@ void Init_google_rpc_event() {
INT2NUM(GRPC_FINISH_ACCEPTED));
rb_define_const(rb_mCompletionType, "CLIENT_METADATA_READ",
INT2NUM(GRPC_CLIENT_METADATA_READ));
- rb_define_const(rb_mCompletionType, "FINISHED",
- INT2NUM(GRPC_FINISHED));
+ rb_define_const(rb_mCompletionType, "FINISHED", INT2NUM(GRPC_FINISHED));
rb_define_const(rb_mCompletionType, "SERVER_RPC_NEW",
INT2NUM(GRPC_SERVER_RPC_NEW));
rb_define_const(rb_mCompletionType, "RESERVED",
diff --git a/src/ruby/ext/grpc/rb_event.h b/src/ruby/ext/grpc/rb_event.h
index e4e4a796c2..a406e9e9f1 100644
--- a/src/ruby/ext/grpc/rb_event.h
+++ b/src/ruby/ext/grpc/rb_event.h
@@ -50,4 +50,4 @@ VALUE grpc_rb_new_event(grpc_event *ev);
/* Initializes the Event and EventError classes. */
void Init_google_rpc_event();
-#endif /* GRPC_RB_EVENT_H_ */
+#endif /* GRPC_RB_EVENT_H_ */
diff --git a/src/ruby/ext/grpc/rb_grpc.c b/src/ruby/ext/grpc/rb_grpc.c
index eae011d33b..8feefb047c 100644
--- a/src/ruby/ext/grpc/rb_grpc.c
+++ b/src/ruby/ext/grpc/rb_grpc.c
@@ -98,18 +98,16 @@ gpr_timespec grpc_rb_time_timeval(VALUE time, int interval) {
const char *want = " want <secs from epoch>|<Time>|<GRPC::TimeConst.*>";
switch (TYPE(time)) {
-
case T_DATA:
if (CLASS_OF(time) == rb_cTimeVal) {
Data_Get_Struct(time, gpr_timespec, time_const);
t = *time_const;
} else if (CLASS_OF(time) == rb_cTime) {
- t.tv_sec = NUM2INT(rb_funcall(time, id_tv_sec, 0));
+ t.tv_sec = NUM2INT(rb_funcall(time, id_tv_sec, 0));
t.tv_nsec = NUM2INT(rb_funcall(time, id_tv_nsec, 0));
} else {
- rb_raise(rb_eTypeError,
- "bad input: (%s)->c_timeval, got <%s>,%s",
- tstr, rb_obj_classname(time), want);
+ rb_raise(rb_eTypeError, "bad input: (%s)->c_timeval, got <%s>,%s", tstr,
+ rb_obj_classname(time), want);
}
break;
@@ -136,7 +134,7 @@ gpr_timespec grpc_rb_time_timeval(VALUE time, int interval) {
rb_raise(rb_eRangeError, "%f out of Time range",
RFLOAT(time)->float_value);
}
- t.tv_nsec = (time_t)(d*1e9+0.5);
+ t.tv_nsec = (time_t)(d * 1e9 + 0.5);
}
break;
@@ -148,9 +146,8 @@ gpr_timespec grpc_rb_time_timeval(VALUE time, int interval) {
break;
default:
- rb_raise(rb_eTypeError,
- "bad input: (%s)->c_timeval, got <%s>,%s",
- tstr, rb_obj_classname(time), want);
+ rb_raise(rb_eTypeError, "bad input: (%s)->c_timeval, got <%s>,%s", tstr,
+ rb_obj_classname(time), want);
break;
}
return t;
@@ -158,8 +155,8 @@ gpr_timespec grpc_rb_time_timeval(VALUE time, int interval) {
void Init_google_status_codes() {
/* Constants representing the status codes or grpc_status_code in status.h */
- VALUE rb_mStatusCodes = rb_define_module_under(rb_mGoogleRpcCore,
- "StatusCodes");
+ VALUE rb_mStatusCodes =
+ rb_define_module_under(rb_mGoogleRpcCore, "StatusCodes");
rb_define_const(rb_mStatusCodes, "OK", INT2NUM(GRPC_STATUS_OK));
rb_define_const(rb_mStatusCodes, "CANCELLED", INT2NUM(GRPC_STATUS_CANCELLED));
rb_define_const(rb_mStatusCodes, "UNKNOWN", INT2NUM(GRPC_STATUS_UNKNOWN));
@@ -218,19 +215,19 @@ VALUE grpc_rb_time_val_to_s(VALUE self) {
/* Adds a module with constants that map to gpr's static timeval structs. */
void Init_google_time_consts() {
- VALUE rb_mTimeConsts = rb_define_module_under(rb_mGoogleRpcCore,
- "TimeConsts");
- rb_cTimeVal = rb_define_class_under(rb_mGoogleRpcCore, "TimeSpec",
- rb_cObject);
+ VALUE rb_mTimeConsts =
+ rb_define_module_under(rb_mGoogleRpcCore, "TimeConsts");
+ rb_cTimeVal =
+ rb_define_class_under(rb_mGoogleRpcCore, "TimeSpec", rb_cObject);
rb_define_const(rb_mTimeConsts, "ZERO",
- Data_Wrap_Struct(rb_cTimeVal, GC_NOT_MARKED,
- GC_DONT_FREE, (void *)&gpr_time_0));
+ Data_Wrap_Struct(rb_cTimeVal, GC_NOT_MARKED, GC_DONT_FREE,
+ (void *)&gpr_time_0));
rb_define_const(rb_mTimeConsts, "INFINITE_FUTURE",
- Data_Wrap_Struct(rb_cTimeVal, GC_NOT_MARKED,
- GC_DONT_FREE, (void *)&gpr_inf_future));
+ Data_Wrap_Struct(rb_cTimeVal, GC_NOT_MARKED, GC_DONT_FREE,
+ (void *)&gpr_inf_future));
rb_define_const(rb_mTimeConsts, "INFINITE_PAST",
- Data_Wrap_Struct(rb_cTimeVal, GC_NOT_MARKED,
- GC_DONT_FREE, (void *)&gpr_inf_past));
+ Data_Wrap_Struct(rb_cTimeVal, GC_NOT_MARKED, GC_DONT_FREE,
+ (void *)&gpr_inf_past));
rb_define_method(rb_cTimeVal, "to_time", grpc_rb_time_val_to_time, 0);
rb_define_method(rb_cTimeVal, "inspect", grpc_rb_time_val_inspect, 0);
rb_define_method(rb_cTimeVal, "to_s", grpc_rb_time_val_to_s, 0);
@@ -241,9 +238,7 @@ void Init_google_time_consts() {
id_tv_nsec = rb_intern("tv_nsec");
}
-void grpc_rb_shutdown(void *vm) {
- grpc_shutdown();
-}
+void grpc_rb_shutdown(void *vm) { grpc_shutdown(); }
/* Initialize the Google RPC module structs */
diff --git a/src/ruby/ext/grpc/rb_grpc.h b/src/ruby/ext/grpc/rb_grpc.h
index c2c894244f..d5e8930fca 100644
--- a/src/ruby/ext/grpc/rb_grpc.h
+++ b/src/ruby/ext/grpc/rb_grpc.h
@@ -74,4 +74,4 @@ VALUE grpc_rb_cannot_init_copy(VALUE copy, VALUE self);
/* grpc_rb_time_timeval creates a gpr_timespec from a ruby time object. */
gpr_timespec grpc_rb_time_timeval(VALUE time, int interval);
-#endif /* GRPC_RB_H_ */
+#endif /* GRPC_RB_H_ */
diff --git a/src/ruby/ext/grpc/rb_metadata.c b/src/ruby/ext/grpc/rb_metadata.c
index dcacc4a976..88eb62ab73 100644
--- a/src/ruby/ext/grpc/rb_metadata.c
+++ b/src/ruby/ext/grpc/rb_metadata.c
@@ -48,7 +48,6 @@ typedef struct grpc_rb_metadata {
grpc_metadata *wrapped;
} grpc_rb_metadata;
-
/* Destroys Metadata instances. */
static void grpc_rb_metadata_free(void *p) {
if (p == NULL) {
@@ -102,7 +101,7 @@ static VALUE grpc_rb_metadata_init(VALUE self, VALUE key, VALUE value) {
wrapper->wrapped = md;
if (TYPE(key) == T_SYMBOL) {
md->key = (char *)rb_id2name(SYM2ID(key));
- } else { /* StringValueCStr does all other type exclusions for us */
+ } else { /* StringValueCStr does all other type exclusions for us */
md->key = StringValueCStr(key);
}
md->value = RSTRING_PTR(value);
@@ -189,8 +188,8 @@ static VALUE grpc_rb_metadata_value(VALUE self) {
/* rb_cMetadata is the Metadata class whose instances proxy grpc_metadata. */
VALUE rb_cMetadata = Qnil;
void Init_google_rpc_metadata() {
- rb_cMetadata = rb_define_class_under(rb_mGoogleRpcCore, "Metadata",
- rb_cObject);
+ rb_cMetadata =
+ rb_define_class_under(rb_mGoogleRpcCore, "Metadata", rb_cObject);
/* Allocates an object managed by the ruby runtime */
rb_define_alloc_func(rb_cMetadata, grpc_rb_metadata_alloc);
@@ -209,7 +208,7 @@ void Init_google_rpc_metadata() {
}
/* Gets the wrapped metadata from the ruby wrapper */
-grpc_metadata* grpc_rb_get_wrapped_metadata(VALUE v) {
+grpc_metadata *grpc_rb_get_wrapped_metadata(VALUE v) {
grpc_rb_metadata *wrapper = NULL;
Data_Get_Struct(v, grpc_rb_metadata, wrapper);
return wrapper->wrapped;
diff --git a/src/ruby/ext/grpc/rb_metadata.h b/src/ruby/ext/grpc/rb_metadata.h
index 6b705914d6..329ef15c68 100644
--- a/src/ruby/ext/grpc/rb_metadata.h
+++ b/src/ruby/ext/grpc/rb_metadata.h
@@ -42,7 +42,7 @@ extern VALUE rb_cMetadata;
/* grpc_rb_metadata_create_with_mark creates a grpc_rb_metadata with a ruby mark
* object that will be kept alive while the metadata is alive. */
-extern VALUE grpc_rb_metadata_create_with_mark(VALUE mark, grpc_metadata *md);
+extern VALUE grpc_rb_metadata_create_with_mark(VALUE mark, grpc_metadata* md);
/* Gets the wrapped metadata from the ruby wrapper */
grpc_metadata* grpc_rb_get_wrapped_metadata(VALUE v);
@@ -50,4 +50,4 @@ grpc_metadata* grpc_rb_get_wrapped_metadata(VALUE v);
/* Initializes the Metadata class. */
void Init_google_rpc_metadata();
-#endif /* GRPC_RB_METADATA_H_ */
+#endif /* GRPC_RB_METADATA_H_ */
diff --git a/src/ruby/ext/grpc/rb_server.c b/src/ruby/ext/grpc/rb_server.c
index 84fba5be4f..ef2a9f107b 100644
--- a/src/ruby/ext/grpc/rb_server.c
+++ b/src/ruby/ext/grpc/rb_server.c
@@ -128,7 +128,7 @@ static VALUE grpc_rb_server_init(int argc, VALUE *argv, VALUE self) {
}
if (args.args != NULL) {
- xfree(args.args); /* Allocated by grpc_rb_hash_convert_to_channel_args */
+ xfree(args.args); /* Allocated by grpc_rb_hash_convert_to_channel_args */
}
if (srv == NULL) {
rb_raise(rb_eRuntimeError, "could not create a gRPC server, not sure why");
@@ -240,8 +240,8 @@ static VALUE grpc_rb_server_add_http2_port(int argc, VALUE *argv, VALUE self) {
StringValueCStr(port));
}
} else if (TYPE(is_secure) != T_FALSE) {
- added_ok = grpc_server_add_secure_http2_port(s->wrapped,
- StringValueCStr(port));
+ added_ok =
+ grpc_server_add_secure_http2_port(s->wrapped, StringValueCStr(port));
if (added_ok == 0) {
rb_raise(rb_eRuntimeError,
"could not add secure port %s to server, not sure why",
@@ -271,7 +271,7 @@ void Init_google_rpc_server() {
}
/* Gets the wrapped server from the ruby wrapper */
-grpc_server* grpc_rb_get_wrapped_server(VALUE v) {
+grpc_server *grpc_rb_get_wrapped_server(VALUE v) {
grpc_rb_server *wrapper = NULL;
Data_Get_Struct(v, grpc_rb_server, wrapper);
return wrapper->wrapped;
diff --git a/src/ruby/ext/grpc/rb_server.h b/src/ruby/ext/grpc/rb_server.h
index 7fcd32c32f..92047efd18 100644
--- a/src/ruby/ext/grpc/rb_server.h
+++ b/src/ruby/ext/grpc/rb_server.h
@@ -47,4 +47,4 @@ void Init_google_rpc_server();
/* Gets the wrapped server from the ruby wrapper */
grpc_server* grpc_rb_get_wrapped_server(VALUE v);
-#endif /* GRPC_RB_SERVER_H_ */
+#endif /* GRPC_RB_SERVER_H_ */
diff --git a/src/ruby/ext/grpc/rb_server_credentials.c b/src/ruby/ext/grpc/rb_server_credentials.c
index fa0d6f2ce8..e534c11444 100644
--- a/src/ruby/ext/grpc/rb_server_credentials.c
+++ b/src/ruby/ext/grpc/rb_server_credentials.c
@@ -40,7 +40,6 @@
#include "rb_grpc.h"
-
/* grpc_rb_server_credentials wraps a grpc_server_credentials. It provides a
peer ruby object, 'mark' to minimize copying when a server credential is
created from ruby. */
@@ -91,8 +90,7 @@ static VALUE grpc_rb_server_credentials_alloc(VALUE cls) {
wrapper->wrapped = NULL;
wrapper->mark = Qnil;
return Data_Wrap_Struct(cls, grpc_rb_server_credentials_mark,
- grpc_rb_server_credentials_free,
- wrapper);
+ grpc_rb_server_credentials_free, wrapper);
}
/* Clones ServerCredentials instances.
@@ -123,7 +121,6 @@ static VALUE grpc_rb_server_credentials_init_copy(VALUE copy, VALUE orig) {
return copy;
}
-
/* The attribute used on the mark object to hold the pem_root_certs. */
static ID id_pem_root_certs;
@@ -188,9 +185,8 @@ static VALUE grpc_rb_server_credentials_init(VALUE self, VALUE pem_root_certs,
VALUE rb_cServerCredentials = Qnil;
void Init_google_rpc_server_credentials() {
- rb_cServerCredentials = rb_define_class_under(rb_mGoogleRpcCore,
- "ServerCredentials",
- rb_cObject);
+ rb_cServerCredentials =
+ rb_define_class_under(rb_mGoogleRpcCore, "ServerCredentials", rb_cObject);
/* Allocates an object managed by the ruby runtime */
rb_define_alloc_func(rb_cServerCredentials, grpc_rb_server_credentials_alloc);
@@ -199,8 +195,7 @@ void Init_google_rpc_server_credentials() {
rb_define_method(rb_cServerCredentials, "initialize",
grpc_rb_server_credentials_init, 3);
rb_define_method(rb_cServerCredentials, "initialize_copy",
- grpc_rb_server_credentials_init_copy,
- 1);
+ grpc_rb_server_credentials_init_copy, 1);
id_pem_cert_chain = rb_intern("__pem_cert_chain");
id_pem_private_key = rb_intern("__pem_private_key");
@@ -208,7 +203,7 @@ void Init_google_rpc_server_credentials() {
}
/* Gets the wrapped grpc_server_credentials from the ruby wrapper */
-grpc_server_credentials* grpc_rb_get_wrapped_server_credentials(VALUE v) {
+grpc_server_credentials *grpc_rb_get_wrapped_server_credentials(VALUE v) {
grpc_rb_server_credentials *wrapper = NULL;
Data_Get_Struct(v, grpc_rb_server_credentials, wrapper);
return wrapper->wrapped;
diff --git a/src/ruby/ext/grpc/rb_server_credentials.h b/src/ruby/ext/grpc/rb_server_credentials.h
index 39189511ab..2a2e1fbc82 100644
--- a/src/ruby/ext/grpc/rb_server_credentials.h
+++ b/src/ruby/ext/grpc/rb_server_credentials.h
@@ -47,4 +47,4 @@ void Init_google_rpc_server_credentials();
/* Gets the wrapped server_credentials from the ruby wrapper */
grpc_server_credentials* grpc_rb_get_wrapped_server_credentials(VALUE v);
-#endif /* GRPC_RB_SERVER_CREDENTIALS_H_ */
+#endif /* GRPC_RB_SERVER_CREDENTIALS_H_ */