Merge branch 'master' of github.com:ctiller/grpc

changes/47/217547/1
Craig Tiller 10 years ago
commit 4170a45732
  1. 54
      .clang-format
  2. 5
      .gitignore
  3. 2
      INSTALL
  4. 312
      Makefile
  5. 54
      build.json
  6. 60
      examples/tips/client.cc
  7. 36
      examples/tips/client.h
  8. 73
      examples/tips/client_main.cc
  9. 106
      examples/tips/client_test.cc
  10. 13
      examples/tips/empty.proto
  11. 48
      examples/tips/label.proto
  12. 702
      examples/tips/pubsub.proto
  13. 8
      include/grpc++/server_credentials.h
  14. 3
      include/grpc/grpc.h
  15. 56
      include/grpc/grpc_security.h
  16. 8
      include/grpc/support/port_platform.h
  17. 6
      src/core/iomgr/endpoint_pair_posix.c
  18. 6
      src/core/iomgr/fd_posix.c
  19. 4
      src/core/iomgr/pollset.h
  20. 6
      src/core/iomgr/pollset_kick.h
  21. 6
      src/core/iomgr/pollset_kick_posix.c
  22. 45
      src/core/iomgr/pollset_kick_windows.h
  23. 6
      src/core/iomgr/pollset_posix.c
  24. 38
      src/core/iomgr/pollset_windows.c
  25. 54
      src/core/iomgr/pollset_windows.h
  26. 6
      src/core/iomgr/resolve_address.h
  27. 10
      src/core/iomgr/socket_utils_common_posix.c
  28. 18
      src/core/iomgr/socket_utils_posix.c
  29. 6
      src/core/iomgr/tcp_client_posix.c
  30. 6
      src/core/iomgr/tcp_posix.c
  31. 5
      src/core/iomgr/tcp_server.h
  32. 10
      src/core/iomgr/tcp_server_posix.c
  33. 113
      src/core/security/credentials.c
  34. 13
      src/core/security/credentials.h
  35. 19
      src/core/security/security_context.c
  36. 2
      src/core/security/security_context.h
  37. 16
      src/core/security/server_secure_chttp2.c
  38. 2
      src/core/support/time_posix.c
  39. 2
      src/core/transport/chttp2/frame_data.c
  40. 2
      src/core/transport/chttp2/hpack_parser.c
  41. 2
      src/core/transport/chttp2_transport.c
  42. 2
      src/core/transport/stream_op.c
  43. 22
      src/cpp/client/credentials.cc
  44. 23
      src/cpp/server/server_credentials.cc
  45. 3
      src/node/binding.gyp
  46. 53
      src/node/client.js
  47. 5
      src/node/common.js
  48. 24
      src/node/credentials.cc
  49. 8
      src/node/examples/math_server.js
  50. 19
      src/node/interop/empty.proto
  51. 274
      src/node/interop/interop_client.js
  52. 203
      src/node/interop/interop_server.js
  53. 94
      src/node/interop/messages.proto
  54. 42
      src/node/interop/test.proto
  55. 12
      src/node/main.js
  56. 6
      src/node/package.json
  57. 4
      src/node/server.cc
  58. 69
      src/node/server.js
  59. 18
      src/node/server_credentials.cc
  60. 12
      src/node/surface_client.js
  61. 13
      src/node/surface_server.js
  62. 159
      src/node/test/client_server_test.js
  63. 239
      src/node/test/end_to_end_test.js
  64. 71
      src/node/test/interop_sanity_test.js
  65. 18
      src/node/test/math_client_test.js
  66. 87
      src/node/test/server_test.js
  67. 6
      src/node/test/surface_test.js
  68. 15
      src/php/ext/grpc/credentials.c
  69. 14
      src/php/ext/grpc/server_credentials.c
  70. 0
      src/python/__init__.py
  71. 0
      src/python/_framework/__init__.py
  72. 0
      src/python/_framework/foundation/__init__.py
  73. 65
      src/python/_framework/foundation/_logging_pool_test.py
  74. 83
      src/python/_framework/foundation/logging_pool.py
  75. 83
      src/ruby/README.md
  76. 11
      src/ruby/bin/interop/README.md
  77. 16
      src/ruby/bin/interop/interop_client.rb
  78. 6
      src/ruby/bin/interop/interop_server.rb
  79. 8
      src/ruby/ext/grpc/extconf.rb
  80. 2
      src/ruby/ext/grpc/rb_completion_queue.c
  81. 19
      src/ruby/ext/grpc/rb_credentials.c
  82. 14
      src/ruby/ext/grpc/rb_server_credentials.c
  83. 8
      src/ruby/grpc.gemspec
  84. 2
      src/ruby/lib/grpc/generic/bidi_call.rb
  85. 6
      src/ruby/lib/grpc/generic/rpc_server.rb
  86. 2
      src/ruby/lib/grpc/logconfig.rb
  87. 2
      src/ruby/spec/client_server_spec.rb
  88. 3
      src/ruby/spec/testdata/README
  89. 30
      templates/Makefile.template
  90. 12
      test/core/end2end/cq_verifier.c
  91. 5
      test/core/end2end/data/prod_roots_certs.c
  92. 5
      test/core/end2end/data/server1_cert.c
  93. 5
      test/core/end2end/data/server1_key.c
  94. 12
      test/core/end2end/data/ssl_test_data.h
  95. 5
      test/core/end2end/data/test_root_cert.c
  96. 11
      test/core/end2end/fixtures/chttp2_simple_ssl_fullstack.c
  97. 10
      test/core/end2end/fixtures/chttp2_simple_ssl_with_oauth2_fullstack.c
  98. 7
      test/core/fling/server.c
  99. 25
      test/core/iomgr/fd_posix_test.c
  100. 5
      test/core/iomgr/resolve_address_test.c
  101. Some files were not shown because too many files have changed in this diff Show More

@ -1,57 +1,5 @@
---
Language: Cpp
# BasedOnStyle: Google
AccessModifierOffset: -1
ConstructorInitializerIndentWidth: 4
AlignEscapedNewlinesLeft: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: false
AllowShortIfStatementsOnASingleLine: true
AllowShortLoopsOnASingleLine: true
AllowShortFunctionsOnASingleLine: All
AlwaysBreakTemplateDeclarations: true
AlwaysBreakBeforeMultilineStrings: true
BreakBeforeBinaryOperators: false
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BinPackParameters: true
ColumnLimit: 80
ConstructorInitializerAllOnOneLineOrOnePerLine: true
DerivePointerAlignment: true
ExperimentalAutoDetectBinPacking: false
IndentCaseLabels: true
IndentWrappedFunctionNames: false
IndentFunctionDeclarationAfterType: false
MaxEmptyLinesToKeep: 1
KeepEmptyLinesAtTheStartOfBlocks: false
NamespaceIndentation: None
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: false
PenaltyBreakBeforeFirstCallParameter: 1
PenaltyBreakComment: 300
PenaltyBreakString: 1000
PenaltyBreakFirstLessLess: 120
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 200
PointerAlignment: Left
SpacesBeforeTrailingComments: 2
Cpp11BracedListStyle: true
Standard: Auto
IndentWidth: 2
TabWidth: 8
UseTab: Never
BreakBeforeBraces: Attach
SpacesInParentheses: false
SpacesInAngles: false
SpaceInEmptyParentheses: false
SpacesInCStyleCastParentheses: false
SpacesInContainerLiterals: true
SpaceBeforeAssignmentOperators: true
ContinuationIndentWidth: 4
CommentPragmas: '^ IWYU pragma:'
ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
SpaceBeforeParens: ControlStatements
DisableFormat: false
BasedOnStyle: Google
...

5
.gitignore vendored

@ -4,6 +4,9 @@ gens
libs
objs
# Python virtual environment (pre-3.4 only)
python2.7_virtual_environment
# gcov coverage data
coverage
*.gcno
@ -17,3 +20,5 @@ coverage
# cache for run_tests.py
.run_tests_cache
# emacs temp files
*~

@ -17,7 +17,7 @@ A typical unix installation won't require any more steps than running:
You don't need anything else than GNU Make and gcc. Under a Debian or
Ubuntu system, this should boil down to the following package:
# apt-get install build-essential
# apt-get install build-essential python-all-dev python-virtualenv
*******************************

File diff suppressed because one or more lines are too long

@ -48,7 +48,9 @@
"src/core/iomgr/pollset.h",
"src/core/iomgr/pollset_kick.h",
"src/core/iomgr/pollset_kick_posix.h",
"src/core/iomgr/pollset_kick_windows.h",
"src/core/iomgr/pollset_posix.h",
"src/core/iomgr/pollset_windows.h",
"src/core/iomgr/resolve_address.h",
"src/core/iomgr/sockaddr.h",
"src/core/iomgr/sockaddr_posix.h",
@ -126,6 +128,7 @@
"src/core/iomgr/pollset_kick_posix.c",
"src/core/iomgr/pollset_multipoller_with_poll_posix.c",
"src/core/iomgr/pollset_posix.c",
"src/core/iomgr/pollset_windows.c",
"src/core/iomgr/resolve_address_posix.c",
"src/core/iomgr/sockaddr_utils.c",
"src/core/iomgr/socket_utils_common_posix.c",
@ -408,6 +411,22 @@
"test/cpp/end2end/async_test_server.cc",
"test/cpp/util/create_test_channel.cc"
]
},
{
"name": "tips_client_lib",
"build": "private",
"language": "c++",
"src": [
"examples/tips/label.proto",
"examples/tips/empty.proto",
"examples/tips/pubsub.proto",
"examples/tips/client.cc"
],
"deps": [
"grpc++",
"grpc",
"gpr"
]
}
],
"targets": [
@ -1493,6 +1512,41 @@
],
"run": false
},
{
"name": "tips_client",
"build": "test",
"run": false,
"language": "c++",
"src": [
"examples/tips/client_main.cc"
],
"deps": [
"tips_client_lib",
"grpc++_test_util",
"grpc_test_util",
"grpc++",
"grpc",
"gpr_test_util",
"gpr"
]
},
{
"name": "tips_client_test",
"build": "test",
"language": "c++",
"src": [
"examples/tips/client_test.cc"
],
"deps": [
"tips_client_lib",
"grpc++_test_util",
"grpc_test_util",
"grpc++",
"grpc",
"gpr_test_util",
"gpr"
]
},
{
"name": "qps_client",
"build": "test",

@ -0,0 +1,60 @@
/*
*
* Copyright 2014, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <grpc++/client_context.h>
#include "examples/tips/client.h"
using tech::pubsub::Topic;
using tech::pubsub::PublisherService;
namespace grpc {
namespace examples {
namespace tips {
Client::Client(std::shared_ptr<ChannelInterface> channel)
: stub_(PublisherService::NewStub(channel)) {
}
Status Client::CreateTopic(grpc::string topic) {
Topic request;
Topic response;
request.set_name(topic);
ClientContext context;
return stub_->CreateTopic(&context, request, &response);
}
} // namespace tips
} // namespace examples
} // namespace grpc

@ -31,22 +31,24 @@
*
*/
var net = require('net');
#include <grpc++/channel_interface.h>
#include <grpc++/status.h>
/**
* 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());
});
});
}
#include "examples/tips/pubsub.pb.h"
namespace grpc {
namespace examples {
namespace tips {
class Client {
public:
Client(std::shared_ptr<grpc::ChannelInterface> channel);
Status CreateTopic(grpc::string topic);
private:
std::unique_ptr<tech::pubsub::PublisherService::Stub> stub_;
};
exports.nextAvailablePort = nextAvailablePort;
} // namespace tips
} // namespace examples
} // namespace grpc

@ -0,0 +1,73 @@
/*
*
* Copyright 2014, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <grpc/grpc.h>
#include <grpc/support/log.h>
#include <google/gflags.h>
#include <grpc++/channel_interface.h>
#include <grpc++/create_channel.h>
#include <grpc++/status.h>
#include "examples/tips/client.h"
#include "test/cpp/util/create_test_channel.h"
DEFINE_bool(enable_ssl, true, "Whether to use ssl/tls.");
DEFINE_bool(use_prod_roots, true, "True to use SSL roots for production GFE");
DEFINE_int32(server_port, 0, "Server port.");
DEFINE_string(server_host, "127.0.0.1", "Server host to connect to");
DEFINE_string(server_host_override, "foo.test.google.com",
"Override the server host which is sent in HTTP header");
int main(int argc, char** argv) {
grpc_init();
google::ParseCommandLineFlags(&argc, &argv, true);
gpr_log(GPR_INFO, "Start TIPS client");
GPR_ASSERT(FLAGS_server_port);
const int host_port_buf_size = 1024;
char host_port[host_port_buf_size];
snprintf(host_port, host_port_buf_size, "%s:%d", FLAGS_server_host.c_str(),
FLAGS_server_port);
std::shared_ptr<grpc::ChannelInterface> channel(
grpc::CreateTestChannel(host_port, FLAGS_server_host_override,
FLAGS_enable_ssl, FLAGS_use_prod_roots));
grpc::examples::tips::Client client(channel);
grpc::Status s = client.CreateTopic("test");
GPR_ASSERT(s.IsOk());
channel.reset();
grpc_shutdown();
return 0;
}

@ -0,0 +1,106 @@
/*
*
* Copyright 2014, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <grpc++/channel_arguments.h>
#include <grpc++/channel_interface.h>
#include <grpc++/client_context.h>
#include <grpc++/create_channel.h>
#include <grpc++/server.h>
#include <grpc++/server_builder.h>
#include <grpc++/server_context.h>
#include <grpc++/status.h>
#include <gtest/gtest.h>
#include "examples/tips/client.h"
#include "test/core/util/port.h"
#include "test/core/util/test_config.h"
using grpc::ChannelInterface;
namespace grpc {
namespace testing {
namespace {
const char kTopic[] = "test topic";
class PublishServiceImpl : public tech::pubsub::PublisherService::Service {
public:
Status CreateTopic(::grpc::ServerContext* context,
const ::tech::pubsub::Topic* request,
::tech::pubsub::Topic* response) override {
EXPECT_EQ(request->name(), kTopic);
return Status::OK;
}
};
class End2endTest : public ::testing::Test {
protected:
void SetUp() override {
int port = grpc_pick_unused_port_or_die();
server_address_ << "localhost:" << port;
// Setup server
ServerBuilder builder;
builder.AddPort(server_address_.str());
builder.RegisterService(service_.service());
server_ = builder.BuildAndStart();
channel_ = CreateChannel(server_address_.str(), ChannelArguments());
}
void TearDown() override { server_->Shutdown(); }
std::unique_ptr<Server> server_;
std::ostringstream server_address_;
PublishServiceImpl service_;
std::shared_ptr<ChannelInterface> channel_;
};
TEST_F(End2endTest, CreateTopic) {
grpc::examples::tips::Client client(channel_);
client.CreateTopic(kTopic);
}
} // namespace
} // namespace testing
} // namespace grpc
int main(int argc, char** argv) {
grpc_test_init(argc, argv);
grpc_init();
::testing::InitGoogleTest(&argc, argv);
gpr_log(GPR_INFO, "Start test ...");
int result = RUN_ALL_TESTS();
grpc_shutdown();
return result;
}

@ -0,0 +1,13 @@
syntax = "proto2";
package proto2;
// An empty message that you can re-use to avoid defining duplicated empty
// messages in your project. A typical example is to use it as argument or the
// return value of a service API. For instance:
//
// service Foo {
// rpc Bar (proto2.Empty) returns (proto2.Empty) { };
// };
//
message Empty {}

@ -0,0 +1,48 @@
// Labels provide a way to associate user-defined metadata with various
// objects. Labels may be used to organize objects into non-hierarchical
// groups; think metadata tags attached to mp3s.
syntax = "proto2";
package tech.label;
// A key-value pair applied to a given object.
message Label {
// The key of a label is a syntactically valid URL (as per RFC 1738) with
// the "scheme" and initial slashes omitted and with the additional
// restrictions noted below. Each key should be globally unique. The
// "host" portion is called the "namespace" and is not necessarily
// resolvable to a network endpoint. Instead, the namespace indicates what
// system or entity defines the semantics of the label. Namespaces do not
// restrict the set of objects to which a label may be associated.
//
// Keys are defined by the following grammar:
//
// key = hostname "/" kpath
// kpath = ksegment *[ "/" ksegment ]
// ksegment = alphadigit | *[ alphadigit | "-" | "_" | "." ]
//
// where "hostname" and "alphadigit" are defined as in RFC 1738.
//
// Example key:
// spanner.google.com/universe
required string key = 1;
// The value of the label.
oneof value {
// A string value.
string str_value = 2;
// An integer value.
int64 num_value = 3;
}
}
// A collection of labels, such as the set of all labels attached to an
// object. Each label in the set must have a different key.
//
// Users should prefer to embed "repeated Label" directly when possible.
// This message should only be used in cases where that isn't possible (e.g.
// with oneof).
message Labels {
repeated Label label = 1;
}

@ -0,0 +1,702 @@
// Specification of the Pubsub API.
syntax = "proto2";
import "examples/tips/empty.proto";
import "examples/tips/label.proto";
package tech.pubsub;
// -----------------------------------------------------------------------------
// Overview of the Pubsub API
// -----------------------------------------------------------------------------
// This file describes an API for a Pubsub system. This system provides a
// reliable many-to-many communication mechanism between independently written
// publishers and subscribers where the publisher publishes messages to "topics"
// and each subscriber creates a "subscription" and consumes messages from it.
//
// (a) The pubsub system maintains bindings between topics and subscriptions.
// (b) A publisher publishes messages into a topic.
// (c) The pubsub system delivers messages from topics into relevant
// subscriptions.
// (d) A subscriber receives pending messages from its subscription and
// acknowledges or nacks each one to the pubsub system.
// (e) The pubsub system removes acknowledged messages from that subscription.
// -----------------------------------------------------------------------------
// Data Model
// -----------------------------------------------------------------------------
// The data model consists of the following:
//
// * Topic: A topic is a resource to which messages are published by publishers.
// Topics are named, and the name of the topic is unique within the pubsub
// system.
//
// * Subscription: A subscription records the subscriber's interest in a topic.
// It can optionally include a query to select a subset of interesting
// messages. The pubsub system maintains a logical cursor tracking the
// matching messages which still need to be delivered and acked so that
// they can retried as needed. The set of messages that have not been
// acknowledged is called the subscription backlog.
//
// * Message: A message is a unit of data that flows in the system. It contains
// opaque data from the publisher along with its labels.
//
// * Message Labels (optional): A set of opaque key, value pairs assigned
// by the publisher which the subscriber can use for filtering out messages
// in the topic. For example, a label with key "foo.com/device_type" and
// value "mobile" may be added for messages that are only relevant for a
// mobile subscriber; a subscriber on a phone may decide to create a
// subscription only for messages that have this label.
// -----------------------------------------------------------------------------
// Publisher Flow
// -----------------------------------------------------------------------------
// A publisher publishes messages to the topic using the Publish request:
//
// PubsubMessage message;
// message.set_data("....");
// Label label;
// label.set_key("foo.com/key1");
// label.set_str_value("value1");
// message.add_label(label);
// PublishRequest request;
// request.set_topic("topicName");
// request.set_message(message);
// PublisherService.Publish(request);
// -----------------------------------------------------------------------------
// Subscriber Flow
// -----------------------------------------------------------------------------
// The subscriber part of the API is richer than the publisher part and has a
// number of concepts w.r.t. subscription creation and monitoring:
//
// (1) A subscriber creates a subscription using the CreateSubscription call.
// It may specify an optional "query" to indicate that it wants to receive
// only messages with a certain set of labels using the label query syntax.
// It may also specify an optional truncation policy to indicate when old
// messages from the subcription can be removed.
//
// (2) A subscriber receives messages in one of two ways: via push or pull.
//
// (a) To receive messages via push, the PushConfig field must be specified in
// the Subscription parameter when creating a subscription. The PushConfig
// specifies an endpoint at which the subscriber must expose the
// PushEndpointService. Messages are received via the HandlePubsubEvent
// method. The push subscriber responds to the HandlePubsubEvent method
// with a result code that indicates one of three things: Ack (the message
// has been successfully processed and the Pubsub system may delete it),
// Nack (the message has been rejected, the Pubsub system should resend it
// at a later time), or Push-Back (this is a Nack with the additional
// semantics that the subscriber is overloaded and the pubsub system should
// back off on the rate at which it is invoking HandlePubsubEvent). The
// endpoint may be a load balancer for better scalability.
//
// (b) To receive messages via pull a subscriber calls the Pull method on the
// SubscriberService to get messages from the subscription. For each
// individual message, the subscriber may use the ack_id received in the
// PullResponse to Ack the message, Nack the message, or modify the ack
// deadline with ModifyAckDeadline. See the
// Subscription.ack_deadline_seconds field documentation for details on the
// ack deadline behavior.
//
// Note: Messages may be consumed in parallel by multiple subscribers making
// Pull calls to the same subscription; this will result in the set of
// messages from the subscription being shared and each subscriber
// receiving a subset of the messages.
//
// (4) The subscriber can explicitly truncate the current subscription.
//
// (5) "Truncated" events are delivered when a subscription is
// truncated, whether due to the subscription's truncation policy
// or an explicit request from the subscriber.
//
// Subscription creation:
//
// Subscription subscription;
// subscription.set_topic("topicName");
// subscription.set_name("subscriptionName");
// subscription.push_config().set_push_endpoint("machinename:8888");
// SubscriberService.CreateSubscription(subscription);
//
// Consuming messages via push:
//
// TODO(eschapira): Add HTTP push example.
//
// The port 'machinename:8888' must be bound to a stubby server that implements
// the PushEndpointService with the following method:
//
// int HandlePubsubEvent(PubsubEvent event) {
// if (event.subscription().equals("subscriptionName")) {
// if (event.has_message()) {
// Process(event.message().data());
// } else if (event.truncated()) {
// ProcessTruncatedEvent();
// }
// }
// return OK; // This return code implies an acknowledgment
// }
//
// Consuming messages via pull:
//
// The subscription must be created without setting the push_config field.
//
// PullRequest pull_request;
// pull_request.set_subscription("subscriptionName");
// pull_request.set_return_immediately(false);
// while (true) {
// PullResponse pull_response;
// if (SubscriberService.Pull(pull_request, pull_response) == OK) {
// PubsubEvent event = pull_response.pubsub_event();
// if (event.has_message()) {
// Process(event.message().data());
// } else if (event.truncated()) {
// ProcessTruncatedEvent();
// }
// AcknowledgeRequest ack_request;
// ackRequest.set_subscription("subscriptionName");
// ackRequest.set_ack_id(pull_response.ack_id());
// SubscriberService.Acknowledge(ack_request);
// }
// }
// -----------------------------------------------------------------------------
// Reliability Semantics
// -----------------------------------------------------------------------------
// When a subscriber successfully creates a subscription using
// Subscriber.CreateSubscription, it establishes a "subscription point" with
// respect to that subscription - the subscriber is guaranteed to receive any
// message published after this subscription point that matches the
// subscription's query. Note that messages published before the Subscription
// point may or may not be delivered.
//
// If the system truncates the subscription according to the specified
// truncation policy, the system delivers a subscription status event with the
// "truncated" field set to true. We refer to such events as "truncation
// events". A truncation event:
//
// * Informs the subscriber that part of the subscription messages have been
// discarded. The subscriber may want to recover from the message loss, e.g.,
// by resyncing its state with its backend.
// * Establishes a new subscription point, i.e., the subscriber is guaranteed to
// receive all changes published after the trunction event is received (or
// until another truncation event is received).
//
// Note that messages are not delivered in any particular order by the pubsub
// system. Furthermore, the system guarantees at-least-once delivery
// of each message or truncation events until acked.
// -----------------------------------------------------------------------------
// Deletion
// -----------------------------------------------------------------------------
// Both topics and subscriptions may be deleted. Deletion of a topic implies
// deletion of all attached subscriptions.
//
// When a subscription is deleted directly by calling DeleteSubscription, all
// messages are immediately dropped. If it is a pull subscriber, future pull
// requests will return NOT_FOUND.
//
// When a topic is deleted all corresponding subscriptions are immediately
// deleted, and subscribers experience the same behavior as directly deleting
// the subscription.
// -----------------------------------------------------------------------------
// The Publisher service and its protos.
// -----------------------------------------------------------------------------
// The service that an application uses to manipulate topics, and to send
// messages to a topic.
service PublisherService {
// Creates the given topic with the given name.
rpc CreateTopic(Topic) returns (Topic) {
}
// Adds a message to the topic. Returns NOT_FOUND if the topic does not
// exist.
// (-- For different error code values returned via Stubby, see
// util/task/codes.proto. --)
rpc Publish(PublishRequest) returns (proto2.Empty) {
}
// Adds one or more messages to the topic. Returns NOT_FOUND if the topic does
// not exist.
rpc PublishBatch(PublishBatchRequest) returns (PublishBatchResponse) {
}
// Gets the configuration of a topic. Since the topic only has the name
// attribute, this method is only useful to check the existence of a topic.
// If other attributes are added in the future, they will be returned here.
rpc GetTopic(GetTopicRequest) returns (Topic) {
}
// Lists matching topics.
rpc ListTopics(ListTopicsRequest) returns (ListTopicsResponse) {
}
// Deletes the topic with the given name. All subscriptions to this topic
// are also deleted. Returns NOT_FOUND if the topic does not exist.
// After a topic is deleted, a new topic may be created with the same name.
rpc DeleteTopic(DeleteTopicRequest) returns (proto2.Empty) {
}
}
// A topic resource.
message Topic {
// Name of the topic.
optional string name = 1;
}
// A message data and its labels.
message PubsubMessage {
// The message payload.
optional bytes data = 1;
// Optional list of labels for this message. Keys in this collection must
// be unique.
//(-- TODO(eschapira): Define how key namespace may be scoped to the topic.--)
repeated tech.label.Label label = 2;
// ID of this message assigned by the server at publication time. Guaranteed
// to be unique within the topic. This value may be read by a subscriber
// that receives a PubsubMessage via a Pull call or a push delivery. It must
// not be populated by a publisher in a Publish call.
optional string message_id = 3;
}
// Request for the GetTopic method.
message GetTopicRequest {
// The name of the topic to get.
optional string topic = 1;
}
// Request for the Publish method.
message PublishRequest {
// The message in the request will be published on this topic.
optional string topic = 1;
// The message to publish.
optional PubsubMessage message = 2;
}
// Request for the PublishBatch method.
message PublishBatchRequest {
// The messages in the request will be published on this topic.
optional string topic = 1;
// The messages to publish.
repeated PubsubMessage messages = 2;
}
// Response for the PublishBatch method.
message PublishBatchResponse {
// The server-assigned ID of each published message, in the same order as
// the messages in the request. IDs are guaranteed to be unique within
// the topic.
repeated string message_ids = 1;
}
// Request for the ListTopics method.
message ListTopicsRequest {
// A valid label query expression.
// (-- Which labels are required or supported is implementation-specific. --)
optional string query = 1;
// Maximum number of topics to return.
// (-- If not specified or <= 0, the implementation will select a reasonable
// value. --)
optional int32 max_results = 2;
// The value obtained in the last <code>ListTopicsResponse</code>
// for continuation.
optional string page_token = 3;
}
// Response for the ListTopics method.
message ListTopicsResponse {
// The resulting topics.
repeated Topic topic = 1;
// If not empty, indicates that there are more topics that match the request,
// and this value should be passed to the next <code>ListTopicsRequest</code>
// to continue.
optional string next_page_token = 2;
}
// Request for the Delete method.
message DeleteTopicRequest {
// Name of the topic to delete.
optional string topic = 1;
}
// -----------------------------------------------------------------------------
// The Subscriber service and its protos.
// -----------------------------------------------------------------------------
// The service that an application uses to manipulate subscriptions and to
// consume messages from a subscription via the pull method.
service SubscriberService {
// Creates a subscription on a given topic for a given subscriber.
// If the subscription already exists, returns ALREADY_EXISTS.
// If the corresponding topic doesn't exist, returns NOT_FOUND.
//
// If the name is not provided in the request, the server will assign a random
// name for this subscription on the same project as the topic.
rpc CreateSubscription(Subscription) returns (Subscription) {
}
// Gets the configuration details of a subscription.
rpc GetSubscription(GetSubscriptionRequest) returns (Subscription) {
}
// Lists matching subscriptions.
rpc ListSubscriptions(ListSubscriptionsRequest)
returns (ListSubscriptionsResponse) {
}
// Deletes an existing subscription. All pending messages in the subscription
// are immediately dropped. Calls to Pull after deletion will return
// NOT_FOUND.
rpc DeleteSubscription(DeleteSubscriptionRequest) returns (proto2.Empty) {
}
// Removes all the pending messages in the subscription and releases the
// storage associated with them. Results in a truncation event to be sent to
// the subscriber. Messages added after this call returns are stored in the
// subscription as before.
rpc TruncateSubscription(TruncateSubscriptionRequest) returns (proto2.Empty) {
}
//
// Push subscriber calls.
//
// Modifies the <code>PushConfig</code> for a specified subscription.
// This method can be used to suspend the flow of messages to an endpoint
// by clearing the <code>PushConfig</code> field in the request. Messages
// will be accumulated for delivery even if no push configuration is
// defined or while the configuration is modified.
rpc ModifyPushConfig(ModifyPushConfigRequest) returns (proto2.Empty) {
}
//
// Pull Subscriber calls
//
// Pulls a single message from the server.
// If return_immediately is true, and no messages are available in the
// subscription, this method returns FAILED_PRECONDITION. The system is free
// to return an UNAVAILABLE error if no messages are available in a
// reasonable amount of time (to reduce system load).
rpc Pull(PullRequest) returns (PullResponse) {
}
// Pulls messages from the server. Returns an empty list if there are no
// messages available in the backlog. The system is free to return UNAVAILABLE
// if there are too many pull requests outstanding for the given subscription.
rpc PullBatch(PullBatchRequest) returns (PullBatchResponse) {
}
// Modifies the Ack deadline for a message received from a pull request.
rpc ModifyAckDeadline(ModifyAckDeadlineRequest) returns (proto2.Empty) {
}
// Acknowledges a particular received message: the Pub/Sub system can remove
// the given message from the subscription. Acknowledging a message whose
// Ack deadline has expired may succeed, but the message could have been
// already redelivered. Acknowledging a message more than once will not
// result in an error. This is only used for messages received via pull.
rpc Acknowledge(AcknowledgeRequest) returns (proto2.Empty) {
}
// Refuses processing a particular received message. The system will
// redeliver this message to some consumer of the subscription at some
// future time. This is only used for messages received via pull.
rpc Nack(NackRequest) returns (proto2.Empty) {
}
}
// A subscription resource.
message Subscription {
// Name of the subscription.
optional string name = 1;
// The name of the topic from which this subscription is receiving messages.
optional string topic = 2;
// If <code>query</code> is non-empty, only messages on the subscriber's
// topic whose labels match the query will be returned. Otherwise all
// messages on the topic will be returned.
// (-- The query syntax is described in tech/label/proto/label_query.proto --)
optional string query = 3;
// The subscriber may specify requirements for truncating unacknowledged
// subscription entries. The system will honor the
// <code>CreateSubscription</code> request only if it can meet these
// requirements. If this field is not specified, messages are never truncated
// by the system.
optional TruncationPolicy truncation_policy = 4;
// Specifies which messages can be truncated by the system.
message TruncationPolicy {
oneof policy {
// If <code>max_bytes</code> is specified, the system is allowed to drop
// old messages to keep the combined size of stored messages under
// <code>max_bytes</code>. This is a hint; the system may keep more than
// this many bytes, but will make a best effort to keep the size from
// growing much beyond this parameter.
int64 max_bytes = 1;
// If <code>max_age_seconds</code> is specified, the system is allowed to
// drop messages that have been stored for at least this many seconds.
// This is a hint; the system may keep these messages, but will make a
// best effort to remove them when their maximum age is reached.
int64 max_age_seconds = 2;
}
}
// If push delivery is used with this subscription, this field is
// used to configure it.
optional PushConfig push_config = 5;
// For either push or pull delivery, the value is the maximum time after a
// subscriber receives a message before the subscriber should acknowledge or
// Nack the message. If the Ack deadline for a message passes without an
// Ack or a Nack, the Pub/Sub system will eventually redeliver the message.
// If a subscriber acknowledges after the deadline, the Pub/Sub system may
// accept the Ack, but it is possible that the message has been already
// delivered again. Multiple Acks to the message are allowed and will
// succeed.
//
// For push delivery, this value is used to set the request timeout for
// the call to the push endpoint.
//
// For pull delivery, this value is used as the initial value for the Ack
// deadline. It may be overridden for a specific pull request (message) with
// <code>ModifyAckDeadline</code>.
// While a message is outstanding (i.e. it has been delivered to a pull
// subscriber and the subscriber has not yet Acked or Nacked), the Pub/Sub
// system will not deliver that message to another pull subscriber
// (on a best-effort basis).
optional int32 ack_deadline_seconds = 6;
// If this parameter is set to n, the system is allowed to (but not required
// to) delete the subscription when at least n seconds have elapsed since the
// client presence was detected. (Presence is detected through any
// interaction using the subscription ID, including Pull(), Get(), or
// acknowledging a message.)
//
// If this parameter is not set, the subscription will stay live until
// explicitly deleted.
//
// Clients can detect such garbage collection when a Get call or a Pull call
// (for pull subscribers only) returns NOT_FOUND.
optional int64 garbage_collect_seconds = 7;
}
// Configuration for a push delivery endpoint.
message PushConfig {
// A URL locating the endpoint to which messages should be pushed.
// For example, a Webhook endpoint might use "https://example.com/push".
// (-- An Android application might use "gcm:<REGID>", where <REGID> is a
// GCM registration id allocated for pushing messages to the application. --)
optional string push_endpoint = 1;
}
// An event indicating a received message or truncation event.
message PubsubEvent {
// The subscription that received the event.
optional string subscription = 1;
oneof type {
// A received message.
PubsubMessage message = 2;
// Indicates that this subscription has been truncated.
bool truncated = 3;
// Indicates that this subscription has been deleted. (Note that pull
// subscribers will always receive NOT_FOUND in response in their pull
// request on the subscription, rather than seeing this boolean.)
bool deleted = 4;
}
}
// Request for the GetSubscription method.
message GetSubscriptionRequest {
// The name of the subscription to get.
optional string subscription = 1;
}
// Request for the ListSubscriptions method.
message ListSubscriptionsRequest {
// A valid label query expression.
// (-- Which labels are required or supported is implementation-specific.
// TODO(eschapira): This method must support to query by topic. We must
// define the key URI for the "topic" label. --)
optional string query = 1;
// Maximum number of subscriptions to return.
// (-- If not specified or <= 0, the implementation will select a reasonable
// value. --)
optional int32 max_results = 3;
// The value obtained in the last <code>ListSubscriptionsResponse</code>
// for continuation.
optional string page_token = 4;
}
// Response for the ListSubscriptions method.
message ListSubscriptionsResponse {
// The subscriptions that match the request.
repeated Subscription subscription = 1;
// If not empty, indicates that there are more subscriptions that match the
// request and this value should be passed to the next
// <code>ListSubscriptionsRequest</code> to continue.
optional string next_page_token = 2;
}
// Request for the TruncateSubscription method.
message TruncateSubscriptionRequest {
// The subscription that is being truncated.
optional string subscription = 1;
}
// Request for the DeleteSubscription method.
message DeleteSubscriptionRequest {
// The subscription to delete.
optional string subscription = 1;
}
// Request for the ModifyPushConfig method.
message ModifyPushConfigRequest {
// The name of the subscription.
optional string subscription = 1;
// An empty <code>push_config</code> indicates that the Pub/Sub system should
// pause pushing messages from the given subscription.
optional PushConfig push_config = 2;
}
// -----------------------------------------------------------------------------
// The protos used by a pull subscriber.
// -----------------------------------------------------------------------------
// Request for the Pull method.
message PullRequest {
// The subscription from which a message should be pulled.
optional string subscription = 1;
// If this is specified as true the system will respond immediately even if
// it is not able to return a message in the Pull response. Otherwise the
// system is allowed to wait until at least one message is available rather
// than returning FAILED_PRECONDITION. The client may cancel the request if
// it does not wish to wait any longer for the response.
optional bool return_immediately = 2;
}
// Either a <code>PubsubMessage</code> or a truncation event. One of these two
// must be populated.
message PullResponse {
// This ID must be used to acknowledge the received event or message.
optional string ack_id = 1;
// A pubsub message or truncation event.
optional PubsubEvent pubsub_event = 2;
}
// Request for the PullBatch method.
message PullBatchRequest {
// The subscription from which messages should be pulled.
optional string subscription = 1;
// If this is specified as true the system will respond immediately even if
// it is not able to return a message in the Pull response. Otherwise the
// system is allowed to wait until at least one message is available rather
// than returning no messages. The client may cancel the request if it does
// not wish to wait any longer for the response.
optional bool return_immediately = 2;
// The maximum number of PubsubEvents returned for this request. The Pub/Sub
// system may return fewer than the number of events specified.
optional int32 max_events = 3;
}
// Response for the PullBatch method.
message PullBatchResponse {
// Received Pub/Sub messages or status events. The Pub/Sub system will return
// zero messages if there are no more messages available in the backlog. The
// Pub/Sub system may return fewer than the max_events requested even if
// there are more messages available in the backlog.
repeated PullResponse pull_responses = 2;
}
// Request for the ModifyAckDeadline method.
message ModifyAckDeadlineRequest {
// The name of the subscription from which messages are being pulled.
optional string subscription = 1;
// The acknowledgment ID.
optional string ack_id = 2;
// The new Ack deadline. Must be >= 0.
optional int32 ack_deadline_seconds = 3;
}
// Request for the Acknowledge method.
message AcknowledgeRequest {
// The subscription whose message is being acknowledged.
optional string subscription = 1;
// The acknowledgment ID for the message being acknowledged. This was
// returned by the Pub/Sub system in the Pull response.
repeated string ack_id = 2;
}
// Request for the Nack method.
message NackRequest {
// The subscription whose message is being Nacked.
optional string subscription = 1;
// The acknowledgment ID for the message being refused. This was returned by
// the Pub/Sub system in the Pull response.
repeated string ack_id = 2;
}
// -----------------------------------------------------------------------------
// The service and protos used by a push subscriber.
// -----------------------------------------------------------------------------
// The service that a subscriber uses to handle messages sent via push
// delivery.
// This service is not currently exported for HTTP clients.
// TODO(eschapira): Explain HTTP subscribers.
service PushEndpointService {
// Sends a <code>PubsubMessage</code> or a subscription status event to a
// push endpoint.
// The push endpoint responds with an empty message and a code from
// util/task/codes.proto. The following codes have a particular meaning to the
// Pub/Sub system:
// OK - This is interpreted by Pub/Sub as Ack.
// ABORTED - This is intepreted by Pub/Sub as a Nack, without implying
// pushback for congestion control. The Pub/Sub system will
// retry this message at a later time.
// UNAVAILABLE - This is intepreted by Pub/Sub as a Nack, with the additional
// semantics of push-back. The Pub/Sub system will use an AIMD
// congestion control algorithm to backoff the rate of sending
// messages from this subscription.
// Any other code, or a failure to respond, will be interpreted in the same
// way as ABORTED; i.e. the system will retry the message at a later time to
// ensure reliable delivery.
rpc HandlePubsubEvent(PubsubEvent) returns (proto2.Empty);
}

@ -35,6 +35,7 @@
#define __GRPCPP_SERVER_CREDENTIALS_H_
#include <memory>
#include <vector>
#include <grpc++/config.h>
@ -60,9 +61,12 @@ class ServerCredentials final {
// Options to create ServerCredentials with SSL
struct SslServerCredentialsOptions {
struct PemKeyCertPair{
grpc::string private_key;
grpc::string cert_chain;
};
grpc::string pem_root_certs;
grpc::string pem_private_key;
grpc::string pem_cert_chain;
std::vector<PemKeyCertPair> pem_key_cert_pairs;
};
// Factory for building different types of ServerCredentials

@ -428,7 +428,8 @@ grpc_server *grpc_server_create(grpc_completion_queue *cq,
REQUIRES: server not started */
int grpc_server_add_http2_port(grpc_server *server, const char *addr);
/* Add a secure port to server; returns 1 on success, 0 on failure
/* Add a secure port to server.
Returns bound port number on success, 0 on failure.
REQUIRES: server not started */
int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr);

@ -54,22 +54,26 @@ void grpc_credentials_release(grpc_credentials *creds);
/* Creates default credentials. */
grpc_credentials *grpc_default_credentials_create(void);
/* Object that holds a private key / certificate chain pair in PEM format. */
typedef struct {
/* private_key is the NULL-terminated string containing the PEM encoding of
the client's private key. */
const char *private_key;
/* cert_chain is the NULL-terminated string containing the PEM encoding of
the client's certificate chain. */
const char *cert_chain;
} grpc_ssl_pem_key_cert_pair;
/* Creates an SSL credentials object.
- pem_roots_cert is the buffer containing the PEM encoding of the server
root certificates. This parameter cannot be NULL.
- pem_roots_cert_size is the size of the associated buffer.
- pem_private_key is the buffer containing the PEM encoding of the client's
private key. This parameter can be NULL if the client does not have a
private key.
- pem_private_key_size is the size of the associated buffer.
- pem_cert_chain is the buffer containing the PEM encoding of the client's
certificate chain. This parameter can be NULL if the client does not have
a certificate chain.
- pem_cert_chain_size is the size of the associated buffer. */
- pem_roots_cert is the NULL-terminated string containing the PEM encoding
of the server root certificates. If this parameter is NULL, the default
roots will be used.
- pem_key_cert_pair is a pointer on the object containing client's private
key and certificate chain. This parameter can be NULL if the client does
not have such a key/cert pair. */
grpc_credentials *grpc_ssl_credentials_create(
const unsigned char *pem_root_certs, size_t pem_root_certs_size,
const unsigned char *pem_private_key, size_t pem_private_key_size,
const unsigned char *pem_cert_chain, size_t pem_cert_chain_size);
const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pair);
/* Creates a composite credentials object. */
grpc_credentials *grpc_composite_credentials_create(grpc_credentials *creds1,
@ -130,22 +134,16 @@ typedef struct grpc_server_credentials grpc_server_credentials;
void grpc_server_credentials_release(grpc_server_credentials *creds);
/* Creates an SSL server_credentials object.
TODO(jboeuf): Change the constructor so that it can support multiple
key/cert pairs.
- pem_roots_cert is the buffer containing the PEM encoding of the server
root certificates. This parameter may be NULL if the server does not want
the client to be authenticated with SSL.
- pem_roots_cert_size is the size of the associated buffer.
- pem_private_key is the buffer containing the PEM encoding of the client's
private key. This parameter cannot be NULL.
- pem_private_key_size is the size of the associated buffer.
- pem_cert_chain is the buffer containing the PEM encoding of the client's
certificate chain. This parameter cannot be NULL.
- pem_cert_chain_size is the size of the associated buffer. */
- pem_roots_cert is the NULL-terminated string containing the PEM encoding of
the client root certificates. This parameter may be NULL if the server does
not want the client to be authenticated with SSL.
- pem_key_cert_pairs is an array private key / certificate chains of the
server. This parameter cannot be NULL.
- num_key_cert_pairs indicates the number of items in the private_key_files
and cert_chain_files parameters. It should be at least 1. */
grpc_server_credentials *grpc_ssl_server_credentials_create(
const unsigned char *pem_root_certs, size_t pem_root_certs_size,
const unsigned char *pem_private_key, size_t pem_private_key_size,
const unsigned char *pem_cert_chain, size_t pem_cert_chain_size);
const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pairs,
size_t num_key_cert_pairs);
/* Creates a fake server transport security credentials object for testing. */
grpc_server_credentials *grpc_fake_transport_security_server_credentials_create(

@ -132,6 +132,14 @@
#error Must define exactly one of GPR_CPU_LINUX, GPR_CPU_POSIX, GPR_WIN32
#endif
#if defined(GPR_POSIX_MULTIPOLL_WITH_POLL) && !defined(GPR_POSIX_SOCKET)
#error Must define GPR_POSIX_SOCKET to use GPR_POSIX_MULTIPOLL_WITH_POLL
#endif
#if defined(GPR_POSIX_SOCKET) + defined(GPR_WIN32) != 1
#error Must define exactly one of GPR_POSIX_POLLSET, GPR_WIN32
#endif
typedef int16_t gpr_int16;
typedef int32_t gpr_int32;
typedef int64_t gpr_int64;

@ -31,6 +31,10 @@
*
*/
#include <grpc/support/port_platform.h>
#ifdef GPR_POSIX_SOCKET
#include "src/core/iomgr/endpoint_pair.h"
#include <errno.h>
@ -59,3 +63,5 @@ grpc_endpoint_pair grpc_iomgr_create_endpoint_pair(size_t read_slice_size) {
p.server = grpc_tcp_create(grpc_fd_create(sv[0]), read_slice_size);
return p;
}
#endif

@ -31,6 +31,10 @@
*
*/
#include <grpc/support/port_platform.h>
#ifdef GPR_POSIX_SOCKET
#include "src/core/iomgr/fd_posix.h"
#include <assert.h>
@ -272,3 +276,5 @@ void grpc_fd_become_readable(grpc_fd *fd, int allow_synchronous_callback) {
void grpc_fd_become_writable(grpc_fd *fd, int allow_synchronous_callback) {
set_ready(fd, &fd->writest, allow_synchronous_callback);
}
#endif

@ -48,6 +48,10 @@
#include "src/core/iomgr/pollset_posix.h"
#endif
#ifdef GPR_WIN32
#include "src/core/iomgr/pollset_windows.h"
#endif
void grpc_pollset_init(grpc_pollset *pollset);
void grpc_pollset_destroy(grpc_pollset *pollset);

@ -41,8 +41,10 @@
#ifdef GPR_POSIX_SOCKET
#include "src/core/iomgr/pollset_kick_posix.h"
#else
#error "No pollset kick support on platform"
#endif
#ifdef GPR_WIN32
#include "src/core/iomgr/pollset_kick_windows.h"
#endif
void grpc_pollset_kick_global_init(void);

@ -31,6 +31,10 @@
*
*/
#include <grpc/support/port_platform.h>
#ifdef GPR_POSIX_SOCKET
#include "src/core/iomgr/pollset_kick_posix.h"
#include <errno.h>
@ -175,3 +179,5 @@ void grpc_pollset_kick_kick(grpc_pollset_kick_state *kick_state) {
}
gpr_mu_unlock(&kick_state->mu);
}
#endif

@ -0,0 +1,45 @@
/*
*
* Copyright 2015, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef __GRPC_INTERNAL_IOMGR_POLLSET_KICK_WINDOWS_H_
#define __GRPC_INTERNAL_IOMGR_POLLSET_KICK_WINDOWS_H_
#include <grpc/support/sync.h>
struct grpc_kick_pipe_info;
typedef struct grpc_pollset_kick_state {
int unused;
} grpc_pollset_kick_state;
#endif /* __GRPC_INTERNAL_IOMGR_POLLSET_KICK_WINDOWS_H_ */

@ -31,6 +31,10 @@
*
*/
#include <grpc/support/port_platform.h>
#ifdef GPR_POSIX_SOCKET
#include "src/core/iomgr/pollset_posix.h"
#include <errno.h>
@ -288,3 +292,5 @@ static void become_unary_pollset(grpc_pollset *pollset, grpc_fd *fd) {
pollset->data.ptr = fd;
grpc_fd_ref(fd);
}
#endif /* GPR_POSIX_POLLSET */

@ -0,0 +1,38 @@
/*
*
* Copyright 2014, Google Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <grpc/support/port_platform.h>
#ifdef GPR_WIN32
#endif /* GPR_WIN32 */

@ -0,0 +1,54 @@
/*
*
* 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 __GRPC_INTERNAL_IOMGR_POLLSET_WINDOWS_H_
#define __GRPC_INTERNAL_IOMGR_POLLSET_WINDOWS_H_
#include <grpc/support/sync.h>
#include "src/core/iomgr/pollset_kick.h"
/* forward declare only in this file to avoid leaking impl details via
pollset.h; real users of grpc_fd should always include 'fd_posix.h' and not
use the struct tag */
struct grpc_fd;
typedef struct grpc_pollset {
gpr_mu mu;
gpr_cv cv;
} grpc_pollset;
#define GRPC_POLLSET_MU(pollset) (&(pollset)->mu)
#define GRPC_POLLSET_CV(pollset) (&(pollset)->cv)
#endif /* __GRPC_INTERNAL_IOMGR_POLLSET_WINDOWS_H_ */

@ -34,10 +34,12 @@
#ifndef __GRPC_INTERNAL_IOMGR_RESOLVE_ADDRESS_H__
#define __GRPC_INTERNAL_IOMGR_RESOLVE_ADDRESS_H__
#include <sys/socket.h>
#include <stddef.h>
#define GRPC_MAX_SOCKADDR_SIZE 128
typedef struct {
struct sockaddr_storage addr;
char addr[GRPC_MAX_SOCKADDR_SIZE];
int len;
} grpc_resolved_address;

@ -31,6 +31,10 @@
*
*/
#include <grpc/support/port_platform.h>
#ifdef GPR_POSIX_SOCKET
#include "src/core/iomgr/socket_utils_posix.h"
#include <arpa/inet.h>
@ -99,7 +103,7 @@ int grpc_set_socket_reuse_addr(int fd, int reuse) {
socklen_t intlen = sizeof(newval);
return 0 == setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) &&
0 == getsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &newval, &intlen) &&
newval == val;
(newval != 0) == val;
}
/* disable nagle */
@ -109,7 +113,7 @@ int grpc_set_socket_low_latency(int fd, int low_latency) {
socklen_t intlen = sizeof(newval);
return 0 == setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)) &&
0 == getsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &newval, &intlen) &&
newval == val;
(newval != 0) == val;
}
static gpr_once g_probe_ipv6_once = GPR_ONCE_INIT;
@ -187,3 +191,5 @@ int grpc_create_dualstack_socket(const struct sockaddr *addr, int type,
*dsmode = family == AF_INET ? GRPC_DSMODE_IPV4 : GRPC_DSMODE_NONE;
return socket(family, type, protocol);
}
#endif

@ -50,12 +50,22 @@ int grpc_accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen,
fd = accept(sockfd, addr, addrlen);
if (fd >= 0) {
flags = fcntl(fd, F_GETFL, 0);
flags |= nonblock ? O_NONBLOCK : 0;
flags |= cloexec ? FD_CLOEXEC : 0;
GPR_ASSERT(fcntl(fd, F_SETFL, flags) == 0);
if (nonblock) {
flags = fcntl(fd, F_GETFL, 0);
if (flags < 0) goto close_and_error;
if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) != 0) goto close_and_error;
}
if (cloexec) {
flags = fcntl(fd, F_GETFD, 0);
if (flags < 0) goto close_and_error;
if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) != 0) goto close_and_error;
}
}
return fd;
close_and_error:
close(fd);
return -1;
}
#endif /* GPR_POSIX_SOCKETUTILS */

@ -31,6 +31,10 @@
*
*/
#include <grpc/support/port_platform.h>
#ifdef GPR_POSIX_SOCKET
#include "src/core/iomgr/tcp_client.h"
#include <errno.h>
@ -229,3 +233,5 @@ void grpc_tcp_client_connect(void (*cb)(void *arg, grpc_endpoint *ep),
grpc_alarm_init(&ac->alarm, deadline, on_alarm, ac, gpr_now());
grpc_fd_notify_on_write(ac->fd, on_writable, ac);
}
#endif

@ -31,6 +31,10 @@
*
*/
#include <grpc/support/port_platform.h>
#ifdef GPR_POSIX_SOCKET
#include "src/core/iomgr/tcp_posix.h"
#include <errno.h>
@ -539,3 +543,5 @@ grpc_endpoint *grpc_tcp_create(grpc_fd *em_fd, size_t slice_size) {
tcp->em_fd = em_fd;
return &tcp->base;
}
#endif

@ -34,9 +34,6 @@
#ifndef __GRPC_INTERNAL_IOMGR_TCP_SERVER_H__
#define __GRPC_INTERNAL_IOMGR_TCP_SERVER_H__
#include <sys/types.h>
#include <sys/socket.h>
#include "src/core/iomgr/endpoint.h"
/* Forward decl of grpc_tcp_server */
@ -63,7 +60,7 @@ void grpc_tcp_server_start(grpc_tcp_server *server, grpc_pollset *pollset,
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 grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr,
int addr_len);
/* Returns the file descriptor of the Nth listening socket on this server,

@ -31,6 +31,10 @@
*
*/
#include <grpc/support/port_platform.h>
#ifdef GPR_POSIX_SOCKET
#define _GNU_SOURCE
#include "src/core/iomgr/tcp_server.h"
@ -252,7 +256,7 @@ static int add_socket_to_server(grpc_tcp_server *s, int fd,
if (s->nports == s->port_capacity) {
s->port_capacity *= 2;
s->ports =
gpr_realloc(s->ports, sizeof(server_port *) * s->port_capacity);
gpr_realloc(s->ports, sizeof(server_port) * s->port_capacity);
}
sp = &s->ports[s->nports++];
sp->server = s;
@ -265,7 +269,7 @@ static int add_socket_to_server(grpc_tcp_server *s, int fd,
return port;
}
int grpc_tcp_server_add_port(grpc_tcp_server *s, const struct sockaddr *addr,
int grpc_tcp_server_add_port(grpc_tcp_server *s, const void *addr,
int addr_len) {
int allocated_port1 = -1;
int allocated_port2 = -1;
@ -364,3 +368,5 @@ void grpc_tcp_server_start(grpc_tcp_server *s, grpc_pollset *pollset,
}
gpr_mu_unlock(&s->mu);
}
#endif

@ -139,7 +139,7 @@ typedef struct {
typedef struct {
grpc_server_credentials base;
grpc_ssl_config config;
grpc_ssl_server_config config;
} grpc_ssl_server_credentials;
static void ssl_destroy(grpc_credentials *creds) {
@ -152,9 +152,24 @@ static void ssl_destroy(grpc_credentials *creds) {
static void ssl_server_destroy(grpc_server_credentials *creds) {
grpc_ssl_server_credentials *c = (grpc_ssl_server_credentials *)creds;
size_t i;
for (i = 0; i < c->config.num_key_cert_pairs; i++) {
if (c->config.pem_private_keys[i] != NULL) {
gpr_free(c->config.pem_private_keys[i]);
}
if (c->config.pem_cert_chains[i]!= NULL) {
gpr_free(c->config.pem_cert_chains[i]);
}
}
if (c->config.pem_private_keys != NULL) gpr_free(c->config.pem_private_keys);
if (c->config.pem_private_keys_sizes != NULL) {
gpr_free(c->config.pem_private_keys_sizes);
}
if (c->config.pem_cert_chains != NULL) gpr_free(c->config.pem_cert_chains);
if (c->config.pem_cert_chains_sizes != NULL) {
gpr_free(c->config.pem_cert_chains_sizes);
}
if (c->config.pem_root_certs != NULL) gpr_free(c->config.pem_root_certs);
if (c->config.pem_private_key != NULL) gpr_free(c->config.pem_private_key);
if (c->config.pem_cert_chain != NULL) gpr_free(c->config.pem_cert_chain);
gpr_free(creds);
}
@ -179,7 +194,7 @@ const grpc_ssl_config *grpc_ssl_credentials_get_config(
}
}
const grpc_ssl_config *grpc_ssl_server_credentials_get_config(
const grpc_ssl_server_config *grpc_ssl_server_credentials_get_config(
const grpc_server_credentials *creds) {
if (creds == NULL || strcmp(creds->type, GRPC_CREDENTIALS_TYPE_SSL)) {
return NULL;
@ -189,57 +204,89 @@ const grpc_ssl_config *grpc_ssl_server_credentials_get_config(
}
}
static void ssl_build_config(const unsigned char *pem_root_certs,
size_t pem_root_certs_size,
const unsigned char *pem_private_key,
size_t pem_private_key_size,
const unsigned char *pem_cert_chain,
size_t pem_cert_chain_size,
static void ssl_copy_key_material(const char *input, unsigned char **output,
size_t *output_size) {
*output_size = strlen(input);
*output = gpr_malloc(*output_size);
memcpy(*output, input, *output_size);
}
static void ssl_build_config(const char *pem_root_certs,
grpc_ssl_pem_key_cert_pair *pem_key_cert_pair,
grpc_ssl_config *config) {
if (pem_root_certs == NULL) {
/* TODO(jboeuf): Get them from the environment. */
gpr_log(GPR_ERROR, "Default SSL roots not yet implemented.");
} else {
ssl_copy_key_material(pem_root_certs, &config->pem_root_certs,
&config->pem_root_certs_size);
}
if (pem_key_cert_pair != NULL) {
GPR_ASSERT(pem_key_cert_pair->private_key != NULL);
GPR_ASSERT(pem_key_cert_pair->cert_chain != NULL);
ssl_copy_key_material(pem_key_cert_pair->private_key,
&config->pem_private_key,
&config->pem_private_key_size);
ssl_copy_key_material(pem_key_cert_pair->cert_chain,
&config->pem_cert_chain,
&config->pem_cert_chain_size);
}
}
static void ssl_build_server_config(
const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pairs,
size_t num_key_cert_pairs, grpc_ssl_server_config *config) {
size_t i;
if (pem_root_certs != NULL) {
config->pem_root_certs = gpr_malloc(pem_root_certs_size);
memcpy(config->pem_root_certs, pem_root_certs, pem_root_certs_size);
config->pem_root_certs_size = pem_root_certs_size;
ssl_copy_key_material(pem_root_certs, &config->pem_root_certs,
&config->pem_root_certs_size);
}
if (pem_private_key != NULL) {
config->pem_private_key = gpr_malloc(pem_private_key_size);
memcpy(config->pem_private_key, pem_private_key, pem_private_key_size);
config->pem_private_key_size = pem_private_key_size;
if (num_key_cert_pairs > 0) {
GPR_ASSERT(pem_key_cert_pairs != NULL);
config->pem_private_keys =
gpr_malloc(num_key_cert_pairs * sizeof(unsigned char *));
config->pem_cert_chains =
gpr_malloc(num_key_cert_pairs * sizeof(unsigned char *));
config->pem_private_keys_sizes =
gpr_malloc(num_key_cert_pairs * sizeof(size_t));
config->pem_cert_chains_sizes =
gpr_malloc(num_key_cert_pairs * sizeof(size_t));
}
if (pem_cert_chain != NULL) {
config->pem_cert_chain = gpr_malloc(pem_cert_chain_size);
memcpy(config->pem_cert_chain, pem_cert_chain, pem_cert_chain_size);
config->pem_cert_chain_size = pem_cert_chain_size;
config->num_key_cert_pairs = num_key_cert_pairs;
for (i = 0; i < num_key_cert_pairs; i++) {
GPR_ASSERT(pem_key_cert_pairs[i].private_key != NULL);
GPR_ASSERT(pem_key_cert_pairs[i].cert_chain != NULL);
ssl_copy_key_material(pem_key_cert_pairs[i].private_key,
&config->pem_private_keys[i],
&config->pem_private_keys_sizes[i]);
ssl_copy_key_material(pem_key_cert_pairs[i].cert_chain,
&config->pem_cert_chains[i],
&config->pem_cert_chains_sizes[i]);
}
}
grpc_credentials *grpc_ssl_credentials_create(
const unsigned char *pem_root_certs, size_t pem_root_certs_size,
const unsigned char *pem_private_key, size_t pem_private_key_size,
const unsigned char *pem_cert_chain, size_t pem_cert_chain_size) {
const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pair) {
grpc_ssl_credentials *c = gpr_malloc(sizeof(grpc_ssl_credentials));
memset(c, 0, sizeof(grpc_ssl_credentials));
c->base.type = GRPC_CREDENTIALS_TYPE_SSL;
c->base.vtable = &ssl_vtable;
gpr_ref_init(&c->base.refcount, 1);
ssl_build_config(pem_root_certs, pem_root_certs_size, pem_private_key,
pem_private_key_size, pem_cert_chain, pem_cert_chain_size,
&c->config);
ssl_build_config(pem_root_certs, pem_key_cert_pair, &c->config);
return &c->base;
}
grpc_server_credentials *grpc_ssl_server_credentials_create(
const unsigned char *pem_root_certs, size_t pem_root_certs_size,
const unsigned char *pem_private_key, size_t pem_private_key_size,
const unsigned char *pem_cert_chain, size_t pem_cert_chain_size) {
const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pairs,
size_t num_key_cert_pairs) {
grpc_ssl_server_credentials *c =
gpr_malloc(sizeof(grpc_ssl_server_credentials));
memset(c, 0, sizeof(grpc_ssl_server_credentials));
c->base.type = GRPC_CREDENTIALS_TYPE_SSL;
c->base.vtable = &ssl_server_vtable;
ssl_build_config(pem_root_certs, pem_root_certs_size, pem_private_key,
pem_private_key_size, pem_cert_chain, pem_cert_chain_size,
&c->config);
ssl_build_server_config(pem_root_certs, pem_key_cert_pairs,
num_key_cert_pairs, &c->config);
return &c->base;
}

@ -137,10 +137,17 @@ struct grpc_server_credentials {
const char *type;
};
/* TODO(jboeuf): Have an ssl_server_config that can contain multiple key/cert
pairs. */
typedef struct {
unsigned char **pem_private_keys;
size_t *pem_private_keys_sizes;
unsigned char **pem_cert_chains;
size_t *pem_cert_chains_sizes;
size_t num_key_cert_pairs;
unsigned char *pem_root_certs;
size_t pem_root_certs_size;
} grpc_ssl_server_config;
const grpc_ssl_config *grpc_ssl_server_credentials_get_config(
const grpc_ssl_server_config *grpc_ssl_server_credentials_get_config(
const grpc_server_credentials *ssl_creds);
#endif /* __GRPC_INTERNAL_SECURITY_CREDENTIALS_H__ */

@ -382,7 +382,7 @@ error:
}
grpc_security_status grpc_ssl_server_security_context_create(
const grpc_ssl_config *config, grpc_security_context **ctx) {
const grpc_ssl_server_config *config, grpc_security_context **ctx) {
size_t num_alpn_protocols = grpc_chttp2_num_alpn_versions();
const unsigned char **alpn_protocol_strings =
gpr_malloc(sizeof(const char *) * num_alpn_protocols);
@ -399,8 +399,7 @@ grpc_security_status grpc_ssl_server_security_context_create(
strlen(grpc_chttp2_get_alpn_version_index(i));
}
if (config == NULL || config->pem_private_key == NULL ||
config->pem_cert_chain == NULL) {
if (config == NULL || config->num_key_cert_pairs == 0) {
gpr_log(GPR_ERROR, "An SSL server needs a key and a cert.");
goto error;
}
@ -410,13 +409,13 @@ grpc_security_status grpc_ssl_server_security_context_create(
gpr_ref_init(&c->base.refcount, 1);
c->base.vtable = &ssl_server_vtable;
result = tsi_create_ssl_server_handshaker_factory(
(const unsigned char **)&config->pem_private_key,
&config->pem_private_key_size,
(const unsigned char **)&config->pem_cert_chain,
&config->pem_cert_chain_size, 1, config->pem_root_certs,
config->pem_root_certs_size, GRPC_SSL_CIPHER_SUITES,
alpn_protocol_strings, alpn_protocol_string_lengths, num_alpn_protocols,
&c->handshaker_factory);
(const unsigned char **)config->pem_private_keys,
config->pem_private_keys_sizes,
(const unsigned char **)config->pem_cert_chains,
config->pem_cert_chains_sizes, config->num_key_cert_pairs,
config->pem_root_certs, config->pem_root_certs_size,
GRPC_SSL_CIPHER_SUITES, alpn_protocol_strings,
alpn_protocol_string_lengths, num_alpn_protocols, &c->handshaker_factory);
if (result != TSI_OK) {
gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.",
tsi_result_to_string(result));

@ -157,7 +157,7 @@ grpc_security_status grpc_ssl_channel_security_context_create(
specific error code otherwise.
*/
grpc_security_status grpc_ssl_server_security_context_create(
const grpc_ssl_config *config, grpc_security_context **ctx);
const grpc_ssl_server_config *config, grpc_security_context **ctx);
/* --- Creation of high level objects. --- */

@ -93,6 +93,8 @@ int grpc_server_add_secure_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, "https");
if (!resolved) {
@ -105,9 +107,15 @@ int grpc_server_add_secure_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++;
}
}
@ -125,7 +133,7 @@ int grpc_server_add_secure_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:

@ -61,7 +61,7 @@ gpr_timespec gpr_now(void) {
struct timeval now_tv;
gettimeofday(&now_tv, NULL);
now.tv_sec = now_tv.tv_sec;
now.tv_nsec = now_tv.tv_usec / 1000;
now.tv_nsec = now_tv.tv_usec * 1000;
return now;
}
#endif

@ -141,7 +141,7 @@ grpc_chttp2_parse_error grpc_chttp2_data_parser_parse(
gpr_slice_sub(slice, cur - beg, end - beg));
p->state = GRPC_CHTTP2_DATA_FH_0;
return GRPC_CHTTP2_PARSE_OK;
} else if (end - cur > p->frame_size) {
} else if ((gpr_uint32)(end - cur) > p->frame_size) {
state->need_flush_reads = 1;
grpc_sopb_add_slice(
&p->incoming_sopb,

@ -1212,7 +1212,7 @@ static int huff_nibble(grpc_chttp2_hpack_parser *p, gpr_uint8 nibble) {
gpr_int16 next = next_sub_tbl[16 * next_tbl[p->huff_state] + nibble];
if (emit != -1) {
if (emit >= 0 && emit < 256) {
gpr_uint8 c = emit;
gpr_uint8 c = (gpr_uint8) emit;
if (!append_string(p, &c, (&c) + 1)) return 0;
} else {
assert(emit == 256);

@ -1611,7 +1611,7 @@ static int process_read(transport *t, gpr_slice slice) {
}
t->deframe_state = DTS_FH_0;
return 1;
} else if (end - cur > t->incoming_frame_size) {
} else if ((gpr_uint32)(end - cur) > t->incoming_frame_size) {
if (!parse_frame_slice(
t, gpr_slice_sub_no_ref(slice, cur - beg,
cur + t->incoming_frame_size - beg),

@ -63,7 +63,7 @@ void grpc_sopb_reset(grpc_stream_op_buffer *sopb) {
}
void grpc_stream_ops_unref_owned_objects(grpc_stream_op *ops, size_t nops) {
int i;
size_t i;
for (i = 0; i < nops; i++) {
switch (ops[i].type) {
case GRPC_OP_SLICE:

@ -54,26 +54,12 @@ std::unique_ptr<Credentials> CredentialsFactory::DefaultCredentials() {
// Builds SSL Credentials given SSL specific options
std::unique_ptr<Credentials> CredentialsFactory::SslCredentials(
const SslCredentialsOptions &options) {
const unsigned char *pem_root_certs =
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 *>(
options.pem_private_key.c_str());
const unsigned char *pem_cert_chain =
options.pem_cert_chain.empty() ? nullptr
: reinterpret_cast<const unsigned char *>(
options.pem_cert_chain.c_str());
grpc_ssl_pem_key_cert_pair pem_key_cert_pair = {
options.pem_private_key.c_str(), options.pem_cert_chain.c_str()};
grpc_credentials *c_creds = grpc_ssl_credentials_create(
pem_root_certs, options.pem_root_certs.size(), pem_private_key,
options.pem_private_key.size(), pem_cert_chain,
options.pem_cert_chain.size());
options.pem_root_certs.empty() ? nullptr : options.pem_root_certs.c_str(),
options.pem_private_key.empty() ? nullptr : &pem_key_cert_pair);
std::unique_ptr<Credentials> cpp_creds(
c_creds == nullptr ? nullptr : new Credentials(c_creds));
return cpp_creds;

@ -48,23 +48,14 @@ grpc_server_credentials *ServerCredentials::GetRawCreds() { return creds_; }
std::shared_ptr<ServerCredentials> ServerCredentialsFactory::SslCredentials(
const SslServerCredentialsOptions &options) {
const unsigned char *pem_root_certs =
options.pem_root_certs.empty() ? nullptr
: reinterpret_cast<const unsigned char *>(
options.pem_root_certs.c_str());
const unsigned char *pem_private_key =
options.pem_private_key.empty() ? nullptr
: reinterpret_cast<const unsigned char *>(
options.pem_private_key.c_str());
const unsigned char *pem_cert_chain =
options.pem_cert_chain.empty() ? nullptr
: reinterpret_cast<const unsigned char *>(
options.pem_cert_chain.c_str());
std::vector<grpc_ssl_pem_key_cert_pair> pem_key_cert_pairs;
for (const auto &key_cert_pair : options.pem_key_cert_pairs) {
pem_key_cert_pairs.push_back(
{key_cert_pair.private_key.c_str(), key_cert_pair.cert_chain.c_str()});
}
grpc_server_credentials *c_creds = grpc_ssl_server_credentials_create(
pem_root_certs, options.pem_root_certs.size(), pem_private_key,
options.pem_private_key.size(), pem_cert_chain,
options.pem_cert_chain.size());
options.pem_root_certs.empty() ? nullptr : options.pem_root_certs.c_str(),
&pem_key_cert_pairs[0], pem_key_cert_pairs.size());
return std::shared_ptr<ServerCredentials>(new ServerCredentials(c_creds));
}

@ -19,9 +19,6 @@
'link_settings': {
'libraries': [
'-lgrpc',
'-levent',
'-levent_pthreads',
'-levent_core',
'-lrt',
'-lgpr',
'-lpthread'

@ -45,10 +45,22 @@ util.inherits(GrpcClientStream, Duplex);
* from stream.Duplex.
* @constructor
* @param {grpc.Call} call Call object to proxy
* @param {object} options Stream options
* @param {function(*):Buffer=} serialize Serialization function for requests
* @param {function(Buffer):*=} deserialize Deserialization function for
* responses
*/
function GrpcClientStream(call, options) {
Duplex.call(this, options);
function GrpcClientStream(call, serialize, deserialize) {
Duplex.call(this, {objectMode: true});
if (!serialize) {
serialize = function(value) {
return value;
};
}
if (!deserialize) {
deserialize = function(value) {
return value;
};
}
var self = this;
// Indicates that we can start reading and have not received a null read
var can_read = false;
@ -59,6 +71,32 @@ function GrpcClientStream(call, options) {
// Indicates that a write is currently pending
var writing = false;
this._call = call;
/**
* Serialize a request value to a buffer. Always maps null to null. Otherwise
* uses the provided serialize function
* @param {*} value The value to serialize
* @return {Buffer} The serialized value
*/
this.serialize = function(value) {
if (value === null || value === undefined) {
return null;
}
return serialize(value);
};
/**
* Deserialize a response buffer to a value. Always maps null to null.
* Otherwise uses the provided deserialize function.
* @param {Buffer} buffer The buffer to deserialize
* @return {*} The deserialized value
*/
this.deserialize = function(buffer) {
if (buffer === null) {
return null;
}
return deserialize(buffer);
};
/**
* Callback to handle receiving a READ event. Pushes the data from that event
* onto the read queue and starts reading again if applicable.
@ -66,7 +104,7 @@ function GrpcClientStream(call, options) {
*/
function readCallback(event) {
var data = event.data;
if (self.push(data)) {
if (self.push(self.deserialize(data))) {
if (data == null) {
// Disable starting to read after null read was received
can_read = false;
@ -102,7 +140,7 @@ function GrpcClientStream(call, options) {
next.callback();
writeNext();
};
call.startWrite(next.chunk, writeCallback, 0);
call.startWrite(self.serialize(next.chunk), writeCallback, 0);
} else {
writing = false;
}
@ -171,6 +209,9 @@ GrpcClientStream.prototype._write = function(chunk, encoding, 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 {function(*):Buffer} serialize Serialization function for requests
* @param {function(Buffer):*} deserialize Deserialization function for
* responses
* @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.
@ -178,6 +219,8 @@ GrpcClientStream.prototype._write = function(chunk, encoding, callback) {
*/
function makeRequest(channel,
method,
serialize,
deserialize,
metadata,
deadline) {
if (deadline === undefined) {

@ -31,6 +31,8 @@
*
*/
var capitalize = require('underscore.string/capitalize');
/**
* Get a function that deserializes a specific type of protobuf.
* @param {function()} cls The constructor of the message type to deserialize
@ -73,6 +75,9 @@ function fullyQualifiedName(value) {
return '';
}
var name = value.name;
if (value.className === 'Service.RPCMethod') {
name = capitalize(name);
}
if (value.hasOwnProperty('parent')) {
var parent_name = fullyQualifiedName(value.parent);
if (parent_name !== '') {

@ -136,33 +136,29 @@ NAN_METHOD(Credentials::CreateDefault) {
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])) {
char *root_certs = NULL;
grpc_ssl_pem_key_cert_pair key_cert_pair = {NULL, NULL};
if (Buffer::HasInstance(args[0])) {
root_certs = Buffer::Data(args[0]);
} else if (!(args[0]->IsNull() || args[0]->IsUndefined())) {
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]);
key_cert_pair.private_key = Buffer::Data(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]);
key_cert_pair.cert_chain = Buffer::Data(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)));
root_certs,
key_cert_pair.private_key == NULL ? NULL : &key_cert_pair)));
}
NAN_METHOD(Credentials::CreateComposite) {

@ -119,10 +119,10 @@ function mathDivMany(stream) {
var server = new Server({
'math.Math' : {
Div: mathDiv,
Fib: mathFib,
Sum: mathSum,
DivMany: mathDivMany
div: mathDiv,
fib: mathFib,
sum: mathSum,
divMany: mathDivMany
}
});

@ -0,0 +1,19 @@
syntax = "proto2";
package grpc.testing;
// An empty message that you can re-use to avoid defining duplicated empty
// messages in your project. A typical example is to use it as argument or the
// return value of a service API. For instance:
//
// service Foo {
// rpc Bar (grpc.testing.Empty) returns (grpc.testing.Empty) { };
// };
//
// MOE:begin_strip
// The difference between this one and net/rpc/empty-message.proto is that
// 1) The generated message here is in proto2 C++ API.
// 2) The proto2.Empty has minimum dependencies
// (no message_set or net/rpc dependencies)
// MOE:end_strip
message Empty {}

@ -0,0 +1,274 @@
/*
*
* 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 fs = require('fs');
var path = require('path');
var grpc = require('..');
var testProto = grpc.load(__dirname + '/test.proto').grpc.testing;
var assert = require('assert');
/**
* Create a buffer filled with size zeroes
* @param {number} size The length of the buffer
* @return {Buffer} The new buffer
*/
function zeroBuffer(size) {
var zeros = new Buffer(size);
zeros.fill(0);
return zeros;
}
/**
* Run the empty_unary test
* @param {Client} client The client to test against
* @param {function} done Callback to call when the test is completed. Included
* primarily for use with mocha
*/
function emptyUnary(client, done) {
var call = client.emptyCall({}, function(err, resp) {
assert.ifError(err);
});
call.on('status', function(status) {
assert.strictEqual(status.code, grpc.status.OK);
if (done) {
done();
}
});
}
/**
* Run the large_unary test
* @param {Client} client The client to test against
* @param {function} done Callback to call when the test is completed. Included
* primarily for use with mocha
*/
function largeUnary(client, done) {
var arg = {
response_type: testProto.PayloadType.COMPRESSABLE,
response_size: 314159,
payload: {
body: zeroBuffer(271828)
}
};
var call = client.unaryCall(arg, function(err, resp) {
assert.ifError(err);
assert.strictEqual(resp.payload.type, testProto.PayloadType.COMPRESSABLE);
assert.strictEqual(resp.payload.body.limit - resp.payload.body.offset,
314159);
});
call.on('status', function(status) {
assert.strictEqual(status.code, grpc.status.OK);
if (done) {
done();
}
});
}
/**
* Run the client_streaming test
* @param {Client} client The client to test against
* @param {function} done Callback to call when the test is completed. Included
* primarily for use with mocha
*/
function clientStreaming(client, done) {
var call = client.streamingInputCall(function(err, resp) {
assert.ifError(err);
assert.strictEqual(resp.aggregated_payload_size, 74922);
});
call.on('status', function(status) {
assert.strictEqual(status.code, grpc.status.OK);
if (done) {
done();
}
});
var payload_sizes = [27182, 8, 1828, 45904];
for (var i = 0; i < payload_sizes.length; i++) {
call.write({payload: {body: zeroBuffer(payload_sizes[i])}});
}
call.end();
}
/**
* Run the server_streaming test
* @param {Client} client The client to test against
* @param {function} done Callback to call when the test is completed. Included
* primarily for use with mocha
*/
function serverStreaming(client, done) {
var arg = {
response_type: testProto.PayloadType.COMPRESSABLE,
response_parameters: [
{size: 31415},
{size: 9},
{size: 2653},
{size: 58979}
]
};
var call = client.streamingOutputCall(arg);
var resp_index = 0;
call.on('data', function(value) {
assert(resp_index < 4);
assert.strictEqual(value.payload.type, testProto.PayloadType.COMPRESSABLE);
assert.strictEqual(value.payload.body.limit - value.payload.body.offset,
arg.response_parameters[resp_index].size);
resp_index += 1;
});
call.on('status', function(status) {
assert.strictEqual(resp_index, 4);
assert.strictEqual(status.code, grpc.status.OK);
if (done) {
done();
}
});
}
/**
* Run the ping_pong test
* @param {Client} client The client to test against
* @param {function} done Callback to call when the test is completed. Included
* primarily for use with mocha
*/
function pingPong(client, done) {
var payload_sizes = [27182, 8, 1828, 45904];
var response_sizes = [31415, 9, 2653, 58979];
var call = client.fullDuplexCall();
call.on('status', function(status) {
assert.strictEqual(status.code, grpc.status.OK);
if (done) {
done();
}
});
var index = 0;
call.write({
response_type: testProto.PayloadType.COMPRESSABLE,
response_parameters: [
{size: response_sizes[index]}
],
payload: {body: zeroBuffer(payload_sizes[index])}
});
call.on('data', function(response) {
assert.strictEqual(response.payload.type,
testProto.PayloadType.COMPRESSABLE);
assert.equal(response.payload.body.limit - response.payload.body.offset,
response_sizes[index]);
index += 1;
if (index == 4) {
call.end();
} else {
call.write({
response_type: testProto.PayloadType.COMPRESSABLE,
response_parameters: [
{size: response_sizes[index]}
],
payload: {body: zeroBuffer(payload_sizes[index])}
});
}
});
}
/**
* Run the empty_stream test.
* NOTE: This does not work, but should with the new invoke API
* @param {Client} client The client to test against
* @param {function} done Callback to call when the test is completed. Included
* primarily for use with mocha
*/
function emptyStream(client, done) {
var call = client.fullDuplexCall();
call.on('status', function(status) {
assert.strictEqual(status.code, grpc.status.OK);
if (done) {
done();
}
});
call.on('data', function(value) {
assert.fail(value, null, 'No data should have been received', '!==');
});
call.end();
}
/**
* Map from test case names to test functions
*/
var test_cases = {
empty_unary: emptyUnary,
large_unary: largeUnary,
client_streaming: clientStreaming,
server_streaming: serverStreaming,
ping_pong: pingPong,
empty_stream: emptyStream
};
/**
* Execute a single test case.
* @param {string} address The address of the server to connect to, in the
* format "hostname:port"
* @param {string} host_overrirde The hostname of the server to use as an SSL
* override
* @param {string} test_case The name of the test case to run
* @param {bool} tls Indicates that a secure channel should be used
* @param {function} done Callback to call when the test is completed. Included
* primarily for use with mocha
*/
function runTest(address, host_override, test_case, tls, done) {
// TODO(mlumish): enable TLS functionality
var options = {};
if (tls) {
var ca_path = path.join(__dirname, '../test/data/ca.pem');
var ca_data = fs.readFileSync(ca_path);
var creds = grpc.Credentials.createSsl(ca_data);
options.credentials = creds;
if (host_override) {
options['grpc.ssl_target_name_override'] = host_override;
}
}
var client = new testProto.TestService(address, options);
test_cases[test_case](client, done);
}
if (require.main === module) {
var parseArgs = require('minimist');
var argv = parseArgs(process.argv, {
string: ['server_host', 'server_host_override', 'server_port', 'test_case',
'use_tls', 'use_test_ca']
});
runTest(argv.server_host + ':' + argv.server_port, argv.server_host_override,
argv.test_case, argv.use_tls === 'true');
}
/**
* See docs for runTest
*/
exports.runTest = runTest;

@ -0,0 +1,203 @@
/*
*
* 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 fs = require('fs');
var path = require('path');
var _ = require('underscore');
var grpc = require('..');
var testProto = grpc.load(__dirname + '/test.proto').grpc.testing;
var Server = grpc.buildServer([testProto.TestService.service]);
/**
* Create a buffer filled with size zeroes
* @param {number} size The length of the buffer
* @return {Buffer} The new buffer
*/
function zeroBuffer(size) {
var zeros = new Buffer(size);
zeros.fill(0);
return zeros;
}
/**
* Respond to an empty parameter with an empty response.
* NOTE: this currently does not work due to issue #137
* @param {Call} call Call to handle
* @param {function(Error, Object)} callback Callback to call with result
* or error
*/
function handleEmpty(call, callback) {
callback(null, {});
}
/**
* Handle a unary request by sending the requested payload
* @param {Call} call Call to handle
* @param {function(Error, Object)} callback Callback to call with result or
* error
*/
function handleUnary(call, callback) {
var req = call.request;
var zeros = zeroBuffer(req.response_size);
var payload_type = req.response_type;
if (payload_type === testProto.PayloadType.RANDOM) {
payload_type = [
testProto.PayloadType.COMPRESSABLE,
testProto.PayloadType.UNCOMPRESSABLE][Math.random() < 0.5 ? 0 : 1];
}
callback(null, {payload: {type: payload_type, body: zeros}});
}
/**
* Respond to a streaming call with the total size of all payloads
* @param {Call} call Call to handle
* @param {function(Error, Object)} callback Callback to call with result or
* error
*/
function handleStreamingInput(call, callback) {
var aggregate_size = 0;
call.on('data', function(value) {
aggregate_size += value.payload.body.limit - value.payload.body.offset;
});
call.on('end', function() {
callback(null, {aggregated_payload_size: aggregate_size});
});
}
/**
* Respond to a payload request with a stream of the requested payloads
* @param {Call} call Call to handle
*/
function handleStreamingOutput(call) {
var req = call.request;
var payload_type = req.response_type;
if (payload_type === testProto.PayloadType.RANDOM) {
payload_type = [
testProto.PayloadType.COMPRESSABLE,
testProto.PayloadType.UNCOMPRESSABLE][Math.random() < 0.5 ? 0 : 1];
}
_.each(req.response_parameters, function(resp_param) {
call.write({
payload: {
body: zeroBuffer(resp_param.size),
type: payload_type
}
});
});
call.end();
}
/**
* Respond to a stream of payload requests with a stream of payload responses as
* they arrive.
* @param {Call} call Call to handle
*/
function handleFullDuplex(call) {
call.on('data', function(value) {
var payload_type = value.response_type;
if (payload_type === testProto.PayloadType.RANDOM) {
payload_type = [
testProto.PayloadType.COMPRESSABLE,
testProto.PayloadType.UNCOMPRESSABLE][Math.random() < 0.5 ? 0 : 1];
}
_.each(value.response_parameters, function(resp_param) {
call.write({
payload: {
body: zeroBuffer(resp_param.size),
type: payload_type
}
});
});
});
call.on('end', function() {
call.end();
});
}
/**
* Respond to a stream of payload requests with a stream of payload responses
* after all requests have arrived
* @param {Call} call Call to handle
*/
function handleHalfDuplex(call) {
throw new Error('HalfDuplexCall not yet implemented');
}
/**
* Get a server object bound to the given port
* @param {string} port Port to which to bind
* @param {boolean} tls Indicates that the bound port should use TLS
* @return {{server: Server, port: number}} Server object bound to the support,
* and port number that the server is bound to
*/
function getServer(port, tls) {
// TODO(mlumish): enable TLS functionality
var options = {};
if (tls) {
var key_path = path.join(__dirname, '../test/data/server1.key');
var pem_path = path.join(__dirname, '../test/data/server1.pem');
var key_data = fs.readFileSync(key_path);
var pem_data = fs.readFileSync(pem_path);
var server_creds = grpc.ServerCredentials.createSsl(null,
key_data,
pem_data);
options.credentials = server_creds;
}
var server = new Server({
'grpc.testing.TestService' : {
emptyCall: handleEmpty,
unaryCall: handleUnary,
streamingOutputCall: handleStreamingOutput,
streamingInputCall: handleStreamingInput,
fullDuplexCall: handleFullDuplex,
halfDuplexCall: handleHalfDuplex
}
}, options);
var port_num = server.bind('0.0.0.0:' + port, tls);
return {server: server, port: port_num};
}
if (require.main === module) {
var parseArgs = require('minimist');
var argv = parseArgs(process.argv, {
string: ['port', 'use_tls']
});
var server_obj = getServer(argv.port, argv.use_tls === 'true');
server_obj.server.start();
}
/**
* See docs for getServer
*/
exports.getServer = getServer;

@ -0,0 +1,94 @@
// Message definitions to be used by integration test service definitions.
syntax = "proto2";
package grpc.testing;
// The type of payload that should be returned.
enum PayloadType {
// Compressable text format.
COMPRESSABLE = 0;
// Uncompressable binary format.
UNCOMPRESSABLE = 1;
// Randomly chosen from all other formats defined in this enum.
RANDOM = 2;
}
// A block of data, to simply increase gRPC message size.
message Payload {
// The type of data in body.
optional PayloadType type = 1;
// Primary contents of payload.
optional bytes body = 2;
}
// Unary request.
message SimpleRequest {
// Desired payload type in the response from the server.
// If response_type is RANDOM, server randomly chooses one from other formats.
optional PayloadType response_type = 1;
// Desired payload size in the response from the server.
// If response_type is COMPRESSABLE, this denotes the size before compression.
optional int32 response_size = 2;
// Optional input payload sent along with the request.
optional Payload payload = 3;
}
// Unary response, as configured by the request.
message SimpleResponse {
// Payload to increase message size.
optional Payload payload = 1;
// The user the request came from, for verifying authentication was
// successful when the client expected it.
optional int64 effective_gaia_user_id = 2;
}
// Client-streaming request.
message StreamingInputCallRequest {
// Optional input payload sent along with the request.
optional Payload payload = 1;
// Not expecting any payload from the response.
}
// Client-streaming response.
message StreamingInputCallResponse {
// Aggregated size of payloads received from the client.
optional int32 aggregated_payload_size = 1;
}
// Configuration for a particular response.
message ResponseParameters {
// Desired payload sizes in responses from the server.
// If response_type is COMPRESSABLE, this denotes the size before compression.
optional int32 size = 1;
// Desired interval between consecutive responses in the response stream in
// microseconds.
optional int32 interval_us = 2;
}
// Server-streaming request.
message StreamingOutputCallRequest {
// Desired payload type in the response from the server.
// If response_type is RANDOM, the payload from each response in the stream
// might be of different types. This is to simulate a mixed type of payload
// stream.
optional PayloadType response_type = 1;
// Configuration for each expected response message.
repeated ResponseParameters response_parameters = 2;
// Optional input payload sent along with the request.
optional Payload payload = 3;
}
// Server-streaming response, as configured by the request and parameters.
message StreamingOutputCallResponse {
// Payload to increase response size.
optional Payload payload = 1;
}

@ -0,0 +1,42 @@
// An integration test service that covers all the method signature permutations
// of unary/streaming requests/responses.
syntax = "proto2";
import "empty.proto";
import "messages.proto";
package grpc.testing;
// A simple service to test the various types of RPCs and experiment with
// performance with various types of payload.
service TestService {
// One empty request followed by one empty response.
rpc EmptyCall(grpc.testing.Empty) returns (grpc.testing.Empty);
// One request followed by one response.
// The server returns the client payload as-is.
rpc UnaryCall(SimpleRequest) returns (SimpleResponse);
// One request followed by a sequence of responses (streamed download).
// The server returns the payload with client desired type and sizes.
rpc StreamingOutputCall(StreamingOutputCallRequest)
returns (stream StreamingOutputCallResponse);
// A sequence of requests followed by one response (streamed upload).
// The server returns the aggregated size of client payload as the result.
rpc StreamingInputCall(stream StreamingInputCallRequest)
returns (StreamingInputCallResponse);
// A sequence of requests with each request served by the server immediately.
// As one request could lead to multiple responses, this interface
// demonstrates the idea of full duplexing.
rpc FullDuplexCall(stream StreamingOutputCallRequest)
returns (stream StreamingOutputCallResponse);
// A sequence of requests followed by a sequence of responses.
// The server buffers all the client requests and then serves them in order. A
// stream of responses are returned to the client when the server starts with
// first request.
rpc HalfDuplexCall(stream StreamingOutputCallRequest)
returns (stream StreamingOutputCallResponse);
}

@ -55,7 +55,7 @@ function loadObject(value) {
return result;
} else if (value.className === 'Service') {
return surface_client.makeClientConstructor(value);
} else if (value.className === 'Service.Message') {
} else if (value.className === 'Message' || value.className === 'Enum') {
return value.build();
} else {
return value;
@ -96,3 +96,13 @@ exports.status = grpc.status;
* Call error name to code number mapping
*/
exports.callError = grpc.callError;
/**
* Credentials factories
*/
exports.Credentials = grpc.Credentials;
/**
* ServerCredentials factories
*/
exports.ServerCredentials = grpc.ServerCredentials;

@ -8,12 +8,14 @@
"dependencies": {
"bindings": "^1.2.1",
"nan": "~1.3.0",
"protobufjs": "murgatroid99/ProtoBuf.js",
"underscore": "^1.7.0",
"protobufjs": "murgatroid99/ProtoBuf.js"
"underscore.string": "^3.0.0"
},
"devDependencies": {
"highland": "~2.2.0",
"mocha": "~1.21.0",
"highland": "~2.0.0"
"minimist": "^1.1.0"
},
"main": "main.js"
}

@ -194,7 +194,7 @@ NAN_METHOD(Server::AddHttp2Port) {
return NanThrowTypeError("addHttp2Port's argument must be a String");
}
Server *server = ObjectWrap::Unwrap<Server>(args.This());
NanReturnValue(NanNew<Boolean>(grpc_server_add_http2_port(
NanReturnValue(NanNew<Number>(grpc_server_add_http2_port(
server->wrapped_server, *NanUtf8String(args[0]))));
}
@ -208,7 +208,7 @@ NAN_METHOD(Server::AddSecureHttp2Port) {
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(
NanReturnValue(NanNew<Number>(grpc_server_add_secure_http2_port(
server->wrapped_server, *NanUtf8String(args[0]))));
}

@ -47,10 +47,22 @@ util.inherits(GrpcServerStream, Duplex);
* from stream.Duplex.
* @constructor
* @param {grpc.Call} call Call object to proxy
* @param {object} options Stream options
* @param {function(*):Buffer=} serialize Serialization function for responses
* @param {function(Buffer):*=} deserialize Deserialization function for
* requests
*/
function GrpcServerStream(call, options) {
Duplex.call(this, options);
function GrpcServerStream(call, serialize, deserialize) {
Duplex.call(this, {objectMode: true});
if (!serialize) {
serialize = function(value) {
return value;
};
}
if (!deserialize) {
deserialize = function(value) {
return value;
};
}
this._call = call;
// Indicate that a status has been sent
var finished = false;
@ -59,6 +71,33 @@ function GrpcServerStream(call, options) {
'code' : grpc.status.OK,
'details' : 'OK'
};
/**
* Serialize a response value to a buffer. Always maps null to null. Otherwise
* uses the provided serialize function
* @param {*} value The value to serialize
* @return {Buffer} The serialized value
*/
this.serialize = function(value) {
if (value === null || value === undefined) {
return null;
}
return serialize(value);
};
/**
* Deserialize a request buffer to a value. Always maps null to null.
* Otherwise uses the provided deserialize function.
* @param {Buffer} buffer The buffer to deserialize
* @return {*} The deserialized value
*/
this.deserialize = function(buffer) {
if (buffer === null) {
return null;
}
return deserialize(buffer);
};
/**
* Send the pending status
*/
@ -75,7 +114,6 @@ function GrpcServerStream(call, options) {
* @param {Error} err The error object
*/
function setStatus(err) {
console.log('Server setting status to', err);
var code = grpc.status.INTERNAL;
var details = 'Unknown Error';
@ -113,7 +151,7 @@ function GrpcServerStream(call, options) {
return;
}
var data = event.data;
if (self.push(data) && data != null) {
if (self.push(deserialize(data)) && data != null) {
self._call.startRead(readCallback);
} else {
reading = false;
@ -155,7 +193,7 @@ GrpcServerStream.prototype._read = function(size) {
*/
GrpcServerStream.prototype._write = function(chunk, encoding, callback) {
var self = this;
self._call.startWrite(chunk, function(event) {
self._call.startWrite(self.serialize(chunk), function(event) {
callback();
}, 0);
};
@ -211,12 +249,13 @@ function Server(options) {
}
}, 0);
call.serverEndInitialMetadata(0);
var stream = new GrpcServerStream(call);
var stream = new GrpcServerStream(call, handler.serialize,
handler.deserialize);
Object.defineProperty(stream, 'cancelled', {
get: function() { return cancelled;}
});
try {
handler(stream, data.metadata);
handler.func(stream, data.metadata);
} catch (e) {
stream.emit('error', e);
}
@ -237,14 +276,20 @@ function Server(options) {
* handle/respond to.
* @param {function} handler Function that takes a stream of request values and
* returns a stream of response values
* @param {function(*):Buffer} serialize Serialization function for responses
* @param {function(Buffer):*} deserialize Deserialization function for requests
* @return {boolean} True if the handler was set. False if a handler was already
* set for that name.
*/
Server.prototype.register = function(name, handler) {
Server.prototype.register = function(name, handler, serialize, deserialize) {
if (this.handlers.hasOwnProperty(name)) {
return false;
}
this.handlers[name] = handler;
this.handlers[name] = {
func: handler,
serialize: serialize,
deserialize: deserialize
};
return true;
};
@ -256,9 +301,9 @@ Server.prototype.register = function(name, handler) {
*/
Server.prototype.bind = function(port, secure) {
if (secure) {
this._server.addSecureHttp2Port(port);
return this._server.addSecureHttp2Port(port);
} else {
this._server.addHttp2Port(port);
return this._server.addHttp2Port(port);
}
};

@ -123,14 +123,12 @@ NAN_METHOD(ServerCredentials::New) {
}
NAN_METHOD(ServerCredentials::CreateSsl) {
// TODO: have the node API support multiple key/cert pairs.
NanScope();
char *root_certs = NULL;
char *private_key;
char *cert_chain;
int root_certs_length = 0, private_key_length, cert_chain_length;
grpc_ssl_pem_key_cert_pair key_cert_pair;
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");
@ -138,17 +136,13 @@ NAN_METHOD(ServerCredentials::CreateSsl) {
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]);
key_cert_pair.private_key = Buffer::Data(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)));
key_cert_pair.cert_chain = Buffer::Data(args[2]);
NanReturnValue(WrapStruct(
grpc_ssl_server_credentials_create(root_certs, &key_cert_pair, 1)));
}
NAN_METHOD(ServerCredentials::CreateFake) {

@ -33,6 +33,9 @@
var _ = require('underscore');
var capitalize = require('underscore.string/capitalize');
var decapitalize = require('underscore.string/decapitalize');
var client = require('./client.js');
var common = require('./common.js');
@ -352,10 +355,11 @@ function makeClientConstructor(service) {
method_type = 'unary';
}
}
SurfaceClient.prototype[method.name] = requester_makers[method_type](
prefix + method.name,
common.serializeCls(method.resolvedRequestType.build()),
common.deserializeCls(method.resolvedResponseType.build()));
SurfaceClient.prototype[decapitalize(method.name)] =
requester_makers[method_type](
prefix + capitalize(method.name),
common.serializeCls(method.resolvedRequestType.build()),
common.deserializeCls(method.resolvedResponseType.build()));
});
SurfaceClient.service = service;

@ -33,6 +33,9 @@
var _ = require('underscore');
var capitalize = require('underscore.string/capitalize');
var decapitalize = require('underscore.string/decapitalize');
var Server = require('./server.js');
var stream = require('stream');
@ -332,15 +335,16 @@ function makeServerConstructor(services) {
method_type = 'unary';
}
}
if (service_handlers[service_name][method.name] === undefined) {
if (service_handlers[service_name][decapitalize(method.name)] ===
undefined) {
throw new Error('Method handler for ' +
common.fullyQualifiedName(method) + ' not provided.');
}
var binary_handler = handler_makers[method_type](
service_handlers[service_name][method.name],
service_handlers[service_name][decapitalize(method.name)],
common.serializeCls(method.resolvedResponseType.build()),
common.deserializeCls(method.resolvedRequestType.build()));
server.register(prefix + method.name, binary_handler);
server.register(prefix + capitalize(method.name), binary_handler);
});
}, this);
}
@ -353,8 +357,7 @@ function makeServerConstructor(services) {
* @return {SurfaceServer} this
*/
SurfaceServer.prototype.bind = function(port, secure) {
this.inner_server.bind(port, secure);
return this;
return this.inner_server.bind(port, secure);
};
/**

@ -37,7 +37,6 @@ 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');
@ -80,55 +79,50 @@ function errorHandler(stream) {
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();
});
var server = new Server();
var port_num = server.bind('0.0.0.0:0');
server.register('echo', echoHandler);
server.start();
var messages = ['echo1', 'echo2', 'echo3', 'echo4'];
var channel = new grpc.Channel('localhost:' + port_num);
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();
});
var server = new Server();
var port_num = server.bind('0.0.0.0:0');
server.register('error', errorHandler);
server.start();
var channel = new grpc.Channel('localhost:' + port_num);
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();
});
});
});
@ -136,46 +130,43 @@ describe('echo client', function() {
* 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) {
fs.readFile(ca_path, function(err, ca_data) {
assert.ifError(err);
fs.readFile(key_path, function(err, key_data) {
assert.ifError(err);
fs.readFile(key_path, function(err, key_data) {
fs.readFile(pem_path, function(err, pem_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();
});
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});
var port_num = server.bind('0.0.0.0:0', true);
server.register('echo', echoHandler);
server.start();
var messages = ['echo1', 'echo2', 'echo3', 'echo4'];
var channel = new grpc.Channel('localhost:' + port_num, {
'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();
});
});
});
});

@ -33,7 +33,6 @@
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
@ -58,143 +57,139 @@ function multiDone(done, count) {
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);
var server = new grpc.Server();
var done = multiDone(function() {
complete();
server.shutdown();
}, 2);
var port_num = server.addHttp2Port('0.0.0.0:0');
var channel = new grpc.Channel('localhost:' + port_num);
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) {
call.writesDone(function(event) {
assert.strictEqual(event.type,
grpc.completionType.CLIENT_METADATA_READ);
},function(event) {
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);
var status = event.data;
assert.strictEqual(status.code, grpc.status.OK);
assert.strictEqual(status.details, status_text);
done();
}, 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();
});
});
});
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) {
it('should send and receive data without error', function(complete) {
var req_text = 'client_request';
var reply_text = 'server_response';
var server = new grpc.Server();
var done = multiDone(function() {
complete();
server.shutdown();
}, 6);
var port_num = server.addHttp2Port('0.0.0.0:0');
var channel = new grpc.Channel('localhost:' + port_num);
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);
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),
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);
call.writesDone(function(event) {
assert.strictEqual(event.type,
grpc.completionType.FINISH_ACCEPTED);
assert.strictEqual(event.data, grpc.opError.OK);
done();
});
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);
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);
});
});
});
});

@ -0,0 +1,71 @@
/*
*
* 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 interop_server = require('../interop/interop_server.js');
var interop_client = require('../interop/interop_client.js');
var server;
var port;
var name_override = 'foo.test.google.com';
describe('Interop tests', function() {
before(function(done) {
var server_obj = interop_server.getServer(0, true);
server = server_obj.server;
server.listen();
port = 'localhost:' + server_obj.port;
done();
});
// This depends on not using a binary stream
it('should pass empty_unary', function(done) {
interop_client.runTest(port, name_override, 'empty_unary', true, done);
});
it('should pass large_unary', function(done) {
interop_client.runTest(port, name_override, 'large_unary', true, done);
});
it('should pass client_streaming', function(done) {
interop_client.runTest(port, name_override, 'client_streaming', true, done);
});
it('should pass server_streaming', function(done) {
interop_client.runTest(port, name_override, 'server_streaming', true, done);
});
it('should pass ping_pong', function(done) {
interop_client.runTest(port, name_override, 'ping_pong', true, done);
});
// This depends on the new invoke API
it.skip('should pass empty_stream', function(done) {
interop_client.runTest(port, name_override, 'empty_stream', true, done);
});
});

@ -32,7 +32,6 @@
*/
var assert = require('assert');
var port_picker = require('../port_picker');
var grpc = require('..');
var math = grpc.load(__dirname + '/../examples/math.proto').math;
@ -50,18 +49,17 @@ var server = require('../examples/math_server.js');
describe('Math client', function() {
before(function(done) {
port_picker.nextAvailablePort(function(port) {
server.bind(port).listen();
math_client = new math.Math(port);
done();
});
var port_num = server.bind('0.0.0.0:0');
server.listen();
math_client = new math.Math('localhost:' + port_num);
done();
});
after(function() {
server.shutdown();
});
it('should handle a single request', function(done) {
var arg = {dividend: 7, divisor: 4};
var call = math_client.Div(arg, function handleDivResult(err, value) {
var call = math_client.div(arg, function handleDivResult(err, value) {
assert.ifError(err);
assert.equal(value.quotient, 1);
assert.equal(value.remainder, 3);
@ -72,7 +70,7 @@ describe('Math client', function() {
});
});
it('should handle a server streaming request', function(done) {
var call = math_client.Fib({limit: 7});
var call = math_client.fib({limit: 7});
var expected_results = [1, 1, 2, 3, 5, 8, 13];
var next_expected = 0;
call.on('data', function checkResponse(value) {
@ -85,7 +83,7 @@ describe('Math client', function() {
});
});
it('should handle a client streaming request', function(done) {
var call = math_client.Sum(function handleSumResult(err, value) {
var call = math_client.sum(function handleSumResult(err, value) {
assert.ifError(err);
assert.equal(value.num, 21);
});
@ -103,7 +101,7 @@ describe('Math client', function() {
assert.equal(value.quotient, index);
assert.equal(value.remainder, 1);
}
var call = math_client.DivMany();
var call = math_client.divMany();
var response_index = 0;
call.on('data', function(value) {
checkResponse(response_index, value);

@ -34,7 +34,6 @@
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
@ -68,54 +67,52 @@ function echoHandler(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 server = new Server();
var port_num = server.bind('[::]:0');
server.register('echo', echoHandler);
server.start();
var req_text = 'echo test string';
var status_text = 'OK';
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) {
var channel = new grpc.Channel('localhost:' + port_num);
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.WRITE_ACCEPTED);
grpc.completionType.FINISH_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();
});
}, 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.FINISHED);
var status = event.data;
assert.strictEqual(status.code, grpc.status.OK);
assert.strictEqual(status.details, status_text);
server.shutdown();
done();
}, 0);
});
});
},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);
});
});

@ -59,9 +59,9 @@ describe('Surface server constructor', function() {
assert.throws(function() {
new Server({
'math.Math': {
'Div': function() {},
'DivMany': function() {},
'Fib': function() {}
'div': function() {},
'divMany': function() {},
'fib': function() {}
}
});
}, /math.Math.Sum/);

@ -77,24 +77,25 @@ PHP_METHOD(Credentials, createDefault) {
*/
PHP_METHOD(Credentials, createSsl) {
char *pem_root_certs;
char *pem_private_key = NULL;
char *pem_cert_chain = NULL;
grpc_ssl_pem_key_cert_pair pem_key_cert_pair;
int root_certs_length, private_key_length = 0, cert_chain_length = 0;
pem_key_cert_pair.private_key = pem_key_cert_pair.cert_chain = NULL;
/* "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) {
&pem_key_cert_pair.private_key, &private_key_length,
&pem_key_cert_pair.cert_chain,
&cert_chain_length) == FAILURE) {
zend_throw_exception(spl_ce_InvalidArgumentException,
"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);
pem_root_certs,
pem_key_cert_pair.private_key == NULL ? NULL : &pem_key_cert_pair);
zval *creds_object = grpc_php_wrap_credentials(creds);
RETURN_DESTROY_ZVAL(creds_object);
}

@ -66,24 +66,22 @@ zval *grpc_php_wrap_server_credentials(grpc_server_credentials *wrapped) {
*/
PHP_METHOD(ServerCredentials, createSsl) {
char *pem_root_certs = 0;
char *pem_private_key;
char *pem_cert_chain;
grpc_ssl_pem_key_cert_pair pem_key_cert_pair;
int root_certs_length = 0, private_key_length, cert_chain_length;
/* "s!ss" == 1 nullable string, 2 strings */
/* TODO: support multiple key cert pairs. */
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,
&root_certs_length, &pem_key_cert_pair.private_key,
&private_key_length, &pem_key_cert_pair.cert_chain,
&cert_chain_length) == FAILURE) {
zend_throw_exception(spl_ce_InvalidArgumentException,
"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);
grpc_server_credentials *creds =
grpc_ssl_server_credentials_create(pem_root_certs, &pem_key_cert_pair, 1);
zval *creds_object = grpc_php_wrap_server_credentials(creds);
RETURN_DESTROY_ZVAL(creds_object);
}

@ -1,4 +1,4 @@
# Copyright 2014, Google Inc.
# Copyright 2015, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@ -27,31 +27,38 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
require 'beefcake'
module Beefcake
# Re-open the beefcake message module to add a static encode
#
# This is a temporary measure while beefcake is used as the default proto
# library for developing grpc ruby. Once that changes to the official proto
# library this can be removed. It's necessary to allow the update the service
# module to assume a static encode method.
# TODO(temiola): remove this.
module Message
# additional mixin module that adds static encode method when include
module StaticEncode
# encodes o with its instance#encode method
def encode(o)
o.encode
end
end
# extend self.included in Beefcake::Message to include StaticEncode
def self.included(o)
o.extend StaticEncode
o.extend Dsl
o.extend Decode
o.send(:include, Encode)
end
end
end
"""Tests for google3.net.rpc.python.framework.foundation.logging_pool."""
import unittest
from _framework.foundation import logging_pool
_POOL_SIZE = 16
class LoggingPoolTest(unittest.TestCase):
def testUpAndDown(self):
pool = logging_pool.pool(_POOL_SIZE)
pool.shutdown(wait=True)
with logging_pool.pool(_POOL_SIZE) as pool:
self.assertIsNotNone(pool)
def testTaskExecuted(self):
test_list = []
with logging_pool.pool(_POOL_SIZE) as pool:
pool.submit(lambda: test_list.append(object())).result()
self.assertTrue(test_list)
def testException(self):
with logging_pool.pool(_POOL_SIZE) as pool:
raised_exception = pool.submit(lambda: 1/0).exception()
self.assertIsNotNone(raised_exception)
if __name__ == '__main__':
unittest.main()

@ -0,0 +1,83 @@
# Copyright 2015, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""A thread pool that logs exceptions raised by tasks executed within it."""
import functools
import logging
from concurrent import futures
def _wrap(behavior):
"""Wraps an arbitrary callable behavior in exception-logging."""
@functools.wraps(behavior)
def _wrapping(*args, **kwargs):
try:
return behavior(*args, **kwargs)
except Exception as e:
logging.exception('Unexpected exception from task run in logging pool!')
raise
return _wrapping
class _LoggingPool(object):
"""An exception-logging futures.ThreadPoolExecutor-compatible thread pool."""
def __init__(self, backing_pool):
self._backing_pool = backing_pool
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self._backing_pool.shutdown(wait=True)
def submit(self, fn, *args, **kwargs):
return self._backing_pool.submit(_wrap(fn), *args, **kwargs)
def map(self, func, *iterables, **kwargs):
return self._backing_pool.map(
_wrap(func), *iterables, timeout=kwargs.get('timeout', None))
def shutdown(self, wait=True):
self._backing_pool.shutdown(wait=wait)
def pool(max_workers):
"""Creates a thread pool that logs exceptions raised by the tasks within it.
Args:
max_workers: The maximum number of worker threads to allow the pool.
Returns:
A futures.ThreadPoolExecutor-compatible thread pool that logs exceptions
raised by the tasks executed within it.
"""
return _LoggingPool(futures.ThreadPoolExecutor(max_workers))

@ -1,64 +1,63 @@
Ruby for GRPC
=============
gRPC Ruby
=========
LAYOUT
------
A Ruby implementation of gRPC, Google's RPC library.
Directory structure is the recommended layout for [ruby extensions](http://guides.rubygems.org/gems-with-extensions/)
* ext: the extension code
* lib: the entrypoint grpc ruby library to be used in a 'require' statement
* test: tests
INSTALLATION PREREQUISITES
--------------------------
This requires Ruby 2.x, as the rpc api surface uses keyword args.
DEPENDENCIES
------------
INSTALLING
----------
* Extension
- Install the gRPC core library
TODO: describe this, once the core distribution mechanism is defined.
The extension can be built and tested using
[rake](https://rubygems.org/gems/rake). However, the rake-extensiontask rule
is not supported on older versions of rubygems, and the necessary version of
rubygems.
$ gem install grpc
This is resolved by using [RVM](https://rvm.io/) instead; install a single-user
ruby environment, and develop on the latest stable version of ruby (2.1.5).
Installing from source
----------------------
INSTALLATION PREREQUISITES
--------------------------
Install RVM
- Build or Install the gRPC core
E.g, from the root of the grpc [git repo](https://github.com/google/grpc)
$ cd ../..
$ make && sudo make install
- Install Ruby 2.x. Consider doing this with [RVM](http://rvm.io), it's a nice way of controlling
the exact ruby version that's used.
$ command curl -sSL https://rvm.io/mpapis.asc | gpg --import -
$ \curl -sSL https://get.rvm.io | bash -s stable --ruby
$
$ # follow the instructions to ensure that your're using the latest stable version of Ruby
$ # and that the rvm command is installed
$
$ gem install bundler # install bundler, the standard ruby package manager
HACKING
-------
- Install [bundler](http://bundler.io/)
$ gem install bundler
The extension can be built and tested using the Rakefile.
- Finally, install grpc ruby locally.
$ cd <install_dir>
$ bundle install
$ rake # compiles the extension, runs the unit tests, see rake -T for other options
$ # create a workspace
$ git5 start <your-git5-branch> net/grpc
$
$ # build the C library and install it in $HOME/grpc_dev
$ <google3>/net/grpc/c/build_gyp/build_grpc_dev.sh
$
$ # build the ruby extension and test it.
$ cd google3_dir/net/grpc/ruby
$ rake
Finally, install grpc ruby locally.
CONTENTS
--------
$ cd <this_dir>
$
$ # update the Gemfile, modify the line beginning # gem 'beefcake' to refer to
$ # the patched beefcake dir
$
$ bundle install
Directory structure is the layout for [ruby extensions](http://guides.rubygems.org/gems-with-extensions/)
* ext: the extension code
* lib: the entrypoint grpc ruby library to be used in a 'require' statement
* spec: tests
* bin: example gRPC clients and servers, e.g,
```ruby
# client
stub = Math::Math::Stub.new('my.test.math.server.com:8080')
req = Math::DivArgs.new(dividend: 7, divisor: 3)
logger.info("div(7/3): req=#{req.inspect}")
resp = stub.div(req, INFINITE_FUTURE)
logger.info("Answer: #{resp.inspect}")
```

@ -1,11 +1,8 @@
Interop test protos
===================
These were generated by a patched version of beefcake and a patched version of
protoc.
These ruby classes were generated with protoc v3, using grpc's ruby compiler
plugin.
- set up and access of the patched versions is described in ../../README.md
The actual test proto is found in Google3 at
- third_party/stubby/testing/proto/test.proto
- As of 2015/01 protoc v3 is available in the
[google-protobuf](https://github.com/google/protobuf) repo

@ -107,11 +107,11 @@ class PingPongPlayer
@msg_sizes.each do |m|
req_size, resp_size = m
req = req_cls.new(payload: Payload.new(body: nulls(req_size)),
response_type: COMPRESSABLE,
response_type: :COMPRESSABLE,
response_parameters: [p_cls.new(size: resp_size)])
yield req
resp = @queue.pop
assert_equal(PayloadType.lookup(COMPRESSABLE), resp.payload.type,
assert_equal(:COMPRESSABLE, resp.payload.type,
'payload type is wrong')
assert_equal(resp_size, resp.payload.body.length,
'payload body #{i} has the wrong length')
@ -149,11 +149,13 @@ class NamedTests
# FAILED
def large_unary
req_size, wanted_response_size = 271_828, 314_159
payload = Payload.new(type: COMPRESSABLE, body: nulls(req_size))
req = SimpleRequest.new(response_type: COMPRESSABLE,
payload = Payload.new(type: :COMPRESSABLE, body: nulls(req_size))
req = SimpleRequest.new(response_type: :COMPRESSABLE,
response_size: wanted_response_size,
payload: payload)
resp = @stub.unary_call(req)
assert_equal(:COMPRESSABLE, resp.payload.type,
'large_unary: payload had the wrong type')
assert_equal(wanted_response_size, resp.payload.body.length,
'large_unary: payload had the wrong length')
assert_equal(nulls(wanted_response_size), resp.payload.body,
@ -185,12 +187,12 @@ class NamedTests
def server_streaming
msg_sizes = [31_415, 9, 2653, 58_979]
response_spec = msg_sizes.map { |s| ResponseParameters.new(size: s) }
req = StreamingOutputCallRequest.new(response_type: COMPRESSABLE,
req = StreamingOutputCallRequest.new(response_type: :COMPRESSABLE,
response_parameters: response_spec)
resps = @stub.streaming_output_call(req)
resps.each_with_index do |r, i|
assert i < msg_sizes.length, 'too many responses'
assert_equal(PayloadType.lookup(COMPRESSABLE), r.payload.type,
assert_equal(:COMPRESSABLE, r.payload.type,
'payload type is wrong')
assert_equal(msg_sizes[i], r.payload.body.length,
'payload body #{i} has the wrong length')
@ -235,7 +237,7 @@ def parse_options
end
end.parse!
%w(server_host, server_port, test_case).each do |arg|
%w(server_host server_port test_case).each do |arg|
if options[arg].nil?
fail(OptionParser::MissingArgument, "please specify --#{arg}")
end

@ -104,7 +104,7 @@ class TestTarget < Grpc::Testing::TestService::Service
def unary_call(simple_req, _call)
req_size = simple_req.response_size
SimpleResponse.new(payload: Payload.new(type: COMPRESSABLE,
SimpleResponse.new(payload: Payload.new(type: :COMPRESSABLE,
body: nulls(req_size)))
end
@ -145,8 +145,8 @@ class TestTarget < Grpc::Testing::TestService::Service
end
def half_duplex_call(reqs)
# TODO(temiola): clarify the behaviour of the half_duplex_call, it's not
# currently used in any tests
# TODO: update with unique behaviour of the half_duplex_call if that's
# ever required by any of the tests.
full_duplex_call(reqs)
end
end

@ -68,13 +68,9 @@ $CFLAGS << ' -Wno-return-type '
$CFLAGS << ' -Wall '
$CFLAGS << ' -pedantic '
$LDFLAGS << ' -lgrpc -lgpr -levent -levent_pthreads -levent_core'
# crash('need grpc lib') unless have_library('grpc', 'grpc_channel_destroy')
#
# TODO(temiola): figure out why this stopped working, but the so is built OK
# and the tests pass
$LDFLAGS << ' -lgrpc -lgpr -ldl'
crash('need grpc lib') unless have_library('grpc', 'grpc_channel_destroy')
have_library('grpc', 'grpc_channel_destroy')
crash('need gpr lib') unless have_library('gpr', 'gpr_now')
create_makefile('grpc/grpc')

@ -75,7 +75,7 @@ static void grpc_rb_completion_queue_shutdown_drain(grpc_completion_queue *cq) {
grpc_completion_queue_shutdown(cq);
next_call.cq = cq;
next_call.event = NULL;
/* TODO(temiola): the timeout should be a module level constant that defaults
/* TODO: the timeout should be a module level constant that defaults
* to gpr_inf_future.
*
* - at the moment this does not work, it stalls. Using a small timeout like

@ -214,6 +214,7 @@ static VALUE grpc_rb_credentials_init(int argc, VALUE *argv, VALUE self) {
VALUE pem_cert_chain = Qnil;
grpc_rb_credentials *wrapper = NULL;
grpc_credentials *creds = NULL;
/* TODO: Remove mandatory arg when we support default roots. */
/* "12" == 1 mandatory arg, 2 (credentials) is optional */
rb_scan_args(argc, argv, "12", &pem_root_certs, &pem_private_key,
&pem_cert_chain);
@ -225,22 +226,12 @@ static VALUE grpc_rb_credentials_init(int argc, VALUE *argv, VALUE self) {
return Qnil;
}
if (pem_private_key == Qnil && pem_cert_chain == Qnil) {
creds = grpc_ssl_credentials_create(RSTRING_PTR(pem_root_certs),
RSTRING_LEN(pem_root_certs), NULL, 0,
NULL, 0);
} else if (pem_cert_chain == Qnil) {
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),
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_cert_chain), RSTRING_LEN(pem_cert_chain));
creds = grpc_ssl_credentials_create(RSTRING_PTR(pem_root_certs), NULL);
} else {
grpc_ssl_pem_key_cert_pair key_cert_pair = {RSTRING_PTR(pem_private_key),
RSTRING_PTR(pem_cert_chain)};
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_root_certs), &key_cert_pair);
}
if (creds == NULL) {
rb_raise(rb_eRuntimeError, "could not create a credentials, not sure why");

@ -145,8 +145,10 @@ static ID id_pem_cert_chain;
static VALUE grpc_rb_server_credentials_init(VALUE self, VALUE pem_root_certs,
VALUE pem_private_key,
VALUE pem_cert_chain) {
/* TODO support multiple key cert pairs in the ruby API. */
grpc_rb_server_credentials *wrapper = NULL;
grpc_server_credentials *creds = NULL;
grpc_ssl_pem_key_cert_pair key_cert_pair = {NULL, NULL};
Data_Get_Struct(self, grpc_rb_server_credentials, wrapper);
if (pem_cert_chain == Qnil) {
rb_raise(rb_eRuntimeError,
@ -157,15 +159,13 @@ static VALUE grpc_rb_server_credentials_init(VALUE self, VALUE pem_root_certs,
"could not create a server credential: nil pem_private_key");
return Qnil;
}
key_cert_pair.private_key = RSTRING_PTR(pem_private_key);
key_cert_pair.cert_chain = RSTRING_PTR(pem_cert_chain);
if (pem_root_certs == Qnil) {
creds = grpc_ssl_server_credentials_create(
NULL, 0, RSTRING_PTR(pem_private_key), RSTRING_LEN(pem_private_key),
RSTRING_PTR(pem_cert_chain), RSTRING_LEN(pem_cert_chain));
creds = grpc_ssl_server_credentials_create(NULL, &key_cert_pair, 1);
} else {
creds = grpc_ssl_server_credentials_create(
RSTRING_PTR(pem_root_certs), RSTRING_LEN(pem_root_certs),
RSTRING_PTR(pem_private_key), RSTRING_LEN(pem_private_key),
RSTRING_PTR(pem_cert_chain), RSTRING_LEN(pem_cert_chain));
creds = grpc_ssl_server_credentials_create(RSTRING_PTR(pem_root_certs),
&key_cert_pair, 1);
}
if (creds == NULL) {
rb_raise(rb_eRuntimeError, "could not create a credentials, not sure why");

@ -5,11 +5,11 @@ require 'grpc/version'
Gem::Specification.new do |s|
s.name = 'grpc'
s.version = Google::RPC::VERSION
s.authors = ['One Platform Team']
s.email = 'stubby-team@google.com'
s.homepage = 'http://go/grpc'
s.authors = ['gRPC Authors']
s.email = 'tbetbetbe@gmail.com'
s.homepage = 'https://github.com/google/grpc/tree/master/src/ruby'
s.summary = 'Google RPC system in Ruby'
s.description = 'Send RPCs from Ruby'
s.description = 'Send RPCs from Ruby using Google\'s RPC system'
s.files = `git ls-files`.split("\n")
s.test_files = `git ls-files -- spec/*`.split("\n")

@ -142,7 +142,7 @@ module Google
# during bidi-streaming, read the requests to send from a separate thread
# read so that read_loop does not block waiting for requests to read.
def start_write_loop(requests, is_client: true)
Thread.new do # TODO(temiola) run on a thread pool
Thread.new do # TODO: run on a thread pool
write_tag = Object.new
begin
count = 0

@ -233,10 +233,6 @@ module Google
end
def new_active_server_call(call, new_server_rpc)
# TODO(temiola): perhaps reuse the main server completion queue here,
# but for now, create a new completion queue per call, pending best
# practice usage advice from the c core.
# Accept the call. This is necessary even if a status is to be sent
# back immediately
finished_tag = Object.new
@ -340,7 +336,7 @@ module Google
@workers.size.times { schedule { throw :exit } }
@stopped = true
# TODO(temiola): allow configuration of the keepalive period
# TODO: allow configuration of the keepalive period
keep_alive = 5
@stop_mutex.synchronize do
@stop_cond.wait(@stop_mutex, keep_alive) if @workers.size > 0

@ -34,7 +34,7 @@ include Logging.globally # logger is accessible everywhere
Logging.logger.root.appenders = Logging.appenders.stdout
Logging.logger.root.level = :info
# TODO(temiola): provide command-line configuration for logging
# TODO: provide command-line configuration for logging
Logging.logger['Google::RPC'].level = :debug
Logging.logger['Google::RPC::ActiveCall'].level = :info
Logging.logger['Google::RPC::BidiCall'].level = :info

@ -294,7 +294,7 @@ shared_examples 'GRPC metadata delivery works OK' do
expect_next_event_on(@server_queue, WRITE_ACCEPTED, @server_tag)
# there is the HTTP status metadata, though there should not be any
# TODO(temiola): update this with the bug number to be resolved
# TODO: update this with the bug number to be resolved
ev = expect_next_event_on(@client_queue, CLIENT_METADATA_READ, @tag)
expect(ev.result).to eq(':status' => '200')
end

@ -1,4 +1 @@
These are test keys *NOT* to be used in production.
http://go/keyhunt requires this README
CONFIRMEDTESTKEY

@ -19,6 +19,14 @@
return 'gens/' + m.group(1) + '.pb.cc'
%>
# Basic platform detection
HOST_SYSTEM = $(shell uname | cut -f 1 -d_)
ifeq ($(SYSTEM),)
SYSTEM = $(HOST_SYSTEM)
endif
# Configurations
VALID_CONFIG_opt = 1
@ -132,10 +140,15 @@ LDFLAGS += $(LDFLAGS_$(CONFIG))
CFLAGS += -std=c89 -pedantic
CXXFLAGS += -std=c++11
CPPFLAGS += -g -fPIC -Wall -Werror -Wno-long-long
LDFLAGS += -g -pthread -fPIC
LDFLAGS += -g -fPIC
INCLUDES = . include gens
ifeq ($(SYSTEM),Darwin)
LIBS = m z
else
LIBS = rt m z pthread
LDFLAGS += -pthread
endif
LIBSXX = protobuf
LIBS_PROTOC = protoc protobuf
@ -173,11 +186,6 @@ HOST_LDLIBS = $(LDLIBS)
# These are automatically computed variables.
# There shouldn't be any need to change anything from now on.
HOST_SYSTEM = $(shell uname | cut -f 1 -d_)
ifeq ($(SYSTEM),)
SYSTEM = $(HOST_SYSTEM)
endif
ifeq ($(SYSTEM),MINGW32)
SHARED_EXT = dll
endif
@ -340,8 +348,12 @@ libs/$(CONFIG)/zlib/libz.a:
$(Q)cp third_party/zlib/libz.a libs/$(CONFIG)/zlib
libs/$(CONFIG)/openssl/libssl.a:
$(E) "[MAKE] Building openssl"
$(E) "[MAKE] Building openssl for $(SYSTEM)"
ifeq ($(SYSTEM),Darwin)
$(Q)(cd third_party/openssl ; CC="$(CC) -fPIC -fvisibility=hidden $(CPPFLAGS_$(CONFIG)) $(OPENSSL_CFLAGS_$(CONFIG))" ./Configure darwin64-x86_64-cc $(OPENSSL_CONFIG_$(CONFIG)))
else
$(Q)(cd third_party/openssl ; CC="$(CC) -fPIC -fvisibility=hidden $(CPPFLAGS_$(CONFIG)) $(OPENSSL_CFLAGS_$(CONFIG))" ./config $(OPENSSL_CONFIG_$(CONFIG)))
endif
$(Q)$(MAKE) -C third_party/openssl clean
$(Q)$(MAKE) -C third_party/openssl build_crypto build_ssl
$(Q)mkdir -p libs/$(CONFIG)/openssl
@ -695,6 +707,7 @@ libs/$(CONFIG)/lib${lib.name}.a: $(ZLIB_DEP) $(LIB${lib.name.upper()}_OBJS)
% endif
$(E) "[AR] Creating $@"
$(Q) mkdir -p `dirname $@`
$(Q) rm -f libs/$(CONFIG)/lib${lib.name}.a
$(Q) $(AR) rcs libs/$(CONFIG)/lib${lib.name}.a $(LIB${lib.name.upper()}_OBJS)
% if lib.get('baselib', False):
% if lib.get('secure', True):
@ -707,6 +720,9 @@ libs/$(CONFIG)/lib${lib.name}.a: $(ZLIB_DEP) $(LIB${lib.name.upper()}_OBJS)
$(Q) rm -rf tmp-merge
% endif
% endif
ifeq ($(SYSTEM),Darwin)
$(Q) ranlib libs/$(CONFIG)/lib${lib.name}.a
endif
<%
if lib.language == 'c++':

@ -56,8 +56,8 @@
typedef struct metadata {
size_t count;
size_t cap;
const char **keys;
const char **values;
char **keys;
char **values;
} metadata;
/* details what we expect to find on a single event - and forms a linked
@ -409,11 +409,11 @@ static metadata *metadata_from_args(va_list args) {
if (md->cap == md->count) {
md->cap = GPR_MAX(md->cap + 1, md->cap * 3 / 2);
md->keys = gpr_realloc(md->keys, sizeof(const char *) * md->cap);
md->values = gpr_realloc(md->values, sizeof(const char *) * md->cap);
md->keys = gpr_realloc(md->keys, sizeof(char *) * md->cap);
md->values = gpr_realloc(md->values, sizeof(char *) * md->cap);
}
md->keys[md->count] = key;
md->values[md->count] = value;
md->keys[md->count] = (char *)key;
md->values[md->count] = (char *)value;
md->count++;
}
}

@ -31,7 +31,7 @@
*
*/
unsigned char prod_roots_certs[] = {
const char prod_roots_certs[] = {
0x23, 0x20, 0x49, 0x73, 0x73, 0x75, 0x65, 0x72, 0x3a, 0x20, 0x43, 0x4e,
0x3d, 0x47, 0x54, 0x45, 0x20, 0x43, 0x79, 0x62, 0x65, 0x72, 0x54, 0x72,
0x75, 0x73, 0x74, 0x20, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x20, 0x52,
@ -11270,5 +11270,4 @@ unsigned char prod_roots_certs[] = {
0x33, 0x50, 0x59, 0x74, 0x6c, 0x4e, 0x58, 0x4c, 0x66, 0x62, 0x51, 0x34,
0x64, 0x64, 0x49, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44,
0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45,
0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a};
unsigned int prod_roots_certs_size = 134862;
0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x00};

@ -31,7 +31,7 @@
*
*/
unsigned char test_server1_cert[] = {
const char test_server1_cert[] = {
0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43,
0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d,
0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x43, 0x6d, 0x7a, 0x43, 0x43,
@ -112,5 +112,4 @@ unsigned char test_server1_cert[] = {
0x32, 0x77, 0x65, 0x2f, 0x4b, 0x44, 0x34, 0x6f, 0x6a, 0x66, 0x39, 0x73,
0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43,
0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d,
0x2d, 0x2d, 0x2d, 0x0a};
unsigned int test_server1_cert_size = 964;
0x2d, 0x2d, 0x2d, 0x0a, 0x00};

@ -31,7 +31,7 @@
*
*/
unsigned char test_server1_key[] = {
const char test_server1_key[] = {
0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x52,
0x53, 0x41, 0x20, 0x50, 0x52, 0x49, 0x56, 0x41, 0x54, 0x45, 0x20, 0x4b,
0x45, 0x59, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x43,
@ -105,5 +105,4 @@ unsigned char test_server1_key[] = {
0x6e, 0x68, 0x66, 0x66, 0x46, 0x79, 0x65, 0x37, 0x53, 0x42, 0x58, 0x79,
0x61, 0x67, 0x3d, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e,
0x44, 0x20, 0x52, 0x53, 0x41, 0x20, 0x50, 0x52, 0x49, 0x56, 0x41, 0x54,
0x45, 0x20, 0x4b, 0x45, 0x59, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a};
unsigned int test_server1_key_size = 887;
0x45, 0x20, 0x4b, 0x45, 0x59, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x00};

@ -34,14 +34,10 @@
#ifndef __GRPC_TEST_END2END_DATA_SSL_TEST_DATA_H__
#define __GRPC_TEST_END2END_DATA_SSL_TEST_DATA_H__
extern unsigned char test_root_cert[];
extern unsigned int test_root_cert_size;
extern unsigned char test_server1_cert[];
extern unsigned int test_server1_cert_size;
extern unsigned char test_server1_key[];
extern unsigned int test_server1_key_size;
extern const char test_root_cert[];
extern const char test_server1_cert[];
extern const char test_server1_key[];
extern unsigned char prod_roots_certs[];
extern unsigned int prod_roots_certs_size;
extern const char prod_roots_certs[];
#endif /* __GRPC_TEST_END2END_DATA_SSL_TEST_DATA_H__ */

@ -31,7 +31,7 @@
*
*/
unsigned char test_root_cert[] = {
const char test_root_cert[] = {
0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43,
0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d,
0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x43, 0x49, 0x7a, 0x43, 0x43,
@ -98,5 +98,4 @@ unsigned char test_root_cert[] = {
0x31, 0x59, 0x75, 0x58, 0x32, 0x72, 0x6e, 0x65, 0x78, 0x30, 0x4a, 0x68,
0x75, 0x54, 0x51, 0x66, 0x63, 0x49, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d,
0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49,
0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a};
unsigned int test_root_cert_size = 802;
0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x00};

@ -98,8 +98,8 @@ void chttp2_tear_down_secure_fullstack(grpc_end2end_test_fixture *f) {
static void chttp2_init_client_simple_ssl_secure_fullstack(
grpc_end2end_test_fixture *f, grpc_channel_args *client_args) {
grpc_credentials *ssl_creds = grpc_ssl_credentials_create(
test_root_cert, test_root_cert_size, NULL, 0, NULL, 0);
grpc_credentials *ssl_creds =
grpc_ssl_credentials_create(test_root_cert, NULL);
grpc_arg ssl_name_override = {GRPC_ARG_STRING,
GRPC_SSL_TARGET_NAME_OVERRIDE_ARG,
{"foo.test.google.com"}};
@ -111,9 +111,10 @@ static void chttp2_init_client_simple_ssl_secure_fullstack(
static void chttp2_init_server_simple_ssl_secure_fullstack(
grpc_end2end_test_fixture *f, grpc_channel_args *server_args) {
grpc_server_credentials *ssl_creds = grpc_ssl_server_credentials_create(
NULL, 0, test_server1_key, test_server1_key_size, test_server1_cert,
test_server1_cert_size);
grpc_ssl_pem_key_cert_pair pem_cert_key_pair = {test_server1_key,
test_server1_cert};
grpc_server_credentials *ssl_creds =
grpc_ssl_server_credentials_create(NULL, &pem_cert_key_pair, 1);
chttp2_init_server_secure_fullstack(f, server_args, ssl_creds);
}

@ -99,8 +99,7 @@ void chttp2_tear_down_secure_fullstack(grpc_end2end_test_fixture *f) {
static void chttp2_init_client_simple_ssl_with_oauth2_secure_fullstack(
grpc_end2end_test_fixture *f, grpc_channel_args *client_args) {
grpc_credentials *ssl_creds = grpc_ssl_credentials_create(
test_root_cert, test_root_cert_size, NULL, 0, NULL, 0);
grpc_credentials *ssl_creds = grpc_ssl_credentials_create(test_root_cert, NULL);
grpc_credentials *oauth2_creds =
grpc_fake_oauth2_credentials_create("Bearer aaslkfjs424535asdf", 1);
grpc_credentials *ssl_oauth2_creds =
@ -118,9 +117,10 @@ static void chttp2_init_client_simple_ssl_with_oauth2_secure_fullstack(
static void chttp2_init_server_simple_ssl_secure_fullstack(
grpc_end2end_test_fixture *f, grpc_channel_args *server_args) {
grpc_server_credentials *ssl_creds = grpc_ssl_server_credentials_create(
NULL, 0, test_server1_key, test_server1_key_size, test_server1_cert,
test_server1_cert_size);
grpc_ssl_pem_key_cert_pair pem_key_cert_pair = {test_server1_key,
test_server1_cert};
grpc_server_credentials *ssl_creds =
grpc_ssl_server_credentials_create(NULL, &pem_key_cert_pair, 1);
chttp2_init_server_secure_fullstack(f, server_args, ssl_creds);
}

@ -101,9 +101,10 @@ int main(int argc, char **argv) {
cq = grpc_completion_queue_create();
if (secure) {
grpc_server_credentials *ssl_creds = grpc_ssl_server_credentials_create(
NULL, 0, test_server1_key, test_server1_key_size, test_server1_cert,
test_server1_cert_size);
grpc_ssl_pem_key_cert_pair pem_key_cert_pair = {test_server1_key,
test_server1_cert};
grpc_server_credentials *ssl_creds =
grpc_ssl_server_credentials_create(NULL, &pem_key_cert_pair, 1);
server = grpc_secure_server_create(ssl_creds, cq, NULL);
GPR_ASSERT(grpc_server_add_secure_http2_port(server, addr));
grpc_server_credentials_release(ssl_creds);

@ -37,6 +37,7 @@
#include <errno.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <poll.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -79,7 +80,7 @@ static void create_test_socket(int port, int *socket_fd,
/* Use local address for test */
sin->sin_family = AF_INET;
sin->sin_addr.s_addr = 0;
sin->sin_addr.s_addr = htonl(0x7f000001);
sin->sin_port = htons(port);
}
@ -164,7 +165,7 @@ static void session_read_cb(void *arg, /*session*/
grpc_fd_notify_on_read(se->em_fd, session_read_cb, se);
} else {
gpr_log(GPR_ERROR, "Unhandled read error %s", strerror(errno));
GPR_ASSERT(0);
abort();
}
}
}
@ -316,7 +317,7 @@ static void client_session_write(void *arg, /*client*/
gpr_mu_unlock(&cl->mu);
} else {
gpr_log(GPR_ERROR, "unknown errno %s", strerror(errno));
GPR_ASSERT(0);
abort();
}
}
@ -325,10 +326,20 @@ static void client_start(client *cl, int port) {
int fd;
struct sockaddr_in sin;
create_test_socket(port, &fd, &sin);
if (connect(fd, (struct sockaddr *)&sin, sizeof(sin)) == -1 &&
errno != EINPROGRESS) {
gpr_log(GPR_ERROR, "Failed to connect to the server");
GPR_ASSERT(0);
if (connect(fd, (struct sockaddr *)&sin, sizeof(sin)) == -1) {
if (errno == EINPROGRESS) {
struct pollfd pfd;
pfd.fd = fd;
pfd.events = POLLOUT;
pfd.revents = 0;
if (poll(&pfd, 1, -1) == -1) {
gpr_log(GPR_ERROR, "poll() failed during connect; errno=%d", errno);
abort();
}
} else {
gpr_log(GPR_ERROR, "Failed to connect to the server (errno=%d)", errno);
abort();
}
}
cl->em_fd = grpc_fd_create(fd);

@ -32,6 +32,7 @@
*/
#include "src/core/iomgr/resolve_address.h"
#include "src/core/iomgr/iomgr.h"
#include <grpc/support/log.h>
#include <grpc/support/sync.h>
#include <grpc/support/time.h>
@ -122,7 +123,7 @@ static void test_unparseable_hostports(void) {
int main(int argc, char** argv) {
grpc_test_init(argc, argv);
grpc_iomgr_init();
test_localhost();
test_default_port();
test_missing_default_port();
@ -130,6 +131,6 @@ int main(int argc, char** argv) {
test_ipv6_without_port();
test_invalid_ip_addresses();
test_unparseable_hostports();
grpc_iomgr_shutdown();
return 0;
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save