diff options
author | David Garcia Quintas <dgq@google.com> | 2016-05-12 14:28:36 -0700 |
---|---|---|
committer | David Garcia Quintas <dgq@google.com> | 2016-05-12 14:28:36 -0700 |
commit | 6d0b4d20c0dbb9326724343a0c04b52d390e25a4 (patch) | |
tree | c815c2d33c28f0d10112d8239fcf6fe5d6b250ef | |
parent | d9c58961f91d877e760008e2916527b0d56b8826 (diff) | |
parent | a709afe241d8b264a1c326315f757b4a8d330207 (diff) |
Merge branch 'master' of github.com:grpc/grpc into merge
51 files changed, 4407 insertions, 76 deletions
@@ -296,6 +296,7 @@ cc_library( "src/core/ext/client_config/subchannel_call_holder.h", "src/core/ext/client_config/subchannel_index.h", "src/core/ext/client_config/uri_parser.h", + "third_party/objective_c/Cronet/cronet_c_for_grpc.h", "src/core/ext/lb_policy/grpclb/load_balancer_api.h", "src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h", "src/core/ext/census/aggregation.h", @@ -460,6 +461,9 @@ cc_library( "src/core/ext/client_config/uri_parser.c", "src/core/ext/transport/chttp2/server/insecure/server_chttp2.c", "src/core/ext/transport/chttp2/client/insecure/channel_create.c", + "src/core/ext/transport/cronet/client/secure/cronet_channel_create.c", + "src/core/ext/transport/cronet/transport/cronet_api_dummy.c", + "src/core/ext/transport/cronet/transport/cronet_transport.c", "src/core/ext/lb_policy/grpclb/load_balancer_api.c", "src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c", "src/core/ext/lb_policy/pick_first/pick_first.c", @@ -504,6 +508,7 @@ cc_library( "include/grpc/impl/codegen/sync_posix.h", "include/grpc/impl/codegen/sync_win32.h", "include/grpc/impl/codegen/time.h", + "include/grpc/grpc_cronet.h", "include/grpc/grpc_security.h", "include/grpc/grpc_security_constants.h", "include/grpc/census.h", @@ -1497,6 +1502,9 @@ objc_library( "src/core/ext/client_config/uri_parser.c", "src/core/ext/transport/chttp2/server/insecure/server_chttp2.c", "src/core/ext/transport/chttp2/client/insecure/channel_create.c", + "src/core/ext/transport/cronet/client/secure/cronet_channel_create.c", + "src/core/ext/transport/cronet/transport/cronet_api_dummy.c", + "src/core/ext/transport/cronet/transport/cronet_transport.c", "src/core/ext/lb_policy/grpclb/load_balancer_api.c", "src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c", "src/core/ext/lb_policy/pick_first/pick_first.c", @@ -1541,6 +1549,7 @@ objc_library( "include/grpc/impl/codegen/sync_posix.h", "include/grpc/impl/codegen/sync_win32.h", "include/grpc/impl/codegen/time.h", + "include/grpc/grpc_cronet.h", "include/grpc/grpc_security.h", "include/grpc/grpc_security_constants.h", "include/grpc/census.h", @@ -1679,6 +1688,7 @@ objc_library( "src/core/ext/client_config/subchannel_call_holder.h", "src/core/ext/client_config/subchannel_index.h", "src/core/ext/client_config/uri_parser.h", + "third_party/objective_c/Cronet/cronet_c_for_grpc.h", "src/core/ext/lb_policy/grpclb/load_balancer_api.h", "src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h", "src/core/ext/census/aggregation.h", @@ -2651,6 +2651,9 @@ LIBGRPC_SRC = \ src/core/ext/client_config/uri_parser.c \ src/core/ext/transport/chttp2/server/insecure/server_chttp2.c \ src/core/ext/transport/chttp2/client/insecure/channel_create.c \ + src/core/ext/transport/cronet/client/secure/cronet_channel_create.c \ + src/core/ext/transport/cronet/transport/cronet_api_dummy.c \ + src/core/ext/transport/cronet/transport/cronet_transport.c \ src/core/ext/lb_policy/grpclb/load_balancer_api.c \ src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c \ third_party/nanopb/pb_common.c \ @@ -2698,6 +2701,7 @@ PUBLIC_HEADERS_C += \ include/grpc/impl/codegen/sync_posix.h \ include/grpc/impl/codegen/sync_win32.h \ include/grpc/impl/codegen/time.h \ + include/grpc/grpc_cronet.h \ include/grpc/grpc_security.h \ include/grpc/grpc_security_constants.h \ include/grpc/census.h \ @@ -14480,6 +14484,9 @@ ifneq ($(OPENSSL_DEP),) # otherwise parallel compilation will fail if a source is compiled first. src/core/ext/transport/chttp2/client/secure/secure_channel_create.c: $(OPENSSL_DEP) src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c: $(OPENSSL_DEP) +src/core/ext/transport/cronet/client/secure/cronet_channel_create.c: $(OPENSSL_DEP) +src/core/ext/transport/cronet/transport/cronet_api_dummy.c: $(OPENSSL_DEP) +src/core/ext/transport/cronet/transport/cronet_transport.c: $(OPENSSL_DEP) src/core/lib/http/httpcli_security_connector.c: $(OPENSSL_DEP) src/core/lib/security/context/security_context.c: $(OPENSSL_DEP) src/core/lib/security/credentials/composite/composite_credentials.c: $(OPENSSL_DEP) diff --git a/binding.gyp b/binding.gyp index d4689be524..135128b7c4 100644 --- a/binding.gyp +++ b/binding.gyp @@ -719,6 +719,9 @@ 'src/core/ext/client_config/uri_parser.c', 'src/core/ext/transport/chttp2/server/insecure/server_chttp2.c', 'src/core/ext/transport/chttp2/client/insecure/channel_create.c', + 'src/core/ext/transport/cronet/client/secure/cronet_channel_create.c', + 'src/core/ext/transport/cronet/transport/cronet_api_dummy.c', + 'src/core/ext/transport/cronet/transport/cronet_transport.c', 'src/core/ext/lb_policy/grpclb/load_balancer_api.c', 'src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c', 'third_party/nanopb/pb_common.c', diff --git a/build.yaml b/build.yaml index 8d4ff6ce2e..8b2610c69e 100644 --- a/build.yaml +++ b/build.yaml @@ -402,6 +402,7 @@ filegroups: - grpc_client_config - name: grpc_secure public_headers: + - include/grpc/grpc_cronet.h - include/grpc/grpc_security.h - include/grpc/grpc_security_constants.h headers: @@ -568,6 +569,16 @@ filegroups: - grpc_transport_chttp2 - grpc_base - grpc_secure +- name: grpc_transport_cronet_client_secure + headers: + - third_party/objective_c/Cronet/cronet_c_for_grpc.h + src: + - src/core/ext/transport/cronet/client/secure/cronet_channel_create.c + - src/core/ext/transport/cronet/transport/cronet_api_dummy.c + - src/core/ext/transport/cronet/transport/cronet_transport.c + filegroups: + - grpc_base + - grpc_transport_chttp2 - name: nanopb headers: - third_party/nanopb/pb.h @@ -757,6 +768,7 @@ libs: - grpc_transport_chttp2_client_secure - grpc_transport_chttp2_server_insecure - grpc_transport_chttp2_client_insecure + - grpc_transport_cronet_client_secure - grpc_lb_policy_grpclb - grpc_lb_policy_pick_first - grpc_lb_policy_round_robin @@ -238,6 +238,9 @@ if test "$PHP_GRPC" != "no"; then src/core/ext/client_config/uri_parser.c \ src/core/ext/transport/chttp2/server/insecure/server_chttp2.c \ src/core/ext/transport/chttp2/client/insecure/channel_create.c \ + src/core/ext/transport/cronet/client/secure/cronet_channel_create.c \ + src/core/ext/transport/cronet/transport/cronet_api_dummy.c \ + src/core/ext/transport/cronet/transport/cronet_transport.c \ src/core/ext/lb_policy/grpclb/load_balancer_api.c \ src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c \ third_party/nanopb/pb_common.c \ @@ -576,6 +579,8 @@ if test "$PHP_GRPC" != "no"; then PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/transport/chttp2/server/insecure) PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/transport/chttp2/server/secure) PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/transport/chttp2/transport) + PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/transport/cronet/client/secure) + PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/transport/cronet/transport) PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/channel) PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/compression) PHP_ADD_BUILD_DIR($ext_builddir/src/core/lib/debug) diff --git a/examples/node/README.md b/examples/node/README.md index 28878833ce..59fb4a17f5 100644 --- a/examples/node/README.md +++ b/examples/node/README.md @@ -22,18 +22,24 @@ INSTALL TRY IT! ------- +There are two ways to generate the code needed to work with protocol buffers in Node.js - one approach uses [Protobuf.js](https://github.com/dcodeIO/ProtoBuf.js/) to dynamically generate the code at runtime, the other uses code statically generated using the protocol buffer compiler `protoc`. The examples behave identically, and either server can be used with either client. + - Run the server ```sh $ # from this directory - $ node ./greeter_server.js & + $ node ./dynamic_codegen/greeter_server.js & + $ # OR + $ node ./static_codegen/greeter_server.js & ``` - Run the client ```sh $ # from this directory - $ node ./greeter_client.js + $ node ./dynamic_codegen/greeter_client.js + $ # OR + $ node ./dynamic_codegen/greeter_client.js ``` TUTORIAL diff --git a/examples/node/dynamic_codegen/README.md b/examples/node/dynamic_codegen/README.md new file mode 100644 index 0000000000..1a6ec17a3e --- /dev/null +++ b/examples/node/dynamic_codegen/README.md @@ -0,0 +1 @@ +This is the dynamic code generation variant of the Node examples. Code in these examples is generated at runtime using Protobuf.js. diff --git a/examples/node/greeter_client.js b/examples/node/dynamic_codegen/greeter_client.js index 2820acbbb7..e24fb07f4c 100644 --- a/examples/node/greeter_client.js +++ b/examples/node/dynamic_codegen/greeter_client.js @@ -31,7 +31,7 @@ * */ -var PROTO_PATH = __dirname + '/../protos/helloworld.proto'; +var PROTO_PATH = __dirname + '/../../protos/helloworld.proto'; var grpc = require('grpc'); var hello_proto = grpc.load(PROTO_PATH).helloworld; diff --git a/examples/node/greeter_server.js b/examples/node/dynamic_codegen/greeter_server.js index e7ad51f600..aa43e4c672 100644 --- a/examples/node/greeter_server.js +++ b/examples/node/dynamic_codegen/greeter_server.js @@ -31,7 +31,7 @@ * */ -var PROTO_PATH = __dirname + '/../protos/helloworld.proto'; +var PROTO_PATH = __dirname + '/../../protos/helloworld.proto'; var grpc = require('grpc'); var hello_proto = grpc.load(PROTO_PATH).helloworld; diff --git a/examples/node/route_guide/README.md b/examples/node/dynamic_codegen/route_guide/README.md index 22bcf78986..22bcf78986 100644 --- a/examples/node/route_guide/README.md +++ b/examples/node/dynamic_codegen/route_guide/README.md diff --git a/examples/node/route_guide/route_guide_client.js b/examples/node/dynamic_codegen/route_guide/route_guide_client.js index fd05a59b63..775b9addbf 100644 --- a/examples/node/route_guide/route_guide_client.js +++ b/examples/node/dynamic_codegen/route_guide/route_guide_client.js @@ -31,7 +31,7 @@ * */ -var PROTO_PATH = __dirname + '/../../protos/route_guide.proto'; +var PROTO_PATH = __dirname + '/../../../protos/route_guide.proto'; var async = require('async'); var fs = require('fs'); diff --git a/examples/node/route_guide/route_guide_db.json b/examples/node/dynamic_codegen/route_guide/route_guide_db.json index 9d6a980ab7..9d6a980ab7 100644 --- a/examples/node/route_guide/route_guide_db.json +++ b/examples/node/dynamic_codegen/route_guide/route_guide_db.json diff --git a/examples/node/route_guide/route_guide_server.js b/examples/node/dynamic_codegen/route_guide/route_guide_server.js index 6c01fac246..6d59348cc9 100644 --- a/examples/node/route_guide/route_guide_server.js +++ b/examples/node/dynamic_codegen/route_guide/route_guide_server.js @@ -31,7 +31,7 @@ * */ -var PROTO_PATH = __dirname + '/../../protos/route_guide.proto'; +var PROTO_PATH = __dirname + '/../../../protos/route_guide.proto'; var fs = require('fs'); var parseArgs = require('minimist'); diff --git a/examples/node/package.json b/examples/node/package.json index d135df2464..2cae031175 100644 --- a/examples/node/package.json +++ b/examples/node/package.json @@ -3,7 +3,8 @@ "version": "0.1.0", "dependencies": { "async": "^1.5.2", - "grpc": "0.13.0", + "google-protobuf": "^3.0.0-alpha.5", + "grpc": "^0.14.0", "lodash": "^4.6.1", "minimist": "^1.2.0" } diff --git a/examples/node/static_codegen/README.md b/examples/node/static_codegen/README.md new file mode 100644 index 0000000000..fc97d34a38 --- /dev/null +++ b/examples/node/static_codegen/README.md @@ -0,0 +1,7 @@ +This is the static code generation variant of the Node examples. Code in these examples is pre-generated using protoc and the Node gRPC protoc plugin, and the generated code can be found in various `*_pb.js` files. The command line sequence for generating those files is as follows (assuming that `protoc` and `grpc_node_plugin` are present, and starting in the base directory of this package): + +```sh +cd ../protos +protoc --js_out=import_style=commonjs,binary:../node/static_codegen/ --grpc_out=../node/static_codegen --plugin=protoc-gen-grpc=grpc_node_plugin helloworld.proto +protoc --js_out=import_style=commonjs,binary:../node/static_codegen/route_guide/ --grpc_out=../node/static_codegen/route_guide/ --plugin=protoc-gen-grpc=grpc_node_plugin route_guide.proto +``` diff --git a/examples/node/static_codegen/greeter_client.js b/examples/node/static_codegen/greeter_client.js new file mode 100644 index 0000000000..da80cf34d8 --- /dev/null +++ b/examples/node/static_codegen/greeter_client.js @@ -0,0 +1,55 @@ +/* + * + * 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. + * + */ + +var messages = require('./helloworld_pb'); +var services = require('./helloworld_grpc_pb'); + +var grpc = require('grpc'); + +function main() { + var client = new services.GreeterClient('localhost:50051', + grpc.credentials.createInsecure()); + var user; + if (process.argv.length >= 3) { + user = process.argv[2]; + } else { + user = 'world'; + } + var request = new messages.HelloRequest(); + request.setName(user); + client.sayHello(request, function(err, response) { + console.log('Greeting:', response.getMessage()); + }); +} + +main(); diff --git a/examples/node/static_codegen/greeter_server.js b/examples/node/static_codegen/greeter_server.js new file mode 100644 index 0000000000..a1591b89fa --- /dev/null +++ b/examples/node/static_codegen/greeter_server.js @@ -0,0 +1,59 @@ +/* + * + * 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. + * + */ + +var messages = require('./helloworld_pb'); +var services = require('./helloworld_grpc_pb'); + +var grpc = require('grpc'); + +/** + * Implements the SayHello RPC method. + */ +function sayHello(call, callback) { + var reply = new messages.HelloReply(); + reply.setMessage('Hello ' + call.request.getName()); + callback(null, reply); +} + +/** + * Starts an RPC server that receives requests for the Greeter service at the + * sample server port + */ +function main() { + var server = new grpc.Server(); + server.addService(services.GreeterService, {sayHello: sayHello}); + server.bind('0.0.0.0:50051', grpc.ServerCredentials.createInsecure()); + server.start(); +} + +main(); diff --git a/examples/node/static_codegen/helloworld_grpc_pb.js b/examples/node/static_codegen/helloworld_grpc_pb.js new file mode 100644 index 0000000000..846f8b6bf5 --- /dev/null +++ b/examples/node/static_codegen/helloworld_grpc_pb.js @@ -0,0 +1,44 @@ +// GENERATED CODE -- DO NOT EDIT! + +'use strict'; +var grpc = require('grpc'); +var helloworld_pb = require('./helloworld_pb.js'); + +function serialize_HelloReply(arg) { + if (!(arg instanceof helloworld_pb.HelloReply)) { + throw new Error('Expected argument of type HelloReply'); + } + return new Buffer(arg.serializeBinary()); +} + +function deserialize_HelloReply(buffer_arg) { + return helloworld_pb.HelloReply.deserializeBinary(new Uint8Array(buffer_arg)); +} + +function serialize_HelloRequest(arg) { + if (!(arg instanceof helloworld_pb.HelloRequest)) { + throw new Error('Expected argument of type HelloRequest'); + } + return new Buffer(arg.serializeBinary()); +} + +function deserialize_HelloRequest(buffer_arg) { + return helloworld_pb.HelloRequest.deserializeBinary(new Uint8Array(buffer_arg)); +} + + +var GreeterService = exports.GreeterService = { + sayHello: { + path: '/helloworld.Greeter/SayHello', + requestStream: false, + responseStream: false, + requestType: helloworld_pb.HelloRequest, + responseType: helloworld_pb.HelloReply, + requestSerialize: serialize_HelloRequest, + requestDeserialize: deserialize_HelloRequest, + responseSerialize: serialize_HelloReply, + responseDeserialize: deserialize_HelloReply, + }, +}; + +exports.GreeterClient = grpc.makeGenericClientConstructor(GreeterService); diff --git a/examples/node/static_codegen/helloworld_pb.js b/examples/node/static_codegen/helloworld_pb.js new file mode 100644 index 0000000000..6405bd90f1 --- /dev/null +++ b/examples/node/static_codegen/helloworld_pb.js @@ -0,0 +1,332 @@ +/** + * @fileoverview + * @enhanceable + * @public + */ +// GENERATED CODE -- DO NOT EDIT! + +var jspb = require('google-protobuf'); +var goog = jspb; +var global = Function('return this')(); + +goog.exportSymbol('proto.helloworld.HelloReply', null, global); +goog.exportSymbol('proto.helloworld.HelloRequest', null, global); + +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.helloworld.HelloRequest = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.helloworld.HelloRequest, jspb.Message); +if (goog.DEBUG && !COMPILED) { + proto.helloworld.HelloRequest.displayName = 'proto.helloworld.HelloRequest'; +} + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto suitable for use in Soy templates. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * To access a reserved field use, foo.pb_<name>, eg, foo.pb_default. + * For the list of reserved names please see: + * com.google.apps.jspb.JsClassTemplate.JS_RESERVED_WORDS. + * @param {boolean=} opt_includeInstance Whether to include the JSPB instance + * for transitional soy proto support: http://goto/soy-param-migration + * @return {!Object} + */ +proto.helloworld.HelloRequest.prototype.toObject = function(opt_includeInstance) { + return proto.helloworld.HelloRequest.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Whether to include the JSPB + * instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.helloworld.HelloRequest} msg The msg instance to transform. + * @return {!Object} + */ +proto.helloworld.HelloRequest.toObject = function(includeInstance, msg) { + var f, obj = { + name: msg.getName() + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.helloworld.HelloRequest} + */ +proto.helloworld.HelloRequest.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.helloworld.HelloRequest; + return proto.helloworld.HelloRequest.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.helloworld.HelloRequest} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.helloworld.HelloRequest} + */ +proto.helloworld.HelloRequest.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {string} */ (reader.readString()); + msg.setName(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Class method variant: serializes the given message to binary data + * (in protobuf wire format), writing to the given BinaryWriter. + * @param {!proto.helloworld.HelloRequest} message + * @param {!jspb.BinaryWriter} writer + */ +proto.helloworld.HelloRequest.serializeBinaryToWriter = function(message, writer) { + message.serializeBinaryToWriter(writer); +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.helloworld.HelloRequest.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + this.serializeBinaryToWriter(writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the message to binary data (in protobuf wire format), + * writing to the given BinaryWriter. + * @param {!jspb.BinaryWriter} writer + */ +proto.helloworld.HelloRequest.prototype.serializeBinaryToWriter = function (writer) { + var f = undefined; + f = this.getName(); + if (f.length > 0) { + writer.writeString( + 1, + f + ); + } +}; + + +/** + * Creates a deep clone of this proto. No data is shared with the original. + * @return {!proto.helloworld.HelloRequest} The clone. + */ +proto.helloworld.HelloRequest.prototype.cloneMessage = function() { + return /** @type {!proto.helloworld.HelloRequest} */ (jspb.Message.cloneMessage(this)); +}; + + +/** + * optional string name = 1; + * @return {string} + */ +proto.helloworld.HelloRequest.prototype.getName = function() { + return /** @type {string} */ (jspb.Message.getFieldProto3(this, 1, "")); +}; + + +/** @param {string} value */ +proto.helloworld.HelloRequest.prototype.setName = function(value) { + jspb.Message.setField(this, 1, value); +}; + + + +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.helloworld.HelloReply = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.helloworld.HelloReply, jspb.Message); +if (goog.DEBUG && !COMPILED) { + proto.helloworld.HelloReply.displayName = 'proto.helloworld.HelloReply'; +} + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto suitable for use in Soy templates. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * To access a reserved field use, foo.pb_<name>, eg, foo.pb_default. + * For the list of reserved names please see: + * com.google.apps.jspb.JsClassTemplate.JS_RESERVED_WORDS. + * @param {boolean=} opt_includeInstance Whether to include the JSPB instance + * for transitional soy proto support: http://goto/soy-param-migration + * @return {!Object} + */ +proto.helloworld.HelloReply.prototype.toObject = function(opt_includeInstance) { + return proto.helloworld.HelloReply.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Whether to include the JSPB + * instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.helloworld.HelloReply} msg The msg instance to transform. + * @return {!Object} + */ +proto.helloworld.HelloReply.toObject = function(includeInstance, msg) { + var f, obj = { + message: msg.getMessage() + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.helloworld.HelloReply} + */ +proto.helloworld.HelloReply.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.helloworld.HelloReply; + return proto.helloworld.HelloReply.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.helloworld.HelloReply} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.helloworld.HelloReply} + */ +proto.helloworld.HelloReply.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {string} */ (reader.readString()); + msg.setMessage(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Class method variant: serializes the given message to binary data + * (in protobuf wire format), writing to the given BinaryWriter. + * @param {!proto.helloworld.HelloReply} message + * @param {!jspb.BinaryWriter} writer + */ +proto.helloworld.HelloReply.serializeBinaryToWriter = function(message, writer) { + message.serializeBinaryToWriter(writer); +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.helloworld.HelloReply.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + this.serializeBinaryToWriter(writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the message to binary data (in protobuf wire format), + * writing to the given BinaryWriter. + * @param {!jspb.BinaryWriter} writer + */ +proto.helloworld.HelloReply.prototype.serializeBinaryToWriter = function (writer) { + var f = undefined; + f = this.getMessage(); + if (f.length > 0) { + writer.writeString( + 1, + f + ); + } +}; + + +/** + * Creates a deep clone of this proto. No data is shared with the original. + * @return {!proto.helloworld.HelloReply} The clone. + */ +proto.helloworld.HelloReply.prototype.cloneMessage = function() { + return /** @type {!proto.helloworld.HelloReply} */ (jspb.Message.cloneMessage(this)); +}; + + +/** + * optional string message = 1; + * @return {string} + */ +proto.helloworld.HelloReply.prototype.getMessage = function() { + return /** @type {string} */ (jspb.Message.getFieldProto3(this, 1, "")); +}; + + +/** @param {string} value */ +proto.helloworld.HelloReply.prototype.setMessage = function(value) { + jspb.Message.setField(this, 1, value); +}; + + +goog.object.extend(exports, proto.helloworld); diff --git a/examples/node/static_codegen/route_guide/README.md b/examples/node/static_codegen/route_guide/README.md new file mode 100644 index 0000000000..22bcf78986 --- /dev/null +++ b/examples/node/static_codegen/route_guide/README.md @@ -0,0 +1,5 @@ +#gRPC Basics: Node.js sample code + +The files in this folder are the samples used in [gRPC Basics: Node.js][], a detailed tutorial for using gRPC in Node.js. + +[gRPC Basics: Node.js]:http://www.grpc.io/docs/tutorials/basic/node.html diff --git a/examples/node/static_codegen/route_guide/route_guide_client.js b/examples/node/static_codegen/route_guide/route_guide_client.js new file mode 100644 index 0000000000..ecde78616b --- /dev/null +++ b/examples/node/static_codegen/route_guide/route_guide_client.js @@ -0,0 +1,247 @@ +/* + * + * 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. + * + */ + +var messages = require('./route_guide_pb'); +var services = require('./route_guide_grpc_pb'); + +var async = require('async'); +var fs = require('fs'); +var parseArgs = require('minimist'); +var path = require('path'); +var _ = require('lodash'); +var grpc = require('grpc'); + +var client = new services.RouteGuideClient('localhost:50051', + grpc.credentials.createInsecure()); + +var COORD_FACTOR = 1e7; + +/** + * Run the getFeature demo. Calls getFeature with a point known to have a + * feature and a point known not to have a feature. + * @param {function} callback Called when this demo is complete + */ +function runGetFeature(callback) { + var next = _.after(2, callback); + function featureCallback(error, feature) { + if (error) { + callback(error); + } + var latitude = feature.getLocation().getLatitude(); + var longitude = feature.getLocation().getLongitude(); + if (feature.getName() === '') { + console.log('Found no feature at ' + + latitude/COORD_FACTOR + ', ' + longitude/COORD_FACTOR); + } else { + console.log('Found feature called "' + feature.getName() + '" at ' + + latitude/COORD_FACTOR + ', ' + longitude/COORD_FACTOR); + } + next(); + } + var point1 = new messages.Point(); + point1.setLatitude(409146138); + point1.setLongitude(-746188906); + var point2 = new messages.Point(); + point2.setLatitude(0); + point2.setLongitude(0); + client.getFeature(point1, featureCallback); + client.getFeature(point2, featureCallback); +} + +/** + * Run the listFeatures demo. Calls listFeatures with a rectangle containing all + * of the features in the pre-generated database. Prints each response as it + * comes in. + * @param {function} callback Called when this demo is complete + */ +function runListFeatures(callback) { + var rect = new messages.Rectangle(); + var lo = new messages.Point(); + lo.setLatitude(400000000); + lo.setLongitude(-750000000); + rect.setLo(lo); + var hi = new messages.Point(); + hi.setLatitude(420000000); + hi.setLongitude(-730000000); + rect.setHi(hi); + console.log('Looking for features between 40, -75 and 42, -73'); + var call = client.listFeatures(rect); + call.on('data', function(feature) { + console.log('Found feature called "' + feature.getName() + '" at ' + + feature.getLocation().getLatitude()/COORD_FACTOR + ', ' + + feature.getLocation().getLongitude()/COORD_FACTOR); + }); + call.on('end', callback); +} + +/** + * Run the recordRoute demo. Sends several randomly chosen points from the + * pre-generated feature database with a variable delay in between. Prints the + * statistics when they are sent from the server. + * @param {function} callback Called when this demo is complete + */ +function runRecordRoute(callback) { + var argv = parseArgs(process.argv, { + string: 'db_path' + }); + fs.readFile(path.resolve(argv.db_path), function(err, data) { + if (err) callback(err); + // Transform the loaded features to Feature objects + var feature_list = _.map(JSON.parse(data), function(value) { + var feature = new messages.Feature(); + feature.setName(value.name); + var location = new messages.Point(); + location.setLatitude(value.location.latitude); + location.setLongitude(value.location.longitude); + feature.setLocation(location); + return feature; + }); + + var num_points = 10; + var call = client.recordRoute(function(error, stats) { + if (error) { + callback(error); + } + console.log('Finished trip with', stats.getPointCount(), 'points'); + console.log('Passed', stats.getFeatureCount(), 'features'); + console.log('Travelled', stats.getDistance(), 'meters'); + console.log('It took', stats.getElapsedTime(), 'seconds'); + callback(); + }); + /** + * Constructs a function that asynchronously sends the given point and then + * delays sending its callback + * @param {messages.Point} location The point to send + * @return {function(function)} The function that sends the point + */ + function pointSender(location) { + /** + * Sends the point, then calls the callback after a delay + * @param {function} callback Called when complete + */ + return function(callback) { + console.log('Visiting point ' + location.getLatitude()/COORD_FACTOR + + ', ' + location.getLongitude()/COORD_FACTOR); + call.write(location); + _.delay(callback, _.random(500, 1500)); + }; + } + var point_senders = []; + for (var i = 0; i < num_points; i++) { + var rand_point = feature_list[_.random(0, feature_list.length - 1)]; + point_senders[i] = pointSender(rand_point.getLocation()); + } + async.series(point_senders, function() { + call.end(); + }); + }); +} + +/** + * Run the routeChat demo. Send some chat messages, and print any chat messages + * that are sent from the server. + * @param {function} callback Called when the demo is complete + */ +function runRouteChat(callback) { + var call = client.routeChat(); + call.on('data', function(note) { + console.log('Got message "' + note.getMessage() + '" at ' + + note.getLocation().getLatitude() + ', ' + + note.getLocation().getLongitude()); + }); + + call.on('end', callback); + + var notes = [{ + location: { + latitude: 0, + longitude: 0 + }, + message: 'First message' + }, { + location: { + latitude: 0, + longitude: 1 + }, + message: 'Second message' + }, { + location: { + latitude: 1, + longitude: 0 + }, + message: 'Third message' + }, { + location: { + latitude: 0, + longitude: 0 + }, + message: 'Fourth message' + }]; + for (var i = 0; i < notes.length; i++) { + var note = notes[i]; + console.log('Sending message "' + note.message + '" at ' + + note.location.latitude + ', ' + note.location.longitude); + var noteMsg = new messages.RouteNote(); + noteMsg.setMessage(note.message); + var location = new messages.Point(); + location.setLatitude(note.location.latitude); + location.setLongitude(note.location.longitude); + noteMsg.setLocation(location); + call.write(noteMsg); + } + call.end(); +} + +/** + * Run all of the demos in order + */ +function main() { + async.series([ + runGetFeature, + runListFeatures, + runRecordRoute, + runRouteChat + ]); +} + +if (require.main === module) { + main(); +} + +exports.runGetFeature = runGetFeature; + +exports.runListFeatures = runListFeatures; + +exports.runRecordRoute = runRecordRoute; + +exports.runRouteChat = runRouteChat; diff --git a/examples/node/static_codegen/route_guide/route_guide_db.json b/examples/node/static_codegen/route_guide/route_guide_db.json new file mode 100644 index 0000000000..9d6a980ab7 --- /dev/null +++ b/examples/node/static_codegen/route_guide/route_guide_db.json @@ -0,0 +1,601 @@ +[{ + "location": { + "latitude": 407838351, + "longitude": -746143763 + }, + "name": "Patriots Path, Mendham, NJ 07945, USA" +}, { + "location": { + "latitude": 408122808, + "longitude": -743999179 + }, + "name": "101 New Jersey 10, Whippany, NJ 07981, USA" +}, { + "location": { + "latitude": 413628156, + "longitude": -749015468 + }, + "name": "U.S. 6, Shohola, PA 18458, USA" +}, { + "location": { + "latitude": 419999544, + "longitude": -740371136 + }, + "name": "5 Conners Road, Kingston, NY 12401, USA" +}, { + "location": { + "latitude": 414008389, + "longitude": -743951297 + }, + "name": "Mid Hudson Psychiatric Center, New Hampton, NY 10958, USA" +}, { + "location": { + "latitude": 419611318, + "longitude": -746524769 + }, + "name": "287 Flugertown Road, Livingston Manor, NY 12758, USA" +}, { + "location": { + "latitude": 406109563, + "longitude": -742186778 + }, + "name": "4001 Tremley Point Road, Linden, NJ 07036, USA" +}, { + "location": { + "latitude": 416802456, + "longitude": -742370183 + }, + "name": "352 South Mountain Road, Wallkill, NY 12589, USA" +}, { + "location": { + "latitude": 412950425, + "longitude": -741077389 + }, + "name": "Bailey Turn Road, Harriman, NY 10926, USA" +}, { + "location": { + "latitude": 412144655, + "longitude": -743949739 + }, + "name": "193-199 Wawayanda Road, Hewitt, NJ 07421, USA" +}, { + "location": { + "latitude": 415736605, + "longitude": -742847522 + }, + "name": "406-496 Ward Avenue, Pine Bush, NY 12566, USA" +}, { + "location": { + "latitude": 413843930, + "longitude": -740501726 + }, + "name": "162 Merrill Road, Highland Mills, NY 10930, USA" +}, { + "location": { + "latitude": 410873075, + "longitude": -744459023 + }, + "name": "Clinton Road, West Milford, NJ 07480, USA" +}, { + "location": { + "latitude": 412346009, + "longitude": -744026814 + }, + "name": "16 Old Brook Lane, Warwick, NY 10990, USA" +}, { + "location": { + "latitude": 402948455, + "longitude": -747903913 + }, + "name": "3 Drake Lane, Pennington, NJ 08534, USA" +}, { + "location": { + "latitude": 406337092, + "longitude": -740122226 + }, + "name": "6324 8th Avenue, Brooklyn, NY 11220, USA" +}, { + "location": { + "latitude": 406421967, + "longitude": -747727624 + }, + "name": "1 Merck Access Road, Whitehouse Station, NJ 08889, USA" +}, { + "location": { + "latitude": 416318082, + "longitude": -749677716 + }, + "name": "78-98 Schalck Road, Narrowsburg, NY 12764, USA" +}, { + "location": { + "latitude": 415301720, + "longitude": -748416257 + }, + "name": "282 Lakeview Drive Road, Highland Lake, NY 12743, USA" +}, { + "location": { + "latitude": 402647019, + "longitude": -747071791 + }, + "name": "330 Evelyn Avenue, Hamilton Township, NJ 08619, USA" +}, { + "location": { + "latitude": 412567807, + "longitude": -741058078 + }, + "name": "New York State Reference Route 987E, Southfields, NY 10975, USA" +}, { + "location": { + "latitude": 416855156, + "longitude": -744420597 + }, + "name": "103-271 Tempaloni Road, Ellenville, NY 12428, USA" +}, { + "location": { + "latitude": 404663628, + "longitude": -744820157 + }, + "name": "1300 Airport Road, North Brunswick Township, NJ 08902, USA" +}, { + "location": { + "latitude": 407113723, + "longitude": -749746483 + }, + "name": "" +}, { + "location": { + "latitude": 402133926, + "longitude": -743613249 + }, + "name": "" +}, { + "location": { + "latitude": 400273442, + "longitude": -741220915 + }, + "name": "" +}, { + "location": { + "latitude": 411236786, + "longitude": -744070769 + }, + "name": "" +}, { + "location": { + "latitude": 411633782, + "longitude": -746784970 + }, + "name": "211-225 Plains Road, Augusta, NJ 07822, USA" +}, { + "location": { + "latitude": 415830701, + "longitude": -742952812 + }, + "name": "" +}, { + "location": { + "latitude": 413447164, + "longitude": -748712898 + }, + "name": "165 Pedersen Ridge Road, Milford, PA 18337, USA" +}, { + "location": { + "latitude": 405047245, + "longitude": -749800722 + }, + "name": "100-122 Locktown Road, Frenchtown, NJ 08825, USA" +}, { + "location": { + "latitude": 418858923, + "longitude": -746156790 + }, + "name": "" +}, { + "location": { + "latitude": 417951888, + "longitude": -748484944 + }, + "name": "650-652 Willi Hill Road, Swan Lake, NY 12783, USA" +}, { + "location": { + "latitude": 407033786, + "longitude": -743977337 + }, + "name": "26 East 3rd Street, New Providence, NJ 07974, USA" +}, { + "location": { + "latitude": 417548014, + "longitude": -740075041 + }, + "name": "" +}, { + "location": { + "latitude": 410395868, + "longitude": -744972325 + }, + "name": "" +}, { + "location": { + "latitude": 404615353, + "longitude": -745129803 + }, + "name": "" +}, { + "location": { + "latitude": 406589790, + "longitude": -743560121 + }, + "name": "611 Lawrence Avenue, Westfield, NJ 07090, USA" +}, { + "location": { + "latitude": 414653148, + "longitude": -740477477 + }, + "name": "18 Lannis Avenue, New Windsor, NY 12553, USA" +}, { + "location": { + "latitude": 405957808, + "longitude": -743255336 + }, + "name": "82-104 Amherst Avenue, Colonia, NJ 07067, USA" +}, { + "location": { + "latitude": 411733589, + "longitude": -741648093 + }, + "name": "170 Seven Lakes Drive, Sloatsburg, NY 10974, USA" +}, { + "location": { + "latitude": 412676291, + "longitude": -742606606 + }, + "name": "1270 Lakes Road, Monroe, NY 10950, USA" +}, { + "location": { + "latitude": 409224445, + "longitude": -748286738 + }, + "name": "509-535 Alphano Road, Great Meadows, NJ 07838, USA" +}, { + "location": { + "latitude": 406523420, + "longitude": -742135517 + }, + "name": "652 Garden Street, Elizabeth, NJ 07202, USA" +}, { + "location": { + "latitude": 401827388, + "longitude": -740294537 + }, + "name": "349 Sea Spray Court, Neptune City, NJ 07753, USA" +}, { + "location": { + "latitude": 410564152, + "longitude": -743685054 + }, + "name": "13-17 Stanley Street, West Milford, NJ 07480, USA" +}, { + "location": { + "latitude": 408472324, + "longitude": -740726046 + }, + "name": "47 Industrial Avenue, Teterboro, NJ 07608, USA" +}, { + "location": { + "latitude": 412452168, + "longitude": -740214052 + }, + "name": "5 White Oak Lane, Stony Point, NY 10980, USA" +}, { + "location": { + "latitude": 409146138, + "longitude": -746188906 + }, + "name": "Berkshire Valley Management Area Trail, Jefferson, NJ, USA" +}, { + "location": { + "latitude": 404701380, + "longitude": -744781745 + }, + "name": "1007 Jersey Avenue, New Brunswick, NJ 08901, USA" +}, { + "location": { + "latitude": 409642566, + "longitude": -746017679 + }, + "name": "6 East Emerald Isle Drive, Lake Hopatcong, NJ 07849, USA" +}, { + "location": { + "latitude": 408031728, + "longitude": -748645385 + }, + "name": "1358-1474 New Jersey 57, Port Murray, NJ 07865, USA" +}, { + "location": { + "latitude": 413700272, + "longitude": -742135189 + }, + "name": "367 Prospect Road, Chester, NY 10918, USA" +}, { + "location": { + "latitude": 404310607, + "longitude": -740282632 + }, + "name": "10 Simon Lake Drive, Atlantic Highlands, NJ 07716, USA" +}, { + "location": { + "latitude": 409319800, + "longitude": -746201391 + }, + "name": "11 Ward Street, Mount Arlington, NJ 07856, USA" +}, { + "location": { + "latitude": 406685311, + "longitude": -742108603 + }, + "name": "300-398 Jefferson Avenue, Elizabeth, NJ 07201, USA" +}, { + "location": { + "latitude": 419018117, + "longitude": -749142781 + }, + "name": "43 Dreher Road, Roscoe, NY 12776, USA" +}, { + "location": { + "latitude": 412856162, + "longitude": -745148837 + }, + "name": "Swan Street, Pine Island, NY 10969, USA" +}, { + "location": { + "latitude": 416560744, + "longitude": -746721964 + }, + "name": "66 Pleasantview Avenue, Monticello, NY 12701, USA" +}, { + "location": { + "latitude": 405314270, + "longitude": -749836354 + }, + "name": "" +}, { + "location": { + "latitude": 414219548, + "longitude": -743327440 + }, + "name": "" +}, { + "location": { + "latitude": 415534177, + "longitude": -742900616 + }, + "name": "565 Winding Hills Road, Montgomery, NY 12549, USA" +}, { + "location": { + "latitude": 406898530, + "longitude": -749127080 + }, + "name": "231 Rocky Run Road, Glen Gardner, NJ 08826, USA" +}, { + "location": { + "latitude": 407586880, + "longitude": -741670168 + }, + "name": "100 Mount Pleasant Avenue, Newark, NJ 07104, USA" +}, { + "location": { + "latitude": 400106455, + "longitude": -742870190 + }, + "name": "517-521 Huntington Drive, Manchester Township, NJ 08759, USA" +}, { + "location": { + "latitude": 400066188, + "longitude": -746793294 + }, + "name": "" +}, { + "location": { + "latitude": 418803880, + "longitude": -744102673 + }, + "name": "40 Mountain Road, Napanoch, NY 12458, USA" +}, { + "location": { + "latitude": 414204288, + "longitude": -747895140 + }, + "name": "" +}, { + "location": { + "latitude": 414777405, + "longitude": -740615601 + }, + "name": "" +}, { + "location": { + "latitude": 415464475, + "longitude": -747175374 + }, + "name": "48 North Road, Forestburgh, NY 12777, USA" +}, { + "location": { + "latitude": 404062378, + "longitude": -746376177 + }, + "name": "" +}, { + "location": { + "latitude": 405688272, + "longitude": -749285130 + }, + "name": "" +}, { + "location": { + "latitude": 400342070, + "longitude": -748788996 + }, + "name": "" +}, { + "location": { + "latitude": 401809022, + "longitude": -744157964 + }, + "name": "" +}, { + "location": { + "latitude": 404226644, + "longitude": -740517141 + }, + "name": "9 Thompson Avenue, Leonardo, NJ 07737, USA" +}, { + "location": { + "latitude": 410322033, + "longitude": -747871659 + }, + "name": "" +}, { + "location": { + "latitude": 407100674, + "longitude": -747742727 + }, + "name": "" +}, { + "location": { + "latitude": 418811433, + "longitude": -741718005 + }, + "name": "213 Bush Road, Stone Ridge, NY 12484, USA" +}, { + "location": { + "latitude": 415034302, + "longitude": -743850945 + }, + "name": "" +}, { + "location": { + "latitude": 411349992, + "longitude": -743694161 + }, + "name": "" +}, { + "location": { + "latitude": 404839914, + "longitude": -744759616 + }, + "name": "1-17 Bergen Court, New Brunswick, NJ 08901, USA" +}, { + "location": { + "latitude": 414638017, + "longitude": -745957854 + }, + "name": "35 Oakland Valley Road, Cuddebackville, NY 12729, USA" +}, { + "location": { + "latitude": 412127800, + "longitude": -740173578 + }, + "name": "" +}, { + "location": { + "latitude": 401263460, + "longitude": -747964303 + }, + "name": "" +}, { + "location": { + "latitude": 412843391, + "longitude": -749086026 + }, + "name": "" +}, { + "location": { + "latitude": 418512773, + "longitude": -743067823 + }, + "name": "" +}, { + "location": { + "latitude": 404318328, + "longitude": -740835638 + }, + "name": "42-102 Main Street, Belford, NJ 07718, USA" +}, { + "location": { + "latitude": 419020746, + "longitude": -741172328 + }, + "name": "" +}, { + "location": { + "latitude": 404080723, + "longitude": -746119569 + }, + "name": "" +}, { + "location": { + "latitude": 401012643, + "longitude": -744035134 + }, + "name": "" +}, { + "location": { + "latitude": 404306372, + "longitude": -741079661 + }, + "name": "" +}, { + "location": { + "latitude": 403966326, + "longitude": -748519297 + }, + "name": "" +}, { + "location": { + "latitude": 405002031, + "longitude": -748407866 + }, + "name": "" +}, { + "location": { + "latitude": 409532885, + "longitude": -742200683 + }, + "name": "" +}, { + "location": { + "latitude": 416851321, + "longitude": -742674555 + }, + "name": "" +}, { + "location": { + "latitude": 406411633, + "longitude": -741722051 + }, + "name": "3387 Richmond Terrace, Staten Island, NY 10303, USA" +}, { + "location": { + "latitude": 413069058, + "longitude": -744597778 + }, + "name": "261 Van Sickle Road, Goshen, NY 10924, USA" +}, { + "location": { + "latitude": 418465462, + "longitude": -746859398 + }, + "name": "" +}, { + "location": { + "latitude": 411733222, + "longitude": -744228360 + }, + "name": "" +}, { + "location": { + "latitude": 410248224, + "longitude": -747127767 + }, + "name": "3 Hasta Way, Newton, NJ 07860, USA" +}] diff --git a/examples/node/static_codegen/route_guide/route_guide_grpc_pb.js b/examples/node/static_codegen/route_guide/route_guide_grpc_pb.js new file mode 100644 index 0000000000..1dd71331db --- /dev/null +++ b/examples/node/static_codegen/route_guide/route_guide_grpc_pb.js @@ -0,0 +1,110 @@ +// GENERATED CODE -- DO NOT EDIT! + +'use strict'; +var grpc = require('grpc'); +var route_guide_pb = require('./route_guide_pb.js'); + +function serialize_Feature(arg) { + if (!(arg instanceof route_guide_pb.Feature)) { + throw new Error('Expected argument of type Feature'); + } + return new Buffer(arg.serializeBinary()); +} + +function deserialize_Feature(buffer_arg) { + return route_guide_pb.Feature.deserializeBinary(new Uint8Array(buffer_arg)); +} + +function serialize_Point(arg) { + if (!(arg instanceof route_guide_pb.Point)) { + throw new Error('Expected argument of type Point'); + } + return new Buffer(arg.serializeBinary()); +} + +function deserialize_Point(buffer_arg) { + return route_guide_pb.Point.deserializeBinary(new Uint8Array(buffer_arg)); +} + +function serialize_Rectangle(arg) { + if (!(arg instanceof route_guide_pb.Rectangle)) { + throw new Error('Expected argument of type Rectangle'); + } + return new Buffer(arg.serializeBinary()); +} + +function deserialize_Rectangle(buffer_arg) { + return route_guide_pb.Rectangle.deserializeBinary(new Uint8Array(buffer_arg)); +} + +function serialize_RouteNote(arg) { + if (!(arg instanceof route_guide_pb.RouteNote)) { + throw new Error('Expected argument of type RouteNote'); + } + return new Buffer(arg.serializeBinary()); +} + +function deserialize_RouteNote(buffer_arg) { + return route_guide_pb.RouteNote.deserializeBinary(new Uint8Array(buffer_arg)); +} + +function serialize_RouteSummary(arg) { + if (!(arg instanceof route_guide_pb.RouteSummary)) { + throw new Error('Expected argument of type RouteSummary'); + } + return new Buffer(arg.serializeBinary()); +} + +function deserialize_RouteSummary(buffer_arg) { + return route_guide_pb.RouteSummary.deserializeBinary(new Uint8Array(buffer_arg)); +} + + +var RouteGuideService = exports.RouteGuideService = { + getFeature: { + path: '/routeguide.RouteGuide/GetFeature', + requestStream: false, + responseStream: false, + requestType: route_guide_pb.Point, + responseType: route_guide_pb.Feature, + requestSerialize: serialize_Point, + requestDeserialize: deserialize_Point, + responseSerialize: serialize_Feature, + responseDeserialize: deserialize_Feature, + }, + listFeatures: { + path: '/routeguide.RouteGuide/ListFeatures', + requestStream: false, + responseStream: true, + requestType: route_guide_pb.Rectangle, + responseType: route_guide_pb.Feature, + requestSerialize: serialize_Rectangle, + requestDeserialize: deserialize_Rectangle, + responseSerialize: serialize_Feature, + responseDeserialize: deserialize_Feature, + }, + recordRoute: { + path: '/routeguide.RouteGuide/RecordRoute', + requestStream: true, + responseStream: false, + requestType: route_guide_pb.Point, + responseType: route_guide_pb.RouteSummary, + requestSerialize: serialize_Point, + requestDeserialize: deserialize_Point, + responseSerialize: serialize_RouteSummary, + responseDeserialize: deserialize_RouteSummary, + }, + routeChat: { + path: '/routeguide.RouteGuide/RouteChat', + requestStream: true, + responseStream: true, + requestType: route_guide_pb.RouteNote, + responseType: route_guide_pb.RouteNote, + requestSerialize: serialize_RouteNote, + requestDeserialize: deserialize_RouteNote, + responseSerialize: serialize_RouteNote, + responseDeserialize: deserialize_RouteNote, + }, +}; + +exports.RouteGuideClient = grpc.makeGenericClientConstructor(RouteGuideService); diff --git a/examples/node/static_codegen/route_guide/route_guide_pb.js b/examples/node/static_codegen/route_guide/route_guide_pb.js new file mode 100644 index 0000000000..f604cd6d50 --- /dev/null +++ b/examples/node/static_codegen/route_guide/route_guide_pb.js @@ -0,0 +1,1033 @@ +/** + * @fileoverview + * @enhanceable + * @public + */ +// GENERATED CODE -- DO NOT EDIT! + +var jspb = require('google-protobuf'); +var goog = jspb; +var global = Function('return this')(); + +goog.exportSymbol('proto.routeguide.Feature', null, global); +goog.exportSymbol('proto.routeguide.Point', null, global); +goog.exportSymbol('proto.routeguide.Rectangle', null, global); +goog.exportSymbol('proto.routeguide.RouteNote', null, global); +goog.exportSymbol('proto.routeguide.RouteSummary', null, global); + +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.routeguide.Point = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.routeguide.Point, jspb.Message); +if (goog.DEBUG && !COMPILED) { + proto.routeguide.Point.displayName = 'proto.routeguide.Point'; +} + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto suitable for use in Soy templates. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * To access a reserved field use, foo.pb_<name>, eg, foo.pb_default. + * For the list of reserved names please see: + * com.google.apps.jspb.JsClassTemplate.JS_RESERVED_WORDS. + * @param {boolean=} opt_includeInstance Whether to include the JSPB instance + * for transitional soy proto support: http://goto/soy-param-migration + * @return {!Object} + */ +proto.routeguide.Point.prototype.toObject = function(opt_includeInstance) { + return proto.routeguide.Point.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Whether to include the JSPB + * instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.routeguide.Point} msg The msg instance to transform. + * @return {!Object} + */ +proto.routeguide.Point.toObject = function(includeInstance, msg) { + var f, obj = { + latitude: msg.getLatitude(), + longitude: msg.getLongitude() + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.routeguide.Point} + */ +proto.routeguide.Point.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.routeguide.Point; + return proto.routeguide.Point.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.routeguide.Point} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.routeguide.Point} + */ +proto.routeguide.Point.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {number} */ (reader.readInt32()); + msg.setLatitude(value); + break; + case 2: + var value = /** @type {number} */ (reader.readInt32()); + msg.setLongitude(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Class method variant: serializes the given message to binary data + * (in protobuf wire format), writing to the given BinaryWriter. + * @param {!proto.routeguide.Point} message + * @param {!jspb.BinaryWriter} writer + */ +proto.routeguide.Point.serializeBinaryToWriter = function(message, writer) { + message.serializeBinaryToWriter(writer); +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.routeguide.Point.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + this.serializeBinaryToWriter(writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the message to binary data (in protobuf wire format), + * writing to the given BinaryWriter. + * @param {!jspb.BinaryWriter} writer + */ +proto.routeguide.Point.prototype.serializeBinaryToWriter = function (writer) { + var f = undefined; + f = this.getLatitude(); + if (f !== 0) { + writer.writeInt32( + 1, + f + ); + } + f = this.getLongitude(); + if (f !== 0) { + writer.writeInt32( + 2, + f + ); + } +}; + + +/** + * Creates a deep clone of this proto. No data is shared with the original. + * @return {!proto.routeguide.Point} The clone. + */ +proto.routeguide.Point.prototype.cloneMessage = function() { + return /** @type {!proto.routeguide.Point} */ (jspb.Message.cloneMessage(this)); +}; + + +/** + * optional int32 latitude = 1; + * @return {number} + */ +proto.routeguide.Point.prototype.getLatitude = function() { + return /** @type {number} */ (jspb.Message.getFieldProto3(this, 1, 0)); +}; + + +/** @param {number} value */ +proto.routeguide.Point.prototype.setLatitude = function(value) { + jspb.Message.setField(this, 1, value); +}; + + +/** + * optional int32 longitude = 2; + * @return {number} + */ +proto.routeguide.Point.prototype.getLongitude = function() { + return /** @type {number} */ (jspb.Message.getFieldProto3(this, 2, 0)); +}; + + +/** @param {number} value */ +proto.routeguide.Point.prototype.setLongitude = function(value) { + jspb.Message.setField(this, 2, value); +}; + + + +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.routeguide.Rectangle = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.routeguide.Rectangle, jspb.Message); +if (goog.DEBUG && !COMPILED) { + proto.routeguide.Rectangle.displayName = 'proto.routeguide.Rectangle'; +} + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto suitable for use in Soy templates. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * To access a reserved field use, foo.pb_<name>, eg, foo.pb_default. + * For the list of reserved names please see: + * com.google.apps.jspb.JsClassTemplate.JS_RESERVED_WORDS. + * @param {boolean=} opt_includeInstance Whether to include the JSPB instance + * for transitional soy proto support: http://goto/soy-param-migration + * @return {!Object} + */ +proto.routeguide.Rectangle.prototype.toObject = function(opt_includeInstance) { + return proto.routeguide.Rectangle.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Whether to include the JSPB + * instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.routeguide.Rectangle} msg The msg instance to transform. + * @return {!Object} + */ +proto.routeguide.Rectangle.toObject = function(includeInstance, msg) { + var f, obj = { + lo: (f = msg.getLo()) && proto.routeguide.Point.toObject(includeInstance, f), + hi: (f = msg.getHi()) && proto.routeguide.Point.toObject(includeInstance, f) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.routeguide.Rectangle} + */ +proto.routeguide.Rectangle.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.routeguide.Rectangle; + return proto.routeguide.Rectangle.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.routeguide.Rectangle} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.routeguide.Rectangle} + */ +proto.routeguide.Rectangle.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new proto.routeguide.Point; + reader.readMessage(value,proto.routeguide.Point.deserializeBinaryFromReader); + msg.setLo(value); + break; + case 2: + var value = new proto.routeguide.Point; + reader.readMessage(value,proto.routeguide.Point.deserializeBinaryFromReader); + msg.setHi(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Class method variant: serializes the given message to binary data + * (in protobuf wire format), writing to the given BinaryWriter. + * @param {!proto.routeguide.Rectangle} message + * @param {!jspb.BinaryWriter} writer + */ +proto.routeguide.Rectangle.serializeBinaryToWriter = function(message, writer) { + message.serializeBinaryToWriter(writer); +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.routeguide.Rectangle.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + this.serializeBinaryToWriter(writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the message to binary data (in protobuf wire format), + * writing to the given BinaryWriter. + * @param {!jspb.BinaryWriter} writer + */ +proto.routeguide.Rectangle.prototype.serializeBinaryToWriter = function (writer) { + var f = undefined; + f = this.getLo(); + if (f != null) { + writer.writeMessage( + 1, + f, + proto.routeguide.Point.serializeBinaryToWriter + ); + } + f = this.getHi(); + if (f != null) { + writer.writeMessage( + 2, + f, + proto.routeguide.Point.serializeBinaryToWriter + ); + } +}; + + +/** + * Creates a deep clone of this proto. No data is shared with the original. + * @return {!proto.routeguide.Rectangle} The clone. + */ +proto.routeguide.Rectangle.prototype.cloneMessage = function() { + return /** @type {!proto.routeguide.Rectangle} */ (jspb.Message.cloneMessage(this)); +}; + + +/** + * optional Point lo = 1; + * @return {proto.routeguide.Point} + */ +proto.routeguide.Rectangle.prototype.getLo = function() { + return /** @type{proto.routeguide.Point} */ ( + jspb.Message.getWrapperField(this, proto.routeguide.Point, 1)); +}; + + +/** @param {proto.routeguide.Point|undefined} value */ +proto.routeguide.Rectangle.prototype.setLo = function(value) { + jspb.Message.setWrapperField(this, 1, value); +}; + + +proto.routeguide.Rectangle.prototype.clearLo = function() { + this.setLo(undefined); +}; + + +/** + * optional Point hi = 2; + * @return {proto.routeguide.Point} + */ +proto.routeguide.Rectangle.prototype.getHi = function() { + return /** @type{proto.routeguide.Point} */ ( + jspb.Message.getWrapperField(this, proto.routeguide.Point, 2)); +}; + + +/** @param {proto.routeguide.Point|undefined} value */ +proto.routeguide.Rectangle.prototype.setHi = function(value) { + jspb.Message.setWrapperField(this, 2, value); +}; + + +proto.routeguide.Rectangle.prototype.clearHi = function() { + this.setHi(undefined); +}; + + + +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.routeguide.Feature = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.routeguide.Feature, jspb.Message); +if (goog.DEBUG && !COMPILED) { + proto.routeguide.Feature.displayName = 'proto.routeguide.Feature'; +} + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto suitable for use in Soy templates. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * To access a reserved field use, foo.pb_<name>, eg, foo.pb_default. + * For the list of reserved names please see: + * com.google.apps.jspb.JsClassTemplate.JS_RESERVED_WORDS. + * @param {boolean=} opt_includeInstance Whether to include the JSPB instance + * for transitional soy proto support: http://goto/soy-param-migration + * @return {!Object} + */ +proto.routeguide.Feature.prototype.toObject = function(opt_includeInstance) { + return proto.routeguide.Feature.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Whether to include the JSPB + * instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.routeguide.Feature} msg The msg instance to transform. + * @return {!Object} + */ +proto.routeguide.Feature.toObject = function(includeInstance, msg) { + var f, obj = { + name: msg.getName(), + location: (f = msg.getLocation()) && proto.routeguide.Point.toObject(includeInstance, f) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.routeguide.Feature} + */ +proto.routeguide.Feature.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.routeguide.Feature; + return proto.routeguide.Feature.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.routeguide.Feature} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.routeguide.Feature} + */ +proto.routeguide.Feature.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {string} */ (reader.readString()); + msg.setName(value); + break; + case 2: + var value = new proto.routeguide.Point; + reader.readMessage(value,proto.routeguide.Point.deserializeBinaryFromReader); + msg.setLocation(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Class method variant: serializes the given message to binary data + * (in protobuf wire format), writing to the given BinaryWriter. + * @param {!proto.routeguide.Feature} message + * @param {!jspb.BinaryWriter} writer + */ +proto.routeguide.Feature.serializeBinaryToWriter = function(message, writer) { + message.serializeBinaryToWriter(writer); +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.routeguide.Feature.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + this.serializeBinaryToWriter(writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the message to binary data (in protobuf wire format), + * writing to the given BinaryWriter. + * @param {!jspb.BinaryWriter} writer + */ +proto.routeguide.Feature.prototype.serializeBinaryToWriter = function (writer) { + var f = undefined; + f = this.getName(); + if (f.length > 0) { + writer.writeString( + 1, + f + ); + } + f = this.getLocation(); + if (f != null) { + writer.writeMessage( + 2, + f, + proto.routeguide.Point.serializeBinaryToWriter + ); + } +}; + + +/** + * Creates a deep clone of this proto. No data is shared with the original. + * @return {!proto.routeguide.Feature} The clone. + */ +proto.routeguide.Feature.prototype.cloneMessage = function() { + return /** @type {!proto.routeguide.Feature} */ (jspb.Message.cloneMessage(this)); +}; + + +/** + * optional string name = 1; + * @return {string} + */ +proto.routeguide.Feature.prototype.getName = function() { + return /** @type {string} */ (jspb.Message.getFieldProto3(this, 1, "")); +}; + + +/** @param {string} value */ +proto.routeguide.Feature.prototype.setName = function(value) { + jspb.Message.setField(this, 1, value); +}; + + +/** + * optional Point location = 2; + * @return {proto.routeguide.Point} + */ +proto.routeguide.Feature.prototype.getLocation = function() { + return /** @type{proto.routeguide.Point} */ ( + jspb.Message.getWrapperField(this, proto.routeguide.Point, 2)); +}; + + +/** @param {proto.routeguide.Point|undefined} value */ +proto.routeguide.Feature.prototype.setLocation = function(value) { + jspb.Message.setWrapperField(this, 2, value); +}; + + +proto.routeguide.Feature.prototype.clearLocation = function() { + this.setLocation(undefined); +}; + + + +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.routeguide.RouteNote = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.routeguide.RouteNote, jspb.Message); +if (goog.DEBUG && !COMPILED) { + proto.routeguide.RouteNote.displayName = 'proto.routeguide.RouteNote'; +} + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto suitable for use in Soy templates. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * To access a reserved field use, foo.pb_<name>, eg, foo.pb_default. + * For the list of reserved names please see: + * com.google.apps.jspb.JsClassTemplate.JS_RESERVED_WORDS. + * @param {boolean=} opt_includeInstance Whether to include the JSPB instance + * for transitional soy proto support: http://goto/soy-param-migration + * @return {!Object} + */ +proto.routeguide.RouteNote.prototype.toObject = function(opt_includeInstance) { + return proto.routeguide.RouteNote.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Whether to include the JSPB + * instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.routeguide.RouteNote} msg The msg instance to transform. + * @return {!Object} + */ +proto.routeguide.RouteNote.toObject = function(includeInstance, msg) { + var f, obj = { + location: (f = msg.getLocation()) && proto.routeguide.Point.toObject(includeInstance, f), + message: msg.getMessage() + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.routeguide.RouteNote} + */ +proto.routeguide.RouteNote.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.routeguide.RouteNote; + return proto.routeguide.RouteNote.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.routeguide.RouteNote} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.routeguide.RouteNote} + */ +proto.routeguide.RouteNote.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new proto.routeguide.Point; + reader.readMessage(value,proto.routeguide.Point.deserializeBinaryFromReader); + msg.setLocation(value); + break; + case 2: + var value = /** @type {string} */ (reader.readString()); + msg.setMessage(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Class method variant: serializes the given message to binary data + * (in protobuf wire format), writing to the given BinaryWriter. + * @param {!proto.routeguide.RouteNote} message + * @param {!jspb.BinaryWriter} writer + */ +proto.routeguide.RouteNote.serializeBinaryToWriter = function(message, writer) { + message.serializeBinaryToWriter(writer); +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.routeguide.RouteNote.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + this.serializeBinaryToWriter(writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the message to binary data (in protobuf wire format), + * writing to the given BinaryWriter. + * @param {!jspb.BinaryWriter} writer + */ +proto.routeguide.RouteNote.prototype.serializeBinaryToWriter = function (writer) { + var f = undefined; + f = this.getLocation(); + if (f != null) { + writer.writeMessage( + 1, + f, + proto.routeguide.Point.serializeBinaryToWriter + ); + } + f = this.getMessage(); + if (f.length > 0) { + writer.writeString( + 2, + f + ); + } +}; + + +/** + * Creates a deep clone of this proto. No data is shared with the original. + * @return {!proto.routeguide.RouteNote} The clone. + */ +proto.routeguide.RouteNote.prototype.cloneMessage = function() { + return /** @type {!proto.routeguide.RouteNote} */ (jspb.Message.cloneMessage(this)); +}; + + +/** + * optional Point location = 1; + * @return {proto.routeguide.Point} + */ +proto.routeguide.RouteNote.prototype.getLocation = function() { + return /** @type{proto.routeguide.Point} */ ( + jspb.Message.getWrapperField(this, proto.routeguide.Point, 1)); +}; + + +/** @param {proto.routeguide.Point|undefined} value */ +proto.routeguide.RouteNote.prototype.setLocation = function(value) { + jspb.Message.setWrapperField(this, 1, value); +}; + + +proto.routeguide.RouteNote.prototype.clearLocation = function() { + this.setLocation(undefined); +}; + + +/** + * optional string message = 2; + * @return {string} + */ +proto.routeguide.RouteNote.prototype.getMessage = function() { + return /** @type {string} */ (jspb.Message.getFieldProto3(this, 2, "")); +}; + + +/** @param {string} value */ +proto.routeguide.RouteNote.prototype.setMessage = function(value) { + jspb.Message.setField(this, 2, value); +}; + + + +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.routeguide.RouteSummary = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.routeguide.RouteSummary, jspb.Message); +if (goog.DEBUG && !COMPILED) { + proto.routeguide.RouteSummary.displayName = 'proto.routeguide.RouteSummary'; +} + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto suitable for use in Soy templates. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * To access a reserved field use, foo.pb_<name>, eg, foo.pb_default. + * For the list of reserved names please see: + * com.google.apps.jspb.JsClassTemplate.JS_RESERVED_WORDS. + * @param {boolean=} opt_includeInstance Whether to include the JSPB instance + * for transitional soy proto support: http://goto/soy-param-migration + * @return {!Object} + */ +proto.routeguide.RouteSummary.prototype.toObject = function(opt_includeInstance) { + return proto.routeguide.RouteSummary.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Whether to include the JSPB + * instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.routeguide.RouteSummary} msg The msg instance to transform. + * @return {!Object} + */ +proto.routeguide.RouteSummary.toObject = function(includeInstance, msg) { + var f, obj = { + pointCount: msg.getPointCount(), + featureCount: msg.getFeatureCount(), + distance: msg.getDistance(), + elapsedTime: msg.getElapsedTime() + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.routeguide.RouteSummary} + */ +proto.routeguide.RouteSummary.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.routeguide.RouteSummary; + return proto.routeguide.RouteSummary.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.routeguide.RouteSummary} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.routeguide.RouteSummary} + */ +proto.routeguide.RouteSummary.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {number} */ (reader.readInt32()); + msg.setPointCount(value); + break; + case 2: + var value = /** @type {number} */ (reader.readInt32()); + msg.setFeatureCount(value); + break; + case 3: + var value = /** @type {number} */ (reader.readInt32()); + msg.setDistance(value); + break; + case 4: + var value = /** @type {number} */ (reader.readInt32()); + msg.setElapsedTime(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Class method variant: serializes the given message to binary data + * (in protobuf wire format), writing to the given BinaryWriter. + * @param {!proto.routeguide.RouteSummary} message + * @param {!jspb.BinaryWriter} writer + */ +proto.routeguide.RouteSummary.serializeBinaryToWriter = function(message, writer) { + message.serializeBinaryToWriter(writer); +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.routeguide.RouteSummary.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + this.serializeBinaryToWriter(writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the message to binary data (in protobuf wire format), + * writing to the given BinaryWriter. + * @param {!jspb.BinaryWriter} writer + */ +proto.routeguide.RouteSummary.prototype.serializeBinaryToWriter = function (writer) { + var f = undefined; + f = this.getPointCount(); + if (f !== 0) { + writer.writeInt32( + 1, + f + ); + } + f = this.getFeatureCount(); + if (f !== 0) { + writer.writeInt32( + 2, + f + ); + } + f = this.getDistance(); + if (f !== 0) { + writer.writeInt32( + 3, + f + ); + } + f = this.getElapsedTime(); + if (f !== 0) { + writer.writeInt32( + 4, + f + ); + } +}; + + +/** + * Creates a deep clone of this proto. No data is shared with the original. + * @return {!proto.routeguide.RouteSummary} The clone. + */ +proto.routeguide.RouteSummary.prototype.cloneMessage = function() { + return /** @type {!proto.routeguide.RouteSummary} */ (jspb.Message.cloneMessage(this)); +}; + + +/** + * optional int32 point_count = 1; + * @return {number} + */ +proto.routeguide.RouteSummary.prototype.getPointCount = function() { + return /** @type {number} */ (jspb.Message.getFieldProto3(this, 1, 0)); +}; + + +/** @param {number} value */ +proto.routeguide.RouteSummary.prototype.setPointCount = function(value) { + jspb.Message.setField(this, 1, value); +}; + + +/** + * optional int32 feature_count = 2; + * @return {number} + */ +proto.routeguide.RouteSummary.prototype.getFeatureCount = function() { + return /** @type {number} */ (jspb.Message.getFieldProto3(this, 2, 0)); +}; + + +/** @param {number} value */ +proto.routeguide.RouteSummary.prototype.setFeatureCount = function(value) { + jspb.Message.setField(this, 2, value); +}; + + +/** + * optional int32 distance = 3; + * @return {number} + */ +proto.routeguide.RouteSummary.prototype.getDistance = function() { + return /** @type {number} */ (jspb.Message.getFieldProto3(this, 3, 0)); +}; + + +/** @param {number} value */ +proto.routeguide.RouteSummary.prototype.setDistance = function(value) { + jspb.Message.setField(this, 3, value); +}; + + +/** + * optional int32 elapsed_time = 4; + * @return {number} + */ +proto.routeguide.RouteSummary.prototype.getElapsedTime = function() { + return /** @type {number} */ (jspb.Message.getFieldProto3(this, 4, 0)); +}; + + +/** @param {number} value */ +proto.routeguide.RouteSummary.prototype.setElapsedTime = function(value) { + jspb.Message.setField(this, 4, value); +}; + + +goog.object.extend(exports, proto.routeguide); diff --git a/examples/node/static_codegen/route_guide/route_guide_server.js b/examples/node/static_codegen/route_guide/route_guide_server.js new file mode 100644 index 0000000000..53628fb046 --- /dev/null +++ b/examples/node/static_codegen/route_guide/route_guide_server.js @@ -0,0 +1,261 @@ +/* + * + * 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. + * + */ + +var messages = require('./route_guide_pb'); +var services = require('./route_guide_grpc_pb'); + +var fs = require('fs'); +var parseArgs = require('minimist'); +var path = require('path'); +var _ = require('lodash'); +var grpc = require('grpc'); + +var COORD_FACTOR = 1e7; + +/** + * For simplicity, a point is a record type that looks like + * {latitude: number, longitude: number}, and a feature is a record type that + * looks like {name: string, location: point}. feature objects with name==='' + * are points with no feature. + */ + +/** + * List of feature objects at points that have been requested so far. + */ +var feature_list = []; + +/** + * Get a feature object at the given point, or creates one if it does not exist. + * @param {point} point The point to check + * @return {feature} The feature object at the point. Note that an empty name + * indicates no feature + */ +function checkFeature(point) { + var feature; + // Check if there is already a feature object for the given point + for (var i = 0; i < feature_list.length; i++) { + feature = feature_list[i]; + if (feature.getLocation().getLatitude() === point.getLatitude() && + feature.getLocation().getLongitude() === point.getLongitude()) { + return feature; + } + } + var name = ''; + feature = new messages.Feature(); + feature.setName(name); + feature.setLocation(point); + return feature; +} + +/** + * getFeature request handler. Gets a request with a point, and responds with a + * feature object indicating whether there is a feature at that point. + * @param {EventEmitter} call Call object for the handler to process + * @param {function(Error, feature)} callback Response callback + */ +function getFeature(call, callback) { + callback(null, checkFeature(call.request)); +} + +/** + * listFeatures request handler. Gets a request with two points, and responds + * with a stream of all features in the bounding box defined by those points. + * @param {Writable} call Writable stream for responses with an additional + * request property for the request value. + */ +function listFeatures(call) { + var lo = call.request.getLo(); + var hi = call.request.getHi(); + var left = _.min([lo.getLongitude(), hi.getLongitude()]); + var right = _.max([lo.getLongitude(), hi.getLongitude()]); + var top = _.max([lo.getLatitude(), hi.getLatitude()]); + var bottom = _.min([lo.getLatitude(), hi.getLatitude()]); + // For each feature, check if it is in the given bounding box + _.each(feature_list, function(feature) { + if (feature.getName() === '') { + return; + } + if (feature.getLocation().getLongitude() >= left && + feature.getLocation().getLongitude() <= right && + feature.getLocation().getLatitude() >= bottom && + feature.getLocation().getLatitude() <= top) { + call.write(feature); + } + }); + call.end(); +} + +/** + * Calculate the distance between two points using the "haversine" formula. + * This code was taken from http://www.movable-type.co.uk/scripts/latlong.html. + * @param start The starting point + * @param end The end point + * @return The distance between the points in meters + */ +function getDistance(start, end) { + function toRadians(num) { + return num * Math.PI / 180; + } + var lat1 = start.getLatitude() / COORD_FACTOR; + var lat2 = end.getLatitude() / COORD_FACTOR; + var lon1 = start.getLongitude() / COORD_FACTOR; + var lon2 = end.getLongitude() / COORD_FACTOR; + var R = 6371000; // metres + var φ1 = toRadians(lat1); + var φ2 = toRadians(lat2); + var Δφ = toRadians(lat2-lat1); + var Δλ = toRadians(lon2-lon1); + + var a = Math.sin(Δφ/2) * Math.sin(Δφ/2) + + Math.cos(φ1) * Math.cos(φ2) * + Math.sin(Δλ/2) * Math.sin(Δλ/2); + var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); + + return R * c; +} + +/** + * recordRoute handler. Gets a stream of points, and responds with statistics + * about the "trip": number of points, number of known features visited, total + * distance traveled, and total time spent. + * @param {Readable} call The request point stream. + * @param {function(Error, routeSummary)} callback The callback to pass the + * response to + */ +function recordRoute(call, callback) { + var point_count = 0; + var feature_count = 0; + var distance = 0; + var previous = null; + // Start a timer + var start_time = process.hrtime(); + call.on('data', function(point) { + point_count += 1; + if (checkFeature(point).name !== '') { + feature_count += 1; + } + /* For each point after the first, add the incremental distance from the + * previous point to the total distance value */ + if (previous != null) { + distance += getDistance(previous, point); + } + previous = point; + }); + call.on('end', function() { + var summary = new messages.RouteSummary(); + summary.setPointCount(point_count); + summary.setFeatureCount(feature_count); + // Cast the distance to an integer + summary.setDistance(distance|0); + // End the timer + summary.setElapsedTime(process.hrtime(start_time)[0]); + callback(null, summary); + }); +} + +var route_notes = {}; + +/** + * Turn the point into a dictionary key. + * @param {point} point The point to use + * @return {string} The key for an object + */ +function pointKey(point) { + return point.getLatitude() + ' ' + point.getLongitude(); +} + +/** + * routeChat handler. Receives a stream of message/location pairs, and responds + * with a stream of all previous messages at each of those locations. + * @param {Duplex} call The stream for incoming and outgoing messages + */ +function routeChat(call) { + call.on('data', function(note) { + var key = pointKey(note.getLocation()); + /* For each note sent, respond with all previous notes that correspond to + * the same point */ + if (route_notes.hasOwnProperty(key)) { + _.each(route_notes[key], function(note) { + call.write(note); + }); + } else { + route_notes[key] = []; + } + // Then add the new note to the list + route_notes[key].push(note); + }); + call.on('end', function() { + call.end(); + }); +} + +/** + * Get a new server with the handler functions in this file bound to the methods + * it serves. + * @return {Server} The new server object + */ +function getServer() { + var server = new grpc.Server(); + server.addService(services.RouteGuideService, { + getFeature: getFeature, + listFeatures: listFeatures, + recordRoute: recordRoute, + routeChat: routeChat + }); + return server; +} + +if (require.main === module) { + // If this is run as a script, start a server on an unused port + var routeServer = getServer(); + routeServer.bind('0.0.0.0:50051', grpc.ServerCredentials.createInsecure()); + var argv = parseArgs(process.argv, { + string: 'db_path' + }); + fs.readFile(path.resolve(argv.db_path), function(err, data) { + if (err) throw err; + // Transform the loaded features to Feature objects + feature_list = _.map(JSON.parse(data), function(value) { + var feature = new messages.Feature(); + feature.setName(value.name); + var location = new messages.Point(); + location.setLatitude(value.location.latitude); + location.setLongitude(value.location.longitude); + feature.setLocation(location); + return feature; + }); + routeServer.start(); + }); +} + +exports.getServer = getServer; diff --git a/gRPC.podspec b/gRPC.podspec index 785f2e1705..41dcdcd9ac 100644 --- a/gRPC.podspec +++ b/gRPC.podspec @@ -299,6 +299,7 @@ Pod::Spec.new do |s| 'src/core/ext/client_config/subchannel_call_holder.h', 'src/core/ext/client_config/subchannel_index.h', 'src/core/ext/client_config/uri_parser.h', + 'third_party/objective_c/Cronet/cronet_c_for_grpc.h', 'src/core/ext/lb_policy/grpclb/load_balancer_api.h', 'src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h', 'third_party/nanopb/pb.h', @@ -337,6 +338,7 @@ Pod::Spec.new do |s| 'include/grpc/impl/codegen/sync_posix.h', 'include/grpc/impl/codegen/sync_win32.h', 'include/grpc/impl/codegen/time.h', + 'include/grpc/grpc_cronet.h', 'include/grpc/grpc_security.h', 'include/grpc/grpc_security_constants.h', 'include/grpc/census.h', @@ -496,6 +498,9 @@ Pod::Spec.new do |s| 'src/core/ext/client_config/uri_parser.c', 'src/core/ext/transport/chttp2/server/insecure/server_chttp2.c', 'src/core/ext/transport/chttp2/client/insecure/channel_create.c', + 'src/core/ext/transport/cronet/client/secure/cronet_channel_create.c', + 'src/core/ext/transport/cronet/transport/cronet_api_dummy.c', + 'src/core/ext/transport/cronet/transport/cronet_transport.c', 'src/core/ext/lb_policy/grpclb/load_balancer_api.c', 'src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c', 'third_party/nanopb/pb_common.c', @@ -663,6 +668,7 @@ Pod::Spec.new do |s| 'src/core/ext/client_config/subchannel_call_holder.h', 'src/core/ext/client_config/subchannel_index.h', 'src/core/ext/client_config/uri_parser.h', + 'third_party/objective_c/Cronet/cronet_c_for_grpc.h', 'src/core/ext/lb_policy/grpclb/load_balancer_api.h', 'src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h', 'third_party/nanopb/pb.h', @@ -87,6 +87,7 @@ EXPORTS grpc_header_nonbin_value_is_legal grpc_is_binary_header grpc_call_error_to_string + grpc_cronet_secure_channel_create grpc_auth_property_iterator_next grpc_auth_context_property_iterator grpc_auth_context_peer_identity diff --git a/grpc.gemspec b/grpc.gemspec index 3ea5f851b9..6cb0594bd3 100755 --- a/grpc.gemspec +++ b/grpc.gemspec @@ -169,6 +169,7 @@ Gem::Specification.new do |s| s.files += %w( include/grpc/impl/codegen/sync_posix.h ) s.files += %w( include/grpc/impl/codegen/sync_win32.h ) s.files += %w( include/grpc/impl/codegen/time.h ) + s.files += %w( include/grpc/grpc_cronet.h ) s.files += %w( include/grpc/grpc_security.h ) s.files += %w( include/grpc/grpc_security_constants.h ) s.files += %w( include/grpc/census.h ) @@ -307,6 +308,7 @@ Gem::Specification.new do |s| s.files += %w( src/core/ext/client_config/subchannel_call_holder.h ) s.files += %w( src/core/ext/client_config/subchannel_index.h ) s.files += %w( src/core/ext/client_config/uri_parser.h ) + s.files += %w( third_party/objective_c/Cronet/cronet_c_for_grpc.h ) s.files += %w( src/core/ext/lb_policy/grpclb/load_balancer_api.h ) s.files += %w( src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h ) s.files += %w( third_party/nanopb/pb.h ) @@ -475,6 +477,9 @@ Gem::Specification.new do |s| s.files += %w( src/core/ext/client_config/uri_parser.c ) s.files += %w( src/core/ext/transport/chttp2/server/insecure/server_chttp2.c ) s.files += %w( src/core/ext/transport/chttp2/client/insecure/channel_create.c ) + s.files += %w( src/core/ext/transport/cronet/client/secure/cronet_channel_create.c ) + s.files += %w( src/core/ext/transport/cronet/transport/cronet_api_dummy.c ) + s.files += %w( src/core/ext/transport/cronet/transport/cronet_transport.c ) s.files += %w( src/core/ext/lb_policy/grpclb/load_balancer_api.c ) s.files += %w( src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c ) s.files += %w( third_party/nanopb/pb_common.c ) diff --git a/include/grpc/grpc_cronet.h b/include/grpc/grpc_cronet.h new file mode 100644 index 0000000000..295e0f55e8 --- /dev/null +++ b/include/grpc/grpc_cronet.h @@ -0,0 +1,51 @@ +/* + * + * Copyright 2016, 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_GRPC_CRONET_H +#define GRPC_GRPC_CRONET_H + +#include <grpc/grpc.h> + +#ifdef __cplusplus +extern "C" { +#endif + +GRPCAPI grpc_channel *grpc_cronet_secure_channel_create( + void *engine, const char *target, const grpc_channel_args *args, + void *reserved); + +#ifdef __cplusplus +} +#endif + +#endif /* GRPC_GRPC_CRONET_H */ diff --git a/package.xml b/package.xml index 8b1b8b293d..08f2386b2b 100644 --- a/package.xml +++ b/package.xml @@ -176,6 +176,7 @@ <file baseinstalldir="/" name="include/grpc/impl/codegen/sync_posix.h" role="src" /> <file baseinstalldir="/" name="include/grpc/impl/codegen/sync_win32.h" role="src" /> <file baseinstalldir="/" name="include/grpc/impl/codegen/time.h" role="src" /> + <file baseinstalldir="/" name="include/grpc/grpc_cronet.h" role="src" /> <file baseinstalldir="/" name="include/grpc/grpc_security.h" role="src" /> <file baseinstalldir="/" name="include/grpc/grpc_security_constants.h" role="src" /> <file baseinstalldir="/" name="include/grpc/census.h" role="src" /> @@ -314,6 +315,7 @@ <file baseinstalldir="/" name="src/core/ext/client_config/subchannel_call_holder.h" role="src" /> <file baseinstalldir="/" name="src/core/ext/client_config/subchannel_index.h" role="src" /> <file baseinstalldir="/" name="src/core/ext/client_config/uri_parser.h" role="src" /> + <file baseinstalldir="/" name="third_party/objective_c/Cronet/cronet_c_for_grpc.h" role="src" /> <file baseinstalldir="/" name="src/core/ext/lb_policy/grpclb/load_balancer_api.h" role="src" /> <file baseinstalldir="/" name="src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h" role="src" /> <file baseinstalldir="/" name="third_party/nanopb/pb.h" role="src" /> @@ -482,6 +484,9 @@ <file baseinstalldir="/" name="src/core/ext/client_config/uri_parser.c" role="src" /> <file baseinstalldir="/" name="src/core/ext/transport/chttp2/server/insecure/server_chttp2.c" role="src" /> <file baseinstalldir="/" name="src/core/ext/transport/chttp2/client/insecure/channel_create.c" role="src" /> + <file baseinstalldir="/" name="src/core/ext/transport/cronet/client/secure/cronet_channel_create.c" role="src" /> + <file baseinstalldir="/" name="src/core/ext/transport/cronet/transport/cronet_api_dummy.c" role="src" /> + <file baseinstalldir="/" name="src/core/ext/transport/cronet/transport/cronet_transport.c" role="src" /> <file baseinstalldir="/" name="src/core/ext/lb_policy/grpclb/load_balancer_api.c" role="src" /> <file baseinstalldir="/" name="src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c" role="src" /> <file baseinstalldir="/" name="third_party/nanopb/pb_common.c" role="src" /> diff --git a/src/compiler/python_generator.cc b/src/compiler/python_generator.cc index 8e76e6dce6..cd5ddd8832 100644 --- a/src/compiler/python_generator.cc +++ b/src/compiler/python_generator.cc @@ -147,7 +147,8 @@ class IndentScope { // END FORMATTING BOILERPLATE // //////////////////////////////// -// TODO(protobuf team): Export `ModuleName` from protobuf's +// TODO(https://github.com/google/protobuf/issues/888): +// Export `ModuleName` from protobuf's // `src/google/protobuf/compiler/python/python_generator.cc` file. grpc::string ModuleName(const grpc::string& filename) { grpc::string basename = StripProto(filename); @@ -156,8 +157,23 @@ grpc::string ModuleName(const grpc::string& filename) { return basename + "_pb2"; } +// TODO(https://github.com/google/protobuf/issues/888): +// Export `ModuleAlias` from protobuf's +// `src/google/protobuf/compiler/python/python_generator.cc` file. +grpc::string ModuleAlias(const grpc::string& filename) { + grpc::string module_name = ModuleName(filename); + // We can't have dots in the module name, so we replace each with _dot_. + // But that could lead to a collision between a.b and a_dot_b, so we also + // duplicate each underscore. + module_name = StringReplace(module_name, "_", "__"); + module_name = StringReplace(module_name, ".", "_dot_"); + return module_name; +} + + bool GetModuleAndMessagePath(const Descriptor* type, - pair<grpc::string, grpc::string>* out) { + const ServiceDescriptor* service, + grpc::string* out) { const Descriptor* path_elem_type = type; vector<const Descriptor*> message_path; do { @@ -170,7 +186,9 @@ bool GetModuleAndMessagePath(const Descriptor* type, file_name.find_last_of(".proto") == file_name.size() - 1)) { return false; } - grpc::string module = ModuleName(file_name); + grpc::string service_file_name = service->file()->name(); + grpc::string module = service_file_name == file_name ? + "" : ModuleAlias(file_name) + "."; grpc::string message_type; for (auto path_iter = message_path.rbegin(); path_iter != message_path.rend(); ++path_iter) { @@ -178,7 +196,7 @@ bool GetModuleAndMessagePath(const Descriptor* type, } // no pop_back prior to C++11 message_type.resize(message_type.size() - 1); - *out = make_pair(module, message_type); + *out = module + message_type; return true; } @@ -210,7 +228,7 @@ static void PrintAllComments(const DescriptorType* desc, Printer* printer) { bool PrintBetaServicer(const ServiceDescriptor* service, Printer* out) { - out->Print("\n"); + out->Print("\n\n"); out->Print("class Beta$Service$Servicer(object):\n", "Service", service->name()); { @@ -234,7 +252,7 @@ bool PrintBetaServicer(const ServiceDescriptor* service, bool PrintBetaStub(const ServiceDescriptor* service, Printer* out) { - out->Print("\n"); + out->Print("\n\n"); out->Print("class Beta$Service$Stub(object):\n", "Service", service->name()); { IndentScope raii_class_indent(out); @@ -244,7 +262,7 @@ bool PrintBetaStub(const ServiceDescriptor* service, grpc::string arg_name = meth->client_streaming() ? "request_iterator" : "request"; auto methdict = ListToDict({"Method", meth->name(), "ArgName", arg_name}); - out->Print(methdict, "def $Method$(self, $ArgName$, timeout):\n"); + out->Print(methdict, "def $Method$(self, $ArgName$, timeout, metadata=None, with_call=False, protocol_options=None):\n"); { IndentScope raii_method_indent(out); PrintAllComments(meth, out); @@ -260,38 +278,31 @@ bool PrintBetaStub(const ServiceDescriptor* service, bool PrintBetaServerFactory(const grpc::string& package_qualified_service_name, const ServiceDescriptor* service, Printer* out) { - out->Print("\n"); + out->Print("\n\n"); out->Print("def beta_create_$Service$_server(servicer, pool=None, " "pool_size=None, default_timeout=None, maximum_timeout=None):\n", "Service", service->name()); { IndentScope raii_create_server_indent(out); map<grpc::string, grpc::string> method_implementation_constructors; - map<grpc::string, pair<grpc::string, grpc::string>> - input_message_modules_and_classes; - map<grpc::string, pair<grpc::string, grpc::string>> - output_message_modules_and_classes; + map<grpc::string, grpc::string> input_message_modules_and_classes; + map<grpc::string, grpc::string> output_message_modules_and_classes; for (int i = 0; i < service->method_count(); ++i) { const MethodDescriptor* method = service->method(i); const grpc::string method_implementation_constructor = grpc::string(method->client_streaming() ? "stream_" : "unary_") + grpc::string(method->server_streaming() ? "stream_" : "unary_") + "inline"; - pair<grpc::string, grpc::string> input_message_module_and_class; - if (!GetModuleAndMessagePath(method->input_type(), + grpc::string input_message_module_and_class; + if (!GetModuleAndMessagePath(method->input_type(), service, &input_message_module_and_class)) { return false; } - pair<grpc::string, grpc::string> output_message_module_and_class; - if (!GetModuleAndMessagePath(method->output_type(), + grpc::string output_message_module_and_class; + if (!GetModuleAndMessagePath(method->output_type(), service, &output_message_module_and_class)) { return false; } - // Import the modules that define the messages used in RPCs. - out->Print("import $Module$\n", "Module", - input_message_module_and_class.first); - out->Print("import $Module$\n", "Module", - output_message_module_and_class.first); method_implementation_constructors.insert( make_pair(method->name(), method_implementation_constructor)); input_message_modules_and_classes.insert( @@ -307,13 +318,11 @@ bool PrintBetaServerFactory(const grpc::string& package_qualified_service_name, name_and_input_module_class_pair++) { IndentScope raii_indent(out); out->Print("(\'$PackageQualifiedServiceName$\', \'$MethodName$\'): " - "$InputTypeModule$.$InputTypeClass$.FromString,\n", + "$InputTypeModuleAndClass$.FromString,\n", "PackageQualifiedServiceName", package_qualified_service_name, "MethodName", name_and_input_module_class_pair->first, - "InputTypeModule", - name_and_input_module_class_pair->second.first, - "InputTypeClass", - name_and_input_module_class_pair->second.second); + "InputTypeModuleAndClass", + name_and_input_module_class_pair->second); } out->Print("}\n"); out->Print("response_serializers = {\n"); @@ -324,13 +333,11 @@ bool PrintBetaServerFactory(const grpc::string& package_qualified_service_name, name_and_output_module_class_pair++) { IndentScope raii_indent(out); out->Print("(\'$PackageQualifiedServiceName$\', \'$MethodName$\'): " - "$OutputTypeModule$.$OutputTypeClass$.SerializeToString,\n", + "$OutputTypeModuleAndClass$.SerializeToString,\n", "PackageQualifiedServiceName", package_qualified_service_name, "MethodName", name_and_output_module_class_pair->first, - "OutputTypeModule", - name_and_output_module_class_pair->second.first, - "OutputTypeClass", - name_and_output_module_class_pair->second.second); + "OutputTypeModuleAndClass", + name_and_output_module_class_pair->second); } out->Print("}\n"); out->Print("method_implementations = {\n"); @@ -366,37 +373,30 @@ bool PrintBetaStubFactory(const grpc::string& package_qualified_service_name, map<grpc::string, grpc::string> dict = ListToDict({ "Service", service->name(), }); - out->Print("\n"); + out->Print("\n\n"); out->Print(dict, "def beta_create_$Service$_stub(channel, host=None," " metadata_transformer=None, pool=None, pool_size=None):\n"); { IndentScope raii_create_server_indent(out); map<grpc::string, grpc::string> method_cardinalities; - map<grpc::string, pair<grpc::string, grpc::string>> - input_message_modules_and_classes; - map<grpc::string, pair<grpc::string, grpc::string>> - output_message_modules_and_classes; + map<grpc::string, grpc::string> input_message_modules_and_classes; + map<grpc::string, grpc::string> output_message_modules_and_classes; for (int i = 0; i < service->method_count(); ++i) { const MethodDescriptor* method = service->method(i); const grpc::string method_cardinality = grpc::string(method->client_streaming() ? "STREAM" : "UNARY") + "_" + - grpc::string(method->server_streaming() ? "STREAM" : "UNARY"); - pair<grpc::string, grpc::string> input_message_module_and_class; - if (!GetModuleAndMessagePath(method->input_type(), + grpc::string(method->server_streaming() ? "STREAM" : "UNARY"); + grpc::string input_message_module_and_class; + if (!GetModuleAndMessagePath(method->input_type(), service, &input_message_module_and_class)) { return false; } - pair<grpc::string, grpc::string> output_message_module_and_class; - if (!GetModuleAndMessagePath(method->output_type(), + grpc::string output_message_module_and_class; + if (!GetModuleAndMessagePath(method->output_type(), service, &output_message_module_and_class)) { return false; } - // Import the modules that define the messages used in RPCs. - out->Print("import $Module$\n", "Module", - input_message_module_and_class.first); - out->Print("import $Module$\n", "Module", - output_message_module_and_class.first); method_cardinalities.insert( make_pair(method->name(), method_cardinality)); input_message_modules_and_classes.insert( @@ -412,13 +412,11 @@ bool PrintBetaStubFactory(const grpc::string& package_qualified_service_name, name_and_input_module_class_pair++) { IndentScope raii_indent(out); out->Print("(\'$PackageQualifiedServiceName$\', \'$MethodName$\'): " - "$InputTypeModule$.$InputTypeClass$.SerializeToString,\n", + "$InputTypeModuleAndClass$.SerializeToString,\n", "PackageQualifiedServiceName", package_qualified_service_name, "MethodName", name_and_input_module_class_pair->first, - "InputTypeModule", - name_and_input_module_class_pair->second.first, - "InputTypeClass", - name_and_input_module_class_pair->second.second); + "InputTypeModuleAndClass", + name_and_input_module_class_pair->second); } out->Print("}\n"); out->Print("response_deserializers = {\n"); @@ -429,13 +427,11 @@ bool PrintBetaStubFactory(const grpc::string& package_qualified_service_name, name_and_output_module_class_pair++) { IndentScope raii_indent(out); out->Print("(\'$PackageQualifiedServiceName$\', \'$MethodName$\'): " - "$OutputTypeModule$.$OutputTypeClass$.FromString,\n", + "$OutputTypeModuleAndClass$.FromString,\n", "PackageQualifiedServiceName", package_qualified_service_name, "MethodName", name_and_output_module_class_pair->first, - "OutputTypeModule", - name_and_output_module_class_pair->second.first, - "OutputTypeClass", - name_and_output_module_class_pair->second.second); + "OutputTypeModuleAndClass", + name_and_output_module_class_pair->second); } out->Print("}\n"); out->Print("cardinalities = {\n"); @@ -463,8 +459,6 @@ bool PrintBetaStubFactory(const grpc::string& package_qualified_service_name, bool PrintPreamble(const FileDescriptor* file, const GeneratorConfiguration& config, Printer* out) { - out->Print("import abc\n"); - out->Print("import six\n"); out->Print("from $Package$ import implementations as beta_implementations\n", "Package", config.beta_package_root); out->Print("from $Package$ import interfaces as beta_interfaces\n", diff --git a/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c b/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c index a74c1a27eb..629959b7c0 100644 --- a/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c +++ b/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c @@ -178,6 +178,7 @@ int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr, grpc_server_security_connector *sc = NULL; grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_error *err = GRPC_ERROR_NONE; + grpc_error **errors = NULL; GRPC_API_TRACE( "grpc_server_add_secure_http2_port(" @@ -220,7 +221,7 @@ int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr, gpr_mu_init(&state->mu); gpr_ref_init(&state->refcount, 1); - grpc_error **errors = gpr_malloc(sizeof(*errors) * resolved->naddrs); + errors = gpr_malloc(sizeof(*errors) * resolved->naddrs); for (i = 0; i < resolved->naddrs; i++) { errors[i] = grpc_tcp_server_add_port( tcp, (struct sockaddr *)&resolved->addrs[i].addr, diff --git a/src/core/ext/transport/cronet/client/secure/cronet_channel_create.c b/src/core/ext/transport/cronet/client/secure/cronet_channel_create.c new file mode 100644 index 0000000000..df1acddcc0 --- /dev/null +++ b/src/core/ext/transport/cronet/client/secure/cronet_channel_create.c @@ -0,0 +1,69 @@ +/* + * + * Copyright 2016, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <grpc/impl/codegen/port_platform.h> + +#include <stdio.h> +#include <string.h> + +#include <grpc/support/alloc.h> +#include <grpc/support/log.h> + +#include "src/core/lib/surface/channel.h" +#include "src/core/lib/transport/transport_impl.h" + +// Cronet transport object +typedef struct cronet_transport { + grpc_transport base; // must be first element in this structure + void *engine; + char *host; +} cronet_transport; + +extern grpc_transport_vtable grpc_cronet_vtable; + +GRPCAPI grpc_channel *grpc_cronet_secure_channel_create( + void *engine, const char *target, const grpc_channel_args *args, + void *reserved) { + cronet_transport *ct = gpr_malloc(sizeof(cronet_transport)); + ct->base.vtable = &grpc_cronet_vtable; + ct->engine = engine; + ct->host = gpr_malloc(strlen(target) + 1); + strcpy(ct->host, target); + gpr_log(GPR_DEBUG, + "grpc_create_cronet_transport: cronet_engine = %p, target=%s", engine, + ct->host); + + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + return grpc_channel_create(&exec_ctx, target, args, + GRPC_CLIENT_DIRECT_CHANNEL, (grpc_transport *)ct); +} diff --git a/src/core/ext/transport/cronet/transport/cronet_api_dummy.c b/src/core/ext/transport/cronet/transport/cronet_api_dummy.c new file mode 100644 index 0000000000..687026c9fd --- /dev/null +++ b/src/core/ext/transport/cronet/transport/cronet_api_dummy.c @@ -0,0 +1,85 @@ +/* + * + * Copyright 2016, 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. + * + */ + +/* This file has empty implementation of all the functions exposed by the cronet +library, so we can build it in all environments */ + +#include <stdbool.h> + +#include <grpc/support/log.h> + +#include "third_party/objective_c/Cronet/cronet_c_for_grpc.h" + +#ifdef GRPC_COMPILE_WITH_CRONET +/* link with the real CRONET library in the build system */ +#else +/* Dummy implementation of cronet API just to test for build-ability */ +cronet_bidirectional_stream* cronet_bidirectional_stream_create( + cronet_engine* engine, void* annotation, + cronet_bidirectional_stream_callback* callback) { + GPR_ASSERT(0); + return NULL; +} + +int cronet_bidirectional_stream_destroy(cronet_bidirectional_stream* stream) { + GPR_ASSERT(0); + return 0; +} + +int cronet_bidirectional_stream_start( + cronet_bidirectional_stream* stream, const char* url, int priority, + const char* method, const cronet_bidirectional_stream_header_array* headers, + bool end_of_stream) { + GPR_ASSERT(0); + return 0; +} + +int cronet_bidirectional_stream_read(cronet_bidirectional_stream* stream, + char* buffer, int capacity) { + GPR_ASSERT(0); + return 0; +} + +int cronet_bidirectional_stream_write(cronet_bidirectional_stream* stream, + const char* buffer, int count, + bool end_of_stream) { + GPR_ASSERT(0); + return 0; +} + +int cronet_bidirectional_stream_cancel(cronet_bidirectional_stream* stream) { + GPR_ASSERT(0); + return 0; +} + +#endif /* GRPC_COMPILE_WITH_CRONET */ diff --git a/src/core/ext/transport/cronet/transport/cronet_transport.c b/src/core/ext/transport/cronet/transport/cronet_transport.c new file mode 100644 index 0000000000..ea0f2bcba4 --- /dev/null +++ b/src/core/ext/transport/cronet/transport/cronet_transport.c @@ -0,0 +1,640 @@ +/* + * + * Copyright 2016, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <string.h> + +#include <grpc/impl/codegen/port_platform.h> +#include <grpc/support/alloc.h> +#include <grpc/support/host_port.h> +#include <grpc/support/log.h> +#include <grpc/support/slice_buffer.h> +#include <grpc/support/string_util.h> +#include <grpc/support/useful.h> + +#include "src/core/ext/transport/chttp2/transport/incoming_metadata.h" +#include "src/core/lib/iomgr/exec_ctx.h" +#include "src/core/lib/support/string.h" +#include "src/core/lib/surface/channel.h" +#include "src/core/lib/transport/metadata_batch.h" +#include "src/core/lib/transport/transport_impl.h" +#include "third_party/objective_c/Cronet/cronet_c_for_grpc.h" + +#define GRPC_HEADER_SIZE_IN_BYTES 5 + +// Global flag that gets set with GRPC_TRACE env variable +int grpc_cronet_trace = 1; + +// Cronet transport object +struct grpc_cronet_transport { + grpc_transport base; /* must be first element in this structure */ + cronet_engine *engine; + char *host; +}; + +typedef struct grpc_cronet_transport grpc_cronet_transport; + +enum send_state { + CRONET_SEND_IDLE = 0, + CRONET_REQ_STARTED, + CRONET_SEND_HEADER, + CRONET_WRITE, + CRONET_WRITE_COMPLETED, +}; + +enum recv_state { + CRONET_RECV_IDLE = 0, + CRONET_RECV_READ_LENGTH, + CRONET_RECV_READ_DATA, + CRONET_RECV_CLOSED, +}; + +static const char *recv_state_name[] = { + "CRONET_RECV_IDLE", "CRONET_RECV_READ_LENGTH", "CRONET_RECV_READ_DATA,", + "CRONET_RECV_CLOSED"}; + +// Enum that identifies calling function. +enum e_caller { + PERFORM_STREAM_OP, + ON_READ_COMPLETE, + ON_RESPONSE_HEADERS_RECEIVED, + ON_RESPONSE_TRAILERS_RECEIVED +}; + +enum callback_id { + CB_SEND_INITIAL_METADATA = 0, + CB_SEND_MESSAGE, + CB_SEND_TRAILING_METADATA, + CB_RECV_MESSAGE, + CB_RECV_INITIAL_METADATA, + CB_RECV_TRAILING_METADATA, + CB_NUM_CALLBACKS +}; + +struct stream_obj { + // we store received bytes here as they trickle in. + gpr_slice_buffer write_slice_buffer; + cronet_bidirectional_stream *cbs; + gpr_slice slice; + gpr_slice_buffer read_slice_buffer; + struct grpc_slice_buffer_stream sbs; + char *read_buffer; + int remaining_read_bytes; + int total_read_bytes; + + char *write_buffer; + size_t write_buffer_size; + + // Hold the URL + char *url; + + bool response_headers_received; + bool read_requested; + bool response_trailers_received; + bool read_closed; + + // Recv message stuff + grpc_byte_buffer **recv_message; + // Initial metadata stuff + grpc_metadata_batch *recv_initial_metadata; + // Trailing metadata stuff + grpc_metadata_batch *recv_trailing_metadata; + grpc_chttp2_incoming_metadata_buffer imb; + + // This mutex protects receive state machine execution + gpr_mu recv_mu; + // we can queue up up to 2 callbacks for each OP + grpc_closure *callback_list[CB_NUM_CALLBACKS][2]; + + // storage for header + cronet_bidirectional_stream_header *headers; + uint32_t num_headers; + cronet_bidirectional_stream_header_array header_array; + // state tracking + enum recv_state cronet_recv_state; + enum send_state cronet_send_state; +}; + +typedef struct stream_obj stream_obj; + +static void next_send_step(stream_obj *s); +static void next_recv_step(stream_obj *s, enum e_caller caller); + +static void set_pollset_do_nothing(grpc_exec_ctx *exec_ctx, grpc_transport *gt, + grpc_stream *gs, grpc_pollset *pollset) {} + +static void enqueue_callbacks(grpc_closure *callback_list[]) { + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + if (callback_list[0]) { + grpc_exec_ctx_push(&exec_ctx, callback_list[0], GRPC_ERROR_NONE, NULL); + callback_list[0] = NULL; + } + if (callback_list[1]) { + grpc_exec_ctx_push(&exec_ctx, callback_list[1], GRPC_ERROR_NONE, NULL); + callback_list[1] = NULL; + } + grpc_exec_ctx_finish(&exec_ctx); +} + +static void on_canceled(cronet_bidirectional_stream *stream) { + if (grpc_cronet_trace) { + gpr_log(GPR_DEBUG, "on_canceled %p", stream); + } +} + +static void on_failed(cronet_bidirectional_stream *stream, int net_error) { + if (grpc_cronet_trace) { + gpr_log(GPR_DEBUG, "on_failed %p, error = %d", stream, net_error); + } +} + +static void on_succeeded(cronet_bidirectional_stream *stream) { + if (grpc_cronet_trace) { + gpr_log(GPR_DEBUG, "on_succeeded %p", stream); + } +} + +static void on_response_trailers_received( + cronet_bidirectional_stream *stream, + const cronet_bidirectional_stream_header_array *trailers) { + if (grpc_cronet_trace) { + gpr_log(GPR_DEBUG, "R: on_response_trailers_received"); + } + stream_obj *s = (stream_obj *)stream->annotation; + + memset(&s->imb, 0, sizeof(s->imb)); + grpc_chttp2_incoming_metadata_buffer_init(&s->imb); + unsigned int i = 0; + for (i = 0; i < trailers->count; i++) { + grpc_chttp2_incoming_metadata_buffer_add( + &s->imb, grpc_mdelem_from_metadata_strings( + grpc_mdstr_from_string(trailers->headers[i].key), + grpc_mdstr_from_string(trailers->headers[i].value))); + } + s->response_trailers_received = true; + next_recv_step(s, ON_RESPONSE_TRAILERS_RECEIVED); +} + +static void on_write_completed(cronet_bidirectional_stream *stream, + const char *data) { + if (grpc_cronet_trace) { + gpr_log(GPR_DEBUG, "W: on_write_completed"); + } + stream_obj *s = (stream_obj *)stream->annotation; + enqueue_callbacks(s->callback_list[CB_SEND_MESSAGE]); + s->cronet_send_state = CRONET_WRITE_COMPLETED; + next_send_step(s); +} + +static void process_recv_message(stream_obj *s, const uint8_t *recv_data) { + gpr_slice read_data_slice = gpr_slice_malloc((uint32_t)s->total_read_bytes); + uint8_t *dst_p = GPR_SLICE_START_PTR(read_data_slice); + memcpy(dst_p, recv_data, (size_t)s->total_read_bytes); + gpr_slice_buffer_add(&s->read_slice_buffer, read_data_slice); + grpc_slice_buffer_stream_init(&s->sbs, &s->read_slice_buffer, 0); + *s->recv_message = (grpc_byte_buffer *)&s->sbs; +} + +static int parse_grpc_header(const uint8_t *data) { + const uint8_t *p = data + 1; + int length = 0; + length |= ((uint8_t)*p++) << 24; + length |= ((uint8_t)*p++) << 16; + length |= ((uint8_t)*p++) << 8; + length |= ((uint8_t)*p++); + return length; +} + +static void on_read_completed(cronet_bidirectional_stream *stream, char *data, + int count) { + stream_obj *s = (stream_obj *)stream->annotation; + if (grpc_cronet_trace) { + gpr_log(GPR_DEBUG, "R: on_read_completed count=%d, total=%d, remaining=%d", + count, s->total_read_bytes, s->remaining_read_bytes); + } + if (count > 0) { + GPR_ASSERT(s->recv_message); + s->remaining_read_bytes -= count; + next_recv_step(s, ON_READ_COMPLETE); + } else { + s->read_closed = true; + next_recv_step(s, ON_READ_COMPLETE); + } +} + +static void on_response_headers_received( + cronet_bidirectional_stream *stream, + const cronet_bidirectional_stream_header_array *headers, + const char *negotiated_protocol) { + if (grpc_cronet_trace) { + gpr_log(GPR_DEBUG, "R: on_response_headers_received"); + } + stream_obj *s = (stream_obj *)stream->annotation; + enqueue_callbacks(s->callback_list[CB_RECV_INITIAL_METADATA]); + s->response_headers_received = true; + next_recv_step(s, ON_RESPONSE_HEADERS_RECEIVED); +} + +static void on_request_headers_sent(cronet_bidirectional_stream *stream) { + if (grpc_cronet_trace) { + gpr_log(GPR_DEBUG, "W: on_request_headers_sent"); + } + stream_obj *s = (stream_obj *)stream->annotation; + enqueue_callbacks(s->callback_list[CB_SEND_INITIAL_METADATA]); + s->cronet_send_state = CRONET_SEND_HEADER; + next_send_step(s); +} + +// Callback function pointers (invoked by cronet in response to events) +static cronet_bidirectional_stream_callback callbacks = { + on_request_headers_sent, + on_response_headers_received, + on_read_completed, + on_write_completed, + on_response_trailers_received, + on_succeeded, + on_failed, + on_canceled}; + +static void invoke_closing_callback(stream_obj *s) { + grpc_chttp2_incoming_metadata_buffer_publish(&s->imb, + s->recv_trailing_metadata); + if (s->callback_list[CB_RECV_TRAILING_METADATA]) { + enqueue_callbacks(s->callback_list[CB_RECV_TRAILING_METADATA]); + } +} + +static void set_recv_state(stream_obj *s, enum recv_state state) { + if (grpc_cronet_trace) { + gpr_log(GPR_DEBUG, "next_state = %s", recv_state_name[state]); + } + s->cronet_recv_state = state; +} + +// This is invoked from perform_stream_op, and all on_xxxx callbacks. +static void next_recv_step(stream_obj *s, enum e_caller caller) { + gpr_mu_lock(&s->recv_mu); + switch (s->cronet_recv_state) { + case CRONET_RECV_IDLE: + if (grpc_cronet_trace) { + gpr_log(GPR_DEBUG, "cronet_recv_state = CRONET_RECV_IDLE"); + } + if (caller == PERFORM_STREAM_OP || + caller == ON_RESPONSE_HEADERS_RECEIVED) { + if (s->read_closed && s->response_trailers_received) { + invoke_closing_callback(s); + set_recv_state(s, CRONET_RECV_CLOSED); + } else if (s->response_headers_received == true && + s->read_requested == true) { + set_recv_state(s, CRONET_RECV_READ_LENGTH); + s->total_read_bytes = s->remaining_read_bytes = + GRPC_HEADER_SIZE_IN_BYTES; + GPR_ASSERT(s->read_buffer); + if (grpc_cronet_trace) { + gpr_log(GPR_DEBUG, "R: cronet_bidirectional_stream_read()"); + } + cronet_bidirectional_stream_read(s->cbs, s->read_buffer, + s->remaining_read_bytes); + } + } + break; + case CRONET_RECV_READ_LENGTH: + if (grpc_cronet_trace) { + gpr_log(GPR_DEBUG, "cronet_recv_state = CRONET_RECV_READ_LENGTH"); + } + if (caller == ON_READ_COMPLETE) { + if (s->read_closed) { + invoke_closing_callback(s); + enqueue_callbacks(s->callback_list[CB_RECV_MESSAGE]); + set_recv_state(s, CRONET_RECV_CLOSED); + } else { + GPR_ASSERT(s->remaining_read_bytes == 0); + set_recv_state(s, CRONET_RECV_READ_DATA); + s->total_read_bytes = s->remaining_read_bytes = + parse_grpc_header((const uint8_t *)s->read_buffer); + s->read_buffer = + gpr_realloc(s->read_buffer, (uint32_t)s->remaining_read_bytes); + GPR_ASSERT(s->read_buffer); + if (grpc_cronet_trace) { + gpr_log(GPR_DEBUG, "R: cronet_bidirectional_stream_read()"); + } + cronet_bidirectional_stream_read(s->cbs, (char *)s->read_buffer, + s->remaining_read_bytes); + } + } + break; + case CRONET_RECV_READ_DATA: + if (grpc_cronet_trace) { + gpr_log(GPR_DEBUG, "cronet_recv_state = CRONET_RECV_READ_DATA"); + } + if (caller == ON_READ_COMPLETE) { + if (s->remaining_read_bytes > 0) { + int offset = s->total_read_bytes - s->remaining_read_bytes; + GPR_ASSERT(s->read_buffer); + if (grpc_cronet_trace) { + gpr_log(GPR_DEBUG, "R: cronet_bidirectional_stream_read()"); + } + cronet_bidirectional_stream_read( + s->cbs, (char *)s->read_buffer + offset, s->remaining_read_bytes); + } else { + gpr_slice_buffer_init(&s->read_slice_buffer); + uint8_t *p = (uint8_t *)s->read_buffer; + process_recv_message(s, p); + set_recv_state(s, CRONET_RECV_IDLE); + enqueue_callbacks(s->callback_list[CB_RECV_MESSAGE]); + } + } + break; + case CRONET_RECV_CLOSED: + break; + default: + GPR_ASSERT(0); // Should not reach here + break; + } + gpr_mu_unlock(&s->recv_mu); +} + +// This function takes the data from s->write_slice_buffer and assembles into +// a contiguous byte stream with 5 byte gRPC header prepended. +static void create_grpc_frame(stream_obj *s) { + gpr_slice slice = gpr_slice_buffer_take_first(&s->write_slice_buffer); + uint8_t *raw_data = GPR_SLICE_START_PTR(slice); + size_t length = GPR_SLICE_LENGTH(slice); + s->write_buffer_size = length + GRPC_HEADER_SIZE_IN_BYTES; + s->write_buffer = gpr_realloc(s->write_buffer, s->write_buffer_size); + uint8_t *p = (uint8_t *)s->write_buffer; + // Append 5 byte header + *p++ = 0; + *p++ = (uint8_t)(length >> 24); + *p++ = (uint8_t)(length >> 16); + *p++ = (uint8_t)(length >> 8); + *p++ = (uint8_t)(length); + // append actual data + memcpy(p, raw_data, length); +} + +static void do_write(stream_obj *s) { + gpr_slice_buffer *sb = &s->write_slice_buffer; + GPR_ASSERT(sb->count <= 1); + if (sb->count > 0) { + create_grpc_frame(s); + if (grpc_cronet_trace) { + gpr_log(GPR_DEBUG, "W: cronet_bidirectional_stream_write"); + } + cronet_bidirectional_stream_write(s->cbs, s->write_buffer, + (int)s->write_buffer_size, false); + } +} + +// +static void next_send_step(stream_obj *s) { + switch (s->cronet_send_state) { + case CRONET_SEND_IDLE: + GPR_ASSERT( + s->cbs); // cronet_bidirectional_stream is not initialized yet. + s->cronet_send_state = CRONET_REQ_STARTED; + if (grpc_cronet_trace) { + gpr_log(GPR_DEBUG, "cronet_bidirectional_stream_start to %s", s->url); + } + cronet_bidirectional_stream_start(s->cbs, s->url, 0, "POST", + &s->header_array, false); + // we no longer need the memory that was allocated earlier. + gpr_free(s->header_array.headers); + break; + case CRONET_SEND_HEADER: + do_write(s); + s->cronet_send_state = CRONET_WRITE; + break; + case CRONET_WRITE_COMPLETED: + do_write(s); + break; + default: + GPR_ASSERT(0); + break; + } +} + +static void convert_metadata_to_cronet_headers(grpc_linked_mdelem *head, + const char *host, + stream_obj *s) { + grpc_linked_mdelem *curr = head; + // Walk the linked list and get number of header fields + uint32_t num_headers_available = 0; + while (curr != NULL) { + curr = curr->next; + num_headers_available++; + } + // Allocate enough memory + s->headers = (cronet_bidirectional_stream_header *)gpr_malloc( + sizeof(cronet_bidirectional_stream_header) * num_headers_available); + + // Walk the linked list again, this time copying the header fields. + // s->num_headers + // can be less than num_headers_available, as some headers are not used for + // cronet + curr = head; + s->num_headers = 0; + while (s->num_headers < num_headers_available) { + grpc_mdelem *mdelem = curr->md; + curr = curr->next; + const char *key = grpc_mdstr_as_c_string(mdelem->key); + const char *value = grpc_mdstr_as_c_string(mdelem->value); + if (strcmp(key, ":scheme") == 0 || strcmp(key, ":method") == 0 || + strcmp(key, ":authority") == 0) { + // Cronet populates these fields on its own. + continue; + } + if (strcmp(key, ":path") == 0) { + // Create URL by appending :path value to the hostname + gpr_asprintf(&s->url, "https://%s%s", host, value); + if (grpc_cronet_trace) { + gpr_log(GPR_DEBUG, "extracted URL = %s", s->url); + } + continue; + } + s->headers[s->num_headers].key = key; + s->headers[s->num_headers].value = value; + s->num_headers++; + if (curr == NULL) { + break; + } + } +} + +static void perform_stream_op(grpc_exec_ctx *exec_ctx, grpc_transport *gt, + grpc_stream *gs, grpc_transport_stream_op *op) { + grpc_cronet_transport *ct = (grpc_cronet_transport *)gt; + GPR_ASSERT(ct->engine); + stream_obj *s = (stream_obj *)gs; + if (op->recv_trailing_metadata) { + if (grpc_cronet_trace) { + gpr_log(GPR_DEBUG, + "perform_stream_op - recv_trailing_metadata: on_complete=%p", + op->on_complete); + } + s->recv_trailing_metadata = op->recv_trailing_metadata; + GPR_ASSERT(!s->callback_list[CB_RECV_TRAILING_METADATA][0]); + s->callback_list[CB_RECV_TRAILING_METADATA][0] = op->on_complete; + } + if (op->recv_message) { + if (grpc_cronet_trace) { + gpr_log(GPR_DEBUG, "perform_stream_op - recv_message: on_complete=%p", + op->on_complete); + } + s->recv_message = (grpc_byte_buffer **)op->recv_message; + GPR_ASSERT(!s->callback_list[CB_RECV_MESSAGE][0]); + GPR_ASSERT(!s->callback_list[CB_RECV_MESSAGE][1]); + s->callback_list[CB_RECV_MESSAGE][0] = op->recv_message_ready; + s->callback_list[CB_RECV_MESSAGE][1] = op->on_complete; + s->read_requested = true; + next_recv_step(s, PERFORM_STREAM_OP); + } + if (op->recv_initial_metadata) { + if (grpc_cronet_trace) { + gpr_log(GPR_DEBUG, "perform_stream_op - recv_initial_metadata:=%p", + op->on_complete); + } + s->recv_initial_metadata = op->recv_initial_metadata; + GPR_ASSERT(!s->callback_list[CB_RECV_INITIAL_METADATA][0]); + GPR_ASSERT(!s->callback_list[CB_RECV_INITIAL_METADATA][1]); + s->callback_list[CB_RECV_INITIAL_METADATA][0] = + op->recv_initial_metadata_ready; + s->callback_list[CB_RECV_INITIAL_METADATA][1] = op->on_complete; + } + if (op->send_initial_metadata) { + if (grpc_cronet_trace) { + gpr_log(GPR_DEBUG, + "perform_stream_op - send_initial_metadata: on_complete=%p", + op->on_complete); + } + s->num_headers = 0; + convert_metadata_to_cronet_headers(op->send_initial_metadata->list.head, + ct->host, s); + s->header_array.count = s->num_headers; + s->header_array.capacity = s->num_headers; + s->header_array.headers = s->headers; + GPR_ASSERT(!s->callback_list[CB_SEND_INITIAL_METADATA][0]); + s->callback_list[CB_SEND_INITIAL_METADATA][0] = op->on_complete; + } + if (op->send_message) { + if (grpc_cronet_trace) { + gpr_log(GPR_DEBUG, "perform_stream_op - send_message: on_complete=%p", + op->on_complete); + } + grpc_byte_stream_next(exec_ctx, op->send_message, &s->slice, + op->send_message->length, NULL); + // Check that compression flag is not ON. We don't support compression yet. + // TODO (makdharma): add compression support + GPR_ASSERT(op->send_message->flags == 0); + gpr_slice_buffer_add(&s->write_slice_buffer, s->slice); + if (s->cbs == NULL) { + if (grpc_cronet_trace) { + gpr_log(GPR_DEBUG, "cronet_bidirectional_stream_create"); + } + s->cbs = cronet_bidirectional_stream_create(ct->engine, s, &callbacks); + GPR_ASSERT(s->cbs); + s->read_closed = false; + s->response_trailers_received = false; + s->response_headers_received = false; + s->cronet_send_state = CRONET_SEND_IDLE; + s->cronet_recv_state = CRONET_RECV_IDLE; + } + GPR_ASSERT(!s->callback_list[CB_SEND_MESSAGE][0]); + s->callback_list[CB_SEND_MESSAGE][0] = op->on_complete; + next_send_step(s); + } + if (op->send_trailing_metadata) { + if (grpc_cronet_trace) { + gpr_log(GPR_DEBUG, + "perform_stream_op - send_trailing_metadata: on_complete=%p", + op->on_complete); + } + GPR_ASSERT(!s->callback_list[CB_SEND_TRAILING_METADATA][0]); + s->callback_list[CB_SEND_TRAILING_METADATA][0] = op->on_complete; + if (s->cbs) { + // Send an "empty" write to the far end to signal that we're done. + // This will induce the server to send down trailers. + if (grpc_cronet_trace) { + gpr_log(GPR_DEBUG, "W: cronet_bidirectional_stream_write"); + } + cronet_bidirectional_stream_write(s->cbs, "abc", 0, true); + } else { + // We never created a stream. This was probably an empty request. + invoke_closing_callback(s); + } + } +} + +static int init_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt, + grpc_stream *gs, grpc_stream_refcount *refcount, + const void *server_data) { + stream_obj *s = (stream_obj *)gs; + memset(s->callback_list, 0, sizeof(s->callback_list)); + s->cbs = NULL; + gpr_mu_init(&s->recv_mu); + s->read_buffer = gpr_malloc(GRPC_HEADER_SIZE_IN_BYTES); + s->write_buffer = gpr_malloc(GRPC_HEADER_SIZE_IN_BYTES); + gpr_slice_buffer_init(&s->write_slice_buffer); + if (grpc_cronet_trace) { + gpr_log(GPR_DEBUG, "cronet_transport - init_stream"); + } + return 0; +} + +static void destroy_stream(grpc_exec_ctx *exec_ctx, grpc_transport *gt, + grpc_stream *gs, void *and_free_memory) { + if (grpc_cronet_trace) { + gpr_log(GPR_DEBUG, "Destroy stream"); + } + stream_obj *s = (stream_obj *)gs; + s->cbs = NULL; + gpr_free(s->read_buffer); + gpr_free(s->write_buffer); + gpr_free(s->url); + gpr_mu_destroy(&s->recv_mu); + if (and_free_memory) { + gpr_free(and_free_memory); + } +} + +static void destroy_transport(grpc_exec_ctx *exec_ctx, grpc_transport *gt) { + grpc_cronet_transport *ct = (grpc_cronet_transport *)gt; + gpr_free(ct->host); + if (grpc_cronet_trace) { + gpr_log(GPR_DEBUG, "Destroy transport"); + } +} + +const grpc_transport_vtable grpc_cronet_vtable = { + sizeof(stream_obj), "cronet_http", init_stream, + set_pollset_do_nothing, perform_stream_op, NULL, + destroy_stream, destroy_transport, NULL}; diff --git a/src/core/lib/http/parser.c.orig b/src/core/lib/http/parser.c.orig new file mode 100644 index 0000000000..74d90fd8bf --- /dev/null +++ b/src/core/lib/http/parser.c.orig @@ -0,0 +1,357 @@ +/* + * + * 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. + * + */ + +#include "src/core/lib/http/parser.h" + +#include <string.h> + +#include <grpc/support/alloc.h> +#include <grpc/support/log.h> +#include <grpc/support/useful.h> + +int grpc_http1_trace = 0; + +static char *buf2str(void *buffer, size_t length) { + char *out = gpr_malloc(length + 1); + memcpy(out, buffer, length); + out[length] = 0; + return out; +} + +static grpc_error *handle_response_line(grpc_http_parser *parser) { + uint8_t *beg = parser->cur_line; + uint8_t *cur = beg; + uint8_t *end = beg + parser->cur_line_length; + + if (cur == end || *cur++ != 'H') return GRPC_ERROR_CREATE("Expected 'H'"); + if (cur == end || *cur++ != 'T') return GRPC_ERROR_CREATE("Expected 'T'"); + if (cur == end || *cur++ != 'T') return GRPC_ERROR_CREATE("Expected 'T'"); + if (cur == end || *cur++ != 'P') return GRPC_ERROR_CREATE("Expected 'P'"); + if (cur == end || *cur++ != '/') return GRPC_ERROR_CREATE("Expected '/'"); + if (cur == end || *cur++ != '1') return GRPC_ERROR_CREATE("Expected '1'"); + if (cur == end || *cur++ != '.') return GRPC_ERROR_CREATE("Expected '.'"); + if (cur == end || *cur < '0' || *cur++ > '1') { + return GRPC_ERROR_CREATE("Expected HTTP/1.0 or HTTP/1.1"); + } + if (cur == end || *cur++ != ' ') return GRPC_ERROR_CREATE("Expected ' '"); + if (cur == end || *cur < '1' || *cur++ > '9') + return GRPC_ERROR_CREATE("Expected status code"); + if (cur == end || *cur < '0' || *cur++ > '9') + return GRPC_ERROR_CREATE("Expected status code"); + if (cur == end || *cur < '0' || *cur++ > '9') + return GRPC_ERROR_CREATE("Expected status code"); + parser->http.response->status = + (cur[-3] - '0') * 100 + (cur[-2] - '0') * 10 + (cur[-1] - '0'); + if (cur == end || *cur++ != ' ') return GRPC_ERROR_CREATE("Expected ' '"); + + /* we don't really care about the status code message */ + + return GRPC_ERROR_NONE; +} + +static grpc_error *handle_request_line(grpc_http_parser *parser) { + uint8_t *beg = parser->cur_line; + uint8_t *cur = beg; + uint8_t *end = beg + parser->cur_line_length; + uint8_t vers_major = 0; + uint8_t vers_minor = 0; + + while (cur != end && *cur++ != ' ') + ; + if (cur == end) return GRPC_ERROR_CREATE("No method on HTTP request line"); + parser->http.request->method = buf2str(beg, (size_t)(cur - beg - 1)); + + beg = cur; + while (cur != end && *cur++ != ' ') + ; + if (cur == end) return GRPC_ERROR_CREATE("No path on HTTP request line"); + parser->http.request->path = buf2str(beg, (size_t)(cur - beg - 1)); + + if (cur == end || *cur++ != 'H') return GRPC_ERROR_CREATE("Expected 'H'"); + if (cur == end || *cur++ != 'T') return GRPC_ERROR_CREATE("Expected 'T'"); + if (cur == end || *cur++ != 'T') return GRPC_ERROR_CREATE("Expected 'T'"); + if (cur == end || *cur++ != 'P') return GRPC_ERROR_CREATE("Expected 'P'"); + if (cur == end || *cur++ != '/') return GRPC_ERROR_CREATE("Expected '/'"); + vers_major = (uint8_t)(*cur++ - '1' + 1); + ++cur; + if (cur == end) + return GRPC_ERROR_CREATE("End of line in HTTP version string"); + vers_minor = (uint8_t)(*cur++ - '1' + 1); + + if (vers_major == 1) { + if (vers_minor == 0) { + parser->http.request->version = GRPC_HTTP_HTTP10; + } else if (vers_minor == 1) { + parser->http.request->version = GRPC_HTTP_HTTP11; + } else { + return GRPC_ERROR_CREATE( + "Expected one of HTTP/1.0, HTTP/1.1, or HTTP/2.0"); + } + } else if (vers_major == 2) { + if (vers_minor == 0) { + parser->http.request->version = GRPC_HTTP_HTTP20; + } else { + return GRPC_ERROR_CREATE( + "Expected one of HTTP/1.0, HTTP/1.1, or HTTP/2.0"); + } + } else { + return GRPC_ERROR_CREATE("Expected one of HTTP/1.0, HTTP/1.1, or HTTP/2.0"); + } + + return GRPC_ERROR_NONE; +} + +static grpc_error *handle_first_line(grpc_http_parser *parser) { + switch (parser->type) { + case GRPC_HTTP_REQUEST: + return handle_request_line(parser); + case GRPC_HTTP_RESPONSE: + return handle_response_line(parser); + } + GPR_UNREACHABLE_CODE(return GRPC_ERROR_CREATE("Should never reach here")); +} + +static grpc_error *add_header(grpc_http_parser *parser) { + uint8_t *beg = parser->cur_line; + uint8_t *cur = beg; + uint8_t *end = beg + parser->cur_line_length; + size_t *hdr_count = NULL; + grpc_http_header **hdrs = NULL; + grpc_http_header hdr = {NULL, NULL}; + grpc_error *error = GRPC_ERROR_NONE; + + GPR_ASSERT(cur != end); + + if (*cur == ' ' || *cur == '\t') { + error = GRPC_ERROR_CREATE("Continued header lines not supported yet"); + goto done; + } + + while (cur != end && *cur != ':') { + cur++; + } + if (cur == end) { +<<<<<<< HEAD + error = GRPC_ERROR_CREATE("Didn't find ':' in header string"); + goto done; +======= + if (grpc_http1_trace) { + gpr_log(GPR_ERROR, "Didn't find ':' in header string"); + } + goto error; +>>>>>>> a709afe241d8b264a1c326315f757b4a8d330207 + } + GPR_ASSERT(cur >= beg); + hdr.key = buf2str(beg, (size_t)(cur - beg)); + cur++; /* skip : */ + + while (cur != end && (*cur == ' ' || *cur == '\t')) { + cur++; + } + GPR_ASSERT((size_t)(end - cur) >= parser->cur_line_end_length); + hdr.value = buf2str(cur, (size_t)(end - cur) - parser->cur_line_end_length); + + switch (parser->type) { + case GRPC_HTTP_RESPONSE: + hdr_count = &parser->http.response->hdr_count; + hdrs = &parser->http.response->hdrs; + break; + case GRPC_HTTP_REQUEST: + hdr_count = &parser->http.request->hdr_count; + hdrs = &parser->http.request->hdrs; + break; + } + + if (*hdr_count == parser->hdr_capacity) { + parser->hdr_capacity = + GPR_MAX(parser->hdr_capacity + 1, parser->hdr_capacity * 3 / 2); + *hdrs = gpr_realloc(*hdrs, parser->hdr_capacity * sizeof(**hdrs)); + } + (*hdrs)[(*hdr_count)++] = hdr; + +done: + if (error != GRPC_ERROR_NONE) { + gpr_free(hdr.key); + gpr_free(hdr.value); + } + return error; +} + +static grpc_error *finish_line(grpc_http_parser *parser) { + grpc_error *err; + switch (parser->state) { + case GRPC_HTTP_FIRST_LINE: + err = handle_first_line(parser); + if (err != GRPC_ERROR_NONE) return err; + parser->state = GRPC_HTTP_HEADERS; + break; + case GRPC_HTTP_HEADERS: + if (parser->cur_line_length == parser->cur_line_end_length) { + parser->state = GRPC_HTTP_BODY; + break; + } + err = add_header(parser); + if (err != GRPC_ERROR_NONE) { + return err; + } + break; + case GRPC_HTTP_BODY: + GPR_UNREACHABLE_CODE(return GRPC_ERROR_CREATE("Should never reach here")); + } + + parser->cur_line_length = 0; + return GRPC_ERROR_NONE; +} + +static grpc_error *addbyte_body(grpc_http_parser *parser, uint8_t byte) { + size_t *body_length = NULL; + char **body = NULL; + + if (parser->type == GRPC_HTTP_RESPONSE) { + body_length = &parser->http.response->body_length; + body = &parser->http.response->body; + } else if (parser->type == GRPC_HTTP_REQUEST) { + body_length = &parser->http.request->body_length; + body = &parser->http.request->body; + } else { + GPR_UNREACHABLE_CODE(return GRPC_ERROR_CREATE("Should never reach here")); + } + + if (*body_length == parser->body_capacity) { + parser->body_capacity = GPR_MAX(8, parser->body_capacity * 3 / 2); + *body = gpr_realloc((void *)*body, parser->body_capacity); + } + (*body)[*body_length] = (char)byte; + (*body_length)++; + + return GRPC_ERROR_NONE; +} + +static bool check_line(grpc_http_parser *parser) { + if (parser->cur_line_length >= 2 && + parser->cur_line[parser->cur_line_length - 2] == '\r' && + parser->cur_line[parser->cur_line_length - 1] == '\n') { + return true; + } + + // HTTP request with \n\r line termiantors. + else if (parser->cur_line_length >= 2 && + parser->cur_line[parser->cur_line_length - 2] == '\n' && + parser->cur_line[parser->cur_line_length - 1] == '\r') { + return true; + } + + // HTTP request with only \n line terminators. + else if (parser->cur_line_length >= 1 && + parser->cur_line[parser->cur_line_length - 1] == '\n') { + parser->cur_line_end_length = 1; + return true; + } + + return false; +} + +static grpc_error *addbyte(grpc_http_parser *parser, uint8_t byte) { + switch (parser->state) { + case GRPC_HTTP_FIRST_LINE: + case GRPC_HTTP_HEADERS: + if (parser->cur_line_length >= GRPC_HTTP_PARSER_MAX_HEADER_LENGTH) { + if (grpc_http1_trace) + gpr_log(GPR_ERROR, "HTTP client max line length (%d) exceeded", + GRPC_HTTP_PARSER_MAX_HEADER_LENGTH); + return 0; + } + parser->cur_line[parser->cur_line_length] = byte; + parser->cur_line_length++; + if (check_line(parser)) { + return finish_line(parser); + } else { + return GRPC_ERROR_NONE; + } + GPR_UNREACHABLE_CODE(return 0); + case GRPC_HTTP_BODY: + return addbyte_body(parser, byte); + } + GPR_UNREACHABLE_CODE(return 0); +} + +void grpc_http_parser_init(grpc_http_parser *parser, grpc_http_type type, + void *request_or_response) { + memset(parser, 0, sizeof(*parser)); + parser->state = GRPC_HTTP_FIRST_LINE; + parser->type = type; + parser->http.request_or_response = request_or_response; + parser->cur_line_end_length = 2; +} + +void grpc_http_parser_destroy(grpc_http_parser *parser) {} + +void grpc_http_request_destroy(grpc_http_request *request) { + size_t i; + gpr_free(request->body); + for (i = 0; i < request->hdr_count; i++) { + gpr_free(request->hdrs[i].key); + gpr_free(request->hdrs[i].value); + } + gpr_free(request->hdrs); + gpr_free(request->method); + gpr_free(request->path); +} + +void grpc_http_response_destroy(grpc_http_response *response) { + size_t i; + gpr_free(response->body); + for (i = 0; i < response->hdr_count; i++) { + gpr_free(response->hdrs[i].key); + gpr_free(response->hdrs[i].value); + } + gpr_free(response->hdrs); +} + +grpc_error *grpc_http_parser_parse(grpc_http_parser *parser, gpr_slice slice) { + size_t i; + + for (i = 0; i < GPR_SLICE_LENGTH(slice); i++) { + grpc_error *err = addbyte(parser, GPR_SLICE_START_PTR(slice)[i]); + if (err != GRPC_ERROR_NONE) return err; + } + + return GRPC_ERROR_NONE; +} + +grpc_error *grpc_http_parser_eof(grpc_http_parser *parser) { + if (parser->state != GRPC_HTTP_BODY) { + return GRPC_ERROR_CREATE("Did not finish headers"); + } + return GRPC_ERROR_NONE; +} diff --git a/src/core/lib/iomgr/udp_server.c b/src/core/lib/iomgr/udp_server.c index df6cf956d9..98ffccd59b 100644 --- a/src/core/lib/iomgr/udp_server.c +++ b/src/core/lib/iomgr/udp_server.c @@ -81,6 +81,7 @@ typedef struct { grpc_closure read_closure; grpc_closure destroyed_closure; grpc_udp_server_read_cb read_cb; + grpc_udp_server_orphan_cb orphan_cb; } server_port; /* the overall server */ @@ -168,6 +169,10 @@ static void deactivated_all_ports(grpc_exec_ctx *exec_ctx, grpc_udp_server *s) { server_port *sp = &s->ports[i]; sp->destroyed_closure.cb = destroyed_port; sp->destroyed_closure.cb_arg = s; + + GPR_ASSERT(sp->orphan_cb); + sp->orphan_cb(sp->emfd); + grpc_fd_orphan(exec_ctx, sp->emfd, &sp->destroyed_closure, NULL, "udp_listener_shutdown"); } @@ -268,7 +273,8 @@ static void on_read(grpc_exec_ctx *exec_ctx, void *arg, bool success) { static int add_socket_to_server(grpc_udp_server *s, int fd, const struct sockaddr *addr, size_t addr_len, - grpc_udp_server_read_cb read_cb) { + grpc_udp_server_read_cb read_cb, + grpc_udp_server_orphan_cb orphan_cb) { server_port *sp; int port; char *addr_str; @@ -292,6 +298,7 @@ static int add_socket_to_server(grpc_udp_server *s, int fd, memcpy(sp->addr.untyped, addr, addr_len); sp->addr_len = addr_len; sp->read_cb = read_cb; + sp->orphan_cb = orphan_cb; GPR_ASSERT(sp->emfd); gpr_mu_unlock(&s->mu); gpr_free(name); @@ -301,7 +308,8 @@ static int add_socket_to_server(grpc_udp_server *s, int fd, } int grpc_udp_server_add_port(grpc_udp_server *s, const void *addr, - size_t addr_len, grpc_udp_server_read_cb read_cb) { + size_t addr_len, grpc_udp_server_read_cb read_cb, + grpc_udp_server_orphan_cb orphan_cb) { int allocated_port1 = -1; int allocated_port2 = -1; unsigned i; @@ -348,7 +356,8 @@ int grpc_udp_server_add_port(grpc_udp_server *s, const void *addr, addr = (struct sockaddr *)&wild6; addr_len = sizeof(wild6); fd = grpc_create_dualstack_socket(addr, SOCK_DGRAM, IPPROTO_UDP, &dsmode); - allocated_port1 = add_socket_to_server(s, fd, addr, addr_len, read_cb); + allocated_port1 = + add_socket_to_server(s, fd, addr, addr_len, read_cb, orphan_cb); if (fd >= 0 && dsmode == GRPC_DSMODE_DUALSTACK) { goto done; } @@ -370,7 +379,8 @@ int grpc_udp_server_add_port(grpc_udp_server *s, const void *addr, addr = (struct sockaddr *)&addr4_copy; addr_len = sizeof(addr4_copy); } - allocated_port2 = add_socket_to_server(s, fd, addr, addr_len, read_cb); + allocated_port2 = + add_socket_to_server(s, fd, addr, addr_len, read_cb, orphan_cb); done: gpr_free(allocated_addr); diff --git a/src/core/lib/iomgr/udp_server.h b/src/core/lib/iomgr/udp_server.h index d8cf957a22..33c5ce11cd 100644 --- a/src/core/lib/iomgr/udp_server.h +++ b/src/core/lib/iomgr/udp_server.h @@ -48,6 +48,9 @@ typedef struct grpc_udp_server grpc_udp_server; typedef void (*grpc_udp_server_read_cb)(grpc_exec_ctx *exec_ctx, grpc_fd *emfd, struct grpc_server *server); +/* Called when the grpc_fd is about to be orphaned (and the FD closed). */ +typedef void (*grpc_udp_server_orphan_cb)(grpc_fd *emfd); + /* Create a server, initially not bound to any ports */ grpc_udp_server *grpc_udp_server_create(void); @@ -69,7 +72,8 @@ int grpc_udp_server_get_fd(grpc_udp_server *s, unsigned index); /* TODO(ctiller): deprecate this, and make grpc_udp_server_add_ports to handle all of the multiple socket port matching logic in one place */ int grpc_udp_server_add_port(grpc_udp_server *s, const void *addr, - size_t addr_len, grpc_udp_server_read_cb read_cb); + size_t addr_len, grpc_udp_server_read_cb read_cb, + grpc_udp_server_orphan_cb orphan_cb); void grpc_udp_server_destroy(grpc_exec_ctx *exec_ctx, grpc_udp_server *server, grpc_closure *on_done); diff --git a/src/python/grpcio/grpc/_cython/imports.generated.c b/src/python/grpcio/grpc/_cython/imports.generated.c index f0a40dbb35..09551472b5 100644 --- a/src/python/grpcio/grpc/_cython/imports.generated.c +++ b/src/python/grpcio/grpc/_cython/imports.generated.c @@ -125,6 +125,7 @@ grpc_header_key_is_legal_type grpc_header_key_is_legal_import; grpc_header_nonbin_value_is_legal_type grpc_header_nonbin_value_is_legal_import; grpc_is_binary_header_type grpc_is_binary_header_import; grpc_call_error_to_string_type grpc_call_error_to_string_import; +grpc_cronet_secure_channel_create_type grpc_cronet_secure_channel_create_import; grpc_auth_property_iterator_next_type grpc_auth_property_iterator_next_import; grpc_auth_context_property_iterator_type grpc_auth_context_property_iterator_import; grpc_auth_context_peer_identity_type grpc_auth_context_peer_identity_import; @@ -395,6 +396,7 @@ void pygrpc_load_imports(HMODULE library) { grpc_header_nonbin_value_is_legal_import = (grpc_header_nonbin_value_is_legal_type) GetProcAddress(library, "grpc_header_nonbin_value_is_legal"); grpc_is_binary_header_import = (grpc_is_binary_header_type) GetProcAddress(library, "grpc_is_binary_header"); grpc_call_error_to_string_import = (grpc_call_error_to_string_type) GetProcAddress(library, "grpc_call_error_to_string"); + grpc_cronet_secure_channel_create_import = (grpc_cronet_secure_channel_create_type) GetProcAddress(library, "grpc_cronet_secure_channel_create"); grpc_auth_property_iterator_next_import = (grpc_auth_property_iterator_next_type) GetProcAddress(library, "grpc_auth_property_iterator_next"); grpc_auth_context_property_iterator_import = (grpc_auth_context_property_iterator_type) GetProcAddress(library, "grpc_auth_context_property_iterator"); grpc_auth_context_peer_identity_import = (grpc_auth_context_peer_identity_type) GetProcAddress(library, "grpc_auth_context_peer_identity"); diff --git a/src/python/grpcio/grpc/_cython/imports.generated.h b/src/python/grpcio/grpc/_cython/imports.generated.h index d5e810b7cf..54c8aaad13 100644 --- a/src/python/grpcio/grpc/_cython/imports.generated.h +++ b/src/python/grpcio/grpc/_cython/imports.generated.h @@ -43,6 +43,7 @@ #include <grpc/census.h> #include <grpc/compression.h> #include <grpc/grpc.h> +#include <grpc/grpc_cronet.h> #include <grpc/grpc_security.h> #include <grpc/impl/codegen/alloc.h> #include <grpc/impl/codegen/byte_buffer.h> @@ -325,6 +326,9 @@ extern grpc_is_binary_header_type grpc_is_binary_header_import; typedef const char *(*grpc_call_error_to_string_type)(grpc_call_error error); extern grpc_call_error_to_string_type grpc_call_error_to_string_import; #define grpc_call_error_to_string grpc_call_error_to_string_import +typedef grpc_channel *(*grpc_cronet_secure_channel_create_type)(void *engine, const char *target, const grpc_channel_args *args, void *reserved); +extern grpc_cronet_secure_channel_create_type grpc_cronet_secure_channel_create_import; +#define grpc_cronet_secure_channel_create grpc_cronet_secure_channel_create_import typedef const grpc_auth_property *(*grpc_auth_property_iterator_next_type)(grpc_auth_property_iterator *it); extern grpc_auth_property_iterator_next_type grpc_auth_property_iterator_next_import; #define grpc_auth_property_iterator_next grpc_auth_property_iterator_next_import diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py index 7ba4fc1193..2cbf19ec98 100644 --- a/src/python/grpcio/grpc_core_dependencies.py +++ b/src/python/grpcio/grpc_core_dependencies.py @@ -232,6 +232,9 @@ CORE_SOURCE_FILES = [ 'src/core/ext/client_config/uri_parser.c', 'src/core/ext/transport/chttp2/server/insecure/server_chttp2.c', 'src/core/ext/transport/chttp2/client/insecure/channel_create.c', + 'src/core/ext/transport/cronet/client/secure/cronet_channel_create.c', + 'src/core/ext/transport/cronet/transport/cronet_api_dummy.c', + 'src/core/ext/transport/cronet/transport/cronet_transport.c', 'src/core/ext/lb_policy/grpclb/load_balancer_api.c', 'src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c', 'third_party/nanopb/pb_common.c', diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.c b/src/ruby/ext/grpc/rb_grpc_imports.generated.c index bc43f9d36b..cebbe8c40f 100644 --- a/src/ruby/ext/grpc/rb_grpc_imports.generated.c +++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.c @@ -125,6 +125,7 @@ grpc_header_key_is_legal_type grpc_header_key_is_legal_import; grpc_header_nonbin_value_is_legal_type grpc_header_nonbin_value_is_legal_import; grpc_is_binary_header_type grpc_is_binary_header_import; grpc_call_error_to_string_type grpc_call_error_to_string_import; +grpc_cronet_secure_channel_create_type grpc_cronet_secure_channel_create_import; grpc_auth_property_iterator_next_type grpc_auth_property_iterator_next_import; grpc_auth_context_property_iterator_type grpc_auth_context_property_iterator_import; grpc_auth_context_peer_identity_type grpc_auth_context_peer_identity_import; @@ -391,6 +392,7 @@ void grpc_rb_load_imports(HMODULE library) { grpc_header_nonbin_value_is_legal_import = (grpc_header_nonbin_value_is_legal_type) GetProcAddress(library, "grpc_header_nonbin_value_is_legal"); grpc_is_binary_header_import = (grpc_is_binary_header_type) GetProcAddress(library, "grpc_is_binary_header"); grpc_call_error_to_string_import = (grpc_call_error_to_string_type) GetProcAddress(library, "grpc_call_error_to_string"); + grpc_cronet_secure_channel_create_import = (grpc_cronet_secure_channel_create_type) GetProcAddress(library, "grpc_cronet_secure_channel_create"); grpc_auth_property_iterator_next_import = (grpc_auth_property_iterator_next_type) GetProcAddress(library, "grpc_auth_property_iterator_next"); grpc_auth_context_property_iterator_import = (grpc_auth_context_property_iterator_type) GetProcAddress(library, "grpc_auth_context_property_iterator"); grpc_auth_context_peer_identity_import = (grpc_auth_context_peer_identity_type) GetProcAddress(library, "grpc_auth_context_peer_identity"); diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.h b/src/ruby/ext/grpc/rb_grpc_imports.generated.h index b67361ca25..d7ea6c574c 100644 --- a/src/ruby/ext/grpc/rb_grpc_imports.generated.h +++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.h @@ -43,6 +43,7 @@ #include <grpc/census.h> #include <grpc/compression.h> #include <grpc/grpc.h> +#include <grpc/grpc_cronet.h> #include <grpc/grpc_security.h> #include <grpc/impl/codegen/alloc.h> #include <grpc/impl/codegen/byte_buffer.h> @@ -325,6 +326,9 @@ extern grpc_is_binary_header_type grpc_is_binary_header_import; typedef const char *(*grpc_call_error_to_string_type)(grpc_call_error error); extern grpc_call_error_to_string_type grpc_call_error_to_string_import; #define grpc_call_error_to_string grpc_call_error_to_string_import +typedef grpc_channel *(*grpc_cronet_secure_channel_create_type)(void *engine, const char *target, const grpc_channel_args *args, void *reserved); +extern grpc_cronet_secure_channel_create_type grpc_cronet_secure_channel_create_import; +#define grpc_cronet_secure_channel_create grpc_cronet_secure_channel_create_import typedef const grpc_auth_property *(*grpc_auth_property_iterator_next_type)(grpc_auth_property_iterator *it); extern grpc_auth_property_iterator_next_type grpc_auth_property_iterator_next_import; #define grpc_auth_property_iterator_next grpc_auth_property_iterator_next_import diff --git a/test/core/iomgr/udp_server_test.c b/test/core/iomgr/udp_server_test.c index 5248b613d7..a29a68eb33 100644 --- a/test/core/iomgr/udp_server_test.c +++ b/test/core/iomgr/udp_server_test.c @@ -54,6 +54,7 @@ static grpc_pollset *g_pollset; static gpr_mu *g_mu; static int g_number_of_reads = 0; static int g_number_of_bytes_read = 0; +static int g_number_of_orphan_calls = 0; static void on_read(grpc_exec_ctx *exec_ctx, grpc_fd *emfd, grpc_server *server) { @@ -71,6 +72,12 @@ static void on_read(grpc_exec_ctx *exec_ctx, grpc_fd *emfd, gpr_mu_unlock(g_mu); } +static void on_fd_orphaned(grpc_fd *emfd) { + gpr_log(GPR_INFO, "gRPC FD about to be orphaned: %d", + grpc_fd_wrapped_fd(emfd)); + g_number_of_orphan_calls++; +} + static void test_no_op(void) { grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; grpc_udp_server *s = grpc_udp_server_create(); @@ -88,6 +95,7 @@ static void test_no_op_with_start(void) { } static void test_no_op_with_port(void) { + g_number_of_orphan_calls = 0; grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; struct sockaddr_in addr; grpc_udp_server *s = grpc_udp_server_create(); @@ -96,13 +104,17 @@ static void test_no_op_with_port(void) { memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; GPR_ASSERT(grpc_udp_server_add_port(s, (struct sockaddr *)&addr, sizeof(addr), - on_read)); + on_read, on_fd_orphaned)); grpc_udp_server_destroy(&exec_ctx, s, NULL); grpc_exec_ctx_finish(&exec_ctx); + + /* The server had a single FD, which should be orphaned. */ + GPR_ASSERT(g_number_of_orphan_calls == 1); } static void test_no_op_with_port_and_start(void) { + g_number_of_orphan_calls = 0; grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; struct sockaddr_in addr; grpc_udp_server *s = grpc_udp_server_create(); @@ -111,12 +123,15 @@ static void test_no_op_with_port_and_start(void) { memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; GPR_ASSERT(grpc_udp_server_add_port(s, (struct sockaddr *)&addr, sizeof(addr), - on_read)); + on_read, on_fd_orphaned)); grpc_udp_server_start(&exec_ctx, s, NULL, 0, NULL); grpc_udp_server_destroy(&exec_ctx, s, NULL); grpc_exec_ctx_finish(&exec_ctx); + + /* The server had a single FD which should be orphaned. */ + GPR_ASSERT(g_number_of_orphan_calls == 1); } static void test_receive(int number_of_clients) { @@ -133,11 +148,12 @@ static void test_receive(int number_of_clients) { gpr_log(GPR_INFO, "clients=%d", number_of_clients); g_number_of_bytes_read = 0; + g_number_of_orphan_calls = 0; memset(&addr, 0, sizeof(addr)); addr.ss_family = AF_INET; - GPR_ASSERT( - grpc_udp_server_add_port(s, (struct sockaddr *)&addr, addr_len, on_read)); + GPR_ASSERT(grpc_udp_server_add_port(s, (struct sockaddr *)&addr, addr_len, + on_read, on_fd_orphaned)); svrfd = grpc_udp_server_get_fd(s, 0); GPR_ASSERT(svrfd >= 0); @@ -176,6 +192,8 @@ static void test_receive(int number_of_clients) { grpc_udp_server_destroy(&exec_ctx, s, NULL); grpc_exec_ctx_finish(&exec_ctx); + + GPR_ASSERT(g_number_of_orphan_calls == 5); } static void destroy_pollset(grpc_exec_ctx *exec_ctx, void *p, bool success) { diff --git a/test/core/surface/public_headers_must_be_c89.c b/test/core/surface/public_headers_must_be_c89.c index 3eeb55d033..fd6ff2c26f 100644 --- a/test/core/surface/public_headers_must_be_c89.c +++ b/test/core/surface/public_headers_must_be_c89.c @@ -36,6 +36,7 @@ #include <grpc/census.h> #include <grpc/compression.h> #include <grpc/grpc.h> +#include <grpc/grpc_cronet.h> #include <grpc/grpc_security.h> #include <grpc/grpc_security_constants.h> #include <grpc/impl/codegen/alloc.h> diff --git a/third_party/objective_c/Cronet/cronet_c_for_grpc.h b/third_party/objective_c/Cronet/cronet_c_for_grpc.h new file mode 100644 index 0000000000..15a511aebd --- /dev/null +++ b/third_party/objective_c/Cronet/cronet_c_for_grpc.h @@ -0,0 +1,202 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_CRONET_IOS_CRONET_C_FOR_GRPC_H_ +#define COMPONENTS_CRONET_IOS_CRONET_C_FOR_GRPC_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stddef.h> + +/* Cronet Engine API. */ + +/* Opaque object representing Cronet Engine. Created and configured outside + * of this API to facilitate sharing with other components */ +typedef struct cronet_engine { void* obj; } cronet_engine; + +void cronet_engine_add_quic_hint(cronet_engine* engine, + const char* host, + int port, + int alternate_port); + +/* Cronet Bidirectional Stream API */ + +/* Opaque object representing Cronet Bidirectional Stream. */ +typedef struct cronet_bidirectional_stream { + void* obj; + void* annotation; +} cronet_bidirectional_stream; + +/* A single request or response header element. */ +typedef struct cronet_bidirectional_stream_header { + const char* key; + const char* value; +} cronet_bidirectional_stream_header; + +/* Array of request or response headers or trailers. */ +typedef struct cronet_bidirectional_stream_header_array { + size_t count; + size_t capacity; + cronet_bidirectional_stream_header* headers; +} cronet_bidirectional_stream_header_array; + +/* Set of callbacks used to receive callbacks from bidirectional stream. */ +typedef struct cronet_bidirectional_stream_callback { + /* Invoked when request headers are sent. Indicates that stream has initiated + * the request. Consumer may call cronet_bidirectional_stream_write() to start + * writing data. + */ + void (*on_request_headers_sent)(cronet_bidirectional_stream* stream); + + /* Invoked when initial response headers are received. + * Consumer must call cronet_bidirectional_stream_read() to start reading. + * Consumer may call cronet_bidirectional_stream_write() to start writing or + * close the stream. Contents of |headers| is valid for duration of the call. + */ + void (*on_response_headers_received)( + cronet_bidirectional_stream* stream, + const cronet_bidirectional_stream_header_array* headers, + const char* negotiated_protocol); + + /* Invoked when data is read into the buffer passed to + * cronet_bidirectional_stream_read(). Only part of the buffer may be + * populated. To continue reading, call cronet_bidirectional_stream_read(). + * It may be invoked after on_response_trailers_received()}, if there was + * pending read data before trailers were received. + * + * If count is 0, it means the remote side has signaled that it will send no + * more data; future calls to cronet_bidirectional_stream_read() will result + * in the on_data_read() callback or on_succeded() callback if + * cronet_bidirectional_stream_write() was invoked with end_of_stream set to + * true. + */ + void (*on_read_completed)(cronet_bidirectional_stream* stream, + char* data, + int count); + + /** + * Invoked when all data passed to cronet_bidirectional_stream_write() is + * sent. + * To continue writing, call cronet_bidirectional_stream_write(). + */ + void (*on_write_completed)(cronet_bidirectional_stream* stream, + const char* data); + + /* Invoked when trailers are received before closing the stream. Only invoked + * when server sends trailers, which it may not. May be invoked while there is + * read data remaining in local buffer. Contents of |trailers| is valid for + * duration of the call. + */ + void (*on_response_trailers_received)( + cronet_bidirectional_stream* stream, + const cronet_bidirectional_stream_header_array* trailers); + + /** + * Invoked when there is no data to be read or written and the stream is + * closed successfully remotely and locally. Once invoked, no further callback + * methods will be invoked. + */ + void (*on_succeded)(cronet_bidirectional_stream* stream); + + /** + * Invoked if the stream failed for any reason after + * cronet_bidirectional_stream_start(). HTTP/2 error codes are + * mapped to chrome net error codes. Once invoked, no further callback methods + * will be invoked. + */ + void (*on_failed)(cronet_bidirectional_stream* stream, int net_error); + + /** + * Invoked if the stream was canceled via + * cronet_bidirectional_stream_cancel(). Once invoked, no further callback + * methods will be invoked. + */ + void (*on_canceled)(cronet_bidirectional_stream* stream); +} cronet_bidirectional_stream_callback; + +/* Create a new stream object that uses |engine| and |callback|. All stream + * tasks are performed asynchronously on the |engine| network thread. |callback| + * methods are invoked synchronously on the |engine| network thread, but must + * not run tasks on the current thread to prevent blocking networking operations + * and causing exceptions during shutdown. The |annotation| is stored in + * bidirectional stream for arbitrary use by application. + * + * Returned |cronet_bidirectional_stream*| is owned by the caller, and must be + * destroyed using |cronet_bidirectional_stream_destroy|. + * + * Both |calback| and |engine| must remain valid until stream is destroyed. + */ +cronet_bidirectional_stream* cronet_bidirectional_stream_create( + cronet_engine* engine, + void* annotation, + cronet_bidirectional_stream_callback* callback); + +/* TBD: The following methods return int. Should it be a custom type? */ + +/* Destroy stream object. Destroy could be called from any thread, including + * network thread, but is posted, so |stream| is valid until calling task is + * complete. + */ +int cronet_bidirectional_stream_destroy(cronet_bidirectional_stream* stream); + +/* Start the stream by sending request to |url| using |method| and |headers|. If + * |end_of_stream| is true, then no data is expected to be written. + */ +int cronet_bidirectional_stream_start( + cronet_bidirectional_stream* stream, + const char* url, + int priority, + const char* method, + const cronet_bidirectional_stream_header_array* headers, + bool end_of_stream); + +/* Read response data into |buffer| of |capacity| length. Must only be called at + * most once in response to each invocation of the + * on_response_headers_received() and on_read_completed() methods of the + * cronet_bidirectional_stream_callback. + * Each call will result in an invocation of one of the callback's + * on_read_completed method if data is read, its on_succeeded() method if + * the stream is closed, or its on_failed() method if there's an error. + */ +int cronet_bidirectional_stream_read(cronet_bidirectional_stream* stream, + char* buffer, + int capacity); + +/* Read response data into |buffer| of |capacity| length. Must only be called at + * most once in response to each invocation of the + * on_response_headers_received() and on_read_completed() methods of the + * cronet_bidirectional_stream_callback. + * Each call will result in an invocation of one of the callback's + * on_read_completed method if data is read, its on_succeeded() method if + * the stream is closed, or its on_failed() method if there's an error. + */ +int cronet_bidirectional_stream_write(cronet_bidirectional_stream* stream, + const char* buffer, + int count, + bool end_of_stream); + +/* Cancels the stream. Can be called at any time after + * cronet_bidirectional_stream_start(). The on_canceled() method of + * cronet_bidirectional_stream_callback will be invoked when cancelation + * is complete and no further callback methods will be invoked. If the + * stream has completed or has not started, calling + * cronet_bidirectional_stream_cancel() has no effect and on_canceled() will not + * be invoked. At most one callback method may be invoked after + * cronet_bidirectional_stream_cancel() has completed. + */ +int cronet_bidirectional_stream_cancel(cronet_bidirectional_stream* stream); + +/* Returns true if the |stream| was successfully started and is now done + * (succeeded, canceled, or failed). + * Returns false if the |stream| stream is not yet started or is in progress. + */ +bool cronet_bidirectional_stream_is_done(cronet_bidirectional_stream* stream); + +#ifdef __cplusplus +} +#endif + +#endif // COMPONENTS_CRONET_IOS_CRONET_C_FOR_GRPC_H_ diff --git a/tools/doxygen/Doxyfile.core b/tools/doxygen/Doxyfile.core index eed84252cc..aabca410da 100644 --- a/tools/doxygen/Doxyfile.core +++ b/tools/doxygen/Doxyfile.core @@ -786,6 +786,7 @@ include/grpc/impl/codegen/sync_generic.h \ include/grpc/impl/codegen/sync_posix.h \ include/grpc/impl/codegen/sync_win32.h \ include/grpc/impl/codegen/time.h \ +include/grpc/grpc_cronet.h \ include/grpc/grpc_security.h \ include/grpc/grpc_security_constants.h \ include/grpc/census.h \ diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal index ef3122b758..38d1477432 100644 --- a/tools/doxygen/Doxyfile.core.internal +++ b/tools/doxygen/Doxyfile.core.internal @@ -786,6 +786,7 @@ include/grpc/impl/codegen/sync_generic.h \ include/grpc/impl/codegen/sync_posix.h \ include/grpc/impl/codegen/sync_win32.h \ include/grpc/impl/codegen/time.h \ +include/grpc/grpc_cronet.h \ include/grpc/grpc_security.h \ include/grpc/grpc_security_constants.h \ include/grpc/census.h \ @@ -924,6 +925,7 @@ src/core/ext/client_config/subchannel.h \ src/core/ext/client_config/subchannel_call_holder.h \ src/core/ext/client_config/subchannel_index.h \ src/core/ext/client_config/uri_parser.h \ +third_party/objective_c/Cronet/cronet_c_for_grpc.h \ src/core/ext/lb_policy/grpclb/load_balancer_api.h \ src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h \ third_party/nanopb/pb.h \ @@ -1092,6 +1094,9 @@ src/core/ext/client_config/subchannel_index.c \ src/core/ext/client_config/uri_parser.c \ src/core/ext/transport/chttp2/server/insecure/server_chttp2.c \ src/core/ext/transport/chttp2/client/insecure/channel_create.c \ +src/core/ext/transport/cronet/client/secure/cronet_channel_create.c \ +src/core/ext/transport/cronet/transport/cronet_api_dummy.c \ +src/core/ext/transport/cronet/transport/cronet_transport.c \ src/core/ext/lb_policy/grpclb/load_balancer_api.c \ src/core/ext/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c \ third_party/nanopb/pb_common.c \ diff --git a/tools/run_tests/sources_and_headers.json b/tools/run_tests/sources_and_headers.json index e05786072b..70332b6f2e 100644 --- a/tools/run_tests/sources_and_headers.json +++ b/tools/run_tests/sources_and_headers.json @@ -4208,7 +4208,8 @@ "grpc_transport_chttp2_client_insecure", "grpc_transport_chttp2_client_secure", "grpc_transport_chttp2_server_insecure", - "grpc_transport_chttp2_server_secure" + "grpc_transport_chttp2_server_secure", + "grpc_transport_cronet_client_secure" ], "headers": [], "language": "c", @@ -6085,6 +6086,7 @@ "tsi" ], "headers": [ + "include/grpc/grpc_cronet.h", "include/grpc/grpc_security.h", "include/grpc/grpc_security_constants.h", "src/core/lib/security/context/security_context.h", @@ -6110,6 +6112,7 @@ "language": "c", "name": "grpc_secure", "src": [ + "include/grpc/grpc_cronet.h", "include/grpc/grpc_security.h", "include/grpc/grpc_security_constants.h", "src/core/lib/http/httpcli_security_connector.c", @@ -6365,6 +6368,24 @@ "type": "filegroup" }, { + "deps": [ + "grpc_base", + "grpc_transport_chttp2" + ], + "headers": [ + "third_party/objective_c/Cronet/cronet_c_for_grpc.h" + ], + "language": "c", + "name": "grpc_transport_cronet_client_secure", + "src": [ + "src/core/ext/transport/cronet/client/secure/cronet_channel_create.c", + "src/core/ext/transport/cronet/transport/cronet_api_dummy.c", + "src/core/ext/transport/cronet/transport/cronet_transport.c" + ], + "third_party": false, + "type": "filegroup" + }, + { "deps": [], "headers": [ "third_party/nanopb/pb.h", diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj b/vsprojects/vcxproj/grpc/grpc.vcxproj index b387300ad2..f6c3ca093c 100644 --- a/vsprojects/vcxproj/grpc/grpc.vcxproj +++ b/vsprojects/vcxproj/grpc/grpc.vcxproj @@ -293,6 +293,7 @@ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_posix.h" /> <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\sync_win32.h" /> <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\time.h" /> + <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc_cronet.h" /> <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc_security.h" /> <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc_security_constants.h" /> <ClInclude Include="$(SolutionDir)\..\include\grpc\census.h" /> @@ -433,6 +434,7 @@ <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\subchannel_call_holder.h" /> <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\subchannel_index.h" /> <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\uri_parser.h" /> + <ClInclude Include="$(SolutionDir)\..\third_party\objective_c\Cronet\cronet_c_for_grpc.h" /> <ClInclude Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\load_balancer_api.h" /> <ClInclude Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\proto\grpc\lb\v1\load_balancer.pb.h" /> <ClInclude Include="$(SolutionDir)\..\third_party\nanopb\pb.h" /> @@ -759,6 +761,12 @@ </ClCompile> <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\insecure\channel_create.c"> </ClCompile> + <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\cronet\client\secure\cronet_channel_create.c"> + </ClCompile> + <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\cronet\transport\cronet_api_dummy.c"> + </ClCompile> + <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\cronet\transport\cronet_transport.c"> + </ClCompile> <ClCompile Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\load_balancer_api.c"> </ClCompile> <ClCompile Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\proto\grpc\lb\v1\load_balancer.pb.c"> diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters index ed70daee49..44c6d0d8d9 100644 --- a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters +++ b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters @@ -469,6 +469,15 @@ <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\chttp2\client\insecure\channel_create.c"> <Filter>src\core\ext\transport\chttp2\client\insecure</Filter> </ClCompile> + <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\cronet\client\secure\cronet_channel_create.c"> + <Filter>src\core\ext\transport\cronet\client\secure</Filter> + </ClCompile> + <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\cronet\transport\cronet_api_dummy.c"> + <Filter>src\core\ext\transport\cronet\transport</Filter> + </ClCompile> + <ClCompile Include="$(SolutionDir)\..\src\core\ext\transport\cronet\transport\cronet_transport.c"> + <Filter>src\core\ext\transport\cronet\transport</Filter> + </ClCompile> <ClCompile Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\load_balancer_api.c"> <Filter>src\core\ext\lb_policy\grpclb</Filter> </ClCompile> @@ -606,6 +615,9 @@ <ClInclude Include="$(SolutionDir)\..\include\grpc\impl\codegen\time.h"> <Filter>include\grpc\impl\codegen</Filter> </ClInclude> + <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc_cronet.h"> + <Filter>include\grpc</Filter> + </ClInclude> <ClInclude Include="$(SolutionDir)\..\include\grpc\grpc_security.h"> <Filter>include\grpc</Filter> </ClInclude> @@ -1022,6 +1034,9 @@ <ClInclude Include="$(SolutionDir)\..\src\core\ext\client_config\uri_parser.h"> <Filter>src\core\ext\client_config</Filter> </ClInclude> + <ClInclude Include="$(SolutionDir)\..\third_party\objective_c\Cronet\cronet_c_for_grpc.h"> + <Filter>third_party\objective_c\Cronet</Filter> + </ClInclude> <ClInclude Include="$(SolutionDir)\..\src\core\ext\lb_policy\grpclb\load_balancer_api.h"> <Filter>src\core\ext\lb_policy\grpclb</Filter> </ClInclude> @@ -1154,6 +1169,18 @@ <Filter Include="src\core\ext\transport\chttp2\transport"> <UniqueIdentifier>{6f34254e-e69f-c9b4-156d-5024bade5408}</UniqueIdentifier> </Filter> + <Filter Include="src\core\ext\transport\cronet"> + <UniqueIdentifier>{1e9c85e9-5522-7ef8-0017-7e19990a6194}</UniqueIdentifier> + </Filter> + <Filter Include="src\core\ext\transport\cronet\client"> + <UniqueIdentifier>{d0530883-75d9-b5f7-d594-26735a70ac7b}</UniqueIdentifier> + </Filter> + <Filter Include="src\core\ext\transport\cronet\client\secure"> + <UniqueIdentifier>{4fa6fe90-b7a8-5c8f-d629-db1e68d89eed}</UniqueIdentifier> + </Filter> + <Filter Include="src\core\ext\transport\cronet\transport"> + <UniqueIdentifier>{31518af8-5860-6d0d-ff78-4059fce29ec2}</UniqueIdentifier> + </Filter> <Filter Include="src\core\lib"> <UniqueIdentifier>{5b2ded3f-84a5-f6b4-2060-286c7d1dc945}</UniqueIdentifier> </Filter> @@ -1232,6 +1259,12 @@ <Filter Include="third_party\nanopb"> <UniqueIdentifier>{93d6596d-330c-1d27-6f84-3c840e57869e}</UniqueIdentifier> </Filter> + <Filter Include="third_party\objective_c"> + <UniqueIdentifier>{3a56a516-857e-d2aa-95cc-11685baf4e8c}</UniqueIdentifier> + </Filter> + <Filter Include="third_party\objective_c\Cronet"> + <UniqueIdentifier>{a165c6e3-0776-6f40-7351-d7865668e220}</UniqueIdentifier> + </Filter> </ItemGroup> </Project> |