Merge branch 'master' of github.com:google/grpc into json

Conflicts:
	src/core/security/credentials.c
pull/168/head
Nicolas Noble 10 years ago
commit fee065c1c7
  1. 3
      .gitignore
  2. 6
      INSTALL
  3. 330
      Makefile
  4. 73
      README.md
  5. 58
      build.json
  6. 60
      examples/tips/client.cc
  7. 59
      examples/tips/client.h
  8. 72
      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. 14
      include/grpc/grpc.h
  14. 8
      include/grpc/support/port_platform.h
  15. 2
      src/core/channel/call_op_string.c
  16. 2
      src/core/channel/channel_args.c
  17. 6
      src/core/channel/client_channel.c
  18. 24
      src/core/channel/connected_channel.c
  19. 3
      src/core/httpcli/httpcli.c
  20. 2
      src/core/httpcli/httpcli_security_context.c
  21. 6
      src/core/iomgr/endpoint_pair_posix.c
  22. 6
      src/core/iomgr/fd_posix.c
  23. 4
      src/core/iomgr/pollset.h
  24. 6
      src/core/iomgr/pollset_kick.h
  25. 6
      src/core/iomgr/pollset_kick_posix.c
  26. 45
      src/core/iomgr/pollset_kick_windows.h
  27. 6
      src/core/iomgr/pollset_posix.c
  28. 20
      src/core/iomgr/pollset_windows.c
  29. 54
      src/core/iomgr/pollset_windows.h
  30. 7
      src/core/iomgr/resolve_address.c
  31. 6
      src/core/iomgr/resolve_address.h
  32. 4
      src/core/iomgr/sockaddr_posix.h
  33. 3
      src/core/iomgr/sockaddr_utils.c
  34. 2
      src/core/iomgr/sockaddr_win32.h
  35. 12
      src/core/iomgr/socket_utils_common_posix.c
  36. 16
      src/core/iomgr/socket_utils_posix.c
  37. 6
      src/core/iomgr/tcp_client_posix.c
  38. 8
      src/core/iomgr/tcp_posix.c
  39. 5
      src/core/iomgr/tcp_server.h
  40. 10
      src/core/iomgr/tcp_server_posix.c
  41. 16
      src/core/security/credentials.c
  42. 2
      src/core/security/json_token.c
  43. 2
      src/core/security/secure_endpoint.c
  44. 2
      src/core/security/security_context.c
  45. 16
      src/core/security/server_secure_chttp2.c
  46. 2
      src/core/statistics/census_rpc_stats.c
  47. 2
      src/core/statistics/census_tracing.c
  48. 2
      src/core/support/cmdline.c
  49. 2
      src/core/support/host_port.c
  50. 6
      src/core/support/murmur_hash.c
  51. 32
      src/core/support/string.c
  52. 11
      src/core/support/string.h
  53. 2
      src/core/support/time_posix.c
  54. 11
      src/core/surface/byte_buffer.c
  55. 160
      src/core/surface/call.c
  56. 4
      src/core/surface/channel_create.c
  57. 2
      src/core/surface/client.c
  58. 7
      src/core/surface/completion_queue.c
  59. 2
      src/core/surface/event_string.c
  60. 2
      src/core/surface/lame_client.c
  61. 4
      src/core/surface/secure_channel_create.c
  62. 2
      src/core/surface/server.c
  63. 4
      src/core/transport/chttp2/frame_data.c
  64. 4
      src/core/transport/chttp2/hpack_parser.c
  65. 38
      src/core/transport/chttp2/timeout_encoding.c
  66. 3
      src/core/transport/chttp2/timeout_encoding.h
  67. 8
      src/core/transport/chttp2_transport.c
  68. 1
      src/core/transport/metadata.c
  69. 2
      src/core/transport/stream_op.c
  70. 13
      src/cpp/client/channel.cc
  71. 12
      src/cpp/stream/stream_context.cc
  72. 1
      src/cpp/stream/stream_context.h
  73. 33
      src/node/binding.gyp
  74. 31
      src/node/call.cc
  75. 2
      src/node/call.h
  76. 138
      src/node/client.js
  77. 7
      src/node/examples/math_server.js
  78. 2
      src/node/interop/interop_client.js
  79. 12
      src/node/interop/interop_server.js
  80. 2
      src/node/node_grpc.cc
  81. 4
      src/node/server.cc
  82. 71
      src/node/server.js
  83. 113
      src/node/surface_client.js
  84. 141
      src/node/surface_server.js
  85. 30
      src/node/test/call_test.js
  86. 21
      src/node/test/client_server_test.js
  87. 1
      src/node/test/constant_test.js
  88. 51
      src/node/test/end_to_end_test.js
  89. 17
      src/node/test/interop_sanity_test.js
  90. 8
      src/node/test/math_client_test.js
  91. 32
      src/node/test/server_test.js
  92. 21
      src/php/ext/grpc/call.c
  93. 2
      src/php/ext/grpc/credentials.c
  94. 4
      src/php/ext/grpc/php_grpc.c
  95. 3
      src/php/lib/Grpc/ActiveCall.php
  96. 6
      src/php/tests/unit_tests/CallTest.php
  97. 16
      src/php/tests/unit_tests/EndToEndTest.php
  98. 16
      src/php/tests/unit_tests/SecureEndToEndTest.php
  99. 0
      src/python/__init__.py
  100. 0
      src/python/_framework/__init__.py
  101. Some files were not shown because too many files have changed in this diff Show More

3
.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,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
*******************************
@ -58,7 +58,7 @@ for that particular dependency if you want to reduce the libraries' size.
The recommended version of OpenSSL that provides ALPN support is available
at this URL:
https://www.openssl.org/source/openssl-1.0.2-beta3.tar.gz
https://www.openssl.org/source/openssl-1.0.2.tar.gz
Dependencies to compile and run the tests
@ -101,7 +101,7 @@ A word on OpenSSL
Secure HTTP2 requires to have the TLS extension ALPN (see rfc 7301 and
http://http2.github.io/http2-spec/ section 3.3). Our HTTP2 implementation
relies on OpenSSL's implementation. OpenSSL 1.0.2beta3 is the first version
relies on OpenSSL's implementation. OpenSSL 1.0.2 is the first released version
of OpenSSL that has ALPN support, and this explains our dependency on it.
Note that the Makefile supports compiling only the unsecure elements of grpc,

File diff suppressed because one or more lines are too long

@ -0,0 +1,73 @@
[gRPC - An RPC library and framework](http://github.com/google/grpc)
===================================
Copyright 2015 Google Inc.
#Installation
See grpc/INSTALL for installation instructions for various platforms.
#Overview
Remote Procedure Calls (RPCs) provide a useful abstraction for building
distributed applications and services. The libraries in this repository
provide a concrete implementation of the gRPC protocol, layered over HTTP/2.
These libraries enable communication between clients and servers using any
combination of the supported languages.
##Interface
Developers using gRPC typically start with the description of an RPC service
(a collection of methods), and generate client and server side interfaces
which they use on the client-side and implement on the server side.
By default, gRPC uses [Protocol Buffers](github.com/google/protobuf) as the
Interface Definition Language (IDL) for describing both the service interface
and the structure of the payload messages. It is possible to use other
alternatives if desired.
###Surface API
Starting from an interface definition in a .proto file, gRPC provides
Protocol Compiler plugins that generate Client- and Server-side APIs.
gRPC users typically call into these APIs on the Client side and implement
the corresponding API on the server side.
#### Synchronous vs. asynchronous
Synchronous RPC calls, that block until a response arrives from the server, are
the closest approximation to the abstraction of a procedure call that RPC
aspires to.
On the other hand, networks are inherently asynchronous and in many scenarios,
it is desirable to have the ability to start RPCs without blocking the current
thread.
The gRPC programming surface in most languages comes in both synchronous and
asynchronous flavors.
## Streaming
gRPC supports streaming semantics, where either the client or the server (or both)
send a stream of messages on a single RPC call. The most general case is
Bidirectional Streaming where a single gRPC call establishes a stream where both
the client and the server can send a stream of messages to each other. The streamed
messages are delivered in the order they were sent.
#Protocol
The gRPC protocol specifies the abstract requirements for communication between
clients and servers. A concrete embedding over HTTP/2 completes the picture by
fleshing out the details of each of the required operations.
## Abstract gRPC protocol
A gRPC RPC comprises of a bidirectional stream of messages, initiated by the client. In the client-to-server direction, this stream begins with a mandatory `Call Header`, followed by optional `Initial-Metadata`, followed by zero or more `Payload Messages`. The server-to-client direction contains an optional `Initial-Metadata`, followed by zero or more `Payload Messages` terminated with a mandatory `Status` and optional `Status-Metadata` (a.k.a.,`Trailing-Metadata`).
## Implementation over HTTP/2
The abstract protocol defined above is implemented over [HTTP/2](https://http2.github.io/). gRPC bidirectional streams are mapped to HTTP/2 streams. The contents of `Call Header` and `Initial Metadata` are sent as HTTP/2 headers and subject to HPAC compression. `Payload Messages` are serialized into a byte stream of length prefixed gRPC frames which are then fragmented into HTTP/2 frames at the sender and reassembled at the receiver. `Status` and `Trailing-Metadata` are sent as HTTP/2 trailing headers (a.k.a., trailers).
## Flow Control
gRPC inherits the flow control mchanims in HTTP/2 and uses them to enable fine-grained control of the amount of memory used for buffering in-flight messages.

@ -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,7 +128,8 @@
"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/resolve_address_posix.c",
"src/core/iomgr/pollset_windows.c",
"src/core/iomgr/resolve_address.c",
"src/core/iomgr/sockaddr_utils.c",
"src/core/iomgr/socket_utils_common_posix.c",
"src/core/iomgr/socket_utils_linux.c",
@ -403,12 +406,28 @@
"build": "private",
"language": "c++",
"src": [
"test/cpp/util/messages.proto",
"test/cpp/util/echo.proto",
"test/cpp/util/echo_duplicate.proto",
"test/cpp/util/messages.proto",
"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": [
@ -1494,6 +1513,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

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

@ -0,0 +1,72 @@
/*
*
* 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_int32(server_port, 443, "Server port.");
DEFINE_string(server_host,
"pubsub-staging.googleapis.com", "Server host to connect to");
int main(int argc, char** argv) {
grpc_init();
google::ParseCommandLineFlags(&argc, &argv, true);
gpr_log(GPR_INFO, "Start TIPS client");
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,
true, // enable SSL
true)); // use prod roots
grpc::examples::tips::Client client(channel);
grpc::Status s = client.CreateTopic("test");
gpr_log(GPR_INFO, "return code %d", s.code());
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);
}

@ -158,6 +158,7 @@ typedef struct grpc_byte_buffer grpc_byte_buffer;
/* Sample helpers to obtain byte buffers (these will certainly move place */
grpc_byte_buffer *grpc_byte_buffer_create(gpr_slice *slices, size_t nslices);
grpc_byte_buffer *grpc_byte_buffer_copy(grpc_byte_buffer *bb);
size_t grpc_byte_buffer_length(grpc_byte_buffer *bb);
void grpc_byte_buffer_destroy(grpc_byte_buffer *byte_buffer);
@ -313,18 +314,14 @@ grpc_call_error grpc_call_add_metadata(grpc_call *call, grpc_metadata *metadata,
flags is a bit-field combination of the write flags defined above.
REQUIRES: Can be called at most once per call.
Can only be called on the client.
Produces a GRPC_INVOKE_ACCEPTED event with invoke_accepted_tag when the
call has been invoked (meaning bytes can start flowing to the wire).
Produces a GRPC_CLIENT_METADATA_READ event with metadata_read_tag when
the servers initial metadata has been read.
Produces a GRPC_FINISHED event with finished_tag when the call has been
completed (there may be other events for the call pending at this
time) */
grpc_call_error grpc_call_start_invoke(grpc_call *call,
grpc_completion_queue *cq,
void *invoke_accepted_tag,
void *metadata_read_tag,
void *finished_tag, gpr_uint32 flags);
grpc_call_error grpc_call_invoke(grpc_call *call, grpc_completion_queue *cq,
void *metadata_read_tag, void *finished_tag,
gpr_uint32 flags);
/* Accept an incoming RPC, binding a completion queue to it.
To be called before sending or receiving messages.
@ -428,7 +425,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);

@ -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;

@ -37,8 +37,8 @@
#include <stdio.h>
#include <string.h>
#include "src/core/support/string.h"
#include <grpc/support/alloc.h>
#include <grpc/support/string.h>
#include <grpc/support/useful.h>
#define MAX_APPEND 1024

@ -33,9 +33,9 @@
#include <grpc/grpc.h>
#include "src/core/channel/channel_args.h"
#include "src/core/support/string.h"
#include <grpc/support/alloc.h>
#include <grpc/support/string.h>
#include <string.h>

@ -40,9 +40,9 @@
#include "src/core/channel/connected_channel.h"
#include "src/core/channel/metadata_buffer.h"
#include "src/core/iomgr/iomgr.h"
#include "src/core/support/string.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string.h>
#include <grpc/support/sync.h>
#include <grpc/support/useful.h>
@ -410,7 +410,7 @@ static void init_channel_elem(grpc_channel_element *elem,
grpc_mdctx *metadata_context, int is_first,
int is_last) {
channel_data *chand = elem->channel_data;
char temp[16];
char temp[GPR_LTOA_MIN_BUFSIZE];
GPR_ASSERT(!is_first);
GPR_ASSERT(is_last);
@ -425,7 +425,7 @@ static void init_channel_elem(grpc_channel_element *elem,
chand->transport_setup_initiated = 0;
chand->args = grpc_channel_args_copy(args);
sprintf(temp, "%d", GRPC_STATUS_CANCELLED);
gpr_ltoa(GRPC_STATUS_CANCELLED, temp);
chand->cancel_status =
grpc_mdelem_from_strings(metadata_context, "grpc-status", temp);
}

@ -37,12 +37,12 @@
#include <stdio.h>
#include <string.h>
#include "src/core/support/string.h"
#include "src/core/transport/transport.h"
#include <grpc/byte_buffer.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/slice_buffer.h>
#include <grpc/support/string.h>
#define MAX_BUFFER_LENGTH 8192
/* the protobuf library will (by default) start warning at 100megs */
@ -384,23 +384,25 @@ static void recv_batch(void *user_data, grpc_transport *transport,
case GRPC_OP_BEGIN_MESSAGE:
/* can't begin a message when we're still reading a message */
if (calld->reading_message) {
char message[128];
sprintf(message,
char *message = NULL;
gpr_asprintf(&message,
"Message terminated early; read %d bytes, expected %d",
(int)calld->incoming_message.length,
(int)calld->incoming_message_length);
recv_error(chand, calld, __LINE__, message);
gpr_free(message);
return;
}
/* stash away parameters, and prepare for incoming slices */
length = stream_op->data.begin_message.length;
if (length > calld->max_message_length) {
char message[128];
sprintf(
message,
char *message = NULL;
gpr_asprintf(
&message,
"Maximum message length of %d exceeded by a message of length %d",
calld->max_message_length, length);
recv_error(chand, calld, __LINE__, message);
gpr_free(message);
} else if (length > 0) {
calld->reading_message = 1;
calld->incoming_message_length = length;
@ -423,12 +425,13 @@ static void recv_batch(void *user_data, grpc_transport *transport,
gpr_slice_buffer_add(&calld->incoming_message, stream_op->data.slice);
if (calld->incoming_message.length > calld->incoming_message_length) {
/* if we got too many bytes, complain */
char message[128];
sprintf(message,
char *message = NULL;
gpr_asprintf(&message,
"Receiving message overflow; read %d bytes, expected %d",
(int)calld->incoming_message.length,
(int)calld->incoming_message_length);
recv_error(chand, calld, __LINE__, message);
gpr_free(message);
return;
} else if (calld->incoming_message.length ==
calld->incoming_message_length) {
@ -441,8 +444,9 @@ static void recv_batch(void *user_data, grpc_transport *transport,
final_state == GRPC_STREAM_CLOSED)) {
calld->got_read_close = 1;
if (calld->reading_message) {
char message[128];
sprintf(message, "Last message truncated; read %d bytes, expected %d",
char *message = NULL;
gpr_asprintf(&message,
"Last message truncated; read %d bytes, expected %d",
(int)calld->incoming_message.length,
(int)calld->incoming_message_length);
recv_error(chand, calld, __LINE__, message);

@ -31,6 +31,7 @@
*
*/
#include "src/core/iomgr/sockaddr.h"
#include "src/core/httpcli/httpcli.h"
#include <string.h>
@ -44,9 +45,9 @@
#include "src/core/security/security_context.h"
#include "src/core/security/google_root_certs.h"
#include "src/core/security/secure_transport_setup.h"
#include "src/core/support/string.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string.h>
typedef struct {
gpr_slice request_text;

@ -36,9 +36,9 @@
#include <string.h>
#include "src/core/security/secure_transport_setup.h"
#include "src/core/support/string.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string.h>
#include "src/core/tsi/ssl_transport_security.h"
typedef struct {

@ -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 */

@ -31,22 +31,8 @@
*
*/
var net = require('net');
#include <grpc/support/port_platform.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());
});
});
}
#ifdef GPR_WIN32
exports.nextAvailablePort = nextAvailablePort;
#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_ */

@ -33,20 +33,17 @@
#define _POSIX_SOURCE
#include "src/core/iomgr/sockaddr.h"
#include "src/core/iomgr/resolve_address.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include <string.h>
#include "src/core/iomgr/iomgr_internal.h"
#include "src/core/iomgr/sockaddr_utils.h"
#include "src/core/iomgr/socket_utils_posix.h"
#include "src/core/support/string.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string.h>
#include <grpc/support/thd.h>
#include <grpc/support/time.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;

@ -34,7 +34,11 @@
#ifndef __GRPC_INTERNAL_IOMGR_SOCKADDR_POSIX_H_
#define __GRPC_INTERNAL_IOMGR_SOCKADDR_POSIX_H_
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <unistd.h>
#endif /* __GRPC_INTERNAL_IOMGR_SOCKADDR_POSIX_H_ */

@ -33,12 +33,11 @@
#include "src/core/iomgr/sockaddr_utils.h"
#include <arpa/inet.h>
#include <errno.h>
#include <string.h>
#include "src/core/support/string.h"
#include <grpc/support/host_port.h>
#include <grpc/support/string.h>
#include <grpc/support/log.h>
#include <grpc/support/port_platform.h>

@ -34,4 +34,6 @@
#ifndef __GRPC_INTERNAL_IOMGR_SOCKADDR_WIN32_H_
#define __GRPC_INTERNAL_IOMGR_SOCKADDR_WIN32_H_
#include <ws2tcpip.h>
#endif // __GRPC_INTERNAL_IOMGR_SOCKADDR_WIN32_H_

@ -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>
@ -46,8 +50,8 @@
#include <errno.h>
#include "src/core/iomgr/sockaddr_utils.h"
#include "src/core/support/string.h"
#include <grpc/support/host_port.h>
#include <grpc/support/string.h>
#include <grpc/support/log.h>
#include <grpc/support/port_platform.h>
#include <grpc/support/sync.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) {
if (nonblock) {
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 (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>
@ -40,10 +44,10 @@
#include <sys/socket.h>
#include <unistd.h>
#include "src/core/support/string.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/slice.h>
#include <grpc/support/string.h>
#include <grpc/support/sync.h>
#include <grpc/support/time.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

@ -36,9 +36,9 @@
#include "src/core/httpcli/httpcli.h"
#include "src/core/iomgr/iomgr.h"
#include "src/core/security/json_token.h"
#include "src/core/support/string.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string.h>
#include <grpc/support/sync.h>
#include <grpc/support/time.h>
@ -355,7 +355,6 @@ grpc_oauth2_token_fetcher_credentials_parse_server_response(
grpc_json *token_type = NULL;
grpc_json *expires_in = NULL;
grpc_json *ptr;
size_t new_access_token_size = 0;
json = grpc_json_parse_string(null_terminated_body);
if (json == NULL) {
gpr_log(GPR_ERROR, "Could not parse JSON from %s", null_terminated_body);
@ -391,12 +390,9 @@ grpc_oauth2_token_fetcher_credentials_parse_server_response(
status = GRPC_CREDENTIALS_ERROR;
goto end;
}
new_access_token_size =
strlen(token_type->value) + 1 + strlen(access_token->value) + 1;
new_access_token = gpr_malloc(new_access_token_size);
/* C89 does not have snprintf :(. */
sprintf(new_access_token, "%s %s", token_type->value, access_token->value);
token_lifetime->tv_sec = strtol(expires_in->value, NULL, 10);
gpr_asprintf(&new_access_token, "%s %s", token_type->value,
access_token->value);
token_lifetime->tv_sec = expires_in->valueint;
token_lifetime->tv_nsec = 0;
if (*token_elem != NULL) grpc_mdelem_unref(*token_elem);
*token_elem = grpc_mdelem_from_strings(ctx, GRPC_AUTHORIZATION_METADATA_KEY,
@ -545,9 +541,7 @@ static void service_account_fetch_oauth2(
response_cb(metadata_req, &response);
return;
}
body = gpr_malloc(strlen(GRPC_SERVICE_ACCOUNT_POST_BODY_PREFIX) +
strlen(jwt) + 1);
sprintf(body, "%s%s", GRPC_SERVICE_ACCOUNT_POST_BODY_PREFIX, jwt);
gpr_asprintf(&body, "%s%s", GRPC_SERVICE_ACCOUNT_POST_BODY_PREFIX, jwt);
memset(&request, 0, sizeof(grpc_httpcli_request));
request.host = GRPC_SERVICE_ACCOUNT_HOST;
request.path = GRPC_SERVICE_ACCOUNT_TOKEN_PATH;

@ -37,9 +37,9 @@
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string.h>
#include "src/core/security/base64.h"
#include "src/core/support/string.h"
#include <openssl/bio.h>
#include <openssl/evp.h>

@ -32,11 +32,11 @@
*/
#include "src/core/security/secure_endpoint.h"
#include "src/core/support/string.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/slice_buffer.h>
#include <grpc/support/slice.h>
#include <grpc/support/string.h>
#include <grpc/support/sync.h>
#include "src/core/tsi/transport_security_interface.h"

@ -39,12 +39,12 @@
#include "src/core/channel/http_client_filter.h"
#include "src/core/security/credentials.h"
#include "src/core/security/secure_endpoint.h"
#include "src/core/support/string.h"
#include "src/core/surface/lame_client.h"
#include "src/core/transport/chttp2/alpn.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/slice_buffer.h>
#include <grpc/support/string.h>
#include "src/core/tsi/fake_transport_security.h"
#include "src/core/tsi/ssl_transport_security.h"

@ -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:

@ -39,9 +39,9 @@
#include "src/core/statistics/census_tracing.h"
#include "src/core/statistics/window_stats.h"
#include "src/core/support/murmur_hash.h"
#include "src/core/support/string.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string.h>
#include <grpc/support/sync.h>
#define NUM_INTERVALS 3

@ -38,10 +38,10 @@
#include "src/core/statistics/census_rpc_stats.h"
#include "src/core/statistics/hash_table.h"
#include "src/core/support/string.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/port_platform.h>
#include <grpc/support/string.h>
#include <grpc/support/sync.h>
#include <grpc/support/time.h>

@ -37,9 +37,9 @@
#include <stdio.h>
#include <string.h>
#include "src/core/support/string.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string.h>
typedef enum { ARGTYPE_INT, ARGTYPE_BOOL, ARGTYPE_STRING } argtype;

@ -35,8 +35,8 @@
#include <string.h>
#include "src/core/support/string.h"
#include <grpc/support/log.h>
#include <grpc/support/string.h>
int gpr_join_host_port(char **out, const char *host, int port) {
if (host[0] != '[' && strchr(host, ':') != NULL) {

@ -52,7 +52,7 @@ gpr_uint32 gpr_murmur_hash3(const void *key, size_t len, gpr_uint32 seed) {
int i;
gpr_uint32 h1 = seed;
gpr_uint32 k1 = 0;
gpr_uint32 k1;
const gpr_uint32 c1 = 0xcc9e2d51;
const gpr_uint32 c2 = 0x1b873593;
@ -62,7 +62,7 @@ gpr_uint32 gpr_murmur_hash3(const void *key, size_t len, gpr_uint32 seed) {
/* body */
for (i = -nblocks; i; i++) {
gpr_uint32 k1 = GETBLOCK32(blocks, i);
k1 = GETBLOCK32(blocks, i);
k1 *= c1;
k1 = ROTL32(k1, 15);
@ -73,6 +73,8 @@ gpr_uint32 gpr_murmur_hash3(const void *key, size_t len, gpr_uint32 seed) {
h1 = h1 * 5 + 0xe6546b64;
}
k1 = 0;
/* tail */
switch (len & 3) {
case 3:

@ -31,7 +31,7 @@
*
*/
#include <grpc/support/string.h>
#include "src/core/support/string.h"
#include <ctype.h>
#include <stddef.h>
@ -122,3 +122,33 @@ int gpr_parse_bytes_to_uint32(const char *buf, size_t len, gpr_uint32 *result) {
*result = out;
return 1;
}
void gpr_reverse_bytes(char *str, int len) {
char *p1, *p2;
for (p1 = str, p2 = str + len - 1; p2 > p1; ++p1, --p2) {
char temp = *p1;
*p1 = *p2;
*p2 = temp;
}
}
int gpr_ltoa(long value, char *string) {
int i = 0;
int neg = value < 0;
if (value == 0) {
string[0] = '0';
string[1] = 0;
return 1;
}
if (neg) value = -value;
while (value) {
string[i++] = '0' + value % 10;
value /= 10;
}
if (neg) string[i++] = '-';
gpr_reverse_bytes(string, i);
string[i] = 0;
return i;
}

@ -60,6 +60,17 @@ char *gpr_hexdump(const char *buf, size_t len, gpr_uint32 flags);
int gpr_parse_bytes_to_uint32(const char *data, size_t length,
gpr_uint32 *result);
/* Minimum buffer size for calling ltoa */
#define GPR_LTOA_MIN_BUFSIZE (3 * sizeof(long))
/* Convert a long to a string in base 10; returns the length of the
output string (or 0 on failure).
output must be at least GPR_LTOA_MIN_BUFSIZE bytes long. */
int gpr_ltoa(long value, char *output);
/* Reverse a run of bytes */
void gpr_reverse_bytes(char *str, int len);
/* printf to a newly-allocated string. The set of supported formats may vary
between platforms.

@ -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

@ -49,6 +49,17 @@ grpc_byte_buffer *grpc_byte_buffer_create(gpr_slice *slices, size_t nslices) {
return bb;
}
grpc_byte_buffer *grpc_byte_buffer_copy(grpc_byte_buffer *bb) {
switch (bb->type) {
case GRPC_BB_SLICE_BUFFER:
return grpc_byte_buffer_create(bb->data.slice_buffer.slices,
bb->data.slice_buffer.count);
}
gpr_log(GPR_INFO, "should never get here");
abort();
return NULL;
}
void grpc_byte_buffer_destroy(grpc_byte_buffer *bb) {
switch (bb->type) {
case GRPC_BB_SLICE_BUFFER:

@ -35,11 +35,11 @@
#include "src/core/channel/channel_stack.h"
#include "src/core/channel/metadata_buffer.h"
#include "src/core/iomgr/alarm.h"
#include "src/core/support/string.h"
#include "src/core/surface/channel.h"
#include "src/core/surface/completion_queue.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string.h>
#include <stdio.h>
#include <stdlib.h>
@ -173,11 +173,14 @@ struct grpc_call {
/* protects variables in this section */
gpr_mu read_mu;
gpr_uint8 received_start;
gpr_uint8 start_ok;
gpr_uint8 reads_done;
gpr_uint8 received_finish;
gpr_uint8 received_metadata;
gpr_uint8 have_read;
gpr_uint8 have_alarm;
gpr_uint8 pending_writes_done;
gpr_uint8 got_status_code;
/* The current outstanding read message tag (only valid if have_read == 1) */
void *read_tag;
@ -190,6 +193,8 @@ struct grpc_call {
/* The current outstanding send message/context/invoke/end tag (only valid if
have_write == 1) */
void *write_tag;
grpc_byte_buffer *pending_write;
gpr_uint32 pending_write_flags;
/* The final status of the call */
grpc_status_code status_code;
@ -227,11 +232,15 @@ grpc_call *grpc_call_create(grpc_channel *channel,
call->have_alarm = 0;
call->received_metadata = 0;
call->got_status_code = 0;
call->start_ok = 0;
call->status_code =
server_transport_data != NULL ? GRPC_STATUS_OK : GRPC_STATUS_UNKNOWN;
call->status_details = NULL;
call->received_finish = 0;
call->reads_done = 0;
call->received_start = 0;
call->pending_write = NULL;
call->pending_writes_done = 0;
grpc_metadata_buffer_init(&call->incoming_metadata);
gpr_ref_init(&call->internal_refcount, 1);
grpc_call_stack_init(channel_stack, server_transport_data,
@ -360,16 +369,6 @@ grpc_call_error grpc_call_add_metadata(grpc_call *call, grpc_metadata *metadata,
return GRPC_CALL_OK;
}
static void done_invoke(void *user_data, grpc_op_error error) {
grpc_call *call = user_data;
void *tag = call->write_tag;
GPR_ASSERT(call->have_write);
call->have_write = 0;
call->write_tag = INVALID_TAG;
grpc_cq_end_invoke_accepted(call->cq, tag, call, NULL, NULL, error);
}
static void finish_call(grpc_call *call) {
size_t count;
grpc_metadata *elements;
@ -384,11 +383,81 @@ static void finish_call(grpc_call *call) {
elements, count);
}
grpc_call_error grpc_call_start_invoke(grpc_call *call,
grpc_completion_queue *cq,
void *invoke_accepted_tag,
void *metadata_read_tag,
void *finished_tag, gpr_uint32 flags) {
static void done_write(void *user_data, grpc_op_error error) {
grpc_call *call = user_data;
void *tag = call->write_tag;
GPR_ASSERT(call->have_write);
call->have_write = 0;
call->write_tag = INVALID_TAG;
grpc_cq_end_write_accepted(call->cq, tag, call, NULL, NULL, error);
}
static void done_writes_done(void *user_data, grpc_op_error error) {
grpc_call *call = user_data;
void *tag = call->write_tag;
GPR_ASSERT(call->have_write);
call->have_write = 0;
call->write_tag = INVALID_TAG;
grpc_cq_end_finish_accepted(call->cq, tag, call, NULL, NULL, error);
}
static void call_started(void *user_data, grpc_op_error error) {
grpc_call *call = user_data;
grpc_call_element *elem;
grpc_byte_buffer *pending_write = NULL;
gpr_uint32 pending_write_flags = 0;
gpr_uint8 pending_writes_done = 0;
int ok;
grpc_call_op op;
gpr_mu_lock(&call->read_mu);
GPR_ASSERT(!call->received_start);
call->received_start = 1;
ok = call->start_ok = (error == GRPC_OP_OK);
pending_write = call->pending_write;
pending_write_flags = call->pending_write_flags;
pending_writes_done = call->pending_writes_done;
gpr_mu_unlock(&call->read_mu);
if (pending_write) {
if (ok) {
op.type = GRPC_SEND_MESSAGE;
op.dir = GRPC_CALL_DOWN;
op.flags = pending_write_flags;
op.done_cb = done_write;
op.user_data = call;
op.data.message = pending_write;
elem = CALL_ELEM_FROM_CALL(call, 0);
elem->filter->call_op(elem, NULL, &op);
} else {
done_write(call, error);
}
grpc_byte_buffer_destroy(pending_write);
}
if (pending_writes_done) {
if (ok) {
op.type = GRPC_SEND_FINISH;
op.dir = GRPC_CALL_DOWN;
op.flags = 0;
op.done_cb = done_writes_done;
op.user_data = call;
elem = CALL_ELEM_FROM_CALL(call, 0);
elem->filter->call_op(elem, NULL, &op);
} else {
done_writes_done(call, error);
}
}
grpc_call_internal_unref(call);
}
grpc_call_error grpc_call_invoke(grpc_call *call, grpc_completion_queue *cq,
void *metadata_read_tag, void *finished_tag,
gpr_uint32 flags) {
grpc_call_element *elem;
grpc_call_op op;
@ -420,7 +489,6 @@ grpc_call_error grpc_call_start_invoke(grpc_call *call,
/* inform the completion queue of an incoming operation */
grpc_cq_begin_op(cq, call, GRPC_FINISHED);
grpc_cq_begin_op(cq, call, GRPC_CLIENT_METADATA_READ);
grpc_cq_begin_op(cq, call, GRPC_INVOKE_ACCEPTED);
gpr_mu_lock(&call->read_mu);
@ -431,8 +499,6 @@ grpc_call_error grpc_call_start_invoke(grpc_call *call,
if (call->received_finish) {
/* handle early cancellation */
grpc_cq_end_invoke_accepted(call->cq, invoke_accepted_tag, call, NULL, NULL,
GRPC_OP_ERROR);
grpc_cq_end_client_metadata_read(call->cq, metadata_read_tag, call, NULL,
NULL, 0, NULL);
finish_call(call);
@ -442,20 +508,18 @@ grpc_call_error grpc_call_start_invoke(grpc_call *call,
return GRPC_CALL_OK;
}
call->write_tag = invoke_accepted_tag;
call->metadata_tag = metadata_read_tag;
call->have_write = 1;
gpr_mu_unlock(&call->read_mu);
/* call down the filter stack */
op.type = GRPC_SEND_START;
op.dir = GRPC_CALL_DOWN;
op.flags = flags;
op.done_cb = done_invoke;
op.done_cb = call_started;
op.data.start.pollset = grpc_cq_pollset(cq);
op.user_data = call;
grpc_call_internal_ref(call);
elem = CALL_ELEM_FROM_CALL(call, 0);
elem->filter->call_op(elem, NULL, &op);
@ -486,6 +550,7 @@ grpc_call_error grpc_call_server_accept(grpc_call *call,
call->state = CALL_BOUNDCQ;
call->cq = cq;
call->finished_tag = finished_tag;
call->received_start = 1;
if (prq_is_empty(&call->prq) && call->received_finish) {
finish_call(call);
@ -535,26 +600,6 @@ grpc_call_error grpc_call_server_end_initial_metadata(grpc_call *call,
return GRPC_CALL_OK;
}
static void done_writes_done(void *user_data, grpc_op_error error) {
grpc_call *call = user_data;
void *tag = call->write_tag;
GPR_ASSERT(call->have_write);
call->have_write = 0;
call->write_tag = INVALID_TAG;
grpc_cq_end_finish_accepted(call->cq, tag, call, NULL, NULL, error);
}
static void done_write(void *user_data, grpc_op_error error) {
grpc_call *call = user_data;
void *tag = call->write_tag;
GPR_ASSERT(call->have_write);
call->have_write = 0;
call->write_tag = INVALID_TAG;
grpc_cq_end_write_accepted(call->cq, tag, call, NULL, NULL, error);
}
void grpc_call_client_initial_metadata_complete(
grpc_call_element *surface_element) {
grpc_call *call = grpc_call_from_top_element(surface_element);
@ -617,7 +662,7 @@ grpc_call_error grpc_call_start_read(grpc_call *call, void *tag) {
} else {
call->read_tag = tag;
call->have_read = 1;
request_more = 1;
request_more = call->received_start;
}
} else if (prq_is_empty(&call->prq) && call->received_finish) {
finish_call(call);
@ -654,8 +699,6 @@ grpc_call_error grpc_call_start_write(grpc_call *call,
grpc_cq_begin_op(call->cq, call, GRPC_WRITE_ACCEPTED);
/* for now we do no buffering, so a NULL byte_buffer can have no impact
on our behavior -- succeed immediately */
/* TODO(ctiller): if flags & GRPC_WRITE_BUFFER_HINT == 0, this indicates a
flush, and that flush should be propogated down from here */
if (byte_buffer == NULL) {
@ -666,6 +709,15 @@ grpc_call_error grpc_call_start_write(grpc_call *call,
call->write_tag = tag;
call->have_write = 1;
gpr_mu_lock(&call->read_mu);
if (!call->received_start) {
call->pending_write = grpc_byte_buffer_copy(byte_buffer);
call->pending_write_flags = flags;
gpr_mu_unlock(&call->read_mu);
} else {
gpr_mu_unlock(&call->read_mu);
op.type = GRPC_SEND_MESSAGE;
op.dir = GRPC_CALL_DOWN;
op.flags = flags;
@ -675,6 +727,7 @@ grpc_call_error grpc_call_start_write(grpc_call *call,
elem = CALL_ELEM_FROM_CALL(call, 0);
elem->filter->call_op(elem, NULL, &op);
}
return GRPC_CALL_OK;
}
@ -706,6 +759,14 @@ grpc_call_error grpc_call_writes_done(grpc_call *call, void *tag) {
call->write_tag = tag;
call->have_write = 1;
gpr_mu_lock(&call->read_mu);
if (!call->received_start) {
call->pending_writes_done = 1;
gpr_mu_unlock(&call->read_mu);
} else {
gpr_mu_unlock(&call->read_mu);
op.type = GRPC_SEND_FINISH;
op.dir = GRPC_CALL_DOWN;
op.flags = 0;
@ -714,6 +775,7 @@ grpc_call_error grpc_call_writes_done(grpc_call *call, void *tag) {
elem = CALL_ELEM_FROM_CALL(call, 0);
elem->filter->call_op(elem, NULL, &op);
}
return GRPC_CALL_OK;
}
@ -760,8 +822,8 @@ grpc_call_error grpc_call_start_write_status(grpc_call *call,
/* always send status */
{
grpc_mdelem *md;
char buffer[32];
sprintf(buffer, "%d", status);
char buffer[GPR_LTOA_MIN_BUFSIZE];
gpr_ltoa(status, buffer);
md =
grpc_mdelem_from_strings(call->metadata_context, "grpc-status", buffer);
@ -818,6 +880,8 @@ void grpc_call_recv_metadata(grpc_call_element *elem, grpc_call_op *op) {
grpc_call *call = CALL_FROM_TOP_ELEM(elem);
grpc_mdelem *md = op->data.metadata;
grpc_mdstr *key = md->key;
gpr_log(GPR_DEBUG, "call %p got metadata %s %s", call,
grpc_mdstr_as_c_string(md->key), grpc_mdstr_as_c_string(md->value));
if (key == grpc_channel_get_status_string(call->channel)) {
maybe_set_status_code(call, decode_status(md));
grpc_mdelem_unref(md);

@ -31,6 +31,8 @@
*
*/
#include "src/core/iomgr/sockaddr.h"
#include <grpc/grpc.h>
#include <stdlib.h>
@ -48,10 +50,10 @@
#include "src/core/iomgr/tcp_client.h"
#include "src/core/surface/channel.h"
#include "src/core/surface/client.h"
#include "src/core/support/string.h"
#include "src/core/transport/chttp2_transport.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string.h>
#include <grpc/support/sync.h>
#include <grpc/support/useful.h>

@ -34,9 +34,9 @@
#include "src/core/surface/client.h"
#include "src/core/surface/call.h"
#include "src/core/support/string.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string.h>
typedef struct { void *unused; } call_data;

@ -37,13 +37,13 @@
#include <string.h>
#include "src/core/iomgr/pollset.h"
#include "src/core/support/string.h"
#include "src/core/surface/call.h"
#include "src/core/surface/event_string.h"
#include "src/core/surface/surface_trace.h"
#include <grpc/support/alloc.h>
#include <grpc/support/atm.h>
#include <grpc/support/log.h>
#include <grpc/support/string.h>
#define NUM_TAG_BUCKETS 31
@ -396,12 +396,13 @@ void grpc_event_finish(grpc_event *base) {
void grpc_cq_dump_pending_ops(grpc_completion_queue *cc) {
#ifndef NDEBUG
char tmp[256];
char tmp[GRPC_COMPLETION_DO_NOT_USE * (1 + GPR_LTOA_MIN_BUFSIZE)];
char *p = tmp;
int i;
for (i = 0; i < GRPC_COMPLETION_DO_NOT_USE; i++) {
p += sprintf(p, " %d", (int)cc->pending_op_count[i]);
*p++ = ' ';
p += gpr_ltoa(cc->pending_op_count[i], p);
}
gpr_log(GPR_INFO, "pending ops:%s", tmp);

@ -35,7 +35,7 @@
#include <stdio.h>
#include <grpc/support/string.h>
#include "src/core/support/string.h"
#include <grpc/byte_buffer.h>
static size_t addhdr(char *p, grpc_event *ev) {

@ -36,11 +36,11 @@
#include <string.h>
#include "src/core/channel/channel_stack.h"
#include "src/core/support/string.h"
#include "src/core/surface/channel.h"
#include "src/core/surface/call.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string.h>
typedef struct { void *unused; } call_data;

@ -31,6 +31,8 @@
*
*/
#include "src/core/iomgr/sockaddr.h"
#include <grpc/grpc.h>
#include <stdlib.h>
@ -48,13 +50,13 @@
#include "src/core/security/auth.h"
#include "src/core/security/security_context.h"
#include "src/core/security/secure_transport_setup.h"
#include "src/core/support/string.h"
#include "src/core/surface/channel.h"
#include "src/core/surface/client.h"
#include "src/core/transport/chttp2_transport.h"
#include <grpc/grpc_security.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string.h>
#include <grpc/support/sync.h>
#include <grpc/support/useful.h>
#include "src/core/tsi/transport_security_interface.h"

@ -40,12 +40,12 @@
#include "src/core/channel/channel_args.h"
#include "src/core/channel/connected_channel.h"
#include "src/core/iomgr/iomgr.h"
#include "src/core/support/string.h"
#include "src/core/surface/call.h"
#include "src/core/surface/channel.h"
#include "src/core/surface/completion_queue.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string.h>
#include <grpc/support/useful.h>
typedef enum { PENDING_START, ALL_CALLS, CALL_LIST_COUNT } call_list;

@ -35,9 +35,9 @@
#include <string.h>
#include "src/core/support/string.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string.h>
#include <grpc/support/useful.h>
#include "src/core/transport/transport.h"
@ -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,

@ -38,10 +38,10 @@
#include <assert.h>
#include "src/core/transport/chttp2/bin_encoder.h"
#include "src/core/support/string.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/port_platform.h>
#include <grpc/support/string.h>
#include <grpc/support/useful.h>
typedef enum {
@ -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);

@ -36,6 +36,8 @@
#include <stdio.h>
#include <string.h>
#include "src/core/support/string.h"
static int round_up(int x, int divisor) {
return (x / divisor + (x % divisor != 0)) * divisor;
}
@ -53,15 +55,21 @@ static int round_up_to_three_sig_figs(int x) {
}
/* encode our minimum viable timeout value */
static void enc_tiny(char *buffer) { strcpy(buffer, "1n"); }
static void enc_tiny(char *buffer) { memcpy(buffer, "1n", 3); }
static void enc_ext(char *buffer, long value, char ext) {
int n = gpr_ltoa(value, buffer);
buffer[n] = ext;
buffer[n+1] = 0;
}
static void enc_seconds(char *buffer, long sec) {
if (sec % 3600 == 0) {
sprintf(buffer, "%ldH", sec / 3600);
enc_ext(buffer, sec / 3600, 'H');
} else if (sec % 60 == 0) {
sprintf(buffer, "%ldM", sec / 60);
enc_ext(buffer, sec / 60, 'M');
} else {
sprintf(buffer, "%ldS", sec);
enc_ext(buffer, sec, 'S');
}
}
@ -69,23 +77,23 @@ static void enc_nanos(char *buffer, int x) {
x = round_up_to_three_sig_figs(x);
if (x < 100000) {
if (x % 1000 == 0) {
sprintf(buffer, "%du", x / 1000);
enc_ext(buffer, x / 1000, 'u');
} else {
sprintf(buffer, "%dn", x);
enc_ext(buffer, x, 'n');
}
} else if (x < 100000000) {
if (x % 1000000 == 0) {
sprintf(buffer, "%dm", x / 1000000);
enc_ext(buffer, x / 1000000, 'm');
} else {
sprintf(buffer, "%du", x / 1000);
enc_ext(buffer, x / 1000, 'u');
}
} else if (x < 1000000000) {
sprintf(buffer, "%dm", x / 1000000);
enc_ext(buffer, x / 1000000, 'm');
} else {
/* note that this is only ever called with times of less than one second,
so if we reach here the time must have been rounded up to a whole second
(and no more) */
strcpy(buffer, "1S");
memcpy(buffer, "1S", 3);
}
}
@ -93,18 +101,18 @@ static void enc_micros(char *buffer, int x) {
x = round_up_to_three_sig_figs(x);
if (x < 100000) {
if (x % 1000 == 0) {
sprintf(buffer, "%dm", x / 1000);
enc_ext(buffer, x / 1000, 'm');
} else {
sprintf(buffer, "%du", x);
enc_ext(buffer, x, 'u');
}
} else if (x < 100000000) {
if (x % 1000000 == 0) {
sprintf(buffer, "%dS", x / 1000000);
enc_ext(buffer, x / 1000000, 'S');
} else {
sprintf(buffer, "%dm", x / 1000);
enc_ext(buffer, x / 1000, 'm');
}
} else {
sprintf(buffer, "%dS", x / 1000000);
enc_ext(buffer, x / 1000000, 'S');
}
}

@ -34,8 +34,11 @@
#ifndef __GRPC_INTERNAL_TRANSPORT_CHTTP2_TIMEOUT_ENCODING_H_
#define __GRPC_INTERNAL_TRANSPORT_CHTTP2_TIMEOUT_ENCODING_H_
#include "src/core/support/string.h"
#include <grpc/support/time.h>
#define GRPC_CHTTP2_TIMEOUT_ENCODE_MIN_BUFSIZE (GPR_LTOA_MIN_BUFSIZE + 1)
/* Encode/decode timeouts to the GRPC over HTTP2 format;
encoding may round up arbitrarily */
void grpc_chttp2_encode_timeout(gpr_timespec timeout, char *buffer);

@ -37,6 +37,7 @@
#include <stdio.h>
#include <string.h>
#include "src/core/support/string.h"
#include "src/core/transport/chttp2/frame_data.h"
#include "src/core/transport/chttp2/frame_goaway.h"
#include "src/core/transport/chttp2/frame_ping.h"
@ -53,7 +54,6 @@
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/slice_buffer.h>
#include <grpc/support/string.h>
#include <grpc/support/useful.h>
#define DEFAULT_WINDOW 65535
@ -1002,7 +1002,7 @@ static void cancel_stream_inner(transport *t, stream *s, gpr_uint32 id,
grpc_chttp2_error_code error_code,
int send_rst) {
int had_outgoing;
char buffer[32];
char buffer[GPR_LTOA_MIN_BUFSIZE];
if (s) {
/* clear out any unreported input & output: nobody cares anymore */
@ -1015,7 +1015,7 @@ static void cancel_stream_inner(transport *t, stream *s, gpr_uint32 id,
s->cancelled = 1;
stream_list_join(t, s, CANCELLED);
sprintf(buffer, "%d", local_status);
gpr_ltoa(local_status, buffer);
grpc_sopb_add_metadata(
&s->parser.incoming_sopb,
grpc_mdelem_from_strings(t->metadata_context, "grpc-status", buffer));
@ -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),

@ -31,6 +31,7 @@
*
*/
#include "src/core/iomgr/sockaddr.h"
#include "src/core/transport/metadata.h"
#include <stddef.h>

@ -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:

@ -104,7 +104,6 @@ Status Channel::StartBlockingRpc(const RpcMethod &method,
context->set_call(call);
grpc_event *ev;
void *finished_tag = reinterpret_cast<char *>(call);
void *invoke_tag = reinterpret_cast<char *>(call) + 1;
void *metadata_read_tag = reinterpret_cast<char *>(call) + 2;
void *write_tag = reinterpret_cast<char *>(call) + 3;
void *halfclose_tag = reinterpret_cast<char *>(call) + 4;
@ -115,19 +114,11 @@ Status Channel::StartBlockingRpc(const RpcMethod &method,
// add_metadata from context
//
// invoke
GPR_ASSERT(grpc_call_start_invoke(call, cq, invoke_tag, metadata_read_tag,
finished_tag,
GPR_ASSERT(grpc_call_invoke(call, cq, metadata_read_tag, finished_tag,
GRPC_WRITE_BUFFER_HINT) == GRPC_CALL_OK);
ev = grpc_completion_queue_pluck(cq, invoke_tag, gpr_inf_future);
bool success = ev->data.invoke_accepted == GRPC_OP_OK;
grpc_event_finish(ev);
if (!success) {
GetFinalStatus(cq, finished_tag, &status);
return status;
}
// write request
grpc_byte_buffer *write_buffer = nullptr;
success = SerializeProto(request, &write_buffer);
bool success = SerializeProto(request, &write_buffer);
if (!success) {
grpc_call_cancel(call);
status =

@ -80,17 +80,9 @@ void StreamContext::Start(bool buffered) {
if (is_client_) {
// TODO(yangg) handle metadata send path
int flag = buffered ? GRPC_WRITE_BUFFER_HINT : 0;
grpc_call_error error = grpc_call_start_invoke(call(), cq(), invoke_tag(),
client_metadata_read_tag(),
finished_tag(), flag);
grpc_call_error error = grpc_call_invoke(
call(), cq(), client_metadata_read_tag(), finished_tag(), flag);
GPR_ASSERT(GRPC_CALL_OK == error);
grpc_event *invoke_ev =
grpc_completion_queue_pluck(cq(), invoke_tag(), gpr_inf_future);
if (invoke_ev->data.invoke_accepted != GRPC_OP_OK) {
peer_halfclosed_ = true;
self_halfclosed_ = true;
}
grpc_event_finish(invoke_ev);
} else {
// TODO(yangg) metadata needs to be added before accept
// TODO(yangg) correctly set flag to accept

@ -76,7 +76,6 @@ class StreamContext final : public StreamContextInterface {
void *read_tag() { return reinterpret_cast<char *>(this) + 1; }
void *write_tag() { return reinterpret_cast<char *>(this) + 2; }
void *halfclose_tag() { return reinterpret_cast<char *>(this) + 3; }
void *invoke_tag() { return reinterpret_cast<char *>(this) + 4; }
void *client_metadata_read_tag() {
return reinterpret_cast<char *>(this) + 5;
}

@ -1,8 +1,13 @@
{
"variables" : {
'no_install': "<!(echo $GRPC_NO_INSTALL)",
'grpc_root': "<!(echo $GRPC_ROOT)",
'grpc_lib_subdir': "<!(echo $GRPC_LIB_SUBDIR)"
},
"targets" : [
{
'include_dirs': [
"<!(node -e \"require('nan')\")"
"<!(nodejs -e \"require('nan')\")"
],
'cxxflags': [
'-Wall',
@ -13,14 +18,11 @@
'-Werror',
],
'ldflags': [
'-g',
'-L/usr/local/google/home/mlumish/grpc_dev/lib'
'-g'
],
'link_settings': {
'libraries': [
'-lgrpc',
'-lrt',
'-lgpr',
'-lpthread'
],
},
@ -37,6 +39,27 @@
"server_credentials.cc",
"tag.cc",
"timeval.cc"
],
'conditions' : [
['no_install=="yes"', {
'include_dirs': [
"<(grpc_root)/include"
],
'link_settings': {
'libraries': [
'<(grpc_root)/<(grpc_lib_subdir)/libgrpc.a',
'<(grpc_root)/<(grpc_lib_subdir)/libgpr.a'
]
}
}],
['no_install!="yes"', {
'link_settings': {
'libraries': [
'-lgrpc',
'-lgpr'
]
}
}]
]
}
]

@ -78,8 +78,8 @@ void Call::Init(Handle<Object> exports) {
tpl->InstanceTemplate()->SetInternalFieldCount(1);
NanSetPrototypeTemplate(tpl, "addMetadata",
FunctionTemplate::New(AddMetadata)->GetFunction());
NanSetPrototypeTemplate(tpl, "startInvoke",
FunctionTemplate::New(StartInvoke)->GetFunction());
NanSetPrototypeTemplate(tpl, "invoke",
FunctionTemplate::New(Invoke)->GetFunction());
NanSetPrototypeTemplate(tpl, "serverAccept",
FunctionTemplate::New(ServerAccept)->GetFunction());
NanSetPrototypeTemplate(
@ -203,37 +203,30 @@ NAN_METHOD(Call::AddMetadata) {
NanReturnUndefined();
}
NAN_METHOD(Call::StartInvoke) {
NAN_METHOD(Call::Invoke) {
NanScope();
if (!HasInstance(args.This())) {
return NanThrowTypeError("startInvoke can only be called on Call objects");
return NanThrowTypeError("invoke can only be called on Call objects");
}
if (!args[0]->IsFunction()) {
return NanThrowTypeError("StartInvoke's first argument must be a function");
return NanThrowTypeError("invoke's first argument must be a function");
}
if (!args[1]->IsFunction()) {
return NanThrowTypeError(
"StartInvoke's second argument must be a function");
}
if (!args[2]->IsFunction()) {
return NanThrowTypeError("StartInvoke's third argument must be a function");
return NanThrowTypeError("invoke's second argument must be a function");
}
if (!args[3]->IsUint32()) {
return NanThrowTypeError(
"StartInvoke's fourth argument must be integer flags");
if (!args[2]->IsUint32()) {
return NanThrowTypeError("invoke's third argument must be integer flags");
}
Call *call = ObjectWrap::Unwrap<Call>(args.This());
unsigned int flags = args[3]->Uint32Value();
grpc_call_error error = grpc_call_start_invoke(
grpc_call_error error = grpc_call_invoke(
call->wrapped_call, CompletionQueueAsyncWorker::GetQueue(),
CreateTag(args[0], args.This()), CreateTag(args[1], args.This()),
CreateTag(args[2], args.This()), flags);
CreateTag(args[0], args.This()), CreateTag(args[1], args.This()), flags);
if (error == GRPC_CALL_OK) {
CompletionQueueAsyncWorker::Next();
CompletionQueueAsyncWorker::Next();
CompletionQueueAsyncWorker::Next();
} else {
return NanThrowError("startInvoke failed", error);
return NanThrowError("invoke failed", error);
}
NanReturnUndefined();
}
@ -281,7 +274,7 @@ NAN_METHOD(Call::ServerEndInitialMetadata) {
NAN_METHOD(Call::Cancel) {
NanScope();
if (!HasInstance(args.This())) {
return NanThrowTypeError("startInvoke can only be called on Call objects");
return NanThrowTypeError("cancel can only be called on Call objects");
}
Call *call = ObjectWrap::Unwrap<Call>(args.This());
grpc_call_error error = grpc_call_cancel(call->wrapped_call);

@ -61,7 +61,7 @@ class Call : public ::node::ObjectWrap {
static NAN_METHOD(New);
static NAN_METHOD(AddMetadata);
static NAN_METHOD(StartInvoke);
static NAN_METHOD(Invoke);
static NAN_METHOD(ServerAccept);
static NAN_METHOD(ServerEndInitialMetadata);
static NAN_METHOD(Cancel);

@ -45,106 +45,96 @@ 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;
var finished = false;
// Indicates that a read is currently pending
var reading = false;
// Indicates that we can call startWrite
var can_write = false;
// Indicates that a write is currently pending
var writing = false;
this._call = call;
/**
* Callback to handle receiving a READ event. Pushes the data from that event
* onto the read queue and starts reading again if applicable.
* @param {grpc.Event} event The READ event object
* 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
*/
function readCallback(event) {
var data = event.data;
if (self.push(data)) {
if (data == null) {
// Disable starting to read after null read was received
can_read = false;
reading = false;
} else {
call.startRead(readCallback);
}
} else {
// Indicate that reading can be resumed by calling startReading
reading = false;
this.serialize = function(value) {
if (value === null || value === undefined) {
return null;
}
return serialize(value);
};
/**
* Initiate a read, which continues until self.push returns false (indicating
* that reading should be paused) or data is null (indicating that there is no
* more data to read).
* 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
*/
function startReading() {
call.startRead(readCallback);
this.deserialize = function(buffer) {
if (buffer === null) {
return null;
}
// TODO(mlumish): possibly change queue implementation due to shift slowness
var write_queue = [];
return deserialize(buffer);
};
/**
* Write the next chunk of data in the write queue if there is one. Otherwise
* indicate that there is no pending write. When the write succeeds, this
* function is called again.
* Callback to be called when a READ event is received. Pushes the data onto
* the read queue and starts reading again if applicable
* @param {grpc.Event} event READ event object
*/
function writeNext() {
if (write_queue.length > 0) {
writing = true;
var next = write_queue.shift();
var writeCallback = function(event) {
next.callback();
writeNext();
};
call.startWrite(next.chunk, writeCallback, 0);
function readCallback(event) {
if (finished) {
self.push(null);
return;
}
var data = event.data;
if (self.push(self.deserialize(data)) && data != null) {
self._call.startRead(readCallback);
} else {
writing = false;
reading = false;
}
}
call.startInvoke(function(event) {
can_read = true;
can_write = true;
startReading();
writeNext();
}, function(event) {
call.invoke(function(event) {
self.emit('metadata', event.data);
}, function(event) {
finished = true;
self.emit('status', event.data);
}, 0);
this.on('finish', function() {
call.writesDone(function() {});
});
/**
* Indicate that reads should start, and start them if the INVOKE_ACCEPTED
* event has been received.
* Start reading if there is not already a pending read. Reading will
* continue until self.push returns false (indicating reads should slow
* down) or the read data is null (indicating that there is no more data).
*/
this._enableRead = function() {
this.startReading = function() {
if (finished) {
self.push(null);
} else {
if (!reading) {
reading = true;
if (can_read) {
startReading();
self._call.startRead(readCallback);
}
}
};
/**
* Push the chunk onto the write queue, and write from the write queue if
* there is not a pending write
* @param {Buffer} chunk The chunk of data to write
* @param {function(Error=)} callback The callback to call when the write
* completes
*/
this._tryWrite = function(chunk, callback) {
write_queue.push({chunk: chunk, callback: callback});
if (can_write && !writing) {
writeNext();
}
};
}
/**
@ -153,7 +143,7 @@ function GrpcClientStream(call, options) {
* @param {number} size Ignored
*/
GrpcClientStream.prototype._read = function(size) {
this._enableRead();
this.startReading();
};
/**
@ -164,13 +154,19 @@ GrpcClientStream.prototype._read = function(size) {
* @param {function(Error=)} callback Ignored
*/
GrpcClientStream.prototype._write = function(chunk, encoding, callback) {
this._tryWrite(chunk, callback);
var self = this;
self._call.startWrite(self.serialize(chunk), function(event) {
callback();
}, 0);
};
/**
* 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 +174,8 @@ GrpcClientStream.prototype._write = function(chunk, encoding, callback) {
*/
function makeRequest(channel,
method,
serialize,
deserialize,
metadata,
deadline) {
if (deadline === undefined) {
@ -187,7 +185,7 @@ function makeRequest(channel,
if (metadata) {
call.addMetadata(metadata);
}
return new GrpcClientStream(call);
return new GrpcClientStream(call, serialize, deserialize);
}
/**

@ -52,7 +52,8 @@ var Server = grpc.buildServer([math.Math.service]);
*/
function mathDiv(call, cb) {
var req = call.request;
if (req.divisor == 0) {
// Unary + is explicit coersion to integer
if (+req.divisor === 0) {
cb(new Error('cannot divide by zero'));
}
cb(null, {
@ -89,7 +90,7 @@ function mathSum(call, cb) {
// Here, call is a standard readable Node object Stream
var sum = 0;
call.on('data', function(data) {
sum += data.num | 0;
sum += (+data.num);
});
call.on('end', function() {
cb(null, {num: sum});
@ -104,7 +105,7 @@ function mathDivMany(stream) {
Transform.call(this, options);
}
DivTransform.prototype._transform = function(div_args, encoding, callback) {
if (div_args.divisor == 0) {
if (+div_args.divisor === 0) {
callback(new Error('cannot divide by zero'));
}
callback(null, {

@ -183,7 +183,7 @@ function pingPong(client, done) {
assert.equal(response.payload.body.limit - response.payload.body.offset,
response_sizes[index]);
index += 1;
if (index == 4) {
if (index === 4) {
call.end();
} else {
call.write({

@ -157,7 +157,8 @@ function handleHalfDuplex(call) {
* 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 object bound to the support
* @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
@ -183,8 +184,8 @@ function getServer(port, tls) {
halfDuplexCall: handleHalfDuplex
}
}, options);
server.bind('0.0.0.0:' + port, tls);
return server;
var port_num = server.bind('0.0.0.0:' + port, tls);
return {server: server, port: port_num};
}
if (require.main === module) {
@ -192,8 +193,9 @@ if (require.main === module) {
var argv = parseArgs(process.argv, {
string: ['port', 'use_tls']
});
var server = getServer(argv.port, argv.use_tls === 'true');
server.start();
var server_obj = getServer(argv.port, argv.use_tls === 'true');
console.log('Server attaching to port ' + argv.port);
server_obj.server.listen();
}
/**

@ -148,8 +148,6 @@ void InitCompletionTypeConstants(Handle<Object> exports) {
completion_type->Set(NanNew("QUEUE_SHUTDOWN"), QUEUE_SHUTDOWN);
Handle<Value> READ(NanNew<Uint32, uint32_t>(GRPC_READ));
completion_type->Set(NanNew("READ"), READ);
Handle<Value> INVOKE_ACCEPTED(NanNew<Uint32, uint32_t>(GRPC_INVOKE_ACCEPTED));
completion_type->Set(NanNew("INVOKE_ACCEPTED"), INVOKE_ACCEPTED);
Handle<Value> WRITE_ACCEPTED(NanNew<Uint32, uint32_t>(GRPC_WRITE_ACCEPTED));
completion_type->Set(NanNew("WRITE_ACCEPTED"), WRITE_ACCEPTED);
Handle<Value> FINISH_ACCEPTED(NanNew<Uint32, uint32_t>(GRPC_FINISH_ACCEPTED));

@ -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(self.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);
};
@ -195,7 +233,7 @@ function Server(options) {
function handleNewCall(event) {
var call = event.call;
var data = event.data;
if (data == null) {
if (data === null) {
return;
}
server.requestCall(handleNewCall);
@ -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);
}
};

@ -63,114 +63,70 @@ util.inherits(ClientReadableObjectStream, Readable);
* client side. Extends from stream.Readable.
* @constructor
* @param {stream} stream Underlying binary Duplex stream for the call
* @param {function(Buffer)} deserialize Function for deserializing binary data
* @param {object} options Stream options
*/
function ClientReadableObjectStream(stream, deserialize, options) {
options = _.extend(options, {objectMode: true});
function ClientReadableObjectStream(stream) {
var options = {objectMode: true};
Readable.call(this, options);
this._stream = stream;
var self = this;
forwardEvent(stream, this, 'status');
forwardEvent(stream, this, 'metadata');
this._stream.on('data', function forwardData(chunk) {
if (!self.push(deserialize(chunk))) {
if (!self.push(chunk)) {
self._stream.pause();
}
});
this._stream.pause();
}
util.inherits(ClientWritableObjectStream, Writable);
/**
* Class for representing a gRPC client streaming call as a Node stream on the
* client side. Extends from stream.Writable.
* @constructor
* @param {stream} stream Underlying binary Duplex stream for the call
* @param {function(*):Buffer} serialize Function for serializing objects
* @param {object} options Stream options
* _read implementation for both types of streams that allow reading.
* @this {ClientReadableObjectStream}
* @param {number} size Ignored
*/
function ClientWritableObjectStream(stream, serialize, options) {
options = _.extend(options, {objectMode: true});
Writable.call(this, options);
this._stream = stream;
this._serialize = serialize;
forwardEvent(stream, this, 'status');
forwardEvent(stream, this, 'metadata');
this.on('finish', function() {
this._stream.end();
});
function _read(size) {
this._stream.resume();
}
/**
* See docs for _read
*/
ClientReadableObjectStream.prototype._read = _read;
util.inherits(ClientBidiObjectStream, Duplex);
util.inherits(ClientWritableObjectStream, Writable);
/**
* Class for representing a gRPC bidi streaming call as a Node stream on the
* client side. Extends from stream.Duplex.
* Class for representing a gRPC client streaming call as a Node stream on the
* client side. Extends from stream.Writable.
* @constructor
* @param {stream} stream Underlying binary Duplex stream for the call
* @param {function(*):Buffer} serialize Function for serializing objects
* @param {function(Buffer)} deserialize Function for deserializing binary data
* @param {object} options Stream options
*/
function ClientBidiObjectStream(stream, serialize, deserialize, options) {
options = _.extend(options, {objectMode: true});
Duplex.call(this, options);
function ClientWritableObjectStream(stream) {
var options = {objectMode: true};
Writable.call(this, options);
this._stream = stream;
this._serialize = serialize;
var self = this;
forwardEvent(stream, this, 'status');
forwardEvent(stream, this, 'metadata');
this._stream.on('data', function forwardData(chunk) {
if (!self.push(deserialize(chunk))) {
self._stream.pause();
}
});
this._stream.pause();
this.on('finish', function() {
this._stream.end();
});
}
/**
* _read implementation for both types of streams that allow reading.
* @this {ClientReadableObjectStream|ClientBidiObjectStream}
* @param {number} size Ignored
*/
function _read(size) {
this._stream.resume();
}
/**
* See docs for _read
*/
ClientReadableObjectStream.prototype._read = _read;
/**
* See docs for _read
*/
ClientBidiObjectStream.prototype._read = _read;
/**
* _write implementation for both types of streams that allow writing
* @this {ClientWritableObjectStream|ClientBidiObjectStream}
* @this {ClientWritableObjectStream}
* @param {*} chunk The value to write to the stream
* @param {string} encoding Ignored
* @param {function(Error)} callback Callback to call when finished writing
*/
function _write(chunk, encoding, callback) {
this._stream.write(this._serialize(chunk), encoding, callback);
this._stream.write(chunk, encoding, callback);
}
/**
* See docs for _write
*/
ClientWritableObjectStream.prototype._write = _write;
/**
* See docs for _write
*/
ClientBidiObjectStream.prototype._write = _write;
/**
* Get a function that can make unary requests to the specified method.
@ -196,15 +152,16 @@ function makeUnaryRequestFunction(method, serialize, deserialize) {
* @return {EventEmitter} An event emitter for stream related events
*/
function makeUnaryRequest(argument, callback, metadata, deadline) {
var stream = client.makeRequest(this.channel, method, metadata, deadline);
var stream = client.makeRequest(this.channel, method, serialize,
deserialize, metadata, deadline);
var emitter = new EventEmitter();
forwardEvent(stream, emitter, 'status');
forwardEvent(stream, emitter, 'metadata');
stream.write(serialize(argument));
stream.write(argument);
stream.end();
stream.on('data', function forwardData(chunk) {
try {
callback(null, deserialize(chunk));
callback(null, chunk);
} catch (e) {
callback(e);
}
@ -236,11 +193,12 @@ function makeClientStreamRequestFunction(method, serialize, deserialize) {
* @return {EventEmitter} An event emitter for stream related events
*/
function makeClientStreamRequest(callback, metadata, deadline) {
var stream = client.makeRequest(this.channel, method, metadata, deadline);
var obj_stream = new ClientWritableObjectStream(stream, serialize, {});
var stream = client.makeRequest(this.channel, method, serialize,
deserialize, metadata, deadline);
var obj_stream = new ClientWritableObjectStream(stream);
stream.on('data', function forwardData(chunk) {
try {
callback(null, deserialize(chunk));
callback(null, chunk);
} catch (e) {
callback(e);
}
@ -272,9 +230,10 @@ function makeServerStreamRequestFunction(method, serialize, deserialize) {
* @return {EventEmitter} An event emitter for stream related events
*/
function makeServerStreamRequest(argument, metadata, deadline) {
var stream = client.makeRequest(this.channel, method, metadata, deadline);
var obj_stream = new ClientReadableObjectStream(stream, deserialize, {});
stream.write(serialize(argument));
var stream = client.makeRequest(this.channel, method, serialize,
deserialize, metadata, deadline);
var obj_stream = new ClientReadableObjectStream(stream);
stream.write(argument);
stream.end();
return obj_stream;
}
@ -301,12 +260,8 @@ function makeBidiStreamRequestFunction(method, serialize, deserialize) {
* @return {EventEmitter} An event emitter for stream related events
*/
function makeBidiStreamRequest(metadata, deadline) {
var stream = client.makeRequest(this.channel, method, metadata, deadline);
var obj_stream = new ClientBidiObjectStream(stream,
serialize,
deserialize,
{});
return obj_stream;
return client.makeRequest(this.channel, method, serialize,
deserialize, metadata, deadline);
}
return makeBidiStreamRequest;
}

@ -54,11 +54,9 @@ util.inherits(ServerReadableObjectStream, Readable);
* server side. Extends from stream.Readable.
* @constructor
* @param {stream} stream Underlying binary Duplex stream for the call
* @param {function(Buffer)} deserialize Function for deserializing binary data
* @param {object} options Stream options
*/
function ServerReadableObjectStream(stream, deserialize, options) {
options = _.extend(options, {objectMode: true});
function ServerReadableObjectStream(stream) {
var options = {objectMode: true};
Readable.call(this, options);
this._stream = stream;
Object.defineProperty(this, 'cancelled', {
@ -66,7 +64,7 @@ function ServerReadableObjectStream(stream, deserialize, options) {
});
var self = this;
this._stream.on('data', function forwardData(chunk) {
if (!self.push(deserialize(chunk))) {
if (!self.push(chunk)) {
self._stream.pause();
}
});
@ -76,57 +74,6 @@ function ServerReadableObjectStream(stream, deserialize, options) {
this._stream.pause();
}
util.inherits(ServerWritableObjectStream, Writable);
/**
* Class for representing a gRPC server streaming call as a Node stream on the
* server side. Extends from stream.Writable.
* @constructor
* @param {stream} stream Underlying binary Duplex stream for the call
* @param {function(*):Buffer} serialize Function for serializing objects
* @param {object} options Stream options
*/
function ServerWritableObjectStream(stream, serialize, options) {
options = _.extend(options, {objectMode: true});
Writable.call(this, options);
this._stream = stream;
this._serialize = serialize;
this.on('finish', function() {
this._stream.end();
});
}
util.inherits(ServerBidiObjectStream, Duplex);
/**
* Class for representing a gRPC bidi streaming call as a Node stream on the
* server side. Extends from stream.Duplex.
* @constructor
* @param {stream} stream Underlying binary Duplex stream for the call
* @param {function(*):Buffer} serialize Function for serializing objects
* @param {function(Buffer)} deserialize Function for deserializing binary data
* @param {object} options Stream options
*/
function ServerBidiObjectStream(stream, serialize, deserialize, options) {
options = _.extend(options, {objectMode: true});
Duplex.call(this, options);
this._stream = stream;
this._serialize = serialize;
var self = this;
this._stream.on('data', function forwardData(chunk) {
if (!self.push(deserialize(chunk))) {
self._stream.pause();
}
});
this._stream.on('end', function forwardEnd() {
self.push(null);
});
this._stream.pause();
this.on('finish', function() {
this._stream.end();
});
}
/**
* _read implementation for both types of streams that allow reading.
* @this {ServerReadableObjectStream|ServerBidiObjectStream}
@ -140,39 +87,46 @@ function _read(size) {
* See docs for _read
*/
ServerReadableObjectStream.prototype._read = _read;
util.inherits(ServerWritableObjectStream, Writable);
/**
* See docs for _read
* Class for representing a gRPC server streaming call as a Node stream on the
* server side. Extends from stream.Writable.
* @constructor
* @param {stream} stream Underlying binary Duplex stream for the call
*/
ServerBidiObjectStream.prototype._read = _read;
function ServerWritableObjectStream(stream) {
var options = {objectMode: true};
Writable.call(this, options);
this._stream = stream;
this.on('finish', function() {
this._stream.end();
});
}
/**
* _write implementation for both types of streams that allow writing
* @this {ServerWritableObjectStream|ServerBidiObjectStream}
* @this {ServerWritableObjectStream}
* @param {*} chunk The value to write to the stream
* @param {string} encoding Ignored
* @param {function(Error)} callback Callback to call when finished writing
*/
function _write(chunk, encoding, callback) {
this._stream.write(this._serialize(chunk), encoding, callback);
this._stream.write(chunk, encoding, callback);
}
/**
* See docs for _write
*/
ServerWritableObjectStream.prototype._write = _write;
/**
* See docs for _write
*/
ServerBidiObjectStream.prototype._write = _write;
/**
* Creates a binary stream handler function from a unary handler function
* @param {function(Object, function(Error, *))} handler Unary call handler
* @param {function(*):Buffer} serialize Serialization function
* @param {function(Buffer):*} deserialize Deserialization function
* @return {function(stream)} Binary stream handler
*/
function makeUnaryHandler(handler, serialize, deserialize) {
function makeUnaryHandler(handler) {
/**
* Handles a stream by reading a single data value, passing it to the handler,
* and writing the response back to the stream.
@ -180,7 +134,7 @@ function makeUnaryHandler(handler, serialize, deserialize) {
*/
return function handleUnaryCall(stream) {
stream.on('data', function handleUnaryData(value) {
var call = {request: deserialize(value)};
var call = {request: value};
Object.defineProperty(call, 'cancelled', {
get: function() { return stream.cancelled;}
});
@ -188,7 +142,7 @@ function makeUnaryHandler(handler, serialize, deserialize) {
if (err) {
stream.emit('error', err);
} else {
stream.write(serialize(value));
stream.write(value);
stream.end();
}
});
@ -201,23 +155,21 @@ function makeUnaryHandler(handler, serialize, deserialize) {
* function
* @param {function(Readable, function(Error, *))} handler Client stream call
* handler
* @param {function(*):Buffer} serialize Serialization function
* @param {function(Buffer):*} deserialize Deserialization function
* @return {function(stream)} Binary stream handler
*/
function makeClientStreamHandler(handler, serialize, deserialize) {
function makeClientStreamHandler(handler) {
/**
* Handles a stream by passing a deserializing stream to the handler and
* writing the response back to the stream.
* @param {stream} stream Binary data stream
*/
return function handleClientStreamCall(stream) {
var object_stream = new ServerReadableObjectStream(stream, deserialize, {});
var object_stream = new ServerReadableObjectStream(stream);
handler(object_stream, function sendClientStreamData(err, value) {
if (err) {
stream.emit('error', err);
} else {
stream.write(serialize(value));
stream.write(value);
stream.end();
}
});
@ -228,11 +180,9 @@ function makeClientStreamHandler(handler, serialize, deserialize) {
* Creates a binary stream handler function from a server stream handler
* function
* @param {function(Writable)} handler Server stream call handler
* @param {function(*):Buffer} serialize Serialization function
* @param {function(Buffer):*} deserialize Deserialization function
* @return {function(stream)} Binary stream handler
*/
function makeServerStreamHandler(handler, serialize, deserialize) {
function makeServerStreamHandler(handler) {
/**
* Handles a stream by attaching it to a serializing stream, and passing it to
* the handler.
@ -240,10 +190,8 @@ function makeServerStreamHandler(handler, serialize, deserialize) {
*/
return function handleServerStreamCall(stream) {
stream.on('data', function handleClientData(value) {
var object_stream = new ServerWritableObjectStream(stream,
serialize,
{});
object_stream.request = deserialize(value);
var object_stream = new ServerWritableObjectStream(stream);
object_stream.request = value;
handler(object_stream);
});
};
@ -252,23 +200,10 @@ function makeServerStreamHandler(handler, serialize, deserialize) {
/**
* Creates a binary stream handler function from a bidi stream handler function
* @param {function(Duplex)} handler Unary call handler
* @param {function(*):Buffer} serialize Serialization function
* @param {function(Buffer):*} deserialize Deserialization function
* @return {function(stream)} Binary stream handler
*/
function makeBidiStreamHandler(handler, serialize, deserialize) {
/**
* Handles a stream by wrapping it in a serializing and deserializing object
* stream, and passing it to the handler.
* @param {stream} stream Binary data stream
*/
return function handleBidiStreamCall(stream) {
var object_stream = new ServerBidiObjectStream(stream,
serialize,
deserialize,
{});
handler(object_stream);
};
function makeBidiStreamHandler(handler) {
return handler;
}
/**
@ -341,10 +276,13 @@ function makeServerConstructor(services) {
common.fullyQualifiedName(method) + ' not provided.');
}
var binary_handler = handler_makers[method_type](
service_handlers[service_name][decapitalize(method.name)],
common.serializeCls(method.resolvedResponseType.build()),
common.deserializeCls(method.resolvedRequestType.build()));
server.register(prefix + capitalize(method.name), binary_handler);
service_handlers[service_name][decapitalize(method.name)]);
var serialize = common.serializeCls(
method.resolvedResponseType.build());
var deserialize = common.deserializeCls(
method.resolvedRequestType.build());
server.register(prefix + capitalize(method.name), binary_handler,
serialize, deserialize);
});
}, this);
}
@ -357,8 +295,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);
};
/**

@ -118,10 +118,9 @@ describe('call', function() {
call.addMetadata(5);
}, TypeError);
});
it('should fail if startInvoke was already called', function(done) {
it('should fail if invoke was already called', function(done) {
var call = new grpc.Call(channel, 'method', getDeadline(1));
call.startInvoke(function() {},
function() {},
call.invoke(function() {},
function() {done();},
0);
assert.throws(function() {
@ -133,30 +132,24 @@ describe('call', function() {
call.cancel();
});
});
describe('startInvoke', function() {
it('should fail with fewer than 4 arguments', function() {
describe('invoke', function() {
it('should fail with fewer than 3 arguments', function() {
var call = new grpc.Call(channel, 'method', getDeadline(1));
assert.throws(function() {
call.startInvoke();
call.invoke();
}, TypeError);
assert.throws(function() {
call.startInvoke(function() {});
call.invoke(function() {});
}, TypeError);
assert.throws(function() {
call.startInvoke(function() {},
function() {});
}, TypeError);
assert.throws(function() {
call.startInvoke(function() {},
function() {},
call.invoke(function() {},
function() {});
}, TypeError);
});
it('should work with 3 args and an int', function(done) {
it('should work with 2 args and an int', function(done) {
assert.doesNotThrow(function() {
var call = new grpc.Call(channel, 'method', getDeadline(1));
call.startInvoke(function() {},
function() {},
call.invoke(function() {},
function() {done();},
0);
// Cancel to speed up the test
@ -166,11 +159,10 @@ describe('call', function() {
it('should reject incorrectly typed arguments', function() {
var call = new grpc.Call(channel, 'method', getDeadline(1));
assert.throws(function() {
call.startInvoke(0, 0, 0, 0);
call.invoke(0, 0, 0);
}, TypeError);
assert.throws(function() {
call.startInvoke(function() {},
function() {},
call.invoke(function() {},
function() {}, 'test');
});
});

@ -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,14 +79,13 @@ 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);
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(port);
var channel = new grpc.Channel('localhost:' + port_num);
var stream = client.makeRequest(
channel,
'echo');
@ -104,15 +102,13 @@ describe('echo client', function() {
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);
var port_num = server.bind('0.0.0.0:0');
server.register('error', errorHandler);
server.start();
var channel = new grpc.Channel(port);
var channel = new grpc.Channel('localhost:' + port_num);
var stream = client.makeRequest(
channel,
'error',
@ -128,15 +124,12 @@ describe('echo client', function() {
server.shutdown();
done();
});
});
});
});
/* TODO(mlumish): explore options for reducing duplication between this test
* and the insecure echo client test */
describe('secure echo client', function() {
it('should recieve echo responses', function(done) {
port_picker.nextAvailablePort(function(port) {
fs.readFile(ca_path, function(err, ca_data) {
assert.ifError(err);
fs.readFile(key_path, function(err, key_data) {
@ -149,12 +142,12 @@ describe('secure echo client', function() {
pem_data);
var server = new Server({'credentials' : server_creds});
server.bind(port, true);
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(port, {
var channel = new grpc.Channel('localhost:' + port_num, {
'grpc.ssl_target_name_override' : 'foo.test.google.com',
'credentials' : creds
});
@ -175,8 +168,6 @@ describe('secure echo client', function() {
done();
});
});
});
});
});
});

@ -94,7 +94,6 @@ var opErrorNames = [
var completionTypeNames = [
'QUEUE_SHUTDOWN',
'READ',
'INVOKE_ACCEPTED',
'WRITE_ACCEPTED',
'FINISH_ACCEPTED',
'CLIENT_METADATA_READ',

@ -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,30 +57,20 @@ 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 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.invoke(function(event) {
assert.strictEqual(event.type,
grpc.completionType.CLIENT_METADATA_READ);
},function(event) {
@ -111,11 +100,13 @@ describe('end-to-end', function() {
done();
});
});
call.writesDone(function(event) {
assert.strictEqual(event.type,
grpc.completionType.FINISH_ACCEPTED);
assert.strictEqual(event.data, grpc.opError.OK);
});
});
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();
@ -123,17 +114,25 @@ describe('end-to-end', function() {
complete();
server.shutdown();
}, 6);
server.addHttp2Port(port);
var channel = new grpc.Channel(port);
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) {
call.invoke(function(event) {
assert.strictEqual(event.type,
grpc.completionType.INVOKE_ACCEPTED);
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);
call.startWrite(
new Buffer(req_text),
function(event) {
@ -152,17 +151,6 @@ describe('end-to-end', function() {
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) {
@ -198,4 +186,3 @@ describe('end-to-end', function() {
});
});
});
});

@ -34,8 +34,6 @@
var interop_server = require('../interop/interop_server.js');
var interop_client = require('../interop/interop_client.js');
var port_picker = require('../port_picker');
var server;
var port;
@ -44,18 +42,18 @@ var name_override = 'foo.test.google.com';
describe('Interop tests', function() {
before(function(done) {
port_picker.nextAvailablePort(function(addr) {
server = interop_server.getServer(addr.substring(addr.indexOf(':') + 1), true);
var server_obj = interop_server.getServer(0, true);
server = server_obj.server;
server.listen();
port = addr;
port = 'localhost:' + server_obj.port;
done();
});
});
// This depends on not using a binary stream
it.skip('should pass empty_unary', function(done) {
it('should pass empty_unary', function(done) {
interop_client.runTest(port, name_override, 'empty_unary', true, done);
});
it('should pass large_unary', function(done) {
// This fails due to an unknown bug
it.skip('should pass large_unary', function(done) {
interop_client.runTest(port, name_override, 'large_unary', true, done);
});
it('should pass client_streaming', function(done) {
@ -67,8 +65,7 @@ describe('Interop tests', function() {
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) {
it('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,12 +49,11 @@ 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);
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();
});

@ -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,24 +67,32 @@ 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);
var port_num = server.bind('[::]:0');
server.register('echo', echoHandler);
server.start();
var req_text = 'echo test string';
var status_text = 'OK';
var channel = new grpc.Channel(port);
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) {
call.invoke(function(event) {
assert.strictEqual(event.type,
grpc.completionType.INVOKE_ACCEPTED);
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);
call.startWrite(
new Buffer(req_text),
function(event) {
@ -104,18 +111,5 @@ describe('echo server', function() {
assert.strictEqual(event.data.toString(), req_text);
done();
});
},function(event) {
assert.strictEqual(event.type,
grpc.completionType.CLIENT_METADATA_READ);
done();
},function(event) {
assert.strictEqual(event.type, grpc.completionType.FINISHED);
var status = event.data;
assert.strictEqual(status.code, grpc.status.OK);
assert.strictEqual(status.details, status_text);
server.shutdown();
done();
}, 0);
});
});
});

@ -224,27 +224,25 @@ PHP_METHOD(Call, add_metadata) {
/**
* Invoke the RPC. Starts sending metadata and request headers over the wire
* @param CompletionQueue $queue The completion queue to use with this call
* @param long $invoke_accepted_tag The tag to associate with this invocation
* @param long $metadata_tag The tag to associate with returned metadata
* @param long $finished_tag The tag to associate with the finished event
* @param long $flags A bitwise combination of the Grpc\WRITE_* constants
* (optional)
* @return Void
*/
PHP_METHOD(Call, start_invoke) {
PHP_METHOD(Call, invoke) {
grpc_call_error error_code;
long tag1;
long tag2;
long tag3;
zval *queue_obj;
long flags = 0;
/* "Olll|l" == 1 Object, 3 mandatory longs, 1 optional long */
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Olll|l", &queue_obj,
grpc_ce_completion_queue, &tag1, &tag2, &tag3,
/* "Oll|l" == 1 Object, 3 mandatory longs, 1 optional long */
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Oll|l", &queue_obj,
grpc_ce_completion_queue, &tag1, &tag2,
&flags) == FAILURE) {
zend_throw_exception(
spl_ce_InvalidArgumentException,
"start_invoke needs a CompletionQueue, 3 longs, and an optional long",
"invoke needs a CompletionQueue, 2 longs, and an optional long",
1 TSRMLS_CC);
return;
}
@ -254,10 +252,9 @@ PHP_METHOD(Call, start_invoke) {
wrapped_grpc_completion_queue *queue =
(wrapped_grpc_completion_queue *)zend_object_store_get_object(
queue_obj TSRMLS_CC);
error_code =
grpc_call_start_invoke(call->wrapped, queue->wrapped, (void *)tag1,
(void *)tag2, (void *)tag3, (gpr_uint32)flags);
MAYBE_THROW_CALL_ERROR(start_invoke, error_code);
error_code = grpc_call_invoke(call->wrapped, queue->wrapped, (void *)tag1,
(void *)tag2, (gpr_uint32)flags);
MAYBE_THROW_CALL_ERROR(invoke, error_code);
}
/**
@ -427,7 +424,7 @@ static zend_function_entry call_methods[] = {
PHP_ME(Call, server_end_initial_metadata, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Call, add_metadata, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Call, cancel, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Call, start_invoke, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Call, invoke, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Call, start_read, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Call, start_write, NULL, ZEND_ACC_PUBLIC)
PHP_ME(Call, start_write_status, NULL, ZEND_ACC_PUBLIC)

@ -81,6 +81,8 @@ PHP_METHOD(Credentials, createSsl) {
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,

@ -107,11 +107,9 @@ PHP_MINIT_FUNCTION(grpc) {
/* Register completion type constants */
REGISTER_LONG_CONSTANT("Grpc\\QUEUE_SHUTDOWN", GRPC_QUEUE_SHUTDOWN, CONST_CS);
REGISTER_LONG_CONSTANT("Grpc\\READ", GRPC_READ, CONST_CS);
REGISTER_LONG_CONSTANT("Grpc\\INVOKE_ACCEPTED", GRPC_INVOKE_ACCEPTED,
CONST_CS);
REGISTER_LONG_CONSTANT("Grpc\\WRITE_ACCEPTED", GRPC_WRITE_ACCEPTED, CONST_CS);
REGISTER_LONG_CONSTANT("Grpc\\FINISH_ACCEPTED", GRPC_FINISH_ACCEPTED,
CONST_CS);
REGISTER_LONG_CONSTANT("Grpc\\WRITE_ACCEPTED", GRPC_WRITE_ACCEPTED, CONST_CS);
REGISTER_LONG_CONSTANT("Grpc\\CLIENT_METADATA_READ",
GRPC_CLIENT_METADATA_READ, CONST_CS);
REGISTER_LONG_CONSTANT("Grpc\\FINISHED", GRPC_FINISHED, CONST_CS);

@ -29,11 +29,8 @@ class ActiveCall {
// Invoke the call.
$this->call->start_invoke($this->completion_queue,
INVOKE_ACCEPTED,
CLIENT_METADATA_READ,
FINISHED, 0);
$this->completion_queue->pluck(INVOKE_ACCEPTED,
Timeval::inf_future());
$metadata_event = $this->completion_queue->pluck(CLIENT_METADATA_READ,
Timeval::inf_future());
$this->metadata = $metadata_event->data;

@ -19,10 +19,10 @@ class CallTest extends PHPUnit_Framework_TestCase{
/**
* @expectedException LogicException
* @expectedExceptionCode Grpc\CALL_ERROR_INVALID_FLAGS
* @expectedExceptionMessage start_invoke
* @expectedExceptionMessage invoke
*/
public function testStartInvokeRejectsBadFlags() {
$this->call->start_invoke($this->cq, 0, 0, 0, 0xDEADBEEF);
public function testInvokeRejectsBadFlags() {
$this->call->invoke($this->cq, 0, 0, 0xDEADBEEF);
}
/**

@ -25,18 +25,12 @@ class EndToEndTest extends PHPUnit_Framework_TestCase{
$deadline);
$tag = 1;
$this->assertEquals(Grpc\CALL_OK,
$call->start_invoke($this->client_queue,
$tag,
$call->invoke($this->client_queue,
$tag,
$tag));
$server_tag = 2;
// the client invocation was accepted
$event = $this->client_queue->next($deadline);
$this->assertNotNull($event);
$this->assertEquals(Grpc\INVOKE_ACCEPTED, $event->type);
$call->writes_done($tag);
$event = $this->client_queue->next($deadline);
$this->assertNotNull($event);
@ -103,18 +97,12 @@ class EndToEndTest extends PHPUnit_Framework_TestCase{
$deadline);
$tag = 1;
$this->assertEquals(Grpc\CALL_OK,
$call->start_invoke($this->client_queue,
$tag,
$call->invoke($this->client_queue,
$tag,
$tag));
$server_tag = 2;
// the client invocation was accepted
$event = $this->client_queue->next($deadline);
$this->assertNotNull($event);
$this->assertEquals(Grpc\INVOKE_ACCEPTED, $event->type);
// the client writes
$call->start_write($req_text, $tag);
$event = $this->client_queue->next($deadline);

@ -37,17 +37,11 @@ class SecureEndToEndTest extends PHPUnit_Framework_TestCase{
$deadline);
$tag = 1;
$this->assertEquals(Grpc\CALL_OK,
$call->start_invoke($this->client_queue,
$tag,
$call->invoke($this->client_queue,
$tag,
$tag));
$server_tag = 2;
// the client invocation was accepted
$event = $this->client_queue->next($deadline);
$this->assertNotNull($event);
$this->assertEquals(Grpc\INVOKE_ACCEPTED, $event->type);
$call->writes_done($tag);
$event = $this->client_queue->next($deadline);
$this->assertNotNull($event);
@ -113,18 +107,12 @@ class SecureEndToEndTest extends PHPUnit_Framework_TestCase{
$deadline);
$tag = 1;
$this->assertEquals(Grpc\CALL_OK,
$call->start_invoke($this->client_queue,
$tag,
$call->invoke($this->client_queue,
$tag,
$tag));
$server_tag = 2;
// the client invocation was accepted
$event = $this->client_queue->next($deadline);
$this->assertNotNull($event);
$this->assertEquals(Grpc\INVOKE_ACCEPTED, $event->type);
// the client writes
$call->start_write($req_text, $tag);
$event = $this->client_queue->next($deadline);

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

Loading…
Cancel
Save